diff --git a/.github/workflows/tox-experimental.yml b/.github/workflows/tox-experimental.yml index 862f00476e9..7bf186ace20 100644 --- a/.github/workflows/tox-experimental.yml +++ b/.github/workflows/tox-experimental.yml @@ -40,7 +40,8 @@ jobs: matrix: # This list is different from the one in tox.yml: # Trac #31526 switches gcc 4.x-based distributions to using the gcc_spkg configuration factor - tox_system_factor: [ubuntu-trusty-gcc_spkg, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie-gcc_spkg, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17-gcc_spkg, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7-gcc_spkg, centos-8, gentoo, archlinux-latest, opensuse-15, opensuse-15.3, opensuse-tumbleweed, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-gcc_spkg] + # Trac #32281 removes gcc 4.x-based distributions whose binutils are unusable + tox_system_factor: [ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie-gcc_spkg, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7-gcc_spkg, centos-8, gentoo, archlinux-latest, opensuse-15, opensuse-15.3, opensuse-tumbleweed, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-i386-gcc_spkg] tox_packages_factor: [maximal] targets_pattern: [0-g, h-o, p, q-z] env: diff --git a/.github/workflows/tox-optional.yml b/.github/workflows/tox-optional.yml index 279c6d23feb..9ffc60010d3 100644 --- a/.github/workflows/tox-optional.yml +++ b/.github/workflows/tox-optional.yml @@ -40,7 +40,8 @@ jobs: matrix: # This list is different from the one in tox.yml: # Trac #31526 switches gcc 4.x-based distributions to using the gcc_spkg configuration factor - tox_system_factor: [ubuntu-trusty-gcc_spkg, ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie-gcc_spkg, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-17-gcc_spkg, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7-gcc_spkg, centos-8, gentoo, archlinux-latest, opensuse-15, opensuse-15.3, opensuse-tumbleweed, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-gcc_spkg] + # Trac #32281 removes gcc 4.x-based distributions whose binutils are unusable + tox_system_factor: [ubuntu-xenial, ubuntu-bionic, ubuntu-focal, ubuntu-groovy, ubuntu-hirsute, debian-jessie-gcc_spkg, debian-stretch, debian-buster, debian-bullseye, debian-sid, linuxmint-18, linuxmint-19, linuxmint-19.3, linuxmint-20.1, fedora-26, fedora-27, fedora-28, fedora-29, fedora-30, fedora-31, fedora-32, fedora-33, fedora-34, centos-7-gcc_spkg, centos-8, gentoo, archlinux-latest, opensuse-15, opensuse-15.3, opensuse-tumbleweed, slackware-14.2, conda-forge, ubuntu-bionic-i386, manylinux-2_24-i686, debian-buster-i386, centos-7-i386-gcc_spkg] tox_packages_factor: [maximal] targets_pattern: [0-g, h-o, p, q-z] env: diff --git a/.zenodo.json b/.zenodo.json index 51e1992f633..035015bacf5 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.5.beta2", - "version": "9.5.beta2", + "title": "sagemath/sage: 9.5.beta3", + "version": "9.5.beta3", "upload_type": "software", - "publication_date": "2021-09-26", + "publication_date": "2021-10-11", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.5.beta2", + "identifier": "https://github.com/sagemath/sage/tree/9.5.beta3", "relation": "isSupplementTo" }, { diff --git a/COPYING.txt b/COPYING.txt index 2da3a8e492c..1ddd77c21a1 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -32,7 +32,6 @@ the licenses of the components of Sage are included below as well. SOFTWARE LICENSE ----------------------------------------------------------------------- arb GPLv2+ -atlas Modified BSD boehm_gc MIT-like license (see below) backports_ssl_match_hostname Python License boost_cropped Boost Software License (see below) diff --git a/README.md b/README.md index 6b9350c1fba..f4d21b555c1 100644 --- a/README.md +++ b/README.md @@ -349,7 +349,7 @@ Simplified directory layout (only essential files/directories): SAGE_ROOT Root directory (sage-x.y.z in Sage tarball) ├── build │ └── pkgs Every package is a subdirectory here -│ ├── atlas +│ ├── 4ti2 │ … │ └── zn_poly ├── configure Top-level configure script @@ -381,9 +381,9 @@ SAGE_ROOT Root directory (sage-x.y.z in Sage tarball) │ ├── dochtml.log Log of the documentation build │ ├── install.log Full install log │ └── pkgs Build logs of individual packages -│ ├── atlas-3.10.1.p7.log +│ ├── alabaster-0.7.12.log │ … -│ └── zn_poly-0.9.p11.log +│ └── zn_poly-0.9.2.log ├── m4 M4 macros for configure │ └── *.m4 ├── Makefile Running "make" uses this file @@ -394,9 +394,9 @@ SAGE_ROOT Root directory (sage-x.y.z in Sage tarball) │ ├── doc Sage documentation sources │ └── sage The Sage library source code ├── upstream Source tarballs of packages -│ ├── atlas-3.10.1.tar.bz2 +│ ├── Babel-2.9.1.tar.gz │ … -│ └── zn_poly-0.9.tar.bz2 +│ └── zn_poly-0.9.2.tar.gz └── VERSION.txt ``` For more details see [our Developer's Guide](https://doc.sagemath.org/html/en/developer/coding_basics.html#files-and-directory-structure). diff --git a/VERSION.txt b/VERSION.txt index 85f52b22a59..88f7d68ebc9 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.5.beta2, Release Date: 2021-09-26 +SageMath version 9.5.beta3, Release Date: 2021-10-11 diff --git a/build/bin/sage-package b/build/bin/sage-package index ed72756bf26..eeebbcd2c2e 100755 --- a/build/bin/sage-package +++ b/build/bin/sage-package @@ -16,7 +16,6 @@ # $ sage-package list | sort # 4ti2 # arb -# atlas # autotools # [...] # zn_poly diff --git a/build/make/Makefile.in b/build/make/Makefile.in index bd8ca2a99da..912f455c566 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -33,7 +33,7 @@ SPKG_INST_RELDIR = var/lib/sage/installed TOOLCHAIN = @SAGE_TOOLCHAIN@ PYTHON = python3 MP_LIBRARY = @SAGE_MP_LIBRARY@ -BLAS = @SAGE_BLAS@ +BLAS = openblas # pkgconfig files generated/installed at build time PCFILES = @SAGE_SYSTEM_FACADE_PC_FILES@ diff --git a/build/pkgs/4ti2/distros/arch.txt b/build/pkgs/4ti2/distros/arch.txt new file mode 100644 index 00000000000..252f9efdbd4 --- /dev/null +++ b/build/pkgs/4ti2/distros/arch.txt @@ -0,0 +1 @@ +4ti2 diff --git a/build/pkgs/4ti2/distros/cygwin.txt b/build/pkgs/4ti2/distros/cygwin.txt new file mode 100644 index 00000000000..cd62bb6f0a0 --- /dev/null +++ b/build/pkgs/4ti2/distros/cygwin.txt @@ -0,0 +1 @@ +lib4ti2-devel diff --git a/build/pkgs/4ti2/distros/debian.txt b/build/pkgs/4ti2/distros/debian.txt new file mode 100644 index 00000000000..252f9efdbd4 --- /dev/null +++ b/build/pkgs/4ti2/distros/debian.txt @@ -0,0 +1 @@ +4ti2 diff --git a/build/pkgs/4ti2/distros/fedora.txt b/build/pkgs/4ti2/distros/fedora.txt new file mode 100644 index 00000000000..252f9efdbd4 --- /dev/null +++ b/build/pkgs/4ti2/distros/fedora.txt @@ -0,0 +1 @@ +4ti2 diff --git a/build/pkgs/4ti2/distros/freebsd.txt b/build/pkgs/4ti2/distros/freebsd.txt new file mode 100644 index 00000000000..2554e2f0552 --- /dev/null +++ b/build/pkgs/4ti2/distros/freebsd.txt @@ -0,0 +1 @@ +math/4ti2 diff --git a/build/pkgs/4ti2/distros/gentoo.txt b/build/pkgs/4ti2/distros/gentoo.txt new file mode 100644 index 00000000000..81580261c2f --- /dev/null +++ b/build/pkgs/4ti2/distros/gentoo.txt @@ -0,0 +1 @@ +sci-mathematics/4ti2 diff --git a/build/pkgs/4ti2/spkg-configure.m4 b/build/pkgs/4ti2/spkg-configure.m4 new file mode 100644 index 00000000000..a16da8fc4b7 --- /dev/null +++ b/build/pkgs/4ti2/spkg-configure.m4 @@ -0,0 +1,32 @@ +SAGE_SPKG_CONFIGURE([4ti2], [ + SAGE_SPKG_DEPCHECK([gmp mpir glpk zlib], [ + dnl Debian installs these programs with an executable prefix "4ti2-", + dnl OpenSUSE uses the prefix "4ti2_". + dnl Singular checks for unprefixed and prefixed with "4ti2-". + dnl Polymake does not check for prefixed binaries. + m4_foreach([prog], [hilbert,markov,graver,zsolve,qsolve,rays,ppi,circuits,groebner], [ + AC_CHECK_PROGS([FOURTITWO_]m4_toupper(prog), prog [4ti2-]prog [4ti2_]prog) + AS_VAR_IF([FOURTITWO_]m4_toupper(prog), [""], [sage_spkg_install_4ti2=yes]) + AC_SUBST([FOURTITWO_]m4_toupper(prog)) + ]) + dnl Adapted from https://github.com/latte-int/latte/blob/master/m4/4ti2-check.m4 + AC_MSG_CHECKING(for library 4ti2gmp) + BACKUP_CXXFLAGS=${CXXFLAGS} + BACKUP_LIBS=${LIBS} + FORTYTWO_CXXFLAGS="-D__STDC_LIMIT_MACROS -D_4ti2_GMP_" + FORTYTWO_LIBS="-l4ti2gmp -lzsolve" + CXXFLAGS="${BACKUP_CXXFLAGS} ${FORTYTWO_CXXFLAGS} ${GMP_CFLAGS}" + LIBS="${BACKUP_LIBS} ${FORTYTWO_LIBS} ${GMP_LIBS}" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include "4ti2/4ti2.h" +]], [[ _4ti2_rays_create_state(_4ti2_PREC_INT_ARB); +]])],[ + AC_MSG_RESULT([yes]) +],[ + AC_MSG_RESULT([no]) + sage_spkg_install_4ti2=yes +]) + CXXFLAGS=${BACKUP_CXXFLAGS} + LIBS=${BACKUP_LIBS} + ]) +]) diff --git a/build/pkgs/_bootstrap/distros/void.txt b/build/pkgs/_bootstrap/distros/void.txt index 3b19fa50690..eefc9315cb5 100644 --- a/build/pkgs/_bootstrap/distros/void.txt +++ b/build/pkgs/_bootstrap/distros/void.txt @@ -1,4 +1,4 @@ # Packages needed for ./bootstrap -gettext autoconf automake libtool pkg-config +gettext autoconf automake libtool gettext-devel xtools mk-configure diff --git a/build/pkgs/_prereq/distros/void.txt b/build/pkgs/_prereq/distros/void.txt index 5f6fed81c71..a2e7644840f 100644 --- a/build/pkgs/_prereq/distros/void.txt +++ b/build/pkgs/_prereq/distros/void.txt @@ -2,6 +2,7 @@ binutils make m4 perl +pkg-config python3 tar bc diff --git a/build/pkgs/arb/distros/void.txt b/build/pkgs/arb/distros/void.txt new file mode 100644 index 00000000000..3319855150c --- /dev/null +++ b/build/pkgs/arb/distros/void.txt @@ -0,0 +1 @@ +arb-devel diff --git a/build/pkgs/argcomplete/SPKG.rst b/build/pkgs/argcomplete/SPKG.rst new file mode 100644 index 00000000000..4e823cf2f7d --- /dev/null +++ b/build/pkgs/argcomplete/SPKG.rst @@ -0,0 +1,18 @@ +argcomplete: Bash tab completion for argparse +============================================= + +Description +----------- + +Bash tab completion for argparse + +License +------- + +Apache Software License + +Upstream Contact +---------------- + +https://pypi.org/project/argcomplete/ + diff --git a/build/pkgs/argcomplete/checksums.ini b/build/pkgs/argcomplete/checksums.ini new file mode 100644 index 00000000000..6acbb72e9a2 --- /dev/null +++ b/build/pkgs/argcomplete/checksums.ini @@ -0,0 +1,5 @@ +tarball=argcomplete-VERSION.tar.gz +sha1=bd6b35aee6fc44c82d02772b054b5c5ff1bc5983 +md5=ded03f9c5d41c193dfe5869634d78211 +cksum=3352024634 +upstream_url=https://pypi.io/packages/source/a/argcomplete/argcomplete-VERSION.tar.gz diff --git a/build/pkgs/scandir/dependencies b/build/pkgs/argcomplete/dependencies similarity index 54% rename from build/pkgs/scandir/dependencies rename to build/pkgs/argcomplete/dependencies index 15df0c4d6d8..0738c2d7777 100644 --- a/build/pkgs/scandir/dependencies +++ b/build/pkgs/argcomplete/dependencies @@ -2,4 +2,3 @@ $(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. -It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/argcomplete/install-requires.txt b/build/pkgs/argcomplete/install-requires.txt new file mode 100644 index 00000000000..e60624ffee6 --- /dev/null +++ b/build/pkgs/argcomplete/install-requires.txt @@ -0,0 +1 @@ +argcomplete diff --git a/build/pkgs/argcomplete/package-version.txt b/build/pkgs/argcomplete/package-version.txt new file mode 100644 index 00000000000..81f363239f5 --- /dev/null +++ b/build/pkgs/argcomplete/package-version.txt @@ -0,0 +1 @@ +1.12.3 diff --git a/build/pkgs/argcomplete/spkg-install.in b/build/pkgs/argcomplete/spkg-install.in new file mode 100644 index 00000000000..37ac1a53437 --- /dev/null +++ b/build/pkgs/argcomplete/spkg-install.in @@ -0,0 +1,2 @@ +cd src +sdh_pip_install . diff --git a/build/pkgs/atlas/type b/build/pkgs/argcomplete/type similarity index 100% rename from build/pkgs/atlas/type rename to build/pkgs/argcomplete/type diff --git a/build/pkgs/atlas/SPKG.rst b/build/pkgs/atlas/SPKG.rst deleted file mode 100644 index f024ff2c753..00000000000 --- a/build/pkgs/atlas/SPKG.rst +++ /dev/null @@ -1,107 +0,0 @@ -atlas: Automatically Tuned Linear Algebra Software (BLAS implementation) -======================================================================== - -Description ------------ - -Automatically Tuned Linear Algebra Software - -License -------- - -3-clause BSD - - -Upstream Contact ----------------- - -- http://math-atlas.sourceforge.net -- Atlas devel mailing list. -- Clint Whaley has frequently answered questions from the Sage project - -Dependencies ------------- - -- Python - - -Special Update/Build Instructions ---------------------------------- - -- src/lapack-x.y.z.tgz: The netlib lapack tarball. If you update this, - make sure you also update the LAPACK_TARBALL variable in - spkg-install. - -- src/ATLAS-lib: We are using a dummy autotools/libtools project - to repack the static ATLAS libraries into shared libraries. - -- src/ARCHS: We ship some archdef tarballs to speed ATLAS build. -- spkg-install: If you update atlas to a new version make sure that the - ATLAS_OSTYPE, ATLAS_MACHTYPE, and ATLAS_ISAEXT variables in - spkg-install remain in sync with atlas' CONFIG/include/atlconf.h - -- The package is never installed on OS X, unless you set - SAGE_ATLAS_ARCH. - -Patches -~~~~~~~ - -- patches/detect.patch: Fix Itanium2 support on modern - RHEL 5 and SLES 10 systems, work around -m64 issue on Itanium2, - and correctly detect number and speed of CPUs on a bunch of systems. - -- patches/arm_hard_floats.patch: make sure soft floats are not enforced - on ARM. -- patches/Makefile.patch: fix clean target. -- patches/do_not_force_mutex.patch: always use assembly over mutex - since the mutex version fails to build a shared library. See #15045 - for details. - -- patches/glibc_scanf_workaround.patch: Workaround for the scanf bug - in glibc-2.18 that breaks the atlas auto-tuning system. - -Configuration -~~~~~~~~~~~~~ - -The package can be configured via three environment variables: - -- SAGE_ATLAS_LIB=path - - If this environment variable is set, the libraries libatlas, - libcblas, liblapack, and libf77blas from the direcory "path" are - used and ATLAS is not compiled from source. The libraries can be - either static (endin in .a) or shared libraries (ending in .so or - .dylib). - -- SAGE_ATLAS_ARCH=arch[,isaext1][,isaext2]...[,isaextN] - - The given architectural default and instruction set extensions are - used instead of the empirical tuning. Available architectures are - - POWER3, POWER4, POWER5, PPCG4, PPCG5, POWER6, POWER7, IBMz9, - IBMz10, IBMz196, x86x87, x86SSE1, x86SSE2, x86SSE3, P5, P5MMX, - PPRO, PII, PIII, PM, CoreSolo, CoreDuo, Core2Solo, Core2, Corei1, - Corei2, Atom, P4, P4E, Efficeon, K7, HAMMER, AMD64K10h, AMDDOZER, - UNKNOWNx86, IA64Itan, IA64Itan2, USI, USII, USIII, USIV, UST1, UST2, - UnknownUS, MIPSR1xK, MIPSICE9, ARMv6, ARMv7 - - and instruction set extensions are - - VSX, AltiVec, AVXMAC, AVXFMA4, AVX, SSE3, SSE2, SSE1, 3DNow, NEON - - In addition, you can also set - -- SAGE_ATLAS_ARCH=fast picks defaults for a modern (2-3 year old) - CPU of your processor line, and - -- SAGE_ATLAS_ARCH=base picks defaults that should work for a ~10 - year old CPU. - - For example, - - SAGE_ATLAS_ARCH=Corei2,AVX,SSE3,SSE2,SSE1 - - would be appropriate for a Core i7 CPU. - -- If SAGE_ATLAS_SAVE_ARCHDEF = is given, then a new archdef - file is created and saved to the given path. diff --git a/build/pkgs/atlas/checksums.ini b/build/pkgs/atlas/checksums.ini deleted file mode 100644 index 76fce8ca4cd..00000000000 --- a/build/pkgs/atlas/checksums.ini +++ /dev/null @@ -1,4 +0,0 @@ -tarball=atlas-VERSION.tar.bz2 -sha1=7d24b5f5213479bd55d997d03d187731be4013b6 -md5=d9ca580b85e165a9870db6187542582e -cksum=1184071458 diff --git a/build/pkgs/atlas/configuration.py b/build/pkgs/atlas/configuration.py deleted file mode 100644 index cea295d1906..00000000000 --- a/build/pkgs/atlas/configuration.py +++ /dev/null @@ -1,249 +0,0 @@ -###################################################################### -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -###################################################################### - -from __future__ import print_function - -import platform -import os -import sys -import shutil -import glob -import subprocess - - -# this dictionary will hold all configuration information -conf = dict() - -# Here is a list of keys and (some of) their possible values. First, -# strings: -# -# system: Linux, SunOS, Darwin, FreeBSD, CYGWIN -# release: (Version number of the operating system, output of uname -r) -# machine: i386, x86_64, # Linux, Darwin, *BSD -# sun4u, i86pc # SunOS -# processor: i386, x86_64, powerpc, sparc -# bits: 32bit, 64bit -# fortran: g95, gfortran -# ld: GNU, Solaris, Darwin - -# The following pre-defined boolean values are determined from the -# strings. The keys are distinguished by a question mark at the -# end. If possible use these keys as they guard against typos. -# -# Linux?, Solaris?, Darwin?, FreeBSD?, CYGWIN? # system -# OS_X_Lion? # release -# Intel?, PPC?, SPARC? ARM? # processor -# 64bit?, 32bit? # bits -# fortran_g95?, fortran_GNU? # fortran -# linker_GNU?, linker_Solaris?, linker_Darwin? # ld - - -###################################################################### -### Functions -###################################################################### - -def try_run(command, ignore=False): - """ - Try to execute ``command`` and return its output as string. - - Return ``None`` if command not found. Return ``None`` if execution - fails and ``ignore=False`` (default). Otherwise, return output of - ``command`` as string. Here, output always means the concatenation - of stdout and stderr. - """ - f = subprocess.Popen(command, shell=True, - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - result = f.communicate() - rc = f.wait() - if (not ignore) and (rc!=0): - return None - # concatenate stdout and stderr - return (result[0].strip() + result[1].strip()).decode('utf8') - - -def cp(source_pattern, destination): - """ - Portable implementation of "cp -p" - """ - for filename in glob.iglob(source_pattern): - print('Copying', filename, 'to', destination) - shutil.copy2(filename, destination) - - -def ln(source, destination): - """ - Portable implementation of "ln -sf" - """ - if os.path.exists(destination): - os.remove(destination) - print('Linking', source, 'to', destination) - os.symlink(source, destination) - - -def is_executable_file(fpath): - """ - Check that `fpath` is a file and executable (ie not a directory with +x set) - """ - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - -def which(program): - """ - Portable implementation of "which" - """ - fpath, fname = os.path.split(program) - if fpath != '': - return program - for path in os.environ['PATH'].split(os.pathsep): - f = os.path.join(path, program) - if is_executable_file(f): - return f - raise ValueError('The program '+program+' is not in the $PATH.') - -class edit_in_place(object): - """ - Edit a file in-place by search/replacing regular expressions. - """ - def __init__(self, filename): - self.filename = filename - f = open(filename, 'r') - self.data = f.read() - f.close() - - def replace(self, find_regex, subs, count=0): - self.data = glob.re.sub(find_regex, subs, self.data, count) - return self - - def close(self): - f = open(self.filename, 'w') - f.write(self.data) - f.close() - - -###################################################################### -### uname -###################################################################### - -try: - conf['system'] = os.environ['UNAME'] -except KeyError: - conf['system'] = platform.system() - -try: - conf['release'] = subprocess.check_output(['uname', '-r']).decode('utf8').strip() -except subprocess.CalledProcessError: - conf['release'] = "" - -conf['Linux?' ] = (conf['system'] == 'Linux') -conf['Solaris?'] = (conf['system'] == 'SunOS') -conf['Darwin?' ] = (conf['system'] == 'Darwin') -conf['OS_X_Lion?'] = (conf['Darwin?'] and conf['release'].startswith('11.')) -conf['FreeBSD?'] = (conf['system'] == 'FreeBSD') -conf['CYGWIN?' ] = (conf['system'] == 'CYGWIN') - -conf['machine'] = platform.machine() - -conf['processor'] = platform.processor() - -conf['ARM?'] = (platform.machine().startswith('arm')) -conf['Intel?'] = (platform.machine() in ('i386', 'i486', 'i586', 'i686', 'x86_64', - 'AMD64', 'i86pc')) -conf['IA64?'] = ((platform.processor() == 'ia64') - or (platform.machine() == 'ia64')) -conf['PPC?'] = (platform.processor() == 'powerpc') -conf['SPARC?'] = (platform.processor() == 'sparc') - -conf['generic_binary?'] = (os.environ.get('SAGE_FAT_BINARY', 'no') == 'yes') - -conf['user'] = os.environ.get('ATLAS_CONFIGURE', '') - -###################################################################### -### bit width -###################################################################### - -conf['bits'] = platform.architecture()[0] - -conf['64bit?'] = (conf['bits'] == '64bit') -conf['32bit?'] = (conf['bits'] != '64bit') - - -###################################################################### -### fortran compiler -###################################################################### - -fortran_version = try_run('$FC --version') -if fortran_version is None: - print('Cannot execute fortran compiler ($FC)!') - sys.exit(3) -if 'G95' in fortran_version: - conf['fortran'] = 'g95' -elif 'GNU Fortran' in fortran_version: - conf['fortran'] = 'gfortran' -else: - print('Unknown fortran compiler version: '+fortran_version) - conf['fortran'] = None - - -conf['fortran_g95?'] = (conf['fortran'] == 'g95') -conf['fortran_GNU?'] = (conf['fortran'] == 'gfortran') - - -if conf['fortran_g95?']: - g95_dir = glob.glob(os.environ['SAGE_LOCAL']+'/lib/gcc-lib/*/*') - assert len(g95_dir)==1, 'Could not find G95 dir: '+str(g95_dir) - conf['fortran_g95_dir'] = g95_dir[0] - -###################################################################### -### linker -###################################################################### - -if conf['Solaris?']: - # Note: Solaris linker does not accept --version - # ignore error code as 'ld -V' likes to error on some Solaris versions - ld_version = try_run('ld -V', ignore=True) -else: - ld_version = try_run('ld -v') - -if ld_version is None: - print('Cannot execute ld!') - sys.exit(3) -if 'GNU' in ld_version: - conf['ld'] = 'GNU' -elif 'Solaris' in ld_version: - conf['ld'] = 'Solaris' -elif 'Apple' in ld_version: - conf['ld'] = 'Darwin' -else: - print('Unknown linker: '+ld_version) - conf['ld'] = None - -conf['linker_GNU?'] = (conf['ld'] == 'GNU') -conf['linker_Solaris?'] = (conf['ld'] == 'Solaris') -conf['linker_Darwin?'] = (conf['ld'] == 'Darwin') - - -if conf['Solaris?'] and conf['linker_GNU?']: - print("WARNING: You are using the GNU linker from 'binutils'") - print("Generally it is considered better to use the Sun linker") - print("but Sage has been built on Solaris using the GNU linker") - print("although that was a very old version of Sage, which") - print("never passes all the Sage test-suite.") - - - -###################################################################### -### paths, files, and environment variables -###################################################################### - -conf['SPKG_DIR'] = os.getcwd() -conf['SAGE_LOCAL'] = os.environ['SAGE_LOCAL'] - - -###################################################################### -### The end: print configuration -###################################################################### - -print("Configuration:") -for k in sorted(conf, key=str.lower): - print(' {}: {}'.format(k, conf[k])) diff --git a/build/pkgs/atlas/dependencies b/build/pkgs/atlas/dependencies deleted file mode 100644 index 46757bc2b61..00000000000 --- a/build/pkgs/atlas/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -gfortran | $(PYTHON) - ----------- -All lines of this file are ignored except the first. -It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/atlas/distros/macports.txt b/build/pkgs/atlas/distros/macports.txt deleted file mode 100644 index ef8830e002d..00000000000 --- a/build/pkgs/atlas/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -atlas diff --git a/build/pkgs/atlas/distros/repology.txt b/build/pkgs/atlas/distros/repology.txt deleted file mode 100644 index fcea775a974..00000000000 --- a/build/pkgs/atlas/distros/repology.txt +++ /dev/null @@ -1 +0,0 @@ -atlas-linear-algebra diff --git a/build/pkgs/atlas/enums.py b/build/pkgs/atlas/enums.py deleted file mode 100644 index 29a2ca787ba..00000000000 --- a/build/pkgs/atlas/enums.py +++ /dev/null @@ -1,202 +0,0 @@ -""" -Verify that the ATLAS enums are in sync with the spkg-install enums - -TESTS:: - - sage: check_enums(sample_print_enums_output) -""" - -from __future__ import print_function - -# constants from src/ATLAS/CONFIG/include/atlconf.h -# Note: must be lists, not tuples, for Python-2.4 support - -ATLAS_OSTYPE = ( # static char *osnam - 'UNKNOWN', 'Linux', 'SunOS', 'SunOS4', 'OSF1', 'IRIX', 'AIX', - 'Win9x', 'WinNT', 'Win64', 'HPUX', 'FreeBSD', 'OSX') - -ATLAS_MACHTYPE = ( # static char *machnam - 'UNKNOWN', 'POWER3', 'POWER4', 'POWER5', 'PPCG4', 'PPCG5', - 'POWER6', 'POWER7', 'POWERe6500', 'IBMz9', 'IBMz10', 'IBMz196', - 'x86x87', 'x86SSE1', 'x86SSE2', 'x86SSE3', - 'P5', 'P5MMX', 'PPRO', 'PII', 'PIII', 'PM', 'CoreSolo', - 'CoreDuo', 'Core2Solo', 'Core2', 'Corei1', 'Corei2', 'Corei3', - 'Atom', 'P4', 'P4E', - 'Efficeon', 'K7', 'HAMMER', 'AMD64K10h', 'AMDLLANO', 'AMDDOZER','AMDDRIVER', - 'UNKNOWNx86', 'IA64Itan', 'IA64Itan2', - 'USI', 'USII', 'USIII', 'USIV', 'UST1', 'UST2', 'UnknownUS', - 'MIPSR1xK', 'MIPSICE9', 'ARMv6', 'ARMv7') - -ATLAS_ISAEXT = ( # static char *ISAXNAM - 'None', 'VSX', 'AltiVec', 'AVXMAC', 'AVXFMA4', 'AVX', 'SSE3', 'SSE2', 'SSE1', - '3DNow', 'NEON') - - - -# for doctesting purposes -sample_print_enums_output = \ -""" -Architectural enums (Config's enum MACHTYPE): - 0 = 'UNKNOWN' - 1 = 'POWER3' - 2 = 'POWER4' - 3 = 'POWER5' - 4 = 'PPCG4' - 5 = 'PPCG5' - 6 = 'POWER6' - 7 = 'POWER7' - 8 = 'POWERe6500' - 9 = 'IBMz9' - 10 = 'IBMz10' - 11 = 'IBMz196' - 12 = 'x86x87' - 13 = 'x86SSE1' - 14 = 'x86SSE2' - 15 = 'x86SSE3' - 16 = 'P5' - 17 = 'P5MMX' - 18 = 'PPRO' - 19 = 'PII' - 20 = 'PIII' - 21 = 'PM' - 22 = 'CoreSolo' - 23 = 'CoreDuo' - 24 = 'Core2Solo' - 25 = 'Core2' - 26 = 'Corei1' - 27 = 'Corei2' - 28 = 'Corei3' - 29 = 'Atom' - 30 = 'P4' - 31 = 'P4E' - 32 = 'Efficeon' - 33 = 'K7' - 34 = 'HAMMER' - 35 = 'AMD64K10h' - 36 = 'AMDLLANO' - 37 = 'AMDDOZER' - 38 = 'AMDDRIVER' - 39 = 'UNKNOWNx86' - 40 = 'IA64Itan' - 41 = 'IA64Itan2' - 42 = 'USI' - 43 = 'USII' - 44 = 'USIII' - 45 = 'USIV' - 46 = 'UST1' - 47 = 'UST2' - 48 = 'UnknownUS' - 49 = 'MIPSR1xK' - 50 = 'MIPSICE9' - 51 = 'ARMv6' - 52 = 'ARMv7' - -Operating System enums (Config's enum OSTYPE): - 0 = 'UNKNOWN' - 1 = 'Linux' - 2 = 'SunOS' - 3 = 'SunOS4' - 4 = 'OSF1' - 5 = 'IRIX' - 6 = 'AIX' - 7 = 'Win9x' - 8 = 'WinNT' - 9 = 'Win64' - 10 = 'HPUX' - 11 = 'FreeBSD' - 12 = 'OSX' - -Compiler integer defines: - 0 = 'ICC' - 1 = 'SMC' - 2 = 'DMC' - 3 = 'SKC' - 4 = 'DKC' - 5 = 'XCC' - 6 = 'GCC' - 7 = 'F77' - - -ISA extensions are combined by adding their values together (bitvector): - none: 1 - VSX: 2 - AltiVec: 4 - AVXMAC: 8 - AVXFMA4: 16 - AVX: 32 - SSE3: 64 - SSE2: 128 - SSE1: 256 - 3DNow: 512 - NEON: 1024 - -""" - - -def check_enums(print_enums_output): - """ - Verify that the output of ATLAS print_enums matches our enums - - INPUT: - - - ``print_enums_output`` -- string. The output of the ATLAS - print_enums utility. - """ - lines = print_enums_output.splitlines() - found_MACHTYPE = found_OSTYPE = found_ISAEXT = False - while len(lines) > 0: - line = lines.pop(0) - if line.startswith('Architectural enums'): - check_enums_ATLAS_MACHTYPE(lines) - found_MACHTYPE = True - if line.startswith('Operating System enums'): - check_enums_ATLAS_OSTYPE(lines) - found_OSTYPE = True - if line.startswith('ISA extensions'): - check_enums_ATLAS_ISAEXT(lines) - found_ISAEXT = True - if not (found_MACHTYPE and found_OSTYPE and found_ISAEXT): - raise RuntimeError('failed to parse the output of print_enums') - - -def check_enums_ATLAS_MACHTYPE(lines): - for i, mach_type in enumerate(ATLAS_MACHTYPE): - got = lines.pop(0).strip() - expect = "{0} = '{1}'".format(i, mach_type) - if got != expect: - raise RuntimeError('ATLAS_MACHTYPE mismatch at position '+str(i)+ - ': got >>'+got+'<<, expected >>'+expect+'<<') - -def check_enums_ATLAS_OSTYPE(lines): - for i, os_type in enumerate(ATLAS_OSTYPE): - got = lines.pop(0).strip() - expect = "{0} = '{1}'".format(i, os_type) - if got != expect: - raise RuntimeError('ATLAS_OSTYPE mismatch at position '+str(i)+ - ': got >>'+got+'<<, expected >>'+expect+'<<') - -def check_enums_ATLAS_ISAEXT(lines): - for i, isaext in enumerate(ATLAS_ISAEXT): - got = lines.pop(0).strip() - if i == 0: - expect = 'none: 1' - else: - expect = "{0}: {1}".format(isaext, 1 << i) - if got != expect: - raise RuntimeError('ATLAS_ISAEXT mismatch at position '+str(i)+ - ': got >>'+got+'<<, expected >>'+expect+'<<') - - -def make_check_enums(): - """ - Build the print_enums utility and check its output against our - enums - - You can only call this function when you are in the atlas build - directory, and only after configuring atlas. - """ - from subprocess import check_output - output = check_output('make xprint_enums ; ./xprint_enums', shell=True) - print(output) - check_enums(output.decode('ascii')) - diff --git a/build/pkgs/atlas/package-version.txt b/build/pkgs/atlas/package-version.txt deleted file mode 100644 index d7150972a41..00000000000 --- a/build/pkgs/atlas/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -3.10.2.p3 diff --git a/build/pkgs/atlas/patches/ATLAS-lib/Makefile.am b/build/pkgs/atlas/patches/ATLAS-lib/Makefile.am deleted file mode 100644 index 46abdb9e6e4..00000000000 --- a/build/pkgs/atlas/patches/ATLAS-lib/Makefile.am +++ /dev/null @@ -1,118 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 - -# Upstream doesn't version libraries, so this is kind of arbitrary -SO_VERSION=3:0 - -# You shouldn't have to customize anything from here on - -ATLAS_SERIAL_LIBS=atlas cblas f77blas lapack - -ATLAS_PARALLEL_LIBS=ptcblas ptf77blas ptlapack - -all: all_parallel - -all_serial: $(ATLAS_SERIAL_LIBS) - -all_parallel: all_serial $(ATLAS_PARALLEL_LIBS) - -clean: - $(RM) -r -f .libs *.la *.dll *.dll.a *-obj - -install: install_parallel - -install_serial: $(ATLAS_SERIAL_LIBS) - $(MKDIR_P) @libdir@ - $(MKDIR_P) @bindir@ - for module in $(ATLAS_SERIAL_LIBS); do \ - @LTINSTALL@; \ - done; - @LIBTOOL@ --finish @libdir@ - @LIBTOOL@ --finish @bindir@ - -install_parallel: install_serial $(ATLAS_PARALLEL_LIBS) - $(MKDIR_P) @libdir@ - $(MKDIR_P) @bindir@ - for module in $(ATLAS_PARALLEL_LIBS); do \ - @LTINSTALL@; \ - done; - @LIBTOOL@ --finish @libdir@ - @LIBTOOL@ --finish @bindir@ - -# In presence of multiple definitions of thread related functions, use the ones from *_mut.o -# Works with all nm output formats (BSD/POSIX/System V) -atlas: libatlas.a - -$(RM) -r -f libatlas-obj - $(MKDIR) libatlas-obj - cd libatlas-obj && $(AR) x ../$< && cd .. - if [ `$(NM) -g $< | $(EGREP) -w 'ATL_(Set|Reset|Free|Dec)AtomicCount' | $(GREP) -w T | wc -l` -gt 4 ]; then \ - $(RM) `ls -1 libatlas-obj/ATL_{Set,Reset,Free,Dec}AtomicCount_*.o | $(GREP) -v '_mut.o$$'`; \ - fi - @LTCLINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libatlas-obj/*.o \ - @PTHREAD_LIB@ -lm \ - @LTLINKFLAGS@ - -cblas: libcblas.a @LTPREFIX@atlas@LTSUFFIX@ - -$(RM) -r -f libcblas-obj - $(MKDIR) libcblas-obj - cd libcblas-obj && $(AR) x ../$< && cd .. - @LTCLINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libcblas-obj/*.o \ - -latlas \ - @LTLINKFLAGS@ - -ptcblas: libptcblas.a @LTPREFIX@atlas@LTSUFFIX@ - -$(RM) -r -f libptcblas-obj - $(MKDIR) libptcblas-obj - cd libptcblas-obj && $(AR) x ../$< && cd .. - @LTCLINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libptcblas-obj/*.o \ - @PTHREAD_LIB@ -latlas \ - @LTLINKFLAGS@ - -f77blas: libf77blas.a @LTPREFIX@atlas@LTSUFFIX@ - -$(RM) -r -f libf77blas-obj - $(MKDIR) libf77blas-obj - cd libf77blas-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libf77blas-obj/*.o \ - -latlas \ - @LTLINKFLAGS@ - -ptf77blas: libptf77blas.a @LTPREFIX@atlas@LTSUFFIX@ - -$(RM) -r -f libptf77blas-obj - $(MKDIR) libptf77blas-obj - cd libptf77blas-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libptf77blas-obj/*.o \ - @PTHREAD_LIB@ -latlas \ - @LTLINKFLAGS@ - -f77refblas: libf77refblas.a - -$(RM) -r -f libf77refblas-obj - $(MKDIR) libf77refblas-obj - cd libf77refblas-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libf77refblas-obj/*.o \ - -latlas \ - @LTLINKFLAGS@ - -lapack: liblapack.a @LTPREFIX@atlas@LTSUFFIX@ @LTPREFIX@cblas@LTSUFFIX@ @LTPREFIX@f77blas@LTSUFFIX@ - -$(RM) -r -f liblapack-obj - $(MKDIR) liblapack-obj - cd liblapack-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ liblapack-obj/*.o \ - -lcblas -lf77blas -latlas -lm \ - @LTLINKFLAGS@ - -ptlapack: libptlapack.a @LTPREFIX@atlas@LTSUFFIX@ @LTPREFIX@ptcblas@LTSUFFIX@ @LTPREFIX@ptf77blas@LTSUFFIX@ - -$(RM) -r -f libptlapack-obj - $(MKDIR) libptlapack-obj - cd libptlapack-obj && $(AR) x ../$< && cd .. - @LTF77LINK@ \ - -o @LTPREFIX@$@@LTSUFFIX@ libptlapack-obj/*.o \ - @PTHREAD_LIB@ -lptcblas -lptf77blas -latlas -lm \ - @LTLINKFLAGS@ - -.PHONY: all all_serial all_parallel build install install_serial install_parallel clean $(ATLAS_SERIAL_LIBS) $(ATLAS_PARALLEL_LIBS) diff --git a/build/pkgs/atlas/patches/ATLAS-lib/README b/build/pkgs/atlas/patches/ATLAS-lib/README deleted file mode 100644 index 461f03e8ebb..00000000000 --- a/build/pkgs/atlas/patches/ATLAS-lib/README +++ /dev/null @@ -1,3 +0,0 @@ -This is a stub autotools project to generate the system-dependent -libtool script. Nothing is compiled here. The Makefile.am unpacks the -atlas static libraries and repacks them into shared libraries. diff --git a/build/pkgs/atlas/patches/ATLAS-lib/configure.ac b/build/pkgs/atlas/patches/ATLAS-lib/configure.ac deleted file mode 100644 index 0ce6a0f44b9..00000000000 --- a/build/pkgs/atlas/patches/ATLAS-lib/configure.ac +++ /dev/null @@ -1,51 +0,0 @@ -AC_INIT([ATLAS],[3.10.1]) -AM_INIT_AUTOMAKE(foreign) - -AC_CANONICAL_HOST - -LT_INIT - -AC_PROG_CC -AC_PROG_F77 - -AC_CONFIG_FILES([Makefile]) -AC_CONFIG_MACRO_DIR([m4]) - -AC_CHECK_LIB(pthread, pthread_create, [PTHREAD_LIB="-lpthread"]) -AC_SUBST(PTHREAD_LIB) - -AC_ARG_ENABLE([static], - [AS_HELP_STRING([--enable-static], - [also install static libtool library (default: no)])]) -AS_IF([test "x$enable_static" = "xyes"], - [libtool_type=""], - [libtool_type=-shared]) -AC_SUBST(LIBTOOL_TYPE, [$libtool_type]) - -case $host in - *-*-cygwin*) - LTPREFIX=cyg - LTSUFFIX=.dll - LTCLINK="\$(CC) -L. -shared" - LTF77LINK="\$(F77) -L. -shared" - LTLINKFLAGS="-Wl,--out-implib=lib\$@.dll.a -Wl,--export-all-symbols -Wl,--enable-auto-import" - LTINSTALL="\$(CP) \$(LTPREFIX)\$\${module}\$(LTSUFFIX) \$(bindir)/\$(LTPREFIX)\$\${module}\$(LTSUFFIX); \$(CP) lib\$\${module}.dll.a \$(libdir)/lib\$\${module}.dll.a" - ;; - *) - LTPREFIX=lib - LTSUFFIX=.la - LTCLINK="\$(LIBTOOL) --tag=CC --mode=link \$(CC) \$(LIBTOOL_FLAG)" - LTF77LINK="\$(LIBTOOL) --tag=F77 --mode=link \$(F77) \$(LIBTOOL_FLAG)" - LTLINKFLAGS="-rpath \$(libdir) -version-info \$(SO_VERSION)" - LTINSTALL="\$(LIBTOOL) --mode=install \$(INSTALL) -c \$(LTPREFIX)\$\${module}\$(LTSUFFIX) \$(libdir)/\$(LTPREFIX)\$\${module}\$(LTSUFFIX)" - ;; -esac - -AC_SUBST(LTPREFIX) -AC_SUBST(LTSUFFIX) -AC_SUBST(LTCLINK) -AC_SUBST(LTF77LINK) -AC_SUBST(LTLINKFLAGS) -AC_SUBST(LTINSTALL) - -AC_OUTPUT diff --git a/build/pkgs/atlas/patches/Makefile.patch b/build/pkgs/atlas/patches/Makefile.patch deleted file mode 100644 index 69662626b49..00000000000 --- a/build/pkgs/atlas/patches/Makefile.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- src/ATLAS/CONFIG/src/Makefile 2012-06-23 17:27:27.000000000 +0100 -+++ new/ATLAS/CONFIG/src/Makefile 2012-06-24 03:05:52.043151077 +0100 -@@ -580,6 +580,6 @@ - confclean: $(CLEANdep) - rm -f *core* *.o config?.out - clean : $(CLEANdep) -- rm -f *.o x* config?.out *core* -+ rm -rf *.o x* config?.out *core* - cleanall: clean - $(MAKE) -f Make.top clean diff --git a/build/pkgs/atlas/patches/arm_hard_floats.patch b/build/pkgs/atlas/patches/arm_hard_floats.patch deleted file mode 100644 index 64cadd1f404..00000000000 --- a/build/pkgs/atlas/patches/arm_hard_floats.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -druN ATLAS.detect/ATLAS/CONFIG/src/atlcomp.txt ATLAS/ATLAS/CONFIG/src/atlcomp.txt ---- ATLAS.detect/ATLAS/CONFIG/src/atlcomp.txt 2013-01-08 10:15:42.000000000 -0800 -+++ ATLAS/ATLAS/CONFIG/src/atlcomp.txt 2014-02-10 04:36:26.113011794 -0800 -@@ -255,13 +255,13 @@ - # ARM defaults - # - MACH=ARMv7 OS=ALL LVL=1000 COMPS=xcc -- 'gcc' '-mcpu=cortex-a8 -O1 -mfpu=vfpv3 -mfloat-abi=softfp ' -+ 'gcc' '-mcpu=cortex-a8 -O1 -mfpu=vfpv3 -mfloat-abi=hard ' - MACH=ARMv7 OS=ALL LVL=1000 COMPS=smc,skc,gcc,icc -- 'gcc' '-O1 -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=vfpv3 -mfloat-abi=softfp -fno-expensive-optimizations' -+ 'gcc' '-O1 -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=vfpv3 -mfloat-abi=hard -fno-expensive-optimizations' - MACH=ARMv7 OS=ALL LVL=1000 COMPS=dmc,dkc -- 'gcc' '-O1 -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=vfpv3 -mfloat-abi=softfp -fno-schedule-insns2' -+ 'gcc' '-O1 -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=vfpv3 -mfloat-abi=hard -fno-schedule-insns2' - MACH=ARMv7 OS=ALL LVL=1000 COMPS=f77 -- 'gfortran' '-mcpu=cortex-a8 -mfpu=vfpv3 -mfloat-abi=softfp -O' -+ 'gfortran' '-mcpu=cortex-a8 -mfpu=vfpv3 -mfloat-abi=hard -O' - # - # Generic defaults - # diff --git a/build/pkgs/atlas/patches/atlas-config b/build/pkgs/atlas/patches/atlas-config deleted file mode 100755 index 1f92bb43e62..00000000000 --- a/build/pkgs/atlas/patches/atlas-config +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env sage-bootstrap-python - -import sys, errno, os, platform, time, glob, subprocess, signal, argparse - -parser = argparse.ArgumentParser( - description='(Re-)Build ATLAS (http://math-atlas.sourceforge.net) ' - 'according to the SAGE_ATLAS_ARCH environment variable') - -parser.add_argument('--unthrottle', nargs=1, type=int, - help='switch CPU throttling off until PID finishes', - metavar='PID') - -parser.add_argument('--archdef', action='store_const', const=True, - help='build archdef tarball and save it to the current directory') - - -def pid_exists(pid): - """ - Check whether pid exists in the current process table. - """ - if pid < 0: - return False - try: - os.kill(pid, 0) - except OSError as e: - return e.errno == errno.EPERM - else: - return True - - -def unthrottle_posix(pid): - cpus = list(glob.glob('/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor')) - scaling_governor = [] - for cpu in cpus: - with open(cpu, 'r') as f: - scaling_governor.append(f.readline()) - for cpu in cpus: - with open(cpu, 'w') as f: - f.write('performance') - - def signal_handler(signum, frame): - print('Signal handler called with signal', signum) - for cpu, governor in zip(cpus, scaling_governor): - with open(cpu, 'w') as f: - f.write(governor) - print('Reverted throttling to the previous behaviour.') - sys.exit(0) - - signal.signal(signal.SIGPIPE, signal_handler) - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) - - try: - while pid_exists(pid): - time.sleep(1) - except KeyboardInterrupt: - pass - - signal_handler(None, None) - - -def unthrottle(pid): - if os.name == 'posix': - unthrottle_posix(pid) - else: - print('I don\'t know how to unthrottle your system (' + - platform.system() + ')') - sys.exit(3) - - - -def is_throttled_posix(): - cpus = list(glob.glob('/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor')) - for cpu in cpus: - with open(cpu, 'r') as f: - if f.readline().strip() != 'performance': - return True - return False - - -def is_throttled(): - if os.name == 'posix': - return is_throttled_posix() - else: - print('I don\'t know how to unthrottle your system (' + - platform.system() + ')') - sys.exit(3) - - -def check_root(): - if os.name == 'posix': - if os.getuid() == 0: - return - print('\nError: You need to be root to (un)throttle the CPU.\n') - sys.exit(1) - else: - print('I don\'t know how to probe administrator rights on your system ('+platform.system()+')') - sys.exit(3) - - -def check_nonroot(): - if os.name == 'posix': - if os.getuid() > 0: - return - print('\nError: You are crazy to run this as root, exiting.\n') - sys.exit(2) - else: - print('I don\'t know how to probe administrator rights on your system ('+platform.system()+')') - sys.exit(3) - - -command = None - -def wait_for_command(): - global command - if command is None: - return - else: - command.send_signal(signal.SIGTERM) - -import atexit -atexit.register(wait_for_command) - - -def unthrottle_self(): - if os.name == 'posix': - global command - print('Running sudo atlas-config --unthrottle to turn CPU throttling off.') - command = subprocess.Popen(['sudo', os.path.abspath( __file__ ), - '--unthrottle', str(os.getpid())]) - else: - print('I don\'t know how to unthrottle your system ('+platform.system()+')') - sys.exit(2) - - print('Waiting for CPU throttling to be turned off...') - while is_throttled(): - time.sleep(1) - - - -if __name__ == '__main__': - args = parser.parse_args() - - if args.unthrottle: - check_root() - unthrottle(args.unthrottle[0]) - - check_nonroot() - unthrottle_self() - print - if os.environ.get('SAGE_FAT_BINARY', 'no') == 'yes': - print('Building ATLAS with SAGE_FAT_BINARY (generic archdefs).') - elif 'SAGE_ATLAS_ARCH' in os.environ: - print('Building ATLAS with SAGE_ATLAS_ARCH =', os.environ['SAGE_ATLAS_ARCH']) - else: - print('Building ATLAS without specifying architecture.') - print('This may take many hours during which you should leave the computer otherwise') - print('idle to obtain accurate timings.') - if args.archdef: - os.environ['SAGE_ATLAS_SAVE_ARCHDEF'] = os.getcwd() - print('The resulting .tar.bz2 will be saved in ' + os.getcwd()) - print() - print('You have 5 seconds to interrupt...') - time.sleep(1) - print('You have 4 seconds to interrupt...') - time.sleep(1) - print('You have 3 seconds to interrupt...') - time.sleep(1) - print('You have 2 seconds to interrupt...') - time.sleep(1) - print('You have 1 second to interrupt...') - time.sleep(1) - - sys.stdout.flush() - sys.stderr.flush() - os.system('sage -f atlas') diff --git a/build/pkgs/atlas/patches/cygwin_threads.patch b/build/pkgs/atlas/patches/cygwin_threads.patch deleted file mode 100644 index e2db2ec236c..00000000000 --- a/build/pkgs/atlas/patches/cygwin_threads.patch +++ /dev/null @@ -1,30 +0,0 @@ -Let ATLAS use Cygwin thread functions on Cygwin64. -diff -druN ATLAS.orig/ATLAS/src/threads/ATL_thread_start.c ATLAS.new/ATLAS/src/threads/ATL_thread_start.c ---- ATLAS.orig/ATLAS/src/threads/ATL_thread_start.c 2014-07-10 09:22:06.000000000 -0700 -+++ ATLAS.new/ATLAS/src/threads/ATL_thread_start.c 2014-11-18 07:17:39.207997205 -0800 -@@ -14,14 +14,14 @@ - */ - { - #ifdef ATL_WINTHREADS -- #ifdef ATL_WIN32THREADS -+ #if defined(ATL_WIN32THREADS) || defined(__CYGWIN__) - DWORD thrID; - #else - unsigned thrID; - #endif - - #ifdef ATL_NOAFFINITY -- #ifdef ATL_WIN32THREADS -+ #if defined(ATL_WIN32THREADS) || defined(__CYGWIN__) - thr->thrH = CreateThread(NULL, 0, rout, arg, 0, &thrID); - #else - thr->thrH = (HANDLE)_beginthreadex(NULL, 0, rout, arg, 0, &thrID); -@@ -29,7 +29,7 @@ - ATL_assert(thr->thrH); - #else - thr->rank = proc; -- #ifdef ATL_WIN32THREADS -+ #if defined(ATL_WIN32THREADS) || defined(__CYGWIN__) - thr->thrH = CreateThread(NULL, 0, rout, arg, CREATE_SUSPENDED, &thrID); - #else - thr->thrH = (HANDLE)_beginthreadex(NULL, 0, rout, arg, diff --git a/build/pkgs/atlas/patches/detect.patch b/build/pkgs/atlas/patches/detect.patch deleted file mode 100644 index 7c997e387d2..00000000000 --- a/build/pkgs/atlas/patches/detect.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff -druN ATLAS.orig/ATLAS/CONFIG/include/atlconf.h ATLAS/ATLAS/CONFIG/include/atlconf.h ---- ATLAS.orig/ATLAS/CONFIG/include/atlconf.h 2013-01-08 10:15:42.000000000 -0800 -+++ ATLAS/ATLAS/CONFIG/include/atlconf.h 2014-02-10 04:31:19.992981182 -0800 -@@ -18,7 +18,7 @@ - enum ARCHFAM {AFOther=0, AFPPC, AFSPARC, AFALPHA, AFX86, AFIA64, AFMIPS, - AFARM, AFS390}; - --#define NMACH 52 -+#define NMACH 53 - static char *machnam[NMACH] = - {"UNKNOWN", "POWER3", "POWER4", "POWER5", "PPCG4", "PPCG5", - "POWER6", "POWER7", "POWERe6500", "IBMz9", "IBMz10", "IBMz196", -@@ -29,7 +29,7 @@ - "Efficeon", "K7", "HAMMER", "AMD64K10h", "AMDLLANO", "AMDDOZER","AMDDRIVER", - "UNKNOWNx86", "IA64Itan", "IA64Itan2", - "USI", "USII", "USIII", "USIV", "UST1", "UST2", "UnknownUS", -- "MIPSR1xK", "MIPSICE9", "ARMv7"}; -+ "MIPSR1xK", "MIPSICE9", "ARMv6", "ARMv7"}; - enum MACHTYPE {MACHOther, IbmPwr3, IbmPwr4, IbmPwr5, PPCG4, PPCG5, - IbmPwr6, IbmPwr7, Pwre6500, - IbmZ9, IbmZ10, IbmZ196, /* s390(x) in Linux */ -@@ -42,6 +42,7 @@ - SunUSI, SunUSII, SunUSIII, SunUSIV, SunUST1, SunUST2, SunUSX, - MIPSR1xK, /* includes R10K, R12K, R14K, R16K */ - MIPSICE9, /* SiCortex ICE9 -- like MIPS5K */ -+ ARMv6, /* includes Raspberry Pi */ - ARMv7 /* includes Cortex A8, A9 */ - }; - #define MachIsX86(mach_) \ -@@ -60,7 +61,7 @@ - #define MachIsPPC(mach_) \ - ( (mach_) >= PPCG4 && (mach_) <= PPCG5 ) - #define MachIsARM(mach_) \ -- ( (mach_) == ARMv7 ) -+ ( (mach_) >= ARMv6 && (mach_) <= ARMv7 ) - #define MachIsS390(mach_) \ - ( (mach_) >= IbmZ9 && (mach_) <= IbmZ196 ) - diff --git a/build/pkgs/atlas/patches/do_not_force_mutex.patch b/build/pkgs/atlas/patches/do_not_force_mutex.patch deleted file mode 100644 index bd09ae08c12..00000000000 --- a/build/pkgs/atlas/patches/do_not_force_mutex.patch +++ /dev/null @@ -1,18 +0,0 @@ -Always use assembly over mutex since the mutex version fails to build -a shared library. See #15045 for details. - -diff --git a/ATLAS/tune/threads/tune_count.c b/ATLAS/tune/threads/tune_count.c -index f09717f..4dc3fde 100644 ---- a/ATLAS/tune/threads/tune_count.c -+++ b/ATLAS/tune/threads/tune_count.c -@@ -241,8 +241,8 @@ int main(int nargs, char **args) - */ - if (tmut < tldec*1.02) - { -- printf("\nNO REAL ADVANTAGE TO ASSEMBLY, FORCING USE OF MUTEX\n"); -- ATL_assert(!system("make iForceUseMutex")); -+ printf("\nNO REAL ADVANTAGE TO ASSEMBLY OVER MUTEX\n"); -+ printf("\nASSEMBLY/MUTEX ratio is %.2f, but we'll stick with assembly anyway\n", tldec/tmut); - } - } - free(timearr); diff --git a/build/pkgs/atlas/patches/glibc_scanf_workaround.patch b/build/pkgs/atlas/patches/glibc_scanf_workaround.patch deleted file mode 100644 index dba90a94677..00000000000 --- a/build/pkgs/atlas/patches/glibc_scanf_workaround.patch +++ /dev/null @@ -1,29 +0,0 @@ -Bug in glibc-2.18: https://sourceware.org/bugzilla/show_bug.cgi?id=15917 - - ---- a/ATLAS/tune/sysinfo/masrch.c -+++ b/ATLAS/tune/sysinfo/masrch.c -@@ -1,6 +1,7 @@ - #include - #include - #include -+#include - - #ifndef NTIM - #define NTIM 3 -@@ -113,7 +114,14 @@ - j = 0; - for (i=0; i != NTIM; i++) - { -- assert( fscanf(fp, "%lf", &mflop[i]) ); -+ /* FIXME: This assumes one float per line immediately followed by \n. */ -+ char buf[100]; /* enough to read a double */ -+ char *end; -+ -+ assert(fgets(buf, sizeof buf, fp)); -+ errno = 0; -+ mflop[i] = strtod(buf, &end); -+ assert(errno == 0 && end != buf && *end == '\n'); - } - fclose(fp); - /* diff --git a/build/pkgs/atlas/spkg-check.in b/build/pkgs/atlas/spkg-check.in deleted file mode 100644 index 506f8f7ad89..00000000000 --- a/build/pkgs/atlas/spkg-check.in +++ /dev/null @@ -1,47 +0,0 @@ -###################################################################### -### Skip building ATLAS on specific systems -###################################################################### - -if [ "$UNAME" = "Darwin" -a -z "$SAGE_ATLAS_ARCH" ]; then - echo "System-wide accelerate framework is used on Darwin; skipping ATLAS test suite." - exit 0 -fi - -if [ ! -z "$SAGE_ATLAS_LIB" ]; then - echo "SAGE_ATLAS_LIB is set to \"$SAGE_ATLAS_LIB\"; skipping ATLAS test suite." - exit 0 -fi - - -###################################################################### -### check and collect timings -###################################################################### - -make_check() -{ - # make sure everything builds correctly - $MAKE check - if [ $? -ne 0 ]; then - echo >&2 "The ATLAS self-tests failed." - exit 1 - else - echo "The ATLAS self-tests successfully passed." - fi -} - - -make_time() -{ - # collect some timings - $MAKE time - if [ $? -ne 0 ]; then - echo >&2 "The ATLAS timing data failed to be collected." - exit 1 - else - echo "The ATLAS timing data was successfully collected." - fi -} - -cd src/ATLAS-build -make_check -make_time diff --git a/build/pkgs/atlas/spkg-configure.m4 b/build/pkgs/atlas/spkg-configure.m4 deleted file mode 100644 index cbaaa21af17..00000000000 --- a/build/pkgs/atlas/spkg-configure.m4 +++ /dev/null @@ -1,8 +0,0 @@ -SAGE_SPKG_CONFIGURE([atlas], [dnl use old test/installation procedure with env. variables - sage_spkg_install_atlas=yes - ], [ - AC_REQUIRE([SAGE_SPKG_CONFIGURE_OPENBLAS]) - AS_IF([test x"$with_blas" = xatlas], [ - sage_require_openblas=no - sage_require_atlas=yes]) -]) diff --git a/build/pkgs/atlas/spkg-install.in b/build/pkgs/atlas/spkg-install.in deleted file mode 100644 index 1a1fe5a9f78..00000000000 --- a/build/pkgs/atlas/spkg-install.in +++ /dev/null @@ -1 +0,0 @@ -exec sage-bootstrap-python spkg-install.py diff --git a/build/pkgs/atlas/spkg-install.py b/build/pkgs/atlas/spkg-install.py deleted file mode 100644 index f6dfb3e8a6c..00000000000 --- a/build/pkgs/atlas/spkg-install.py +++ /dev/null @@ -1,681 +0,0 @@ -###################################################################### -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -###################################################################### - -from __future__ import print_function - -###################################################################### -### Import stuff -###################################################################### - -import os, sys, shutil, time, glob -from configuration import conf, cp, ln, which, try_run, edit_in_place -from enums import ATLAS_OSTYPE, ATLAS_MACHTYPE, ATLAS_ISAEXT, make_check_enums - - -###################################################################### -### The following variables may need to be updated if you -### update ATLAS or LAPACK to a newer version -###################################################################### - -PATCH_DIR = os.path.join(conf['SPKG_DIR'], 'patches') - -# the current lapack source tarball -LAPACK_TARFILE = os.path.join(conf['SPKG_DIR'], 'src', 'lapack-3.5.0.tar') - -# temporary directory to build everything in -BUILD_DIR = os.path.join(conf['SPKG_DIR'], 'src', 'ATLAS-build') - -# the shared library autotools stub project -BUILD_LIB_DIR = os.path.join(conf['SPKG_DIR'], 'src', 'ATLAS-lib') - -# we need to disable parallel builds -os.environ['MAKE'] += ' -j1' -MAKE = os.environ['MAKE'] - -# SAGE_LOCAL -SAGE_LOCAL = os.environ['SAGE_LOCAL'] - -###################################################################### -### Some auxiliary functions to facilitate IO and error checking -###################################################################### - -# Run shell command "command", but flush stdout and stderr before doing -# this. Also echo commands which are executed. -def system_with_flush(command): - print('Running', command) - sys.stdout.flush() - sys.stderr.flush() - import subprocess - return subprocess.call(command, shell=True) - -def assert_success(rc, good=None, bad=None): - if rc == 0: - if good is not None: - print(good) - return - print('-'*60) - import traceback - traceback.print_stack(file=sys.stdout) - print('-'*60) - if bad is not None: - print('Error:', bad) - sys.exit(rc) - - -###################################################################### -### function to save ATLAS' configuration to .pc files -###################################################################### - -def write_pc_file(libs,target): - pkgconfigdir=os.path.join(SAGE_LOCAL, 'lib', 'pkgconfig') - if not os.path.isdir(pkgconfigdir): - os.makedirs(pkgconfigdir) - libflags='-l%s'%(' -l'.join(libs)) - pcfile ="""SAGE_LOCAL=%s -prefix=${SAGE_LOCAL} -libdir=${prefix}/lib -includedir=${prefix}/include -Name: %s -Version: 1.0 -Description: %s for sage, set up by the ATLAS spkg. -Libs: -L${libdir} %s -"""%(SAGE_LOCAL, target, target, libflags) - open(os.path.join(SAGE_LOCAL, 'lib/pkgconfig/%s.pc'%target), 'w').write(pcfile) - - -###################################################################### -### Skip building ATLAS on specific systems -###################################################################### - -if conf['Darwin?'] and 'SAGE_ATLAS_ARCH' not in os.environ: - print('Skipping build of ATLAS on OS X, using system library instead.') - print('You can try building your own ATLAS by setting SAGE_ATLAS_ARCH') - print('to something sensible although that is not officially supported.') - if conf['PPC?']: # OSX 10.4 PPC linker needs help to find the accelerate blas - veclib_dir = '/System/Library/Frameworks/Accelerate.framework/' + \ - 'Versions/A/Frameworks/vecLib.framework/Versions/A' - for lib in [ 'libBLAS.dylib', 'libLAPACK.dylib']: - ln(os.path.join(veclib_dir, lib), - os.path.join(conf['SAGE_LOCAL'], 'lib', lib)) - write_pc_file(['blas'], 'cblas') - write_pc_file(['blas'], 'blas') - write_pc_file(['lapack'], 'lapack') - sys.exit(0) - - -###################################################################### -### Use SAGE_ATLAS_LIB='directory' if provided -###################################################################### - -# On Cygwin, we used to require that the system-wide lapack packages were -# installed (this included the lapack-devel and lapack packages). -# These packages indeed include BLAS and LAPACK and are enough to build -# the rest of Sage, whereas building ATLAS was problematic. -# For the record, the corresponding files to symlink from the system-wide -# packages are: '/usr/lib/libblas.dll.a' and '/usr/lib/liblapack.dll.a'. - -if 'SAGE_ATLAS_LIB' in os.environ: - ATLAS_LIB = os.environ['SAGE_ATLAS_LIB'] - - prefix = 'lib' - - libraries_sets = [['lapack', 'cblas', 'f77blas', 'atlas'], ['lapack', 'blas']] - libraries_optional = ['ptcblas', 'ptf77blas'] - - def is_atlas_lib_path(path, libs): - if path is None: - return False - if not os.path.isdir(path): - return False - filenames = os.listdir(path) - for lib in libs: - if not any(fname.startswith(prefix+lib) for fname in filenames): - print('Cannot find '+prefix+lib+'.* in '+path) - break - else: - return True - return False - - paths = [ ATLAS_LIB, os.path.join(ATLAS_LIB, 'lib64'), os.path.join(ATLAS_LIB, 'lib') ] - ATLAS_LIB = None - libraries = [] - for libs in libraries_sets: - for path in paths: - if is_atlas_lib_path(path, libs): - ATLAS_LIB = path - libraries = libs - break - else: - continue - break - - if ATLAS_LIB is None: - print('Unable to find required libraries in the directory', ATLAS_LIB) - print('Set SAGE_ATLAS_LIB to the directory containing:') - print('- liblapack, libcblas, libf77blas and libatlas;') - print('- or liblapack and libblas;') - print('you wish to use existing ATLAS libraries.') - print('For more details, see:') - print('https://doc.sagemath.org/html/en/installation/source.html#environment-variables') - print('Unset SAGE_ATLAS_LIB to build ATLAS from source.') - print('Then type make.') - sys.exit(2) - - for fname in os.listdir(ATLAS_LIB): - if fname.startswith(prefix + 'f77blas'): - f77blas = os.path.join(ATLAS_LIB, fname) - break - else: - f77blas = None - if f77blas is not None: - symbol_table = try_run('readelf -s ' + f77blas) - else: - symbol_table = None - if symbol_table is not None: - sym_gfortran = 'gfortran' in symbol_table - sym_g95 = 'g95' in symbol_table - if sym_gfortran and conf['fortran'] != 'gfortran': - print("Symbols in lib77blas indicate it was built with gfortran.\n") - print("However, Sage is using a different fortran compiler.\n") - print("If you wish to use this blas library, make sure FC points\n") - print("to a fortran compiler compatible with this library.\n") - sys.exit(2) - if sym_g95 and conf['fortran'] != 'g95': - print("Symbols in lib77blas indicate it was built with g95 \n") - print("However, Sage is using a different fortran compiler.\n") - print("If you wish to use this blas library, make sure FC points\n") - print("to a fortran compiler compatible with this library.\n") - sys.exit(2) - - SAGE_LOCAL_LIB = os.path.join(conf['SAGE_LOCAL'], 'lib') - def symlinkOSlibrary(library_basename): - filenames = [ fname for fname in os.listdir(path) - if fname.startswith(library_basename) ] - for fname in filenames: - source = os.path.join(ATLAS_LIB, fname) - destination = os.path.join(SAGE_LOCAL_LIB, fname) - print('Symlinking '+destination+' -> '+source) - try: - os.remove(destination) - except OSError: - pass - try: - os.symlink(source, destination) - except OSError: - pass - for lib in libraries + libraries_optional: - symlinkOSlibrary(prefix+lib) - - if 'atlas' in libraries: - write_pc_file(['cblas', 'atlas'], 'cblas') - write_pc_file(['f77blas', 'atlas'], 'blas') - # The inclusion of cblas is not a mistake. ATLAS' lapack include - # a custom version of clapack which depends on cblas. - write_pc_file(['lapack', 'f77blas', 'cblas', 'atlas'], 'lapack') - else: - write_pc_file(['blas'], 'cblas') - write_pc_file(['blas'], 'blas') - write_pc_file(['lapack', 'blas'], 'lapack') - - - sys.exit(0) - -# Because blas, cblas and lapack libraries are properly linked -# with no unknown symbols, no extra libraries needs to be given. -write_pc_file(['cblas'], 'cblas') -write_pc_file(['f77blas'], 'blas') -write_pc_file(['lapack'], 'lapack') - -# add extra architectural defaults -cp('src/ARCHS/*.tar.bz2', 'src/ATLAS/CONFIG/ARCHS/') - -# hardcoded gcc in SpewMakeInc.c -edit_in_place('src/ATLAS/CONFIG/src/SpewMakeInc.c') \ - .replace(' goodgcc = .*', ' goodgcc = "' + os.environ['CC'] + '";') \ - .close() - - -# override throttling check if architecture is specified -edit_in_place('src/ATLAS/CONFIG/src/config.c') \ - .replace('if \(mach == MACHOther\)', 'if (mach != MACHOther) thrchk=0; else') \ - .close() - - - -###################################################################### -### configure functions -###################################################################### - -# For debug purposes one can install static libraries via SAGE_ATLAS_ARCH=static,... -INSTALL_STATIC_LIBRARIES = False - -def configure_options_from_environment(): - # Figure out architecture (see ATLAS_MACHTYPE) and isa extensions (see - # ATLAS_ISAEXT) from environment variables: - arch = None - isa_ext = None - thread_limit = None - if conf['generic_binary?']: - print('Sage "fat" binary mode set: Building "base" binary') - print('NOTE: This can result in a Sage that is significantly slower at certain numerical') - print('linear algebra since full FAT binary support has not been implemented yet.') - arch = 'generic' - if 'SAGE_ATLAS_ARCH' not in os.environ: - return (arch, isa_ext, thread_limit) - for opt in os.environ['SAGE_ATLAS_ARCH'].split(','): - if opt.startswith('thread'): - thread_limit = int(opt.split(':')[-1]) - elif opt == 'static': - global INSTALL_STATIC_LIBRARIES - INSTALL_STATIC_LIBRARIES = True - elif opt in ATLAS_MACHTYPE + ('fast', 'base'): - if arch is not None: - raise ValueError('multiple architectures specified: {0} and {1}'.format(arch, opt)) - arch = opt - elif opt in ATLAS_ISAEXT: - if isa_ext is None: - isa_ext = [opt] - else: - isa_ext.append(opt) - else: - print('unknown SAGE_ATLAS_ARCH option: '+opt) - print('SAGE_ATLAS_ARCH architecture must be "fast", "base", or one of '+ \ - ', '.join(ATLAS_MACHTYPE)) - print('SAGE_ATLAS_ARCH ISA extension must be one of '+ ', '.join(ATLAS_ISAEXT)) - sys.exit(1) - return (arch, isa_ext, thread_limit) - - -def configure(arch=None, isa_ext=None): - """ - Configure for ``arch``. - - INPUT: - - - ``arch`` -- ``None`` or one of ``ATLAS_MACHTYPE`` - - - ``isa_ext`` -- ``None`` or a sublist of ``ATLAS_ISAEXT`` - - OUTPUT: 0 if ``configure`` was successful, 1 if it failed. - """ - try: - if arch is None: - arch, isa_ext, thread_limit = configure_options_from_environment() - if arch == 'fast': - arch, isa_ext, thread_limit = configure_fast() - if arch == 'generic' or arch == 'base': - arch, isa_ext, thread_limit = configure_base() - except NotImplementedError: - return 1 - - print('Running configure with arch = '+str(arch)+ \ - ', isa extensions '+str(isa_ext), ' thread limit '+str(thread_limit)) - if os.path.isdir(BUILD_DIR): - os.chdir(conf['SPKG_DIR']) # Solaris/ZFS can't delete cwd - shutil.rmtree(BUILD_DIR) - os.mkdir(BUILD_DIR) - os.chdir(BUILD_DIR) - - # We need to provide full pathes to FC and CC to ATLAS configure script, - # so that it does not use 'find' and travel around the filesystem to find - # them. - # We first split the compiler executable names from potential options, e.g. - # as in 'gcc -m64', then use 'which' to locate them, and finally add the - # options back. - FC = os.environ['FC'] - FCsplit = FC.find(' ') - if FCsplit != -1: - FCbin, FCopt = FC[:FCsplit], FC[FCsplit:] - else: - FCbin, FCopt = FC, '' - - CC = os.environ['CC'] - CCsplit = CC.find(' ') - if CCsplit != -1: - CCbin, CCopt = CC[:CCsplit], CC[CCsplit:] - else: - CCbin, CCopt = CC, '' - - cmd = '../ATLAS/configure' - cmd += ' --prefix=' + conf['SAGE_LOCAL'] - cmd += ' --with-netlib-lapack-tarfile=' + LAPACK_TARFILE - cmd += ' --cc="' + CC + '"' - - ## -Si latune 1: enable lapack tuning - ## typically adds 3-4 hours of install time - cmd += ' -Si latune 0' - - # Set flags for all compilers so we can build dynamic libraries - ALLFLAGS = "-fPIC " + os.environ["LDFLAGS"] - cmd += ' -Fa alg "{}"'.format(ALLFLAGS) - - # set number of threads limit: 0 = off, -1 = unlimited - if thread_limit is not None: - cmd += ' -t ' + str(thread_limit) - - # set fortran compiler - cmd += ' -C if "' + which(FCbin) + FCopt + '"' - - # set C compiler - cmd += ' -C acg "' + which(CCbin) + CCopt + '"' - - # set bit width - cmd += ' -b ' + conf['bits'][0:2] - - # set OS type - try: - if conf['Darwin?']: - atlas_osnam = 'OSX' - elif conf['CYGWIN?']: -# Picking Win64 currently does not work on Cygwin though it might be a better -# choice in the future. -# Not that ATLAS does not seem to officialy support Cygwin64 anyway in 3.10.1. -# if conf['64bit?']: -# atlas_osnam = 'Win64' -# else: - atlas_osnam = 'WinNT' - else: - atlas_osnam = conf['system'] - atlas_system = ATLAS_OSTYPE.index(atlas_osnam) - cmd += ' -O '+str(atlas_system) - except ValueError: - pass - - # use hard floats on ARM - if conf['ARM?']: - cmd += ' -D c -DATL_ARM_HARDFP=1' - - # set machine architecture - if arch is not None: - cmd += ' -A '+str(ATLAS_MACHTYPE.index(arch)) - - # set cpu instruction set extensions - if isa_ext is not None: - isa_extension = sum(1 << ATLAS_ISAEXT.index(x) for x in isa_ext) - cmd += ' -V '+str(isa_extension) - - # Custom configure options - if conf['user']: - cmd += " " + conf['user'] - - rc = system_with_flush(cmd) - make_check_enums() - return rc - - -def configure_fast(): - isa_ext = ('None',) - thread_limit = None - if conf['Intel?'] and conf['64bit?']: - print('Fast configuration on Intel x86_64 compatible CPUs.') - arch = 'P4E' - if not conf['CYGWIN?']: # cannot use assembly on Cygwin64 - isa_ext = ('SSE3', 'SSE2', 'SSE1') - elif conf['Intel?'] and conf['32bit?']: - print('Fast configuration on Intel i386 compatible CPUs.') - arch = 'x86SSE2' - isa_ext = ('SSE2', 'SSE1') - elif conf['SPARC?']: - print('Fast configuration on SPARC.') - arch = 'USIV' - elif conf['PPC?']: - print('Fast configuration on PPC.') - arch = 'PPCG5' - isa_ext = ('AltiVec', ) - elif conf['IA64?']: - print('Fast configuration on Itanium.') - arch = 'IA64Itan2' - elif conf['ARM?']: - print('Fast configuration on ARM.') - arch='ARMv7' - else: - raise NotImplementedError('I don\'t know a "fast" configuration for your cpu.') - return (arch, isa_ext, thread_limit) - - -def configure_base(): - isa_ext = ('None',) - thread_limit = 0 # disable threading in "base" - if conf['Intel?'] and conf['64bit?']: - print('Generic configuration on Intel x86_64 compatible CPUs.') - arch = 'x86SSE2' - if not conf['CYGWIN?']: # cannot use assembly on Cygwin64 - isa_ext = ('SSE2', 'SSE1') - elif conf['Intel?'] and conf['32bit?']: - print('Generic configuration on Intel i386 compatible CPUs.') - arch = 'x86x87' - elif conf['SPARC?']: - print('Base configuration on SPARC.') - arch = 'USIII' - elif conf['PPC?']: - print('Base configuration on PPC.') - arch = 'PPCG4' - elif conf['IA64?']: - print('Base configuration on Itanium.') - arch = 'IA64Itan' - elif conf['ARM?']: - print('Base configuration on ARM.') - arch = 'ARMv6' - else: - raise NotImplementedError('I don\'t know a "base" configuration for your cpu.') - return (arch, isa_ext, thread_limit) - - -###################################################################### -### make function -###################################################################### - -def make_atlas(target=None): - os.chdir(BUILD_DIR) - if target is None: - return system_with_flush(MAKE) - else: - return system_with_flush(MAKE + ' ' + target) - - -def make_atlas_library(target=None): - os.chdir(os.path.join(BUILD_DIR, 'lib')) - cmd = (MAKE + ' ' + target) if target else MAKE - return system_with_flush(cmd) - - -###################################################################### -### make and save archdef function -###################################################################### - -def build_and_save_archdef(): - try: - ARCHDEF_SAVE_DIR = os.environ['SAGE_ATLAS_SAVE_ARCHDEF'] - except KeyError: - return - os.chdir(os.path.join(BUILD_DIR, 'ARCHS')) - rc = system_with_flush(MAKE + ' ArchNew') - assert_success(rc, bad='Making archdef failed.', - good='Finished building archdef.') - rc = system_with_flush(MAKE + ' tarfile') - assert_success(rc, bad='Making archdef tarfile failed.', - good='Finished building archdef tarfile.') - for tarfile in glob.glob('*.tar.bz2'): - cp(tarfile, ARCHDEF_SAVE_DIR) - - -###################################################################### -### static libraries functions -###################################################################### - -def build(arch=None, isa_ext=None): - """ - Configure/build with given architectural information. - - Return ``0`` if successfull. - """ - rc = configure(arch, isa_ext) - if rc: - print("Configure failed.") - return rc - print("Finished configuring ATLAS.") - return make_atlas() - -def build_tuning(): - """ - Configure/build by going through the full tuning process. - - Return ``0`` if successfull. - """ - rc = configure() - if rc!=0: - print('Configure failed, possibly because you have CPU throttling enabled.') - print('Skipping tuning attempts.') - return rc - print('First attempt: automatic tuning.') - rc = make_atlas() - if rc==0: - return rc - print('ATLAS failed to build, possibly because of throttling or a loaded system.') - print('Waiting 1 minute...') - sys.stdout.flush() - time.sleep(60) - print('Second attempt: Re-running make.') - return make_atlas() - - -###################################################################### -### shared library hack functions -###################################################################### - -def configure_shared_library(): - os.chdir(BUILD_LIB_DIR) - static_library_dir = os.path.join(BUILD_DIR, 'lib') - for static_lib in glob.glob(os.path.join(static_library_dir, 'lib*.a')): - shutil.copy(static_lib, BUILD_LIB_DIR) - cmd = './configure' - cmd += ' --prefix=' + conf['SAGE_LOCAL'] - cmd += ' --libdir=' + os.path.join(conf['SAGE_LOCAL'],'lib') - cmd += ' --disable-static' - return system_with_flush(cmd) - -def make_shared_library(target=None): - os.chdir(BUILD_LIB_DIR) - cmd = (MAKE + ' ' + target) if target else MAKE - return system_with_flush(cmd) - - -###################################################################### -### build atlas and lapack static libraries -###################################################################### - -# -# Workaround for specific platforms: Disable tuning and go straight to -# fast/base architectural defaults -# -skip_tuning = conf['IA64?'] # Itanium is dead and tuning is broken - - -rc = None -if 'SAGE_ATLAS_ARCH' in os.environ or conf['generic_binary?']: - print('Building using specific architecture.') - rc = build() -else: - print('Configuring ATLAS.') - if skip_tuning: - print('Skipping tuning attempts (skip_tuning = True).') - rc = 1 # Fake failed tuning attempts - else: - rc = build_tuning() - if rc!=0: - print('Third attempt: use "fast" options.') - rc = build(arch='fast') - if rc!=0: - print('Fourth attempt: use "base" options.') - rc = build(arch='base') - -assert_success(rc, bad='Failed to build ATLAS.', good='Finished building ATLAS core.') - -build_and_save_archdef() - - -###################################################################### -### build ATLAS shared libraries -###################################################################### - -rc = make_atlas_library('shared') -if rc!=0: - print('Failed to build shared library (using the ATLAS build system)') -else: - print('Installed ATLAS shared library (ATLAS build system)') - -rc = make_atlas_library('ptshared') -if rc!=0: - print('Failed to build threaded library (using the ATLAS build system)') -else: - print('Installed ATLAS multi-threaded shared library (ATLAS build system)') - - -###################################################################### -### configure and build atlas and lapack shared library hack -###################################################################### - -rc = configure_shared_library() -assert_success(rc, bad='Configuring shared ATLAS library failed (libtool).', - good='Finished configuring shared ATLAS library (libtool).') - -have_serial_libs = False -have_parallel_libs = False - -rc = make_shared_library() -if rc!=0: - print('Failed to build serial+parallel shared libraries, possibly because your') - print('system does not support both. Trying to build serial libraries only (libtool).') - rc = make_shared_library('all_serial') - if rc!=0: - print('Failed to build any shared library, installing static library as last resort (libtool).') - INSTALL_STATIC_LIBRARIES = True - else: - print('Finished building serial shared ATLAS library (libtool).') - have_serial_libs = True -else: - have_parallel_libs = True - - -###################################################################### -### install shared library hack -###################################################################### - -if have_parallel_libs: - rc = make_shared_library('install') - assert_success(rc, bad='Installing the parallel+serial shared ATLAS library failed (libtool).', - good='Finished installing parallel+serial shared ATLAS library (libtool).') - -if have_serial_libs: - rc = make_shared_library('install_serial') - assert_success(rc, bad='Installing the serial shared ATLAS library failed (libtool).', - good='Finished installing serial shared ATLAS library (libtool).') - - -###################################################################### -### install atlas and lapack headers and libraries -###################################################################### - -if not INSTALL_STATIC_LIBRARIES: - edit_in_place(os.path.join(BUILD_DIR, 'Make.top')) \ - .replace('.*/liblapack.a.*', '') \ - .replace('.*/libcblas.a.*', '') \ - .replace('.*/libf77blas.a.*', '') \ - .replace('.*/libptcblas.a.*', '') \ - .replace('.*/libptf77blas.a.*', '') \ - .replace('.*/libatlas.a.*', '') \ - .close() - -rc = make_atlas('install') -assert_success(rc, bad='Failed to install ATLAS headers', - good='Installed ATLAS headers') - - -###################################################################### -### install script to tune and build ATLAS -###################################################################### - -cp(os.path.join(PATCH_DIR, 'atlas-config'), - os.path.join(conf['SAGE_LOCAL'], 'bin')) diff --git a/build/pkgs/atlas/spkg-src b/build/pkgs/atlas/spkg-src deleted file mode 100755 index 2595f6a1d5a..00000000000 --- a/build/pkgs/atlas/spkg-src +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env bash - -if [ $# -ne 0 ]; then - UPSTREAM_SOURCE_DIRECTORY=$1 - echo "Using tarballs from $UPSTREAM_SOURCE_DIRECTORY instead of downloading" -fi - -SPKG_ROOT=`pwd` - -set -e -shopt -s extglob - -# Remove old sources and download new -rm -rf src -mkdir src -cd src - - -### ATLAS ### - -ATLAS=atlas3.10.1.tar.bz2 - -if [ -z "$UPSTREAM_SOURCE_DIRECTORY" ]; then - tar xjf <( curl -L "http://downloads.sourceforge.net/project/math-atlas/Stable/3.10.1/$ATLAS?r=&ts=1373163744&use_mirror=iweb" ) -else - tar xjf "$UPSTREAM_SOURCE_DIRECTORY/$ATLAS" -fi -if [ ! -d ATLAS ]; then - echo 'ATLAS directory not in atlas tarball, aborting' - exit 1 -fi - - -### Lapack ### - -LAPACK=lapack-3.4.2.tgz - -if [ -z "$UPSTREAM_SOURCE_DIRECTORY" ]; then - curl -O http://www.netlib.org/lapack/$LAPACK -else - cp "$UPSTREAM_SOURCE_DIRECTORY/$LAPACK" . -fi -gunzip $LAPACK - -### Our archdefs ### - -if [ -z "$SAGE_ATLAS_ARCHDEFS_DIR" ]; then - echo "SAGE_ATLAS_ARCHDEFS_DIR should point to a directory containing the archedef tarballs." - exit 1 -fi - -mkdir ARCHS -cp -p "$SAGE_ATLAS_ARCHDEFS_DIR"/*.tar.bz2 ARCHS/ - -### Our shared library hack ### - -cp -rp "$SPKG_ROOT"/patches/ATLAS-lib . -cd ATLAS-lib -mkdir m4 -autoreconf -fiv -rm -rf autom4te.cache - - -### Finished creating the src/ directory - -# Make everything writable -cd "$SPKG_ROOT" -chmod -R u+w src diff --git a/build/pkgs/cbc/distros/void.txt b/build/pkgs/cbc/distros/void.txt new file mode 100644 index 00000000000..1fbb928840a --- /dev/null +++ b/build/pkgs/cbc/distros/void.txt @@ -0,0 +1 @@ +CoinMP-devel diff --git a/build/pkgs/cbc/spkg-configure.m4 b/build/pkgs/cbc/spkg-configure.m4 index 999d4b7497b..56153c3b70b 100644 --- a/build/pkgs/cbc/spkg-configure.m4 +++ b/build/pkgs/cbc/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([cbc], [ - SAGE_SPKG_DEPCHECK([atlas openblas zlib bzip2], [ + SAGE_SPKG_DEPCHECK([openblas zlib bzip2], [ dnl checking with pkg-config PKG_CHECK_MODULES([CBC], [cbc >= 2.9.4], [], [sage_spkg_install_cbc=yes]) ]) diff --git a/build/pkgs/ccache/distros/void.txt b/build/pkgs/ccache/distros/void.txt new file mode 100644 index 00000000000..812b9efc0c5 --- /dev/null +++ b/build/pkgs/ccache/distros/void.txt @@ -0,0 +1 @@ +ccache diff --git a/build/pkgs/cmake/dependencies b/build/pkgs/cmake/dependencies index 8637994a7b7..2b79396e60e 100644 --- a/build/pkgs/cmake/dependencies +++ b/build/pkgs/cmake/dependencies @@ -1,4 +1,4 @@ -curl zlib bzip2 xz +curl zlib bzip2 liblzma ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 7e67ba41b21..95ba9591301 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=9b22a30a08e51ba00cd1d83434baaefd3185301e -md5=0ac843dd51c77c37da876beae77af4bf -cksum=1637280499 +sha1=9c45053634b6912dd4e4e68a483b5dbd483fc47d +md5=11496f4636f7c19bb4cfbaf6e57af698 +cksum=2205302326 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index f8d177cfe6e..42d10d82fec 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -0a4f2a302c23d9c821b7be2cd6a7429075b7da60 +32c0d4075fb515a073925ad1feefcc4fc349b47d diff --git a/build/pkgs/cvxopt/checksums.ini b/build/pkgs/cvxopt/checksums.ini index 68a7862becf..6c90f288444 100644 --- a/build/pkgs/cvxopt/checksums.ini +++ b/build/pkgs/cvxopt/checksums.ini @@ -1,5 +1,5 @@ tarball=cvxopt-VERSION.tar.gz -sha1=d44cec6d4ea8738de94dc7dc4888ddb25914a11e -md5=b35d010b57bdd4fd78458bc764d2b013 -cksum=1219983379 +sha1=18cd006e45f8b10c8724d835a30cf1210bd685b1 +md5=af758ea38fcdd5cc1c102df4d378ffc3 +cksum=876134541 upstream_url=https://pypi.io/packages/source/c/cvxopt/cvxopt-VERSION.tar.gz diff --git a/build/pkgs/cvxopt/package-version.txt b/build/pkgs/cvxopt/package-version.txt index 3c43790f5d8..c04c650a7ad 100644 --- a/build/pkgs/cvxopt/package-version.txt +++ b/build/pkgs/cvxopt/package-version.txt @@ -1 +1 @@ -1.2.6 +1.2.7 diff --git a/build/pkgs/ecl/distros/void.txt b/build/pkgs/ecl/distros/void.txt new file mode 100644 index 00000000000..100aa2efb32 --- /dev/null +++ b/build/pkgs/ecl/distros/void.txt @@ -0,0 +1 @@ +ecl diff --git a/build/pkgs/eclib/distros/void.txt b/build/pkgs/eclib/distros/void.txt new file mode 100644 index 00000000000..0f514d35416 --- /dev/null +++ b/build/pkgs/eclib/distros/void.txt @@ -0,0 +1 @@ +eclib-devel diff --git a/build/pkgs/fflas_ffpack/SPKG.rst b/build/pkgs/fflas_ffpack/SPKG.rst index 4c512511265..26c7e6385a1 100644 --- a/build/pkgs/fflas_ffpack/SPKG.rst +++ b/build/pkgs/fflas_ffpack/SPKG.rst @@ -30,7 +30,8 @@ Dependencies ------------ - Givaro -- ATLAS (non-OSX)/The Accelerate FrameWork (on OSX) +- a BLAS implementation such as openblas + Patches ------- diff --git a/build/pkgs/fflas_ffpack/spkg-configure.m4 b/build/pkgs/fflas_ffpack/spkg-configure.m4 index f85295a7767..2d3a46a1a3e 100644 --- a/build/pkgs/fflas_ffpack/spkg-configure.m4 +++ b/build/pkgs/fflas_ffpack/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([fflas_ffpack], [ # fflas-lapack uses whatever multi-precision library givaro uses, # either gmp or mpir. - SAGE_SPKG_DEPCHECK([atlas givaro gmp mpir openblas], [ + SAGE_SPKG_DEPCHECK([givaro gmp mpir openblas], [ # If our dependencies come from the system, then we can use # the system fflas-ffpack, too. Use pkg-config to find a # recentish version, if there is one. diff --git a/build/pkgs/flint/distros/void.txt b/build/pkgs/flint/distros/void.txt index 61c2ffe155a..43e808a1904 100644 --- a/build/pkgs/flint/distros/void.txt +++ b/build/pkgs/flint/distros/void.txt @@ -1 +1 @@ -flint +flintlib-devel diff --git a/build/pkgs/freetype/distros/void.txt b/build/pkgs/freetype/distros/void.txt index 377935546a3..9d250f11947 100644 --- a/build/pkgs/freetype/distros/void.txt +++ b/build/pkgs/freetype/distros/void.txt @@ -1,3 +1 @@ freetype-devel -harfbuzz -glib diff --git a/build/pkgs/gc/distros/void.txt b/build/pkgs/gc/distros/void.txt new file mode 100644 index 00000000000..7a1f48d3ffd --- /dev/null +++ b/build/pkgs/gc/distros/void.txt @@ -0,0 +1 @@ +gc-devel diff --git a/build/pkgs/gcc/distros/void.txt b/build/pkgs/gcc/distros/void.txt new file mode 100644 index 00000000000..90584dda5b9 --- /dev/null +++ b/build/pkgs/gcc/distros/void.txt @@ -0,0 +1 @@ +gcc diff --git a/build/pkgs/gf2x/distros/void.txt b/build/pkgs/gf2x/distros/void.txt new file mode 100644 index 00000000000..971035e4030 --- /dev/null +++ b/build/pkgs/gf2x/distros/void.txt @@ -0,0 +1 @@ +gf2x-devel diff --git a/build/pkgs/giac/distros/void.txt b/build/pkgs/giac/distros/void.txt index daf8fd8679a..e603965872c 100644 --- a/build/pkgs/giac/distros/void.txt +++ b/build/pkgs/giac/distros/void.txt @@ -1,2 +1 @@ giac-devel -libgiac diff --git a/build/pkgs/git/distros/void.txt b/build/pkgs/git/distros/void.txt new file mode 100644 index 00000000000..5664e303b5d --- /dev/null +++ b/build/pkgs/git/distros/void.txt @@ -0,0 +1 @@ +git diff --git a/build/pkgs/gp2c/distros/void.txt b/build/pkgs/gp2c/distros/void.txt new file mode 100644 index 00000000000..f4ab6d425f1 --- /dev/null +++ b/build/pkgs/gp2c/distros/void.txt @@ -0,0 +1 @@ +gp2c diff --git a/build/pkgs/graphviz/distros/void.txt b/build/pkgs/graphviz/distros/void.txt index f137846bc26..4d95609306f 100644 --- a/build/pkgs/graphviz/distros/void.txt +++ b/build/pkgs/graphviz/distros/void.txt @@ -1 +1 @@ -graphviz-devel +graphviz diff --git a/build/pkgs/gsl/spkg-configure.m4 b/build/pkgs/gsl/spkg-configure.m4 index 81c5e35e6a9..4581bb688c9 100644 --- a/build/pkgs/gsl/spkg-configure.m4 +++ b/build/pkgs/gsl/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([gsl], [ m4_pushdef([SAGE_GSL_MINVER],["2.4"]) - SAGE_SPKG_DEPCHECK([atlas openblas], [ + SAGE_SPKG_DEPCHECK([openblas], [ PKG_CHECK_MODULES([GSL], [gsl >= $SAGE_GSL_MINVER], [ PKG_CHECK_VAR([GSLPCDIR], [gsl], [pcfiledir], [ GSL_PC="$GSLPCDIR"/gsl.pc diff --git a/build/pkgs/igraph/spkg-configure.m4 b/build/pkgs/igraph/spkg-configure.m4 index a292b33d8a7..c6c180b342e 100644 --- a/build/pkgs/igraph/spkg-configure.m4 +++ b/build/pkgs/igraph/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([igraph], [ -SAGE_SPKG_DEPCHECK([glpk atlas openblas gmp mpir], [ +SAGE_SPKG_DEPCHECK([glpk openblas gmp mpir], [ dnl check for igraph with pkg-config PKG_CHECK_MODULES([IGRAPH], [igraph >= 0.8.3], [], [ sage_spkg_install_igraph=yes]) diff --git a/build/pkgs/iml/SPKG.rst b/build/pkgs/iml/SPKG.rst index 7228ae5d12d..ffb045c9113 100644 --- a/build/pkgs/iml/SPKG.rst +++ b/build/pkgs/iml/SPKG.rst @@ -30,7 +30,7 @@ Dependencies ------------ - GMP -- ATLAS +- a BLAS implementation such as openblas Special Update/Build Instructions diff --git a/build/pkgs/iml/distros/void.txt b/build/pkgs/iml/distros/void.txt deleted file mode 100644 index e1a62af8917..00000000000 --- a/build/pkgs/iml/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -imlib2-devel diff --git a/build/pkgs/ipykernel/dependencies b/build/pkgs/ipykernel/dependencies index 45d2d0c0eb9..eec7126f687 100644 --- a/build/pkgs/ipykernel/dependencies +++ b/build/pkgs/ipykernel/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) debugpy matplotlib_inline ipython jupyter_client scandir | $(PYTHON_TOOLCHAIN) +$(PYTHON) ipython_genutils importlib_metadata argcomplete debugpy matplotlib_inline ipython jupyter_client tornado appnope traitlets | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/isl/distros/void.txt b/build/pkgs/isl/distros/void.txt index 97c6659d351..d54c646d7a7 100644 --- a/build/pkgs/isl/distros/void.txt +++ b/build/pkgs/isl/distros/void.txt @@ -1 +1 @@ -isl15-devel +isl-devel diff --git a/build/pkgs/jmol/distros/void.txt b/build/pkgs/jmol/distros/void.txt new file mode 100644 index 00000000000..f07a1f4e035 --- /dev/null +++ b/build/pkgs/jmol/distros/void.txt @@ -0,0 +1 @@ +jmol diff --git a/build/pkgs/libatomic_ops/distros/void.txt b/build/pkgs/libatomic_ops/distros/void.txt new file mode 100644 index 00000000000..56dbd90c363 --- /dev/null +++ b/build/pkgs/libatomic_ops/distros/void.txt @@ -0,0 +1 @@ +libatomic_ops-devel diff --git a/build/pkgs/libgd/distros/void.txt b/build/pkgs/libgd/distros/void.txt new file mode 100644 index 00000000000..5d1b511668c --- /dev/null +++ b/build/pkgs/libgd/distros/void.txt @@ -0,0 +1 @@ +gd-devel diff --git a/build/pkgs/liblzma/SPKG.rst b/build/pkgs/liblzma/SPKG.rst new file mode 100644 index 00000000000..925da031898 --- /dev/null +++ b/build/pkgs/liblzma/SPKG.rst @@ -0,0 +1,23 @@ +liblzma: General-purpose data compression software +================================================== + +Description +----------- + +This packages represents liblzma, a part of XZ Utils, the free general-purpose +data compression software with a high compression ratio. + +License +------- + +Some parts public domain, other parts GNU LGPLv2.1, GNU GPLv2, or GNU +GPLv3. + + +Upstream Contact +---------------- + +http://tukaani.org/xz/ + +Dependencies +------------ diff --git a/build/pkgs/liblzma/dependencies b/build/pkgs/liblzma/dependencies new file mode 100644 index 00000000000..f111204fa1f --- /dev/null +++ b/build/pkgs/liblzma/dependencies @@ -0,0 +1,9 @@ +$(SAGE_LOCAL)/$(SPKG_INST_RELDIR)/xz-$(vers_xz) + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. + +Adding the above instead of "xz" makes sure that the dependency is not replaced +by ".dummy". In this way, liblzma delegates building to xz when +liblzma appears as a dependency. diff --git a/build/pkgs/liblzma/distros/conda.txt b/build/pkgs/liblzma/distros/conda.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/conda.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/cygwin.txt b/build/pkgs/liblzma/distros/cygwin.txt new file mode 100644 index 00000000000..c5fa156f8a0 --- /dev/null +++ b/build/pkgs/liblzma/distros/cygwin.txt @@ -0,0 +1,2 @@ +xz +liblzma-devel diff --git a/build/pkgs/liblzma/distros/debian.txt b/build/pkgs/liblzma/distros/debian.txt new file mode 100644 index 00000000000..5cc8e2ad176 --- /dev/null +++ b/build/pkgs/liblzma/distros/debian.txt @@ -0,0 +1,3 @@ +xz-utils +liblzma-dev +# pixz # provides pixz but not xz on debian buster diff --git a/build/pkgs/liblzma/distros/fedora.txt b/build/pkgs/liblzma/distros/fedora.txt new file mode 100644 index 00000000000..813a264efd5 --- /dev/null +++ b/build/pkgs/liblzma/distros/fedora.txt @@ -0,0 +1 @@ +xz xz-devel diff --git a/build/pkgs/liblzma/distros/homebrew.txt b/build/pkgs/liblzma/distros/homebrew.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/homebrew.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/macports.txt b/build/pkgs/liblzma/distros/macports.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/macports.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/opensuse.txt b/build/pkgs/liblzma/distros/opensuse.txt new file mode 100644 index 00000000000..f84d903df3e --- /dev/null +++ b/build/pkgs/liblzma/distros/opensuse.txt @@ -0,0 +1,2 @@ +xz +"pkgconfig(liblzma)" diff --git a/build/pkgs/liblzma/distros/repology.txt b/build/pkgs/liblzma/distros/repology.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/repology.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/slackware.txt b/build/pkgs/liblzma/distros/slackware.txt new file mode 100644 index 00000000000..d66e95ca507 --- /dev/null +++ b/build/pkgs/liblzma/distros/slackware.txt @@ -0,0 +1 @@ +xz diff --git a/build/pkgs/liblzma/distros/void.txt b/build/pkgs/liblzma/distros/void.txt new file mode 100644 index 00000000000..c5fa156f8a0 --- /dev/null +++ b/build/pkgs/liblzma/distros/void.txt @@ -0,0 +1,2 @@ +xz +liblzma-devel diff --git a/build/pkgs/liblzma/package-version.txt b/build/pkgs/liblzma/package-version.txt new file mode 120000 index 00000000000..814cca4c8bc --- /dev/null +++ b/build/pkgs/liblzma/package-version.txt @@ -0,0 +1 @@ +../xz/package-version.txt \ No newline at end of file diff --git a/build/pkgs/liblzma/spkg-configure.m4 b/build/pkgs/liblzma/spkg-configure.m4 new file mode 100644 index 00000000000..52caa060f0a --- /dev/null +++ b/build/pkgs/liblzma/spkg-configure.m4 @@ -0,0 +1,10 @@ +SAGE_SPKG_CONFIGURE([liblzma], [ + SAGE_SPKG_DEPCHECK([xz], [ + dnl The library is actually installed by the xz spkg. + AC_CHECK_LIB([lzma], [lzma_raw_decoder], [lzma_cv_liblzma=yes], [lzma_cv_liblzma=no]) + AC_CHECK_HEADER([lzma.h], [lzma_cv_lzma_h=yes], [lzma_cv_lzma_h=no]) + if test "$lzma_cv_liblzma" != "yes" -o "$lzma_cv_lzma_h" != "yes"; then + sage_spkg_install_liblzma=yes + fi + ]) +]) diff --git a/build/pkgs/liblzma/spkg-install b/build/pkgs/liblzma/spkg-install new file mode 100755 index 00000000000..3104094580f --- /dev/null +++ b/build/pkgs/liblzma/spkg-install @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +# Actual installation is done by the xz spkg +# via a tricky dependency in liblzma/dependencies. diff --git a/build/pkgs/scandir/type b/build/pkgs/liblzma/type similarity index 100% rename from build/pkgs/scandir/type rename to build/pkgs/liblzma/type diff --git a/build/pkgs/linbox/SPKG.rst b/build/pkgs/linbox/SPKG.rst index 1c2f0d2fbcc..be48c4dc8ca 100644 --- a/build/pkgs/linbox/SPKG.rst +++ b/build/pkgs/linbox/SPKG.rst @@ -40,9 +40,7 @@ Dependencies - M4RIE - Givaro - FFLAS/FFPACK -- ATLAS (non-OSX)/The Accelerate FrameWork (on OSX) -- ATLAS (non-MacOS X) / The Accelerate FrameWork (on MacOS X), or GSL's - CBLAS +- a BLAS implementation such as openblas Special Update/Build Instructions diff --git a/build/pkgs/llvm/distros/debian.txt b/build/pkgs/llvm/distros/debian.txt index d9c90515cfc..e671fa21003 100644 --- a/build/pkgs/llvm/distros/debian.txt +++ b/build/pkgs/llvm/distros/debian.txt @@ -1 +1 @@ -llvm-toolchain +clang diff --git a/build/pkgs/mathjax/distros/void.txt b/build/pkgs/mathjax/distros/void.txt new file mode 100644 index 00000000000..37aaaac759c --- /dev/null +++ b/build/pkgs/mathjax/distros/void.txt @@ -0,0 +1 @@ +mathjax diff --git a/build/pkgs/maxima/distros/void.txt b/build/pkgs/maxima/distros/void.txt new file mode 100644 index 00000000000..f5fe3fdc6cb --- /dev/null +++ b/build/pkgs/maxima/distros/void.txt @@ -0,0 +1 @@ +maxima diff --git a/build/pkgs/maxima/package-version.txt b/build/pkgs/maxima/package-version.txt index 5a053acd6b8..83476624dc0 100644 --- a/build/pkgs/maxima/package-version.txt +++ b/build/pkgs/maxima/package-version.txt @@ -1 +1 @@ -5.45.0 +5.45.0.p0 diff --git a/build/pkgs/maxima/patches/undoing_true_false_printing_patch.patch b/build/pkgs/maxima/patches/undoing_true_false_printing_patch.patch deleted file mode 100644 index 535134b01b6..00000000000 --- a/build/pkgs/maxima/patches/undoing_true_false_printing_patch.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/src/grind.lisp b/src/grind.lisp -index 4ae73a3..86b80e6 100644 ---- a/src/grind.lisp -+++ b/src/grind.lisp -@@ -295,12 +295,12 @@ - (msz nil l r) - (do ((nl) (w 0)) - ((null (cdr x)) -- (setq nl (cons (if (stringp (car x)) -+ (setq nl (cons (if (atom (car x)) - (msz (makestring (car x)) l r) - (msize (car x) l r lop rop)) - nl)) - (cons (+ w (caar nl)) (nreverse nl))) -- (setq nl (cons (if (stringp (car x)) -+ (setq nl (cons (if (atom (car x)) - (msz (makestring (car x)) l r) - (msize (car x) l r lop rop)) - nl) diff --git a/build/pkgs/mpc/distros/void.txt b/build/pkgs/mpc/distros/void.txt index ec2f198bdd3..279a55fdb8b 100644 --- a/build/pkgs/mpc/distros/void.txt +++ b/build/pkgs/mpc/distros/void.txt @@ -1,2 +1 @@ -mpc libmpc-devel diff --git a/build/pkgs/mpfr/distros/void.txt b/build/pkgs/mpfr/distros/void.txt index 5bcf2cdfb19..2654a0c9ea0 100644 --- a/build/pkgs/mpfr/distros/void.txt +++ b/build/pkgs/mpfr/distros/void.txt @@ -1 +1 @@ -mpfr +mpfr-devel diff --git a/build/pkgs/mpir/distros/void.txt b/build/pkgs/mpir/distros/void.txt new file mode 100644 index 00000000000..c490ad530ef --- /dev/null +++ b/build/pkgs/mpir/distros/void.txt @@ -0,0 +1 @@ +mpir-devel diff --git a/build/pkgs/ntl/distros/void.txt b/build/pkgs/ntl/distros/void.txt new file mode 100644 index 00000000000..978728a7592 --- /dev/null +++ b/build/pkgs/ntl/distros/void.txt @@ -0,0 +1 @@ +ntl-devel diff --git a/build/pkgs/openblas/spkg-configure.m4 b/build/pkgs/openblas/spkg-configure.m4 index 177bbb1d4ff..c81533ba71a 100644 --- a/build/pkgs/openblas/spkg-configure.m4 +++ b/build/pkgs/openblas/spkg-configure.m4 @@ -110,26 +110,5 @@ SAGE_SPKG_CONFIGURE([openblas], [ LIBS="$SAVE_LIBS" CFLAGS="$SAVE_CFLAGS" ]) - ], [ - dnl REQUIRED-CHECK - AS_IF([test "x$with_blas" = xopenblas], [ - sage_require_openblas=yes - sage_require_atlas=no]) - ], [ - dnl PRE - AC_MSG_CHECKING([BLAS library]) - AC_ARG_WITH([blas], - [AS_HELP_STRING([--with-blas=openblas], - [use OpenBLAS as BLAS library (default)])] - [AS_HELP_STRING([--with-blas=atlas], - [use ATLAS as BLAS library])],, - [with_blas=openblas] # default - ) - AS_CASE(["$with_blas"], - [openblas], [], - [atlas], [sage_spkg_install_openblas=no], - [AC_MSG_ERROR([allowed values for --with-blas are 'atlas' and 'openblas'])]) - AC_MSG_RESULT([$with_blas]) - AC_SUBST([SAGE_BLAS], [$with_blas]) - ] + ] ) diff --git a/build/pkgs/openssl/distros/void.txt b/build/pkgs/openssl/distros/void.txt index 1dbc44b98df..2192a62851a 100644 --- a/build/pkgs/openssl/distros/void.txt +++ b/build/pkgs/openssl/distros/void.txt @@ -1 +1 @@ -libressl-openssl +openssl-devel diff --git a/build/pkgs/openssl/spkg-configure.m4 b/build/pkgs/openssl/spkg-configure.m4 index 76158601461..650c046667b 100644 --- a/build/pkgs/openssl/spkg-configure.m4 +++ b/build/pkgs/openssl/spkg-configure.m4 @@ -1,11 +1,37 @@ SAGE_SPKG_CONFIGURE([openssl], [ - AX_CHECK_OPENSSL([], [ + AX_CHECK_OPENSSL([ + AC_MSG_CHECKING([whether OpenSSL >= 1.1.1, as required by PEP 644]) + AC_COMPILE_IFELSE( + dnl Trac #32580: Need OpenSSL >= 1.1.1 for PEP 644 + dnl From https://www.openssl.org/docs/man3.0/man3/OPENSSL_VERSION_NUMBER.html: + dnl If M is the number from OPENSSL_VERSION_MAJOR + dnl NN is the number from OPENSSL_VERSION_MINOR + dnl PP is the number from OPENSSL_VERSION_PATCH + dnl -> OPENSSL_VERSION_NUMBER is 0xMNN00PP0L + dnl From https://www.openssl.org/docs/man1.1.1/man3/OPENSSL_VERSION_NUMBER.html + dnl FF is "fix" + dnl S is "status" (f = release) + dnl -> OPENSSL_VERSION_NUMBER is 0xMNNFFPPSL + [AC_LANG_PROGRAM([[ + #include + #if OPENSSL_VERSION_NUMBER < 0x10101000L + # error OpenSSL >= 1.1.1 is required according to PEP 644 + #endif + ]], [])], [ + AC_MSG_RESULT([yes]) + sage_spkg_install_openssl=no + ], [ + AC_MSG_RESULT([no]) + sage_spkg_install_openssl=yes + ]) + ], [dnl No openssl found sage_spkg_install_openssl=yes - AC_MSG_WARN([Because your system does not have a suitable OpenSSL library, -Sage will install a prerelease version of OpenSSL from the 3.0 alpha series. -The OpenSSL Project Team indicates that this prerelease version has been provided -for testing ONLY. It should NOT be used for security critical purposes. -We strongly recommend to install OpenSSL using the system package manager and -to re-run configure.]) + ]) +], [dnl REQUIRED-CHECK + AC_REQUIRE([SAGE_SPKG_CONFIGURE_PYTHON3]) + dnl openssl is a dependency only of python3; so if we use system python3, + dnl we do not require it. (In particular, we do not need a specific version.) + AS_IF([test x$sage_spkg_install_python3 = xno], [ + sage_require_openssl=no ]) ]) diff --git a/build/pkgs/patch/distros/void.txt b/build/pkgs/patch/distros/void.txt new file mode 100644 index 00000000000..9eb7b90ed50 --- /dev/null +++ b/build/pkgs/patch/distros/void.txt @@ -0,0 +1 @@ +patch diff --git a/build/pkgs/pcre/distros/void.txt b/build/pkgs/pcre/distros/void.txt index cfc6bffc3eb..cac6a31d037 100644 --- a/build/pkgs/pcre/distros/void.txt +++ b/build/pkgs/pcre/distros/void.txt @@ -1,2 +1 @@ pcre-devel -pcre2-devel diff --git a/build/pkgs/pkgconf/distros/void.txt b/build/pkgs/pkgconf/distros/void.txt new file mode 100644 index 00000000000..05a1a221b7d --- /dev/null +++ b/build/pkgs/pkgconf/distros/void.txt @@ -0,0 +1 @@ +pkgconf diff --git a/build/pkgs/pybind11/package-version.txt b/build/pkgs/pybind11/package-version.txt index 860487ca19c..da323e3f838 100644 --- a/build/pkgs/pybind11/package-version.txt +++ b/build/pkgs/pybind11/package-version.txt @@ -1 +1 @@ -2.7.1 +2.7.1.p0 diff --git a/build/pkgs/pybind11/patches/3270.patch b/build/pkgs/pybind11/patches/3270.patch new file mode 100644 index 00000000000..e434eda6834 --- /dev/null +++ b/build/pkgs/pybind11/patches/3270.patch @@ -0,0 +1,25 @@ +From 8920453affdcaad3e4a3a02d39181f5b5bf67fb7 Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Tue, 14 Sep 2021 21:57:58 -0700 +Subject: [PATCH] include/pybind11/numpy.h: gcc 4.8.4 does not have + is_trivially_copyable + +Manually edited -- the sdist has a layout different from the git repo. + +--- + include/pybind11/numpy.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h +index 7313897fe1..34b7536d38 100644 +--- a/pybind11/include/pybind11/numpy.h ++++ b/pybind11/include/pybind11/numpy.h +@@ -319,7 +319,7 @@ template using remove_all_extents_t = typename array_info::type; + + template using is_pod_struct = all_of< + std::is_standard_layout, // since we're accessing directly in memory we need a standard layout type +-#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803) ++#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150426 || __GLIBCXX__ == 20150623 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803) + // libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after 5) + // don't implement is_trivially_copyable, so approximate it + std::is_trivially_destructible, diff --git a/build/pkgs/pyopenssl/SPKG.rst b/build/pkgs/pyopenssl/SPKG.rst deleted file mode 100644 index 8eeedaee32d..00000000000 --- a/build/pkgs/pyopenssl/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -pyopenssl: Python wrapper module around the OpenSSL library -=========================================================== - -Description ------------ - -Python wrapper module around the OpenSSL library - -License -------- - -Apache License, Version 2.0 - -Upstream Contact ----------------- - -https://pypi.org/project/pyOpenSSL/ - diff --git a/build/pkgs/pyopenssl/distros/conda.txt b/build/pkgs/pyopenssl/distros/conda.txt deleted file mode 100644 index f0bff404425..00000000000 --- a/build/pkgs/pyopenssl/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -pyopenssl diff --git a/build/pkgs/pyopenssl/distros/macports.txt b/build/pkgs/pyopenssl/distros/macports.txt deleted file mode 100644 index eb73f41bc31..00000000000 --- a/build/pkgs/pyopenssl/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-openssl diff --git a/build/pkgs/pyopenssl/distros/opensuse.txt b/build/pkgs/pyopenssl/distros/opensuse.txt deleted file mode 100644 index 353babfd9aa..00000000000 --- a/build/pkgs/pyopenssl/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -python3-pyOpenSSL diff --git a/build/pkgs/pyopenssl/distros/repology.txt b/build/pkgs/pyopenssl/distros/repology.txt deleted file mode 100644 index b3288b190ea..00000000000 --- a/build/pkgs/pyopenssl/distros/repology.txt +++ /dev/null @@ -1,2 +0,0 @@ -pyopenssl -python:pyopenssl diff --git a/build/pkgs/pyopenssl/requirements.txt b/build/pkgs/pyopenssl/requirements.txt deleted file mode 100755 index 74e8b70d952..00000000000 --- a/build/pkgs/pyopenssl/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -service_identity -pyopenssl diff --git a/build/pkgs/pyopenssl/type b/build/pkgs/pyopenssl/type deleted file mode 100644 index 134d9bc32d5..00000000000 --- a/build/pkgs/pyopenssl/type +++ /dev/null @@ -1 +0,0 @@ -optional diff --git a/build/pkgs/python3/dependencies b/build/pkgs/python3/dependencies index 4dd1e381802..0b9e91a711c 100644 --- a/build/pkgs/python3/dependencies +++ b/build/pkgs/python3/dependencies @@ -1,4 +1,4 @@ -zlib readline sqlite libpng bzip2 xz libffi openssl +zlib readline sqlite libpng bzip2 liblzma xz libffi openssl ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/python3/distros/void.txt b/build/pkgs/python3/distros/void.txt index 0a1b2134e3e..07358a92e89 100644 --- a/build/pkgs/python3/distros/void.txt +++ b/build/pkgs/python3/distros/void.txt @@ -1,2 +1 @@ -python3 python3-devel diff --git a/build/pkgs/python3/spkg-build.in b/build/pkgs/python3/spkg-build.in index 9e1ae082dab..c8c02917cbc 100644 --- a/build/pkgs/python3/spkg-build.in +++ b/build/pkgs/python3/spkg-build.in @@ -2,6 +2,7 @@ # the Python installer. unset PYTHONHOME unset PYTHONPATH +unset SETUPTOOLS_USE_DISTUTILS # Prevent use of the system hg and svn as it might make the installation fail export HAS_HG=no diff --git a/build/pkgs/python3/spkg-configure.m4 b/build/pkgs/python3/spkg-configure.m4 index e1bbb6c27eb..9cb396d0c81 100644 --- a/build/pkgs/python3/spkg-configure.m4 +++ b/build/pkgs/python3/spkg-configure.m4 @@ -19,7 +19,7 @@ SAGE_SPKG_CONFIGURE([python3], [ dnl dnl However, if we add another package (providing a shared library linked into a Python module) dnl that also uses libsqlite3, then we will have to put the DEPCHECK back in. - SAGE_SPKG_DEPCHECK([bzip2 xz libffi], [ + SAGE_SPKG_DEPCHECK([bzip2 liblzma libffi], [ dnl Check if we can do venv with a system python3 dnl instead of building our own copy. dnl Trac #31160: We no longer check for readline here. diff --git a/build/pkgs/qhull/SPKG.rst b/build/pkgs/qhull/SPKG.rst index 285c1ef1a1b..069a6808b21 100644 --- a/build/pkgs/qhull/SPKG.rst +++ b/build/pkgs/qhull/SPKG.rst @@ -33,6 +33,8 @@ http://pythonhosted.org/pyhull/). Upstream Contact ---------------- +http://www.qhull.org/html + C. Bradford Barber bradb@shore.net or qhull@qhull.org Dependencies diff --git a/build/pkgs/qhull/checksums.ini b/build/pkgs/qhull/checksums.ini index e8d02d0cf6e..65635055fa6 100644 --- a/build/pkgs/qhull/checksums.ini +++ b/build/pkgs/qhull/checksums.ini @@ -1,4 +1,5 @@ tarball=qhull-VERSION.tgz -sha1=8188765b9f9f004e38e9906fd2a68e81119f05fb -md5=e6270733a826a6a7c32b796e005ec3dc -cksum=2560098443 +sha1=2dbc240919560ac008a92363984754a70677b353 +md5=295f7332269a38279478f555cc185296 +cksum=3092762704 +upstream_url=http://www.qhull.org/download/qhull-VERSION.tgz diff --git a/build/pkgs/qhull/distros/arch.txt b/build/pkgs/qhull/distros/arch.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/arch.txt @@ -0,0 +1 @@ +qhull diff --git a/build/pkgs/qhull/distros/cygwin.txt b/build/pkgs/qhull/distros/cygwin.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/cygwin.txt @@ -0,0 +1 @@ +qhull diff --git a/build/pkgs/qhull/distros/debian.txt b/build/pkgs/qhull/distros/debian.txt new file mode 100644 index 00000000000..c4e91af6528 --- /dev/null +++ b/build/pkgs/qhull/distros/debian.txt @@ -0,0 +1 @@ +libqhull-dev diff --git a/build/pkgs/qhull/distros/fedora.txt b/build/pkgs/qhull/distros/fedora.txt new file mode 100644 index 00000000000..f9702ea0653 --- /dev/null +++ b/build/pkgs/qhull/distros/fedora.txt @@ -0,0 +1,2 @@ +qhull +qhull-devel diff --git a/build/pkgs/qhull/distros/freebsd.txt b/build/pkgs/qhull/distros/freebsd.txt new file mode 100644 index 00000000000..1f24ee3c6e7 --- /dev/null +++ b/build/pkgs/qhull/distros/freebsd.txt @@ -0,0 +1 @@ +math/qhull diff --git a/build/pkgs/qhull/distros/gentoo.txt b/build/pkgs/qhull/distros/gentoo.txt new file mode 100644 index 00000000000..a7c7a4e1261 --- /dev/null +++ b/build/pkgs/qhull/distros/gentoo.txt @@ -0,0 +1 @@ +media-libs/qhull diff --git a/build/pkgs/qhull/distros/nix.txt b/build/pkgs/qhull/distros/nix.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/nix.txt @@ -0,0 +1 @@ +qhull diff --git a/build/pkgs/qhull/distros/void.txt b/build/pkgs/qhull/distros/void.txt new file mode 100644 index 00000000000..95d316779cf --- /dev/null +++ b/build/pkgs/qhull/distros/void.txt @@ -0,0 +1 @@ +qhull diff --git a/build/pkgs/qhull/package-version.txt b/build/pkgs/qhull/package-version.txt index f3d5a78f033..26328103545 100644 --- a/build/pkgs/qhull/package-version.txt +++ b/build/pkgs/qhull/package-version.txt @@ -1 +1 @@ -2015-src-7.2.0.p1 +2020-src-8.0.2 diff --git a/build/pkgs/qhull/patches/Makefile.patch b/build/pkgs/qhull/patches/Makefile.patch deleted file mode 100644 index c4255d319c9..00000000000 --- a/build/pkgs/qhull/patches/Makefile.patch +++ /dev/null @@ -1,40 +0,0 @@ -* fix dependencies between target (otherwise compilation fails with "make -j3") - ---- a/Makefile -+++ b/Makefile -@@ -200,7 +200,7 @@ cleanall: clean - doc: - $(PRINTMAN) $(TXTFILES) $(DOCFILES) - --install: -+install: bin/qconvex bin/qdelaunay bin/qhalf bin/qhull bin/qvoronoi bin/rbox - mkdir -p $(BINDIR) - mkdir -p $(DOCDIR) - mkdir -p $(INCDIR)/libqhull -@@ -240,7 +240,7 @@ printc: - printf: - $(PRINTC) $(FILES) - --qtest: -+qtest: bin/testqset bin/rbox - @echo ============================================ - @echo == make qtest ============================== - @echo ============================================ -@@ -262,7 +262,7 @@ qtest: - @echo ============================================ - -bin/rbox D4 | bin/qhull Tv - --test: qtest -+test: qtest bin/qconvex bin/qdelaunay bin/qhalf bin/qhull bin/qvoronoi bin/rbox - @echo ============================================ - @echo == make test =============================== - @echo ============================================ -@@ -319,7 +319,7 @@ testall: test - -eg/q_egtest - -eg/q_test - --qconvex-prompt: -+qconvex-prompt: bin/qconvex bin/rbox - bin/qconvex - @echo - @echo ============================================ diff --git a/build/pkgs/qhull/spkg-configure.m4 b/build/pkgs/qhull/spkg-configure.m4 new file mode 100644 index 00000000000..6eaf6461ec8 --- /dev/null +++ b/build/pkgs/qhull/spkg-configure.m4 @@ -0,0 +1,26 @@ +SAGE_SPKG_CONFIGURE([qhull], [ + m4_pushdef([SAGE_QHULL_MINVER],["8.0.2"]) + AC_PATH_PROG([QHULL], [qhull]) + AS_IF([test x$QHULL = x], [ + AC_MSG_NOTICE([qhull not found. Installing qhull]) + sage_spkg_install_qhull=yes + ], [ + AC_MSG_CHECKING([is qhull's version good enough? ]) + qhull_ver=`$QHULL -V | cut -d' ' -f2 2>> config.log` + AX_COMPARE_VERSION([$qhull_ver], [ge], [$SAGE_QHULL_MINVER], [ + AC_MSG_RESULT([yes.]) + AC_MSG_CHECKING([is qhull_r library and headers installed? ]) + AC_CHECK_HEADER([libqhull_r/libqhull_r.h], [ + AC_SEARCH_LIBS([qh_distplane], [qhull_r], [ + AC_MSG_RESULT([yes. Use system's qhull]) + ], [ + AC_MSG_RESULT([no. Install qhull]) + sage_spkg_install_qhull=yes]) dnl SEARCH_LIBS + ], [ + AC_MSG_RESULT([no. Install qhull]) + sage_spkg_install_qhull=yes + ]) dnl CHECK_HEADER + ]) dnl COMPARE_VERSION + ]) dnl IF + m4_popdef([SAGE_QHULL_MINVER]) +]) diff --git a/build/pkgs/r/dependencies b/build/pkgs/r/dependencies index ceb34c5e8c2..281dc007225 100644 --- a/build/pkgs/r/dependencies +++ b/build/pkgs/r/dependencies @@ -1,4 +1,4 @@ -$(BLAS) gfortran iconv readline bzip2 xz pcre curl | pkgconf +$(BLAS) gfortran iconv readline bzip2 liblzma pcre curl | pkgconf ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/r/spkg-configure.m4 b/build/pkgs/r/spkg-configure.m4 index e88f3393a91..dafa9113ece 100644 --- a/build/pkgs/r/spkg-configure.m4 +++ b/build/pkgs/r/spkg-configure.m4 @@ -1,12 +1,12 @@ SAGE_SPKG_CONFIGURE([r], [ m4_pushdef([SAGE_R_MINVER],["3.4.4"]) - SAGE_SPKG_DEPCHECK([atlas openblas iconv readline bzip2 xz pcre curl], [ + SAGE_SPKG_DEPCHECK([openblas iconv readline bzip2 liblzma pcre curl], [ AS_CASE([$host], [*-*-cygwin*], [ dnl #29486: rpy2 2.8.x does not build against system R on cygwin. sage_spkg_install_r=yes ], [ - PKG_CHECK_MODULES([R], [libR >= $SAGE_R_MINVER], [ + PKG_CHECK_MODULES([R], [libR >= SAGE_R_MINVER], [ AC_PATH_PROG([R], [R]) AS_IF([test "x$R" = x], [ AC_MSG_NOTICE([R is not found]) diff --git a/build/pkgs/rw/distros/void.txt b/build/pkgs/rw/distros/void.txt deleted file mode 100644 index 16feab0960b..00000000000 --- a/build/pkgs/rw/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -rw diff --git a/build/pkgs/sagelib/package-version.txt b/build/pkgs/sagelib/package-version.txt index bc12a7eeb60..173833eaf87 100644 --- a/build/pkgs/sagelib/package-version.txt +++ b/build/pkgs/sagelib/package-version.txt @@ -1 +1 @@ -9.5.beta2 +9.5.beta3 diff --git a/build/pkgs/scandir/SPKG.rst b/build/pkgs/scandir/SPKG.rst deleted file mode 100644 index df729b9205a..00000000000 --- a/build/pkgs/scandir/SPKG.rst +++ /dev/null @@ -1,18 +0,0 @@ -scandir: Fast file system iteration for Python -============================================== - -Description ------------ - -scandir, a better directory iterator and faster os.walk() - -License -------- - -New BSD License - -Upstream Contact ----------------- - -https://pypi.org/project/scandir/ - diff --git a/build/pkgs/scandir/checksums.ini b/build/pkgs/scandir/checksums.ini deleted file mode 100644 index e1e2591b621..00000000000 --- a/build/pkgs/scandir/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=scandir-VERSION.tar.gz -sha1=460c739b514872233c573dded3490718348ec820 -md5=f8378f4d9f95a6a78e97ab01aa900c1d -cksum=855102986 -upstream_url=https://pypi.io/packages/source/s/scandir/scandir-VERSION.tar.gz diff --git a/build/pkgs/scandir/distros/conda.txt b/build/pkgs/scandir/distros/conda.txt deleted file mode 100644 index f649108ecda..00000000000 --- a/build/pkgs/scandir/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -scandir diff --git a/build/pkgs/scandir/distros/macports.txt b/build/pkgs/scandir/distros/macports.txt deleted file mode 100644 index 9cd1875e243..00000000000 --- a/build/pkgs/scandir/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -py-scandir diff --git a/build/pkgs/scandir/distros/opensuse.txt b/build/pkgs/scandir/distros/opensuse.txt deleted file mode 100644 index d05b4d1319d..00000000000 --- a/build/pkgs/scandir/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -python3-scandir diff --git a/build/pkgs/scandir/distros/repology.txt b/build/pkgs/scandir/distros/repology.txt deleted file mode 100644 index e098979afc8..00000000000 --- a/build/pkgs/scandir/distros/repology.txt +++ /dev/null @@ -1 +0,0 @@ -python:scandir diff --git a/build/pkgs/scandir/install-requires.txt b/build/pkgs/scandir/install-requires.txt deleted file mode 100644 index 75f24d3b10a..00000000000 --- a/build/pkgs/scandir/install-requires.txt +++ /dev/null @@ -1 +0,0 @@ -scandir >=1.9.0 diff --git a/build/pkgs/scandir/package-version.txt b/build/pkgs/scandir/package-version.txt deleted file mode 100644 index 81c871de46b..00000000000 --- a/build/pkgs/scandir/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.10.0 diff --git a/build/pkgs/scandir/spkg-install.in b/build/pkgs/scandir/spkg-install.in deleted file mode 100644 index deba1bb42bb..00000000000 --- a/build/pkgs/scandir/spkg-install.in +++ /dev/null @@ -1 +0,0 @@ -cd src && sdh_pip_install . diff --git a/build/pkgs/sirocco/checksums.ini b/build/pkgs/sirocco/checksums.ini index 672a9235128..2f0181ec823 100644 --- a/build/pkgs/sirocco/checksums.ini +++ b/build/pkgs/sirocco/checksums.ini @@ -1,5 +1,5 @@ tarball=libsirocco-VERSION.tar.gz -sha1=96e16ce48d6d320895b8d1ee8e07b738765f5e8d -md5=44c67dccf82fe3e2c61b5b7a51543718 -cksum=596947378 +sha1=23311c0944f0c128b493589c1575476cf88177b6 +md5=e86b1dc9b72aee0d80186be7f49c295e +cksum=784051898 upstream_url=https://github.com/miguelmarco/SIROCCO2/releases/download/VERSION/libsirocco-VERSION.tar.gz diff --git a/build/pkgs/sirocco/package-version.txt b/build/pkgs/sirocco/package-version.txt index e9307ca5751..7ec1d6db408 100644 --- a/build/pkgs/sirocco/package-version.txt +++ b/build/pkgs/sirocco/package-version.txt @@ -1 +1 @@ -2.0.2 +2.1.0 diff --git a/build/pkgs/xz/checksums.ini b/build/pkgs/xz/checksums.ini index b344faf8359..6fa58c3a084 100644 --- a/build/pkgs/xz/checksums.ini +++ b/build/pkgs/xz/checksums.ini @@ -1,4 +1,5 @@ tarball=xz-VERSION.tar.gz -sha1=14663612422ab61386673be78fbb2556f50a1f08 -md5=7cf6a8544a7dae8e8106fdf7addfa28c -cksum=2298486723 +sha1=fa2ae4db119f639a01b02f99f1ba671ece2828eb +md5=0d270c997aff29708c74d53f599ef717 +cksum=1153713708 +upstream_url=https://tukaani.org/xz/xz-VERSION.tar.gz diff --git a/build/pkgs/xz/distros/cygwin.txt b/build/pkgs/xz/distros/cygwin.txt index 0267fff5270..d66e95ca507 100644 --- a/build/pkgs/xz/distros/cygwin.txt +++ b/build/pkgs/xz/distros/cygwin.txt @@ -1 +1 @@ -xz liblzma-devel +xz diff --git a/build/pkgs/xz/distros/debian.txt b/build/pkgs/xz/distros/debian.txt index 5cc8e2ad176..4b3b46661f7 100644 --- a/build/pkgs/xz/distros/debian.txt +++ b/build/pkgs/xz/distros/debian.txt @@ -1,3 +1,2 @@ xz-utils -liblzma-dev # pixz # provides pixz but not xz on debian buster diff --git a/build/pkgs/xz/distros/fedora.txt b/build/pkgs/xz/distros/fedora.txt index 813a264efd5..d66e95ca507 100644 --- a/build/pkgs/xz/distros/fedora.txt +++ b/build/pkgs/xz/distros/fedora.txt @@ -1 +1 @@ -xz xz-devel +xz diff --git a/build/pkgs/xz/distros/opensuse.txt b/build/pkgs/xz/distros/opensuse.txt index f84d903df3e..d66e95ca507 100644 --- a/build/pkgs/xz/distros/opensuse.txt +++ b/build/pkgs/xz/distros/opensuse.txt @@ -1,2 +1 @@ xz -"pkgconfig(liblzma)" diff --git a/build/pkgs/xz/distros/void.txt b/build/pkgs/xz/distros/void.txt index c5fa156f8a0..d66e95ca507 100644 --- a/build/pkgs/xz/distros/void.txt +++ b/build/pkgs/xz/distros/void.txt @@ -1,2 +1 @@ xz -liblzma-devel diff --git a/build/pkgs/xz/package-version.txt b/build/pkgs/xz/package-version.txt index 7cffe05675a..462faf74854 100644 --- a/build/pkgs/xz/package-version.txt +++ b/build/pkgs/xz/package-version.txt @@ -1 +1 @@ -5.2.2.p0 +5.2.5 diff --git a/build/pkgs/xz/spkg-configure.m4 b/build/pkgs/xz/spkg-configure.m4 index 4a02e31bead..a4ed2f8c15e 100644 --- a/build/pkgs/xz/spkg-configure.m4 +++ b/build/pkgs/xz/spkg-configure.m4 @@ -1,7 +1,4 @@ SAGE_SPKG_CONFIGURE([xz], [ - AC_CHECK_LIB([lzma], [lzma_raw_decoder], [lzma_cv_liblzma=yes], [lzma_cv_liblzma=no]) - AC_CHECK_HEADER([lzma.h], [lzma_cv_lzma_h=yes], [lzma_cv_lzma_h=no]) - if test "$lzma_cv_liblzma" = "yes" && test "$lzma_cv_lzma_h" = "yes"; then AC_CACHE_CHECK([for xz >= 4.999.0], [ac_cv_path_XZ], [ AC_PATH_PROGS_FEATURE_CHECK([XZ], [xz], [ xz_version=`$ac_path_XZ --version 2>&1 | cut -d' ' -f4 | $SED -n 1p` @@ -14,7 +11,12 @@ SAGE_SPKG_CONFIGURE([xz], [ ]) AS_IF([test -z "$ac_cv_path_XZ"], [sage_spkg_install_xz=yes]) ]) - else - sage_spkg_install_xz=yes - fi +], [dnl REQUIRED-CHECK + dnl Trac #30948: All dependencies on "xz" are merely build-time dependencies + dnl on the xz binary (for unpacking the tarball in sage_bootstrap.uncompress.tar_file + dnl - when sage-bootstrap-python is so old that it cannot do that by itself). + dnl Packages that depend on actual xz or liblzma should depend on the liblzma spkg. + AS_IF(["$SAGE_BOOTSTRAP_PYTHON" -c "import lzma"], [ + sage_require_xz=no + ]) ]) diff --git a/build/pkgs/zlib/distros/void.txt b/build/pkgs/zlib/distros/void.txt new file mode 100644 index 00000000000..f47c16b504b --- /dev/null +++ b/build/pkgs/zlib/distros/void.txt @@ -0,0 +1 @@ +zlib-devel diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index 3514da9200c..ca1f8aa6078 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -50,7 +50,6 @@ def list_cls(self, *package_classes, **filters): $ sage --package list | sort 4ti2 arb - atlas autotools [...] zn_poly diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index b8e5f66f9d0..4408b00e9d7 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -66,14 +66,12 @@ $ sage --package list | sort 4ti2 arb - atlas autotools [...] zn_poly $ sage --package list :standard: | sort arb - atlas backports_ssl_match_hostname [...] zn_poly diff --git a/configure.ac b/configure.ac index 3309a57eb20..0e092a93853 100644 --- a/configure.ac +++ b/configure.ac @@ -447,7 +447,7 @@ AC_ARG_ENABLE([notebook], AC_ARG_ENABLE([r], AS_HELP_STRING([--disable-r], [disable build of the R package and related packages]), [ - for pkg in r rpy2 r_jupyter; do + for pkg in r rpy2 r_jupyter pcre; do AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) done ]) diff --git a/pkgs/sage-conf/sage_conf.py.in b/pkgs/sage-conf/sage_conf.py.in index d156a274250..86375d2f286 100644 --- a/pkgs/sage-conf/sage_conf.py.in +++ b/pkgs/sage-conf/sage_conf.py.in @@ -27,6 +27,17 @@ ECL_CONFIG = "@SAGE_ECL_CONFIG@".replace('${prefix}', SAGE_LOCAL) SAGE_NAUTY_BINS_PREFIX = "@SAGE_NAUTY_BINS_PREFIX@" +# Names or paths of the 4ti2 executables +FOURTITWO_HILBERT = "@FOURTITWO_HILBERT@" +FOURTITWO_MARKOV = "@FOURTITWO_MARKOV@" +FOURTITWO_GRAVER = "@FOURTITWO_GRAVER@" +FOURTITWO_ZSOLVE = "@FOURTITWO_ZSOLVE@" +FOURTITWO_QSOLVE = "@FOURTITWO_QSOLVE@" +FOURTITWO_RAYS = "@FOURTITWO_RAYS@" +FOURTITWO_PPI = "@FOURTITWO_PPI@" +FOURTITWO_CIRCUITS = "@FOURTITWO_CIRCUITS@" +FOURTITWO_GROEBNER = "@FOURTITWO_GROEBNER@" + # Colon-separated list of pkg-config modules to search for cblas functionality. # We hard-code it here as cblas because configure (build/pkgs/openblas/spkg-configure.m4) # always provides cblas.pc, if necessary by creating a facade pc file for a system BLAS. diff --git a/src/VERSION.txt b/src/VERSION.txt index bc12a7eeb60..173833eaf87 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.5.beta2 +9.5.beta3 diff --git a/src/bin/sage-runtests b/src/bin/sage-runtests index 16d3295b922..4fc2062b152 100755 --- a/src/bin/sage-runtests +++ b/src/bin/sage-runtests @@ -1,11 +1,12 @@ #!/usr/bin/env sage-python -import optparse +import argparse import os import sys # Note: the DOT_SAGE and SAGE_STARTUP_FILE environment variables have already been set by sage-env -DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'),'.sage')) +DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'), + '.sage')) SAGE_ROOT = os.environ.get('SAGE_ROOT') # Override to not pick up user configuration, see Trac #20270 @@ -27,36 +28,26 @@ def _get_optional_defaults(): if __name__ == "__main__": - parser = optparse.OptionParser() - - def optional_argument(option, opt_str, value, parser, typ, default_arg): - assert value is None - try: - next_arg = typ(parser.rargs[0]) - except Exception: - next_arg = default_arg - else: - parser.rargs.pop(0) - setattr(parser.values, option.dest, next_arg) - - parser.add_option("-p", "--nthreads", dest="nthreads", default=1, action="callback", - callback=optional_argument, callback_args=(int, 0), nargs=0, - metavar="N", help="tests in parallel using N threads with 0 interpreted as max(2, min(8, cpu_count()))") - parser.add_option("-T", "--timeout", type=int, default=-1, help="timeout (in seconds) for doctesting one file, 0 for no timeout") - parser.add_option("-a", "--all", action="store_true", default=False, help="test all files in the Sage library") - parser.add_option("--logfile", metavar="FILE", help="log all output to FILE") - - parser.add_option("-l", "--long", action="store_true", default=False, help="include lines with the phrase 'long time'") - parser.add_option("-s", "--short", dest="target_walltime", default=None, action="callback", - callback=optional_argument, callback_args=(int, 300), nargs=0, - metavar="SECONDS", help="run as many doctests as possible in about 300 seconds (or the number of seconds given as an optional argument)") - parser.add_option("--warn-long", dest="warn_long", default=None, action="callback", - callback=optional_argument, callback_args=(float, 1.0), nargs=0, - metavar="SECONDS", help="warn if tests take more time than SECONDS") + parser = argparse.ArgumentParser(usage="sage -t [options] filenames") + parser.add_argument("-p", "--nthreads", dest="nthreads", + type=int, nargs='?', const=0, default=1, metavar="N", + help="tests in parallel using N threads with 0 interpreted as max(2, min(8, cpu_count()))") + parser.add_argument("-T", "--timeout", type=int, default=-1, help="timeout (in seconds) for doctesting one file, 0 for no timeout") + what = parser.add_mutually_exclusive_group() + what.add_argument("-a", "--all", action="store_true", default=False, help="test all files in the Sage library") + parser.add_argument("--logfile", type=argparse.FileType('a'), metavar="FILE", help="log all output to FILE") + + parser.add_argument("-l", "--long", action="store_true", default=False, help="include lines with the phrase 'long time'") + parser.add_argument("-s", "--short", dest="target_walltime", nargs='?', + type=int, default=-1, const=300, metavar="SECONDS", + help="run as many doctests as possible in about 300 seconds (or the number of seconds given as an optional argument)") + parser.add_argument("--warn-long", dest="warn_long", nargs='?', + type=float, default=-1.0, const=1.0, metavar="SECONDS", + help="warn if tests take more time than SECONDS") # By default, include all tests marked 'dochtml' -- see # https://trac.sagemath.org/ticket/25345 and # https://trac.sagemath.org/ticket/26110: - parser.add_option("--optional", metavar="PKGS", default=_get_optional_defaults(), + parser.add_argument("--optional", metavar="PKGS", default=_get_optional_defaults(), help='only run tests including one of the "# optional" tags listed in PKGS; ' 'if "sage" is listed, will also run the standard doctests; ' 'if "dochtml" is listed, will also run the tests relying on the HTML documentation; ' @@ -64,75 +55,91 @@ if __name__ == "__main__": 'if "external" is listed, will also run tests for available external software; ' 'if "build" is listed, will also run tests specific to Sage\'s build/packaging system; ' 'if set to "all", then all tests will be run') - parser.add_option("--randorder", type=int, metavar="SEED", help="randomize order of tests") - parser.add_option("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed for fuzzing doctests") - parser.add_option("--global-iterations", "--global_iterations", type=int, default=0, help="repeat the whole testing process this many times") - parser.add_option("--file-iterations", "--file_iterations", type=int, default=0, help="repeat each file this many times, stopping on the first failure") - parser.add_option("--environment", type=str, default="sage.repl.ipython_kernel.all_jupyter", help="name of a module that provides the global environment for tests") - - parser.add_option("-i", "--initial", action="store_true", default=False, help="only show the first failure in each file") - parser.add_option("--exitfirst", action="store_true", default=False, help="end the test run immediately after the first failure or unexpected exception") - parser.add_option("--force_lib", "--force-lib", action="store_true", default=False, help="do not import anything from the tested file(s)") - parser.add_option("--abspath", action="store_true", default=False, help="print absolute paths rather than relative paths") - parser.add_option("--verbose", action="store_true", default=False, help="print debugging output during the test") - parser.add_option("-d", "--debug", action="store_true", default=False, help="drop into a python debugger when an unexpected error is raised") - parser.add_option("--only-errors", action="store_true", default=False, help="only output failures, not test successes") - - parser.add_option("--gdb", action="store_true", default=False, help="run doctests under the control of gdb") - parser.add_option("--valgrind", "--memcheck", action="store_true", default=False, - help="run doctests using Valgrind's memcheck tool. The log " - "files are named sage-memcheck.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - parser.add_option("--massif", action="store_true", default=False, - help="run doctests using Valgrind's massif tool. The log " - "files are named sage-massif.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - parser.add_option("--cachegrind", action="store_true", default=False, - help="run doctests using Valgrind's cachegrind tool. The log " - "files are named sage-cachegrind.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - parser.add_option("--omega", action="store_true", default=False, - help="run doctests using Valgrind's omega tool. The log " - "files are named sage-omega.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - - parser.add_option("-f", "--failed", action="store_true", default=False, + parser.add_argument("--randorder", type=int, metavar="SEED", help="randomize order of tests") + parser.add_argument("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed for fuzzing doctests") + parser.add_argument("--global-iterations", "--global_iterations", type=int, default=0, help="repeat the whole testing process this many times") + parser.add_argument("--file-iterations", "--file_iterations", type=int, default=0, help="repeat each file this many times, stopping on the first failure") + parser.add_argument("--environment", type=str, default="sage.repl.ipython_kernel.all_jupyter", help="name of a module that provides the global environment for tests") + + parser.add_argument("-i", "--initial", action="store_true", default=False, help="only show the first failure in each file") + parser.add_argument("--exitfirst", action="store_true", default=False, help="end the test run immediately after the first failure or unexpected exception") + parser.add_argument("--force_lib", "--force-lib", action="store_true", default=False, help="do not import anything from the tested file(s)") + parser.add_argument("--abspath", action="store_true", default=False, help="print absolute paths rather than relative paths") + parser.add_argument("--verbose", action="store_true", default=False, help="print debugging output during the test") + parser.add_argument("-d", "--debug", action="store_true", default=False, help="drop into a python debugger when an unexpected error is raised") + parser.add_argument("--only-errors", action="store_true", default=False, help="only output failures, not test successes") + + parser.add_argument("--gdb", action="store_true", default=False, help="run doctests under the control of gdb") + parser.add_argument("--valgrind", "--memcheck", action="store_true", default=False, + help="run doctests using Valgrind's memcheck tool. The log " + "files are named sage-memcheck.PID and can be found in " + + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--massif", action="store_true", default=False, + help="run doctests using Valgrind's massif tool. The log " + "files are named sage-massif.PID and can be found in " + + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--cachegrind", action="store_true", default=False, + help="run doctests using Valgrind's cachegrind tool. The log " + "files are named sage-cachegrind.PID and can be found in " + + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--omega", action="store_true", default=False, + help="run doctests using Valgrind's omega tool. The log " + "files are named sage-omega.PID and can be found in " + + os.path.join(DOT_SAGE, "valgrind")) + + parser.add_argument("-f", "--failed", action="store_true", default=False, help="doctest only those files that failed in the previous run") - parser.add_option("-n", "--new", action="store_true", default=False, + what.add_argument("-n", "--new", action="store_true", default=False, help="doctest only those files that have been changed in the repository and not yet been committed") - parser.add_option("--show-skipped", "--show_skipped", action="store_true", default=False, + parser.add_argument("--show-skipped", "--show_skipped", action="store_true", default=False, help="print a summary at the end of each file of optional tests that were skipped") - parser.add_option("--stats_path", "--stats-path", default=os.path.join(DOT_SAGE, "timings2.json"), - help="path to a json dictionary for the latest run storing a timing for each file") + parser.add_argument("--stats_path", "--stats-path", default=os.path.join(DOT_SAGE, "timings2.json"), + help="path to a json dictionary for the latest run storing a timing for each file") - def gc_option(option, opt_str, value, parser): - gcopts = dict(DEFAULT=0, ALWAYS=1, NEVER=-1) - try: - arg = gcopts[value.upper()] - except KeyError: - parser.error("unknown value {0}={1}".format(opt_str, value)) - setattr(parser.values, option.dest, arg) + class GCAction(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + gcopts = dict(DEFAULT=0, ALWAYS=1, NEVER=-1) + new_value = gcopts[values] + setattr(namespace, self.dest, new_value) - parser.add_option("--gc", type="string", action="callback", callback=gc_option, - help="control garbarge collection " - "(ALWAYS: collect garbage before every test; NEVER: disable gc; DEFAULT: Python default)") + parser.add_argument("--gc", + choices=["DEFAULT", "ALWAYS", "NEVER"], + default=0, + action=GCAction, + help="control garbarge collection " + "(ALWAYS: collect garbage before every test; NEVER: disable gc; DEFAULT: Python default)") # The --serial option is only really for internal use, better not # document it. - parser.add_option("--serial", action="store_true", default=False, help=optparse.SUPPRESS_HELP) - - parser.set_usage("sage -t [options] filenames") - - options, args = parser.parse_args() - - if not args and not (options.all or options.new): - parser.print_help() + parser.add_argument("--serial", action="store_true", default=False, help=argparse.SUPPRESS) + + parser.add_argument("filenames", help="file names", nargs='*') + + # custom treatment to separate properly + # one or several file names at the end + new_arguments = [] + need_filenames = True + in_filenames = False + afterlog = False + for arg in sys.argv[1:]: + if arg in ('-n', '--new', '-a', '--all'): + need_filenames = False + elif need_filenames and not (afterlog or in_filenames) and os.path.exists(arg): + in_filenames = True + new_arguments.append('--') + new_arguments.append(arg) + afterlog = bool(arg == '--logfile') + + args = parser.parse_args(new_arguments) + + if not args.filenames and not (args.all or args.new): + print('either use --new or --all or some filenames') sys.exit(2) # Limit the number of threads to 2 to save system resources. # See Trac #23713, #23892, #30351 - if sys.platform == 'darwin': + if sys.platform == 'darwin': os.environ["OMP_NUM_THREADS"] = "1" else: os.environ["OMP_NUM_THREADS"] = "2" @@ -140,21 +147,19 @@ if __name__ == "__main__": os.environ["SAGE_NUM_THREADS"] = "2" from sage.doctest.control import DocTestController - DC = DocTestController(options, args) + DC = DocTestController(args, args.filenames) err = DC.run() try: exit_code_pytest = 0 import pytest pytest_options = ["--import-mode", "importlib"] - if options.verbose: + if args.verbose: pytest_options.append("-v") exit_code_pytest = pytest.main(pytest_options + args) except ModuleNotFoundError: print("Pytest is not installed, skip checking tests that rely on it.") - - if err == 0: sys.exit(exit_code_pytest) else: diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 46acf9862a7..750e10d31e0 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,5 +1,5 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.5.beta2' -SAGE_RELEASE_DATE='2021-09-26' -SAGE_VERSION_BANNER='SageMath version 9.5.beta2, Release Date: 2021-09-26' +SAGE_VERSION='9.5.beta3' +SAGE_RELEASE_DATE='2021-10-11' +SAGE_VERSION_BANNER='SageMath version 9.5.beta3, Release Date: 2021-10-11' diff --git a/src/doc/de/tutorial/interactive_shell.rst b/src/doc/de/tutorial/interactive_shell.rst index 048f1c6f0ac..a95e8e83b53 100644 --- a/src/doc/de/tutorial/interactive_shell.rst +++ b/src/doc/de/tutorial/interactive_shell.rst @@ -385,7 +385,7 @@ z.B. ``NameError`` oder ``ValueError`` (vgl. Python Library Reference File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/doc/de/tutorial/tour_linalg.rst b/src/doc/de/tutorial/tour_linalg.rst index 4a090f259ba..2a5467e8884 100644 --- a/src/doc/de/tutorial/tour_linalg.rst +++ b/src/doc/de/tutorial/tour_linalg.rst @@ -255,4 +255,4 @@ Beachten Sie, dass Python zwischen Klein- und Großschreibung unterscheidet: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index f6413de91e8..7830c674573 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -1079,6 +1079,26 @@ framework. Here is a comprehensive list: sage: SloaneEncyclopedia[60843] # optional - sloane_database + .. NOTE:: + + If one of the first 10 lines of a file starts with any of + ``r""" sage.doctest: optional - keyword`` + (or ``""" sage.doctest: optional - keyword`` + or ``# sage.doctest: optional - keyword`` + or ``% sage.doctest: optional - keyword`` + or ``.. sage.doctest: optional - keyword``, + or any of these with different spacing), + then that file will be skipped unless + the ``--optional=keyword`` flag is passed to ``sage -t``. + + This does not apply to files which are explicitly given + as command line arguments: those are always tested. + + If you add such a line to a file, you are strongly encouraged + to add a note to the module-level documentation, saying that + the doctests in this file will be skipped unless the + appropriate conditions are met. + - **internet:** For lines that require an internet connection:: sage: oeis(60843) # optional - internet diff --git a/src/doc/en/faq/faq-general.rst b/src/doc/en/faq/faq-general.rst index 53fa60f5c96..ebc04f45144 100644 --- a/src/doc/en/faq/faq-general.rst +++ b/src/doc/en/faq/faq-general.rst @@ -181,8 +181,6 @@ Why did you write Sage from scratch, instead of using other existing software an Sage was not written from scratch. Most of its underlying mathematics functionalities are made possible through FOSS projects such as -* `ATLAS `_ --- Automatically Tuned - Linear Algebra Software. * `BLAS `_ --- Basic Linear Algebra Subprograms. * `ECL `_ --- Embeddable Common-Lisp system diff --git a/src/doc/en/faq/faq-usage.rst b/src/doc/en/faq/faq-usage.rst index 5da1732f538..7b3f38bea2d 100644 --- a/src/doc/en/faq/faq-usage.rst +++ b/src/doc/en/faq/faq-usage.rst @@ -176,28 +176,8 @@ Can I use SageMath with Python 3.x? Since release 9.0 from January 2020, SageMath is running on top of Python 3. - -I downloaded a Sage binary and it crashes on startup with "Illegal instruction". What can I do? -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -One way to fix this is to build Sage entirely from source. Another -option is to fix your Sage installation by rebuilding MPIR and ATLAS -by typing the following from the ``SAGE_ROOT`` of your Sage -installation directory and wait about 15 to 20 minutes - -.. CODE-BLOCK:: shell-session - - $ rm spkg/installed/mpir* spkg/installed/atlas* - $ make - -It is possible that the binaries have been built for a newer -architecture than what you have. Nobody has yet figured out how to -build Sage in such a way that MPIR and ATLAS work on all -hardware. This will eventually get fixed. Any help is appreciated. - - I used XXX to install Sage X.Y and that version is giving lots of errors. What can I do? -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" The version of Sage, i.e. Sage version X.Y, that is available on your XXX system through its package manager, is very old. No one has yet diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 0b30005d755..5ccd5fc7a83 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -187,8 +187,7 @@ On Redhat-derived systems not all perl components are installed by default and you might have to install the ``perl-ExtUtils-MakeMaker`` package. -On Cygwin, the ``lapack`` and ``liblapack-devel`` packages are required to -provide ATLAS support as the Sage package for ATLAS is not built by default. +On Cygwin, the ``lapack`` and ``liblapack-devel`` packages are required. Installing prerequisites ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1074,7 +1073,7 @@ Here are some of the more commonly used variables affecting the build process: - :envvar:`MAKE` - one useful setting for this variable when building Sage is ``MAKE='make -jNUM'`` to tell the ``make`` program to run ``NUM`` jobs in parallel when building. - Note that not all Sage packages (e.g. ATLAS) support this variable. + Note that some Sage packages may not support this variable. Some people advise using more jobs than there are CPU cores, at least if the system is not heavily loaded and has plenty of RAM; for example, a good @@ -1202,11 +1201,11 @@ Here are some of the more commonly used variables affecting the build process: - :envvar:`SAGE_BUILD_DIR` - the default behavior is to build each spkg in a subdirectory of :file:`$SAGE_ROOT/local/var/tmp/sage/build/`; for - example, build version 3.8.3.p12 of - :file:`atlas` in the directory - :file:`$SAGE_ROOT/local/var/tmp/sage/build/atlas-3.8.3.p12/`. + example, build version 7.27.0 of + :file:`ipython` in the directory + :file:`$SAGE_ROOT/local/var/tmp/sage/build/ipython-7.27.0/`. If this variable is set, then build in - :file:`$SAGE_BUILD_DIR/atlas-3.8.3.p12/` instead. + :file:`$SAGE_BUILD_DIR/ipython-7.27.0/` instead. If the directory :file:`$SAGE_BUILD_DIR` does not exist, it is created. As of this writing (Sage 4.8), when building the standard Sage packages, 1.5 gigabytes of free space are required in this directory (or more if @@ -1288,66 +1287,6 @@ Environment variables dealing with specific Sage packages: ``MPIR`` (default choice), ``GMP``. -- :envvar:`SAGE_ATLAS_ARCH` - if you are compiling ATLAS (in particular, - if :envvar:`SAGE_ATLAS_LIB` is not set), you can use this environment - variable to set a particular architecture and instruction set extension, - to control the maximum number of threads ATLAS can use, and to trigger the - installation of a static library (which is disabled by default unless - building our custom shared libraries fails). - The syntax is - - ``SAGE_ATLAS_ARCH=[threads:n,][static,]arch[,isaext1][,isaext2]...[,isaextN]``. - - While ATLAS comes with precomputed timings for a variety of CPUs, it only - uses them if it finds an exact match. - Otherwise, ATLAS runs through a lengthy automated tuning process in order - to optimize performance for your particular system, which can take several - days on slow and unusual systems. - You drastically reduce the total Sage compile time if you manually select a - suitable architecture. - It is recommended to specify a suitable architecture on laptops or other - systems with CPU throttling or if you want to distribute the binaries. - Available architectures are - - ``POWER3``, ``POWER4``, ``POWER5``, ``PPCG4``, ``PPCG5``, - ``POWER6``, ``POWER7``, ``IBMz9``, ``IBMz10``, ``IBMz196``, - ``x86x87``, ``x86SSE1``, ``x86SSE2``, ``x86SSE3``, ``P5``, - ``P5MMX``, ``PPRO``, ``PII``, ``PIII``, ``PM``, ``CoreSolo``, - ``CoreDuo``, ``Core2Solo``, ``Core2``, ``Corei1``, ``Corei2``, - ``Atom``, ``P4``, ``P4E``, ``Efficeon``, ``K7``, ``HAMMER``, - ``AMD64K10h``, ``AMDDOZER``, ``UNKNOWNx86``, ``IA64Itan``, - ``IA64Itan2``, ``USI``, ``USII``, ``USIII``, ``USIV``, ``UST2``, - ``UnknownUS``, ``MIPSR1xK``, ``MIPSICE9``, ``ARMv7``. - - and instruction set extensions are - - ``VSX``, ``AltiVec``, ``AVXMAC``, ``AVXFMA4``, ``AVX``, ``SSE3``, - ``SSE2``, ``SSE1``, ``3DNow``, ``NEON``. - - In addition, you can also set - - - ``SAGE_ATLAS_ARCH=fast`` which picks defaults for a modern (2-3 year old) - CPU of your processor line, and - - - ``SAGE_ATLAS_ARCH=base`` which picks defaults that should work for a ~10 - year old CPU. - - For example, - - ``SAGE_ATLAS_ARCH=Corei2,AVX,SSE3,SSE2,SSE1`` - - would be appropriate for a Core i7 CPU. - -- :envvar:`SAGE_ATLAS_LIB` - if you have an installation of ATLAS on your - system and you want Sage to use it instead of building and installing its - own version of ATLAS, set this variable to be the directory containing your - ATLAS installation. - It should contain the files :file:`libatlas`, :file:`liblapack`, - :file:`libcblas`, :file:`libf77blas` (and optionally :file:`libptcblas` and - :file:`libptf77blas` for multi-threaded computations), with extensions ``.a``, - ``.so``, or ``.dylib``. For backward compatibility, the libraries may also be - in the subdirectory :file:`SAGE_ATLAS_LIB/lib/`. - - :envvar:`SAGE_MATPLOTLIB_GUI` - if set to anything non-empty except ``no``, then Sage will attempt to build the graphical backend when it builds the matplotlib package. diff --git a/src/doc/en/reference/graphs/index.rst b/src/doc/en/reference/graphs/index.rst index 2347747d65b..b1ec35240de 100644 --- a/src/doc/en/reference/graphs/index.rst +++ b/src/doc/en/reference/graphs/index.rst @@ -91,6 +91,7 @@ Libraries of algorithms sage/graphs/traversals sage/graphs/graph_plot sage/graphs/graph_plot_js + sage/graphs/graph_decompositions/tree_decomposition sage/graphs/graph_decompositions/vertex_separation sage/graphs/graph_decompositions/rankwidth sage/graphs/graph_decompositions/bandwidth diff --git a/src/doc/en/reference/manifolds/diff_vector_bundle.rst b/src/doc/en/reference/manifolds/diff_vector_bundle.rst index 5cfb22dae90..fdfdf39df61 100644 --- a/src/doc/en/reference/manifolds/diff_vector_bundle.rst +++ b/src/doc/en/reference/manifolds/diff_vector_bundle.rst @@ -8,4 +8,4 @@ Differentiable Vector Bundles sage/manifolds/differentiable/bundle_connection - sage/manifolds/differentiable/characteristic_class + sage/manifolds/differentiable/characteristic_cohomology_class diff --git a/src/doc/en/reference/power_series/index.rst b/src/doc/en/reference/power_series/index.rst index bdb582b5e74..dba377477f1 100644 --- a/src/doc/en/reference/power_series/index.rst +++ b/src/doc/en/reference/power_series/index.rst @@ -15,8 +15,8 @@ Power Series Rings and Laurent Series Rings sage/rings/laurent_series_ring sage/rings/laurent_series_ring_element - sage/rings/lazy_laurent_series - sage/rings/lazy_laurent_series_ring + sage/rings/lazy_series + sage/rings/lazy_series_ring sage/rings/puiseux_series_ring sage/rings/puiseux_series_ring_element diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 8ff9195aed1..2916ebcaf05 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1070,6 +1070,27 @@ REFERENCES: *Reverse-Engineering the S-Box of Streebog, Kuznyechik and STRIBOBr1*; in EuroCrypt'16, pp. 372-402. +.. [Br1910] Bruckner, "Uber die Ableitung der allgemeinen Polytope und + die nach Isomorphismus verschiedenen Typen der allgemeinen + Achtzelle (Oktatope)", Verhand. Konik. Akad. Wetenschap, + Erste Sectie, 10 (1910) + +.. [Br2000] Kenneth S. Brown, *Semigroups, rings, and Markov chains*, + :arxiv:`math/0006145v1`. + + +.. [BR2000a] \P. Barreto and V. Rijmen, + *The ANUBIS Block Cipher*; in + First Open NESSIE Workshop, (2000). + +.. [BR2000b] \P. Barreto and V. Rijmen, + *The Khazad legacy-level Block Cipher*; in + First Open NESSIE Workshop, (2000). + +.. [BR2000c] \P. Barreto and V. Rijmen, + *The Whirlpool hashing function*; in + First Open NESSIE Workshop, (2000). + .. [BR2010] Matthew Baker and Robert Rumely. Potential theory and dynamics on the Berkovich projective line. Mathematical Surveys and Monographs, Volumne 159. 2010. @@ -1078,6 +1099,13 @@ REFERENCES: *Noncommutative Rational Series With Applications*. Cambridge, 2010. +.. [BR2010b] Valérie Berthé and Michel Rigo, editors. Combinatorics, automata, + and number theory, volume 135. Cambridge: Cambridge University Press, 2010. + +.. [Br2016] *Bresenham's Line Algorithm*, Python, 26 December 2016. + http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm + + .. [Brandes01] Ulrik Brandes, A faster algorithm for betweenness centrality, Journal of Mathematical Sociology 25.2 (2001): 163-177, @@ -1111,30 +1139,6 @@ REFERENCES: .. [Bro2016] \A.E. Brouwer, Personal communication, 2016. -.. [Br1910] Bruckner, "Uber die Ableitung der allgemeinen Polytope und - die nach Isomorphismus verschiedenen Typen der allgemeinen - Achtzelle (Oktatope)", Verhand. Konik. Akad. Wetenschap, - Erste Sectie, 10 (1910) - -.. [Br2000] Kenneth S. Brown, *Semigroups, rings, and Markov chains*, - :arxiv:`math/0006145v1`. - - -.. [BR2000a] \P. Barreto and V. Rijmen, - *The ANUBIS Block Cipher*; in - First Open NESSIE Workshop, (2000). - -.. [BR2000b] \P. Barreto and V. Rijmen, - *The Khazad legacy-level Block Cipher*; in - First Open NESSIE Workshop, (2000). - -.. [BR2000c] \P. Barreto and V. Rijmen, - *The Whirlpool hashing function*; in - First Open NESSIE Workshop, (2000). - -.. [Br2016] *Bresenham's Line Algorithm*, Python, 26 December 2016. - http://www.roguebasin.com/index.php?title=Bresenham%27s_Line_Algorithm - .. [Bro1982] \A. Brouwer, *Polarities of G. Higman's symmetric design and a strongly regular graph on 176 vertices*, @@ -1280,6 +1284,10 @@ REFERENCES: Coinvariants Quasi-Symétriques*, Electronic Journal of Combinatorics Vol 12(1) (2005) N16. +.. [Che1944] \S. Chern, *A simple intrinsic proof of the Gauss-Bonnet formula + for closed Riemannian manifolds*, Ann. of Math. (2) 45 (1944), + 747–752. + .. [CQ2019] \A. Cassella and C. Quadrelli. *Right-angled Artin groups and enhanced Koszul properties*. Preprint, :arxiv:`1907.03824`, (2019). @@ -1900,6 +1908,11 @@ REFERENCES: standards et permutations de Baxter, proceedings of Formal Power Series and Algebraic Combinatorics, 1994. +.. [DG2006] Yon Dourisboure and Cyril Gavoille. *Tree-decompositions with bags + of small diameter*. Discrete Mathematics, 307 (16) (2007), + pp. 2008-2029. + :doi:`10.1016/j.disc.2005.12.060` + .. [DGH2020] \C. Donnot, A. Genitrini and Y. Herida. Unranking Combinations Lexicographically: an efficient new strategy compared with others, 2020, https://hal.archives-ouvertes.fr/hal-02462764v1 @@ -3794,6 +3807,12 @@ REFERENCES: Algebra 207 (2006), no 1, pages 1-18. Preprint: :arxiv:`math/0504296v2`. +.. [LKOL2002] Hyeong-Ok Lee, Jong-Seok Kim, Eunseuk Oh and Hyeong-Seok Lim, + *Hyper-Star Graph: A New Interconnection Network Improving the + Network Cost of the Hypercube*, Eurasian Conference on Information + and Communication Technology, LNCS 2510, pp 858-865, 2002. + :doi:`10.1007/3-540-36087-5_99` + .. [LLM2003] \A. Lascoux, L. Lapointe, and J. Morse. *Tableau atoms and a new Macdonald positivity conjecture.* Duke Math Journal, **116 (1)**, 2003. :arxiv:`math/0008073` @@ -3872,6 +3891,11 @@ REFERENCES: modular functions*, Int. Math. Res. Not 2007 (050). :arxiv:`math/0701168`. +.. [Lokshtanov2009] Daniel Lokshtanov. *On the complexity of computing + treelength*. Discrete Applied + Mathematics. 158(7):820-827, 2009. + :doi:`10.1016/j.dam.2009.10.007` + .. [Lom2019] Davide Lombardo, *Computing the geometric endomorphism ring of a genus 2 Jacobian*, Mathematics of Computation 88 (2019), 889-929. :doi:`10.1090/mcom/3358`. diff --git a/src/doc/en/thematic_tutorials/geometry/tips.rst b/src/doc/en/thematic_tutorials/geometry/tips.rst index f1fad488ddd..458e0741906 100644 --- a/src/doc/en/thematic_tutorials/geometry/tips.rst +++ b/src/doc/en/thematic_tutorials/geometry/tips.rst @@ -81,20 +81,20 @@ the latex presentation, there is a method for that! sage: print(TCube.Hrepresentation_str(latex=True)) \begin{array}{rcl} - -6 \, x_{0} - 6 \, x_{1} - 6 \, x_{2} & \geq & -7 \\ - -6 \, x_{0} - 6 \, x_{1} + 6 \, x_{2} & \geq & -7 \\ - -6 \, x_{0} + 6 \, x_{1} - 6 \, x_{2} & \geq & -7 \\ - -6 \, x_{0} + 6 \, x_{1} + 6 \, x_{2} & \geq & -7 \\ - -2 \, x_{0} & \geq & -1 \\ - -2 \, x_{1} & \geq & -1 \\ - -2 \, x_{2} & \geq & -1 \\ - 6 \, x_{0} + 6 \, x_{1} + 6 \, x_{2} & \geq & -7 \\ - 2 \, x_{2} & \geq & -1 \\ - 2 \, x_{1} & \geq & -1 \\ - 2 \, x_{0} & \geq & -1 \\ - 6 \, x_{0} - 6 \, x_{1} - 6 \, x_{2} & \geq & -7 \\ - 6 \, x_{0} - 6 \, x_{1} + 6 \, x_{2} & \geq & -7 \\ - 6 \, x_{0} + 6 \, x_{1} - 6 \, x_{2} & \geq & -7 + -6x_{0} - 6x_{1} - 6x_{2} & \geq & -7 \\ + -6x_{0} - 6x_{1} + 6x_{2} & \geq & -7 \\ + -6x_{0} + 6x_{1} - 6x_{2} & \geq & -7 \\ + -6x_{0} + 6x_{1} + 6x_{2} & \geq & -7 \\ + -2x_{0} & \geq & -1 \\ + -2x_{1} & \geq & -1 \\ + -2x_{2} & \geq & -1 \\ + 6x_{0} + 6x_{1} + 6x_{2} & \geq & -7 \\ + 2x_{2} & \geq & -1 \\ + 2x_{1} & \geq & -1 \\ + 2x_{0} & \geq & -1 \\ + 6x_{0} - 6x_{1} - 6x_{2} & \geq & -7 \\ + 6x_{0} - 6x_{1} + 6x_{2} & \geq & -7 \\ + 6x_{0} + 6x_{1} - 6x_{2} & \geq & -7 \end{array} sage: Latex_repr = LatexExpr(TCube.Hrepresentation_str(latex=True)) diff --git a/src/doc/en/tutorial/interactive_shell.rst b/src/doc/en/tutorial/interactive_shell.rst index 564de65aa24..0ca57bfaf5a 100644 --- a/src/doc/en/tutorial/interactive_shell.rst +++ b/src/doc/en/tutorial/interactive_shell.rst @@ -465,7 +465,7 @@ for a complete list of exceptions). For example, File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/doc/en/tutorial/tour_linalg.rst b/src/doc/en/tutorial/tour_linalg.rst index a38b6e1ac72..054e338cea7 100644 --- a/src/doc/en/tutorial/tour_linalg.rst +++ b/src/doc/en/tutorial/tour_linalg.rst @@ -249,4 +249,4 @@ Note that Python is case sensitive: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/fr/tutorial/interactive_shell.rst b/src/doc/fr/tutorial/interactive_shell.rst index 3f28f110c3a..bebb972e6d2 100644 --- a/src/doc/fr/tutorial/interactive_shell.rst +++ b/src/doc/fr/tutorial/interactive_shell.rst @@ -472,7 +472,7 @@ de référence de la bibliothèque de Python [PyLR]_ pour une liste complète). File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/doc/fr/tutorial/tour_linalg.rst b/src/doc/fr/tutorial/tour_linalg.rst index 906793390ad..1343fa126fa 100644 --- a/src/doc/fr/tutorial/tour_linalg.rst +++ b/src/doc/fr/tutorial/tour_linalg.rst @@ -252,4 +252,4 @@ Notez que Python distingue les majuscules des minuscules : sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/it/faq/faq-general.rst b/src/doc/it/faq/faq-general.rst index 298178d1337..5f9234d57c8 100644 --- a/src/doc/it/faq/faq-general.rst +++ b/src/doc/it/faq/faq-general.rst @@ -168,9 +168,6 @@ Perché avete scritto Sage da zero, invece di usare software e librerie preesist Sage non è stato scritto da zero. La maggior parte delle sue funzionalità sono realizzate attraverso progetti FOSS come -* `ATLAS `_ --- libreria software per Algebra - Lineare ottimizzata automaticamente. - * `BLAS `_ --- sottoprogrammi per Algebra Lineare di base. diff --git a/src/doc/it/faq/faq-usage.rst b/src/doc/it/faq/faq-usage.rst index 5267c991c94..51a13b207fb 100644 --- a/src/doc/it/faq/faq-usage.rst +++ b/src/doc/it/faq/faq-usage.rst @@ -156,25 +156,6 @@ Posso usare Sage con la versione 3.x di Python? Dalla versione 9.0 del Gennaio 2020, SageMath utilizza Python 3. -Ho scaricato il binario di Sage e va in crash quando lo lancio, con il messaggio "illegal instruction" (istruzione non permessa). Cosa posso fare? -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -Un modo di risolvere è compilare Sage interamente dal codice sorgente. -Un'altra possibilità è correggere la tua installazione di Sage con la -ricompilazione dei componenti MPIR e ATLAS (richiede da 15 a 20 minuti), -da effettuarsi da riga di comando a partire dalla cartella -``SAGE_ROOT`` della tua installazione con le 2 istruzioni:: - - rm spkg/installed/mpir* spkg/installed/atlas* - make - -È possibile che i binari siano stati compilati per un'architettura più -recente di quella della tua macchina. Nessuno ha ancora trovato un -modo di compilare Sage in maniera che MPIR ed ATLAS funzionino su -qualunque hardware. Questo sarà prima o poi risolto. -Qualunque aiuto in tal senso sarà apprezzato. - - Ho usato Debian/Ubuntu per installare la versione 3.0.5 di Sage ed essa sta dando un sacco di errori. Cosa posso fare? """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" @@ -461,28 +442,6 @@ riattivare successivamente l'interfaccia grafica, prima di tentare di accedere tramite un'interfaccia testuale. -Sage 2.9 o superiore non riesce a compilare ATLAS su Linux. Come posso risolvere? -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -La causa più probabile è l'abilitazione della gestione -dell'alimentazione. Disabilitala per risolvere il problema. -In base al tuo tipo di distribuzione ciò si può fare da interfaccia -grafica oppure no. Digita da riga di comando, come utente root, -quanto segue, per ogni CPU presente sul tuo sistema:: - - /usr/bin/cpufreq-selector -g performance -c #number CPU - -Su Ubuntu, prova a disabilitare “Power Manager” -(gestione alimentazione) via - -.. CODE-BLOCK:: text - - System --> Preferences --> Sessions - -nel menu “Startup Programs” (programmi di avvio) o -utilizzando ``cpufreq-set`` da riga di comando. - - Quando lancio Sage, SELinux segnala che "/path/to/libpari-gmp.so.2" richiede "text-relocation" (riallocazione del testo). Come posso risolvere? """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" diff --git a/src/doc/ja/tutorial/tour_linalg.rst b/src/doc/ja/tutorial/tour_linalg.rst index 769dbb32006..cf24ab37ed1 100644 --- a/src/doc/ja/tutorial/tour_linalg.rst +++ b/src/doc/ja/tutorial/tour_linalg.rst @@ -266,4 +266,4 @@ Pythonでは,大文字小文字が区別されることに注意: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/pt/tutorial/interactive_shell.rst b/src/doc/pt/tutorial/interactive_shell.rst index cba3f29cfcd..64ef511d7e4 100644 --- a/src/doc/pt/tutorial/interactive_shell.rst +++ b/src/doc/pt/tutorial/interactive_shell.rst @@ -452,7 +452,7 @@ exemplo, File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/doc/pt/tutorial/tour_linalg.rst b/src/doc/pt/tutorial/tour_linalg.rst index e7dd77f36dd..9cdf7671dd7 100644 --- a/src/doc/pt/tutorial/tour_linalg.rst +++ b/src/doc/pt/tutorial/tour_linalg.rst @@ -230,4 +230,4 @@ Note que o Python é sensível a maiúsculas e minúsculas: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/doc/ru/tutorial/interactive_shell.rst b/src/doc/ru/tutorial/interactive_shell.rst index 51dffa1c923..7abfe99fe53 100644 --- a/src/doc/ru/tutorial/interactive_shell.rst +++ b/src/doc/ru/tutorial/interactive_shell.rst @@ -369,7 +369,7 @@ Wall time. Однако, если существует существенная File "", line 1 ZZ(3)_2 ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: EllipticCurve([0,infinity]) ------------------------------------------------------------ diff --git a/src/doc/ru/tutorial/tour_linalg.rst b/src/doc/ru/tutorial/tour_linalg.rst index 7b5cf65426d..2e1e6620549 100644 --- a/src/doc/ru/tutorial/tour_linalg.rst +++ b/src/doc/ru/tutorial/tour_linalg.rst @@ -224,4 +224,4 @@ Sage поддерживает разреженную линейную алгеб sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse' diff --git a/src/pyproject.toml.m4 b/src/pyproject.toml.m4 index 1d610ab0149..125da7ac1cc 100644 --- a/src/pyproject.toml.m4 +++ b/src/pyproject.toml.m4 @@ -18,5 +18,6 @@ requires = [ numpy \ pkgconfig \ pplpy \ + memory_allocator \ ')] build-backend = "setuptools.build_meta" diff --git a/src/sage/__init__.py b/src/sage/__init__.py index 49098fa7e08..6ea8b846de3 100644 --- a/src/sage/__init__.py +++ b/src/sage/__init__.py @@ -3,11 +3,6 @@ # See https://trac.sagemath.org/ticket/29705 -# IPython calls this when starting up -def load_ipython_extension(*args): - import sage.repl.ipython_extension - sage.repl.ipython_extension.load_ipython_extension(*args) - # Deprecated leftover of monkey-patching inspect.isfunction() to support Cython functions. # We cannot use lazy_import for the deprecation here. diff --git a/src/sage/algebras/affine_nil_temperley_lieb.py b/src/sage/algebras/affine_nil_temperley_lieb.py index 4f38d110e1c..7115271eab9 100644 --- a/src/sage/algebras/affine_nil_temperley_lieb.py +++ b/src/sage/algebras/affine_nil_temperley_lieb.py @@ -11,7 +11,7 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.root_system.weyl_group import WeylGroup from sage.rings.ring import Ring -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.free_module import CombinatorialFreeModule from sage.misc.cachefunc import cached_method diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index dfb3ff479b6..9993f6cda68 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -25,7 +25,7 @@ from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.modules.with_basis.morphism import ModuleMorphismByLinearity from sage.categories.poor_man_map import PoorManMap -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.modules.free_module import FreeModule, FreeModule_generic from sage.matrix.constructor import Matrix from sage.matrix.args import MatrixArgs diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index a5e5404bf9f..87dc61cb7a4 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -92,7 +92,7 @@ from sage.matrix.constructor import matrix from sage.modules.free_module import VectorSpace from sage.modules.free_module_element import vector -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.homset import RingHomset_generic from sage.rings.morphism import RingHomomorphism_im_gens from sage.rings.polynomial.term_order import TermOrder @@ -3327,7 +3327,7 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, sage: AQ.differential() Traceback (most recent call last): ... - TypeError: differential() missing 1 required positional argument: + TypeError: ...differential() missing 1 required positional argument: 'diff' Now we add a differential to ``AQ``:: diff --git a/src/sage/algebras/hall_algebra.py b/src/sage/algebras/hall_algebra.py index 20b8b9c624c..a8ea8d18aff 100644 --- a/src/sage/algebras/hall_algebra.py +++ b/src/sage/algebras/hall_algebra.py @@ -20,7 +20,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.hall_polynomial import hall_polynomial from sage.combinat.sf.sf import SymmetricFunctions -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from functools import cmp_to_key, reduce diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 660699d2a93..023d66931b5 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -26,7 +26,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.realizations import Realizations, Category_realization_of_parent from sage.categories.all import AlgebrasWithBasis, FiniteDimensionalAlgebrasWithBasis, CoxeterGroups -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.arith.all import is_square from sage.combinat.root_system.coxeter_group import CoxeterGroup diff --git a/src/sage/algebras/lie_algebras/free_lie_algebra.py b/src/sage/algebras/lie_algebras/free_lie_algebra.py index 81acd327602..085a83e8120 100644 --- a/src/sage/algebras/lie_algebras/free_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/free_lie_algebra.py @@ -42,7 +42,7 @@ from sage.algebras.lie_algebras.morphism import LieAlgebraHomomorphism_im_gens from sage.misc.superseded import experimental_warning -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class FreeLieBasis_abstract(FinitelyGeneratedLieAlgebra, IndexedGenerators, BindableClass): """ diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index ad1a76d123f..fa683e3ee7f 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -30,7 +30,7 @@ from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElementWrapper, LieAlgebraMatrixWrapper) -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.ring import Ring from sage.matrix.matrix_space import MatrixSpace from sage.sets.family import Family, AbstractFamily diff --git a/src/sage/algebras/lie_algebras/morphism.py b/src/sage/algebras/lie_algebras/morphism.py index 58be66b34d6..6e2fcf200f3 100644 --- a/src/sage/algebras/lie_algebras/morphism.py +++ b/src/sage/algebras/lie_algebras/morphism.py @@ -499,7 +499,7 @@ def __init__(self, on_generators, domain=None, codomain=None, check=True, base_m sage: L.morphism({X: int(1)}) Traceback (most recent call last): ... - TypeError: codomain is not a Lie algebra + TypeError: codomain is not a Lie algebra sage: from sage.algebras.lie_algebras.morphism import LieAlgebraMorphism_from_generators sage: LieAlgebraMorphism_from_generators({ZZ(1): X}) diff --git a/src/sage/algebras/lie_algebras/onsager.py b/src/sage/algebras/lie_algebras/onsager.py index 0368a1a32a0..32bf898f470 100644 --- a/src/sage/algebras/lie_algebras/onsager.py +++ b/src/sage/algebras/lie_algebras/onsager.py @@ -197,7 +197,7 @@ def basis(self): Lazy family (Onsager monomial(i))_{i in Disjoint union of Family (Integer Ring, Positive integers)} """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.positive_integers import PositiveIntegers I = DisjointUnionEnumeratedSets([ZZ, PositiveIntegers()], diff --git a/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py b/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py index a208c5b5c1f..d0d2f0ec4ba 100644 --- a/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +++ b/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py @@ -19,7 +19,7 @@ from sage.misc.cachefunc import cached_method from sage.categories.lie_algebras import LieAlgebras -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.sets.family import Family from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index 90369cc0386..fbf29870f72 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -19,7 +19,7 @@ from sage.misc.cachefunc import cached_method from sage.categories.lie_algebras import LieAlgebras from sage.categories.modules import Modules -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.sets.family import Family from sage.sets.set import Set diff --git a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py index 47a7bb15823..b0e049a0c93 100644 --- a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py @@ -85,7 +85,7 @@ def __init__(self, R, ngens=2, names=None, index_set=None): sage: V = lie_conformal_algebras.BosonicGhosts(QQ) sage: TestSuite(V).run() """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ try: assert (ngens in ZZ and ngens > 0 and ngens % 2 == 0) except AssertionError: diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py index 5606e82fc4d..e2ea7dd3c7c 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py @@ -56,7 +56,7 @@ def T(self,n=1): sage: (L + 2*G.T() + 4*C).T(2) 2*T^(2)L + 12*T^(3)G """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if n not in ZZ or n < 0: raise ValueError("n must be a nonnegative Integer") if n == 0 or self.is_zero(): diff --git a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py index 980f3e1a8d8..3d5a85dddd8 100644 --- a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py @@ -132,7 +132,7 @@ def __init__(self,R,ngens=None, gram_matrix=None, names=None, from sage.matrix.matrix_space import MatrixSpace if ngens: try: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ assert ngens in ZZ and ngens % 2 == 0 except AssertionError: raise ValueError("ngens needs to be an even positive "+ diff --git a/src/sage/algebras/q_system.py b/src/sage/algebras/q_system.py index 8103916d8f1..9f4f9b7367b 100644 --- a/src/sage/algebras/q_system.py +++ b/src/sage/algebras/q_system.py @@ -23,7 +23,7 @@ from sage.misc.misc_c import prod from sage.categories.algebras import Algebras -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.sets.family import Family diff --git a/src/sage/algebras/quantum_groups/fock_space.py b/src/sage/algebras/quantum_groups/fock_space.py index f3703018e02..33e9eb0d686 100644 --- a/src/sage/algebras/quantum_groups/fock_space.py +++ b/src/sage/algebras/quantum_groups/fock_space.py @@ -25,7 +25,7 @@ from sage.categories.modules_with_basis import ModulesWithBasis from sage.categories.realizations import Realizations, Category_realization_of_parent -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.fraction_field import FractionField from sage.rings.finite_rings.integer_mod_ring import IntegerModRing diff --git a/src/sage/algebras/quantum_matrix_coordinate_algebra.py b/src/sage/algebras/quantum_matrix_coordinate_algebra.py index 498aa34811d..f93f147758b 100644 --- a/src/sage/algebras/quantum_matrix_coordinate_algebra.py +++ b/src/sage/algebras/quantum_matrix_coordinate_algebra.py @@ -25,7 +25,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class QuantumMatrixCoordinateAlgebra_abstract(CombinatorialFreeModule): diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index 5aea58d06bf..e97dd879375 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -40,7 +40,7 @@ from sage.rings.integer cimport Integer from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint from sage.rings.number_field.number_field_element cimport NumberFieldElement from sage.rings.all import PolynomialRing -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.libs.gmp.mpz cimport * diff --git a/src/sage/algebras/rational_cherednik_algebra.py b/src/sage/algebras/rational_cherednik_algebra.py index 7d7e9f7929f..880a7112b8e 100644 --- a/src/sage/algebras/rational_cherednik_algebra.py +++ b/src/sage/algebras/rational_cherednik_algebra.py @@ -19,7 +19,7 @@ from sage.sets.family import Family from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.all import QQ +from sage.rings.rational_field import QQ class RationalCherednikAlgebra(CombinatorialFreeModule): diff --git a/src/sage/algebras/yangian.py b/src/sage/algebras/yangian.py index f01eeb93cbe..1d6df948b18 100644 --- a/src/sage/algebras/yangian.py +++ b/src/sage/algebras/yangian.py @@ -22,7 +22,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.sets.family import Family diff --git a/src/sage/algebras/yokonuma_hecke_algebra.py b/src/sage/algebras/yokonuma_hecke_algebra.py index 33c432bef41..976b6e448e9 100644 --- a/src/sage/algebras/yokonuma_hecke_algebra.py +++ b/src/sage/algebras/yokonuma_hecke_algebra.py @@ -18,7 +18,7 @@ from sage.misc.cachefunc import cached_method from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.categories.algebras import Algebras from sage.categories.rings import Rings from sage.combinat.free_module import CombinatorialFreeModule diff --git a/src/sage/all.py b/src/sage/all.py index 4fa89329e81..954b0c0972d 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -41,7 +41,7 @@ Check lazy import of ``interacts``:: sage: type(interacts) - + sage: interacts """ diff --git a/src/sage/arith/functions.pyx b/src/sage/arith/functions.pyx index 74b95dee846..8d1d25528f8 100644 --- a/src/sage/arith/functions.pyx +++ b/src/sage/arith/functions.pyx @@ -145,14 +145,14 @@ cpdef LCM_list(v): sage: w = LCM_list([3,9,30]); w 90 sage: type(w) - + The inputs are converted to Sage integers:: sage: w = LCM_list([int(3), int(9), int(30)]); w 90 sage: type(w) - + TESTS:: diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 039e786aff7..651dfb8917d 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -223,7 +223,7 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, is_complex = isinstance(z, ComplexNumber) n = degree+1 - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix M = matrix(ZZ, n, n+1+int(is_complex)) r = ZZ.one() << prec M[0, 0] = 1 @@ -807,7 +807,7 @@ def prime_powers(start, stop=None): sage: v = prime_powers(10) sage: type(v[0]) - + sage: prime_powers(0,1) [] @@ -1365,9 +1365,9 @@ def random_prime(n, proof=None, lbound=2): TESTS:: sage: type(random_prime(2)) - + sage: type(random_prime(100)) - + sage: random_prime(1, lbound=-2) #caused Sage hang #10112 Traceback (most recent call last): ... @@ -1699,7 +1699,7 @@ def gcd(a, b=None, **kwargs): sage: gcd(3, 6, 2) Traceback (most recent call last): ... - TypeError: gcd() takes ... + TypeError: ...gcd() takes ... sage: gcd([3, 6, 2]) 1 @@ -1715,7 +1715,7 @@ def gcd(a, b=None, **kwargs): sage: gcd([]) 0 sage: type(gcd([])) - + TESTS: @@ -2963,7 +2963,7 @@ class Euler_Phi: sage: euler_phi(0) 0 sage: type(euler_phi(0)) - + We verify directly that the phi function is correct for 21. @@ -3472,22 +3472,22 @@ def binomial(x, m, **kwds): sage: a = binomial(float(1001), float(1)); a 1001.0 sage: type(a) - <... 'float'> + sage: binomial(float(1000), 1001) 0.0 Test more output types:: sage: type(binomial(5r, 2)) - <... 'int'> + sage: type(binomial(5, 2r)) - + sage: type(binomial(5.0r, 2)) - <... 'float'> + sage: type(binomial(5/1, 2)) - + sage: R = Integers(11) sage: b = binomial(R(7), R(3)) @@ -5756,7 +5756,7 @@ def squarefree_divisors(x): sage: a 1 sage: type(a) - + Tests with numpy and gmpy2 numbers:: diff --git a/src/sage/arith/srange.pyx b/src/sage/arith/srange.pyx index ccbfd98cb98..1603b87ca68 100644 --- a/src/sage/arith/srange.pyx +++ b/src/sage/arith/srange.pyx @@ -223,7 +223,7 @@ def srange(*args, **kwds): sage: v = srange(5); v [0, 1, 2, 3, 4] sage: type(v[2]) - + sage: srange(1, 10) [1, 2, 3, 4, 5, 6, 7, 8, 9] sage: srange(10, 1, -1) diff --git a/src/sage/calculus/all.py b/src/sage/calculus/all.py index 1f89c3f7ffe..fe463d63bae 100644 --- a/src/sage/calculus/all.py +++ b/src/sage/calculus/all.py @@ -30,7 +30,7 @@ lazy_import("sage.calculus.riemann",["Riemann_Map"]) lazy_import("sage.calculus.interpolators",["polygon_spline","complex_cubic_spline"]) -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix @@ -51,13 +51,13 @@ def symbolic_expression(x): sage: a = symbolic_expression(3/2); a 3/2 sage: type(a) - + sage: R. = QQ[]; type(x) - + sage: a = symbolic_expression(2*x^2 + 3); a 2*x^2 + 3 sage: type(a) - + sage: from sage.symbolic.expression import is_Expression sage: is_Expression(a) True diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index 80e4a5de019..19966cfb8b6 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -40,7 +40,7 @@ sage: x^2 x^2 sage: type(x) - + More complicated expressions in Sage can be built up using ordinary arithmetic. The following are valid, and follow the rules of Python @@ -1628,8 +1628,11 @@ def laplace(ex, t, s, algorithm='maxima'): sage: laplace(dirac_delta(t), t, s) 1 - sage: laplace(dirac_delta(t), t, s, algorithm='sympy') - (-heaviside(0) + 1, -oo, True) + sage: F, a, cond = laplace(dirac_delta(t), t, s, algorithm='sympy') + sage: a, cond + (-oo, True) + sage: F # random - sympy <1.9 includes undefined heaviside(0) in answer + 1 sage: laplace(dirac_delta(t), t, s, algorithm='giac') 1 diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 0b8668f8521..6a06f755101 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -1,7 +1,7 @@ r""" Calculus functions """ -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix from sage.structure.element import is_Vector from sage.symbolic.ring import is_SymbolicVariable diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 56456173632..7d624bf7528 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -32,7 +32,6 @@ from memory_allocator cimport MemoryAllocator from sage.rings.real_double import RDF from sage.libs.gsl.all cimport * from sage.misc.sageinspect import sage_getargspec -from sage.ext.fast_eval cimport FastDoubleFunc from sage.ext.interpreters.wrapper_rdf cimport Wrapper_rdf from sage.ext.fast_callable import fast_callable @@ -61,9 +60,6 @@ cdef double c_f(double t, void *params): return value -cdef double c_ff(double t, void *params): - return (params)._call_c(&t) - def numerical_integral(func, a, b=None, algorithm='qag', @@ -273,7 +269,7 @@ def numerical_integral(func, a, b=None, cdef gsl_integration_workspace* W W = NULL - if not isinstance(func, FastDoubleFunc): + if True: from sage.rings.infinity import Infinity try: if hasattr(func, 'arguments'): @@ -315,13 +311,10 @@ def numerical_integral(func, a, b=None, else: if ell.is_numeric() and not ell.is_zero(): raise ValueError('integral does not converge at infinity') - func = func._fast_float_(v) + func = fast_callable(func, vars=[v], domain=float) - if isinstance(func, FastDoubleFunc): - F.function = c_ff - F.params = func - elif not isinstance(func, compiled_integrand): + if not isinstance(func, compiled_integrand): wrapper = PyFunctionWrapper() if not func is None: wrapper.the_function = func diff --git a/src/sage/calculus/interpolation.pyx b/src/sage/calculus/interpolation.pyx index b368ea28c50..1c81a072f0e 100644 --- a/src/sage/calculus/interpolation.pyx +++ b/src/sage/calculus/interpolation.pyx @@ -91,7 +91,6 @@ cdef class Spline: Traceback (most recent call last): ... ValueError: Order of derivative must be 1 or 2. - """ def __init__(self, v=[]): """ @@ -100,7 +99,7 @@ cdef class Spline: sage: S = spline([(1,1), (2,3), (4,5)]); S [(1, 1), (2, 3), (4, 5)] sage: type(S) - + """ self.v = list(v) self.started = 0 diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index 5d5d550c7cc..ac59aa2a898 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -30,7 +30,7 @@ from cysignals.signals cimport sig_on, sig_off from sage.misc.decorators import options from sage.plot.all import list_plot, Graphics -from sage.ext.fast_eval import fast_callable +from sage.ext.fast_callable import fast_callable from sage.rings.all import CDF diff --git a/src/sage/calculus/test_sympy.py b/src/sage/calculus/test_sympy.py index 86f93667040..7cf7f3f6bfd 100644 --- a/src/sage/calculus/test_sympy.py +++ b/src/sage/calculus/test_sympy.py @@ -152,7 +152,7 @@ sage: type(t1) sage: type(t2) - + sage: t1, t2 (omega + x, omega + x) sage: e=sympy.sin(var("y"))+sage.all.cos(sympy.Symbol("x")) @@ -162,7 +162,7 @@ sin(y) + cos(x) sage: e=e._sage_() sage: type(e) - + sage: e cos(x) + sin(y) sage: e = sage.all.cos(var("y")**3)**4+var("x")**2 @@ -193,7 +193,7 @@ sage: u = Function('u') sage: n = Symbol('n', integer=True) sage: f = u(n+2) - u(n+1) + u(n)/4 - sage: rsolve(f,u(n)) - 2**(-n)*(C0 + C1*n) + sage: 2**n * rsolve(f,u(n)) + C1*n + C0 """ diff --git a/src/sage/calculus/var.pyx b/src/sage/calculus/var.pyx index 70ec9487868..85359ac098d 100644 --- a/src/sage/calculus/var.pyx +++ b/src/sage/calculus/var.pyx @@ -112,7 +112,7 @@ def var(*args, **kwds): to the symbolic expression ring:: sage: type(theta) - + sage: parent(theta) Symbolic Ring """ diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 59f3ee7ac99..44366e35a84 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -348,9 +348,9 @@ class inheritance from ``C.parent_class``. sage: D.__class__.mro() [, , - , - , - , + , + , + , , , , diff --git a/src/sage/categories/category_singleton.pyx b/src/sage/categories/category_singleton.pyx index c1ba98b6b4a..cf612f9a447 100644 --- a/src/sage/categories/category_singleton.pyx +++ b/src/sage/categories/category_singleton.pyx @@ -218,8 +218,8 @@ class Category_singleton(Category): , , , - , - , + , + , , , , diff --git a/src/sage/categories/covariant_functorial_construction.py b/src/sage/categories/covariant_functorial_construction.py index 8a948f827b4..e9afe0736f4 100644 --- a/src/sage/categories/covariant_functorial_construction.py +++ b/src/sage/categories/covariant_functorial_construction.py @@ -345,11 +345,11 @@ def __classget__(cls, base_category, base_category_class): It also forces the resolution of lazy imports (see :trac:`15648`):: sage: type(Algebras.__dict__["Graded"]) - + sage: Algebras.Graded sage: type(Algebras.__dict__["Graded"]) - + .. TODO:: diff --git a/src/sage/categories/examples/filtered_modules_with_basis.py b/src/sage/categories/examples/filtered_modules_with_basis.py index 56454fe5603..1be62053555 100644 --- a/src/sage/categories/examples/filtered_modules_with_basis.py +++ b/src/sage/categories/examples/filtered_modules_with_basis.py @@ -117,7 +117,7 @@ def degree_on_basis(self, t): sage: A.degree_on_basis(Partition((4,2,1,1,1,1))) 10 sage: type(A.degree_on_basis(Partition((1,1)))) - + """ return t.size() diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 4550e1a2fc0..0374b723a71 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -1,12 +1,12 @@ r""" Examples of a finite dimensional Lie algebra with basis """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.cachefunc import cached_method from sage.sets.family import Family @@ -16,6 +16,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.examples.lie_algebras import LieAlgebraFromAssociative as BaseExample + class AbelianLieAlgebra(Parent, UniqueRepresentation): r""" An example of a finite dimensional Lie algebra with basis: diff --git a/src/sage/categories/examples/graded_modules_with_basis.py b/src/sage/categories/examples/graded_modules_with_basis.py index 35314866ea4..0be39623fa3 100644 --- a/src/sage/categories/examples/graded_modules_with_basis.py +++ b/src/sage/categories/examples/graded_modules_with_basis.py @@ -131,7 +131,7 @@ def degree_on_basis(self, t): sage: A.degree_on_basis(Partition((4,2,1,1,1,1))) 10 sage: type(A.degree_on_basis(Partition((1,1)))) - + """ return t.size() diff --git a/src/sage/categories/examples/infinite_enumerated_sets.py b/src/sage/categories/examples/infinite_enumerated_sets.py index 850bb4385e3..d606c9274da 100644 --- a/src/sage/categories/examples/infinite_enumerated_sets.py +++ b/src/sage/categories/examples/infinite_enumerated_sets.py @@ -1,18 +1,19 @@ """ Examples of infinite enumerated sets """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent import Parent from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.structure.unique_representation import UniqueRepresentation from sage.rings.integer import Integer + class NonNegativeIntegers(UniqueRepresentation, Parent): r""" An example of infinite enumerated set: the non negative integers @@ -31,12 +32,12 @@ class NonNegativeIntegers(UniqueRepresentation, Parent): ... NotImplementedError: cannot list an infinite set sage: NN.element_class - + sage: it = iter(NN) sage: [next(it), next(it), next(it), next(it), next(it)] [0, 1, 2, 3, 4] sage: x = next(it); type(x) - + sage: x.parent() Integer Ring sage: x+3 @@ -176,7 +177,7 @@ def _element_constructor_(self, i): sage: x = NN(42); x 42 sage: type(x) - + sage: x.parent() Integer Ring """ diff --git a/src/sage/categories/examples/semigroups_cython.pyx b/src/sage/categories/examples/semigroups_cython.pyx index 931ce2fdc03..6b6e179bc3a 100644 --- a/src/sage/categories/examples/semigroups_cython.pyx +++ b/src/sage/categories/examples/semigroups_cython.pyx @@ -79,7 +79,7 @@ cdef class LeftZeroSemigroupElement(Element): sage: S = LeftZeroSemigroup() sage: x = S(3) sage: x.__reduce__() - (, + (, (An example of a semigroup: the left zero semigroup, 3)) """ return LeftZeroSemigroupElement, (self._parent, self._value) diff --git a/src/sage/categories/examples/sets_cat.py b/src/sage/categories/examples/sets_cat.py index 5a691d46792..c2fba4de679 100644 --- a/src/sage/categories/examples/sets_cat.py +++ b/src/sage/categories/examples/sets_cat.py @@ -1,12 +1,12 @@ """ Examples of sets """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent import Parent from sage.structure.element import Element @@ -44,7 +44,7 @@ class PrimeNumbers(UniqueRepresentation, Parent): sage: x = P(13); x 13 sage: type(x) - + sage: x.parent() Integer Ring sage: 13 in P @@ -54,7 +54,7 @@ class PrimeNumbers(UniqueRepresentation, Parent): sage: y = x+1; y 14 sage: type(y) - + sage: TestSuite(P).run(verbose=True) running ._test_an_element() . . . pass @@ -334,13 +334,13 @@ class PrimeNumbers_Inherits(PrimeNumbers_Abstract): sage: y = x+1; y 14 sage: type(y) - + sage: y.parent() Integer Ring sage: type(P(13)+P(17)) - + sage: type(P(2)+P(3)) - + sage: z = P.next(x); z 17 @@ -385,9 +385,9 @@ def __init__(self): sage: P = Sets().example("inherits") sage: type(P(13)+P(17)) - + sage: type(P(2)+P(3)) - + """ super(PrimeNumbers_Inherits, self).__init__() self._populate_coercion_lists_(embedding=IntegerRing()) @@ -468,7 +468,7 @@ class PrimeNumbers_Wrapper(PrimeNumbers_Abstract): sage: y = x+1; y 14 sage: type(y) - + sage: z = P.next(x); z 17 @@ -579,7 +579,7 @@ class PrimeNumbers_Facade(PrimeNumbers_Abstract): sage: x = P(13); x 13 sage: type(x) - + sage: x.parent() Integer Ring sage: 13 in P @@ -589,12 +589,12 @@ class PrimeNumbers_Facade(PrimeNumbers_Abstract): sage: y = x+1; y 14 sage: type(y) - + sage: z = P.next(x); z 17 sage: type(z) - + sage: z.parent() Integer Ring diff --git a/src/sage/categories/examples/with_realizations.py b/src/sage/categories/examples/with_realizations.py index f3c9e23845a..d322aba065a 100644 --- a/src/sage/categories/examples/with_realizations.py +++ b/src/sage/categories/examples/with_realizations.py @@ -173,12 +173,12 @@ def __init__(self, R, S): # Initializes the bases and change of bases of ``self`` - F = self.F() - In = self.In() + F = self.F() + In = self.In() Out = self.Out() category = self.Bases() - key = lambda x: self.indices_key(x) + key = self.indices_key In_to_F = In.module_morphism(F.sum_of_monomials * Subsets, codomain=F, category=category, triangular='upper', unitriangular=True, diff --git a/src/sage/categories/finite_complex_reflection_groups.py b/src/sage/categories/finite_complex_reflection_groups.py index 817b762c2ac..bb3df827890 100644 --- a/src/sage/categories/finite_complex_reflection_groups.py +++ b/src/sage/categories/finite_complex_reflection_groups.py @@ -12,7 +12,7 @@ # **************************************************************************** from sage.misc.abstract_method import abstract_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.coxeter_groups import CoxeterGroups diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index c3a5506db8d..c796801944d 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -6,15 +6,15 @@ - Travis Scrimshaw (07-15-2013): Initial implementation """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # # This 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.abstract_method import abstract_method @@ -28,6 +28,7 @@ from sage.sets.family import Family from sage.matrix.constructor import matrix + class FiniteDimensionalLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ Category of finite dimensional Lie algebras with a basis. @@ -196,7 +197,7 @@ def _basis_key(self, x): sage: sl2.indices() {'e1', 'f1', 'h1'} sage: type(sl2.basis().keys()) - + sage: Usl2 = sl2.pbw_basis() sage: Usl2._basis_key(2) 2 diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index 1e4620ab12d..0f423dbb5de 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -124,7 +124,7 @@ def _cardinality_from_iterator(self, *ignored_args, **ignored_kwds): does not do it for us:: sage: type(C._cardinality_from_iterator()) - + We ignore additional inputs since during doctests classes which override ``cardinality()`` call up to the category rather than diff --git a/src/sage/categories/group_algebras.py b/src/sage/categories/group_algebras.py index 3a9ff84ce44..742ba8d9393 100644 --- a/src/sage/categories/group_algebras.py +++ b/src/sage/categories/group_algebras.py @@ -156,7 +156,7 @@ def _latex_(self): sage: latex(A) # indirect doctest \Bold{Z}[\langle (3,4), (1,2) \rangle] """ - from sage.misc.all import latex + from sage.misc.latex import latex return "%s[%s]" % (latex(self.base_ring()), latex(self.group())) def group(self): diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 600572b671b..335cb4af368 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -514,7 +514,7 @@ def free(index_set=None, names=None, **kwds): sage: F. = Groups().Commutative().free(); F Multiplicative Abelian group isomorphic to Z x Z x Z """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if names is not None: if isinstance(names, str): if ',' not in names and index_set in ZZ: diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 2e28f84f1f1..d9a4c21a00d 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -1040,7 +1040,7 @@ def element_class_set_morphism(self): sage: H = Hom(ZZ, ZZ) sage: H.element_class_set_morphism - + """ return self.__make_element_class__(morphism.SetMorphism) diff --git a/src/sage/categories/homsets.py b/src/sage/categories/homsets.py index 5d2952c8bac..182a5929c9a 100644 --- a/src/sage/categories/homsets.py +++ b/src/sage/categories/homsets.py @@ -1,4 +1,4 @@ -## -*- encoding: utf-8 -*- +# -*- encoding: utf-8 -*- r""" Homset categories """ diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index 06bd9f55a17..78c39cd27e1 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -120,9 +120,7 @@ def digraph(self, subset=None, index_set=None): G = Crystals().parent_class.digraph(self, subset, index_set) if have_dot2tex(): def eopt(u_v_label): - if u_v_label[2] == 0: - return {"dir": "back"} - return {} + return {"backward": u_v_label[2] == 0} G.set_latex_options(edge_options=eopt) return G @@ -855,7 +853,7 @@ def one_dimensional_configuration_sum(self, q=None, group_components=True): True """ if q is None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ q = QQ['q'].gens()[0] P0 = self.weight_lattice_realization().classical() B = P0.algebra(q.parent()) diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index a74ab9ee525..c63a7b71639 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -155,7 +155,7 @@ cdef class Map(Element): sage: phi.domain sage: type(phi) - + sage: psi = copy(phi) # indirect doctest sage: psi Composite map: @@ -796,7 +796,7 @@ cdef class Map(Element): sage: f(1/2) # indirect doctest Traceback (most recent call last): ... - NotImplementedError: + NotImplementedError: """ raise NotImplementedError(type(self)) @@ -811,7 +811,7 @@ cdef class Map(Element): sage: f(1/2, 2, foo='bar') # indirect doctest Traceback (most recent call last): ... - NotImplementedError: _call_with_args not overridden to accept arguments for + NotImplementedError: _call_with_args not overridden to accept arguments for """ if not args and not kwds: return self(x) @@ -1185,7 +1185,7 @@ cdef class Map(Element): sage: f.is_surjective() Traceback (most recent call last): ... - NotImplementedError: + NotImplementedError: """ raise NotImplementedError(type(self)) @@ -1278,7 +1278,7 @@ cdef class Map(Element): sage: f = sage.rings.morphism.RingMap(ZZ.Hom(ZZ)) sage: type(f) - + sage: hash(f) == hash(f) True sage: {f: 1}[f] @@ -1310,7 +1310,7 @@ cdef class Section(Map): sage: sf(a) Traceback (most recent call last): ... - NotImplementedError: + NotImplementedError: """ def __init__(self, map): diff --git a/src/sage/categories/primer.py b/src/sage/categories/primer.py index 2149f1d8cb8..f9a8f35252c 100644 --- a/src/sage/categories/primer.py +++ b/src/sage/categories/primer.py @@ -398,7 +398,7 @@ class implements: sage: i = 12 sage: type(i) - + Applying an operation is generally done by *calling a method*:: @@ -408,7 +408,7 @@ class implements: sage: x = var('x') sage: p = 6*x^2 + 12*x + 6 sage: type(p) - + sage: p.factor() 6*(x + 1)^2 @@ -421,7 +421,7 @@ class implements: sage: pZ = ZZ['x'] ( p ) sage: type(pZ) - + sage: pZ.factor() 2 * 3 * (x + 1)^2 diff --git a/src/sage/categories/quotient_fields.py b/src/sage/categories/quotient_fields.py index 7198e394643..41acdaf3735 100644 --- a/src/sage/categories/quotient_fields.py +++ b/src/sage/categories/quotient_fields.py @@ -215,7 +215,7 @@ def lcm(self, other): sage: (1/2).lcm(2) 2 sage: type((1/2).lcm(2)) - + """ P = self.parent() try: diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 49207666782..31da05bd00c 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -454,7 +454,7 @@ def trivial_representation(self, base_ring=None, side="twosided"): as a permutation group over Integer Ring """ if base_ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ base_ring = ZZ from sage.modules.with_basis.representation import TrivialRepresentation return TrivialRepresentation(self, base_ring) @@ -474,7 +474,7 @@ def regular_representation(self, base_ring=None, side="left"): as a permutation group over Integer Ring """ if base_ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ base_ring = ZZ from sage.modules.with_basis.representation import RegularRepresentation return RegularRepresentation(self, base_ring, side) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 7e8cdc95146..fdebfd93799 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -118,10 +118,10 @@ class Sets(Category_singleton): - - - - + + + + @@ -169,18 +169,18 @@ class Sets(Category_singleton): sage: for cl in x.__class__.mro(): print(cl) - - - - - - - - - + + + + + + + + + - - + + @@ -954,7 +954,7 @@ def _element_constructor_(self): sage: A = FreeModule(QQ, 3) sage: A.element_class - + sage: A._element_constructor_ @@ -1710,7 +1710,7 @@ def _sympy_(self): sage: list(sF) [1, 2, 3] sage: from sympy import FiniteSet - sage: FiniteSet.fromiter(sF) + sage: FiniteSet.fromiter(sF) # random - this output format is sympy >= 1.9 FiniteSet(1, 2, 3) sage: RR._sympy_().is_finite_set diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 056e3a51e63..d2450bfb601 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -4088,7 +4088,7 @@ cdef class BinaryCodeClassifier: for j from 0 <= j < B.nrows: temp_basis[j] = permute_word_by_wp(can_lab_inv, temp_basis[j]) from sage.matrix.constructor import matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.groups.perm_gps.permgroup import PermutationGroup from sage.groups.perm_gps.constructor import PermutationGroupElement from sage.interfaces.gap import gap diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index e5b48049d11..c5971d48e9e 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -40,7 +40,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import quadratic_residues, gcd from sage.structure.sequence import Sequence, Sequence_generic diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 7c68023292c..eb50986d29e 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -223,7 +223,7 @@ class should inherit from this class. Also ``AbstractLinearCode`` should never from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.functional import is_even from sage.misc.cachefunc import cached_method from sage.misc.randstate import current_randstate diff --git a/src/sage/coding/self_dual_codes.py b/src/sage/coding/self_dual_codes.py index ca7f80cfc4f..199db9257a7 100644 --- a/src/sage/coding/self_dual_codes.py +++ b/src/sage/coding/self_dual_codes.py @@ -87,7 +87,7 @@ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.matrix.matrix_space import MatrixSpace -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.matrix.constructor import block_diagonal_matrix from sage.rings.integer_ring import ZZ from sage.groups.perm_gps.permgroup import PermutationGroup diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 7dc60852255..057dbfe6e06 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -35,7 +35,7 @@ from sage.misc.classcall_metaclass import ClasscallMetaclass from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.flatten import flatten -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element @@ -45,7 +45,7 @@ from sage.matrix.constructor import matrix from sage.modules.free_module_element import zero_vector from sage.misc.all import cached_method -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import factorial from sage.rings.integer import Integer from sage.combinat.posets.lattices import LatticePoset @@ -848,7 +848,7 @@ def to_dyck_word(self, algorithm): sage: asm.to_dyck_word() Traceback (most recent call last): ... - TypeError: to_dyck_word() ...argument... + TypeError: ...to_dyck_word() ...argument... sage: asm.to_dyck_word(algorithm = 'notamethod') Traceback (most recent call last): ... diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index 2fe7021d9f2..3852aadbe47 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -498,32 +498,32 @@ def _latex_term(self, diagram): sage: R. = ZZ[] sage: B2 = algebras.Blob(2, q, r, s) sage: latex(B2.an_element()) # indirect doctest - 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] - \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] - \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; - \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; - \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; - \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; - \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); - \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); - \end{tikzpicture} - + 3\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] - \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] - \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; - \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; - \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; - \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; - \draw[blue,very thick] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. node[midway,circle,fill,scale=0.6] {} (G--1); - \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); - \end{tikzpicture} - + 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] - \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] - \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; - \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; - \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; - \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; - \draw[blue,very thick] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. node[midway,circle,fill,scale=0.6] {} (G-2); - \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); + 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); + \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); + \end{tikzpicture} + + 3\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \draw[blue,very thick] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. node[midway,circle,fill,scale=0.6] {} (G--1); + \draw[] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. (G-2); + \end{tikzpicture} + + 2\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] + \tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] + \node[vertex] (G-1) at (0.0, 1) [shape = circle, draw] {}; + \node[vertex] (G-2) at (1.5, 1) [shape = circle, draw] {}; + \node[vertex] (G--2) at (1.5, -1) [shape = circle, draw] {}; + \node[vertex] (G--1) at (0.0, -1) [shape = circle, draw] {}; + \draw[blue,very thick] (G-1) .. controls +(0.5, -0.5) and +(-0.5, -0.5) .. node[midway,circle,fill,scale=0.6] {} (G-2); + \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); \end{tikzpicture} """ def edge_options(P): @@ -678,4 +678,3 @@ def product_on_basis(self, top, bot): return self.zero() diagram = self._indices.element_class(self._indices, ret_lists[0], ret_lists[1]) return self._from_dict({diagram: coeff}, remove_zeros=False) - diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 8ce5cc5c1b0..59abf94470f 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -46,7 +46,7 @@ from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import QuiverMutationType_Irreducible, QuiverMutationType_Reducible from sage.combinat.cluster_algebra_quiver.mutation_type import is_mutation_finite from random import randint -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.matrix.all import identity_matrix from sage.matrix.constructor import matrix from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver @@ -1545,7 +1545,7 @@ def g_matrix(self, show_warnings=True): ValueError: Unable to calculate g-vectors. Need to use g vectors. """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix if self._use_g_vec: return copy(self._G) elif self._use_fpolys and self._cluster: # This only calls g_vector when it will not create a loop. @@ -1812,7 +1812,7 @@ def coefficient(self,k): sage: [ S.coefficient(k) for k in range(3) ] [y0, 1/y2, 1/y1] """ - from sage.misc.all import prod + from sage.misc.misc_c import prod if k in self._nlist: k = self._nlist.index(k) @@ -3036,7 +3036,7 @@ def universal_extension(self): "for finite type cluster algebras at a " "bipartite initial cluster") - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix from sage.combinat.root_system.cartan_matrix import CartanMatrix A = 2 - self.b_matrix().apply_map(abs).transpose() diff --git a/src/sage/combinat/cluster_algebra_quiver/interact.py b/src/sage/combinat/cluster_algebra_quiver/interact.py index ec34a97aabe..4e54c64e179 100644 --- a/src/sage/combinat/cluster_algebra_quiver/interact.py +++ b/src/sage/combinat/cluster_algebra_quiver/interact.py @@ -1,5 +1,5 @@ import ipywidgets as widgets -from sage.misc.all import latex +from sage.misc.latex import latex from sage.repl.rich_output.pretty_print import pretty_print from IPython.display import clear_output diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index b819aed8966..ef3eb1e6d5d 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -27,7 +27,7 @@ from sage.graphs.all import Graph, DiGraph from sage.arith.all import binomial, euler_phi from sage.all import prod -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix class QuiverMutationTypeFactory(SageObject): diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index eb139497a52..e291eabd08c 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -19,7 +19,7 @@ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.number_field.number_field import CyclotomicField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class ColoredPermutation(MultiplicativeGroupElement): diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 1b63e315221..d366cc15930 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -156,7 +156,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.libs.all import pari from sage.misc.prandom import randint -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_function from sage.structure.sage_object import SageObject from sage.structure.parent import Parent @@ -1508,19 +1508,19 @@ def __init__(self, parent, *args, **kwds): sage: CombinatorialElement(ZZ) Traceback (most recent call last): ... - TypeError: __init__() takes exactly 2 arguments (1 given) + TypeError: ...__init__() takes exactly 2 arguments (1 given) sage: CombinatorialElement(ZZ, 1, 2) Traceback (most recent call last): ... - TypeError: __init__() takes exactly 2 arguments (3 given) + TypeError: ...__init__() takes exactly 2 arguments (3 given) sage: CombinatorialElement(ZZ, 1, list=2) Traceback (most recent call last): ... - TypeError: __init__() takes exactly 2 arguments (3 given) + TypeError: ...__init__() takes exactly 2 arguments (3 given) sage: CombinatorialElement(ZZ, a=1, b=2) Traceback (most recent call last): ... - TypeError: __init__() takes exactly 2 arguments (3 given) + TypeError: ...__init__() takes exactly 2 arguments (3 given) """ # There should be one "list" argument, which can be given as # positional or keyword argument (in the latter case, the name diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 674c2c96ba2..38152061cd0 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -24,6 +24,8 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +import itertools + from sage.rings.all import ZZ, Integer from sage.arith.all import binomial from .integer_vector import IntegerVectors @@ -421,24 +423,18 @@ def cardinality(self): class Combinations_setk(Combinations_msetk): - def _iterator(self, items, len_items, n): + def _iterator(self, items, n): """ An iterator for all the n-combinations of items. EXAMPLES:: - sage: it = Combinations([1,2,3,4],3)._iterator([1,2,3,4],4,3) + sage: it = Combinations([1,2,3,4],3)._iterator([1,2,3,4],3) sage: list(it) [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]] """ - for i in range(len_items): - v = items[i: i + 1] - if n == 1: - yield v - else: - rest = items[i + 1:] - for c in self._iterator(rest, len_items - i - 1, n - 1): - yield v + c + for combination in itertools.combinations(items, n): + yield list(combination) def _iterator_zero(self): """ @@ -454,8 +450,8 @@ def _iterator_zero(self): def __iter__(self): r""" - Posted by Raymond Hettinger, 2006/03/23, to the Python Cookbook: - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/474124 + Uses Python's :func:`itertools.combinations` to iterate through all + of the combinations. EXAMPLES:: @@ -474,7 +470,7 @@ def __iter__(self): if self.k == 0: return self._iterator_zero() else: - return self._iterator(self.mset, len(self.mset), self.k) + return self._iterator(self.mset, self.k) def list(self): """ diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index 52cdc1010b0..930ae037346 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -36,7 +36,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.sets.finite_enumerated_set import FiniteEnumeratedSet -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from .combinat import CombinatorialElement from sage.categories.cartesian_product import cartesian_product diff --git a/src/sage/combinat/crystals/affine_factorization.py b/src/sage/combinat/crystals/affine_factorization.py index 9b4d2be0a4e..e273a5c09c2 100644 --- a/src/sage/combinat/crystals/affine_factorization.py +++ b/src/sage/combinat/crystals/affine_factorization.py @@ -152,7 +152,7 @@ def __init__(self, w, n, x = None): cartan_type = CartanType(['A',n-1]) self._cartan_type = cartan_type from sage.combinat.sf.sf import SymmetricFunctions - from sage.rings.all import QQ + from sage.rings.rational_field import QQ Sym = SymmetricFunctions(QQ) s = Sym.schur() support = s(w.stanley_symmetric_function()).support() diff --git a/src/sage/combinat/crystals/kac_modules.py b/src/sage/combinat/crystals/kac_modules.py index 51005ec5047..f6244cd4158 100644 --- a/src/sage/combinat/crystals/kac_modules.py +++ b/src/sage/combinat/crystals/kac_modules.py @@ -15,7 +15,7 @@ from sage.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.categories.regular_supercrystals import RegularSuperCrystals from sage.combinat.crystals.tensor_product import CrystalOfTableaux diff --git a/src/sage/combinat/crystals/kirillov_reshetikhin.py b/src/sage/combinat/crystals/kirillov_reshetikhin.py index 2cb25976f54..e3a1767263b 100644 --- a/src/sage/combinat/crystals/kirillov_reshetikhin.py +++ b/src/sage/combinat/crystals/kirillov_reshetikhin.py @@ -31,7 +31,7 @@ from sage.categories.homset import Hom from sage.categories.map import Map from sage.rings.integer import Integer -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.combinat.crystals.affine import (AffineCrystalFromClassical, AffineCrystalFromClassicalElement, AffineCrystalFromClassicalAndPromotion, diff --git a/src/sage/combinat/crystals/littelmann_path.py b/src/sage/combinat/crystals/littelmann_path.py index 187d5fd0b92..4efbef4a0c3 100644 --- a/src/sage/combinat/crystals/littelmann_path.py +++ b/src/sage/combinat/crystals/littelmann_path.py @@ -800,7 +800,7 @@ def one_dimensional_configuration_sum(self, q=None, group_components=True): True """ if q is None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ q = QQ['q'].gens()[0] #P0 = self.weight_lattice_realization().classical() P0 = RootSystem(self.cartan_type().classical()).weight_lattice() diff --git a/src/sage/combinat/crystals/multisegments.py b/src/sage/combinat/crystals/multisegments.py index ca12ef818f4..7db77030117 100644 --- a/src/sage/combinat/crystals/multisegments.py +++ b/src/sage/combinat/crystals/multisegments.py @@ -20,7 +20,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.root_system.cartan_type import CartanType from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class InfinityCrystalOfMultisegments(Parent, UniqueRepresentation): r""" diff --git a/src/sage/combinat/crystals/tensor_product_element.pyx b/src/sage/combinat/crystals/tensor_product_element.pyx index cbc8cce74e3..ed3e688ee56 100644 --- a/src/sage/combinat/crystals/tensor_product_element.pyx +++ b/src/sage/combinat/crystals/tensor_product_element.pyx @@ -36,7 +36,7 @@ from sage.structure.parent cimport Parent from sage.misc.cachefunc import cached_method, cached_in_parent_method from sage.functions.other import ceil from sage.combinat.tableau import Tableau -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ ############################################################################## # Support classes diff --git a/src/sage/combinat/cyclic_sieving_phenomenon.py b/src/sage/combinat/cyclic_sieving_phenomenon.py index e4e64868730..023d123ab94 100644 --- a/src/sage/combinat/cyclic_sieving_phenomenon.py +++ b/src/sage/combinat/cyclic_sieving_phenomenon.py @@ -24,7 +24,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import lcm from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing diff --git a/src/sage/combinat/derangements.py b/src/sage/combinat/derangements.py index 4ad088c9575..d9db2b087e1 100644 --- a/src/sage/combinat/derangements.py +++ b/src/sage/combinat/derangements.py @@ -26,7 +26,7 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.prandom import random, randrange from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.all import ZZ, QQ diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 66f2ef0891d..5d904202fa7 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1136,7 +1136,7 @@ def incidence_matrix(self): [0 1 1 1] """ from sage.matrix.constructor import Matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ A = Matrix(ZZ, self.num_points(), self.num_blocks(), sparse=True) for j, b in enumerate(self._blocks): for i in b: diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 07aa49ffacc..05e4ab5fd25 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -40,7 +40,7 @@ from sage.matrix.constructor import matrix from sage.arith.all import factorial from sage.rings.integer import Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod # edges of a fpl in terms of the six vertex possible configurations R = (1, 0) diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index a7c245f13ea..4cd334ceaf6 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -45,11 +45,11 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.cachefunc import cached_method from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.partition import Partitions from sage.combinat.tableau import Tableau, SemistandardTableaux from sage.combinat.combinatorial_map import combinatorial_map -from sage.misc.all import prod +from sage.misc.misc_c import prod class GelfandTsetlinPattern(ClonableArray, diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index ace55dd1709..c92608b002c 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -1823,8 +1823,7 @@ def P_graph(self, n): return D else: return Poset(([w for k in range(n) for w in self.vertices(k)], - lambda x, y: self.is_P_edge(x, y)), - cover_relations=True) + self.is_P_edge), cover_relations=True) def Q_graph(self, n): r""" @@ -1843,22 +1842,22 @@ def Q_graph(self, n): [[1, 1, 1, 1], [3, 1], [2, 2]] """ if self.has_multiple_edges: - D = DiGraph([(x,y,e) for k in range(n-1) - for x in self.vertices(k) - for y in self.vertices(k+1) - for e in self.is_Q_edge(x, y)], multiedges=True) + D = DiGraph([(x, y, e) for k in range(n - 1) + for x in self.vertices(k) + for y in self.vertices(k + 1) + for e in self.is_Q_edge(x, y)], multiedges=True) # unfortunately, layout_acyclic will not show multiple edges # D.layout_default = D.layout_acyclic return D else: return Poset(([w for k in range(n) for w in self.vertices(k)], - lambda x,y: self.is_Q_edge(x, y)), - cover_relations=True) + self.is_Q_edge), cover_relations=True) ###################################################################### # Specific rules of growth diagrams ###################################################################### + class RuleShiftedShapes(Rule): r""" A class modelling the Schensted correspondence for shifted diff --git a/src/sage/combinat/hall_polynomial.py b/src/sage/combinat/hall_polynomial.py index 575087d7335..cd540de429c 100644 --- a/src/sage/combinat/hall_polynomial.py +++ b/src/sage/combinat/hall_polynomial.py @@ -16,8 +16,8 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod -from sage.rings.all import ZZ +from sage.misc.misc_c import prod +from sage.rings.integer_ring import ZZ from sage.combinat.partition import Partition from sage.combinat.q_analogues import q_binomial diff --git a/src/sage/combinat/integer_lists/nn.py b/src/sage/combinat/integer_lists/nn.py index 24f58de9635..4329c6164d9 100644 --- a/src/sage/combinat/integer_lists/nn.py +++ b/src/sage/combinat/integer_lists/nn.py @@ -3,6 +3,7 @@ from sage.rings.semirings.non_negative_integer_semiring import NN from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets + def IntegerListsNN(**kwds): """ Lists of nonnegative integers with constraints. diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index 6f785645b63..ea9be362fdc 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -42,7 +42,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.rings.infinity import PlusInfinity from sage.arith.all import binomial -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.semirings.all import NN from sage.rings.integer import Integer diff --git a/src/sage/combinat/integer_vector_weighted.py b/src/sage/combinat/integer_vector_weighted.py index 3f1e52c0a09..8f1b68ffe85 100644 --- a/src/sage/combinat/integer_vector_weighted.py +++ b/src/sage/combinat/integer_vector_weighted.py @@ -22,7 +22,7 @@ from sage.categories.sets_with_grading import SetsWithGrading from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.rings.integer import Integer -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.integer_vector import IntegerVector from sage.combinat.words.word import Word from sage.combinat.permutation import Permutation diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 7709195e447..ed2de3bd9ce 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -30,8 +30,8 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations from collections.abc import Iterator -from typing import List, Tuple, Union, NewType from sage.categories.enumerated_sets import EnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -60,9 +60,6 @@ from sage.graphs.digraph import DiGraph -TIP = NewType('TIP', 'TamariIntervalPoset') - - class TamariIntervalPoset(Element, metaclass=InheritComparisonClasscallMetaclass): r""" @@ -540,7 +537,7 @@ def draw_decreasing(i, j) -> str: return start + nodes + relations + end - def poset(self): + def poset(self) -> Poset: r""" Return ``self`` as a labelled poset. @@ -598,7 +595,7 @@ def _mul_(self, other: TIP) -> TIP: for i, j in other._poset.cover_relations_iterator()]) P = FinitePoset(DiGraph([list(range(1, n + m + 1)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore def __hash__(self): """ @@ -613,7 +610,7 @@ def __hash__(self): return hash(pair) @cached_method - def increasing_cover_relations(self) -> List[Tuple[int, int]]: + def increasing_cover_relations(self) -> list[tuple[int, int]]: r""" Return the cover relations of the initial forest of ``self``. @@ -721,7 +718,7 @@ def increasing_children(self, v) -> list: root = i return children - def increasing_parent(self, v) -> Union[None, int]: + def increasing_parent(self, v) -> None | int: r""" Return the vertex parent of ``v`` in the initial forest of ``self``. @@ -754,7 +751,7 @@ def increasing_parent(self, v) -> Union[None, int]: return parent @cached_method - def decreasing_cover_relations(self) -> List[Tuple[int, int]]: + def decreasing_cover_relations(self) -> list[tuple[int, int]]: r""" Return the cover relations of the final forest of ``self``. @@ -857,7 +854,7 @@ def decreasing_children(self, v) -> list: root = i return children - def decreasing_parent(self, v) -> Union[None, int]: + def decreasing_parent(self, v) -> None | int: r""" Return the vertex parent of ``v`` in the final forest of ``self``. @@ -981,7 +978,7 @@ def size(self) -> Integer: return self._size @cached_method - def cubical_coordinates(self) -> Tuple[int, ...]: + def cubical_coordinates(self) -> tuple[int, ...]: """ Return the cubical coordinates of ``self``. @@ -1061,7 +1058,7 @@ def complement(self) -> TIP: for i, j in self._poset.cover_relations_iterator()] P = FinitePoset(DiGraph([list(range(1, N)), new_covers], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore def left_branch_involution(self) -> TIP: """ @@ -1713,7 +1710,7 @@ def initial_forest(self) -> TIP: relations = self.increasing_cover_relations() P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore def final_forest(self) -> TIP: r""" @@ -1733,7 +1730,7 @@ def final_forest(self) -> TIP: relations = self.decreasing_cover_relations() P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore def is_initial_interval(self) -> bool: r""" @@ -1972,14 +1969,14 @@ class of ``self.lower_binary_tree()`` and is a 312-avoiding self.decreasing_cover_relations()], format='vertices_and_edges') - def add(perm: List, i): + def add(perm: list, i): r""" Internal recursive method to compute the min linear extension. """ for j in sorted(final_forest.neighbors_in(i)): add(perm, j) perm.append(i) - perm = [] + perm: list[int] = [] for i in sorted(final_forest.sinks()): add(perm, i) return Permutation(perm) @@ -2022,14 +2019,14 @@ class of ``self.upper_binary_tree()`` and is a 132-avoiding self.increasing_cover_relations()], format='vertices_and_edges') - def add(perm: List, i): + def add(perm: list, i): r""" Internal recursive method to compute the max linear extension. """ for j in sorted(initial_forest.neighbors_in(i), reverse=True): add(perm, j) perm.append(i) - perm = [] + perm: list[int] = [] for i in sorted(initial_forest.sinks(), reverse=True): add(perm, i) return Permutation(perm) @@ -2289,7 +2286,7 @@ def maximal_chain_dyck_words(self) -> Iterator: for it in self.maximal_chain_tamari_intervals(): yield it.lower_dyck_word() - def tamari_inversions(self) -> List[Tuple[int, int]]: + def tamari_inversions(self) -> list[tuple[int, int]]: r""" Return the Tamari inversions of ``self``. @@ -2440,7 +2437,7 @@ def number_of_new_components(self) -> Integer: t_up = self.upper_binary_tree().to_tilting() return sum(1 for p in t_low if p in t_up) - def new_decomposition(self) -> List[TIP]: + def new_decomposition(self) -> list[TIP]: """ Return the decomposition of the interval-poset into new interval-posets. @@ -2508,7 +2505,7 @@ def extract_tree(x, y, tilt, common): extract_tree(cx, cy, t_up, common)) for cx, cy in common] - def decomposition_to_triple(self) -> Union[None, Tuple[TIP, TIP, int]]: + def decomposition_to_triple(self) -> None | tuple[TIP, TIP, int]: """ Decompose an interval-poset into a triple (``left``, ``right``, ``r``). @@ -2571,7 +2568,9 @@ def grafting_tree(self): n = self.size() if n == 0: return LabelledBinaryTree(None) - left, right, r = self.decomposition_to_triple() + triplet = self.decomposition_to_triple() + assert triplet is not None + left, right, r = triplet return LabelledBinaryTree([left.grafting_tree(), right.grafting_tree()], label=r) @@ -3047,7 +3046,7 @@ def get_relations(bt, start=1): roots, relations, index = get_relations(binary_tree) P = FinitePoset(DiGraph([list(range(1, index)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore @staticmethod def initial_forest(element): @@ -3155,7 +3154,7 @@ def get_relations(bt, start=1): roots, relations, index = get_relations(binary_tree) P = FinitePoset(DiGraph([list(range(1, index)), relations], format='vertices_and_edges')) - return TamariIntervalPoset(P, check=False) + return TamariIntervalPoset(P, check=False) # type:ignore @staticmethod def from_binary_trees(tree1, tree2) -> TIP: @@ -3619,6 +3618,9 @@ def __contains__(self, x) -> bool: Element = TamariIntervalPoset +TIP = TamariIntervalPoset + + ################################################################# # Enumerated set of Tamari interval-posets of a given size ################################################################# diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 005f3504456..1e9e57b8d86 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -39,7 +39,7 @@ from sage.combinat.partition import Partition, Partitions from sage.combinat.root_system.weyl_group import WeylGroup from sage.combinat.core import Core -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.functions.generalized import sgn from sage.misc.flatten import flatten from sage.combinat.skew_partition import SkewPartition diff --git a/src/sage/combinat/matrices/latin.py b/src/sage/combinat/matrices/latin.py index 765b2065cae..367facaa301 100644 --- a/src/sage/combinat/matrices/latin.py +++ b/src/sage/combinat/matrices/latin.py @@ -129,8 +129,8 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.matrix.all import matrix -from sage.rings.all import ZZ +from sage.matrix.constructor import matrix +from sage.rings.integer_ring import ZZ from sage.rings.all import Integer from sage.matrix.matrix_integer_dense import Matrix_integer_dense from sage.groups.perm_gps.permgroup_element import PermutationGroupElement diff --git a/src/sage/combinat/misc.py b/src/sage/combinat/misc.py index 6a17f46d24c..d3bdbccf03a 100644 --- a/src/sage/combinat/misc.py +++ b/src/sage/combinat/misc.py @@ -16,7 +16,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod class DoublyLinkedList(): """ diff --git a/src/sage/combinat/ncsf_qsym/combinatorics.py b/src/sage/combinat/ncsf_qsym/combinatorics.py index e3662ff2912..35a2cc1eb7b 100644 --- a/src/sage/combinat/ncsf_qsym/combinatorics.py +++ b/src/sage/combinat/ncsf_qsym/combinatorics.py @@ -21,7 +21,7 @@ from sage.misc.cachefunc import cached_function from sage.combinat.composition import Composition, Compositions from sage.combinat.composition_tableau import CompositionTableaux -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ # The following might call for defining a morphism from ``structure diff --git a/src/sage/combinat/ncsf_qsym/ncsf.py b/src/sage/combinat/ncsf_qsym/ncsf.py index 2ab7a4c8f44..f145ecde76d 100644 --- a/src/sage/combinat/ncsf_qsym/ncsf.py +++ b/src/sage/combinat/ncsf_qsym/ncsf.py @@ -5013,7 +5013,7 @@ def _to_complete_transition_matrix(self, n): return (matrix([[]]), []) CO = compositions_order(n) # ZZ is faster than over QQ for inverting a matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ MS = MatrixSpace(ZZ, len(CO)) return (MS([[number_of_SSRCT(al,be) for be in CO] for al in CO]).inverse(), CO) diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index f76f1891ad3..3a46c666078 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -2897,7 +2897,7 @@ def _from_monomial_transition_matrix(self, n): return (matrix([[]]), []) CO = compositions_order(n) # ZZ is faster than over QQ for inverting a matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ MS = MatrixSpace(ZZ, len(CO)) M = MS([[number_of_SSRCT(al, be) for al in CO] for be in CO]) return (M.inverse_of_unit(), CO) diff --git a/src/sage/combinat/ncsf_qsym/tutorial.py b/src/sage/combinat/ncsf_qsym/tutorial.py index ac452cdb142..6236a3ba2af 100644 --- a/src/sage/combinat/ncsf_qsym/tutorial.py +++ b/src/sage/combinat/ncsf_qsym/tutorial.py @@ -132,7 +132,7 @@ sage: M[] Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... Working with symmetric functions diff --git a/src/sage/combinat/ncsym/ncsym.py b/src/sage/combinat/ncsym/ncsym.py index 95c46b177be..1a5caa8f2e7 100644 --- a/src/sage/combinat/ncsym/ncsym.py +++ b/src/sage/combinat/ncsym/ncsym.py @@ -29,7 +29,7 @@ from sage.combinat.sf.sf import SymmetricFunctions from sage.matrix.matrix_space import MatrixSpace from sage.sets.set import Set -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from functools import reduce def matchings(A, B): diff --git a/src/sage/combinat/necklace.py b/src/sage/combinat/necklace.py index 475433bf44d..bbfb5c215d2 100644 --- a/src/sage/combinat/necklace.py +++ b/src/sage/combinat/necklace.py @@ -29,7 +29,7 @@ from sage.arith.all import euler_phi, factorial, divisors, gcd from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.combinat.misc import DoublyLinkedList diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 12b264a43cc..c85dcf8b4d9 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -296,7 +296,7 @@ lazy_import('sage.combinat.skew_partition', 'SkewPartition') lazy_import('sage.combinat.partition_tuple', 'PartitionTuple') -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.prandom import randrange from sage.misc.cachefunc import cached_method, cached_function @@ -6655,9 +6655,15 @@ def __iter__(self): sage: [x for x in Partitions(4)] [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] + + TESTS:: + + sage: all(isinstance(i, Integer) for p in Partitions(4) for i in p) + True + """ for p in ZS1_iterator(self.n): - yield self.element_class(self, p) + yield self.element_class(self, [Integer(i) for i in p]) def subset(self, **kwargs): r""" @@ -6787,10 +6793,17 @@ def __iter__(self): ....: == number_of_partitions_length(n, k) ....: for n in range(9) for k in range(n+2) ) True + + TESTS:: + + sage: partitions = Partitions(9, length=3) + sage: all(isinstance(i, Integer) for p in partitions for i in p) + True + """ for p in ZS1_iterator_nk(self.n - self.k, self.k): - v = [i + 1 for i in p] - adds = [1] * (self.k - len(v)) + v = [Integer(i + 1) for i in p] + adds = [Integer(1)] * (self.k - len(v)) yield self.element_class(self, v + adds) def cardinality(self, algorithm='hybrid'): diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 19c0f6a5382..72947e020a1 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -706,7 +706,7 @@ def size(self) -> Integer: return len(self) grade = size # for the category SetsWithGrading() - + def cycle_string(self, singletons=False) -> str: """ Return a string of the permutation in cycle notation. diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 0675a1000c4..52d7897b498 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -31,7 +31,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.posets.posets import Poset from sage.rings.integer import Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.combinat.tableau import Tableau from sage.plot.plot3d.platonic import cube diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index 024ae3c8644..22cf011fba8 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -1993,7 +1993,7 @@ def join(L): elems = [e for e in H.order_ideal([j]) if e not in too_close] achains = PairwiseCompatibleSubsets(elems, - lambda x, y: H.are_incomparable(x, y)) + H.are_incomparable) achains_n = achains.elements_of_depth_iterator(B) for A in achains_n: @@ -3347,7 +3347,7 @@ def sublattices_lattice(self, labels='lattice'): return L.canonical_label() L = L.relabel(lambda x: tuple(self._vertex_to_element(y) for y in x)) if labels == 'lattice': - return L.relabel(lambda x: self.sublattice(x)) + return L.relabel(self.sublattice) return L def isomorphic_sublattices_iterator(self, other): @@ -4934,7 +4934,7 @@ def congruences_lattice(self, labels='congruence'): for e in L: low = L.lower_covers(e) if len(low) == 1: # a join-irreducible element - C[e] = congs[max(e, key=lambda x: cong_ji._element_to_vertex(x))] + C[e] = congs[max(e, key=cong_ji._element_to_vertex)] if len(low) > 1: # "extending" congruence to avoid re-computation low_0 = min(low, key=lambda x: C[x].number_of_subsets()) for new_pair in e: diff --git a/src/sage/combinat/posets/mobile.py b/src/sage/combinat/posets/mobile.py index b98696faf93..e059a2ed0f1 100644 --- a/src/sage/combinat/posets/mobile.py +++ b/src/sage/combinat/posets/mobile.py @@ -143,7 +143,7 @@ def _anchor(self): sage: M._anchor (4, 3) """ - ribbon = list(map(lambda x: self._element_to_vertex(x), self._ribbon)) + ribbon = [self._element_to_vertex(x) for x in self._ribbon] H = self._hasse_diagram R = H.subgraph(ribbon) diff --git a/src/sage/combinat/posets/moebius_algebra.py b/src/sage/combinat/posets/moebius_algebra.py index 539548bd55c..9ed121e66c2 100644 --- a/src/sage/combinat/posets/moebius_algebra.py +++ b/src/sage/combinat/posets/moebius_algebra.py @@ -26,7 +26,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.free_module import CombinatorialFreeModule from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class BasisAbstract(CombinatorialFreeModule, BindableClass): diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index 7913c50f7df..962f354c236 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -1599,7 +1599,7 @@ def YoungFibonacci(n): current_level = new_level D = DiGraph([[], covers], format='vertices_and_edges') - D.relabel(lambda v: Word(v), inplace=True) + D.relabel(Word, inplace=True) return FiniteMeetSemilattice(hasse_diagram=D, category=FinitePosets()) @staticmethod diff --git a/src/sage/combinat/q_analogues.py b/src/sage/combinat/q_analogues.py index b7b206fd1cd..10333aaa455 100644 --- a/src/sage/combinat/q_analogues.py +++ b/src/sage/combinat/q_analogues.py @@ -15,9 +15,9 @@ from sage.misc.cachefunc import cached_function -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.structure.element import parent -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.dyck_word import DyckWords from sage.combinat.partition import _Partitions diff --git a/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py b/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py index 50533fbc842..57a17f31e83 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py +++ b/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py @@ -39,7 +39,7 @@ from sage.combinat.rigged_configurations.bij_type_C import RCToKRTBijectionTypeC from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA -from sage.rings.all import QQ +from sage.rings.rational_field import QQ class KRTToRCBijectionTypeA2Dual(KRTToRCBijectionTypeC): r""" diff --git a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py index efbe5b1b368..4a64e2c31f7 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py +++ b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py @@ -448,7 +448,7 @@ def _ascii_art_(self): if Partitions.options.convention == "French": baseline = lambda s: 0 else: - baseline = lambda s: len(s) + baseline = len from sage.typeset.ascii_art import AsciiArt s = repr(self[0]).splitlines() ret = AsciiArt(s, baseline=baseline(s)) diff --git a/src/sage/combinat/rigged_configurations/rigged_configurations.py b/src/sage/combinat/rigged_configurations/rigged_configurations.py index c16b92649ee..702be558013 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configurations.py +++ b/src/sage/combinat/rigged_configurations/rigged_configurations.py @@ -30,7 +30,7 @@ from sage.structure.parent import Parent from sage.combinat.misc import IterableFunctionCall import sage.combinat.tableau as tableau -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.categories.loop_crystals import KirillovReshetikhinCrystals from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.rigged_configurations.kleber_tree import KleberTree, VirtualKleberTree diff --git a/src/sage/combinat/root_system/branching_rules.py b/src/sage/combinat/root_system/branching_rules.py index ded9b53460b..4947d1357db 100644 --- a/src/sage/combinat/root_system/branching_rules.py +++ b/src/sage/combinat/root_system/branching_rules.py @@ -15,7 +15,7 @@ from sage.structure.sage_object import SageObject from sage.combinat.root_system.cartan_type import CartanType from sage.modules.free_module_element import vector -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.misc.functional import is_even, is_odd diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index 0a02a262f7c..2bffa360060 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -34,7 +34,7 @@ from sage.misc.classcall_metaclass import typecall from sage.misc.misc import powerset from sage.matrix.matrix_integer_sparse import Matrix_integer_sparse -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract from sage.combinat.root_system.root_system import RootSystem from sage.sets.family import Family @@ -490,7 +490,7 @@ def symmetrizer(self): # The result from is_symmetrizable needs to be scaled # to integer coefficients from sage.arith.all import LCM - from sage.rings.all import QQ + from sage.rings.rational_field import QQ scalar = LCM([QQ(x).denominator() for x in sym]) return Family( {iset[i]: ZZ(val*scalar) for i, val in enumerate(sym)} ) diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 8cc8bafa19e..ea50c75079e 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -479,7 +479,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.abstract_method import abstract_method from sage.misc.lazy_import import LazyImport -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.infinity import Infinity from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation diff --git a/src/sage/combinat/root_system/extended_affine_weyl_group.py b/src/sage/combinat/root_system/extended_affine_weyl_group.py index 82ee907e1b5..874aa191690 100644 --- a/src/sage/combinat/root_system/extended_affine_weyl_group.py +++ b/src/sage/combinat/root_system/extended_affine_weyl_group.py @@ -585,16 +585,16 @@ def __init__(self, cartan_type, general_linear, **print_options): # coercions between realizations - W0P_to_PW0 = SetMorphism(Hom(W0P, PW0, Groups()),lambda x: PW0(x.to_opposite())) + W0P_to_PW0 = SetMorphism(Hom(W0P, PW0, Groups()), lambda x: PW0(x.to_opposite())) W0P_to_PW0.register_as_coercion() - PW0_to_W0P = SetMorphism(Hom(PW0, W0P, Groups()),lambda x: W0P(x.to_opposite())) + PW0_to_W0P = SetMorphism(Hom(PW0, W0P, Groups()), lambda x: W0P(x.to_opposite())) PW0_to_W0P.register_as_coercion() - FW_to_WF = SetMorphism(Hom(FW, WF, Groups()),lambda x: WF(x.to_opposite())) + FW_to_WF = SetMorphism(Hom(FW, WF, Groups()), lambda x: WF(x.to_opposite())) FW_to_WF.register_as_coercion() - WF_to_FW = SetMorphism(Hom(WF, FW, Groups()),lambda x: FW(x.to_opposite())) + WF_to_FW = SetMorphism(Hom(WF, FW, Groups()), lambda x: FW(x.to_opposite())) WF_to_FW.register_as_coercion() PW0_to_WF = SetMorphism(Hom(PW0, WF, Groups()), self.PW0_to_WF_func) @@ -602,9 +602,9 @@ def __init__(self, cartan_type, general_linear, **print_options): WF_to_PW0 = SetMorphism(Hom(WF, PW0, Groups()), self.WF_to_PW0_func) WF_to_PW0.register_as_coercion() - PvW0_to_W0Pv = SetMorphism(Hom(PvW0, W0Pv, Groups()),lambda x: W0Pv(x.to_opposite())) + PvW0_to_W0Pv = SetMorphism(Hom(PvW0, W0Pv, Groups()), lambda x: W0Pv(x.to_opposite())) PvW0_to_W0Pv.register_as_coercion() - W0Pv_to_PvW0 = SetMorphism(Hom(W0Pv, PvW0, Groups()),lambda x: PvW0(x.to_opposite())) + W0Pv_to_PvW0 = SetMorphism(Hom(W0Pv, PvW0, Groups()), lambda x: PvW0(x.to_opposite())) W0Pv_to_PvW0.register_as_coercion() if self._general_linear: @@ -629,39 +629,39 @@ def __init__(self, cartan_type, general_linear, **print_options): W0Pv_to_W0P.register_as_coercion() # coercions of the translation lattice into the appropriate realizations - P_to_PW0 = SetMorphism(Hom(self.lattice(), PW0, Sets()), lambda x: PW0.from_translation(x)) + P_to_PW0 = SetMorphism(Hom(self.lattice(), PW0, Sets()), PW0.from_translation) P_to_PW0.register_as_coercion() - P_to_W0P = SetMorphism(Hom(self.lattice(), W0P, Sets()), lambda x: W0P.from_translation(x)) + P_to_W0P = SetMorphism(Hom(self.lattice(), W0P, Sets()), W0P.from_translation) P_to_W0P.register_as_coercion() - Pv_to_PvW0 = SetMorphism(Hom(self.dual_lattice(), PvW0, Sets()), lambda x: PvW0.from_dual_translation(x)) + Pv_to_PvW0 = SetMorphism(Hom(self.dual_lattice(), PvW0, Sets()), PvW0.from_dual_translation) Pv_to_PvW0.register_as_coercion() - Pv_to_W0Pv = SetMorphism(Hom(self.dual_lattice(), W0Pv, Sets()), lambda x: W0Pv.from_dual_translation(x)) + Pv_to_W0Pv = SetMorphism(Hom(self.dual_lattice(), W0Pv, Sets()), W0Pv.from_dual_translation) Pv_to_W0Pv.register_as_coercion() # coercions of the classical Weyl group into the appropriate realizations - W0_to_PW0 = SetMorphism(Hom(self.classical_weyl(), PW0, Groups()), lambda x: PW0.from_classical_weyl(x)) + W0_to_PW0 = SetMorphism(Hom(self.classical_weyl(), PW0, Groups()), PW0.from_classical_weyl) W0_to_PW0.register_as_coercion() - W0_to_W0P = SetMorphism(Hom(self.classical_weyl(), W0P, Groups()), lambda x: W0P.from_classical_weyl(x)) + W0_to_W0P = SetMorphism(Hom(self.classical_weyl(), W0P, Groups()), W0P.from_classical_weyl) W0_to_W0P.register_as_coercion() - W0v_to_PvW0 = SetMorphism(Hom(self.dual_classical_weyl(), PvW0, Groups()), lambda x: PvW0.from_dual_classical_weyl(x)) + W0v_to_PvW0 = SetMorphism(Hom(self.dual_classical_weyl(), PvW0, Groups()), PvW0.from_dual_classical_weyl) W0v_to_PvW0.register_as_coercion() - W0v_to_W0Pv = SetMorphism(Hom(self.dual_classical_weyl(), W0Pv, Groups()), lambda x: W0Pv.from_dual_classical_weyl(x)) + W0v_to_W0Pv = SetMorphism(Hom(self.dual_classical_weyl(), W0Pv, Groups()), W0Pv.from_dual_classical_weyl) W0v_to_W0Pv.register_as_coercion() # coercions of the fundamental group into the appropriate realizations - F_to_WF = SetMorphism(Hom(self.fundamental_group(), WF, Groups()), lambda x: WF.from_fundamental(x)) + F_to_WF = SetMorphism(Hom(self.fundamental_group(), WF, Groups()), WF.from_fundamental) F_to_WF.register_as_coercion() - F_to_FW = SetMorphism(Hom(self.fundamental_group(), FW, Groups()), lambda x: FW.from_fundamental(x)) + F_to_FW = SetMorphism(Hom(self.fundamental_group(), FW, Groups()), FW.from_fundamental) F_to_FW.register_as_coercion() # coercions of the affine Weyl group into the appropriate realizations - W_to_WF = SetMorphism(Hom(self.affine_weyl(), WF, Groups()), lambda x: WF.from_affine_weyl(x)) + W_to_WF = SetMorphism(Hom(self.affine_weyl(), WF, Groups()), WF.from_affine_weyl) W_to_WF.register_as_coercion() - W_to_FW = SetMorphism(Hom(self.affine_weyl(), FW, Groups()), lambda x: FW.from_affine_weyl(x)) + W_to_FW = SetMorphism(Hom(self.affine_weyl(), FW, Groups()), FW.from_affine_weyl) W_to_FW.register_as_coercion() def PW0(self): @@ -2041,7 +2041,7 @@ def simple_reflections(self): sage: ExtendedAffineWeylGroup("A3").PW0().simple_reflections() Finite family {0: t[Lambdacheck[1] + Lambdacheck[3]] * s1*s2*s3*s2*s1, 1: s1, 2: s2, 3: s3} """ - return Family(self.realization_of().cartan_type().index_set(), lambda i: self.simple_reflection(i)) + return Family(self.realization_of().cartan_type().index_set(), self.simple_reflection) def from_classical_weyl(self, w): r""" @@ -2202,7 +2202,7 @@ def simple_reflections(self): sage: ExtendedAffineWeylGroup(["A",3,1]).W0P().simple_reflections() Finite family {0: s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]], 1: s1, 2: s2, 3: s3} """ - return Family(self.realization_of().cartan_type().index_set(), lambda i: self.simple_reflection(i)) + return Family(self.realization_of().cartan_type().index_set(), self.simple_reflection) def from_classical_weyl(self, w): r""" diff --git a/src/sage/combinat/root_system/fundamental_group.py b/src/sage/combinat/root_system/fundamental_group.py index 7c097ad7fe3..0f378d7e510 100644 --- a/src/sage/combinat/root_system/fundamental_group.py +++ b/src/sage/combinat/root_system/fundamental_group.py @@ -503,7 +503,7 @@ def group_generators(self): sage: FundamentalGroupOfExtendedAffineWeylGroup(['E',6,1],prefix="f").group_generators() Finite family {0: f[0], 1: f[1], 6: f[6]} """ - return Family(self.special_nodes(), lambda i: self(i)) + return Family(self.special_nodes(), self) def __iter__(self): r""" diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 080bbf21971..de677e03deb 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -14,7 +14,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.category_object import CategoryObject from sage.categories.modules import Modules -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.all import cached_method from sage.matrix.constructor import Matrix from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index ac27b0e073f..310e9f5305b 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -46,7 +46,7 @@ from sage.misc.cachefunc import cached_function, cached_method, cached_in_parent_method from sage.combinat.root_system.cartan_type import CartanType, CartanType_abstract -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.interfaces.gap3 import gap3 from sage.combinat.root_system.reflection_group_complex import ComplexReflectionGroup, IrreducibleComplexReflectionGroup from sage.misc.sage_eval import sage_eval diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index 46215563e3d..42709ef1847 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -9,7 +9,7 @@ #***************************************************************************** from sage.misc.cachefunc import cached_method, cached_in_parent_method -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.free_module import CombinatorialFreeModule from .root_lattice_realizations import RootLatticeRealizations import functools diff --git a/src/sage/combinat/root_system/type_A.py b/src/sage/combinat/root_system/type_A.py index f76cf3e9cbe..ef014e05d66 100644 --- a/src/sage/combinat/root_system/type_A.py +++ b/src/sage/combinat/root_system/type_A.py @@ -10,7 +10,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.root_system.root_lattice_realizations import RootLatticeRealizations from . import ambient_space diff --git a/src/sage/combinat/root_system/type_E.py b/src/sage/combinat/root_system/type_E.py index 7c910ecab6d..5c49a148806 100644 --- a/src/sage/combinat/root_system/type_E.py +++ b/src/sage/combinat/root_system/type_E.py @@ -12,7 +12,7 @@ # **************************************************************************** from . import ambient_space -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.family import Family class AmbientSpace(ambient_space.AmbientSpace): diff --git a/src/sage/combinat/root_system/type_F.py b/src/sage/combinat/root_system/type_F.py index f7b9dbcf667..744ef0547bb 100644 --- a/src/sage/combinat/root_system/type_F.py +++ b/src/sage/combinat/root_system/type_F.py @@ -12,7 +12,7 @@ # **************************************************************************** from . import ambient_space -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.family import Family # TODO: double check that this can't be defined over ZZ diff --git a/src/sage/combinat/root_system/type_super_A.py b/src/sage/combinat/root_system/type_super_A.py index 17cf933e14c..1bbbbfdcbff 100644 --- a/src/sage/combinat/root_system/type_super_A.py +++ b/src/sage/combinat/root_system/type_super_A.py @@ -11,7 +11,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method from . import ambient_space from .cartan_type import SuperCartanType_standard diff --git a/src/sage/combinat/root_system/weight_lattice_realizations.py b/src/sage/combinat/root_system/weight_lattice_realizations.py index 033152d42ec..3ad10279619 100644 --- a/src/sage/combinat/root_system/weight_lattice_realizations.py +++ b/src/sage/combinat/root_system/weight_lattice_realizations.py @@ -21,7 +21,7 @@ from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.categories.category_types import Category_over_base_ring from sage.combinat.family import Family from .root_lattice_realizations import RootLatticeRealizations @@ -215,7 +215,7 @@ def __init_extra__(self): The embeddings are systematically tested in :meth:`_test_weight_lattice_realization`. """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from .weight_space import WeightSpace K = self.base_ring() # If self is the root lattice or the root space, we don't want @@ -247,7 +247,7 @@ def _test_weight_lattice_realization(self, **options): sage: RootSystem(['A',3]).weight_lattice()._test_weight_lattice_realization() """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ tester = self._tester(**options) Lambda = self.fundamental_weights() alphacheck = self.simple_coroots() @@ -947,7 +947,7 @@ def _symmetric_form_matrix(self): M = M.inverse() if a[0] != 1: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ S = matrix([~a[0]]+[0]*(r-1)) A = cm.symmetrized_matrix().change_ring(QQ).stack(S) else: diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 977d191646d..22a7eca5513 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -18,7 +18,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from sage.misc.functional import is_even -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class WeylCharacterRing(CombinatorialFreeModule): diff --git a/src/sage/combinat/rsk.py b/src/sage/combinat/rsk.py index 9bc3f1d8720..134f5cd4747 100644 --- a/src/sage/combinat/rsk.py +++ b/src/sage/combinat/rsk.py @@ -170,7 +170,7 @@ from bisect import bisect_left, bisect_right from sage.structure.element import is_Matrix -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ @@ -1888,14 +1888,14 @@ class RuleSuperRSK(RuleRSK): * The input (in terms of biwords) is no longer an arbitrary biword, but rather a restricted super biword (i.e., a pair of two lists `[a_1, a_2, \ldots, a_n]` and `[b_1, b_2, \ldots, b_n]` that - contains entries with even and odd parity and pairs with mixed + contains entries with even and odd parity and pairs with mixed parity entries do not repeat). * The output still consists of two tableaux `(P, Q)` of equal shapes, but rather than both of them being semistandard, now they are semistandard super tableaux. - * The main difference is in the way bumping works. Instead of having + * The main difference is in the way bumping works. Instead of having only row bumping super RSK uses `\epsilon`-insertion, a combination of classical RSK bumping along the rows and a dual RSK like bumping (i.e. when a number `k_i` is inserted into the `i`-th row of `P`, it @@ -1912,7 +1912,7 @@ class RuleSuperRSK(RuleRSK): [[[1, 3], [3']], [[1, 2], [3]]] sage: RSK([1, 3, "3p", "2p"], insertion='superRSK') [[[1, 3', 3], [2']], [[1', 1, 2'], [2]]] - sage: RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], + sage: RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], ....: ["1p", 1, "2p", 2, "3p", "3p", "3p", 3], insertion='superRSK') [[[1', 2, 3', 3], [1, 3'], [2'], [3']], [[1', 2, 3', 3], [2', 3'], [2], [3]]] sage: P = SemistandardSuperTableau([[1, '3p', 3], ['2p']]) @@ -1922,7 +1922,7 @@ class RuleSuperRSK(RuleRSK): We apply super RSK on Example 5.1 in [Muth2019]_:: - sage: P,Q = RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], + sage: P,Q = RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], ....: ["3p", 1, 2, 3, "3p", "3p", "2p", "1p"], insertion='superRSK') sage: (P, Q) ([[1', 2', 3', 3], [1, 2, 3'], [3']], [[1', 2, 2, 3'], [2', 3, 3], [3']]) @@ -1935,7 +1935,7 @@ class RuleSuperRSK(RuleRSK): Example 6.1 in [Muth2019]_:: - sage: P,Q = RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], + sage: P,Q = RSK(["1p", "2p", 2, 2, "3p", "3p", 3, 3], ....: ["3p", 1, 2, 3, "3p", "3p", "2p", "1p"], insertion='superRSK') sage: ascii_art((P, Q)) ( 1' 2' 3' 3 1' 2 2 3' ) @@ -1944,7 +1944,7 @@ class RuleSuperRSK(RuleRSK): sage: RSK_inverse(P, Q, insertion=RSK.rules.superRSK) [[1', 2', 2, 2, 3', 3', 3, 3], [3', 1, 2, 3, 3', 3', 2', 1']] - sage: P,Q = RSK(["1p", 1, "2p", 2, "3p", "3p", "3p", 3], + sage: P,Q = RSK(["1p", 1, "2p", 2, "3p", "3p", "3p", 3], ....: [3, "2p", 3, 2, "3p", "3p", "1p", 2], insertion='superRSK') sage: ascii_art((P, Q)) ( 1' 2 2 3' 1' 2' 3' 3 ) @@ -1960,7 +1960,7 @@ class RuleSuperRSK(RuleRSK): sage: RSK_inverse(P, Q, insertion=RSK.rules.superRSK) [[1, 2, 2, 2], [2, 1, 2, 3]] - When applied to two tableaux with only even parity elements, reverse super + When applied to two tableaux with only even parity elements, reverse super RSK insertion behaves identically to the usual reversel RSK insertion:: sage: t1 = Tableau([[1, 2, 5], [3], [4]]) @@ -1985,7 +1985,7 @@ class RuleSuperRSK(RuleRSK): different types of inputs/outputs:: sage: from sage.combinat.shifted_primed_tableau import PrimedEntry - sage: RSK_inverse(SemistandardSuperTableau([]), + sage: RSK_inverse(SemistandardSuperTableau([]), ....: SemistandardSuperTableau([]), insertion=RSK.rules.superRSK) [[], []] sage: f = lambda p: RSK_inverse(*RSK(p, insertion=RSK.rules.superRSK), @@ -2002,8 +2002,8 @@ class RuleSuperRSK(RuleRSK): Checking that tableaux should be of same shape:: - sage: RSK_inverse(SemistandardSuperTableau([[1, 2, 3]]), - ....: SemistandardSuperTableau([[1, 2]]), + sage: RSK_inverse(SemistandardSuperTableau([[1, 2, 3]]), + ....: SemistandardSuperTableau([[1, 2]]), ....: insertion=RSK.rules.superRSK) Traceback (most recent call last): ... @@ -2014,8 +2014,8 @@ def to_pairs(self, obj1=None, obj2=None, check=True): Given a valid input for the super RSK algorithm, such as two `n`-tuples ``obj1`` `= [a_1, a_2, \ldots, a_n]` and ``obj2`` `= [b_1, b_2, \ldots, b_n]` forming a restricted - super biword (i.e., entries with even and odd parity and no - repetition of corresponding pairs with mixed parity entries) + super biword (i.e., entries with even and odd parity and no + repetition of corresponding pairs with mixed parity entries) return the array `[(a_1, b_1), (a_2, b_2), \ldots, (a_n, b_n)]`. INPUT: @@ -2059,7 +2059,7 @@ def to_pairs(self, obj1=None, obj2=None, check=True): raise ValueError("the two arrays must be the same length") mixed_parity = [] # Check it is a restricted superbiword: that is, - # the entries can have even or odd parity, but repetition of + # the entries can have even or odd parity, but repetition of # the pairs of corresponding entries of obj1 # and obj2 with mixed-parity is not allowed for t, b in zip(obj1, obj2): @@ -2239,8 +2239,8 @@ def forward_rule(self, obj1, obj2, check_standard=False, check=True): def insertion(self, j, r, epsilon=0): r""" Insert the letter ``j`` from the second row of the biword - into the row ``r`` using dual RSK insertion or classical - Schensted insertion depending on the value of ``epsilon``, + into the row ``r`` using dual RSK insertion or classical + Schensted insertion depending on the value of ``epsilon``, if there is bumping to be done. The row `r` is modified in place if bumping occurs. The bumped-out @@ -2289,15 +2289,15 @@ def _forward_format_output(self, p, q, check_standard): sage: from sage.combinat.rsk import RuleSuperRSK sage: isinstance(RuleSuperRSK()._forward_format_output( - ....: [['1p', 1, '2p']], [['1p', '1', '2p']], True)[0], + ....: [['1p', 1, '2p']], [['1p', '1', '2p']], True)[0], ....: StandardSuperTableau) True sage: isinstance(RuleSuperRSK()._forward_format_output( - ....: [[1, '2p', 3]], [[1, 2, 3]], False)[0], + ....: [[1, '2p', 3]], [[1, 2, 3]], False)[0], ....: SemistandardSuperTableau) True sage: isinstance(RuleSuperRSK()._forward_format_output( - ....: [[1, 1, 3]], [[1, 2, 3]], True)[0], + ....: [[1, 1, 3]], [[1, 2, 3]], True)[0], ....: SemistandardSuperTableau) True """ @@ -2401,7 +2401,7 @@ def backward_rule(self, p, q, output='array'): def reverse_insertion(self, x, row, epsilon=0): r""" Reverse bump the row ``row`` of the current insertion tableau - with the number ``x`` using dual RSK insertion or classical + with the number ``x`` using dual RSK insertion or classical Schensted insertion depending on the value of `epsilon`. The row ``row`` is modified in place. The bumped-out entry @@ -2442,7 +2442,7 @@ def reverse_insertion(self, x, row, epsilon=0): x, row[y_pos] = row[y_pos], x return x, y_pos - def _backward_format_output(self, lower_row, upper_row, output, + def _backward_format_output(self, lower_row, upper_row, output, q_is_standard): r""" Return the final output of the ``RSK_inverse`` correspondence @@ -2459,19 +2459,19 @@ def _backward_format_output(self, lower_row, upper_row, output, sage: from sage.combinat.rsk import RuleSuperRSK sage: from sage.combinat.shifted_primed_tableau import PrimedEntry - sage: RuleSuperRSK()._backward_format_output([PrimedEntry('1p'), - ....: PrimedEntry(1), PrimedEntry('3p'), PrimedEntry(9)], - ....: [PrimedEntry(1), PrimedEntry('2p'), PrimedEntry('3p'), + sage: RuleSuperRSK()._backward_format_output([PrimedEntry('1p'), + ....: PrimedEntry(1), PrimedEntry('3p'), PrimedEntry(9)], + ....: [PrimedEntry(1), PrimedEntry('2p'), PrimedEntry('3p'), ....: PrimedEntry(4)], 'array', False) [[4, 3', 2', 1], [9, 3', 1, 1']] - sage: RuleSuperRSK()._backward_format_output([PrimedEntry(1), - ....: PrimedEntry('2p'), PrimedEntry('3p'), PrimedEntry(4)], - ....: [PrimedEntry('1p'), PrimedEntry(1), PrimedEntry('2p'), + sage: RuleSuperRSK()._backward_format_output([PrimedEntry(1), + ....: PrimedEntry('2p'), PrimedEntry('3p'), PrimedEntry(4)], + ....: [PrimedEntry('1p'), PrimedEntry(1), PrimedEntry('2p'), ....: PrimedEntry(2)], 'word', True) word: 4,3',2',1 - sage: RuleSuperRSK()._backward_format_output([PrimedEntry(1), - ....: PrimedEntry(2), PrimedEntry(3), PrimedEntry(4)], - ....: [PrimedEntry('1p'), PrimedEntry(1), PrimedEntry('2p'), + sage: RuleSuperRSK()._backward_format_output([PrimedEntry(1), + ....: PrimedEntry(2), PrimedEntry(3), PrimedEntry(4)], + ....: [PrimedEntry('1p'), PrimedEntry(1), PrimedEntry('2p'), ....: PrimedEntry(2)], 'word', True) word: 4321 """ @@ -3062,9 +3062,9 @@ def RSK(obj1=None, obj2=None, insertion=InsertionRules.RSK, check_standard=False - ``RSK.rules.Hecke`` (or ``'hecke'``) -- Hecke insertion (only guaranteed for generalized permutations whose top row is strictly increasing) (:class:`~sage.combinat.rsk.RuleHecke`) - - ``RSK.rules.dualRSK`` (or ``'dualRSK'``) -- Dual RSK insertion + - ``RSK.rules.dualRSK`` (or ``'dualRSK'``) -- Dual RSK insertion (only for strict biwords) (:class:`~sage.combinat.rsk.RuleDualRSK`) - - ``RSK.rules.coRSK`` (or ``'coRSK'``) -- CoRSK insertion (only + - ``RSK.rules.coRSK`` (or ``'coRSK'``) -- CoRSK insertion (only for strict cobiwords) (:class:`~sage.combinat.rsk.RuleCoRSK`) - ``RSK.rules.superRSK`` (or ``'super'``) -- Super RSK insertion (only for restricted super biwords) (:class:`~sage.combinat.rsk.RuleSuperRSK`) @@ -3221,9 +3221,9 @@ def RSK_inverse(p, q, output='array', insertion=InsertionRules.RSK): - ``RSK.rules.Hecke`` (or ``'hecke'``) -- Hecke insertion (only guaranteed for generalized permutations whose top row is strictly increasing) (:class:`~sage.combinat.rsk.RuleHecke`) - - ``RSK.rules.dualRSK`` (or ``'dualRSK'``) -- Dual RSK insertion + - ``RSK.rules.dualRSK`` (or ``'dualRSK'``) -- Dual RSK insertion (only for strict biwords) (:class:`~sage.combinat.rsk.RuleDualRSK`) - - ``RSK.rules.coRSK`` (or ``'coRSK'``) -- CoRSK insertion (only + - ``RSK.rules.coRSK`` (or ``'coRSK'``) -- CoRSK insertion (only for strict cobiwords) (:class:`~sage.combinat.rsk.RuleCoRSK`) - ``RSK.rules.superRSK`` (or ``'super'``) -- Super RSK insertion (only for restricted super biwords) (:class:`~sage.combinat.rsk.RuleSuperRSK`) @@ -3414,4 +3414,3 @@ def to_matrix(t, b): else: entries[pos] = 1 return matrix(entries, sparse=True) - diff --git a/src/sage/combinat/sf/dual.py b/src/sage/combinat/sf/dual.py index 83f3564c246..c98d02324d8 100644 --- a/src/sage/combinat/sf/dual.py +++ b/src/sage/combinat/sf/dual.py @@ -18,7 +18,7 @@ #***************************************************************************** from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix import sage.combinat.partition import sage.data_structures.blas_dict as blas from . import classical diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 3e1bb2607ad..755c3cd51bd 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -19,7 +19,7 @@ #***************************************************************************** from . import multiplicative, classical from sage.combinat.partition import Partition -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import factorial, binomial from sage.rings.all import infinity diff --git a/src/sage/combinat/sf/hall_littlewood.py b/src/sage/combinat/sf/hall_littlewood.py index e2a2f18f775..4fd478c8f94 100644 --- a/src/sage/combinat/sf/hall_littlewood.py +++ b/src/sage/combinat/sf/hall_littlewood.py @@ -22,7 +22,7 @@ from sage.libs.symmetrica.all import hall_littlewood from . import sfa import sage.combinat.partition -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom from sage.rings.rational_field import QQ diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index 25635d42c14..98162e978dc 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -28,7 +28,7 @@ from . import multiplicative, classical from sage.combinat.partition import Partition from sage.rings.all import infinity -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import factorial, binomial diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py index 514823e82fb..74d02ab7c53 100644 --- a/src/sage/combinat/sf/jack.py +++ b/src/sage/combinat/sf/jack.py @@ -35,7 +35,7 @@ from sage.rings.all import Integer, QQ from sage.arith.all import gcd, lcm from sage.rings.fraction_field import is_FractionField -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom, End from sage.rings.fraction_field import FractionField diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index d7e4af8fe94..01302cff7d3 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -33,7 +33,7 @@ from . import sfa import sage.combinat.ribbon_tableau as ribbon_tableau import sage.combinat.skew_partition -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.partition import Partition, Partitions, _Partitions from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 938b09d23dd..c797d7a0cd4 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -54,8 +54,8 @@ from . import sfa from sage.combinat.partition import Partitions_n, _Partitions from sage.matrix.all import MatrixSpace -from sage.rings.all import QQ -from sage.misc.all import prod +from sage.rings.rational_field import QQ +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_function import functools @@ -1167,19 +1167,20 @@ def _to_s(self, part): sage: Sym.schur()( J[2,1] ) (q*t^3-t^4-q*t^2+t^3-q*t+t^2+q-t)*s[1, 1, 1] + (-q*t^4+2*q*t^3-q*t^2+t^2-2*t+1)*s[2, 1] """ - q,t = QQqt.gens() + q, t = QQqt.gens() S = self._macdonald.S() res = S(1) for k in reversed(part): res = res.creation(k) res = res._omega_qt_in_schurs() - res = res.map_coefficients(lambda c: c(t,q)) - f = lambda part2: res.coefficient(part2) + res = res.map_coefficients(lambda c: c(t, q)) + f = res.coefficient return f class Element(MacdonaldPolynomials_generic.Element): pass + class MacdonaldPolynomials_h(MacdonaldPolynomials_generic): def __init__(self, macdonald): r""" @@ -1776,14 +1777,14 @@ def _to_s(self, part): sage: S2(Partition([1,1])) (q*t - t^2 - q + t)/(-q^3 + q^2 + q - 1) """ - #Convert to the power sum - (q,t) = QQqt.gens() + # Convert to the power sum + (q, t) = QQqt.gens() p = self._sym.p() s = self._s p_x = p(s(part)) - f = lambda m, c: (m, c*prod([(1-t**k)/(1-q**k) for k in m])) + f = lambda m, c: (m, c * prod([(1 - t**k) / (1 - q**k) for k in m])) res = s(p_x.map_item(f)) - f = lambda part2: res.coefficient(part2) + f = res.coefficient return f def _s_cache(self, n): diff --git a/src/sage/combinat/sf/ns_macdonald.py b/src/sage/combinat/sf/ns_macdonald.py index 7ac278837c8..d2a0928b2a6 100644 --- a/src/sage/combinat/sf/ns_macdonald.py +++ b/src/sage/combinat/sf/ns_macdonald.py @@ -8,7 +8,7 @@ from sage.combinat.combination import Combinations from sage.combinat.permutation import Permutation from sage.rings.all import QQ, PolynomialRing -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.combinat.backtrack import GenericBacktracker from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index eb33d33963a..b4181b239eb 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -22,7 +22,7 @@ from sage.arith.all import divisors from sage.rings.all import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.misc.all import prod +from sage.misc.misc_c import prod class SymmetricFunctionAlgebra_power(multiplicative.SymmetricFunctionAlgebra_multiplicative): def __init__(self, Sym): diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index ca4858e744f..7cc7f800135 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -19,7 +19,7 @@ from . import classical import sage.libs.lrcalc.lrcalc as lrcalc -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.arith.misc import factorial diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 89b1b35abfe..739b642ade1 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -221,7 +221,7 @@ from sage.categories.tensor import tensor from sage.combinat.free_module import CombinatorialFreeModule from sage.matrix.constructor import matrix -from sage.misc.all import prod +from sage.misc.misc_c import prod from copy import copy from functools import reduce @@ -2619,9 +2619,9 @@ def set_print_style(self, ps): if ps == 'lex': self.print_options(sorting_key=lambda x: x) elif ps == 'length': - self.print_options(sorting_key=lambda x: len(x)) + self.print_options(sorting_key=len) elif ps == 'maximal_part': - self.print_options(sorting_key=lambda x: _lmax(x)) + self.print_options(sorting_key=_lmax) else: raise ValueError("the print style must be one of lex, length, or maximal_part ") self._print_style = ps diff --git a/src/sage/combinat/sf/witt.py b/src/sage/combinat/sf/witt.py index 625f76e8521..fbc7979936b 100644 --- a/src/sage/combinat/sf/witt.py +++ b/src/sage/combinat/sf/witt.py @@ -18,7 +18,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from . import multiplicative -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix class SymmetricFunctionAlgebra_witt(multiplicative.SymmetricFunctionAlgebra_multiplicative): r""" diff --git a/src/sage/combinat/similarity_class_type.py b/src/sage/combinat/similarity_class_type.py index cba51173f03..a77f5b65bca 100644 --- a/src/sage/combinat/similarity_class_type.py +++ b/src/sage/combinat/similarity_class_type.py @@ -176,7 +176,7 @@ class type, it is also possible to compute the number of classes of that type # **************************************************************************** from itertools import chain, product -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.misc import factorial from sage.arith.all import moebius, divisors from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass diff --git a/src/sage/combinat/sloane_functions.py b/src/sage/combinat/sloane_functions.py index a890c188bed..4307051be34 100644 --- a/src/sage/combinat/sloane_functions.py +++ b/src/sage/combinat/sloane_functions.py @@ -321,7 +321,7 @@ def __getitem__(self, n): from sage.matrix.matrix_space import MatrixSpace from sage.rings.rational_field import QQ from sage.combinat import combinat -from sage.misc.all import prod +from sage.misc.misc_c import prod # This one should be here! diff --git a/src/sage/combinat/species/cycle_species.py b/src/sage/combinat/species/cycle_species.py index ba41b643d73..83c82fc44a3 100644 --- a/src/sage/combinat/species/cycle_species.py +++ b/src/sage/combinat/species/cycle_species.py @@ -16,7 +16,7 @@ from .structure import GenericSpeciesStructure from .generating_series import _integers_from from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import divisors, euler_phi from sage.combinat.species.misc import accept_size diff --git a/src/sage/combinat/species/misc.py b/src/sage/combinat/species/misc.py index ba1193e6097..60436e72d23 100644 --- a/src/sage/combinat/species/misc.py +++ b/src/sage/combinat/species/misc.py @@ -17,7 +17,7 @@ #***************************************************************************** from sage.groups.all import PermutationGroup, PermutationGroup_generic, PermutationGroupElement, SymmetricGroup -from sage.misc.all import prod +from sage.misc.misc_c import prod from functools import wraps def change_support(perm, support, change_perm=None): diff --git a/src/sage/combinat/species/partition_species.py b/src/sage/combinat/species/partition_species.py index af4ed3cf8fe..7ba6ea84a13 100644 --- a/src/sage/combinat/species/partition_species.py +++ b/src/sage/combinat/species/partition_species.py @@ -183,23 +183,23 @@ def _structures(self, structure_class, labels): yield structure_class(self, labels, []) return - u = [i for i in reversed(range(1, n+1))] + u = [i for i in reversed(range(1, n + 1))] s0 = u.pop() - #Reconstruct the set partitions from - #restricted growth arrays + # Reconstruct the set partitions from + # restricted growth arrays for a in RestrictedGrowthArrays(n): m = a.pop(0) r = [[] for _ in range(m)] i = n - for i,z in enumerate(u): + for i, z in enumerate(u): r[a[i]].append(z) r[0].append(s0) for sp in r: sp.reverse() - r.sort(key=lambda x: len(x), reverse=True) + r.sort(key=len, reverse=True) yield structure_class(self, labels, r) diff --git a/src/sage/combinat/species/permutation_species.py b/src/sage/combinat/species/permutation_species.py index 57b282e211b..d8ae5c216ea 100644 --- a/src/sage/combinat/species/permutation_species.py +++ b/src/sage/combinat/species/permutation_species.py @@ -20,7 +20,7 @@ from .structure import GenericSpeciesStructure from .generating_series import _integers_from from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.combinat.permutation import Permutation, Permutations from sage.combinat.species.misc import accept_size diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index 4bbee606925..77894d6f572 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -411,7 +411,7 @@ def _equation(self, var_mapping): sage: S.algebraic_equation_system() [node0 - z^2] """ - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod(var_mapping[operand] for operand in self._state_info) diff --git a/src/sage/combinat/species/recursive_species.py b/src/sage/combinat/species/recursive_species.py index 7af1a0dee36..04121797d6e 100644 --- a/src/sage/combinat/species/recursive_species.py +++ b/src/sage/combinat/species/recursive_species.py @@ -17,7 +17,7 @@ #***************************************************************************** from sage.combinat.species.species import GenericCombinatorialSpecies from sage.combinat.species.structure import SpeciesStructureWrapper -from sage.rings.all import QQ +from sage.rings.rational_field import QQ class CombinatorialSpeciesStructure(SpeciesStructureWrapper): diff --git a/src/sage/combinat/species/series.py b/src/sage/combinat/species/series.py index ea79a9c9c0e..b312148a2f3 100644 --- a/src/sage/combinat/species/series.py +++ b/src/sage/combinat/species/series.py @@ -34,7 +34,7 @@ from .stream import Stream, Stream_class from .series_order import bounded_decrement, increment, inf, unk from sage.rings.all import Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from functools import partial from sage.misc.misc import is_iterator from sage.misc.repr import repr_lincomb diff --git a/src/sage/combinat/species/species.py b/src/sage/combinat/species/species.py index aa5e29356d2..26a0c2e58ec 100644 --- a/src/sage/combinat/species/species.py +++ b/src/sage/combinat/species/species.py @@ -51,7 +51,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from .generating_series import OrdinaryGeneratingSeriesRing, ExponentialGeneratingSeriesRing, CycleIndexSeriesRing -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_method from sage.combinat.species.misc import accept_size diff --git a/src/sage/combinat/subword_complex.py b/src/sage/combinat/subword_complex.py index 2e447d7076a..f59113ef04f 100644 --- a/src/sage/combinat/subword_complex.py +++ b/src/sage/combinat/subword_complex.py @@ -1529,7 +1529,7 @@ def is_root_independent(self): sage: SC.is_root_independent() True """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix M = matrix(self.greedy_facet(side="negative").root_configuration()) return M.rank() == max(M.ncols(), M.nrows()) @@ -1689,7 +1689,7 @@ def minkowski_summand(self, i): A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex """ G = self.group() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if G.coxeter_matrix().is_crystallographic(): min_sum = [[QQ(v) for v in F.extended_weight_configuration()[i]] for F in self] else: @@ -1740,7 +1740,7 @@ def brick_polytope(self, coefficients=None): """ BV = self.brick_vectors(coefficients=coefficients) G = self.group() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if G.coxeter_matrix().is_crystallographic(): BV = [[QQ(v) for v in V] for V in BV] else: diff --git a/src/sage/combinat/super_tableau.py b/src/sage/combinat/super_tableau.py index c73e3f6fcc3..fc054567e4d 100644 --- a/src/sage/combinat/super_tableau.py +++ b/src/sage/combinat/super_tableau.py @@ -23,7 +23,7 @@ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.non_negative_integers import NonNegativeIntegers -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.sets.family import Family from sage.structure.parent import Parent from sage.rings.integer import Integer diff --git a/src/sage/combinat/superpartition.py b/src/sage/combinat/superpartition.py index b7658bcbe02..3de4852411d 100644 --- a/src/sage/combinat/superpartition.py +++ b/src/sage/combinat/superpartition.py @@ -86,7 +86,7 @@ from sage.categories.enumerated_sets import EnumeratedSets from sage.rings.integer import Integer from sage.structure.global_options import GlobalOptions -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index 10a69e02a8c..6263dfea7cb 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -21,8 +21,8 @@ from sage.categories.weyl_groups import WeylGroups from sage.rings.all import QQ, PolynomialRing from sage.arith.all import factorial -from sage.matrix.all import matrix -from sage.modules.all import vector +from sage.matrix.constructor import matrix +from sage.modules.free_module_element import vector from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.misc.persist import register_unpickle_override diff --git a/src/sage/combinat/symmetric_group_representations.py b/src/sage/combinat/symmetric_group_representations.py index bce78a410a0..169d0f862ef 100644 --- a/src/sage/combinat/symmetric_group_representations.py +++ b/src/sage/combinat/symmetric_group_representations.py @@ -951,7 +951,7 @@ def representation_matrix(self, permutation): """ ret = self._representation_matrix_uncached(permutation) ret.set_immutable() - return ret + return ret def _representation_matrix_uncached(self, permutation): r""" diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index ab24316debc..3cb05d80804 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -106,7 +106,7 @@ import sage.misc.prandom as random from sage.combinat import permutation from sage.groups.perm_gps.permgroup import PermutationGroup -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.misc import powerset from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets @@ -1125,7 +1125,7 @@ def to_sign_matrix(self, max_entry=None): ... ValueError: the entries must be non-negative integers """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.sets.positive_integers import PositiveIntegers PI = PositiveIntegers() for row in self: @@ -6439,7 +6439,7 @@ def random_element(self): sage: SemistandardTableaux(6, max_entry=7).random_element() # random [[2, 4, 4, 6, 6, 6]] """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.matrix.constructor import diagonal_matrix from sage.combinat.rsk import RSK kchoose2m1 = self.max_entry * (self.max_entry - 1) // 2 - 1 diff --git a/src/sage/combinat/tiling.py b/src/sage/combinat/tiling.py index 025adfe7d58..b34dad8f9ad 100644 --- a/src/sage/combinat/tiling.py +++ b/src/sage/combinat/tiling.py @@ -475,7 +475,7 @@ class Polyomino(SageObject): - ``coords`` -- iterable of integer coordinates in `\ZZ^d` - ``color`` -- string (default: ``'gray'``), color for display - - ``dimension`` -- integer (default: ``None``), dimension of the space, + - ``dimension`` -- integer (default: ``None``), dimension of the space, if ``None``, it is guessed from the ``coords`` if ``coords`` is non empty diff --git a/src/sage/combinat/tuple.py b/src/sage/combinat/tuple.py index ae380274f1a..9b773e0be70 100644 --- a/src/sage/combinat/tuple.py +++ b/src/sage/combinat/tuple.py @@ -17,7 +17,7 @@ # **************************************************************************** from sage.libs.gap.libgap import libgap -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py new file mode 100644 index 00000000000..3311872c50c --- /dev/null +++ b/src/sage/combinat/words/morphic.py @@ -0,0 +1,363 @@ +# -*- coding: utf-8 -*- +r""" +Morphic words + +This modules implements morphic words (letter-to-letter coding of fixed +point of a morphism). + +AUTHORS: + +- Jana Lepsova (January 2021): initial version + +EXAMPLES: + +Creation of the fixed point of a morphism:: + + sage: m = WordMorphism('a->abc,b->baba,c->ca') + sage: w = m.fixed_point('a') + sage: w + word: abcbabacababaabcbabaabccaabcbabaabcbabaa... + sage: w.length() + +Infinity + +Computing the n-th letter of a fixed point is fast as it is using the +abstract numeration system associated to the morphism and the starting +letter, see chapter 3 of the book [BR2010b]_:: + + sage: w[10000000] + 'b' + +""" + +from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable +from sage.rings.all import Infinity +from sage.modules.free_module_element import vector + +class WordDatatype_morphic(WordDatatype_callable): + r""" + Datatype for a morphic word defined by a morphism, a starting letter + and a coding. + """ + def __init__(self, parent, morphism, letter, coding=None, length=Infinity): + r""" + INPUT: + + - ``parent`` - a parent + - ``morphism`` - a word morphism + - ``letter`` - a starting letter + - ``coding`` - dict (default: ``None``), if ``None`` + the identity map is used for the coding + - ``length`` - integer or ``'finite'`` or ``Infinity`` or + ``'unknown'`` (default: ``Infinity``) the length of the word + + EXAMPLES:: + + sage: m = WordMorphism('a->ab,b->a') + sage: w = m.fixed_point('a') + sage: w + word: abaababaabaababaababaabaababaabaababaaba... + sage: w[555:1000] + word: abaababaabaababaababaabaababaabaababaaba... + sage: w.length() + +Infinity + + :: + + sage: m = WordMorphism('a->abc,b->baba,c->ca') + sage: m.fixed_point('a') + word: abcbabacababaabcbabaabccaabcbabaabcbabaa... + sage: w = m.fixed_point('a') + sage: w[7] + 'c' + sage: w[2:7] + word: cbaba + sage: w[500:503] + word: caa + + When the morphic word is finite:: + + sage: m = WordMorphism("a->ab,b->") + sage: w = m.fixed_point("a") + sage: w + word: ab + sage: w[0] + 'a' + sage: w.length() + 2 + + Using the coding argument:: + + sage: m = WordMorphism('a->ab,b->a') + sage: W = m.domain() + sage: from sage.combinat.words.morphic import WordDatatype_morphic + sage: coding = {'a':'x', 'b':'y'} + sage: w = WordDatatype_morphic(W, m, 'a', coding=coding) + sage: [w[i] for i in range(10)] + ['x', 'y', 'x', 'x', 'y', 'x', 'y', 'x', 'x', 'y'] + + TESTS:: + + sage: m = WordMorphism('a->abcd,b->bbc,c->cddd,d->cba') + sage: w = m.fixed_point('a') + sage: it = iter(w) + sage: for _ in range(10000): _ = next(it) + sage: L = [next(it) for _ in range(10)]; L + ['d', 'd', 'd', 'c', 'd', 'd', 'd', 'c', 'b', 'a'] + sage: w[10000:10010] + word: dddcdddcba + sage: list(w[10000:10010]) == L + True + + """ + self._parent = parent + # self._func = callable + # for hashing + self._hash = None + + if length is Infinity: + self._len = Infinity + elif length is None or length == 'unknown' or length == 'finite': + self._len = None + else: + self._len = length + + self._morphism = morphism + self._letter = letter + self._alphabet = self._morphism.domain().alphabet() + if coding == None: + self._coding = {a:a for a in self._alphabet} + else: + self._coding = coding + + def __reduce__(self): + r""" + EXAMPLES:: + + sage: m = WordMorphism('a->ab,b->a') + sage: w = m.fixed_point('a') + sage: w.__reduce__() + (, + (Infinite words over {'a', 'b'}, + WordMorphism: a->ab, b->a, + 'a', + {'a': 'a', 'b': 'b'}, + +Infinity)) + + Below is the behavior for words of finite length:: + + sage: m = WordMorphism("a->ab,b->") + sage: w = m.fixed_point("a") + sage: w.__reduce__() + (, + (Finite words over {'a', 'b'}, + WordMorphism: a->ab, b->, + 'a', + {'a': 'a', 'b': 'b'}, + 2)) + + """ + return self.__class__, (self._parent, self._morphism, self._letter, + self._coding, self._len) + + def representation(self, n): + r""" + Return the representation of the integer n in the numeration system + associated to the morphism. + + INPUT: + + - ``n`` -- nonnegative integer + + OUTPUT: + + list + + EXAMPLES:: + + sage: m = WordMorphism('a->ab,b->a') + sage: w = m.fixed_point('a') + sage: w.representation(5) + [1, 0, 0, 0] + + When the morphic word is finite:: + + sage: m = WordMorphism("a->ab,b->,c->cdab,d->dcab") + sage: w = m.fixed_point("a") + sage: w.representation(0) + [] + sage: w.representation(1) + [1] + sage: w.representation(2) + Traceback (most recent call last): + ... + IndexError: Index (=2) out of range, the fixed point is finite and has length 2. + + TESTS: + + Accessing this method from an instance of the current class (no using + the inherited word classes):: + + sage: m = WordMorphism('a->ab,b->a') + sage: W = m.domain() + sage: from sage.combinat.words.morphic import WordDatatype_morphic + sage: w = WordDatatype_morphic(W, m, 'a') + sage: type(w) + + sage: w.representation(5) + [1, 0, 0, 0] + """ + letters_to_int = {a:i for (i,a) in enumerate(self._alphabet)} + position = letters_to_int[self._letter] + M = self._morphism.incidence_matrix() + vMk = vector([1]*len(self._alphabet)) + length_of_images = [] + while vMk[position] <= n: + length_of_images.append(vMk) + vMk_next = vMk*M + if vMk[position] == vMk_next[position]: + raise IndexError('Index (={}) out of range, the fixed point is finite and has length {}.'.format(n,vMk[position])) + vMk = vMk_next + k = len(length_of_images) + letter_k = self._letter + n_k = n + path = [] + while k > 0: + m_letter_k = self._morphism(letter_k) + S = 0 + j = 0 + while S <= n_k: + a = m_letter_k[j] + i = letters_to_int[a] + pile_length = length_of_images[k-1][i] + S += pile_length + j += 1 + path.append(j-1) + n_k -= S - pile_length + letter_k = a + k -= 1 + return path + + def _func(self, key): + """ + Return a letter of a fixed point of a morphism on position ``key``. + + INPUT: + + - ``self`` - a fixed point of a morphism + - ``key`` - an integer, the position + + OUTPUT: + + - a letter + + EXAMPLES:: + + sage: m = WordMorphism("a->ab,b->a") + sage: w = m.fixed_point("a") + sage: w[0] + 'a' + sage: w[5] + 'a' + sage: w[10000] + 'a' + + TESTS: + + Accessing this method from an instance of the current class + (without using the inherited word classes):: + + sage: m = WordMorphism('a->ab,b->a') + sage: W = m.domain() + sage: from sage.combinat.words.morphic import WordDatatype_morphic + sage: w = WordDatatype_morphic(W, m, 'a') + sage: w._func(5) + 'a' + + """ + letter = self._letter + for a in self.representation(key): + letter = (self._morphism(letter))[a] + if key == 0: + return self._coding[letter] + return self._coding[letter] + + def __iter__(self): + r""" + Return an iterator of the letters of the fixed point of ``self`` + starting with ``letter``. + + If w is the iterated word, then this iterator: outputs the elements + of morphism[ w[i] ], appends morphism[ w[i+1] ] to w, increments i. + + INPUT: + + - ``self`` - an endomorphism, must be prolongable on + letter + + - ``letter`` - a letter in the domain of ``self`` + + OUTPUT: + + - iterator of the fixed point + + EXAMPLES:: + + sage: m = WordMorphism("a->ab,b->a") + sage: w = m.fixed_point("a") + sage: it = iter(w) + sage: [next(it) for _ in range(10)] + ['a', 'b', 'a', 'a', 'b', 'a', 'b', 'a', 'a', 'b'] + + Works with erasing morphisms:: + + sage: m = WordMorphism('a->abc,b->,c->') + sage: w = m.fixed_point("a") + sage: list(w) + ['a', 'b', 'c'] + + The morphism must be prolongable on the letter or the iterator will + be empty:: + + sage: list(m.fixed_point("b")) + Traceback (most recent call last): + ... + TypeError: self must be prolongable on b + + The morphism must be an endomorphism:: + + sage: m = WordMorphism('a->ac,b->aac') + sage: w = m.fixed_point('a') + Traceback (most recent call last): + ... + TypeError: self (=a->ac, b->aac) is not an endomorphism + + We check that :trac:`8595` is fixed:: + + sage: s = WordMorphism({('a', 1):[('a', 1), ('a', 2)], ('a', 2):[('a', 1)]}) + sage: w = s.fixed_point(('a', 1)) + sage: it = iter(w) + sage: next(it) + ('a', 1) + + This shows that ticket :trac:`13668` has been resolved:: + + sage: s = WordMorphism({1:[1,2],2:[2,3],3:[4],4:[5],5:[6],6:[7],7:[8],8:[9],9:[10],10:[1]}) + sage: (s^7).fixed_points() + [word: 1223234234523456234567234567823456789234..., + word: 2,3,4,5,6,7,8,9,10,1,1,2,1,2,2,3,1,2,2,3,2,3,4,1,2,2,3,2,3,4,2,3,4,5,1,2,2,3,2,3,...] + sage: (s^7).reversal().fixed_points() + [] + """ + from itertools import chain + w = iter(self._morphism.image(self._letter)) + while True: + try: + for a in self._morphism.image(next(w)): + yield self._coding[a] + else: + next_w = next(w) + w = chain([next_w], w, self._morphism.image(next_w)) + except StopIteration: + return + + diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index bc6a540c2d0..3a25a49b64c 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -89,14 +89,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from itertools import chain - from sage.misc.callable_dict import CallableDict from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_method from sage.misc.lazy_list import lazy_list from sage.sets.set import Set -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.rings.infinity import Infinity from sage.rings.integer_ring import IntegerRing from sage.rings.integer import Integer @@ -1728,73 +1726,6 @@ def is_uniform(self, k=None): else: return all(w.length() == k for w in self.images()) - def _fixed_point_iterator(self, letter): - r""" - Returns an iterator of the letters of the fixed point of ``self`` - starting with ``letter``. - - If w is the iterated word, then this iterator: outputs the elements - of morphism[ w[i] ], appends morphism[ w[i+1] ] to w, increments i. - - INPUT: - - - ``self`` - an endomorphism, must be prolongable on - letter - - - ``letter`` - a letter in the domain of ``self`` - - OUTPUT: - - - iterator of the fixed point - - EXAMPLES:: - - sage: m = WordMorphism('a->abc,b->,c->') - sage: list(m._fixed_point_iterator('a')) - ['a', 'b', 'c'] - - The morphism must be prolongable on the letter or the iterator will - be empty:: - - sage: list(m._fixed_point_iterator('b')) - [] - - The morphism must be an endomorphism:: - - sage: m = WordMorphism('a->ac,b->aac') - sage: list(m._fixed_point_iterator('a')) - Traceback (most recent call last): - ... - KeyError: 'c' - - We check that :trac:`8595` is fixed:: - - sage: s = WordMorphism({('a', 1):[('a', 1), ('a', 2)], ('a', 2):[('a', 1)]}) - sage: it = s._fixed_point_iterator(('a',1)) - sage: next(it) - ('a', 1) - - This shows that ticket :trac:`13668` has been resolved:: - - sage: s = WordMorphism({1:[1,2],2:[2,3],3:[4],4:[5],5:[6],6:[7],7:[8],8:[9],9:[10],10:[1]}) - sage: (s^7).fixed_points() - [word: 1223234234523456234567234567823456789234..., - word: 2,3,4,5,6,7,8,9,10,1,1,2,1,2,2,3,1,2,2,3,2,3,4,1,2,2,3,2,3,4,2,3,4,5,1,2,2,3,2,3,...] - sage: (s^7).reversal().fixed_points() - [] - """ - w = iter(self.image(letter)) - while True: - try: - for a in self.image(next(w)): - yield a - else: - next_w = next(w) - w = chain([next_w], w, self.image(next_w)) - except StopIteration: - return - - def fixed_point(self, letter): r""" Returns the fixed point of ``self`` beginning by the given ``letter``. @@ -1886,8 +1817,18 @@ def fixed_point(self, letter): parent = self.codomain() if self.is_growing(letter): - parent = parent.shift() - return parent(self._fixed_point_iterator(letter)) + from sage.combinat.words.word import InfiniteWord_morphic + return InfiniteWord_morphic(parent.shift(), self, letter, + coding=None, length=Infinity) + else: + from sage.combinat.words.word import FiniteWord_morphic + w = FiniteWord_morphic(parent, self, letter, + coding=None, length='finite') + # since FiniteWord_morphic uses the method __getitem__ + # from FiniteWord_callable, the length must be precomputed + # for __getitem__ to work properly + w.length() + return w def fixed_points(self): r""" diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index 2ab59314376..4762a5b55d6 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -9,6 +9,7 @@ - Sébastien Labbé - Franco Saliola + """ #***************************************************************************** # Copyright (C) 2008 Arnaud Bergeron , @@ -34,6 +35,7 @@ WordDatatype_iter, WordDatatype_callable_with_caching, WordDatatype_callable) +from .morphic import WordDatatype_morphic from sage.monoids.free_monoid_element import FreeMonoidElement # TODO. Word needs to be replaced by Word. Consider renaming @@ -687,3 +689,57 @@ class Word_iter(WordDatatype_iter, Word_class): """ pass +##### Morphic Words ##### +class FiniteWord_morphic(WordDatatype_morphic, FiniteWord_class): + r""" + Finite morphic word. + + For such word `w`, type ``w.`` and hit TAB key to see the list of + functions defined on `w`. + + EXAMPLES:: + + sage: m = WordMorphism("a->ab,b->") + sage: w = m.fixed_point("a") + sage: w + word: ab + + + TESTS:: + + sage: m = WordMorphism("a->ab,b->") + sage: w = m.fixed_point("a") + sage: type(w) + + sage: loads(dumps(w)) + word: ab + + """ + pass + +class InfiniteWord_morphic(WordDatatype_morphic, InfiniteWord_class): + r""" + Morphic word of infinite length. + + For such word `w`, type ``w.`` and hit TAB key to see the list of + functions defined on `w`. + + Infinite words behave like a Python list : they can be sliced using + square braquets to define for example a prefix or a factor. + + EXAMPLES:: + + sage: m = WordMorphism('a->ab,b->a') + sage: w = m.fixed_point('a') + sage: w + word: abaababaabaababaababaabaababaabaababaaba... + + TESTS: + + Pickle is supported:: + + sage: loads(dumps(w)) + word: abaababaabaababaababaabaababaabaababaaba... + + """ + pass diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 26d31aefb9d..9b5c7fe08fb 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -1898,7 +1898,7 @@ def s_adic(self, sequence, letters, morphisms=None): from sage.combinat.words.word import FiniteWord_class if isinstance(sequence,(tuple,list,str,FiniteWord_class)) \ and hasattr(letters, "__len__") and len(letters) == 1: - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod(seq)(letters) from itertools import tee diff --git a/src/sage/cpython/cython_metaclass.pyx b/src/sage/cpython/cython_metaclass.pyx index 11294c2bb97..e3a00bdecb5 100644 --- a/src/sage/cpython/cython_metaclass.pyx +++ b/src/sage/cpython/cython_metaclass.pyx @@ -76,13 +76,13 @@ EXAMPLES:: ....: cdef class MyDerivedType(MyCustomType): ....: pass ....: ''') - Calling MyMetaclass.__init__(, None, None, None) - Calling MyMetaclass.__init__(, None, None, None) + Calling MyMetaclass.__init__(, None, None, None) + Calling MyMetaclass.__init__(, None, None, None) sage: MyCustomType.__class__ sage: class MyPythonType(MyDerivedType): ....: pass - Calling MyMetaclass.__init__(, 'MyPythonType', (,), {...}) + Calling MyMetaclass.__init__(, 'MyPythonType', (,), {...}) Implementation ============== diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index a8aa0f48fbb..647bdf760ca 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -996,11 +996,11 @@ cdef class BooleanFunction(SageObject): G = R.gens() r = [R(1)] - from sage.modules.all import vector + from sage.modules.free_module_element import vector s = vector(self.truth_table()).support() from sage.combinat.combination import Combinations - from sage.misc.all import prod + from sage.misc.misc_c import prod from sage.matrix.constructor import Matrix from sage.arith.all import binomial @@ -1387,7 +1387,7 @@ cdef class BooleanFunctionIterator: sage: from sage.crypto.boolean_function import BooleanFunction sage: B = BooleanFunction(3) sage: type(B.__iter__()) - + """ self.f = f self.index = -1 diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index 5a5c10072f8..5e3c6131cea 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -1788,7 +1788,7 @@ def ring(self, order=None, reverse_variables=None): reverse_variables = self._reverse_variables if reverse_variables: - process = lambda x: reversed(x) + process = reversed else: process = lambda x: x diff --git a/src/sage/crypto/util.py b/src/sage/crypto/util.py index 1d1e375e6cc..44b7185f43e 100644 --- a/src/sage/crypto/util.py +++ b/src/sage/crypto/util.py @@ -375,7 +375,7 @@ def carmichael_lambda(n): sage: from sage.crypto.util import carmichael_lambda sage: type(carmichael_lambda(16)) - + REFERENCES: diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index a5704d624cb..988a6a1be02 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1604,7 +1604,7 @@ def element(self, key): sage: e = P.element(42); e 42 sage: type(e) - + .. SEEALSO:: @@ -1850,9 +1850,9 @@ def elements(self, **kwargs): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP([3, 42, 7]) sage: [(v, type(v)) for v in sorted(P.elements())] - [(3, ), - (7, ), - (42, )] + [(3, ), + (7, ), + (42, )] Note that @@ -1937,14 +1937,14 @@ def keys(self, **kwargs): sage: from sage.data_structures.mutable_poset import MutablePoset as MP sage: P = MP([3, 42, 7], key=lambda c: -c) sage: [(v, type(v)) for v in sorted(P.keys())] - [(-42, ), - (-7, ), - (-3, )] + [(-42, ), + (-7, ), + (-3, )] sage: [(v, type(v)) for v in sorted(P.elements())] - [(3, ), - (7, ), - (42, )] + [(3, ), + (7, ), + (42, )] sage: [(v, type(v)) for v in sorted(P.shells(), ....: key=lambda c: c.element)] @@ -1984,9 +1984,9 @@ def keys_topological(self, **kwargs): sage: P = MP([(1, 1), (2, 1), (4, 4)], ....: key=lambda c: c[0]) sage: [(v, type(v)) for v in P.keys_topological(key=repr)] - [(1, ), - (2, ), - (4, )] + [(1, ), + (2, ), + (4, )] sage: [(v, type(v)) for v in P.elements_topological(key=repr)] [((1, 1), <... 'tuple'>), ((2, 1), <... 'tuple'>), diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 21f3fa47ad4..e606f25579b 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -95,7 +95,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity - +from sage.arith.misc import divisors class Stream(): """ @@ -188,6 +188,25 @@ def __init__(self, is_sparse, approximate_order): self._offset = approximate_order self._iter = self.iterate_coefficients() + def is_nonzero(self): + r""" + Return ``True`` if and only if the cache contains a nonzero element. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function + sage: CS = Stream_function(lambda n: 1/n, ZZ, False, 1) + sage: CS.is_nonzero() + False + sage: CS[1] + 1 + sage: CS.is_nonzero() + True + """ + if self._is_sparse: + return any(self._cache.values()) + return any(self._cache) + def __getstate__(self): """ Build the dictionary for pickling ``self``. @@ -1397,6 +1416,154 @@ def is_nonzero(self): return self._left.is_nonzero() and self._right.is_nonzero() +class Stream_dirichlet_convolve(Stream_binary): + r""" + Operator for the Dirichlet convolution of two streams. + + INPUT: + + - ``left`` -- stream of coefficients on the left side of the operator + - ``right`` -- stream of coefficients on the right side of the operator + + The coefficient of `n^{-s}` in the convolution of `l` and `r` + equals `\sum_{k | n} l_k r_{n/k}`. + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) + sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: g = Stream_exact([0], True, constant=1) + sage: h = Stream_dirichlet_convolve(f, g) + sage: [h[i] for i in range(1, 10)] + [1, 3, 4, 7, 6, 12, 8, 15, 13] + sage: [sigma(n) for n in range(1, 10)] + [1, 3, 4, 7, 6, 12, 8, 15, 13] + + sage: u = Stream_dirichlet_convolve(g, f) + sage: [u[i] for i in range(1, 10)] + [1, 3, 4, 7, 6, 12, 8, 15, 13] + """ + def __init__(self, left, right): + """ + Initalize ``self``. + + sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) + sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: g = Stream_exact([1], True, constant=0) + sage: Stream_dirichlet_convolve(f, g) + Traceback (most recent call last): + ... + AssertionError: Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1 + sage: Stream_dirichlet_convolve(g, f) + Traceback (most recent call last): + ... + AssertionError: Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1 + """ + if left._is_sparse != right._is_sparse: + raise NotImplementedError + + assert left._approximate_order > 0 and right._approximate_order > 0, "Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1" + + vl = left._approximate_order + vr = right._approximate_order + a = vl * vr + super().__init__(left, right, left._is_sparse, a) + + def get_coefficient(self, n): + """ + Return the ``n``-th coefficient of ``self``. + + INPUT: + + - ``n`` -- integer; the degree for the coefficient + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) + sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: g = Stream_exact([0], True, constant=1) + sage: h = Stream_dirichlet_convolve(f, g) + sage: h.get_coefficient(7) + 8 + sage: [h[i] for i in range(1, 10)] + [1, 3, 4, 7, 6, 12, 8, 15, 13] + """ + c = ZZ.zero() + for k in divisors(n): + if k < self._left._approximate_order or n // k < self._right._approximate_order: + continue + val = self._left[k] + if val: + c += val * self._right[n//k] + return c + + +class Stream_dirichlet_invert(Stream_unary): + r""" + Operator for inverse with respect to Dirichlet convolution of the stream. + + INPUT: + + - ``series`` -- a :class:`Stream` + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_dirichlet_invert, Stream_function) + sage: f = Stream_function(lambda n: 1, ZZ, True, 1) + sage: g = Stream_dirichlet_invert(f) + sage: [g[i] for i in range(10)] + [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] + sage: [moebius(i) for i in range(10)] + [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] + """ + def __init__(self, series): + """ + Initialize. + + TESTS:: + + sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) + sage: f = Stream_exact([0, 0], True, constant=1) + sage: g = Stream_dirichlet_invert(f) + Traceback (most recent call last): + ... + AssertionError: the Dirichlet inverse only exists if the coefficient with index 1 is non-zero + """ + assert series[1], "the Dirichlet inverse only exists if the coefficient with index 1 is non-zero" + super().__init__(series, series._is_sparse, 1) + + self._ainv = ~series[1] + self._zero = ZZ.zero() + + def get_coefficient(self, n): + """ + Return the ``n``-th coefficient of ``self``. + + INPUT: + + - ``n`` -- integer; the degree for the coefficient + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) + sage: f = Stream_exact([0, 3], True, constant=2) + sage: g = Stream_dirichlet_invert(f) + sage: g.get_coefficient(6) + 2/27 + sage: [g[i] for i in range(8)] + [0, 1/3, -2/9, -2/9, -2/27, -2/9, 2/27, -2/9] + """ + if n == 1: + return self._ainv + c = self._zero + for k in divisors(n): + if k < n: + val = self._series[n//k] + if val: + c += self[k] * val + return -c * self._ainv + + class Stream_cauchy_compose(Stream_binary): r""" Return ``f`` composed by ``g``. diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 6ba94aed722..ada9bb53ee0 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -4395,7 +4395,7 @@ def name(self, style="singular"): lambda x: x.node_number(), lambda x: isinstance(x, BinaryTree)), "Cores": - _SupportedFindStatCollection(lambda x: (lambda pi, k: Core(pi, k))(*literal_eval(x)), + _SupportedFindStatCollection(lambda x: Core(*literal_eval(x)), lambda X: "( " + X._repr_() + ", " + str(X.k()) + " )", lambda x: Cores(x[1], x[0]), lambda x: (x.length(), x.k()), diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 611755ebd6d..ead5a2174ef 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -389,7 +389,7 @@ def __call__(self, query, max_results=3, first_result=0): sage: oeis() Traceback (most recent call last): ... - TypeError: __call__() ... + TypeError: ...__call__() ... """ if isinstance(query, str): if re.match('^A[0-9]{6}$', query): diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index afb0d6cbcf1..8ba552e6806 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -38,9 +38,11 @@ from .reporting import DocTestReporter from .util import Timer, count_noun, dict_difference from .external import external_software, available_software +from .parsing import parse_optional_tags nodoctest_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*nodoctest') optionaltag_regex = re.compile(r'^\w+$') +optionalfiledirective_regex = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*sage\.doctest: (.*)') # Optional tags which are always automatically added @@ -99,7 +101,7 @@ def __init__(self, **kwds): self.all = False self.logfile = None self.long = False - self.warn_long = None + self.warn_long = -1.0 self.randorder = None self.random_seed = 0 self.global_iterations = 1 # sage-runtests default is 0 @@ -120,7 +122,7 @@ def __init__(self, **kwds): self.failed = False self.new = False self.show_skipped = False - self.target_walltime = None + self.target_walltime = -1 # sage-runtests contains more optional tags. Technically, adding # auto_optional_tags here is redundant, since that is added @@ -204,11 +206,23 @@ def skipdir(dirname): return True return False -def skipfile(filename): +def skipfile(filename, tested_optional_tags=False): """ Return True if and only if the file ``filename`` should not be doctested. + INPUT: + + - ``filename`` - name of a file + + - ``tested_optional_tags`` - a list or tuple or set of optional tags to test, + or ``False`` (no optional test) or ``True`` (all optional tests) + + If ``filename`` contains a line of the form ``"# sage.doctest: + optional - xyz")``, then this will return ``False`` if "xyz" is in + ``tested_optional_tags``. Otherwise, it returns the matching tag + ("optional - xyz"). + EXAMPLES:: sage: from sage.doctest.control import skipfile @@ -221,6 +235,18 @@ def skipfile(filename): ....: _ = f.write("# nodoctest") sage: skipfile(filename) True + sage: with open(filename, "w") as f: + ....: _ = f.write("# sage.doctest: optional - xyz") + sage: skipfile(filename, False) + 'optional - xyz' + sage: bool(skipfile(filename, False)) + True + sage: skipfile(filename, ['abc']) + 'optional - xyz' + sage: skipfile(filename, ['abc', 'xyz']) + False + sage: skipfile(filename, True) + False """ base, ext = os.path.splitext(filename) if ext not in ('.py', '.pyx', '.pxd', '.pxi', '.sage', '.spyx', '.rst', '.tex'): @@ -230,6 +256,16 @@ def skipfile(filename): for line in F: if nodoctest_regex.match(line): return True + if tested_optional_tags is not True: + # Adapted from code in SageDocTestParser.parse + m = optionalfiledirective_regex.match(line) + if m: + if tested_optional_tags is False: + return m.group(2) + optional_tags = parse_optional_tags('#' + m.group(2)) + extra = optional_tags - set(tested_optional_tags) + if extra: + return m.group(2) line_count += 1 if line_count >= 10: break @@ -382,11 +418,16 @@ def __init__(self, options, args): self.files = args if options.logfile: - try: - self.logfile = open(options.logfile, 'a') - except IOError: - print("Unable to open logfile {!r}\nProceeding without logging.".format(options.logfile)) - self.logfile = None + if not isinstance(options.logfile, str): + # file from sage-runtests + self.logfile = options.logfile + else: + # string from DocTestDefaults + try: + self.logfile = open(options.logfile, 'a') + except IOError: + print("Unable to open logfile {!r}\nProceeding without logging.".format(options.logfile)) + self.logfile = None else: self.logfile = None @@ -450,7 +491,8 @@ def _init_warn_long(self): sage: DC.options.warn_long # existing command-line options are not changed 5.00000000000000 """ - if self.options.warn_long is not None: # Specified on the command line + # default is -1.0 + if self.options.warn_long >= 0: # Specified on the command line return try: self.options.warn_long = 60.0 * self.second_on_modern_computer() @@ -780,7 +822,7 @@ def expand(): if dir[0] == "." or skipdir(os.path.join(root,dir)): dirs.remove(dir) for file in files: - if not skipfile(os.path.join(root,file)): + if not skipfile(os.path.join(root, file), self.options.optional): yield os.path.join(root, file) else: # the user input this file explicitly, so we don't skip it diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index 77f9c333977..aa81f16cc01 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -304,6 +304,19 @@ def has_rubiks(): from sage.features.rubiks import Rubiks return Rubiks().is_present() +def has_4ti2(): + """ + Test if the 4ti2 package is available. + + EXAMPLES:: + + sage: from sage.doctest.external import has_4ti2 + sage: has_4ti2() # optional -- 4ti2 + FeatureTestResult('4ti2', True) + """ + from sage.features.four_ti_2 import FourTi2 + return FourTi2().is_present() + def external_software(): """ Return the alphabetical list of external software supported by this module. @@ -346,7 +359,8 @@ class AvailableSoftware(object): sage: from sage.doctest.external import external_software, available_software sage: external_software - ['cplex', + ['4ti2', + 'cplex', 'ffmpeg', 'graphviz', 'gurobi', diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 960429a8ed0..0151041d08f 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -617,7 +617,7 @@ def _run(self, test, compileflags, out): # Skip this test if we exceeded our --short budget of walltime for # this doctest - if self.options.target_walltime is not None and self.total_walltime >= self.options.target_walltime: + if self.options.target_walltime != -1 and self.total_walltime >= self.options.target_walltime: walltime_skips += 1 self.optionflags |= doctest.SKIP @@ -766,7 +766,7 @@ def compiler(example): # Report the outcome. if outcome is SUCCESS: - if self.options.warn_long and example.walltime > self.options.warn_long: + if self.options.warn_long > 0 and example.walltime > self.options.warn_long: self.report_overtime(out, test, example, got) elif not quiet: self.report_success(out, test, example, got) @@ -1743,7 +1743,7 @@ def parallel_dispatch(self): # If we think that we can not finish running all tests until # target_endtime, we skip individual tests. (Only enabled with # --short.) - if opt.target_walltime is None: + if opt.target_walltime == -1: target_endtime = None else: target_endtime = time.time() + opt.target_walltime diff --git a/src/sage/doctest/reporting.py b/src/sage/doctest/reporting.py index 3752213e50a..f51e347670a 100644 --- a/src/sage/doctest/reporting.py +++ b/src/sage/doctest/reporting.py @@ -141,7 +141,7 @@ def have_optional_tag(self, tag): False """ - if tag in self.controller.options.optional: + if self.controller.options.optional is True or tag in self.controller.options.optional: return True if 'external' in self.controller.options.optional: if tag in available_software.seen(): @@ -182,10 +182,10 @@ def report_head(self, source): cmd += " --long" warnlong = self.controller.options.warn_long - if warnlong is not None: + if warnlong >= 0: cmd += " --warn-long" if warnlong != 1.0: - cmd += " %.1f"%(warnlong) + cmd += " %.1f" % (warnlong) seed = self.controller.options.random_seed cmd += " --random-seed={}".format(seed) cmd += " " + source.printpath diff --git a/src/sage/doctest/test.py b/src/sage/doctest/test.py index 997cd5ce7ee..1d9c0ef182d 100644 --- a/src/sage/doctest/test.py +++ b/src/sage/doctest/test.py @@ -327,7 +327,7 @@ Test logfiles in serial and parallel mode (see :trac:`19271`):: sage: t = tmp_filename() - sage: subprocess.call(["sage", "-t", "--serial", "--warn-long", "0", "--random-seed=0", "simple_failure.rst", "--logfile", t], stdout=open(os.devnull, "w"), **kwds) # long time + sage: subprocess.call(["sage", "-t", "--serial", "--warn-long", "0", "--random-seed=0", "--logfile", t, "simple_failure.rst"], stdout=open(os.devnull, "w"), **kwds) # long time 1 sage: print(open(t).read()) # long time Running doctests... @@ -350,7 +350,7 @@ ---------------------------------------------------------------------- ... - sage: subprocess.call(["sage", "-t", "--warn-long", "0", "--random-seed=0", "simple_failure.rst", "--logfile", t], stdout=open(os.devnull, "w"), **kwds) # long time + sage: subprocess.call(["sage", "-t", "--warn-long", "0", "--random-seed=0", "--logfile", t, "simple_failure.rst"], stdout=open(os.devnull, "w"), **kwds) # long time 1 sage: print(open(t).read()) # long time Running doctests... diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index bbec2269143..8f8578ef8b9 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -258,13 +258,13 @@ def __classcall_private__(cls, dynamical_system, domain=None, ideal=None): if not isinstance(morphism_domain.base_ring(), pAdicBaseGeneric): if morphism_domain.base_ring() in NumberFields(): - if domain is None and ideal != None: + if domain is None and ideal is not None: if is_AffineSpace(morphism_domain): domain = Berkovich_Cp_Affine(morphism_domain.base_ring(), ideal) else: domain = Berkovich_Cp_Projective(morphism_domain, ideal) else: - if ideal != None: + if ideal is not None: if ideal != domain.ideal(): raise ValueError('conflicting inputs for ideal and domain') else: diff --git a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py index 74f05820b49..825fdf9187a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py @@ -27,7 +27,7 @@ from copy import copy from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem from sage.dynamics.arithmetic_dynamics.projective_ds import DynamicalSystem_projective -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.quotient_ring import QuotientRing_generic from sage.schemes.product_projective.morphism import ProductProjectiveSpaces_morphism_ring diff --git a/src/sage/dynamics/finite_dynamical_system_catalog.py b/src/sage/dynamics/finite_dynamical_system_catalog.py index 429b06d73e9..fc925c2d5cf 100755 --- a/src/sage/dynamics/finite_dynamical_system_catalog.py +++ b/src/sage/dynamics/finite_dynamical_system_catalog.py @@ -299,14 +299,16 @@ def order_ideal_rowmotion(P): # Using P.order_ideals_lattice() instead causes intransparency issues: # sage can't always do P.rowmotion(I) when I is in P.order_ideals_lattice(). # Bug in P.order_ideals_lattice() when P is facade? - phi = lambda I : P.rowmotion(I) - def psi(I): # inverse of rowmotion + phi = P.rowmotion + + def psi(I): # inverse of rowmotion result = I for i in P.linear_extension(): result = P.order_ideal_toggle(result, i) return result return InvertibleFiniteDynamicalSystem(X, phi, inverse=psi) + def bulgarian_solitaire(n): r""" Return the finite discrete dynamical system defined diff --git a/src/sage/env.py b/src/sage/env.py index 2205c4f6573..44fc8481346 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -211,6 +211,15 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st MAXIMA_FAS = var("MAXIMA_FAS") KENZO_FAS = var("KENZO_FAS") SAGE_NAUTY_BINS_PREFIX = var("SAGE_NAUTY_BINS_PREFIX", "") +FOURTITWO_HILBERT = var("FOURTITWO_HILBERT") +FOURTITWO_MARKOV = var("FOURTITWO_MARKOV") +FOURTITWO_GRAVER = var("FOURTITWO_GRAVER") +FOURTITWO_ZSOLVE = var("FOURTITWO_ZSOLVE") +FOURTITWO_QSOLVE = var("FOURTITWO_QSOLVE") +FOURTITWO_RAYS = var("FOURTITWO_RAYS") +FOURTITWO_PPI = var("FOURTITWO_PPI") +FOURTITWO_CIRCUITS = var("FOURTITWO_CIRCUITS") +FOURTITWO_GROEBNER = var("FOURTITWO_GROEBNER") ARB_LIBRARY = var("ARB_LIBRARY", "arb") CBLAS_PC_MODULES = var("CBLAS_PC_MODULES", "cblas:openblas:blas") ECL_CONFIG = var("ECL_CONFIG", "ecl-config") @@ -397,18 +406,27 @@ def get_cblas_pc_module_name() -> str: cblas_pc_modules = CBLAS_PC_MODULES.split(':') return next((blas_lib for blas_lib in cblas_pc_modules if pkgconfig.exists(blas_lib))) -def cython_aliases(required_modules=('fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular', - 'libpng', 'gdlib', 'm4ri', 'zlib', 'cblas'), - optional_modules=('lapack',)): + +default_required_modules = ('fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular', + 'libpng', 'gdlib', 'm4ri', 'zlib', 'cblas') + + +default_optional_modules = ('lapack',) + + +def cython_aliases(required_modules=None, + optional_modules=None): """ Return the aliases for compiling Cython code. These aliases are macros which can occur in ``# distutils`` headers. INPUT: - - ``required_modules`` -- iterable of ``str`` values. + - ``required_modules`` -- (default: taken from ``default_required_modules``) + iterable of ``str`` values. - - ``optional_modules`` -- iterable of ``str`` values. + - ``optional_modules`` -- (default: taken from ``default_optional_modules``) + iterable of ``str`` values. EXAMPLES:: @@ -451,6 +469,12 @@ def cython_aliases(required_modules=('fflas-ffpack', 'givaro', 'gsl', 'linbox', import pkgconfig import itertools + if required_modules is None: + required_modules = default_required_modules + + if optional_modules is None: + optional_modules = default_optional_modules + aliases = {} for lib, required in itertools.chain(((lib, True) for lib in required_modules), diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 11d4b652ceb..d16ea7b5ed0 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -614,9 +614,9 @@ cdef class ExpressionTreeBuilder: sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder('x') sage: v = etb(3); v, type(v) - (3, ) + (3, ) sage: v = etb(polygen(QQ)); v, type(v) - (v_0, ) + (v_0, ) sage: v is etb(v) True """ @@ -1084,7 +1084,7 @@ cdef class ExpressionConstant(Expression): sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb(3)) - + """ cdef object _value @@ -1152,7 +1152,7 @@ cdef class ExpressionVariable(Expression): sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb.var(x)) - + """ cdef int _variable_index @@ -1219,7 +1219,7 @@ cdef class ExpressionCall(Expression): sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb.call(sin, x)) - + """ cdef object _function cdef object _arguments @@ -1308,7 +1308,7 @@ cdef class ExpressionIPow(Expression): sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb.var('x')^17) - + """ cdef object _base cdef object _exponent @@ -1708,7 +1708,7 @@ cpdef generate_code(Expression expr, InstructionStream stream): sage: instr_stream.instr('return') sage: v = Wrapper_py(instr_stream.get_current()) sage: type(v) - + sage: v(7) 8*pi + 56 @@ -1980,7 +1980,7 @@ cdef class InstructionStream: 'stack': 0} sage: md = instr_stream.get_metadata() sage: type(md) - + sage: md.by_opname['py_call'] (CompilerInstrSpec(0, 1, ['py_constants', 'n_inputs']), 3) sage: md.by_opcode[3] @@ -2154,7 +2154,7 @@ cdef class InstructionStream: sage: instr_stream = InstructionStream(metadata, 1) sage: md = instr_stream.get_metadata() sage: type(md) - + """ return self._metadata diff --git a/src/sage/ext/fast_eval.pxd b/src/sage/ext/fast_eval.pxd index f88495fa158..e69de29bb2d 100644 --- a/src/sage/ext/fast_eval.pxd +++ b/src/sage/ext/fast_eval.pxd @@ -1,30 +0,0 @@ -from cpython.object cimport PyObject - -cdef union double_op_params: - PyObject* func - double (*f)(double) - double (*ff)(double, double) - double c - int n - -cdef struct fast_double_op: - char type - double_op_params params - -cdef class FastDoubleFunc: - cdef readonly int max_height - cdef readonly int nargs - cdef readonly int nops - cdef fast_double_op* ops - - cdef double* argv - cdef double* stack - - # need to keep this around because structs can't contain (ref-counted) python objects - cdef py_funcs - - cdef int allocate_stack(FastDoubleFunc self) except -1 - cdef double _call_c(FastDoubleFunc self, double* argv) except? -2 - cpdef bint is_pure_c(self) - cdef FastDoubleFunc cfunc(FastDoubleFunc self, void* func) - cdef FastDoubleFunc unop(FastDoubleFunc self, char type) diff --git a/src/sage/ext/fast_eval.pyx b/src/sage/ext/fast_eval.pyx index d4e736b83ec..7b45ea1c5a0 100644 --- a/src/sage/ext/fast_eval.pyx +++ b/src/sage/ext/fast_eval.pyx @@ -9,68 +9,9 @@ point values. Doing this via recursive calls over a python representation of the object (even if Maxima or other outside packages are not involved) is extremely inefficient. -Up until now the solution has been to use lambda expressions, but this -is neither intuitive, Sage-like, nor efficient (compared to operating -on raw C doubles). This module provides a representation of algebraic -expression in Reverse Polish Notation, and provides an efficient -interpreter on C double values as a callable python object. It does -what it can in C, and will call out to Python if necessary. - -Essential to the understanding of this class is the distinction -between symbolic expressions and callable symbolic expressions (where -the latter binds argument names to argument positions). The -``*vars`` parameter passed around encapsulates this information. - -See the function ``fast_float(f, *vars)`` to create a fast-callable -version of f. - -.. NOTE:: - - Sage temporarily has two implementations of this functionality ; - one in this file, which will probably be deprecated soon, and one in - fast_callable.pyx. The following instructions are for the old - implementation; you probably want to be looking at fast_callable.pyx - instead. - -To provide this interface for a class, implement ``fast_float_(self, *vars)``. The basic building blocks are -provided by the functions ``fast_float_constant`` (returns a -constant function), ``fast_float_arg`` (selects the ``n``-th value -when called with ``\ge_n`` arguments), and ``fast_float_func`` which -wraps a callable Python function. These may be combined with the -standard Python arithmetic operators, and support many of the basic -math functions such ``sqrt``, ``exp``, and trig functions. - -EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float - sage: f = fast_float(sqrt(x^7+1), 'x', old=True) - sage: f(1) - 1.4142135623730951 - sage: f.op_list() - ['load 0', 'push 7.0', 'pow', 'push 1.0', 'add', 'call sqrt(1)'] - -To interpret that last line, we load argument 0 (``x`` in this case) onto -the stack, push the constant 2.0 onto the stack, call the pow function -(which takes 2 arguments from the stack), push the constant 1.0, add the -top two arguments of the stack, and then call sqrt. - -Here we take ``sin`` of the first argument and add it to ``f``:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: g = fast_float_arg(0).sin() - sage: (f+g).op_list() - ['load 0', 'push 7.0', 'pow', 'push 1.0', 'add', 'call sqrt(1)', 'load 0', 'call sin(1)', 'add'] - -TESTS: - -This used to segfault because of an assumption that assigning None to a -variable would raise a TypeError:: - - sage: from sage.ext.fast_eval import fast_float_arg, fast_float - sage: fast_float_arg(0)+None - Traceback (most recent call last): - ... - TypeError +The solution implemented in this module, by Robert Bradshaw (2008-10), +has been superseded by :func:`~sage.ext.fast_callable.fast_callable`. +All that remains here is a compatible interface function :func:`fast_float`. AUTHORS: @@ -87,1252 +28,8 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** -from cysignals.memory cimport sig_malloc, sig_free - from sage.ext.fast_callable import fast_callable, Wrapper -from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool - -cimport cython -from cpython.ref cimport Py_INCREF -from cpython.object cimport PyObject_CallObject -from cpython.int cimport PyInt_AS_LONG -from cpython.tuple cimport PyTuple_New, PyTuple_SET_ITEM - - -cdef extern from "math.h": - double sqrt(double) - double pow(double, double) - - double ceil(double) - double floor(double) - - double sin(double) - double cos(double) - double tan(double) - - double asin(double) - double acos(double) - double atan(double) - double atan2(double, double) - - double sinh(double) - double cosh(double) - double tanh(double) - - double asinh(double) - double acosh(double) - double atanh(double) - - double exp(double) - double log(double) - double log10(double) - double log2_ "log2"(double) - - -# This is only needed on Cygwin since log2 is a macro. -# If we don't do this the cygwin GCC gets very confused. -cdef inline double log2(double x): - return log2_(x) - -cdef extern from *: - void* memcpy(void* dst, void* src, size_t len) - -cdef inline int max(int a, int b): - return a if a > b else b - -cdef inline int min(int a, int b): - return a if a < b else b - -cdef enum: -# stack - LOAD_ARG # push input argument n onto the stack - PUSH_CONST - POP - POP_N - DUP - -# basic arithmetic - ADD - SUB - MUL - DIV - NEG - ABS - INVERT - POW - -# basic comparison - LT - LE - EQ - NE - GT - GE - -# functional - ONE_ARG_FUNC - TWO_ARG_FUNC - PY_FUNC - - -# These two dictionaries are for printable and machine independent representation. - -op_names = { - LOAD_ARG: 'load', - PUSH_CONST: 'push', - POP: 'pop', - POP_N: 'popn', - DUP: 'dup', - - ADD: 'add', - SUB: 'sub', - MUL: 'mul', - DIV: 'div', - NEG: 'neg', - ABS: 'abs', - INVERT: 'invert', - POW: 'pow', - - - LT: 'lt', - LE: 'le', - EQ: 'eq', - NE: 'ne', - GT: 'gt', - GE: 'ge', - - - ONE_ARG_FUNC: 'call', - TWO_ARG_FUNC: 'call', - PY_FUNC: 'py_call', -} - -cfunc_names = { - &sqrt: 'sqrt', - &pow: 'pow', - - &ceil: 'ceil', - &floor: 'floor', - - &sin: 'sin', - &cos: 'cos', - &tan: 'tan', - - &asin: 'asin', - &atan: 'atan', - &atan2: 'atan2', - - &sinh: 'sinh', - &cosh: 'cosh', - &tanh: 'tanh', - - &asinh: 'asinh', - &acosh: 'acosh', - &atanh: 'atanh', - - &exp: 'exp', - &log: 'log', - &log2: 'log2', - &log10: 'log10', - -} - -cdef reverse_map(m): - r = {} - for key, value in m.iteritems(): - r[value] = key - return r - -# With all the functionality around the op struct, perhaps there should be -# a wrapper class, though we still wish to operate on pure structs for speed. - -cdef op_to_string(fast_double_op op): - s = op_names[op.type] - if op.type in [LOAD_ARG, POP_N]: - s += " %s" % op.params.n - elif op.type == PUSH_CONST: - s += " %s" % op.params.c - elif op.type in [ONE_ARG_FUNC, TWO_ARG_FUNC]: - try: - cname = cfunc_names[op.params.func] - except KeyError: - cname = "0x%x" % op.params.func - s += " %s(%s)" % (cname, 1 if op.type == ONE_ARG_FUNC else 2) - elif op.type == PY_FUNC: - n, func = (op.params.func) - s += " %s(%s)" % (func, n) - return s - -cdef op_to_tuple(fast_double_op op): - s = op_names[op.type] - if op.type in [LOAD_ARG, POP_N]: - param = op.params.n - elif op.type == PUSH_CONST: - param = op.params.c - elif op.type in [ONE_ARG_FUNC, TWO_ARG_FUNC]: - param_count = 1 if op.type == ONE_ARG_FUNC else 2 - try: - param = param_count, cfunc_names[op.params.func] - except KeyError: - raise ValueError("Unknown C function: 0x%x" - % op.params.func) - elif op.type == PY_FUNC: - param = (op.params.func) - else: - param = None - if param is None: - return (s,) - else: - return s, param - -def _unpickle_FastDoubleFunc(nargs, max_height, op_list): - cdef FastDoubleFunc self = FastDoubleFunc.__new__(FastDoubleFunc) - self.nops = len(op_list) - self.nargs = nargs - self.max_height = max_height - self.ops = sig_malloc(sizeof(fast_double_op) * self.nops) - self.allocate_stack() - cfunc_addresses = reverse_map(cfunc_names) - op_enums = reverse_map(op_names) - cdef size_t address - cdef int i = 0, type - for op in op_list: - self.ops[i].type = type = op_enums[op[0]] - if type in [LOAD_ARG, POP_N]: - self.ops[i].params.n = op[1] - elif type == PUSH_CONST: - self.ops[i].params.c = op[1] - elif type in [ONE_ARG_FUNC, TWO_ARG_FUNC]: - param_count, cfunc = op[1] - address = cfunc_addresses[cfunc] - self.ops[i].params.func = address - self.ops[i].type = ['', ONE_ARG_FUNC, TWO_ARG_FUNC][param_count] - elif type == PY_FUNC: - if self.py_funcs is None: - self.py_funcs = op[1] - else: - self.py_funcs = self.py_funcs + (op[1],) - self.ops[i].params.func = op[1] - i += 1 - return self - - -@cython.boundscheck(False) -@cython.wraparound(False) -cdef inline int process_op(fast_double_op op, double* stack, double* argv, int top) except -2: - cdef int i, n - cdef object arg - cdef tuple py_args - - if op.type == LOAD_ARG: - stack[top+1] = argv[op.params.n] - return top+1 - - elif op.type == PUSH_CONST: - stack[top+1] = op.params.c - return top+1 - - elif op.type == POP: - return top-1 - - elif op.type == POP_N: - return top-op.params.n - - elif op.type == DUP: - stack[top+1] = stack[top] - return top+1 - - elif op.type == ADD: - stack[top-1] += stack[top] - return top-1 - - elif op.type == SUB: - stack[top-1] -= stack[top] - return top-1 - - elif op.type == MUL: - stack[top-1] *= stack[top] - return top-1 - - elif op.type == DIV: - stack[top-1] /= stack[top] - return top-1 - - elif op.type == NEG: - stack[top] = -stack[top] - return top - - elif op.type == ABS: - if stack[top] < 0: - stack[top] = -stack[top] - return top - - elif op.type == INVERT: - stack[top] = 1/stack[top] - return top - - elif op.type == POW: - if stack[top-1] < 0 and stack[top] != floor(stack[top]): - raise ValueError("negative number to a fractional power not real") - stack[top-1] = pow(stack[top-1], stack[top]) - return top-1 - - elif op.type == LT: - stack[top-1] = 1.0 if stack[top-1] < stack[top] else 0.0 - return top-1 - - elif op.type == LE: - stack[top-1] = 1.0 if stack[top-1] <= stack[top] else 0.0 - return top-1 - - elif op.type == EQ: - stack[top-1] = 1.0 if stack[top-1] == stack[top] else 0.0 - return top-1 - - elif op.type == NE: - stack[top-1] = 1.0 if stack[top-1] != stack[top] else 0.0 - return top-1 - - elif op.type == GT: - stack[top-1] = 1.0 if stack[top-1] > stack[top] else 0.0 - return top-1 - - elif op.type == GE: - stack[top-1] = 1.0 if stack[top-1] >= stack[top] else 0.0 - return top-1 - - elif op.type == ONE_ARG_FUNC: - stack[top] = (op.params.f)(stack[top]) - return top - - elif op.type == TWO_ARG_FUNC: - stack[top-1] = (op.params.ff)(stack[top-1], stack[top]) - return top-1 - - elif op.type == PY_FUNC: - # We use a few direct C/API calls here because Cython itself - # doesn't generate optimal code for this. - n = PyInt_AS_LONG((op.params.func)[0]) - top = top - n + 1 - py_args = PyTuple_New(n) - for i in range(n): - arg = stack[top+i] - Py_INCREF(arg) # PyTuple_SET_ITEM() steals a reference - PyTuple_SET_ITEM(py_args, i, arg) - stack[top] = PyObject_CallObject((op.params.func)[1], py_args) - return top - - raise RuntimeError("Bad op code %s" % op.type) - - -cdef class FastDoubleFunc: - """ - This class is for fast evaluation of algebraic expressions over - the real numbers (e.g. for plotting). It represents an expression - as a stack-based series of operations. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import FastDoubleFunc - sage: f = FastDoubleFunc('const', 1.5) # the constant function - sage: f() - 1.5 - sage: g = FastDoubleFunc('arg', 0) # the first argument - sage: g(5) - 5.0 - sage: h = f+g - sage: h(17) - 18.5 - sage: h = h.sin() - sage: h(pi/2-1.5) - 1.0 - sage: h.is_pure_c() - True - sage: list(h) - ['push 1.5', 'load 0', 'add', 'call sin(1)'] - - We can wrap Python functions too:: - - sage: h = FastDoubleFunc('callable', lambda x,y: x*x*x - y, g, f) - sage: h(10) - 998.5 - sage: h.is_pure_c() - False - sage: list(h) - ['load 0', 'push 1.5', 'py_call at 0x...>(2)'] - - Here's a more complicated expression:: - - sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg - sage: a = fast_float_constant(1.5) - sage: b = fast_float_constant(3.14) - sage: c = fast_float_constant(7) - sage: x = fast_float_arg(0) - sage: y = fast_float_arg(1) - sage: f = a*x^2 + b*x + c - y/sqrt(sin(y)^2+a) - sage: f(2,3) - 16.846610528508116 - sage: f.max_height - 4 - sage: f.is_pure_c() - True - sage: list(f) - ['push 1.5', 'load 0', 'dup', 'mul', 'mul', 'push 3.14', 'load 0', 'mul', 'add', 'push 7.0', 'add', 'load 1', 'load 1', 'call sin(1)', 'dup', 'mul', 'push 1.5', 'add', 'call sqrt(1)', 'div', 'sub'] - - AUTHORS: - - - Robert Bradshaw - """ - def __init__(self, type, param, *args): - - cdef FastDoubleFunc arg - cdef int i - - if type == 'arg': - self.nargs = param+1 - self.nops = 1 - self.max_height = 1 - self.ops = sig_malloc(sizeof(fast_double_op)) - self.ops[0].type = LOAD_ARG - self.ops[0].params.n = param - - elif type == 'const': - self.nargs = 0 - self.nops = 1 - self.max_height = 1 - self.ops = sig_malloc(sizeof(fast_double_op)) - self.ops[0].type = PUSH_CONST - self.ops[0].params.c = param - - elif type == 'callable': - py_func = len(args), param - self.py_funcs = (py_func,) # just so it doesn't get garbage collected - self.nops = 1 - self.nargs = 0 - for i from 0 <= i < len(args): - a = args[i] - if not isinstance(a, FastDoubleFunc): - a = FastDoubleFunc('const', a) - args = args[:i] + (a,) + args[i+1:] - arg = a - self.nops += arg.nops - if arg.py_funcs is not None: - self.py_funcs += arg.py_funcs - self.nargs = max(self.nargs, arg.nargs) - self.max_height = max(self.max_height, arg.max_height+i) - self.ops = sig_malloc(sizeof(fast_double_op) * self.nops) - if self.ops == NULL: - raise MemoryError - i = 0 - for arg in args: - memcpy(self.ops + i, arg.ops, sizeof(fast_double_op) * arg.nops) - i += arg.nops - self.ops[self.nops-1].type = PY_FUNC - self.ops[self.nops-1].params.func = py_func - - else: - raise ValueError("Unknown operation: %s" % type) - - self.allocate_stack() - - cdef int allocate_stack(FastDoubleFunc self) except -1: - self.argv = sig_malloc(sizeof(double) * self.nargs) - if self.argv == NULL: - raise MemoryError - self.stack = sig_malloc(sizeof(double) * self.max_height) - if self.stack == NULL: - raise MemoryError - - def __dealloc__(self): - sig_free(self.ops) - sig_free(self.stack) - sig_free(self.argv) - - def __reduce__(self): - """ - TESTS:: - - sage: from sage.ext.fast_eval import fast_float_arg, fast_float_func - sage: f = fast_float_arg(0).sin() * 10 + fast_float_func(hash, fast_float_arg(1)) - sage: loads(dumps(f)) == f - True - """ - L = [op_to_tuple(self.ops[i]) for i from 0 <= i < self.nops] - return _unpickle_FastDoubleFunc, (self.nargs, self.max_height, L) - - def __richcmp__(self, other, op): - """ - Two functions are considered equal if they represent the same - exact sequence of operations. - - TESTS:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: fast_float_arg(0) == fast_float_arg(0) - True - sage: fast_float_arg(0) == fast_float_arg(1) - False - sage: fast_float_arg(0) == fast_float_arg(0).sin() - False - """ - cdef int c, i - cdef FastDoubleFunc left, right - try: - left = self - right = other - - lx = left.nargs - rx = right.nargs - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - lx = left.nops - rx = right.nops - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - lx = left.max_height - rx = right.max_height - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - for i from 0 <= i < self.nops: - lx = left.ops[i].type - rx = right.ops[i].type - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - for i from 0 <= i < self.nops: - lx = op_to_tuple(left.ops[i]) - rx = op_to_tuple(right.ops[i]) - if lx != rx: - return richcmp_not_equal(lx, rx, op) - - return rich_to_bool(op, 0) - except TypeError: - return NotImplemented - - def __call__(FastDoubleFunc self, *args): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(2) - sage: f(0,1,2,3) - 2.0 - sage: f(10) - Traceback (most recent call last): - ... - TypeError: Wrong number of arguments (need at least 3, got 1) - sage: f('blah', 1, 2, 3) # py2 - Traceback (most recent call last): - ... - TypeError: a float is required - sage: f('blah', 1, 2, 3) # py3 - Traceback (most recent call last): - ... - TypeError: must be real number, not str - """ - if len(args) < self.nargs: - raise TypeError("Wrong number of arguments (need at least %s, got %s)" % (self.nargs, len(args))) - cdef int i = 0 - for i from 0 <= i < self.nargs: - self.argv[i] = args[i] - res = self._call_c(self.argv) - return res - - cdef double _call_c(FastDoubleFunc self, double* argv) except? -2: - # The caller must assure that argv has length at least self.nargs - # The bulk of this function is in the (inlined) function process_op. - cdef int i, top = -1 - for i from 0 <= i < self.nops: - top = process_op(self.ops[i], self.stack, argv, top) - cdef double res = self.stack[0] - return res - - def _fast_float_(self, *vars): - r""" - Returns ``self`` if there are enough arguments, otherwise raises a ``TypeError``. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(1) - sage: f._fast_float_('x','y') is f - True - sage: f._fast_float_('x') is f - Traceback (most recent call last): - ... - TypeError: Needs at least 2 arguments (1 provided) - """ - if self.nargs > len(vars): - raise TypeError("Needs at least %s arguments (%s provided)" % (self.nargs, len(vars))) - return self - - def op_list(self): - """ - Returns a list of string representations of the - operations that make up this expression. - - Python and C function calls may be only available by function - pointer addresses. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg - sage: a = fast_float_constant(17) - sage: x = fast_float_arg(0) - sage: a.op_list() - ['push 17.0'] - sage: x.op_list() - ['load 0'] - sage: (a*x).op_list() - ['push 17.0', 'load 0', 'mul'] - sage: (a+a*x^2).sqrt().op_list() - ['push 17.0', 'push 17.0', 'load 0', 'dup', 'mul', 'mul', 'add', 'call sqrt(1)'] - """ - cdef int i - return [op_to_string(self.ops[i]) for i from 0 <= i < self.nops] - - def __iter__(self): - """ - Returns the list of operations of ``self``. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0)*2 + 3 - sage: list(f) - ['load 0', 'push 2.0', 'mul', 'push 3.0', 'add'] - """ - return iter(self.op_list()) - - cpdef bint is_pure_c(self): - """ - Returns ``True`` if this function can be evaluated without - any python calls (at any level). - - EXAMPLES:: - sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg, fast_float_func - sage: fast_float_constant(2).is_pure_c() - True - sage: fast_float_arg(2).sqrt().sin().is_pure_c() - True - sage: fast_float_func(lambda _: 2).is_pure_c() - False - """ - cdef int i - for i from 0 <= i < self.nops: - if self.ops[i].type == PY_FUNC: - return 0 - return 1 - - def python_calls(self): - """ - Returns a list of all python calls used by function. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_func, fast_float_arg - sage: x = fast_float_arg(0) - sage: f = fast_float_func(hash, sqrt(x)) - sage: f.op_list() - ['load 0', 'call sqrt(1)', 'py_call (1)'] - sage: f.python_calls() - [] - """ - L = [] - cdef int i - for i from 0 <= i < self.nops: - if self.ops[i].type == PY_FUNC: - L.append((self.ops[i].params.func)[1]) - return L - - ################################################################### - # Basic Arithmetic - ################################################################### - - def __add__(left, right): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0) + fast_float_arg(1) - sage: f(3,4) - 7.0 - """ - return binop(left, right, ADD) - - def __sub__(left, right): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0) - fast_float_arg(2) - sage: f(3,4,5) - -2.0 - """ - return binop(left, right, SUB) - - def __mul__(left, right): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0) * 2 - sage: f(17) - 34.0 - """ - return binop(left, right, MUL) - - def __truediv__(left, right): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).__truediv__(7) - sage: f(14) - 2.0 - """ - return binop(left, right, DIV) - - def __pow__(FastDoubleFunc left, right, dummy): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import FastDoubleFunc - sage: f = FastDoubleFunc('arg', 0)^2 - sage: f(2) - 4.0 - sage: f = FastDoubleFunc('arg', 0)^4 - sage: f(2) - 16.0 - sage: f = FastDoubleFunc('arg', 0)^-3 - sage: f(2) - 0.125 - sage: f = FastDoubleFunc('arg', 0)^FastDoubleFunc('arg', 1) - sage: f(5,3) - 125.0 - - TESTS:: - - sage: var('a,b') - (a, b) - sage: ff = (a^b)._fast_float_(a,b) - sage: ff(2, 9) - 512.0 - sage: ff(-2, 9) - -512.0 - sage: ff(-2, 9.1) - Traceback (most recent call last): - ... - ValueError: negative number to a fractional power not real - """ - if isinstance(right, FastDoubleFunc) and right.nargs == 0: - right = float(right) - if not isinstance(right, FastDoubleFunc): - if right == int(float(right)): - if right == 1: - return left - elif right == 2: - return left.unop(DUP).unop(MUL) - elif right == 3: - return left.unop(DUP).unop(DUP).unop(MUL).unop(MUL) - elif right == 4: - return left.unop(DUP).unop(MUL).unop(DUP).unop(MUL) - elif right < 0: - return (~left)**(-right) - right = FastDoubleFunc('const', right) - cdef FastDoubleFunc feval = binop(left, right, POW) - return feval - - def __neg__(FastDoubleFunc self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = -fast_float_arg(0) - sage: f(3.5) - -3.5 - """ - return self.unop(NEG) - - def __abs__(FastDoubleFunc self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = abs(fast_float_arg(0)) - sage: f(-3) - 3.0 - """ - return self.unop(ABS) - - def __float__(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_constant, fast_float_arg - sage: ff = fast_float_constant(17) - sage: float(ff) - 17.0 - sage: ff = fast_float_constant(17) - fast_float_constant(2)^2 - sage: float(ff) - 13.0 - sage: ff = fast_float_constant(17) - fast_float_constant(2)^2 + fast_float_arg(1) - sage: float(ff) - Traceback (most recent call last): - ... - TypeError: Not a constant. - """ - if self.nargs == 0: - return self._call_c(NULL) - else: - raise TypeError("Not a constant.") - - def abs(FastDoubleFunc self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).abs() - sage: f(3) - 3.0 - """ - return self.unop(ABS) - - def __invert__(FastDoubleFunc self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = ~fast_float_arg(0) - sage: f(4) - 0.25 - """ - return self.unop(INVERT) - - def sqrt(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).sqrt() - sage: f(4) - 2.0 - """ - return self.cfunc(&sqrt) - - ################################################################### - # Exponential and log - ################################################################### - - def log(self, base=None): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).log() - sage: f(2) - 0.693147180559945... - sage: f = fast_float_arg(0).log(2) - sage: f(2) - 1.0 - sage: f = fast_float_arg(0).log(3) - sage: f(9) - 2.0... - """ - if base is None: - return self.cfunc(&log) - elif base == 2: - return self.cfunc(&log2) - elif base == 10: - return self.cfunc(&log10) - else: - try: - base = fast_float_constant(log(float(base))) - except TypeError as e: - base = fast_float(base.log()) - return binop(self.cfunc(&log), base, DIV) - - def exp(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).exp() - sage: f(1) - 2.718281828459045... - sage: f(100) - 2.6881171418161356e+43 - """ - return self.cfunc(&exp) - - ################################################################### - # Rounding - ################################################################### - - def ceil(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).ceil() - sage: f(1.5) - 2.0 - sage: f(-1.5) - -1.0 - """ - return self.cfunc(&ceil) - - def floor(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).floor() - sage: f(11.5) - 11.0 - sage: f(-11.5) - -12.0 - """ - return self.cfunc(&floor) - - ################################################################### - # Trigonometric - ################################################################### - - def sin(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).sin() - sage: f(pi/2) - 1.0 - """ - return self.cfunc(&sin) - - def cos(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).cos() - sage: f(0) - 1.0 - """ - return self.cfunc(&cos) - - def tan(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).tan() - sage: f(pi/3) - 1.73205080756887... - """ - return self.cfunc(&tan) - - def csc(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).csc() - sage: f(pi/2) - 1.0 - """ - return ~self.sin() - - def sec(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).sec() - sage: f(pi) - -1.0 - """ - return ~self.cos() - - def cot(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).cot() - sage: f(pi/4) - 1.0... - """ - return ~self.tan() - - def arcsin(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arcsin() - sage: f(0.5) - 0.523598775598298... - """ - return self.cfunc(&asin) - - def arccos(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arccos() - sage: f(sqrt(3)/2) - 0.5235987755982989... - """ - return self.cfunc(&acos) - - def arctan(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arctan() - sage: f(1) - 0.785398163397448... - """ - return self.cfunc(&atan) - - ################################################################### - # Hyperbolic - ################################################################### - - def sinh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).sinh() - sage: f(log(2)) - 0.75 - """ - return self.cfunc(&sinh) - - def cosh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).cosh() - sage: f(log(2)) - 1.25 - """ - return self.cfunc(&cosh) - - def tanh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).tanh() - sage: f(0) - 0.0 - """ - return self.cfunc(&tanh) - - def arcsinh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arcsinh() - sage: f(sinh(5)) - 5.0 - """ - return self.cfunc(&asinh) - - def arccosh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arccosh() - sage: f(cosh(5)) - 5.0 - """ - return self.cfunc(&acosh) - - def arctanh(self): - """ - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0).arctanh() - sage: abs(f(tanh(0.5)) - 0.5) < 0.0000001 - True - """ - return self.cfunc(&atanh) - - cdef FastDoubleFunc cfunc(FastDoubleFunc self, void* func): - cdef FastDoubleFunc feval = self.unop(ONE_ARG_FUNC) - feval.ops[feval.nops - 1].params.func = func - feval.allocate_stack() - return feval - - ################################################################### - # Utility functions - ################################################################### - - cdef FastDoubleFunc unop(FastDoubleFunc self, char type): - cdef FastDoubleFunc feval = FastDoubleFunc.__new__(FastDoubleFunc) - feval.nargs = self.nargs - feval.nops = self.nops + 1 - feval.max_height = self.max_height - if type == DUP: - feval.max_height += 1 - feval.ops = sig_malloc(sizeof(fast_double_op) * feval.nops) - memcpy(feval.ops, self.ops, sizeof(fast_double_op) * self.nops) - feval.ops[feval.nops - 1].type = type - feval.py_funcs = self.py_funcs - feval.allocate_stack() - return feval - -cdef FastDoubleFunc binop(_left, _right, char type): - r""" - Returns a function that calculates left and right on the stack, leaving - their results on the top, and then calls operation ``type``. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(1) - sage: g = fast_float_arg(2) * 11 - sage: f.op_list() - ['load 1'] - sage: g.op_list() - ['load 2', 'push 11.0', 'mul'] - sage: (f+g).op_list() - ['load 1', 'load 2', 'push 11.0', 'mul', 'add'] - - Correctly calculates the maximum stack heights and number of arguments:: - - sage: f.max_height - 1 - sage: g.max_height - 2 - sage: (f+g).max_height - 3 - sage: (g+f).max_height - 2 - - sage: f.nargs - 2 - sage: g.nargs - 3 - sage: (f+g).nargs - 3 - """ - cdef FastDoubleFunc left, right - try: - left = _left - except TypeError: - left = fast_float(_left) - try: - right = _right - except TypeError: - right = fast_float(_right) - - # In Cython assigning None does NOT raise a TypeError above. - if left is None or right is None: - raise TypeError - - cdef FastDoubleFunc feval = FastDoubleFunc.__new__(FastDoubleFunc) - feval.nargs = max(left.nargs, right.nargs) - feval.nops = left.nops + right.nops + 1 - feval.max_height = max(left.max_height, right.max_height+1) - feval.ops = sig_malloc(sizeof(fast_double_op) * feval.nops) - memcpy(feval.ops, left.ops, sizeof(fast_double_op) * left.nops) - memcpy(feval.ops + left.nops, right.ops, sizeof(fast_double_op) * right.nops) - feval.ops[feval.nops - 1].type = type - if left.py_funcs is None: - feval.py_funcs = right.py_funcs - elif right.py_funcs is None: - feval.py_funcs = left.py_funcs - else: - feval.py_funcs = left.py_funcs + right.py_funcs - feval.allocate_stack() - return feval - - -def fast_float_constant(x): - """ - Return a fast-to-evaluate constant function. - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_constant - sage: f = fast_float_constant(-2.75) - sage: f() - -2.75 - - This is all that goes on under the hood:: - - sage: fast_float_constant(pi).op_list() - ['push 3.1415926535...'] - """ - return FastDoubleFunc('const', x) - -def fast_float_arg(n): - """ - Return a fast-to-evaluate argument selector. - - INPUT: - - - ``n`` -- the (zero-indexed) argument to select - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_arg - sage: f = fast_float_arg(0) - sage: f(1,2) - 1.0 - sage: f = fast_float_arg(1) - sage: f(1,2) - 2.0 - - This is all that goes on under the hood:: - - sage: fast_float_arg(10).op_list() - ['load 10'] - """ - return FastDoubleFunc('arg', n) - -def fast_float_func(f, *args): - """ - Returns a wrapper around a python function. - - INPUT: - - - ``f`` -- a callable python object - - ``args`` -- a list of FastDoubleFunc inputs - - EXAMPLES:: - - sage: from sage.ext.fast_eval import fast_float_func, fast_float_arg - sage: f = fast_float_arg(0) - sage: g = fast_float_arg(1) - sage: h = fast_float_func(lambda x,y: x-y, f, g) - sage: h(5, 10) - -5.0 - - This is all that goes on under the hood:: - - sage: h.op_list() - ['load 0', 'load 1', 'py_call at 0x...>(2)'] - """ - return FastDoubleFunc('callable', f, *args) - - -new_fast_float=True def fast_float(f, *vars, old=None, expect_one_var=False): """ @@ -1347,7 +44,7 @@ def fast_float(f, *vars, old=None, expect_one_var=False): - ``f`` -- an expression - ``vars`` -- the names of the arguments - - ``old`` -- use the original algorithm for fast_float + - ``old`` -- deprecated, do not use - ``expect_one_var`` -- don't give deprecation warning if ``vars`` is omitted, as long as expression has only one var @@ -1369,8 +66,11 @@ def fast_float(f, *vars, old=None, expect_one_var=False): sage: f(1,2) 1.0 """ - if old is None: - old = not new_fast_float + if old: + raise ValueError("the old implementation of fast_float has been removed") + if old is not None: + from sage.misc.superseded import deprecation + deprecation(32234, "passing old=False to fast_float is deprecated") if isinstance(f, (tuple, list)): return tuple([fast_float(x, *vars, expect_one_var=expect_one_var) for x in f]) @@ -1385,19 +85,11 @@ def fast_float(f, *vars, old=None, expect_one_var=False): vars = vars[:i] + (v,) + vars[i+1:] try: - if old: - return f._fast_float_(*vars) - else: - return fast_callable(f, vars=vars, domain=float, - expect_one_var=expect_one_var) + return fast_callable(f, vars=vars, domain=float, + expect_one_var=expect_one_var) except AttributeError: pass - try: - return FastDoubleFunc('const', float(f)) - except TypeError: - pass - try: from sage.symbolic.ring import SR return fast_float(SR(f), *vars) @@ -1411,4 +103,4 @@ def fast_float(f, *vars, old=None, expect_one_var=False): def is_fast_float(x): - return isinstance(x, FastDoubleFunc) or isinstance(x, Wrapper) + return isinstance(x, Wrapper) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 42058cf07dc..839bde0d8d4 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -52,8 +52,7 @@ """ import os -from distutils.errors import CCompilerError -from distutils.spawn import find_executable +import shutil from sage.env import SAGE_SHARE from sage.misc.lazy_string import lazy_string @@ -571,6 +570,8 @@ class Executable(Feature): sage: from sage.features import Executable sage: Executable(name="sh", executable="sh").is_present() FeatureTestResult('sh', True) + sage: Executable(name="does-not-exist", executable="does-not-exist-xxxxyxyyxyy").is_present() + FeatureTestResult('does-not-exist', False) """ def __init__(self, name, executable, **kwds): r""" @@ -595,7 +596,7 @@ def _is_present(self): sage: Executable(name="sh", executable="sh").is_present() FeatureTestResult('sh', True) """ - if find_executable(self.executable) is None: + if shutil.which(self.executable) is None: return FeatureTestResult(self, False, "Executable {executable!r} not found on PATH.".format(executable=self.executable)) return self.is_functional() @@ -768,6 +769,7 @@ def _is_present(self): FeatureTestResult('empty', True) """ from sage.misc.temporary_file import tmp_filename + from distutils.errors import CCompilerError with open(tmp_filename(ext=".pyx"), 'w') as pyx: pyx.write(self.test_code) from sage.misc.cython import cython_import diff --git a/src/sage/features/four_ti_2.py b/src/sage/features/four_ti_2.py new file mode 100644 index 00000000000..7f53a1135b9 --- /dev/null +++ b/src/sage/features/four_ti_2.py @@ -0,0 +1,32 @@ +from . import Executable +from .join_feature import JoinFeature + + +class FourTi2Executable(Executable): + r""" + Feature for the 4ti2 executables. + """ + def __init__(self, name): + from sage.env import SAGE_ENV + Executable.__init__(self, + name="4ti2-" + name, + executable=SAGE_ENV.get("FOURTITWO_" + name.upper(), None) or name, + spkg="4ti2") + + +class FourTi2(JoinFeature): + r""" + A :class:`sage.features.Feature` describing the presence of the ``4ti2`` executables. + + EXAMPLES:: + + sage: from sage.features.four_ti_2 import FourTi2 + sage: FourTi2().is_present() # optional - 4ti2 + FeatureTestResult('4ti2', True) + """ + def __init__(self): + JoinFeature.__init__(self, '4ti2', + [FourTi2Executable(x) + # same list is tested in build/pkgs/4ti2/spkg-configure.m4 + for x in ('hilbert', 'markov', 'graver', 'zsolve', 'qsolve', + 'rays', 'ppi', 'circuits', 'groebner')]) diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py new file mode 100644 index 00000000000..f011b40a7f6 --- /dev/null +++ b/src/sage/features/join_feature.py @@ -0,0 +1,82 @@ +r""" +Join features +""" + +from . import Feature, FeatureTestResult + + +class JoinFeature(Feature): + r""" + Join of several :class:`sage.features.Feature` instances. + + EXAMPLES:: + + sage: from sage.features import Executable + sage: from sage.features.join_feature import JoinFeature + sage: F = JoinFeature("shell-boolean", + ....: (Executable('shell-true', 'true'), + ....: Executable('shell-false', 'false'))) + sage: F.is_present() + FeatureTestResult('shell-boolean', True) + sage: F = JoinFeature("asdfghjkl", + ....: (Executable('shell-true', 'true'), + ....: Executable('xxyyyy', 'xxyyyy-does-not-exist'))) + sage: F.is_present() + FeatureTestResult('xxyyyy', False) + """ + def __init__(self, name, features, spkg=None, url=None): + """ + TESTS: + + The empty join feature is present:: + + sage: from sage.features.join_feature import JoinFeature + sage: JoinFeature("empty", ()).is_present() + FeatureTestResult('empty', True) + """ + if spkg is None: + spkgs = set(f.spkg for f in features if f.spkg) + if len(spkgs) > 1: + raise ValueError('given features have more than one spkg; provide spkg argument') + elif len(spkgs) == 1: + spkg = next(iter(spkgs)) + if url is None: + urls = set(f.url for f in features if f.url) + if len(urls) > 1: + raise ValueError('given features have more than one url; provide url argument') + elif len(urls) == 1: + url = next(iter(urls)) + super().__init__(name, spkg=spkg, url=url) + self._features = features + + def _is_present(self): + r""" + Test for the presence of the join feature. + + EXAMPLES:: + + sage: from sage.features.latte import Latte + sage: Latte()._is_present() # optional - latte_int + FeatureTestResult('LattE', True) + """ + for f in self._features: + test = f._is_present() + if not test: + return test + return FeatureTestResult(self, True) + + def is_functional(self): + r""" + Test whether the join feature is functional. + + EXAMPLES:: + + sage: from sage.features.latte import Latte + sage: Latte().is_functional() # optional - latte_int + FeatureTestResult('LattE', True) + """ + for f in self._features: + test = f.is_functional() + if not test: + return test + return FeatureTestResult(self, True) diff --git a/src/sage/features/latte.py b/src/sage/features/latte.py index 5462331177d..6abc450281c 100644 --- a/src/sage/features/latte.py +++ b/src/sage/features/latte.py @@ -3,6 +3,8 @@ Check for LattE """ from . import Executable, Feature, FeatureTestResult +from .join_feature import JoinFeature + LATTE_URL = "https://www.math.ucdavis.edu/~latte/software.php" @@ -27,7 +29,7 @@ def __init__(self): url=LATTE_URL) -class Latte(Feature): +class Latte(JoinFeature): r""" A :class:`sage.features.Feature` describing the presence of the ``LattE`` binaries which comes as a part of ``latte_int``. @@ -46,39 +48,5 @@ def __init__(self): sage: isinstance(Latte(), Latte) True """ - Feature.__init__(self, "LattE") - - def _is_present(self): - r""" - Test for the presence of LattE binaries. - - EXAMPLES:: - - sage: from sage.features.latte import Latte - sage: Latte()._is_present() # optional - latte_int - FeatureTestResult('LattE', True) - """ - - test = (Latte_count()._is_present() and - Latte_integrate()._is_present()) - if not test: - return test - - return FeatureTestResult(self, True) - - def is_functional(self): - r""" - Test whether count and integrate are functionals. - - EXAMPLES:: - - sage: from sage.features.latte import Latte - sage: Latte().is_functional() # optional - latte_int - FeatureTestResult('LattE', True) - """ - test = (Latte_count().is_functional() and - Latte_integrate().is_functional()) - if not test: - return test - - return FeatureTestResult(self, True) + JoinFeature.__init__(self, "LattE", + (Latte_count(), Latte_integrate())) diff --git a/src/sage/finance/fractal.pyx b/src/sage/finance/fractal.pyx index 3b9425302d7..a3323bc6c3c 100644 --- a/src/sage/finance/fractal.pyx +++ b/src/sage/finance/fractal.pyx @@ -22,7 +22,7 @@ AUTHOR: """ from sage.rings.all import RDF, CDF, Integer -from sage.modules.all import vector +from sage.modules.free_module_element import vector I = CDF.gen() from sage.stats.time_series cimport TimeSeries diff --git a/src/sage/functions/exp_integral.py b/src/sage/functions/exp_integral.py index b20f7779f1a..4a1a897ade0 100644 --- a/src/sage/functions/exp_integral.py +++ b/src/sage/functions/exp_integral.py @@ -55,7 +55,7 @@ mpmath_utils_call = mpmath_utils.call # eliminate some overhead in _evalf_ from sage.rings.real_mpfr import RealField -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.functions.log import exp, log from sage.functions.trig import sin, cos from sage.functions.hyperbolic import sinh, cosh diff --git a/src/sage/functions/gamma.py b/src/sage/functions/gamma.py index 8c66cbd3390..3e58cbe5a22 100644 --- a/src/sage/functions/gamma.py +++ b/src/sage/functions/gamma.py @@ -357,12 +357,12 @@ def _method_arguments(self, x, y): TESTS:: sage: b = RBF(1, 1e-10) - sage: gamma(b) - [1.00000000 +/- 8.07e-10] - sage: gamma(CBF(b)) - [1.00000000 +/- 8.07e-10] - sage: gamma(CBF(b), 4) - [0.01831564 +/- 2.65e-9] + sage: gamma(b) # abs tol 1e-9 + [1.0000000000 +/- 5.78e-11] + sage: gamma(CBF(b)) # abs tol 1e-9 + [1.0000000000 +/- 5.78e-11] + sage: gamma(CBF(b), 4) # abs tol 2e-9 + [0.018315639 +/- 9.00e-10] sage: gamma(CBF(1), b) [0.3678794412 +/- 6.54e-11] """ diff --git a/src/sage/functions/hypergeometric.py b/src/sage/functions/hypergeometric.py index 846f2c486db..0a9a2ae8030 100644 --- a/src/sage/functions/hypergeometric.py +++ b/src/sage/functions/hypergeometric.py @@ -389,24 +389,6 @@ def _tderivative_(self, a, b, z, *args, **kwargs): hypergeometric([c + 1 for c in a], [c + 1 for c in b], z)) class EvaluationMethods(object): - def _fast_float_(self, *args): - """ - Do not support the old ``fast_float``. - - OUTPUT: - - This method raises ``NotImplementedError``; use the newer - ``fast_callable`` implementation. - - EXAMPLES:: - - sage: f = hypergeometric([], [], x) - sage: f._fast_float_() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError def _fast_callable_(self, a, b, z, etb): """ diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 0e965c57da6..265f077066b 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -308,7 +308,7 @@ from sage.symbolic.function import BuiltinFunction, GinacFunction from sage.symbolic.expression import Expression -from sage.symbolic.all import SR +from sage.symbolic.ring import SR from sage.functions.other import factorial, binomial from sage.structure.all import parent diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index c2f196c70ac..bbccf43c386 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -334,7 +334,7 @@ def __init__(self): sage: ceil(5.4) 6 sage: type(ceil(5.4)) - + :: @@ -483,7 +483,7 @@ def __init__(self): sage: floor(5.4) 5 sage: type(floor(5.4)) - + sage: var('x') x sage: a = floor(5.4 + x); a @@ -693,7 +693,7 @@ def __init__(self): sage: frac(5.4) 0.400000000000000 sage: type(frac(5.4)) - + sage: frac(456/123) 29/41 sage: var('x') @@ -867,7 +867,7 @@ def sqrt(x, *args, **kwds): sage: sqrt(4,hold=True) Traceback (most recent call last): ... - TypeError: _do_sqrt() got an unexpected keyword argument 'hold' + TypeError: ..._do_sqrt() got an unexpected keyword argument 'hold' This illustrates that the bug reported in :trac:`6171` has been fixed:: @@ -875,7 +875,7 @@ def sqrt(x, *args, **kwds): sage: a.sqrt(prec=100) # this is supposed to fail Traceback (most recent call last): ... - TypeError: sqrt() got an unexpected keyword argument 'prec' + TypeError: ...sqrt() got an unexpected keyword argument 'prec' sage: sqrt(a, prec=100) 1.0488088481701515469914535137 sage: sqrt(4.00, prec=250) @@ -1245,7 +1245,7 @@ def __init__(self): sage: real(a) 2.50000000000000 sage: type(real(a)) - + sage: real(1.0r) 1.0 sage: real(complex(3, 4)) @@ -1578,8 +1578,8 @@ def __init__(self): Check that :trac:`16166` is fixed:: sage: RBF = RealBallField(53) - sage: factorial(RBF(4.2)) - [32.5780960503313 +/- 6.72e-14] + sage: factorial(RBF(4.2)) # abs tol 1e-13 + [32.5780960503314 +/- 6.06e-14] Test pickling:: @@ -1629,7 +1629,7 @@ def _eval_(self, x): sage: factorial(float(3.2)) # abs tol 1e-14 7.7566895357931776 sage: type(factorial(float(3.2))) - + """ if isinstance(x, Integer): try: @@ -1793,7 +1793,7 @@ def _binomial_sym(self, n, k): if k == 1: return n - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod(n - i for i in range(k)) / factorial(k) def _eval_(self, n, k): @@ -1803,9 +1803,9 @@ def _eval_(self, n, k): sage: binomial._eval_(5, 3) 10 sage: type(binomial._eval_(5, 3)) - + sage: type(binomial._eval_(5., 3)) - + sage: binomial._eval_(x, 3) 1/6*(x - 1)*(x - 2)*x sage: binomial._eval_(x, x-2) @@ -2131,7 +2131,7 @@ def __call__(self, l, **kwargs): sage: cases() Traceback (most recent call last): ... - TypeError: __call__() missing 1 required positional argument: 'l' + TypeError: ...__call__() missing 1 required positional argument: 'l' sage: cases(x) Traceback (most recent call last): diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 861dbf25cde..bc25aad5cd1 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -469,25 +469,6 @@ def __call__(self, parameters, variable, value=None, **kwds): substitution[variable] = value return self.subs(substitution) - def _fast_float_(self, *args): - """ - Do not support the old ``fast_float`` - - OUTPUT: - - This method raises ``NotImplementedError`` so that - plotting uses the newer `fast_callable` implementation. - - EXAMPLES:: - - sage: f = piecewise([([0,0], sin(x)), ((0,2), cos(x))]) - sage: f._fast_float_() - Traceback (most recent call last): - ... - NotImplementedError - """ - raise NotImplementedError - def _fast_callable_(self, parameters, variable, etb): """ Override the ``fast_callable`` diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 63083a617a0..97070d07d9e 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -161,7 +161,7 @@ import sage.rings.abc from sage.rings.integer import Integer from sage.misc.latex import latex -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.symbolic.constants import pi from sage.symbolic.function import BuiltinFunction from sage.libs.mpmath import utils as mpmath_utils diff --git a/src/sage/functions/spike_function.py b/src/sage/functions/spike_function.py index 2ea29f292d2..4e6b43d86c6 100644 --- a/src/sage/functions/spike_function.py +++ b/src/sage/functions/spike_function.py @@ -21,7 +21,7 @@ from sage.plot.all import line from sage.modules.free_module_element import vector -from sage.rings.all import RDF +from sage.rings.real_double import RDF class SpikeFunction: diff --git a/src/sage/game_theory/cooperative_game.py b/src/sage/game_theory/cooperative_game.py index 6d2c630cd40..0cb18189191 100644 --- a/src/sage/game_theory/cooperative_game.py +++ b/src/sage/game_theory/cooperative_game.py @@ -320,7 +320,7 @@ def __init__(self, characteristic_function): sortedkey = tuple(sorted(key)) self.ch_f[sortedkey] = self.ch_f.pop(key) - self.player_list = max(characteristic_function, key=lambda key: len(key)) + self.player_list = max(characteristic_function, key=len) for coalition in powerset(self.player_list): if tuple(sorted(coalition)) not in self.ch_f: raise ValueError("characteristic function must be the power set") diff --git a/src/sage/game_theory/matching_game.py b/src/sage/game_theory/matching_game.py index b35f80c4b2f..8dcd3eb14a2 100644 --- a/src/sage/game_theory/matching_game.py +++ b/src/sage/game_theory/matching_game.py @@ -20,7 +20,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from sage.structure.sage_object import SageObject -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from copy import deepcopy from sage.graphs.bipartite_graph import BipartiteGraph diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index 0ca60758b69..5d51c857a50 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -636,7 +636,7 @@ from .parser import Parser from sage.misc.latex import latex from sage.misc.misc import powerset -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.matrix.constructor import matrix from sage.matrix.constructor import vector @@ -744,7 +744,7 @@ def __init__(self, generator=None): sage: error = NormalFormGame(p1, p2) Traceback (most recent call last): ... - TypeError: __init__() takes from 1 to 2 positional arguments but 3 were given + TypeError: ...__init__() takes from 1 to 2 positional arguments but 3 were given When initiating, argument passed must be a list or nothing:: diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index d7f278e18b8..177e143dd5e 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -216,11 +216,16 @@ from sage.geometry.toric_plotter import ToricPlotter, label_list from sage.geometry.relative_interior import RelativeInterior from sage.graphs.digraph import DiGraph -from sage.matrix.all import column_matrix, matrix, MatrixSpace +from sage.matrix.constructor import matrix +from sage.matrix.matrix_space import MatrixSpace +from sage.matrix.special import column_matrix from sage.misc.cachefunc import cached_method -from sage.misc.all import flatten, latex -from sage.modules.all import span, vector, VectorSpace -from sage.rings.all import QQ, ZZ +from sage.misc.flatten import flatten +from sage.misc.latex import latex +from sage.modules.free_module import span, VectorSpace +from sage.modules.free_module_element import vector +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.structure.all import SageObject, parent from sage.structure.richcmp import richcmp_method, richcmp from sage.geometry.integral_points import parallelotope_points @@ -591,8 +596,6 @@ def _ambient_space_point(body, data): (1.00000000000000, 3.14159265358979) """ - from sage.rings.all import AA, RR - L = body.lattice() def try_base_extend(ring): @@ -617,6 +620,9 @@ def try_base_extend(ring): # If we don't have a lattice element, try successively # less-desirable ambient spaces until (as a last resort) we # attempt a numerical representation. + from sage.rings.qqbar import AA + from sage.rings.real_mpfr import RR + for ring in [QQ, AA, RR]: p = try_base_extend(ring) if p is not None: @@ -722,7 +728,7 @@ def normalize_rays(rays, lattice): if lattice.is_ambient(): # Handle the most common case efficiently. V = lattice.base_extend(QQ) - length = lambda ray: integral_length(ray) + length = integral_length except AttributeError: pass if V is None: diff --git a/src/sage/geometry/cone_catalog.py b/src/sage/geometry/cone_catalog.py index 94e4c136bb6..005f341e353 100644 --- a/src/sage/geometry/cone_catalog.py +++ b/src/sage/geometry/cone_catalog.py @@ -237,7 +237,7 @@ def nonnegative_orthant(ambient_dim=None, lattice=None): """ from sage.geometry.cone import Cone from sage.matrix.constructor import matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice) @@ -466,7 +466,7 @@ def rearrangement(p, ambient_dim=None, lattice=None): """ from sage.geometry.cone import Cone from sage.matrix.constructor import matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice) @@ -599,7 +599,7 @@ def schur(ambient_dim=None, lattice=None): """ from sage.geometry.cone import Cone from sage.matrix.constructor import matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ (ambient_dim, lattice) = _preprocess_args(ambient_dim, lattice) diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index fda6fa9d374..82ce25e48c6 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -859,11 +859,14 @@ def _test_contains(self, tester=None, **options): ext_space = self.ambient_vector_space(AA) ext_space_point = ext_space(space_point) tester.assertEqual(contains_space_point, self.contains(ext_space_point)) - from sage.symbolic.ring import SR - symbolic_space = self.ambient_vector_space(SR) - symbolic_space_point = symbolic_space(space_point) - # Only test that it can accept SR vectors without error. - self.contains(symbolic_space_point) + try: + from sage.symbolic.ring import SR + symbolic_space = self.ambient_vector_space(SR) + symbolic_space_point = symbolic_space(space_point) + # Only test that it can accept SR vectors without error. + self.contains(symbolic_space_point) + except ImportError: + pass # Test that elements returned by some_elements are contained. try: points = self.some_elements() diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index 164371a1c8a..5f8754941d4 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -251,11 +251,14 @@ from sage.geometry.toric_lattice import ToricLattice, is_ToricLattice from sage.geometry.toric_plotter import ToricPlotter from sage.graphs.digraph import DiGraph -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method -from sage.misc.all import walltime, prod -from sage.modules.all import vector, span -from sage.rings.all import QQ, ZZ +from sage.misc.misc import walltime +from sage.misc.misc_c import prod +from sage.modules.free_module import span +from sage.modules.free_module_element import vector +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ def is_Fan(x): diff --git a/src/sage/geometry/fan_isomorphism.py b/src/sage/geometry/fan_isomorphism.py index 18a6c9b199a..a66d9ac6fd7 100644 --- a/src/sage/geometry/fan_isomorphism.py +++ b/src/sage/geometry/fan_isomorphism.py @@ -11,7 +11,7 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.matrix.constructor import column_matrix, matrix from sage.geometry.cone import Cone diff --git a/src/sage/geometry/fan_morphism.py b/src/sage/geometry/fan_morphism.py index e17b155ed6c..5b3cff567be 100644 --- a/src/sage/geometry/fan_morphism.py +++ b/src/sage/geometry/fan_morphism.py @@ -77,16 +77,20 @@ import operator -from sage.categories.all import Hom +from sage.categories.homset import Hom from sage.geometry.cone import Cone from sage.geometry.fan import Fan, is_Fan -from sage.matrix.all import identity_matrix, matrix +from sage.matrix.constructor import matrix +from sage.matrix.special import identity_matrix from sage.structure.element import is_Matrix from sage.misc.cachefunc import cached_method -from sage.misc.all import latex, prod, walltime +from sage.misc.latex import latex +from sage.misc.misc import walltime +from sage.misc.misc_c import prod from sage.modules.free_module_morphism import (FreeModuleMorphism, is_FreeModuleMorphism) -from sage.rings.all import Infinity, ZZ +from sage.rings.infinity import Infinity +from sage.rings.integer_ring import ZZ from sage.rings.infinity import is_Infinite from functools import reduce diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index 5b4cd774a57..ccb1fcdd95c 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -86,7 +86,8 @@ from sage.symbolic.constants import I from sage.misc.lazy_attribute import lazy_attribute from sage.rings.infinity import infinity -from sage.rings.all import CC, RR +from sage.rings.all import CC +from sage.rings.real_mpfr import RR from sage.plot.arc import arc from sage.plot.line import line from sage.symbolic.constants import pi diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py index 08beb8fc76a..896dc71be58 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py @@ -50,7 +50,7 @@ from sage.modules.free_module_element import vector from sage.rings.infinity import infinity from sage.misc.latex import latex -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.functions.other import imag, sqrt from sage.functions.all import arccosh, sign diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py index 9ccbb7caa63..6a891b88046 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py @@ -83,7 +83,9 @@ from sage.misc.lazy_import import lazy_import from sage.functions.other import imag, real, sqrt from sage.functions.all import arccosh -from sage.rings.all import CC, RR, RDF +from sage.rings.all import CC +from sage.rings.real_double import RDF +from sage.rings.real_mpfr import RR from sage.rings.infinity import infinity from sage.symbolic.constants import I from sage.matrix.constructor import matrix @@ -1479,7 +1481,7 @@ def get_background_graphic(self, **bdry_options): sage: H = HyperbolicPlane().HM().get_background_graphic() """ from sage.plot.plot3d.all import plot3d - from sage.all import SR + from sage.symbolic.ring import SR hyperboloid_opacity = bdry_options.get('hyperboloid_opacity', .1) z_height = bdry_options.get('z_height', 7.0) x_max = sqrt((z_height ** 2 - 1) / 2.0) diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py index 570a1cd7310..2fba9b50df9 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py @@ -68,7 +68,8 @@ from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector from sage.rings.infinity import infinity -from sage.rings.all import RR, CC +from sage.rings.all import CC +from sage.rings.real_mpfr import RR from sage.functions.other import real, imag from sage.geometry.hyperbolic_space.hyperbolic_isometry import HyperbolicIsometry diff --git a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py index 7ce7a70e7b5..cc7314f2505 100644 --- a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py +++ b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py @@ -108,7 +108,7 @@ def __init__(self, p, V): (0, 0, 0, 0) """ R = V.base_ring() - from sage.categories.all import Fields + from sage.categories.fields import Fields if R not in Fields(): R = R.fraction_field() V = V.change_ring(R) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 05b5181342c..1914442251c 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -348,7 +348,8 @@ from sage.structure.element import Element from sage.structure.richcmp import richcmp from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method from sage.matrix.constructor import matrix, vector from sage.modules.free_module import VectorSpace @@ -1240,7 +1241,7 @@ def has_good_reduction(self, p): raise TypeError('arrangement must be defined over QQ') if not p.is_prime(): raise TypeError('must reduce modulo a prime number') - from sage.rings.all import GF + from sage.rings.finite_rings.finite_field_constructor import GF a = self.change_ring(GF(p)) p = self.intersection_poset() q = a.intersection_poset() @@ -2937,7 +2938,7 @@ def varchenko_matrix(self, names='h'): (h2 - 1) * (h2 + 1) * (h1 - 1) * (h1 + 1) """ from sage.matrix.constructor import identity_matrix - from sage.misc.all import prod + from sage.misc.misc_c import prod k = len(self) R = PolynomialRing(QQ, names, k) h = R.gens() @@ -3402,7 +3403,7 @@ def __init__(self, base_ring, names=tuple()): sage: K = HyperplaneArrangements(QQ) sage: TestSuite(K).run() """ - from sage.categories.all import Sets + from sage.categories.sets_cat import Sets from sage.rings.ring import _Fields if base_ring not in _Fields: raise ValueError('base ring must be a field') diff --git a/src/sage/geometry/hyperplane_arrangement/hyperplane.py b/src/sage/geometry/hyperplane_arrangement/hyperplane.py index 1f125bca8f4..fd5bb34da7f 100644 --- a/src/sage/geometry/hyperplane_arrangement/hyperplane.py +++ b/src/sage/geometry/hyperplane_arrangement/hyperplane.py @@ -247,7 +247,7 @@ def _normal_pivot(self): try: values = [abs(x) for x in self.A()] except ArithmeticError: - from sage.rings.all import RDF + from sage.rings.real_double import RDF values = [abs(RDF(x)) for x in self.A()] max_pos = 0 max_value = values[max_pos] diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index 55fb1e056f0..cd66827debb 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -14,7 +14,9 @@ from sage.graphs.all import graphs from sage.matrix.constructor import matrix, random_matrix -from sage.rings.all import QQ, ZZ, NN +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.semirings.non_negative_integer_semiring import NN from sage.misc.misc_c import prod from sage.combinat.combinat import stirling_number2 diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index a85923eee94..a8750290fb8 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -113,7 +113,7 @@ from sage.plot.text import text from sage.plot.point import point from sage.plot.plot import parametric_plot -from sage.symbolic.all import SR +from sage.symbolic.ring import SR def plot(hyperplane_arrangement, **kwds): diff --git a/src/sage/geometry/integral_points.pyx b/src/sage/geometry/integral_points.pyx index 37e1d23339d..8db5599877f 100644 --- a/src/sage/geometry/integral_points.pyx +++ b/src/sage/geometry/integral_points.pyx @@ -18,11 +18,13 @@ import copy import itertools from sage.matrix.constructor import matrix, column_matrix, vector, diagonal_matrix -from sage.rings.all import QQ, RR, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RR from sage.rings.integer cimport Integer from sage.arith.all import gcd, lcm from sage.combinat.permutation import Permutation -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.modules.free_module import FreeModule from sage.modules.vector_integer_dense cimport Vector_integer_dense from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 586157fce6f..23b91ab478d 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -125,13 +125,16 @@ from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix from sage.misc.cachefunc import cached_method -from sage.misc.all import flatten, tmp_filename -from sage.modules.all import vector +from sage.misc.flatten import flatten +from sage.misc.temporary_file import tmp_filename +from sage.modules.free_module_element import vector from sage.numerical.mip import MixedIntegerLinearProgram from sage.plot.plot3d.index_face_set import IndexFaceSet from sage.plot.plot3d.all import line3d, point3d from sage.plot.plot3d.shapes2 import text3d -from sage.rings.all import Integer, ZZ, QQ +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.sets.set import Set_generic from sage.structure.all import Sequence from sage.structure.sage_object import SageObject diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index be20596ca50..dbe09170c4c 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -685,7 +685,7 @@ def ambient_module(self): sage: M.ambient_vector_space() Vector space of dimension 2 over Rational Field """ - from sage.modules.all import FreeModule + from sage.modules.free_module import FreeModule return FreeModule(self.base_ring(), self.ngens()) @cached_method @@ -714,7 +714,7 @@ def ambient_vector_space(self): sage: M.ambient_vector_space() Vector space of dimension 2 over Rational Field """ - from sage.modules.all import VectorSpace + from sage.modules.free_module import VectorSpace field = self.base_ring().fraction_field() return VectorSpace(field, self.ngens()) diff --git a/src/sage/geometry/point_collection.pyx b/src/sage/geometry/point_collection.pyx index 3fb6955ead3..8b2f7e26828 100644 --- a/src/sage/geometry/point_collection.pyx +++ b/src/sage/geometry/point_collection.pyx @@ -80,8 +80,8 @@ from sage.structure.sage_object cimport SageObject from sage.structure.richcmp cimport richcmp_not_equal, richcmp from sage.geometry.toric_lattice import ToricLattice -from sage.matrix.all import matrix -from sage.misc.all import latex +from sage.matrix.constructor import matrix +from sage.misc.latex import latex def is_PointCollection(x): diff --git a/src/sage/geometry/polyhedron/backend_cdd.py b/src/sage/geometry/polyhedron/backend_cdd.py index d839bc3ca5e..7b48eb7b45b 100644 --- a/src/sage/geometry/polyhedron/backend_cdd.py +++ b/src/sage/geometry/polyhedron/backend_cdd.py @@ -16,7 +16,7 @@ from subprocess import Popen, PIPE -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix from .base import Polyhedron_base diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index af8f3287d9a..e629fb58abe 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -25,13 +25,14 @@ from sage.structure.element import Element from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.features import PythonModule from sage.misc.lazy_import import lazy_import lazy_import('PyNormaliz', ['NmzResult', 'NmzCompute', 'NmzCone', 'NmzConeCopy'], feature=PythonModule("PyNormaliz", spkg="pynormaliz")) -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.arith.functions import LCM_list from sage.misc.functional import denominator from sage.matrix.constructor import vector @@ -951,7 +952,7 @@ def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays """ from sage.categories.number_fields import NumberFields - from sage.rings.all import RDF + from sage.rings.real_double import RDF if self.base_ring() in (QQ, ZZ): normaliz_field = QQ diff --git a/src/sage/geometry/polyhedron/backend_ppl.py b/src/sage/geometry/polyhedron/backend_ppl.py index 69702213084..3ac2bb267f7 100644 --- a/src/sage/geometry/polyhedron/backend_ppl.py +++ b/src/sage/geometry/polyhedron/backend_ppl.py @@ -3,7 +3,7 @@ """ from sage.structure.element import Element -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from sage.arith.functions import LCM_list from sage.misc.functional import denominator diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 47063568802..d50d33b1053 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -37,11 +37,13 @@ from sage.cpython.string import bytes_to_str from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.randstate import current_randstate from sage.misc.superseded import deprecated_function_alias -from sage.rings.all import QQ, ZZ, AA +from sage.rings.integer_ring import ZZ +from sage.rings.qqbar import AA +from sage.rings.rational_field import QQ from sage.rings.real_double import RDF from sage.modules.free_module_element import vector from sage.modules.vector_space_morphism import linear_transformation @@ -215,7 +217,7 @@ def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pre ....: Vrep_minimal=True, Hrep_minimal=True, pref_rep='Vrep') Traceback (most recent call last): ... - TypeError: _init_Hrepresentation() takes 3 positional arguments but 9 were given + TypeError: ..._init_Hrepresentation() takes 3 positional arguments but 9 were given The empty polyhedron is detected when the Vrepresentation is given with generator; see :trac:`29899`:: @@ -666,9 +668,8 @@ def change_ring(self, base_ring, backend=None): A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex sage: P.n_vertices() == Q.n_vertices() False - """ - - from sage.categories.all import Rings + """ + from sage.categories.rings import Rings if base_ring not in Rings(): raise ValueError("invalid base ring") @@ -1819,7 +1820,7 @@ def Hrepresentation_str(self, separator='\n', latex=False, style='>=', align=Non sage: c = polytopes.cube() sage: c.Hrepresentation_str(separator=', ', style='positive') - '1 >= x0, 1 >= x1, 1 >= x2, x0 + 1 >= 0, x2 + 1 >= 0, x1 + 1 >= 0' + '1 >= x0, 1 >= x1, 1 >= x2, 1 + x0 >= 0, 1 + x2 >= 0, 1 + x1 >= 0' """ pretty_hs = [h.repr_pretty(split=True, latex=latex, style=style, **kwds) for h in self.Hrepresentation()] shift = any(pretty_h[2].startswith('-') for pretty_h in pretty_hs) diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index c02940a820e..520e871ecb1 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -2,9 +2,9 @@ Base class for polyhedra over `\QQ` """ -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from .base import Polyhedron_base diff --git a/src/sage/geometry/polyhedron/base_RDF.py b/src/sage/geometry/polyhedron/base_RDF.py index 7f4fc7334ad..38485ed396a 100644 --- a/src/sage/geometry/polyhedron/base_RDF.py +++ b/src/sage/geometry/polyhedron/base_RDF.py @@ -2,7 +2,7 @@ Base class for polyhedra over ``RDF`` """ -from sage.rings.all import RDF +from sage.rings.real_double import RDF from .base import Polyhedron_base diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index aabb5806504..8015f360560 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -12,7 +12,8 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ, QQ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method from sage.modules.free_module_element import vector from .base_QQ import Polyhedron_QQ diff --git a/src/sage/geometry/polyhedron/cdd_file_format.py b/src/sage/geometry/polyhedron/cdd_file_format.py index e08c7eccad4..78fd01787b7 100644 --- a/src/sage/geometry/polyhedron/cdd_file_format.py +++ b/src/sage/geometry/polyhedron/cdd_file_format.py @@ -61,7 +61,7 @@ def cdd_Vrepresentation(cdd_type, vertices, rays, lines, file_output=None): num += 1 if cdd_type == 'real': - from sage.rings.all import RDF + from sage.rings.real_double import RDF base_ring = RDF else: base_ring = None @@ -121,7 +121,7 @@ def cdd_Hrepresentation(cdd_type, ieqs, eqns, file_output=None): ambient_dim -= 1 if cdd_type == 'real': - from sage.rings.all import RDF + from sage.rings.real_double import RDF base_ring = RDF else: base_ring = None diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index dd1a2ba54d7..85131c81ad6 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -391,7 +391,7 @@ cdef class CombinatorialPolyhedron(SageObject): self._n_Hrepresentation = len(facets) far_face = tuple(i for i in range(len(Vrep) - 1)) self._dimension = data.dim() - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix from sage.rings.all import ZZ data = matrix(ZZ, data.incidence_matrix().rows() + [[ZZ.one() for _ in range(len(facets))]]) @@ -442,7 +442,7 @@ cdef class CombinatorialPolyhedron(SageObject): if not isinstance(data, Matrix_integer_dense): from sage.rings.all import ZZ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix data = matrix(ZZ, data, sparse=False) assert isinstance(data, Matrix_integer_dense), "conversion to ``Matrix_integer_dense`` didn't work" @@ -1096,7 +1096,7 @@ cdef class CombinatorialPolyhedron(SageObject): sage: C.incidence_matrix().base_ring() Integer Ring """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix cdef Matrix_integer_dense incidence_matrix = matrix( ZZ, self.n_Vrepresentation(), self.n_Hrepresentation(), 0) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx index 98b3d4df828..5ea9711090d 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx @@ -477,7 +477,7 @@ cdef class ListOfFaces: sage: facets.matrix().transpose() == Vrep.matrix() True """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix cdef Matrix_integer_dense M = matrix( ZZ, self.n_faces(), self.n_atoms(), 0) diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index 7f68ca41ce0..2df40ce6c59 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -292,7 +292,9 @@ # https://www.gnu.org/licenses/ ######################################################################## -from sage.rings.all import ZZ, RDF, RR +from sage.rings.integer_ring import ZZ +from sage.rings.real_double import RDF +from sage.rings.real_mpfr import RR from .misc import _make_listlist, _common_length_of @@ -615,7 +617,8 @@ def Polyhedron(vertices=None, rays=None, lines=None, # figure out base_ring from sage.misc.flatten import flatten from sage.structure.element import parent - from sage.categories.all import Rings, Fields + from sage.categories.fields import Fields + from sage.categories.rings import Rings values = flatten(vertices + rays + lines + ieqs + eqns) if base_ring is not None: @@ -649,7 +652,10 @@ def Polyhedron(vertices=None, rays=None, lines=None, if base_ring not in Rings(): raise ValueError('invalid base ring') - from sage.symbolic.ring import SR + try: + from sage.symbolic.ring import SR + except ImportError: + SR = None if base_ring is not SR and not base_ring.is_exact(): # TODO: remove this hack? if base_ring is RR: diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index d8d85adde6e..ee8cb5a7e86 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -74,7 +74,7 @@ import itertools from sage.misc.cachefunc import cached_method -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.modules.free_module_element import vector from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py index a113fde50b3..b94be057249 100644 --- a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py +++ b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py @@ -53,7 +53,7 @@ from sage.structure.sage_object import SageObject from sage.matrix.constructor import matrix -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.geometry.polyhedron.double_description import StandardAlgorithm as Algorithm # Compare with PPL if the base ring is QQ. Can be left enabled since @@ -363,7 +363,7 @@ def verify(self, inequalities, equations): sage: H = Hrep2Vrep(QQ, 1, [(1,2)], []) sage: H.verify([(1,2)], []) """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.geometry.polyhedron.constructor import Polyhedron if self.base_ring is not QQ: return @@ -558,7 +558,7 @@ def verify(self, vertices, rays, lines): sage: V2H = Vrep2Hrep(QQ, 2, vertices, rays, lines) sage: V2H.verify(vertices, rays, lines) """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.geometry.polyhedron.constructor import Polyhedron if self.base_ring is not QQ: return diff --git a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py index 4309d09a1e0..79331133960 100644 --- a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py +++ b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py @@ -15,7 +15,7 @@ from sage.structure.sage_object import SageObject from sage.rings.integer_ring import ZZ -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 8b49227cec6..31cec880ccf 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -81,7 +81,11 @@ import itertools -from sage.rings.all import ZZ, QQ, RDF, RR, AA, QQbar +from sage.rings.integer_ring import ZZ +from sage.rings.qqbar import AA, QQbar +from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF +from sage.rings.real_mpfr import RR from sage.combinat.permutation import Permutations from sage.groups.perm_gps.permgroup_named import AlternatingGroup from .constructor import Polyhedron @@ -441,7 +445,7 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None): ValueError: input vectors not totally cyclic """ from sage.modules.free_module_element import vector - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix if base_ring: vectors = tuple(vector(base_ring, x) for x in vectors) else: diff --git a/src/sage/geometry/polyhedron/palp_database.py b/src/sage/geometry/polyhedron/palp_database.py index 158ea5c38ca..a9bd90eca8b 100644 --- a/src/sage/geometry/polyhedron/palp_database.py +++ b/src/sage/geometry/polyhedron/palp_database.py @@ -33,7 +33,7 @@ from subprocess import Popen, PIPE from sage.structure.sage_object import SageObject -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.interfaces.process import terminate diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 7f14eb0766e..2c1614ed87d 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -14,7 +14,10 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.modules.free_module import FreeModule, is_FreeModule from sage.misc.cachefunc import cached_method, cached_function -from sage.rings.all import ZZ, QQ, RDF, CommutativeRing +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF +from sage.rings.ring import CommutativeRing from sage.categories.fields import Fields from sage.categories.rings import Rings from sage.categories.modules import Modules @@ -145,7 +148,10 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * else: raise ValueError("no default backend for computations with {}".format(base_ring)) - from sage.symbolic.ring import SR + try: + from sage.symbolic.ring import SR + except ImportError: + SR = None if backend == 'ppl' and base_ring is QQ: return Polyhedra_QQ_ppl(base_ring, ambient_dim, backend) elif backend == 'ppl' and base_ring is ZZ: diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 7b4eace75ef..a7976de6d2e 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -11,14 +11,15 @@ # https://www.gnu.org/licenses/ ######################################################################## -from sage.rings.all import RDF +from math import pi + +from sage.rings.real_double import RDF from sage.structure.sage_object import SageObject from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix, identity_matrix from sage.matrix.special import diagonal_matrix from sage.misc.functional import norm from sage.misc.latex import LatexExpr -from sage.symbolic.constants import pi from sage.structure.sequence import Sequence from sage.plot.all import Graphics, point2d, line2d, arrow, polygon2d diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py index 75135c37d1a..03343dc6f9f 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py @@ -20,7 +20,7 @@ from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method, cached_function -from sage.modules.all import (vector, zero_vector) +from sage.modules.free_module_element import vector, zero_vector from sage.matrix.constructor import (matrix, zero_matrix, block_matrix) from ppl import C_Polyhedron, Poly_Con_Relation from sage.geometry.polyhedron.lattice_euclidean_group_element import ( diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py index 1a97bd6c33c..207160401c8 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py @@ -69,7 +69,7 @@ from sage.rings.integer import GCD_list, Integer from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix from ppl import ( C_Polyhedron, Linear_Expression, Variable, diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index 1fcefddd53b..9b4cb1586d2 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -17,7 +17,7 @@ from sage.structure.sage_object import SageObject from sage.structure.element import is_Vector from sage.structure.richcmp import richcmp_method, richcmp -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.modules.free_module_element import vector from copy import copy @@ -712,7 +712,7 @@ def _latex_(self): ....: print(latex(h)) x_{0} + x_{1} - x_{2} = 1 x_{0} \geq 0 - 2 \, x_{0} + x_{1} \geq -1 + 2x_{0} + x_{1} \geq -1 """ return self.repr_pretty(latex=True) @@ -1690,15 +1690,16 @@ def repr_pretty(coefficients, type, prefix='x', indices=None, sage: print(repr_pretty((1, -1, -1, 1), PolyhedronRepresentation.EQUATION)) -x0 - x1 + x2 == -1 """ - from sage.misc.latex import latex as latex_function - from sage.modules.free_module_element import vector - from sage.symbolic.ring import SR + from sage.misc.repr import repr_lincomb - coeffs = vector(coefficients) + coeffs = list(coefficients) if indices is None: indices = range(len(coeffs)-1) - vars = vector([1] + list(SR(prefix + '{}'.format(i)) for i in indices)) - f = latex_function if latex else repr + vars = [1] + if latex: + vars += ['x_{{{}}}'.format(i) for i in indices] + else: + vars += ['x{}'.format(i) for i in indices] if type == PolyhedronRepresentation.EQUATION: rel = '=' if latex else '==' elif type == PolyhedronRepresentation.INEQUALITY: @@ -1710,18 +1711,20 @@ def repr_pretty(coefficients, type, prefix='x', indices=None, raise NotImplementedError( 'no pretty printing available: wrong type {}'.format(type)) + rvars = range(len(vars)) + if style == 'positive': - pos_part = vector([max(c, 0) for c in coeffs]) - neg_part = pos_part - coeffs - assert coeffs == pos_part - neg_part - left_part = f(pos_part*vars) - right_part = f(neg_part*vars) + pos_part = [max(c, 0) for c in coeffs] + neg_part = [pos_part[i] - coeffs[i] for i in rvars] + assert all(coeffs[i] == pos_part[i] - neg_part[i] for i in rvars) + left_part = repr_lincomb([[vars[i], pos_part[i]] for i in rvars], is_latex=latex, strip_one=True) + right_part = repr_lincomb([[vars[i], neg_part[i]] for i in rvars], is_latex=latex, strip_one=True) elif style == '>=': - left_part = f(coeffs[1:]*vars[1:]) - right_part = f(-coeffs[0]) + left_part = repr_lincomb([[vars[i], coeffs[i]] for i in rvars[1:]], is_latex=latex) + right_part = repr_lincomb([[vars[0], -coeffs[0]]], is_latex=latex, strip_one=True) elif style == '<=': - left_part = f(-coeffs[1:]*vars[1:]) - right_part = f(coeffs[0]) + left_part = repr_lincomb([[vars[i], -coeffs[i]] for i in rvars[1:]], is_latex=latex) + right_part = repr_lincomb([[vars[0], coeffs[0]]], is_latex=latex, strip_one=True) else: raise NotImplementedError('no pretty printing available: wrong style {}'.format(style)) diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index 4d8ef3fba62..e8920bfb701 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -148,7 +148,7 @@ from sage.geometry.toric_lattice_element import (ToricLatticeElement, is_ToricLatticeElement) from sage.geometry.toric_plotter import ToricPlotter -from sage.misc.all import latex +from sage.misc.latex import latex from sage.structure.all import parent from sage.structure.richcmp import (richcmp_method, richcmp, rich_to_bool, richcmp_not_equal) @@ -158,7 +158,8 @@ FreeModule_generic_pid, FreeModule_submodule_pid, FreeModule_submodule_with_basis_pid) -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.structure.factory import UniqueFactory diff --git a/src/sage/geometry/toric_plotter.py b/src/sage/geometry/toric_plotter.py index 2814060a271..5afd455ed20 100644 --- a/src/sage/geometry/toric_plotter.py +++ b/src/sage/geometry/toric_plotter.py @@ -51,11 +51,11 @@ from sage.functions.all import arccos, arctan2, ceil, floor from sage.geometry.polyhedron.constructor import Polyhedron -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.plot.all import (Color, Graphics, arrow, disk, line, point, polygon, rainbow, text) from sage.plot.plot3d.all import text3d -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.structure.sage_object import SageObject diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index b19b9170258..9aea06b7fb5 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -41,8 +41,9 @@ from sage.structure.richcmp import richcmp from sage.structure.element import Element -from sage.rings.all import QQ, ZZ -from sage.modules.all import vector +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.modules.free_module_element import vector from sage.misc.cachefunc import cached_method from sage.sets.set import Set from sage.graphs.graph import Graph diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index b074c114e52..0346c9cdac4 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -184,9 +184,10 @@ from sage.misc.cachefunc import cached_method from sage.combinat.combination import Combinations -from sage.rings.all import QQ, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.matrix.constructor import matrix -from sage.modules.all import vector +from sage.modules.free_module_element import vector from copy import copy import sys diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index 58aff796910..1859a5e0c1a 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -15,10 +15,12 @@ from sage.structure.sage_object import SageObject from sage.geometry.polyhedron.constructor import Polyhedron -from sage.all import RDF, QQ, AA +from sage.rings.qqbar import AA +from sage.rings.rational_field import QQ +from sage.rings.real_double import RDF from sage.rings.real_mpfr import RealField_class from sage.geometry.triangulation.point_configuration import PointConfiguration -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.plot.all import line, point, rainbow, plot diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index af1de86c552..480ae451395 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -684,7 +684,7 @@ cpdef min_spanning_tree(g, sage: min_spanning_tree(g) Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... """ from sage.graphs.graph import Graph diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index 5df1a220cd3..dd1fb496861 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -1473,9 +1473,9 @@ def _run_it_on_static_instead(f): sage: Graph.new_graph_method = new_graph_method sage: g = Graph(5) sage: print("My backend is of type {}".format(type(g._backend))) - My backend is of type + My backend is of type sage: g.new_graph_method() - My backend is of type + My backend is of type """ def same_function_on_static_version(*kwd, **kwds): if not isinstance(kwd[0]._backend, StaticSparseBackend): @@ -1485,4 +1485,3 @@ def _run_it_on_static_instead(f): return f(*kwd, **kwds) return same_function_on_static_version - diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 415f1fa34d9..7c34008eb43 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -1555,7 +1555,7 @@ class :class:`MixedIntegerLinearProgram sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Edmonds') 4 sage: B.matching(use_edge_labels=True, value_only=True, algorithm='LP') - 4.0 + 4 sage: B.matching(use_edge_labels=True, value_only=True, algorithm='Eppstein') Traceback (most recent call last): ... diff --git a/src/sage/graphs/chrompoly.pyx b/src/sage/graphs/chrompoly.pyx index e1b9c80d2a0..07d87a6d509 100644 --- a/src/sage/graphs/chrompoly.pyx +++ b/src/sage/graphs/chrompoly.pyx @@ -30,7 +30,7 @@ from memory_allocator cimport MemoryAllocator from sage.libs.gmp.mpz cimport * from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod def chromatic_polynomial(G, return_tree_basis=False): diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 04bf4293815..bcf919c4a7d 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -1685,14 +1685,13 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, # Variables are binary, and their coefficient in the objective is # the number of occurrences of the corresponding edge, so 1 if the # graph is simple - p.set_objective( p.sum(b[u,v] for u,v in self.edge_iterator(labels=False))) - - p.solve(log=verbose) + p.set_objective( p.sum(b[e] for e in self.edge_iterator(labels=False))) # For as long as we do not break because the digraph is acyclic.... while True: # Building the graph without the edges removed by the MILP + p.solve(log=verbose) val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) h = DiGraph([e for e in self.edge_iterator(labels=False) if not val[e]], format='list_of_edges') @@ -1702,7 +1701,11 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, # If so, we are done ! if isok: - break + if value_only: + return sum(1 for e in self.edge_iterator(labels=False) if val[e]) + else: + # listing the edges contained in the MFAS + return [e for e in self.edge_iterator(labels=False) if val[e]] # There is a circuit left. Let's add the corresponding # constraint ! @@ -1712,7 +1715,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, print("Adding a constraint on circuit : {}".format(certificate)) edges = zip(certificate, certificate[1:] + [certificate[0]]) - p.add_constraint(p.sum(b[u, v] for u, v in edges), min=1) + p.add_constraint(p.sum(b[e] for e in edges), min=1) # Is there another edge disjoint circuit ? # for python3, we need to recreate the zip iterator @@ -1720,16 +1723,6 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, h.delete_edges(edges) isok, certificate = h.is_directed_acyclic(certificate=True) - obj = p.solve(log=verbose) - - if value_only: - return Integer(round(obj)) - - else: - # listing the edges contained in the MFAS - val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [e for e in self.edge_iterator(labels=False) if val[e]] - ###################################### # Ordering-based MILP Implementation # ###################################### @@ -1747,16 +1740,16 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, for v in self: p.add_constraint(d[v] <= n) - p.set_objective(p.sum(b[u,v] for u,v in self.edge_iterator(labels=None))) + p.set_objective(p.sum(b[e] for e in self.edge_iterator(labels=False))) - if value_only: - return Integer(round(p.solve(objective_only=True, log=verbose))) - else: - p.solve(log=verbose) + p.solve(log=verbose) - b_sol = p.get_values(b, convert=bool, tolerance=integrality_tolerance) + b_sol = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [e for e in self.edge_iterator(labels=None) if b_sol[e]] + if value_only: + return sum(1 for e in self.edge_iterator(labels=False) if b_sol[e]) + else: + return [e for e in self.edge_iterator(labels=False) if b_sol[e]] ### Construction diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 0b5af35c2a8..c4c573e6fa1 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -8,13 +8,15 @@ The methods defined here appear in :mod:`sage.graphs.graph_generators`. """ -########################################################################### -# +# **************************************************************************** # Copyright (C) 2015 Sagemath project # -# Distributed under the terms of the GNU General Public License (GPL) -# https://www.gnu.org/licenses/ -########################################################################### +# This 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 sage.graphs.graph import Graph from sage.arith.all import is_prime_power @@ -23,23 +25,24 @@ def SymplecticPolarGraph(d, q, algorithm=None): r""" - Returns the Symplectic Polar Graph `Sp(d,q)`. + Return the Symplectic Polar Graph `Sp(d,q)`. - The Symplectic Polar Graph `Sp(d,q)` is built from a projective space of dimension - `d-1` over a field `F_q`, and a symplectic form `f`. Two vertices `u,v` are - made adjacent if `f(u,v)=0`. + The Symplectic Polar Graph `Sp(d,q)` is built from a projective space of + dimension `d-1` over a field `F_q`, and a symplectic form `f`. Two vertices + `u,v` are made adjacent if `f(u,v)=0`. See the page `on symplectic graphs on Andries Brouwer's website `_. INPUT: - - ``d,q`` (integers) -- note that only even values of `d` are accepted by - the function. + - ``d,q`` -- integers; note that only even values of `d` are accepted by the + function. - - ``algorithm`` -- if set to 'gap' then the computation is carried via GAP - library interface, computing totally singular subspaces, which is faster for `q>3`. - Otherwise it is done directly. + - ``algorithm`` -- string (default: ``None``); if set to 'gap' then the + computation is carried via GAP library interface, computing totally + singular subspaces, which is faster for `q>3`. Otherwise it is done + directly. EXAMPLES: @@ -97,19 +100,19 @@ def SymplecticPolarGraph(d, q, algorithm=None): V = VectorSpace(F,d) PV = list(ProjectiveSpace(d-1,F)) - G = Graph([[tuple(_) for _ in PV], lambda x,y:V(x)*(M*V(y)) == 0], loops = False) + G = Graph([[tuple(_) for _ in PV], lambda x,y:V(x)*(M*V(y)) == 0], loops=False) else: raise ValueError("unknown algorithm!") - G.name("Symplectic Polar Graph Sp("+str(d)+","+str(q)+")") + G.name("Symplectic Polar Graph Sp({},{})".format(d,q)) G.relabel() return G -def AffineOrthogonalPolarGraph(d,q,sign="+"): +def AffineOrthogonalPolarGraph(d, q, sign="+"): r""" - Returns the affine polar graph `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. + Return the affine polar graph `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. Affine Polar graphs are built from a `d`-dimensional vector space over `F_q`, and a quadratic form which is hyperbolic, elliptic or parabolic @@ -118,20 +121,19 @@ def AffineOrthogonalPolarGraph(d,q,sign="+"): Note that `VO^+(d,q),VO^-(d,q)` are strongly regular graphs, while `VO(d,q)` is not. - For more information on Affine Polar graphs, see `Affine Polar - Graphs page of Andries Brouwer's website - `_. + For more information on Affine Polar graphs, see `Affine Polar Graphs page + of Andries Brouwer's website `_. INPUT: - - ``d`` (integer) -- ``d`` must be even if ``sign is not None``, and odd - otherwise. + - ``d`` -- integer; ``d`` must be even if ``sign is not None``, and odd + otherwise - - ``q`` (integer) -- a power of a prime number, as `F_q` must exist. + - ``q`` -- integer; a power of a prime number, as `F_q` must exist - - ``sign`` -- must be equal to ``"+"``, ``"-"``, or ``None`` to compute - (respectively) `VO^+(d,q),VO^-(d,q)` or `VO(d,q)`. By default - ``sign="+"``. + - ``sign`` -- string (default: ``"+"``); must be equal to ``"+"``, ``"-"``, + or ``None`` to compute (respectively) `VO^+(d,q),VO^-(d,q)` or + `VO(d,q)` .. NOTE:: @@ -176,7 +178,7 @@ def AffineOrthogonalPolarGraph(d,q,sign="+"): if d % 2: raise ValueError("d must be even when sign is not None") else: - if d % 2 == 0: + if not d % 2: raise ValueError("d must be odd when sign is None") s = 0 @@ -208,10 +210,10 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power - - ``sign`` -- ``"+"`` or ``"-"`` if `m` is even, ``"+"`` (default) - otherwise. + - ``sign`` -- string (default: ``"+"``); must be ``"+"`` or ``"-"`` if `m` + is even, ``"+"`` (default) otherwise - ``point_type`` -- a list of elements from `F_q` @@ -235,13 +237,13 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): `NO^+(7,3)`:: sage: g=_orthogonal_polar_graph(7,3,point_type=[1]) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (378, 117, 36, 36) `NO^-(7,3)`:: - sage: g=_orthogonal_polar_graph(7,3,point_type=[-1]) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g=_orthogonal_polar_graph(7,3,point_type=[-1]) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (351, 126, 45, 45) `NO^+(6,3)`:: @@ -258,14 +260,14 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): `NO^{-,\perp}(5,5)`:: - sage: g=_orthogonal_polar_graph(5,5,point_type=[2,3]) # long time - sage: g.is_strongly_regular(parameters=True) # long time + sage: g=_orthogonal_polar_graph(5,5,point_type=[2,3]) # long time + sage: g.is_strongly_regular(parameters=True) # long time (300, 65, 10, 15) `NO^{+,\perp}(5,5)`:: - sage: g=_orthogonal_polar_graph(5,5,point_type=[1,-1]) # not tested (long time) - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g=_orthogonal_polar_graph(5,5,point_type=[1,-1]) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (325, 60, 15, 10) TESTS:: @@ -283,7 +285,7 @@ def _orthogonal_polar_graph(m, q, sign="+", point_type=[0]): from sage.matrix.constructor import Matrix from sage.libs.gap.libgap import libgap - if m % 2 == 0: + if not m % 2: if sign != "+" and sign != "-": raise ValueError("sign must be equal to either '-' or '+' when " "m is even") @@ -323,17 +325,17 @@ def P(x,y): def OrthogonalPolarGraph(m, q, sign="+"): r""" - Returns the Orthogonal Polar Graph `O^{\epsilon}(m,q)`. + Return the Orthogonal Polar Graph `O^{\epsilon}(m,q)`. - For more information on Orthogonal Polar graphs, see the `page of - Andries Brouwer's website `_. + For more information on Orthogonal Polar graphs, see the `page of Andries + Brouwer's website `_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power - - ``sign`` -- ``"+"`` or ``"-"`` if `m` is even, ``"+"`` (default) - otherwise. + - ``sign`` -- string (default: ``"+"``); must be ``"+"`` or ``"-"`` if `m` + is even, ``"+"`` (default) otherwise EXAMPLES:: @@ -378,22 +380,22 @@ def OrthogonalPolarGraph(m, q, sign="+"): def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): r""" - Returns the Graph `NO^{\epsilon,\perp}_{m}(q)` + Return the Graph `NO^{\epsilon,\perp}_{m}(q)` - Let the vectorspace of dimension `m` over `F_q` be - endowed with a nondegenerate quadratic form `F`, of type ``sign`` for `m` even. + Let the vectorspace of dimension `m` over `F_q` be endowed with a + nondegenerate quadratic form `F`, of type ``sign`` for `m` even. * `m` even: assume further that `q=2` or `3`. Returns the graph of the - points (in the underlying projective space) `x` satisfying `F(x)=1`, with adjacency - given by orthogonality w.r.t. `F`. Parameter ``perp`` is ignored. - - * `m` odd: if ``perp`` is not ``None``, then we assume that `q=5` and - return the graph of the points `x` satisfying `F(x)=\pm 1` if ``sign="+"``, - respectively `F(x) \in \{2,3\}` if ``sign="-"``, with adjacency - given by orthogonality w.r.t. `F` (cf. Sect 7.D of [BL1984]_). - Otherwise return the graph - of nongenerate hyperplanes of type ``sign``, adjacent whenever the intersection - is degenerate (cf. Sect. 7.C of [BL1984]_). + points (in the underlying projective space) `x` satisfying `F(x)=1`, with + adjacency given by orthogonality w.r.t. `F`. Parameter ``perp`` is + ignored. + + * `m` odd: if ``perp`` is not ``None``, then we assume that `q=5` and return + the graph of the points `x` satisfying `F(x)=\pm 1` if ``sign="+"``, + respectively `F(x) \in \{2,3\}` if ``sign="-"``, with adjacency given by + orthogonality w.r.t. `F` (cf. Sect 7.D of [BL1984]_). Otherwise return + the graph of nongenerate hyperplanes of type ``sign``, adjacent whenever + the intersection is degenerate (cf. Sect. 7.C of [BL1984]_). Note that for `q=2` one will get a complete graph. For more information, see Sect. 9.9 of [BH2012]_ and [BL1984]_. Note that @@ -402,11 +404,11 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): INPUT: - - ``m`` - integer, half the dimension of the underlying vectorspace + - ``m`` -- integer; half the dimension of the underlying vectorspace - - ``q`` - a power of a prime number, the size of the underlying field + - ``q`` -- a power of a prime number, the size of the underlying field - - ``sign`` -- ``"+"`` (default) or ``"-"``. + - ``sign`` -- string (default: ``"+"``); must be either ``"+"`` or ``"-"`` EXAMPLES: @@ -435,9 +437,9 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): Wilbrink's graphs for `q=5`:: - sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_regular(parameters=True) # long time + sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,perp=1).is_strongly_regular(parameters=True) # long time (325, 60, 15, 10) - sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_regular(parameters=True) # long time + sage: graphs.NonisotropicOrthogonalPolarGraph(5,5,'-',perp=1).is_strongly_regular(parameters=True) # long time (300, 65, 10, 15) Wilbrink's graphs:: @@ -448,9 +450,9 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): sage: g=graphs.NonisotropicOrthogonalPolarGraph(5,4,'-') sage: g.is_strongly_regular(parameters=True) (120, 51, 18, 24) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time) + sage: g=graphs.NonisotropicOrthogonalPolarGraph(7,4,'+'); g # not tested (long time) NO^+(7, 4): Graph on 2080 vertices - sage: g.is_strongly_regular(parameters=True) # not tested (long time) + sage: g.is_strongly_regular(parameters=True) # not tested (long time) (2080, 1071, 558, 544) TESTS:: @@ -466,7 +468,7 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'+') # long time sage: g.is_strongly_regular(parameters=True) # long time (117, 36, 15, 9) - sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time + sage: g=graphs.NonisotropicOrthogonalPolarGraph(6,3,'-'); g # long time NO^-(6, 3): Graph on 126 vertices sage: g.is_strongly_regular(parameters=True) # long time (126, 45, 12, 18) @@ -480,18 +482,17 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): Traceback (most recent call last): ... ValueError: for m even q must be 2 or 3 - """ p, k = is_prime_power(q, get_data=True) - if k == 0: + if not k: raise ValueError('q must be a prime power') dec = '' - if m % 2 == 0: + if not m % 2: if q in [2, 3]: G = _orthogonal_polar_graph(m, q, sign=sign, point_type=[1]) else: raise ValueError("for m even q must be 2 or 3") - elif not perp is None: + elif perp is not None: if q == 5: G = _orthogonal_polar_graph(m, q, point_type=\ [-1,1] if sign=='+' else [2,3] if sign=='-' else []) @@ -499,7 +500,7 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): else: raise ValueError("for perp not None q must be 5") else: - if not sign in ['+','-']: + if sign not in ['+', '-']: raise ValueError("sign must be '+' or '-'") from sage.libs.gap.libgap import libgap g0 = libgap.GeneralOrthogonalGroup(m,q) @@ -532,13 +533,14 @@ def _polar_graph(m, q, g, intersection_size=None): r""" The helper function to build graphs `(D)U(m,q)` and `(D)Sp(m,q)` - Building a graph on an orbit of a group `g` of `m\times m` matrices over `GF(q)` on - the points (or subspaces of dimension ``m//2``) isotropic w.r.t. the form `F` - left invariant by the group `g`. + Building a graph on an orbit of a group `g` of `m\times m` matrices over + `GF(q)` on the points (or subspaces of dimension ``m//2``) isotropic + w.r.t. the form `F` left invariant by the group `g`. The only constraint is that the first ``m//2`` elements of the standard - basis must generate a totally isotropic w.r.t. `F` subspace; this is the case with - these groups coming from GAP; namely, `F` has the anti-diagonal all-1 matrix. + basis must generate a totally isotropic w.r.t. `F` subspace; this is the + case with these groups coming from GAP; namely, `F` has the anti-diagonal + all-1 matrix. INPUT: @@ -548,10 +550,10 @@ def _polar_graph(m, q, g, intersection_size=None): - ``g`` -- the group acting - - ``intersection_size`` -- if ``None``, build the graph on the isotropic points, with - adjacency being orthogonality w.r.t. `F`. Otherwise, build the graph on the maximal - totally isotropic subspaces, with adjacency specified by ``intersection_size`` being - as given. + - ``intersection_size`` -- (default: ``None``); if ``None``, build the graph + on the isotropic points, with adjacency being orthogonality w.r.t. `F`. + Otherwise, build the graph on the maximal totally isotropic subspaces, + with adjacency specified by ``intersection_size`` being as given. TESTS:: @@ -563,18 +565,18 @@ def _polar_graph(m, q, g, intersection_size=None): """ from sage.libs.gap.libgap import libgap from itertools import combinations - W=libgap.FullRowSpace(libgap.GF(q), m) # F_q^m - B=libgap.Elements(libgap.Basis(W)) # the standard basis of W - V = libgap.Orbit(g,B[0],libgap.OnLines) # orbit on isotropic points - gp = libgap.Action(g,V,libgap.OnLines) # make a permutation group - s = libgap.Subspace(W,[B[i] for i in range(m//2)]) # a totally isotropic subspace + W=libgap.FullRowSpace(libgap.GF(q), m) # F_q^m + B=libgap.Elements(libgap.Basis(W)) # the standard basis of W + V = libgap.Orbit(g,B[0],libgap.OnLines) # orbit on isotropic points + gp = libgap.Action(g,V,libgap.OnLines) # make a permutation group + s = libgap.Subspace(W,[B[i] for i in range(m//2)]) # a totally isotropic subspace # and the points there sp = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1))] - h = libgap.Set([libgap.Position(V, x) for x in sp]) # indices of the points in s - L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on these subspaces + h = libgap.Set([libgap.Position(V, x) for x in sp]) # indices of the points in s + L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on these subspaces if intersection_size is None: G = Graph() - for x in L: # every pair of points in the subspace is adjacent to each other in G + for x in L: # every pair of points in the subspace is adjacent to each other in G G.add_edges(combinations(x, 2)) return G else: @@ -583,18 +585,19 @@ def _polar_graph(m, q, g, intersection_size=None): def UnitaryPolarGraph(m, q, algorithm="gap"): r""" - Returns the Unitary Polar Graph `U(m,q)`. + Return the Unitary Polar Graph `U(m,q)`. - For more information on Unitary Polar graphs, see the `page of - Andries Brouwer's website `_. + For more information on Unitary Polar graphs, see the `page of Andries + Brouwer's website `_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power - - ``algorithm`` -- if set to 'gap' then the computation is carried via GAP - library interface, computing totally singular subspaces, which is faster for - large examples (especially with `q>2`). Otherwise it is done directly. + - ``algorithm`` -- string (default: ``"gap"``); if set to 'gap' then the + computation is carried via GAP library interface, computing totally + singular subspaces, which is faster for large examples (especially with + `q>2`). Otherwise it is done directly. EXAMPLES:: @@ -622,7 +625,7 @@ def UnitaryPolarGraph(m, q, algorithm="gap"): from sage.libs.gap.libgap import libgap G = _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q)) - elif algorithm is None: # slow on large examples + elif algorithm is None: # slow on large examples from sage.schemes.projective.projective_space import ProjectiveSpace from sage.modules.free_module_element import free_module_element as vector Fq = FiniteField(q**2, 'a') @@ -650,17 +653,17 @@ def P(x, y): def NonisotropicUnitaryPolarGraph(m, q): r""" - Returns the Graph `NU(m,q)`. + Return the Graph `NU(m,q)`. - Returns the graph on nonisotropic, with respect to a nondegenerate - Hermitean form, points of the `(m-1)`-dimensional projective space over `F_q`, - with points adjacent whenever they lie on a tangent (to the set of isotropic points) - line. - For more information, see Sect. 9.9 of [BH2012]_ and series C14 in [Hub1975]_. + This returns the graph on nonisotropic, with respect to a nondegenerate + Hermitean form, points of the `(m-1)`-dimensional projective space over + `F_q`, with points adjacent whenever they lie on a tangent (to the set of + isotropic points) line. For more information, see Sect. 9.9 of [BH2012]_ + and series C14 in [Hub1975]_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power EXAMPLES:: @@ -673,7 +676,7 @@ def NonisotropicUnitaryPolarGraph(m, q): sage: graphs.NonisotropicUnitaryPolarGraph(4,2).is_strongly_regular(parameters=True) (40, 27, 18, 18) - sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time + sage: graphs.NonisotropicUnitaryPolarGraph(4,3).is_strongly_regular(parameters=True) # long time (540, 224, 88, 96) sage: graphs.NonisotropicUnitaryPolarGraph(6,6) Traceback (most recent call last): @@ -681,13 +684,13 @@ def NonisotropicUnitaryPolarGraph(m, q): ValueError: q must be a prime power """ p, k = is_prime_power(q,get_data=True) - if k==0: + if not k: raise ValueError('q must be a prime power') from sage.libs.gap.libgap import libgap from itertools import combinations F=libgap.GF(q**2) # F_{q^2} W=libgap.FullRowSpace(F, m) # F_{q^2}^m - B=libgap.Elements(libgap.Basis(W)) # the standard basis of W + B=libgap.Elements(libgap.Basis(W)) # the standard basis of W if m % 2: point = B[(m-1)/2] else: @@ -696,18 +699,18 @@ def NonisotropicUnitaryPolarGraph(m, q): else: point = B[(m-2)/2] + B[m/2] g = libgap.GeneralUnitaryGroup(m,q) - V = libgap.Orbit(g,point,libgap.OnLines) # orbit on nonisotropic points + V = libgap.Orbit(g,point,libgap.OnLines) # orbit on nonisotropic points gp = libgap.Action(g,V,libgap.OnLines) # make a permutation group - s = libgap.Subspace(W,[point, point+B[0]]) # a tangent line on point + s = libgap.Subspace(W,[point, point+B[0]]) # a tangent line on point # and the points there sp = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1))] h = libgap.Set([libgap.Position(V, x) for x in libgap.Intersection(V, sp)]) # indices - L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on the tangent lines + L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on the tangent lines G = Graph() - for x in L: # every pair of points in the subspace is adjacent to each other in G + for x in L: # every pair of points in the subspace is adjacent to each other in G G.add_edges(combinations(x, 2)) G.relabel() G.name("NU" + str((m, q))) @@ -715,14 +718,14 @@ def NonisotropicUnitaryPolarGraph(m, q): def UnitaryDualPolarGraph(m, q): r""" - Returns the Dual Unitary Polar Graph `U(m,q)`. + Return the Dual Unitary Polar Graph `U(m,q)`. For more information on Unitary Dual Polar graphs, see [BCN1989]_ and Sect. 2.3.1 of [Coh1981]_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power. + - ``m,q`` -- integers; `q` must be a prime power EXAMPLES: @@ -760,23 +763,23 @@ def UnitaryDualPolarGraph(m, q): intersection_size=int((q**(2*(m//2-1))-1)/(q**2-1))) G.relabel() G.name("Unitary Dual Polar Graph DU" + str((m, q))) - if m==4: + if m == 4: G.name(G.name()+'; GQ'+str((q,q**2))) - if m==5: + if m == 5: G.name(G.name()+'; GQ'+str((q**3,q**2))) return G def SymplecticDualPolarGraph(m, q): r""" - Returns the Symplectic Dual Polar Graph `DSp(m,q)`. + Return the Symplectic Dual Polar Graph `DSp(m,q)`. For more information on Symplectic Dual Polar graphs, see [BCN1989]_ and Sect. 2.3.1 of [Coh1981]_. INPUT: - - ``m,q`` (integers) -- `q` must be a prime power, and `m` must be even. + - ``m,q`` -- integers; `q` must be a prime power, and `m` must be even EXAMPLES:: @@ -802,13 +805,13 @@ def SymplecticDualPolarGraph(m, q): G.relabel() G.name("Symplectic Dual Polar Graph DSp" + str((m, q))) - if m==4: + if m == 4: G.name(G.name()+'; GQ'+str((q,q))) return G -def TaylorTwographDescendantSRG(q, clique_partition=None): +def TaylorTwographDescendantSRG(q, clique_partition=False): r""" - constructing the descendant graph of the Taylor's two-graph for `U_3(q)`, `q` odd + Return the descendant graph of the Taylor's two-graph for `U_3(q)`, `q` odd. This is a strongly regular graph with parameters `(v,k,\lambda,\mu)=(q^3, (q^2+1)(q-1)/2, (q-1)^3/4-1, (q^2+1)(q-1)/4)` @@ -818,17 +821,19 @@ def TaylorTwographDescendantSRG(q, clique_partition=None): :func:`~sage.graphs.graph_generators.GraphGenerators.TaylorTwographSRG`, a strongly regular graph on `q^3+1` vertices in the Seidel switching class of `T`, for which we need `(q^2+1)/2` cliques. - The cliques are the `q^2` lines on `v_0` of the projective plane containing the unital - for `U_3(q)`, and intersecting the unital (i.e. the vertices of the graph and the point - we remove) in `q+1` points. This is all taken from §7E of [BL1984]_. + The cliques are the `q^2` lines on `v_0` of the projective plane containing + the unital for `U_3(q)`, and intersecting the unital (i.e. the vertices of + the graph and the point we remove) in `q+1` points. This is all taken from + §7E of [BL1984]_. INPUT: - ``q`` -- a power of an odd prime number - - ``clique_partition`` -- if ``True``, return `q^2-1` cliques of size `q` - with empty pairwise intersection. (Removing all of them leaves a clique, too), - and the point removed from the unital. + - ``clique_partition`` -- boolean (default: ``False``); when set to + ``True``, return `q^2-1` cliques of size `q` with empty pairwise + intersection. (Removing all of them leaves a clique, too), and the point + removed from the unital. EXAMPLES:: @@ -838,7 +843,7 @@ def TaylorTwographDescendantSRG(q, clique_partition=None): (27, 10, 1, 5) sage: from sage.combinat.designs.twographs import taylor_twograph sage: T = taylor_twograph(3) # long time - sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time + sage: g.is_isomorphic(T.descendant(T.ground_set()[1])) # long time True sage: g=graphs.TaylorTwographDescendantSRG(5) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) @@ -859,7 +864,7 @@ def TaylorTwographDescendantSRG(q, clique_partition=None): ValueError: q must be an odd prime power """ p, k = is_prime_power(q,get_data=True) - if k==0 or p==2: + if not k or p == 2: raise ValueError('q must be an odd prime power') from sage.schemes.projective.projective_space import ProjectiveSpace from sage.rings.finite_rings.integer_mod import mod @@ -872,7 +877,7 @@ def S(x, y): V = [x for x in PG if S(x,x) == 0] # the points of the unital v0 = V[0] V.remove(v0) - if mod(q,4)==1: + if mod(q, 4) == 1: G = Graph([V,lambda y,z: not (S(v0,y)*S(y,z)*S(z,v0)).is_square()], loops=False) else: G = Graph([V,lambda y,z: (S(v0,y)*S(y,z)*S(z,v0)).is_square()], loops=False) @@ -887,7 +892,8 @@ def S(x, y): def TaylorTwographSRG(q): r""" - constructing a strongly regular graph from the Taylor's two-graph for `U_3(q)`, `q` odd + Return a strongly regular graph from the Taylor's two-graph for `U_3(q)`, + `q` odd This is a strongly regular graph with parameters `(v,k,\lambda,\mu)=(q^3+1, q(q^2+1)/2, (q^2+3)(q-1)/4, (q^2+1)(q+1)/4)` @@ -909,7 +915,6 @@ def TaylorTwographSRG(q): Taylor two-graph SRG: Graph on 28 vertices sage: t.is_strongly_regular(parameters=True) (28, 15, 6, 10) - """ G, l, v0 = TaylorTwographDescendantSRG(q, clique_partition=True) G.add_vertex(v0) @@ -919,7 +924,8 @@ def TaylorTwographSRG(q): def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): r""" - Return the collinearity graph of the generalized quadrangle `AS(q)`, or of its dual + Return the collinearity graph of the generalized quadrangle `AS(q)`, or of + its dual Let `q` be an odd prime power. `AS(q)` is a generalized quadrangle (:wikipedia:`Generalized_quadrangle`) of @@ -936,8 +942,8 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): - ``q`` -- a power of an odd prime number - - ``dual`` -- if ``False`` (default), return the collinearity graph of `AS(q)`. - Otherwise return the collinearity graph of the dual `AS(q)`. + - ``dual`` -- boolean (default: ``False``); whether to return the + collinearity graph of `AS(q)` or of the dual `AS(q)` (when ``True``) EXAMPLES:: @@ -952,7 +958,7 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): """ from sage.combinat.designs.incidence_structures import IncidenceStructure p, k = is_prime_power(q,get_data=True) - if k==0 or p==2: + if not k or p == 2: raise ValueError('q must be an odd prime power') F = FiniteField(q, 'a') L = [] @@ -972,38 +978,39 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False): def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True): r""" - Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or of its dual + Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or + of its dual Let `q=2^k` and `\Theta=PG(3,q)`. `T_2^*(q)` is a generalized quadrangle (:wikipedia:`Generalized_quadrangle`) of order `(q-1,q+1)`, see 3.1.3 in [PT2009]_. Fix a plane `\Pi \subset \Theta` and a `hyperoval `__ - `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of `\Theta` - outside `\Pi`, and the lines are the lines of `\Theta` outside `\Pi` - that meet `\Pi` in a point of `O`. + `O \subset \Pi`. The points of `T_2^*(q):=T_2^*(O)` are the points of + `\Theta` outside `\Pi`, and the lines are the lines of `\Theta` outside + `\Pi` that meet `\Pi` in a point of `O`. INPUT: - ``q`` -- a power of two - - ``dual`` -- if ``False`` (default), return the graph of `T_2^*(O)`. - Otherwise return the graph of the dual `T_2^*(O)`. + - ``dual`` -- boolean (default: ``False``); whether to return the graph of + `T_2^*(O)` or of the dual `T_2^*(O)` (when ``True``) - - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane - meeting every line in 0 or 2 points) in the plane of points with 0th coordinate - 0 in `PG(3,q)` over the field ``field``. Each point of ``hyperoval`` must be a length 4 - vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and - ``field`` are not specified, and constructed on the fly. In particular, ``hyperoval`` - we build is the classical one, i.e. a conic with the point of intersection of its - tangent lines. + - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in + the plane meeting every line in 0 or 2 points) in the plane of points with + 0th coordinate 0 in `PG(3,q)` over the field ``field``. Each point of + ``hyperoval`` must be a length 4 vector over ``field`` with 1st non-0 + coordinate equal to 1. By default, ``hyperoval`` and ``field`` are not + specified, and constructed on the fly. In particular, ``hyperoval`` we + build is the classical one, i.e. a conic with the point of intersection of + its tangent lines. - ``field`` -- an instance of a finite field of order `q`, must be provided - if ``hyperoval`` is provided. - - - ``check_hyperoval`` -- (default: ``True``) if ``True``, - check ``hyperoval`` for correctness. + if ``hyperoval`` is provided + - ``check_hyperoval`` -- boolean (default: ``True``); whether to check + ``hyperoval`` for correctness or not EXAMPLES: @@ -1045,7 +1052,7 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, from sage.combinat.designs.block_design import ProjectiveGeometryDesign as PG p, k = is_prime_power(q,get_data=True) - if k==0 or p!=2: + if not k or p != 2: raise ValueError('q must be a power of 2') if field is None: F = FiniteField(q, 'a') @@ -1090,16 +1097,16 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h of a strongly regular graph with parameters `(q^2(q+2),q^2+q-1,q-2,q)` from the graph of `T_2^*(q)^*`, constructed by :func:`~sage.graphs.graph_generators.GraphGenerators.T2starGeneralizedQuadrangleGraph`, - by redefining adjacencies in the way specified by an arbitrary ``hyperoval_matching`` - of the points (i.e. partitioning into size two parts) of ``hyperoval`` defining - `T_2^*(q)^*`. + by redefining adjacencies in the way specified by an arbitrary + ``hyperoval_matching`` of the points (i.e. partitioning into size two parts) + of ``hyperoval`` defining `T_2^*(q)^*`. While [BL1984]_ gives the construction in geometric terms, it can be formulated, and is implemented, in graph-theoretic ones, of re-adjusting the - edges. Namely, `G=T_2^*(q)^*` has a partition - into `q+2` independent sets `I_k` of size `q^2` each. Each vertex in `I_j` is - adjacent to `q` vertices from `I_k`. Each `I_k` is paired to some `I_{k'}`, - according to ``hyperoval_matching``. One adds edges `(s,t)` for `s,t \in I_k` whenever + edges. Namely, `G=T_2^*(q)^*` has a partition into `q+2` independent sets + `I_k` of size `q^2` each. Each vertex in `I_j` is adjacent to `q` vertices + from `I_k`. Each `I_k` is paired to some `I_{k'}`, according to + ``hyperoval_matching``. One adds edges `(s,t)` for `s,t \in I_k` whenever `s` and `t` are adjacent to some `u \in I_{k'}`, and removes all the edges between `I_k` and `I_{k'}`. @@ -1118,10 +1125,10 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h for more information. - ``field`` -- an instance of a finite field of order `q`, must be provided - if ``hyperoval`` is provided. + if ``hyperoval`` is provided - - ``check_hyperoval`` -- (default: ``True``) if ``True``, check - ``hyperoval`` for correctness. + - ``check_hyperoval`` -- boolean (default: ``True``); whether to check + ``hyperoval`` for correctness or not EXAMPLES: @@ -1164,7 +1171,7 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h from itertools import combinations p, k = is_prime_power(q, get_data=True) - if k == 0 or p != 2: + if not k or p != 2: raise ValueError('q must be a power of 2') if hyperoval_matching is None: @@ -1175,7 +1182,9 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_h F = field # for q=8, 95% of CPU time taken by this function is spent in the following call - G = T2starGeneralizedQuadrangleGraph(q, field=F, dual=True, hyperoval=hyperoval, check_hyperoval=check_hyperoval) + G = T2starGeneralizedQuadrangleGraph(q, field=F, dual=True, + hyperoval=hyperoval, + check_hyperoval=check_hyperoval) def normalize(v): # make sure the 1st non-0 coordinate is 1. d = next(x for x in v if x != F.zero()) @@ -1184,7 +1193,7 @@ def normalize(v): # make sure the 1st non-0 coordinate is 1. # build the partition into independent sets P = [tuple(normalize(v[0] - v[1])) for v in G.vertices()] O = list(set(P)) - I_ks = {x:[] for x in range(q+2)} # the partition into I_k's + I_ks = {x:[] for x in range(q+2)} # the partition into I_k's for i, Pi in enumerate(P): I_ks[O.index(tuple(Pi))].append(i) @@ -1195,7 +1204,7 @@ def normalize(v): # make sure the 1st non-0 coordinate is 1. Pij = set(I_ks[i]+I_ks[j]) for v in Pij: cliques.append(Pij.intersection(G.neighbors(v))) - G.delete_edges(G.edge_boundary(I_ks[i],I_ks[j])) # edges on (I_i,I_j) + G.delete_edges(G.edge_boundary(I_ks[i],I_ks[j])) # edges on (I_i,I_j) G.add_edges(e for c in cliques for e in combinations(c,2)) G.name('Haemers('+str(q)+')') return G @@ -1203,30 +1212,34 @@ def normalize(v): # make sure the 1st non-0 coordinate is 1. def CossidentePenttilaGraph(q): r""" - Cossidente-Penttila `((q^3+1)(q+1)/2,(q^2+1)(q-1)/2,(q-3)/2,(q-1)^2/2)`-strongly regular graph - - For each odd prime power `q`, one can partition the points of the `O_6^-(q)`-generalized - quadrangle `GQ(q,q^2)` into two parts, so that on any of them the induced subgraph of - the point graph of the GQ has parameters as above [CP2005]_. - - Directly following the construction in [CP2005]_ is not efficient, - as one then needs to construct the dual `GQ(q^2,q)`. Thus we - describe here a more efficient approach that we came up with, following a suggestion by - T.Penttila. Namely, this partition is invariant - under the subgroup `H=\Omega_3(q^2)3` one gets new graphs. :: - sage: G=graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) + sage: G=graphs.CossidentePenttilaGraph(5) # optional - gap_packages (grape) + sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) (378, 52, 1, 8) TESTS:: - sage: G=graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time - sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time + sage: G=graphs.CossidentePenttilaGraph(7) # optional - gap_packages (grape) # long time + sage: G.is_strongly_regular(parameters=True) # optional - gap_packages (grape) # long time (1376, 150, 2, 18) sage: graphs.CossidentePenttilaGraph(2) Traceback (most recent call last): @@ -1257,14 +1270,14 @@ def CossidentePenttilaGraph(q): ValueError: q(=2) must be an odd prime power """ p, k = is_prime_power(q,get_data=True) - if k==0 or p==2: + if not k or p == 2: raise ValueError('q(={}) must be an odd prime power'.format(q)) from sage.features.gap import GapPackage GapPackage("grape", spkg="gap_packages").require() from sage.libs.gap.libgap import libgap - adj_list=libgap.function_factory("""function(q) + adj_list = libgap.function_factory("""function(q) local z, e, so, G, nu, G1, G0, B, T, s, O1, O2, x; LoadPackage("grape"); G0:=SO(3,q^2); @@ -1298,41 +1311,42 @@ def CossidentePenttilaGraph(q): def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperoval=True): r""" - Return the subgraph of nowhere 0 words from two-weight code of projective plane hyperoval. + Return the subgraph of nowhere 0 words from two-weight code of projective + plane hyperoval. Let `q=2^k` and `\Pi=PG(2,q)`. Fix a `hyperoval `__ - `O \subset \Pi`. Let `V=F_q^3` and `C` the two-weight 3-dimensional linear code - over `F_q` with words `c(v)` obtained from `v\in V` by computing + `O \subset \Pi`. Let `V=F_q^3` and `C` the two-weight 3-dimensional linear + code over `F_q` with words `c(v)` obtained from `v\in V` by computing .. MATH:: c(v)=(\langle v,o_1 \rangle,...,\langle v,o_{q+2} \rangle), o_j \in O. - `C` contains `q(q-1)^2/2` words without 0 entries. The subgraph of the strongly - regular graph of `C` induced on the latter words is also strongly regular, - assuming `q>4`. This is a construction due to A.E.Brouwer [Bro2016]_, and - leads to graphs with parameters also given by a construction in [HHL2009]_. - According to [Bro2016]_, these two constructions are likely to produce - isomorphic graphs. + `C` contains `q(q-1)^2/2` words without 0 entries. The subgraph of the + strongly regular graph of `C` induced on the latter words is also strongly + regular, assuming `q>4`. This is a construction due to A.E.Brouwer + [Bro2016]_, and leads to graphs with parameters also given by a construction + in [HHL2009]_. According to [Bro2016]_, these two constructions are likely + to produce isomorphic graphs. INPUT: - ``q`` -- a power of two - - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in the plane - meeting every line in 0 or 2 points) in `PG(2,q)` over the field ``field``. - Each point of ``hyperoval`` must be a length 3 - vector over ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` and - ``field`` are not specified, and constructed on the fly. In particular, ``hyperoval`` - we build is the classical one, i.e. a conic with the point of intersection of its - tangent lines. + - ``hyperoval`` -- a hyperoval (i.e. a complete 2-arc; a set of points in + the plane meeting every line in 0 or 2 points) in `PG(2,q)` over the field + ``field``. Each point of ``hyperoval`` must be a length 3 vector over + ``field`` with 1st non-0 coordinate equal to 1. By default, ``hyperoval`` + and ``field`` are not specified, and constructed on the fly. In + particular, ``hyperoval`` we build is the classical one, i.e. a conic with + the point of intersection of its tangent lines. - ``field`` -- an instance of a finite field of order `q`, must be provided if ``hyperoval`` is provided. - - ``check_hyperoval`` -- (default: ``True``) if ``True``, - check ``hyperoval`` for correctness. + - ``check_hyperoval`` -- boolean (default: ``True``); whether to check + ``hyperoval`` for correctness or not .. SEEALSO:: @@ -1347,7 +1361,7 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov Nowhere0WordsTwoWeightCodeGraph(8): Graph on 196 vertices sage: g.is_strongly_regular(parameters=True) (196, 60, 14, 20) - sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time) + sage: g=graphs.Nowhere0WordsTwoWeightCodeGraph(16) # not tested (long time) sage: g.is_strongly_regular(parameters=True) # not tested (long time) (1800, 728, 268, 312) @@ -1378,9 +1392,9 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov from sage.matrix.constructor import matrix p, k = is_prime_power(q,get_data=True) - if k==0 or p!=2: + if not k or p != 2: raise ValueError('q must be a power of 2') - if k<3: + if k < 3: raise ValueError('q must be a at least 8') if field is None: F = FiniteField(q, 'a') @@ -1399,7 +1413,7 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov O = set(hyperoval) if check_hyperoval: - if len(O) != q+2: + if len(O) != q + 2: raise RuntimeError("incorrect hyperoval size") for L in Theta.blocks(): if set(L).issubset(Pi): @@ -1419,11 +1433,11 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperov def OrthogonalDualPolarGraph(e, d, q): r""" - Return dual polar graph on $GO^e(n,q)$ of diameter `d`. + Return the dual polar graph on $GO^e(n,q)$ of diameter `d`. + The value of `n` is determined by `d` and `e`. - The graph is distance-regular with classical parameters - `(d, q, 0, q^e)`. + The graph is distance-regular with classical parameters `(d, q, 0, q^e)`. INPUT: diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx index 91ab0818722..38c356d8863 100644 --- a/src/sage/graphs/generators/distance_regular.pyx +++ b/src/sage/graphs/generators/distance_regular.pyx @@ -2512,7 +2512,7 @@ def near_polygon_graph(family, params): sage: near_polygon_graph((0, 12)) Traceback (most recent call last): ... - TypeError: near_polygon_graph() takes exactly 2 positional arguments (1 given) + TypeError: ...near_polygon_graph() takes exactly 2 positional arguments (1 given) sage: near_polygon_graph(0, 12) Cycle graph: Graph on 12 vertices sage: near_polygon_graph(*is_near_polygon([8, 7, 6, 5, 1, 2, 3, 8])) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index e3da579d10a..91003aae159 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -21,6 +21,7 @@ from copy import copy from math import sin, cos, pi from sage.graphs.graph import Graph +from itertools import combinations def JohnsonGraph(n, k): @@ -199,7 +200,7 @@ def FurerGadget(k, prefix=None): (('Prefix', (1, 2)), ('Prefix', (1, 'a')), None), (('Prefix', (1, 2)), ('Prefix', (2, 'a')), None)] """ - from itertools import repeat as rep, chain, combinations + from itertools import repeat as rep, chain if k <= 0: raise ValueError("The order of the Furer gadget must be greater than zero") G = Graph() @@ -2091,62 +2092,77 @@ def HararyGraph( k, n ): G.name('Harary graph {0}, {1}'.format(k,n)) return G -def HyperStarGraph(n,k): +def HyperStarGraph(n, k): r""" - Returns the hyper-star graph HS(n,k). + Return the hyper-star graph `HS(n, k)`. - The vertices of the hyper-star graph are the set of binary strings - of length n which contain k 1s. Two vertices, u and v, are adjacent - only if u can be obtained from v by swapping the first bit with a - different symbol in another position. + The vertices of the hyper-star graph are the set of binary strings of length + `n` which contain `k` 1s. Two vertices, `u` and `v`, are adjacent only if + `u` can be obtained from `v` by swapping the first bit with a different + symbol in another position. For instance, vertex ``'011100'`` of `HS(6, 3)` + is adjacent to vertices ``'101100'``, ``'110100'`` and ``'111000'``. + See [LKOL2002]_ for more details. INPUT: - - ``n`` + - ``n`` -- non-negative integer; length of the binary strings - - ``k`` + - ``k`` -- non-negative integer; number of 1s per binary string EXAMPLES:: sage: g = graphs.HyperStarGraph(6,3) - sage: g.plot() # long time + sage: sorted(g.neighbors('011100')) + ['101100', '110100', '111000'] + sage: g.plot() # long time Graphics object consisting of 51 graphics primitives - REFERENCES: + TESTS:: - - Lee, Hyeong-Ok, Jong-Seok Kim, Eunseuk Oh, and Hyeong-Seok Lim. - "Hyper-Star Graph: A New Interconnection Network Improving the - Network Cost of the Hypercube." In Proceedings of the First EurAsian - Conference on Information and Communication Technology, 858-865. - Springer-Verlag, 2002. + sage: graphs.HyperStarGraph(-1, 1) + Traceback (most recent call last): + ... + ValueError: parameters n and k must be non-negative integers satisfying n >= k >= 0 + sage: graphs.HyperStarGraph(1, -1) + Traceback (most recent call last): + ... + ValueError: parameters n and k must be non-negative integers satisfying n >= k >= 0 + sage: graphs.HyperStarGraph(1, 2) + Traceback (most recent call last): + ... + ValueError: parameters n and k must be non-negative integers satisfying n >= k >= 0 AUTHORS: - Michael Yurko (2009-09-01) """ - from sage.combinat.combination import Combinations - # dictionary associating the positions of the 1s to the corresponding - # string: e.g. if n=6 and k=3, comb_to_str([0,1,4])=='110010' - comb_to_str={} - for c in Combinations(n,k): - L = ['0']*n - for i in c: - L[i]='1' - comb_to_str[tuple(c)] = ''.join(L) - - g = Graph(name="HS(%d,%d)"%(n,k)) - g.add_vertices(comb_to_str.values()) - - for c in Combinations(list(range(1, n)), k): # 0 is not in c - L = [] - u = comb_to_str[tuple(c)] - # switch 0 with the 1s - for i in range(len(c)): - v = tuple([0]+c[:i]+c[i+1:]) - g.add_edge( u , comb_to_str[v] ) - - return g - + if n < 0 or k < 0 or k > n: + raise ValueError("parameters n and k must be non-negative integers " + "satisfying n >= k >= 0") + if not n: + adj = {} + elif not k: + adj = {'0'*n: []} + elif k == n: + adj = {'1'*n: []} + else: + from sage.data_structures.bitset import Bitset + adj = dict() + # We consider the strings of n bits with k 1s and starting with a 0 + for c in combinations(range(1, n), k): + u = str(Bitset(c, capacity=n)) + L = [] + c = list(c) + # The neighbors of u are all the strings obtained by swapping a 1 + # with the first bit (0) + for i in range(k): + one = c[i] + c[i] = 0 + L.append(str(Bitset(c, capacity=n))) + c[i] = one + adj[u] = L + + return Graph(adj, format='dict_of_lists', name="HS(%d,%d)"%(n,k)) def LCFGraph(n, shift_list, repeats): r""" @@ -3839,7 +3855,6 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from time import time - import itertools assert d > 1, 'd must be at least 2' assert is_even(n * (d-1)), 'n must be even or d must be odd' @@ -3887,7 +3902,7 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): for C in ParClasses: EC = matrix(QQ, v) for line in C: - for i,j in itertools.combinations(line, 2): + for i,j in combinations(line, 2): EC[i,j] = EC[j,i] = 1/k EC -= ones_v E[tuple(C[0])] = EC diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 9c27944e532..927f9681aa7 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -577,16 +577,14 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): def RandomBoundedToleranceGraph(n): r""" - Returns a random bounded tolerance graph. + Return a random bounded tolerance graph. - The random tolerance graph is built from a random bounded - tolerance representation by using the function - `ToleranceGraph`. This representation is a list - `((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where - `k = n-1` and `I_i = (l_i,r_i)` denotes a random interval and - `t_i` a random positive value less then or equal to the length - of the interval `I_i`. The width of the representation is - limited to n**2 * 2**n. + The random tolerance graph is built from a random bounded tolerance + representation by using the function `ToleranceGraph`. This representation + is a list `((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where `k = + n-1` and `I_i = (l_i,r_i)` denotes a random interval and `t_i` a random + positive value less than or equal to the length of the interval `I_i`. The + width of the representation is limited to `n^2 * 2^n`. .. NOTE:: @@ -611,15 +609,27 @@ def RandomBoundedToleranceGraph(n): Check that :trac:`32186` is fixed:: sage: for _ in range(100): _ = graphs.RandomBoundedToleranceGraph(1) + + Check input parameter:: + + sage: g = graphs.RandomToleranceGraph(-2) + Traceback (most recent call last): + ... + ValueError: the number `n` of vertices must be >= 0 """ - from sage.misc.prandom import randint - from sage.combinat.combination import Combinations + if n < 0: + raise ValueError('the number `n` of vertices must be >= 0') + from sage.graphs.generators.intersection import ToleranceGraph W = n ** 2 * 2 ** n - C = Combinations(W + 1, 2) - - tolrep = [(l_r[0], l_r[1], randint(1, l_r[1] - l_r[0])) for l_r in [C.random_element() for i in range(n)]] + tolrep = [] + for _ in range(n): + l = randint(0, W - 1) + r = randint(0, W) + if l >= r: + l, r = r, l + 1 + tolrep.append((l, r, randint(1, r - l))) return ToleranceGraph(tolrep) @@ -1334,7 +1344,6 @@ def RandomTree(n): sage: graphs.RandomTree(1) Graph on 1 vertex """ - from sage.misc.prandom import randint g = Graph(n) if n <= 1: return g @@ -1492,13 +1501,13 @@ def RandomShell(constructor, seed=None): def RandomToleranceGraph(n): r""" - Returns a random tolerance graph. + Return a random tolerance graph. The random tolerance graph is built from a random tolerance representation by using the function `ToleranceGraph`. This representation is a list `((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where `k = n-1` and `I_i = (l_i,r_i)` denotes a random interval and `t_i` a random positive - value. The width of the representation is limited to n**2 * 2**n. + value. The width of the representation is limited to `n^2 * 2^n`. .. NOTE:: @@ -1524,17 +1533,22 @@ def RandomToleranceGraph(n): sage: g = graphs.RandomToleranceGraph(-2) Traceback (most recent call last): ... - ValueError: The number `n` of vertices must be >= 0. + ValueError: the number `n` of vertices must be >= 0 """ - from sage.misc.prandom import randint from sage.graphs.generators.intersection import ToleranceGraph - if n<0: - raise ValueError('The number `n` of vertices must be >= 0.') + if n < 0: + raise ValueError('the number `n` of vertices must be >= 0') W = n**2 * 2**n - tolrep = [tuple(sorted((randint(0,W), randint(0,W)))) + (randint(0,W),) for i in range(n)] + tolrep = [] + for _ in range(n): + l = randint(0, W) + r = randint(0, W) + if l > r: + l, r = r, l + tolrep.append((l, r, randint(0, W))) return ToleranceGraph(tolrep) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 77489cfaacb..a7ddfa7c1d9 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -1052,20 +1052,9 @@ def BidiakisCube(): edge_dict = { 0:[1,6,11], 1:[2,5], 2:[3,10], 3:[4,9], 4:[5,8], 5:[6], 6:[7], 7:[8,11], 8:[9], 9:[10], 10:[11]} - pos_dict = { - 0: [0, 1], - 1: [0.5, 0.866025403784439], - 2: [0.866025403784439, 0.500000000000000], - 3: [1, 0], - 4: [0.866025403784439, -0.5], - 5: [0.5, -0.866025403784439], - 6: [0, -1], - 7: [-0.5, -0.866025403784439], - 8: [-0.866025403784439, -0.5], - 9: [-1, 0], - 10: [-0.866025403784439, 0.5], - 11: [-0.5, 0.866025403784439]} - return Graph(edge_dict, pos=pos_dict, name="Bidiakis cube") + g = Graph(edge_dict, format='dict_of_lists', name="Bidiakis cube") + g._circle_embedding(range(12), angle=pi/2) + return g def BiggsSmithGraph(embedding=1): r""" @@ -1307,29 +1296,11 @@ def BrinkmannGraph(): 15: [18,19], 16: [19,20], 17: [20]} - pos_dict = { - 0: [0, 4], - 1: [3.12732592987212, 2.49395920743493], - 2: [3.89971164872729, -0.890083735825258], - 3: [1.73553495647023, -3.60387547160968], - 4: [-1.73553495647023, -3.60387547160968], - 5: [-3.89971164872729, -0.890083735825258], - 6: [-3.12732592987212, 2.49395920743493], - 7: [0.867767478235116, 1.80193773580484], - 8: [1.94985582436365, 0.445041867912629], - 9: [1.56366296493606, -1.24697960371747], - 10: [0, -2], - 11: [-1.56366296493606, -1.24697960371747], - 12: [-1.94985582436365, 0.445041867912629], - 13: [-0.867767478235116, 1.80193773580484], - 14: [0.433883739117558, 0.900968867902419], - 15: [0.974927912181824, 0.222520933956314], - 16: [0.781831482468030, -0.623489801858733], - 17: [0, -1], - 18: [-0.781831482468030, -0.623489801858733], - 19: [-0.974927912181824, 0.222520933956315], - 20: [-0.433883739117558, 0.900968867902419]} - return Graph(edge_dict, pos=pos_dict, name="Brinkmann graph") + g = Graph(edge_dict, format='dict_of_lists', name="Brinkmann graph") + g._circle_embedding(range(7), radius=4, angle=pi/2) + g._circle_embedding(range(7, 14), radius=2, angle=pi/2 + pi/7) + g._circle_embedding(range(14, 21), radius=1, angle=pi/2 + pi/7) + return g def BrouwerHaemersGraph(): r""" @@ -1788,19 +1759,11 @@ def ChvatalGraph(): """ edges = {0:[1, 4, 6, 9], 1:[2, 5, 7], 2:[3, 6, 8], 3:[4, 7, 9], 4:[5, 8], 5:[10, 11], 6:[10, 11], 7:[8, 11], 8:[10], 9:[10, 11]} - pos_dict = {} - for i in range(5, 10): - x = float(cos((pi / 2) + ((2 * pi) / 5) * i)) - y = float(sin((pi / 2) + ((2 * pi) / 5) * i)) - pos_dict[i] = (x, y) - for i in range(5): - x = float(2 * (cos((pi / 2) + ((2 * pi) / 5) * (i - 5)))) - y = float(2 * (sin((pi / 2) + ((2 * pi) / 5) * (i - 5)))) - pos_dict[i] = (x, y) - pos_dict[10] = (0.5, 0) - pos_dict[11] = (-0.5, 0) - - return Graph(edges, pos=pos_dict, name="Chvatal graph") + g = Graph(edges, format='dict_of_lists', name="Chvatal graph") + g._circle_embedding(range(5), radius=4, angle=pi/2) + g._circle_embedding(range(5, 10), radius=2, angle=pi/2) + g._circle_embedding(range(10, 12), radius=1) + return g def ClebschGraph(): r""" @@ -1956,31 +1919,10 @@ def DurerGraph(): sage: ag.is_isomorphic(DihedralGroup(6)) True """ - edge_dict = { - 0: [1,5,6], - 1: [2,7], - 2: [3,8], - 3: [4,9], - 4: [5,10], - 5: [11], - 6: [8,10], - 7: [9,11], - 8: [10], - 9: [11]} - pos_dict = { - 0: [2, 0], - 1: [1, 1.73205080756888], - 2: [-1, 1.73205080756888], - 3: [-2, 0], - 4: [-1, -1.73205080756888], - 5: [1, -1.73205080756888], - 6: [1, 0], - 7: [0.5, 0.866025403784439], - 8: [-0.5, 0.866025403784439], - 9: [-1, 0], - 10: [-0.5, -0.866025403784439], - 11: [0.5, -0.866025403784439]} - return Graph(edge_dict, pos=pos_dict, name="Durer graph") + from sage.graphs.generators.families import GeneralizedPetersenGraph + G = GeneralizedPetersenGraph(6, 2) + G.name("Durer graph") + return G def DyckGraph(): """ @@ -2411,19 +2353,13 @@ def FlowerSnark(): sage: F.show() # long time """ - pos_dict = {} - for i in range(15): - x = float(2.5*(cos((pi/2) + ((2*pi)/15)*i))) - y = float(2.5*(sin((pi/2) + ((2*pi)/15)*i))) - pos_dict[i] = (x,y) - for i in range(15,20): - x = float(cos((pi/2) + ((2*pi)/5)*i)) - y = float(sin((pi/2) + ((2*pi)/5)*i)) - pos_dict[i] = (x,y) d = {0: [1, 14, 15], 1: [2, 11], 2: [3, 7], 3: [2, 4, 16], 4: [5, 14], 5: [6, 10], 6: [5, 7, 17], 8: [7, 9, 13], 9: [10, 18], 11: [10, 12], 12: [13, 19], 13: [14], 15: [19], 16: [15, 17], 18: [17, 19]} - return Graph(d, format="dict_of_lists", pos=pos_dict, name="Flower Snark") + g = Graph(d, format="dict_of_lists", name="Flower Snark") + g._circle_embedding(range(15), radius=2.5, angle=pi/2) + g._circle_embedding(range(15, 20), radius=1, angle=pi/2) + return g def FolkmanGraph(): """ @@ -2541,20 +2477,10 @@ def FranklinGraph(): 7: [10], 8: [9,11], 10: [11]} - pos_dict = { - 0: [2, 0], - 1: [1, 1.73205080756888], - 2: [-1, 1.73205080756888], - 3: [-2, 0], - 4: [-1, -1.73205080756888], - 5: [1, -1.73205080756888], - 6: [1, 0], - 7: [0.5, 0.866025403784439], - 8: [-0.5, 0.866025403784439], - 9: [-1, 0], - 10: [-0.5, -0.866025403784439], - 11: [0.5, -0.866025403784439]} - return Graph(edge_dict, pos=pos_dict, name="Franklin graph") + g = Graph(edge_dict, format='dict_of_lists', name="Franklin graph") + g._circle_embedding(range(6), radius=2) + g._circle_embedding(range(6, 12), radius=1) + return g def FruchtGraph(): """ @@ -2586,17 +2512,11 @@ def FruchtGraph(): """ edges = {0:[1, 6, 7], 1:[2, 7], 2:[3, 8], 3:[4, 9], 4:[5, 9], 5:[6, 10], 6:[10], 7:[11], 8:[9, 11], 10:[11]} - pos_dict = {} - for i in range(7): - x = float(2*(cos((pi/2) + ((2*pi)/7)*i))) - y = float(2*(sin((pi/2) + ((2*pi)/7)*i))) - pos_dict[i] = (x,y) - pos_dict[7] = (0,1) - pos_dict[8] = (-1,0) - pos_dict[9] = (0,-1) - pos_dict[10] = (1,0) - pos_dict[11] = (0,0) - return Graph(edges, pos=pos_dict, name="Frucht graph") + g = Graph(edges, format='dict_of_lists', name="Frucht graph") + g._circle_embedding(range(7), radius=2, angle=pi/2) + g._circle_embedding(range(7, 11), radius=1, angle=pi/2) + g._pos[11] = (0, 0) + return g def GoldnerHararyGraph(): r""" @@ -2808,14 +2728,12 @@ def GrotzschGraph(): for u in range(7, 11): edges.append((u, u - 6)) - pos = {} - pos[0] = (0,0) - for u in range(1, 6): - theta = (u - 1) * 2 * pi / 5 - pos[u] = (float(5 * sin(theta)), float(5 * cos(theta))) - pos[u + 5] = (2 * pos[u][0], 2 * pos[u][1]) + g = Graph(edges, format='list_of_edges', name="Grotzsch graph") + g._circle_embedding(range(1, 6), radius=1, angle=pi/2) + g._circle_embedding(range(6, 11), radius=2, angle=pi/2) + g._pos[0] = (0, 0) - return Graph(edges, format='list_of_edges', pos=pos, name="Grotzsch graph") + return g def HeawoodGraph(): """ @@ -2850,12 +2768,9 @@ def HeawoodGraph(): """ edges = {0:[1, 5, 13], 1:[2, 10], 2:[3, 7], 3:[4, 12], 4:[5, 9], 5:[6], 6:[7, 11], 7:[8], 8:[9, 13], 9:[10], 10:[11], 11:[12], 12:[13]} - pos_dict = {} - for i in range(14): - x = float(cos((pi/2) + (pi/7)*i)) - y = float(sin((pi/2) + (pi/7)*i)) - pos_dict[i] = (x,y) - return Graph(edges, pos=pos_dict, name="Heawood graph") + g = Graph(edges, format='dict_of_lists', name="Heawood graph") + g._circle_embedding(range(14), radius=1, angle=pi/2) + return g def HerschelGraph(): r""" @@ -2911,19 +2826,11 @@ def HerschelGraph(): 7: [8], 8: [10], 9: [10]} - pos_dict = { - 0: [2, 0], - 1: [0, 2], - 2: [-2, 0], - 3: [0, -2], - 4: [1, 0], - 5: [0.5, 0.866025403784439], - 6: [-0.5, 0.866025403784439], - 7: [-1, 0], - 8: [-0.5, -0.866025403784439], - 9: [0.5, -0.866025403784439], - 10: [0, 0]} - return Graph(edge_dict, pos=pos_dict, name="Herschel graph") + g = Graph(edge_dict, format='dict_of_lists', name="Herschel graph") + g._circle_embedding(range(4), radius=2) + g._circle_embedding(range(4, 10), radius=1) + g._pos[10] = (0, 0) + return g def GritsenkoGraph(): r""" @@ -3083,21 +2990,10 @@ def HigmanSimsGraph(relabel=True): c = (m*(m-a) + b - 2) % 5 HS.add_edge(('1%d%d'%(m, c), '3%d%d'%(a, b))) - # Rename to integer vertex labels, creating dictionary - # Or not, and create identity mapping + # Layout vertices in a circle, in the order given in vlist + HS._circle_embedding(vlist, radius=10, angle=pi/2) if relabel: - vmap = HS.relabel(range(100), return_map=True) - else: - vmap = {v: v for v in vlist} - # Layout vertices in a circle - # In the order given in vlist - # Using labels from vmap - pos_dict = {} - for i in range(100): - x = float(cos((pi/2) + ((2*pi)/100)*i)) - y = float(sin((pi/2) + ((2*pi)/100)*i)) - pos_dict[vmap[vlist[i]]] = (x, y) - HS.set_pos(pos_dict) + HS.relabel(range(100)) return HS def HoffmanSingletonGraph(): @@ -3180,12 +3076,7 @@ def HoffmanSingletonGraph(): s = int(v[0]) l += 1 map = H.relabel(range(50), return_map=True) - pos_dict = {} - for i in range(50): - x = float(cos((pi/2) + ((2*pi)/50)*i)) - y = float(sin((pi/2) + ((2*pi)/50)*i)) - pos_dict[map[D[i]]] = (x, y) - H.set_pos(pos_dict) + H._circle_embedding([map[d] for d in D], angle=pi/2) return H def HoffmanGraph(): @@ -3862,18 +3753,14 @@ def PappusGraph(): sage: G.is_isomorphic(L) True """ - pos_dict = {} - for i in range(6): - pos_dict[i] = [float(cos(pi/2 + ((2*pi)/6)*i)), - float(sin(pi/2 + ((2*pi)/6)*i))] - pos_dict[6 + i] = [(2/3.0)*float(cos(pi/2 + ((2*pi)/6)*i)), - (2/3.0)*float(sin(pi/2 + ((2*pi)/6)*i))] - pos_dict[12 + i] = [(1/3.0)*float(cos(pi/2 + ((2*pi)/6)*i)), - (1/3.0)*float(sin(pi/2 + ((2*pi)/6)*i))] edges = {0: [1, 5, 6], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 10], 5: [11], 6: [13, 17], 7: [12, 14], 8: [13, 15], 9: [14, 16], 10: [15, 17], 11: [12, 16], 12: [15], 13: [16], 14: [17]} - return Graph(edges, pos=pos_dict, name="Pappus Graph") + g = Graph(edges, format='dict_of_lists', name="Pappus Graph") + g._circle_embedding(range(6), radius=3, angle=pi/2) + g._circle_embedding(range(6, 12), radius=2, angle=pi/2) + g._circle_embedding(range(12, 18), radius=1, angle=pi/2) + return g def PoussinGraph(): r""" diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 6a966a01e3f..2ab81f802b2 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -541,7 +541,7 @@ def __add__(self, other): sage: G+42 Traceback (most recent call last): ... - TypeError: adding and is not defined + TypeError: adding and is not defined """ if isinstance(other, GenericGraph): return self.disjoint_union(other, labels='integers') @@ -2581,7 +2581,7 @@ def _check_embedding_validity(self, embedding=None, boolean=True): if self._directed: connected = lambda u, v: self.has_edge(u, v) or self.has_edge(v, u) else: - connected = lambda u, v: self.has_edge(u, v) + connected = self.has_edge for v in embedding: if len(embedding[v]) != self.degree(v): if boolean: @@ -4308,31 +4308,31 @@ def min_spanning_tree(self, sage: g.min_spanning_tree(algorithm="Prim_Boost") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Prim_fringe") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Prim_edge") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Kruskal") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Filter_Kruskal") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="Kruskal_Boost") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: g.min_spanning_tree(algorithm="NetworkX") Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number... + TypeError: float() argument must be a string or a... number... sage: graphs.EmptyGraph().min_spanning_tree() [] @@ -5810,6 +5810,16 @@ def faces(self, embedding=None): neighbors of each vertex. From this information one can define the faces of the embedding, which is what this method returns. + If no embedding is provided or stored as ``self._embedding``, this + method will compute the set of faces from the embedding returned by + :meth:`is_planar` (if the graph is, of course, planar). + + .. WARNING:: + + This method is not well defined when the graph is not connected. + Indeed, the result may contain several faces corresponding to the + external face. + INPUT: - ``embedding`` -- dictionary (default: ``None``); a combinatorial @@ -5922,6 +5932,17 @@ def num_faces(self, embedding=None): """ Return the number of faces of an embedded graph. + If no embedding is provided or stored as ``self._embedding``, this + method uses Euler's formula (see the :wikipedia:`Euler_characteristic`) + to determine the number of faces if the graph is planar. If the graph is + not planar, an error is raised. + + If an embedding is provided or stored as ``self._embedding``, this + method calls method :meth:`faces` to get the list of faces induced by + the embedding in each connected component of the graph. Then it returns + the sum of size of these lists minus the number of connected components + plus one to ensure that the external face is counted only once. + INPUT: - ``embedding`` -- dictionary (default: ``None``); a combinatorial @@ -5938,6 +5959,21 @@ def num_faces(self, embedding=None): sage: T.num_faces() 4 + The external face of a disconnected graph is counted only once:: + + sage: (T + T).num_faces() + 7 + sage: (T + T + T).num_faces() + 10 + + Trees and forests have a single face:: + + sage: T = graphs.RandomTree(10) + sage: T.num_faces() + 1 + sage: (T + T).num_faces() + 1 + TESTS:: sage: G = graphs.CompleteBipartiteGraph(3, 3) @@ -5945,8 +5981,41 @@ def num_faces(self, embedding=None): Traceback (most recent call last): ... ValueError: no embedding is provided and the graph is not planar + + Ticket :trac:`22003` is fixed: + + sage: Graph(1).num_faces() + 1 """ - return len(self.faces(embedding)) + if not self: + return 0 + if self.is_connected(): + if self.order() == self.size() + 1: + # a tree has a single face + return 1 + return len(self.faces(embedding)) + + if embedding is None: + # Is self._embedding available ? + if self._check_embedding_validity(): + embedding = self._embedding + else: + if self.is_planar(): + # We use Euler's formula: V-E+F-C=1 + C = len(self.connected_components()) + return self.size() - self.order() + C + 1 + else: + raise ValueError("no embedding is provided and the graph is not planar") + + # We compute the number Fc of faces of each connected component c. + # The number of faces of the graph is the sum of the Fc values minus the + # number of connected components minus 1 to ensure that the external + # face is counted only once. That is, 1 + sum_{c} (Fc - 1). + F = 1 + for g in self.connected_components_subgraphs(): + emb = None if embedding is None else {v: embedding[v] for v in g} + F += g.num_faces(emb) - 1 + return F def planar_dual(self, embedding=None): """ @@ -6032,12 +6101,12 @@ def planar_dual(self, embedding=None): from sage.graphs.graph import Graph from itertools import combinations - verts = [tuple(f) for f in self.faces()] + verts = [tuple(f) for f in self.faces(embedding=embedding)] edges = [] for v1, v2 in combinations(verts, 2): e = set([tuple(reversed(e)) for e in v1]).intersection(v2) if e: - e = e.pop() # just one edge since self and its dual are simple + e = e.pop() # just one edge since self and its dual are simple edges.append([v1, v2, self.edge_label(e[0], e[1])]) return Graph([verts, edges]) @@ -6531,16 +6600,18 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, sage: G.edge_cut(0, 1, value_only=False, use_edge_labels=True) [1, [(2, 1, 1)]] sage: G.edge_cut(0, 1, value_only=False, use_edge_labels=True, algorithm='LP') - (1.0, [(2, 1)]) + (1, [(2, 1)]) """ self._scream_if_not_simple(allow_loops=True) if vertices: value_only = False if use_edge_labels: - weight = lambda x: x if (x != {} and x is not None) else 1 + def weight(x): + return x if (x != {} and x is not None) else 1 else: - weight = lambda x: 1 + def weight(x): + return 1 if algorithm in ["FF", "igraph", None]: if value_only: @@ -6578,6 +6649,14 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, b = p.new_variable(binary=True) v = p.new_variable(binary=True) + # Helper function to ensure that we use arcs when g is directed and + # frozensets otherwise + if g.is_directed(): + def good_edge(e): + return e + else: + good_edge = frozenset + # Some vertices belong to part 1, others to part 0 p.add_constraint(v[s], min=0, max=0) p.add_constraint(v[t], min=1, max=1) @@ -6585,51 +6664,46 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, if g.is_directed(): # we minimize the number of edges - p.set_objective(p.sum(weight(w) * b[x,y] for x,y,w in g.edge_iterator())) + p.set_objective(p.sum(weight(w) * b[good_edge((x, y))] for x, y, w in g.edge_iterator())) # Adjacent vertices can belong to different parts only if the # edge that connects them is part of the cut for x,y in g.edge_iterator(labels=None): - p.add_constraint(v[x] + b[x,y] - v[y], min=0) + p.add_constraint(v[x] + b[good_edge((x, y))] - v[y], min=0) else: # we minimize the number of edges - p.set_objective(p.sum(weight(w) * b[frozenset((x,y))] for x,y,w in g.edge_iterator())) + p.set_objective(p.sum(weight(w) * b[good_edge((x,y))] for x, y, w in g.edge_iterator())) # Adjacent vertices can belong to different parts only if the # edge that connects them is part of the cut for x,y in g.edge_iterator(labels=None): - p.add_constraint(v[x] + b[frozenset((x,y))] - v[y], min=0) - p.add_constraint(v[y] + b[frozenset((x,y))] - v[x], min=0) + p.add_constraint(v[x] + b[good_edge((x, y))] - v[y], min=0) + p.add_constraint(v[y] + b[good_edge((x, y))] - v[x], min=0) - if value_only: - if use_edge_labels: - return p.solve(objective_only=True, log=verbose) - else: - return Integer(round(p.solve(objective_only=True, log=verbose))) + p.solve(log=verbose) + b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) + if use_edge_labels: + obj = sum(weight(w) for x, y, w in g.edge_iterator() if b[good_edge((x,y))]) else: - obj = p.solve(log=verbose) + obj = Integer(sum(1 for e in g.edge_iterator(labels=False) if b[good_edge(e)])) - if use_edge_labels is False: - obj = Integer(round(obj)) + if value_only: + return obj - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - answer = [obj] - if g.is_directed(): - answer.append([(x,y) for (x,y) in g.edge_iterator(labels=None) if b[x,y]]) - else: - answer.append([(x,y) for (x,y) in g.edge_iterator(labels=None) if b[frozenset((x,y))]]) + answer = [obj] + answer.append([e for e in g.edge_iterator(labels=False) if b[good_edge(e)]]) - if vertices: - v = p.get_values(v, convert=bool, tolerance=integrality_tolerance) - l0 = [] - l1 = [] - for x in g: - if v.get(x, False): - l1.append(x) - else: - l0.append(x) - answer.append([l0, l1]) - return tuple(answer) + if vertices: + v = p.get_values(v, convert=bool, tolerance=integrality_tolerance) + l0 = [] + l1 = [] + for x in g: + if v.get(x, False): + l1.append(x) + else: + l0.append(x) + answer.append([l0, l1]) + return tuple(answer) def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -6718,42 +6792,42 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose p.add_constraint(b[s] == 0) p.add_constraint(b[t] == 0) - if g.is_directed(): - - p.set_objective(p.sum(b[x] for x in g)) + p.set_objective(p.sum(b[x] for x in g)) + if g.is_directed(): # adjacent vertices belong to the same part except if one of them # belongs to the cut for x,y in g.edge_iterator(labels=None): p.add_constraint(v[x] + b[y] - v[y], min=0) else: - p.set_objective(p.sum(b[x] for x in g)) # adjacent vertices belong to the same part except if one of them # belongs to the cut for x,y in g.edge_iterator(labels=None): p.add_constraint(v[x] + b[y] >= v[y]) p.add_constraint(v[y] + b[x] >= v[x]) + p.solve(log=verbose) + b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) + obj = Integer(sum(1 for x in g if b[x])) + if value_only: - return Integer(round(p.solve(objective_only=True, log=verbose))) - else: - obj = Integer(round(p.solve(log=verbose))) - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - answer = [obj, [x for x in g if b[x]]] - if vertices: - v = p.get_values(v, convert=bool, tolerance=integrality_tolerance) - l0 = [] - l1 = [] - for x in g: - # if the vertex is not in the cut - if not b.get(x, False): - if v.get(x, False): - l1.append(x) - else: - l0.append(x) - answer.append([l0, l1]) - return tuple(answer) + return obj + + answer = [obj, [x for x in g if b[x]]] + if vertices: + v = p.get_values(v, convert=bool, tolerance=integrality_tolerance) + l0 = [] + l1 = [] + for x in g: + # if the vertex is not in the cut + if not b.get(x, False): + if v.get(x, False): + l1.append(x) + else: + l0.append(x) + answer.append([l0, l1]) + return tuple(answer) def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, @@ -6846,17 +6920,25 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, # cut[e] represents whether e is in the cut cut = p.new_variable(binary=True) + # Helper function to correctly index variables cut + if self.is_directed(): + def good_edge(e): + return e + else: + good_edge = frozenset + # Weight function if use_edge_labels: - w = lambda l: l if l is not None else 1 + def weight(l): + return l if l is not None else 1 else: - w = lambda l: 1 - - if self.is_directed(): + def weight(l): + return 1 - p.set_objective(p.sum(w(l) * cut[u,v] for u,v,l in self.edge_iterator())) + p.set_objective(p.sum(weight(l) * cut[good_edge((u, v))] for u, v, l in self.edge_iterator())) - for s,t in chain(combinations(vertices, 2), [(x_y[1], x_y[0]) for x_y in combinations(vertices, 2)]): + if self.is_directed(): + for s,t in chain(combinations(vertices, 2), [(y, x) for x, y in combinations(vertices, 2)]): # For each commodity, the source is at height 0 # and the destination is at height 1 p.add_constraint(height[(s,t),s], min=0, max=0) @@ -6865,12 +6947,9 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, # given a commodity (s,t), the height of two adjacent vertices u,v # can differ of at most the value of the edge between them for u,v in self.edge_iterator(labels=False): - p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[u,v], max=0) + p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[good_edge((u, v))], max=0) else: - - p.set_objective(p.sum(w(l) * cut[frozenset((u,v))] for u,v,l in self.edge_iterator())) - for s,t in combinations(vertices, 2): # For each commodity, the source is at height 0 # and the destination is at height 1 @@ -6880,23 +6959,19 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, # given a commodity (s,t), the height of two adjacent vertices u,v # can differ of at most the value of the edge between them for u,v in self.edge_iterator(labels=False): - p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[frozenset((u,v))], max=0) - p.add_constraint(height[(s,t),v] - height[(s,t),u] - cut[frozenset((u,v))], max=0) - - if value_only: - if use_edge_labels: - return p.solve(objective_only=True, log=verbose) - else: - return Integer(round(p.solve(objective_only=True, log=verbose))) + p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[good_edge((u,v))], max=0) + p.add_constraint(height[(s,t),v] - height[(s,t),u] - cut[good_edge((u,v))], max=0) p.solve(log=verbose) - cut = p.get_values(cut, convert=bool, tolerance=integrality_tolerance) - if self.is_directed(): - return [x for x in self.edge_iterator() if cut[x[0], x[1]]] + if value_only: + if use_edge_labels: + return sum(weight(l) for u, v, l in self.edge_iterator() if cut[good_edge((u, v))]) + else: + return Integer(sum(1 for e in self.edge_iterator(labels=False) if cut[good_edge(e)])) - return [x for x in self.edge_iterator() if cut[frozenset((x[0], x[1]))]] + return [e for e in self.edge_iterator() if cut[good_edge((e[0], e[1]))]] def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, @@ -6973,9 +7048,17 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, if use_edge_labels: from sage.rings.real_mpfr import RR - weight = lambda x: x if x in RR else 1 + def weight(x): + return x if x in RR else 1 else: - weight = lambda x: 1 + def weight(x): + return 1 + + if g.is_directed(): + def good_edge(e): + return e + else: + good_edge = frozenset from sage.numerical.mip import MixedIntegerLinearProgram @@ -6993,8 +7076,7 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, p.add_constraint(p.sum(in_set[0,v] for v in g), min=1) if g.is_directed(): - # There is no edge from set 0 to set 1 which - # is not in the cut + # There is no edge from set 0 to set 1 which is not in the cut. # Besides, an edge can only be in the cut if its vertices # belong to different sets for u,v in g.edge_iterator(labels=None): @@ -7002,48 +7084,34 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, p.add_constraint(in_set[0,u] + in_set[0,v] + in_cut[u,v], max=2) p.add_constraint(in_set[1,u] + in_set[1,v] + in_cut[u,v], max=2) - p.set_objective(p.sum(weight(l) * in_cut[u,v] for u,v,l in g.edge_iterator())) - else: - # Two adjacent vertices are in different sets if and only if # the edge between them is in the cut for u,v in g.edge_iterator(labels=None): - fuv = frozenset((u,v)) + fuv = good_edge((u, v)) p.add_constraint(in_set[0,u] + in_set[1,v] - in_cut[fuv], max=1) p.add_constraint(in_set[1,u] + in_set[0,v] - in_cut[fuv], max=1) p.add_constraint(in_set[0,u] + in_set[0,v] + in_cut[fuv], max=2) p.add_constraint(in_set[1,u] + in_set[1,v] + in_cut[fuv], max=2) - p.set_objective(p.sum(weight(l) * in_cut[frozenset((u,v))] for u,v,l in g.edge_iterator())) - - if value_only: - obj = p.solve(objective_only=True, log=verbose) - return obj if use_edge_labels else Integer(round(obj)) - else: - obj = p.solve(log=verbose) - - if use_edge_labels: - obj = Integer(round(obj)) - - val = [obj] + p.set_objective(p.sum(weight(l) * in_cut[good_edge((u, v))] for u, v, l in g.edge_iterator())) - in_cut = p.get_values(in_cut, convert=bool, tolerance=integrality_tolerance) - in_set = p.get_values(in_set, convert=bool, tolerance=integrality_tolerance) + p.solve(log=verbose) - edges = [] - if g.is_directed(): - for u,v,l in g.edge_iterator(): - if in_cut[u,v]: - edges.append((u,v,l)) - else: - for u,v,l in g.edge_iterator(): - if in_cut[frozenset((u,v))]: - edges.append((u,v,l)) + in_cut = p.get_values(in_cut, convert=bool, tolerance=integrality_tolerance) + if use_edge_labels: + obj = sum(weight(l) for u, v, l in g.edge_iterator() if in_cut[good_edge((u, v))]) + else: + obj = Integer(sum(1 for e in g.edge_iterator(labels=False) if in_cut[good_edge(e)])) - val.append(edges) + if value_only: + return obj + else: + edges = [(u, v, l) for u, v, l in g.edge_iterator() if in_cut[good_edge((u, v))]] + val = [obj, edges] if vertices: + in_set = p.get_values(in_set, convert=bool, tolerance=integrality_tolerance) a = [] b = [] for v in g: @@ -8514,11 +8582,11 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, # Variables are binary, and their coefficient in the objective is 1 p.set_objective(p.sum(b[v] for v in self)) - p.solve(log=verbose) - # For as long as we do not break because the digraph is acyclic.... while True: + p.solve(log=verbose) + # Building the graph without the vertices removed by the LP b_val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) h = self.subgraph([v for v in self if not b_val[v]]) @@ -8531,7 +8599,10 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, # If so, we are done ! if isok: - break + if value_only: + return Integer(self.order() - h.order()) + else: + return [v for v in self if b_val[v]] # There is a circuit left. Let's add the corresponding # constraint ! @@ -8548,17 +8619,6 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, else: isok, certificate = h.is_forest(certificate=True) - obj = p.solve(log=verbose) - - if value_only: - return obj - - else: - - # Listing the vertices contained in the MFVS - b_val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [v for v in self if b_val[v]] - else: ###################################### @@ -8580,12 +8640,11 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, p.set_objective(p.sum(b[v] for v in self)) + p.solve(log=verbose) + b_sol = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if value_only: - return Integer(round(p.solve(objective_only=True, log=verbose))) + return Integer(sum(1 for v in self if b_sol[v])) else: - p.solve(log=verbose) - b_sol = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [v for v in self if b_sol[v]] def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, @@ -8762,11 +8821,14 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, from sage.rings.real_mpfr import RR if integer: from math import floor - capacity=lambda x: floor(x) if x in RR else 1 + def capacity(z): + return floor(z) if z in RR else 1 else: - capacity=lambda x: x if x in RR else 1 + def capacity(z): + return z if z in RR else 1 else: - capacity=lambda x: 1 + def capacity(z): + return 1 if algorithm is None: if vertex_bound: @@ -8822,7 +8884,8 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, from sage.numerical.mip import MixedIntegerLinearProgram g = self p = MixedIntegerLinearProgram(maximization=True, solver=solver) - flow = p.new_variable(nonnegative=True) + flow = p.new_variable(integer=integer, nonnegative=True) + obj = p.new_variable(integer=integer, nonnegative=True) if g.is_directed(): # This function return the balance of flow at X @@ -8846,11 +8909,12 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, capacity_sum = lambda u,v: flow[u,v] + flow[v,u] # Maximizes the flow leaving x - p.set_objective(flow_sum(x)) + p.add_constraint(flow_sum(x) == obj[0]) + p.set_objective(obj[0]) # Elsewhere, the flow is equal to 0 for v in g: - if v!=x and v!=y: + if v != x and v != y: p.add_constraint(flow_sum(v), min=0, max=0) # Capacity constraints @@ -8860,25 +8924,23 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, # No vertex except the sources can send more than 1 if vertex_bound: for v in g: - if v!=x and v!=y: + if v != x and v != y: p.add_constraint(flow_leaving(v), max=1) - if integer: - p.set_integer(flow) - - - if value_only: - return p.solve(objective_only=True, log=verbose) - - obj = p.solve(log=verbose) - - if integer or use_edge_labels is False: - obj = Integer(round(obj)) + p.solve(log=verbose) # If integer is True, flow variables will be converted to integers. # Otherwise, the base ring of the MILP solver is used flow = p.get_values(flow, convert=True, tolerance=integrality_tolerance) + if not integer and use_edge_labels is False: + obj = p.get_values(obj[0], convert=ZZ, tolerance=integrality_tolerance) + else: + obj = p.get_values(obj[0], convert=True, tolerance=integrality_tolerance) + + if value_only: + return obj + # Builds a clean flow Draph flow_graph = g._build_flow_graph(flow, integer=integer) @@ -20630,6 +20692,12 @@ def graphviz_string(self, **options): - ``"label_style"`` (``"string"`` or ``"latex"``) - ``"edge_string"`` (``"--"`` or ``"->"``) - ``"dir"`` (``"forward"``, ``"back"``, ``"both"`` or ``"none"``) + - ``"backward"`` (boolean), instead of defining the edge in the + graphviz string as ``u -> v`` it draws it as ``v -> u + [dir=back]`` and instead of ``u -> v [dir=back]`` it draws it as + ``v -> u``, this changes the way it is drawn by Graphviz's dot + program: vertex ``v`` will be *above* vertex ``u`` instead of + below. Here we state that the graph should be laid out so that edges starting from ``1`` are going backward (e.g. going up instead of @@ -20720,6 +20788,30 @@ def graphviz_string(self, **options): node_3 -> node_4 [dir=both]; } + We test the same graph and ``'dir'`` edge options but with + ``backward=True``, which reverses the natural direction + each edge wants to be pointing for the layout:: + + sage: def edge_options(data): + ....: u,v,label = data + ....: if label == 'a': return {'dir':'forward', 'backward':True} + ....: if label == 'b': return {'dir':'back', 'backward':True} + ....: if label == 'c': return {'dir':'none', 'backward':True} + ....: if label == 'd': return {'dir':'both', 'backward':True} + sage: print(G.graphviz_string(edge_options=edge_options)) + digraph { + node_0 [label="0"]; + node_1 [label="1"]; + node_2 [label="2"]; + node_3 [label="3"]; + node_4 [label="4"]; + + node_1 -> node_0 [dir=back]; + node_2 -> node_1; + node_3 -> node_2 [dir=none]; + node_4 -> node_3 [dir=both]; + } + TESTS: The following digraph has tuples as vertices:: @@ -20847,20 +20939,6 @@ def graphviz_string(self, **options): ... ValueError: edge_string(='<-') in edge_options dict for the edge (0, 1) should be '--' or '->' - - The ``'backward'`` parameter of an edge option is deprecated since - :trac:`31381`:: - - sage: edges = [(0,1,'a'), (1,2,'b'), (2,3,'c'), (3,4,'d')] - sage: G = DiGraph(edges) - sage: def edge_options(data): - ....: u,v,label = data - ....: return {'backward':True} if label == 'a' else {} - sage: _ = G.graphviz_string(edge_options=edge_options) - doctest:...: DeprecationWarning: parameter {'backward':True} (in edge_options) - is deprecated. Use {'dir':'back'} instead. - See https://trac.sagemath.org/31381 for details. - """ from sage.graphs.dot2tex_utils import quoted_latex, quoted_str @@ -20952,6 +21030,7 @@ def graphviz_string(self, **options): for u, v, label in self.edge_iterator(): edge_options = { 'dir': default_edge_dir, + 'backward': False, 'dot': None, 'edge_string': default_edge_string, 'color' : default_color, @@ -20966,12 +21045,6 @@ def graphviz_string(self, **options): "edge ({}, {}) should be '--' " "or '->'".format(edge_options['edge_string'], u, v)) - if 'backward' in edge_options and edge_options['backward']: - deprecation(31381, "parameter {'backward':True} (in edge_options) is" - " deprecated. Use {'dir':'back'} instead.") - del edge_options['backward'] - edge_options['dir'] = 'back' - dot_options = [] if edge_options['dot'] is not None: @@ -20993,6 +21066,13 @@ def graphviz_string(self, **options): dot_options.append('color = "%s"' % col) + if edge_options['backward']: + u, v = v, u + if edge_options['dir'] == 'forward': + edge_options['dir'] = 'back' + elif edge_options['dir'] == 'back': + edge_options['dir'] = 'forward' + if edge_options['dir'] == default_edge_dir: pass elif edge_options['dir'] in ['forward', 'back', 'both', 'none']: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 6bcf419e065..36346cdaec7 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4200,14 +4200,15 @@ def weight(x): for v in g: p.add_constraint(p.sum(b[frozenset(e)] for e in self.edge_iterator(vertices=[v], labels=False) if e[0] != e[1]), max=1) + + p.solve(log=verbose) + b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if value_only: if use_edge_labels: - return p.solve(objective_only=True, log=verbose) + return sum(w for fe, w in W.items() if b[fe]) else: - return Integer(round(p.solve(objective_only=True, log=verbose))) + return Integer(sum(1 for fe in L if b[fe])) else: - p.solve(log=verbose) - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) return [(u, v, L[frozenset((u, v))]) for u, v in L if b[frozenset((u, v))]] else: @@ -4318,7 +4319,7 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, p.set_objective(p.sum(m[vh] for vh in H)) try: - p.solve(log = verbose) + p.solve(log=verbose) except MIPSolverException: return False @@ -6787,11 +6788,11 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, for u,v in g.edge_iterator(labels=None): p.add_constraint(b[u] + b[v], min=1) + p.solve(log=verbose) + b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if value_only: - size_cover_g = p.solve(objective_only=True, log=verbose) + size_cover_g = sum(1 for v in g if b[v]) else: - p.solve(log=verbose) - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) cover_g = set(v for v in g if b[v]) else: raise ValueError('the algorithm must be "Cliquer", "MILP" or "mcqd"') @@ -9409,6 +9410,7 @@ def bipartite_double(self, extended=False): from sage.graphs.graph_decompositions.rankwidth import rank_decomposition from sage.graphs.graph_decompositions.tree_decomposition import treewidth from sage.graphs.graph_decompositions.vertex_separation import pathwidth + from sage.graphs.graph_decompositions.tree_decomposition import treelength from sage.graphs.graph_decompositions.clique_separators import atoms_and_clique_separators from sage.graphs.matchpoly import matching_polynomial from sage.graphs.cliquer import all_max_clique as cliques_maximum @@ -9446,6 +9448,7 @@ def bipartite_double(self, extended=False): "rank_decomposition" : "Algorithmically hard stuff", "treewidth" : "Algorithmically hard stuff", "pathwidth" : "Algorithmically hard stuff", + "treelength" : "Algorithmically hard stuff", "matching_polynomial" : "Algorithmically hard stuff", "all_max_clique" : "Clique-related methods", "cliques_maximum" : "Clique-related methods", diff --git a/src/sage/graphs/graph_coloring.pyx b/src/sage/graphs/graph_coloring.pyx index 24ee5fa5b92..98529763aef 100644 --- a/src/sage/graphs/graph_coloring.pyx +++ b/src/sage/graphs/graph_coloring.pyx @@ -1004,18 +1004,18 @@ def grundy_coloring(g, k, value_only=True, solver=None, verbose=0, p.set_objective(p.sum(is_used[i] for i in range(k))) try: - obj = p.solve(log=verbose, objective_only=value_only) - from sage.rings.integer import Integer - obj = Integer(obj) - + p.solve(log=verbose) except MIPSolverException: raise ValueError("this graph cannot be colored with k colors") + from sage.rings.integer import Integer + is_used = p.get_values(is_used, convert=bool, tolerance=integrality_tolerance) + obj = Integer(sum(1 for i in range(k) if is_used[i])) + if value_only: return obj # Building the dictionary associating its color to every vertex - b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) cdef dict coloring = {} @@ -1197,19 +1197,18 @@ def b_coloring(g, k, value_only=True, solver=None, verbose=0, try: - obj = p.solve(log=verbose, objective_only=value_only) - from sage.rings.integer import Integer - obj = Integer(obj) - + p.solve(log=verbose) except MIPSolverException: raise ValueError("this graph cannot be colored with k colors") + from sage.rings.integer import Integer + is_used = p.get_values(is_used, convert=bool, tolerance=integrality_tolerance) + obj = Integer(sum(1 for i in range(k) if is_used[i])) + if value_only: return obj - # Building the dictionary associating its color to every vertex - c = p.get_values(color, convert=bool, tolerance=integrality_tolerance) cdef dict coloring = {} diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index 1e695e6047b..c7c6fe18cca 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -669,18 +669,18 @@ def show(self, max_field_size=20, with_picture=False): relabel[col] = ' '.join([word.capitalize() for word in col.split('_')]) if re.search('SELECT .*degree_sequence.* FROM', self.__query_string__): - format_cols = {'degree_sequence': (lambda x, y: data_to_degseq(x, y))} + format_cols = {'degree_sequence': data_to_degseq} else: format_cols = {} if with_picture: SQLQuery.show(self, max_field_size=max_field_size, - plot_cols={'graph6': (lambda x: graph6_to_plot(x))}, - format_cols=format_cols, id_col='graph6', - relabel_cols=relabel) + plot_cols={'graph6': graph6_to_plot}, + format_cols=format_cols, id_col='graph6', + relabel_cols=relabel) else: SQLQuery.show(self, max_field_size=max_field_size, - format_cols=format_cols, relabel_cols=relabel, - id_col='graph6') + format_cols=format_cols, relabel_cols=relabel, + id_col='graph6') def get_graphs_list(self): """ diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pxd b/src/sage/graphs/graph_decompositions/tree_decomposition.pxd new file mode 100644 index 00000000000..e8afe048691 --- /dev/null +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pxd @@ -0,0 +1,16 @@ +from sage.graphs.generic_graph_pyx cimport GenericGraph_pyx + +cdef class TreelengthConnected: + cdef unsigned int n + cdef unsigned short * c_distances + cdef unsigned short ** distances + cdef unsigned int diameter + cdef str name + cdef dict perm_inv + cdef bint certificate + cdef bint k_is_defined + cdef unsigned int k + cdef GenericGraph_pyx tree # The final tree decomposition is stored + cdef unsigned int length + cdef bint leq_k + cdef bint _treelength(self, g, k) diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index a8a6ea0dc64..e2608da8995 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -9,11 +9,13 @@ X_2, \ldots, X_t\}` is a familly of subsets of `V`, usually called *bags*, and `T` is a tree of order `t` whose nodes are the subsets `X_i` satisfying the following properties: -1. The union of all sets `X_i` equals `V`. That is, each vertex of the graph `G` +- The union of all sets `X_i` equals `V`. That is, each vertex of the graph `G` is associated with at least one tree node. -2. For every edge `(v, w)` in the graph, there is a subset `X_i` that contains + +- For every edge `(v, w)` in the graph, there is a subset `X_i` that contains both `v` and `w`. That is, each edge of the graph `G` appears in a tree node. -3. The nodes associated with vertex `v \in V` form a connected subtree of + +- The nodes associated with vertex `v \in V` form a connected subtree of `T`. That is, if `X_i` and `X_j` both contain a vertex `v \in V`, then all nodes `X_k` of the tree in the (unique) path between `X_i` and `X_j` contain `v` as well, and we have `X_i \cap X_j \subseteq X_k`. @@ -24,6 +26,40 @@ one, i.e., `\max_{X_i \in X} |X_i| - 1`, and the *treewidth* `tw(G)` of a graph that, the size of the largest set is diminished by one in order to make the treewidth of a tree equal to one. +The *length* of a tree decomposition, as proposed in [DG2006]_, is the maximum +*diameter* in `G` of its bags, where the diameter of a bag `X_i` is the largest +distance in `G` between the vertices in `X_i` (i.e., `\max_{u, v \in X_i} +dist_G(u, v)`). The *treelength* `tl(G)` of a graph `G` is the minimum length +among all possible tree decompositions of `G`. + +While deciding whether a graph has treelength 1 can be done in linear time +(equivalant to deciding if the graph is chordal), deciding if it has treelength +at most `k` for any fixed constant `k \leq 2` is NP-complete [Lokshtanov2009]_. + +Treewidth and treelength are different measures of tree-likeness. In particular, +trees have treewidth and treelength 1:: + + sage: T = graphs.RandomTree(20) + sage: T.treewidth() + 1 + sage: T.treelength() + 1 + +The treewidth of a cycle is 2 and its treelength is `\lceil n/3 \rceil`:: + + sage: [graphs.CycleGraph(n).treewidth() for n in range(3, 11)] + [2, 2, 2, 2, 2, 2, 2, 2] + sage: [graphs.CycleGraph(n).treelength() for n in range(3, 11)] + [1, 2, 2, 2, 3, 3, 3, 4] + +The treewidth of a clique is `n-1` and its treelength is 1:: + + sage: [graphs.CompleteGraph(n).treewidth() for n in range(3, 11)] + [2, 3, 4, 5, 6, 7, 8, 9] + sage: [graphs.CompleteGraph(n).treelength() for n in range(3, 11)] + [1, 1, 1, 1, 1, 1, 1, 1] + + .. SEEALSO:: - :wikipedia:`Tree_decomposition` @@ -37,16 +73,16 @@ treewidth of a tree equal to one. :widths: 30, 70 :delim: | - :meth:`treewidth` | Compute the tree-width of `G` (and provide a decomposition). + :meth:`treewidth` | Compute the treewidth of `G` (and provide a decomposition). + :meth:`treelength` | Compute the treelength of `G` (and provide a decomposition). :meth:`is_valid_tree_decomposition` | Check whether `T` is a valid tree-decomposition for `G`. - :meth:`reduced_tree_decomposition(T)` | Return a reduced tree-decomposition of `T`. + :meth:`reduced_tree_decomposition` | Return a reduced tree-decomposition of `T`. + :meth:`width_of_tree_decomposition` | Return the width of the tree decomposition `T` of `G`. .. TODO: - Add method to return a *nice* tree decomposition - - Add methods to compute treelength and examples in the module documentation - of the difference between treewidth and treelength - Approximation of treelength based on :meth:`~sage.graphs.graph.Graph.lex_M` - Approximation of treelength based on BFS Layering @@ -72,6 +108,10 @@ from itertools import combinations from itertools import chain from sage.features import PythonModule from sage.sets.disjoint_set import DisjointSet +from sage.rings.infinity import Infinity +from sage.graphs.distances_all_pairs cimport c_distances_all_pairs +from cysignals.memory cimport sig_malloc, sig_calloc, sig_free + def is_valid_tree_decomposition(G, T): r""" @@ -210,7 +250,7 @@ def reduced_tree_decomposition(T): This method assumes that the vertices of the input tree `T` are hashable and have attribute ``issuperset``, e.g., ``frozenset`` or - :class:`~sage.sets.set.Set_object_enumerated_with_category`. + :class:`~sage.sets.set.Set_object_enumerated`. INPUT: @@ -241,7 +281,16 @@ def reduced_tree_decomposition(T): True sage: T == reduced_tree_decomposition(T) True + sage: G = Graph(1) + sage: T = G.treewidth(certificate=True) + sage: T.order() + 1 + sage: T == reduced_tree_decomposition(T) + True """ + if T.order() < 2: + return T + def get_ancestor(ancestor, u): if ancestor[u] == u: return u @@ -313,7 +362,7 @@ def width_of_tree_decomposition(G, T, check=True): def _from_tree_decompositions_of_atoms_to_tree_decomposition(T_atoms, cliques): r""" - Return a tree-decomposition formed by the tree_decompositions of the atoms. + Return a tree-decomposition formed by the tree-decompositions of the atoms. This is a helper method to avoid duplicated code. @@ -384,7 +433,7 @@ def _from_tree_decompositions_of_atoms_to_tree_decomposition(T_atoms, cliques): def treewidth(g, k=None, kmin=None, certificate=False, algorithm=None): r""" - Computes the tree-width of `g` (and provides a decomposition) + Compute the treewidth of `g` (and provide a decomposition). INPUT: @@ -409,22 +458,22 @@ def treewidth(g, k=None, kmin=None, certificate=False, algorithm=None): OUTPUT: - ``g.treewidth()`` returns the treewidth of ``g``. When ``k`` is - specified, it returns ``False`` when no tree-decomposition of width - `\leq k` exists or ``True`` otherwise. When ``certificate=True``, the - tree-decomposition is also returned. + ``g.treewidth()`` returns the treewidth of ``g``. When ``k`` is specified, + it returns ``False`` when no tree-decomposition of width `\leq k` exists or + ``True`` otherwise. When ``certificate=True``, the tree-decomposition is + also returned. ALGORITHM: - This function virtually explores the graph of all pairs - ``(vertex_cut,cc)``, where ``vertex_cut`` is a vertex cut of the graph - of cardinality `\leq k+1`, and ``connected_component`` is a connected - component of the graph induced by ``G-vertex_cut``. + This function virtually explores the graph of all pairs ``(vertex_cut,cc)``, + where ``vertex_cut`` is a vertex cut of the graph of cardinality `\leq k+1`, + and ``connected_component`` is a connected component of the graph induced by + ``G-vertex_cut``. - We deduce that the pair ``(vertex_cut,cc)`` is feasible with tree-width - `k` if ``cc`` is empty, or if a vertex ``v`` from ``vertex_cut`` can be - replaced with a vertex from ``cc``, such that the pair - ``(vertex_cut+v,cc-v)`` is feasible. + We deduce that the pair ``(vertex_cut,cc)`` is feasible with tree-width `k` + if ``cc`` is empty, or if a vertex ``v`` from ``vertex_cut`` can be replaced + with a vertex from ``cc``, such that the pair ``(vertex_cut+v,cc-v)`` is + feasible. .. NOTE:: @@ -723,3 +772,749 @@ def treewidth(g, k=None, kmin=None, certificate=False, algorithm=None): G.name("Tree decomposition") return G + +# +# Treelength +# + +def treelength_lowerbound(G): + r""" + Return a lower bound on the treelength of `G`. + + See [DG2006]_ for more details. + + INPUT: + + - ``G`` -- a sage Graph + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import treelength_lowerbound + sage: G = graphs.PetersenGraph() + sage: treelength_lowerbound(G) + 1 + sage: G.treelength() + 2 + sage: G = graphs.CycleGraph(5) + sage: treelength_lowerbound(G) + 2 + sage: G.treelength() + 2 + + TESTS:: + + sage: treelength_lowerbound(Graph()) + 0 + """ + if G.is_cycle(): + from sage.functions.other import ceil + return int(ceil(G.order() / 3.0)) + + lowerbound = 0 + girth = G.girth() + if girth is not Infinity: + lowerbound = max(lowerbound, girth / 3.0) + + return int(lowerbound) + + +cdef class TreelengthConnected: + r""" + Compute the treelength of a connected graph (and provide a decomposition). + + This class implements an algorithm for computing the treelength of a + connected graph that virtually explores the graph of all pairs + ``(vertex_cut, connected_component)``, where ``vertex_cut`` is a vertex cut + of the graph of length `\leq k`, and ``connected_component`` is a connected + component of the graph induced by ``G - vertex_cut``. + + We deduce that the pair ``(vertex_cut, connected_component)`` is feasible + with treelength `k` if ``connected_component`` is empty, or if a vertex + ``v`` from ``vertex_cut`` can be replaced with a vertex from + ``connected_component``, such that the pair ``(vertex_cut + v, + connected_component - v)`` is feasible. + + INPUT: + + - ``G`` -- a sage Graph + + - ``k`` -- integer (default: ``None``); indicates the length to be + considered. When `k` is an integer, the method checks that the graph has + treelength `\leq k`. If `k` is ``None`` (default), the method computes the + optimal treelength. + + - ``certificate`` -- boolean (default: ``False``); whether to also compute + the tree-decomposition itself + + OUTPUT: + + ``TreelengthConnected(G)`` returns the treelength of `G`. When `k` is + specified, it returns ``False`` when no tree-decomposition of length + `\leq k` exists or ``True`` otherwise. When ``certificate=True``, the + tree-decomposition is also returned. + + EXAMPLES: + + A clique has treelength 1:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: TreelengthConnected(graphs.CompleteGraph(3)).get_length() + 1 + sage: TC = TreelengthConnected(graphs.CompleteGraph(4), certificate=True) + sage: TC.get_length() + 1 + sage: TC.get_tree_decomposition() + Tree decomposition of Complete graph: Graph on 1 vertex + + A cycle has treelength `\lceil n/3 \rceil`:: + + sage: TreelengthConnected(graphs.CycleGraph(6)).get_length() + 2 + sage: TreelengthConnected(graphs.CycleGraph(7)).get_length() + 3 + sage: TreelengthConnected(graphs.CycleGraph(7), k=3).is_less_than_k() + True + sage: TreelengthConnected(graphs.CycleGraph(7), k=2).is_less_than_k() + False + + TESTS: + + The input graph must be connected:: + + sage: TreelengthConnected(Graph(2)) + Traceback (most recent call last): + ... + ValueError: the graph is not connected + + The parameter `k` must be non-negative:: + + sage: TreelengthConnected(Graph(1), k=-1) + Traceback (most recent call last): + ... + ValueError: k (= -1) must be a nonnegative integer + + Parameter ``certificate`` must be ``True`` to get a tree decomposition:: + + sage: TreelengthConnected(Graph(1), certificate=False).get_tree_decomposition() + Traceback (most recent call last): + ... + ValueError: parameter 'certificate' has not been set to True + + When parameter `k` is specified and ``certificate`` is ``True``, the + computed tree decomposition is any valid tree decomposition with length at + most `k`. However, this tree decomposition exists only if the treelength of + `G` is at most `k` (i.e., `tl(G) \leq k`):: + + sage: G = graphs.Grid2dGraph(2, 3) + sage: TC = TreelengthConnected(G, k=2, certificate=True) + sage: TC.is_less_than_k() + True + sage: TC.get_tree_decomposition() + Tree decomposition of 2D Grid Graph for [2, 3]: Graph on 3 vertices + sage: TC = TreelengthConnected(G, k=1, certificate=True) + sage: TC.is_less_than_k() + False + sage: TC.get_tree_decomposition() + Traceback (most recent call last): + ... + ValueError: no tree decomposition with length <= 1 was found + """ + + def __init__(self, G, k=None, certificate=False): + r""" + Initialize this object and compute the treelength of `G`. + + INPUT: + + - ``G`` -- a sage Graph + + - ``k`` -- integer (default: ``None``); indicates the length to be + considered. When `k` is an integer, the method checks that the graph + has treelength `\leq k`. If `k` is ``None`` (default), the method + computes the optimal treelength. + + - ``certificate`` -- boolean (default: ``False``); whether to compute + the tree-decomposition itself + + TESTS:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G).get_length() + 2 + """ + if k is not None and k < 0: + raise ValueError("k (= {}) must be a nonnegative integer".format(k)) + G._scream_if_not_simple() + if not G.is_connected(): + raise ValueError("the graph is not connected") + + self.certificate = certificate + self.k_is_defined = k is not None + self.k = k if self.k_is_defined else 0 + + if certificate: + from sage.graphs.graph import Graph + self.name = "Tree decomposition of {}".format(G.name()) + + self.n = G.order() + self.distances = NULL # used in the destructor + + # Trivial cases + if (self.n <= 1 or + (self.k_is_defined and self.n <= k)): + if certificate: + if self.n: + self.tree = Graph({Set(G): []}, format="dict_of_lists", name=self.name) + else: + self.tree = Graph(name=self.name) + self.length = 0 if self.n <= 1 else G.diameter(algorithm='DHV') + self.leq_k = True # We know that k is non negative + return + + if self.k_is_defined and not k: + # We have at least 2 vertices and 1 edges, so tl >= 1 + self.leq_k = False + return + + if G.is_clique(): + if certificate: + self.tree = Graph({Set(G): []}, format="dict_of_lists", name=self.name) + self.length = 1 + self.leq_k = True + return + + cdef unsigned int i, j + + # If the vertices are not labeled 0..n-1, we relabel the graph. This + # way, the labeling of the vertices matches the rows and columns of the + # distance matrix + if set(G) == set(range(self.n)): + graph = G + self.perm_inv = dict() + else: + graph, perm = G.relabel(inplace=False, return_map=True) + self.perm_inv = {i: u for u, i in perm.items()} + + # We compute the distance matrix. + self.c_distances = c_distances_all_pairs(graph, vertex_list=list(range(self.n))) + self.distances = sig_calloc(self.n, sizeof(unsigned short *)) + for i in range(self.n): + self.distances[i] = self.c_distances + i * self.n + + # and the diameter of the graph + self.diameter = 0 + for i in range(self.n): + for j in range(i, self.n): + self.diameter = max(self.diameter, self.distances[i][j]) + + if self.k_is_defined and k >= self.diameter: + # All vertices fit in one bag + if certificate: + self.tree = Graph({Set(G): []}, format="dict_of_lists", name=self.name) + self.length = self.diameter + self.leq_k = True + return + + # Forcing k to be defined + if not self.k_is_defined: + for i in range(treelength_lowerbound(graph), self.diameter + 1): + ans = self._treelength(graph, i) + if ans: + self.length = i + return + + # If k is defined + ans = self._treelength(graph, k) + if ans: + self.length = k + self.leq_k = True + else: + self.leq_k = False + + def __dealloc__(self): + r""" + Destroy the object + + TESTS:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G).get_length() + 2 + """ + if self.distances: + sig_free(self.c_distances) + sig_free(self.distances) + + + cdef bint _treelength(self, g, k): + r""" + Check whether the treelength of `g` is at most `k`. + + INPUT: + + - ``g`` -- a sage Graph + + - ``k`` -- integer; indicates the length to be considered + + TESTS:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G, k=2).is_less_than_k() + True + """ + + # This is the recursion described in the method's documentation. All + # computations are cached, and depends on the pair ``cut, + # connected_component`` only. + # + # It returns either a boolean or the corresponding tree-decomposition, + # as a list of edges between vertex cuts (used to build the complete + # tree-decomposition at the end of the _treelength method). + @cached_function + def rec(cut, cc): + cdef int v + cdef frozenset reduced_cut + + if len(cc) == 1: + [v] = cc + # We identify the neighbors of v in cut + reduced_cut = cut.intersection(g.neighbor_iterator(v)) + # We can form a new bag with its closed neighborhood, and this + # bag has diameter at most 2. Furthermore, if k == 1, we know + # that the bag cut has diameter <= 1, and so the new bag has + # diameter 1 + if self.certificate: + if cut == reduced_cut: + return [(cut, cut.union(cc))] + # We need to forget some vertices + return [(cut, reduced_cut), (reduced_cut, reduced_cut.union(cc))] + + return True + + # We explore all possible extensions of the cut + cdef frozenset cutv + cdef frozenset ccv + cdef frozenset cci + cdef frozenset reduced_cuti + cdef list sons + cdef int x + + for v in cc: + + # We know that the cut has diameter <= k. So we check is adding + # v to the cut does not make its diameter > k + if any(self.distances[v][x] > k for x in cut): + continue + # We add v to the cut and remove it from cc + cutv = cut.union([v]) + ccv = cc.difference([v]) + + # The values returned by the recursive calls. + sons = [] + + # Removing v may have disconnected cc. We iterate on its + # connected components + for _cci in g.subgraph(ccv).connected_components(): + cci = frozenset(_cci) + + # The recursive subcalls. We remove on-the-fly the vertices + # from the cut which play no role in separating the + # connected component from the rest of the graph. That is, + # we identify the vertices of cutv with a neighbor in cci + reduced_cuti = frozenset([x for x in cutv + if any(xx in cci for xx in g.neighbor_iterator(x))]) + if not reduced_cuti: + # This should not happen + break + + # and we do a recursive call + son = rec(reduced_cuti, cci) + if not son: + break + + # We get a valid decomposition of cci + if self.certificate: + # We connect cut, cutv, reduced_cci and son + sons.append((cut, cutv)) + if v in reduced_cuti: + sons.append((cutv, reduced_cuti)) + else: + reduced_cutv = reduced_cuti.union([v]) + sons.append((cutv, reduced_cutv)) + sons.append((reduced_cutv, reduced_cuti)) + sons.extend(son) + + # Weird Python syntax which is useful once in a lifetime : if break + # was never called in the loop above, we return "sons". + else: + return sons if self.certificate else True + + return False + + # Main call to rec function, i.e. rec({v}, V-{v}) + cdef list V = list(g) + cdef frozenset v = frozenset([V.pop()]) + TD = rec(v, frozenset(V)) + + if TD is False: + return False + + if not self.certificate: + return True + + # Building the Tree-Decomposition graph. Its vertices are cuts of the + # decomposition, and there is an edge from a cut C1 to a cut C2 if C2 is an + # immediate subcall of C1. If needed, the vertices are relabeled. + if self.perm_inv: + def good_label(x): + return Set([self.perm_inv[i] for i in x]) + else: + def good_label(x): + return Set(x) + + from sage.graphs.graph import Graph + T = Graph([(good_label(x), good_label(y)) for x, y in TD if x != y], + format="list_of_edges") + self.tree = reduced_tree_decomposition(T) + self.tree.name(self.name) + return True + + def get_tree_decomposition(self): + """ + Return the tree-decomposition. + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G, certificate=True).get_tree_decomposition() + Tree decomposition of Cycle graph: Graph on 2 vertices + sage: G.diameter() + 2 + sage: TreelengthConnected(G, k=2, certificate=True).get_tree_decomposition() + Tree decomposition of Cycle graph: Graph on 1 vertex + sage: TreelengthConnected(G, k=1, certificate=True).get_tree_decomposition() + Traceback (most recent call last): + ... + ValueError: no tree decomposition with length <= 1 was found + + TESTS:: + + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G, certificate=False).get_tree_decomposition() + Traceback (most recent call last): + ... + ValueError: parameter 'certificate' has not been set to True + """ + if self.certificate: + if self.k_is_defined and not self.leq_k: + raise ValueError("no tree decomposition with length <= {} was found".format(self.k)) + return self.tree + else: + raise ValueError("parameter 'certificate' has not been set to True") + + def get_length(self): + """ + Return the length of the tree decomposition. + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G).get_length() + 2 + sage: TreelengthConnected(G, k=2).get_length() + 2 + sage: TreelengthConnected(G, k=1).get_length() + Traceback (most recent call last): + ... + ValueError: no tree decomposition with length <= 1 was found + + TESTS:: + + sage: TreelengthConnected(Graph()).get_length() + 0 + """ + if self.k_is_defined and not self.leq_k: + raise ValueError("no tree decomposition with length <= {} was found".format(self.k)) + return self.length + + def is_less_than_k(self): + """ + Return whether a tree decomposition with length at most `k` was found. + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: G = graphs.CycleGraph(4) + sage: TreelengthConnected(G, k=1).is_less_than_k() + False + sage: TreelengthConnected(G, k=2).is_less_than_k() + True + sage: TreelengthConnected(G).is_less_than_k() + Traceback (most recent call last): + ... + ValueError: parameter 'k' has not been specified + + TESTS:: + + sage: TreelengthConnected(Graph(), k=1).is_less_than_k() + True + """ + if self.k_is_defined: + return self.leq_k + raise ValueError("parameter 'k' has not been specified") + + +def treelength(G, k=None, certificate=False): + r""" + Compute the treelength of `G` (and provide a decomposition). + + The *length* of a tree decomposition, as proposed in [DG2006]_, is the + maximum *diameter* in `G` of its bags, where the diameter of a bag `X_i` is + the largest distance in `G` between the vertices in `X_i` (i.e., `\max_{u, v + \in X_i} dist_G(u, v)`). The *treelength* `tl(G)` of a graph `G` is the + minimum length among all possible tree decompositions of `G`. + See the documentation of the + :mod:`~sage.graphs.graph_decompositions.tree_decomposition` module for more + details. + + INPUT: + + - ``G`` -- a sage Graph + + - ``k`` -- integer (default: ``None``); indicates the length to be + considered. When `k` is an integer, the method checks that the graph has + treelength `\leq k`. If `k` is ``None`` (default), the method computes the + optimal treelength. + + - ``certificate`` -- boolean (default: ``False``); whether to also return + the tree-decomposition itself + + OUTPUT: + + ``G.treelength()`` returns the treelength of `G`. When `k` is specified, it + returns ``False`` when no tree-decomposition of length `\leq k` exists or + ``True`` otherwise. When ``certificate=True``, the tree-decomposition is + also returned. + + ALGORITHM: + + This method virtually explores the graph of all pairs ``(vertex_cut, + connected_component)``, where ``vertex_cut`` is a vertex cut of the graph of + length `\leq k`, and ``connected_component`` is a connected component of the + graph induced by ``G - vertex_cut``. + + We deduce that the pair ``(vertex_cut, connected_component)`` is feasible + with treelength `k` if ``connected_component`` is empty, or if a vertex + ``v`` from ``vertex_cut`` can be replaced with a vertex from + ``connected_component``, such that the pair ``(vertex_cut + v, + connected_component - v)`` is feasible. + + In practice, this method decomposes the graph by its clique minimal + separators into atoms, computes the treelength of each of atom and returns + the maximum value over all the atoms. Indeed, we have that `tl(G) = \max_{X + \in A} tl(G[X])` where `A` is the set of atoms of the decomposition by + clique separators of `G`. When ``certificate == True``, the + tree-decompositions of the atoms are connected to each others by adding + edges with respect to the clique separators. + + .. SEEALSO:: + + - :meth:`treewidth` computes the treewidth of a graph. + - :meth:`~sage.graphs.graph_decompositions.vertex_separation.path_decomposition` + computes the pathwidth of a graph. + - module :mod:`~sage.graphs.graph_decompositions.vertex_separation`. + - :meth:`~sage.graphs.graph_decompositions.clique_separators.atoms_and_clique_separators` + + EXAMPLES: + + The PetersenGraph has treelength 2:: + + sage: G = graphs.PetersenGraph() + sage: G.treelength() + 2 + + Disconnected graphs have infinite treelength:: + + sage: G = Graph(2) + sage: G.treelength() + +Infinity + sage: G.treelength(k=+Infinity) + True + sage: G.treelength(k=2) + False + sage: G.treelength(certificate=True) + Traceback (most recent call last): + ... + ValueError: the tree decomposition of a disconnected graph is not defined + + Chordal graphs have treelength 1:: + + sage: G = graphs.RandomChordalGraph(30) + sage: while not G.is_connected(): + ....: G = graphs.RandomChordalGraph(30) + sage: G.treelength() + 1 + + Cycles have treelength `\lceil n/3 \rceil`:: + + sage: [graphs.CycleGraph(n).treelength() for n in range(3, 11)] + [1, 2, 2, 2, 3, 3, 3, 4] + + TESTS: + + Check that the decomposition by clique separators is valid:: + + sage: from sage.graphs.graph_decompositions.tree_decomposition import TreelengthConnected + sage: from sage.graphs.graph_decompositions.tree_decomposition import is_valid_tree_decomposition + sage: G = graphs.StarGraph(3) + sage: G.subdivide_edges(G.edges(sort=False), 2) + sage: G = G.cartesian_product(graphs.CycleGraph(3)) + sage: tl, T = G.treelength(certificate=True) + sage: tl == TreelengthConnected(G).get_length() + True + sage: is_valid_tree_decomposition(G, T) + True + + Corner cases:: + + sage: Graph().treelength() + 0 + sage: Graph().treelength(certificate=True) + (0, Tree decomposition: Graph on 0 vertices) + sage: Graph(1).treelength() + 0 + sage: Graph(1).treelength(k=0) + True + sage: Graph(1).treelength(certificate=True) + (0, Tree decomposition: Graph on 1 vertex) + sage: Graph(1).treelength(k=0, certificate=True) + (True, Tree decomposition: Graph on 1 vertex) + sage: G = graphs.PathGraph(2) + sage: G.treelength() + 1 + sage: G.treelength(k=0) + False + sage: G.treelength(certificate=True) + (1, Tree decomposition of Path graph: Graph on 1 vertex) + sage: G.treelength(certificate=True, k=0) + (False, None) + sage: G.treelength(certificate=True, k=1) + (True, Tree decomposition of Path graph: Graph on 1 vertex) + sage: G.treelength(certificate=True, k=0) + (False, None) + sage: G.treelength(k=-1) + Traceback (most recent call last): + ... + ValueError: k(=-1) must be a nonnegative integer + """ + if G.is_directed(): + raise ValueError("this method is defined for undirected graphs only") + if k is not None and k < 0: + raise ValueError("k(={}) must be a nonnegative integer".format(k)) + + cdef str name = "Tree decomposition" + if G.name(): + name += " of {}".format(G.name()) + + # Corner cases + from sage.graphs.graph import Graph + if G.order() <= 1: + answer = 0 if k is None else True + if certificate: + if G: + answer = answer, Graph({Set(G): []}, format="dict_of_lists", name=name) + else: + answer = answer, Graph(name=name) + return answer + if not G.is_connected(): + if certificate: + raise ValueError("the tree decomposition of a disconnected graph is not defined") + elif k is None: + return +Infinity + else: + return k is Infinity + if k == 0: + return (False, None) if certificate else False + if not certificate and G.is_chordal(): + return 1 if k is None else True + + # We decompose the graph by clique minimal separators into atoms and solve + # the problem on each of them + atoms, cliques = G.atoms_and_clique_separators() + + if not cliques: + # We have a single atom + TC = TreelengthConnected(G, k=k, certificate=certificate) + if certificate: + if k is None: + return TC.get_length(), TC.get_tree_decomposition() + elif TC.is_less_than_k(): + return True, TC.get_tree_decomposition() + else: + return False, None + if k is None: + return TC.get_length() + return TC.is_less_than_k() + + # As some atoms might be isomorphic, we use a dictionary keyed by immutable + # copies of canonical graphs to store intermediate results. + cdef dict data = dict() + cdef list result = [] + cdef int tl = 1 # The graph is connected and of order at least 2 + cdef dict certif_inv + cdef dict perm + + for atom in atoms: + + ga = G.subgraph(atom) + if ga.is_clique(): + if certificate: + result.append(Graph({Set(atom): []}, format="dict_of_lists")) + continue + + gc, certif = ga.canonical_label(certificate=True) + gci = gc.copy(immutable=True) + + if gci in data: + # We already solved the problem for an isomorphic atom. + if certificate: + # We deduce the solution for this atom + certif_inv = {i: u for u, i in certif.items()} + perm = {u: Set([certif_inv[i] for i in u]) for u in data[gci]} + result.append(data[gci].relabel(perm=perm, inplace=False, immutable=False)) + continue + + # We solve the problem for this atom and store the result + TC = TreelengthConnected(gci, k=k, certificate=certificate) + if certificate: + T = TC.get_tree_decomposition() + data[gci] = T + certif_inv = {i: u for u, i in certif.items()} + perm = {u: Set([certif_inv[i] for i in u]) for u in T} + result.append(T.relabel(perm=perm, inplace=False, immutable=False)) + if k is None: + tl = max(tl, TC.get_length()) + elif not TC.is_less_than_k(): + return False if not certificate else (False, None) + + if not certificate: + if k is None: + return tl + return True + + # We now build the tree decomposition of the graph by connecting the tree + # decompositions of its atoms. + T = _from_tree_decompositions_of_atoms_to_tree_decomposition(result, cliques) + + # The Tree-Decomposition may contain a lot of useless nodes. + # We merge all edges between two sets S,S' where S is a subset of S' + T = reduced_tree_decomposition(T) + T.name(name) + if k is None: + return tl, T + return True, T diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 558eb4f22c8..23ffeb016f0 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -126,10 +126,10 @@ # **************************************************************************** from collections import defaultdict -from math import sqrt, cos, sin, acos, atan, pi +from math import sqrt, cos, sin, atan, pi from sage.structure.sage_object import SageObject from sage.plot.all import ( - Graphics, scatter_plot, bezier_path, line, arrow, text, arc, circle) + Graphics, scatter_plot, bezier_path, line, arrow, text, circle) layout_options = { 'layout': @@ -175,7 +175,11 @@ 'pos': 'The position dictionary of vertices.', 'vertex_labels': - 'Whether or not to draw vertex labels.', + 'Vertex labels to draw. This can be ``True``/``False`` to indicate ' + 'whether to print the vertex string representation of not, ' + 'a dictionary keyed by vertices and associating to each vertex ' + 'a label string, or a function taking as input a vertex and returning ' + 'a label string.', 'vertex_color': 'Default color for vertices not listed ' 'in vertex_colors dictionary.', @@ -429,6 +433,54 @@ def set_vertices(self, **vertex_options): GP.set_vertices(talk=True) GP.set_vertices(vertex_color='green', vertex_shape='^') sphinx_plot(GP) + + Vertex labels are flexible:: + + sage: g = graphs.PathGraph(4) + sage: g.plot(vertex_labels=False) + Graphics object consisting of 4 graphics primitives + + .. PLOT:: + + g = graphs.PathGraph(4) + P = g.graphplot(vertex_labels=False) + sphinx_plot(P) + + :: + + sage: g = graphs.PathGraph(4) + sage: g.plot(vertex_labels=True) + Graphics object consisting of 8 graphics primitives + + .. PLOT:: + + g = graphs.PathGraph(4) + P = g.graphplot(vertex_labels=True) + sphinx_plot(P) + + :: + + sage: g = graphs.PathGraph(4) + sage: g.plot(vertex_labels=dict(zip(g, ['+', '-', '/', '*']))) + Graphics object consisting of 8 graphics primitives + + .. PLOT:: + + g = graphs.PathGraph(4) + P = g.graphplot(vertex_labels=dict(zip(g, ['+', '-', '/', '*']))) + sphinx_plot(P) + + :: + + sage: g = graphs.PathGraph(4) + sage: g.plot(vertex_labels=lambda x: str(x % 2)) + Graphics object consisting of 8 graphics primitives + + .. PLOT:: + + g = graphs.PathGraph(4) + P = g.graphplot(vertex_labels=lambda x: str(x % 2)) + sphinx_plot(P) """ # Handle base vertex options voptions = {} @@ -509,12 +561,18 @@ def set_vertices(self, **vertex_options): self._plot_components['vertices'] = scatter_plot( pos, facecolor=colors, clip=False, **voptions) - if self._options['vertex_labels']: - self._plot_components['vertex_labels'] = [] + vlabels = self._options['vertex_labels'] + if vlabels: + if vlabels is True: + vfun = str + elif isinstance(vlabels, dict): + def vfun(x): + return vlabels.get(x, "") + else: + vfun = vlabels # TODO: allow text options - for v in self._nodelist: - self._plot_components['vertex_labels'].append( - text(str(v), self._pos[v], rgbcolor=(0, 0, 0), zorder=8)) + self._plot_components['vertex_labels'] = [text(vfun(v), self._pos[v], color='black', zorder=8) + for v in self._nodelist] def set_edges(self, **edge_options): """ diff --git a/src/sage/graphs/matchpoly.pyx b/src/sage/graphs/matchpoly.pyx index 434e6bbf8bd..3226350f7be 100644 --- a/src/sage/graphs/matchpoly.pyx +++ b/src/sage/graphs/matchpoly.pyx @@ -41,7 +41,7 @@ from cysignals.signals cimport sig_on, sig_off from sage.rings.polynomial.polynomial_ring import polygen from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.libs.flint.fmpz cimport * from sage.libs.flint.fmpz_poly cimport * diff --git a/src/sage/groups/abelian_gps/abelian_aut.py b/src/sage/groups/abelian_gps/abelian_aut.py index a4ad9f41524..18afe029eda 100644 --- a/src/sage/groups/abelian_gps/abelian_aut.py +++ b/src/sage/groups/abelian_gps/abelian_aut.py @@ -82,7 +82,7 @@ from sage.groups.libgap_mixin import GroupMixinLibGAP from sage.libs.gap.libgap import libgap from sage.matrix.matrix_space import MatrixSpace -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.unique_representation import CachedRepresentation diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index 5ae1a14a997..00cf0f3c9d7 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -210,7 +210,7 @@ from sage.arith.all import divisors, gcd, lcm from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.mrange import mrange, cartesian_product_iterator from sage.groups.group import AbelianGroup as AbelianGroupBase from sage.categories.groups import Groups diff --git a/src/sage/groups/abelian_gps/abelian_group_morphism.py b/src/sage/groups/abelian_gps/abelian_group_morphism.py index 623cacc4554..518946ea839 100644 --- a/src/sage/groups/abelian_gps/abelian_group_morphism.py +++ b/src/sage/groups/abelian_gps/abelian_group_morphism.py @@ -22,7 +22,7 @@ from sage.interfaces.gap import gap from sage.categories.morphism import Morphism -from sage.misc.all import prod +from sage.misc.misc_c import prod def is_AbelianGroupMorphism(f): diff --git a/src/sage/groups/abelian_gps/dual_abelian_group_element.py b/src/sage/groups/abelian_gps/dual_abelian_group_element.py index 1c4120c7b53..a4f2879fb3d 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group_element.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group_element.py @@ -57,7 +57,7 @@ import operator from sage.arith.all import LCM -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.groups.abelian_gps.element_base import AbelianGroupElementBase from functools import reduce diff --git a/src/sage/groups/abelian_gps/values.py b/src/sage/groups/abelian_gps/values.py index e411ecbf407..27e91cf30ed 100644 --- a/src/sage/groups/abelian_gps/values.py +++ b/src/sage/groups/abelian_gps/values.py @@ -70,7 +70,7 @@ # http://www.gnu.org/licenses/ ########################################################################## -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.integer import Integer from sage.categories.morphism import Morphism from sage.groups.abelian_gps.abelian_group import AbelianGroup_class, _normalize diff --git a/src/sage/groups/additive_abelian/additive_abelian_group.py b/src/sage/groups/additive_abelian/additive_abelian_group.py index 2c76b75e0cd..d94255e2d3f 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_group.py +++ b/src/sage/groups/additive_abelian/additive_abelian_group.py @@ -9,7 +9,7 @@ from sage.groups.old import AbelianGroup from sage.modules.fg_pid.fgp_module import FGP_Module_class from sage.modules.fg_pid.fgp_element import FGP_Element -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ def AdditiveAbelianGroup(invs, remember_generators = True): r""" diff --git a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py index b27c8a8f1a0..566a07c4d33 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py +++ b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py @@ -50,7 +50,7 @@ """ from . import additive_abelian_group as addgp -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.categories.morphism import Morphism from sage.structure.element import parent from sage.modules.free_module_element import vector diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index 9b158d22720..ab02e07f097 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -422,7 +422,7 @@ def __call__(self, v): from sage.rings.polynomial.multi_polynomial import is_MPolynomial if is_MPolynomial(v) and parent.degree() == v.parent().ngens(): ring = v.parent() - from sage.modules.all import vector + from sage.modules.free_module_element import vector image_coords = self._A * vector(ring, ring.gens()) + self._b return v(*image_coords) diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 0011358343e..113bf59b2c3 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -1092,7 +1092,7 @@ def _enhanced_states(self): last_crossing_in_row[abs(cr)] = i # tie up the ends of the list for k, i in enumerate(first_crossing_in_row): - if i != None: + if i is not None: j = last_crossing_in_row[k] if abs(crossings[i]["cr"]) == k: crossings[i]["prev_below"] = j @@ -1697,6 +1697,45 @@ def sliding_circuits(self): B = self.parent() return [[B._element_from_libbraiding(i) for i in s] for s in slc] + def mirror_image(self): + r""" + Return the image of ``self`` under the mirror involution (see + :meth:`BraidGroup_class.mirror_involution`). The link closure of + it is mirrored to the closure of ``self`` (see the example below + of a positive amphicheiral knot). + + EXAMPLES:: + + sage: B5 = BraidGroup(5) + sage: b = B5((-1, 2, -3, -1, -3, 4, 2, -3, 2, 4, 2, -3)) # closure K12a_427 + sage: bm = b.mirror_image(); bm + s0*s1^-1*s2*s0*s2*s3^-1*s1^-1*s2*s1^-1*s3^-1*s1^-1*s2 + sage: bm.is_conjugated(b) + True + sage: bm.is_conjugated(~b) + False + """ + return self.parent().mirror_involution()(self) + + def reverse(self): + r""" + Return the reverse of ``self`` obtained by reversing the order of the + generators in its word. This defines an anti-involution on the braid + group. The link closure of it has the reversed orientation (see the + example below of a non reversible knot). + + EXAMPLES:: + + sage: b = BraidGroup(3)((1, 1, -2, 1, -2, 1, -2, -2)) # closure K8_17 + sage: br = b.reverse(); br + s1^-1*(s1^-1*s0)^3*s0 + sage: br.is_conjugated(b) + False + """ + t = [i for i in self.Tietze()] + t.reverse() + return self.parent()(tuple(t)) + class BraidGroup_class(FiniteTypeArtinGroup): """ @@ -2475,6 +2514,31 @@ def _element_from_libbraiding(self, nf): from sage.misc.misc_c import prod return self.delta() ** nf[0][0] * prod(self(i) for i in nf[1:]) + def mirror_involution(self): + r""" + Return the mirror involution of ``self``. + + This automorphism maps a braid to another one by replacing each generator + in its word by the inverse. In general this is different from the inverse + of the braid since the order of the generators in the word is not reversed. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: mirr = B.mirror_involution() + sage: b = B((1,-2,-1,3,2,1)) + sage: bm = mirr(b); bm + s0^-1*s1*s0*s2^-1*s1^-1*s0^-1 + sage: bm == ~b + False + sage: bm.is_conjugated(b) + False + sage: bm.is_conjugated(~b) + True + """ + gens_mirr = [~g for g in self.gens()] + return self.hom(gens_mirr, check=False) + def BraidGroup(n=None, names='s'): """ diff --git a/src/sage/groups/fqf_orthogonal.py b/src/sage/groups/fqf_orthogonal.py index ae9fc2fae2d..184efa9be0b 100644 --- a/src/sage/groups/fqf_orthogonal.py +++ b/src/sage/groups/fqf_orthogonal.py @@ -51,8 +51,8 @@ from sage.libs.gap.libgap import libgap from sage.groups.abelian_gps.abelian_aut import AbelianGroupAutomorphismGroup_subgroup, AbelianGroupAutomorphism, AbelianGroupAutomorphismGroup_gap from sage.modules.torsion_quadratic_module import TorsionQuadraticModule -from sage.rings.all import ZZ -from sage.matrix.all import matrix +from sage.rings.integer_ring import ZZ +from sage.matrix.constructor import matrix from sage.categories.action import Action diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 7cec7db1333..af6221de6b4 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -111,7 +111,7 @@ from copy import copy -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.rings.integer_ring as integer_ring import sage.rings.integer from sage.arith.srange import xsrange diff --git a/src/sage/groups/group.pyx b/src/sage/groups/group.pyx index d54fdc7b5f2..9fdc2b87db2 100644 --- a/src/sage/groups/group.pyx +++ b/src/sage/groups/group.pyx @@ -219,7 +219,7 @@ cdef class Group(Parent): sage: G.an_element() f0*f1*f2*f3 """ - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod(self.gens()) def quotient(self, H, **kwds): diff --git a/src/sage/groups/libgap_morphism.py b/src/sage/groups/libgap_morphism.py index ed1530d09e9..86a16984e0c 100644 --- a/src/sage/groups/libgap_morphism.py +++ b/src/sage/groups/libgap_morphism.py @@ -578,7 +578,7 @@ def section(self): from sage.categories.homset import Hom from sage.categories.sets_cat import Sets H = Hom(self.codomain(), self.domain(), category=Sets()) - return H(lambda x: self.lift(x)) + return H(self.lift) class GroupHomset_libgap(HomsetWithBase): diff --git a/src/sage/groups/libgap_wrapper.pyx b/src/sage/groups/libgap_wrapper.pyx index d06bebe881b..451cb5c65c2 100644 --- a/src/sage/groups/libgap_wrapper.pyx +++ b/src/sage/groups/libgap_wrapper.pyx @@ -430,7 +430,7 @@ class ParentLibGAP(SageObject): sage: G._an_element_() a*b """ - from sage.misc.all import prod + from sage.misc.misc_c import prod gens = self.gens() if gens: return prod(gens) diff --git a/src/sage/groups/matrix_gps/binary_dihedral.py b/src/sage/groups/matrix_gps/binary_dihedral.py index 44b2d3ef729..0edae3511c2 100644 --- a/src/sage/groups/matrix_gps/binary_dihedral.py +++ b/src/sage/groups/matrix_gps/binary_dihedral.py @@ -21,7 +21,7 @@ from sage.rings.number_field.number_field import CyclotomicField from sage.matrix.matrix_space import MatrixSpace from sage.categories.groups import Groups -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class BinaryDihedralGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gap): diff --git a/src/sage/groups/matrix_gps/coxeter_group.py b/src/sage/groups/matrix_gps/coxeter_group.py index ec8db50992e..3a2781d8c24 100644 --- a/src/sage/groups/matrix_gps/coxeter_group.py +++ b/src/sage/groups/matrix_gps/coxeter_group.py @@ -27,7 +27,7 @@ from sage.matrix.args import SparseEntry from sage.matrix.matrix_space import MatrixSpace -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField from sage.rings.number_field.number_field import QuadraticField, is_QuadraticField diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index a69e5bfd325..cef211ea07c 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -62,11 +62,11 @@ # https://www.gnu.org/licenses/ ############################################################################## -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.all import QQbar from sage.structure.element import is_Matrix from sage.matrix.matrix_space import MatrixSpace, is_MatrixSpace -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.structure.sequence import Sequence from sage.misc.cachefunc import cached_method from sage.modules.free_module_element import vector diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index 1bf2b88e6d5..d15e2a6802b 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -84,7 +84,7 @@ from sage.groups.libgap_wrapper cimport ElementLibGAP from sage.structure.element import is_Matrix from sage.structure.factorization import Factorization from sage.misc.cachefunc import cached_method -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ cpdef is_MatrixGroupElement(x): diff --git a/src/sage/groups/matrix_gps/heisenberg.py b/src/sage/groups/matrix_gps/heisenberg.py index 4fefcd47ebb..bec87b2cc1a 100644 --- a/src/sage/groups/matrix_gps/heisenberg.py +++ b/src/sage/groups/matrix_gps/heisenberg.py @@ -22,7 +22,7 @@ from sage.matrix.matrix_space import MatrixSpace from sage.categories.groups import Groups from sage.categories.rings import Rings -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from copy import copy class HeisenbergGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gap): diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index 19536eace9a..e82abf76246 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -364,7 +364,7 @@ def sign_representation(self, base_ring=None, side="twosided"): 2*B['v'] """ if base_ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ base_ring = ZZ from sage.modules.with_basis.representation import SignRepresentationMatrixGroup return SignRepresentationMatrixGroup(self, base_ring) diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index 38f7de9b02c..39bb43c710a 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -97,7 +97,7 @@ def normalize_args_vectorspace(*args, **kwds): sage: normalize_args_vectorspace(2, QQ) (2, Rational Field) """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if len(args) == 1: V = args[0] try: diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 4896cd64b81..f049e7b21a1 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -84,7 +84,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_base import is_FiniteField from sage.misc.latex import latex from sage.misc.cachefunc import cached_method diff --git a/src/sage/groups/perm_gps/cubegroup.py b/src/sage/groups/perm_gps/cubegroup.py index 1e32c439688..dfdd6d52e74 100644 --- a/src/sage/groups/perm_gps/cubegroup.py +++ b/src/sage/groups/perm_gps/cubegroup.py @@ -98,7 +98,7 @@ from sage.structure.sage_object import SageObject from sage.structure.richcmp import richcmp, richcmp_method -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.interfaces.all import gap from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.plot.polygon import polygon diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 54dd562df09..11b640c7c45 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -4727,7 +4727,7 @@ def sign_representation(self, base_ring=None, side="twosided"): as a permutation group over Integer Ring """ if base_ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ base_ring = ZZ from sage.modules.with_basis.representation import SignRepresentationPermgroup return SignRepresentationPermgroup(self, base_ring) diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 513c7ade76d..f1c8c715889 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -1934,7 +1934,9 @@ def __init__(self): Category of facade infinite enumerated sets sage: TestSuite(TransitiveGroups()).run() """ - DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), lambda i: TransitiveGroups(i)) ) + DisjointUnionEnumeratedSets.__init__(self, + Family(NonNegativeIntegers(), + TransitiveGroups)) # We override the __call__ as the elements are not instances of Element __call__ = DisjointUnionEnumeratedSets._element_constructor_facade @@ -2338,7 +2340,9 @@ def __init__(self): sage: S.category() Category of facade infinite enumerated sets """ - DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), lambda i: PrimitiveGroups(i)) ) + DisjointUnionEnumeratedSets.__init__(self, + Family(NonNegativeIntegers(), + PrimitiveGroups)) def _repr_(self): """ diff --git a/src/sage/homology/koszul_complex.py b/src/sage/homology/koszul_complex.py index 83cbe9dd243..c83605db2f5 100644 --- a/src/sage/homology/koszul_complex.py +++ b/src/sage/homology/koszul_complex.py @@ -16,7 +16,7 @@ from sage.structure.parent import Parent from sage.combinat.combination import rank from sage.arith.all import binomial -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix from sage.homology.chain_complex import ChainComplex_class diff --git a/src/sage/interacts/library_cython.pyx b/src/sage/interacts/library_cython.pyx index 6e23ef27d42..59fbc931e6b 100644 --- a/src/sage/interacts/library_cython.pyx +++ b/src/sage/interacts/library_cython.pyx @@ -16,7 +16,7 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod cpdef julia(ff_j, z, int iterations): diff --git a/src/sage/interfaces/axiom.py b/src/sage/interfaces/axiom.py index 22ed05c8606..50991843902 100644 --- a/src/sage/interfaces/axiom.py +++ b/src/sage/interfaces/axiom.py @@ -841,10 +841,10 @@ def _sage_(self): x,e,b = self.unparsed_input_form().lstrip('float(').rstrip(')').split(',') return R(ZZ(x)*ZZ(b)**ZZ(e)) elif type == "DoubleFloat": - from sage.rings.all import RDF + from sage.rings.real_double import RDF return RDF(repr(self)) elif type in ["PositiveInteger", "Integer"]: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ(repr(self)) elif type.startswith('Polynomial'): from sage.rings.all import PolynomialRing @@ -886,10 +886,10 @@ def _sage_domain(self): P = self._check_valid() name = str(self) if name == 'Integer': - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ elif name == 'DoubleFloat': - from sage.rings.all import RDF + from sage.rings.real_double import RDF return RDF elif name.startswith('Fraction '): return P(name.lstrip('Fraction '))._sage_domain().fraction_field() diff --git a/src/sage/interfaces/chomp.py b/src/sage/interfaces/chomp.py index 00f4b3f93b3..4d5f1ba4570 100644 --- a/src/sage/interfaces/chomp.py +++ b/src/sage/interfaces/chomp.py @@ -833,8 +833,8 @@ def process_generators_chain(gen_string, dim, base_ring=None): sage: process_generators_chain(s, 1, base_ring=GF(2)) [(1, 1), (0, 0, 1)] """ - from sage.modules.all import vector - from sage.rings.all import ZZ + from sage.modules.free_module_element import vector + from sage.rings.integer_ring import ZZ if base_ring is None: base_ring = ZZ # each dim in gens starts with a string like diff --git a/src/sage/interfaces/four_ti_2.py b/src/sage/interfaces/four_ti_2.py index 067535f2d40..dcf240a74d0 100644 --- a/src/sage/interfaces/four_ti_2.py +++ b/src/sage/interfaces/four_ti_2.py @@ -36,6 +36,8 @@ #***************************************************************************** from sage.rings.integer_ring import ZZ +from sage.features.four_ti_2 import FourTi2Executable + import os @@ -271,7 +273,7 @@ def _process_input(self, kwds): # Commands # ############ - def call(self, command, project, verbose=True): + def call(self, command, project, verbose=True, *, options=()): r""" Run the 4ti2 program ``command`` on the project named ``project`` in the directory ``directory()``. @@ -281,6 +283,7 @@ def call(self, command, project, verbose=True): - command -- The 4ti2 program to run. - project -- The file name of the project to run on. - verbose -- Display the output of 4ti2 if ``True``. + - options -- A list of strings to pass to the program. EXAMPLES:: @@ -292,8 +295,11 @@ def call(self, command, project, verbose=True): [-5 3 0] """ import subprocess - - cmd = '%s %s' % (command, project) + feature = FourTi2Executable(command) + feature.require() + executable = feature.executable + options = " ".join(options) + cmd = f'{executable} {options} {project}' if verbose is False: cmd += " > /dev/null 2> /dev/null" subprocess.call(cmd, shell=True, cwd=self.directory()) @@ -326,7 +332,7 @@ def zsolve(self, mat=None, rel=None, rhs=None, sign=None, lat=None, project=None """ project = self._process_input(locals()) - self.call('zsolve -q', project) + self.call('zsolve', project, options=['-q']) return [self.read_matrix(project+'.'+ext) for ext in ['zinhom', 'zhom', 'zfree']] @@ -343,7 +349,7 @@ def qsolve(self, mat=None, rel=None, sign=None, project=None): [[], [ 1 -2 1]] """ project = self._process_input(locals()) - self.call('qsolve -q -parbitrary', project) + self.call('qsolve', project, options=['-q', '-parbitrary']) return [self.read_matrix(project+'.'+ext) for ext in ['qhom', 'qfree']] @@ -362,7 +368,7 @@ def rays(self, mat=None, project=None): [2 0 1 0 1 2 1 2 0] """ project = self._process_input(locals()) - self.call('rays -q -parbitrary', project) + self.call('rays', project, options=['-q', '-parbitrary']) return self.read_matrix(project+'.ray') def hilbert(self, mat=None, lat=None, project=None): @@ -385,7 +391,7 @@ def hilbert(self, mat=None, lat=None, project=None): [1 1 1] """ project = self._process_input(locals()) - self.call('hilbert -q', project) + self.call('hilbert', project, options=['-q']) return self.read_matrix(project+'.hil') def graver(self, mat=None, lat=None, project=None): @@ -409,7 +415,7 @@ def graver(self, mat=None, lat=None, project=None): [ 2 1 0] """ project = self._process_input(locals()) - self.call('graver -q', project) + self.call('graver', project, options=['-q']) return self.read_matrix(project+'.gra') def ppi(self, n): @@ -428,7 +434,7 @@ def ppi(self, n): [ 1 -2 1] """ - self.call('ppi 2> /dev/null', n) + self.call('ppi', f'{n} 2> /dev/null') return self.read_matrix('ppi%s.gra'%n) def circuits(self, mat=None, project=None): @@ -445,7 +451,7 @@ def circuits(self, mat=None, project=None): [ 3 0 -1] """ project = self._process_input(locals()) - self.call('circuits -q -parbitrary', project) + self.call('circuits', project, options=['-q', '-parbitrary']) return self.read_matrix(project+'.cir') def minimize(self, mat=None, lat=None): @@ -482,7 +488,7 @@ def groebner(self, mat=None, lat=None, project=None): [ 2 1 0] """ project = self._process_input(locals()) - self.call('groebner -q -parbitrary', project) + self.call('groebner', project, options=['-q', '-parbitrary']) return self.read_matrix(project+'.gro') def _magic3x3(self): diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index 9d1b817d2ba..98e452513cf 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -205,7 +205,6 @@ from sage.docs.instancedoc import instancedoc from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.infinity import infinity from sage.misc.lazy_import import lazy_import lazy_import('sage.symbolic.expression', ['symbol_table', 'register_symbol']) lazy_import('sage.calculus.var', ['var', 'function']) @@ -213,10 +212,7 @@ FRICAS_CONSTANTS = {'%i': I, '%e': e, - '%pi': pi, - 'infinity': infinity, - 'plusInfinity': infinity, - 'minusInfinity': -infinity} + '%pi': pi} FRICAS_SINGLE_LINE_START = 3 # where output starts when it fits next to the line number FRICAS_MULTI_LINE_START = 2 # and when it doesn't @@ -591,7 +587,11 @@ def _register_symbols(): from sage.functions.other import abs from sage.functions.gamma import gamma from sage.misc.functional import symbolic_sum, symbolic_prod - register_symbol(pi, {'fricas': 'pi'}) # pi is also a function in fricas + from sage.rings.infinity import infinity + register_symbol(pi, {'fricas': 'pi'}) # %pi::INFORM is %pi, but (pi) also exists + register_symbol(lambda: infinity, {'fricas': 'infinity'}) # %infinity::INFORM is (infinity) + register_symbol(lambda: infinity, {'fricas': 'plusInfinity'}) # %plusInfinity::INFORM is (minusInfinity) + register_symbol(lambda: -infinity, {'fricas': 'minusInfinity'}) # %minusInfinity::INFORM is (minusInfinity) register_symbol(cos, {'fricas': 'cos'}) register_symbol(sin, {'fricas': 'sin'}) register_symbol(tan, {'fricas': 'tan'}) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 767d7525bd5..7fc8ce6c537 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -33,7 +33,7 @@ from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.homology.chain_complex import ChainComplex from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 64dd877ab05..1d942d497d7 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -1540,10 +1540,10 @@ def _sage_(self): cls_cls_str = str(self.cls().cls()) if repr_str == "ZZ": - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ elif repr_str == "QQ": - from sage.rings.all import QQ + from sage.rings.rational_field import QQ return QQ if cls_cls_str == "Type": @@ -1659,10 +1659,10 @@ def _sage_(self): else: #Handle the integers and rationals separately if cls_str == "ZZ": - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ(repr_str) elif cls_str == "QQ": - from sage.rings.all import QQ + from sage.rings.rational_field import QQ repr_str = self.external_string() if "/" not in repr_str: repr_str = repr_str + "/1" @@ -1713,7 +1713,7 @@ def _matrix_(self, R): sage: matrix(ZZ, m.transpose()).dimensions() # optional - macaulay2 (0, 2) """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix m = matrix(R, self.entries()._sage_()) if not m.nrows(): return matrix(R, 0, self.numcols()._sage_()) diff --git a/src/sage/interfaces/maple.py b/src/sage/interfaces/maple.py index 4ddb8424cf4..ff201d48fec 100644 --- a/src/sage/interfaces/maple.py +++ b/src/sage/interfaces/maple.py @@ -1222,7 +1222,7 @@ def _sage_(self): elif maple_type == '`=`': # (1, 1) = 2 return (self.op(1)._sage_() == self.op(2)._sage()) try: - from sage.symbolic.all import SR + from sage.symbolic.ring import SR return SR(result) except Exception: raise NotImplementedError("Unable to parse Maple output: %s" % result) diff --git a/src/sage/interfaces/matlab.py b/src/sage/interfaces/matlab.py index 5f72363b520..986dc665b39 100644 --- a/src/sage/interfaces/matlab.py +++ b/src/sage/interfaces/matlab.py @@ -343,7 +343,7 @@ def _matrix_(self, R): 50 x 50 dense matrix over Real Field with 53 bits of precision """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix matlab = self.parent() entries = matlab.strip_answer(matlab.eval("mat2str({0})".format(self.name()))) entries = entries.strip()[1:-1].replace(';', ' ') diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index d52685990aa..12005b269e8 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -113,45 +113,40 @@ ecl_eval("(remprop 'mfactorial 'grind)") # don't use ! for factorials (#11539) ecl_eval("(setf $errormsg nil)") -# the following is a direct adaptation of the definition of "retrieve" -# in the Maxima file macsys.lisp. This routine is normally responsible -# for displaying a question and returning the answer. We change it to -# throw an error in which the text of the question is included. We do -# this by running exactly the same code as in the original definition -# of "retrieve", but with *standard-output* redirected to a string. +# The following is an adaptation of the "retrieve" function in maxima +# itself. This routine is normally responsible for displaying a +# question and returning the answer. Our version throws an error in +# which the text of the question is included. This is accomplished by +# redirecting *standard-output* to a string. +# +# After an update in Trac 31553, this routine also preprocesses the +# text to replace space symbols with strings. This prevents those +# symbols from being turned into ugly newlines -- a problem that we +# used to avoid with a custom patch. ecl_eval(r""" (defun retrieve (msg flag &aux (print? nil)) (declare (special msg flag print?)) + (setq msg (mapcar #'(lambda (x) (if (eq x '| |) " " x)) msg)) (or (eq flag 'noprint) (setq print? t)) (error - (concatenate 'string "Maxima asks: " + (concatenate 'string + "Maxima asks: " (string-trim '(#\Newline) - (with-output-to-string (*standard-output*) - (cond ((not print?) - (setq print? t) - (princ *prompt-prefix*) - (princ *prompt-suffix*) - ) - ((null msg) - (princ *prompt-prefix*) - (princ *prompt-suffix*) - ) - ((atom msg) - (format t "~a~a~a" *prompt-prefix* msg *prompt-suffix*) - ) - ((eq flag t) - (princ *prompt-prefix*) - (mapc #'princ (cdr msg)) - (princ *prompt-suffix*) - ) - (t - (princ *prompt-prefix*) - (displa msg) - (princ *prompt-suffix*) - ) - )))) - ) -) + (with-output-to-string (*standard-output*) + (cond ((not print?) + (setq print? t) + (format-prompt t "")) + ((null msg) + (format-prompt t "")) + ((atom msg) + (format-prompt t "~A" msg) + (mterpri)) + ((eq flag t) + (format-prompt t "~{~A~}" (cdr msg)) + (mterpri)) + (t + (format-prompt t "~M" msg) + (mterpri)))))))) """) ## Redirection of ECL and Maxima stdout to /dev/null diff --git a/src/sage/interfaces/mwrank.py b/src/sage/interfaces/mwrank.py index 1bab65a9174..636b7d6d961 100644 --- a/src/sage/interfaces/mwrank.py +++ b/src/sage/interfaces/mwrank.py @@ -123,7 +123,7 @@ def validate_mwrank_input(s): """ if isinstance(s,(list,tuple)): - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if len(s)!=5: raise ValueError("%s is not valid input to mwrank (should have 5 entries)" % s) try: diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index d5e74dce41b..845fa0fd264 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -503,7 +503,7 @@ def solve_linear_system(self, A, b): if m != len(b): raise ValueError("dimensions of A and b must be compatible") from sage.matrix.all import MatrixSpace - from sage.rings.all import QQ + from sage.rings.rational_field import QQ MS = MatrixSpace(QQ,m,1) b = MS(list(b)) # converted b to a "column vector" sA = self.sage2octave_matrix_string(A) diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 8ac83e87ad6..4111116598c 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -1561,9 +1561,9 @@ def _sage_(self): r = self._repr_() if 'Float' in T1: - from sage.rings.all import RDF + from sage.rings.real_double import RDF base_ring = RDF - str_to_base_ring = lambda s: RDF(s) + str_to_base_ring = RDF elif 'QuadraticExtension' in T1 and 'r' in r: i = r.find('r') i1 = min((r[i:]+' ').find(' '), (r[i:]+'\n').find('\n')) @@ -1574,12 +1574,12 @@ def _sage_(self): def str_to_base_ring(s): m = re.match(r'(-?[0-9/]+)[+]?((-?[0-9/]+)r([0-9/]+))?', s) a, b = m.group(1), m.group(3) - return base_ring(a) + base_ring(b)*base_ring.gen() + return base_ring(a) + base_ring(b) * base_ring.gen() elif 'Rational' in T1: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ base_ring = QQ - str_to_base_ring = lambda s: QQ(s) + str_to_base_ring = QQ else: raise NotImplementedError diff --git a/src/sage/interfaces/scilab.py b/src/sage/interfaces/scilab.py index ace7bb33ccd..610f64f8d81 100644 --- a/src/sage/interfaces/scilab.py +++ b/src/sage/interfaces/scilab.py @@ -132,7 +132,7 @@ sage: M = scilab(x) # optional - scilab Traceback (most recent call last): ... - TypeError: _interface_init_() takes exactly one argument (0 given) + TypeError: ..._interface_init_() takes exactly one argument (0 given) sage: M = scilab(matrix(3,range(9))); M # optional - scilab 0. 1. 2. 3. 4. 5. diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index 7678ea14fc1..ff7a64eee4f 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -383,6 +383,9 @@ def __init__(self, data): else: raise ValueError("invalid input: data must be either a list or a braid") + self._mirror = None # set on invocation of :meth:`mirror_image` + self._reverse = None # set on invocation of :meth:`reverse` + def arcs(self, presentation='pd'): r""" Return the arcs of ``self``. @@ -2256,9 +2259,23 @@ def mirror_image(self): K = Link([[[1,-2,3,-1,2,-3]],[1,1,1]]) K2 = K.mirror_image() sphinx_plot(K2.plot()) + + TESTS: + + check that :trac:`30997` is fixed:: + + sage: L = Link([[6, 2, 7, 1], [5, 13, 6, 12], [8, 3, 9, 4], + ....: [2, 13, 3, 14], [14, 8, 15, 7], [11, 17, 12, 16], + ....: [9, 18, 10, 11], [17, 10, 18, 5], [4, 16, 1, 15]]) # L9n25{0}{0} from KnotInfo + sage: Lmm = L.mirror_image().mirror_image() + sage: L == Lmm + True """ # Use the braid information if it is the shortest version # of what we have already computed + if self._mirror: + return self._mirror + if self._braid: lb = len(self._braid.Tietze()) @@ -2273,11 +2290,67 @@ def mirror_image(self): logc = float('inf') if lb <= logc and lb <= lpd: - return type(self)(~self._braid) + self._mirror = type(self)(self._braid.mirror_image()) + self._mirror._mirror = self + return self._mirror # Otherwise we fallback to the PD code pd = [[a[0], a[3], a[2], a[1]] for a in self.pd_code()] - return type(self)(pd) + self._mirror = type(self)(pd) + self._mirror._mirror = self + return self._mirror + + def reverse(self): + r""" + Return the reverse of ``self``. This is the link obtained from ``self`` + by reverting the orientation on all components. + + EXAMPLES:: + + sage: K3 = Knot([[5, 2, 4, 1], [3, 6, 2, 5], [1, 4, 6, 3]]) + sage: K3r = K3.reverse(); K3r.pd_code() + [[4, 1, 5, 2], [2, 5, 3, 6], [6, 3, 1, 4]] + sage: K3 == K3r + True + + a non reversable knot:: + + sage: K8_17 = Knot([[6, 2, 7, 1], [14, 8, 15, 7], [8, 3, 9, 4], + ....: [2, 13, 3, 14], [12, 5, 13, 6], [4, 9, 5, 10], + ....: [16, 12, 1, 11], [10, 16, 11, 15]]) + sage: K8_17r = K8_17.reverse() + sage: b = K8_17.braid(); b + s0^2*s1^-1*(s1^-1*s0)^2*s1^-1 + sage: br = K8_17r.braid(); br + s0^-1*s1*s0^-2*s1^2*s0^-1*s1 + sage: b.is_conjugated(br) + False + sage: b == br.reverse() + False + sage: b.is_conjugated(br.reverse()) + True + sage: K8_17b = Link(b) + sage: K8_17br = K8_17b.reverse() + sage: bbr = K8_17br.braid(); bbr + (s1^-1*s0)^2*s1^-2*s0^2 + sage: br == bbr + False + sage: br.is_conjugated(bbr) + True + """ + if self._reverse: + return self._reverse + + if self._braid: + self._reverse = type(self)(self._braid.reverse()) + self._reverse._reverse = self + return self._reverse + + # Otherwise we fallback to the PD code + pd = [[a[2], a[3], a[0], a[1]] for a in self.pd_code()] + self._reverse = type(self)(pd) + self._reverse._reverse = self + return self._reverse def writhe(self): r""" diff --git a/src/sage/libs/eclib/homspace.pyx b/src/sage/libs/eclib/homspace.pyx index 599a73938e2..900aa7834a9 100644 --- a/src/sage/libs/eclib/homspace.pyx +++ b/src/sage/libs/eclib/homspace.pyx @@ -10,7 +10,7 @@ from .mat cimport MatrixFactory from sage.matrix.all import MatrixSpace from sage.matrix.matrix_integer_sparse cimport Matrix_integer_sparse -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer cdef MatrixFactory MF = MatrixFactory() diff --git a/src/sage/libs/eclib/mat.pyx b/src/sage/libs/eclib/mat.pyx index 9cd06f9b344..d740a695654 100644 --- a/src/sage/libs/eclib/mat.pyx +++ b/src/sage/libs/eclib/mat.pyx @@ -5,7 +5,7 @@ Cremona matrices from ..eclib cimport scalar, addscalar from sage.matrix.all import MatrixSpace -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.matrix.matrix_integer_sparse cimport Matrix_integer_sparse from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense diff --git a/src/sage/libs/flint/fmpz_poly.pyx b/src/sage/libs/flint/fmpz_poly.pyx index 97338c79cad..ba7f81d7143 100644 --- a/src/sage/libs/flint/fmpz_poly.pyx +++ b/src/sage/libs/flint/fmpz_poly.pyx @@ -454,6 +454,6 @@ cdef class Fmpz_poly(SageObject): sage: Fmpz_poly([-1,0,0,1])._sage_() x^3 - 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ[var](self.list()) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index a4c1eda97f1..049ab672415 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -3004,7 +3004,7 @@ cdef class GapElement_List(GapElement): """ if not self.IsVector(): raise ValueError('not a GAP vector') - from sage.modules.all import vector + from sage.modules.free_module_element import vector entries = self.Flat() n = self.Length().sage() if ring is None: diff --git a/src/sage/libs/gap/libgap.pyx b/src/sage/libs/gap/libgap.pyx index 3db0bbfded8..9f9f62be13a 100644 --- a/src/sage/libs/gap/libgap.pyx +++ b/src/sage/libs/gap/libgap.pyx @@ -217,7 +217,7 @@ from .element cimport * from sage.structure.parent cimport Parent from sage.structure.element cimport Vector -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method from sage.misc.randstate cimport current_randstate diff --git a/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi b/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi index 81b47988b39..b797782c657 100644 --- a/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi +++ b/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi @@ -864,5 +864,5 @@ cdef cmatrix_mod_pn(celement a, long aprec, long valshift, PowComputer_ prime_po L[-1].append(zero) fmpz_poly_shift_left(prime_pow.poly_matmod, prime_pow.poly_matmod, 1) creduce(prime_pow.poly_matmod, prime_pow.poly_matmod, aprec, prime_pow) - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix return matrix(R, deg, deg, L) diff --git a/src/sage/libs/sirocco.pyx b/src/sage/libs/sirocco.pyx index 312075376a9..5bd4062394d 100644 --- a/src/sage/libs/sirocco.pyx +++ b/src/sage/libs/sirocco.pyx @@ -23,7 +23,8 @@ from sage.rings.real_mpfr import RealField cdef extern from "sirocco.h": mpfr_t* homotopyPath_mp(int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec) double* homotopyPath(int degree, double *_coef, double _y0R, double _y0I) - + mpfr_t* homotopyPath_mp_comps(int degree, mpfr_t *_coef, mpfr_t _y0R, mpfr_t _y0I, int prec, int nothercomps, int *degreescomps, mpfr_t *_coefscomps) + double* homotopyPath_comps(int degree, double *_coef, double _y0R, double _y0I, int nothercomps, int *degreescomps, double *_coefscomps) cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0i, int prec): @@ -34,6 +35,17 @@ cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0 - A extra argument is needed, indicating the bits of precision used in the computations. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath_mp # optional - sirocco + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR, [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath_mp(2, pol, RR(0), RR(0), 53) # optional - sirocco # abs tol 1e-15 + [(0.000000000000000, 0.000000000000000, 0.000000000000000), + (0.500000000000000, -0.250000000000000, 0.000000000000000), + (1.00000000000000, -1.00000000000000, 0.000000000000000)] + """ cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) cdef mpfr_t* rop @@ -76,6 +88,85 @@ cpdef list[list] contpath_mp(int deg, list values, RealNumber y0r, RealNumber y0 free(rop) return l +cpdef list[list] contpath_mp_comps(int deg, list values, RealNumber y0r, RealNumber y0i, int prec, list otherdegs, list othercoefs): + """ + Mimics :func:`contpath`, but with the following differences: + + - The floating point numbers can be arbitrary precision RealNumbers. + + - A extra argument is needed, indicating the bits of precision used + in the computations. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath_mp_comps # optional - sirocco + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: fac = list(map(RR,[0, 0, 0.1, 0.2, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath_mp_comps(2, pol, RR(0), RR(0), 53, [2], fac) # optional - sirocco # abs tol 1e-15 + [(0.000000000000000, 0.000000000000000, 0.000000000000000), + (0.125000000000000, -0.0156250000000000, 0.000000000000000), + (0.250000000000000, -0.0625000000000000, 0.000000000000000), + (0.375000000000000, -0.140625000000000, 0.000000000000000), + (0.500000000000000, -0.250000000000000, 0.000000000000000), + (0.625000000000000, -0.390625000000000, 0.000000000000000), + (0.750000000000000, -0.562500000000000, 0.000000000000000), + (0.875000000000000, -0.765625000000000, 0.000000000000000), + (1.00000000000000, -1.00000000000000, 0.000000000000000)] + + """ + + cdef mpfr_t* cvalues = check_allocarray(len(values), sizeof(mpfr_t)) + cdef mpfr_t* cothercoefs = check_allocarray(len(othercoefs), sizeof(mpfr_t)) + cdef int* cotherdegs = check_allocarray(len(otherdegs), sizeof(int)) + cdef mpfr_t* rop + cdef int i, j + cdef mpfr_t y0R + cdef mpfr_t y0I + + for j in range(len(values)): + mpfr_init2(cvalues[j], prec) + mpfr_set(cvalues[j], (values[j]).value, MPFR_RNDN) + + for j in range(len(othercoefs)): + mpfr_init2(cothercoefs[j], prec) + mpfr_set(cothercoefs[j], (othercoefs[j]).value, MPFR_RNDN) + + for j in range(len(otherdegs)): + cotherdegs[j] = int(otherdegs[j]) + sig_on() + mpfr_init2(y0R, prec) + mpfr_set(y0R, (y0r).value, MPFR_RNDN) + mpfr_init2(y0I, prec) + mpfr_set(y0I, (y0i).value, MPFR_RNDN) + rop = homotopyPath_mp_comps(deg, cvalues, y0R, y0I, prec, int(len(otherdegs)), cotherdegs, cothercoefs) + sig_off() + for j in range(len(values)): + mpfr_clear(cvalues[j]) + free(cvalues) + for j in range(len(othercoefs)): + mpfr_clear(cothercoefs[j]) + free(cothercoefs) + free(cotherdegs) + if rop == NULL: + raise ValueError("libsirocco could not guarantee one step") + cdef int n = mpfr_get_si(rop[0], MPFR_RNDN) + cdef list l = [] + cdef list inner + cdef RealNumber RN + field = RealField(prec) + for i in range(n): + inner = [] + for j in range(3*i+1, 3*(i+1)+1): + RN = RealNumber.__new__(RealNumber, field) + mpfr_set(RN.value, rop[j], MPFR_RNDN) + mpfr_clear(rop[j]) + inner.append(RN) + l.append(tuple(inner)) + free(rop) + return l + + cpdef list[list] contpath(int deg, list values, double y0r, double y0i): """ INPUT: @@ -97,12 +188,24 @@ cpdef list[list] contpath(int deg, list values, double y0r, double y0i): A list of tuples. Each tuple represents the `x` value (between 0 and 1) and the real and imaginary parts of the `y` value of a vertex in the piecewise linear approximation of the path tracked by the root. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath # optional - sirocco + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath(2, pol, RR(0), RR(0)) # optional - sirocco # abs tol 1e-15 + [(0.0, 0.0, 0.0), + (0.3535533905932738, -0.12500000000000003, 0.0), + (0.7071067811865476, -0.5000000000000001, 0.0), + (1.0, -1.0, 0.0)] + """ cdef double* rop cdef double* c_values = check_allocarray(len(values), sizeof(double)) cdef int clen = len(values) cdef int i - for i,v in enumerate(values): + for i, v in enumerate(values): c_values[i] = values[i] cdef double y0R = y0r cdef double y0I = y0i @@ -119,3 +222,74 @@ cpdef list[list] contpath(int deg, list values, double y0r, double y0i): free(c_values) return l +cpdef list[list] contpath_comps(int deg, list values, double y0r, double y0i, list otherdegrees, list othercoefs): + """ + INPUT: + + - An integer, representing the degree of the polynomial + + - A list of floating point numbers. Each four consecutive elements + of this list represent the interval corresponding to a coefficient. + Coefficients are listed in increasing deglex order, and inside each + coefficients, the four numbers represent the lower real, upper real, + lower imaginary and real imaginary limits of the interval. + + - A float representing the real part of the initial root approximation + + - A float representing the imaginary part of the initial root. + + OUTPUT: + + A list of tuples. Each tuple represents the `x` value (between 0 and 1) + and the real and imaginary parts of the `y` value of a vertex in + the piecewise linear approximation of the path tracked by the root. + + EXAMPLES:: + + sage: from sage.libs.sirocco import contpath_comps # optional - sirocco + sage: from sage.rings.real_mpfr import RR + sage: pol = list(map(RR,[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: fac = list(map(RR,[0, 0, 0.1, 0.2, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])) + sage: contpath_comps(2, pol, RR(0), RR(0), [2], fac) # optional - sirocco # abs tol 1e-15 + [(0.0, 0.0, 0.0), + (0.125, -0.015625, 0.0), + (0.25, -0.0625, 0.0), + (0.375, -0.140625, 0.0), + (0.5, -0.25, 0.0), + (0.625, -0.390625, 0.0), + (0.75, -0.5625, 0.0), + (0.875, -0.765625, 0.0), + (1.0, -1.0, 0.0)] + + """ + cdef double* rop + cdef double* c_values = check_allocarray(len(values), sizeof(double)) + cdef int* c_otherdegrees = check_allocarray(len(otherdegrees), sizeof(int)) + cdef double* c_othercoefs = check_allocarray(len(othercoefs), sizeof(double)) + cdef int clen = len(values) + cdef int i + for i, v in enumerate(values): + c_values[i] = values[i] + + for i, v in enumerate(otherdegrees): + c_otherdegrees[i] = otherdegrees[i] + for i, v in enumerate(othercoefs): + c_othercoefs[i] = othercoefs[i] + + cdef double y0R = y0r + cdef double y0I = y0i + sig_on() + rop = homotopyPath_comps(deg, c_values, y0R, y0I, int(len(otherdegrees)), c_otherdegrees, c_othercoefs) + sig_off() + if rop == NULL: + raise ValueError("libsirocco could not guarantee one step") + cdef int n = int(rop[0]) + cdef list l = [0] * n + for i in range(n): + l[i] = (rop[3*i+1], rop[3*i+2], rop[3*i+3]) + free(rop) + free(c_values) + free(c_otherdegrees) + free(c_othercoefs) + return l + diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index 3c0c22a2b0d..a3353b820cb 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -266,7 +266,7 @@ def __init__(self, vbundle, name, latex_name=None): "vector bundle") Mutability.__init__(self) self._vbundle = vbundle - self._base_space = vbundle.base_space() + self._domain = vbundle.base_space() self._name = name if latex_name is None: self._latex_name = self._name @@ -394,7 +394,7 @@ def __eq__(self, other): return True if not isinstance(other, BundleConnection): return False - if other._base_space != self._base_space: + if other._domain != self._domain: return False if self._connection_forms == {}: return False @@ -566,7 +566,7 @@ def connection_forms(self, frame=None): """ if frame is None: - smodule = self._vbundle.section_module(domain=self._base_space) + smodule = self._vbundle.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a frame must be provided") @@ -832,7 +832,7 @@ def add_connection_form(self, i, j, frame=None): """ self._require_mutable() if frame is None: - smodule = self._vbundle.section_module(domain=self._base_space) + smodule = self._vbundle.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a frame must be provided") @@ -840,7 +840,7 @@ def add_connection_form(self, i, j, frame=None): if frame not in self._connection_forms: if frame not in self._vbundle._frames: raise ValueError("the {} is not".format(frame) + - " a frame on the {}".format(self._base_space)) + " a frame on the {}".format(self._domain)) self._connection_forms[frame] = self._new_forms(frame) self._del_derived() # deletes the derived quantities return self._connection_forms[frame][(i, j)] @@ -967,7 +967,7 @@ def del_other_forms(self, frame=None): """ if frame is None: - smodule = self._vbundle.section_module(domain=self._base_space) + smodule = self._vbundle.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a frame must be provided") @@ -1023,7 +1023,7 @@ def curvature_form(self, i, j, frame=None): """ if frame is None: - smodule = self._vbundle.section_module(domain=self._base_space) + smodule = self._vbundle.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a frame must be provided") @@ -1127,13 +1127,13 @@ def __getitem__(self, args): # extract frame from first index: vb = self._vbundle if isinstance(args, (int, Integer, slice)): - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() elif not isinstance(args[0], (int, Integer, slice)): frame = args[0] args = args[1:] else: - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() # indexing: if isinstance(args, slice): @@ -1200,13 +1200,13 @@ def __setitem__(self, args, value): # extract frame from first index: vb = self._vbundle if isinstance(args, (int, Integer, slice)): - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() elif not isinstance(args[0], (int, Integer, slice)): frame = args[0] args = args[1:] else: - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() # determine indices: if isinstance(args, slice): @@ -1350,7 +1350,7 @@ def display(self, frame=None, vector_frame=None, chart=None, """ vb = self._vbundle if frame is None: - smodule = vb.section_module(domain=self._base_space) + smodule = vb.section_module(domain=self._domain) frame = smodule.default_frame() if frame is None: raise ValueError("a local frame must be provided") diff --git a/src/sage/manifolds/differentiable/characteristic_class.py b/src/sage/manifolds/differentiable/characteristic_class.py deleted file mode 100644 index de846d2262b..00000000000 --- a/src/sage/manifolds/differentiable/characteristic_class.py +++ /dev/null @@ -1,962 +0,0 @@ -r""" -Characteristic Classes - -A *characteristic class* `\kappa` is a natural transformation that -associates to each vector bundle `E \to M` a cohomology class -`\kappa(E) \in H^*(M;R)` such that for any continuous map `f\colon N \to M` -from another topological manifold `N`, the *naturality condition* is -satisfied: - -.. MATH:: - - f^*\kappa(E) = \kappa(f^* E) \in H^*(N;R) - -Roughly speaking, characteristic classes measure the non-triviality of -vector bundles. - -One way to obtain and compute characteristic classes in the de Rham cohomology -with coefficients in the ring `\CC` is via the so-called *Chern-Weil theory* -using the curvature of a differentiable vector bundle. - -For that let `\nabla` be a connection on `E`, `e` a local frame on -`E` and `\Omega` be the corresponding curvature matrix -(see: :meth:`~sage.manifolds.differentiable.bundle_connection.BundleConnection.curvature_form`). - -Namely, if `P: \mathrm{Mat}_{n \times n}(\CC) \to \CC` is an invariant -polynomial, the object - -.. MATH:: - - \left[ P \left( \Omega \right) \right] \in H^{2*}_{\mathrm{dR}}(M, \CC) - -is well-defined, independent of the choice of `\nabla` (the proof can be -found in [Roe1988]_ pp. 31) and fulfills the naturality condition. -This is the foundation of the Chern-Weil theory and therefore the following -definitions. - -.. NOTE:: - - This documentation is rich of examples, but sparse in explanations. Please - consult the references for more details. - -AUTHORS: - -- Michael Jung (2019) : initial version - -REFERENCES: - -- [Mil1974]_ -- [Roe1988]_ - -Contents --------- - -We consider the following three types of classes: - -- :ref:`additive` -- :ref:`multiplicative` -- :ref:`Pfaffian` - -.. _additive: - -Additive Classes ----------------- - -In the **complex** case, let `f` be a holomorphic function around zero. Then -we call - -.. MATH:: - - \left[\mathrm{tr}\left( f\left( \frac{\Omega}{2 \pi i} \right) - \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) - -the *additive characteristic class associated to* `f` of the complex vector -bundle `E`. - -Important and predefined additive classes are: - -- *Chern Character* with `f(x) = \exp(x)` - -In the **real** case, let `g` be a holomorphic function around zero with -`g(0)=0`. Then we call - -.. MATH:: - - \left[\mathrm{tr}\left( \frac{1}{2} g\left( -\frac{\Omega^2}{4 \pi^2} - \right) \right)\right] \in H^{4*}_{\mathrm{dR}}(M, \CC) - -the *additive characteristic class associated to* `g` of the **real** vector -bundle `E`. - -EXAMPLES: - -Consider the **Chern character** on some 2-dimensional spacetime:: - - sage: M = Manifold(2, 'M', structure='Lorentzian') - sage: X. = M.chart() - sage: E = M.vector_bundle(1, 'E', field='complex'); E - Differentiable complex vector bundle E -> M of rank 1 over the base space - 2-dimensional Lorentzian manifold M - sage: e = E.local_frame('e') - -Let us define the connection `\nabla^E` in terms of an electro-magnetic -potential `A(t)`:: - - sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') - sage: omega = M.one_form(name='omega') - sage: A = function('A') - sage: nab.set_connection_form(0, 0)[1] = I*A(t) - sage: nab[0, 0].display() - connection (0,0) of bundle connection nabla^E w.r.t. Local frame - (E|_M, (e_0)) = I*A(t) dx - sage: nab.set_immutable() - -The Chern character is then given by:: - - sage: ch = E.characteristic_class('ChernChar'); ch - Characteristic class ch of additive type associated to e^x on the - Differentiable complex vector bundle E -> M of rank 1 over the base space - 2-dimensional Lorentzian manifold M - -The corresponding characteristic form w.r.t. the bundle connection can be -obtained via :meth:`~CharacteristicClass.get_form`:: - - sage: ch_form = ch.get_form(nab); ch_form.display_expansion() - ch(E, nabla^E) = 1 + 1/2*d(A)/dt/pi dt∧dx - -.. _multiplicative: - -Multiplicative Classes ----------------------- - -In the **complex** case, let `f` be a holomorphic function around zero. -Then we call - -.. MATH:: - - \left[\det\left( f\left( \frac{\Omega}{2 \pi i} \right) - \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) - -the *multiplicative characteristic class associated to* `f` of the complex -vector bundle `E`. - -Important and predefined multiplicative classes on complex vector bundles are: - -- *Chern class* with `f(x) = 1+x` -- *Todd class* with `f(x) = \frac{x}{1-\exp(-x)}` - -In the **real** case, let `g` be a holomorphic function around zero with -`g(0)=1`. Then we call - -.. MATH:: - - \left[\det\left( \sqrt{ g \left( -\frac{\Omega^2}{4 \pi^2} \right) } \right) - \right] \in H^{4*}_{\mathrm{dR}}(M, \CC) - -the *multiplicative characteristic class associated to* `g` on the **real** -vector bundle `E`. - -Important and predefined multiplicative classes on real vector bundles are: - -- *Pontryagin class* with `g(x) = 1+x` -- `\hat{A}` *class* with `g(x) = \frac{\sqrt{x}/2}{\sinh(\sqrt{x}/2)}` -- *Hirzebruch class* with `g(x) = \frac{\sqrt{x}}{\tanh(\sqrt{x})}` - -EXAMPLES: - -We consider the **Chern class** of the tautological line bundle `\gamma^1` over -`\CC\mathbf{P}^1`:: - - sage: M = Manifold(2, 'CP^1', start_index=1) - sage: U = M.open_subset('U') - sage: c_cart. = U.chart() # homogeneous coordinates in real terms - sage: c_comp. = U.chart(r'z:z zbar:\bar{z}') # complexification - sage: cart_to_comp = c_cart.transition_map(c_comp, (x+I*y, x-I*y)) - sage: comp_to_cart = cart_to_comp.inverse() - sage: E = M.vector_bundle(1, 'gamma^1', field='complex') - sage: e = E.local_frame('e', domain=U) - -To apply the Chern-Weil approach, we need a bundle connection in terms of a -connection one form. To achieve this, we take the connection induced from the -hermitian metric on the trivial bundle -`\CC^2 \times \CC\mathbf{P}^1 \supset \gamma^1`. In this the frame `e` -corresponds to the section `[z:1] \mapsto (z,1)` and its magnitude-squared -is given by `1+|z|^2`:: - - sage: nab = E.bundle_connection('nabla') - sage: omega = U.one_form(name='omega') - sage: omega[c_comp.frame(),1,c_comp] = zbar/(1+z*zbar) - sage: nab[e, 1, 1] = omega - sage: nab.set_immutable() - -Now, the Chern class can be constructed:: - - sage: c = E.characteristic_class('Chern'); c - Characteristic class c of multiplicative type associated to x + 1 on the - Differentiable complex vector bundle gamma^1 -> CP^1 of rank 1 over the - base space 2-dimensional differentiable manifold CP^1 - sage: c_form = c.get_form(nab) - sage: c_form.display_expansion(c_comp.frame(), chart=c_comp) - c(gamma^1, nabla) = 1 + 1/2*I/(pi + pi*z^2*zbar^2 + 2*pi*z*zbar) dz∧dzbar - -Since `U` and `\CC\mathbf{P}^1` differ only by a point and therefore a null -set, it is enough to integrate the top form over the domain `U`:: - - sage: integrate(integrate(c_form[2][[1,2]].expr(c_cart), x, -infinity, infinity).full_simplify(), - ....: y, -infinity, infinity) - 1 - -The result shows that `c_1(\gamma^1)` generates the second integer -cohomology of `\CC\mathbf{P}^1`. - -.. _Pfaffian: - -Pfaffian Classes ----------------- - -Usually, there is no such thing as "Pfaffian classes" in literature. However, -using the matrix' Pfaffian and inspired by the aforementioned definitions, -such classes can be defined as follows. - -Let `E` be a real vector bundle of rank `2n` and `f` an odd real function -being analytic at zero. Furthermore, let `\Omega` be skew-symmetric, which -certainly will be true if `\nabla` is metric and `e` is orthonormal. Then -we call - -.. MATH:: - - \left[\mathrm{Pf}\left( f\left( \frac{\Omega}{2 \pi} \right) \right)\right] - \in H^{2n*}(M,\RR) - -the *Pfaffian class associated to f*. - -The most important Pfaffian class is the *Euler class* which is simply given by -`f(x)=x`. - -EXAMPLES: - -We consider the **Euler class** of `S^2`:: - - sage: M = Manifold(2, name='S2', latex_name=r'S^2', start_index=1) - sage: U = M.open_subset('U') ; V = M.open_subset('V') - sage: M.declare_union(U,V) # M is the union of U and V - sage: c_xy. = U.chart() ; c_uv. = V.chart() - sage: xy_to_uv = c_xy.transition_map(c_uv, - ....: (x/(x^2+y^2), y/(x^2+y^2)), - ....: intersection_name='W', - ....: restrictions1= x^2+y^2!=0, - ....: restrictions2= u^2+v^2!=0) - sage: uv_to_xy = xy_to_uv.inverse() - sage: eU = c_xy.frame() ; eV = c_uv.frame() - sage: TM = M.tangent_bundle() - sage: e_class = TM.characteristic_class('Euler'); e_class - Characteristic class e of Pfaffian type associated to x on the Tangent - bundle TS2 over the 2-dimensional differentiable manifold S2 - -To compute a particular representative of the Euler class, we need to determine -a connection:: - - sage: g = M.metric('g') # standard metric on S2 - sage: g[eU,1,1], g[eU,2,2] = 4/(1+x^2+y^2)^2, 4/(1+x^2+y^2)^2 - sage: g[eV,1,1], g[eV,2,2] = 4/(1+u^2+v^2)^2, 4/(1+u^2+v^2)^2 - sage: nab = g.connection() - -In case of the Euler class, skew-symmetric curvature matrices are needed -for the Pfaffian. For this, we need to define the curvature matrices by -hand:: - - sage: cmatrix_U = [[nab.curvature_form(i,j,eU) for j in TM.irange()] - ....: for i in TM.irange()] - sage: cmatrix_V = [[nab.curvature_form(i,j,eV) for j in TM.irange()] - ....: for i in TM.irange()] - -Fortunately, both curvature matrices are already skew-symmetric:: - - sage: for i in range(TM.rank()): - ....: for j in range(TM.rank()): - ....: print(cmatrix_U[i][j].display()) - curvature (1,1) of connection nabla_g w.r.t. Coordinate frame - (U, (∂/∂x,∂/∂y)) = 0 - curvature (1,2) of connection nabla_g w.r.t. Coordinate frame - (U, (∂/∂x,∂/∂y)) = 4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx∧dy - curvature (2,1) of connection nabla_g w.r.t. Coordinate frame - (U, (∂/∂x,∂/∂y)) = -4/(x^4 + y^4 + 2*(x^2 + 1)*y^2 + 2*x^2 + 1) dx∧dy - curvature (2,2) of connection nabla_g w.r.t. Coordinate frame - (U, (∂/∂x,∂/∂y)) = 0 - sage: for i in range(TM.rank()): - ....: for j in range(TM.rank()): - ....: print(cmatrix_V[i][j].display()) - curvature (1,1) of connection nabla_g w.r.t. Coordinate frame - (V, (∂/∂u,∂/∂v)) = 0 - curvature (1,2) of connection nabla_g w.r.t. Coordinate frame - (V, (∂/∂u,∂/∂v)) = 4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du∧dv - curvature (2,1) of connection nabla_g w.r.t. Coordinate frame - (V, (∂/∂u,∂/∂v)) = -4/(u^4 + v^4 + 2*(u^2 + 1)*v^2 + 2*u^2 + 1) du∧dv - curvature (2,2) of connection nabla_g w.r.t. Coordinate frame - (V, (∂/∂u,∂/∂v)) = 0 - sage: nab.set_immutable() # make nab immutable - -Now the representative of the Euler class with respect to the connection -`\nabla_g` induced by the standard metric can be computed:: - - sage: cmatrices = {eU: cmatrix_U, eV: cmatrix_V} - sage: e_class_form = e_class.get_form(nab, cmatrices) - sage: e_class_form.display_expansion() - e(TS2, nabla_g) = 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy - -Let us check whether this form represents the Euler class correctly:: - - sage: integrate(integrate(e_class_form[2][[1,2]].expr(), x, -infinity, infinity).simplify_full(), - ....: y, -infinity, infinity) - 2 - -As we can see, the integral coincides with the Euler characteristic of `S^2` so -that our form actually represents the Euler class appropriately. - -""" - -#****************************************************************************** -# Copyright (C) 2019 Michael Jung -# -# Distributed under the terms of the GNU General Public License (GPL) -# 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 sage.structure.unique_representation import UniqueRepresentation -from sage.misc.cachefunc import cached_method -from sage.structure.sage_object import SageObject -from sage.symbolic.ring import SR -from sage.rings.rational_field import QQ - -################################################################################ -## Separate functions - -def _get_predefined_class(arg): - r""" - Return the signature of the predefined class given by the string ``arg``. - - The signature is given by a tuple following the syntax - (base field, class type, name, LaTeX name, function). - - Modify this method to add new predefined characteristic classes. - - TESTS:: - - sage: from sage.manifolds.differentiable.characteristic_class import _get_predefined_class - sage: _get_predefined_class('Chern') - ('complex', 'multiplicative', 'c', 'c', x + 1) - sage: _get_predefined_class('Pontryagin') - ('real', 'multiplicative', 'p', 'p', x + 1) - sage: _get_predefined_class('Euler') - ('real', 'Pfaffian', 'e', 'e', x) - - """ - if not isinstance(arg, str): - raise TypeError("argument 'arg' must be string") - # Define variable: - x = SR.symbol('x') - # Define dictionary. The syntax is as follows: - # (field_type, class_type, name, latex_name, func) - if arg == 'ChernChar': - return ('complex', 'additive', 'ch', r'\mathrm{ch}', x.exp()) - elif arg == 'Todd': - return ('complex', 'additive', 'Td', r'\mathrm{Td}', - x / (1 - (-x).exp())) - elif arg == 'Chern': - return ('complex', 'multiplicative', 'c', 'c', 1 + x) - elif arg == 'Pontryagin': - return ('real', 'multiplicative', 'p', 'p', 1 + x) - elif arg == 'AHat': - return ('real', 'multiplicative', 'A^', r'\hat{A}', - x.sqrt() / (2 * (x.sqrt() / 2).sinh())) - elif arg == 'Hirzebruch': - return ('real', 'multiplicative', 'L', 'L', - x.sqrt() / x.sqrt().tanh()) - elif arg == 'Euler': - return ('real', 'Pfaffian', 'e', 'e', x) - else: - raise ValueError("the characteristic class '{}' is ".format(arg) + - "not predefined yet.") - -################################################################################ -## Classes - -class CharacteristicClass(UniqueRepresentation, SageObject): - r""" - An instance of this class represents a characteristic class on some - differentiable vector bundle over the field `\RR` or `\CC`. - - INPUT: - - - vbundle -- vector bundle on which the characteristic class should be - defined - - func -- symbolic expression representing the function to which ``self`` - should be associated to - - class_type -- (default: ``'multiplicative'``) class type of the - characteristic class; at this stage, the following options are possible: - - - ``'multiplicative'`` -- returns a class of multiplicative type, - using the determinant - - ``'additive'`` -- returns a class of additive type, using the trace - - ``'Pfaffian'`` -- returns a class of Pfaffian type, using the - Pfaffian - - - ``name`` -- string representation given to the characteristic class - - ``latex_name`` -- (default: ``None``) LaTeX name given to the - characteristic class - - EXAMPLES: - - Get characteristic classes using predefined ones:: - - sage: M = Manifold(4, 'M') - sage: TM = M.tangent_bundle() - sage: TM.characteristic_class('Pontryagin') - Characteristic class p of multiplicative type associated to x + 1 on the - Tangent bundle TM over the 4-dimensional differentiable manifold M - sage: TM.characteristic_class('Hirzebruch') - Characteristic class L of multiplicative type associated to - sqrt(x)/tanh(sqrt(x)) on the Tangent bundle TM over the 4-dimensional - differentiable manifold M - sage: TM.characteristic_class('AHat') - Characteristic class A^ of multiplicative type associated to - 1/2*sqrt(x)/sinh(1/2*sqrt(x)) on the Tangent bundle TM over the - 4-dimensional differentiable manifold M - - The vector bundle's base field and definition domain of the characteristic - class must fit together, otherwise an error message occurs:: - - sage: TM.characteristic_class('Chern') - Traceback (most recent call last): - ... - ValueError: base field must be complex for class 'Chern' - - If your favourite class is not predefined yet, the associated function can - be put manually:: - - sage: cl = TM.characteristic_class(1+x^2, name='cl'); cl - Characteristic class cl of multiplicative type associated to x^2 + 1 on - the Tangent bundle TM over the 4-dimensional differentiable manifold M - - """ - def __init__(self, vbundle, func, class_type='multiplicative', name=None, - latex_name=None): - r""" - Construct a characteristic class. - - TESTS:: - - sage: M = Manifold(3, 'M') - sage: TM = M.tangent_bundle() - sage: from sage.manifolds.differentiable.characteristic_class import CharacteristicClass - sage: c = CharacteristicClass(TM, 1+x, name='c'); c - Characteristic class c of multiplicative type associated to x + 1 on - the Tangent bundle TM over the 3-dimensional differentiable - manifold M - sage: TestSuite(c).run() - - """ - if vbundle._field_type == 'neither_real_nor_complex': - raise ValueError("the vector bundle must either be real or complex") - if class_type not in ['additive', 'multiplicative', 'Pfaffian']: - raise ValueError("the argument 'class_type' must either be " - "'additive', 'multiplicative' or 'Pfaffian'") - if class_type == 'Pfaffian': - if vbundle._field_type != 'real' or vbundle._rank % 2 != 0: - raise ValueError("Pfaffian classes can only be defined for real" - " vector bundles of even rank") - self._name = name - if latex_name is None: - self._latex_name = name - else: - self._latex_name = latex_name - self._func = func - self._class_type = class_type - self._vbundle = vbundle - self._base_space = vbundle._base_space - self._rank = vbundle._rank - self._coeff_list = self._get_coeff_list() - self._init_derived() - - def _get_coeff_list(self, distinct_real=True): - r""" - Return the list of coefficients of the Taylor expansion at zero of the - function. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: E = M.vector_bundle(1, 'E', field='complex') - sage: c = E.characteristic_class(1+x) - sage: c._get_coeff_list() - [1, 1] - - """ - pow_range = self._base_space._dim // 2 - def_var = self._func.default_variable() - # Use a complex variable without affecting the old one: - with SR.temp_var(domain='complex') as new_var: - if self._vbundle._field_type == 'real' and distinct_real: - if self._class_type == 'additive': - func = self._func.subs({def_var: new_var ** 2}) / 2 - elif self._class_type == 'multiplicative': - # This could case problems in the real domain, where sqrt(x^2) - # is simplified to |x|. However, the variable must be complex - # anyway. - func = self._func.subs({def_var : new_var**2}).sqrt() - elif self._class_type == 'Pfaffian': - # There are no canonical Pfaffian classes, however, consider the - # projection onto the odd part of the function to keep the - # matrices skew: - func = (self._func.subs({def_var: new_var}) - - self._func.subs({def_var: -new_var})) / 2 - else: - func = self._func.subs({def_var: new_var}) - - if self._vbundle._field_type == 'real' and not distinct_real: - pow_range = pow_range // 2 - - return func.taylor(new_var, 0, pow_range).coefficients(sparse=False) - - def _init_derived(self): - r""" - Initialize the derived quantities. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: c = TM.characteristic_class(1+x) - sage: c._init_derived() - - """ - self._mixed_forms = {} # dict. of mixed forms corresponding this - # characteristic class - # (key: bundle connection) - - def _del_derived(self): - r""" - Delete the derived quantities. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: c = TM.characteristic_class(1+x) - sage: c._del_derived() - - """ - self._mixed_forms.clear() - - def _repr_(self): - r""" - String representation of the object. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: c = TM.characteristic_class(1+x, name='c') - sage: c # indirect doctest - Characteristic class c of multiplicative type associated to x + 1 on - the Tangent bundle TM over the 2-dimensional differentiable - manifold M - sage: repr(c) # indirect doctest - 'Characteristic class c of multiplicative type associated to x + 1 - on the Tangent bundle TM over the 2-dimensional differentiable - manifold M' - sage: c._repr_() - 'Characteristic class c of multiplicative type associated to x + 1 - on the Tangent bundle TM over the 2-dimensional differentiable - manifold M' - - """ - desc = "Characteristic class " - if self._name is not None: - desc += self._name + " " - desc += "of {} type ".format(self._class_type) - desc += "associated to {} on the {}".format(self._func, self._vbundle) - return desc - - def _latex_(self): - r""" - LaTeX representation of the object. - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: ch = TM.characteristic_class(exp(x), class_type='additive', - ....: name='ch', latex_name=r'\mathrm{ch}') - sage: ch._latex_() - '\\mathrm{ch}(TM)' - - """ - return self._latex_name + "(" + self._vbundle._latex_name + ")" - - def class_type(self): - r""" - Return the class type of ``self``. - - EXAMPLES:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: ch = TM.characteristic_class(exp(x), class_type='additive', - ....: name='ch', latex_name=r'\mathrm{ch}') - sage: ch.class_type() - 'additive' - - """ - return self._class_type - - def function(self): - r""" - Return the function corresponding to this characteristic class. - - EXAMPLES:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: e_class = TM.characteristic_class('Euler') - sage: e_class.function() - x - sage: AHat = TM.characteristic_class('AHat') - sage: AHat.function() - 1/2*sqrt(x)/sinh(1/2*sqrt(x)) - sage: c = TM.characteristic_class(1+x, name='c') - sage: c.function() - x + 1 - - """ - return self._func - - @cached_method - def sequence(self, ring=QQ): - r""" - Return the multiplicative/additive sequence (depending on the class - type of ``self``) of ``self.function`` in terms of elementary symmetric - functions `e_i`. - - If `f(x)` is the function with respect to ``self`` then its - multiplicative sequence is given by - - .. MATH:: - - \Pi_{i = 1}^n f(x_i) = \sum^n_{i=0} c_i \, e_i(x_1, \ldots, x_n) - - whereas its additive sequence is given by - - .. MATH:: - - \sum_{i = 1}^n f(x_i) = \sum^n_{i=0} c_i \, e_i(x_1, \ldots, x_n). - - Here, `e_i` denotes the `i`-th elementary symmetric function. - - INPUT: - - - ``ring`` -- (default: ``QQ``) the base ring of the symmetric - function ring; in most cases, one can assume ``QQ`` which is - supposed to work faster, if it doesn't work, try ``SR`` instead. - - OUTPUT: - - - a symmetric function in the elementary symmetric basis represented - by an instance of - :class:`~sage.combinat.sf.elementary.SymmetricFunctionAlgebra_elementary` - - EXAMPLES: - - Consider the multiplicative sequence of the `\hat{A}` class:: - - sage: M = Manifold(8, 'M') - sage: A = M.tangent_bundle().characteristic_class('AHat') - sage: A.sequence() - e[] - 1/24*e[1] + 7/5760*e[1, 1] - 1/1440*e[2] - - This is an element of the symmetric functions over the rational field:: - - sage: A.sequence().parent() - Symmetric Functions over Rational Field in the elementary basis - - To get the sequence as an element of usual polynomial ring, we can do - the following:: - - sage: P = PolynomialRing(QQ, 'e', 3) - sage: poly = P(sum(c * prod(P.gens()[i] for i in p) - ....: for p, c in A.sequence())) - sage: poly - 7/5760*e1^2 - 1/24*e1 - 1/1440*e2 + 1 - - Get an additive sequence:: - - sage: E = M.vector_bundle(2, 'E', field='complex') - sage: ch = E.characteristic_class('ChernChar') - sage: ch.sequence() - 2*e[] + e[1] + 1/2*e[1, 1] + 1/6*e[1, 1, 1] + 1/24*e[1, 1, 1, 1] - - e[2] - 1/2*e[2, 1] - 1/6*e[2, 1, 1] + 1/12*e[2, 2] + 1/2*e[3] - + 1/6*e[3, 1] - 1/6*e[4] - - .. SEEALSO:: - - See :class:`~sage.combinat.sf.elementary.SymmetricFunctionAlgebra_elementary` - for detailed information about elementary symmetric functions. - - """ - if self._class_type == 'Pfaffian': - return NotImplementedError('this functionality is not supported ' - 'for characteristic classes of ' - 'Pfaffian type') - - from sage.combinat.sf.sf import SymmetricFunctions - from sage.misc.misc_c import prod - - Sym = SymmetricFunctions(ring) - - coeff = self._get_coeff_list(distinct_real=False) - from sage.combinat.partition import Partitions - m = Sym.m() - if self._class_type == 'multiplicative': - # Get the multiplicative sequence in the monomial basis: - mon_pol = m._from_dict({p: prod(ring(coeff[i]) for i in p) - for k in range(len(coeff)) - for p in Partitions(k)}) - elif self._class_type == 'additive': - # Express the additive sequence in the monomial basis, the 0th - # order term must be treated separately: - - m_dict = {Partitions(0)([]): self._vbundle._rank * ring(coeff[0])} - m_dict.update({Partitions(k)([k]): ring(coeff[k]) for k in range(1, len(coeff))}) - mon_pol = m._from_dict(m_dict) - # Convert to elementary symmetric polynomials: - return Sym.e()(mon_pol) - - def get_form(self, connection, cmatrices=None): - r""" - Return the form representing ``self`` with respect to the given - connection ``connection``. - - INPUT: - - - ``connection`` -- connection to which the form should be associated to; - this can be either a bundle connection as an instance of - :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection` - or, in case of the tensor bundle, an affine connection as an instance - of :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection` - - ``cmatrices`` -- (default: ``None``) a dictionary of curvature - matrices with local frames as keys and curvature matrices as items; if - ``None``, Sage tries to get the curvature matrices from the connection - - OUTPUT: - - - mixed form as an instance of - :class:`~sage.manifolds.differentiable.mixed_form.MixedForm` - representing the total characteristic class - - .. NOTE:: - - Be aware that depending on the characteristic class and complexity - of the manifold, computation times may vary a lot. In addition, if - not done before, the curvature form is computed from the connection, - here. If this behaviour is not wanted and the curvature form is - already known, please use the argument ``cmatrices``. - - EXAMPLES: - - Again, consider the Chern character on some 2-dimensional spacetime:: - - sage: M = Manifold(2, 'M', structure='Lorentzian') - sage: X. = M.chart() - sage: E = M.vector_bundle(1, 'E', field='complex'); E - Differentiable complex vector bundle E -> M of rank 1 over the base - space 2-dimensional Lorentzian manifold M - sage: e = E.local_frame('e') - - And again, we define the connection `\nabla^E` in terms of an - electro-magnetic potential `A(t)`:: - - sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') - sage: omega = M.one_form(name='omega') - sage: A = function('A') - sage: nab.set_connection_form(0, 0)[1] = I*A(t) - sage: nab.set_immutable() - sage: nab[0, 0].display() - connection (0,0) of bundle connection nabla^E w.r.t. Local frame - (E|_M, (e_0)) = I*A(t) dx - - .. NOTE:: - - The characteristic form is strongly linked to the connection - which is why we must make the connection unchangeable, - i.e. immutable, with the command - :meth:`sage.manifolds.differentiable.bundle_connection.BundleConnection.set_immutable` - before we can use :meth:`get_form`. - - The Chern character is then given by:: - - sage: ch = E.characteristic_class('ChernChar'); ch - Characteristic class ch of additive type associated to e^x on the - Differentiable complex vector bundle E -> M of rank 1 over the base - space 2-dimensional Lorentzian manifold M - - Inserting the connection, the result is a mixed differential form with - a priori non-zero components in even degrees:: - - sage: ch_form = ch.get_form(nab); ch_form - Mixed differential form ch(E, nabla^E) on the 2-dimensional - Lorentzian manifold M - sage: ch_form.display() - ch(E, nabla^E) = ch_0(E, nabla^E) + zero + ch_1(E, nabla^E) - sage: ch_form.display_expansion() - ch(E, nabla^E) = 1 + 1/2*d(A)/dt/pi dt∧dx - - Due to long computation times, the form is saved:: - - sage: ch_form is ch.get_form(nab) - True - - """ - from .bundle_connection import BundleConnection - from .affine_connection import AffineConnection - if not isinstance(connection, (AffineConnection, BundleConnection)): - raise TypeError("argument must be an affine connection on the " - "manifold or bundle connection on the vector " - "bundle") - if connection not in self._mixed_forms: - base_space = self._base_space - if cmatrices is None: - if self._class_type == 'Pfaffian': - raise NotImplementedError( - "At this stage, Pfaffian forms cannot be derived from " - "(metric) connections. Please use the argument " - "'cmatrices' to insert a dictionary of skew-symmetric " - "curvature matrices by hand, instead.") - cmatrices = {} - for frame in base_space._get_min_covering(connection._coefficients): - cmatrix = [[connection.curvature_form(i, j, frame) - for j in self._vbundle.irange()] - for i in self._vbundle.irange()] - cmatrices[frame] = cmatrix - # Prepare mixed form: - name, latex_name = self._name, self._latex_name - if name is not None and connection._name is not None: - name += "(" + self._vbundle._name + ", " + connection._name + ")" - if latex_name is not None and connection._latex_name is not None: - latex_name += "(" + self._vbundle._latex_name + ", " + \ - connection._latex_name + ")" - res = base_space.mixed_form(name=name, latex_name=latex_name) - # BEGIN computation: - from sage.matrix.matrix_space import MatrixSpace - for frame, cmatrix in cmatrices.items(): - # Define matrix space: - dom = frame._domain - alg = dom.mixed_form_algebra() - mspace = MatrixSpace(alg, self._rank) - # Insert "normalized" curvature matrix into polynomial: - cmatrix = mspace(cmatrix) # convert curvature matrix - ncmatrix = self._normalize_matrix(cmatrix) - rmatrix = self._insert_in_polynomial(ncmatrix) - # Compute classes: - if self._class_type == 'additive': - rst = rmatrix.trace() # mixed form - elif self._class_type == 'multiplicative': - rst = rmatrix.det() # mixed form - elif self._class_type == 'Pfaffian': - rst = rmatrix.pfaffian() # mixed form - # Set restriction: - res.set_restriction(rst) - # END of computation - # - # Preparation to name each homogeneous component; only even (or in - # the real case, by four divisible) degrees are non-zero: - if self._class_type == 'Pfaffian': - deg_dist = self._rank - elif self._vbundle._field_type == 'real': - deg_dist = 4 - elif self._vbundle._field_type == 'complex': - deg_dist = 2 - else: - # You never know... - deg_dist = 1 - # Now, define the name for each form: - for k in res.irange(): - if k % deg_dist != 0 or (self._class_type == 'Pfaffian' and - k == 0): - res[k] = 0 # this form is zero anyway - else: - # String representation: - if self._name is not None: - name = self._name + "_" + str(k // deg_dist) + \ - "(" + self._vbundle._name - if connection._name is not None: - name += ", " + connection._name - name += ")" - # LaTeX name: - if self._latex_name is not None: - latex_name = self._latex_name + \ - r"_{" + str(k // deg_dist) + r"}" + \ - r"(" + self._vbundle._latex_name - if connection._latex_name is not None: - latex_name += r", " + connection._latex_name - latex_name += r")" - # Set name: - res[k].set_name(name=name, latex_name=latex_name) - # Add the result to the dictionary: - self._mixed_forms[connection] = res - - return self._mixed_forms[connection] - - def _insert_in_polynomial(self, cmatrix): - r""" - Return the matrix after inserting `cmatrix` into the polynomial given by - the taylor expansion of `self._func`. - - TESTS:: - - sage: M = Manifold(4, 'M') - sage: c = M.tangent_bundle().characteristic_class('Pontryagin') - sage: c._insert_in_polynomial(x) - 1/2*x^2 + 1 - - """ - mspace = cmatrix.parent() - # Compute matrix powers: - power_list = [mspace.one()] - for pow in range(len(self._coeff_list) - 1): - power_list.append(cmatrix * power_list[pow]) - # Put things together: - rmatrix = sum(self._coeff_list[k] * power_list[k] - for k in range(len(self._coeff_list))) - - return rmatrix - - def _normalize_matrix(self, cmatrix): - r""" - Return the curvature matrix "normalized" with `i/(2 \pi)` or `1/(2 \pi)` - respectively. - - INPUT: - - - ``cmatrix`` -- curvature matrix - - OUTPUT: - - - ``I/(2*pi)*cmatrix`` - - TESTS:: - - sage: M = Manifold(2, 'M') - sage: TM = M.tangent_bundle() - sage: c = TM.characteristic_class(1+x) - sage: c._normalize_matrix(x) - -1/2*I*x/pi - - """ - from sage.symbolic.constants import pi - fac = 1 / (2 * pi) - if self._class_type != 'Pfaffian': - from sage.symbolic.expression import I - fac = fac / I - return fac * cmatrix diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py new file mode 100644 index 00000000000..e5c80062844 --- /dev/null +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -0,0 +1,1843 @@ +r""" +Characteristic cohomology classes + +A *characteristic class* `\kappa` is a natural transformation that +associates with each vector bundle `E \to M` a cohomology class +`\kappa(E) \in H^*(M;R)` such that for any continuous map `f\colon N \to M` +from another topological manifold `N`, the *naturality condition* is +satisfied: + +.. MATH:: + + f^*\kappa(E) = \kappa(f^* E) \in H^*(N;R) + +The cohomology class `\kappa(E)` is called *characteristic cohomology class*. +Roughly speaking, characteristic cohomology classes measure the non-triviality +of vector bundles. + +One way to obtain and compute characteristic classes in the de Rham cohomology +with coefficients in the ring `\CC` is via the so-called *Chern-Weil theory* +using the curvature of a differentiable vector bundle. + +For that let `\nabla` be a connection on `E`, `e` a local frame on +`E` and `\Omega` be the corresponding curvature matrix +(see: :meth:`~sage.manifolds.differentiable.bundle_connection.BundleConnection.curvature_form`). + +Namely, if `P: \mathrm{Mat}_{n \times n}(\CC) \to \CC` is an invariant +polynomial, the object + +.. MATH:: + + \left[ P \left( \Omega \right) \right] \in H^{2*}_{\mathrm{dR}}(M, \CC) + +is well-defined, independent of the choice of `\nabla` (the proof can be +found in [Roe1988]_ pp. 31) and fulfills the naturality condition. +This is the foundation of the Chern-Weil theory and the following definitions. + +.. NOTE:: + + This documentation is rich of examples, but sparse in explanations. Please + consult the references for more details. + +AUTHORS: + +- Michael Jung (2019) : initial version +- Michael Jung (2021) : new algorithm; complete refactoring + +REFERENCES: + +- [Mil1974]_ +- [Roe1988]_ + +Contents +-------- + +We consider the following three types of classes: + +- :ref:`additive` +- :ref:`multiplicative` +- :ref:`Pfaffian` + +.. _additive: + +Additive Classes +---------------- + +In the **complex** case, let `f` be a holomorphic function around zero. Then +we call + +.. MATH:: + + \left[\mathrm{tr}\left( f\left( \frac{\Omega}{2 \pi i} \right) + \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) + +the *additive characteristic class associated to* `f` of the complex vector +bundle `E`. + +Important and predefined additive classes are: + +- *Chern Character* with `f(x) = \exp(x)` + +In the **real** case, let `g` be a holomorphic function around zero with +`g(0)=0`. Then we call + +.. MATH:: + + \left[\mathrm{tr}\left( \frac{1}{2} g\left( -\frac{\Omega^2}{4 \pi^2} + \right) \right)\right] \in H^{4*}_{\mathrm{dR}}(M, \CC) + +the *additive characteristic class associated to* `g` of the **real** vector +bundle `E`. + +EXAMPLES: + +Consider the **Chern character** on some 2-dimensional spacetime:: + + sage: M = Manifold(2, 'M', structure='Lorentzian') + sage: X. = M.chart() + sage: E = M.vector_bundle(1, 'E', field='complex'); E + Differentiable complex vector bundle E -> M of rank 1 over the base space + 2-dimensional Lorentzian manifold M + sage: e = E.local_frame('e') + +Let us define the connection `\nabla^E` in terms of an electro-magnetic +potential `A(t)`:: + + sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') + sage: omega = M.one_form(name='omega') + sage: A = function('A') + sage: nab.set_connection_form(0, 0)[1] = I*A(t) + sage: nab[0, 0].display() + connection (0,0) of bundle connection nabla^E w.r.t. Local frame + (E|_M, (e_0)) = I*A(t) dx + sage: nab.set_immutable() + +The Chern character is then given by:: + + sage: ch = E.characteristic_cohomology_class('ChernChar'); ch + Characteristic cohomology class ch(E) of the Differentiable complex vector + bundle E -> M of rank 1 over the base space 2-dimensional Lorentzian + manifold M + +The corresponding characteristic form w.r.t. the bundle connection can be +obtained via :meth:`get_form`:: + + sage: ch_form = ch.get_form(nab); ch_form.display_expansion() + ch(E, nabla^E) = 1 + 1/2*d(A)/dt/pi dt∧dx + +.. _multiplicative: + +Multiplicative Classes +---------------------- + +In the **complex** case, let `f` be a holomorphic function around zero. +Then we call + +.. MATH:: + + \left[\det\left( f\left( \frac{\Omega}{2 \pi i} \right) + \right)\right] \in H^{2*}_{\mathrm{dR}}(M, \CC) + +the *multiplicative characteristic class associated to* `f` of the complex +vector bundle `E`. + +Important and predefined multiplicative classes on complex vector bundles are: + +- *Chern class* with `f(x) = 1+x` +- *Todd class* with `f(x) = \frac{x}{1-\exp(-x)}` + +In the **real** case, let `g` be a holomorphic function around zero with +`g(0)=1`. Then we call + +.. MATH:: + + \left[\det\left( \sqrt{ g \left( -\frac{\Omega^2}{4 \pi^2} \right) } \right) + \right] \in H^{4*}_{\mathrm{dR}}(M, \CC) + +the *multiplicative characteristic class associated to* `g` on the **real** +vector bundle `E`. + +Important and predefined multiplicative classes on real vector bundles are: + +- *Pontryagin class* with `g(x) = 1+x` +- `\hat{A}` *class* with `g(x) = \frac{\sqrt{x}/2}{\sinh(\sqrt{x}/2)}` +- *Hirzebruch class* with `g(x) = \frac{\sqrt{x}}{\tanh(\sqrt{x})}` + +EXAMPLES: + +We consider the **Chern class** of the tautological line bundle `\gamma^1` over +`\CC\mathbf{P}^1`:: + + sage: M = Manifold(2, 'CP^1', start_index=1) + sage: U = M.open_subset('U') + sage: c_cart. = U.chart() # homogeneous coordinates in real terms + sage: c_comp. = U.chart(r'z:z zbar:\bar{z}') # complexification + sage: cart_to_comp = c_cart.transition_map(c_comp, (x+I*y, x-I*y)) + sage: comp_to_cart = cart_to_comp.inverse() + sage: E = M.vector_bundle(1, 'gamma^1', field='complex') + sage: e = E.local_frame('e', domain=U) + +To apply the Chern-Weil approach, we need a bundle connection in terms of a +connection one form. To achieve this, we take the connection induced from the +hermitian metric on the trivial bundle +`\CC^2 \times \CC\mathbf{P}^1 \supset \gamma^1`. In this the frame `e` +corresponds to the section `[z:1] \mapsto (z,1)` and its magnitude-squared +is given by `1+|z|^2`:: + + sage: nab = E.bundle_connection('nabla') + sage: omega = U.one_form(name='omega') + sage: omega[c_comp.frame(),1,c_comp] = zbar/(1+z*zbar) + sage: nab[e, 1, 1] = omega + sage: nab.set_immutable() + +Now, the Chern class can be constructed:: + + sage: c = E.characteristic_cohomology_class('Chern'); c + Characteristic cohomology class c(gamma^1) of the Differentiable complex + vector bundle gamma^1 -> CP^1 of rank 1 over the base space 2-dimensional + differentiable manifold CP^1 + sage: c_form = c.get_form(nab) + sage: c_form.display_expansion(c_comp.frame(), chart=c_comp) + c(gamma^1, nabla) = 1 + 1/2*I/(pi + pi*z^2*zbar^2 + 2*pi*z*zbar) dz∧dzbar + +Since `U` and `\CC\mathbf{P}^1` differ only by a point and therefore a null +set, it is enough to integrate the top form over the domain `U`:: + + sage: integrate(integrate(c_form[2][[1,2]].expr(c_cart), x, -infinity, infinity).full_simplify(), + ....: y, -infinity, infinity) + 1 + +The result shows that `c_1(\gamma^1)` generates the second integer +cohomology of `\CC\mathbf{P}^1`. + +.. _Pfaffian: + +Pfaffian Classes +---------------- + +Usually, there is no such thing as "Pfaffian classes" in literature. However, +using the matrix' Pfaffian and inspired by the aforementioned definitions, +such classes can be defined as follows. + +Let `E` be a real vector bundle of rank `2n` and `f` an odd real function +being analytic at zero. Furthermore, let `\Omega` be skew-symmetric, which +certainly will be true if `\nabla` is metric and `e` is orthonormal. Then +we call + +.. MATH:: + + \left[\mathrm{Pf}\left( f\left( \frac{\Omega}{2 \pi} \right) \right)\right] + \in H^{2n*}(M,\RR) + +the *Pfaffian class associated to f*. + +The most important Pfaffian class is the *Euler class* which is simply given by +`f(x)=x`. + +EXAMPLES: + +We consider the **Euler class** of `S^2`:: + + sage: M. = manifolds.Sphere(2, coordinates='stereographic') + sage: TM = M.tangent_bundle() + sage: e_class = TM.characteristic_cohomology_class('Euler'); e_class + Characteristic cohomology class e(TS^2) of the Tangent bundle TS^2 over the + 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3 + +To compute a particular representative of the Euler class, we need to determine +a connection, which is in this case given by the standard metric:: + + sage: g = M.metric('g') # standard metric on S2 + sage: nab = g.connection() + sage: nab.set_immutable() + +Now the representative of the Euler class with respect to the connection +`\nabla_g` induced by the standard metric can be computed:: + + sage: e_class_form = e_class.get_form(nab) + sage: e_class_form.display_expansion() + e(TS^2, nabla_g) = 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy + +Let us check whether this form represents the Euler class correctly:: + + sage: integrate(integrate(e_class_form[2][[1,2]].expr(), x, -infinity, infinity).simplify_full(), + ....: y, -infinity, infinity) + 2 + +As we can see, the integral coincides with the Euler characteristic of `S^2` so +that our form actually represents the Euler class appropriately. + +""" + +#****************************************************************************** +# Copyright (C) 2021 Michael Jung +# +# Distributed under the terms of the GNU General Public License (GPL) +# 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 sage.algebras.finite_gca import FiniteGCAlgebra +from sage.combinat.free_module import IndexedFreeModuleElement +from sage.misc.fast_methods import Singleton +from sage.structure.sage_object import SageObject +from sage.misc.cachefunc import cached_method +from sage.misc.abstract_method import abstract_method +from .affine_connection import AffineConnection +from .bundle_connection import BundleConnection +from .levi_civita_connection import LeviCivitaConnection +from sage.symbolic.expression import Expression +from sage.rings.polynomial.polynomial_element import is_Polynomial +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + + +class CharacteristicCohomologyClassRingElement(IndexedFreeModuleElement): + r""" + Characteristic cohomology class. + + Let `E \to M` be a real/complex vector bundle of rank `k`. A characteristic + cohomology class of `E` is generated by either + + - Chern classes if `E` is complex, + - Pontryagin classes if `E` is real, + - Pontryagin classes and the Euler class if `E` is real and orientable, + + via the Chern-Weil homomorphism. + + For details about the ring structure, see + :class:`CharacteristicCohomologyClassRing`. + + To construct a characteristic cohomology class, please use + :func:`CharacteristicCohomologyClass`. + + EXAMPLES:: + + sage: M = Manifold(12, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring() + sage: p1, p2, p3 = CR.gens() + sage: p1*p2+p3 + Characteristic cohomology class (p_1⌣p_2 + p_3)(TM) of the Tangent + bundle TM over the 12-dimensional differentiable manifold M + sage: A = TM.characteristic_cohomology_class('AHat'); A + Characteristic cohomology class A^(TM) of the Tangent bundle TM over + the 12-dimensional differentiable manifold M + sage: A == 1 - p1/24 + (7*p1^2-4*p2)/5760 + (44*p1*p2-31*p1^3-16*p3)/967680 + True + """ + def __init__(self, parent, x, name=None, latex_name=None): + r""" + Construct a characteristic cohomology class. + + TESTS:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: TestSuite(p).run() + """ + self._name = name + if latex_name is None: + self._latex_name = self._name + else: + self._latex_name = latex_name + self._mixed_forms = {} # dict. of characteristic forms of `self` + # (key: bundle connection) + super().__init__(parent, x) + + def _repr_(self): + r""" + String representation of the object. + + TESTS:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: p._repr_() + 'Characteristic cohomology class p(TM) of the Tangent bundle TM + over the 8-dimensional differentiable manifold M' + sage: p # indirect doctest + Characteristic cohomology class p(TM) of the Tangent bundle TM over + the 8-dimensional differentiable manifold M + + :: + + sage: x = var('x') + sage: k = TM.characteristic_cohomology_class(1+x^2, class_type='multiplicative') + sage: k._repr_() + 'Characteristic cohomology class (1 + p_1^2 - 2*p_2)(TM) of the + Tangent bundle TM over the 8-dimensional differentiable manifold M' + sage: k # indirect doctest + Characteristic cohomology class (1 + p_1^2 - 2*p_2)(TM) of the + Tangent bundle TM over the 8-dimensional differentiable manifold M + """ + if self._name is None: + name = f'({super()._repr_()})' + else: + name = self._name + vbundle = self.parent()._vbundle + name = f'{name}({vbundle._name})' + return f'Characteristic cohomology class {name} of the {vbundle}' + + def _latex_(self): + r""" + LaTeX representation of the object. + + TESTS:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: p._latex_() + 'p\\left(TM\\right)' + sage: latex(p) # indirect doctest + p\left(TM\right) + + :: + + sage: x = var('x') + sage: k = TM.characteristic_cohomology_class(1+x^2, class_type='multiplicative') + sage: k._latex_() + '\\left(1 + p_1^{2} - 2p_2\\right)\\left(TM\\right)' + sage: latex(k) + \left(1 + p_1^{2} - 2p_2\right)\left(TM\right) + """ + if self._latex_name is None: + latex = r'\left(' + super()._latex_() + r'\right)' + else: + latex = self._latex_name + vbundle = self.parent()._vbundle + latex += r'\left(' + vbundle._latex_name + r'\right)' + return latex + + def get_form(self, nab): + r""" + Return the characteristic form of ``self``. + + INPUT: + + - ``nab`` -- get the characteristic form w.r.t. to the + connection ``nab`` + + OUTPUT: + + - an instance of + :class:`sage.manifolds.differentiable.mixed_form.MixedForm` + + EXAMPLES: + + Trivial characteristic form on Euclidean space:: + + sage: M = manifolds.EuclideanSpace(4) + sage: TM = M.tangent_bundle() + sage: one = TM.characteristic_cohomology_class_ring().one() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + sage: one.get_form(nab) + Mixed differential form one on the 4-dimensional Euclidean space E^4 + + Pontryagin form on the 4-sphere:: + + sage: M = manifolds.Sphere(4) + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin'); p + Characteristic cohomology class p(TS^4) of the Tangent bundle TS^4 + over the 4-sphere S^4 of radius 1 smoothly embedded in the + 5-dimensional Euclidean space E^5 + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + sage: p_form = p.get_form(nab); p_form + Mixed differential form p(TS^4, nabla_g) on the 4-sphere S^4 of + radius 1 smoothly embedded in the 5-dimensional Euclidean space E^5 + sage: p_form.display_expansion() + p(TS^4, nabla_g) = 1 + """ + if nab not in self._mixed_forms: + dom = nab._domain + A = dom.mixed_form_algebra() + + # trivial cases + if self == 1: + self._mixed_forms[nab] = A(dom._one_scalar_field) + elif self == 0: + self._mixed_forms[nab] = A(dom._zero_scalar_field) + else: # non-trivial case + from functools import reduce + + parent = self.parent() + algorithm = parent._algorithm + + grading = parent.print_options()['sorting_key'] + res = [dom.diff_form_module(i).zero() + for i in range(dom._dim + 1)] + for ind, c in self: + deg = grading(ind) + gen_pow = [algorithm.get_gen_pow(nab, i, ind[i]) + for i in range(len(ind))] + res[deg] += c * reduce(lambda x, y: x.wedge(y), gen_pow) + + res = A(res) # convert result into mixed form + + # preparse names + vbundle = parent._vbundle + if self._name is None: + name = f'({super()._repr_()})' + else: + name = self._name + if self._latex_name is None: + latex_name = r'\left(' + super()._latex_() + r'\right)' + else: + latex_name = self._latex_name + # appendix + append_name = f'({vbundle._name}, {nab._name})' + append_latex_name = r'\left(' + vbundle._latex_name + append_latex_name += ', ' + nab._latex_name + r'\right)' + + # set names of components + from sage.arith.misc import gcd + + step = gcd(parent._degrees) # step size of (possibly) non-zero + for i in range(dom._dim // step + 1): + # enumerate (possibly) non-zero components + comp_name = name + f'_{i}' + append_name + comp_latex_name = latex_name + r'_{' + str(i) + '}' + comp_latex_name += append_latex_name + res[step * i].set_name(name=comp_name, + latex_name=comp_latex_name) + + # set global names + res._name = name + append_name + res._latex_name = latex_name + append_latex_name + + res.set_immutable() + + self._mixed_forms[nab] = res # cache result in dict + + return self._mixed_forms[nab] + + def representative(self, nab=None): + r""" + Return any representative of ``self``. + + INPUT: + + - ``nab`` -- (default: ``None``) if stated, return the representative + w.r.t. to the connection ``nab``; otherwise an arbitrary already + computed representative will be chosen. + + OUTPUT: + + - an instance of + :class:`sage.manifolds.differentiable.mixed_form.MixedForm` + + EXAMPLES: + + Define the 4-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(4) + sage: TM = M.tangent_bundle() + sage: one = TM.characteristic_cohomology_class_ring().one() + + No characteristic form has been computed so far, thus we get an error:: + + sage: one.representative() + Traceback (most recent call last): + ... + AttributeError: cannot pick a representative + + Get a characteristic form:: + + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + sage: one.get_form(nab) + Mixed differential form one on the 4-dimensional Euclidean space E^4 + + Now, the result is cached and `representative` returns a form:: + + sage: one.representative() + Mixed differential form one on the 4-dimensional Euclidean space E^4 + + Alternatively, the option ``nab`` can be used to return the + characteristic form w.r.t. a fixed connection:: + + sage: one.representative(nab) + Mixed differential form one on the 4-dimensional Euclidean space E^4 + + .. SEEALSO:: + + :meth:`CharacteristicCohomologyClassRingElement.get_form` + """ + if nab is None: + if not self._mixed_forms: + raise AttributeError('cannot pick a representative') + return next(iter(self._mixed_forms.values())) + return self.get_form(nab) + + def set_name(self, name=None, latex_name=None): + r""" + Set (or change) the text name and LaTeX name of the characteristic + class. + + INPUT: + + - ``name`` -- (string; default: ``None``) name given to the + characteristic cohomology class + - ``latex_name`` -- (string; default: ``None``) LaTeX symbol to denote + the characteristic cohomology class; if ``None`` while ``name`` is + provided, the LaTeX symbol is set to ``name`` + + EXAMPLES:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: x = var('x') + sage: k = TM.characteristic_cohomology_class(1+x^2, + ....: class_type='multiplicative'); k + Characteristic cohomology class (1 + p_1^2 - 2*p_2)(TM) of the + Tangent bundle TM over the 8-dimensional differentiable manifold M + sage: k.set_name(name='k', latex_name=r'\kappa') + sage: k + Characteristic cohomology class k(TM) of the Tangent bundle TM over + the 8-dimensional differentiable manifold M + sage: latex(k) + \kappa\left(TM\right) + """ + if name is not None: + self._name = name + if latex_name is None: + self._latex_name = self._name + if latex_name is not None: + self._latex_name = latex_name + + +class CharacteristicCohomologyClassRing(FiniteGCAlgebra): + r""" + Characteristic cohomology class ring. + + Let `E \to M` be a real or complex vector bundle of rank `k` and `R` be a + torsion-free subring of `\CC`. + + Let `BG` be the classifying space of the group `G`. As for vector bundles, + we consider + + - `G = O(k)` if `E` is real, + - `G = SO(k)` if `E` is real and oriented, + - `G = U(k)` if `E` is complex. + + The cohomology ring `H^*(BG; R)` can be explicitly expressed for the + aforementioned cases: + + .. MATH:: + + H^*(BG; R) \cong \begin{cases} + R[c_1, \ldots c_k] & \text{if } G = U(k), \\ + R[p_1, \ldots p_{\lfloor \frac{k}{2}\rfloor}] & \text{if } G = O(k), \\ + R[p_1, \ldots p_k, e] \big/ (p_k-e^2) & \text{if } G = SO(2k), \\ + R[p_1, \ldots p_k, e] & \text{if } G = SO(2k+1). \\ + \end{cases} + + The Chern-Weil homomorphism relates the generators in the de Rham + cohomology as follows. If `\Omega` is a curvature form matrix on `E`, for + the Chern classes we get + + .. MATH:: + + \left[ \det\left( 1 + \frac{t \Omega}{2 \pi i} \right) \right] = 1 + + \sum^k_{n=1} c_n(E) t^n, + + for the Pontryagin classes we have + + .. MATH:: + + \left[ \det\left( 1 - \frac{t \Omega}{2 \pi} \right) \right] = 1 + + \sum^{\lfloor\frac{k}{2} \rfloor}_{n=1} p_n(E) t^n, + + and for the Euler class we obtain + + .. MATH:: + + \left[ \mathrm{Pf}\left(\frac{\Omega}{2 \pi} \right) \right] = e(E). + + Consequently, the cohomology ring `H^*(BG; R)` is mapped (not + necessarily injectively) to a subring of `H^*_\mathrm{dR}(M, \CC)` via + the Chern-Weil homomorphism. This implementation attempts to represent this + subring. + + .. NOTE:: + + Some generators might have torsion in `H^*(BG; R)` giving a zero + element in the de Rham cohomology. Those generators are still + considered in the implementation. Generators whose degree exceed the + dimension of the base space, however, are ignored. + + INPUT: + + - ``base`` -- base ring + - ``vbundle`` -- vector bundle + + EXAMPLES: + + Characteristic cohomology class ring over the tangent bundle of an + 8-dimensional manifold:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring(); CR + Algebra of characteristic cohomology classes of the Tangent bundle TM + over the 8-dimensional differentiable manifold M + sage: CR.gens() + [Characteristic cohomology class (p_1)(TM) of the Tangent bundle TM over + the 8-dimensional differentiable manifold M, + Characteristic cohomology class (p_2)(TM) of the Tangent bundle TM + over the 8-dimensional differentiable manifold M] + + The default base ring is `\QQ`:: + + sage: CR.base_ring() + Rational Field + + Characteristic cohomology class ring over a complex vector bundle:: + + sage: M = Manifold(4, 'M') + sage: E = M.vector_bundle(2, 'E', field='complex') + sage: CR_E = E.characteristic_cohomology_class_ring(); CR_E + Algebra of characteristic cohomology classes of the Differentiable + complex vector bundle E -> M of rank 2 over the base space + 4-dimensional differentiable manifold M + sage: CR_E.gens() + [Characteristic cohomology class (c_1)(E) of the Differentiable complex + vector bundle E -> M of rank 2 over the base space 4-dimensional + differentiable manifold M, + Characteristic cohomology class (c_2)(E) of the Differentiable + complex vector bundle E -> M of rank 2 over the base space + 4-dimensional differentiable manifold M] + + Characteristic cohomology class ring over an oriented manifold:: + + sage: S2 = manifolds.Sphere(2, coordinates='stereographic') + sage: TS2 = S2.tangent_bundle() + sage: S2.has_orientation() + True + sage: CR = TS2.characteristic_cohomology_class_ring() + sage: CR.gens() + [Characteristic cohomology class (e)(TS^2) of the Tangent bundle TS^2 + over the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean + space E^3] + """ + Element = CharacteristicCohomologyClassRingElement + + def __init__(self, base, vbundle): + r""" + Construct a characteristic cohomology ring. + + TESTS:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring() + sage: TestSuite(CR).run() + """ + self._vbundle = vbundle + self._domain = vbundle._base_space + dim = self._domain._dim + rk = vbundle._rank + if vbundle._field_type == 'complex': + ran = min(rk, dim // 2) + names = [f'c_{i}' for i in range(1, ran + 1)] + degrees = [2 * i for i in range(1, ran + 1)] + self._algorithm = ChernAlgorithm() + elif vbundle._field_type == 'real': + ran = min(rk // 2, dim // 4) + names = [f'p_{i}' for i in range(1, ran + 1)] + degrees = [4 * i for i in range(1, ran + 1)] + self._algorithm = PontryaginAlgorithm() + if vbundle.has_orientation(): + # add Euler class generator + # Euler should be first entry; see `PontryaginEulerAlgorithm` + names = ['e'] + names + degrees = [rk] + degrees + self._algorithm = PontryaginEulerAlgorithm() + # TODO: add relation e^2=p_k for dim=2*k + else: + raise TypeError(f'Characteristic cohomology classes not supported ' + f'for vector bundles with ' + f'field type {vbundle._field_type}') + + if not names or not degrees: + raise ValueError('cannot find any generators') + + names = tuple(names) # hashable + degrees = tuple(degrees) # hashable + super().__init__(base=base, names=names, degrees=degrees, + max_degree=dim, mul_symbol='⌣', + mul_latex_symbol=r'\smile') + + def _element_constructor_(self, x, **kwargs): + r""" + Convert ``x`` into ``self``. + + TESTS:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring() + sage: p = CR('Pontryagin'); p + Characteristic cohomology class p(TM) of the Tangent bundle TM over + the 8-dimensional differentiable manifold M + sage: CR(p, name='pontr') + Characteristic cohomology class pontr(TM) of the Tangent bundle + TM over the 8-dimensional differentiable manifold M + """ + if isinstance(x, (str, Expression)) or is_Polynomial(x): + return self._build_element(x, **kwargs) + + R = self.base_ring() + + if x in R: + one_basis = self.one_basis() + d = {one_basis: R(x)} + elif isinstance(x, CharacteristicCohomologyClassRingElement): + d = x._monomial_coefficients + # x is an element of the basis enumerated set; + # This is a very ugly way of testing this + elif ((hasattr(self._indices, 'element_class') and + isinstance(self._indices.element_class, type) and + isinstance(x, self._indices.element_class)) or + self.parent()(x) == self._indices): + d = {x: R.one()} + elif x in self._indices: + d = {self._indices(x): R.one()} + else: + raise TypeError(f"do not know how to make x (= {x}) " + f"an element of self (={self})") + name, latex_name = kwargs.get('name'), kwargs.get('latex_name') + return self.element_class(self, d, name=name, latex_name=latex_name) + + @cached_method + def _build_element(self, *args, **kwargs): + r""" + Construct a characteristic cohomology class. + + The result is cached. + + INPUT: + + - ``val`` -- the input data corresponding to the characteristic class + using the Chern-Weil homomorphism; this argument can be either a + symbolic expression, a polynomial or one of the following predefined + classes: + + - ``'Chern'`` -- total Chern class, + - ``'ChernChar'`` -- Chern character, + - ``'Todd'`` -- Todd class, + - ``'Pontryagin'`` -- total Pontryagin class, + - ``'Hirzebruch'`` -- Hirzebruch class, + - ``'AHat'`` -- `\hat{A}` class, + - ``'Euler'`` -- Euler class. + + - ``name`` -- (default: ``None``) string representation given to the + characteristic class; if ``None`` the default algebra representation or + predefined name is used + - ``latex_name`` -- (default: ``None``) LaTeX name given to the + characteristic class; if ``None`` the value of ``name`` is used + - ``class_type`` -- (default: ``None``) class type of the characteristic + cohomology class; the following options are possible: + + - ``'multiplicative'`` -- returns a class of multiplicative type + - ``'additive'`` -- returns a class of additive type + - ``'Pfaffian'`` -- returns a class of Pfaffian type + + This argument must be stated if ``val`` is a polynomial or symbolic + expression. + + EXAMPLES: + + Total Pontryagin class of an 8-dimensional manifold:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: p = TM.characteristic_cohomology_class('Pontryagin'); p + Characteristic cohomology class p(TM) of the Tangent bundle TM over the + 8-dimensional differentiable manifold M + + Define a multiplicative class (see :func:`multiplicative_sequence`):: + + sage: P. = PolynomialRing(QQ) + sage: f = 1 + x - x^2 + sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class + Characteristic cohomology class (1 + p_1 - p_1^2 + 3*p_2)(TM) of the + Tangent bundle TM over the 8-dimensional differentiable manifold M + + Pass a symbolic expression, whose Taylor expansion at zero will be used:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: x = var('x') + sage: f = cos(x) + sage: f_class = TM.characteristic_cohomology_class(f, class_type='multiplicative'); f_class + Characteristic cohomology class (1 - 1/2*p_1^2 + p_2)(TM) of the Tangent + bundle TM over the 8-dimensional differentiable manifold M + """ + name, latex_name = kwargs.get('name'), kwargs.get('latex_name') + base_ring = self.base_ring() + class_type = kwargs.get('class_type') + vbundle = self._vbundle + val = args[0] + dim = vbundle._base_space._dim + + # predefined classes accessible via class names + if isinstance(val, str): + from sage.arith.misc import factorial, bernoulli + + P = PolynomialRing(base_ring, 'x') + x = P.gen() + if val == 'Chern': + if vbundle._field_type != 'complex': + raise ValueError(f'total Chern class not defined on {vbundle}') + if name is None: + name = 'c' + class_type = 'multiplicative' + val = 1 + x + if val == 'Pontryagin': + if vbundle._field_type != 'real': + raise ValueError(f'total Pontryagin class not defined on {vbundle}') + if name is None: + name = 'p' + class_type = 'multiplicative' + val = 1 + x + elif val == 'ChernChar': + if vbundle._field_type != 'complex': + raise ValueError(f'Chern character not defined on {vbundle}') + if name is None: + name = 'ch' + if latex_name is None: + latex_name = r'\mathrm{ch}' + class_type = 'additive' + coeff = [1 / factorial(k) for k in + range(dim // 2 + 1)] # exp(x) + val = P(coeff) + elif val == 'Todd': + if vbundle._field_type != 'complex': + raise ValueError(f'Todd class not defined on {vbundle}') + if name is None: + name = 'Td' + if latex_name is None: + latex_name = r'\mathrm{Td}' + class_type = 'multiplicative' + val = 1 + x / 2 + for k in range(1, dim // 2 + 1): + val += (-1) ** (k + 1) / factorial(2 * k) * bernoulli( + 2 * k) * x ** (2 * k) + elif val == 'Hirzebruch': + if vbundle._field_type != 'real': + raise ValueError(f'Hirzebruch class not defined on {vbundle}') + if name is None: + name = 'L' + if latex_name is None: + latex_name = 'L' + class_type = 'multiplicative' + coeff = [2 ** (2 * k) * bernoulli(2 * k) / factorial(2 * k) + for k in range(dim // 4 + 1)] + val = P(coeff) + elif val == 'AHat': + if vbundle._field_type != 'real': + raise ValueError(f'AHat class not defined on {vbundle}') + if name is None: + name = 'A^' + if latex_name is None: + latex_name = r'\hat{A}' + class_type = 'multiplicative' + coeff = [- (2 ** (2 * k) - 2) / 2 ** (2 * k) * bernoulli( + 2 * k) / factorial(2 * k) + for k in range(dim // 4 + 1)] + val = P(coeff) + elif val == 'Euler': + if vbundle._field_type != 'real' or not vbundle.has_orientation(): + raise ValueError(f'Euler class not defined on {vbundle}') + if name is None: + name = 'e' + class_type = 'Pfaffian' + val = x + else: + ValueError(f'predefined class "{val}" unknown') + + # turn symbolic expression into a polynomial via Taylor expansion + if isinstance(val, Expression): + x = val.default_variable() + P = PolynomialRing(base_ring, x) + + if vbundle._field_type == 'real': + pow_range = dim // 4 + elif vbundle._field_type == 'complex': + pow_range = dim // 2 + else: + ValueError(f'field type of {vbundle} must be real or complex') + + val = P(val.taylor(x, 0, pow_range)) + + # turn polynomial into a characteristic cohomology class via sequences + if is_Polynomial(val): + if class_type is None: + raise TypeError(f'class_type must be stated if {val} ' + f'is a polynomial') + n = self.ngens() + s = 0 # shift; important in case of Euler class generator + if self._algorithm is PontryaginEulerAlgorithm(): + s = 1 # skip Euler class + n -= 1 # ignore Euler class + + if class_type == 'additive': + sym = additive_sequence(val, vbundle._rank, n) + elif class_type == 'multiplicative': + sym = multiplicative_sequence(val, n) + elif class_type == 'Pfaffian': + P = val.parent() + x = P.gen() + val = (val(x) - val(-x)) / 2 # project to odd functions + val = P([(-1) ** k * val[2 * k + 1] for k in range(n + 1)]) + sym = multiplicative_sequence(val, n) + else: + AttributeError('unkown class type') + + d = {} + w_vec = self._weighted_vectors + for p, c in sym: + vec = [0] * self.ngens() + if class_type == 'Pfaffian': + vec[0] = 1 # always multiply with e + for i in p: + vec[i - 1 + s] += 1 + key = w_vec(vec) + d[key] = c + res = self._from_dict(d) + res.set_name(name=name, latex_name=latex_name) + return res + + # Nothing worked? Then something went wrong! + raise ValueError(f'cannot convert {val} into an element of {self}') + + def _repr_(self): + r""" + String representation of the object. + + TESTS:: + + sage: M = Manifold(8, 'M') + sage: TM = M.tangent_bundle() + sage: CR = TM.characteristic_cohomology_class_ring() + sage: CR._repr_() + 'Algebra of characteristic cohomology classes of the Tangent bundle + TM over the 8-dimensional differentiable manifold M' + sage: CR # indirect doctest + Algebra of characteristic cohomology classes of the Tangent bundle + TM over the 8-dimensional differentiable manifold M + """ + vbundle = self._vbundle + repr = f'Algebra of characteristic cohomology classes of the {vbundle}' + return repr + +# ***************************************************************************** +# ALGORITHMS +# ***************************************************************************** + +def multiplicative_sequence(q, n=None): + r""" + Turn the polynomial ``q`` into its multiplicative sequence. + + Let `q` be a polynomial and `x_1, \ldots x_n` indeterminates. The + *multiplicative sequence of* `q` is then given by the polynomials `K_j` + + .. MATH:: + + \sum_{j=0}^n K_j(\sigma_1, \ldots, \sigma_j) z^j = + \prod_{i=1}^{n} q(z \,x_i), + + where `\sigma_i` is the `i`-th elementary symmetric polynomial in the + indeterminates `x_i`. + + INPUT: + + - ``q`` -- polynomial to turn into its multiplicative sequence. + - ``n`` -- (default: ``None``) the highest order `n` of the sequence; + if ``None``, the order of ``q`` is assumed. + + OUTPUT: + + - A symmetric polynomial representing the multiplicative sequence. + + EXAMPLES:: + + sage: P. = PolynomialRing(QQ) + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import multiplicative_sequence + sage: f = 1 + x - x^2 + sage: sym = multiplicative_sequence(f); sym + e[] + e[1] - e[1, 1] + 3*e[2] + + The maximal order of the result can be stated with ``n``:: + + sage: sym_5 = multiplicative_sequence(f, n=5); sym_5 + e[] + e[1] - e[1, 1] + 3*e[2] - e[2, 1] + e[2, 2] + 4*e[3] - 3*e[3, 1] + + e[3, 2] + 7*e[4] - 4*e[4, 1] + 11*e[5] + """ + from sage.combinat.sf.sf import SymmetricFunctions + from sage.combinat.partition import Partitions + from sage.misc.misc_c import prod + + if n is None: + n = q.degree() + + R = q.parent().base_ring() + Sym = SymmetricFunctions(R) + m = Sym.m() + + # Get the multiplicative sequence in the monomial basis: + mon_pol = m._from_dict({p: prod(q[i] for i in p) + for k in range(n + 1) + for p in Partitions(k)}) + return Sym.e()(mon_pol) + +def additive_sequence(q, k, n=None): + r""" + Turn the polynomial ``q`` into its additive sequence. + + Let `q` be a polynomial and `x_1, \ldots x_n` indeterminates. The + *additive sequence of* `q` is then given by the polynomials `Q_j` + + .. MATH:: + + \sum_{j=0}^n Q_j(\sigma_1, \ldots, \sigma_j) z^j = + \sum_{i=1}^{k} q(z \,x_i), + + where `\sigma_i` is the `i`-th elementary symmetric polynomial in the + indeterminates `x_i`. + + INPUT: + + - ``q`` -- polynomial to turn into its additive sequence. + - ``k`` -- maximal index `k` of the sum + - ``n`` -- (default: ``None``) the highest order of the sequence `n`; + if ``None``, the order of ``q`` is assumed. + + OUTPUT: + + - A symmetric polynomial representing the additive sequence. + + EXAMPLES:: + + sage: P. = PolynomialRing(QQ) + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import additive_sequence + sage: f = 1 + x - x^2 + sage: sym = additive_sequence(f, 2); sym + 2*e[] + e[1] - e[1, 1] + 2*e[2] + + The maximal order of the result can be stated with ``n``:: + + sage: sym_1 = additive_sequence(f, 2, 1); sym_1 + 2*e[] + e[1] + """ + from sage.combinat.sf.sf import SymmetricFunctions + from sage.combinat.partition import Partitions + + if n is None: + n = q.degree() + + R = q.parent().base_ring() + Sym = SymmetricFunctions(R) + m = Sym.m() + + # Express the additive sequence in the monomial basis, the 0-th + # order term must be treated separately; here comes ``rk`` into play: + m_dict = {Partitions(0)([]): k * q[0]} + m_dict.update({Partitions(k)([k]): q[k] for k in range(1, n + 1)}) + mon_pol = m._from_dict(m_dict) + return Sym.e()(mon_pol) + + +def fast_wedge_power(form, n): + r""" + Return the wedge product power of `form` using a square-and-wedge + algorithm. + + INPUT: + + - ``form`` -- a differential form + - ``n`` -- a non-negative integer + + EXAMPLES:: + + sage: M = Manifold(4, 'M') + sage: X. = M.chart() + sage: omega = M.diff_form(2, name='omega') + sage: omega[0,1] = t*y^2 + 2*x + sage: omega[0,3] = z - 2*y + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import fast_wedge_power + sage: fast_wedge_power(omega, 0) + Scalar field 1 on the 4-dimensional differentiable manifold M + sage: fast_wedge_power(omega, 1) + 2-form omega on the 4-dimensional differentiable manifold M + sage: fast_wedge_power(omega, 2) + 4-form omega∧omega on the 4-dimensional differentiable manifold M + """ + if n == 0: + return form._domain._one_scalar_field + elif n < 0: + raise ValueError("'n' must be non-negative") + val = form + while not (n & 1): + val = val.wedge(val) + n >>= 1 + + # Now multiply together the correct factors form^(2^i) + res = val + n >>= 1 + while n: + val = val.wedge(val) + if n & 1: + res = val.wedge(res) + n >>= 1 + + return res + + +class Algorithm_generic(SageObject): + r""" + Abstract algorithm class to compute the characteristic forms of the + generators. + + EXAMPLES:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import Algorithm_generic + sage: algorithm = Algorithm_generic() + sage: algorithm.get + Cached version of + sage: algorithm.get_local + Traceback (most recent call last): + ... + NotImplementedError: + sage: algorithm.get_gen_pow + Cached version of + """ + @cached_method + def get(self, nab): + r""" + Return the global characteristic forms of the generators w.r.t. a given + connection. + + The result is cached. + + OUTPUT: + + - a list containing the generator's global characteristic forms as + instances of + :class:`sage.manifolds.differentiable.diff_form.DiffForm` + + EXAMPLES:: + + sage: M = manifolds.EuclideanSpace(4) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + :: + + sage: p = TM.characteristic_cohomology_class('Pontryagin') + sage: p_form = p.get_form(nab); p_form + Mixed differential form p(TE^4, nabla_g) on the 4-dimensional + Euclidean space E^4 + sage: p_form.display_expansion() + p(TE^4, nabla_g) = 1 + """ + if isinstance(nab, AffineConnection): + vbundle = nab._domain.tangent_bundle() + elif isinstance(nab, BundleConnection): + vbundle = nab._vbundle + else: + raise TypeError(f'{nab} must be a connection') + dom = nab._domain + res = [] # will be specified within first iteration + for frame in dom._get_min_covering(nab._coefficients): + cmat = [[nab.curvature_form(i, j, frame) for j in vbundle.irange()] + for i in vbundle.irange()] + res_loc = self.get_local(cmat) + if not res: + # until now, degrees of generators were unknown + res = [dom.diff_form(loc_form.degree()) + for loc_form in res_loc] + for form, loc_form in zip(res, res_loc): + form.set_restriction(loc_form) + # TODO: make `res` immutable? + return res + + @abstract_method + def get_local(self, cmat): + r""" + Abstract method to get the local forms of the generators w.r.t. a given + curvature form matrix ``cmat``. + + OUTPUT: + + - a list containing the generator's local characteristic forms + + ALGORITHM: + + The inherited class determines the algorithm. + + EXAMPLES: + + 4-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(4) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: e = M.frames()[0] # select standard frame + sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] + ....: for i in TM.irange()] + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginAlgorithm + sage: algorithm = PontryaginAlgorithm() + sage: [p1] = algorithm.get_local(cmat) + sage: p1.display() + 0 + + A concrete implementation is given by a + :class:`sage.misc.fast_methods.Singleton`:: + + sage: algorithm is PontryaginAlgorithm() + True + """ + pass + + @cached_method + def get_gen_pow(self, nab, i, n): + r""" + Return the `n`-th power of the `i`-th generator's characteristic form + w.r.t ``nab``. + + The result is cached. + + EXAMPLES:: + + sage: M = manifolds.EuclideanSpace(8) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + :: + + sage: A = TM.characteristic_cohomology_class('AHat') + sage: A_form = A.get_form(nab); A_form # long time + Mixed differential form A^(TE^8, nabla_g) on the 8-dimensional + Euclidean space E^8 + sage: A_form.display_expansion() # long time + A^(TE^8, nabla_g) = 1 + """ + if n == 0: + return nab._domain._one_scalar_field # no computation necessary + return fast_wedge_power(self.get(nab)[i], n) + + +class ChernAlgorithm(Singleton, Algorithm_generic): + r""" + Algorithm class to generate Chern forms. + + EXAMPLES: + + Define a complex line bundle over a 2-dimensional manifold:: + + sage: M = Manifold(2, 'M', structure='Lorentzian') + sage: X. = M.chart() + sage: E = M.vector_bundle(1, 'E', field='complex'); E + Differentiable complex vector bundle E -> M of rank 1 over the base space + 2-dimensional Lorentzian manifold M + sage: e = E.local_frame('e') + sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') + sage: omega = M.one_form(name='omega') + sage: A = function('A') + sage: nab.set_connection_form(0, 0)[1] = I*A(t) + sage: nab[0, 0].display() + connection (0,0) of bundle connection nabla^E w.r.t. Local frame + (E|_M, (e_0)) = I*A(t) dx + sage: nab.set_immutable() + + Import the algorithm and apply ``nab`` to it:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import ChernAlgorithm + sage: algorithm = ChernAlgorithm() + sage: algorithm.get(nab) + [2-form on the 2-dimensional Lorentzian manifold M] + sage: algorithm.get(nab)[0].display() + 1/2*d(A)/dt/pi dt∧dx + + Check some equalities:: + + sage: cmat = [[nab.curvature_form(0, 0, e)]] + sage: algorithm.get(nab)[0] == algorithm.get_local(cmat)[0] # bundle trivial + True + sage: algorithm.get_gen_pow(nab, 0, 1) == algorithm.get(nab)[0] + True + """ + def get_local(self, cmat): + r""" + Return the local Chern forms w.r.t. a given curvature form matrix. + + OUTPUT: + + - a list containing the local characteristic Chern forms as + instances of + :class:`sage.manifolds.differentiable.diff_form.DiffForm` + + ALGORITHM:: + + The algorithm is based on the Faddeev-LeVerrier algorithm for the + characteristic polynomial. + + EXAMPLES: + + Define a complex line bundle over a 2-dimensional manifold:: + + sage: M = Manifold(2, 'M', structure='Lorentzian') + sage: X. = M.chart() + sage: E = M.vector_bundle(1, 'E', field='complex'); E + Differentiable complex vector bundle E -> M of rank 1 over the base + space 2-dimensional Lorentzian manifold M + sage: e = E.local_frame('e') + sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E') + sage: omega = M.one_form(name='omega') + sage: A = function('A') + sage: nab.set_connection_form(0, 0)[1] = I*A(t) + sage: nab[0, 0].display() + connection (0,0) of bundle connection nabla^E w.r.t. Local frame + (E|_M, (e_0)) = I*A(t) dx + sage: cmat = [[nab.curvature_form(i, j, e) for j in E.irange()] + ....: for i in E.irange()] + + Import the algorithm and apply ``cmat`` to it:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import ChernAlgorithm + sage: algorithm = ChernAlgorithm() + sage: algorithm.get_local(cmat) + [2-form on the 2-dimensional Lorentzian manifold M] + """ + from sage.symbolic.constants import pi, I + + dom = cmat[0][0]._domain + rk = len(cmat) + dim = dom._dim + ran = min(rk, dim // 2) + if ran < 1: + return [] # nothing to compute + fac = I / (2 * pi) + res = [] + m = cmat + for k in range(1, ran): + c = -sum(m[i][i] for i in range(rk)) / k + res.append(fac * c) + for i in range(rk): + m[i][i] += c + fac *= I / (2 * pi) + m = [[sum(cmat[i][l].wedge(m[l][j]) for l in range(rk)) + for j in range(rk)] for i in range(rk)] + res.append(-fac * sum(m[i][i] for i in range(rk)) / ran) + return res + + +class PontryaginAlgorithm(Singleton, Algorithm_generic): + r""" + Algorithm class to generate Pontryagin forms. + + EXAMPLES: + + 5-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(5) + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginAlgorithm + sage: algorithm = PontryaginAlgorithm() + sage: [p1] = algorithm.get(nab) + sage: p1.display() + 0 + """ + def get_local(self, cmat): + r""" + Return the local Pontryagin forms w.r.t. a given curvature form matrix. + + OUTPUT: + + - a list containing the local characteristic Pontryagin forms + + ALGORITHM:: + + The algorithm is based on the Faddeev-LeVerrier algorithm for the + characteristic polynomial. + + EXAMPLES: + + 5-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(5) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: e = M.frames()[0] # select standard frame + sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] + ....: for i in TM.irange()] + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginAlgorithm + sage: algorithm = PontryaginAlgorithm() + sage: [p1] = algorithm.get_local(cmat) + sage: p1.display() + 0 + """ + from sage.symbolic.constants import pi + + dom = cmat[0][0]._domain + rk = len(cmat) + dim = dom._dim + ran = min(rk // 2, dim // 4) + if ran < 1: + return [] # nothing to compute + fac = 1 / (2 * pi) ** 2 + res = [] + m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) + for l in range(rk)) + for j in range(rk)] for i in range(rk)] + for k in range(1, ran): + c = -sum(m[i][i] for i in range(rk)) / (2 * k) + res.append(fac * c) + for i in range(rk): + m[i][i] += c + fac *= 1 / (2 * pi) ** 2 + m = [[sum(cmat2[i][l].wedge(m[l][j]) for l in range(rk)) + for j in range(rk)] for i in range(rk)] + res.append(-fac * sum(m[i][i] for i in range(rk)) / (2 * ran)) + return res + + +class EulerAlgorithm(Singleton, Algorithm_generic): + r""" + Algorithm class to generate Euler forms. + + EXAMPLES: + + Consider the 2-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(2) + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm and apply ``nab`` to it:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm + sage: algorithm = EulerAlgorithm() + sage: algorithm.get(nab) + [2-form on the Euclidean plane E^2] + sage: algorithm.get(nab)[0].display() + 0 + """ + @cached_method + def get(self, nab): + r""" + Return the global characteristic forms of the generators w.r.t. a given + connection. + + INPUT: + + - a metric connection `\nabla` + + OUTPUT: + + - a list containing the global characteristic Euler form + + ALGORITHM: + + Assume that `\nabla` is compatible with the metric `g`, and let + `(s_1, \ldots, s_n)` be any oriented frame. Denote by + `G_s = (g(s_i, s_j))_{ij}` the metric tensor and let + `\Omega_s` be the curvature form matrix of `\nabla` w.r.t. `s`. + Then, we get: + + .. MATH:: + + \left(G_s \cdot \Omega_s \right)_{ij} = g\!\left(R(.,.)s_i, s_j\right), + + where `R` is the Riemannian curvature tensor w.r.t. `\nabla`. + + The characteristic Euler form is now obtained by the expression + + .. MATH:: + + \frac{1}{\sqrt{\left|\det(G_s)\right|}} \ + \mathrm{Pf}\!\left(G_s \cdot \frac{\Omega_s}{2 \pi}\right). + + EXAMPLES: + + Consider the 2-sphere:: + + sage: M. = manifolds.Sphere(2, coordinates='stereographic') + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm and apply ``nab`` to it:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm + sage: algorithm = EulerAlgorithm() + sage: algorithm.get(nab) + [2-form on the 2-sphere S^2 of radius 1 smoothly embedded in the + Euclidean space E^3] + sage: algorithm.get(nab)[0].display() + 2/(pi + pi*x^4 + pi*y^4 + 2*pi*x^2 + 2*(pi + pi*x^2)*y^2) dx∧dy + + REFERENCES: + + - [Che1944]_ + - [Baer2020]_ + """ + if not isinstance(nab, LeviCivitaConnection): + raise TypeError('Euler forms are currently only supported for ' + 'Levi-Civita connections') + dom = nab._domain + vbundle = dom.tangent_bundle() + rk = vbundle._rank + if not vbundle.has_orientation(): + raise ValueError('Euler forms can only be defined for orientable ' + 'vector bundles') + if rk % 2 != 0: + raise ValueError('Euler forms are currently only supported for ' + 'vector bundles with even rank') + res = dom.diff_form(rk) + g = nab._metric + for frame in dom._get_min_covering(vbundle.orientation()): + # (G_s * Ω_s)_ij = g(R(.,.)s_i, s_j) + gcmat = [[sum(g[[frame, i, j]] * nab.curvature_form(j, k, frame) + for j in vbundle.irange()) + for k in vbundle.irange()] for i in vbundle.irange()] + [res_loc] = self.get_local(gcmat) # Pf(G_s * Ω_s) mod const. + # e = 1 / sqrt(|det(G_s)|) * Pf(G_s * Ω_s) mod const. + det = g.det(frame) + if det.is_trivial_zero(): + raise ValueError(f'metric {g} must be non-degenerate') + sqrt_det = det.abs().sqrt() + res.set_restriction(res_loc / sqrt_det) # local Euler form + # TODO: make `res` immutable? + return [res] + + def get_local(self, cmat): + r""" + Return the normalized Pfaffian w.r.t. a given curvature form matrix. + + The normalization is given by the factor + `\left(\frac{1}{2 \pi}\right)^{\frac{k}{2}}`, where `k` is the + dimension of the curvature matrix. + + OUTPUT: + + - a list containing the normalized Pfaffian of a given curvature form + + .. NOTE:: + + In general, the output does *not* represent the local + characteristic Euler form. The result is only guaranteed to be the + local Euler form if ``cmat`` is given w.r.t. an orthonormal + oriented frame. See :meth:`get` for details. + + ALGORITHM:: + + The algorithm is based on the Bär-Faddeev-LeVerrier algorithm for + the Pfaffian. + + EXAMPLES: + + Consider the 2-sphere:: + + sage: M. = manifolds.Sphere(2) # use spherical coordinates + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: e = M.frames()[0] # select frame (opposite orientation!) + sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] + ....: for i in TM.irange()] + + We need some preprocessing because the frame is not orthonormal:: + + sage: gcmat = [[sum(g[[e, i, j]] * nab.curvature_form(j, k, e) + ....: for j in TM.irange()) + ....: for k in TM.irange()] for i in TM.irange()] + + Now, ``gcmat`` is guaranteed to be skew-symmetric and can be applied + to :meth:`get_local`. Then, the result must be normalized:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import EulerAlgorithm + sage: algorithm = EulerAlgorithm() + sage: euler = -algorithm.get_local(gcmat)[0] / sqrt(g.det(frame=e)) + sage: euler.display() + 1/2*sin(th)/pi dth∧dphi + """ + from sage.symbolic.constants import pi + + rk = len(cmat) + ran = rk // 2 + m = a = [cmat[i].copy() for i in range(rk)] + for i in range(0, rk, 2): + m[i], m[i + 1] = m[i + 1], m[i] # swap entries + for k in range(rk): + m[k][i + 1] = -m[k][i + 1] + for k in range(1, ran): + e = -sum(m[i][i] for i in range(rk)) / (2 * k) + for i in range(rk): + m[i][i] += e + m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) + for j in range(rk)] for i in range(rk)] + e = -sum(m[i][i] for i in range(rk)) / (2 * ran) # Pfaffian mod sign + e *= (-1 / (2 * pi)) ** ran # normalize + return [e] + + +class PontryaginEulerAlgorithm(Singleton, Algorithm_generic): + r""" + Algorithm class to generate Euler and Pontryagin forms. + + EXAMPLES: + + 6-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(6) + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm + sage: algorithm = PontryaginEulerAlgorithm() + sage: e_form, p1_form = algorithm.get(nab) # long time + sage: e_form.display() # long time + 0 + sage: p1_form.display() # long time + 0 + """ + + @cached_method + def get(self, nab): + r""" + Return the global characteristic forms of the generators w.r.t. a given + connection. + + OUTPUT: + + - a list containing the global Euler form in the first entry, and the + global Pontryagin forms in the remaining entries. + + EXAMPLES: + + 4-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(4) + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm + sage: algorithm = PontryaginEulerAlgorithm() + sage: algorithm.get(nab) + [4-form on the 4-dimensional Euclidean space E^4, + 4-form on the 4-dimensional Euclidean space E^4] + """ + return EulerAlgorithm().get(nab) + PontryaginAlgorithm().get(nab) + + def get_local(self, cmat): + r""" + Return the local Euler and Pontryagin forms w.r.t. a given curvature + form matrix. + + .. NOTE:: + + Similar as for :class:`EulerAlgorithm`, the first entry only + represents the Euler form if the curvature form matrix is chosen + w.r.t. an orthonormal oriented frame. See + :meth:`EulerAlgorithm.get_local` for details. + + OUTPUT: + + - a list containing the local Euler form in the first entry, and the + local Pontryagin forms in the remaining entries. + + EXAMPLES: + + 6-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(6) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: e = M.frames()[0] # select the standard frame + sage: cmat = [[nab.curvature_form(i, j, e) for j in TM.irange()] + ....: for i in TM.irange()] # long time + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm + sage: algorithm = PontryaginEulerAlgorithm() + sage: e, p1 = algorithm.get_local(cmat) # long time + sage: e.display() # long time + 0 + sage: p1.display() # long time + 0 + """ + res = EulerAlgorithm().get_local(cmat) # first entry is Euler class + res += PontryaginAlgorithm().get_local(cmat) # rest Pontryagin + return res + + @cached_method + def get_gen_pow(self, nab, i, n): + r""" + Return the `n`-th power of the `i`-th generator w.r.t ``nab``. + + The result is cached. + + EXAMPLES: + + 4-dimensional Euclidean space:: + + sage: M = manifolds.EuclideanSpace(4) + sage: TM = M.tangent_bundle() + sage: g = M.metric() + sage: nab = g.connection() + sage: nab.set_immutable() + + Import the algorithm:: + + sage: from sage.manifolds.differentiable.characteristic_cohomology_class import PontryaginEulerAlgorithm + sage: algorithm = PontryaginEulerAlgorithm() + sage: e = algorithm.get_gen_pow(nab, 0, 1) # Euler + sage: e.display() + 0 + sage: p1_pow2 = algorithm.get_gen_pow(nab, 1, 2) # 1st Pontryagin squared + sage: p1_pow2 + 8-form zero on the 4-dimensional Euclidean space E^4 + """ + if n == 0: + return nab._domain._one_scalar_field # no computation necessary + if i == 0: + return fast_wedge_power(EulerAlgorithm().get(nab)[0], n) + return fast_wedge_power(PontryaginAlgorithm().get(nab)[i-1], n) diff --git a/src/sage/manifolds/differentiable/de_rham_cohomology.py b/src/sage/manifolds/differentiable/de_rham_cohomology.py index 3f6cc7aa9c0..403f9f37f00 100644 --- a/src/sage/manifolds/differentiable/de_rham_cohomology.py +++ b/src/sage/manifolds/differentiable/de_rham_cohomology.py @@ -51,6 +51,8 @@ from sage.structure.parent import Parent from sage.structure.element import AlgebraElement from sage.categories.algebras import Algebras +from .characteristic_cohomology_class import (CharacteristicCohomologyClassRing, + CharacteristicCohomologyClassRingElement) class DeRhamCohomologyClass(AlgebraElement): r""" @@ -412,13 +414,45 @@ def _element_constructor_(self, x): differentiable manifold M must be a closed form """ - if x not in self._module: + if isinstance(x, CharacteristicCohomologyClassRingElement): + x = x.representative() + elif x not in self._module: raise TypeError(f"{x} must be an element of {self._module}") x = self._module(x) if x.derivative() != 0: raise ValueError(f"{x} must be a closed form") return self.element_class(self, x) + def _coerce_map_from_(self, other): + r""" + Determine whether coercion to ``self`` exists from other parent. + + TESTS:: + + sage: M = Manifold(2, 'M') + sage: C = M.de_rham_complex() + sage: H = C.cohomology() + sage: H.has_coerce_map_from(QQ) + True + + :: + + sage: M = Manifold(4, 'M') + sage: C = M.de_rham_complex() + sage: H = C.cohomology() + sage: TM = M.tangent_bundle() + sage: C = TM.characteristic_cohomology_class_ring(); C + Algebra of characteristic cohomology classes of the Tangent bundle + TM over the 4-dimensional differentiable manifold M + sage: H.has_coerce_map_from(C) + True + + """ + if isinstance(other, CharacteristicCohomologyClassRing): + # TODO: we need to be careful if manifolds have boundary! + return other._vbundle._base_space == self._manifold + return super()._coerce_map_from_(other) + def _repr_(self): r""" Return a string representation of the object. diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index c40d4d2acf3..b23207a6d3d 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -35,6 +35,8 @@ from sage.rings.real_mpfr import RR from sage.manifolds.vector_bundle import TopologicalVectorBundle from sage.rings.infinity import infinity +from sage.misc.superseded import deprecated_function_alias +from sage.rings.rational_field import QQ class DifferentiableVectorBundle(TopologicalVectorBundle): r""" @@ -163,45 +165,72 @@ def bundle_connection(self, name, latex_name=None): from .bundle_connection import BundleConnection return BundleConnection(self, name, latex_name) - def characteristic_class(self, func, **kwargs): + def characteristic_cohomology_class_ring(self, base=QQ): r""" - Return a characteristic class of the given type with respect to the - given function. + Return the characteristic cohomology class ring of ``self`` over + a given base. INPUT: - - ``func`` -- the function corresponding to the characteristic class - using the Chern-Weil homomorphism; this argument can be either one of - the predefined classes, in the following specified by - (field type, class type, name, LaTeX name, function): - - - ``'Chern'`` -- (complex, multiplicative, ``c``, `c`, `1+x`), - - ``'ChernChar'`` -- (complex, additive, ``ch``, `\mathrm{ch}`, - `\exp(x)`), - - ``'Todd'`` -- (complex, additive, ``Td``, `\mathrm{Td}`, - `\frac{x}{1-\exp(-x)}`), - - ``'Pontryagin'`` -- (real, multiplicative, ``p``, `p`, `1+x`), - - ``'Hirzebruch'`` -- (real, multiplicative, ``L``, `L`, - `\frac{\sqrt{x}}{\tanh(\sqrt{x})}`), - - ``'AHat'`` -- (real, multiplicative, ``A^``, `\hat{A}`, - `\frac{\sqrt{x}/2}{\sinh(\sqrt{x}/2)}`), - - ``'Euler'`` -- (real, Pfaffian, ``e``, `e`, `x`), - - or a symbolic expression. If ``func`` is one of the predefined classes, - the following arguments are obsolete. - - - ``class_type`` -- (default: ``'multiplicative'``) the type of the - characteristic class; possible values are: - - - ``'multiplicative'`` -- returns a class of multiplicative type, - using the determinant - - ``'additive'`` -- returns a class of additive type, using the trace - - ``'Pfaffian'`` -- returns a class of Pfaffian type, using the - Pfaffian - - - ``name`` -- string representation given to the characteristic class + - ``base`` -- (default: ``QQ``) base over which the ring should be + constructed; typically that would be `\ZZ`, `\QQ`, `\RR` or the + symbolic ring + + EXAMPLES:: + + sage: M = Manifold(4, 'M', start_index=1) + sage: R = M.tangent_bundle().characteristic_cohomology_class_ring() + sage: R + Algebra of characteristic cohomology classes of the Tangent bundle + TM over the 4-dimensional differentiable manifold M + sage: p1 = R.gen(0); p1 + Characteristic cohomology class (p_1)(TM) of the Tangent bundle TM + over the 4-dimensional differentiable manifold M + sage: 1 + p1 + Characteristic cohomology class (1 + p_1)(TM) of the Tangent bundle + TM over the 4-dimensional differentiable manifold M + + """ + from .characteristic_cohomology_class import CharacteristicCohomologyClassRing + + return CharacteristicCohomologyClassRing(base, self) + + def characteristic_cohomology_class(self, *args, **kwargs): + r""" + Return a characteristic cohomology class associated with the input + data. + + INPUT: + + - ``val`` -- the input data associated with the characteristic class + using the Chern-Weil homomorphism; this argument can be either a + symbolic expression, a polynomial or one of the following predefined + classes: + + - ``'Chern'`` -- total Chern class, + - ``'ChernChar'`` -- Chern character, + - ``'Todd'`` -- Todd class, + - ``'Pontryagin'`` -- total Pontryagin class, + - ``'Hirzebruch'`` -- Hirzebruch class, + - ``'AHat'`` -- `\hat{A}` class, + - ``'Euler'`` -- Euler class. + + - ``base_ring`` -- (default: ``QQ``) base ring over which the + characteristic cohomology class ring shall be defined + - ``name`` -- (default: ``None``) string representation given to the + characteristic cohomology class; if ``None`` the default algebra + representation or predefined name is used - ``latex_name`` -- (default: ``None``) LaTeX name given to the - characteristic class + characteristic class; if ``None`` the value of ``name`` is used + - ``class_type`` -- (default: ``None``) class type of the characteristic + cohomology class; the following options are possible: + + - ``'multiplicative'`` -- returns a class of multiplicative type + - ``'additive'`` -- returns a class of additive type + - ``'Pfaffian'`` -- returns a class of Pfaffian type + + This argument must be stated if ``val`` is a polynomial or symbolic + expression. EXAMPLES: @@ -233,12 +262,9 @@ def characteristic_class(self, func, **kwargs): sage: TM = M.tangent_bundle(); TM Tangent bundle TM over the 4-dimensional Lorentzian manifold M - sage: p = TM.characteristic_class('Pontryagin'); p - Characteristic class p of multiplicative type associated to x + 1 - on the Tangent bundle TM over the 4-dimensional Lorentzian - manifold M - sage: p.function() - x + 1 + sage: p = TM.characteristic_cohomology_class('Pontryagin'); p + Characteristic cohomology class p(TM) of the Tangent bundle TM over + the 4-dimensional Lorentzian manifold M sage: p_form = p.get_form(nab); p_form.display_expansion() p(TM, nabla_g) = 1 @@ -248,27 +274,11 @@ def characteristic_class(self, func, **kwargs): :class:`~sage.manifolds.differentiable.characteristic_class.CharacteristicClass`. """ - if self._field_type == 'neither_real_nor_complex': - raise ValueError("the vector bundle must be real or complex") - from .characteristic_class import CharacteristicClass, _get_predefined_class - # Is func a predefined class? - if isinstance(func, str): - func_str = func - # Get predefined class: - (field_type, class_type, name, - latex_name, func) = _get_predefined_class(func_str) - # The fields must be equal: - if field_type != self._field_type: - raise ValueError("base field must be {} ".format(field_type) + - "for class '{}'".format(func_str)) - else: - # Get arguments: - class_type = kwargs.pop('class_type', 'multiplicative') - name = kwargs.pop('name', None) - latex_name = kwargs.pop('latex_name', None) + base_ring = kwargs.get('base_ring', QQ) + R = self.characteristic_cohomology_class_ring(base_ring) + return R(*args, **kwargs) - return CharacteristicClass(self, func, class_type=class_type, - name=name, latex_name=latex_name) + characteristic_class = deprecated_function_alias(29581, characteristic_cohomology_class) def diff_degree(self): r""" diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 354fe0b096d..044fcb67029 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -2393,7 +2393,7 @@ cdef class Matrix(Matrix0): :meth:`get_is_zero_unsafe` for derived matrix classes. """ if ring is None: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ ring = ZZ cdef object one = ring.one() diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index f2aca987f51..8168239ff1c 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -422,7 +422,7 @@ cdef class Matrix_double_dense(Matrix_dense): Note that if this matrix is (nearly) singular, finding its inverse will not help much and will give slightly different answers on similar platforms depending on the hardware - and tuning options given to ATLAS:: + and other factors:: sage: A = matrix(RDF,3,range(1,10));A [1.0 2.0 3.0] diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index affaa351af6..32b77a861fa 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -1,11 +1,11 @@ # distutils: libraries = mtx # sage_setup: distribution = sagemath-meataxe +# sage.doctest: optional - meataxe r""" Dense Matrices over `\mathbb F_q`, with `q<255`. -This module is a wrapper for version 2.4.24 of the Aachen -`C-MeatAxe `_, +This module is a wrapper for the `Aachen C-MeatAxe library <../spkg/meataxe.html>`_, improved by an implementation of the Winograd-Strassen multiplication algorithm. It provides matrices over the finite field `\mathbb F_q`, where `q\le 255`. @@ -14,6 +14,11 @@ By default, it is only used when `q` is odd and not prime, because other matrix implementations in SageMath perform better for prime fields or in characteristic two. +.. NOTE:: + + The examples shown here will only work when the `meataxe + <../spkg/meataxe.html>` package has been installed. + AUTHORS: - Simon King (2015-09): initial version @@ -94,15 +99,15 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense sage: F. = GF(125) - sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() # optional: meataxe - sage: C = M._converter # optional: meataxe - sage: C.fel_to_field(15) # optional: meataxe + sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() + sage: C = M._converter + sage: C.fel_to_field(15) 3*y sage: F.fetch_int(15) 3*y - sage: C.field_to_fel(y) # optional: meataxe + sage: C.field_to_fel(y) 5 sage: y.integer_representation() 5 @@ -116,8 +121,8 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class # optional: meataxe - sage: FieldConverter_class(GF(13^2)) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class + sage: FieldConverter_class(GF(13^2)) """ self.field = field._cache.fetch_int @@ -129,10 +134,10 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class sage: F. = GF(125) - sage: C = FieldConverter_class(F) # optional: meataxe - sage: C.fel_to_field(15) # optional: meataxe + sage: C = FieldConverter_class(F) + sage: C.fel_to_field(15) 3*y sage: F.fetch_int(15) 3*y @@ -145,10 +150,10 @@ cdef class FieldConverter_class: EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import FieldConverter_class sage: F. = GF(125) - sage: C = FieldConverter_class(F) # optional: meataxe - sage: C.field_to_fel(y) # optional: meataxe + sage: C = FieldConverter_class(F) + sage: C.field_to_fel(y) 5 sage: y.integer_representation() 5 @@ -157,7 +162,7 @@ cdef class FieldConverter_class: Test invalid input:: - sage: C.field_to_fel('foo') # optional: meataxe + sage: C.field_to_fel('foo') Traceback (most recent call last): ... AttributeError: 'str' object has no attribute 'integer_representation' @@ -187,15 +192,15 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense sage: F = GF(5) - sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() # optional: meataxe - sage: C = M._converter # optional: meataxe - sage: C.fel_to_field(2) # optional: meataxe + sage: M = MatrixSpace(F, 2, 2, implementation=Matrix_gfpn_dense).one() + sage: C = M._converter + sage: C.fel_to_field(2) 2 sage: F(2) 2 - sage: C.field_to_fel(F(2)) # optional: meataxe + sage: C.field_to_fel(F(2)) 2 sage: int(F(2)) 2 @@ -209,8 +214,8 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class # optional: meataxe - sage: PrimeFieldConverter_class(GF(251)) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class + sage: PrimeFieldConverter_class(GF(251)) """ self.field = field @@ -221,10 +226,10 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class sage: F = GF(5) - sage: C = PrimeFieldConverter_class(F) # optional: meataxe - sage: C.fel_to_field(2) # optional: meataxe + sage: C = PrimeFieldConverter_class(F) + sage: C.fel_to_field(2) 2 """ return IntegerMod_int(self.field, FfToInt(x)) @@ -235,17 +240,17 @@ cdef class PrimeFieldConverter_class(FieldConverter_class): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import PrimeFieldConverter_class sage: F = GF(5) - sage: C = PrimeFieldConverter_class(F) # optional: meataxe - sage: C.field_to_fel(F(2)) # optional: meataxe + sage: C = PrimeFieldConverter_class(F) + sage: C.field_to_fel(F(2)) 2 TESTS: Test invalid input:: - sage: C.field_to_fel('foo') # optional: meataxe + sage: C.field_to_fel('foo') Traceback (most recent call last): ... TypeError: an integer is required @@ -339,7 +344,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: print(M) [1 2 3] [4 0 1] - sage: type(M) # optional: meataxe + sage: type(M) The documentation of the ``__init__`` methods shows further @@ -355,11 +360,11 @@ cdef class Matrix_gfpn_dense(Matrix_dense): TESTS:: sage: MS = MatrixSpace(GF(64), 0) - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe - sage: Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, MS) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense + sage: Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, MS) [] sage: M = None - sage: M = Matrix_gfpn_dense(MatrixSpace(GF(64,'z'),4), None) # optional: meataxe + sage: M = Matrix_gfpn_dense(MatrixSpace(GF(64,'z'),4), None) sage: del M # indirect doctest """ if self.Data != NULL: @@ -384,27 +389,27 @@ cdef class Matrix_gfpn_dense(Matrix_dense): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense 1. Creating a zero (3x2)-matrix:: - sage: Matrix_gfpn_dense(MatrixSpace(GF(4,'z'),3,2)) # optional: meataxe + sage: Matrix_gfpn_dense(MatrixSpace(GF(4,'z'),3,2)) [0 0] [0 0] [0 0] 2. Creating a matrix from a list or list of lists:: - sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[1,2,3,4,5,6]) # optional: meataxe + sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[1,2,3,4,5,6]) [1 2 3] [4 0 1] - sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[[1,2,3],[4,5,6]]) # optional: meataxe + sage: Matrix_gfpn_dense(MatrixSpace(GF(5),2,3),[[1,2,3],[4,5,6]]) [1 2 3] [4 0 1] 3. Creating a diagonal matrix:: - sage: M = Matrix_gfpn_dense(MatrixSpace(GF(7),5),2); M # optional: meataxe + sage: M = Matrix_gfpn_dense(MatrixSpace(GF(7),5),2); M [2 0 0 0 0] [0 2 0 0 0] [0 0 2 0 0] @@ -457,12 +462,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): does not exist, an error raised by the MeatAxe library is propagated:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe - sage: Matrix_gfpn_dense.from_filename('foobarNONEXISTING_FILE') # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense + sage: Matrix_gfpn_dense.from_filename('foobarNONEXISTING_FILE') Traceback (most recent call last): ... OSError: foobarNONEXISTING_FILE: No such file or directory in file os.c (line 255) - sage: Matrix_gfpn_dense.from_filename('') # optional: meataxe + sage: Matrix_gfpn_dense.from_filename('') Traceback (most recent call last): ... ValueError: cannot construct meataxe matrix from empty filename @@ -496,9 +501,9 @@ cdef class Matrix_gfpn_dense(Matrix_dense): True sage: N is M False - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense # optional: meataxe - sage: M = Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, parent(M)) # optional: meataxe - sage: copy(M) # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense + sage: M = Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, parent(M)) + sage: copy(M) Traceback (most recent call last): ... ValueError: cannot copy an uninitialized matrix @@ -559,7 +564,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: F. = GF(9) sage: M = MatrixSpace(F,3)(sorted(list(F))) - sage: type(M) # optional: meataxe + sage: type(M) sage: M # indirect doctest [ 0 1 2] @@ -606,18 +611,18 @@ cdef class Matrix_gfpn_dense(Matrix_dense): EXAMPLES:: - sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX # optional: meataxe - sage: M = MTX(MatrixSpace(GF(7), 5, 3), [[0,1,2], [1,2,3], [2,3,4], [3,4,5], [4,5,6]]) # optional: meataxe - sage: M # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX + sage: M = MTX(MatrixSpace(GF(7), 5, 3), [[0,1,2], [1,2,3], [2,3,4], [3,4,5], [4,5,6]]) + sage: M [0 1 2] [1 2 3] [2 3 4] [3 4 5] [4 5 6] - sage: M.get_slice(1,3) # optional: meataxe + sage: M.get_slice(1,3) [1 2 3] [2 3 4] - sage: type(_) is MTX # optional: meataxe + sage: type(_) is MTX True """ @@ -696,23 +701,23 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: MS = MatrixSpace(GF(27,'z'),6,6) sage: M = MS.random_element() # indirect doctest - sage: M # optional: meataxe + sage: M [ 1 z + 1 z^2 + z + 1 z^2 2*z^2 + z z + 1] [2*z^2 + 2*z + 2 2*z^2 + z + 2 z^2 + 1 2*z^2 + 2*z + 2 z^2 + z 2*z^2 + z + 1] [ 2*z + 2 z^2 + z + 2 z + 2 2*z^2 + 2*z + 2 2*z^2 2*z^2] [ 2*z^2 + z + 2 z^2 z + 2 z^2 + z 2*z^2 + 2 z^2 + 2] [ 2*z^2 + z 2*z 2*z^2 + 2*z + 1 2*z^2 + 1 2*z^2 + 2*z + 1 2*z^2 + z] [ 2*z + 1 z^2 + z z^2 z^2 2*z^2 + 2*z z + 1] - sage: type(M) # optional: meataxe + sage: type(M) - sage: MS.random_element(nonzero=True) # optional: meataxe + sage: MS.random_element(nonzero=True) [ 2*z 1 z^2 + 2*z + 1 2*z^2 + z + 1 z^2 z^2 + z + 1] [ 2*z^2 + 2*z 2*z^2 + z + 2 2*z + 1 z^2 + 2*z 2*z^2 + 2*z z^2] [ z^2 + z z^2 + z + 2 2*z^2 + 2*z + 1 z^2 + 2 1 2*z^2] [ z 2*z^2 + 2*z 2*z^2 2*z + 1 z + 2 z + 2] [ z^2 + z z^2 z + 2 2*z^2 + 2*z 2*z + 1 z^2 + z] [ z^2 + z + 2 2*z^2 + z z^2 z + 1 2*z^2 + 2*z z^2 + 2*z + 1] - sage: MS.random_element(density=0.5) # optional: meataxe + sage: MS.random_element(density=0.5) [ z^2 + 2 0 z^2 + 2*z + 2 2*z^2 + z 0 z^2 + z + 2] [ 0 1 0 0 0 0] [ 2*z^2 + z + 1 2*z^2 + z + 2 0 z^2 + z + 2 0 z^2 + z + 1] @@ -723,7 +728,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): The following tests against a bug that was fixed in :trac:`23352`:: sage: MS = MatrixSpace(GF(9,'x'),1,5) - sage: MS.random_element() # optional: meataxe + sage: MS.random_element() [x + 1 x 2 x + 2 x + 2] """ @@ -897,19 +902,19 @@ cdef class Matrix_gfpn_dense(Matrix_dense): EXAMPLES:: sage: M = random_matrix(GF(25,'x'), 5,5) - sage: M # optional: meataxe + sage: M [ 4 4*x x + 3 4*x + 2 3*x + 4] [ x + 2 3*x + 1 3 0 3] [ 3*x 2*x + 4 1 0 2*x] [4*x + 4 2*x + 3 4*x 1 3*x + 1] [3*x + 3 x + 3 x + 2 x + 1 3*x + 2] - sage: M._rowlist_(1) # optional: meataxe + sage: M._rowlist_(1) [7, 16, 3, 0, 3] - sage: [M[1,i]._int_repr() for i in range(5)] # optional: meataxe + sage: [M[1,i]._int_repr() for i in range(5)] ['7', '16', '3', '0', '3'] - sage: M._rowlist_(2,4) # optional: meataxe + sage: M._rowlist_(2,4) [15, 14, 1, 0, 10, 24, 13, 20, 1, 16, 18, 8, 7, 6, 17] - sage: [[M[i,j]._int_repr() for j in range(5)] for i in range(2,5)] # optional: meataxe + sage: [[M[i,j]._int_repr() for j in range(5)] for i in range(2,5)] [['15', '14', '1', '0', '10'], ['24', '13', '20', '1', '16'], ['18', '8', '7', '6', '17']] @@ -1340,7 +1345,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: M = MatrixSpace(GF(9,'x'),1000,500).random_element() sage: N = MatrixSpace(GF(9,'x'),500,2000).random_element() - sage: M*N == M._multiply_classical(N) # optional: meataxe + sage: M*N == M._multiply_classical(N) True """ @@ -1376,7 +1381,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: M = MatrixSpace(GF(9,'x'),1500,600).random_element() sage: N = MatrixSpace(GF(9,'x'),600,1500).random_element() - sage: M._multiply_strassen(N) == M._multiply_strassen(N,80) == M._multiply_strassen(N,2) # optional: meataxe + sage: M._multiply_strassen(N) == M._multiply_strassen(N,80) == M._multiply_strassen(N,2) True """ @@ -1483,7 +1488,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): ....: M = MS.random_element(density=0.4) ....: if M.rank() < 5: ....: break - sage: ~M # optional: meataxe + sage: ~M Traceback (most recent call last): ... ZeroDivisionError: Division by zero in file matinv.c (line 50) @@ -1540,7 +1545,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): sage: M = MatrixSpace(K, 4)([2*x^2 + 2*x, 2*x^2 + x, 2*x^2 + x + 1, ....: x^2 + x + 2, x + 2, x^2, 2*x + 2, 2*x^2 + 2*x, 2*x^2 + 1, ....: 1, 2, x^2 + 2*x + 1, x^2 + x + 2, x + 1, 2*x^2 + 2*x, x^2 + x]) - sage: M.order() # optional: meataxe + sage: M.order() 104 sage: M^104 == 1 True @@ -1594,7 +1599,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): Basis matrix: [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 0 0 1 0 0] - sage: M.left_kernel_matrix() # optional: meataxe + sage: M.left_kernel_matrix() [0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 0 0 1 0 0] @@ -1707,9 +1712,9 @@ cdef class Matrix_gfpn_dense(Matrix_dense): method directly:: sage: N = copy(M) - sage: N._echelon_in_place_classical(reduced=False) # optional: meataxe + sage: N._echelon_in_place_classical(reduced=False) (2, 1, 3, 4, 5, 6, 7, 8) - sage: N # optional: meataxe + sage: N [ 0 0 x 0 3*x + 2 0 0 0 2*x 0] [ 0 x + 3 0 0 0 3*x x + 4 0 0 0] [ 0 0 0 2*x 0 4*x + 1 4 0 0 0] @@ -1726,7 +1731,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): We verify that the above echelon form is consistent with Sage's generic implementation of dense matrices:: - sage: type(M) # optional: meataxe + sage: type(M) sage: MS = MatrixSpace(M.base_ring(), M.nrows(), M.ncols(), implementation='generic') sage: X = MS(M) @@ -1864,19 +1869,19 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): sage: s = b'Uq\x82\xa7\x8bh' sage: len(s) 6 - sage: from sage.matrix.matrix_gfpn_dense import mtx_unpickle, Matrix_gfpn_dense # optional: meataxe - sage: MS = MatrixSpace(GF(13), 2, 5, implementation=Matrix_gfpn_dense) # optional: meataxe - sage: N = mtx_unpickle(MS, 2, 5, s, True) # optional: meataxe - sage: N # optional: meataxe + sage: from sage.matrix.matrix_gfpn_dense import mtx_unpickle, Matrix_gfpn_dense + sage: MS = MatrixSpace(GF(13), 2, 5, implementation=Matrix_gfpn_dense) + sage: N = mtx_unpickle(MS, 2, 5, s, True) + sage: N [ 6 7 8 9 10] [12 11 10 9 8] - sage: type(N) # optional: meataxe + sage: type(N) We demonstrate that a slightly different pickle format can be understood as well, that was at some point used by some optional package:: - sage: N == mtx_unpickle(int(13), 2, 5, s, True) # optional: meataxe + sage: N == mtx_unpickle(int(13), 2, 5, s, True) True In a previous version of this optional module, the whole memory chunk @@ -1887,7 +1892,7 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): sage: t = b'Uq\x82\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00' sage: len(t) 16 - sage: N == mtx_unpickle(MS, 2, 5, t, True) # optional: meataxe + sage: N == mtx_unpickle(MS, 2, 5, t, True) doctest:warning ... DeprecationWarning: Reading this pickle may be machine dependent @@ -1900,12 +1905,12 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): sage: t = b'Uq\x82\x00\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00\x00' sage: len(t) 18 - sage: N == mtx_unpickle(MS, 2, 5, t, True) # optional: meataxe + sage: N == mtx_unpickle(MS, 2, 5, t, True) True The data may be empty, which results in the zero matrix:: - sage: mtx_unpickle(MS, 2, 5, b'', True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, b'', True) [0 0 0 0 0] [0 0 0 0 0] @@ -1914,27 +1919,27 @@ def mtx_unpickle(f, int nr, int nc, data, bint m): pickle format (we test several code paths here):: sage: t = b'Uq\x82\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00\x00' - sage: mtx_unpickle(MS, 2, 5, t, True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, t, True) Traceback (most recent call last): ... ValueError: Expected a pickle with 3*2 bytes, got 17 instead sage: t = b'Uq\x82\x00\x00\x00\x00\x00\xa7\x8bh\x00\x00\x00\x00\x00\x00' - sage: mtx_unpickle(MS, 2, 5, t[:4], True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, t[:4], True) Traceback (most recent call last): ... ValueError: Expected a pickle with 3*2 bytes, got 2*2 instead sage: MS = MatrixSpace(GF(13), 0, 5) - sage: mtx_unpickle(MS, 0, 5, s, True) # optional: meataxe + sage: mtx_unpickle(MS, 0, 5, s, True) Traceback (most recent call last): ... ValueError: This matrix pickle contains data, thus, the number of rows and columns must be positive sage: MS = MatrixSpace(GF(13), 3, 5) - sage: mtx_unpickle(MS, 2, 5, s, True) # optional: meataxe + sage: mtx_unpickle(MS, 2, 5, s, True) Traceback (most recent call last): ... ValueError: Inconsistent dimensions in this matrix pickle - sage: mtx_unpickle(MatrixSpace(GF(19),0,5), 0, 5, b'', True) # optional: meataxe + sage: mtx_unpickle(MatrixSpace(GF(19),0,5), 0, 5, b'', True) [] """ # The expected input type is bytes. However, Python-2 legacy pickles do diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index 3432de8c349..0e2781e0663 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -116,7 +116,7 @@ from sage.arith.all import gcd from .matrix2 import decomp_seq from .matrix0 import Matrix as Matrix_base -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose, get_verbose ######################################################### diff --git a/src/sage/matrix/strassen.pyx b/src/sage/matrix/strassen.pyx index c5c53c32640..c42f131cfa0 100644 --- a/src/sage/matrix/strassen.pyx +++ b/src/sage/matrix/strassen.pyx @@ -801,7 +801,7 @@ def test(n, m, R, c=2): 3 True 4 True """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix A = matrix(R,n,m,range(n*m)) B = A.__copy__(); B._echelon_in_place_classical() C = A.__copy__(); C._echelon_strassen(c) diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index 8fc0a44957a..bf1f6d5c298 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -663,19 +663,19 @@ def Matroid(groundset=None, data=None, **kwds): sage: Matroid("abc", bases=["abc"], foo="bar") Traceback (most recent call last): ... - TypeError: Matroid() got an unexpected keyword argument 'foo' + TypeError: ...Matroid() got an unexpected keyword argument 'foo' sage: Matroid(data=["x"], matrix=Matrix(1,1)) Traceback (most recent call last): ... - TypeError: Matroid() got an unexpected keyword argument 'matrix' + TypeError: ...Matroid() got an unexpected keyword argument 'matrix' sage: Matroid(bases=["x"], matrix=Matrix(1,1)) Traceback (most recent call last): ... - TypeError: Matroid() got an unexpected keyword argument 'matrix' + TypeError: ...Matroid() got an unexpected keyword argument 'matrix' sage: Matroid(Matrix(1,1), ring=ZZ, field=QQ) Traceback (most recent call last): ... - TypeError: Matroid() got an unexpected keyword argument 'ring' + TypeError: ...Matroid() got an unexpected keyword argument 'ring' sage: Matroid(rank_function=lambda X: len(X)) Traceback (most recent call last): ... diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 2fa72ef84ff..b4c068e88b5 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -339,7 +339,7 @@ from sage.graphs.graph import Graph from sage.matrix.constructor import matrix from .utilities import newlabel, sanitize_contractions_deletions, spanning_forest, spanning_stars -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.numerical.mip import MixedIntegerLinearProgram from sage.matroids.lean_matrix cimport BinaryMatrix, TernaryMatrix diff --git a/src/sage/media/wav.py b/src/sage/media/wav.py index cef295e7e94..e1ec4f6b21c 100644 --- a/src/sage/media/wav.py +++ b/src/sage/media/wav.py @@ -42,7 +42,7 @@ from sage.structure.sage_object import SageObject from sage.arith.srange import srange from sage.misc.html import html -from sage.rings.all import RDF +from sage.rings.real_double import RDF class Wave(SageObject): diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index d28ff94ce65..448e641191c 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -2826,11 +2826,11 @@ def append(self): sage: v.append(7) # py2 Traceback (most recent call last): ... - TypeError: append() takes exactly 1 argument (2 given) + TypeError: ...append() takes exactly 1 argument (2 given) sage: v.append(7) # py3 Traceback (most recent call last): ... - TypeError: append() takes 1 positional argument but 2 were given + TypeError: ...append() takes 1 positional argument but 2 were given We can still append by directly using the list method:: @@ -2851,11 +2851,11 @@ def extend(self): sage: v.extend([3,1,4,1,5,9]) # py2 Traceback (most recent call last): ... - TypeError: extend() takes exactly 1 argument (2 given) + TypeError: ...extend() takes exactly 1 argument (2 given) sage: v.extend([3,1,4,1,5,9]) # py3 Traceback (most recent call last): ... - TypeError: extend() takes 1 positional argument but 2 were given + TypeError: ...extend() takes 1 positional argument but 2 were given We can still extend by directly using the list method:: diff --git a/src/sage/misc/lazy_attribute.pyx b/src/sage/misc/lazy_attribute.pyx index ab55c9c0f24..9cee5d3c4b4 100644 --- a/src/sage/misc/lazy_attribute.pyx +++ b/src/sage/misc/lazy_attribute.pyx @@ -363,7 +363,7 @@ class lazy_attribute(_lazy_attribute): sage: a.x = 4 Traceback (most recent call last): ... - AttributeError: can...t set attribute + AttributeError: can...t set attribute... sage: a.__dict__ {} sage: a.x diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 41b9f4f211d..d69b82128f1 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -19,7 +19,7 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod def _len(L): @@ -700,7 +700,7 @@ def cantor_product(*args, **kwds): sage: next(cantor_product(count(), toto='hey')) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'toto' + TypeError: ...__init__() got an unexpected keyword argument 'toto' :: diff --git a/src/sage/misc/random_testing.py b/src/sage/misc/random_testing.py index c1eda49d940..13ff9be3b57 100644 --- a/src/sage/misc/random_testing.py +++ b/src/sage/misc/random_testing.py @@ -178,7 +178,7 @@ def test_add_commutes(trials, verbose=False): sage: test_add_commutes(10) sage: test_add_commutes(1000) # long time """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ for _ in range(trials): a = QQ.random_element() b = QQ.random_element() @@ -252,7 +252,7 @@ def test_add_is_mul(trials, verbose=False): Random seed: 216390410596009428782506007128692114173 AssertionError() """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ for _ in range(trials): a = QQ.random_element() b = QQ.random_element() diff --git a/src/sage/misc/randstate.pyx b/src/sage/misc/randstate.pyx index 8b422fe6d9c..f5c282bdb65 100644 --- a/src/sage/misc/randstate.pyx +++ b/src/sage/misc/randstate.pyx @@ -486,7 +486,7 @@ cdef class randstate: sage: seed(1,2) # indirect doctest Traceback (most recent call last): ... - TypeError: __init__() takes at most 1 positional argument (2 given) + TypeError: ...__init__() takes at most 1 positional argument (2 given) AUTHOR: diff --git a/src/sage/misc/sage_eval.py b/src/sage/misc/sage_eval.py index d5ddf7085bb..5f2b50ab625 100644 --- a/src/sage/misc/sage_eval.py +++ b/src/sage/misc/sage_eval.py @@ -171,7 +171,7 @@ def sage_eval(source, locals=None, cmds='', preparse=True): File "", line 1 $x = $y[Integer(3)] # Does Perl syntax work? ^ - SyntaxError: invalid syntax + SyntaxError: invalid ... """ if isinstance(source, (list, tuple)): cmds = source[0] diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 72c9cdf1d22..d079f9e6931 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1188,7 +1188,7 @@ def _sage_getargspec_cython(source): sage: sgc('def f(*x = 5, z = {(1,2,3): True}): pass') Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: sgc('def f(int *x = 5, z = {(1,2,3): True}): pass') Traceback (most recent call last): ... @@ -1200,7 +1200,7 @@ def _sage_getargspec_cython(source): sage: sgc('def f(int x = 5, , z = {(1,2,3): True}): pass') Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... TESTS: @@ -1210,7 +1210,7 @@ def _sage_getargspec_cython(source): sage: def dummy_python(self, *args, x=1): pass # py2 Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... sage: def dummy_python(self, *args, x=1): pass # py3 sage: sgc("def dummy_python(self, *args, x=1): pass") # py3 ArgSpec(args=['self', 'x'], varargs='args', keywords=None, defaults=(1,)) @@ -2061,6 +2061,15 @@ def sage_getdoc(obj, obj_name='', embedded=False): return '' r = sage_getdoc_original(obj) s = sage.misc.sagedoc.format(r, embedded=embedded) + f = sage_getfile(obj) + if f and os.path.exists(f): + from sage.doctest.control import skipfile + skip = skipfile(f) + if isinstance(skip, str): + warn = """WARNING: the enclosing module is marked '{}', +so doctests may not pass.""".format(skip) + s = warn + "\n\n" + s + pass # Fix object naming if obj_name != '': diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 9367c4d3d37..c0834b3b804 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -57,8 +57,8 @@ from sage.modular.modsym.space import ModularSymbolsSpace from sage.modular.modform.constructor import Newform from sage.matrix.all import matrix, block_diagonal_matrix, identity_matrix -from sage.modules.all import vector -from sage.misc.all import prod +from sage.modules.free_module_element import vector +from sage.misc.misc_c import prod from sage.arith.misc import is_prime from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.sets.primes import Primes diff --git a/src/sage/modular/abvar/abvar_ambient_jacobian.py b/src/sage/modular/abvar/abvar_ambient_jacobian.py index 6b81afe0545..d6338c53262 100644 --- a/src/sage/modular/abvar/abvar_ambient_jacobian.py +++ b/src/sage/modular/abvar/abvar_ambient_jacobian.py @@ -15,7 +15,7 @@ from .abvar import (ModularAbelianVariety_modsym_abstract, simple_factorization_of_modsym_space, modsym_lattices, ModularAbelianVariety_modsym) -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.modular.modsym.modsym import ModularSymbols from sage.modular.modform.constructor import Newforms diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 85bff44ad2e..3c2aefc0ab9 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -105,7 +105,7 @@ from sage.structure.richcmp import richcmp_method, richcmp from sage.rings.all import QQ, ZZ, QQbar, Integer from sage.arith.all import lcm -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.structure.element import coercion_model diff --git a/src/sage/modular/abvar/torsion_point.py b/src/sage/modular/abvar/torsion_point.py index e35677813be..56150c69943 100644 --- a/src/sage/modular/abvar/torsion_point.py +++ b/src/sage/modular/abvar/torsion_point.py @@ -223,7 +223,7 @@ def _richcmp_(self, right, op): [(1/3, 0)] """ A = self.parent().abelian_variety() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if self.__element.change_ring(QQ) - right.__element.change_ring(QQ) in A.lattice(): return rich_to_bool(op, 0) return richcmp(self.__element, right.__element, op) diff --git a/src/sage/modular/arithgroup/arithgroup_element.pyx b/src/sage/modular/arithgroup/arithgroup_element.pyx index 61875fc6161..1fff86aa7ab 100644 --- a/src/sage/modular/arithgroup/arithgroup_element.pyx +++ b/src/sage/modular/arithgroup/arithgroup_element.pyx @@ -16,7 +16,7 @@ Elements of Arithmetic Subgroups from sage.structure.element cimport MultiplicativeGroupElement, MonoidElement, Element from sage.structure.richcmp cimport richcmp -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.modular.cusps import Cusp from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index a2a97d403d9..bb7973f64cc 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -15,7 +15,7 @@ from sage.groups.old import Group from sage.categories.groups import Groups -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import lcm from sage.misc.cachefunc import cached_method from copy import copy # for making copies of lists of cusps diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index 5ea925b2a0d..fc70a66e4e1 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -100,7 +100,7 @@ from .all import SL2Z from .arithgroup_generic import ArithmeticSubgroup -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method import sage.arith.all as arith diff --git a/src/sage/modular/arithgroup/congroup.pyx b/src/sage/modular/arithgroup/congroup.pyx index cc6c8a557c0..e30a9daf5c9 100644 --- a/src/sage/modular/arithgroup/congroup.pyx +++ b/src/sage/modular/arithgroup/congroup.pyx @@ -27,7 +27,7 @@ arith_int = sage.rings.fast_arith.arith_int() from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense from sage.modular.modsym.p1list import lift_to_sl2z from sage.matrix.matrix_space import MatrixSpace -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ Mat2Z = MatrixSpace(ZZ,2) cdef Matrix_integer_dense genS, genT, genI diff --git a/src/sage/modular/arithgroup/congroup_gamma.py b/src/sage/modular/arithgroup/congroup_gamma.py index 5250d5669bc..4625c7abc15 100644 --- a/src/sage/modular/arithgroup/congroup_gamma.py +++ b/src/sage/modular/arithgroup/congroup_gamma.py @@ -11,7 +11,7 @@ #***************************************************************************** from .congroup_generic import CongruenceSubgroup -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.all import ZZ, Zmod, QQ from sage.rings.integer import GCD_list from sage.groups.matrix_gps.finitely_generated import MatrixGroup diff --git a/src/sage/modular/arithgroup/congroup_gamma0.py b/src/sage/modular/arithgroup/congroup_gamma0.py index 724e3901c87..f1fc3f493d8 100644 --- a/src/sage/modular/arithgroup/congroup_gamma0.py +++ b/src/sage/modular/arithgroup/congroup_gamma0.py @@ -19,7 +19,7 @@ from sage.misc.cachefunc import cached_method from sage.rings.all import IntegerModRing, ZZ from sage.arith.all import kronecker_symbol -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.modular.modsym.p1list import sage.arith.all as arith diff --git a/src/sage/modular/arithgroup/congroup_gamma1.py b/src/sage/modular/arithgroup/congroup_gamma1.py index c6f1024ba92..ca1bf498514 100644 --- a/src/sage/modular/arithgroup/congroup_gamma1.py +++ b/src/sage/modular/arithgroup/congroup_gamma1.py @@ -14,9 +14,9 @@ from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from .congroup_gammaH import GammaH_class, is_GammaH, GammaH_constructor -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import euler_phi as phi, moebius, divisors from sage.modular.dirichlet import DirichletGroup diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index c575fc1bc09..acfa7a5ebb7 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -257,7 +257,7 @@ def __call__(self, x): sage: c = kCusps(a,2) Traceback (most recent call last): ... - TypeError: __call__() takes 2 positional arguments but 3 were given + TypeError: ...__call__() takes 2 positional arguments but 3 were given :: diff --git a/src/sage/modular/dims.py b/src/sage/modular/dims.py index 1bf9aba3773..9ad307a4937 100644 --- a/src/sage/modular/dims.py +++ b/src/sage/modular/dims.py @@ -47,7 +47,7 @@ from sage.arith.all import factor, is_prime, valuation -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.all import Mod, Integer, IntegerModRing from sage.rings.rational_field import frac from . import dirichlet diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 22c632c9789..74345c67e5d 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -58,7 +58,7 @@ # **************************************************************************** import sage.categories.all as cat -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.misc.prandom as random from sage.modules.free_module import FreeModule import sage.modules.free_module_element as free_module_element diff --git a/src/sage/modular/local_comp/liftings.py b/src/sage/modular/local_comp/liftings.py index f629bc659b0..e862031f4b2 100644 --- a/src/sage/modular/local_comp/liftings.py +++ b/src/sage/modular/local_comp/liftings.py @@ -6,7 +6,7 @@ problems. """ -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import crt, inverse_mod from sage.modular.modsym.p1list import lift_to_sl2z diff --git a/src/sage/modular/modform/ambient_R.py b/src/sage/modular/modform/ambient_R.py index 97ac8ef61eb..a09a61f1b39 100644 --- a/src/sage/modular/modform/ambient_R.py +++ b/src/sage/modular/modform/ambient_R.py @@ -12,7 +12,7 @@ from . import ambient from .cuspidal_submodule import CuspidalSubmodule_R -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method class ModularFormsAmbient_R(ambient.ModularFormsAmbient): diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 8507f74f4cc..05abc12e1e5 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -39,7 +39,7 @@ from sage.arith.all import lcm, divisors, moebius, sigma, factor, crt from sage.arith.srange import xsrange from sage.matrix.constructor import matrix -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.misc.verbose import verbose from sage.modular.dirichlet import DirichletGroup diff --git a/src/sage/modular/modform/j_invariant.py b/src/sage/modular/modform/j_invariant.py index 2189c32b5f8..3cb5085fa02 100644 --- a/src/sage/modular/modform/j_invariant.py +++ b/src/sage/modular/modform/j_invariant.py @@ -3,7 +3,7 @@ """ from .eis_series import eisenstein_series_qexp from .vm_basis import delta_qexp -from sage.rings.all import QQ +from sage.rings.rational_field import QQ def j_invariant_qexp(prec=10, K=QQ): r""" diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index 45c9c16126f..0bc05f3880a 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -22,7 +22,7 @@ from sage.structure.richcmp import richcmp_method, richcmp from sage.rings.all import Integer, QQ, ZZ -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.misc.cachefunc import cached_method from sage.modular.arithgroup.all import Gamma0, is_CongruenceSubgroup diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index 9e122b1abe7..abea0961e0c 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -2276,7 +2276,7 @@ def rationalize_series(self, laurent_series, coeff_bound = 1e-10, denom_factor = """ from sage.rings.all import prime_range - from sage.misc.all import prod + from sage.misc.misc_c import prod from warnings import warn denom_factor = ZZ(denom_factor) diff --git a/src/sage/modular/modform_hecketriangle/element.py b/src/sage/modular/modform_hecketriangle/element.py index fc9a11523d5..4f8114f1125 100644 --- a/src/sage/modular/modform_hecketriangle/element.py +++ b/src/sage/modular/modform_hecketriangle/element.py @@ -284,7 +284,7 @@ def lseries(self, num_prec=None, max_imaginary_part=0, max_asymp_coeffs=40): sage: L(10).n(53) -23.9781792831... """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ from sage.symbolic.all import pi from sage.functions.other import sqrt from sage.lfunctions.dokchitser import Dokchitser diff --git a/src/sage/modular/modform_hecketriangle/subspace.py b/src/sage/modular/modform_hecketriangle/subspace.py index de082946919..50a5eb10337 100644 --- a/src/sage/modular/modform_hecketriangle/subspace.py +++ b/src/sage/modular/modform_hecketriangle/subspace.py @@ -16,7 +16,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.modules.module import Module from sage.structure.unique_representation import UniqueRepresentation diff --git a/src/sage/modular/modsym/heilbronn.pyx b/src/sage/modular/modsym/heilbronn.pyx index 89a88c25aa1..1c27f95d868 100644 --- a/src/sage/modular/modsym/heilbronn.pyx +++ b/src/sage/modular/modsym/heilbronn.pyx @@ -551,8 +551,8 @@ def hecke_images_gamma0_weight2(int u, int v, int N, indices, R): # Create a zero dense matrix over QQ with len(indices) rows # and #P^1(N) columns. cdef Matrix_rational_dense T - from sage.matrix.all import matrix - from sage.rings.all import QQ + from sage.matrix.constructor import matrix + from sage.rings.rational_field import QQ T = matrix(QQ, len(indices), len(P1), sparse=False) original_base_ring = R.base_ring() if original_base_ring != QQ: @@ -672,7 +672,7 @@ def hecke_images_nonquad_character_weight2(int u, int v, int N, indices, chi, R) """ cdef p1list.P1List P1 = p1list.P1List(N) - from sage.rings.all import QQ + from sage.rings.rational_field import QQ K = chi.base_ring() if K == QQ: @@ -684,7 +684,7 @@ def hecke_images_nonquad_character_weight2(int u, int v, int N, indices, chi, R) # Create a zero dense matrix over K with len(indices) rows # and #P^1(N) columns. cdef Matrix_cyclo_dense T - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix T = matrix(K, len(indices), len(P1), sparse=False) cdef Py_ssize_t i, j @@ -771,14 +771,14 @@ def hecke_images_quad_character_weight2(int u, int v, int N, indices, chi, R): (0, -2, 0, 2, -2, -1) """ cdef p1list.P1List P1 = p1list.P1List(N) - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if chi.base_ring() != QQ: raise TypeError("character must takes values in QQ") # Create a zero dense matrix over QQ with len(indices) rows # and #P^1(N) columns. cdef Matrix_rational_dense T - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix T = matrix(QQ, len(indices), len(P1), sparse=False) if R.base_ring() != QQ: @@ -868,8 +868,8 @@ def hecke_images_gamma0_weight_k(int u, int v, int i, int N, int k, indices, R): # So we create a zero dense matrix over QQ with len(indices) rows # and #P^1(N) * (k-1) columns. cdef Matrix_rational_dense T - from sage.matrix.all import matrix - from sage.rings.all import QQ + from sage.matrix.constructor import matrix + from sage.rings.rational_field import QQ T = matrix(QQ, len(indices), len(P1)*(k-1), sparse=False) if R.base_ring() != QQ: diff --git a/src/sage/modular/modsym/p1list_nf.py b/src/sage/modular/modsym/p1list_nf.py index 91f7efada6f..c366a15fbb6 100644 --- a/src/sage/modular/modsym/p1list_nf.py +++ b/src/sage/modular/modsym/p1list_nf.py @@ -1198,7 +1198,7 @@ def psi(N): if not N.is_integral(): raise ValueError("psi only defined for integral ideals") - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod([(np+1)*np**(e-1) \ for np,e in [(p.absolute_norm(),e) \ for p,e in N.factor()]]) diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index 8e40d26f645..a4b1378547e 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -27,7 +27,7 @@ import sage.matrix.matrix_space as matrix_space from sage.modules.free_module_element import FreeModuleElement from sage.modules.free_module import EchelonMatrixKey -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.modular.hecke.all as hecke from sage.arith.all import divisors, next_prime from sage.rings.fast_arith import prime_range diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index dd3e154b59b..65942454937 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -37,7 +37,7 @@ from sage.arith.all import binomial, bernoulli from sage.modules.free_module_element import vector, zero_vector from sage.matrix.matrix cimport Matrix from sage.matrix.matrix_space import MatrixSpace -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.prandom import random from sage.functions.other import floor from sage.structure.element cimport RingElement, Element diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index 6fcc77b7572..cbc80e7024b 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -341,3 +341,120 @@ def is_modular_form(self): True """ return self._polynomial.degree() <= 0 and self._polynomial[0].is_modular_form() + + def polynomial(self, names='E2, E4, E6'): + r""" + Return a multivariate polynomial `P(E_2, E_4, E_6)` corresponding to the + given form where `E_2`, `E_4` and `E_6` are the generators of the + quasimodular form ring given by + :meth:`~sage.modular.quasiform.ring.QuasiModularForms.gens`. + + INPUT: + + - ``names`` (str, default: ``'E2, E4, E6'``) -- a list or tuple of names + (strings), or a comma separated string. Correspond to the names of the + variables; + + OUTPUT: A multivariate polynomial in the variables ``names`` + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0 + QM.1).polynomial() + E4 + E2 + sage: (1/2 + QM.0 + 2*QM.1^2 + QM.0*QM.2).polynomial() + E2*E6 + 2*E4^2 + E2 + 1/2 + """ + P = self.parent().polynomial_ring(names) + g0, g1 = self.parent().modular_forms_subring().polynomial_ring(names='x').gens() + E2, E4, E6 = P.gens() + return sum(f.to_polynomial().subs({g0:E4, g1:E6}) * E2 ** exp for exp, f in enumerate(self._polynomial.coefficients(sparse=False))) + + to_polynomial = polynomial # alias + + def weights_list(self): + r""" + Return the list of the weights of all the graded components of the given + graded quasimodular form. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0).weights_list() + [2] + sage: (QM.0 + QM.1 + QM.2).weights_list() + [2, 4, 6] + sage: (QM.0 * QM.1 + QM.2).weights_list() + [6] + sage: QM(1/2).weights_list() + [0] + """ + return sorted(list(self.to_polynomial().homogeneous_components())) + + def is_homogeneous(self): + r""" + Return True if the graded quasimodular form is a homogeneous element, + that is it lives in a unique graded components of the graded ring of + self. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0).is_homogeneous() + True + sage: (QM.0 + QM.1).is_homogeneous() + False + sage: (QM.0 * QM.1 + QM.2).is_homogeneous() + True + sage: QM(1).is_homogeneous() + True + sage: (1 + QM.0).is_homogeneous() + False + """ + return len(self.weights_list()) == 1 + + def weight(self): + r""" + Return the weight of the given quasiform. Note that the given form must + be homogeneous. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0).weight() + 2 + sage: (QM.0 * QM.1 + QM.2).weight() + 6 + sage: QM(1/2).weight() + 0 + sage: (QM.0 + QM.1).weight() + Traceback (most recent call last): + ... + ValueError: the given graded quasiform is not an homogeneous element + """ + if self.is_homogeneous(): + return self.to_polynomial().degree() + else: + raise ValueError("the given graded quasiform is not an homogeneous element") + + def homogeneous_components(self): + r""" + Return a dictionnary where the values are the homogeneous components of + the given graded form and the keys are the weights of those components. + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: (QM.0).homogeneous_components() + {2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)} + sage: (QM.0 + QM.1 + QM.2).homogeneous_components() + {2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6), + 4: 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6), + 6: 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)} + sage: (1 + QM.0).homogeneous_components() + {0: 1, 2: 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6)} + """ + QM = self.parent() + poly_self = self.to_polynomial() + pol_hom_comp = poly_self.homogeneous_components() + return { k : QM.from_polynomial(pol) for k, pol in pol_hom_comp.items()} diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index fe521f89a50..5fbcb7e62ec 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -75,8 +75,11 @@ from sage.modular.modform.space import ModularFormsSpace from sage.modular.modform.ring import ModularFormsRing -from sage.rings.all import Integer, QQ +from sage.rings.all import Integer, QQ, ZZ from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.polynomial.multi_polynomial import MPolynomial +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.polynomial.term_order import TermOrder from sage.rings.power_series_poly import PowerSeries_poly from sage.structure.parent import Parent @@ -387,6 +390,18 @@ def gens(self): generators = gens # alias + def ngens(self): + r""" + Return the number of generators of the given graded quasimodular forms + ring. + + EXAMPLES:: + + sage: QuasiModularForms(1).ngens() + 3 + """ + return len(self.gens()) + def gen(self, n): r""" Return the `n`-th generator of the quasimodular forms ring. @@ -475,3 +490,82 @@ def polygen(self): Univariate Polynomial Ring in E2 over Ring of Modular Forms for Modular Group SL(2,Z) over Rational Field """ return self.__polynomial_subring.gen() + + def polynomial_ring(self, names='E2, E4, E6'): + r""" + Return a multivariate polynomial ring isomorphic to the given graded + quasimodular forms ring. + + In the case of the full modular group, this + ring is `R[E_2, E_4, E_6]` where `E_2`, `E_4` and `E_6` have degrees 2, + 4 and 6 respectively. + + INPUT: + + - ``names`` (str, default: ``'E2, E4, E6'``) -- a list or tuple of names + (strings), or a comma separated string. Correspond to the names of the + variables. + + OUTPUT: A multivariate polynomial ring in the variables ``names`` + + EXAMPLES: + + sage: QM = QuasiModularForms(1) + sage: P. = QM.polynomial_ring(); P + Multivariate Polynomial Ring in E2, E4, E6 over Rational Field + sage: E2.degree() + 2 + sage: E4.degree() + 4 + sage: E6.degree() + 6 + sage: P. = QQ[] + sage: QM.from_polynomial(x+y+z+w) + Traceback (most recent call last): + ... + ValueError: the number of variables (4) of the given polynomial cannot exceed the number of generators (3) of the quasimodular forms ring + """ + return PolynomialRing(self.base_ring(), 3, names, order=TermOrder('wdeglex', [ZZ(2), ZZ(4), ZZ(6)])) + + def from_polynomial(self, polynomial): + r""" + Convert the given polynomial `P(X, Y, Z)` to the graded quasiform + `P(E_2, E_4, E_6)` where `E_2`, `E_4` and `E_6` are the generators given + by :meth:`~sage.modular.quasimodform.ring.QuasiModularForms.gens`. + + INPUT: + + - ``plynomial`` -- A multivariate polynomial + + OUTPUT: the graded quasimodular forms `P(E_2, E_4, E_6)` + + EXAMPLES:: + + sage: QM = QuasiModularForms(1) + sage: P. = QQ[] + sage: QM.from_polynomial(x) + 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 - 144*q^5 + O(q^6) + sage: QM.from_polynomial(x) == QM.0 + True + sage: QM.from_polynomial(y) == QM.1 + True + sage: QM.from_polynomial(z) == QM.2 + True + sage: QM.from_polynomial(x^2 + y + x*z + 1) + 4 - 336*q - 2016*q^2 + 322368*q^3 + 3691392*q^4 + 21797280*q^5 + O(q^6) + + TESTS:: + + sage: QuasiModularForms(1).from_polynomial('x') + Traceback (most recent call last): + ... + TypeError: the input must be a polynomial + """ + if not isinstance(polynomial, (MPolynomial, Polynomial)): + raise TypeError('the input must be a polynomial') + poly_parent = polynomial.parent() + nb_var = poly_parent.ngens() + if nb_var > self.ngens(): + raise ValueError("the number of variables (%s) of the given polynomial cannot exceed the number of generators (%s) of the quasimodular forms ring" % (nb_var, self.ngens())) + gens_dict = {poly_parent.gen(i):self.gen(i) for i in range(0, nb_var)} + return self(polynomial.subs(gens_dict)) diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index 5fbde461d12..81a775c99c4 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -203,7 +203,7 @@ # **************************************************************************** # imports -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.rings.all import Integer, ZZ, QQ, PolynomialRing, GF, CommutativeRing diff --git a/src/sage/modules/diamond_cutting.py b/src/sage/modules/diamond_cutting.py index db33d13a77a..b18fc315754 100644 --- a/src/sage/modules/diamond_cutting.py +++ b/src/sage/modules/diamond_cutting.py @@ -258,7 +258,10 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False): artificial_length = None if dim[0] < dim[1]: # introduce "artificial" basis points (representing infinity) - artificial_length = max(abs(v) for v in basis).ceil() * 2 + def approx_norm(v): + r,r1 = (v.inner_product(v)).sqrtrem() + return r + (r1 > 0) + artificial_length = max(approx_norm(v) for v in basis) * 2 additional_vectors = identity_matrix(dim[1]) * artificial_length basis = basis.stack(additional_vectors) # LLL-reduce to get quadratic matrix @@ -277,7 +280,7 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False): # twice the length of longest vertex in Q is a safe choice if radius is None: - radius = 2 * max(abs(v) ** 2 for v in basis) + radius = 2 * max(v.inner_product(v) for v in basis) V = diamond_cut(Q, basis, radius, verbose=verbose) diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index db8fd8cabb7..009d8679e21 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -1741,7 +1741,7 @@ def cardinality(self): except AttributeError: pass from sage.rings.all import infinity - from sage.misc.all import prod + from sage.misc.misc_c import prod v = self.invariants() self.__cardinality = infinity if 0 in v else prod(v) return self.__cardinality @@ -2006,7 +2006,7 @@ def test_morphism_0(*args, **kwds): phi = random_fgp_morphism_0(*args, **kwds) K = phi.kernel() I = phi.image() - from sage.misc.all import prod + from sage.misc.misc_c import prod if prod(K.invariants()): assert prod(phi.domain().invariants()) % prod(K.invariants()) == 0 assert I.is_submodule(phi.codomain()) diff --git a/src/sage/modules/free_module_integer.py b/src/sage/modules/free_module_integer.py index a3b201657a6..a1e8a05fb50 100644 --- a/src/sage/modules/free_module_integer.py +++ b/src/sage/modules/free_module_integer.py @@ -756,6 +756,13 @@ def closest_vector(self, t): sage: u = vector([-423434678248195, -18882583298608161305227077482]) sage: L.closest_vector(u) in L True + + Check that the example, of non-maximal rank, from :trac:`32486` works:: + + from sage.modules.free_module_integer import IntegerLattice + L = IntegerLattice([[-1, 0, 1],[1,0,2]]) + L.closest_vector((1,1,1)) + (2, 0, 1) """ voronoi_cell = self.voronoi_cell() diff --git a/src/sage/modules/tensor_operations.py b/src/sage/modules/tensor_operations.py index 16eb8717e36..3550946581b 100644 --- a/src/sage/modules/tensor_operations.py +++ b/src/sage/modules/tensor_operations.py @@ -64,9 +64,9 @@ from collections import defaultdict from sage.modules.free_module import FreeModule_ambient_field -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.matrix.constructor import matrix -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ def symmetrized_coordinate_sums(dim, n): diff --git a/src/sage/monoids/automatic_semigroup.py b/src/sage/monoids/automatic_semigroup.py index 3a36993927b..b06df8af2f7 100644 --- a/src/sage/monoids/automatic_semigroup.py +++ b/src/sage/monoids/automatic_semigroup.py @@ -912,7 +912,7 @@ def lift(self): sage: m.lift() 3 sage: type(m.lift()) - + """ return self.value diff --git a/src/sage/monoids/free_abelian_monoid.py b/src/sage/monoids/free_abelian_monoid.py index f07eb143c50..288436ab56a 100644 --- a/src/sage/monoids/free_abelian_monoid.py +++ b/src/sage/monoids/free_abelian_monoid.py @@ -60,7 +60,7 @@ from sage.categories.monoids import Monoids from .free_abelian_monoid_element import FreeAbelianMonoidElement from sage.rings.integer import Integer -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.factory import UniqueFactory @@ -303,7 +303,7 @@ def cardinality(self): +Infinity """ if self.__ngens == 0: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ.one() from sage.rings.infinity import infinity return infinity diff --git a/src/sage/monoids/free_monoid.py b/src/sage/monoids/free_monoid.py index f132af2a8d4..9855e5e1a84 100644 --- a/src/sage/monoids/free_monoid.py +++ b/src/sage/monoids/free_monoid.py @@ -33,7 +33,7 @@ from sage.combinat.words.finite_word import FiniteWord_class from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ def is_FreeMonoid(x): diff --git a/src/sage/monoids/indexed_free_monoid.py b/src/sage/monoids/indexed_free_monoid.py index 144a9579072..69168f1e1bd 100644 --- a/src/sage/monoids/indexed_free_monoid.py +++ b/src/sage/monoids/indexed_free_monoid.py @@ -28,7 +28,7 @@ from sage.categories.sets_cat import Sets from sage.rings.integer import Integer from sage.rings.infinity import infinity -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.sets.family import Family diff --git a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx index ced0da89b05..c654f7f21a2 100644 --- a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx +++ b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx @@ -40,7 +40,7 @@ cdef class CVXOPTSDPBackend(MatrixSDPBackend): """ - from sage.rings.all import RDF + from sage.rings.real_double import RDF if base_ring is None: base_ring = RDF if base_ring is not RDF: @@ -101,7 +101,7 @@ cdef class CVXOPTSDPBackend(MatrixSDPBackend): """ from cvxopt import matrix as c_matrix, solvers - from sage.rings.all import RDF + from sage.rings.real_double import RDF G_matrix = [] h_matrix = [] debug_g = [] diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index 75d98d60b95..bc4cc83741b 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -34,7 +34,7 @@ from copy import copy cdef class GenericBackend: cpdef base_ring(self): - from sage.rings.all import RDF + from sage.rings.real_double import RDF return RDF cpdef zero(self): @@ -532,7 +532,7 @@ cdef class GenericBackend: p = cls() # fresh instance of the backend if tester is None: tester = p._tester(**options) - from sage.modules.all import vector + from sage.modules.free_module_element import vector # Ensure there are at least 2 variables p.add_variables(2) coeffs = ([0, vector([1, 2])], [1, vector([2, 3])]) diff --git a/src/sage/numerical/backends/generic_sdp_backend.pyx b/src/sage/numerical/backends/generic_sdp_backend.pyx index 1ad7bddc186..bff1e940b8f 100644 --- a/src/sage/numerical/backends/generic_sdp_backend.pyx +++ b/src/sage/numerical/backends/generic_sdp_backend.pyx @@ -39,7 +39,7 @@ cdef class GenericSDPBackend: sage: GenericSDPBackend().base_ring() Real Double Field """ - from sage.rings.all import RDF + from sage.rings.real_double import RDF return RDF cpdef zero(self): diff --git a/src/sage/numerical/backends/interactivelp_backend.pyx b/src/sage/numerical/backends/interactivelp_backend.pyx index 42a035a3230..6b26a21f1e2 100644 --- a/src/sage/numerical/backends/interactivelp_backend.pyx +++ b/src/sage/numerical/backends/interactivelp_backend.pyx @@ -21,7 +21,7 @@ AUTHORS: from sage.numerical.mip import MIPSolverException from sage.numerical.interactive_simplex_method import InteractiveLPProblem, default_variable_name -from sage.modules.all import vector +from sage.modules.free_module_element import vector from copy import copy @@ -68,7 +68,7 @@ cdef class InteractiveLPBackend: """ if base_ring is None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ base_ring = QQ self.lp = InteractiveLPProblem([], [], [], base_ring=base_ring) diff --git a/src/sage/numerical/backends/logging_backend.py b/src/sage/numerical/backends/logging_backend.py index 01bdf712f6e..901dbdd3b88 100644 --- a/src/sage/numerical/backends/logging_backend.py +++ b/src/sage/numerical/backends/logging_backend.py @@ -183,7 +183,7 @@ def base_ring(self): sage: lb = LoggingBackend(backend=b) sage: lb.base_ring() Real Double Field - sage: from sage.rings.all import QQ + sage: from sage.rings.rational_field import QQ sage: lb = LoggingBackend(backend=b, base_ring=QQ) sage: lb.base_ring() Rational Field @@ -232,7 +232,7 @@ def _test_{name}(cls, tester=None, **options): tester = p._tester(**options) '''.replace("SAGE:", "sage:") # so that the above test does not get picked up by the doctester -from sage.rings.all import QQ +from sage.rings.rational_field import QQ def LoggingBackendFactory(solver=None, printing=True, doctest_file=None, test_method_file=None, test_method=None, base_ring=QQ): diff --git a/src/sage/numerical/backends/matrix_sdp_backend.pyx b/src/sage/numerical/backends/matrix_sdp_backend.pyx index 11dbaf5bb6e..d04446c2287 100644 --- a/src/sage/numerical/backends/matrix_sdp_backend.pyx +++ b/src/sage/numerical/backends/matrix_sdp_backend.pyx @@ -51,7 +51,7 @@ cdef class MatrixSDPBackend(GenericSDPBackend): self.set_sense(-1) if base_ring is None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ base_ring = QQ self._base_ring = base_ring diff --git a/src/sage/numerical/backends/ppl_backend.pyx b/src/sage/numerical/backends/ppl_backend.pyx index 8f7154137ad..b83aa82cbf9 100644 --- a/src/sage/numerical/backends/ppl_backend.pyx +++ b/src/sage/numerical/backends/ppl_backend.pyx @@ -67,7 +67,7 @@ cdef class PPLBackend(GenericBackend): """ if base_ring is not None: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if base_ring is not QQ: raise TypeError('The PPL backend only supports rational data.') @@ -90,7 +90,7 @@ cdef class PPLBackend(GenericBackend): self.set_sense(-1) cpdef base_ring(self): - from sage.rings.all import QQ + from sage.rings.rational_field import QQ return QQ cpdef zero(self): @@ -140,7 +140,7 @@ cdef class PPLBackend(GenericBackend): sage: p.base_ring() Rational Field sage: type(p.zero()) - + sage: p.init_mip() """ diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index 8edecb5ed5c..4386e6f2e9e 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -199,7 +199,7 @@ from sage.plot.all import Graphics, arrow, line, point, rainbow, text from sage.rings.all import Infinity, PolynomialRing, QQ, RDF, ZZ from sage.structure.all import SageObject -from sage.symbolic.all import SR +from sage.symbolic.ring import SR # We produce rather complicated LaTeX code which needs some tweaks to be diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index 6d0c0604c37..309d01bf36a 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -11,12 +11,12 @@ either equalities or less-or-equal. For example:: sage: f = 1 + x[1] + 2*x[2]; f # a linear function 1 + x_0 + 2*x_1 sage: type(f) - + sage: c = (0 <= f); c # a constraint 0 <= 1 + x_0 + 2*x_1 sage: type(c) - + Note that you can use this module without any reference to linear programming, it only implements linear functions over a base ring and @@ -529,7 +529,7 @@ cdef class LinearFunctionsParent_class(Parent): sage: from sage.numerical.linear_functions import LinearFunctionsParent_class sage: LinearFunctionsParent_class - + """ def __cinit__(self): """ @@ -675,7 +675,7 @@ cdef class LinearFunctionsParent_class(Parent): sage: LF(123) # indirect doctest 123 sage: type(_) - + sage: p_QQ = MixedIntegerLinearProgram(solver='ppl') sage: LF_QQ = p_QQ.linear_functions_parent() @@ -1039,7 +1039,7 @@ cdef class LinearFunction(LinearFunctionOrConstraint): sage: p = MixedIntegerLinearProgram() sage: LF = p.linear_functions_parent() sage: f = LF(1); type(f) - + sage: f._coeff_formatter(1) '' sage: f._coeff_formatter(1, constant_term=True) @@ -1075,7 +1075,7 @@ cdef class LinearFunction(LinearFunctionOrConstraint): if coeff == R.one() and not constant_term: return '' try: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ coeff = ZZ(coeff) # print as integer if possible except (TypeError, ValueError): pass @@ -1302,7 +1302,7 @@ cdef class LinearConstraintsParent_class(Parent): x_0 == x_1 == x_2 sage: type(_) - + TESTS:: diff --git a/src/sage/numerical/linear_tensor.py b/src/sage/numerical/linear_tensor.py index ffc253494db..bdf9529659a 100644 --- a/src/sage/numerical/linear_tensor.py +++ b/src/sage/numerical/linear_tensor.py @@ -387,7 +387,7 @@ def _element_constructor_(self, x): sage: LT({1:[1, 2]}) # indirect doctest (1.0, 2.0)*x_1 sage: type(_) - + Construct from scalar: diff --git a/src/sage/numerical/linear_tensor_element.pyx b/src/sage/numerical/linear_tensor_element.pyx index 597f96f953b..f04949d6c02 100644 --- a/src/sage/numerical/linear_tensor_element.pyx +++ b/src/sage/numerical/linear_tensor_element.pyx @@ -7,17 +7,17 @@ Here is an example of a linear function tensored with a vector space:: sage: lt = x[0] * vector([3,4]) + 1; lt (1, 1) + (3, 4)*x_0 sage: type(lt) - + """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cpython.object cimport * diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index 7aa17dc48af..255e958c2d0 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -385,7 +385,7 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm="default", (1.0, 1.0, 1.0) """ from sage.symbolic.expression import Expression - from sage.ext.fast_eval import fast_callable + from sage.ext.fast_callable import fast_callable import numpy from scipy import optimize if isinstance(func, Expression): @@ -418,7 +418,8 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm="default", hess=func.hessian() hess_fast= [ [fast_callable(a, vars=var_names, domain=float) for a in row] for row in hess] hessian=lambda p: [[a(*p) for a in row] for row in hess_fast] - hessian_p=lambda p,v: scipy.dot(numpy.array(hessian(p)),v) + from scipy import dot + hessian_p=lambda p,v: dot(numpy.array(hessian(p)),v) min = optimize.fmin_ncg(f, [float(_) for _ in x0], fprime=gradient, \ fhess=hessian, fhess_p=hessian_p, disp=verbose, **args) return vector(RDF, min) @@ -505,23 +506,27 @@ def minimize_constrained(func,cons,x0,gradient=None,algorithm='default', **args) (805.985..., 1005.985...) """ from sage.symbolic.expression import Expression + from sage.ext.fast_callable import fast_callable import numpy from scipy import optimize function_type = type(lambda x,y: x+y) if isinstance(func, Expression): var_list = func.variables() - var_names = [str(_) for _ in var_list] - fast_f = func._fast_float_(*var_names) + fast_f = fast_callable(func, vars=var_list, domain=float) f = lambda p: fast_f(*p) gradient_list = func.gradient() - fast_gradient_functions = [gi._fast_float_(*var_names) for gi in gradient_list] + fast_gradient_functions = [ fast_callable(gi, + vars=var_list, + domain=float) + for gi in gradient_list ] gradient = lambda p: numpy.array([ a(*p) for a in fast_gradient_functions]) if isinstance(cons, Expression): - fast_cons = cons._fast_float_(*var_names) + fast_cons = fast_callable(cons, vars=var_list, domain=float) cons = lambda p: numpy.array([fast_cons(*p)]) elif isinstance(cons, list) and isinstance(cons[0], Expression): - fast_cons = [ci._fast_float_(*var_names) for ci in cons] + fast_cons = [ fast_callable(ci, vars=var_list, domain=float) + for ci in cons ] cons = lambda p: numpy.array([a(*p) for a in fast_cons]) else: f = func @@ -778,9 +783,9 @@ def find_fit(data, model, initial_guess = None, parameters = None, variables = N raise ValueError("length of initial_guess does not coincide with the number of parameters") if isinstance(model, Expression): + from sage.ext.fast_callable import fast_callable var_list = variables + parameters - var_names = [str(_) for _ in var_list] - func = model._fast_float_(*var_names) + func = fast_callable(model, vars=var_list, domain=float) else: func = model diff --git a/src/sage/plot/colors.py b/src/sage/plot/colors.py index dedb4443ba3..0f2923aa972 100644 --- a/src/sage/plot/colors.py +++ b/src/sage/plot/colors.py @@ -813,7 +813,7 @@ def __truediv__(self, right): sage: papayawhip / yellow Traceback (most recent call last): ... - TypeError: float() argument must be a string or a number, not 'Color' + TypeError: float() argument must be a string or a... number... """ return self * (1 / float(right)) @@ -1231,7 +1231,7 @@ def float_to_html(r, g, b): sage: float_to_html((0.2, 0.6, 0.8)) Traceback (most recent call last): ... - TypeError: float_to_html() missing 2 required positional arguments: 'g' and 'b' + TypeError: ...float_to_html() missing 2 required positional arguments: 'g' and 'b' """ return "#%06x" % float_to_integer(r, g, b) @@ -1272,7 +1272,7 @@ def float_to_integer(r, g, b): sage: float_to_integer((0.2, 0.6, 0.8)) Traceback (most recent call last): ... - TypeError: float_to_integer() missing 2 required positional arguments: 'g' and 'b' + TypeError: ...float_to_integer() missing 2 required positional arguments: 'g' and 'b' """ r, g, b = map(mod_one, (r, g, b)) return int(r * 255) << 16 | int(g * 255) << 8 | int(b * 255) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 81890e55708..fce17eec618 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -1252,12 +1252,12 @@ def plot(self): sage: S.plot(1) Traceback (most recent call last): ... - TypeError: plot() takes 1 positional argument but 2 were given + TypeError: ...plot() takes 1 positional argument but 2 were given sage: S.plot(hey="hou") Traceback (most recent call last): ... - TypeError: plot() got an unexpected keyword argument 'hey' + TypeError: ...plot() got an unexpected keyword argument 'hey' """ return self diff --git a/src/sage/plot/matrix_plot.py b/src/sage/plot/matrix_plot.py index 4b92b3a16c1..041405f2171 100644 --- a/src/sage/plot/matrix_plot.py +++ b/src/sage/plot/matrix_plot.py @@ -562,7 +562,7 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): import scipy.sparse as scipysparse from sage.plot.all import Graphics from sage.structure.element import is_Matrix - from sage.rings.all import RDF + from sage.rings.real_double import RDF orig_mat=mat if is_Matrix(mat): sparse = mat.is_sparse() diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index b170e7c4a3b..b57976552b6 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -192,14 +192,14 @@ def unify_arguments(funcs): vars=set() free_variables=set() if not isinstance(funcs, (list, tuple)): - funcs=[funcs] + funcs = [funcs] for f in funcs: if is_CallableSymbolicExpression(f): - f_args=set(f.arguments()) + f_args = set(f.arguments()) vars.update(f_args) else: - f_args=set() + f_args = set() try: free_vars = set(f.variables()).difference(f_args) @@ -208,7 +208,7 @@ def unify_arguments(funcs): except AttributeError: # we probably have a constant pass - return tuple(sorted(vars, key=lambda x: str(x))), tuple(sorted(free_variables, key=lambda x: str(x))) + return tuple(sorted(vars, key=str)), tuple(sorted(free_variables, key=str)) def _multiple_of_constant(n, pos, const): diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index 7b0e33ed489..2f08cb2b994 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -2390,7 +2390,7 @@ def golden_rainbow(i,lightness=0.4): if excluded_points or detect_poles: start_index = 0 # setup for pole detection - from sage.rings.all import RDF + from sage.rings.real_double import RDF epsilon = 0.0001 pole_options = {} pole_options['linestyle'] = '--' @@ -3023,7 +3023,7 @@ def list_plot(data, plotjoined=False, **kwargs): list_data = list(data.items()) return list_plot(list_data, plotjoined=plotjoined, **kwargs) try: - from sage.rings.all import RDF + from sage.rings.real_double import RDF RDF(data[0]) data = list(enumerate(data)) except TypeError: # we can get this TypeError if the element is a list diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index c9828cbd195..6efc85eb10f 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -84,7 +84,7 @@ from sage.plot.plot3d.transform cimport point_c, face_c, color_c, Transformation from sage.plot.plot3d.base cimport PrimitiveObject from sage.plot.plot3d.base import RenderParams, default_texture from sage.plot.plot3d.index_face_set cimport IndexFaceSet -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.plot.misc import setup_for_eval_on_grid from sage.plot.colors import check_color_data diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index 875165ee972..62894bef1a0 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -3,8 +3,8 @@ """ from sage.structure.element import is_Matrix -from sage.matrix.all import matrix -from sage.rings.all import RDF +from sage.matrix.constructor import matrix +from sage.rings.real_double import RDF from sage.misc.superseded import deprecation diff --git a/src/sage/plot/plot3d/parametric_surface.pyx b/src/sage/plot/plot3d/parametric_surface.pyx index 42d3cb37430..a88ee2e8093 100644 --- a/src/sage/plot/plot3d/parametric_surface.pyx +++ b/src/sage/plot/plot3d/parametric_surface.pyx @@ -87,12 +87,11 @@ from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_check from math import cos, sin -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.plot.colors import check_color_data from .base import RenderParams from .transform cimport point_c, face_c -from sage.ext.fast_eval cimport FastDoubleFunc from sage.ext.interpreters.wrapper_rdf cimport Wrapper_rdf include "point_c.pxi" @@ -605,8 +604,7 @@ cdef class ParametricSurface(IndexFaceSet): - tuple -- split into fx, fy, fz and call each separately - callable -- call f(u,v) - In addition, branches are taken for efficient calling of FastDoubleFunc - (including whether to iterate over python or c doubles). + In addition, branches are taken for efficient calling of fast callables """ cdef Py_ssize_t i, j cdef Py_ssize_t m = len(urange) @@ -634,23 +632,15 @@ cdef class ParametricSurface(IndexFaceSet): fx, fy, fz = self.f # First, deal with the fast functions (if any) - fast_x = isinstance(fx, (FastDoubleFunc, Wrapper_rdf)) - fast_y = isinstance(fy, (FastDoubleFunc, Wrapper_rdf)) - fast_z = isinstance(fz, (FastDoubleFunc, Wrapper_rdf)) + fast_x = isinstance(fx, Wrapper_rdf) + fast_y = isinstance(fy, Wrapper_rdf) + fast_z = isinstance(fz, Wrapper_rdf) if fast_x or fast_y or fast_z: ulist = to_double_array(urange) vlist = to_double_array(vrange) res = self.vs - if isinstance(fx, FastDoubleFunc): - for i in range(m): - uv[0] = ulist[i] - for j in range(n): - sig_check() - uv[1] = vlist[j] - res.x = (fx)._call_c(uv) - res += 1 - elif fast_x: # must be Wrapper_rdf + if fast_x: # must be Wrapper_rdf for i in range(m): uv[0] = ulist[i] for j in range(n): @@ -660,15 +650,7 @@ cdef class ParametricSurface(IndexFaceSet): res += 1 res = self.vs - if isinstance(fy, FastDoubleFunc): - for i in range(m): - uv[0] = ulist[i] - for j in range(n): - sig_check() - uv[1] = vlist[j] - res.y = (fy)._call_c(uv) - res += 1 - elif fast_y: # must be Wrapper_rdf + if fast_y: # must be Wrapper_rdf for i from 0 <= i < m: uv[0] = ulist[i] for j from 0 <= j < n: @@ -678,15 +660,7 @@ cdef class ParametricSurface(IndexFaceSet): res += 1 res = self.vs - if isinstance(fz, FastDoubleFunc): - for i in range(m): - uv[0] = ulist[i] - for j in range(n): - sig_check() - uv[1] = vlist[j] - res.z = (fz)._call_c(uv) - res += 1 - elif fast_z: # must be Wrapper_rdf + if fast_z: # must be Wrapper_rdf for i in range(m): uv[0] = ulist[i] for j in range(n): diff --git a/src/sage/plot/plot3d/platonic.py b/src/sage/plot/plot3d/platonic.py index 5e6019d4989..8fdb45f5a54 100644 --- a/src/sage/plot/plot3d/platonic.py +++ b/src/sage/plot/plot3d/platonic.py @@ -65,7 +65,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import RDF +from sage.rings.real_double import RDF from sage.matrix.constructor import matrix from sage.misc.decorators import rename_keyword from .shapes import Box, ColorCube diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index d5951640950..06dd6a9df65 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -149,8 +149,6 @@ def f(x,y): return math.exp(x/5)*math.cos(y) from sage.plot.colors import rainbow from .texture import Texture -from sage.ext.fast_eval import fast_float_arg - from sage.functions.trig import cos, sin from sage.misc.sageinspect import sage_getargspec, is_function_or_cython_function @@ -1086,9 +1084,12 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): elif adaptive: P = plot3d_adaptive(f, urange, vrange, **kwds) else: - u=fast_float_arg(0) - v=fast_float_arg(1) - P=parametric_plot3d.parametric_plot3d((u,v,f), urange, vrange, **kwds) + arg1 = lambda u,v: u + arg2 = lambda u,v: v + P = parametric_plot3d.parametric_plot3d((arg1,arg2,f), + urange, + vrange, + **kwds) P.frame_aspect_ratio([1.0,1.0,0.5]) return P diff --git a/src/sage/quadratic_forms/constructions.py b/src/sage/quadratic_forms/constructions.py index 8d892b45d08..cf7460c1f88 100644 --- a/src/sage/quadratic_forms/constructions.py +++ b/src/sage/quadratic_forms/constructions.py @@ -5,7 +5,7 @@ ## Some extra routines to make the QuadraticForm class more useful. ## -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_element import is_Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.quadratic_forms.quadratic_form import QuadraticForm diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py index fb35d04f53e..f91857adb82 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py @@ -5,7 +5,7 @@ from sage.rings.rational_field import QQ from sage.arith.all import kronecker_symbol, legendre_symbol, prime_divisors, is_prime, fundamental_discriminant from sage.symbolic.constants import pi -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.quadratic_forms.special_values import gamma__exact, zeta__exact, quadratic_L_function__exact diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py index a7116516724..2941df73430 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py @@ -12,7 +12,7 @@ import copy -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.mrange import mrange from sage.functions.all import floor from sage.rings.integer_ring import ZZ diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index 9960396049a..a206070ef30 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -16,7 +16,7 @@ from sage.misc.functional import is_odd from sage.libs.pari.all import pari -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import (factor, gcd, prime_to_m_part, CRT_vectors, hilbert_symbol, kronecker_symbol) diff --git a/src/sage/quadratic_forms/random_quadraticform.py b/src/sage/quadratic_forms/random_quadraticform.py index 371d89a2a59..7a980bf6d4f 100644 --- a/src/sage/quadratic_forms/random_quadraticform.py +++ b/src/sage/quadratic_forms/random_quadraticform.py @@ -4,7 +4,7 @@ from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.quadratic_forms.ternary_qf import TernaryQF from sage.rings.ring import is_Ring -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ ################################################ ## Routines to create a random quadratic form ## diff --git a/src/sage/quadratic_forms/ternary_qf.py b/src/sage/quadratic_forms/ternary_qf.py index bb44c44cde6..da426c84395 100644 --- a/src/sage/quadratic_forms/ternary_qf.py +++ b/src/sage/quadratic_forms/ternary_qf.py @@ -27,7 +27,7 @@ # **************************************************************************** from sage.structure.sage_object import SageObject -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import gcd, kronecker_symbol from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.matrix.constructor import matrix, identity_matrix diff --git a/src/sage/repl/__init__.py b/src/sage/repl/__init__.py index e69de29bb2d..1357b584ef3 100644 --- a/src/sage/repl/__init__.py +++ b/src/sage/repl/__init__.py @@ -0,0 +1,15 @@ +# IPython calls this when "%load_ext sage.repl" is used. +# The Sage application loads it when starting up. +def load_ipython_extension(*args): + import sage.repl.ipython_extension + sage.repl.ipython_extension.load_ipython_extension(*args) + + +# The above used to be in sage.__init__, allowing users to use "%load_ext sage". +# But we are clearing out the __init__.py file as a preparation for +# making sage a native namespace package. +# +# So we make "%load_ext sage" work by monkey-patching the function +# into the sage package upon importing sage.repl. +import sage +sage.load_ipython_extension = load_ipython_extension diff --git a/src/sage/repl/display/fancy_repr.py b/src/sage/repl/display/fancy_repr.py index de3a5569ba5..2642b091f14 100644 --- a/src/sage/repl/display/fancy_repr.py +++ b/src/sage/repl/display/fancy_repr.py @@ -244,7 +244,7 @@ def __call__(self, obj, p, cycle): sage: from sage.repl.display.fancy_repr import PlainPythonRepr sage: pp = PlainPythonRepr() sage: pp.format_string(type(1)) - "" + "" Do not swallow a trailing newline at the end of the output of a custom representer. Note that it is undesirable to have a diff --git a/src/sage/repl/display/pretty_print.py b/src/sage/repl/display/pretty_print.py index 0948bdd6096..804115051ed 100644 --- a/src/sage/repl/display/pretty_print.py +++ b/src/sage/repl/display/pretty_print.py @@ -92,14 +92,14 @@ def __init__(self, output, max_width, newline, max_seq_length=None): sage: 'this is a string' 'this is a string' sage: type(123) - + sage: type <... 'type'> sage: import types sage: type('name', (), {}) sage: types.BuiltinFunctionType - + sage: def foo(): pass sage: foo diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index f37a712e9da..ded5cdbde78 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -506,13 +506,68 @@ def init_inspector(self): def init_line_transforms(self): """ Set up transforms (like the preparser). + + TESTS: + + Check that :trac:`31951` is fixed:: + + sage: from IPython import get_ipython + sage: ip = get_ipython() + sage: ip.input_transformer_manager.check_complete(''' # indirect doctest + ....: for i in [1 .. 2]: + ....: a = 2''') + ('incomplete', 2) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(L) + ....: K. = L''') + ('invalid', None) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(L): + ....: K. = L''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(L): + ....: K. = L''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(R): + ....: a = R.0''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(a): + ....: b = 2a''') + ('invalid', None) + sage: implicit_multiplication(True) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(a): + ....: b = 2a''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(): + ....: f(x) = x^2''') + ('incomplete', 4) + sage: ip.input_transformer_manager.check_complete(''' + ....: def foo(): + ....: 2.factor()''') + ('incomplete', 4) """ - from .interpreter import (SagePreparseTransformer, - SagePromptTransformer) + from IPython.core.inputtransformer2 import TransformerManager + from .interpreter import SagePromptTransformer, SagePreparseTransformer - self.shell.input_transformers_cleanup.insert(1, SagePromptTransformer) + self.shell.input_transformer_manager.cleanup_transforms.insert(1, SagePromptTransformer) self.shell.input_transformers_post.append(SagePreparseTransformer) + # Create an input transformer that does Sage's special syntax in the first step. + # We append Sage's preparse to the cleanup step, so that ``check_complete`` recognizes + # Sage's special syntax. + # Behaviour is somewhat inconsistent, but the syntax is recognized as desired. + M = TransformerManager() + M.token_transformers = self.shell.input_transformer_manager.token_transformers + M.cleanup_transforms.insert(1, SagePromptTransformer) + M.cleanup_transforms.append(SagePreparseTransformer) + self.shell._check_complete_transformer = M + self.shell.input_transformer_manager.check_complete = M.check_complete + class SageJupyterCustomizations(SageCustomizations): @staticmethod diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index e5ac7f7ab73..1226196294e 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -2,46 +2,6 @@ """ The Sage Preparser -AUTHORS: - - - William Stein (2006-02-19) - - - Fixed bug when loading .py files. - - - William Stein (2006-03-09) - - - Fixed crash in parsing exponentials. - - Precision of real literals now determined by digits of input - (like Mathematica). - - - Joe Wetherell (2006-04-14) - - - Added MAGMA-style constructor preparsing. - - - Bobby Moretti (2007-01-25) - - - Added preliminary function assignment notation. - - - Robert Bradshaw (2007-09-19) - - - Added strip_string_literals, containing_block utility - functions. Arrr! - - Added [1,2,..,n] notation. - - - Robert Bradshaw (2008-01-04) - - - Implicit multiplication (off by default). - - - Robert Bradshaw (2008-09-23) - - - Factor out constants. - - - Robert Bradshaw (2000-01) - - - Simplify preparser by making it modular and using regular - expressions. - - Bug fixes, complex numbers, and binary input. - EXAMPLES: Preparsing:: @@ -86,11 +46,11 @@ Raw and hex work correctly:: sage: type(0xa1) - + sage: type(0xa1r) - + sage: type(0Xa1R) - + The preparser can handle PEP 515 (see :trac:`28490`):: @@ -118,7 +78,7 @@ sage: eval('4.__add__(3)') Traceback (most recent call last): ... - SyntaxError: invalid syntax + SyntaxError: invalid ... Symbolic functional notation:: @@ -165,7 +125,7 @@ sage: a 393939 sage: type(a) - + We create a raw float:: @@ -173,7 +133,7 @@ sage: z 1.5949 sage: type(z) - + You can also use an upper case letter:: @@ -181,7 +141,7 @@ sage: z 3.1415 sage: type(z) - + This next example illustrates how raw literals can be very useful in certain cases. We make a list of even integers up to 10000:: @@ -245,6 +205,26 @@ sage: f'''1{ f"2{ f'4{ 2^3 }4' }2" }1''' '1248421' +AUTHORS: + +- William Stein (2006-02-19): fixed bug when loading .py files + +- William Stein (2006-03-09): fixed crash in parsing exponentials; precision of + real literals now determined by digits of input (like Mathematica) + +- Joe Wetherell (2006-04-14): added MAGMA-style constructor preparsing + +- Bobby Moretti (2007-01-25): added preliminary function assignment notation + +- Robert Bradshaw (2007-09-19): added strip_string_literals, containing_block + utility functions. Arrr!; added [1,2,..,n] notation + +- Robert Bradshaw (2008-01-04): implicit multiplication (off by default) + +- Robert Bradshaw (2008-09-23): factor out constants + +- Robert Bradshaw (2009-01): simplify preparser by making it modular and using + regular expressions; bug fixes, complex numbers, and binary input """ # **************************************************************************** @@ -1105,6 +1085,7 @@ def parse_ellipsis(code, preparse_step=True): ix = code.find('..') return code + def extract_numeric_literals(code): """ Pulls out numeric literals and assigns them to global variables. @@ -1493,11 +1474,17 @@ def preparse_calculus(code): ....: ''') '\n__tmp__=var("a,b,c,d"); f = symbolic_expression(a + b*Integer(2) + c*Integer(3) + d*Integer(4)).function(a,b,c,d)\n' + Check that :trac:`30953` is fixed:: + + sage: preparse(''' + ....: f(x) = (x + (x*x) + # some comment with matching ) + ....: 1); f''') + '\n__tmp__=var("x"); f = symbolic_expression((x + (x*x) + # some comment with matching )\n Integer(1))).function(x); f' """ new_code = [] last_end = 0 # f ( vars ) = expr - for m in re.finditer(r";(\s*)([^\W\d]\w*) *\(([^()]+)\) *= *([^;#=][^;#]*)", code): + for m in re.finditer(r";(\s*)([^\W\d]\w*) *\(([^()]+)\) *= *([^;#=][^;]*)", code): ident, func, vars, expr = m.groups() # Semicolons are removed in order to allow the vars to span multiple lines. # (preparse having converted all \n into ;\n;) @@ -1646,11 +1633,25 @@ def preparse_generators(code): sage: preparse('Ω.<λ,μ> = QQ[]') "Ω = QQ['λ, μ']; (λ, μ,) = Ω._first_ngens(2)" + + Check that :trac:`30953` is fixed:: + + sage: preparse(''' + ....: K. = QuadraticField(2 + + ....: 1)''') + "\nK = QuadraticField(Integer(2) +\n Integer(1), names=('a',)); (a,) = K._first_ngens(1)" + sage: preparse(''' + ....: K. = QuadraticField(2 + (1 + 1) + # some comment + ....: 1)''') + "\nK = QuadraticField(Integer(2) + (Integer(1) + Integer(1)) + # some comment\n Integer(1), names=('a',)); (a,) = K._first_ngens(1)" + sage: preparse(''' + ....: K. = QuadraticField(2) # some comment''') + "\nK = QuadraticField(Integer(2), names=('a',)); (a,) = K._first_ngens(1)# some comment" """ new_code = [] last_end = 0 # obj .< gens > , other = constructor - for m in re.finditer(r";(\s*)([^\W\d]\w*)\.<([^>]+)> *((?:,[\w, ]+)?)= *([^;#]+)", code): + for m in re.finditer(r";(\s*)([^\W\d]\w*)\.<([^>]+)> *((?:,[\w, ]+)?)= *([^;]+)", code): ident, obj, gens, other_objs, constructor = m.groups() gens = [v.strip() for v in gens.split(',')] constructor = constructor.rstrip() @@ -1690,6 +1691,7 @@ def preparse_generators(code): quote_state = None + def preparse(line, reset=True, do_time=False, ignore_prompts=False, numeric_literals=True): r""" @@ -1745,7 +1747,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, 'a * BackslashOperator() * b \\' sage: preparse("time R. = ZZ[]", do_time=True) - '__time__=cputime(); __wall__=walltime(); R = ZZ[\'x\']; print("Time: CPU %.2f s, Wall: %.2f s"%(cputime(__time__), walltime(__wall__))); (x,) = R._first_ngens(1)' + '__time__ = cputime(); __wall__ = walltime(); R = ZZ[\'x\']; print("Time: CPU {:.2f} s, Wall: {:.2f} s".format(cputime(__time__), walltime(__wall__))); (x,) = R._first_ngens(1)' TESTS: @@ -1767,6 +1769,13 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, # some comment __tmp__=var("x"); f = symbolic_expression(x + Integer(1)).function(x) + TESTS:: + + sage: from sage.repl.preparse import preparse + sage: lots_of_numbers = "[%s]" % ", ".join(str(i) for i in range(3000)) + sage: _ = preparse(lots_of_numbers) + sage: print(preparse("type(100r), type(100)")) + type(100), type(Integer(100)) """ global quote_state if reset: @@ -1817,7 +1826,21 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, L = L.replace('\\\n', '') # Make it easy to match statement ends - L = ';%s;' % L.replace('\n', ';\n;') + ends = [] + counta = 0 + countb = 0 + for i in range(len(L)): + if L[i] in ('[', ']'): + counta += 1 if L[i] == '[' else -1 + elif L[i] in ('(', ')'): + countb += 1 if L[i] == '(' else -1 + elif L[i] in ('\n', '#'): + if counta == countb == 0: + ends.append(i) + while ends: + i = ends.pop() + L = L[:i] + ';%s;' % L[i] + L[i+1:] + L = ';' + L + ';' if do_time: # Separate time statement @@ -1837,12 +1860,13 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, if do_time: # Time keyword - L = re.sub(r';time;(\s*)(\S[^;]*)', - r';\1__time__=cputime(); __wall__=walltime(); \2; print(' + - '"Time: CPU %%.2f s, Wall: %%.2f s"%%(cputime(__time__), walltime(__wall__)))', - L) + L = re.sub(r';time;(\s*)(\S[^;\n]*)', + r';\1__time__ = cputime(); __wall__ = walltime(); \2; print(' + + r'"Time: CPU {:.2f} s, Wall: {:.2f} s".format(cputime(__time__), walltime(__wall__)))', + L, flags=re.MULTILINE) # Remove extra ;'s + L = L.replace(';#;', '#') L = L.replace(';\n;', '\n')[1:-1] line = L % literals @@ -1856,7 +1880,9 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, def preparse_file(contents, globals=None, numeric_literals=True): """ - Preparses input, attending to numeric literals and load/attach + Preparse ``contents`` which is input from a file such as ``.sage`` files. + + Special attentions are given to numeric literals and load/attach file directives. .. note:: Temporarily, if @parallel is in the input, then @@ -1886,6 +1912,25 @@ def preparse_file(contents, globals=None, numeric_literals=True): sage: print(preparse_file("type(100r), type(100)")) _sage_const_100 = Integer(100) type(100 ), type(_sage_const_100 ) + + Check that :trac:`4545` is fixed:: + + sage: file_contents = ''' + ....: @parallel(8) + ....: def f(p): + ....: t = cputime() + ....: M = ModularSymbols(p^2,sign=1) + ....: w = M.atkin_lehner_operator(p) + ....: K = (w-1).kernel() + ....: N = K.new_subspace() + ....: D = N.decomposition()''' + sage: t = tmp_filename(ext=".sage") + sage: with open(t, 'w') as f: + ....: f.write(file_contents) + 185 + sage: load(t) + sage: sorted(list(f([11,17]))) + [(((11,), {}), None), (((17,), {}), None)] """ if not isinstance(contents, str): raise TypeError("contents must be a string") @@ -1893,12 +1938,6 @@ def preparse_file(contents, globals=None, numeric_literals=True): if globals is None: globals = {} - # This is a hack, since when we use @parallel to parallelize code, - # the numeric literals that are factored out do not get copied - # to the subprocesses properly. See trac #4545. - if '@parallel' in contents: - numeric_literals = False - if numeric_literals: contents, literals, state = strip_string_literals(contents) contents, nums = extract_numeric_literals(contents) @@ -2017,7 +2056,6 @@ def re_no_keyword(pattern, code): return code % literals - def _strip_quotes(s): """ Strips one set of outer quotes. diff --git a/src/sage/repl/rich_output/pretty_print.py b/src/sage/repl/rich_output/pretty_print.py index 9d4b5927f2b..f45ca3d126b 100644 --- a/src/sage/repl/rich_output/pretty_print.py +++ b/src/sage/repl/rich_output/pretty_print.py @@ -164,7 +164,7 @@ def pretty_print(self): sage: seq._concatenate_graphs().show(edge_labels=True) Traceback (most recent call last): ... - TypeError: matplotlib() got an unexpected keyword argument 'edge_labels' + TypeError: ...matplotlib() got an unexpected keyword argument 'edge_labels' """ from sage.plot.plot import Graphics from sage.graphs.graph import GenericGraph diff --git a/src/sage/rings/algebraic_closure_finite_field.py b/src/sage/rings/algebraic_closure_finite_field.py index f86aab174b9..a0d5bac9d76 100644 --- a/src/sage/rings/algebraic_closure_finite_field.py +++ b/src/sage/rings/algebraic_closure_finite_field.py @@ -865,17 +865,14 @@ def gens(self): sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F = AlgebraicClosureFiniteField(GF(5), 'z') - sage: g = F.gens() - sage: g - Lazy family ((i))_{i in Positive integers} + sage: g = F.gens(); g + Lazy family (...(i))_{i in Positive integers} sage: g[3] z3 - """ from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers - - return Family(PositiveIntegers(), lambda n: self.gen(n)) + return Family(PositiveIntegers(), self.gen) def _first_ngens(self, n): """ diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 50f0a4e190c..a8a1da9ff3d 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -120,7 +120,7 @@ from .laurent_series_ring_element import LaurentSeries # Lazy Laurent series ring -lazy_import('sage.rings.lazy_laurent_series_ring', 'LazyLaurentSeriesRing') +lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyDirichletSeriesRing']) # Tate algebras from .tate_algebra import TateAlgebra diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index 2fc0a3bb420..9aa6ba15d7b 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -1040,8 +1040,8 @@ class ComplexBallField(UniqueRepresentation, Field): sage: CBF.integral(lambda x, _: x, 0, 1) [0.500000000000000 +/- ...e-16] - sage: CBF.integral(lambda x, _: x.gamma(), 1 - CBF(i), 1 + CBF(i)) - [+/- 4...e-15] + [1.5723926694981 +/- 4...e-14]*I + sage: CBF.integral(lambda x, _: x.gamma(), 1 - CBF(i), 1 + CBF(i)) # abs tol 1e-13 + [+/- 1.39e-15] + [1.57239266949806 +/- 8.33e-15]*I sage: C = ComplexBallField(100) sage: C.integral(lambda x, _: x.cos() * x.sin(), 0, 1) @@ -1144,8 +1144,8 @@ class ComplexBallField(UniqueRepresentation, Field): [50.00000000 +/- ...e-9] sage: i = QuadraticField(-1).gen() - sage: CBF.integral(lambda x, _: (1 + i*x).gamma(), -1, 1) - [1.5723926694981 +/- 4...e-14] + [+/- 4...e-15]*I + sage: CBF.integral(lambda x, _: (1 + i*x).gamma(), -1, 1) # abs tol 1e-13 + [1.57239266949806 +/- 8.33e-15] + [+/- 1.39e-15]*I sage: ComplexBallField(10000).integral(lambda x, _: x.sin(), 0, 1, rel_tol=1e-300) [0.459... +/- ...e-3...] @@ -2976,8 +2976,8 @@ cdef class ComplexBall(RingElement): [+/- ...e+347382171326740403407] sage: ComplexBallField(128)(1).rising_factorial(2**64) [2.343691126796861348e+347382171305201285713 +/- ...e+347382171305201285694] - sage: CBF(1/2).rising_factorial(CBF(2,3)) - [-0.123060451458124 +/- ...e-16] + [0.040641263167655 +/- ...e-16]*I + sage: CBF(1/2).rising_factorial(CBF(2,3)) # abs tol 1e-15 + [-0.123060451458124 +/- 3.06e-16] + [0.0406412631676552 +/- 7.57e-17]*I """ cdef ComplexBall result = self._new() @@ -3488,16 +3488,16 @@ cdef class ComplexBall(RingElement): EXAMPLES:: - sage: CBF(1, 1).gamma() - [0.498015668118356 +/- ...e-16] + [-0.154949828301811 +/- ...e-16]*I + sage: CBF(1, 1).gamma() # abs tol 1e-15 + [0.498015668118356 +/- 1.26e-16] + [-0.1549498283018107 +/- 8.43e-17]*I sage: CBF(-1).gamma() nan - sage: CBF(1, 1).gamma(0) - [0.498015668118356 +/- ...e-16] + [-0.154949828301811 +/- ...e-16]*I + sage: CBF(1, 1).gamma(0) # abs tol 1e-15 + [0.498015668118356 +/- 1.26e-16] + [-0.1549498283018107 +/- 8.43e-17]*I sage: CBF(1, 1).gamma(100) [-3.6143867454139e-45 +/- ...e-59] + [-3.7022961377791e-44 +/- ...e-58]*I - sage: CBF(1, 1).gamma(CLF(i)) - [0.32886684193500 +/- ...e-15] + [-0.18974945045621 +/- ...e-15]*I + sage: CBF(1, 1).gamma(CLF(i)) # abs tol 1e-14 + [0.328866841935004 +/- 7.07e-16] + [-0.189749450456210 +/- 9.05e-16]*I """ cdef ComplexBall my_z cdef ComplexBall res = self._new() @@ -3536,9 +3536,9 @@ cdef class ComplexBall(RingElement): sage: CBF(-1/2).log_gamma() [1.265512123484645 +/- ...e-16] + [-3.141592653589793 +/- ...e-16]*I sage: CBF(-1).log_gamma() - nan + [-3.141592653589793 +/- ...e-16]*I - sage: CBF(-3/2).log_gamma() - [0.860047015376481 +/- ...e-16] + [-6.28318530717959 +/- ...e-15]*I + nan + ...*I + sage: CBF(-3/2).log_gamma() # abs tol 1e-14 + [0.860047015376481 +/- 3.82e-16] + [-6.283185307179586 +/- 6.77e-16]*I sage: CBF(-3/2).log_gamma(analytic=True) nan + nan*I """ @@ -3822,8 +3822,8 @@ cdef class ComplexBall(RingElement): sage: CBF(1, 1).hypergeometric([1], []) 1.000000000000000*I - sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2]) - [0.7871684267473 +/- 7...e-14] + [0.2749254173721 +/- 9...e-14]*I + sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2]) # abs tol 1e-14 + [0.7871684267473 +/- 6.79e-14] + [0.2749254173721 +/- 8.82e-14]*I sage: CBF(2+3*I).hypergeometric([1/4,1/3],[1/2],regularized=True) [0.4441122268685 +/- 3...e-14] + [0.1551100567338 +/- 5...e-14]*I @@ -3832,8 +3832,8 @@ cdef class ComplexBall(RingElement): sage: CBF(5).hypergeometric([2,3], [-5], regularized=True) [5106.925964355 +/- ...e-10] - sage: CBF(2016).hypergeometric([], [2/3]) - [2.025642692328e+38 +/- ...e+25] + sage: CBF(2016).hypergeometric([], [2/3]) # abs tol 1e+26 + [2.0256426923278e+38 +/- 9.59e+24] sage: CBF(-2016).hypergeometric([], [2/3], regularized=True) [-0.0005428550847 +/- ...e-14] @@ -4927,8 +4927,8 @@ cdef class ComplexBall(RingElement): [-45.6666666666666 +/- ...e-14] sage: CBF(10).laguerre_L(3, 2) [-6.666666666667 +/- ...e-13] - sage: CBF(5,7).laguerre_L(CBF(2,3), CBF(1,-2)) - [5515.315030271 +/- ...e-10] + [-12386.942845271 +/- ...e-10]*I + sage: CBF(5,7).laguerre_L(CBF(2,3), CBF(1,-2)) # abs tol 1e-9 + [5515.3150302713 +/- 5.02e-11] + [-12386.9428452714 +/- 6.21e-11]*I """ cdef ComplexBall my_n = self._parent.coerce(n) cdef ComplexBall my_m = self._parent.coerce(m) diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index e732148a9a0..9d91fa13048 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -107,7 +107,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): sage: ComplexIntervalFieldElement.__new__(ComplexIntervalFieldElement) Traceback (most recent call last): ... - TypeError: __cinit__() takes at least 1 positional argument (0 given) + TypeError: ...__cinit__() takes at least 1 positional argument (0 given) sage: ComplexIntervalFieldElement.__new__(ComplexIntervalFieldElement, CIF) [.. NaN ..] + [.. NaN ..]*I """ diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index 3021ab5d177..012344ea2a9 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -971,7 +971,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): sage: coerce(CN, 1+I) Traceback (most recent call last): ... - TypeError: __init__() takes at least 2 positional arguments (1 given) + TypeError: ...__init__() takes at least 2 positional arguments (1 given) """ if self._prec != -1: mpfr_clear(self.__re) diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index f3183df44aa..5fc4a0e6d4d 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1257,8 +1257,8 @@ cdef class FiniteField(Field): if inclusion_map is None: inclusion_map = self.coerce_map_from(base) - from sage.modules.all import vector - from sage.matrix.all import matrix + from sage.modules.free_module_element import vector + from sage.matrix.constructor import matrix from .maps_finite_field import ( MorphismVectorSpaceToFiniteField, MorphismFiniteFieldToVectorSpace) diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 3290a11ab19..0980ff8dbdf 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -513,7 +513,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, sage: GF.create_key_and_extra_args(9, 'a', foo='value') Traceback (most recent call last): ... - TypeError: create_key_and_extra_args() got an unexpected keyword argument 'foo' + TypeError: ...create_key_and_extra_args() got an unexpected keyword argument 'foo' Moreover, ``repr`` and ``elem_cache`` are ignored when not using givaro:: diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index b7d7c1127fb..6c2945fbc64 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -3402,7 +3402,7 @@ def L_polynomial(self, name='t'): sage: F.L_polynomial() 2*t^2 + t + 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ q = self.constant_field().order() g = self.genus() diff --git a/src/sage/rings/function_field/function_field_valuation.py b/src/sage/rings/function_field/function_field_valuation.py index 2bcff1b1d25..bff8ad4b1b3 100644 --- a/src/sage/rings/function_field/function_field_valuation.py +++ b/src/sage/rings/function_field/function_field_valuation.py @@ -150,7 +150,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from sage.structure.factory import UniqueFactory -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method from sage.rings.valuation.valuation import DiscreteValuation, DiscretePseudoValuation, InfiniteDiscretePseudoValuation, NegativeInfiniteDiscretePseudoValuation @@ -1247,7 +1247,7 @@ def scale(self, scalar): 3 * (x)-adic valuation (in Rational function field in x over Finite Field of size 2 after x |--> 1/x) """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if scalar in QQ and scalar > 0 and scalar != 1: return self.domain().valuation((self._base_valuation.scale(scalar), self._to_base, self._from_base)) return super(FunctionFieldMappedValuation_base, self).scale(scalar) diff --git a/src/sage/rings/function_field/maps.py b/src/sage/rings/function_field/maps.py index cdd1b6735d0..9ab384ec14c 100644 --- a/src/sage/rings/function_field/maps.py +++ b/src/sage/rings/function_field/maps.py @@ -269,7 +269,7 @@ def __init__(self, L, d): x = self.domain().gen() f = L.polynomial() self._d = d - self._gen_image = - f.map_coefficients(lambda c: d(c))(x) / f.derivative()(x) + self._gen_image = - f.map_coefficients(d)(x) / f.derivative()(x) def _call_(self, x): r""" @@ -1777,7 +1777,7 @@ def __init__(self, field, place, name=None, prec=None, gen_name=None): self._gen_name = gen_name if prec == infinity: - from sage.rings.lazy_laurent_series_ring import LazyLaurentSeriesRing + from sage.rings.lazy_series_ring import LazyLaurentSeriesRing codomain = LazyLaurentSeriesRing(k, name) self._precision = infinity else: # prec < infinity: diff --git a/src/sage/rings/function_field/place.py b/src/sage/rings/function_field/place.py index d95b0d84ef9..43abc67a6fb 100644 --- a/src/sage/rings/function_field/place.py +++ b/src/sage/rings/function_field/place.py @@ -59,7 +59,7 @@ from sage.arith.all import lcm -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.qqbar import QQbar from sage.rings.number_field.number_field_base import NumberField diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 53076ac62ed..3a135b8f982 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -693,7 +693,7 @@ def is_maximal(self): sage: S.ideal(4).is_maximal() False """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ R = self.ring() if hasattr(R, 'cover_ring') and R.cover_ring() is ZZ: # The following test only works for quotients of Z/nZ: for @@ -821,7 +821,7 @@ def is_prime(self): For general rings, uses the list of associated primes. """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ R = self.ring() if hasattr(R, 'cover_ring') and R.cover_ring() is ZZ and R.is_finite(): # For quotient rings of ZZ, prime is the same as maximal. diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 1ca45d0fa27..f468b59bf68 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -2814,7 +2814,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): raise ValueError("log base must be positive") self_sgn = mpz_sgn(self.value) if self_sgn < 0 and prec is None: - from sage.symbolic.all import SR + from sage.symbolic.ring import SR return SR(self).log(m) if prec: if self_sgn >= 0: @@ -3234,7 +3234,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if self.parent() is ZZ: return abs(self) raise NotImplementedError diff --git a/src/sage/rings/invariants/invariant_theory.py b/src/sage/rings/invariants/invariant_theory.py index 059a774025b..dddd27f784e 100644 --- a/src/sage/rings/invariants/invariant_theory.py +++ b/src/sage/rings/invariants/invariant_theory.py @@ -928,7 +928,7 @@ def transformed(self, g): if isinstance(g, dict): transform = g else: - from sage.modules.all import vector + from sage.modules.free_module_element import vector v = vector(self._ring, self._variables) g_v = vector(self._ring, g*v) transform = dict( (v[i], g_v[i]) for i in range(self._n) ) diff --git a/src/sage/rings/invariants/reconstruction.py b/src/sage/rings/invariants/reconstruction.py index 321b7705868..b9db4e07521 100644 --- a/src/sage/rings/invariants/reconstruction.py +++ b/src/sage/rings/invariants/reconstruction.py @@ -375,7 +375,7 @@ def _reduce_invariants(invariants, weights): sage: _reduce_invariants(invariants, weights) [3, 75, 250] """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ factors = [dict(I.factor()) for I in invariants] scalar = ZZ(1) n = len(weights) diff --git a/src/sage/rings/lazy_laurent_series.py b/src/sage/rings/lazy_series.py similarity index 60% rename from src/sage/rings/lazy_laurent_series.py rename to src/sage/rings/lazy_series.py index ce17f93d44e..0892554f272 100644 --- a/src/sage/rings/lazy_laurent_series.py +++ b/src/sage/rings/lazy_series.py @@ -1,9 +1,10 @@ +# -*- coding: utf-8 -*- r""" -Lazy Laurent Series +Lazy Series -A lazy Laurent series is a Laurent series whose coefficients are -computed on demand. Therefore, unlike the usual Laurent series in -Sage, lazy Laurent series have infinite precision. +A lazy series is a series whose coefficients are computed on demand. +Therefore, unlike the usual Laurent/power/etc. series in Sage, +lazy series have infinite precision. EXAMPLES: @@ -86,13 +87,14 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - -from sage.rings.infinity import infinity -from sage.structure.element import Element -from sage.rings.integer_ring import ZZ +from sage.structure.element import Element, parent from sage.structure.richcmp import op_EQ, op_NE +from sage.functions.other import factorial from sage.arith.power import generic_power +from sage.rings.infinity import infinity +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.data_structures.stream import ( Stream_add, Stream_cauchy_mul, @@ -106,7 +108,10 @@ Stream_zero, Stream_exact, Stream_uninitialized, - Stream_shift + Stream_shift, + Stream_function, + Stream_dirichlet_convolve, + Stream_dirichlet_invert ) class LazyModuleElement(Element): @@ -157,6 +162,10 @@ def __init__(self, parent, coeff_stream): sage: L. = LazyLaurentSeriesRing(ZZ) sage: TestSuite(L.an_element()).run() + sage: L = LazyDirichletSeriesRing(QQbar, 'z') + sage: g = L(constant=1) + sage: TestSuite(g).run() + """ Element.__init__(self, parent) self._coeff_stream = coeff_stream @@ -186,6 +195,24 @@ def __getitem__(self, n): sage: M = L(lambda n: n, valuation=0) sage: [M[n] for n in range(20)] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: f = L(lambda n: n) + sage: [f[n] for n in range(1, 11)] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sage: f[1:11] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + sage: M = L(lambda n: n) + sage: [M[n] for n in range(1, 11)] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) + sage: M = L(lambda n: n) + sage: [M[n] for n in range(1, 11)] + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + """ R = self.parent()._coeff_ring if isinstance(n, slice): @@ -238,6 +265,14 @@ def map_coefficients(self, func, ring=None): sage: f.map_coefficients(lambda c: c + 1) 2*z + 2*z^2 + 2*z^3 + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: s = L(lambda n: n-1); s + 1/(2^z) + 2/3^z + 3/4^z + 4/5^z + 5/6^z + 6/7^z + O(1/(8^z)) + sage: s.map_coefficients(lambda c: c + 1) + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) + TESTS:: sage: from sage.data_structures.stream import Stream_zero @@ -315,43 +350,100 @@ def truncate(self, d): return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, order=v)) - def prec(self): - """ - Return the precision of the series, which is infinity. + def shift(self, n): + r""" + Return ``self`` with the indices shifted by ``n``. + + For example, a Laurent series is multiplied by the power `z^n`, + where `z` is the variable of ``self``. EXAMPLES:: sage: L. = LazyLaurentSeriesRing(ZZ) - sage: f = 1/(1 - z) - sage: f.prec() - +Infinity + sage: f = 1 / (1 + 2*z) + sage: f + 1 - 2*z + 4*z^2 - 8*z^3 + 16*z^4 - 32*z^5 + 64*z^6 + O(z^7) + sage: f.shift(3) + z^3 - 2*z^4 + 4*z^5 - 8*z^6 + 16*z^7 - 32*z^8 + 64*z^9 + O(z^10) + sage: f << -3 # shorthand + z^-3 - 2*z^-2 + 4*z^-1 - 8 + 16*z - 32*z^2 + 64*z^3 + O(z^4) + sage: g = z^-3 + 3 + z^2 + sage: g.shift(5) + z^2 + 3*z^5 + z^7 + sage: L([2,0,3], valuation=2, degree=7, constant=1) << -2 + 2 + 3*z^2 + z^5 + z^6 + z^7 + O(z^8) + + sage: D = LazyDirichletSeriesRing(QQ, 't') + sage: f = D([0,1,2]); f + 1/(2^t) + 2/3^t + sage: f.shift(3) + 1/(5^t) + 2/6^t + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: zero = L.zero() + sage: zero.shift(10) is zero + True + + sage: f = 1 / (1 + 2*z + z^2) + sage: f.shift(5).shift(-5) - f + 0 + """ - return infinity + if isinstance(self._coeff_stream, Stream_zero): + return self + elif isinstance(self._coeff_stream, Stream_shift): + n += self._coeff_stream._shift + if n: + coeff_stream = Stream_shift(self._coeff_stream._series, n) + else: + coeff_stream = self._coeff_stream._series + elif isinstance(self._coeff_stream, Stream_exact): + init_coeff = self._coeff_stream._initial_coefficients + degree = self._coeff_stream._degree + n + valuation = self._coeff_stream._approximate_order + n + coeff_stream = Stream_exact(init_coeff, self._coeff_stream._is_sparse, + constant=self._coeff_stream._constant, + order=valuation, degree=degree) + else: + coeff_stream = Stream_shift(self._coeff_stream, n) + P = self.parent() + return P.element_class(P, coeff_stream) - def valuation(self): + __lshift__ = shift + + def __rshift__(self, n): r""" - Return the valuation of ``self``. + Return ``self`` with the indices shifted right by ``n``. - This method determines the valuation of the series by looking for a - nonzero coefficient. Hence if the series happens to be zero, then it - may run forever. + For example, a Laurent series is multiplied by the power `z^-n`, + where `z` is the variable of ``self``. EXAMPLES:: sage: L. = LazyLaurentSeriesRing(ZZ) - sage: s = 1/(1 - z) - 1/(1 - 2*z) - sage: s.valuation() - 1 - sage: t = z - z - sage: t.valuation() - +Infinity - sage: M = L(lambda n: n^2, valuation=0) - sage: M.valuation() - 1 - sage: (M - M).valuation() + sage: f = 1/(1 + 2*z); f + 1 - 2*z + 4*z^2 - 8*z^3 + 16*z^4 - 32*z^5 + 64*z^6 + O(z^7) + sage: f >> 3 + z^-3 - 2*z^-2 + 4*z^-1 - 8 + 16*z - 32*z^2 + 64*z^3 + O(z^4) + sage: f >> -3 + z^3 - 2*z^4 + 4*z^5 - 8*z^6 + 16*z^7 - 32*z^8 + 64*z^9 + O(z^10) + """ + return self.shift(-n) + + def prec(self): + """ + Return the precision of the series, which is infinity. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: f = 1/(1 - z) + sage: f.prec() +Infinity """ - return self._coeff_stream.order() + return infinity def _richcmp_(self, other, op): r""" @@ -582,6 +674,22 @@ def define(self, s): sage: [T[i] for i in range(6)] [0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q] + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: g = L(constant=1, valuation=2) + sage: F = L(None); F.define(1 + g*F) + sage: [F[i] for i in range(1, 16)] + [1, 1, 1, 2, 1, 3, 1, 4, 2, 3, 1, 8, 1, 3, 3] + sage: oeis(_) # optional, internet + 0: A002033: Number of perfect partitions of n. + 1: A074206: Kalmár's [Kalmar's] problem: number of ordered factorizations of n. + ... + + sage: F = L(None); F.define(1 + g*F*F) + sage: [F[i] for i in range(1, 16)] + [1, 1, 1, 3, 1, 5, 1, 10, 3, 5, 1, 24, 1, 5, 5] + TESTS:: sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) @@ -600,56 +708,276 @@ def define(self, s): Traceback (most recent call last): ... ValueError: series already defined + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: L. = LazyLaurentSeriesRing(QQ) + sage: e = L(lambda n: 1/factorial(n), 0) + sage: g = D(None, valuation=2) + sage: o = D(constant=1, valuation=2) + sage: g.define(o * e(g)) + sage: g + 1/(2^s) + 1/(3^s) + 2/4^s + 1/(5^s) + 3/6^s + 1/(7^s) + 9/2/8^s + O(1/(9^s)) """ if not isinstance(self._coeff_stream, Stream_uninitialized) or self._coeff_stream._target is not None: raise ValueError("series already defined") self._coeff_stream._target = s._coeff_stream - # === module structure === + def _repr_(self): + r""" + Return a string representation of ``self``. - def _add_(self, other): - """ - Return the sum of ``self`` and ``other``. + EXAMPLES:: - INPUT: + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: z^-3 + z - 5 + z^-3 - 5 + z + sage: -1/(1 + 2*z) + -1 + 2*z - 4*z^2 + 8*z^3 - 16*z^4 + 32*z^5 - 64*z^6 + O(z^7) + sage: -z^-7/(1 + 2*z) + -z^-7 + 2*z^-6 - 4*z^-5 + 8*z^-4 - 16*z^-3 + 32*z^-2 - 64*z^-1 + O(1) + sage: L([1,5,0,3], valuation=-1, degree=5, constant=2) + z^-1 + 5 + 3*z^2 + 2*z^5 + 2*z^6 + 2*z^7 + O(z^8) + sage: L(constant=5, valuation=2) + 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) + sage: L(constant=5, degree=-2) + 5*z^-2 + 5*z^-1 + 5 + O(z) + sage: L(lambda x: x if x < 0 else 0, valuation=-2) + -2*z^-2 - z^-1 + O(z^5) + sage: L(lambda x: x if x < 0 else 0, valuation=2) + O(z^9) + sage: L(lambda x: x if x > 0 else 0, valuation=-2) + z + 2*z^2 + 3*z^3 + 4*z^4 + O(z^5) + sage: L(lambda x: x if x > 0 else 0, valuation=-10) + O(z^-3) - - ``other`` -- other series + sage: L(None, valuation=0) + Uninitialized Lazy Laurent Series + sage: L(0) + 0 - EXAMPLES: + sage: R. = QQ[] + sage: L. = LazyLaurentSeriesRing(R) + sage: z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4 + (-y + 1)*z^-4 + x^4*z^-3 + z^-2 + (x - y)*z^-1 + + (x^2 - 2*x*y + y^2) + (x^3 - 3*x^2*y + 3*x*y^2 - y^3)*z + + (x^4 - 4*x^3*y + 6*x^2*y^2 - 4*x*y^3 + y^4)*z^2 + O(z^3) + """ + if isinstance(self._coeff_stream, Stream_zero): + return '0' + if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: + return 'Uninitialized Lazy Laurent Series' + return self._format_series(repr) - Dense series can be added:: + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: sage: L. = LazyLaurentSeriesRing(ZZ) - sage: m = L(lambda n: 1 + n, valuation=0) - sage: n = L(lambda n: -n, valuation=0) - sage: s = m + n - sage: s[0:10] - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + sage: latex(z^-3 + z - 5) + \frac{1}{z^{3}} - 5 + z + sage: latex(-1/(1 + 2*z)) + -1 + 2z - 4z^{2} + 8z^{3} - 16z^{4} + 32z^{5} - 64z^{6} + O(z^{7}) + sage: latex(-z^-7/(1 + 2*z)) + \frac{-1}{z^{7}} + \frac{2}{z^{6}} + \frac{-4}{z^{5}} + \frac{8}{z^{4}} + + \frac{-16}{z^{3}} + \frac{32}{z^{2}} + \frac{-64}{z} + O(1) + sage: latex(L([1,5,0,3], valuation=-1, degree=5, constant=2)) + \frac{1}{z} + 5 + 3z^{2} + 2z^{5} + 2z^{6} + 2z^{7} + O(z^{8}) + sage: latex(L(constant=5, valuation=2)) + 5z^{2} + 5z^{3} + 5z^{4} + O(z^{5}) + sage: latex(L(constant=5, degree=-2)) + \frac{5}{z^{2}} + \frac{5}{z} + 5 + O(z) + sage: latex(L(lambda x: x if x < 0 else 0, valuation=-2)) + \frac{-2}{z^{2}} + \frac{-1}{z} + O(z^{5}) + sage: latex(L(lambda x: x if x < 0 else 0, valuation=2)) + O(z^{9}) + sage: latex(L(lambda x: x if x > 0 else 0, valuation=-2)) + z + 2z^{2} + 3z^{3} + 4z^{4} + O(z^{5}) + sage: latex(L(lambda x: x if x > 0 else 0, valuation=-10)) + O(\frac{1}{z^{3}}) - Sparse series can be added:: + sage: latex(L(None, valuation=0)) + \text{\texttt{Undef}} + sage: latex(L(0)) + 0 - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: m = L(lambda n: 1 + n, valuation=0) - sage: n = L(lambda n: -n, valuation=0) - sage: s = m + n - sage: s[0:10] - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + sage: R. = QQ[] + sage: L. = LazyLaurentSeriesRing(R) + sage: latex(z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4) + \frac{-y + 1}{z^{4}} + \frac{x^{4}}{z^{3}} + \frac{1}{z^{2}} + + \frac{x - y}{z} + x^{2} - 2 x y + y^{2} + + \left(x^{3} - 3 x^{2} y + 3 x y^{2} - y^{3}\right)z + + \left(x^{4} - 4 x^{3} y + 6 x^{2} y^{2} - 4 x y^{3} + y^{4}\right)z^{2} + + O(z^{3}) + """ + from sage.misc.latex import latex + if isinstance(self._coeff_stream, Stream_zero): + return latex('0') + if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: + return latex("Undef") + return self._format_series(latex) - Series which are known to be exact can be added:: + def _ascii_art_(self): + r""" + Return an ascii art representation of ``self``. - sage: m = L(1) - sage: n = L([0, 1]) - sage: s = m + n - sage: s[0:10] - [1, 1, 0, 0, 0, 0, 0, 0, 0, 0] + EXAMPLES:: - Adding zero gives the same series:: + sage: e = SymmetricFunctions(QQ).e() + sage: L. = LazyLaurentSeriesRing(e) + sage: L.options.display_length = 3 + sage: ascii_art(1 / (1 - e[1]*z)) + e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) + sage: L.options._reset() + """ + from sage.typeset.ascii_art import ascii_art, AsciiArt + if isinstance(self._coeff_stream, Stream_zero): + return AsciiArt('0') + if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: + return AsciiArt('Uninitialized Lazy Laurent Series') + return self._format_series(ascii_art, True) - sage: m = L(lambda n: 1 + n, valuation=0) - sage: m + 0 is 0 + m is m - True + def _unicode_art_(self): + r""" + Return a unicode art representation of ``self``. + + EXAMPLES:: + + sage: e = SymmetricFunctions(QQ).e() + sage: L. = LazyLaurentSeriesRing(e) + sage: L.options.display_length = 3 + sage: unicode_art(1 / (1 - e[1]*z)) + e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) + sage: L.options._reset() """ - P = self.parent() + from sage.typeset.unicode_art import unicode_art, UnicodeArt + if isinstance(self._coeff_stream, Stream_zero): + return UnicodeArt('0') + if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: + return UnicodeArt('Uninitialized Lazy Laurent Series') + return self._format_series(unicode_art, True) + + + def change_ring(self, ring): + r""" + Return ``self`` with coefficients converted to elements of ``ring``. + + INPUT: + + - ``ring`` -- a ring + + EXAMPLES: + + Dense Implementation:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: s = 2 + z + sage: t = s.change_ring(QQ) + sage: t^-1 + 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Laurent Series Ring in z over Rational Field + sage: M.parent() + Lazy Laurent Series Ring in z over Integer Ring + + Sparse Implementation:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M.parent() + Lazy Laurent Series Ring in z over Integer Ring + sage: N = M.change_ring(QQ) + sage: N.parent() + Lazy Laurent Series Ring in z over Rational Field + sage: M^-1 + z^-1 - 2 + z + O(z^6) + + A Dirichlet series example:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: s = L(constant=2) + sage: t = s.change_ring(QQ) + sage: t.parent() + Lazy Dirichlet Series Ring in z over Rational Field + sage: t^-1 + 1/2 - 1/2/2^z - 1/2/3^z - 1/2/5^z + 1/2/6^z - 1/2/7^z + O(1/(8^z)) + """ + P = self.parent() + Q = type(P)(ring, names=P.variable_names(), sparse=P._sparse) + return Q.element_class(Q, self._coeff_stream) + + # === module structure === + + def _add_(self, other): + """ + Return the sum of ``self`` and ``other``. + + INPUT: + + - ``other`` -- other series + + EXAMPLES: + + Dense series can be added:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: m = L(lambda n: 1 + n, valuation=0) + sage: n = L(lambda n: -n, valuation=0) + sage: s = m + n + sage: s[0:10] + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + + Sparse series can be added:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: m = L(lambda n: 1 + n, valuation=0) + sage: n = L(lambda n: -n, valuation=0) + sage: s = m + n + sage: s[0:10] + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + + Series which are known to be exact can be added:: + + sage: m = L(1) + sage: n = L([0, 1]) + sage: s = m + n + sage: s[0:10] + [1, 1, 0, 0, 0, 0, 0, 0, 0, 0] + + Adding zero gives the same series:: + + sage: m = L(lambda n: 1 + n, valuation=0) + sage: m + 0 is 0 + m is m + True + + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: s = L(lambda n: n); s + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) + sage: t = L(constant=1); t + 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) + sage: s + t + 2 + 3/2^z + 4/3^z + 5/4^z + 6/5^z + 7/6^z + 8/7^z + O(1/(8^z)) + + sage: r = L(constant=-1) + sage: r + t + 0 + + sage: r = L([1,2,3]) + sage: r + t + 2 + 3/2^z + 4/3^z + 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)) + + sage: r = L([1,2,3], constant=-1) + sage: r + t + 2 + 3/2^z + 4/3^z + """ + P = self.parent() left = self._coeff_stream right = other._coeff_stream if isinstance(left, Stream_zero): @@ -831,6 +1159,25 @@ def _acted_upon_(self, scalar, self_on_left): True sage: 0 * N == 0 True + + Similarly for Dirichlet series:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: g = L([0,1]) + sage: 2 * g + 2/2^z + sage: -1 * g + -1/(2^z) + sage: 0*g + 0 + sage: M = L(lambda n: n); M + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) + sage: 3 * M + 3 + 6/2^z + 9/3^z + 12/4^z + 15/5^z + 18/6^z + 21/7^z + O(1/(8^z)) + + sage: 1 * M is M + True + """ # With the current design, the coercion model does not have # enough information to detect a priori that this method only @@ -935,107 +1282,816 @@ def _neg_(self): return P.element_class(P, coeff_stream._series) return P.element_class(P, Stream_neg(coeff_stream)) + # === special functions === -class LazyCauchyProductSeries(LazyModuleElement): - r""" - A class for series where multiplication is the Cauchy product. + def exp(self): + r""" + Return the exponential series of ``self``. - EXAMPLES:: + EXAMPLES:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: f = 1 / (1 - z) - sage: f - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: f * (1 - z) - 1 + O(z^7) + sage: L. = LazyLaurentSeriesRing(QQ) + sage: exp(z) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: exp(z + z^2) + 1 + z + 3/2*z^2 + 7/6*z^3 + 25/24*z^4 + 27/40*z^5 + 331/720*z^6 + O(z^7) + sage: exp(0) + 1 + sage: exp(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: f = 1 / (1 - z) - sage: f - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - """ - def _mul_(self, other): + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: exp(x+y)[4].factor() # not tested + (1/24) * (x + y)^4 + sage: exp(x/(1-y)).finite_part(3) # not tested + 1/6*x^3 + x^2*y + x*y^2 + 1/2*x^2 + x*y + x + 1 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: exp(z)[0:6] == exp(x).series(x, 6).coefficients(sparse=False) + True """ - Return the product of this series with ``other``. + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + f = P(lambda n: 1/factorial(ZZ(n)), valuation=0) + return f(self) - INPUT: + def log(self): + r""" + Return the series for the natural logarithm of ``self``. - - ``other`` -- other series + EXAMPLES:: - TESTS:: + sage: L. = LazyLaurentSeriesRing(QQ) + sage: log(1/(1-z)) + z + 1/2*z^2 + 1/3*z^3 + 1/4*z^4 + 1/5*z^5 + 1/6*z^6 + 1/7*z^7 + O(z^8) - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: (1 - z)*(1 - z) - 1 - 2*z + z^2 - sage: (1 - z)*(1 - z)*(1 - z) - 1 - 3*z + 3*z^2 - z^3 - sage: M = L(lambda n: n, valuation=0) - sage: M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = M * (1 - M) - sage: N - z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + O(z^7) + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: log((1 + x/(1-y))).finite_part(3) # not tested + 1/3*x^3 - x^2*y + x*y^2 + (-1/2)*x^2 + x*y + x - sage: p = (1 - z)*(1 + z^2)^3 * z^-2 - sage: p - z^-2 - z^-1 + 3 - 3*z + 3*z^2 - 3*z^3 + z^4 - z^5 - sage: M = L(lambda n: n, valuation=-2, degree=5, constant=2) - sage: M - -2*z^-2 - z^-1 + z + 2*z^2 + 3*z^3 + 4*z^4 + 2*z^5 + 2*z^6 + 2*z^7 + O(z^8) - sage: M * p - -2*z^-4 + z^-3 - 5*z^-2 + 4*z^-1 - 2 + 7*z + 5*z^2 + 5*z^3 - + 7*z^4 - 2*z^5 + 4*z^6 - 5*z^7 + z^8 - 2*z^9 - sage: M * p == p * M + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: log(1+z)[0:6] == log(1+x).series(x, 6).coefficients(sparse=False) True - sage: q = (1 - 2*z)*(1 + z^2)^3 * z^-2 - sage: q * M - -2*z^-4 + 3*z^-3 - 4*z^-2 + 10*z^-1 + 11*z + 2*z^2 - 3*z^3 - - 6*z^4 - 22*z^5 - 14*z^6 - 27*z^7 - 16*z^8 - 20*z^9 - - 16*z^10 - 16*z^11 - 16*z^12 + O(z^13) - sage: q * M == M * q + sage: log(z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + """ + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + f = P(lambda n: ((-1) ** (n + 1))/ZZ(n), valuation=1) + return f(self-1) + + # trigonometric functions + + def sin(self): + r""" + Return the sine of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: sin(z) + z - 1/6*z^3 + 1/120*z^5 - 1/5040*z^7 + O(z^8) + + sage: sin(1 + z) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sin(x/(1-y)).finite_part(3) # not tested + (-1/6)*x^3 + x*y^2 + x*y + x + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: sin(z)[0:6] == sin(x).series(x, 6).coefficients(sparse=False) True + """ + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + f = P(lambda n: (n % 2)/factorial(ZZ(n)) if n % 4 == 1 else -(n % 2)/factorial(ZZ(n)), + valuation=1) + return f(self) - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = L(lambda n: 1, valuation=0); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: M * N - z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + O(z^7) + def cos(self): + r""" + Return the cosine of ``self``. - sage: L.one() * M is M + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: cos(z) + 1 - 1/2*z^2 + 1/24*z^4 - 1/720*z^6 + O(z^7) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: cos(x/(1-y)).finite_part(4) # not tested + 1/24*x^4 + (-3/2)*x^2*y^2 - x^2*y + (-1/2)*x^2 + 1 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: cos(z)[0:6] == cos(x).series(x, 6).coefficients(sparse=False) True - sage: M * L.one() is M + """ + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + f = P(lambda n: 1/factorial(ZZ(n)) if n % 4 == 0 else (n % 2 - 1)/factorial(ZZ(n)), + valuation=0) + return f(self) + + def tan(self): + r""" + Return the tangent of ``self``. + + EXAMPLES: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: tan(z) + z + 1/3*z^3 + 2/15*z^5 + 17/315*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: tan(x/(1-y)).finite_part(5) # not tested + 2/15*x^5 + 2*x^3*y^2 + x*y^4 + x^3*y + x*y^3 + 1/3*x^3 + x*y^2 + x*y + x + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: tan(z)[0:6] == tan(x).series(x, 6).coefficients(sparse=False) True + """ + return self.sin() / self.cos() - Multiplication of series with eventually constant - coefficients may yield another such series:: + def cot(self): + r""" + Return the cotangent of ``self``. - sage: L. = LazyLaurentSeriesRing(SR) - sage: var("a b c d e u v w") - (a, b, c, d, e, u, v, w) - sage: s = a/z^2 + b*z + c*z^2 + d*z^3 + e*z^4 - sage: t = L([u, v], constant=w, valuation=-1) - sage: s1 = s.approximate_series(44) - sage: t1 = t.approximate_series(44) - sage: s1 * t1 - (s * t).approximate_series(42) - O(z^42) + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: cot(z) + z^-1 - 1/3*z - 1/45*z^3 - 2/945*z^5 + O(z^6) + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: cot(x/(1-x)).polynomial(4) + x^-1 - 1 - 1/3*x - 1/3*x^2 - 16/45*x^3 - 2/5*x^4 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: cot(z)[0:6] == cot(x).series(x, 6).coefficients(sparse=False) + True """ - P = self.parent() - left = self._coeff_stream - right = other._coeff_stream + return ~self.tan() - # Check some trivial products - if isinstance(left, Stream_zero) or isinstance(right, Stream_zero): - return P.zero() - if isinstance(left, Stream_exact) and left._initial_coefficients == (P._coeff_ring.one(),) and left.order() == 0: - return other # self == 1 - if isinstance(right, Stream_exact) and right._initial_coefficients == (P._coeff_ring.one(),) and right.order() == 0: - return self # right == 1 + def csc(self): + r""" + Return the cosecant of ``self``. - # The product is exact if and only if both factors are exact - # and one of the factors has eventually 0 coefficients: + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: csc(z) + z^-1 + 1/6*z + 7/360*z^3 + 31/15120*z^5 + O(z^6) + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: csc(x/(1-x)).polynomial(4) + x^-1 - 1 + 1/6*x + 1/6*x^2 + 67/360*x^3 + 9/40*x^4 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: (z*csc(z))[0:6] == (x*csc(x)).series(x, 6).coefficients(sparse=False) + True + """ + return ~self.sin() + + def sec(self): + r""" + Return the secant of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: sec(z) + 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sec(x/(1-y)).finite_part(4) # not tested + 5/24*x^4 + 3/2*x^2*y^2 + x^2*y + 1/2*x^2 + 1 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: sec(z)[0:6] == sec(x).series(x, 6).coefficients(sparse=False) + True + """ + return ~self.cos() + + # inverse trigonometric functions + + def arcsin(self): + r""" + Return the arcsin of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: arcsin(z) + z + 1/6*z^3 + 3/40*z^5 + 5/112*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: asin(x/(1-y)) # not tested + x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + + (3/40*x^5+x^3*y^2+x*y^4) + (3/8*x^5*y+5/3*x^3*y^3+x*y^5) + + (5/112*x^7+9/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: asin(z)[0:6] == asin(x).series(x, 6).coefficients(sparse=False) + True + """ + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + def f(n): + n = ZZ(n) + if n % 2: + return factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) + return ZZ.zero() + return P(f, valuation=1)(self) + + def arccos(self): + r""" + Return the arccos of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(RR) + sage: arccos(z) + 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + - 0.166666666666667*z^3 + 0.000000000000000*z^4 + - 0.0750000000000000*z^5 + O(1.00000000000000*z^7) + + sage: L. = LazyLaurentSeriesRing(SR) + sage: arccos(z/(1-z)) + 1/2*pi - z - z^2 - 7/6*z^3 - 3/2*z^4 - 83/40*z^5 - 73/24*z^6 + O(z^7) + + sage: L. = LazyTaylorSeriesRing(SR) # not tested + sage: arccos(x/(1-y)) # not tested + 1/2*pi + (-x) + (-x*y) + ((-1/6)*x^3-x*y^2) + ((-1/2)*x^3*y-x*y^3) + + ((-3/40)*x^5-x^3*y^2-x*y^4) + ((-3/8)*x^5*y+(-5/3)*x^3*y^3-x*y^5) + O(x,y)^7 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: acos(z)[0:6] == acos(x).series(x, 6).coefficients(sparse=False) + True + """ + from sage.symbolic.constants import pi + return self.parent()(pi/2) - self.arcsin() + + def arctan(self): + r""" + Return the arctangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: arctan(z) + z - 1/3*z^3 + 1/5*z^5 - 1/7*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: atan(x/(1-y)) # not tested + x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + + (1/5*x^5+(-2)*x^3*y^2+x*y^4) + (x^5*y+(-10/3)*x^3*y^3+x*y^5) + + ((-1/7)*x^7+3*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") + sage: atan(z)[0:6] == atan(x).series(x, 6).coefficients(sparse=False) + True + """ + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + def f(n): + n = ZZ(n) + if n % 4 == 1: + return 1/n + if n % 2 == 0: + return ZZ.zero() + return -1/n + return P(f, valuation=1)(self) + + def arccot(self): + r""" + Return the arctangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(RR) + sage: arccot(z) + 1.57079632679490 - 1.00000000000000*z + 0.000000000000000*z^2 + + 0.333333333333333*z^3 + 0.000000000000000*z^4 + - 0.200000000000000*z^5 + O(1.00000000000000*z^7) + + sage: L. = LazyLaurentSeriesRing(SR) + sage: arccot(z/(1-z)) + 1/2*pi - z - z^2 - 2/3*z^3 + 4/5*z^5 + 4/3*z^6 + O(z^7) + + sage: L. = LazyTaylorSeriesRing(SR) # not tested + sage: acot(x/(1-y)) # not tested + 1/2*pi + (-x) + (-x*y) + (1/3*x^3-x*y^2) + (x^3*y-x*y^3) + + ((-1/5)*x^5+2*x^3*y^2-x*y^4) + (-x^5*y+10/3*x^3*y^3-x*y^5) + O(x,y)^7 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: acot(z)[0:6] == acot(x).series(x, 6).coefficients(sparse=False) + True + """ + from sage.symbolic.constants import pi + return self.parent()(pi/2) - self.arctan() + + # hyperbolic functions + + def sinh(self): + r""" + Return the sinh of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: sinh(z) + z + 1/6*z^3 + 1/120*z^5 + 1/5040*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sinh(x/(1-y)) # not tested + x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + + (1/120*x^5+x^3*y^2+x*y^4) + (1/24*x^5*y+5/3*x^3*y^3+x*y^5) + + (1/5040*x^7+1/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: sinh(z)[0:6] == sinh(x).series(x, 6).coefficients(sparse=False) + True + """ + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + f = P(lambda n: 1/factorial(ZZ(n)) if n % 2 else ZZ.zero(), + valuation=1) + return f(self) + + def cosh(self): + r""" + Return the cosh of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: cosh(z) + 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: cosh(x/(1-y)) # not tested + 1 + 1/2*x^2 + x^2*y + (1/24*x^4+3/2*x^2*y^2) + (1/6*x^4*y+2*x^2*y^3) + + (1/720*x^6+5/12*x^4*y^2+5/2*x^2*y^4) + O(x,y)^7 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: cosh(z)[0:6] == cosh(x).series(x, 6).coefficients(sparse=False) + True + """ + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + f = P(lambda n: ZZ.zero() if n % 2 else 1/factorial(ZZ(n)), + valuation=0) + return f(self) + + def tanh(self): + r""" + Return the tanh of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: tanh(z) + z - 1/3*z^3 + 2/15*z^5 - 17/315*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: tanh(x/(1-y)) # not tested + x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + + (2/15*x^5+(-2)*x^3*y^2+x*y^4) + (2/3*x^5*y+(-10/3)*x^3*y^3+x*y^5) + + ((-17/315)*x^7+2*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: tanh(z)[0:6] == tanh(x).series(x, 6).coefficients(sparse=False) + True + """ + from sage.arith.misc import bernoulli + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + def f(n): + n = ZZ(n) + if n % 2: + h = 4 ** ((n + 1) // 2) + return bernoulli(n + 1) * h * (h -1) / factorial(n + 1) + return ZZ.zero() + return P(f, valuation=1)(self) + + def coth(self): + r""" + Return the hyperbolic cotangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: coth(z) + z^-1 + 1/3*z - 1/45*z^3 + 2/945*z^5 + O(z^6) + + sage: coth(z + z^2) + z^-1 - 1 + 4/3*z - 2/3*z^2 + 44/45*z^3 - 16/15*z^4 + 884/945*z^5 + O(z^6) + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: coth(z)[0:6] == coth(x).series(x, 6).coefficients(sparse=False) + True + """ + from sage.arith.misc import bernoulli + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + def f(n): + n = ZZ(n) + if n % 2: + return ((2 ** (n + 1)) * bernoulli(n + 1))/factorial(n + 1) + return ZZ.zero() + return P(f, valuation=-1)(self) + + def sech(self): + r""" + Return the hyperbolic secant of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: sech(z) + 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sech(x/(1-y)) # not tested + 1 + ((-1/2)*x^2) + (-x^2*y) + (5/24*x^4+(-3/2)*x^2*y^2) + + (5/6*x^4*y+(-2)*x^2*y^3) + ((-61/720)*x^6+25/12*x^4*y^2+(-5/2)*x^2*y^4) + + O(x,y)^7 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: sech(z)[0:6] == sech(x).series(x, 6).coefficients(sparse=False) + True + """ + from sage.combinat.combinat import euler_number + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + def f(n): + n = ZZ(n) + if n % 2: + return ZZ.zero() + return euler_number(n)/factorial(n) + return P(f, valuation=0)(self) + + def csch(self): + r""" + Return the hyperbolic cosecant of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: csch(z) + z^-1 - 1/6*z + 7/360*z^3 - 31/15120*z^5 + O(z^6) + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: csch(z/(1-z)) + z^-1 - 1 - 1/6*z - 1/6*z^2 - 53/360*z^3 - 13/120*z^4 - 787/15120*z^5 + O(z^6) + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: csch(z)[0:6] == csch(x).series(x, 6).coefficients(sparse=False) + True + + """ + from sage.arith.misc import bernoulli + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + def f(n): + n = ZZ(n) + if n % 2: + return 2 * (1 - ZZ(2) ** n) * bernoulli(n + 1)/factorial(n + 1) + return ZZ.zero() + return P(f, valuation=-1)(self) + + # inverse hyperbolic functions + + def arcsinh(self): + r""" + Return the inverse of the hyperbolic sine of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: asinh(z) + z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: asinh(x/(1-y)) # not tested + x + x*y + ((-1/6)*x^3+x*y^2) + ((-1/2)*x^3*y+x*y^3) + + (3/40*x^5-x^3*y^2+x*y^4) + (3/8*x^5*y+(-5/3)*x^3*y^3+x*y^5) + + ((-5/112)*x^7+9/8*x^5*y^2+(-5/2)*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: asinh(z)[0:6] == asinh(x).series(x, 6).coefficients(sparse=False) + True + + """ + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + def f(n): + n = ZZ(n) + if n % 2: + h = (n - 1) // 2 + return ZZ(-1) ** h * factorial(n - 1)/(ZZ(4) ** h * factorial(h) ** 2 * n) + return ZZ.zero() + return P(f, valuation=1)(self) + + def arctanh(self): + r""" + Return the inverse of the hyperbolic tangent of ``self``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: atanh(z) + z + 1/3*z^3 + 1/5*z^5 + 1/7*z^7 + O(z^8) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: atanh(x/(1-y)) # not tested + x + x*y + (1/3*x^3+x*y^2) + (x^3*y+x*y^3) + (1/5*x^5+2*x^3*y^2+x*y^4) + + (x^5*y+10/3*x^3*y^3+x*y^5) + (1/7*x^7+3*x^5*y^2+5*x^3*y^4+x*y^6) + O(x,y)^8 + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: atanh(z)[0:6] == atanh(x).series(x, 6).coefficients(sparse=False) + True + + """ + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + f = P(lambda n: 1/ZZ(n) if n % 2 else ZZ.zero(), valuation=1) + return f(self) + + def hypergeometric(self, a, b): + r""" + Return the `{}_{p}F_{q}`-hypergeometric function + `\,_pF_{q}` where `(p,q)` is the parameterization of ``self``. + + INPUT: + + - ``a`` -- the first parameter of the hypergeometric function + - ``b`` -- the second parameter of the hypergeometric function + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: z.hypergeometric([1, 1], [1]) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: z.hypergeometric([], []) - exp(z) + O(z^7) + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(SR); x = var("x") + sage: z.hypergeometric([1,1],[1])[0:6] == hypergeometric([1,1],[1], x).series(x, 6).coefficients(sparse=False) + True + + """ + from .lazy_series_ring import LazyLaurentSeriesRing + from sage.arith.misc import rising_factorial + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + def coeff(n, c): + num = 1 + for term in range(len(c)): + num *= rising_factorial(c[term], n) + return num + f = P(lambda n: coeff(n, a)/(coeff(n, b) * factorial(ZZ(n))), + valuation=0) + return f(self) + + # === powers === + + def __pow__(self, n): + r""" + Return the ``n``-th power of the series. + + INPUT: + + - ``n`` -- integer; the power to which to raise the series + + EXAMPLES:: + + sage: D = LazyDirichletSeriesRing(QQ, 's') + sage: Z = D(constant=1) + sage: Z^2 + 1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)) + sage: f = Z^(1/3) + sage: f + 1 + 1/3/2^s + 1/3/3^s + 2/9/4^s + 1/3/5^s + 1/9/6^s + 1/3/7^s + O(1/(8^s)) + sage: f^2 + 1 + 2/3/2^s + 2/3/3^s + 5/9/4^s + 2/3/5^s + 4/9/6^s + 2/3/7^s + O(1/(8^s)) + sage: f^3 - Z + O(1/(8^s)) + """ + if n in ZZ: + return generic_power(self, n) + + from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) + exp = P(lambda k: 1/factorial(ZZ(k)), valuation=0) + return exp(self.log() * n) + + def sqrt(self): + """ + Return ``self^(1/2)``. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: sqrt(1+z) + 1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7) + + sage: L. = LazyTaylorSeriesRing(QQ) # not tested + sage: sqrt(1+x/(1-y)) # not tested + 1 + 1/2*x + ((-1/8)*x^2+1/2*x*y) + (1/16*x^3+(-1/4)*x^2*y+1/2*x*y^2) + + ((-5/128)*x^4+3/16*x^3*y+(-3/8)*x^2*y^2+1/2*x*y^3) + + (7/256*x^5+(-5/32)*x^4*y+3/8*x^3*y^2+(-1/2)*x^2*y^3+1/2*x*y^4) + + ((-21/1024)*x^6+35/256*x^5*y+(-25/64)*x^4*y^2+5/8*x^3*y^3+(-5/8)*x^2*y^4+1/2*x*y^5) + + O(x,y)^7 + + This also works for Dirichlet series:: + + sage: D = LazyDirichletSeriesRing(SR, "s") + sage: Z = D(constant=1) + sage: f = sqrt(Z) + sage: f + 1 + 1/2/2^s + 1/2/3^s + 3/8/4^s + 1/2/5^s + 1/4/6^s + 1/2/7^s + O(1/(8^s)) + sage: f*f - Z + O(1/(8^s)) + """ + return self ** (1/ZZ(2)) + + +class LazyCauchyProductSeries(LazyModuleElement): + r""" + A class for series where multiplication is the Cauchy product. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: f = 1 / (1 - z) + sage: f + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: f * (1 - z) + 1 + O(z^7) + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: f = 1 / (1 - z) + sage: f + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + """ + def valuation(self): + r""" + Return the valuation of ``self``. + + This method determines the valuation of the series by looking for a + nonzero coefficient. Hence if the series happens to be zero, then it + may run forever. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: s = 1/(1 - z) - 1/(1 - 2*z) + sage: s.valuation() + 1 + sage: t = z - z + sage: t.valuation() + +Infinity + sage: M = L(lambda n: n^2, 0) + sage: M.valuation() + 1 + sage: (M - M).valuation() + +Infinity + + """ + return self._coeff_stream.order() + + def _mul_(self, other): + """ + Return the product of this series with ``other``. + + INPUT: + + - ``other`` -- other series + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: (1 - z)*(1 - z) + 1 - 2*z + z^2 + sage: (1 - z)*(1 - z)*(1 - z) + 1 - 3*z + 3*z^2 - z^3 + sage: M = L(lambda n: n, valuation=0) + sage: M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: N = M * (1 - M) + sage: N + z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + O(z^7) + + sage: p = (1 - z)*(1 + z^2)^3 * z^-2 + sage: p + z^-2 - z^-1 + 3 - 3*z + 3*z^2 - 3*z^3 + z^4 - z^5 + sage: M = L(lambda n: n, valuation=-2, degree=5, constant=2) + sage: M + -2*z^-2 - z^-1 + z + 2*z^2 + 3*z^3 + 4*z^4 + 2*z^5 + 2*z^6 + 2*z^7 + O(z^8) + sage: M * p + -2*z^-4 + z^-3 - 5*z^-2 + 4*z^-1 - 2 + 7*z + 5*z^2 + 5*z^3 + + 7*z^4 - 2*z^5 + 4*z^6 - 5*z^7 + z^8 - 2*z^9 + sage: M * p == p * M + True + + sage: q = (1 - 2*z)*(1 + z^2)^3 * z^-2 + sage: q * M + -2*z^-4 + 3*z^-3 - 4*z^-2 + 10*z^-1 + 11*z + 2*z^2 - 3*z^3 + - 6*z^4 - 22*z^5 - 14*z^6 - 27*z^7 - 16*z^8 - 20*z^9 + - 16*z^10 - 16*z^11 - 16*z^12 + O(z^13) + sage: q * M == M * q + True + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: N = L(lambda n: 1, valuation=0); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: M * N + z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + O(z^7) + + sage: L.one() * M is M + True + sage: M * L.one() is M + True + + Multiplication of series with eventually constant + coefficients may yield another such series:: + + sage: L. = LazyLaurentSeriesRing(SR) + sage: var("a b c d e u v w") + (a, b, c, d, e, u, v, w) + sage: s = a/z^2 + b*z + c*z^2 + d*z^3 + e*z^4 + sage: t = L([u, v], constant=w, valuation=-1) + sage: s1 = s.approximate_series(44) + sage: t1 = t.approximate_series(44) + sage: s1 * t1 - (s * t).approximate_series(42) + O(z^42) + """ + P = self.parent() + left = self._coeff_stream + right = other._coeff_stream + + # Check some trivial products + if isinstance(left, Stream_zero) or isinstance(right, Stream_zero): + return P.zero() + if isinstance(left, Stream_exact) and left._initial_coefficients == (P._coeff_ring.one(),) and left.order() == 0: + return other # self == 1 + if isinstance(right, Stream_exact) and right._initial_coefficients == (P._coeff_ring.one(),) and right.order() == 0: + return self # right == 1 + + # The product is exact if and only if both factors are exact + # and one of the factors has eventually 0 coefficients: # (p + a x^d/(1-x))(q + b x^e/(1-x)) # = p q + (a x^d q + b x^e p)/(1-x) + a b x^(d+e)/(1-x)^2 if (isinstance(left, Stream_exact) @@ -1077,6 +2133,85 @@ def _mul_(self, other): return P.element_class(P, Stream_cauchy_mul(left, right)) + def __pow__(self, n): + r""" + Return the ``n``-th power of the series. + + INPUT: + + - ``n`` -- integer; the power to which to raise the series + + EXAMPLES: + + Lazy Laurent series that have a dense implementation can be + raised to the power ``n``:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: (1 - z)^-1 + 1 + z + z^2 + O(z^3) + sage: (1 - z)^0 + 1 + sage: (1 - z)^3 + 1 - 3*z + 3*z^2 - z^3 + sage: (1 - z)^-3 + 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M^2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + + We can create a really large power of a monomial, even with + the dense implementation:: + + sage: z^1000000 + z^1000000 + + Lazy Laurent series that have a sparse implementation can be + raised to the power ``n``:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n, valuation=0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: M^2 + z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + + Lazy Laurent series that are known to be exact can be raised + to the power ``n``:: + + sage: z^2 + z^2 + sage: (1 - z)^2 + 1 - 2*z + z^2 + sage: (1 + z)^2 + 1 + 2*z + z^2 + + We also support the general case:: + + sage: L. = LazyLaurentSeriesRing(SR) + sage: (1 + z)^(1 + z) + 1 + z + z^2 + 1/2*z^3 + 1/3*z^4 + 1/12*z^5 + 3/40*z^6 + O(z^7) + + """ + if n == 0: + return self.parent().one() + + cs = self._coeff_stream + if (isinstance(cs, Stream_exact) + and not cs._constant and n in ZZ + and (n > 0 or len(cs._initial_coefficients) == 1)): + # # alternatively: + # return P(self.finite_part() ** ZZ(n)) + P = self.parent() + ret = cs._polynomial_part(P._laurent_poly_ring) ** ZZ(n) + val = ret.valuation() + deg = ret.degree() + 1 + initial_coefficients = [ret[i] for i in range(val, deg)] + return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, + constant=cs._constant, + degree=deg, order=val)) + + return super().__pow__(n) + def __invert__(self): """ Return the multiplicative inverse of the element. @@ -1154,6 +2289,86 @@ def __invert__(self): return P.element_class(P, coeff_stream._series) return P.element_class(P, Stream_cauchy_invert(coeff_stream)) + def _div_(self, other): + r""" + Return ``self`` divided by ``other``. + + INPUT: + + - ``other`` -- nonzero series + + EXAMPLES: + + Lazy Laurent series that have a dense implementation can be divided:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: z/(1 - z) + z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + O(z^8) + sage: M = L(lambda n: n, 0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: N = L(lambda n: 1, 0); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: P = M / N; P + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + + Lazy Laurent series that have a sparse implementation can be divided:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: M = L(lambda n: n, 0); M + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: N = L(lambda n: 1, 0); N + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + sage: P = M / N; P + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + + If the division of exact Lazy Laurent series yields a Laurent + polynomial, it is represented as an exact series:: + + sage: 1/z + z^-1 + + sage: m = z^2 + 2*z + 1 + sage: n = z + 1 + sage: m / n + 1 + z + + An example over the ring of symmetric functions:: + + sage: e = SymmetricFunctions(QQ).e() + sage: R. = LazyLaurentSeriesRing(e) + sage: 1 / (1 - e[1]*z) + e[] + e[1]*z + e[1, 1]*z^2 + e[1, 1, 1]*z^3 + e[1, 1, 1, 1]*z^4 + + e[1, 1, 1, 1, 1]*z^5 + e[1, 1, 1, 1, 1, 1]*z^6 + O(e[]*z^7) + + """ + if isinstance(other._coeff_stream, Stream_zero): + raise ZeroDivisionError("cannot divide by 0") + + P = self.parent() + left = self._coeff_stream + if isinstance(left, Stream_zero): + return P.zero() + right = other._coeff_stream + if (isinstance(left, Stream_exact) + and isinstance(right, Stream_exact)): + if not left._constant and not right._constant: + R = P._laurent_poly_ring + pl = left._polynomial_part(R) + pr = right._polynomial_part(R) + try: + ret = pl / pr + ret = P._laurent_poly_ring(ret) + except (TypeError, ValueError, NotImplementedError): + # We cannot divide the polynomials, so the result must be a series + pass + else: + initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] + return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, + order=ret.valuation(), + constant=left._constant)) + + return P.element_class(P, Stream_cauchy_mul(left, Stream_cauchy_invert(right))) + class LazyLaurentSeries(LazyCauchyProductSeries): r""" @@ -1213,61 +2428,19 @@ class LazyLaurentSeries(LazyCauchyProductSeries): However, we may not always be able to know when a result is exactly a polynomial:: - sage: f * (z^-1 - z + 3*z^2) - z^-2 - 1 + 2*z + O(z^5) - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: f = 1 / (1 - z - z^2) - sage: TestSuite(f).run() - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: f = 1 / (1 - z - z^2) - sage: TestSuite(f).run() - """ - - def change_ring(self, ring): - r""" - Return ``self`` with coefficients converted to elements of ``ring``. - - INPUT: - - - ``ring`` -- a ring - - EXAMPLES: - - Dense Implementation:: + sage: f * (z^-1 - z + 3*z^2) + z^-2 - 1 + 2*z + O(z^5) - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: s = 2 + z - sage: t = s.change_ring(QQ) - sage: t^-1 - 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = M.change_ring(QQ) - sage: N.parent() - Lazy Laurent Series Ring in z over Rational Field - sage: M.parent() - Lazy Laurent Series Ring in z over Integer Ring + TESTS:: - Sparse Implementation:: + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + sage: f = 1 / (1 - z - z^2) + sage: TestSuite(f).run() - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M.parent() - Lazy Laurent Series Ring in z over Integer Ring - sage: N = M.change_ring(QQ) - sage: N.parent() - Lazy Laurent Series Ring in z over Rational Field - sage: M ^-1 - z^-1 - 2 + z + O(z^6) - """ - from .lazy_laurent_series_ring import LazyLaurentSeriesRing - Q = LazyLaurentSeriesRing(ring, names=self.parent().variable_names()) - return Q.element_class(Q, self._coeff_stream) + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: f = 1 / (1 - z - z^2) + sage: TestSuite(f).run() + """ def __call__(self, g): r""" @@ -1300,6 +2473,8 @@ def __call__(self, g): z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + O(z) sage: g^2 + 1 + g z^-6 + 4*z^-5 + 12*z^-4 + 33*z^-3 + 82*z^-2 + 196*z^-1 + 457 + O(z) + sage: f(int(2)) + 7 sage: f = z^-2 + z + 4*z^3 sage: f(f) @@ -1488,13 +2663,68 @@ def __call__(self, g): Traceback (most recent call last): ... ValueError: can only compose with a positive valuation series + + We compose the exponential with a Dirichlet series:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: e = L(lambda n: 1/factorial(n), 0) + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: g = D(constant=1)-1; g + 1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s)) + + sage: e(g)[0:10] + [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] + + sage: sum(g^k/factorial(k) for k in range(10))[0:10] + [0, 1, 1, 1, 3/2, 1, 2, 1, 13/6, 3/2] + + sage: g = D([0,1,0,1,1,2]); g + 1/(2^s) + 1/(4^s) + 1/(5^s) + 2/6^s + sage: e(g)[0:10] + [0, 1, 1, 0, 3/2, 1, 2, 0, 7/6, 0] + sage: sum(g^k/factorial(k) for k in range(10))[0:10] + [0, 1, 1, 0, 3/2, 1, 2, 0, 7/6, 0] + + sage: e(D([1,0,1])) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + sage: e5 = L(e, degree=5); e5 + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + sage: e5(g) + 1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s)) + sage: sum(e5[k] * g^k for k in range(5)) + 1 + 1/(2^s) + 3/2/4^s + 1/(5^s) + 2/6^s + O(1/(8^s)) + + The output parent is always the common parent between the base ring + of `f` and the parent of `g` or extended to the corresponding + lazy series:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: R. = ZZ[] + sage: parent(z(x)) + Univariate Polynomial Ring in x over Rational Field + sage: parent(z(R.zero())) + Univariate Polynomial Ring in x over Rational Field + sage: parent(z(0)) + Rational Field + sage: f = 1 / (1 - z) + sage: f(x) + 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + O(x^7) + sage: three = L(3)(x^2); three + 3 + sage: parent(three) + Univariate Polynomial Ring in x over Rational Field """ # f = self and compute f(g) - P = g.parent() + from sage.structure.element import get_coercion_model + cm = get_coercion_model() + P = cm.common_parent(self.base_ring(), parent(g)) # f = 0 if isinstance(self._coeff_stream, Stream_zero): - return self + return P.zero() # g = 0 case if ((not isinstance(g, LazyModuleElement) and not g) @@ -1514,11 +2744,15 @@ def __call__(self, g): R = self.parent()._laurent_poly_ring poly = self._coeff_stream._polynomial_part(R) if poly.is_constant(): - return self + return P(poly[0]) if not isinstance(g, LazyModuleElement): return poly(g) # g also has finite length, compose the polynomials - if isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant: + # We optimize composition when g is not a Dirichlet series + # by composing the polynomial parts explicitly + if (isinstance(g, LazyCauchyProductSeries) + and isinstance(g._coeff_stream, Stream_exact) + and not g._coeff_stream._constant): R = P._laurent_poly_ring g_poly = g._coeff_stream._polynomial_part(R) try: @@ -1530,8 +2764,9 @@ def __call__(self, g): deg = ret.degree() + 1 initial_coefficients = [ret[i] for i in range(val, deg)] coeff_stream = Stream_exact(initial_coefficients, - self._coeff_stream._is_sparse, constant=P.base_ring().zero(), - degree=deg, order=val) + self._coeff_stream._is_sparse, + constant=P.base_ring().zero(), + degree=deg, order=val) return P.element_class(P, coeff_stream) # Return the sum since g is not known to be finite or we do not get a Laurent polynomial @@ -1561,176 +2796,138 @@ def __call__(self, g): ret += poly[v] * gp return ret - # g != 0 and val(g) > 0 + # f is not known to have finite length and g != 0 with val(g) > 0 if not isinstance(g, LazyModuleElement): + # Check to see if it belongs to a polynomial ring + # that we can extend to a lazy series ring + from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + if isinstance(P, PolynomialRing_general): + from sage.rings.lazy_series_ring import LazyLaurentSeriesRing + R = LazyLaurentSeriesRing(P.base_ring(), P.variable_names(), P.is_sparse()) + g = R(P(g)) + return self(g) + # TODO: Implement case for a regular (Laurent)PowerSeries element # as we can use the (default?) order given - try: - g = self.parent()(g) - except (TypeError, ValueError): - raise NotImplementedError("can only compose with a lazy series") + raise NotImplementedError("can only compose with a lazy series") + # Perhaps we just don't yet know if the valuation is positive if g._coeff_stream._approximate_order <= 0: if any(g._coeff_stream[i] for i in range(g._coeff_stream._approximate_order, 1)): raise ValueError("can only compose with a positive valuation series") g._coeff_stream._approximate_order = 1 + if isinstance(g, LazyDirichletSeries): + if g._coeff_stream._approximate_order == 1: + if g._coeff_stream[1] != 0: + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_order = 2 + # we assume that the valuation of self[i](g) is at least i + def coefficient(n): + return sum(self[i] * (g**i)[n] for i in range(n+1)) + coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 1) + return P.element_class(P, coeff_stream) + coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream) return P.element_class(P, coeff_stream) compose = __call__ - def _div_(self, other): + def revert(self): r""" - Return ``self`` divided by ``other``. - - INPUT: - - - ``other`` -- nonzero series + Return the compositional inverse of ``self``. - EXAMPLES: - - Lazy Laurent series that have a dense implementation can be divided:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: z/(1 - z) - z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + O(z^8) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = L(lambda n: 1, valuation=0); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: P = M / N; P - z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - - Lazy Laurent series that have a sparse implementation can be divided:: - - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: N = L(lambda n: 1, valuation=0); N - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - sage: P = M / N; P - z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - - Lazy Laurent series that are known to be exact can be divided:: - - M = z^2 + 2*z + 1 - N = z + 1 - O = M / N; O - z + 1 - - An example over the ring of symmetric functions:: - - sage: e = SymmetricFunctions(QQ).e() - sage: R. = LazyLaurentSeriesRing(e) - sage: 1 / (1 - e[1]*z) - e[] + e[1]*z + e[1, 1]*z^2 + e[1, 1, 1]*z^3 + e[1, 1, 1, 1]*z^4 - + e[1, 1, 1, 1, 1]*z^5 + e[1, 1, 1, 1, 1, 1]*z^6 + O(e[]*z^7) - """ - if isinstance(other._coeff_stream, Stream_zero): - raise ZeroDivisionError("cannot divide by 0") - - P = self.parent() - left = self._coeff_stream - if isinstance(left, Stream_zero): - return P.zero() - right = other._coeff_stream - if (isinstance(left, Stream_exact) - and isinstance(right, Stream_exact)): - if not left._constant and not right._constant: - R = P._laurent_poly_ring - pl = left._polynomial_part(R) - pr = right._polynomial_part(R) - try: - ret = pl / pr - ret = P._laurent_poly_ring(ret) - initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, - order=ret.valuation(), constant=left._constant)) - except (TypeError, ValueError, NotImplementedError): - # We cannot divide the polynomials, so the result must be a series - pass + Given a Laurent Series `f`. the compositional inverse is a + Laurent Series `g` over the same base ring, such that + `(f \circ g)(z) = f(g(z)) = z`. - return P.element_class(P, Stream_cauchy_mul(left, Stream_cauchy_invert(right))) + The compositional inverse exists if and only if: - def __pow__(self, n): - """ - Return the ``n``-th power of the series. + - `val(f) = 1`, or - INPUT: + - `f = a + b z` with `a b \neq 0`, or - - ``n`` -- integer; the power to which to raise the series + - `f = a/z` with `a \neq 0` - EXAMPLES: + EXAMPLES:: - Lazy Laurent series that have a dense implementation can be - raised to the power ``n``:: + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: z.revert() + z + O(z^8) + sage: (1/z).revert() + z^-1 + sage: (z-z^2).revert() + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: (1 - z)^-1 - 1 + z + z^2 + O(z^3) - sage: (1 - z)^0 - 1 - sage: (1 - z)^3 - 1 - 3*z + 3*z^2 - z^3 - sage: (1 - z)^-3 - 1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + O(z^7) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + TESTS:: - We can create a really large power of a monomial, even with - the dense implementation:: + sage: L. = LazyLaurentSeriesRing(QQ) + sage: s = L(lambda n: 1 if n == 1 else 0, valuation=1); s + z + O(z^8) + sage: s.revert() + z + O(z^8) - sage: z^1000000 - z^1000000 + sage: (2+3*z).revert() + -2/3 + 1/3*z - Lazy Laurent series that have a sparse implementation can be - raised to the power ``n``:: + sage: s = L(lambda n: 2 if n == 0 else 3 if n == 1 else 0, valuation=0); s + 2 + 3*z + O(z^7) + sage: s.revert() + Traceback (most recent call last): + ... + ValueError: cannot determine whether the compositional inverse exists - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: M = L(lambda n: n, valuation=0); M - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: M^2 - z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + O(z^7) + We look at some cases where the compositional inverse does not exist: - Lazy Laurent series that are known to be exact can be raised - to the power ``n``:: + `f = 0`:: - sage: z^2 - z^2 - sage: (1 - z)^2 - 1 - 2*z + z^2 - sage: (1 + z)^2 - 1 + 2*z + z^2 + sage: L(0).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + sage: (z - z).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist - TESTS:: + `val(f) ! = 1` and `f(0) * f(1) = 0`:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L(0)^10 - 0 + sage: (z^2).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + sage: L(1).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist """ - if n == 0: - return self.parent().one() - - cs = self._coeff_stream - if (isinstance(cs, Stream_exact) - and not cs._constant and n in ZZ - and (n > 0 or len(cs._initial_coefficients) == 1)): - P = self.parent() - ret = cs._polynomial_part(P._laurent_poly_ring) ** ZZ(n) - val = ret.valuation() - deg = ret.degree() + 1 - initial_coefficients = [ret[i] for i in range(val, deg)] - return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, - constant=cs._constant, degree=deg, order=val)) - - return generic_power(self, n) + P = self.parent() + if self.valuation() == 1: + z = P.gen() + g = P(None, valuation=1) + g.define(z/((self/z)(g))) + return g + if self.valuation() not in [-1, 0]: + raise ValueError("compositional inverse does not exist") + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_exact): + if (coeff_stream.order() == 0 + and coeff_stream._degree == 2): + a = coeff_stream[0] + b = coeff_stream[1] + coeff_stream = Stream_exact((-a/b, 1/b), + coeff_stream._is_sparse, + order=0) + return P.element_class(P, coeff_stream) + if (coeff_stream.order() == -1 + and coeff_stream._degree == 0): + return self + raise ValueError("compositional inverse does not exist") + raise ValueError("cannot determine whether the compositional inverse exists") def approximate_series(self, prec, name=None): - """ + r""" Return the Laurent series with absolute precision ``prec`` approximated from this series. @@ -1829,108 +3026,36 @@ def polynomial(self, degree=None, name=None): sage: f = 1/(1 + z) sage: f.polynomial() Traceback (most recent call last): - ... - ValueError: not a polynomial - - sage: L.zero().polynomial() - 0 - """ - S = self.parent() - - if degree is None: - if isinstance(self._coeff_stream, Stream_zero): - from sage.rings.all import PolynomialRing - return PolynomialRing(S.base_ring(), name=name).zero() - elif isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: - m = self._coeff_stream._degree - else: - raise ValueError("not a polynomial") - else: - m = degree + 1 - - if name is None: - name = S.variable_name() - - if self.valuation() < 0: - R = LaurentPolynomialRing(S.base_ring(), name=name) - n = self.valuation() - return R([self[i] for i in range(n, m)]).shift(n) - else: - from sage.rings.all import PolynomialRing - R = PolynomialRing(S.base_ring(), name=name) - return R([self[i] for i in range(m)]) - - def shift(self, n): - r""" - Return ``self`` multiplied by the power `z^n`, where `z` is the - variable of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: f = 1 / (1 + 2*z) - sage: f - 1 - 2*z + 4*z^2 - 8*z^3 + 16*z^4 - 32*z^5 + 64*z^6 + O(z^7) - sage: f.shift(3) - z^3 - 2*z^4 + 4*z^5 - 8*z^6 + 16*z^7 - 32*z^8 + 64*z^9 + O(z^10) - sage: f << -3 # shorthand - z^-3 - 2*z^-2 + 4*z^-1 - 8 + 16*z - 32*z^2 + 64*z^3 + O(z^4) - sage: g = z^-3 + 3 + z^2 - sage: g.shift(5) - z^2 + 3*z^5 + z^7 - sage: L([2,0,3], valuation=2, degree=7, constant=1) << -2 - 2 + 3*z^2 + z^5 + z^6 + z^7 + O(z^8) - - TESTS:: - - sage: L. = LazyLaurentSeriesRing(QQ) - sage: zero = L.zero() - sage: zero.shift(10) is zero - True + ... + ValueError: not a polynomial - sage: f = 1 / (1 + 2*z + z^2) - sage: f.shift(5).shift(-5) - f + sage: L.zero().polynomial() 0 - """ - if isinstance(self._coeff_stream, Stream_zero): - return self - elif isinstance(self._coeff_stream, Stream_shift): - n += self._coeff_stream._shift - if n: - coeff_stream = Stream_shift(self._coeff_stream._series, n) + S = self.parent() + + if degree is None: + if isinstance(self._coeff_stream, Stream_zero): + from sage.rings.all import PolynomialRing + return PolynomialRing(S.base_ring(), name=name).zero() + elif isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: + m = self._coeff_stream._degree else: - coeff_stream = self._coeff_stream._series - elif isinstance(self._coeff_stream, Stream_exact): - init_coeff = self._coeff_stream._initial_coefficients - degree = self._coeff_stream._degree + n - valuation = self._coeff_stream._approximate_order + n - coeff_stream = Stream_exact(init_coeff, self._coeff_stream._is_sparse, - constant=self._coeff_stream._constant, - order=valuation, degree=degree) + raise ValueError("not a polynomial") else: - coeff_stream = Stream_shift(self._coeff_stream, n) - P = self.parent() - return P.element_class(P, coeff_stream) - - __lshift__ = shift - - def __rshift__(self, n): - r""" - Return ``self`` multiplied by the power `z^-n`, where `z` is the - variable of ``self``. + m = degree + 1 - EXAMPLES:: + if name is None: + name = S.variable_name() - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: f = 1/(1 + 2*z); f - 1 - 2*z + 4*z^2 - 8*z^3 + 16*z^4 - 32*z^5 + 64*z^6 + O(z^7) - sage: f >> 3 - z^-3 - 2*z^-2 + 4*z^-1 - 8 + 16*z - 32*z^2 + 64*z^3 + O(z^4) - sage: f >> -3 - z^3 - 2*z^4 + 4*z^5 - 8*z^6 + 16*z^7 - 32*z^8 + 64*z^9 + O(z^10) - """ - return self.shift(-n) + if self.valuation() < 0: + R = LaurentPolynomialRing(S.base_ring(), name=name) + n = self.valuation() + return R([self[i] for i in range(n, m)]).shift(n) + else: + from sage.rings.all import PolynomialRing + R = PolynomialRing(S.base_ring(), name=name) + return R([self[i] for i in range(m)]) def _format_series(self, formatter, format_strings=False): """ @@ -1944,7 +3069,7 @@ def _format_series(self, formatter, format_strings=False): 1/2 + 1/4*z^2 + 1/8*z^4 + 1/16*z^6 + O(z^7) """ P = self.parent() - R = P._laurent_poly_ring + R = P._internal_poly_ring z = R.gen() cs = self._coeff_stream v = cs._approximate_order @@ -1958,7 +3083,7 @@ def _format_series(self, formatter, format_strings=False): if not cs._constant: return formatter(poly) m = cs._degree + P.options.constant_length - poly += sum([cs._constant * z**k for k in range(cs._degree, m)]) + poly += sum(cs._constant * z**k for k in range(cs._degree, m)) return formatter(poly) + strformat(" + O({})".format(formatter(z**m))) # This is an inexact series @@ -1970,138 +3095,323 @@ def _format_series(self, formatter, format_strings=False): return strformat("O({})".format(formatter(z**m))) return formatter(poly) + strformat(" + O({})".format(formatter(z**m))) - def _repr_(self): + +class LazyDirichletSeries(LazyModuleElement): + r""" + A Dirichlet series where the coefficients are computed lazily. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: f = L(constant=1)^2; f + 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) + sage: f.coefficient(100) == number_of_divisors(100) + True + + Lazy Dirichlet series is picklable:: + + sage: g = loads(dumps(f)) + sage: g + 1 + 2/2^z + 2/3^z + 3/4^z + 2/5^z + 4/6^z + 2/7^z + O(1/(8^z)) + sage: g == f + True + """ + def valuation(self): r""" - Return a string representation of ``self``. + Return the valuation of ``self``. - EXAMPLES:: + This method determines the valuation of the series by looking for a + nonzero coefficient. Hence if the series happens to be zero, then it + may run forever. - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: z^-3 + z - 5 - z^-3 - 5 + z - sage: -1/(1 + 2*z) - -1 + 2*z - 4*z^2 + 8*z^3 - 16*z^4 + 32*z^5 - 64*z^6 + O(z^7) - sage: -z^-7/(1 + 2*z) - -z^-7 + 2*z^-6 - 4*z^-5 + 8*z^-4 - 16*z^-3 + 32*z^-2 - 64*z^-1 + O(1) - sage: L([1,5,0,3], valuation=-1, degree=5, constant=2) - z^-1 + 5 + 3*z^2 + 2*z^5 + 2*z^6 + 2*z^7 + O(z^8) - sage: L(constant=5, valuation=2) - 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) - sage: L(constant=5, degree=-2) - 5*z^-2 + 5*z^-1 + 5 + O(z) - sage: L(lambda x: x if x < 0 else 0, valuation=-2) - -2*z^-2 - z^-1 + O(z^5) - sage: L(lambda x: x if x < 0 else 0, valuation=2) - O(z^9) - sage: L(lambda x: x if x > 0 else 0, valuation=-2) - z + 2*z^2 + 3*z^3 + 4*z^4 + O(z^5) - sage: L(lambda x: x if x > 0 else 0, valuation=-10) - O(z^-3) + EXAMPLES:: - sage: L(None, valuation=0) - Uninitialized Lazy Laurent Series - sage: L(0) + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: mu = L(moebius); mu.valuation() 0 + sage: (mu - mu).valuation() + +Infinity + sage: g = L(constant=1, valuation=2) + sage: g.valuation() + log(2) + sage: (g*g).valuation() + 2*log(2) + """ + from sage.functions.log import log + return log(self._coeff_stream.order()) - sage: R. = QQ[] - sage: L. = LazyLaurentSeriesRing(R) - sage: z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4 - (-y + 1)*z^-4 + x^4*z^-3 + z^-2 + (x - y)*z^-1 - + (x^2 - 2*x*y + y^2) + (x^3 - 3*x^2*y + 3*x*y^2 - y^3)*z - + (x^4 - 4*x^3*y + 6*x^2*y^2 - 4*x*y^3 + y^4)*z^2 + O(z^3) + def _mul_(self, other): """ - if isinstance(self._coeff_stream, Stream_zero): - return '0' - if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: - return 'Uninitialized Lazy Laurent Series' - return self._format_series(repr) + Return the product of this series with ``other``. - def _latex_(self): - r""" - Return a latex representation of ``self``. + INPUT: - EXAMPLES:: + - ``other`` -- other series - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: latex(z^-3 + z - 5) - \frac{1}{z^{3}} - 5 + z - sage: latex(-1/(1 + 2*z)) - -1 + 2z - 4z^{2} + 8z^{3} - 16z^{4} + 32z^{5} - 64z^{6} + O(z^{7}) - sage: latex(-z^-7/(1 + 2*z)) - \frac{-1}{z^{7}} + \frac{2}{z^{6}} + \frac{-4}{z^{5}} + \frac{8}{z^{4}} - + \frac{-16}{z^{3}} + \frac{32}{z^{2}} + \frac{-64}{z} + O(1) - sage: latex(L([1,5,0,3], valuation=-1, degree=5, constant=2)) - \frac{1}{z} + 5 + 3z^{2} + 2z^{5} + 2z^{6} + 2z^{7} + O(z^{8}) - sage: latex(L(constant=5, valuation=2)) - 5z^{2} + 5z^{3} + 5z^{4} + O(z^{5}) - sage: latex(L(constant=5, degree=-2)) - \frac{5}{z^{2}} + \frac{5}{z} + 5 + O(z) - sage: latex(L(lambda x: x if x < 0 else 0, valuation=-2)) - \frac{-2}{z^{2}} + \frac{-1}{z} + O(z^{5}) - sage: latex(L(lambda x: x if x < 0 else 0, valuation=2)) - O(z^{9}) - sage: latex(L(lambda x: x if x > 0 else 0, valuation=-2)) - z + 2z^{2} + 3z^{3} + 4z^{4} + O(z^{5}) - sage: latex(L(lambda x: x if x > 0 else 0, valuation=-10)) - O(\frac{1}{z^{3}}) + TESTS:: - sage: latex(L(None, valuation=0)) - \text{\texttt{Undef}} - sage: latex(L(0)) - 0 + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: zeta = D(constant=1); zeta + 1 + 1/(2^s) + 1/(3^s) + O(1/(4^s)) + sage: zeta * zeta + 1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)) + sage: [number_of_divisors(n) for n in range(1, 8)] + [1, 2, 2, 3, 2, 4, 2] + + sage: mu = D(moebius); mu + 1 - 1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(8^s)) + sage: zeta * mu + 1 + O(1/(8^s)) + sage: D.one() * mu is mu + True + sage: mu * D.one() is mu + True + + sage: zeta*(2-zeta) + 1 - 1/(4^s) - 2/6^s + O(1/(8^s)) + + sage: d1 = D([0,0,1,2,3]) + sage: d2 = D([0,1,2,3]) + sage: d1 * d2 + 1/(6^s) + 2/8^s + 2/9^s + 3/10^s + 7/12^s + O(1/(13^s)) + + sage: d1 * d2 # not tested - exact result + 1/(6^s) + 2/8^s + 2/9^s + 3/10^s + 7/12^s + 6/15^s + 6/16^s + 9/20^s + + sage: L. = LazyLaurentSeriesRing(D) + sage: 1/(1-t*zeta) + (1 + O(1/(8^s))) + (1 + 1/(2^s) + 1/(3^s) + 1/(4^s) + 1/(5^s) + 1/(6^s) + 1/(7^s) + O(1/(8^s)))*t + (1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)))*t^2 + (1 + 3/2^s + 3/3^s + 6/4^s + 3/5^s + 9/6^s + 3/7^s + O(1/(8^s)))*t^3 + (1 + 4/2^s + 4/3^s + 10/4^s + 4/5^s + 16/6^s + 4/7^s + O(1/(8^s)))*t^4 + (1 + 5/2^s + 5/3^s + 15/4^s + 5/5^s + 25/6^s + 5/7^s + O(1/(8^s)))*t^5 + (1 + 6/2^s + 6/3^s + 21/4^s + 6/5^s + 36/6^s + 6/7^s + O(1/(8^s)))*t^6 + O(t^7) - sage: R. = QQ[] - sage: L. = LazyLaurentSeriesRing(R) - sage: latex(z^-2 / (1 - (x-y)*z) + x^4*z^-3 + (1-y)*z^-4) - \frac{-y + 1}{z^{4}} + \frac{x^{4}}{z^{3}} + \frac{1}{z^{2}} - + \frac{x - y}{z} + x^{2} - 2 x y + y^{2} - + \left(x^{3} - 3 x^{2} y + 3 x y^{2} - y^{3}\right)z - + \left(x^{4} - 4 x^{3} y + 6 x^{2} y^{2} - 4 x y^{3} + y^{4}\right)z^{2} - + O(z^{3}) """ - from sage.misc.latex import latex - if isinstance(self._coeff_stream, Stream_zero): - return latex('0') - if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: - return latex("Undef") - return self._format_series(latex) + P = self.parent() + left = self._coeff_stream + right = other._coeff_stream + if isinstance(left, Stream_zero): + return self + if isinstance(right, Stream_zero): + return other + if (isinstance(left, Stream_exact) + and not left._constant + and left._initial_coefficients == (P._coeff_ring.one(),) + and left.order() == 1): + return other # self == 1 + if (isinstance(right, Stream_exact) + and not right._constant + and right._initial_coefficients == (P._coeff_ring.one(),) + and right.order() == 1): + return self # other == 1 + coeff = Stream_dirichlet_convolve(left, right) + # Performing exact arithmetic is slow because the series grow large + # very quickly as we are multiplying the degree + #if (isinstance(left, Stream_exact) and not left._constant + # and isinstance(right, Stream_exact) and not right._constant): + # # Product of finite length Dirichlet series, + # # so the result has finite length + # deg = (left._degree - 1) * (right._degree - 1) + 1 + # order = left._approximate_order * right._approximate_order + # coeff_vals = [coeff[i] for i in range(order, deg)] + # return P.element_class(P, Stream_exact(coeff_vals, coeff._is_sparse, + # constant=left._constant, order=order, degree=deg)) + return P.element_class(P, coeff) - def _ascii_art_(self): - r""" - Return an ascii art representation of ``self``. + def __invert__(self): + """ + Return the multiplicative inverse of the element. - EXAMPLES:: + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=False) + sage: ~L(constant=1) - L(moebius) + O(1/(8^z)) + sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) + sage: ~L(constant=1) - L(moebius) + O(1/(8^z)) - sage: e = SymmetricFunctions(QQ).e() - sage: L. = LazyLaurentSeriesRing(e) - sage: L.options.display_length = 3 - sage: ascii_art(1 / (1 - e[1]*z)) - e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) - sage: L.options._reset() """ - from sage.typeset.ascii_art import ascii_art, AsciiArt - if isinstance(self._coeff_stream, Stream_zero): - return AsciiArt('0') - if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: - return AsciiArt('Uninitialized Lazy Laurent Series') - return self._format_series(ascii_art, True) + P = self.parent() + return P.element_class(P, Stream_dirichlet_invert(self._coeff_stream)) - def _unicode_art_(self): + def __call__(self, p): r""" - Return a unicode art representation of ``self``. + Return the composition of ``self`` with a linear polynomial ``p``. + + Return the series with the variable `s` replaced by a linear + polynomial `a\cdot s + b`, for positive `a`. + + When `f` is an exact Dirichlet series, we can write + + .. MATH:: + + f(s) = \sum_{n=1}^k a_n / n^s + C \zeta(s). + + Thus we can evaluate this for `p \in \CC` by using the analytic + continuation of the Riemann `\zeta` function for `p \in \CC` + with the real part of `p` at most `1`. In the case `p = 1`, + this will return `\infty` if `C \neq 0`. EXAMPLES:: - sage: e = SymmetricFunctions(QQ).e() - sage: L. = LazyLaurentSeriesRing(e) - sage: L.options.display_length = 3 - sage: unicode_art(1 / (1 - e[1]*z)) - e[] + e[1]*z + e[1, 1]*z^2 + O(e[]*z^3) - sage: L.options._reset() + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: P. = QQ[] + sage: Z = D(constant=1) + sage: from sage.arith.misc import dedekind_psi + sage: Psi = D(dedekind_psi) + sage: Z(s)*Z(s-1)/Z(2*s) - Psi + O(1/(8^s)) + + sage: Z(s)*Z(s-1)/Z(2*s-2) - (1/Psi).map_coefficients(abs) + O(1/(8^s)) + + sage: Z(5) + zeta(5) + sage: Z(1+I) + zeta(I + 1) + sage: Z(0) + -1/2 + sage: Z(1) + Infinity + + sage: f = D([1,2,-3,-4], valuation=2); f + 1/(2^s) + 2/3^s - 3/4^s - 4/5^s + sage: f(2) + 449/3600 + sage: 1/2^2 + 2/3^2 + -3/4^2 + -4/5^2 + 449/3600 + sage: f(0) + -4 + sage: f(1) + -23/60 + sage: f(-2) + -126 + + sage: f = D([4,2,-3,2]) + sage: f(0) + 5 + + sage: f = D([1,2,-3,-4], constant=2) + sage: bool(f(2) == -1 + -5/3^2 + -6/4^2 + 2*zeta(2)) + True + sage: f(0) + -13 + sage: f(1) + Infinity """ - from sage.typeset.unicode_art import unicode_art, UnicodeArt - if isinstance(self._coeff_stream, Stream_zero): - return UnicodeArt('0') - if isinstance(self._coeff_stream, Stream_uninitialized) and self._coeff_stream._target is None: - return UnicodeArt('Uninitialized Lazy Laurent Series') - return self._format_series(unicode_art, True) + P = self.parent() + coeff_stream = self._coeff_stream + + # Special behavior for finite series + if isinstance(coeff_stream, Stream_exact): + from sage.rings.all import CC + if not coeff_stream._constant: + try: + return sum(self[k] * ~(ZZ(k)**p) + for k in range(1, coeff_stream._degree)) + except (ValueError, TypeError, ArithmeticError): + pass + elif p in CC: + from sage.functions.transcendental import zeta + C = coeff_stream._constant + ret = sum((self[k] - C) * ~(ZZ(k)**p) + for k in range(1, coeff_stream._degree)) + return ret + C * zeta(p) + + R = PolynomialRing(ZZ, P.variable_name()) + p = R(p) + if p.degree() != 1: + raise ValueError("the argument must be a linear polynomial of degree 1 with integer coefficients") + b, a = p + if a < 0: + raise ValueError("the leading coefficient must be positive") + def coefficient(m): + m = ZZ(m) + try: + n = m.nth_root(a) + return coeff_stream[n] * n ** (-b) + except ValueError: + return ZZ.zero() + return P.element_class(P, Stream_function(coefficient, P._coeff_ring, P._sparse, 1)) + + def _format_series(self, formatter, format_strings=False): + """ + Return nonzero ``self`` formatted by ``formatter``. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(QQ, "s") + sage: f = L(constant=1) + sage: f._format_series(repr) + '1 + 1/(2^s) + 1/(3^s) + O(1/(4^s))' + sage: f._format_series(unicode_art) + -s -s + 1 + 2 + 3 + O(1/(4^s)) + + sage: L([1,-1,1])._format_series(repr) + '1 - 1/(2^s) + 1/(3^s)' + + sage: L([1,-1,1])._format_series(ascii_art) + -s -s + 1 + -2 + 3 + + sage: R. = QQ[] + sage: L = LazyDirichletSeriesRing(R, "s") + sage: L([1,-1 + x,1/3])._format_series(ascii_art) + ( -s) + (3 ) + ( -s ) (---) + (1) + (2 *(x - 1)) + ( 3 ) + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: D = LazyDirichletSeriesRing(L, "s") + sage: f = D([2, 0, 1/(1-z), 3]); f + (2)/1^s + ((1+z+z^2+z^3+z^4+z^5+z^6+O(z^7))/3^s) + (3)/4^s + sage: f._format_series(ascii_art) + ((2)/1^s) + ((1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7))/3^s) + ((3)/4^s) + """ + P = self.parent() + cs = self._coeff_stream + v = cs._approximate_order + if isinstance(cs, Stream_exact): + if not cs._constant: + m = cs._degree + else: + m = cs._degree + P.options.constant_length + else: + m = v + P.options.display_length + + atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] + if not isinstance(cs, Stream_exact) or cs._constant: + if P._coeff_ring is P.base_ring(): + bigO = ["O(%s)" % P._monomial(1, m)] + else: + bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] + else: + bigO = [] + + from sage.misc.latex import latex + from sage.typeset.unicode_art import unicode_art + from sage.typeset.ascii_art import ascii_art + from sage.misc.repr import repr_lincomb + if formatter == repr: + poly = repr_lincomb([(1, mo) for mo in mons + bigO], strip_one=True) + elif formatter == latex: + poly = repr_lincomb([(1, mo) for mo in mons + bigO], is_latex=True, strip_one=True) + elif formatter in [ascii_art, unicode_art]: + if formatter == ascii_art: + from sage.typeset.symbols import ascii_left_parenthesis as left_paren + from sage.typeset.symbols import ascii_right_parenthesis as right_paren + else: + from sage.typeset.symbols import unicode_left_parenthesis as left_paren + from sage.typeset.symbols import unicode_right_parenthesis as right_paren + if atomic_repr: + poly = formatter(*(mons + bigO), sep=" + ") + else: + def parenthesize(m): + a = formatter(m) + h = a.height() + return formatter(left_paren.character_art(h), + a, right_paren.character_art(h)) + poly = formatter(*([parenthesize(mo) for mo in mons] + bigO), sep=" + ") + + return poly + diff --git a/src/sage/rings/lazy_laurent_series_ring.py b/src/sage/rings/lazy_series_ring.py similarity index 62% rename from src/sage/rings/lazy_laurent_series_ring.py rename to src/sage/rings/lazy_series_ring.py index 19ed63022be..9863af2d81a 100644 --- a/src/sage/rings/lazy_laurent_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1,5 +1,5 @@ r""" -Lazy Laurent Series Rings +Lazy Series Rings AUTHORS: @@ -23,6 +23,7 @@ from sage.structure.element import parent from sage.categories.algebras import Algebras +from sage.categories.rings import Rings from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields @@ -31,8 +32,12 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing -from sage.rings.lazy_laurent_series import LazyCauchyProductSeries, LazyLaurentSeries +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.lazy_series import (LazyModuleElement, + LazyLaurentSeries, + LazyDirichletSeries) from sage.structure.global_options import GlobalOptions +from sage.symbolic.ring import SR from sage.data_structures.stream import ( Stream_zero, @@ -41,8 +46,388 @@ Stream_uninitialized ) +class LazySeriesRing(UniqueRepresentation, Parent): + """ + Abstract base class for lazy series. + """ + def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, coefficients=None): + r""" + Construct a lazy series from ``x``. + + INPUT: + + - ``x`` -- data used to the define a series + - ``valuation`` -- integer (optional); integer; a lower bound for + the valuation of the series + - ``degree`` -- (optional) the degree when the series is ``constant`` + - ``constant`` -- (optional) the eventual constant of the series + - ``coefficients`` -- (optional) a callable that defines the + coefficients of the series; must be ``None`` if ``x`` is provided; + see note below + + If ``valuation`` is specified and ``x`` is convertible into + an element of the underlying ring corresponding to series + with finite support or ``x`` is a lazy series of the same + parent, then the data is shifted so that the result has the + specified valuation. + + .. WARNING:: + + If ``valuation`` is specified and ``x`` is a lazy series, then + the valuation will be computed. If the series ``x`` is not + known to be zero, then this will run forever. + + .. NOTE:: + + When working over a base ring that takes callables as valid + input, then passing a function as ``x`` might be converted to + the base ring. If instead the input is to be treated as the + function giving the coefficients of the lazy series being + constructed, then use the ``coefficients`` argument in this + case and do not provide ``x``. + + .. WARNING:: + + Polynomials, but also :class:`LazyLaurentSeries` and + :class:`LazyDirichletSeries` are callable. Therefore, an + argument ``x`` which is not convertible into an element + of the underlying ring corresponding to series with + finite support is interpreted as a function providing the + coefficients when evaluated at integers. Examples are + provided below. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(GF(2), 'z') + sage: L(2) + 0 + sage: L(3) + 1 + + sage: L. = LazyLaurentSeriesRing(ZZ) + + sage: L(lambda i: i, valuation=5, constant=1, degree=10) + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) + sage: L(lambda i: i, valuation=5, constant=(1, 10)) + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) + + sage: X = L(constant=5, degree=2); X + 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) + sage: X.valuation() + 2 + + sage: def g(i): + ....: if i < 0: + ....: return 1 + ....: else: + ....: return 1 + sum(k for k in range(i+1)) + sage: e = L(g, valuation=-5); e + z^-5 + z^-4 + z^-3 + z^-2 + z^-1 + 1 + 2*z + O(z^2) + sage: f = e^-1; f + z^5 - z^6 - z^11 + O(z^12) + sage: f.coefficient(10) + 0 + sage: f[20] + 9 + sage: f[30] + -219 + + sage: L(valuation=2, constant=1) + z^2 + z^3 + z^4 + O(z^5) + sage: L(constant=1) + Traceback (most recent call last): + ... + ValueError: you must specify the degree for the polynomial 0 + + Alternatively, ``x`` can be a list of elements of the base ring. + Then these elements are read as coefficients of the terms of + degrees starting from the ``valuation``. In this case, ``constant`` + may be just an element of the base ring instead of a tuple or can be + simply omitted if it is zero:: + + sage: f = L([1,2,3,4], valuation=-5) + sage: f + z^-5 + 2*z^-4 + 3*z^-3 + 4*z^-2 + sage: g = L([1,3,5,7,9], valuation=5, constant=-1) + sage: g + z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) + + Finally, ``x`` can be a Laurent polynomial:: + + sage: P. = LaurentPolynomialRing(QQ) + sage: p = x^-2 + 3*x^3 + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L(p) + x^-2 + 3*x^3 + + sage: L(p, valuation=0) + 1 + 3*x^5 + + sage: L(p, valuation=1) + x + 3*x^6 + + We construct a lazy Laurent series over another lazy Laurent series:: + + sage: R. = LazyLaurentSeriesRing(QQ) + sage: L. = LazyLaurentSeriesRing(R) + sage: e = L(lambda n: 1/factorial(n), 0); e + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + sage: L(lambda n: 1/(1 + s^n), 0) + 1/2 + (1 - s + s^2 - s^3 + s^4 - s^5 + s^6 + O(s^7))*z + + (1 - s^2 + s^4 - s^6 + O(s^7))*z^2 + + (1 - s^3 + s^6 + O(s^7))*z^3 + (1 - s^4 + O(s^7))*z^4 + + (1 - s^5 + O(s^7))*z^5 + (1 - s^6 + O(s^7))*z^6 + O(z^7) + + We note that ``e`` builds correctly because ``R`` additionally + requires the valuation to be specified. + + In the next example the argument is interpreted as a constant + polynomial, which happens to be a Dirichlet series:: + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: L. = LazyLaurentSeriesRing(D) + sage: L(lambda n: 1/factorial(n), valuation=0) + (1 + 1/2/2^s + 1/6/3^s + 1/24/4^s + 1/120/5^s + 1/720/6^s + 1/5040/7^s + O(1/(8^s))) + + We can also specify that the given function should be + interpreted as the coefficients of the Laurent series:: + + sage: L(coefficients=lambda n: 1/factorial(n), valuation=0) + 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) + + When the argument ``x`` is callable and not convertible into + an element of the underlying ring of series of finite + support, it is evaluated at integers to compute the + coefficients:: + + sage: R. = QQ[] + sage: D = LazyDirichletSeriesRing(ZZ, 't') + sage: D(1+2*q) + 3 + 5/2^t + 7/3^t + 9/4^t + 11/5^t + 13/6^t + 15/7^t + O(1/(8^t)) + + In this example, the Dirichlet series ``m`` is considered as an + element in the base ring:: + + sage: m = D(moebius) + sage: s = L(m, valuation=0) + sage: s[0] + 1 - 1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(8^s)) + sage: s[1] + 0 + + TESTS: + + Checking the valuation is consistent:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L([0,0,2,3], valuation=-4) + 2*z^-4 + 3*z^-3 + sage: L(range(5), valuation=-4) + z^-4 + 2*z^-3 + 3*z^-2 + 4*z^-1 + sage: P. = ZZ[] + sage: L(x^2 + x^5, valuation=-4) + z^-4 + z^-1 + sage: L(1, valuation=-4) + z^-4 + sage: L(L(1), valuation=-4) + z^-4 + sage: L(1/(1-z), valuation=-4) + z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) + sage: L(z^-3/(1-z), valuation=-4) + z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) + sage: L(z^3/(1-z), valuation=-4) + z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) + + sage: L(z^3/(1-z), valuation=0) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L(lambda n: 1/(n+1), degree=3) + Traceback (most recent call last): + ... + ValueError: the valuation must be specified + + sage: L(5, valuation=3.1) + Traceback (most recent call last): + ... + ValueError: the valuation must be an integer + + sage: L(5, valuation=6/2) + 5*z^3 + + Checking that series are not interpreted as coefficients when + they can be interpreted as series:: + + sage: P. = ZZ[] + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: M. = LazyLaurentSeriesRing(QQ) + sage: L(M(s^2 + s^5), valuation=-4) + z^-4 + z^-1 + + sage: D = LazyDirichletSeriesRing(ZZ, "s") + sage: E = LazyDirichletSeriesRing(QQ, "t") + sage: D(E([1,2,3])) + 1 + 2/2^s + 3/3^s + + This gives zero:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L(lambda n: 0, degree=3, valuation=0) + 0 + sage: L(L.zero(), degree=3) + 0 + sage: L(L.zero(), degree=3, valuation=2) + 0 + sage: L(L.zero(), degree=3, constant=0) + 0 + sage: L(L.zero(), degree=3, valuation=2, constant=0) + 0 + + This does not:: + + sage: L(lambda n: 0, degree=3, constant=1, valuation=0) + z^3 + z^4 + z^5 + O(z^6) + sage: L(L.zero(), degree=-3, constant=1) + z^-3 + z^-2 + z^-1 + O(1) + sage: L(L.zero(), valuation=2, constant=1) + z^2 + z^3 + z^4 + O(z^5) + + This raises an error:: + + sage: L(lambda n: 0, valuation=3, constant=1) + Traceback (most recent call last): + ... + ValueError: constant may only be specified if the degree is specified + + We support the old input format for ``constant``:: + + sage: f = L(lambda i: i, valuation=-3, constant=-1, degree=3) + sage: g = L(lambda i: i, valuation=-3, constant=(-1,3)) + sage: f == g + True + sage: g = L(lambda i: i, -3, (-1,3)) + sage: f == g + True + + .. TODO:: + + Add a method to change the sparse/dense implementation. + + """ + if valuation is not None and valuation not in ZZ: + raise ValueError("the valuation must be an integer") + + if x is None and coefficients is None: + if valuation is None: + raise ValueError("the valuation must be specified") + return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) + + if coefficients is not None and (x is not None and (not isinstance(x, int) or x)): + raise ValueError("coefficients must be None if x is provided") + + BR = self.base_ring() + if isinstance(constant, (tuple, list)): + constant, degree = constant + if isinstance(degree, (tuple, list)): + constant, degree = degree + if constant is not None: + constant = BR(constant) + + if coefficients is None: + # Try to build stuff using the internal polynomial ring constructor + R = self._internal_poly_ring + try: + x = R(x) + except (TypeError, ValueError): + pass + + # If x has been converted to the internal polynomial ring + if parent(x) is R: + if not x and not constant: + return self.zero() + if x and valuation is not None: + x = x.shift(valuation - x.valuation()) + if degree is None and not x: + if valuation is None: + raise ValueError("you must specify the degree for the polynomial 0") + degree = valuation + if x == R.zero(): + coeff_stream = Stream_exact([], self._sparse, order=degree, constant=constant) + return self.element_class(self, coeff_stream) + initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] + coeff_stream = Stream_exact(initial_coefficients, self._sparse, + order=x.valuation(), constant=constant, degree=degree) + return self.element_class(self, coeff_stream) -class LazyLaurentSeriesRing(UniqueRepresentation, Parent): + # Handle when it is a lazy series + if isinstance(x, self.Element): + if x._coeff_stream._is_sparse is not self._sparse: + # TODO: Implement a way to make a self._sparse copy + raise NotImplementedError("cannot convert between sparse and dense") + + # If x is known to be 0 + if isinstance(x._coeff_stream, Stream_zero): + if not constant: + if self is parent(x): + return x + return self.element_class(self, x._coeff_stream) + if degree is None: + if valuation is None: + raise ValueError("you must specify the degree for the polynomial 0") + degree = valuation + coeff_stream = Stream_exact([], self._sparse, order=degree, + constant=constant) + return self.element_class(self, coeff_stream) + + # Make the result exact + if degree is not None: + # truncate the series and then possibly make constant + x_val = x._coeff_stream.order() + if not valuation: + valuation = x_val + initial_coefficients = [x[x_val+i] for i in range(degree-valuation)] + if not any(initial_coefficients): + if not constant: + return self.zero() + # We learned some stuff about x; pass it along + x._coeff_stream._approximate_order += len(initial_coefficients) + initial_coefficients = [] + coeff_stream = Stream_exact(initial_coefficients, self._sparse, + order=valuation, constant=constant, degree=degree) + return self.element_class(self, coeff_stream) + + # We are just possibly shifting the result + ret = self.element_class(self, x._coeff_stream) + if valuation is None: + return ret + return ret.shift(valuation - x._coeff_stream.order()) + + else: + x = coefficients + + if callable(x): + if valuation is None: + raise ValueError("the valuation must be specified") + if degree is None: + if constant is not None: + raise ValueError("constant may only be specified if the degree is specified") + coeff_stream = Stream_function(x, self.base_ring(), self._sparse, valuation) + return self.element_class(self, coeff_stream) + + # degree is not None + if constant is None: + constant = BR.zero() + p = [BR(x(i)) for i in range(valuation, degree)] + if not any(p) and not constant: + return self.zero() + coeff_stream = Stream_exact(p, self._sparse, order=valuation, + constant=constant, degree=degree) + return self.element_class(self, coeff_stream) + + raise ValueError(f"unable to convert {x} into {self}") + + +class LazyLaurentSeriesRing(LazySeriesRing): """ The ring of lazy Laurent series. @@ -221,6 +606,7 @@ def __init__(self, base_ring, names, sparse=True, category=None): self._coeff_ring = base_ring # We always use the dense because our CS_exact is implemented densely self._laurent_poly_ring = LaurentPolynomialRing(base_ring, names) + self._internal_poly_ring = self._laurent_poly_ring category = Algebras(base_ring.category()) if base_ring in Fields(): @@ -262,6 +648,24 @@ def _latex_(self): from sage.misc.latex import latex return latex(self.base_ring()) + r"(\!({})\!)".format(self.variable_name()) + def characteristic(self): + """ + Return the characteristic of this lazy power series ring, which + is the same as the characteristic of its base ring. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L.characteristic() + 0 + sage: R. = LazyLaurentSeriesRing(GF(11)); R + Lazy Laurent Series Ring in w over Finite Field of size 11 + sage: R.characteristic() + 11 + + """ + return self.base_ring().characteristic() + def is_sparse(self): """ Return whether ``self`` is sparse or not. @@ -297,384 +701,75 @@ def gen(self, n=0): raise IndexError("there is only one generator") R = self.base_ring() coeff_stream = Stream_exact([R.one()], self._sparse, - constant=R.zero(), order=1) + constant=R.zero(), order=1) return self.element_class(self, coeff_stream) def ngens(self): r""" Return the number of generators of ``self``. - This is always 1. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L.ngens() - 1 - """ - return 1 - - @cached_method - def gens(self): - """ - Return the generators of ``self``. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L.gens() - (z,) - sage: 1/(1 - z) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - """ - return tuple([self.gen(n) for n in range(self.ngens())]) - - def _coerce_map_from_(self, S): - """ - Return ``True`` if a coercion from ``S`` exists. - - EXAMPLES:: - - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: L.has_coerce_map_from(ZZ) - True - sage: L.has_coerce_map_from(GF(2)) - True - """ - if self.base_ring().has_coerce_map_from(S): - return True - - R = self._laurent_poly_ring - return R.has_coerce_map_from(S) - - def _coerce_map_from_base_ring(self): - """ - Return a coercion map from the base ring of ``self``. - - EXAMPLES:: - - sage: L = LazyLaurentSeriesRing(QQ, 'z') - sage: phi = L._coerce_map_from_base_ring() - sage: phi(2) - 2 - sage: phi(2, valuation=-2) - 2*z^-2 - sage: phi(2, valuation=-2, constant=3, degree=1) - 2*z^-2 + 3*z + 3*z^2 + 3*z^3 + O(z^4) - """ - # Return a DefaultConvertMap_unique; this can pass additional - # arguments to _element_constructor_, unlike the map returned - # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. - return self._generic_coerce_map(self.base_ring()) - - def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, coefficients=None): - """ - Construct a Laurent series from ``x``. - - INPUT: - - - ``x`` -- data used to the define a Laurent series - - ``valuation`` -- integer (optional); integer; a lower bound for - the valuation of the series - - ``constant`` -- (optional) the eventual constant of the series - - ``degree`` -- (optional) the degree when the series is ``constant`` - - ``coefficients`` -- (optional) a callable that defines the - coefficients of the series; ignored if ``x`` is not ``None``; - see note below - - If ``valuation`` is specified and ``x`` is convertible into a Laurent - polynomial or is a lazy Laurent series, then the data is shifted so - that the result has the specified valuation. - - .. WARNING:: - - If ``valuation`` is specified and ``x`` is a lazy series, then - the valuation will be computed. If the series ``x`` is not - known to be zero, then this will run forever. - - .. NOTE:: - - When working over a base ring that takes callables as valid - input, then passing a function as ``x`` might be converted to - the base ring. If instead the input is to be treated as the - function giving the coefficients of the lazy series being - cosntructed, then use the ``coefficients`` argument in this - case and leave ``x`` as ``None``. - - If ``x`` is given ``coefficients`` is ignored. - - EXAMPLES:: - - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: L(2) - 0 - sage: L(3) - 1 - - sage: L. = LazyLaurentSeriesRing(ZZ) - - sage: L(lambda i: i, valuation=5, constant=1, degree=10) - 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) - sage: L(lambda i: i, valuation=5, constant=(1, 10)) - 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) - - sage: X = L(constant=5, degree=2); X - 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) - sage: X.valuation() - 2 - - sage: def g(i): - ....: if i < 0: - ....: return 1 - ....: else: - ....: return 1 + sum(k for k in range(i+1)) - sage: e = L(g, valuation=-5); e - z^-5 + z^-4 + z^-3 + z^-2 + z^-1 + 1 + 2*z + O(z^2) - sage: f = e^-1; f - z^5 - z^6 - z^11 + O(z^12) - sage: f.coefficient(10) - 0 - sage: f[20] - 9 - sage: f[30] - -219 - - sage: L(valuation=2, constant=1) - z^2 + z^3 + z^4 + O(z^5) - sage: L(constant=1) - Traceback (most recent call last): - ... - ValueError: you must specify the degree for the polynomial 0 - - Alternatively, ``x`` can be a list of elements of the base ring. - Then these elements are read as coefficients of the terms of - degrees starting from the ``valuation``. In this case, ``constant`` - may be just an element of the base ring instead of a tuple or can be - simply omitted if it is zero:: - - sage: f = L([1,2,3,4], valuation=-5) - sage: f - z^-5 + 2*z^-4 + 3*z^-3 + 4*z^-2 - sage: g = L([1,3,5,7,9], valuation=5, constant=-1) - sage: g - z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) - - Finally, ``x`` can be a Laurent polynomial:: - - sage: P. = LaurentPolynomialRing(QQ) - sage: p = x^-2 + 3*x^3 - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L(p) - x^-2 + 3*x^3 - - sage: L(p, valuation=0) - 1 + 3*x^5 - - sage: L(p, valuation=1) - x + 3*x^6 - - We construct a lazy Laurent series over another lazy Laurent series:: - - sage: R. = LazyLaurentSeriesRing(QQ) - sage: L. = LazyLaurentSeriesRing(R) - sage: e = L(lambda n: 1/factorial(n), 0); e - 1 + z + 1/2*z^2 + 1/6*z^3 + 1/24*z^4 + 1/120*z^5 + 1/720*z^6 + O(z^7) - sage: L(lambda n: 1/(1 + s^n), 0) - 1/2 + (1 - s + s^2 - s^3 + s^4 - s^5 + s^6 + O(s^7))*z - + (1 - s^2 + s^4 - s^6 + O(s^7))*z^2 - + (1 - s^3 + s^6 + O(s^7))*z^3 + (1 - s^4 + O(s^7))*z^4 - + (1 - s^5 + O(s^7))*z^5 + (1 - s^6 + O(s^7))*z^6 + O(z^7) - - We note that ``e`` builds correctly because ``R`` additionally - requires the valuation to be specified. - - TESTS: - - Checking the valuation is consistent:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L([0,0,2,3], valuation=-4) - 2*z^-4 + 3*z^-3 - sage: L(range(5), valuation=-4) - z^-4 + 2*z^-3 + 3*z^-2 + 4*z^-1 - sage: P. = ZZ[] - sage: L(x^2 + x^5, valuation=-4) - z^-4 + z^-1 - sage: L(1, valuation=-4) - z^-4 - sage: L(L(1), valuation=-4) - z^-4 - sage: L(1/(1-z), valuation=-4) - z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) - sage: L(z^-3/(1-z), valuation=-4) - z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) - sage: L(z^3/(1-z), valuation=-4) - z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) - - sage: L(z^3/(1-z), valuation=0) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) - - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L(lambda n: 1/(n+1), degree=3) - Traceback (most recent call last): - ... - ValueError: the valuation must be specified - - sage: L(5, valuation=3.1) - Traceback (most recent call last): - ... - ValueError: the valuation must be an integer - - sage: L(5, valuation=6/2) - 5*z^3 - - This gives zero:: - - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L(lambda n: 0, degree=3, valuation=0) - 0 - sage: L(L.zero(), degree=3) - 0 - sage: L(L.zero(), degree=3, valuation=2) - 0 - sage: L(L.zero(), degree=3, constant=0) - 0 - sage: L(L.zero(), degree=3, valuation=2, constant=0) - 0 - - This does not:: - - sage: L(lambda n: 0, degree=3, constant=1, valuation=0) - z^3 + z^4 + z^5 + O(z^6) - sage: L(L.zero(), degree=-3, constant=1) - z^-3 + z^-2 + z^-1 + O(1) - sage: L(L.zero(), valuation=2, constant=1) - z^2 + z^3 + z^4 + O(z^5) - - This raises an error:: - - sage: L(lambda n: 0, valuation=3, constant=1) - Traceback (most recent call last): - ... - ValueError: constant may only be specified if the degree is specified - - We support the old input format for ``constant``:: - - sage: f = L(lambda i: i, valuation=-3, constant=-1, degree=3) - sage: g = L(lambda i: i, valuation=-3, constant=(-1,3)) - sage: f == g - True - sage: g = L(lambda i: i, -3, (-1,3)) - sage: f == g - True - - .. TODO:: + This is always 1. - Add a method to change the sparse/dense implementation. - """ - if valuation is not None and valuation not in ZZ: - raise ValueError("the valuation must be an integer") + EXAMPLES:: - if x is None and coefficients is None: - if valuation is None: - raise ValueError("the valuation must be specified") - return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L.ngens() + 1 + """ + return 1 - R = self._laurent_poly_ring - BR = self.base_ring() - try: - # Try to build stuff using the polynomial ring constructor - x = R(x) - except (TypeError, ValueError): - pass - if isinstance(constant, (tuple, list)): - constant, degree = constant - if isinstance(degree, (tuple, list)): - constant, degree = degree - if constant is not None: - constant = BR(constant) + @cached_method + def gens(self): + """ + Return the generators of ``self``. - # If x has been converted to the Laurent polynomial ring - if parent(x) is R: - if not x and not constant: - return self.zero() - if x and valuation is not None: - x = x.shift(valuation - x.valuation()) - if degree is None and not x: - if valuation is None: - raise ValueError("you must specify the degree for the polynomial 0") - degree = valuation - if x == R.zero(): - coeff_stream = Stream_exact([], self._sparse, order=degree, constant=constant) - return self.element_class(self, coeff_stream) - initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] - coeff_stream = Stream_exact(initial_coefficients, self._sparse, - order=x.valuation(), constant=constant, degree=degree) - return self.element_class(self, coeff_stream) + EXAMPLES:: - if isinstance(x, LazyCauchyProductSeries): - if x._coeff_stream._is_sparse is not self._sparse: - # TODO: Implement a way to make a self._sparse copy - raise NotImplementedError("cannot convert between sparse and dense") + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L.gens() + (z,) + sage: 1/(1 - z) + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + """ + return tuple([self.gen(n) for n in range(self.ngens())]) - # If x is known to be 0 - if isinstance(x._coeff_stream, Stream_zero): - if not constant: - return x - if degree is None: - if valuation is None: - raise ValueError("you must specify the degree for the polynomial 0") - degree = valuation - coeff_stream = Stream_exact([], self._sparse, order=degree, - constant=constant) - return self.element_class(self, coeff_stream) + def _coerce_map_from_(self, S): + """ + Return ``True`` if a coercion from ``S`` exists. - # Make the result exact - if degree is not None: - # truncate the series and then possibly make constant - x_val = x.valuation() - if not valuation: - valuation = x_val - initial_coefficients = [x[x_val+i] for i in range(degree-valuation)] - if not any(initial_coefficients): - if not constant: - return self.zero() - # We learned some stuff about x; pass it along - x._coeff_stream._approximate_order += len(initial_coefficients) - initial_coefficients = [] - coeff_stream = Stream_exact(initial_coefficients, self._sparse, - order=valuation, constant=constant, degree=degree) - return self.element_class(self, coeff_stream) + EXAMPLES:: - # We are just possibly shifting the result - ret = self.element_class(self, x._coeff_stream) - if valuation is None: - return ret - return x.shift(valuation - ret.valuation()) + sage: L = LazyLaurentSeriesRing(GF(2), 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(GF(2)) + True + """ + if self.base_ring().has_coerce_map_from(S): + return True - if x is None and coefficients is not None: - x = coefficients + R = self._laurent_poly_ring + return R.has_coerce_map_from(S) - if callable(x): - if valuation is None: - raise ValueError("the valuation must be specified") - if degree is None: - if constant is not None: - raise ValueError("constant may only be specified if the degree is specified") - coeff_stream = Stream_function(x, self.base_ring(), self._sparse, valuation) - return self.element_class(self, coeff_stream) + def _coerce_map_from_base_ring(self): + """ + Return a coercion map from the base ring of ``self``. - # degree is not None - if constant is None: - constant = BR.zero() - p = [BR(x(i)) for i in range(valuation, degree)] - if not any(p) and not constant: - return self.zero() - coeff_stream = Stream_exact(p, self._sparse, order=valuation, - constant=constant, degree=degree) - return self.element_class(self, coeff_stream) + EXAMPLES:: - raise ValueError(f"unable to convert {x} into a lazy Laurent series") + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: phi = L._coerce_map_from_base_ring() + sage: phi(2) + 2 + sage: phi(2, valuation=-2) + 2*z^-2 + sage: phi(2, valuation=-2, constant=3, degree=1) + 2*z^-2 + 3*z + 3*z^2 + 3*z^3 + O(z^4) + """ + # Return a DefaultConvertMap_unique; this can pass additional + # arguments to _element_constructor_, unlike the map returned + # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. + return self._generic_coerce_map(self.base_ring()) def _an_element_(self): """ @@ -688,7 +783,7 @@ def _an_element_(self): """ R = self.base_ring() coeff_stream = Stream_exact([R.an_element(), 3, 0, 2*R.an_element(), 1], - self._sparse, order=-2, constant=R.one()) + self._sparse, order=-2, constant=R.one()) return self.element_class(self, coeff_stream) def some_elements(self): @@ -789,7 +884,7 @@ class options(GlobalOptions): 7 """ NAME = 'LazyLaurentSeriesRing' - module = 'sage.rings.lazy_laurent_series_ring' + module = 'sage.rings.lazy_series_ring' display_length = dict(default=7, description='the number of coefficients to display from the valuation', checker=lambda x: x in ZZ and x > 0) @@ -873,7 +968,7 @@ def series(self, coefficient, valuation, degree=None, constant=None): if degree is None: degree = valuation + len(coefficient) coeff_stream = Stream_exact(coefficient, self._sparse, order=valuation, - constant=constant, degree=degree) + constant=constant, degree=degree) return self.element_class(self, coeff_stream) if degree is not None and valuation > degree and constant: @@ -884,3 +979,295 @@ def series(self, coefficient, valuation, degree=None, constant=None): constant=constant, degree=degree) return t + def _monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L._monomial(1, 3) + z^3 + sage: L._monomial(2, -4) + 2*z^-4 + """ + return self._laurent_poly_ring(c).shift(n) + +class LazyDirichletSeriesRing(LazySeriesRing): + """ + Lazy Dirichlet series ring. + + INPUT: + + - ``base_ring`` -- base ring of this Dirichlet series ring + - ``names`` -- name of the generator of this Dirichlet series ring + - ``sparse`` -- (default: ``True``) whether this series is sparse or not + + EXAMPLES:: + + sage: LazyDirichletSeriesRing(ZZ, 't') + Lazy Dirichlet Series Ring in t over Integer Ring + """ + Element = LazyDirichletSeries + + def __init__(self, base_ring, names, sparse=True, category=None): + """ + Initialize the ring. + + TESTS:: + + sage: L = LazyDirichletSeriesRing(ZZ, 't') + sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) + """ + if base_ring.characteristic() > 0: + raise ValueError("positive characteristic not allowed for Dirichlet series") + + self._sparse = sparse + self._coeff_ring = base_ring + # TODO: it would be good to have something better than the symbolic ring + self._laurent_poly_ring = SR + self._internal_poly_ring = PolynomialRing(base_ring, names, sparse=True) + + category = Algebras(base_ring.category()) + if base_ring in IntegralDomains(): + category &= IntegralDomains() + elif base_ring in Rings().Commutative(): + category = category.Commutative() + category = category.Infinite() + Parent.__init__(self, base=base_ring, names=names, + category=category) + + def _repr_(self): + """ + String representation of this Dirichlet series ring. + + EXAMPLES:: + + sage: LazyDirichletSeriesRing(QQbar, 'z') + Lazy Dirichlet Series Ring in z over Algebraic Field + """ + return "Lazy Dirichlet Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) + + def characteristic(self): + """ + Return the characteristic of this lazy power series ring, which + is the same as the characteristic of its base ring. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, "s") + sage: L.characteristic() + 0 + """ + return self.base_ring().characteristic() + + def _coerce_map_from_(self, S): + """ + Return ``True`` if a coercion from ``S`` exists. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(QQ) + False + """ + if self.base_ring().has_coerce_map_from(S): + return True + + return False + + def _coerce_map_from_base_ring(self): + r""" + Return a coercion map from the base ring of ``self``. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(QQ, 'z') + sage: phi = L._coerce_map_from_base_ring() + sage: phi(2) + 2 + sage: phi(2, valuation=2) + 2/2^z + sage: phi(2, valuation=2, constant=4) + 2/2^z + 4/3^z + 4/4^z + 4/5^z + O(1/(6^z)) + """ + # Return a DefaultConvertMap_unique; this can pass additional + # arguments to _element_constructor_, unlike the map returned + # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. + return self._generic_coerce_map(self.base_ring()) + + def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, coefficients=None): + r""" + Construct a Dirichlet series from ``x``. + + INPUT: + + - ``x`` -- data used to the define a Dirichlet series + - ``valuation`` -- integer (optional); integer; a lower bound for + the exp of the valuation of the series + - ``degree`` -- (optional) the degree when the series is ``constant`` + - ``constant`` -- (optional) the eventual constant of the series + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L(3) + 3 + sage: L(lambda i: i, constant=1, degree=6) + 1 + 2/2^z + 3/3^z + 4/4^z + 5/5^z + 1/(6^z) + 1/(7^z) + 1/(8^z) + O(1/(9^z)) + + sage: X = L(constant=5, degree=3); X + 5/3^z + 5/4^z + 5/5^z + O(1/(6^z)) + sage: X.valuation() + log(3) + sage: e = L(moebius); e + 1 - 1/(2^z) - 1/(3^z) - 1/(5^z) + 1/(6^z) - 1/(7^z) + O(1/(8^z)) + + sage: L([0], constant=1) + 1/(2^z) + 1/(3^z) + 1/(4^z) + O(1/(5^z)) + + sage: L(constant=1) + 1 + 1/(2^z) + 1/(3^z) + O(1/(4^z)) + + sage: L(lambda i: i, valuation=3) + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + 8/8^z + 9/9^z + O(1/(10^z)) + + Alternatively, ``x`` can be a list of elements of the base ring. + Then these elements are read as coefficients of the terms of + degrees starting from the ``valuation``. In this case, ``constant`` + may be just an element of the base ring instead of a tuple or can be + simply omitted if it is zero:: + + sage: f = L([1,2,3,4], 4); f + 1/(4^z) + 2/5^z + 3/6^z + 4/7^z + sage: g = L([1,3,5,7,9], 6, constant=-1); g + 1/(6^z) + 3/7^z + 5/8^z + 7/9^z + 9/10^z - 1/(11^z) - 1/(12^z) - 1/(13^z) + O(1/(14^z)) + + TESTS:: + + sage: L = LazyDirichletSeriesRing(GF(2), 'z') + Traceback (most recent call last): + ... + ValueError: positive characteristic not allowed for Dirichlet series + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: D = LazyDirichletSeriesRing(QQ, 't') + sage: D(L.one()) + 1 + 1/(2^t) + 1/(3^t) + 1/(4^t) + 1/(5^t) + 1/(6^t) + 1/(7^t) + O(1/(8^t)) + + sage: R. = LaurentPolynomialRing(QQ) + sage: D = LazyDirichletSeriesRing(QQ, 't') + sage: D(coefficients=z+z^2) + 2 + 6/2^t + 12/3^t + 20/4^t + 30/5^t + 42/6^t + 56/7^t + O(1/(8^t)) + + sage: s = D(lambda n: n) + sage: D(s, valuation=2) + 1/(2^t) + 2/3^t + 3/4^t + 4/5^t + 5/6^t + 6/7^t + 7/8^t + O(1/(9^t)) + + sage: Ds = LazyDirichletSeriesRing(ZZ, 's') + sage: m = Ds(moebius, valuation=2); m + -1/(2^s) - 1/(3^s) - 1/(5^s) + 1/(6^s) - 1/(7^s) + O(1/(9^s)) + sage: D = LazyDirichletSeriesRing(QQ, 't') + sage: D(m) + -1/(2^t) - 1/(3^t) - 1/(5^t) + 1/(6^t) - 1/(7^t) + O(1/(9^t)) + + .. TODO:: + + Add a method to make a copy of ``self._sparse``. + """ + if isinstance(x, (list, tuple)): + p = self._internal_poly_ring(x) + if valuation is None: + if not p: + valuation = 1 + len(x) + x = p + else: + x = p.shift(1) + else: + if coefficients is not None: + if valuation is None: + valuation = 1 + return super()._element_constructor_(x, valuation, degree, constant, coefficients) + + BR = self.base_ring() + if x in BR: + if valuation is None: + valuation = 1 + x = BR(x) + + elif not isinstance(x, LazyDirichletSeries): + if valuation is None: + valuation = 1 + + if isinstance(x, LazyModuleElement) or callable(x): + if coefficients is not None: + raise ValueError("coefficients must be None if x is provided") + coefficients = x + x = None + + if valuation is not None and (valuation not in ZZ or valuation <= 0): + raise ValueError("the valuation must be a positive integer") + + return super()._element_constructor_(x, valuation, degree, constant, coefficients) + + def _an_element_(self): + """ + Return a Dirichlet series in this ring. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.an_element() + 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)) + """ + c = self.base_ring().an_element() + return self.element_class(self, Stream_exact([], self._sparse, constant=c, order=4)) + + @cached_method + def one(self): + """ + Return the constant series `1`. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.one() + 1 + sage: ~L.one() + 1 + O(1/(8^z)) + """ + R = self.base_ring() + return self.element_class(self, Stream_exact([R.one()], self._sparse, order=1)) + + @cached_method + def zero(self): + """ + Return the zero series. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.zero() + 0 + """ + return self.element_class(self, Stream_zero(self._sparse)) + + def _monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L._monomial(5, 3) + 5/3^z + """ + try: + L = self._laurent_poly_ring + return L(c) * L(n) ** -L(self.variable_name()) + except (ValueError, TypeError): + return '({})/{}^{}'.format(self.base_ring()(c), n, self.variable_name()) + + options = LazyLaurentSeriesRing.options diff --git a/src/sage/rings/number_field/S_unit_solver.py b/src/sage/rings/number_field/S_unit_solver.py index f8e733dd7dc..f3ec1bd7148 100644 --- a/src/sage/rings/number_field/S_unit_solver.py +++ b/src/sage/rings/number_field/S_unit_solver.py @@ -68,7 +68,7 @@ from sage.rings.finite_rings.integer_mod import mod from sage.rings.padics.factory import Qp from sage.combinat.combination import Combinations -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import factorial from sage.matrix.constructor import matrix, identity_matrix, vector, block_matrix, zero_matrix from sage.modules.free_module_element import zero_vector diff --git a/src/sage/rings/number_field/class_group.py b/src/sage/rings/number_field/class_group.py index d0468a3c2d2..34e801aad2a 100644 --- a/src/sage/rings/number_field/class_group.py +++ b/src/sage/rings/number_field/class_group.py @@ -44,7 +44,7 @@ from sage.groups.abelian_gps.values import AbelianGroupWithValues_class, AbelianGroupWithValuesElement from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement from sage.structure.element import MonoidElement -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class FractionalIdealClass(AbelianGroupWithValuesElement): diff --git a/src/sage/rings/number_field/morphism.py b/src/sage/rings/number_field/morphism.py index c6e2b0bd425..174252dad61 100644 --- a/src/sage/rings/number_field/morphism.py +++ b/src/sage/rings/number_field/morphism.py @@ -130,7 +130,7 @@ def preimage(self, y): V,VtoK,KtoV = self.domain().absolute_vector_space() # construct the transformation matrix from K to L by making the columns be the image of the basis of V_K in V_L using the homomorphism from sage.matrix.constructor import matrix - from sage.rings.all import QQ + from sage.rings.rational_field import QQ M = matrix(QQ, [LtoV(self(VtoK(e))) for e in V.basis()]).transpose() self._transformation_data = (M,LtoV,VtoK) diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 67d8274d4c6..d4321a28027 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -1990,7 +1990,7 @@ cdef class NumberFieldElement(FieldElement): raise ArithmeticError("non-principal ideal in factorization") element_fac = [(P.gens_reduced()[0],e) for P,e in fac] # Compute the product of the p^e to figure out the unit - from sage.misc.all import prod + from sage.misc.misc_c import prod element_product = prod([p**e for p,e in element_fac], K(1)) from sage.structure.all import Factorization return Factorization(element_fac, unit=self/element_product) diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 39d0b8eee5e..8a27624e577 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -47,7 +47,7 @@ from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.rings.ideal import Ideal_generic -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.mrange import xmrange_iter from sage.misc.cachefunc import cached_method from sage.structure.element import MultiplicativeGroupElement diff --git a/src/sage/rings/number_field/selmer_group.py b/src/sage/rings/number_field/selmer_group.py index 0e296497051..77facaaf86a 100644 --- a/src/sage/rings/number_field/selmer_group.py +++ b/src/sage/rings/number_field/selmer_group.py @@ -346,11 +346,11 @@ class is a ``p``'th power; k = M.left_kernel() bas = [prod([P ** bj.lift() for P, bj in zip(S, b.list())], C.number_field().ideal(1)) for b in k.basis()] - f = lambda v: k.coordinate_vector(v) - return bas, f + return bas, k.coordinate_vector # The main function + def pSelmerGroup(K, S, p, proof=None, debug=False): r""" Return the ``p``-Selmer group `K(S,p)` of the number field ``K`` diff --git a/src/sage/rings/number_field/small_primes_of_degree_one.py b/src/sage/rings/number_field/small_primes_of_degree_one.py index 235cdd63549..93cb7d97f70 100644 --- a/src/sage/rings/number_field/small_primes_of_degree_one.py +++ b/src/sage/rings/number_field/small_primes_of_degree_one.py @@ -99,7 +99,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ class Small_primes_of_degree_one_iter(): r""" diff --git a/src/sage/rings/number_field/unit_group.py b/src/sage/rings/number_field/unit_group.py index f3a940f80c5..d8f9b7a9c2f 100644 --- a/src/sage/rings/number_field/unit_group.py +++ b/src/sage/rings/number_field/unit_group.py @@ -163,7 +163,7 @@ from sage.groups.abelian_gps.values import AbelianGroupWithValues_class from sage.structure.proof.proof import get_flag from sage.libs.pari.all import pari -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx index 225c52efa83..2055d4d46c2 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx @@ -1972,7 +1972,7 @@ cdef class pAdicZZpXCAElement(pAdicZZpXElement): [1590 1375 1695 1032 2358] [2415 590 2370 2970 1032] """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix # this may be the wrong precision when ram_prec_cap is not divisible by e. R = IntegerModRing(self.prime_pow.pow_Integer(self.prime_pow.capdiv(self.absprec))) n = self.prime_pow.deg diff --git a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx index db39fab2b60..8d44034b121 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx @@ -2859,7 +2859,7 @@ cdef class pAdicZZpXCRElement(pAdicZZpXElement): if self.valuation_c() < 0: raise ValueError("self must be integral") n = self.prime_pow.deg - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix if self._is_exact_zero(): from sage.rings.integer_ring import IntegerRing return matrix(IntegerRing(), n, n) diff --git a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx index 9c0bcff4f69..c58954582ea 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_FM_element.pyx @@ -1032,7 +1032,7 @@ cdef class pAdicZZpXFMElement(pAdicZZpXElement): [1590 1375 1695 1032 2358] [2415 590 2370 2970 1032] """ - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix R = IntegerModRing(self.prime_pow.pow_Integer(self.prime_pow.prec_cap)) n = self.prime_pow.deg L = [] diff --git a/src/sage/rings/padics/padic_valuation.py b/src/sage/rings/padics/padic_valuation.py index f47f1d8de5b..30689e3d0d0 100644 --- a/src/sage/rings/padics/padic_valuation.py +++ b/src/sage/rings/padics/padic_valuation.py @@ -148,7 +148,7 @@ def create_key_for_integers(self, R, prime): 2-adic valuation """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ if prime is None: raise ValueError("prime must be specified for this ring") from sage.rings.valuation.valuation import DiscretePseudoValuation @@ -462,7 +462,7 @@ def __init__(self, parent, p): """ DiscreteValuation.__init__(self, parent) - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ self._p = ZZ(p) def p(self): @@ -1248,7 +1248,7 @@ def simplify(self, x, error=None, force=False, size_heuristic_bound=32): if error < v: return self.domain().zero() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.rings.all import Qp precision_ring = Qp(self.p(), QQ(error).floor() + 1 - v) reduced = precision_ring(x) diff --git a/src/sage/rings/padics/pow_computer_flint.pyx b/src/sage/rings/padics/pow_computer_flint.pyx index 3868c11a6f7..4d64096e4ee 100644 --- a/src/sage/rings/padics/pow_computer_flint.pyx +++ b/src/sage/rings/padics/pow_computer_flint.pyx @@ -17,7 +17,7 @@ from sage.libs.flint.fmpz cimport fmpz_init, fmpz_one, fmpz_mul, fmpz_set, fmpz_ from cpython.object cimport Py_EQ, Py_NE from sage.structure.richcmp cimport richcmp_not_equal from sage.rings.integer cimport Integer -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint diff --git a/src/sage/rings/padics/pow_computer_relative.pyx b/src/sage/rings/padics/pow_computer_relative.pyx index d80419863bb..f28a46f03b7 100644 --- a/src/sage/rings/padics/pow_computer_relative.pyx +++ b/src/sage/rings/padics/pow_computer_relative.pyx @@ -36,7 +36,7 @@ from sage.libs.gmp.mpz cimport mpz_init, mpz_clear, mpz_pow_ui from cpython.object cimport Py_EQ, Py_NE from sage.structure.richcmp cimport richcmp_not_equal from sage.rings.integer cimport Integer -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method cdef class PowComputer_relative(PowComputer_class): diff --git a/src/sage/rings/padics/qadic_flint_CR.pyx b/src/sage/rings/padics/qadic_flint_CR.pyx index 2568578a780..eaedb7a6c12 100644 --- a/src/sage/rings/padics/qadic_flint_CR.pyx +++ b/src/sage/rings/padics/qadic_flint_CR.pyx @@ -64,7 +64,7 @@ cdef class qAdicCappedRelativeElement(CRElement): if self.ordp < 0: raise ValueError("self must be integral") if exactzero(self.ordp): - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix return matrix(ZZ, self.prime_pow.deg, self.prime_pow.deg) else: return cmatrix_mod_pn(self.unit, self.ordp + self.relprec, self.ordp, self.prime_pow) diff --git a/src/sage/rings/padics/qadic_flint_FP.pyx b/src/sage/rings/padics/qadic_flint_FP.pyx index 2b6730c7770..949e132199c 100644 --- a/src/sage/rings/padics/qadic_flint_FP.pyx +++ b/src/sage/rings/padics/qadic_flint_FP.pyx @@ -66,7 +66,7 @@ cdef class qAdicFloatingPointElement(FPElement): if self.ordp < 0: raise ValueError("self must be integral") if very_pos_val(self.ordp): - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix return matrix(ZZ, self.prime_pow.deg, self.prime_pow.deg) else: return cmatrix_mod_pn(self.unit, self.ordp + self.prime_pow.prec_cap, self.ordp, self.prime_pow) diff --git a/src/sage/rings/padics/relaxed_template.pxi b/src/sage/rings/padics/relaxed_template.pxi index 48a0468bc91..6c155e1c8a3 100644 --- a/src/sage/rings/padics/relaxed_template.pxi +++ b/src/sage/rings/padics/relaxed_template.pxi @@ -43,7 +43,7 @@ from sage.structure.element cimport have_same_parent from sage.structure.coerce cimport coercion_model from sage.misc.prandom import randint -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer from sage.rings.infinity import Infinity diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 8106cf5f7a5..e4b64c26a68 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -15,7 +15,7 @@ from sage.rings.integer_ring import ZZ from sage.structure.coerce cimport coercion_model from sage.misc.derivative import multi_derivative -from sage.misc.all import prod +from sage.misc.misc_c import prod def is_MPolynomial(x): return isinstance(x, MPolynomial) @@ -254,65 +254,6 @@ cdef class MPolynomial(CommutativeRingElement): d = self.dict() return R(dict([(k, c) for k, c in d.iteritems() if k[ind] < n])) - def _fast_float_(self, *vars): - """ - Returns a quickly-evaluating function on floats. - - EXAMPLES:: - - sage: K. = QQ[] - sage: f = (x+2*y+3*z^2)^2 + 42 - sage: f(1, 10, 100) - 901260483 - sage: ff = f._fast_float_() - sage: ff(0, 0, 1) - 51.0 - sage: ff(0, 1, 0) - 46.0 - sage: ff(1, 10, 100) - 901260483.0 - sage: ff_swapped = f._fast_float_('z', 'y', 'x') - sage: ff_swapped(100, 10, 1) - 901260483.0 - sage: ff_extra = f._fast_float_('x', 'A', 'y', 'B', 'z', 'C') - sage: ff_extra(1, 7, 10, 13, 100, 19) - 901260483.0 - - Currently, we use a fairly unoptimized method that evaluates one - monomial at a time, with no sharing of repeated computations and - with useless additions of 0 and multiplications by 1:: - - sage: g = (x*y**2*z)._fast_float_() - sage: list(g) - ['push 0.0', 'push 1.0', 'load 0', 'load 1', 'dup', 'mul', - 'mul', 'load 2', 'mul', 'mul', 'add'] - - TESTS:: - - sage: from sage.ext.fast_eval import fast_float - sage: list(fast_float(K(0), old=True)) - ['push 0.0'] - sage: list(fast_float(K(17), old=True)) - ['push 0.0', 'push 17.0', 'add'] - sage: list(fast_float(y, old=True)) - ['push 0.0', 'push 1.0', 'load 1', 'mul', 'add'] - """ - from sage.ext.fast_eval import fast_float_arg, fast_float_constant - my_vars = self.parent().variable_names() - vars = list(vars) - if len(vars) == 0: - indices = list(xrange(len(my_vars))) - else: - indices = [vars.index(v) for v in my_vars] - x = [fast_float_arg(i) for i in indices] - - n = len(x) - expr = fast_float_constant(0) - for m, c in self.dict().iteritems(): - monom = prod([ x[i]**m[i] for i in range(n) if m[i] != 0], fast_float_constant(c)) - expr = expr + monom - return expr - def _fast_callable_(self, etb): """ Given an ExpressionTreeBuilder, return an Expression representing diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 472a9ea4322..cbade28354c 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -54,7 +54,7 @@ #***************************************************************************** from sage.structure.element import CommutativeRingElement, coerce_binop -from sage.misc.all import prod +from sage.misc.misc_c import prod import sage.rings.integer from sage.rings.qqbar_decorators import handle_AA_and_QQbar from . import polydict diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 65e5e7ee7a1..560dcc8c25d 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -4737,7 +4737,7 @@ def degree_of_semi_regularity(self): if m <= n: raise ValueError("This function requires an overdefined system of polynomials.") - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.misc.misc_c import prod from sage.rings.power_series_ring import PowerSeriesRing diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 1e948372613..e89c6450f2f 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -842,66 +842,6 @@ cdef class Polynomial(CommutativeAlgebraElement): # For testing return self._compiled - def _fast_float_(self, *vars): - """ - Return a quickly-evaluating function on floats. - - EXAMPLES:: - - sage: R. = QQ[] - sage: f = t^3-t - sage: ff = f._fast_float_() - sage: ff(10) - 990.0 - - Horner's method is used:: - - sage: f = (t+10)^3; f - t^3 + 30*t^2 + 300*t + 1000 - sage: list(f._fast_float_()) - ['load 0', 'push 30.0', 'add', 'load 0', 'mul', 'push 300.0', 'add', 'load 0', 'mul', 'push 1000.0', 'add'] - - TESTS:: - - sage: f = t + 2 - t - sage: ff = f._fast_float_() - sage: ff(3) - 2.0 - sage: list(f._fast_float_()) - ['push 2.0'] - - sage: f = t - t - sage: ff = f._fast_float_() - sage: ff(3) - 0.0 - sage: list(f._fast_float_()) - ['push 0.0'] - """ - from sage.ext.fast_eval import fast_float_arg, fast_float_constant - var = self._parent._names[0] - if not vars: - x = fast_float_arg(0) - elif var in vars: - x = fast_float_arg(list(vars).index(var)) - else: - raise ValueError("free variable: %s" % var) - cdef int i, d = self.degree() - expr = x - if d == -1: - return fast_float_constant(0) - coeff = self.get_unsafe(d) - if d == 0: - return fast_float_constant(coeff) - if coeff != 1: - expr *= fast_float_constant(coeff) - for i from d > i >= 0: - coeff = self.get_unsafe(i) - if coeff: - expr += fast_float_constant(coeff) - if i > 0: - expr *= x - return expr - def _fast_callable_(self, etb): r""" Given an ExpressionTreeBuilder, return an Expression representing diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx index 7ae80a01254..bb7fd4275cd 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -27,7 +27,7 @@ AUTHOR:: from sage.structure.element cimport parent from sage.rings.ring cimport Ring -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer from sage.matrix.matrix_space import MatrixSpace from sage.matrix.matrix2 import NotFullRankError diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index a63315f93b1..e75d09d58f0 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -7698,7 +7698,7 @@ def simplify(self, n): # for instance, the .exactify() call will try to factor poly, # even though we know that poly is irreducible poly = self.minpoly() - intv = isolating_interval(lambda prec: n._interval_fast(prec), poly) + intv = isolating_interval(n._interval_fast, poly) new_v = QQbar.polynomial_root(poly, intv) new_v.exactify() return new_v._descr diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 9152cc88585..2be63156923 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -3168,7 +3168,7 @@ cdef class Rational(sage.structure.element.FieldElement): raise ValueError("log base must be positive") self_sgn = mpz_sgn(mpq_numref(self.value)) if self_sgn < 0 and prec is None: - from sage.symbolic.all import SR + from sage.symbolic.ring import SR return SR(self).log(m) if prec: if self_sgn >= 0: @@ -3252,7 +3252,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: (1/2).gamma(5) Traceback (most recent call last): ... - TypeError: gamma() takes exactly 0 positional arguments (1 given) + TypeError: ...gamma() takes exactly 0 positional arguments (1 given) """ if prec: return self.n(prec).gamma() @@ -3266,7 +3266,7 @@ cdef class Rational(sage.structure.element.FieldElement): from sage.functions.all import sqrt return sqrt(pi) * rat_part else: - from sage.symbolic.all import SR + from sage.symbolic.ring import SR return SR(self).gamma() def floor(self): diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 295f126caf9..059593e3836 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -1374,7 +1374,7 @@ def selmer_group_iterator(self, S, m, proof=True): """ KSgens, ords = self.selmer_generators(S=S, m=m, proof=proof, orders=True) one = self.one() - from sage.misc.all import prod + from sage.misc.misc_c import prod from itertools import product for ev in product(*[range(o) for o in ords]): yield prod((p**e for p,e in zip(KSgens, ev)), one) diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 66a9d7bda06..72164d0ec13 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -752,8 +752,8 @@ class RealBallField(UniqueRepresentation, Field): EXAMPLES:: - sage: RBF.euler_constant() - [0.577215664901533 +/- ...e-16] + sage: RBF.euler_constant() # abs tol 1e-15 + [0.5772156649015329 +/- 9.00e-17] sage: RealBallField(128).euler_constant() [0.57721566490153286060651209008240243104 +/- ...e-39] """ @@ -896,8 +896,8 @@ class RealBallField(UniqueRepresentation, Field): TESTS:: - sage: RBF.gamma(RLF(pi)) - [2.2880377953400 +/- ...e-14] + sage: RBF.gamma(RLF(pi)) # abs tol 1e-13 + [2.28803779534003 +/- 4.12e-15] """ cdef RealBall res cdef Integer x_as_Integer @@ -1156,8 +1156,8 @@ cdef class RealBall(RingElement): sage: a = RealBallField()(RIF(1)) # indirect doctest sage: b = a.psi() - sage: b - [-0.577215664901533 +/- ...e-16] + sage: b # abs tol 1e-15 + [-0.5772156649015329 +/- 4.84e-17] sage: RIF(b) -0.577215664901533? """ @@ -1302,8 +1302,8 @@ cdef class RealBall(RingElement): [1.282427129100623 +/- ...e-16] sage: RealBall(RBF, sage.symbolic.constants.e) [2.718281828459045 +/- ...e-16] - sage: RealBall(RBF, sage.symbolic.constants.EulerGamma()) - [0.577215664901533 +/- ...e-16] + sage: RealBall(RBF, sage.symbolic.constants.EulerGamma()) # abs tol 1e-15 + [0.5772156649015329 +/- 9.00e-17] sage: RBF("1 +/- 0.001") [1.00 +/- ...e-3] sage: RBF("2.3e10000000000000000000000 +/- 0.00005e10000000000000000000000") @@ -3536,8 +3536,8 @@ cdef class RealBall(RingElement): sage: RBF(1).rising_factorial(5) 120.0000000000000 - sage: RBF(1/2).rising_factorial(1/3) - [0.63684988431797 +/- ...e-15] + sage: RBF(1/2).rising_factorial(1/3) # abs tol 1e-14 + [0.636849884317974 +/- 8.98e-16] """ cdef RealBall result = self._new() cdef RealBall my_n = self._parent.coerce(n) @@ -3552,8 +3552,8 @@ cdef class RealBall(RingElement): EXAMPLES:: - sage: RBF(1).psi() - [-0.577215664901533 +/- ...e-16] + sage: RBF(1).psi() # abs tol 1e-15 + [-0.5772156649015329 +/- 4.84e-17] """ cdef RealBall result = self._new() diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 0be5b7f5d3e..7cc9c6d3f70 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -1113,7 +1113,7 @@ cdef class Ring(ParentWithGens): for P, e in f.factor(): if P.degree() == 1: return -P[0] - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ raise ValueError("no %s root of unity in %r" % (ZZ(n).ordinal_str(), self)) def zeta_order(self): diff --git a/src/sage/rings/semirings/tropical_semiring.pyx b/src/sage/rings/semirings/tropical_semiring.pyx index ab9e785b7f0..8466b9c47b0 100644 --- a/src/sage/rings/semirings/tropical_semiring.pyx +++ b/src/sage/rings/semirings/tropical_semiring.pyx @@ -28,7 +28,7 @@ from sage.structure.richcmp cimport rich_to_bool from sage.categories.semirings import Semirings from sage.categories.map cimport Map from sage.sets.family import Family -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ import operator diff --git a/src/sage/rings/valuation/gauss_valuation.py b/src/sage/rings/valuation/gauss_valuation.py index 3730c21ba22..557edc00149 100644 --- a/src/sage/rings/valuation/gauss_valuation.py +++ b/src/sage/rings/valuation/gauss_valuation.py @@ -391,11 +391,10 @@ def lift(self, F): .. SEEALSO:: :meth:`reduce` - """ F = self.residue_ring().coerce(F) - - return F.map_coefficients(lambda c:self._base_valuation.lift(c), self._base_valuation.domain()) + return F.map_coefficients(self._base_valuation.lift, + self._base_valuation.domain()) def lift_to_key(self, F): """ @@ -491,7 +490,7 @@ def E(self): 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ.one() def F(self): @@ -508,7 +507,7 @@ def F(self): 1 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ.one() def change_domain(self, ring): @@ -690,7 +689,7 @@ def scale(self, scalar): Gauss valuation induced by 3 * 2-adic valuation """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if scalar in QQ and scalar > 0 and scalar != 1: return GaussValuation(self.domain(), self._base_valuation.scale(scalar)) return super(GaussValuation_generic, self).scale(scalar) diff --git a/src/sage/rings/valuation/inductive_valuation.py b/src/sage/rings/valuation/inductive_valuation.py index 5cafb68bfff..f4b9090f1af 100644 --- a/src/sage/rings/valuation/inductive_valuation.py +++ b/src/sage/rings/valuation/inductive_valuation.py @@ -207,9 +207,7 @@ def equivalence_reciprocal(self, f, coefficients=None, valuations=None, check=Tr # - we may lift h to arbitrary precision # - we can add anything which times e0 has positive valuation, e.g., we # may drop coefficients of positive valuation - h = h.map_coefficients(lambda c:_lift_to_maximal_precision(c)) - - return h + return h.map_coefficients(_lift_to_maximal_precision) @cached_method def mu(self): @@ -901,7 +899,7 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a verbose("Augmented %s to %s"%(self, w), level=13) assert slope is -infinity or 0 in w.newton_polygon(G).slopes(repetition=False) - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ assert (phi.degree() / self.phi().degree()) in ZZ degree_bound = multiplicities[slope] * phi.degree() assert degree_bound <= G.degree() @@ -1295,7 +1293,7 @@ def equivalence_decomposition(self, f, assume_not_equivalence_unit=False, coeffi F = list(F) if compute_unit: - from sage.misc.all import prod + from sage.misc.misc_c import prod unit *= self.lift(self.residue_ring()(prod([ psi.leading_coefficient()**e for psi,e in F ]))) # A potential speedup that we tried to implement here: @@ -1384,8 +1382,8 @@ def minimal_representative(self, f): raise ValueError("equivalence units cannot have a minimal representative") e = list(self.coefficients(f))[degree] - h = self.equivalence_reciprocal(e).map_coefficients(lambda c:_lift_to_maximal_precision(c)) - g = h*f + h = self.equivalence_reciprocal(e).map_coefficients(_lift_to_maximal_precision) + g = h * f vg = self(g) coeffs = [c if v == vg else c.parent().zero() for v,c in zip(self.valuations(g), self.coefficients(g))] diff --git a/src/sage/rings/valuation/valuation_space.py b/src/sage/rings/valuation/valuation_space.py index f64072338b5..a4ace6dbece 100644 --- a/src/sage/rings/valuation/valuation_space.py +++ b/src/sage/rings/valuation/valuation_space.py @@ -918,7 +918,7 @@ def shift(self, x, s): x^2 """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ x = self.domain().coerce(x) s = self.value_group()(s) if s == 0: diff --git a/src/sage/rings/valuation/value_group.py b/src/sage/rings/valuation/value_group.py index a3981336668..bc5d0840df1 100644 --- a/src/sage/rings/valuation/value_group.py +++ b/src/sage/rings/valuation/value_group.py @@ -531,7 +531,7 @@ def _solve_linear_program(self, target): return {0 : exp} if len(self._generators) == 2 and self._generators[0] == - self._generators[1]: - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ exp = target / self._generators[0] if exp not in ZZ: return None @@ -679,7 +679,7 @@ def some_elements(self): return for g in self._generators: yield g - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ for x in (ZZ**len(self._generators)).some_elements(): yield QQ.coerce(sum([abs(c)*g for c,g in zip(x,self._generators)])) diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index a03112b98b4..04f7f789718 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -322,13 +322,11 @@ from IPython.lib import pretty -import os # CHECK: possibly unnecessary after removing 4ti2-dependent methods from sage.calculus.functional import derivative from sage.combinat.integer_vector import integer_vectors_nk_fast_iter from sage.combinat.parking_functions import ParkingFunctions from sage.combinat.set_partition import SetPartitions from sage.combinat.vector_partition import IntegerVectorsIterator -from sage.env import SAGE_LOCAL from sage.functions.log import exp from sage.functions.other import binomial from sage.geometry.polyhedron.constructor import Polyhedron @@ -346,10 +344,7 @@ from sage.rings.all import Integer, PolynomialRing, QQ, ZZ from sage.symbolic.constants import I, pi from sage.symbolic.ring import SR - -# TODO: remove the following line once 4ti2 functions are removed -path_to_zsolve = os.path.join(SAGE_LOCAL, 'bin', 'zsolve') - +from sage.features.four_ti_2 import FourTi2Executable def _sandpile_help(cls, usage, verbose=True): @@ -589,7 +584,7 @@ def __init__(self, g, sink=None): sage: G = Sandpile({0:[]}, 0, weighted=False) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'weighted' + TypeError: ...__init__() got an unexpected keyword argument 'weighted' """ # set graph name if isinstance(g, Graph) or isinstance(g, DiGraph): @@ -5122,8 +5117,6 @@ def _set_linear_system(self): This method requires 4ti2. """ - # import os - L = self._sandpile._laplacian.transpose() n = self._sandpile.num_verts() @@ -5172,7 +5165,9 @@ def _set_linear_system(self): sign_file.write('\n') # compute try: - os.system(path_to_zsolve+' -q ' + lin_sys + ' > ' + lin_sys_log) + import os + path_to_zsolve = FourTi2Executable('zsolve').executable + os.system(path_to_zsolve + ' -q ' + lin_sys + ' > ' + lin_sys_log) # process the results zhom_file = open(lin_sys_zhom,'r') except IOError: diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 63a4f348af9..d8dae3b68a0 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -55,7 +55,7 @@ from sage.categories.homset import Hom, End from sage.categories.fields import Fields -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute diff --git a/src/sage/schemes/affine/affine_subscheme.py b/src/sage/schemes/affine/affine_subscheme.py index f6a2171bfca..d2938dc1dcb 100644 --- a/src/sage/schemes/affine/affine_subscheme.py +++ b/src/sage/schemes/affine/affine_subscheme.py @@ -22,7 +22,7 @@ from sage.categories.fields import Fields from sage.interfaces.all import singular -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme from .affine_morphism import SchemeMorphism_polynomial_affine_subscheme_field diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 9fd99a3b3fc..880b420b7b6 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -135,7 +135,7 @@ from sage.categories.homset import Hom, End, hom from sage.categories.number_fields import NumberFields -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.rings.all import degree_lowest_rational_function from sage.rings.number_field.number_field import NumberField @@ -1737,6 +1737,42 @@ def fundamental_group(self): f = self.defining_polynomial() return fundamental_group(f, projective=False) + def braid_monodromy(self): + r""" + Compute the braid monodromy of a projection of the curve. + + OUTPUT: + + A list of braids. The braids correspond to paths based in the same point; + each of this paths is the conjugated of a loop around one of the points + in the discriminant of the projection of `self`. + + NOTE: + + The projection over the `x` axis is used if there are no vertical asymptotes. + Otherwise, a linear change of variables is done to fall into the previous case. + + EXAMPLES:: + + sage: A. = AffineSpace(QQ, 2) + sage: C = A.curve((x^2-y^3)*(x+3*y-5)) + sage: C.braid_monodromy() # optional - sirocco + [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, + s1*s0*s2*s0^-1*s2*s1^-1] + + """ + from sage.schemes.curves.zariski_vankampen import braid_monodromy + F = self.base_ring() + from sage.rings.qqbar import QQbar + if QQbar.coerce_map_from(F) is None: + raise NotImplementedError("the base field must have an embedding" + " to the algebraic field") + f = self.defining_polynomial() + return braid_monodromy(f) + + def riemann_surface(self, **kwargs): r""" Return the complex Riemann surface determined by this curve diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 35eff517c38..2e4c41d961d 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -29,7 +29,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import latex +from sage.misc.latex import latex from sage.categories.finite_fields import FiniteFields from sage.categories.fields import Fields diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 0e6ba6a1e4b..8d8db455481 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -145,7 +145,7 @@ from sage.categories.homset import Hom, End from sage.interfaces.all import singular -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.all import add, sage_eval from sage.rings.all import degree_lowest_rational_function, IntegerRing @@ -1699,7 +1699,7 @@ def fundamental_group(self): f = self.affine_patch(2).defining_polynomial() if f.degree() == self.degree(): return fundamental_group(f, projective=True) - else: #in this case, the line at infinity is part of the curve, so the complement lies in the affine patch + else: # in this case, the line at infinity is part of the curve, so the complement lies in the affine patch return fundamental_group(f, projective=False) def rational_parameterization(self): diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 96d456e7c18..96a7ee5623d 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -16,10 +16,6 @@ braids over this paths gives relations between these generators. This big group presentation is simplified at the end. -.. TODO:: - - Implement the complete braid monodromy approach. - AUTHORS: - Miguel Marco (2015-09-30): Initial version @@ -46,15 +42,22 @@ from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.rings.rational_field import QQ from sage.rings.qqbar import QQbar -from sage.rings.all import CC from sage.parallel.decorate import parallel from sage.misc.flatten import flatten from sage.groups.free_group import FreeGroup from sage.misc.misc_c import prod from sage.rings.complex_mpfr import ComplexField +from sage.rings.real_mpfr import RealField from sage.rings.complex_interval_field import ComplexIntervalField from sage.combinat.permutation import Permutation -from sage.functions.generalized import sign +import itertools +from sage.geometry.voronoi_diagram import VoronoiDiagram +from sage.graphs.graph import Graph +from sage.misc.cachefunc import cached_function +from copy import copy + + +roots_interval_cache = dict() def braid_from_piecewise(strands): @@ -63,8 +66,8 @@ def braid_from_piecewise(strands): INPUT: - - ``strands`` -- a list of lists of tuples ``(t, c)``, where ``t`` - is a number between 0 and 1, and ``c`` is a complex number + - ``strands`` -- a list of lists of tuples ``(t, c1, c2)``, where ``t`` + is a number between 0 and 1, and ``c1`` and ``c2`` are rationals or algebraic reals. OUTPUT: @@ -73,34 +76,36 @@ def braid_from_piecewise(strands): EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import braid_from_piecewise # optional - sirocco - sage: paths = [[(0, I), (0.2, -1 - 0.5*I), (0.8, -1), (1, -I)], - ....: [(0, -1), (0.5, -I), (1, 1)], - ....: [(0, 1), (0.5, 1 + I), (1, I)]] + sage: paths = [[(0, 0, 1), (0.2, -1, -0.5), (0.8, -1, 0), (1, 0, -1)], + ....: [(0, -1, 0), (0.5, 0, -1), (1, 1, 0)], + ....: [(0, 1, 0), (0.5, 1, 1), (1, 0, 1)]] sage: braid_from_piecewise(paths) # optional - sirocco s0*s1 """ L = strands i = min(val[1][0] for val in L) - totalpoints = [[[a[0][1].real(), a[0][1].imag()]] for a in L] + totalpoints = [[[a[0][1], a[0][2]]] for a in L] indices = [1 for a in range(len(L))] while i < 1: for j, val in enumerate(L): if val[indices[j]][0] > i: - xaux = val[indices[j] - 1][1] - yaux = val[indices[j]][1] + xauxr = val[indices[j] - 1][1] + xauxi = val[indices[j] - 1][2] + yauxr = val[indices[j]][1] + yauxi = val[indices[j]][2] aaux = val[indices[j] - 1][0] baux = val[indices[j]][0] - interpola = xaux + (yaux - xaux) * (i - aaux) / (baux - aaux) - totalpoints[j].append([interpola.real(), interpola.imag()]) + interpolar = xauxr + (yauxr - xauxr) * (i - aaux) / (baux - aaux) + interpolai = xauxi + (yauxi - xauxi) * (i - aaux) / (baux - aaux) + totalpoints[j].append([interpolar, interpolai]) else: - totalpoints[j].append([val[indices[j]][1].real(), - val[indices[j]][1].imag()]) + totalpoints[j].append([val[indices[j]][1], + val[indices[j]][2]]) indices[j] = indices[j] + 1 i = min(val[indices[k]][0] for k, val in enumerate(L)) for j, val in enumerate(L): - totalpoints[j].append([val[-1][1].real(), val[-1][1].imag()]) - + totalpoints[j].append([val[-1][1], val[-1][2]]) braid = [] G = SymmetricGroup(len(totalpoints)) @@ -121,7 +126,7 @@ def sgn(x, y): for j in range(len(l2)): for k in range(j): if l2[j] < l2[k]: - t = (l1[j][0] - l1[k][0])/(l2[k][0] - l1[k][0] + l1[j][0] - l2[j][0]) + t = (l1[j][0] - l1[k][0])/((l2[k][0]-l2[j][0]) + (l1[j][0] - l1[k][0])) s = sgn(l1[k][1]*(1 - t) + t*l2[k][1], l1[j][1]*(1 - t) + t*l2[j][1]) cruces.append([t, k, j, s]) if cruces: @@ -163,20 +168,77 @@ def discrim(f): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import discrim # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import discrim sage: R. = QQ[] sage: f = (y^3 + x^3 - 1) * (x + y) - sage: discrim(f) # optional - sirocco + sage: discrim(f) [1, -0.500000000000000? - 0.866025403784439?*I, -0.500000000000000? + 0.866025403784439?*I] """ - x, y = f.variables() + x, y = f.parent().gens() F = f.base_ring() - poly = F[x](f.discriminant(y).resultant(f, y)).radical() + poly = F[x](f.discriminant(y)).radical() return poly.roots(QQbar, multiplicities=False) +@cached_function +def corrected_voronoi_diagram(points): + r""" + Compute a Voronoi diagram of a set of points with rational coordinates, such + that the given points are granted to lie one in each bounded region. + + INPUT: + + - ``points`` -- a list of complex numbers + + OUTPUT: + + A VoronoiDiagram constructed from rational approximations of the points, + with the guarantee that each bounded region contains exactly one of the + input points. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import corrected_voronoi_diagram + sage: points = (2, I, 0.000001, 0, 0.000001*I) + sage: V = corrected_voronoi_diagram(points) + sage: V + The Voronoi diagram of 9 points of dimension 2 in the Rational Field + sage: V.regions() + {P(-7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices and 2 rays, + P(0, -7): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices and 2 rays, + P(0, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, + P(0, 1): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, + P(0, 1/1000000): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, + P(0, 7): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 2 rays, + P(1/1000000, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, + P(2, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, + P(7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays} + + """ + prec = 53 + point_coordinates = [(p.real(), p.imag()) for p in points] + while True: + RF = RealField(prec) + apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))): p for p in point_coordinates} + added_points = 3 * max(map(abs, flatten(apprpoints))) + 1 + configuration = list(apprpoints.keys())+[(added_points, 0), + (-added_points, 0), + (0, added_points), + (0, -added_points)] + V = VoronoiDiagram(configuration) + valid = True + for r in V.regions().items(): + if not r[1].rays() and not r[1].interior_contains(apprpoints[r[0].affine()]): + prec += 53 + valid = False + break + if valid: + break + return V + + def segments(points): """ Return the bounded segments of the Voronoi diagram of the given points. @@ -192,55 +254,53 @@ def segments(points): EXAMPLES:: - sage: from sage.schemes.curves.zariski_vankampen import discrim, segments # optional - sirocco + sage: from sage.schemes.curves.zariski_vankampen import discrim, segments sage: R. = QQ[] sage: f = y^3 + x^3 - 1 - sage: disc = discrim(f) # optional - sirocco - sage: segments(disc) # optional - sirocco # abs tol 1e-15 - [(-2.84740787203333 - 2.84740787203333*I, - -2.14285714285714 + 1.11022302462516e-16*I), - (-2.84740787203333 + 2.84740787203333*I, - -2.14285714285714 + 1.11022302462516e-16*I), - (2.50000000000000 + 2.50000000000000*I, - 1.26513881334184 + 2.19128470333546*I), - (2.50000000000000 + 2.50000000000000*I, - 2.50000000000000 - 2.50000000000000*I), - (1.26513881334184 + 2.19128470333546*I, 0.000000000000000), - (0.000000000000000, 1.26513881334184 - 2.19128470333546*I), - (2.50000000000000 - 2.50000000000000*I, - 1.26513881334184 - 2.19128470333546*I), - (-2.84740787203333 + 2.84740787203333*I, - 1.26513881334184 + 2.19128470333546*I), - (-2.14285714285714 + 1.11022302462516e-16*I, 0.000000000000000), - (-2.84740787203333 - 2.84740787203333*I, - 1.26513881334184 - 2.19128470333546*I)] + sage: disc = discrim(f) + sage: sorted(segments(disc)) + [(-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + -192951821525958031/90044183378780414), + (-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-192951821525958031/90044183378780414, + 192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316), + (-192951821525958031/90044183378780414, 1/38590364305191606), + (1/38590364305191606, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (1/38590364305191606, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-5/2*I + 5/2, + -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326), + (-5/2*I + 5/2, 5/2*I + 5/2), + (5/2*I + 5/2, + 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326)] + """ - from numpy import array, vstack - from scipy.spatial import Voronoi - discpoints = array([(CC(a).real(), CC(a).imag()) for a in points]) - added_points = 3 * abs(discpoints).max() + 1.0 - configuration = vstack([discpoints, array([[added_points, 0], - [-added_points, 0], - [0, added_points], - [0, -added_points]])]) - V = Voronoi(configuration) - res = [] - for rv in V.ridge_vertices: - if -1 not in rv: - p1 = CC(list(V.vertices[rv[0]])) - p2 = CC(list(V.vertices[rv[1]])) - res.append((p1, p2)) - return res - - -def followstrand(f, x0, x1, y0a, prec=53): + V = corrected_voronoi_diagram(tuple(points)) + res = set([]) + for region in V.regions().values(): + if region.rays(): + continue + segments = region.facets() + for s in segments: + t = tuple((tuple(v.vector()) for v in s.vertices())) + if t not in res and not tuple(reversed(t)) in res: + res.add(t) + return [(r[0]+QQbar.gen()*r[1], s[0]+QQbar.gen()*s[1]) for (r, s) in res] + + +def followstrand(f, factors, x0, x1, y0a, prec=53): r""" Return a piecewise linear approximation of the homotopy continuation of the root ``y0a`` from ``x0`` to ``x1``. INPUT: - - ``f`` -- a polynomial in two variables + - ``f`` -- an irreducible polynomial in two variables + - ``factors`` -- a list of irreducible polynomials in two variables - ``x0`` -- a complex value, where the homotopy starts - ``x1`` -- a complex value, where the homotopy ends - ``y0a`` -- an approximate solution of the polynomial `F(y) = f(x_0, y)` @@ -255,7 +315,8 @@ def followstrand(f, x0, x1, y0a, prec=53): is zero (or a good enough approximation) - the piecewise linear path determined by the points has a tubular neighborhood where the actual homotopy continuation path lies, and - no other root intersects it. + no other root of ``f``, nor any root of the polynomials in ``factors``, + intersects it. EXAMPLES:: @@ -264,15 +325,31 @@ def followstrand(f, x0, x1, y0a, prec=53): sage: f = x^2 + y^3 sage: x0 = CC(1, 0) sage: x1 = CC(1, 0.5) - sage: followstrand(f, x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 + sage: followstrand(f, [], x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 [(0.0, -1.0, 0.0), (0.7500000000000001, -1.015090921153253, -0.24752813818386948), (1.0, -1.026166099551513, -0.32768940253604323)] + sage: fup = f.subs({y:y-1/10}) + sage: fdown = f.subs({y:y+1/10}) + sage: followstrand(f, [fup, fdown], x0, x1, -1.0) # optional - sirocco # abs tol 1e-15 + [(0.0, -1.0, 0.0), + (0.5303300858899107, -1.0076747107983448, -0.17588022709184917), + (0.7651655429449553, -1.015686131039112, -0.25243563967299404), + (1.0, -1.026166099551513, -0.3276894025360433)] + """ + if f.degree() == 1: + CF = ComplexField(prec) + g = f.change_ring(CF) + (x, y) = g.parent().gens() + y0 = CF[y](g.subs({x: x0})).roots()[0][0] + y1 = CF[y](g.subs({x: x1})).roots()[0][0] + res = [(0.0, y0.real(), y0.imag()), (1.0, y1.real(), y1.imag())] + return res CIF = ComplexIntervalField(prec) CC = ComplexField(prec) G = f.change_ring(QQbar).change_ring(CIF) - (x, y) = G.variables() + (x, y) = G.parent().gens() g = G.subs({x: (1 - x) * CIF(x0) + x * CIF(x1)}) coefs = [] deg = g.total_degree() @@ -285,26 +362,213 @@ def followstrand(f, x0, x1, y0a, prec=53): coefs += list(ci.endpoints()) yr = CC(y0a).real() yi = CC(y0a).imag() - from sage.libs.sirocco import contpath, contpath_mp + coefsfactors = [] + degsfactors = [] + for fc in factors: + degfc = fc.degree() + degsfactors.append(degfc) + G = fc.change_ring(QQbar).change_ring(CIF) + g = G.subs({x: (1 - x) * CIF(x0) + x * CIF(x1)}) + for d in range(degfc + 1): + for i in range(d + 1): + c = CIF(g.coefficient({x: d - i, y: i})) + cr = c.real() + ci = c.imag() + coefsfactors += list(cr.endpoints()) + coefsfactors += list(ci.endpoints()) + from sage.libs.sirocco import contpath, contpath_mp, contpath_comps, contpath_mp_comps try: if prec == 53: - points = contpath(deg, coefs, yr, yi) + if factors: + points = contpath_comps(deg, coefs, yr, yi, degsfactors, coefsfactors) + else: + points = contpath(deg, coefs, yr, yi) else: - points = contpath_mp(deg, coefs, yr, yi, prec) + if factors: + points = contpath_mp_comps(deg, coefs, yr, yi, prec, degsfactors, coefsfactors) + else: + points = contpath_mp(deg, coefs, yr, yi, prec) return points except Exception: - return followstrand(f, x0, x1, y0a, 2 * prec) + return followstrand(f, factors, x0, x1, y0a, 2 * prec) + + +def newton(f, x0, i0): + r""" + Return the interval Newton operator. + + INPUT: + + - ``f``` -- a univariate polynomial + - ``x0`` -- a number + - ``I0`` -- an interval + + OUTPUT: + + The interval `x_0-\frac{f(x_0)}{f'(I_0)}` + + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import newton + sage: R. = QQbar[] + sage: f = x^3 + x + sage: x0 = 1/10 + sage: I0 = RIF((-1/5,1/5)) + sage: n = newton(f, x0, I0) + sage: n + 0.0? + sage: n.real().endpoints() + (-0.0147727272727274, 0.00982142857142862) + sage: n.imag().endpoints() + (0.000000000000000, -0.000000000000000) + + """ + return x0 - f(x0)/f.derivative()(i0) + + +@parallel +def roots_interval(f, x0): + """ + Find disjoint intervals that isolate the roots of a polynomial for a fixed + value of the first variable. + + INPUT: + + - ``f`` -- a bivariate squarefree polynomial + - ``x0`` -- a value where the first coordinate will be fixed + + The intervals are taken as big as possible to be able to detect when two + approximate roots of `f(x_0, y)` correspond to the same exact root. + + The result is given as a dictionary, where the keys are approximations to the roots + with rational real and imaginary parts, and the values are intervals containing them. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import roots_interval + sage: R. = QQ[] + sage: f = y^3 - x^2 + sage: ri = roots_interval(f, 1) + sage: ri + {-138907099/160396102*I - 1/2: -1.? - 1.?*I, + 138907099/160396102*I - 1/2: -1.? + 1.?*I, + 1: 1.? + 0.?*I} + sage: [r.endpoints() for r in ri.values()] + [(0.566987298107781 - 0.433012701892219*I, + 1.43301270189222 + 0.433012701892219*I, + 0.566987298107781 + 0.433012701892219*I, + 1.43301270189222 - 0.433012701892219*I), + (-0.933012701892219 - 1.29903810567666*I, + -0.0669872981077806 - 0.433012701892219*I, + -0.933012701892219 - 0.433012701892219*I, + -0.0669872981077806 - 1.29903810567666*I), + (-0.933012701892219 + 0.433012701892219*I, + -0.0669872981077806 + 1.29903810567666*I, + -0.933012701892219 + 1.29903810567666*I, + -0.0669872981077806 + 0.433012701892219*I)] + + """ + x, y = f.parent().gens() + I = QQbar.gen() + fx = QQbar[y](f.subs({x: QQ(x0.real())+I*QQ(x0.imag())})) + roots = fx.roots(QQbar, multiplicities=False) + result = {} + for i in range(len(roots)): + r = roots[i] + prec = 53 + IF = ComplexIntervalField(prec) + CF = ComplexField(prec) + divisor = 4 + diam = min((CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]) / divisor + envelop = IF(diam)*IF((-1, 1), (-1, 1)) + while not newton(fx, r, r+envelop) in r+envelop: + prec += 53 + IF = ComplexIntervalField(prec) + CF = ComplexField(prec) + divisor *= 2 + diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor + envelop = IF(diam)*IF((-1, 1), (-1, 1)) + qapr = QQ(CF(r).real())+QQbar.gen()*QQ(CF(r).imag()) + if qapr not in r+envelop: + raise ValueError("Could not approximate roots with exact values") + result[qapr] = r+envelop + return result + + +def roots_interval_cached(f, x0): + r""" + Cached version of :func:`roots_interval`. + + + TESTS:: + + sage: from sage.schemes.curves.zariski_vankampen import roots_interval, roots_interval_cached, roots_interval_cache + sage: R. = QQ[] + sage: f = y^3 - x^2 + sage: (f, 1) in roots_interval_cache + False + sage: ri = roots_interval_cached(f, 1) + sage: ri + {-138907099/160396102*I - 1/2: -1.? - 1.?*I, + 138907099/160396102*I - 1/2: -1.? + 1.?*I, + 1: 1.? + 0.?*I} + sage: (f, 1) in roots_interval_cache + True + + """ + global roots_interval_cache + try: + return roots_interval_cache[(f, x0)] + except KeyError: + result = roots_interval(f, x0) + roots_interval_cache[(f, x0)] = result + return result + + +def populate_roots_interval_cache(inputs): + r""" + Call func:`roots_interval` to the inputs that have not been computed previously, + and cache them. + + INPUT: + + - ``inputs`` -- a list of tuples (f, x0) + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import populate_roots_interval_cache, roots_interval_cache + sage: R. = QQ[] + sage: f = y^5 - x^2 + sage: (f, 3) in roots_interval_cache + False + sage: populate_roots_interval_cache([(f, 3)]) + sage: (f, 3) in roots_interval_cache + True + sage: roots_interval_cache[(f, 3)] + {-1.255469441943070? - 0.9121519421827974?*I: -2.? - 1.?*I, + -1.255469441943070? + 0.9121519421827974?*I: -2.? + 1.?*I, + 0.4795466549853897? - 1.475892845355996?*I: 1.? - 2.?*I, + 0.4795466549853897? + 1.475892845355996?*I: 1.? + 2.?*I, + 14421467174121563/9293107134194871: 2.? + 0.?*I} + + """ + global roots_interval_cache + tocompute = [inp for inp in inputs if inp not in roots_interval_cache] + result = roots_interval(tocompute) + for r in result: + roots_interval_cache[r[0][0]] = r[1] @parallel -def braid_in_segment(f, x0, x1): +def braid_in_segment(g, x0, x1): """ Return the braid formed by the `y` roots of ``f`` when `x` moves from ``x0`` to ``x1``. INPUT: - - ``f`` -- a polynomial in two variables + - ``g`` -- a polynomial factorization in two variables - ``x0`` -- a complex number - ``x1`` -- a complex number @@ -319,7 +583,7 @@ def braid_in_segment(f, x0, x1): sage: f = x^2 + y^3 sage: x0 = CC(1,0) sage: x1 = CC(1, 0.5) - sage: braid_in_segment(f, x0, x1) # optional - sirocco + sage: braid_in_segment(f.factor(), x0, x1) # optional - sirocco s1 TESTS: @@ -335,45 +599,367 @@ def braid_in_segment(f, x0, x1): sage: g = f.subs({x: x + 2*y}) sage: p1 = QQbar(sqrt(-1/3)) sage: p2 = QQbar(1/2+sqrt(-1/3)/2) - sage: B = zvk.braid_in_segment(g,CC(p1),CC(p2)) # optional - sirocco - sage: B.left_normal_form() # optional - sirocco - (1, s5) + sage: B = zvk.braid_in_segment(g.factor(),CC(p1),CC(p2)) # optional - sirocco + sage: B # optional - sirocco + s5*s3^-1 + """ - CC = ComplexField(64) - (x, y) = f.variables() + (x, y) = g.value().parent().gens() I = QQbar.gen() X0 = QQ(x0.real()) + I * QQ(x0.imag()) X1 = QQ(x1.real()) + I * QQ(x1.imag()) - F0 = QQbar[y](f(X0, y)) - y0s = F0.roots(multiplicities=False) - strands = [followstrand(f, x0, x1, CC(a)) for a in y0s] - complexstrands = [[(a[0], CC(a[1], a[2])) for a in b] for b in strands] + intervals = {} + precision = {} + y0s = [] + for (f, naux) in g: + if f.variables() == (y,): + F0 = QQbar[y](f.base_ring()[y](f)) + else: + F0 = QQbar[y](f(X0, y)) + y0sf = F0.roots(multiplicities=False) + y0s += list(y0sf) + precision[f] = 53 + while True: + CIFp = ComplexIntervalField(precision[f]) + intervals[f] = [r.interval(CIFp) for r in y0sf] + if not any(a.overlaps(b) for a, b in itertools.combinations(intervals[f], 2)): + break + precision[f] *= 2 + strands = [followstrand(f[0], [p[0] for p in g if p[0] != f[0]], x0, x1, i.center(), precision[f[0]]) for f in g for i in intervals[f[0]]] + complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b] for b in strands] centralbraid = braid_from_piecewise(complexstrands) initialstrands = [] - y0aps = [c[0][1] for c in complexstrands] - used = [] - for y0ap in y0aps: - distances = [((y0ap - y0).norm(), y0) for y0 in y0s] - y0 = sorted(distances)[0][1] - if y0 in used: - raise ValueError("different roots are too close") - used.append(y0) - initialstrands.append([(0, y0), (1, y0ap)]) - initialbraid = braid_from_piecewise(initialstrands) - F1 = QQbar[y](f(X1, y)) - y1s = F1.roots(multiplicities=False) finalstrands = [] - y1aps = [c[-1][1] for c in complexstrands] - used = [] - for y1ap in y1aps: - distances = [((y1ap - y1).norm(), y1) for y1 in y1s] - y1 = sorted(distances)[0][1] - if y1 in used: - raise ValueError("different roots are too close") - used.append(y1) - finalstrands.append([(0, y1ap), (1, y1)]) - finallbraid = braid_from_piecewise(finalstrands) - return initialbraid * centralbraid * finallbraid + initialintervals = roots_interval_cached(g.value(), X0) + finalintervals = roots_interval_cached(g.value(), X1) + for cs in complexstrands: + ip = cs[0][1] + I*cs[0][2] + fp = cs[-1][1] + I*cs[-1][2] + matched = 0 + for center, interval in initialintervals.items(): + if ip in interval: + initialstrands.append([(0, center.real(), center.imag()), (1, cs[0][1], cs[0][2])]) + matched += 1 + if matched == 0: + raise ValueError("unable to match braid endpoint with root") + if matched > 1: + raise ValueError("braid endpoint mathes more than one root") + matched = 0 + for center, interval in finalintervals.items(): + if fp in interval: + finalstrands.append([(0, cs[-1][1], cs[-1][2]), (1, center.real(), center.imag())]) + matched += 1 + if matched == 0: + raise ValueError("unable to match braid endpoint with root") + if matched > 1: + raise ValueError("braid endpoint mathes more than one root") + initialbraid = braid_from_piecewise(initialstrands) + finalbraid = braid_from_piecewise(finalstrands) + + return initialbraid * centralbraid * finalbraid + + +def orient_circuit(circuit): + r""" + Reverses a circuit if it goes clockwise; otherwise leaves it unchanged. + + INPUT: + + - ``circuit`` -- a circuit in the graph of a Voronoi Diagram, given + by a list of edges + + OUTPUT: + + The same circuit if it goes counterclockwise, and its reverse otherwise + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import orient_circuit + sage: points = [(-4, 0), (4, 0), (0, 4), (0, -4), (0, 0)] + sage: V = VoronoiDiagram(points) + sage: E = Graph() + sage: for reg in V.regions().values(): + ....: if reg.rays() or reg.lines(): + ....: E = E.union(reg.vertex_graph()) + sage: E.vertices() + [A vertex at (-2, -2), + A vertex at (-2, 2), + A vertex at (2, -2), + A vertex at (2, 2)] + sage: cir = E.eulerian_circuit() + sage: cir + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + sage: orient_circuit(cir) + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + sage: cirinv = list(reversed([(c[1],c[0],c[2]) for c in cir])) + sage: cirinv + [(A vertex at (-2, -2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (-2, -2), None)] + sage: orient_circuit(cirinv) + [(A vertex at (-2, -2), A vertex at (2, -2), None), + (A vertex at (2, -2), A vertex at (2, 2), None), + (A vertex at (2, 2), A vertex at (-2, 2), None), + (A vertex at (-2, 2), A vertex at (-2, -2), None)] + + """ + prec = 53 + vectors = [v[1].vector()-v[0].vector() for v in circuit] + while True: + CIF = ComplexIntervalField(prec) + totalangle = sum((CIF(*vectors[i])/CIF(*vectors[i-1])).argument() for i in range(len(vectors))) + if totalangle < 0: + return list(reversed([(c[1], c[0]) + c[2:] for c in circuit])) + elif totalangle > 0: + return circuit + else: + prec *= 2 + + +def geometric_basis(G, E, p): + r""" + Return a geometric basis, based on a vertex. + + INPUT: + + - ``G`` -- the graph of the bounded regions of a Voronoi Diagram + + - ``E`` -- the subgraph of ``G`` formed by the edges that touch an unbounded + region + + - ``p`` -- a vertex of ``E`` + + OUTPUT: A geometric basis. It is formed by a list of sequences of paths. + Each path is a list of vertices, that form a closed path in `G`, based at + `p`, that goes to a region, surrounds it, and comes back by the same path it + came. The concatenation of all these paths is equivalent to `E`. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import geometric_basis + sage: points = [(-3,0),(3,0),(0,3),(0,-3)]+ [(0,0),(0,-1),(0,1),(1,0),(-1,0)] + sage: V = VoronoiDiagram(points) + sage: G = Graph() + sage: for reg in V.regions().values(): + ....: G = G.union(reg.vertex_graph()) + ....: + sage: E = Graph() + sage: for reg in V.regions().values(): + ....: if reg.rays() or reg.lines(): + ....: E = E.union(reg.vertex_graph()) + ....: + sage: p = E.vertices()[0] + sage: geometric_basis(G, E, p) + [[A vertex at (-2, -2), + A vertex at (2, -2), + A vertex at (2, 2), + A vertex at (1/2, 1/2), + A vertex at (1/2, -1/2), + A vertex at (2, -2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (2, -2), + A vertex at (1/2, -1/2), + A vertex at (1/2, 1/2), + A vertex at (-1/2, 1/2), + A vertex at (-1/2, -1/2), + A vertex at (1/2, -1/2), + A vertex at (2, -2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (2, -2), + A vertex at (1/2, -1/2), + A vertex at (-1/2, -1/2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (-1/2, -1/2), + A vertex at (-1/2, 1/2), + A vertex at (1/2, 1/2), + A vertex at (2, 2), + A vertex at (-2, 2), + A vertex at (-1/2, 1/2), + A vertex at (-1/2, -1/2), + A vertex at (-2, -2)], + [A vertex at (-2, -2), + A vertex at (-1/2, -1/2), + A vertex at (-1/2, 1/2), + A vertex at (-2, 2), + A vertex at (-2, -2)]] + + """ + EC = [v[0] for v in orient_circuit(E.eulerian_circuit())] + i = EC.index(p) + EC = EC[i:]+EC[:i+1] # A counterclockwise eulerian circuit on the boundary, based at p + if len(G.edges()) == len(E.edges()): + if E.is_cycle(): + return [EC] + I = Graph() + for e in G.edges(): + if not E.has_edge(e): + I.add_edge(e) # interior graph + # treat the case where I is empty + if not I.vertices(): + for v in E.vertices(): + if len(E.neighbors(v)) > 2: + I.add_vertex(v) + + for i in range(len(EC)): # q and r are the points we will cut through + + if EC[i] in I.vertices(): + q = EC[i] + connecting_path = EC[:i] + break + elif EC[-i] in I.vertices(): + q = EC[-i] + connecting_path = list(reversed(EC[-i:])) + break + distancequotients = [(E.distance(q, v)**2/I.distance(q, v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v == q] + r = max(distancequotients)[1] + cutpath = I.shortest_path(q, r) + Gcut = copy(G) + Ecut = copy(E) + Ecut.delete_vertices([q, r]) + Gcut.delete_vertices(cutpath) + # I think this cannot happen, but just in case, we check it to raise + # an error instead of giving a wrong answer + if Gcut.connected_components_number() != 2: + raise ValueError("unable to compute a correct path") + G1, G2 = Gcut.connected_components_subgraphs() + + for v in cutpath: + neighs = G.neighbors(v) + for n in neighs: + if n in G1.vertices()+cutpath: + G1.add_edge(v, n, None) + if n in G2.vertices()+cutpath: + G2.add_edge(v, n, None) + + if EC[EC.index(q)+1] in G2.vertices(): + G1, G2 = G2, G1 + + E1, E2 = Ecut.connected_components_subgraphs() + if EC[EC.index(q)+1] in E2.vertices(): + E1, E2 = E2, E1 + + for i in range(len(cutpath)-1): + E1.add_edge(cutpath[i], cutpath[i+1], None) + E2.add_edge(cutpath[i], cutpath[i+1], None) + + for v in [q, r]: + for n in E.neighbors(v): + if n in E1.vertices(): + E1.add_edge(v, n, None) + if n in E2.vertices(): + E2.add_edge(v, n, None) + + gb1 = geometric_basis(G1, E1, q) + gb2 = geometric_basis(G2, E2, q) + + resul = [connecting_path + path + list(reversed(connecting_path)) for path in gb1 + gb2] + for r in resul: + i = 0 + while i < len(r)-2: + if r[i] == r[i+2]: + r.pop(i) + r.pop(i) + if i > 0: + i -= 1 + else: + i += 1 + return resul + + +def braid_monodromy(f): + r""" + Compute the braid monodromy of a projection of the curve defined by a polynomial + + INPUT: + + - ``f`` -- a polynomial with two variables, over a number field with an embedding + in the complex numbers. + + OUTPUT: + + A list of braids. The braids correspond to paths based in the same point; + each of this paths is the conjugated of a loop around one of the points + in the discriminant of the projection of ``f``. + + .. NOTE:: + + The projection over the `x` axis is used if there are no vertical asymptotes. + Otherwise, a linear change of variables is done to fall into the previous case. + + EXAMPLES:: + + sage: from sage.schemes.curves.zariski_vankampen import braid_monodromy + sage: R. = QQ[] + sage: f = (x^2-y^3)*(x+3*y-5) + sage: braid_monodromy(f) # optional - sirocco + [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, + s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, + s1*s0*s2*s0^-1*s2*s1^-1] + + """ + global roots_interval_cache + (x, y) = f.parent().gens() + F = f.base_ring() + g = f.radical() + d = g.degree(y) + while not g.coefficient(y**d) in F: + g = g.subs({x: x + y}) + d = g.degree(y) + disc = discrim(g) + V = corrected_voronoi_diagram(tuple(disc)) + G = Graph() + for reg in V.regions().values(): + G = G.union(reg.vertex_graph()) + E = Graph() + for reg in V.regions().values(): + if reg.rays() or reg.lines(): + E = E.union(reg.vertex_graph()) + p = next(E.vertex_iterator()) + geombasis = geometric_basis(G, E, p) + segs = set([]) + for p in geombasis: + for s in zip(p[:-1], p[1:]): + if (s[1], s[0]) not in segs: + segs.add((s[0], s[1])) + I = QQbar.gen() + segs = [(a[0]+I*a[1], b[0]+I*b[1]) for (a, b) in segs] + vertices = list(set(flatten(segs))) + tocacheverts = [(g, v) for v in vertices] + populate_roots_interval_cache(tocacheverts) + gfac = g.factor() + try: + braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) + except ChildProcessError: # hack to deal with random fails first time + braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) + segsbraids = dict() + for braidcomputed in braidscomputed: + seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) + beginseg = (QQ(seg[0].real()), QQ(seg[0].imag())) + endseg = (QQ(seg[1].real()), QQ(seg[1].imag())) + b = braidcomputed[1] + segsbraids[(beginseg, endseg)] = b + segsbraids[(endseg, beginseg)] = b.inverse() + B = b.parent() + result = [] + for path in geombasis: + braidpath = B.one() + for i in range(len(path)-1): + x0 = tuple(path[i].vector()) + x1 = tuple(path[i+1].vector()) + braidpath = braidpath * segsbraids[(x0, x1)] + result.append(braidpath) + return result def fundamental_group(f, simplified=True, projective=False): @@ -394,10 +980,7 @@ def fundamental_group(f, simplified=True, projective=False): of the curve will be computed, otherwise, the fundamental group of the complement in the affine plane will be computed - If ``simplified`` is ``False``, the returned presentation has as - many generators as degree of the polynomial times the points in the - base used to create the segments that surround the discriminant. In - this case, the generators are granted to be meridians of the curve. + If ``simplified`` is ``False``, a Zariski-VanKampen presentation is returned. OUTPUT: @@ -437,35 +1020,13 @@ def fundamental_group(f, simplified=True, projective=False): sage: fundamental_group(f) # optional - sirocco Finitely presented group < x0 | > """ - (x, y) = f.variables() - F = f.base_ring() - g = f.radical() - d = g.degree(y) - while not g.coefficient(y**d) in F or (projective and g.total_degree() > d): - g = g.subs({x: x + y}) - d = g.degree(y) - disc = discrim(g) - segs = segments(disc) - vertices = list(set(flatten(segs))) - Faux = FreeGroup(d) - F = FreeGroup(d * len(vertices)) - rels = [] + bm = braid_monodromy(f) + n = bm[0].parent().strands() + F = FreeGroup(n) + R = [x*b/x for x in F.gens() for b in bm] if projective: - rels.append(prod(F.gen(i) for i in range(d))) - braidscomputed = braid_in_segment([(g, seg[0], seg[1]) for seg in segs]) - for braidcomputed in braidscomputed: - seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) - b = braidcomputed[1] - i = vertices.index(seg[0]) - j = vertices.index(seg[1]) - for k in range(d): - el1 = Faux([k + 1]) * b.inverse() - el2 = k + 1 - w1 = F([sign(a) * d * i + a for a in el1.Tietze()]) - w2 = F([d * j + el2]) - rels.append(w1 / w2) - G = F / rels + R.append(prod(F.gens())) + G = F/R if simplified: return G.simplified() - else: - return G + return G diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index 3868c0a73b7..1cc70925faf 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -17,7 +17,7 @@ Descent on elliptic curves over `\QQ` with a 2-isogeny from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring import polygen cdef object x_ZZ = polygen(ZZ) from sage.rings.polynomial.real_roots import real_roots diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 4cb6514053a..fb8dbde9be0 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -3938,7 +3938,7 @@ def split_kernel_polynomial(poly): sage: poly.factor() (x + 10) * (x + 12) * (x + 16) """ - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod([p for p,e in poly.squarefree_decomposition()]) def compute_isogeny_kernel_polynomial(E1, E2, ell, algorithm="starks"): diff --git a/src/sage/schemes/elliptic_curves/ell_egros.py b/src/sage/schemes/elliptic_curves/ell_egros.py index ab7460a8e28..09ed54aa31f 100644 --- a/src/sage/schemes/elliptic_curves/ell_egros.py +++ b/src/sage/schemes/elliptic_curves/ell_egros.py @@ -90,7 +90,7 @@ # **************************************************************************** from sage.misc.all import xmrange -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from .constructor import EllipticCurve, EllipticCurve_from_j diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index d972c4e1fc9..0013cf1938a 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -696,7 +696,7 @@ def descend_to(self, K, f=None): # j-invariant is in the image, otherwise return an empty list: j = self.j_invariant() - from sage.rings.all import QQ + from sage.rings.rational_field import QQ if K == QQ: try: jK = QQ(j) diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index ffbf9e97553..9945c5bb0c7 100644 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -1429,7 +1429,7 @@ def supersingular_j_polynomial(p, use_cache=True): if p in supersingular_j_polynomials: return J.parent()(supersingular_j_polynomials[p]) - from sage.misc.all import prod + from sage.misc.misc_c import prod m=(p-1)//2 X,T = PolynomialRing(GF(p),2,names=['X','T']).gens() H = sum(binomial(m, i) ** 2 * T ** i for i in range(m + 1)) diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 097ca89624d..576e670d0eb 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -985,7 +985,7 @@ def _scale_by_units(self): c4, c6 = self.c_invariants() c4s = [e(c4) for e in embs] c6s = [e(c6) for e in embs] - from sage.modules.all import vector + from sage.modules.free_module_element import vector v = vector([(x4.abs().nth_root(4)+x6.abs().nth_root(6)).log()*d for x4,x6,d in zip(c4s,c6s,degs)]) es = [e.round() for e in -Ainv*U*v] u = prod([uj**ej for uj,ej in zip(fu,es)]) diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index c900269c530..847a1485f8b 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -7064,7 +7064,7 @@ def elliptic_curve_congruence_graph(curves): from sage.graphs.graph import Graph from sage.arith.all import lcm from sage.rings.fast_arith import prime_range - from sage.misc.all import prod + from sage.misc.misc_c import prod G = Graph() G.add_vertices([curve.cremona_label() for curve in curves]) n = len(curves) diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 97bd761d067..fc7d07086a8 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -93,7 +93,7 @@ # **************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.misc.cachefunc import cached_method diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index 858946c5bb7..b717369aac8 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -36,7 +36,7 @@ from sage.arith.all import lcm, factorial from sage.ext.fast_callable import fast_callable from sage.functions.log import log, exp -from sage.symbolic.all import SR +from sage.symbolic.ring import SR class UnionOfIntervals: @@ -1061,7 +1061,7 @@ def ME(self): sage: E.discriminant()/E.minimal_model().discriminant() 4096 """ - from sage.misc.all import prod + from sage.misc.misc_c import prod if self.K is QQ: return prod([p ** (e - self.E.local_data(p).discriminant_valuation()) for p, e in self.E.discriminant().factor()], QQ.one()) diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 985da715a2f..cd6b328353b 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -12,6 +12,7 @@ from sage.categories.morphism import Morphism + class EllipticCurveHom(Morphism): """ Base class for elliptic-curve morphisms. @@ -67,11 +68,12 @@ def _composition_(self, other, homset): raise TypeError(f'cannot compose {type(self)} with {type(other)}') ret = self._composition_impl(self, other) - if ret is not NotImplemented: return ret + if ret is not NotImplemented: + return ret ret = other._composition_impl(self, other) - if ret is not NotImplemented: return ret + if ret is not NotImplemented: + return ret # fall back to generic formal composite map return Morphism._composition_(self, other, homset) - diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py index d5e08668737..6be7af72487 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py +++ b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py @@ -218,7 +218,7 @@ def Psi(l, use_stored=True): # Here the generic kernel polynomials are actually calculated: j = Fricke_module(l) k = j - 1728 - from sage.misc.all import prod + from sage.misc.misc_c import prod f = prod([p for p, e in j.factor() if e == 3] + [p for p, e in k.factor() if e == 2]) A4 = -3*t**2*j*k // f**2 @@ -312,7 +312,7 @@ def isogenies_prime_degree_genus_0(E, l=None, minimal_models=True): T = c4/(3*c6) jt = Fricke_module(l) kt = jt-1728 - from sage.misc.all import prod + from sage.misc.misc_c import prod psi = Psi(l) X = t f = R(prod( [p for p,e in jt.factor() if e==3] @@ -537,7 +537,7 @@ def _sporadic_Q_data(j): ....: assert g % f == 0 """ from sage.rings.all import RealField - from sage.misc.all import prod + from sage.misc.misc_c import prod ell = sporadic_j[j] E = EllipticCurve(j=j).short_weierstrass_model() a4a6 = list(E.ainvs())[3:] @@ -2201,7 +2201,7 @@ def isogenies_prime_degree_general(E, l, minimal_models=True): # divisors of degree d, then their product is a kernel poly, which # we add to the list and remove the factors used. - from sage.misc.all import prod + from sage.misc.misc_c import prod for d in list(factors_by_degree): if d * len(factors_by_degree[d]) == l2: ker.append(prod(factors_by_degree.pop(d))) diff --git a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx index e72aedf5b10..3f5aba2a992 100644 --- a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx +++ b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx @@ -173,7 +173,7 @@ from sage.rings.real_mpfr cimport RealNumber, RealField from sage.rings.rational cimport Rational from sage.rings.integer cimport Integer -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.arith.all import kronecker_symbol from sage.arith.misc import euler_phi diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 01a96c37627..8ecd30c848c 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -1183,7 +1183,7 @@ def coordinates(self, z, rounding=None): raise TypeError("%s is not a complex number"%z) prec = C.precision() from sage.matrix.all import Matrix - from sage.modules.all import vector + from sage.modules.free_module_element import vector if self.real_flag: w1,w2 = self.basis(prec) M = Matrix([[w1,0], list(w2)])**(-1) diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index f4612b287c7..14b172cacbb 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -51,7 +51,7 @@ #***************************************************************************** from sage.rings.finite_rings.all import GF -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import kronecker_symbol as kro from sage.structure.sage_object import SageObject @@ -123,7 +123,7 @@ def __init__(self, E, verbose=False): self._N = E.discriminant().norm() self._field = K = E.base_field() if K.absolute_degree() == 1: - from sage.rings.all import QQ + from sage.rings.rational_field import QQ from sage.rings.polynomial.all import polygen self._Kpol = polygen(QQ) else: @@ -463,7 +463,7 @@ def p_saturation(self, Plist, p, sieve=True): if verbose: print("Using sieve method to saturate...") - from sage.matrix.all import matrix + from sage.matrix.constructor import matrix from sage.sets.primes import Primes A = matrix(GF(p), 0, n) @@ -667,7 +667,7 @@ def p_projections(Eq, Plist, p, debug=False): print("gens for {}-primary part of G: {}".format(p, gens)) print("{}*points: {}".format(m,pts)) from sage.groups.generic import discrete_log as dlog - from sage.modules.all import vector + from sage.modules.free_module_element import vector Fp = GF(p) # If the p-primary part is cyclic we use elliptic discrete logs directly: diff --git a/src/sage/schemes/generic/divisor.py b/src/sage/schemes/generic/divisor.py index 32f8077c12b..01450320948 100644 --- a/src/sage/schemes/generic/divisor.py +++ b/src/sage/schemes/generic/divisor.py @@ -43,7 +43,7 @@ from sage.misc.latex import latex from sage.misc.repr import repr_lincomb from sage.misc.search import search -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.formal_sum import FormalSum from .morphism import is_SchemeMorphism diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index b97d2d61e5e..a1aa946614e 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -40,7 +40,7 @@ from sage.structure.factory import UniqueFactory from sage.structure.parent import Set_generic -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.ring import CommutativeRing from sage.schemes.generic.scheme import AffineScheme, is_AffineScheme diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py index 67b1e79a436..f69234cdc04 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py @@ -17,7 +17,7 @@ from sage.functions.log import log from sage.modules.free_module import VectorSpace from sage.matrix.constructor import matrix -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field diff --git a/src/sage/schemes/hyperelliptic_curves/invariants.py b/src/sage/schemes/hyperelliptic_curves/invariants.py index 4274bd90cc6..29634192e46 100644 --- a/src/sage/schemes/hyperelliptic_curves/invariants.py +++ b/src/sage/schemes/hyperelliptic_curves/invariants.py @@ -13,7 +13,7 @@ - Nick Alexander """ -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.all import PolynomialRing diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py index cc4fe5f198d..a40a69398c2 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py @@ -112,7 +112,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import latex +from sage.misc.latex import latex from sage.structure.element import AdditiveGroupElement from sage.structure.richcmp import richcmp, op_NE diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index b09c0884be8..af3f5e625d5 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -49,12 +49,12 @@ from sage.arith.all import binomial, integer_ceil as ceil from sage.functions.log import log from sage.functions.other import floor -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method from sage.misc.misc import newton_method_sizes from sage.misc.profiler import Profiler from sage.misc.repr import repr_lincomb -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.modules.free_module import FreeModule from sage.modules.free_module_element import is_FreeModuleElement from sage.modules.module import Module diff --git a/src/sage/schemes/product_projective/point.py b/src/sage/schemes/product_projective/point.py index fecf560ba3c..c773e5f976e 100644 --- a/src/sage/schemes/product_projective/point.py +++ b/src/sage/schemes/product_projective/point.py @@ -442,14 +442,14 @@ def global_height(self, prec=None): sage: PP = ProductProjectiveSpaces(QQ, [2,2], 'x') sage: Q = PP([1, 7, 5, 18, 2, 3]) sage: Q.global_height() - 1.94591014905531 + 2.89037175789616 :: sage: PP = ProductProjectiveSpaces(ZZ, [1,1], 'x') sage: A = PP([-30, 2, 1, 6]) sage: A.global_height() - 3.40119738166216 + 2.70805020110221 :: @@ -458,7 +458,7 @@ def global_height(self, prec=None): sage: PP = ProductProjectiveSpaces(k, [1, 2], 'y') sage: Q = PP([3, 5*w+1, 1, 7*w, 10]) sage: Q.global_height() - 2.30258509299405 + 2.75062910527236 :: diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index ab9fe7e3311..5239fd88203 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -58,7 +58,7 @@ from sage.schemes.generic.scheme import is_Scheme from sage.schemes.product_projective.space import is_ProductProjectiveSpaces from sage.misc.mrange import xmrange -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.arith.all import next_prime, previous_prime, crt from sage.rings.all import ZZ, RR from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index 8e0ac579eab..a7eb86ce43f 100644 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -41,7 +41,7 @@ from sage.misc.cachefunc import cached_method -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.all import (PolynomialRing, QQ, Integer, CommutativeRing) from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.categories.fields import Fields diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py index 7d00e1eb24d..1ac8018f8ab 100644 --- a/src/sage/schemes/product_projective/subscheme.py +++ b/src/sage/schemes/product_projective/subscheme.py @@ -15,7 +15,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.rings.fraction_field import FractionField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index adbffd9008e..1aa7ea7f841 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -66,7 +66,7 @@ from sage.interfaces.all import singular -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index 8e669bb5170..7da8f254e31 100644 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -41,6 +41,7 @@ from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ from sage.arith.all import gcd, lcm +from sage.misc.misc_c import prod from copy import copy from sage.schemes.generic.morphism import (SchemeMorphism, @@ -658,7 +659,7 @@ def dehomogenize(self,n): def global_height(self, prec=None): r""" - Returns the absolute logarithmic height of the point. + Return the absolute logarithmic height of the point. INPUT: @@ -705,7 +706,21 @@ def global_height(self, prec=None): sage: Q = P.point([K(4/3), K.gen(7), K.gen(5)]) sage: Q.global_height() 1.38629436111989 + + TESTS:: + + sage: P = ProjectiveSpace(QQ, 2) + sage: P(1/1,2/3,5/8).global_height() + 3.17805383034795 + + sage: x = polygen(QQ, 'x') + sage: F. = NumberField(x^3 - 5) + sage: P = ProjectiveSpace(F, 2) + sage: P(u,u^2/5,1).global_height() + 1.07295860828940 """ + if prec is None: + prec = 53 K = self.codomain().base_ring() if K in _NumberFields or is_NumberFieldOrder(K): P = self @@ -714,7 +729,21 @@ def global_height(self, prec=None): P = self._number_field_from_algebraics() except TypeError: raise TypeError("must be defined over an algebraic field") - return max([P[i].global_height(prec=prec) for i in range(self.codomain().ambient_space().dimension_relative()+1)]) + else: + K = P.codomain().base_ring() + # first get rid of the denominators + denom = lcm([xi.denominator() for xi in P]) + x = [xi * denom for xi in P] + d = K.degree() + if d == 1: + height = max(abs(xi) for xi in x) / gcd(x) + return height.log().n(prec=prec) + + finite = ~sum(K.ideal(xi) for xi in x).norm() + infinite = prod(max(abs(xi.complex_embedding(prec, i)) + for xi in x) for i in range(d)) + height = (finite * infinite)**(~d) + return height.log() def local_height(self, v, prec=None): r""" diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py index 8b91a17accf..abeeda9799b 100644 --- a/src/sage/schemes/projective/projective_subscheme.py +++ b/src/sage/schemes/projective/projective_subscheme.py @@ -28,7 +28,7 @@ from sage.matrix.constructor import matrix -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import is_RationalField diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index 576845ac1e8..c9ba1d4edf9 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -173,7 +173,7 @@ from sage.topology.simplicial_complex import SimplicialComplex from sage.matrix.constructor import matrix from sage.misc.all import cached_method, flatten, latex, prod -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.modules.free_module import (FreeModule_ambient_field, FreeModule_ambient_pid) from sage.rings.all import QQ, ZZ diff --git a/src/sage/schemes/toric/divisor_class.pyx b/src/sage/schemes/toric/divisor_class.pyx index 52874594a51..dfbd518e951 100644 --- a/src/sage/schemes/toric/divisor_class.pyx +++ b/src/sage/schemes/toric/divisor_class.pyx @@ -57,10 +57,10 @@ divisor representing a divisor class:: from sage.libs.gmp.mpq cimport * -from sage.misc.all import latex -from sage.modules.all import vector +from sage.misc.latex import latex +from sage.modules.free_module_element import vector from sage.modules.vector_rational_dense cimport Vector_rational_dense -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.rings.rational cimport Rational from sage.structure.element cimport Element, Vector from sage.structure.element import is_Vector diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py index f13482bae0c..88516ae0b5e 100644 --- a/src/sage/schemes/toric/homset.py +++ b/src/sage/schemes/toric/homset.py @@ -107,7 +107,7 @@ from sage.categories.finite_fields import FiniteFields -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.element import is_Matrix from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/schemes/toric/morphism.py b/src/sage/schemes/toric/morphism.py index 0d8ed6f20d0..7e891014a65 100644 --- a/src/sage/schemes/toric/morphism.py +++ b/src/sage/schemes/toric/morphism.py @@ -369,7 +369,7 @@ from sage.structure.richcmp import richcmp_not_equal, richcmp from sage.structure.sequence import Sequence -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.arith.all import gcd from sage.misc.all import cached_method from sage.matrix.constructor import matrix, identity_matrix diff --git a/src/sage/schemes/toric/points.py b/src/sage/schemes/toric/points.py index 2ea3067e8ab..724bf0ac40b 100644 --- a/src/sage/schemes/toric/points.py +++ b/src/sage/schemes/toric/points.py @@ -37,7 +37,7 @@ import itertools from copy import copy -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.arith.all import gcd from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -676,7 +676,7 @@ def cone_points_iter(self): [(0, 0), (0, 1)] """ from sage.matrix.constructor import matrix, block_matrix, identity_matrix - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ nrays = len(self.rays()) N = self.multiplicative_group_order() # Want cokernel of the log rescalings in (ZZ/N)^(#rays). But diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py index 1ed3ac290b4..0539f4204d3 100644 --- a/src/sage/schemes/toric/sheaf/klyachko.py +++ b/src/sage/schemes/toric/sheaf/klyachko.py @@ -47,7 +47,7 @@ from sage.structure.all import SageObject from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.misc.all import cached_method from sage.matrix.constructor import vector, block_matrix, zero_matrix from sage.geometry.cone import is_Cone @@ -947,9 +947,11 @@ def random_deformation(self, epsilon=None): sage: V = P1.sheaves.line_bundle(H) + P1.sheaves.line_bundle(-H) sage: V.cohomology(dim=True, weight=(0,)) (1, 0) - sage: Vtilde = V.random_deformation() # not tested, known bug - sage: Vtilde.cohomology(dim=True, weight=(0,)) # not tested, known bug + sage: Vtilde = V.random_deformation() + sage: Vtilde.cohomology(dim=True, weight=(0,)) (1, 0) """ filt = self._filt.random_deformation(epsilon) + while not filt.is_exhaustive(): + filt = self._filt.random_deformation(epsilon) return self.__class__(self.variety(), filt, check=True) diff --git a/src/sage/schemes/toric/toric_subscheme.py b/src/sage/schemes/toric/toric_subscheme.py index 29bf06672dc..728063064cb 100644 --- a/src/sage/schemes/toric/toric_subscheme.py +++ b/src/sage/schemes/toric/toric_subscheme.py @@ -21,7 +21,7 @@ #***************************************************************************** from sage.calculus.functions import jacobian -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme class AlgebraicScheme_subscheme_toric(AlgebraicScheme_subscheme): @@ -309,8 +309,8 @@ def affine_algebraic_patch(self, cone=None, names=None): z0*z2 - z1*z3, z1 + z3 + 1 """ - from sage.modules.all import vector - from sage.misc.all import prod + from sage.modules.free_module_element import vector + from sage.misc.misc_c import prod ambient = self.ambient_space() fan = ambient.fan() if cone is None: diff --git a/src/sage/schemes/toric/weierstrass.py b/src/sage/schemes/toric/weierstrass.py index 45ba7fe3216..e3bdd0cb311 100644 --- a/src/sage/schemes/toric/weierstrass.py +++ b/src/sage/schemes/toric/weierstrass.py @@ -137,9 +137,9 @@ # https://www.gnu.org/licenses/ ######################################################################## -from sage.misc.all import prod +from sage.misc.misc_c import prod from sage.rings.infinity import Infinity -from sage.modules.all import vector +from sage.modules.free_module_element import vector from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL from sage.rings.invariants.all import invariant_theory diff --git a/src/sage/schemes/toric/weierstrass_covering.py b/src/sage/schemes/toric/weierstrass_covering.py index 9a631813c1a..7e141ebfbd9 100644 --- a/src/sage/schemes/toric/weierstrass_covering.py +++ b/src/sage/schemes/toric/weierstrass_covering.py @@ -104,8 +104,8 @@ # https://www.gnu.org/licenses/ ######################################################################## -from sage.rings.all import ZZ -from sage.modules.all import vector +from sage.rings.integer_ring import ZZ +from sage.modules.free_module_element import vector from sage.rings.all import invariant_theory from sage.schemes.toric.weierstrass import ( _partial_discriminant, diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 4b75efb6315..0841971eb22 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -74,7 +74,7 @@ def __init__(self, sets, category, flatten=False): sage: cartesian_product([ZZ, ZZ], blub=None) Traceback (most recent call last): ... - TypeError: __init__() got an unexpected keyword argument 'blub' + TypeError: ...__init__() got an unexpected keyword argument 'blub' """ self._sets = tuple(sets) Parent.__init__(self, category=category) diff --git a/src/sage/sets/finite_enumerated_set.py b/src/sage/sets/finite_enumerated_set.py index 4066668b9ac..ec8f6e3968a 100644 --- a/src/sage/sets/finite_enumerated_set.py +++ b/src/sage/sets/finite_enumerated_set.py @@ -368,7 +368,7 @@ def __call__(self, el): sage: S(1) 1 sage: type(S(1)) - + """ if not isinstance(el, Element): return self._element_constructor_(el) diff --git a/src/sage/sets/primes.py b/src/sage/sets/primes.py index 0b8f99a3642..89cf22eef56 100644 --- a/src/sage/sets/primes.py +++ b/src/sage/sets/primes.py @@ -14,7 +14,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from .set import Set_generic from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.arith.all import nth_prime diff --git a/src/sage/sets/real_set.py b/src/sage/sets/real_set.py index 0c9d276edf2..fca8d3e179b 100644 --- a/src/sage/sets/real_set.py +++ b/src/sage/sets/real_set.py @@ -91,7 +91,7 @@ class RealSet. from sage.categories.topological_spaces import TopologicalSpaces from sage.categories.sets_cat import EmptySetError from sage.sets.set import Set_base, Set_boolean_operators, Set_add_sub_operators -from sage.rings.all import ZZ +from sage.rings.integer_ring import ZZ from sage.rings.real_lazy import LazyFieldElement, RLF from sage.rings.infinity import infinity, minus_infinity @@ -452,8 +452,10 @@ def _sympy_(self): sage: RealSet.open_closed(0, 1)[0]._sympy_() Interval.Lopen(0, 1) - sage: RealSet.point(0)[0]._sympy_() - FiniteSet(0) + sage: RealSet.point(0)[0]._sympy_() # random - this output format is sympy >= 1.9 + {0} + sage: type(_) + sage: RealSet.open(0,1)[0]._sympy_() Interval.open(0, 1) sage: RealSet.open(-oo,1)[0]._sympy_() @@ -2454,10 +2456,10 @@ def _sympy_(self): sage: RealSet()._sympy_() EmptySet - sage: RealSet.point(5)._sympy_() - FiniteSet(5) - sage: (RealSet.point(1).union(RealSet.point(2)))._sympy_() - FiniteSet(1, 2) + sage: RealSet.point(5)._sympy_() # random - this output format is sympy >= 1.9 + {5} + sage: (RealSet.point(1).union(RealSet.point(2)))._sympy_() # random + {1, 2} sage: (RealSet(1, 2).union(RealSet.closed(3, 4)))._sympy_() Union(Interval.open(1, 2), Interval(3, 4)) sage: RealSet(-oo, oo)._sympy_() diff --git a/src/sage/stats/hmm/chmm.pyx b/src/sage/stats/hmm/chmm.pyx index 0f9837745ad..741f3a3efb1 100644 --- a/src/sage/stats/hmm/chmm.pyx +++ b/src/sage/stats/hmm/chmm.pyx @@ -315,7 +315,7 @@ cdef class GaussianHiddenMarkovModel(HiddenMarkovModel): [(1.0, 0.5), (-1.0, 3.0)] """ cdef Py_ssize_t i - from sage.rings.all import RDF + from sage.rings.real_double import RDF return [(RDF(self.B[2*i]),RDF(self.B[2*i+1])) for i in range(self.N)] def __repr__(self): diff --git a/src/sage/stats/hmm/hmm.pyx b/src/sage/stats/hmm/hmm.pyx index c52e27dcec3..8e184e9e251 100644 --- a/src/sage/stats/hmm/hmm.pyx +++ b/src/sage/stats/hmm/hmm.pyx @@ -36,7 +36,7 @@ from cysignals.signals cimport sig_on, sig_off from sage.stats.time_series cimport TimeSeries from sage.structure.element import is_Matrix -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.misc.randstate cimport current_randstate, randstate from cpython.object cimport PyObject_RichCompare @@ -112,7 +112,7 @@ cdef class HiddenMarkovModel: [0.4 0.6] """ from sage.matrix.constructor import matrix - from sage.rings.all import RDF + from sage.rings.real_double import RDF return matrix(RDF, self.N, self.A.list()) def graph(self, eps=1e-3): @@ -409,7 +409,7 @@ cdef class DiscreteHiddenMarkovModel(HiddenMarkovModel): [0.5 0.5] """ from sage.matrix.constructor import matrix - from sage.rings.all import RDF + from sage.rings.real_double import RDF return matrix(RDF, self.N, self.n_out, self.B.list()) diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index d610bbb71cc..7cdddb22644 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -4223,7 +4223,7 @@ def is_InfinityElement(x): cdef class InfinityElement(RingElement): def __invert__(self): - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ return ZZ(0) diff --git a/src/sage/symbolic/constants.py b/src/sage/symbolic/constants.py index 8c2464192ac..a4b43b2a9f3 100644 --- a/src/sage/symbolic/constants.py +++ b/src/sage/symbolic/constants.py @@ -787,7 +787,7 @@ def minpoly(self, bits=None, degree=None, epsilon=0): sage: golden_ratio.minpoly() x^2 - x - 1 """ - from sage.rings.all import QQ + from sage.rings.rational_field import QQ x = QQ['x'].gen(0) return x**2 - x - 1 diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index beab2ce78ca..c589441a970 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -7639,7 +7639,7 @@ cdef class Expression(CommutativeRingElement): ... TypeError: y is not a variable of Multivariate Polynomial Ring in x over Ring of integers modulo 4 """ - from sage.symbolic.all import SR + from sage.symbolic.ring import SR from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing base_ring = R.base_ring() if base_ring == SR: @@ -8273,7 +8273,7 @@ cdef class Expression(CommutativeRingElement): sage: abs(SR(-5),hold=True) Traceback (most recent call last): ... - TypeError: abs() takes no keyword arguments + TypeError: ...abs() takes no keyword arguments But this is possible using the method :meth:`abs`:: @@ -8558,6 +8558,11 @@ cdef class Expression(CommutativeRingElement): sage: (I^m).imag_part() sin(1/2*pi*m) sage: forget() + + Check that :trac:`29400` is fixed:: + + sage: cot(1 + i).imag().n() - (1/tan(1 + i)).imag().n() # abs tol 10^-12 + 0.00000000000000 """ return new_Expression_from_GEx(self._parent, g_hold_wrapper(g_real_part, self._gobj, hold)) @@ -8694,7 +8699,7 @@ cdef class Expression(CommutativeRingElement): sage: sqrt(4,hold=True) Traceback (most recent call last): ... - TypeError: _do_sqrt() got an unexpected keyword argument 'hold' + TypeError: ..._do_sqrt() got an unexpected keyword argument 'hold' """ return new_Expression_from_GEx(self._parent, g_hold2_wrapper(g_power_construct, self._gobj, g_ex1_2, hold)) @@ -9787,7 +9792,7 @@ cdef class Expression(CommutativeRingElement): sage: x.gamma(y) Traceback (most recent call last): ... - TypeError: gamma() takes exactly 0 positional arguments (1 given) + TypeError: ...gamma() takes exactly 0 positional arguments (1 given) """ cdef GEx x sig_on() @@ -12481,7 +12486,9 @@ cdef class Expression(CommutativeRingElement): else: raise RuntimeError("no zero in the interval, since constant expression is not 0.") elif self.number_of_arguments() == 1: - f = self._fast_float_(self.default_variable()) + from sage.ext.fast_callable import fast_callable + # The domain=float is important for numpy if we encounter NaN. + f = fast_callable(self, vars=[self.default_variable()], domain=float) return find_root(f, a=a, b=b, xtol=xtol, rtol=rtol,maxiter=maxiter, full_output=full_output) @@ -12518,16 +12525,20 @@ cdef class Expression(CommutativeRingElement): INPUT: - - ``var`` - variable (default: first variable in - self) + - ``a`` - real number; left endpoint of interval on which to + minimize - - ``a,b`` - endpoints of interval on which to minimize - self. + - ``b`` - real number; right endpoint of interval on which to + minimize - - ``tol`` - the convergence tolerance + - ``var`` - variable (default: first variable in self); the + variable in self to maximize over - - ``maxfun`` - maximum function evaluations + - ``tol`` - positive real (default: 1.48e-08); the convergence + tolerance + - ``maxfun`` - natural number (default: 500); maximum function + evaluations OUTPUT: @@ -12561,33 +12572,18 @@ cdef class Expression(CommutativeRingElement): - William Stein (2007-12-07) """ from sage.numerical.optimize import find_local_minimum + from sage.ext.fast_callable import fast_callable if var is None: var = self.default_variable() - return find_local_minimum(self._fast_float_(var), - a=a, b=b, tol=tol, maxfun=maxfun ) + + # The domain=float is important for numpy if we encounter NaN. + f = fast_callable(self, vars=[var], domain=float) + return find_local_minimum(f, a=a, b=b, tol=tol, maxfun=maxfun) ################### # Fast Evaluation # ################### - def _fast_float_(self, *vars): - """ - Return an object which provides fast floating point - evaluation of this symbolic expression. - - See :mod:`sage.ext.fast_eval` for more information. - - EXAMPLES:: - - sage: f = sqrt(x+1) - sage: ff = f._fast_float_('x') - sage: ff(1.0) - 1.4142135623730951 - sage: type(_) - <... 'float'> - """ - from sage.symbolic.expression_conversions import fast_float - return fast_float(self, *vars) def _fast_callable_(self, etb): """ @@ -13620,7 +13616,7 @@ cpdef new_Expression(parent, x): raise TypeError('positive characteristic not allowed in symbolic computations') exp = x elif isinstance(x, Factorization): - from sage.misc.all import prod + from sage.misc.misc_c import prod return prod([SR(p)**e for p,e in x], SR(x.unit())) elif x in Sets(): from sage.rings.all import NN, ZZ, QQ, AA diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index f7e26daa6fc..98d2820a361 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -123,17 +123,6 @@ def _fast_callable_(self, etb): """ return fast_callable(self, etb) - def _fast_float_(self, *vars): - """ - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import FakeExpression - sage: import operator; x,y = var('x,y') - sage: f = FakeExpression([x, y], operator.truediv) - sage: fast_float(f, 'x', 'y').op_list() - [('load_arg', 0), ('load_arg', 1), 'div', 'return'] - """ - return fast_float(self, *vars) class Converter(object): def __init__(self, use_fake_div=False): @@ -1695,213 +1684,6 @@ def laurent_polynomial(ex, base_ring=None, ring=None): return converter.ring(res) -############## -# Fast Float # -############## - -class FastFloatConverter(Converter): - def __init__(self, ex, *vars): - """ - Returns an object which provides fast floating point - evaluation of the symbolic expression *ex*. This is an class - used internally and is not meant to be used directly. - - See :mod:`sage.ext.fast_eval` for more information. - - EXAMPLES:: - - sage: x,y,z = var('x,y,z') - sage: f = 1 + sin(x)/x + sqrt(z^2+y^2)/cosh(x) - sage: ff = f._fast_float_('x', 'y', 'z') - sage: f(x=1.0,y=2.0,z=3.0).n() - 4.1780638977... - sage: ff(1.0,2.0,3.0) - 4.1780638977... - - Using ``_fast_float_`` without specifying the variable names is - no longer possible:: - - sage: f = x._fast_float_() - Traceback (most recent call last): - ... - ValueError: please specify the variable names - - Using ``_fast_float_`` on a function which is the identity is - now supported (see :trac:`10246`):: - - sage: f = symbolic_expression(x).function(x) - sage: f._fast_float_(x) - - sage: f(22) - 22 - """ - self.ex = ex - - if not vars: - try: - vars = ex.arguments() - except AttributeError: - vars = ex.variables() - - if vars: - raise ValueError('please specify the variable names') - - self.vars = vars - - import sage.ext.fast_eval as fast_float - self.ff = fast_float - - Converter.__init__(self, use_fake_div=True) - - def relation(self, ex, operator): - """ - EXAMPLES:: - - sage: ff = fast_float(x == 2, 'x') - sage: ff(2) - 0.0 - sage: ff(4) - 2.0 - sage: ff = fast_float(x < 2, 'x') - Traceback (most recent call last): - ... - NotImplementedError - """ - if operator is not _operator.eq: - raise NotImplementedError - return self(ex.lhs() - ex.rhs()) - - def pyobject(self, ex, obj): - """ - EXAMPLES:: - - sage: f = SR(2)._fast_float_() - sage: f(3) - 2.0 - """ - try: - return obj._fast_float_(*self.vars) - except AttributeError: - return self.ff.fast_float_constant(float(obj)) - - def symbol(self, ex): - r""" - EXAMPLES:: - - sage: f = x._fast_float_('x', 'y') - sage: f(1,2) - 1.0 - sage: f = x._fast_float_('y', 'x') - sage: f(1,2) - 2.0 - """ - if self.vars == (): - return self.ff.fast_float_arg(0) - - vars = list(self.vars) - name = repr(ex) - if name in vars: - return self.ff.fast_float_arg(vars.index(name)) - svars = [repr(x) for x in vars] - if name in svars: - return self.ff.fast_float_arg(svars.index(name)) - - if ex.is_symbol(): # case of callable function which is the variable, like f(x)=x - name = repr(SR(ex)) # this gets back just the 'output' of the function - if name in svars: - return self.ff.fast_float_arg(svars.index(name)) - - try: - return self.ff.fast_float_constant(float(ex)) - except TypeError: - raise NotImplementedError("free variable: %s" % repr(ex)) - - def arithmetic(self, ex, operator): - """ - EXAMPLES:: - - sage: x,y = var('x,y') - sage: f = x*x-y - sage: ff = f._fast_float_('x','y') - sage: ff(2,3) - 1.0 - - sage: a = x + 2*y - sage: f = a._fast_float_('x', 'y') - sage: f(1,0) - 1.0 - sage: f(0,1) - 2.0 - - sage: f = sqrt(x)._fast_float_('x'); f.op_list() - ['load 0', 'call sqrt(1)'] - - sage: f = (1/2*x)._fast_float_('x'); f.op_list() - ['load 0', 'push 0.5', 'mul'] - """ - operands = ex.operands() - if operator is _operator.neg: - return operator(self(operands[0])) - - from sage.rings.all import Rational - if operator is _operator.pow and operands[1] == Rational(((1,2))): - from sage.functions.all import sqrt - return sqrt(self(operands[0])) - fops = map(self, operands) - if operator == add_vararg: - operator = _operator.add - elif operator == mul_vararg: - operator = _operator.mul - return reduce(operator, fops) - - def composition(self, ex, operator): - """ - EXAMPLES:: - - sage: f = sqrt(x)._fast_float_('x') - sage: f(2) - 1.41421356237309... - sage: y = var('y') - sage: f = sqrt(x+y)._fast_float_('x', 'y') - sage: f(1,1) - 1.41421356237309... - - :: - - sage: f = sqrt(x+2*y)._fast_float_('x', 'y') - sage: f(2,0) - 1.41421356237309... - sage: f(0,1) - 1.41421356237309... - """ - f = operator - g = [self(_) for _ in ex.operands()] - try: - return f(*g) - except TypeError: - from sage.functions.other import abs_symbolic - if f is abs_symbolic: - return abs(*g) # special case - else: - return self.ff.fast_float_func(f, *g) - -def fast_float(ex, *vars): - """ - Returns an object which provides fast floating point evaluation of - the symbolic expression *ex*. - - See :mod:`sage.ext.fast_eval` for more information. - - EXAMPLES:: - - sage: from sage.symbolic.expression_conversions import fast_float - sage: f = sqrt(x+1) - sage: ff = fast_float(f, 'x') - sage: ff(1.0) - 1.4142135623730951 - """ - return FastFloatConverter(ex, *vars)() - ################# # Fast Callable # ################# diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 7feef512673..d2c7d8e468f 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -153,7 +153,6 @@ from sage.structure.coerce cimport (coercion_model, from sage.structure.richcmp cimport richcmp from sage.misc.fpickle import pickle_function, unpickle_function -from sage.ext.fast_eval import FastDoubleFunc # List of functions which ginac allows us to define custom behavior for. # Changing the order of this list could cause problems unpickling old pickles. @@ -516,16 +515,6 @@ cdef class Function(SageObject): if self._nargs > 0 and len(args) != self._nargs: raise TypeError("Symbolic function %s takes exactly %s arguments (%s given)" % (self._name, self._nargs, len(args))) - # support fast_float - if self._nargs == 1: - if isinstance(args[0], FastDoubleFunc): - try: - method = getattr(args[0], self._name) - except AttributeError: - raise TypeError("cannot handle fast float arguments") - else: - return method() - # if the given input is a symbolic expression, we don't convert it back # to a numeric type at the end from .ring import SR @@ -729,47 +718,6 @@ cdef class Function(SageObject): """ return self._conversions.get('maxima', self._name) - def _fast_float_(self, *vars): - """ - Returns an object which provides fast floating point evaluation of - self. - - See sage.ext.fast_eval? for more information. - - EXAMPLES:: - - sage: sin._fast_float_() - - sage: sin._fast_float_()(0) - 0.0 - - :: - - sage: ff = cos._fast_float_(); ff - - sage: ff.is_pure_c() - True - sage: ff(0) - 1.0 - - :: - - sage: ff = erf._fast_float_() - sage: ff.is_pure_c() - False - sage: ff(1.5) # tol 1e-15 - 0.9661051464753108 - sage: erf(1.5) - 0.966105146475311 - """ - import sage.ext.fast_eval as fast_float - - args = [fast_float.fast_float_arg(n) for n in range(self.number_of_arguments())] - try: - return self(*args) - except TypeError as err: - return fast_float.fast_float_func(self, *args) - def _fast_callable_(self, etb): r""" Given an ExpressionTreeBuilder, return an Expression representing diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index 9e50acd181b..acc7d097a4e 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -14,7 +14,7 @@ from sage.misc.prandom import randint, random import operator -from sage.rings.all import QQ +from sage.rings.rational_field import QQ from sage.symbolic.ring import SR from sage.symbolic.expression import symbol_table, mixed_order from sage.symbolic.constants import (pi, e, golden_ratio, log2, euler_gamma, diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 28b1bce0301..da9dcc0a8b1 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -1571,8 +1571,8 @@ def solve_mod(eqns, modulus, solution_dict=False): from sage.rings.all import Integer, Integers, crt_basis from sage.symbolic.expression import is_Expression from sage.misc.all import cartesian_product_iterator - from sage.modules.all import vector - from sage.matrix.all import matrix + from sage.modules.free_module_element import vector + from sage.matrix.constructor import matrix if not isinstance(eqns, (list, tuple)): eqns = [eqns] @@ -1685,7 +1685,7 @@ def _solve_mod_prime_power(eqns, p, m, vars): """ from sage.rings.all import Integers, PolynomialRing - from sage.modules.all import vector + from sage.modules.free_module_element import vector from sage.misc.all import cartesian_product_iterator mrunning = 1 diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 9bc5c1db7a1..acfa342add2 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -1216,10 +1216,10 @@ cdef class NumpyToSRMorphism(Morphism): import numpy if issubclass(numpy_type, numpy.integer): - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ self._intermediate_ring = ZZ elif issubclass(numpy_type, numpy.floating): - from sage.rings.all import RDF + from sage.rings.real_double import RDF self._intermediate_ring = RDF elif issubclass(numpy_type, numpy.complexfloating): from sage.rings.all import CDF @@ -1271,6 +1271,8 @@ cdef class UnderscoreSageMorphism(Morphism): import sage.categories.homset from sage.sets.pythonclass import Set_PythonType Morphism.__init__(self, sage.categories.homset.Hom(Set_PythonType(t), R)) + from sage.interfaces.sympy import sympy_init + sympy_init() cpdef Element _call_(self, a): """ diff --git a/src/sage/symbolic/tests.py b/src/sage/symbolic/tests.py index 8cd32c4eba7..b09ae5cc4b8 100644 --- a/src/sage/symbolic/tests.py +++ b/src/sage/symbolic/tests.py @@ -29,7 +29,7 @@ def rational_powers_memleak(): sage: rational_powers_memleak() False """ - from sage.rings.all import ZZ + from sage.rings.integer_ring import ZZ import gc gc.collect() c0 = sum(1 for obj in gc.get_objects()) diff --git a/src/sage/tensor/modules/free_module_morphism.py b/src/sage/tensor/modules/free_module_morphism.py index 3451b2c0554..404a91e38d1 100644 --- a/src/sage/tensor/modules/free_module_morphism.py +++ b/src/sage/tensor/modules/free_module_morphism.py @@ -1051,7 +1051,7 @@ def matrix(self, basis1=None, basis2=None): [-1 2 0] [ 5 1 2] sage: type(phi.matrix()) - + Matrix in bases different from those in which the homomorphism has been defined:: diff --git a/src/sage/tests/benchmark.py b/src/sage/tests/benchmark.py index 0f084b1f263..3649a81f4f8 100644 --- a/src/sage/tests/benchmark.py +++ b/src/sage/tests/benchmark.py @@ -1555,7 +1555,7 @@ def sage(self): sage: isinstance(B.sage(), float) Traceback (most recent call last): ... - TypeError: anlist() got an unexpected keyword argument 'pari_ints' + TypeError: ...anlist() got an unexpected keyword argument 'pari_ints' """ E = EllipticCurve([1,2,3,4,5]) diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py index bd0d9ab10f7..518e958cad4 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py @@ -152,7 +152,7 @@ sage: mpmath.quad(f, [0, 1]) Traceback (most recent call last): ... - TypeError: no canonical coercion from to ... + TypeError: no canonical coercion from to ... Sage example in ./integration.tex, line 866:: diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py index 97ac97b81d8..1062f4f7e8c 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py @@ -374,8 +374,8 @@ Sage example in ./recequadiff.tex, line 1707:: sage: from sympy import rsolve - sage: rsolve(f, u(n), {u(0):-1,u(1):1}) - 3 - 4*2**(-n) + sage: rsolve(f, u(n), {u(0):-1,u(1):1}) == 3 - 4*2**(-n) + True Sage example in ./recequadiff.tex, line 1798:: diff --git a/src/sage/version.py b/src/sage/version.py index bf1bc3b976e..e9950f06043 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '9.5.beta2' -date = '2021-09-26' -banner = 'SageMath version 9.5.beta2, Release Date: 2021-09-26' +version = '9.5.beta3' +date = '2021-10-11' +banner = 'SageMath version 9.5.beta3, Release Date: 2021-10-11' diff --git a/src/sage_setup/library_order.py b/src/sage_setup/library_order.py index bc04af3fdd9..8830d44a955 100644 --- a/src/sage_setup/library_order.py +++ b/src/sage_setup/library_order.py @@ -10,24 +10,32 @@ # important in particular for Cygwin. Any libraries which are not # listed here will be added at the end of the list (without changing # their relative order). -from sage.env import cython_aliases -aliases = cython_aliases() +from sage.env import cython_aliases, default_required_modules, default_optional_modules -arb_dylib_name = aliases["ARB_LIBRARY"] -library_order_list = aliases["SINGULAR_LIBRARIES"] + [ +modules = default_required_modules + default_optional_modules + +aliases = cython_aliases(required_modules=(), optional_modules=modules) + +if "ARB_LIBRARY" in aliases: + arb_dylib_names = [aliases["ARB_LIBRARY"]] +else: + arb_dylib_names = [] + +library_order_list = aliases.get("SINGULAR_LIBRARIES", []) + [ "giac", "intl", "curl", "ec", "ecm" -] + aliases["LINBOX_LIBRARIES"] + aliases["FFLASFFPACK_LIBRARIES"] + aliases["GSL_LIBRARIES"] + [ +] + aliases.get("LINBOX_LIBRARIES", []) + aliases.get("FFLASFFPACK_LIBRARIES", []) + aliases.get("GSL_LIBRARIES", []) + [ "pari", "flint", "ratpoints", "ecl", "glpk", "ppl", - arb_dylib_name, "mpfi", "mpfr", "mpc", "ntl", "gmp", "gmpxx", +] + arb_dylib_names + [ + "mpfi", "mpfr", "mpc", "ntl", "gmp", "gmpxx", "brial", "brial_groebner", "m4rie", -] + aliases["M4RI_LIBRARIES"] + [ +] + aliases.get("M4RI_LIBRARIES", []) + [ "zn_poly", "gap", -] + aliases["GDLIB_LIBRARIES"] + aliases["LIBPNG_LIBRARIES"] + [ - "m", "readline", "Lfunction" , -] + aliases["CBLAS_LIBRARIES"] + aliases["ZLIB_LIBRARIES"] +] + aliases.get("GDLIB_LIBRARIES", []) + aliases.get("LIBPNG_LIBRARIES", []) + [ + "m", "readline", "Lfunction", +] + aliases.get("CBLAS_LIBRARIES", []) + aliases.get("ZLIB_LIBRARIES", []) # Make a dict with library:order pairs, where the order are negative # integers sorted according to library_order_list. When sorting, diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4 index 60ff8b757a6..655f7628882 100644 --- a/src/setup.cfg.m4 +++ b/src/setup.cfg.m4 @@ -43,6 +43,7 @@ dnl From build/pkgs/sagelib/dependencies numpy \ pkgconfig \ pplpy \ + memory_allocator \ | sed "2,\$s/^/ /;"')dnl dnl From Makefile.in: SAGERUNTIME esyscmd(`sage-get-system-packages install-requires \ diff --git a/src/tox.ini b/src/tox.ini index dc773b0973d..668483ce6a4 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -79,10 +79,13 @@ description = # E401: multiple imports on one line # E701: multiple statements on one line (colon) # E702: multiple statements on one line (semicolon) + # E703: statement ends with a semicolon # W605: invalid escape sequence ‘x’ + # E711: comparison to None should be ‘if cond is None:’ + # E712: comparison to True should be ‘if cond is True:’ or ‘if cond:’ # See https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes deps = pycodestyle -commands = pycodestyle --select E401,E701,E702,W605 {posargs:{toxinidir}/sage/} +commands = pycodestyle --select E401,E70,W605,E711,E712 {posargs:{toxinidir}/sage/} [pycodestyle] max-line-length = 160 diff --git a/tox.ini b/tox.ini index 9bd5ece819d..88bcc65c4e6 100644 --- a/tox.ini +++ b/tox.ini @@ -521,7 +521,7 @@ commands = local-conda: bash -c 'echo > {env:CONDA_PREFIX}/.condarc "pkgs_dirs:"' local-conda: bash -c 'echo >> {env:CONDA_PREFIX}/.condarc " - {env:SHARED_CACHE_DIR}/conda_pkgs"' local-conda: bash -c 'cat {env:CONDARC} >> {env:CONDA_PREFIX}/.condarc' - local-conda: bash -c 'if [ ! -x {env:CONDA_PREFIX}/bin/conda ]; then curl -L {env:CONDA_INSTALLER_URL_BASE}{env:CONDA_INSTALLER_FILE} -C - -o {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} && bash {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} -b -f -p {env:CONDA_PREFIX}; fi' + local-conda: bash -c 'if [ ! -x {env:CONDA_PREFIX}/bin/conda ]; then mkdir {env:CONDA_PREFIX}/conda-meta && curl -L {env:CONDA_INSTALLER_URL_BASE}{env:CONDA_INSTALLER_FILE} -C - -o {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} && bash {env:SHARED_CACHE_DIR}/{env:CONDA_INSTALLER_FILE} -b -f -p {env:CONDA_PREFIX}; fi' local-conda: bash -c 'case "{env:SKIP_SYSTEM_PKG_INSTALL:}" in 1|y*|Y*);; *) {env:SETENV} && {env:CONDA_PREFIX}/bin/conda update -n base --yes conda;; esac' local-conda: bash -c 'PACKAGES=$(build/bin/sage-get-system-packages conda $(PATH=build/bin:$PATH build/bin/sage-package list {env:SAGE_PACKAGE_LIST_ARGS}) {env:EXTRA_SAGE_PACKAGES}); {env:SETENV} && {env:CONDA_PREFIX}/bin/conda install --yes --quiet $PACKAGES' #