diff --git a/Makefile b/Makefile index 1806f6c2f9c..cb1e2913136 100644 --- a/Makefile +++ b/Makefile @@ -53,11 +53,10 @@ build/make/Makefile: configure build/make/deps build/make/Makefile.in build/pkgs fi; ) # This is used to monitor progress towards Python 3 and prevent -# regressions. The target "build" should be upgraded to reflect the -# level of Python 3 support that is known to work. +# regressions. buildbot-python3: configure ./configure --with-python=3 - $(MAKE) build + $(MAKE) # Preemptively download all standard upstream source tarballs. download: @@ -144,6 +143,7 @@ fast-rebuild-clean: misc-clean bdist-clean TESTALL = ./sage -t --all PTESTALL = ./sage -t -p --all +PTEST_PYTHON3 = cat src/ext/doctest/python3-known-passing.txt | xargs ./sage -t --long -p # Flags for ./sage -t --all. # By default, include all tests marked 'dochtml' -- see @@ -189,6 +189,9 @@ ptestoptional: all ptestoptionallong: all $(PTESTALL) --long --logfile=logs/ptestoptionallong.log +ptest-python3: buildbot-python3 + $(PTEST_PYTHON3) --logfile=logs/ptest_python3.log + configure: configure.ac src/bin/sage-version.sh m4/*.m4 build/pkgs/*/spkg-configure.m4 ./bootstrap -d @@ -209,4 +212,4 @@ list: misc-clean bdist-clean distclean bootstrap-clean maintainer-clean \ test check testoptional testall testlong testoptionallong testallong \ ptest ptestoptional ptestall ptestlong ptestoptionallong ptestallong \ - buildbot-python3 list + buildbot-python3 ptest-python3 list diff --git a/README.md b/README.md index 871ac755440..a9743f4c645 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,10 @@ and functions list the authors. Getting Started --------------- -If you downloaded a [binary](http://www.sagemath.org/download.html), -you just need open a terminal in the directory where you extracted the binary -archive and type: +If you downloaded a [binary](http://www.sagemath.org/download.html) +(i.e. a version of SageMath prepared for a specific operating system), +Sage is ready to start -- just open a terminal in the directory where +you extracted the binary archive and type: ./sage @@ -148,45 +149,73 @@ More Detailed Instructions to Build from Source gas/as, gld/ld, gnm/nm. On most platforms, these are automatically installed when you install the programs listed above. -1. Extract the Sage source tarball and cd into a directory with no - spaces in it. If you have a machine with 4 processors, say, type - `export MAKE="make -j4"` the following to configure the build script to - perform a parallel compilation of Sage using 4 jobs. - (With 4 processors, you might also consider `-j5` or `-j6` -- - building with more jobs than CPU cores can speed things up.) +1. Extract the Sage source tarball into a directory, making sure + there are no spaces in the path to the resulting directory. + + Note that moving the directory after Sage has been built will + require to build Sage again. + +1. Change to the Sage directory using `cd`. + +1. Optional: set some environment variables to customize the build. + + For example, the `MAKE` environment variable controls whether to run + several jobs in parallel, while the `SAGE_CHECK` environment variable + controls whether to perform more tests during the installation. For + an in-depth discussion of environment variables for building Sage, see + [the installation guide](http://doc.sagemath.org/html/en/installation/source.html#environment-variables). + + On a machine with 4 processors, say, typing `export MAKE="make -j4"` + will configure the build script to perform a parallel compilation of + Sage using 4 jobs. You might even consider `-j5` or `-j6`, as + building with more jobs than CPU cores can speed things up further. You might in addition pass a `-l` [load flag](https://www.gnu.org/software/make/manual/make.html#Options-Summary) - to "make": this sets a load limit, so for example if you execute + to `make`: this sets a load limit, so for example if you execute `export MAKE="make -j4 -l5.5"` then "make" won't start more than one job at a time if the system load average is above 5.5, see the [make documentation](https://www.gnu.org/software/make/manual/make.html#Parallel). - If you want to run the test suite for each individual spkg as it is - installed, type `export SAGE_CHECK="yes"` before starting the Sage - build. This will run each test suite and will raise an error if any - failures occur. Python's test suite has been disabled by default, - because it causes failures on most systems. To enable the Python - testsuite, set the environment variable `SAGE_CHECK_PACKAGES` to `python`. + If you want to run the test suite for each individual Sage package + as it gets installed, type `export SAGE_CHECK="yes"`. This will run + each test suite, raising an error if any failure occurs. Python's + test suite has been disabled by default, because it causes failures + on most systems. To enable the Python test suite, set the environment + variable `SAGE_CHECK_PACKAGES` to `python`. - To start the build, type `make`. +1. To start the build, type `make`. + + Note: to build a Python3-based Sage, instead of typing `make`, type + + make configure + ./configure --with-python=3 + make + + This will build Sage based on Python 3 rather than based on Python 2, + which is still the default at this point. The resulting Sage mostly + works well, though some features (less of them at each release!) are + not yet ready for Python 3. The progress on this is tracked at + [Sage Trac ticket 15530: Metaticket: Add support for python 3.6+](https://trac.sagemath.org/ticket/15530). 1. Wait about 20 minutes to 14 days, depending on your computer (it took about 2 weeks to build Sage on the T-Mobile G1 Android cell phone). 1. Type `./sage` to try it out. -1. Optional: Type `make ptest` to test all examples in the documentation +1. Optional: Type `make ptestlong` to test all examples in the documentation (over 200,000 lines of input!) -- this takes from 10 minutes to several hours. Don't get too disturbed if there are 2 to 3 failures, - but always feel free to email the section of `logs/ptest.log` that + but always feel free to email the section of `logs/ptestlong.log` that contains errors to the [sage-support mailing list](https://groups.google.com/group/sage-support). If there are numerous failures, there was a serious problem with your build. + Note: if you built for Python 3, you can instead run `make ptest-python3`. + 1. The HTML version of the [documentation](http://doc.sagemath.org/html/en/index.html) is built during the compilation process of Sage and resides in the directory `local/share/doc/sage/html/`. - * Optional: If you want to build the PDF version (requires LaTeX) - of the documentation, run `make doc-pdf`. +1. Optional: If you want to build the PDF version of the documentation, + run `make doc-pdf` (this requires LaTeX to be installed). 1. Optional: You might install optional packages of interest to you: type `./sage --optional` to get a list. @@ -335,7 +364,7 @@ source tree goes something like this: 1. `make python2` 1. run `./bootstrap` if `configure` does not exist -1. run `./configure` if `build/make/Makefile` doe not exist +1. run `./configure` if `build/make/Makefile` does not exist 1. `cd` into `build/make` and run the `install` script--this is little more than a front-end to running `make -f build/make/Makefile python2`, which sets some necessary environment variables and logs some information diff --git a/VERSION.txt b/VERSION.txt index 3389c0066f9..117d7bfed9f 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 8.6, Release Date: 2019-01-15 +SageMath version 8.7, Release Date: 2019-03-23 diff --git a/bootstrap b/bootstrap index 526848f2bfa..2505897c2e0 100755 --- a/bootstrap +++ b/bootstrap @@ -47,13 +47,15 @@ SAGE_SPKG_CONFIGURE_$(echo ${pkgname} | tr '[a-z]' '[A-Z]')" case $st in 0) true;; # Success - 63|127) # Autotools not installed or version too old + 16|63|127) # no m4 for pkg-config, or autotools not installed, or version too old if [ $DOWNLOAD = yes ]; then echo >&2 "Bootstrap failed, downloading required files instead." bootstrap-download || exit $? else if [ $st -eq 127 ]; then verb="install" + elif [ $st -eq 16 ]; then + verb="install pkg-config m4 macros for" else verb="upgrade" fi diff --git a/build/bin/sage-spkg b/build/bin/sage-spkg index f41ce5d3717..eff76b082b2 100755 --- a/build/bin/sage-spkg +++ b/build/bin/sage-spkg @@ -715,7 +715,7 @@ __EOF__ } -WRAPPED_SCRIPTS="build install check postinst legacy-uninstall prerm postrm" +WRAPPED_SCRIPTS="build install check preinst postinst legacy-uninstall prerm postrm" INSTALLED_SCRIPTS="prerm postrm" @@ -850,6 +850,15 @@ if [ "$KEEP_EXISTING" != "yes" ]; then sage-spkg-uninstall "$PKG_BASE" fi +# Run the pre-install script, if any +if [ -f spkg-preinst ]; then + echo "Running pre-install script for $PKG_NAME." + time $SAGE_SUDO ./spkg-preinst + if [ $? -ne 0 ]; then + error_msg "Error running the preinst script for $PKG_NAME." + exit 1 + fi +fi if [ -f spkg-build ]; then # Package has both spkg-build and spkg-install; execute the latter with SAGE_SUDO @@ -976,7 +985,15 @@ if [ "$SAGE_CHECK" = "yes" ]; then fi fi -FILE_LIST="$(echo "$FILE_LIST" | sed 's/^\(.\+\)$/"\1"/; 2,$s/^/ /; $!s/$/,/')" +# For each line in $FILE_LIST, enclose in double quotes: +NEW_LIST="" +for f in $FILE_LIST; do + NEW_LIST+="\"$f\" +" +done +# Now remove the last line (it's blank), indent each line (skipping +# the first) and append a comma (skipping the last). +FILE_LIST="$(echo "$NEW_LIST" | sed '$d' | sed '2,$s/^/ /; $!s/$/,/')" # Mark that the new package has been installed (and tested, if # applicable). diff --git a/build/make/deps b/build/make/deps index e9008d20e69..e74ad78b814 100644 --- a/build/make/deps +++ b/build/make/deps @@ -45,11 +45,8 @@ all-build: toolchain-deps # The 2 preliminary build phases: base and toolchain. -# During the toolchain build, we export SAGE_BUILD_TOOLCHAIN=yes -# such that packages can do different things when they are built -# as prerequisite of GCC. base-toolchain: _clean-broken-gcc base - env SAGE_BUILD_TOOLCHAIN=yes $(MAKE) toolchain + $(MAKE) toolchain # All targets except for the base packages all-sage: \ @@ -127,7 +124,7 @@ base: $(inst_patch) $(inst_pkgconf) # dependencies for Cython files (e.g. PARI, NTL, MP_LIBRARY). sagelib: \ $(inst_arb) \ - $(BLAS) \ + $(inst_$(BLAS)) \ $(inst_brial) \ $(inst_cliquer) \ $(inst_cypari) \ @@ -141,6 +138,7 @@ sagelib: \ $(inst_gap) \ $(inst_givaro) \ $(inst_glpk) \ + $(inst_gmpy2) \ $(inst_gsl) \ $(inst_iml) \ $(inst_jinja2) \ @@ -156,7 +154,7 @@ sagelib: \ $(inst_mpc) \ $(inst_mpfi) \ $(inst_mpfr) \ - $(MP_LIBRARY) \ + $(inst_$(MP_LIBRARY)) \ $(inst_ntl) \ $(inst_numpy) \ $(inst_pari) \ @@ -164,10 +162,10 @@ sagelib: \ $(inst_pkgconfig) \ $(inst_planarity) \ $(inst_ppl) \ + $(inst_pplpy) \ $(inst_pycygwin) \ $(inst_pynac) \ - $(inst_python2) \ - $(inst_python3) \ + $(inst_$(PYTHON)) \ $(inst_ratpoints) \ $(inst_readline) \ $(inst_rw) \ diff --git a/build/pkgs/4ti2/package-version.txt b/build/pkgs/4ti2/package-version.txt index 400084b1bf2..ba598ce6877 100644 --- a/build/pkgs/4ti2/package-version.txt +++ b/build/pkgs/4ti2/package-version.txt @@ -1 +1 @@ -1.6.7 +1.6.7.p0 diff --git a/build/pkgs/4ti2/spkg-install b/build/pkgs/4ti2/spkg-install index 517104bf35f..00eeffe2402 100644 --- a/build/pkgs/4ti2/spkg-install +++ b/build/pkgs/4ti2/spkg-install @@ -1,20 +1,7 @@ cd src/ - -if [ "$SAGE_LOCAL" = "" ]; then - echo "SAGE_LOCAL undefined ... exiting"; - echo "Maybe run 'sage -sh'?" - exit 1 -fi - CFLAGS="-I $SAGE_LOCAL/include -L$SAGE_LOCAL/lib $CFLAGS" export CFLAGS -./configure --prefix=$SAGE_LOCAL --with-gmp=$SAGE_LOCAL --with-glpk=$SAGE_LOCAL --enable-shared=yes --enable-static=no - -$MAKE -$SAGE_SUDO $MAKE install - -if [ $? -ne 0 ]; then - echo "Error building 4ti2" - exit 1 -fi - +sdh_configure --with-gmp=$SAGE_LOCAL --with-glpk=$SAGE_LOCAL \ + --enable-shared=yes --enable-static=no +sdh_make +sdh_make_install diff --git a/build/pkgs/alabaster/checksums.ini b/build/pkgs/alabaster/checksums.ini index bcc1a132b89..497827e5004 100644 --- a/build/pkgs/alabaster/checksums.ini +++ b/build/pkgs/alabaster/checksums.ini @@ -1,4 +1,4 @@ tarball=alabaster-VERSION.tar.gz -sha1=dba599faf1ca5541ef35ab251eb2b365ae2f25c7 -md5=7934dccf38801faa105f6e7b4784f493 -cksum=3227702678 +sha1=36c11bd5d8e99e2009b643b7f6e91bf2a0fd573b +md5=3591827fde96d1dd23970fb05410ed04 +cksum=3567264444 diff --git a/build/pkgs/alabaster/package-version.txt b/build/pkgs/alabaster/package-version.txt index 5b209ea2067..88a7b228577 100644 --- a/build/pkgs/alabaster/package-version.txt +++ b/build/pkgs/alabaster/package-version.txt @@ -1 +1 @@ -0.7.10 +0.7.12 diff --git a/build/pkgs/arb/checksums.ini b/build/pkgs/arb/checksums.ini index 702874c4c91..3e0307d9140 100644 --- a/build/pkgs/arb/checksums.ini +++ b/build/pkgs/arb/checksums.ini @@ -1,4 +1,4 @@ tarball=arb-VERSION.tar.gz -sha1=42c4720675d7fc40d2f6af9de06407c00775b8f2 -md5=35855176fc2c2e69e4b4c3cde004c070 -cksum=745812142 +sha1=cdbb3d63034a39f22f850def9bd365f7073f620a +md5=17816f8aa027a5e7fb8b5e62b2b40ce4 +cksum=577630044 diff --git a/build/pkgs/arb/package-version.txt b/build/pkgs/arb/package-version.txt index 3b1fc7950fa..b2242a0ff1c 100644 --- a/build/pkgs/arb/package-version.txt +++ b/build/pkgs/arb/package-version.txt @@ -1 +1 @@ -2.15.1 +2.16.0.p0 diff --git a/build/pkgs/arb/spkg-install b/build/pkgs/arb/spkg-install index fafe9422dec..9459cb94016 100644 --- a/build/pkgs/arb/spkg-install +++ b/build/pkgs/arb/spkg-install @@ -5,20 +5,8 @@ cd src export EXTRA_SHARED_FLAGS=$LDFLAGS ./configure --disable-static --prefix="$SAGE_LOCAL" --with-flint="$SAGE_LOCAL" \ - --with-gmp="$SAGE_LOCAL" --with-mpfr="$SAGE_LOCAL" -if [ $? -ne 0 ]; then - echo >&2 "Error configuring arb." - exit 1 -fi + --with-gmp="$SAGE_LOCAL" --with-mpfr="$SAGE_LOCAL" || \ + sdh_die "Error configuring arb." -$MAKE verbose -if [ $? -ne 0 ]; then - echo >&2 "Error building arb." - exit 1 -fi - -$MAKE install -if [ $? -ne 0 ]; then - echo >&2 "Error installing arb." - exit 1 -fi +sdh_make verbose +sdh_make_install diff --git a/build/pkgs/atlas/configuration.py b/build/pkgs/atlas/configuration.py index 0b7f50ba1e3..d79f597b87a 100644 --- a/build/pkgs/atlas/configuration.py +++ b/build/pkgs/atlas/configuration.py @@ -5,7 +5,12 @@ from __future__ import print_function -import platform, os, sys, time, shutil, glob, subprocess +import platform +import os +import sys +import shutil +import glob +import subprocess # this dictionary will hold all configuration information diff --git a/build/pkgs/atlas/spkg-install.py b/build/pkgs/atlas/spkg-install.py index f148a0c4565..f6dfb3e8a6c 100644 --- a/build/pkgs/atlas/spkg-install.py +++ b/build/pkgs/atlas/spkg-install.py @@ -164,8 +164,9 @@ def is_atlas_lib_path(path, libs): sys.exit(2) for fname in os.listdir(ATLAS_LIB): - if fname.startswith(prefix+'f77blas'): + if fname.startswith(prefix + 'f77blas'): f77blas = os.path.join(ATLAS_LIB, fname) + break else: f77blas = None if f77blas is not None: diff --git a/build/pkgs/babel/checksums.ini b/build/pkgs/babel/checksums.ini index 8b2790f7643..0c06f1c56df 100644 --- a/build/pkgs/babel/checksums.ini +++ b/build/pkgs/babel/checksums.ini @@ -1,4 +1,4 @@ tarball=Babel-VERSION.tar.gz -sha1=9adbd49864392713c6a3080aeb0a9e6432577277 -md5=60228b3ce93a203357158b909afe8ae1 -cksum=2035941902 +sha1=6aed99e4fb8a2a75de7815599f610cdcbb81e3c2 +md5=c384ac03026e8fe6f9b90f55201f1bff +cksum=3805303136 diff --git a/build/pkgs/babel/package-version.txt b/build/pkgs/babel/package-version.txt index 73462a5a134..e70b4523ae7 100644 --- a/build/pkgs/babel/package-version.txt +++ b/build/pkgs/babel/package-version.txt @@ -1 +1 @@ -2.5.1 +2.6.0 diff --git a/build/pkgs/backports_functools_lru_cache/checksums.ini b/build/pkgs/backports_functools_lru_cache/checksums.ini index 9b49ffbe93d..19e72765bcd 100644 --- a/build/pkgs/backports_functools_lru_cache/checksums.ini +++ b/build/pkgs/backports_functools_lru_cache/checksums.ini @@ -1,4 +1,4 @@ tarball=backports.functools_lru_cache-VERSION.tar.gz -sha1=8a546e7887e961c2873c9b053f4e2cd2a96bd71d -md5=b954e7d5e2ca0f0f66ad2ed12ba800e5 -cksum=2013684405 +sha1=35a5895d22875cd024694d3c7393a793e9fd653d +md5=20f53f54cd3f04b3346ce75a54959754 +cksum=4241725171 diff --git a/build/pkgs/backports_functools_lru_cache/package-version.txt b/build/pkgs/backports_functools_lru_cache/package-version.txt index c068b2447cc..c239c60cba2 100644 --- a/build/pkgs/backports_functools_lru_cache/package-version.txt +++ b/build/pkgs/backports_functools_lru_cache/package-version.txt @@ -1 +1 @@ -1.4 +1.5 diff --git a/build/pkgs/bleach/checksums.ini b/build/pkgs/bleach/checksums.ini index 7ea534c9148..1b3f2703104 100644 --- a/build/pkgs/bleach/checksums.ini +++ b/build/pkgs/bleach/checksums.ini @@ -1,4 +1,4 @@ tarball=bleach-VERSION.tar.gz -sha1=ed09e5428b8a47d57e232457ad944119ce9cba06 -md5=47fb1e6a6fd82ca84c0e9fd1023321e6 -cksum=1206011431 +sha1=e7ee75050ccace055d5040010e3fdfb8e2535a3a +md5=f042c4e8a953824dc8511f535daa20a4 +cksum=3095652578 diff --git a/build/pkgs/bleach/package-version.txt b/build/pkgs/bleach/package-version.txt index ac2cdeba013..b5021469305 100644 --- a/build/pkgs/bleach/package-version.txt +++ b/build/pkgs/bleach/package-version.txt @@ -1 +1 @@ -2.1.3 +3.0.2 diff --git a/build/pkgs/bliss/package-version.txt b/build/pkgs/bliss/package-version.txt index d6af10bbf1d..e93ee1376fa 100644 --- a/build/pkgs/bliss/package-version.txt +++ b/build/pkgs/bliss/package-version.txt @@ -1 +1 @@ -0.73+debian-1+sage-2016-08-02 +0.73+debian-1+sage-2016-08-02.p0 diff --git a/build/pkgs/bliss/spkg-install b/build/pkgs/bliss/spkg-install index 0bc4a64fd66..aaf4c3037bc 100644 --- a/build/pkgs/bliss/spkg-install +++ b/build/pkgs/bliss/spkg-install @@ -1,15 +1,4 @@ -if [ "$SAGE_LOCAL" = "" ]; then - echo "SAGE_LOCAL undefined ... exiting"; - echo "Maybe run 'sage -sh'?" - exit 1 -fi - - -cd "src" - -./configure --prefix="$SAGE_LOCAL" --disable-gmp && $MAKE && $MAKE install - -if [ $? -ne 0 ]; then - echo "An error occurred whilst building bliss" - exit 1 -fi +cd src +sdh_configure --disable-gmp +sdh_make +sdh_make_install diff --git a/build/pkgs/boost_cropped/package-version.txt b/build/pkgs/boost_cropped/package-version.txt index b6148bc0a75..52d48f68cea 100644 --- a/build/pkgs/boost_cropped/package-version.txt +++ b/build/pkgs/boost_cropped/package-version.txt @@ -1 +1 @@ -1.66.0 +1.66.0.p0 diff --git a/build/pkgs/boost_cropped/spkg-install b/build/pkgs/boost_cropped/spkg-install index 0b09d9cc68d..c57a26746ad 100644 --- a/build/pkgs/boost_cropped/spkg-install +++ b/build/pkgs/boost_cropped/spkg-install @@ -1,20 +1,2 @@ -if [ "$SAGE_LOCAL" = "" ]; then - echo "SAGE_LOCAL undefined ... exiting"; - echo "Maybe run 'sage -sh'?" - exit 1 -fi - -echo "Clean out old boost headers" -rm -rf "${SAGE_LOCAL}"/include/boost -if ! [ $? -eq 0 ]; then - echo "Failed to delete old boost headers." - exit 1 -fi - echo "Copying over new boost headers" -cp -r src/boost "${SAGE_LOCAL}"/include/ -if ! [ $? -eq 0 ]; then - echo "Failed to install new boost headers." - exit 1 -fi - +sdh_install src/boost "$SAGE_LOCAL/include" diff --git a/build/pkgs/boost_cropped/spkg-legacy-uninstall b/build/pkgs/boost_cropped/spkg-legacy-uninstall new file mode 100644 index 00000000000..d44862f175c --- /dev/null +++ b/build/pkgs/boost_cropped/spkg-legacy-uninstall @@ -0,0 +1 @@ +rm -rf "${SAGE_LOCAL}"/include/boost diff --git a/build/pkgs/brial/spkg-install b/build/pkgs/brial/spkg-install index 7f338b490c1..a59dc244f48 100644 --- a/build/pkgs/brial/spkg-install +++ b/build/pkgs/brial/spkg-install @@ -1,14 +1,5 @@ cd src -# Use C++11 to compile BRiAl, see https://trac.sagemath.org/ticket/21083 -if [ "$UNAME" = "CYGWIN" ]; then - # However, on Cygwin we need to use gnu++11: - # https://trac.sagemath.org/ticket/24860 - export CXXFLAGS="$CXXFLAGS -std=gnu++11" -else - export CXXFLAGS="$CXXFLAGS -std=c++11" -fi - export PYTHON=sage-python23 # diff --git a/build/pkgs/bzip2/spkg-configure.m4 b/build/pkgs/bzip2/spkg-configure.m4 new file mode 100644 index 00000000000..5a210179a00 --- /dev/null +++ b/build/pkgs/bzip2/spkg-configure.m4 @@ -0,0 +1,5 @@ +SAGE_SPKG_CONFIGURE([bzip2], [ + AC_CHECK_HEADER(bzlib.h, [], [sage_spkg_install_bzip2=yes]) + AC_SEARCH_LIBS([BZ2_bzCompress], [bz2], [], [sage_spkg_install_bzip2=yes]) + AC_CHECK_PROG(bzip2, [break], [sage_spkg_install_bzip2=yes]) +]) diff --git a/build/pkgs/cbc/package-version.txt b/build/pkgs/cbc/package-version.txt index 93ea0c95979..4a90452c956 100644 --- a/build/pkgs/cbc/package-version.txt +++ b/build/pkgs/cbc/package-version.txt @@ -1 +1 @@ -2.9.4 +2.9.4.p0 diff --git a/build/pkgs/cbc/spkg-install b/build/pkgs/cbc/spkg-install index 99cff636d64..058c488ea7a 100644 --- a/build/pkgs/cbc/spkg-install +++ b/build/pkgs/cbc/spkg-install @@ -1,9 +1,3 @@ -if [ "$SAGE_LOCAL" = "" ]; then - echo >&2 "SAGE_LOCAL undefined ... exiting"; - echo >&2 "Maybe run 'sage -sh'?" - exit 1 -fi - export LDFLAGS="$LDFLAGS -lz -lbz2" #export CPPFLAGS="-DHAVE_CLOCK_GETTIME=0" @@ -15,8 +9,10 @@ export LDFLAGS="$LDFLAGS -lz -lbz2" # function. Cbc uses an alternative method to do the job, and it looks like # all this is required when Cbc solves LP with several threads. # -cd src && -sed -i -e "s/clock\_gettime ()/Grrrrrrrrrrrr\ ()/g" Cbc/configure && -./configure --prefix="$SAGE_LOCAL" "${args[@]}" --enable-cbc-parallel --enable-parallel --enable-gnu-packages --enable-static && -make && -make install +cd src +sed -i -e "s/clock\_gettime ()/Grrrrrrrrrrrr\ ()/g" Cbc/configure || \ + sdh_die "Failed to patch clock_gettime issue in Cbc/configure" +sdh_configure --enable-cbc-parallel --enable-parallel \ + --enable-gnu-packages --enable-static +sdh_make +sdh_make_install diff --git a/build/pkgs/certifi/checksums.ini b/build/pkgs/certifi/checksums.ini index f4579fbeefb..7c8e7598253 100644 --- a/build/pkgs/certifi/checksums.ini +++ b/build/pkgs/certifi/checksums.ini @@ -1,4 +1,4 @@ tarball=certifi-VERSION.tar.gz -sha1=8e4574685163771ee40604d7dd89fe60b9461790 -md5=c15ac46ed1fe4b607ff3405928f9a992 -cksum=3062798652 +sha1=673bf8bc29d7ee0a1a0d8af74d050e5769fec2a9 +md5=8160cf662212bc731eccf1af8042c0af +cksum=322391593 diff --git a/build/pkgs/certifi/package-version.txt b/build/pkgs/certifi/package-version.txt index caa9db51eb1..702d989ee94 100644 --- a/build/pkgs/certifi/package-version.txt +++ b/build/pkgs/certifi/package-version.txt @@ -1 +1 @@ -2017.11.5 +2018.11.29 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index fea4c0af58c..984a3188f15 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=7056135dd3147fad1d6791e1e0389775a434aae0 -md5=5b737189c37f0162cd206badb44beae8 -cksum=3470317803 +sha1=a591a45d202e88f88dc69a33734022174bf833aa +md5=23a55e945c2b05d976dea32459503769 +cksum=1484570779 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 274f7143b4c..a1e0432c9a7 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -302 +312 diff --git a/build/pkgs/cryptominisat/checksums.ini b/build/pkgs/cryptominisat/checksums.ini index 5e6fd58fe7b..35adbcee0aa 100644 --- a/build/pkgs/cryptominisat/checksums.ini +++ b/build/pkgs/cryptominisat/checksums.ini @@ -1,4 +1,4 @@ tarball=cryptominisat-VERSION.tar.gz -sha1=f270bc232dbf273d5059f4c0cb704df7cf1f507d -md5=45203be947368de75b44cf734cbac1d7 -cksum=1496245059 +sha1=568cd2f528609a31d217e24e381de87e011499d4 +md5=cce64bfd256700e96baee90b7bdfe770 +cksum=3567560229 diff --git a/build/pkgs/cryptominisat/dependencies b/build/pkgs/cryptominisat/dependencies index df51e312747..743eff61cf1 100644 --- a/build/pkgs/cryptominisat/dependencies +++ b/build/pkgs/cryptominisat/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | cmake sqlite m4ri boost_cropped +$(PYTHON) m4ri zlib libpng | cmake sqlite boost_cropped ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cryptominisat/package-version.txt b/build/pkgs/cryptominisat/package-version.txt index 6b244dcd696..10c11484b9c 100644 --- a/build/pkgs/cryptominisat/package-version.txt +++ b/build/pkgs/cryptominisat/package-version.txt @@ -1 +1 @@ -5.0.1 +5.6.6 diff --git a/build/pkgs/cryptominisat/patches/001-osx_install_nameQA.patch b/build/pkgs/cryptominisat/patches/001-osx_install_nameQA.patch deleted file mode 100644 index 1fdbe0efab7..00000000000 --- a/build/pkgs/cryptominisat/patches/001-osx_install_nameQA.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index 4c1e235..284e348 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -2,6 +2,8 @@ include_directories( - ${PROJECT_SOURCE_DIR} - ) - -+include(GNUInstallDirs) -+ - if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) - endif() -@@ -129,6 +131,8 @@ target_link_libraries(libcryptominisat5 - ) - set_target_properties(libcryptominisat5 PROPERTIES - OUTPUT_NAME cryptominisat5 -+ MACOSX_RPATH TRUE -+ INSTALL_NAME_DIR "${CMAKE_INSTALL_FULL_LIBDIR}" - PUBLIC_HEADER "${cryptominisat5_public_headers}" - VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} - SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} -@@ -185,9 +189,9 @@ endforeach() - - install(TARGETS libcryptominisat5 - EXPORT ${CRYPTOMINISAT5_EXPORT_NAME} -- LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" -- ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" -- PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_PREFIX}/include/cryptominisat5" -+ LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" -+ ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" -+ PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cryptominisat5" - ) - - if (NOT ONLY_SIMPLE) diff --git a/build/pkgs/cryptominisat/patches/002-python-destdir.patch b/build/pkgs/cryptominisat/patches/002-python-destdir.patch deleted file mode 100644 index 37ad4e2a09a..00000000000 --- a/build/pkgs/cryptominisat/patches/002-python-destdir.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -ruN a/python/CMakeLists.txt b/python/CMakeLists.txt ---- a/python/CMakeLists.txt 2018-05-16 15:45:51.351070200 +0200 -+++ b/python/CMakeLists.txt 2018-05-16 15:46:55.471242500 +0200 -@@ -14,7 +14,7 @@ - - add_custom_target(python_interface ALL DEPENDS ${OUTPUT}/timestamp) - --install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} install --record files.txt)") -+install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} install --root=\$ENV{DESTDIR} --record files.txt)") - - if (ENABLE_TESTING) - add_test (NAME pytest diff --git a/build/pkgs/cryptominisat/spkg-install b/build/pkgs/cryptominisat/spkg-install index a4541248b07..7becb20aa8f 100644 --- a/build/pkgs/cryptominisat/spkg-install +++ b/build/pkgs/cryptominisat/spkg-install @@ -1,7 +1,15 @@ cd src -cmake -DCMAKE_INSTALL_PREFIX="${SAGE_LOCAL}" -DUSE_GAUSS='ON' \ - -DZLIB_ROOT="${SAGE_LOCAL}" . || sdh_die 'Error configuring cryptominisat' +if [ $SAGE_PYTHON_VERSION -eq 2 ] +then + EXTRA_OPTS="-DFORCE_PYTHON2='ON'" +fi + +cmake -DCMAKE_INSTALL_PREFIX="${SAGE_LOCAL}" \ + -DZLIB_ROOT="${SAGE_LOCAL}" \ + -DUSE_GAUSS='ON' \ + $EXTRA_OPTS \ + . || sdh_die 'Error configuring cryptominisat' sdh_make VERBOSE=ON sdh_make_install VERBOSE=ON diff --git a/build/pkgs/cryptominisat/type b/build/pkgs/cryptominisat/type index 9839eb20815..134d9bc32d5 100644 --- a/build/pkgs/cryptominisat/type +++ b/build/pkgs/cryptominisat/type @@ -1 +1 @@ -experimental +optional diff --git a/build/pkgs/csdp/package-version.txt b/build/pkgs/csdp/package-version.txt index 0cda48ac61e..98ee58f7b2f 100644 --- a/build/pkgs/csdp/package-version.txt +++ b/build/pkgs/csdp/package-version.txt @@ -1 +1 @@ -6.2 +6.2.p0 diff --git a/build/pkgs/csdp/spkg-install b/build/pkgs/csdp/spkg-install index 4813fe9d6f3..d12a02ca88f 100644 --- a/build/pkgs/csdp/spkg-install +++ b/build/pkgs/csdp/spkg-install @@ -1,9 +1,3 @@ -if [ -z "$SAGE_LOCAL" ]; then - echo >&2 "SAGE_LOCAL undefined - exiting..." - echo >&2 "Maybe run 'sage -sh'?" - exit 1 -fi - cat LICENSE echo "**************************************************" echo "NOTE that csdp's License is NOT GPL-compatible" @@ -11,25 +5,6 @@ echo "**************************************************" cd src - -echo "Configuring csdp..." -./configure CPPFLAGS=-DNOSHORTS --prefix="$SAGE_LOCAL" -if [ $? -ne 0 ]; then - echo >&2 "Error configuring csdp." - exit 1 -fi - -echo "Building csdp..." -$MAKE -if [ $? -ne 0 ]; then - echo >&2 "Error building csdp." - exit 1 -fi - -echo "Installing csdp..." -$MAKE install -if [ $? -ne 0 ]; then - echo >&2 "Error installing csdp." - exit 1 -fi - +sdh_configure CPPFLAGS=-DNOSHORTS +sdh_make +sdh_make_install diff --git a/build/pkgs/cypari/checksums.ini b/build/pkgs/cypari/checksums.ini index 83af1265903..9a059184f19 100644 --- a/build/pkgs/cypari/checksums.ini +++ b/build/pkgs/cypari/checksums.ini @@ -1,4 +1,4 @@ tarball=cypari2-VERSION.tar.gz -sha1=26820d83ecb73555ddfb41b78ee87a3baff0bfbc -md5=32f123679b6fc47c6713be2d9e0d2407 -cksum=4086011827 +sha1=7f0a53f99079c110984ebe352c0848b87bfc2d62 +md5=84c05ca455bed3376a016d1073639ea2 +cksum=506281443 diff --git a/build/pkgs/cypari/dependencies b/build/pkgs/cypari/dependencies index 27f046f88ec..e8630bba15a 100644 --- a/build/pkgs/cypari/dependencies +++ b/build/pkgs/cypari/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) cython pari | pip cysignals +$(PYTHON) cython pari cysignals | pip ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cypari/package-version.txt b/build/pkgs/cypari/package-version.txt index 3a3cd8cc8b0..7e41e597591 100644 --- a/build/pkgs/cypari/package-version.txt +++ b/build/pkgs/cypari/package-version.txt @@ -1 +1 @@ -1.3.1 +2.1.0.p0 diff --git a/build/pkgs/cypari/patches/trashcan.patch b/build/pkgs/cypari/patches/trashcan.patch new file mode 100644 index 00000000000..f4918d4cd39 --- /dev/null +++ b/build/pkgs/cypari/patches/trashcan.patch @@ -0,0 +1,47 @@ +commit 78e6dcf937c960c51132132e14f86bddbbe5b7d9 +Author: Jeroen Demeyer +Date: Tue Feb 19 11:50:49 2019 +0100 + + Use the trashcan for Gen + +diff --git a/cypari2/gen.pxd b/cypari2/gen.pxd +index 2ac0669..664d57d 100644 +--- a/cypari2/gen.pxd ++++ b/cypari2/gen.pxd +@@ -1,3 +1,4 @@ ++cimport cython + from cpython.object cimport PyObject + from .types cimport GEN, pari_sp + +diff --git a/cypari2/gen.pyx b/cypari2/gen.pyx +index d268cf1..687f5b2 100644 +--- a/cypari2/gen.pyx ++++ b/cypari2/gen.pyx +@@ -135,6 +135,7 @@ cdef extern from *: + GEN new_nfeltup(GEN nf, GEN x, GEN zknf) + + ++@cython.trashcan(True) + cdef class Gen(Gen_base): + """ + Wrapper for a PARI ``GEN`` with memory management. +diff --git a/cypari2/pari_instance.pyx b/cypari2/pari_instance.pyx +index ba82438..d13bc45 100644 +--- a/cypari2/pari_instance.pyx ++++ b/cypari2/pari_instance.pyx +@@ -243,6 +243,15 @@ Reset default precision for the following tests: + + >>> pari.set_real_precision_bits(53) + ++Test the trashcan mechanism (without the trashcan, this would cause ++a stack overflow): ++ ++>>> pari.allocatemem(2**27, silent=True) ++>>> L = [pari(i) for i in range(2**20)] ++>>> x = pari.Pi() ++>>> del L ++>>> del x ++ + Test that interrupts work properly: + + >>> pari.allocatemem(8000000, 2**29) diff --git a/build/pkgs/cypari/spkg-check b/build/pkgs/cypari/spkg-check index 86641f7f607..2829f6711e6 100644 --- a/build/pkgs/cypari/spkg-check +++ b/build/pkgs/cypari/spkg-check @@ -1 +1 @@ -cd src && $MAKE check +cd src && $MAKE check PYTHON=sage-python23 diff --git a/build/pkgs/cysignals/checksums.ini b/build/pkgs/cysignals/checksums.ini index 6af79273cb7..b1191cfedf0 100644 --- a/build/pkgs/cysignals/checksums.ini +++ b/build/pkgs/cysignals/checksums.ini @@ -1,4 +1,4 @@ tarball=cysignals-VERSION.tar.gz -sha1=b891c802754e9e35703c013c85adda5ad6dffe35 -md5=0b18a7a58c77c40590d821df62df1312 -cksum=915039650 +sha1=9b8fc96da26b8cb5a43912e7609a7ab68569f55e +md5=b755e9eab91722d0c9375b21a0c38e19 +cksum=3947966122 diff --git a/build/pkgs/cysignals/package-version.txt b/build/pkgs/cysignals/package-version.txt index a8fdfda1c78..5ad2491cf88 100644 --- a/build/pkgs/cysignals/package-version.txt +++ b/build/pkgs/cysignals/package-version.txt @@ -1 +1 @@ -1.8.1 +1.10.2 diff --git a/build/pkgs/cython/checksums.ini b/build/pkgs/cython/checksums.ini index 73665b3fc1f..f27f805ea9f 100644 --- a/build/pkgs/cython/checksums.ini +++ b/build/pkgs/cython/checksums.ini @@ -1,4 +1,4 @@ tarball=Cython-VERSION.tar.gz -sha1=afbb57c0c4a194dcd32167bcca5ee02257b8fbab -md5=3cf61c7ef8e5daa47e469cf7ba2e598c -cksum=901381648 +sha1=19195608d0dcbfe583b3f34144779d84d28eb544 +md5=074f70ec8bd0a6bf5cf658508c63a999 +cksum=866931573 diff --git a/build/pkgs/cython/package-version.txt b/build/pkgs/cython/package-version.txt index 25939d35c73..4c120032536 100644 --- a/build/pkgs/cython/package-version.txt +++ b/build/pkgs/cython/package-version.txt @@ -1 +1 @@ -0.29.1 +0.29.5.p0 diff --git a/build/pkgs/cython/patches/trashcan.patch b/build/pkgs/cython/patches/trashcan.patch new file mode 100644 index 00000000000..18e1b4a7052 --- /dev/null +++ b/build/pkgs/cython/patches/trashcan.patch @@ -0,0 +1,180 @@ +See https://github.com/cython/cython/pull/2842 + +commit c47c4ef735c4b7f1863b21bbe6f112b06c4aad05 +Author: Jeroen Demeyer +Date: Thu Feb 14 10:02:41 2019 +0100 + + @cython.trashcan directive to enable the Python trashcan for deallocations + +diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py +index d5742de..27fcad6 100644 +--- a/Cython/Compiler/ModuleNode.py ++++ b/Cython/Compiler/ModuleNode.py +@@ -1426,6 +1426,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): + + is_final_type = scope.parent_type.is_final_type + needs_gc = scope.needs_gc() ++ needs_trashcan = scope.needs_trashcan() + + weakref_slot = scope.lookup_here("__weakref__") if not scope.is_closure_class_scope else None + if weakref_slot not in scope.var_entries: +@@ -1464,6 +1465,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): + # running this destructor. + code.putln("PyObject_GC_UnTrack(o);") + ++ if needs_trashcan: ++ code.globalstate.use_utility_code( ++ UtilityCode.load_cached("PyTrashcan", "ExtensionTypes.c")) ++ code.putln("__Pyx_TRASHCAN_BEGIN(o, %s)" % slot_func_cname) ++ + # call the user's __dealloc__ + self.generate_usr_dealloc_call(scope, code) + +@@ -1537,6 +1543,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): + code.putln("(*Py_TYPE(o)->tp_free)(o);") + if freelist_size: + code.putln("}") ++ ++ if needs_trashcan: ++ code.putln("__Pyx_TRASHCAN_END") ++ + code.putln( + "}") + +diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py +index d859c19..19d96f1 100644 +--- a/Cython/Compiler/Options.py ++++ b/Cython/Compiler/Options.py +@@ -313,6 +313,7 @@ directive_types = { + 'freelist': int, + 'c_string_type': one_of('bytes', 'bytearray', 'str', 'unicode'), + 'c_string_encoding': normalise_encoding_name, ++ 'trashcan': bool, + } + + for key, val in _directive_defaults.items(): +@@ -355,6 +356,7 @@ directive_scopes = { # defaults to available everywhere + 'np_pythran': ('module',), + 'fast_gil': ('module',), + 'iterable_coroutine': ('module', 'function'), ++ 'trashcan' : ('cclass',), + } + + +diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py +index 3b572d6..f200c5f 100644 +--- a/Cython/Compiler/PyrexTypes.py ++++ b/Cython/Compiler/PyrexTypes.py +@@ -1136,6 +1136,7 @@ class PyObjectType(PyrexType): + is_extern = False + is_subclassed = False + is_gc_simple = False ++ builtin_trashcan = False # builtin type using trashcan + + def __str__(self): + return "Python object" +@@ -1190,10 +1191,14 @@ class PyObjectType(PyrexType): + + + builtin_types_that_cannot_create_refcycles = set([ +- 'bool', 'int', 'long', 'float', 'complex', ++ 'object', 'bool', 'int', 'long', 'float', 'complex', + 'bytearray', 'bytes', 'unicode', 'str', 'basestring' + ]) + ++builtin_types_with_trashcan = set([ ++ 'dict', 'list', 'set', 'frozenset', 'tuple', 'type', ++]) ++ + + class BuiltinObjectType(PyObjectType): + # objstruct_cname string Name of PyObject struct +@@ -1218,6 +1223,7 @@ class BuiltinObjectType(PyObjectType): + self.typeptr_cname = "(&%s)" % cname + self.objstruct_cname = objstruct_cname + self.is_gc_simple = name in builtin_types_that_cannot_create_refcycles ++ self.builtin_trashcan = name in builtin_types_with_trashcan + if name == 'type': + # Special case the type type, as many C API calls (and other + # libraries) actually expect a PyTypeObject* for type arguments. +diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py +index f7443cb..d44484d 100644 +--- a/Cython/Compiler/Symtab.py ++++ b/Cython/Compiler/Symtab.py +@@ -2085,6 +2085,22 @@ class CClassScope(ClassScope): + return not self.parent_type.is_gc_simple + return False + ++ def needs_trashcan(self): ++ # If the trashcan directive is explicitly set to False, ++ # unconditionally disable the trashcan. ++ directive = self.directives.get('trashcan') ++ if directive is False: ++ return False ++ # If the directive is set to True and the class has Python-valued ++ # C attributes, then it should use the trashcan in tp_dealloc. ++ if directive and self.has_cyclic_pyobject_attrs: ++ return True ++ # Use the trashcan if the base class uses it ++ base_type = self.parent_type.base_type ++ if base_type and base_type.scope is not None: ++ return base_type.scope.needs_trashcan() ++ return self.parent_type.builtin_trashcan ++ + def needs_tp_clear(self): + """ + Do we need to generate an implementation for the tp_clear slot? Can +diff --git a/Cython/Utility/ExtensionTypes.c b/Cython/Utility/ExtensionTypes.c +index 50d0e21..ca2adbe 100644 +--- a/Cython/Utility/ExtensionTypes.c ++++ b/Cython/Utility/ExtensionTypes.c +@@ -74,6 +74,49 @@ static int __Pyx_PyType_Ready(PyTypeObject *t) { + return r; + } + ++/////////////// PyTrashcan.proto /////////////// ++ ++// These macros are taken from https://github.com/python/cpython/pull/11841 ++// Unlike the Py_TRASHCAN_SAFE_BEGIN/Py_TRASHCAN_SAFE_END macros, they ++// allow dealing correctly with subclasses. ++ ++// This requires CPython version >= 2.7.4 ++// (or >= 3.2.4 but we don't support such old Python 3 versions anyway) ++#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02070400 ++#define __Pyx_TRASHCAN_BEGIN_CONDITION(op, cond) \ ++ do { \ ++ PyThreadState *_tstate = NULL; \ ++ // If "cond" is false, then _tstate remains NULL and the deallocator ++ // is run normally without involving the trashcan ++ if (cond) { \ ++ _tstate = PyThreadState_GET(); \ ++ if (_tstate->trash_delete_nesting >= PyTrash_UNWIND_LEVEL) { \ ++ // Store the object (to be deallocated later) and jump past ++ // Py_TRASHCAN_END, skipping the body of the deallocator ++ _PyTrash_thread_deposit_object((PyObject*)(op)); \ ++ break; \ ++ } \ ++ ++_tstate->trash_delete_nesting; \ ++ } ++ // The body of the deallocator is here. ++#define __Pyx_TRASHCAN_END \ ++ if (_tstate) { \ ++ --_tstate->trash_delete_nesting; \ ++ if (_tstate->trash_delete_later && _tstate->trash_delete_nesting <= 0) \ ++ _PyTrash_thread_destroy_chain(); \ ++ } \ ++ } while (0); ++ ++#define __Pyx_TRASHCAN_BEGIN(op, dealloc) __Pyx_TRASHCAN_BEGIN_CONDITION(op, \ ++ Py_TYPE(op)->tp_dealloc == (destructor)(dealloc)) ++ ++#else ++// The trashcan is a no-op on other Python implementations ++// or old CPython versions ++#define __Pyx_TRASHCAN_BEGIN(op, dealloc) ++#define __Pyx_TRASHCAN_END ++#endif ++ + /////////////// CallNextTpDealloc.proto /////////////// + + static void __Pyx_call_next_tp_dealloc(PyObject* obj, destructor current_tp_dealloc); diff --git a/build/pkgs/deformation/package-version.txt b/build/pkgs/deformation/package-version.txt index 57eb6dfe3a9..036881eb8b0 100644 --- a/build/pkgs/deformation/package-version.txt +++ b/build/pkgs/deformation/package-version.txt @@ -1 +1 @@ -d05941b +d05941b.p0 diff --git a/build/pkgs/deformation/spkg-install b/build/pkgs/deformation/spkg-install index e0985d153bb..e6fdaa4a3d7 100644 --- a/build/pkgs/deformation/spkg-install +++ b/build/pkgs/deformation/spkg-install @@ -1,21 +1,10 @@ cd src -./configure --disable-static --prefix="$SAGE_LOCAL" \ - --with-gmp="$SAGE_LOCAL" --with-mpfr="$SAGE_LOCAL" \ - --with-flint="$SAGE_LOCAL" -if [ $? -ne 0 ]; then - echo >&2 "Error configuring deformation." - exit 1 -fi - -$MAKE -if [ $? -ne 0 ]; then - echo >&2 "Error building deformation." - exit 1 -fi - -$MAKE install -if [ $? -ne 0 ]; then - echo >&2 "Error installing deformation." - exit 1 -fi +# Note: Not actually an autoconf-generated configure; doesn't support +# all standard flags, so we can't use sdh_configure +./configure --prefix="$SAGE_LOCAL" --disable-static \ + --with-gmp="$SAGE_LOCAL" --with-mpfr="$SAGE_LOCAL" \ + --with-flint="$SAGE_LOCAL" || \ + sdh_die "Failed to configure deformation" +sdh_make +sdh_make_install diff --git a/build/pkgs/defusedxml/SPKG.txt b/build/pkgs/defusedxml/SPKG.txt new file mode 100644 index 00000000000..c3c8d65701d --- /dev/null +++ b/build/pkgs/defusedxml/SPKG.txt @@ -0,0 +1,23 @@ += defusedxml = + +== Description == + +defusedxml addresses vulnerabilities of XML parsers and XML libraries. + +It became a dependency of nbconvert starting with nbconvert 5.4. + +== License == + +Python Software Foundation License (PSFL) + +== Upstream Contact == + +https://pypi.org/project/defusedxml/ + +== Dependencies == + +* pip + +== Special Update/Build Instructions == + +None. diff --git a/build/pkgs/defusedxml/checksums.ini b/build/pkgs/defusedxml/checksums.ini new file mode 100644 index 00000000000..297906dd4c9 --- /dev/null +++ b/build/pkgs/defusedxml/checksums.ini @@ -0,0 +1,4 @@ +tarball=defusedxml-VERSION.tar.gz +sha1=70ff80a849bbc2e9241daa1debda9f43e7fbdff0 +md5=7ff1501366c6d1dcd2de8514dc2b755e +cksum=1883719404 diff --git a/build/pkgs/defusedxml/dependencies b/build/pkgs/defusedxml/dependencies new file mode 100644 index 00000000000..639891a22b2 --- /dev/null +++ b/build/pkgs/defusedxml/dependencies @@ -0,0 +1 @@ +$(PYTHON) | pip \ No newline at end of file diff --git a/build/pkgs/defusedxml/package-version.txt b/build/pkgs/defusedxml/package-version.txt new file mode 100644 index 00000000000..8f0916f768f --- /dev/null +++ b/build/pkgs/defusedxml/package-version.txt @@ -0,0 +1 @@ +0.5.0 diff --git a/build/pkgs/defusedxml/spkg-install b/build/pkgs/defusedxml/spkg-install new file mode 100644 index 00000000000..02c9d98a549 --- /dev/null +++ b/build/pkgs/defusedxml/spkg-install @@ -0,0 +1 @@ +cd src && sdh_pip_install . \ No newline at end of file diff --git a/build/pkgs/defusedxml/type b/build/pkgs/defusedxml/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/defusedxml/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/ecl/spkg-install b/build/pkgs/ecl/spkg-install index 8f3dda20f5a..840f71f8d5b 100644 --- a/build/pkgs/ecl/spkg-install +++ b/build/pkgs/ecl/spkg-install @@ -48,14 +48,6 @@ touch build/TAGS exec &2 "Error - Failed to remove old ECL install ... exiting" - exit 1 -fi - sdh_make_install # Create symbolic link to lib/ecl-version directory. diff --git a/build/pkgs/ecl/spkg-legacy-uninstall b/build/pkgs/ecl/spkg-legacy-uninstall new file mode 100644 index 00000000000..b6138e558a4 --- /dev/null +++ b/build/pkgs/ecl/spkg-legacy-uninstall @@ -0,0 +1,5 @@ +rm -f "$SAGE_LOCAL"/bin/ecl +rm -rf "$SAGE_LOCAL"/include/ecl +rm -rf "$SAGE_LOCAL"/lib/ecl +rm -rf "$SAGE_LOCAL"/lib/ecl-* +rm -rf "$SAGE_LOCAL"/lib/libecl.* diff --git a/build/pkgs/eclib/checksums.ini b/build/pkgs/eclib/checksums.ini index c00d7a10a75..30f53bf62c3 100644 --- a/build/pkgs/eclib/checksums.ini +++ b/build/pkgs/eclib/checksums.ini @@ -1,4 +1,4 @@ tarball=eclib-VERSION.tar.bz2 -sha1=02be25838b644c4724d5ee2c1fc4624033add0a8 -md5=7426924584aa10266cfcadc82b4610bf -cksum=4095791850 +sha1=788c11623bc9998037121d8818b9f99d86a49937 +md5=648b6c8f563908376ccbb49cf14921b9 +cksum=3428322235 diff --git a/build/pkgs/eclib/package-version.txt b/build/pkgs/eclib/package-version.txt index e00be59d1df..2a0fb1f6404 100644 --- a/build/pkgs/eclib/package-version.txt +++ b/build/pkgs/eclib/package-version.txt @@ -1 +1 @@ -20180815 +20190226 diff --git a/build/pkgs/flint/spkg-install b/build/pkgs/flint/spkg-install index 89fd26f5439..f36f749ef33 100644 --- a/build/pkgs/flint/spkg-install +++ b/build/pkgs/flint/spkg-install @@ -3,13 +3,6 @@ # FLINT Sage install script # ############################################################################### - -if [ "$SAGE_LOCAL" = "" ]; then - echo >&2 "Error: SAGE_LOCAL undefined - exiting..." - echo >&2 "Maybe run 'sage -sh'?" - exit 1 -fi - if [ "$SAGE_DEBUG" = "yes" ]; then echo "Building a debug version of FLINT." CFLAGS="-O0 -g $CFLAGS"; export CFLAGS @@ -26,26 +19,12 @@ echo "Configuring FLINT." --with-gmp="$SAGE_LOCAL" \ --with-mpfr="$SAGE_LOCAL" \ --with-ntl="$SAGE_LOCAL" \ - $FLINT_CONFIGURE -if [ $? -ne 0 ]; then - echo >&2 "Error: Failed to configure FLINT." - exit 1 -fi + $FLINT_CONFIGURE || sdh_die "Error: Failed to configure FLINT." -echo "Building FLINT shared library." -$MAKE verbose -if [ $? -ne 0 ]; then - echo >&2 "Error: Failed to build FLINT shared library." - exit 1 -fi +sdh_make verbose echo "Deleting old FLINT files." rm -f $SAGE_LOCAL/lib/libflint* rm -rf $SAGE_LOCAL/include/flint -echo "Installing new FLINT files." -$MAKE install -if [ $? -ne 0 ]; then - echo >&2 "Error: Failed to install FLINT." - exit 1 -fi +sdh_make_install diff --git a/build/pkgs/fpylll/patches/cython3.patch b/build/pkgs/fpylll/patches/cython3.patch new file mode 100644 index 00000000000..844a8999c0c --- /dev/null +++ b/build/pkgs/fpylll/patches/cython3.patch @@ -0,0 +1,25 @@ +From 28e5fcaeabe26d46167e75815e0d9a4fdfa1a973 Mon Sep 17 00:00:00 2001 +From: "Martin R. Albrecht" +Date: Wed, 5 Dec 2018 11:47:33 +0000 +Subject: [PATCH] set language_version + +fixes #127 +--- + setup.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/setup.py b/setup.py +index 8f916a9..a5125f8 100755 +--- a/setup.py ++++ b/setup.py +@@ -110,7 +110,9 @@ def run(self): + self.extensions, + include_path=["src"], + build_dir=self.cythonize_dir, +- compiler_directives={'binding': True, "embedsignature": True}) ++ compiler_directives={'binding': True, ++ 'embedsignature': True, ++ 'language_level': 2}) + super(build_ext, self).run() + + def _generate_config_pxi(self): diff --git a/build/pkgs/freetype/SPKG.txt b/build/pkgs/freetype/SPKG.txt index 5b74f50b7f7..5c0cc067e8c 100644 --- a/build/pkgs/freetype/SPKG.txt +++ b/build/pkgs/freetype/SPKG.txt @@ -1,8 +1,53 @@ += FreeType = + +== Description == + +From the documentation: + +> FreeType is a software font engine that is designed to be small, +> efficient, highly customizable, and portable while capable of +> producing high-quality output (glyph images). It can be used in +> graphics libraries, display servers, font conversion tools, +> text image generation tools, and many other products as well. + +> Note that FreeType is a font service and doesn't provide APIs to +> perform higher-level features like text layout or graphics processing +> (e.g., colored text rendering, ‘hollowing’, etc.). However, it greatly +> simplifies these tasks by providing a simple, easy to use, and uniform +> interface to access the content of font files. + +> Please note that ‘FreeType’ is also called ‘FreeType 2’, to +> distinguish it from the old, deprecated ‘FreeType 1’ library, +> a predecessor no longer maintained and supported. + +The package in Sage is called freetype (in lowercase). + == License == - * FreeType License + + * FreeType (BSD-like) + * GNU Public License v2 + +From the documentation: + +> FreeType is released under two open-source licenses: our own BSD-like +> FreeType License and the GNU Public License, Version 2. It can thus +> be used by any kind of projects, be they proprietary or not. + +== Upstream Contact == + + * home: https://www.freetype.org + * repo: + * official: http://git.savannah.gnu.org/cgit/freetype + * mirror: https://github.com/aseprite/freetype2/ + +== Dependencies == + +See the `dependencies` file. == Releases == +Old changes are listed below. For more recent history, see the git repository. + === freetype-2.5.2.p0 (Emmanuel Charpentier, December 21st 2013) === * #15561: mindless drop-in-place of the current upstream source. * Added the license information in the present file. diff --git a/build/pkgs/freetype/checksums.ini b/build/pkgs/freetype/checksums.ini index cf5055a4136..0914871d825 100644 --- a/build/pkgs/freetype/checksums.ini +++ b/build/pkgs/freetype/checksums.ini @@ -1,4 +1,4 @@ tarball=freetype-VERSION.tar.bz2 -sha1=417bb3747c4ac95b6f2652024a53fad45581fa1c -md5=bf0a210b6fe781228fa0e4a80691a521 -cksum=3520428758 +sha1=220c82062171c513e4017c523d196933c9de4a7d +md5=60ef7d8160cd4bf8cb118ee9d65367ca +cksum=1149809609 diff --git a/build/pkgs/freetype/package-version.txt b/build/pkgs/freetype/package-version.txt index 08b83b2d761..dedcc7d4335 100644 --- a/build/pkgs/freetype/package-version.txt +++ b/build/pkgs/freetype/package-version.txt @@ -1 +1 @@ -2.8.1.p0 +2.9.1 diff --git a/build/pkgs/freetype/spkg-install b/build/pkgs/freetype/spkg-install index 49450d49442..1c33c68b4ef 100644 --- a/build/pkgs/freetype/spkg-install +++ b/build/pkgs/freetype/spkg-install @@ -1,7 +1,7 @@ cd src -# Disabling harfbuzz until upstream properly check for suitable version -GNUMAKE=${MAKE} sdh_configure --with-harfbuzz=no +# Enable the now-deprecated `freetype-config` +GNUMAKE=${MAKE} sdh_configure --enable-freetype-config sdh_make sdh_make_install diff --git a/build/pkgs/fricas/SPKG.txt b/build/pkgs/fricas/SPKG.txt index 83b35656b3e..753f7318252 100644 --- a/build/pkgs/fricas/SPKG.txt +++ b/build/pkgs/fricas/SPKG.txt @@ -2,7 +2,7 @@ == Description == -This package install the software fricas. +FriCAS is a general purpose computer algebra system. == License == @@ -16,6 +16,4 @@ http://fricas.sourceforge.net/ * ecl -== Special Update/Build Instructions == - * uffi.patch: see #21209 for details. diff --git a/build/pkgs/fricas/checksums.ini b/build/pkgs/fricas/checksums.ini index 7bf2a48471b..365c1519331 100644 --- a/build/pkgs/fricas/checksums.ini +++ b/build/pkgs/fricas/checksums.ini @@ -1,4 +1,4 @@ tarball=fricas-VERSION-full.tar.bz2 -sha1=8fc3e850a9890eac21cd9f391dd58000b3537067 -md5=0d3af65758ce93b1cc52c2511e73e674 -cksum=1048748907 +sha1=5bcf66349eda3c6c34d0290892adf4d9e25ece78 +md5=bcf371708f1455f92dcf9c596f807ba5 +cksum=1340692645 diff --git a/build/pkgs/fricas/package-version.txt b/build/pkgs/fricas/package-version.txt index 1892b926767..80e78df6830 100644 --- a/build/pkgs/fricas/package-version.txt +++ b/build/pkgs/fricas/package-version.txt @@ -1 +1 @@ -1.3.2 +1.3.5 diff --git a/build/pkgs/fricas/spkg-install b/build/pkgs/fricas/spkg-install index f1c8cf5e756..df98bfdb00f 100644 --- a/build/pkgs/fricas/spkg-install +++ b/build/pkgs/fricas/spkg-install @@ -3,22 +3,6 @@ cd src # Use newer version of config.guess and config.sub (see Trac #23847) cp "$SAGE_ROOT"/config/config.* config -./configure --prefix="$SAGE_LOCAL" \ - --libdir="$SAGE_LOCAL/lib" \ - --with-lisp=ecl -if [ $? -ne 0 ]; then - echo >&2 "Error configuring fricas." - exit 1 -fi - -$MAKE -if [ $? -ne 0 ]; then - echo >&2 "Error building fricas." - exit 1 -fi - -$MAKE -j1 install -if [ $? -ne 0 ]; then - echo >&2 "Error installing fricas." - exit 1 -fi +sdh_configure --with-lisp=ecl +sdh_make +sdh_make_install -j1 diff --git a/build/pkgs/future/checksums.ini b/build/pkgs/future/checksums.ini index 56f5d18954e..2e6dd115e6c 100644 --- a/build/pkgs/future/checksums.ini +++ b/build/pkgs/future/checksums.ini @@ -1,4 +1,4 @@ tarball=future-VERSION.tar.gz -sha1=86ed881acef874d04576b9df03c29d25ad2cd25f -md5=3e8e88a2bda48d54b1da7634d04760d7 -cksum=1475858329 +sha1=7abd068d09c637f4fa5fb2df3d90cc9607523aee +md5=e42113b4b72fabb5273ff88417104913 +cksum=2947769885 diff --git a/build/pkgs/future/package-version.txt b/build/pkgs/future/package-version.txt index 04a373efe6b..7cca7711a0d 100644 --- a/build/pkgs/future/package-version.txt +++ b/build/pkgs/future/package-version.txt @@ -1 +1 @@ -0.16.0 +0.17.1 diff --git a/build/pkgs/gap/package-version.txt b/build/pkgs/gap/package-version.txt index 2da4316236a..51a04e6c925 100644 --- a/build/pkgs/gap/package-version.txt +++ b/build/pkgs/gap/package-version.txt @@ -1 +1 @@ -4.10.0 +4.10.0.p0 diff --git a/build/pkgs/gap/patches/0004-Don-t-set-SyAllocPool-0-for-Cygwin-but-do-use-MAP_NO.patch b/build/pkgs/gap/patches/0004-Don-t-set-SyAllocPool-0-for-Cygwin-but-do-use-MAP_NO.patch new file mode 100644 index 00000000000..262f16f68ad --- /dev/null +++ b/build/pkgs/gap/patches/0004-Don-t-set-SyAllocPool-0-for-Cygwin-but-do-use-MAP_NO.patch @@ -0,0 +1,78 @@ +From 78506f0a4fba05a238ec6e752c6d3cf2c8336bc8 Mon Sep 17 00:00:00 2001 +From: "Erik M. Bray" +Date: Tue, 26 Feb 2019 13:26:11 +0100 +Subject: [PATCH] Don't set SyAllocPool = 0 for Cygwin, but do use + MAP_NORESERVE for mmaps on Cygwin + +Using MAP_NORESERVE on Cygwin prevents the need to commit physical pages +for the entirety of mmap'd regions until they are actually used. +--- + src/sysmem.c | 16 +++++++++++----- + src/system.c | 4 ---- + 2 files changed, 11 insertions(+), 9 deletions(-) + +diff --git a/src/sysmem.c b/src/sysmem.c +index 68a397b2f..995765828 100644 +--- a/src/sysmem.c ++++ b/src/sysmem.c +@@ -282,6 +282,12 @@ int SyTryToIncreasePool(void) + #define MAP_ANONYMOUS MAP_ANON + #endif + ++#ifdef SYS_IS_CYGWIN32 ++#define GAP_MMAP_FLAGS MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE ++#else ++#define GAP_MMAP_FLAGS MAP_PRIVATE|MAP_ANONYMOUS ++#endif ++ + static void *SyMMapStart = NULL; /* Start of mmap'ed region for POOL */ + static void *SyMMapEnd; /* End of mmap'ed region for POOL */ + static void *SyMMapAdvised; /* We have already advised about non-usage +@@ -342,15 +348,15 @@ void *SyAnonMMap(size_t size) { + size = SyRoundUpToPagesize(size); + #ifdef SYS_IS_64_BIT + /* The following is at 16 Terabyte: */ +- result = mmap((void *) (16L*1024*1024*1024*1024), size, +- PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); ++ result = mmap((void *) (16L*1024*1024*1024*1024), size, ++ PROT_READ|PROT_WRITE, GAP_MMAP_FLAGS, -1, 0); + if (result == MAP_FAILED) { + result = mmap(NULL, size, PROT_READ|PROT_WRITE, +- MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); ++ GAP_MMAP_FLAGS, -1, 0); + } + #else + result = mmap(NULL, size, PROT_READ|PROT_WRITE, +- MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); ++ GAP_MMAP_FLAGS, -1, 0); + #endif + if (result == MAP_FAILED) + result = NULL; +@@ -371,7 +377,7 @@ int SyTryToIncreasePool(void) + size = (Int) SyMMapEnd - (Int) SyMMapStart; + newchunk = SyRoundUpToPagesize(size/2); + result = mmap(SyMMapEnd, newchunk, PROT_READ|PROT_WRITE, +- MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); ++ GAP_MMAP_FLAGS, -1, 0); + if (result == MAP_FAILED) return -1; + if (result != SyMMapEnd) { + munmap(result,newchunk); +diff --git a/src/system.c b/src/system.c +index 7423d76bc..6f4c03517 100644 +--- a/src/system.c ++++ b/src/system.c +@@ -1133,11 +1133,7 @@ void InitSystem ( + #else + SyStorMin = 64 * 1024L; + SyStorMax = 1024*1024L; /* This is in kB! */ +-#ifdef SYS_IS_CYGWIN32 +- SyAllocPool = 0; /* works better on cygwin */ +-#else + SyAllocPool = 1536L*1024*1024; /* Note this is in bytes! */ +-#endif + #endif + SyStorOverrun = 0; + SyStorKill = 0; +-- +2.15.1 + diff --git a/build/pkgs/gap/spkg-install b/build/pkgs/gap/spkg-install index d181772304d..47008b29f11 100644 --- a/build/pkgs/gap/spkg-install +++ b/build/pkgs/gap/spkg-install @@ -4,7 +4,9 @@ cd src +GAP_BUILD_ROOT="$(pwd)" GAP_ROOT="$SAGE_LOCAL/share/gap" +DESTDIR_GAP_ROOT="$SAGE_DESTDIR$GAP_ROOT" # Enable debug info if requested. # Note that -g3 allows you to use preprocessor macros in gdb which are widely used @@ -43,6 +45,10 @@ mkdir -p "$SAGE_DESTDIR$SAGE_BIN" || sdh_die "Failed to create the directory $SA # GAP_ROOT; we don't need everything from the source tree sdh_install bin doc gen grp lib src tst sysinfo.gap "$GAP_ROOT" +# GAP's copy of libtool is also used by the toolchain for build GAP packages +# (i.e. by gac) +sdh_install libtool "$GAP_ROOT" + # Install only the minimal packages GAP needs to run sdh_install pkg/GAPDoc-* pkg/primgrp-* pkg/SmallGrp-* pkg/transgrp "$GAP_ROOT"/pkg @@ -76,16 +82,28 @@ chmod +x "$SAGE_DESTDIR$SAGE_BIN/gap" # Create symlinks under $GAP_ROOT for these executables, as they are expected # (especially when building kernel packages) to exist -ln -sf "$SAGE_BIN/gap-bin" "$SAGE_DESTDIR$GAP_ROOT/gap" -ln -sf "$SAGE_BIN/gac" "$SAGE_DESTDIR$GAP_ROOT/gac" +ln -sf "$SAGE_BIN/gap-bin" "$DESTDIR_GAP_ROOT/gap" +ln -sf "$SAGE_BIN/gac" "$DESTDIR_GAP_ROOT/gac" # Fix the $GAP_ROOT/bin//src symlink to be relative (otherwise it links # to the actual path of the sources GAP was compiled from) -for srclink in "$SAGE_DESTDIR$GAP_ROOT"/bin/*/src; do +for srclink in "$DESTDIR_GAP_ROOT"/bin/*/src; do rm -f "$srclink" ln -s "../../src" "$srclink" done +# Additional fixups for some files after they have been copied into their +# destination directory. gac and sysinfo.gap are generated files that contain +# in them hard-coded references to the GAP build directory, which will soon +# be going away. This breaks the build toolchain for some compiled GAP +# packages. We need to replace these paths with the final GAP_ROOT path. The +# below will work so long as neither of these paths contain '|', and if they do +# then god help you. https://trac.sagemath.org/ticket/27218 +sed -i -e "s|$GAP_BUILD_ROOT|$GAP_ROOT|g" \ + "$SAGE_DESTDIR$SAGE_BIN/gac" "$DESTDIR_GAP_ROOT/sysinfo.gap" \ + "$DESTDIR_GAP_ROOT/bin/gap.sh" "$DESTDIR_GAP_ROOT/doc/make_doc" || \ + sdh_die "Failed to fix up hard-coded paths in GAP build tools." + # TODO: This seems unnecessary--we are already installing all of doc/ to # GAP_ROOT, which is necessary for some functionality in GAP to work. Do # we need this? Maybe doc/gap could just be a symlink to gap/doc?? diff --git a/build/pkgs/gap/spkg-legacy-uninstall b/build/pkgs/gap/spkg-legacy-uninstall index e7416d3cf0e..d379c7e1e60 100644 --- a/build/pkgs/gap/spkg-legacy-uninstall +++ b/build/pkgs/gap/spkg-legacy-uninstall @@ -1,5 +1,6 @@ # Remove existing GAP 4.x install(s) rm -rf "$SAGE_LOCAL/gap/gap-4."* +rm -rf "$SAGE_SHARE/gap" rm -f "$SAGE_LOCAL/gap/latest" rm -f "$SAGE_LOCAL/bin/gap" diff --git a/build/pkgs/gap_packages/package-version.txt b/build/pkgs/gap_packages/package-version.txt index 2da4316236a..51a04e6c925 100644 --- a/build/pkgs/gap_packages/package-version.txt +++ b/build/pkgs/gap_packages/package-version.txt @@ -1 +1 @@ -4.10.0 +4.10.0.p0 diff --git a/build/pkgs/gap_packages/spkg-install b/build/pkgs/gap_packages/spkg-install index 1a3e8c54381..d8260b9aa08 100644 --- a/build/pkgs/gap_packages/spkg-install +++ b/build/pkgs/gap_packages/spkg-install @@ -43,7 +43,7 @@ install_compiled_pkg() local pkg="$1" # Install the bin/ dir (where compiled modules should end up) # under /lib/gap; we then symlink to it later - sdh_install bin/ "$SAGE_LOCAL/lib/gap/pkg/$pkg" + sdh_install bin "$SAGE_LOCAL/lib/gap/pkg/$pkg" # Clean up any build artificts before installing the rest of the package # Also remove configure/Makefiles @@ -63,7 +63,7 @@ install_compiled_pkg() # # These packages have an old ./configure that take the GAP_ROOT as a positional # argument -for pkg in cohomolo-* grape-* guava-* +for pkg in cohomolo-* crypting-* grape-* guava-* do echo "Building GAP package $pkg" cd "$PKG_SRC_DIR/$pkg" @@ -73,9 +73,10 @@ do cd "$PKG_SRC_DIR" done -# These packages (currently just one) have a new-style autoconf ./configure +# These packages have a new-style autoconf ./configure # that takes --with-gaproot -for pkg in nq-* + +for pkg in nq-* io-* do cd "$PKG_SRC_DIR/$pkg" sdh_configure --with-gaproot="$GAP_ROOT" diff --git a/build/pkgs/gcc/build-gcc b/build/pkgs/gcc/build-gcc new file mode 100755 index 00000000000..173d17822d1 --- /dev/null +++ b/build/pkgs/gcc/build-gcc @@ -0,0 +1,66 @@ +#!/bin/bash +# +# Wrapper script for building GCC used for both the gcc and gfortran SPKGs +# Usage: +# +# build-gcc [CONFIGURE_FLAGS ...] +# +# Where all positional arguments are passed as additional arguments to GCC's +# configure script. +set -e + +# Build in a separate directory, not in src/ (a.k.a. a VPATH build). +# This is the recommended way to build GCC. +mkdir -p gcc-build +cd gcc-build + +GCC_CONFIGURE="$@ $GCC_CONFIGURE" + +# On OSX: +if [ "$UNAME" = "Darwin" ]; then + # isl/cloog libraries are almost certainly from Homebrew and won't work + GCC_CONFIGURE="--without-isl --without-cloog $GCC_CONFIGURE" + + # Use 'bootstrap-debug' build configuration to force stripping of object + # files prior to comparison during bootstrap (broken by Xcode 6.3). + # See #18156 + GCC_CONFIGURE="--with-build-config=bootstrap-debug $GCC_CONFIGURE" +fi + +# Let Gfortran build on Raspberry Pi using hard floats. +if [ `uname -m` = "armv6l" ]; then + GCC_CONFIGURE="--with-arch=armv6 --with-fpu=vfp --with-float=hard $GCC_CONFIGURE" +fi + +# Let Gfortran build on more recent ARM boards using hard floats. +if [ `uname -m` = "armv7l" ]; then + GCC_CONFIGURE="--with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard $GCC_CONFIGURE" +fi + +if [ "$SAGE_CHECK" = yes ]; then + # Enable internal checks in GCC. These checks do not affect the + # binaries produced by GCC, but they do increase the compile time + # of everything compiled with GCC. + GCC_CONFIGURE="$GCC_CONFIGURE --enable-checking=yes" +fi + +# Use the assembler/linker specified by $AS/$LD if they differ from the +# default. +if [ -n "$AS" -a "$AS" != "as" ]; then + CONFIGURE_AS="--with-as=$AS" +fi +if [ -n "$LD" -a "$LD" != "ld" ]; then + CONFIGURE_LD="--with-ld=$LD" +fi + +../src/configure \ + --prefix="$SAGE_LOCAL" \ + --with-local-prefix="$SAGE_LOCAL" \ + --with-gmp="$SAGE_LOCAL" --with-mpfr="$SAGE_LOCAL" --with-mpc="$SAGE_LOCAL" \ + --with-system-zlib \ + --disable-multilib \ + --disable-nls \ + --disable-libitm \ + $GCC_CONFIGURE "$CONFIGURE_AS" "$CONFIGURE_LD" + +sdh_make BOOT_LDFLAGS="-Wl,-rpath,$SAGE_LOCAL/lib" diff --git a/build/pkgs/gcc/patches/gcc-multilib-multiarch.patch b/build/pkgs/gcc/patches/gcc-multilib-multiarch.patch new file mode 100644 index 00000000000..9a9a63bf41a --- /dev/null +++ b/build/pkgs/gcc/patches/gcc-multilib-multiarch.patch @@ -0,0 +1,120 @@ +On 64-bit Linux target systems, install 64-bit libraries to ${prefix}/lib +instead of ${prefix}/lib64 + +Adapted to GCC 7.2.0 from Debian's patch at: + +https://salsa.debian.org/toolchain-team/gcc/blob/988272d6dcf649c1d6018763d1ee4b4df191d607/debian/patches/gcc-multilib-multiarch.diff +diff --git a/gcc/config/i386/t-linux64 b/gcc/config/i386/t-linux64 +index e422c44..f7d946b 100644 +--- a/gcc/config/i386/t-linux64 ++++ b/gcc/config/i386/t-linux64 +@@ -33,6 +33,16 @@ + comma=, + MULTILIB_OPTIONS = $(subst $(comma),/,$(TM_MULTILIB_CONFIG)) + MULTILIB_DIRNAMES = $(patsubst m%, %, $(subst /, ,$(MULTILIB_OPTIONS))) ++ifneq (,$(findstring gnux32,$(target))) + MULTILIB_OSDIRNAMES = m64=../lib64$(call if_multiarch,:x86_64-linux-gnu) +-MULTILIB_OSDIRNAMES+= m32=$(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib)$(call if_multiarch,:i386-linux-gnu) ++MULTILIB_OSDIRNAMES+= m32=../lib32$(call if_multiarch,:i386-linux-gnu) ++MULTILIB_OSDIRNAMES+= mx32=../lib$(call if_multiarch,:x86_64-linux-gnux32) ++else ifneq (,$(findstring x86_64,$(target))) ++MULTILIB_OSDIRNAMES = m64=../lib$(call if_multiarch,:x86_64-linux-gnu) ++MULTILIB_OSDIRNAMES+= m32=../lib32$(call if_multiarch,:i386-linux-gnu) + MULTILIB_OSDIRNAMES+= mx32=../libx32$(call if_multiarch,:x86_64-linux-gnux32) ++else ++MULTILIB_OSDIRNAMES = m64=../lib64$(call if_multiarch,:x86_64-linux-gnu) ++MULTILIB_OSDIRNAMES+= m32=../lib$(call if_multiarch,:i386-linux-gnu) ++MULTILIB_OSDIRNAMES+= mx32=../libx32$(call if_multiarch,:x86_64-linux-gnux32) ++endif +diff --git a/gcc/config/mips/t-linux64 b/gcc/config/mips/t-linux64 +index 100f9da..d981884 100644 +--- a/gcc/config/mips/t-linux64 ++++ b/gcc/config/mips/t-linux64 +@@ -20,7 +20,20 @@ MULTILIB_OPTIONS = mabi=n32/mabi=32/mabi=64 + MULTILIB_DIRNAMES = n32 32 64 + MIPS_EL = $(if $(filter %el, $(firstword $(subst -, ,$(target)))),el) + MIPS_SOFT = $(if $(strip $(filter MASK_SOFT_FLOAT_ABI, $(target_cpu_default)) $(filter soft, $(with_float))),soft) ++ ++ifneq (,$(findstring gnuabi64,$(target))) ++MULTILIB_OSDIRNAMES = \ ++ ../lib32$(call if_multiarch,:mips$(MIPS_ISA)64$(MIPS_R6)$(MIPS_EL)-linux-gnuabin32$(MIPS_SOFT)) \ ++ ../libo32$(call if_multiarch,:mips$(MIPS_ISA)$(MIPS_32)$(MIPS_R6)$(MIPS_EL)-linux-gnu$(MIPS_SOFT)) \ ++ ../lib$(call if_multiarch,:mips$(MIPS_ISA)64$(MIPS_R6)$(MIPS_EL)-linux-gnuabi64$(MIPS_SOFT)) ++else ifneq (,$(findstring gnuabin32,$(target))) ++MULTILIB_OSDIRNAMES = \ ++ ../lib$(call if_multiarch,:mips$(MIPS_ISA)64$(MIPS_R6)$(MIPS_EL)-linux-gnuabin32$(MIPS_SOFT)) \ ++ ../libo32$(call if_multiarch,:mips$(MIPS_ISA)$(MIPS_32)$(MIPS_R6)$(MIPS_EL)-linux-gnu$(MIPS_SOFT)) \ ++ ../lib64$(call if_multiarch,:mips$(MIPS_ISA)64$(MIPS_R6)$(MIPS_EL)-linux-gnuabi64$(MIPS_SOFT)) ++else + MULTILIB_OSDIRNAMES = \ +- ../lib32$(call if_multiarch,:mips64$(MIPS_EL)-linux-gnuabin32$(MIPS_SOFT)) \ +- ../lib$(call if_multiarch,:mips$(MIPS_EL)-linux-gnu$(MIPS_SOFT)) \ +- ../lib64$(call if_multiarch,:mips64$(MIPS_EL)-linux-gnuabi64$(MIPS_SOFT)) ++ ../lib32$(call if_multiarch,:mips$(MIPS_ISA)64$(MIPS_R6)$(MIPS_EL)-linux-gnuabin32$(MIPS_SOFT)) \ ++ ../lib$(call if_multiarch,:mips$(MIPS_ISA)$(MIPS_32)$(MIPS_R6)$(MIPS_EL)-linux-gnu$(MIPS_SOFT)) \ ++ ../lib64$(call if_multiarch,:mips$(MIPS_ISA)64$(MIPS_R6)$(MIPS_EL)-linux-gnuabi64$(MIPS_SOFT)) ++endif +diff --git a/gcc/config/rs6000/t-linux b/gcc/config/rs6000/t-linux +index 4cb63bd..c058471 100644 +--- a/gcc/config/rs6000/t-linux ++++ b/gcc/config/rs6000/t-linux +@@ -2,7 +2,7 @@ + # or soft-float. + ifeq (,$(filter $(with_cpu),$(SOFT_FLOAT_CPUS))$(findstring soft,$(with_float))) + ifneq (,$(findstring powerpc64,$(target))) +-MULTILIB_OSDIRNAMES := .=../lib64$(call if_multiarch,:powerpc64-linux-gnu) ++MULTILIB_OSDIRNAMES := .=../lib$(call if_multiarch,:powerpc64-linux-gnu) + else + ifneq (,$(findstring spe,$(target))) + MULTIARCH_DIRNAME := powerpc-linux-gnuspe$(if $(findstring 8548,$(with_cpu)),,v1) +diff --git a/gcc/config/rs6000/t-linux64 b/gcc/config/rs6000/t-linux64 +index 2830ed0..5a3ccb5 100644 +--- a/gcc/config/rs6000/t-linux64 ++++ b/gcc/config/rs6000/t-linux64 +@@ -28,8 +28,13 @@ + MULTILIB_OPTIONS := m64/m32 + MULTILIB_DIRNAMES := 64 32 + MULTILIB_EXTRA_OPTS := ++ifneq (,$(findstring powerpc64,$(target))) ++MULTILIB_OSDIRNAMES := m64=../lib$(call if_multiarch,:powerpc64-linux-gnu) ++MULTILIB_OSDIRNAMES += m32=../lib32$(call if_multiarch,:powerpc-linux-gnu) ++else + MULTILIB_OSDIRNAMES := m64=../lib64$(call if_multiarch,:powerpc64-linux-gnu) +-MULTILIB_OSDIRNAMES += m32=$(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib)$(call if_multiarch,:powerpc-linux-gnu) ++MULTILIB_OSDIRNAMES += m32=../lib$(call if_multiarch,:powerpc-linux-gnu) ++endif + + rs6000-linux.o: $(srcdir)/config/rs6000/rs6000-linux.c + $(COMPILE) $< +diff --git a/gcc/config/s390/t-linux64 b/gcc/config/s390/t-linux64 +index cc6ab36..677219e 100644 +--- a/gcc/config/s390/t-linux64 ++++ b/gcc/config/s390/t-linux64 +@@ -7,5 +7,10 @@ + + MULTILIB_OPTIONS = m64/m31 + MULTILIB_DIRNAMES = 64 32 ++ifneq (,$(findstring s390x,$(target))) ++MULTILIB_OSDIRNAMES = ../lib$(call if_multiarch,:s390x-linux-gnu) ++MULTILIB_OSDIRNAMES += ../lib32$(call if_multiarch,:s390-linux-gnu) ++else + MULTILIB_OSDIRNAMES = ../lib64$(call if_multiarch,:s390x-linux-gnu) +-MULTILIB_OSDIRNAMES += $(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib)$(call if_multiarch,:s390-linux-gnu) ++MULTILIB_OSDIRNAMES += ../lib$(call if_multiarch,:s390-linux-gnu) ++endif +diff --git a/gcc/config/sparc/t-linux64 b/gcc/config/sparc/t-linux64 +index 7511c38..6c59863 100644 +--- a/gcc/config/sparc/t-linux64 ++++ b/gcc/config/sparc/t-linux64 +@@ -25,5 +25,10 @@ + + MULTILIB_OPTIONS = m64/m32 + MULTILIB_DIRNAMES = 64 32 ++ifneq (,$(findstring sparc64,$(target))) ++MULTILIB_OSDIRNAMES = ../lib$(call if_multiarch,:sparc64-linux-gnu) ++MULTILIB_OSDIRNAMES += ../lib32$(call if_multiarch,:sparc-linux-gnu) ++else + MULTILIB_OSDIRNAMES = ../lib64$(call if_multiarch,:sparc64-linux-gnu) +-MULTILIB_OSDIRNAMES += $(if $(wildcard $(shell echo $(SYSTEM_HEADER_DIR))/../../usr/lib32),../lib32,../lib)$(call if_multiarch,:sparc-linux-gnu) ++MULTILIB_OSDIRNAMES += ../lib$(call if_multiarch,:sparc-linux-gnu) ++endif diff --git a/build/pkgs/gcc/spkg-build b/build/pkgs/gcc/spkg-build new file mode 100644 index 00000000000..48008172c92 --- /dev/null +++ b/build/pkgs/gcc/spkg-build @@ -0,0 +1,62 @@ +# Exit on error +set -e + +# The ld (linker) on old Darwin systems doesn't understand +# -compatibility_version, it needs -dylib_compatibility_version. +# Similarly for a few more options. We create an ld wrapper to fix +# these command line options. +if { uname -sr | grep 'Darwin [0-9]\.' ;} &>/dev/null; then + mkdir -p bin/ + LD=`which "${LD:-ld}"` + + echo '#!/bin/bash' >>"bin/ld" + echo '# ld wrapper generated by the GCC spkg' >>"bin/ld" + echo >>"bin/ld" + # Hardcode the path to the "real" ld. + echo "LD=$LD" >>"bin/ld" + +cat >>"bin/ld" <<'EOF' + +for arg in "$@"; do + arg=`echo "$arg" | sed \ + -e 's/^-\(compatibility_version\)/-dylib_\1/' \ + -e 's/^-\(current_version\)/-dylib_\1/' \ + -e 's/^-\(install_name\)/-dylib_\1/' \ + ` + argv=("${argv[@]}" "$arg") +done + +exec "$LD" "${argv[@]}" +EOF + + chmod +x "bin/ld" + + # Make GCC use this ld wrapper (found in the $PATH) + export LD=ld + export PATH="$(pwd)/bin:$PATH" +fi + +# On OS X 10.9, g++ and the cdefs.h header are currently incompatible +# Temporary workaround posted at http://trac.macports.org/ticket/41033 +if { uname -sr | grep 'Darwin 13\.' ;} &>/dev/null; then + mkdir -p "include/sys" + sed 's+defined(__GNUC_STDC_INLINE__)+& \&\& !defined(__cplusplus)+' /usr/include/sys/cdefs.h > "include/sys/cdefs.h" +fi + +# On OS X 10.10 there is random ObjC stuff in a C header +if { uname -sr | grep 'Darwin 14\.' ;} &>/dev/null; then + if [ -f /usr/include/dispatch/object.h ]; then + mkdir -p "include/dispatch" + sed 's+typedef void (\^dispatch_block_t)(void)+typedef void* dispatch_block_t+' \ + /usr/include/dispatch/object.h > "include/dispatch/object.h" + else + echo "Warning: header /usr/include/dispatch/object.h not found, not applying fix." + fi +fi + +# If we wrote any custom headers, make sure to include them on CPATH +if [ -d include ]; then + export CPATH="$(pwd)/include:$CPATH" +fi + +./build-gcc --enable-languages=c,c++,fortran diff --git a/build/pkgs/gcc/spkg-configure.m4 b/build/pkgs/gcc/spkg-configure.m4 index 24362087ff6..330fd3f7ab8 100644 --- a/build/pkgs/gcc/spkg-configure.m4 +++ b/build/pkgs/gcc/spkg-configure.m4 @@ -98,6 +98,7 @@ SAGE_SPKG_CONFIGURE([gcc], [ if test $HAVE_CXX11 != 1; then SAGE_MUST_INSTALL_GCC([your C++ compiler does not support C++11]) fi + AC_SUBST(CXX) AC_LANG_PUSH(C) if test -z "$CC"; then diff --git a/build/pkgs/gcc/spkg-install b/build/pkgs/gcc/spkg-install index c226e5a0553..3226983eb50 100644 --- a/build/pkgs/gcc/spkg-install +++ b/build/pkgs/gcc/spkg-install @@ -1,134 +1,11 @@ -if [ -z "$SAGE_LOCAL" ]; then - echo >&2 "SAGE_LOCAL undefined ... exiting" - echo >&2 "Maybe run 'sage --sh'?" - exit 1 -fi - -# Apply fixes to upstream source -cd src - -# Exit on error -set -e - -# Build in a separate directory, not in src/ (a.k.a. a VPATH build). -# This is the recommended way to build GCC. -cd .. -mkdir gcc-build -cd gcc-build - - -# The ld (linker) on old Darwin systems doesn't understand -# -compatibility_version, it needs -dylib_compatibility_version. -# Similarly for a few more options. We create an ld wrapper to fix -# these command line options. -if { uname -sr | grep 'Darwin [0-9]\.' ;} &>/dev/null; then - rm -f "$SAGE_LOCAL/bin/ld" - LD=`which "${LD:-ld}"` - - echo '#!/bin/bash' >>"$SAGE_LOCAL/bin/ld" - echo '# ld wrapper generated by the GCC spkg' >>"$SAGE_LOCAL/bin/ld" - echo >>"$SAGE_LOCAL/bin/ld" - # Hardcode the path to the "real" ld. - echo "LD=$LD" >>"$SAGE_LOCAL/bin/ld" - -cat >>"$SAGE_LOCAL/bin/ld" <<'EOF' - -for arg in "$@"; do - arg=`echo "$arg" | sed \ - -e 's/^-\(compatibility_version\)/-dylib_\1/' \ - -e 's/^-\(current_version\)/-dylib_\1/' \ - -e 's/^-\(install_name\)/-dylib_\1/' \ - ` - argv=("${argv[@]}" "$arg") -done - -exec "$LD" "${argv[@]}" -EOF - - chmod +x "$SAGE_LOCAL/bin/ld" - - # Make GCC use this ld wrapper (found in the $PATH) - export LD=ld -fi - -# On OS X 10.9, g++ and the cdefs.h header are currently incompatible -# Temporary workaround posted at http://trac.macports.org/ticket/41033 -if { uname -sr | grep 'Darwin 13\.' ;} &>/dev/null; then - mkdir -p "$SAGE_LOCAL/include/sys" - sed 's+defined(__GNUC_STDC_INLINE__)+& \&\& !defined(__cplusplus)+' /usr/include/sys/cdefs.h > "$SAGE_LOCAL/include/sys/cdefs.h" -fi - -# On OS X 10.10 there is random ObjC stuff in a C header -if { uname -sr | grep 'Darwin 14\.' ;} &>/dev/null; then - if [ -f /usr/include/dispatch/object.h ]; then - mkdir -p "$SAGE_LOCAL/include/dispatch" - sed 's+typedef void (\^dispatch_block_t)(void)+typedef void* dispatch_block_t+' \ - /usr/include/dispatch/object.h > "$SAGE_LOCAL/include/dispatch/object.h" - else - echo "Warning: header /usr/include/dispatch/object.h not found, not applying fix." +# First, install any custom binaries or headers we created for macOS +# workarounds +for dir in bin include; do + if [ -d $dir ]; then + sdh_install $dir/* "$SAGE_LOCAL/$dir" fi -fi - -# On OSX: -if [ "$UNAME" = "Darwin" ]; then - # isl/cloog libraries are almost certainly from Homebrew and won't work - GCC_CONFIGURE="--without-isl --without-cloog $GCC_CONFIGURE" - - # Use 'bootstrap-debug' build configuration to force stripping of object - # files prior to comparison during bootstrap (broken by Xcode 6.3). - # See #18156 - GCC_CONFIGURE="--with-build-config=bootstrap-debug $GCC_CONFIGURE" -fi - -# Let GCC build on Raspberry Pi using hard floats. -if [ `uname -m` = "armv6l" ]; then - GCC_CONFIGURE="--with-arch=armv6 --with-fpu=vfp --with-float=hard $GCC_CONFIGURE" -fi - -# Let GCC build on more recent ARM boards using hard floats. -if [ `uname -m` = "armv7l" ]; then - GCC_CONFIGURE="--with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard $GCC_CONFIGURE" -fi - -if [ "$SAGE_CHECK" = yes ]; then - # Enable internal checks in GCC. These checks do not affect the - # binaries produced by GCC, but they do increase the compile time - # of everything compiled with GCC. - GCC_CONFIGURE="$GCC_CONFIGURE --enable-checking=yes" -fi - -# Use the assembler/linker specified by $AS/$LD if they differ from the -# default. -if [ -n "$AS" -a "$AS" != "as" ]; then - CONFIGURE_AS="--with-as=$AS" -fi -if [ -n "$LD" -a "$LD" != "ld" ]; then - CONFIGURE_LD="--with-ld=$LD" -fi - -../src/configure \ - --prefix="$SAGE_LOCAL" \ - --with-local-prefix="$SAGE_LOCAL" \ - --with-gmp="$SAGE_LOCAL" --with-mpfr="$SAGE_LOCAL" --with-mpc="$SAGE_LOCAL" \ - --with-system-zlib \ - --disable-multilib \ - --disable-nls \ - --enable-languages=c,c++,fortran \ - --disable-libitm \ - $GCC_CONFIGURE "$CONFIGURE_AS" "$CONFIGURE_LD" - -$MAKE BOOT_LDFLAGS="-Wl,-rpath,$SAGE_LOCAL/lib" - -$MAKE install - - -# Force re-installation of gmp, mpir, mpfr and mpc with the GCC that we -# just built. This is needed in particular because gmp/mpir was first -# built without C++ support. Also mark gfortran as not installed in case -# somebody first built gfortran and then GCC. -cd "$SAGE_SPKG_INST" -rm -f gmp-* mpir-* mpfr-* mpc-* gfortran-* +done -# Force re-configuration: the next time that "make" is run, we need to -# rebuild all packages (#24703) but we should not rebuild gcc (#19324) -touch "$SAGE_ROOT/configure" +# Install gcc +cd gcc-build +sdh_make_install diff --git a/build/pkgs/gcc/spkg-postinst b/build/pkgs/gcc/spkg-postinst new file mode 100644 index 00000000000..f196d4cb372 --- /dev/null +++ b/build/pkgs/gcc/spkg-postinst @@ -0,0 +1,13 @@ +# Force re-installation of gmp, mpir, mpfr and mpc with the GCC that we +# just built. This is needed in particular because gmp/mpir was first +# built without C++ support. +# We do this without actually uninstalling the package files because they +# are still required for GCC to run and rebuild the packages. +sage-spkg-uninstall --keep-files gmp +sage-spkg-uninstall --keep-files mpir +sage-spkg-uninstall --keep-files mpfr +sage-spkg-uninstall --keep-files mpc + +# Force re-configuration: the next time that "make" is run, we need to rebuild +# all packages (#24703) but we should not rebuild gcc (#19324) +touch "$SAGE_ROOT/configure" diff --git a/build/pkgs/gcc/spkg-postrm b/build/pkgs/gcc/spkg-postrm new file mode 120000 index 00000000000..77b92c4927b --- /dev/null +++ b/build/pkgs/gcc/spkg-postrm @@ -0,0 +1 @@ +spkg-postinst \ No newline at end of file diff --git a/build/pkgs/gcc/spkg-preinst b/build/pkgs/gcc/spkg-preinst new file mode 100644 index 00000000000..c1701aee572 --- /dev/null +++ b/build/pkgs/gcc/spkg-preinst @@ -0,0 +1,3 @@ +# Force uninstallation of the gfortran package since it's superseded by this +# package (which includes gfortran implicitly) +sage-spkg-uninstall gfortran diff --git a/build/pkgs/gf2x/spkg-configure.m4 b/build/pkgs/gf2x/spkg-configure.m4 new file mode 100644 index 00000000000..d64181ad04b --- /dev/null +++ b/build/pkgs/gf2x/spkg-configure.m4 @@ -0,0 +1,25 @@ +SAGE_SPKG_CONFIGURE([gf2x], [ + AC_CHECK_HEADER(gf2x.h, [], [sage_spkg_install_gf2x=yes]) +dnl gf2x_mul_r appeared in version 1.1 of GF2X + AC_SEARCH_LIBS([gf2x_mul_r], [gf2x], [ + AC_MSG_CHECKING([for GF2X 1.2 or later]) + AC_LANG_PUSH(C) + old_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror=incompatible-pointer-types" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[const void (*fptr)(unsigned long *, const unsigned long *, unsigned long,] + [ const unsigned long *, unsigned long, gf2x_mul_pool_t);] + [fptr = gf2x_mul_r;]]) + ],[ + AC_MSG_RESULT([yes]) + sage_spkg_install_gf2x=no + ],[ + AC_MSG_RESULT([no]) + sage_spkg_install_gf2x=yes + ]) + CFLAGS="$old_CFLAGS" + AC_LANG_POP(C)], + [sage_spkg_install_gf2x=yes]) +]) diff --git a/build/pkgs/gfan/package-version.txt b/build/pkgs/gfan/package-version.txt index 46e8cc9d899..91133688e97 100644 --- a/build/pkgs/gfan/package-version.txt +++ b/build/pkgs/gfan/package-version.txt @@ -1 +1 @@ -0.6.2.p0 +0.6.2.p1 diff --git a/build/pkgs/gfan/spkg-install b/build/pkgs/gfan/spkg-install index 17857cad29e..9598d951cde 100644 --- a/build/pkgs/gfan/spkg-install +++ b/build/pkgs/gfan/spkg-install @@ -1,11 +1,4 @@ -if [[ -z "$SAGE_LOCAL" ]]; then - echo >&2 "Error: SAGE_LOCAL undefined - exiting..." - echo >&2 "Maybe run 'sage -sh'?" - exit 1 -fi - -# C++11 workaround https://trac.sagemath.org/ticket/20926 -CXXFLAGS="$CXXFLAGS -std=c++11 -DNOCDDPREFIX" +CXXFLAGS="$CXXFLAGS -DNOCDDPREFIX" export CC CXX CFLAGS CXXFLAGS LDFLAGS @@ -13,32 +6,13 @@ cd src echo "Now building gfan..." # We don't use the makefile to install gfan so we don't need to set PREFIX -$MAKE CPPFLAGS="-I$SAGE_LOCAL/include" -if [[ $? -ne 0 ]]; then - echo >&2 "Error building gfan." - exit 1 -fi - -if [[ ! -f gfan ]]; then - echo >&2 "Error: Build completed normally but gfan executable not found." - exit 1 -fi - -echo "Removing old version of gfan (if any)..." -rm -f "$SAGE_LOCAL"/bin/gfan* +sdh_make CPPFLAGS="-I$SAGE_LOCAL/include" +[ -f gfan ] || \ + sdh_die "Error: Build completed normally but gfan executable not found." -cp -pf gfan "$SAGE_LOCAL/bin/" -if [[ $? -ne 0 ]]; then - echo >&2 "Error copying gfan executable." - exit 1 -fi +sdh_install gfan "$SAGE_LOCAL/bin" -cd "$SAGE_LOCAL/bin/" +cd "${SAGE_DESTDIR_LOCAL}/bin" echo "Now running gfan to install links in '$SAGE_LOCAL/bin/'..." -./gfan installlinks -# XXX How about [just] checking $? here? -if [[ ! -f "$SAGE_LOCAL/bin/gfan_buchberger" ]]; then - echo >&2 "Error: gfan links not created correctly." - exit 1 -fi +./gfan installlinks || sdh_die "gfan links not created correctly" diff --git a/build/pkgs/gfan/spkg-legacy-uninstall b/build/pkgs/gfan/spkg-legacy-uninstall new file mode 100644 index 00000000000..da4a461eca7 --- /dev/null +++ b/build/pkgs/gfan/spkg-legacy-uninstall @@ -0,0 +1,2 @@ +echo "Removing old version of gfan (if any)..." +rm -f "$SAGE_LOCAL"/bin/gfan* diff --git a/build/pkgs/gfortran/build-gcc b/build/pkgs/gfortran/build-gcc new file mode 120000 index 00000000000..adfe242a1ad --- /dev/null +++ b/build/pkgs/gfortran/build-gcc @@ -0,0 +1 @@ +../gcc/build-gcc \ No newline at end of file diff --git a/build/pkgs/gfortran/patches b/build/pkgs/gfortran/patches new file mode 120000 index 00000000000..c42218ef09d --- /dev/null +++ b/build/pkgs/gfortran/patches @@ -0,0 +1 @@ +../gcc/patches \ No newline at end of file diff --git a/build/pkgs/gfortran/spkg-build b/build/pkgs/gfortran/spkg-build new file mode 100644 index 00000000000..5c29f9b819a --- /dev/null +++ b/build/pkgs/gfortran/spkg-build @@ -0,0 +1 @@ +./build-gcc --disable-bootstrap --enable-languages=fortran diff --git a/build/pkgs/gfortran/spkg-install b/build/pkgs/gfortran/spkg-install index da56c4eb848..e643ffe4570 100644 --- a/build/pkgs/gfortran/spkg-install +++ b/build/pkgs/gfortran/spkg-install @@ -1,75 +1,7 @@ -if [ -z "$SAGE_LOCAL" ]; then - echo >&2 "SAGE_LOCAL undefined ... exiting" - echo >&2 "Maybe run 'sage --sh'?" - exit 1 -fi - -# This spkg shouldn't be installed if gcc is already installed -if [ -a "$SAGE_LOCAL"/bin/gcc ]; then - echo >&2 "Error: gcc is already installed" - exit 1 -fi - # Exit on error set -e -# Build in a separate directory, not in src/ (a.k.a. a VPATH build). -# This is the recommended way to build GCC. -mkdir gcc-build cd gcc-build - - -# On OSX: -if [ "$UNAME" = "Darwin" ]; then - # isl/cloog libraries are almost certainly from Homebrew and won't work - GCC_CONFIGURE="--without-isl --without-cloog $GCC_CONFIGURE" - - # Use 'bootstrap-debug' build configuration to force stripping of object - # files prior to comparison during bootstrap (broken by Xcode 6.3). - # See #18156 - GCC_CONFIGURE="--with-build-config=bootstrap-debug $GCC_CONFIGURE" -fi - -# Let Gfortran build on Raspberry Pi using hard floats. -if [ `uname -m` = "armv6l" ]; then - GCC_CONFIGURE="--with-arch=armv6 --with-fpu=vfp --with-float=hard $GCC_CONFIGURE" -fi - -# Let Gfortran build on more recent ARM boards using hard floats. -if [ `uname -m` = "armv7l" ]; then - GCC_CONFIGURE="--with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard $GCC_CONFIGURE" -fi - -if [ "$SAGE_CHECK" = yes ]; then - # Enable internal checks in GCC. These checks do not affect the - # binaries produced by GCC, but they do increase the compile time - # of everything compiled with GCC. - GCC_CONFIGURE="$GCC_CONFIGURE --enable-checking=yes" -fi - -# Use the assembler/linker specified by $AS/$LD if they differ from the -# default. -if [ -n "$AS" -a "$AS" != "as" ]; then - CONFIGURE_AS="--with-as=$AS" -fi -if [ -n "$LD" -a "$LD" != "ld" ]; then - CONFIGURE_LD="--with-ld=$LD" -fi - -../src/configure \ - --prefix="$SAGE_LOCAL" \ - --with-local-prefix="$SAGE_LOCAL" \ - --with-gmp="$SAGE_LOCAL" --with-mpfr="$SAGE_LOCAL" --with-mpc="$SAGE_LOCAL" \ - --with-system-zlib \ - --disable-multilib \ - --disable-nls \ - --enable-languages=fortran \ - --disable-bootstrap \ - --disable-libitm \ - $GCC_CONFIGURE "$CONFIGURE_AS" "$CONFIGURE_LD" - -sdh_make BOOT_LDFLAGS="-Wl,-rpath,$SAGE_LOCAL/lib" - sdh_make_install # The spkg still installs a minimal C compiler that needs to be removed diff --git a/build/pkgs/gfortran/spkg-preinst b/build/pkgs/gfortran/spkg-preinst new file mode 100644 index 00000000000..404f2a29829 --- /dev/null +++ b/build/pkgs/gfortran/spkg-preinst @@ -0,0 +1,6 @@ +# This spkg shouldn't be installed if gcc is already installed +GCC_SPKG_VERSION="$(cat "$SAGE_ROOT/build/pkgs/gcc/package-version.txt")" + +if [ -e "$SAGE_SPKG_INST/gcc-$GCC_SPKG_VERSION" ]; then + sdh_die "Error: The gcc SPKG is already installed and provides gfortran" +fi diff --git a/build/pkgs/giac/checksums.ini b/build/pkgs/giac/checksums.ini index ae2283791d5..51273e250dd 100644 --- a/build/pkgs/giac/checksums.ini +++ b/build/pkgs/giac/checksums.ini @@ -1,4 +1,4 @@ tarball=giac-VERSION.tar.bz2 -sha1=3b61dd5fe79a76c2e0d4ef60ad1ad90dc3c04bd3 -md5=55308225758c547b061b52d699fa8b13 -cksum=2762392051 +sha1=e5f21744b344a8112e1d179e154ecf1e9f1318ba +md5=adc278420abf2573d7e2ac910e67a12c +cksum=785223596 diff --git a/build/pkgs/giac/package-version.txt b/build/pkgs/giac/package-version.txt index ed6339886c2..ce3c8deec63 100644 --- a/build/pkgs/giac/package-version.txt +++ b/build/pkgs/giac/package-version.txt @@ -1 +1 @@ -1.4.9.45.p4 +1.5.0.37.p0 diff --git a/build/pkgs/giac/patches/alloca.patch b/build/pkgs/giac/patches/alloca.patch deleted file mode 100644 index 5dec185c225..00000000000 --- a/build/pkgs/giac/patches/alloca.patch +++ /dev/null @@ -1,38 +0,0 @@ -Always use ALLOCA macro instead of alloca() - -diff -ru a/src/gen.cc b/src/gen.cc ---- a/src/gen.cc 2018-01-10 14:16:00.000000000 +0100 -+++ b/src/gen.cc 2018-02-01 19:36:02.128020823 +0100 -@@ -11153,7 +11153,7 @@ - - /* I/O: Input routines */ - -- gen chartab2gen(char * & s,GIAC_CONTEXT){ -+ gen chartab2gen(char * s,GIAC_CONTEXT){ - gen res; - // subtype=0; - // initialize as a null _INT_ -@@ -11200,11 +11200,7 @@ - if (l>0 && s[l-1]=='.'){ - // make a copy of s, call chartab2gen recursivly, - // because some implementations of strtod do not like a . at the end --#ifdef FREERTOS - ALLOCA(char, scopy, l+2); --#else -- char * scopy=(char *)alloca(l+2); --#endif - strcpy(scopy,s); - scopy[l]='0'; - scopy[l+1]=0; -diff -ru a/src/gen.h b/src/gen.h ---- a/src/gen.h 2017-12-19 21:15:00.000000000 +0100 -+++ b/src/gen.h 2018-02-01 19:35:56.090020807 +0100 -@@ -930,7 +930,7 @@ - void gen_sort_f(iterateur it,iterateur itend,bool (*f)(const gen &a,const gen &b)); - void gen_sort_f_context(iterateur it,iterateur itend,bool (*f)(const gen &a,const gen &b,GIAC_CONTEXT),GIAC_CONTEXT); - gen makemap(); // make a new map -- gen chartab2gen(char * & s,GIAC_CONTEXT); -+ gen chartab2gen(char * s,GIAC_CONTEXT); - - - bool is_zero(const gen & a,GIAC_CONTEXT0); diff --git a/build/pkgs/giac/patches/configure-libpng.patch b/build/pkgs/giac/patches/configure-libpng.patch deleted file mode 100644 index 92fd3946436..00000000000 --- a/build/pkgs/giac/patches/configure-libpng.patch +++ /dev/null @@ -1,101 +0,0 @@ -see https://trac.sagemath.org/ticket/25818 ---- a/configure 2018-07-10 18:26:57.462278000 +0000 -+++ b/configure 2018-07-10 19:08:34.170278000 +0000 -@@ -15488,49 +15488,67 @@ - cat >>confdefs.h <<_ACEOF - #define HAVE_PNG_H 1 - _ACEOF -- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lpng" >&5 --$as_echo_n "checking for main in -lpng... " >&6; } --if ${ac_cv_lib_png_main+:} false; then : -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing png_sig_cmp" >&5 -+$as_echo_n "checking for library containing png_sig_cmp... " >&6; } -+if ${ac_cv_search_png_sig_cmp+:} false; then : - $as_echo_n "(cached) " >&6 - else -- ac_check_lib_save_LIBS=$LIBS --LIBS="-lpng $LIBS" -+ ac_func_search_save_LIBS=$LIBS - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - -- -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char png_sig_cmp (); - int - main () - { --return main (); -+return png_sig_cmp (); - ; - return 0; - } - _ACEOF --if ac_fn_cxx_try_link "$LINENO"; then : -- ac_cv_lib_png_main=yes --else -- ac_cv_lib_png_main=no -+for ac_lib in '' png16 png14 png12 png; do -+ if test -z "$ac_lib"; then -+ ac_res="none required" -+ else -+ ac_res=-l$ac_lib -+ LIBS="-l$ac_lib $ac_func_search_save_LIBS" -+ fi -+ if ac_fn_cxx_try_link "$LINENO"; then : -+ ac_cv_search_png_sig_cmp=$ac_res - fi - rm -f core conftest.err conftest.$ac_objext \ -- conftest$ac_exeext conftest.$ac_ext --LIBS=$ac_check_lib_save_LIBS -+ conftest$ac_exeext -+ if ${ac_cv_search_png_sig_cmp+:} false; then : -+ break - fi --{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_png_main" >&5 --$as_echo "$ac_cv_lib_png_main" >&6; } --if test "x$ac_cv_lib_png_main" = xyes; then : -- cat >>confdefs.h <<_ACEOF --#define HAVE_LIBPNG 1 --_ACEOF -+done -+if ${ac_cv_search_png_sig_cmp+:} false; then : - -- LIBS="-lpng $LIBS" -+else -+ ac_cv_search_png_sig_cmp=no -+fi -+rm conftest.$ac_ext -+LIBS=$ac_func_search_save_LIBS -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_png_sig_cmp" >&5 -+$as_echo "$ac_cv_search_png_sig_cmp" >&6; } -+ac_res=$ac_cv_search_png_sig_cmp -+if test "$ac_res" != no; then : -+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - - fi - - fi - - done -- fi -+ -+fi - - - -@@ -23154,7 +23172,7 @@ - configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - --Copyright (C) 2012 Free Software Foundation, Inc. -+Copyright (C) Free Software Foundation, Inc. - This config.status script is free software; the Free Software Foundation - gives unlimited permission to copy, distribute and modify it." - diff --git a/build/pkgs/giac/patches/dirent.patch b/build/pkgs/giac/patches/dirent.patch index 306f3a90a27..11d2ea20901 100644 --- a/build/pkgs/giac/patches/dirent.patch +++ b/build/pkgs/giac/patches/dirent.patch @@ -19,7 +19,7 @@ diff -ru a/src/help.cc b/src/help.cc #ifndef NO_NAMESPACE_GIAC namespace giac { #endif // ndef NO_NAMESPACE_GIAC -@@ -933,7 +942,7 @@ +@@ -944,7 +953,7 @@ static int dir_select (const struct dirent *d){ #endif string s(d->d_name); @@ -28,7 +28,7 @@ diff -ru a/src/help.cc b/src/help.cc return s!="." && s!=".."; } int t=s.size(); -@@ -997,8 +1006,7 @@ +@@ -1008,8 +1017,7 @@ index_done=find_index(subdir,s,mtt,mall); } #else diff --git a/build/pkgs/giac/patches/gbasis-bigprimesoverflow-1.5.0.37.patch b/build/pkgs/giac/patches/gbasis-bigprimesoverflow-1.5.0.37.patch new file mode 100644 index 00000000000..818d986e718 --- /dev/null +++ b/build/pkgs/giac/patches/gbasis-bigprimesoverflow-1.5.0.37.patch @@ -0,0 +1,21 @@ +For giac 1.5.0-37. Fix an overflow in gbasis computations modulo primes between 2**30 and 2**31 +cf: https://trac.sagemath.org/ticket/27306 + +using upstream patch from: +https://dev.geogebra.org/trac/changeset/66972/ + +Index: /trunk/geogebra/giac/src/giac/cpp/cocoa.cc +=================================================================== +--- a/src/cocoa.cc (revision 66971) ++++ b/src/cocoa.cc (revision 66972) +@@ -12619,8 +12619,8 @@ + n %= env; + #endif +- if (n*2>env) ++ if (n*2LL>env) + it->g -= env; + else { +- if (n*2<=-env) ++ if (n*2LL<=-env) + it->g += env; + } diff --git a/build/pkgs/giac/patches/hashmap.patch b/build/pkgs/giac/patches/hashmap.patch deleted file mode 100644 index 6f538396855..00000000000 --- a/build/pkgs/giac/patches/hashmap.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/giac-1.4.9.45-orig/src/src/index.h b/giac-1.4.9.45/src/src/index.h -index e74be63..8ed12f9 100755 ---- a/src/index.h -+++ b/src/index.h -@@ -42,7 +42,7 @@ - #include - #endif - --#if defined UNORDERED_MAP && !defined(__clang__) && !defined(VISUALC) // && !defined(__APPLE__) -+#if defined UNORDERED_MAP && !defined(VISUALC) // && !defined(__APPLE__) - #include - #define HASH_MAP_NAMESPACE std::tr1 - #define hash_map unordered_map diff --git a/build/pkgs/giac/patches/isnan-conflict.patch b/build/pkgs/giac/patches/isnan-conflict.patch new file mode 100644 index 00000000000..88ca5f715a6 --- /dev/null +++ b/build/pkgs/giac/patches/isnan-conflict.patch @@ -0,0 +1,30 @@ +Just always use std::isnan and std::isinf so there is no risk of +conflicting with the libc math.h equivalents thereof. + +See https://trac.sagemath.org/ticket/27263 +--- a/src/global.cc 2019-02-12 15:49:03.082594000 +0000 ++++ b/src/global.cc 2019-02-12 15:49:43.438594000 +0000 +@@ -4139,11 +4139,7 @@ + return isnan(d); + #endif + #else +-#if defined(FIR_LINUX) || defined(FIR_ANDROID) + return std::isnan(d); +-#else +- return isnan(d); +-#endif + #endif + } + +@@ -4152,11 +4148,7 @@ + double x=0.0; + return d==1.0/x || d==-1.0/x; + #else +-#if defined(FIR_LINUX) || defined(FIR_ANDROID) + return std::isinf(d); +-#else +- return isinf(d); +-#endif + #endif + } + diff --git a/build/pkgs/giac/patches/macos-ifactor.patch b/build/pkgs/giac/patches/macos-ifactor.patch index b2a1050619e..34e84dda7ef 100644 --- a/build/pkgs/giac/patches/macos-ifactor.patch +++ b/build/pkgs/giac/patches/macos-ifactor.patch @@ -1,11 +1,12 @@ --- a/src/ifactor.cc 2014-10-11 16:29:01.000000000 +0200 +++ b/src/ifactor.cc 2014-10-11 16:29:28.000000000 +0200 -@@ -3737,7 +3737,7 @@ - return giac_ifactors(n0._VECTptr->front(),contextptr); +@@ -4007,7 +4007,7 @@ + #endif #ifdef HAVE_LIBPARI #ifdef __APPLE__ - return vecteur(1,gensizeerr(gettext("(Mac OS) Large number, you can try pari(); pari_factor(")+n0.print(contextptr)+")")); + // return vecteur(1,gensizeerr(gettext("(Mac OS) Large number, you can try pari(); pari_factor(")+n0.print(contextptr)+")")); #endif - if (!is_integer(n0) || is_zero(n0)) - return vecteur(1,gensizeerr(gettext("ifactors"))); + gen g(pari_ifactor(n0),contextptr); + if (g.type==_VECT){ + diff --git a/build/pkgs/giac/patches/sunos_abs.patch b/build/pkgs/giac/patches/sunos_abs.patch deleted file mode 100644 index 0e1cd76ed2c..00000000000 --- a/build/pkgs/giac/patches/sunos_abs.patch +++ /dev/null @@ -1,18 +0,0 @@ -Work around _ABS macro on SunOS - -See https://trac.sagemath.org/ticket/24619 - -diff -ru a/src/rpn.h b/src/rpn.h ---- a/src/rpn.h 2016-01-03 09:12:13.000000000 +0100 -+++ b/src/rpn.h 2018-01-31 10:36:43.049921736 +0100 -@@ -24,6 +24,10 @@ - #include - #include - -+/* SunOS defines this as macro */ -+#undef _ABS -+ -+ - #ifndef NO_NAMESPACE_GIAC - namespace giac { - #endif // ndef NO_NAMESPACE_GIAC diff --git a/build/pkgs/giac/spkg-install b/build/pkgs/giac/spkg-install index 7221fa4e661..8e984802c81 100644 --- a/build/pkgs/giac/spkg-install +++ b/build/pkgs/giac/spkg-install @@ -44,7 +44,7 @@ if [ "$UNAME" = "Darwin" ]; then DISABLENLS="--disable-nls" fi -sdh_configure --disable-gui --disable-ao --disable-lapack "$DISABLENLS" +sdh_configure --disable-gui --disable-ao --disable-lapack "$DISABLENLS" --enable-png=no --disable-samplerate ############################################################# # Build diff --git a/build/pkgs/giac/spkg-src b/build/pkgs/giac/spkg-src index e8baa2584f2..061ca795bf4 100755 --- a/build/pkgs/giac/spkg-src +++ b/build/pkgs/giac/spkg-src @@ -13,8 +13,8 @@ fi # Exit on failure set -e -VERSION="1.4.9" -VERSIONREV="45" +VERSION="1.5.0" +VERSIONREV="37" # The upstream tarball name is: giac"$SOURCEORIG".tar.gz SOURCEORIG=_"$VERSION"-"$VERSIONREV" diff --git a/build/pkgs/giacpy_sage/checksums.ini b/build/pkgs/giacpy_sage/checksums.ini index d2cab244fed..7f55bdd2961 100644 --- a/build/pkgs/giacpy_sage/checksums.ini +++ b/build/pkgs/giacpy_sage/checksums.ini @@ -1,4 +1,4 @@ tarball=giacpy_sage-VERSION.tar.gz -sha1=0d82ae71219d546532e1234fee4ea8b1b6f53ccf -md5=d8cc9fe590e808c2543b8fc712ea9481 -cksum=1760632879 +sha1=f23909396c6464c7b8a05538ced73ba34152c7bf +md5=9d250194dc1c7c0ea391e36e3f7a07e2 +cksum=2377016266 diff --git a/build/pkgs/giacpy_sage/package-version.txt b/build/pkgs/giacpy_sage/package-version.txt index 05e8a4593fa..2228cad41f3 100644 --- a/build/pkgs/giacpy_sage/package-version.txt +++ b/build/pkgs/giacpy_sage/package-version.txt @@ -1 +1 @@ -0.6.6 +0.6.7 diff --git a/build/pkgs/glucose/SPKG.txt b/build/pkgs/glucose/SPKG.txt new file mode 100644 index 00000000000..e2871477ba4 --- /dev/null +++ b/build/pkgs/glucose/SPKG.txt @@ -0,0 +1,35 @@ += glucose = + +== Description == + +Glucose is a SAT solver. + +Citing its website: *The name of the solver is a contraction of the concept of +"glue clauses", a particular kind of clauses that glucose detects and preserves +during search. Glucose is heavily based on Minisat, so please do cite Minisat +also if you want to cite Glucose.* + +== License == + +- nonparallel glucose: MIT + +- parallel glucose-syrup: MIT modified with: + + The parallel version of Glucose (all files modified since Glucose 3.0 + releases, 2013) cannot be used in any competitive event (sat + competitions/evaluations) without the express permission of the authors + (Gilles Audemard / Laurent Simon). This is also the case for any competitive + event using Glucose Parallel as an embedded SAT engine (single core or not). + +== Upstream Contact == + +Website: http://www.labri.fr/perso/lsimon/glucose/ + +== Dependencies == + +zlib + +== Special Update/Build Instructions == + +None. + diff --git a/build/pkgs/glucose/checksums.ini b/build/pkgs/glucose/checksums.ini new file mode 100644 index 00000000000..56885793b64 --- /dev/null +++ b/build/pkgs/glucose/checksums.ini @@ -0,0 +1,4 @@ +tarball=glucose-syrup-VERSION.tgz +sha1=5442dff37b8ea113b572bffa27a19314af14a137 +md5=7f13be91b3cd71bd02d4f37570fee011 +cksum=3190126613 diff --git a/build/pkgs/glucose/dependencies b/build/pkgs/glucose/dependencies new file mode 100644 index 00000000000..4c0aa5c0d31 --- /dev/null +++ b/build/pkgs/glucose/dependencies @@ -0,0 +1,5 @@ +zlib + +---------- +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/glucose/package-version.txt b/build/pkgs/glucose/package-version.txt new file mode 100644 index 00000000000..7d5c902e777 --- /dev/null +++ b/build/pkgs/glucose/package-version.txt @@ -0,0 +1 @@ +4.1 diff --git a/build/pkgs/glucose/spkg-install b/build/pkgs/glucose/spkg-install new file mode 100644 index 00000000000..8dabc6458fb --- /dev/null +++ b/build/pkgs/glucose/spkg-install @@ -0,0 +1,25 @@ +cd src + +LFLAGS="${LDFLAGS} -Wall -lpthread" +export LFLAGS + +cd simp +sdh_make +sdh_install glucose ${SAGE_LOCAL}/bin/ +cd .. + +# Possible license issue, see warning below and discussion on https://trac.sagemath.org/ticket/26361 +cd parallel +sdh_make +sdh_install glucose-syrup ${SAGE_LOCAL}/bin/ +cd .. + +echo "WARNING: according to the license: + + The parallel version of Glucose (all files modified since Glucose 3.0 + releases, 2013) cannot be used in any competitive event (sat + competitions/evaluations) without the express permission of the authors + (Gilles Audemard / Laurent Simon). This is also the case for any competitive + event using Glucose Parallel as an embedded SAT engine (single core or not). +" + diff --git a/build/pkgs/glucose/type b/build/pkgs/glucose/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/glucose/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/gmp/spkg-install b/build/pkgs/gmp/spkg-install index 9004a39c259..611da0f1e6c 100644 --- a/build/pkgs/gmp/spkg-install +++ b/build/pkgs/gmp/spkg-install @@ -137,28 +137,16 @@ export ABI CFLAGS CXXFLAGS LDFLAGS # Partially redundant, but safe(r). GMP_CONFIGURE="--enable-shared $GMP_CONFIGURE" -# If we're bootstrapping GCC from the GCC spkg, don't build the C++ -# interface (cf. #12782), static libraries and disable fat binary. -# After GCC is built, we will build GMP again. -if [ "$SAGE_BUILD_TOOLCHAIN" = yes ]; then - echo "Building a reduced version of GMP to bootstrap GCC." - echo "GMP will later get rebuilt (with the C++ interface and static libraries" - echo "enabled) using the new compiler." - GMP_CONFIGURE="$GMP_CONFIGURE --disable-cxx --disable-static" - SAGE_FAT_BINARY=no +# Also build the static library to be used by e.g. ECM +# unless we are on Cygwin where we can only build a shared +# or a static library but not both: +if [ "$UNAME" = "CYGWIN" ]; then + echo "Building GMP with the C++ interface and (only) shared libraries." + GMP_CONFIGURE="--enable-cxx $GMP_CONFIGURE --disable-static" else - # Also build the static library to be used by e.g. ECM - # unless we are on Cygwin where we can only build a shared - # or a static library but not both: - if [ "$UNAME" = "CYGWIN" ]; then - echo "Building GMP with the C++ interface and (only) shared libraries." - GMP_CONFIGURE="--enable-cxx $GMP_CONFIGURE --disable-static" - else - echo "Building GMP with the C++ interface and (also) static libraries." - GMP_CONFIGURE="--enable-cxx --enable-static $GMP_CONFIGURE" - fi + echo "Building GMP with the C++ interface and (also) static libraries." + GMP_CONFIGURE="--enable-cxx --enable-static $GMP_CONFIGURE" fi -# (Further options to 'configure' are added below.) # If SAGE_FAT_BINARY is enabled, then add --enable-fat to configure # options on Linux x86 systems. On other systems, fat binaries are not diff --git a/build/pkgs/gmpy2/package-version.txt b/build/pkgs/gmpy2/package-version.txt index b97332e68e9..d2b9cd4b4cc 100644 --- a/build/pkgs/gmpy2/package-version.txt +++ b/build/pkgs/gmpy2/package-version.txt @@ -1 +1 @@ -2.1.0a4.p0 +2.1.0a4.p1 diff --git a/build/pkgs/gmpy2/patches/PR217_PR218_conversion_methods.patch b/build/pkgs/gmpy2/patches/PR217_PR218_conversion_methods.patch new file mode 100644 index 00000000000..b277d64fec5 --- /dev/null +++ b/build/pkgs/gmpy2/patches/PR217_PR218_conversion_methods.patch @@ -0,0 +1,704 @@ +Patch for the gmpy2's pull requests #217 and #218. +https://github.com/aleaxit/gmpy/pull/217 +https://github.com/aleaxit/gmpy/pull/218 + +diff --git a/docs/conversion.rst b/docs/conversion.rst +new file mode 100644 +index 0000000..6d61d2d +--- /dev/null ++++ b/docs/conversion.rst +@@ -0,0 +1,54 @@ ++Conversion methods and gmpy2's numbers ++====================================== ++ ++Conversion methods ++------------------ ++ ++A python object could interact with gmpy2 if it implements one of the following methods: ++ ++- **__mpz__** : return an object of . ++- **__mpq__** : return an object of . ++- **__mpfr__** : return an object of . ++- **__mpc__** : return an object of . ++ ++| Implementing on of these methods allow gmpy2 to convert a python object into a gmpy2 type. ++| Example:: ++ ++ >>> from gmpy2 import mpz ++ >>> class CustInt: ++ ... def __init__(self, x): ++ ... self.x = x ++ ... def __mpz__(self): ++ ... return mpz(self.x) ++ ... ++ >>> ci = CustInt(5) ++ >>> z = mpz(ci); z ++ mpz(5) ++ >>> type(z) ++ ++ ++Arithmetic operations ++--------------------- ++ ++| gmpy2 allow arithmetic operations between gmpy2 numbers and objects with conversion methods. ++| Operation with object that implements floating conversion and exact conversion methods are not supported. ++| That means that only the following cases are supported: ++ ++- An integer type have to implement **__mpz__** ++- A rational type have to implement **__mpq__** and can implement **__mpz__** ++- A real type have to implement **__mpfr__** ++- A complex type have to implement **__mpc__** and can implement **__mpfr__** ++ ++Examples:: ++ ++ >>> from gmpy2 import mpz, mpq, mpfr, mpc ++ >>> class Q: ++ ... def __mpz__(self): return mpz(1) ++ ... def __mpq__(self): return mpq(3,2) ++ >>> q = Q() ++ >>> mpz(2) + q ++ mpq(7,2) ++ >>> mpq(1,2) * q ++ mpq(3,4) ++ >>> mpfr(10) * q ++ mpfr('15.0') +diff --git a/docs/index.rst b/docs/index.rst +index 046517d..451aa45 100644 +--- a/docs/index.rst ++++ b/docs/index.rst +@@ -19,6 +19,7 @@ Contents: + mpfr + mpc + cython ++ conversion + history + + Indices and tables +diff --git a/src/gmpy2_cache.c b/src/gmpy2_cache.c +index de5774d..410033c 100644 +--- a/src/gmpy2_cache.c ++++ b/src/gmpy2_cache.c +@@ -149,7 +149,7 @@ GMPy_MPZ_NewInit(PyTypeObject *type, PyObject *args, PyObject *keywds) + return (PyObject*)GMPy_MPZ_From_PyStr(n, base, context); + } + +- if (PyObject_HasAttrString(n, "__mpz__")) { ++ if (HAS_MPZ_CONVERSION(n)) { + out = (PyObject *) PyObject_CallMethod(n, "__mpz__", NULL); + + if (out == NULL) +@@ -461,7 +461,7 @@ GMPy_MPQ_NewInit(PyTypeObject *type, PyObject *args, PyObject *keywds) + return (PyObject *) GMPy_MPQ_From_Number(n, context); + } + +- if (PyObject_HasAttrString(n, "__mpq__")) { ++ if (HAS_MPQ_CONVERSION(n)) { + out = (PyObject *) PyObject_CallMethod(n, "__mpq__", NULL); + if (out == NULL) + return out; +@@ -645,6 +645,20 @@ GMPy_MPFR_NewInit(PyTypeObject *type, PyObject *args, PyObject *keywds) + return (PyObject*)GMPy_MPFR_From_PyStr(arg0, base, prec, context); + } + ++ if (HAS_MPFR_CONVERSION(arg0)) { ++ out = (PyObject *) PyObject_CallMethod(arg0, "__mpfr__", NULL); ++ ++ if(out == NULL) ++ return out; ++ if (!MPFR_Check(out)) { ++ PyErr_Format(PyExc_TypeError, ++ "object of type '%.200s' can not be interpreted as mpfr", ++ out->ob_type->tp_name); ++ return NULL; ++ } ++ return out; ++ } ++ + /* A number can only have precision and context as additional arguments. */ + if (IS_REAL(arg0)) { + if (keywdc || argc > 1) { +@@ -666,20 +680,6 @@ GMPy_MPFR_NewInit(PyTypeObject *type, PyObject *args, PyObject *keywds) + return (PyObject*)GMPy_MPFR_From_Real(arg0, prec, context); + } + +- if (PyObject_HasAttrString(arg0, "__mpfr__")) { +- out = (PyObject *) PyObject_CallMethod(arg0, "__mpfr__", NULL); +- +- if(out == NULL) +- return out; +- if (!MPFR_Check(out)) { +- PyErr_Format(PyExc_TypeError, +- "object of type '%.200s' can not be interpreted as mpfr", +- out->ob_type->tp_name); +- return NULL; +- } +- return out; +- } +- + TYPE_ERROR("mpfr() requires numeric or string argument"); + return NULL; + } +@@ -858,6 +858,19 @@ GMPy_MPC_NewInit(PyTypeObject *type, PyObject *args, PyObject *keywds) + return (PyObject*)GMPy_MPC_From_PyStr(arg0, base, rprec, iprec, context); + } + ++ if (HAS_MPC_CONVERSION(arg0)) { ++ out = (PyObject*) PyObject_CallMethod(arg0, "__mpc__", NULL); ++ if(out == NULL) ++ return out; ++ if (!MPC_Check(out)) { ++ PyErr_Format(PyExc_TypeError, ++ "object of type '%.200s' can not be interpreted as mpc", ++ out->ob_type->tp_name); ++ return NULL; ++ } ++ return out; ++ } ++ + /* Should special case PyFLoat to avoid double rounding. */ + + if (IS_REAL(arg0)) { +@@ -968,19 +981,6 @@ GMPy_MPC_NewInit(PyTypeObject *type, PyObject *args, PyObject *keywds) + return (PyObject*)result; + } + +- if (PyObject_HasAttrString(arg0, "__mpc__")) { +- out = (PyObject*) PyObject_CallMethod(arg0, "__mpc__", NULL); +- if(out == NULL) +- return out; +- if (!MPC_Check(out)) { +- PyErr_Format(PyExc_TypeError, +- "object of type '%.200s' can not be interpreted as mpc", +- out->ob_type->tp_name); +- return NULL; +- } +- return out; +- } +- + TYPE_ERROR("mpc() requires numeric or string argument"); + return NULL; + } +diff --git a/src/gmpy2_convert.h b/src/gmpy2_convert.h +index 5db62f6..b1f9ca8 100644 +--- a/src/gmpy2_convert.h ++++ b/src/gmpy2_convert.h +@@ -36,22 +36,34 @@ extern "C" { + /* The following macros classify the numeric types that are supported by + * gmpy2. + */ ++#define HAS_MPZ_CONVERSION(x) PyObject_HasAttrString(x, "__mpz__") ++#define HAS_MPQ_CONVERSION(x) PyObject_HasAttrString(x, "__mpq__") ++#define HAS_MPFR_CONVERSION(x) PyObject_HasAttrString(x, "__mpfr__") ++#define HAS_MPC_CONVERSION(x) PyObject_HasAttrString(x, "__mpc__") ++ ++#define HAS_STRICT_MPZ_CONVERSION(x) (HAS_MPZ_CONVERSION(x) && \ ++ !HAS_MPQ_CONVERSION(x)) ++#define HAS_STRICT_MPFR_CONVERSION(x) (HAS_MPFR_CONVERSION(x) && \ ++ !HAS_MPC_CONVERSION(x)) + + #ifdef PY2 +-#define IS_INTEGER(x) (MPZ_Check(x) || PyInt_Check(x) || PyLong_Check(x) || XMPZ_Check(x)) ++#define IS_INTEGER(x) (MPZ_Check(x) || PyInt_Check(x) || \ ++ PyLong_Check(x) || XMPZ_Check(x) || \ ++ HAS_STRICT_MPZ_CONVERSION(x)) + #else +-#define IS_INTEGER(x) (MPZ_Check(x) || PyLong_Check(x) || XMPZ_Check(x)) ++#define IS_INTEGER(x) (MPZ_Check(x) || PyLong_Check(x) || \ ++ XMPZ_Check(x) || HAS_STRICT_MPZ_CONVERSION(x)) + #endif + + #define IS_FRACTION(x) (!strcmp(Py_TYPE(x)->tp_name, "Fraction")) + +-#define IS_RATIONAL_ONLY(x) (MPQ_Check(x) || IS_FRACTION(x)) ++#define IS_RATIONAL_ONLY(x) (MPQ_Check(x) || IS_FRACTION(x) || HAS_MPQ_CONVERSION(x)) + #define IS_RATIONAL(x) (IS_INTEGER(x) || IS_RATIONAL_ONLY(x)) + +-#define IS_REAL_ONLY(x) (MPFR_Check(x) || PyFloat_Check(x)) ++#define IS_REAL_ONLY(x) (MPFR_Check(x) || PyFloat_Check(x) || HAS_STRICT_MPFR_CONVERSION(x)) + #define IS_REAL(x) (IS_RATIONAL(x) || IS_REAL_ONLY(x)) + +-#define IS_COMPLEX_ONLY(x) (MPC_Check(x) || PyComplex_Check(x)) ++#define IS_COMPLEX_ONLY(x) (MPC_Check(x) || PyComplex_Check(x) || HAS_MPC_CONVERSION(x)) + #define IS_COMPLEX(x) (IS_REAL(x) || IS_COMPLEX_ONLY(x)) + + /* Since the macros are used in gmpy2's codebase, these functions are skipped +diff --git a/src/gmpy2_convert_gmp.c b/src/gmpy2_convert_gmp.c +index 1676a13..b64fa5a 100644 +--- a/src/gmpy2_convert_gmp.c ++++ b/src/gmpy2_convert_gmp.c +@@ -312,6 +312,13 @@ GMPy_MPZ_From_Integer(PyObject *obj, CTXT_Object *context) + if (XMPZ_Check(obj)) + return GMPy_MPZ_From_XMPZ((XMPZ_Object*)obj, context); + ++ if (HAS_STRICT_MPZ_CONVERSION(obj)) { ++ result = (MPZ_Object *) PyObject_CallMethod(obj, "__mpz__", NULL); ++ ++ if (result != NULL && MPZ_Check(result)) ++ return result; ++ } ++ + TYPE_ERROR("cannot convert object to mpz"); + return result; + } +@@ -995,6 +1002,20 @@ GMPy_MPQ_From_Number(PyObject *obj, CTXT_Object *context) + if (IS_FRACTION(obj)) + return GMPy_MPQ_From_Fraction(obj, context); + ++ if (HAS_MPQ_CONVERSION(obj)) { ++ MPQ_Object * res = (MPQ_Object *) PyObject_CallMethod(obj, "__mpq__", NULL); ++ ++ if (res != NULL && MPQ_Check(res)) ++ return res; ++ } ++ ++ if (HAS_MPZ_CONVERSION(obj)) { ++ MPZ_Object * res = (MPZ_Object *) PyObject_CallMethod(obj, "__mpz__", NULL); ++ ++ if (res != NULL && MPZ_Check(res)) ++ return GMPy_MPQ_From_MPZ(res, context); ++ } ++ + TYPE_ERROR("cannot convert object to mpq"); + return NULL; + } +diff --git a/src/gmpy2_convert_mpc.c b/src/gmpy2_convert_mpc.c +index 57266c2..4d6175a 100644 +--- a/src/gmpy2_convert_mpc.c ++++ b/src/gmpy2_convert_mpc.c +@@ -437,6 +437,34 @@ GMPy_MPC_From_Complex(PyObject* obj, mp_prec_t rprec, mp_prec_t iprec, + if (IS_FRACTION(obj)) + return GMPy_MPC_From_Fraction(obj, rprec, iprec, context); + ++ if (HAS_MPC_CONVERSION(obj)) { ++ MPC_Object * res = (MPC_Object *) PyObject_CallMethod(obj, "__mpc__", NULL); ++ ++ if (res != NULL && MPC_Check(res)) ++ return res; ++ } ++ ++ if (HAS_MPFR_CONVERSION(obj)) { ++ MPFR_Object * res = (MPFR_Object *) PyObject_CallMethod(obj, "__mpfr__", NULL); ++ ++ if (res != NULL && MPFR_Check(res)) ++ return GMPy_MPC_From_MPFR(res, rprec, iprec, context); ++ } ++ ++ if (HAS_MPQ_CONVERSION(obj)) { ++ MPQ_Object * res = (MPQ_Object *) PyObject_CallMethod(obj, "__mpq__", NULL); ++ ++ if (res != NULL && MPQ_Check(res)) ++ return GMPy_MPC_From_MPQ(res, rprec, iprec, context); ++ } ++ ++ if (HAS_MPZ_CONVERSION(obj)) { ++ MPZ_Object * res = (MPZ_Object *) PyObject_CallMethod(obj, "__mpz__", NULL); ++ ++ if (res != NULL && MPZ_Check(res)) ++ return GMPy_MPC_From_MPZ(res, rprec, iprec, context); ++ } ++ + TYPE_ERROR("object could not be converted to 'mpc'"); + return NULL; + } +diff --git a/src/gmpy2_convert_mpfr.c b/src/gmpy2_convert_mpfr.c +index aa8aec3..0c1501a 100644 +--- a/src/gmpy2_convert_mpfr.c ++++ b/src/gmpy2_convert_mpfr.c +@@ -437,6 +437,27 @@ GMPy_MPFR_From_Real(PyObject *obj, mp_prec_t prec, CTXT_Object *context) + if (IS_FRACTION(obj)) + return GMPy_MPFR_From_Fraction(obj, prec, context); + ++ if (HAS_MPFR_CONVERSION(obj)) { ++ MPFR_Object *res = (MPFR_Object *) PyObject_CallMethod(obj, "__mpfr__", NULL); ++ ++ if (res != NULL && MPFR_Check(res)) ++ return res; ++ } ++ ++ if (HAS_MPQ_CONVERSION(obj)) { ++ MPQ_Object *res = (MPQ_Object *) PyObject_CallMethod(obj, "__mpq__", NULL); ++ ++ if (res != NULL && MPQ_Check(res)) ++ return GMPy_MPFR_From_MPQ(res, prec, context); ++ } ++ ++ if (HAS_MPZ_CONVERSION(obj)) { ++ MPZ_Object *res = (MPZ_Object *) PyObject_CallMethod(obj, "__mpz__", NULL); ++ ++ if (res != NULL && MPZ_Check(res)) ++ return GMPy_MPFR_From_MPZ(res, prec, context); ++ } ++ + TYPE_ERROR("object could not be converted to 'mpfr'"); + return NULL; + } +diff --git a/test/test_gmpy2_add.txt b/test/test_gmpy2_add.txt +index 73046a1..2aa79ed 100644 +--- a/test/test_gmpy2_add.txt ++++ b/test/test_gmpy2_add.txt +@@ -10,6 +10,20 @@ Test all code in the file gmpy2_add.c. + >>> a = mpz(123) + >>> b = mpz(456) + >>> c = 12345678901234567890 ++>>> class Z: ++... def __mpz__(self): return mpz(1) ++>>> class Q: ++... def __mpz__(self): return mpz(1) ++... def __mpq__(self): return mpq(3,2) ++>>> class R: ++... def __mpfr__(self): return mpfr(1.5) ++>>> class Cx: ++... def __mpfr__(self): return mpfr(1.5) ++... def __mpc__(self): return mpc(42,67) ++>>> z = Z() ++>>> q = Q() ++>>> r = R() ++>>> cx = Cx() + + Test integer operations + ----------------------- +@@ -40,6 +54,8 @@ mpz(579) + mpz(-333) + >>> (-b)+a + mpz(-333) ++>>> a+z ++mpz(124) + + >>> ctx=gmpy2.context() + >>> ctx.add(a,b) == a+b +@@ -106,6 +122,10 @@ mpq(3,2) + mpc('1.0+0.0j') + >>> mpc(0) + mpq(1,1) + mpc('1.0+0.0j') ++>>> mpq(1,2) + z ++mpq(3,2) ++>>> mpq(1,2) + q ++mpq(2,1) + + >>> ctx=gmpy2.context() + >>> ctx.add(mpq(1,2), mpq(3,2)) +@@ -159,6 +179,12 @@ mpfr('2.0') + True + >>> (1 << 100) + mpfr(0) == mpfr('1p100', base=2) + True ++>>> mpfr(1) + z ++mpfr('2.0') ++>>> mpfr(0.5) + q ++mpfr('2.0') ++>>> mpfr(1.5) + r ++mpfr('3.0') + + Test complex operations + ----------------------- +@@ -174,3 +200,11 @@ mpc('2.0+2.0j') + mpc('2.0+2.0j') + >>> 1+0j + mpc(1,2) + mpc('2.0+2.0j') ++>>> mpc(1,2) + cx ++mpc('43.0+69.0j') ++>>> mpc(1,2) + r ++mpc('2.5+2.0j') ++>>> mpc(1,2) + q ++mpc('2.5+2.0j') ++>>> mpc(1,2) + z ++mpc('2.0+2.0j') +diff --git a/test/test_gmpy2_mul.txt b/test/test_gmpy2_mul.txt +index 4b9cb1c..826a519 100644 +--- a/test/test_gmpy2_mul.txt ++++ b/test/test_gmpy2_mul.txt +@@ -10,10 +10,26 @@ Test all code in the file gmpy2_sub.c. + >>> a = mpz(123) + >>> b = mpz(456) + >>> c = 12345678901234567890 ++>>> class Z: ++... def __mpz__(self): return mpz(2) ++>>> class Q: ++... def __mpz__(self): return mpz(1) ++... def __mpq__(self): return mpq(3,2) ++>>> class R: ++... def __mpfr__(self): return mpfr(1.5) ++>>> class Cx: ++... def __mpfr__(self): return mpfr(1.5) ++... def __mpc__(self): return mpc(42,67) ++>>> z = Z() ++>>> q = Q() ++>>> r = R() ++>>> cx = Cx() + + Test integer operations + ----------------------- + ++>>> mpz(2) * z ++mpz(4) + >>> gmpy2.mul(2,1) + mpz(2) + +@@ -56,6 +72,10 @@ mpq(-1,2) + mpc('1.0+0.0j') + >>> mpc(1,0) * mpq(1,1) + mpc('1.0+0.0j') ++>>> mpq(1,2) * z ++mpq(1,1) ++>>> mpq(1,2) * q ++mpq(3,4) + + >>> ctx=gmpy2.context() + >>> ctx.mul(mpq(1,2), mpq(3,2)) +@@ -109,6 +129,12 @@ mpfr('10.0') + True + >>> c * mpfr(1) == mpfr(c) + True ++>>> mpfr(10) * z ++mpfr('20.0') ++>>> mpfr(10) * q ++mpfr('15.0') ++>>> mpfr(10) * r ++mpfr('15.0') + >>> mpfr(10) * 'a' + Traceback (most recent call last): + File "", line 1, in +@@ -134,3 +160,11 @@ mpc('-1.0-2.0j') + mpc('1.0+2.0j') + >>> (1+0j) * mpc(1,2) + mpc('1.0+2.0j') ++>>> mpc(1,2) * z ++mpc('2.0+4.0j') ++>>> mpc(1,2) * q ++mpc('1.5+3.0j') ++>>> mpc(1,2) * r ++mpc('1.5+3.0j') ++>>> mpc(1,2) * cx ++mpc('-92.0+151.0j') +diff --git a/test/test_gmpy2_sub.txt b/test/test_gmpy2_sub.txt +index ea2abc4..93748a4 100644 +--- a/test/test_gmpy2_sub.txt ++++ b/test/test_gmpy2_sub.txt +@@ -10,6 +10,20 @@ Test all code in the file gmpy2_sub.c. + >>> a = mpz(123) + >>> b = mpz(456) + >>> c = 12345678901234567890 ++>>> class Z: ++... def __mpz__(self): return mpz(2) ++>>> class Q: ++... def __mpz__(self): return mpz(1) ++... def __mpq__(self): return mpq(3,2) ++>>> class R: ++... def __mpfr__(self): return mpfr(1.5) ++>>> class Cx: ++... def __mpfr__(self): return mpfr(1.5) ++... def __mpc__(self): return mpc(2,3) ++>>> z = Z() ++>>> q = Q() ++>>> r = R() ++>>> cx = Cx() + + Test integer operations + ----------------------- +@@ -40,6 +54,8 @@ mpz(333) + mpz(579) + >>> (-b)-a + mpz(-579) ++>>> a-z ++mpz(121) + + >>> gmpy2.sub(2,1) + mpz(1) +@@ -105,6 +121,10 @@ mpq(-1,2) + mpc('1.0+0.0j') + >>> mpc(0) - mpq(1,1) + mpc('-1.0+0.0j') ++>>> mpq(1,2) - z ++mpq(-3,2) ++>>> mpq(1,2) - q ++mpq(-1,1) + + >>> ctx=gmpy2.context() + >>> ctx.sub(mpq(1,2), mpq(3,2)) +@@ -158,6 +178,12 @@ mpfr('9.0') + True + >>> (1 << 100) - mpfr(0) == mpfr('1p100', base=2) + True ++>>> mpfr(10) - z ++mpfr('8.0') ++>>> mpfr(10) - q ++mpfr('8.5') ++>>> mpfr(10) - r ++mpfr('8.5') + + Test complex operations + ----------------------- +@@ -173,3 +199,11 @@ mpc('0.0+2.0j') + mpc('0.0+2.0j') + >>> 1+0j - mpc(1,2) + mpc('0.0-2.0j') ++>>> mpc(1,2) - z ++mpc('-1.0+2.0j') ++>>> mpc(1,2) - q ++mpc('-0.5+2.0j') ++>>> mpc(1,2) - r ++mpc('-0.5+2.0j') ++>>> mpc(1,2) - cx ++mpc('-1.0-1.0j') +diff --git a/test/test_mpc.txt b/test/test_mpc.txt +index cc079b4..efc9ce0 100644 +--- a/test/test_mpc.txt ++++ b/test/test_mpc.txt +@@ -14,6 +14,20 @@ Test mpc elementary operations + >>> bq = mpq(17,2) + >>> aj = mpc(1+2j) + >>> bj = mpc(4+5j) ++>>> class Z: ++... def __mpz__(self): return mpz(2) ++>>> class Q: ++... def __mpz__(self): return mpz(1) ++... def __mpq__(self): return mpq(3,2) ++>>> class R: ++... def __mpfr__(self): return mpfr(1.5) ++>>> class Cx: ++... def __mpfr__(self): return mpfr(1.5) ++... def __mpc__(self): return mpc(3,2) ++>>> z = Z() ++>>> q = Q() ++>>> r = R() ++>>> cx = Cx() + + Test addition + ------------- +@@ -98,6 +112,15 @@ mpc('0.008130081300813009+0.016260162601626018j') + mpc('24.600000000000001-49.200000000000003j') + >>> aj / 0 + mpc('inf+infj') ++>>> mpc('2.0+2.0j') / z ++mpc('1.0+1.0j') ++>>> mpc('2.0+2.0j') / q ++mpc('1.3333333333333333+1.3333333333333333j') ++>>> mpc('2.0+2.0j') / r ++mpc('1.3333333333333333+1.3333333333333333j') ++>>> mpc(15,15) / cx ++mpc('5.7692307692307692+1.1538461538461537j') ++ + + Test modulo + ----------- +diff --git a/test/test_mpfr.txt b/test/test_mpfr.txt +index ba31602..0ebeec7 100644 +--- a/test/test_mpfr.txt ++++ b/test/test_mpfr.txt +@@ -23,6 +23,16 @@ Testing of mpfr functionality is split into multiple files. + >>> a = mpfr("12.34") + >>> b = mpfr("45.67") + >>> c = 12345678901234567890 ++ >>> class Z: ++ ... def __mpz__(self): return mpz(2) ++ >>> class Q: ++ ... def __mpz__(self): return mpz(1) ++ ... def __mpq__(self): return mpq(1,2) ++ >>> class R: ++ ... def __mpfr__(self): return mpfr(1.5) ++ >>> z = Z() ++ >>> q = Q() ++ >>> r = R() + + Test elementary operations + ========================== +@@ -142,6 +152,13 @@ Test division + mpfr('-inf') + >>> a/b==12.34/45.67 + True ++ >>> mpfr(10) / z ++ mpfr('5.0') ++ >>> mpfr(10) / q ++ mpfr('20.0') ++ >>> mpfr(10) / r ++ mpfr('6.666666666666667') ++ + + Test modulo + ----------- +@@ -150,6 +167,8 @@ Test modulo + mpfr('0.33999999999999986') + >>> 12.34%1 + 0.33999999999999986 ++ >>> a%z ++ mpfr('0.33999999999999986') + + Test divmod + ----------- +diff --git a/test/test_mpq.txt b/test/test_mpq.txt +index 2d64298..d8ce953 100644 +--- a/test/test_mpq.txt ++++ b/test/test_mpq.txt +@@ -18,6 +18,13 @@ Testing of mpq functionality is split into multiple files. + >>> a = mpq(3,11) + >>> b = mpq(1,2) + >>> c = F(5,7) ++ >>> class Z: ++ ... def __mpz__(self): return mpz(2) ++ >>> class Q: ++ ... def __mpz__(self): return mpz(1) ++ ... def __mpq__(self): return mpq(3,2) ++ >>> z = Z() ++ >>> q = Q() + + Test elementary operations + ========================== +@@ -113,6 +120,14 @@ Test division + mpz(1) + >>> mpq(355, 113) // mpz(2) + mpz(1) ++ >>> a / z ++ mpq(3,22) ++ >>> mpq(355, 113) // z ++ mpz(1) ++ >>> mpq(3,11) / q ++ mpq(2,11) ++ >>> mpq(3,11) // q ++ mpz(0) + + Test modulo + ----------- +@@ -121,6 +136,10 @@ Test modulo + mpq(3,11) + >>> b%a + mpq(5,22) ++ >>> a%z ++ mpq(3,11) ++ >>> mpq(3,1) % q ++ mpq(0,1) + >>> divmod(a,b) + (mpz(0), mpq(3,11)) + >>> divmod(b,a) +diff --git a/test/test_mpz.txt b/test/test_mpz.txt +index d2eb7e8..28f0b5d 100644 +--- a/test/test_mpz.txt ++++ b/test/test_mpz.txt +@@ -22,6 +22,9 @@ Testing of mpz functionality is split into multiple files. + >>> a = mpz(123) + >>> b = mpz(456) + >>> c = 12345678901234567890 ++ >>> class Z: ++ ... def __mpz__(self): return mpz(2) ++ >>> z = Z() + + Test elementary operations + ========================== +@@ -136,6 +139,10 @@ Test division + 100371373180768844 + >>> a**10//c + mpz(64) ++ >>> a / z ++ mpfr('61.5') ++ >>> a // z ++ mpz(61) + + Test modulo + ----------- +@@ -144,6 +151,8 @@ Test modulo + mpz(123) + >>> b%a + mpz(87) ++ >>> a%z ++ mpz(1) + >>> divmod(a,b) + (mpz(0), mpz(123)) + >>> divmod(b,a) diff --git a/build/pkgs/gmpy2/type b/build/pkgs/gmpy2/type index 134d9bc32d5..a6a7b9cd726 100644 --- a/build/pkgs/gmpy2/type +++ b/build/pkgs/gmpy2/type @@ -1 +1 @@ -optional +standard diff --git a/build/pkgs/gp2c/package-version.txt b/build/pkgs/gp2c/package-version.txt index 7c1886bb9f4..9c2078f2f23 100644 --- a/build/pkgs/gp2c/package-version.txt +++ b/build/pkgs/gp2c/package-version.txt @@ -1 +1 @@ -0.0.10 +0.0.10.p0 diff --git a/build/pkgs/gp2c/spkg-install b/build/pkgs/gp2c/spkg-install index fe373011814..5df30d304fd 100644 --- a/build/pkgs/gp2c/spkg-install +++ b/build/pkgs/gp2c/spkg-install @@ -1,13 +1,4 @@ -if [ -z "$SAGE_LOCAL" ]; then - echo "SAGE_LOCAL undefined ... exiting" - echo "Maybe run 'sage -sh'?" - exit 1 -fi - cd src - -set -e - -./configure --prefix="$SAGE_LOCAL" --with-paricfg="$SAGE_LOCAL/lib/pari/pari.cfg" - -$MAKE install +sdh_configure --with-paricfg="$SAGE_LOCAL/lib/pari/pari.cfg" +sdh_make +sdh_make_install diff --git a/build/pkgs/gsl/spkg-legacy-uninstall b/build/pkgs/gsl/spkg-legacy-uninstall new file mode 100644 index 00000000000..ee1d768c334 --- /dev/null +++ b/build/pkgs/gsl/spkg-legacy-uninstall @@ -0,0 +1,2 @@ +rm -rf "$SAGE_LOCAL"/include/gsl +rm -rf "$SAGE_LOCAL"/lib/libgsl* diff --git a/build/pkgs/igraph/package-version.txt b/build/pkgs/igraph/package-version.txt index 7deb86fee42..f5a7e5d6dc5 100644 --- a/build/pkgs/igraph/package-version.txt +++ b/build/pkgs/igraph/package-version.txt @@ -1 +1 @@ -0.7.1 \ No newline at end of file +0.7.1.p0 diff --git a/build/pkgs/igraph/spkg-install b/build/pkgs/igraph/spkg-install index a8d6af4df35..78c3c4710ba 100644 --- a/build/pkgs/igraph/spkg-install +++ b/build/pkgs/igraph/spkg-install @@ -5,21 +5,6 @@ You need libxml2 to run igraph. On Ubuntu and Debian Linux, installing the build fi cd src - -./configure --prefix="$SAGE_LOCAL" --libdir="$SAGE_LOCAL/lib" -if [ $? -ne 0 ]; then - echo >&2 "Error configuring igraph." - exit 1 -fi - -$MAKE -if [ $? -ne 0 ]; then - echo >&2 "Error building igraph." - exit 1 -fi - -$MAKE -j1 install -if [ $? -ne 0 ]; then - echo >&2 "Error installing igraph." - exit 1 -fi +sdh_configure +sdh_make +sdh_make_install -j1 diff --git a/build/pkgs/imagesize/checksums.ini b/build/pkgs/imagesize/checksums.ini index e3cbb1fb168..4fa8f2b6ade 100644 --- a/build/pkgs/imagesize/checksums.ini +++ b/build/pkgs/imagesize/checksums.ini @@ -1,4 +1,4 @@ tarball=imagesize-VERSION.tar.gz -sha1=cfef5d52e8822cca4adecf6a894ca41ddf162de4 -md5=976148283286a6ba5f69b0f81aef8052 -cksum=1015215048 +sha1=48b7277a450654db77dc956812020525f5e478c8 +md5=2f89749b05e07c79c46330dbc62f1e02 +cksum=319793777 diff --git a/build/pkgs/imagesize/package-version.txt b/build/pkgs/imagesize/package-version.txt index f5a7e5d6dc5..9084fa2f716 100644 --- a/build/pkgs/imagesize/package-version.txt +++ b/build/pkgs/imagesize/package-version.txt @@ -1 +1 @@ -0.7.1.p0 +1.1.0 diff --git a/build/pkgs/ipywidgets/checksums.ini b/build/pkgs/ipywidgets/checksums.ini index 72e5c55d2c6..47419c92990 100644 --- a/build/pkgs/ipywidgets/checksums.ini +++ b/build/pkgs/ipywidgets/checksums.ini @@ -1,4 +1,4 @@ tarball=ipywidgets-VERSION.tar.gz -sha1=443148cd72ea1e708f8f0be1ea5de99dd1019808 -md5=de18af90829063fad0990ff89aa3cff5 -cksum=2457014809 +sha1=ae46dd88a2eb22ad975c604f947a085b55b243a7 +md5=e1ac2d4e3dc463f8c20e074d9414436e +cksum=3876771295 diff --git a/build/pkgs/ipywidgets/package-version.txt b/build/pkgs/ipywidgets/package-version.txt index 0ee843cc604..f8cb1fa110d 100644 --- a/build/pkgs/ipywidgets/package-version.txt +++ b/build/pkgs/ipywidgets/package-version.txt @@ -1 +1 @@ -7.2.0 +7.4.2 diff --git a/build/pkgs/itsdangerous/checksums.ini b/build/pkgs/itsdangerous/checksums.ini index f34dca2926d..14d3371ae83 100644 --- a/build/pkgs/itsdangerous/checksums.ini +++ b/build/pkgs/itsdangerous/checksums.ini @@ -1,4 +1,4 @@ tarball=itsdangerous-VERSION.tar.gz -sha1=0a6ae9c20cd72e89d75314ebc7b0f390f93e6a0d -md5=a3d55aa79369aef5345c036a8a26307f -cksum=2767256127 +sha1=b79fef5caacdd247f7def3fe59e6def34bc86905 +md5=9b7f5afa7f1e3acfb7786eeca3d99307 +cksum=1586818548 diff --git a/build/pkgs/itsdangerous/package-version.txt b/build/pkgs/itsdangerous/package-version.txt index baaee52d9b2..9084fa2f716 100644 --- a/build/pkgs/itsdangerous/package-version.txt +++ b/build/pkgs/itsdangerous/package-version.txt @@ -1 +1 @@ -0.24.p0 +1.1.0 diff --git a/build/pkgs/jupyter_client/checksums.ini b/build/pkgs/jupyter_client/checksums.ini index 9fddd8df1e4..81f2448c17d 100644 --- a/build/pkgs/jupyter_client/checksums.ini +++ b/build/pkgs/jupyter_client/checksums.ini @@ -1,4 +1,4 @@ tarball=jupyter_client-VERSION.tar.gz -sha1=b07e542ea729e7964a6249287c0c69820faa2a44 -md5=b474233b67b542889ed54c07ed56e6b3 -cksum=2864036920 +sha1=bb042481944e84b3e6ce06c613c2ed469bfef642 +md5=130d0171368a2bedd2c3903fddd410af +cksum=448365198 diff --git a/build/pkgs/jupyter_client/package-version.txt b/build/pkgs/jupyter_client/package-version.txt index c0baecbaaa9..73ce9502336 100644 --- a/build/pkgs/jupyter_client/package-version.txt +++ b/build/pkgs/jupyter_client/package-version.txt @@ -1 +1 @@ -5.2.3 +5.2.4 diff --git a/build/pkgs/kenzo/SPKG.txt b/build/pkgs/kenzo/SPKG.txt new file mode 100644 index 00000000000..e0f96ea81c6 --- /dev/null +++ b/build/pkgs/kenzo/SPKG.txt @@ -0,0 +1,21 @@ += Kenzo = + +== Description == + +Kenzo is a package to compute properties (mainly homology groups) +of topological spaces. It allows defining spaces created from others +by constuctions like loop spaces, classifying spaces and so on. + + +== License == + +GPL + +== Upstream Contact == + + * https://github.com/gheber/kenzo + +== Dependencies == + + * ECL (Embedded Common Lisp) + diff --git a/build/pkgs/kenzo/checksums.ini b/build/pkgs/kenzo/checksums.ini new file mode 100644 index 00000000000..250f6eee9e3 --- /dev/null +++ b/build/pkgs/kenzo/checksums.ini @@ -0,0 +1,4 @@ +tarball=kenzo-1.1.7-r1.tar.gz +sha1=2c04d8bc958f472489be4c8cd6e7029da0e8a06c +md5=1154e43f6db88b4924b447554329faa2 +cksum=2792773428 diff --git a/build/pkgs/kenzo/dependencies b/build/pkgs/kenzo/dependencies new file mode 100644 index 00000000000..ed6be201375 --- /dev/null +++ b/build/pkgs/kenzo/dependencies @@ -0,0 +1,5 @@ +ecl + +---------- +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/kenzo/package-version.txt b/build/pkgs/kenzo/package-version.txt new file mode 100644 index 00000000000..71d7006ccfe --- /dev/null +++ b/build/pkgs/kenzo/package-version.txt @@ -0,0 +1 @@ +1.1.7-r1 diff --git a/build/pkgs/kenzo/spkg-install b/build/pkgs/kenzo/spkg-install new file mode 100644 index 00000000000..cd64e0213c4 --- /dev/null +++ b/build/pkgs/kenzo/spkg-install @@ -0,0 +1,17 @@ +cd src + + + +# create a short lisp file with the instructions to load kenzo from ecl +# This will compile the lisp files since it is the first time they are loaded + +ecl < compile.lisp + +echo "moving kenzo--all-systems.fasb to $SAGE_LOCAL/lib/ecl/kenzo.fas" +mv kenzo--all-systems.fasb $SAGE_LOCAL/lib/ecl/kenzo.fas + + +if [ $? -ne 0 ]; then + echo >&2 "Error installing Kenzo." + exit 1 +fi diff --git a/build/pkgs/kenzo/type b/build/pkgs/kenzo/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/kenzo/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/latte_int/package-version.txt b/build/pkgs/latte_int/package-version.txt index 6a126f402d5..122e92a1e81 100644 --- a/build/pkgs/latte_int/package-version.txt +++ b/build/pkgs/latte_int/package-version.txt @@ -1 +1 @@ -1.7.5 +1.7.5.p0 diff --git a/build/pkgs/latte_int/spkg-install b/build/pkgs/latte_int/spkg-install index 6cc148e2895..972e07eeffd 100644 --- a/build/pkgs/latte_int/spkg-install +++ b/build/pkgs/latte_int/spkg-install @@ -1,19 +1,8 @@ -if [ "$SAGE_LOCAL" = "" ]; then - echo "SAGE_LOCAL undefined ... exiting"; - echo "Maybe run 'sage -sh'?" - exit 1 -fi - - cd src - -./configure --prefix=$SAGE_LOCAL --enable-shared=yes --enable-static=false --with-gmp=$SAGE_LOCAL --with-ntl=$SAGE_LOCAL --with-cddlib=$SAGE_LOCAL --with-4ti2=$SAGE_LOCAL --with-lidia=$SAGE_LOCAL -$MAKE -$MAKE install - -if [ $? -ne 0 ]; then - echo "Error building latte-int" - exit 1 -fi - +sdh_configure --enable-shared=yes --enable-static=false \ + --with-gmp=$SAGE_LOCAL --with-ntl=$SAGE_LOCAL \ + --with-cddlib=$SAGE_LOCAL --with-4ti2=$SAGE_LOCAL \ + --with-lidia=$SAGE_LOCAL +sdh_make +sdh_make_install diff --git a/build/pkgs/lcalc/package-version.txt b/build/pkgs/lcalc/package-version.txt index 0ac9ab99479..f1b3934b3d1 100644 --- a/build/pkgs/lcalc/package-version.txt +++ b/build/pkgs/lcalc/package-version.txt @@ -1 +1 @@ -1.23.p17 +1.23.p18 diff --git a/build/pkgs/lcalc/spkg-build b/build/pkgs/lcalc/spkg-build index c26b56ee352..cca39a77296 100644 --- a/build/pkgs/lcalc/spkg-build +++ b/build/pkgs/lcalc/spkg-build @@ -20,7 +20,7 @@ fi # Export everything. Probably not necessary in most cases. export CFLAGS -export CXXFLAGS="$CXXFLAGS -std=c++11" +export CXXFLAGS export DEFINES="" diff --git a/build/pkgs/lcalc/spkg-install b/build/pkgs/lcalc/spkg-install index 956adc2c340..7685fc1db9d 100644 --- a/build/pkgs/lcalc/spkg-install +++ b/build/pkgs/lcalc/spkg-install @@ -1,30 +1,14 @@ -if [ -z "$SAGE_LOCAL" ]; then - echo >&2 "Error: SAGE_LOCAL undefined ... exiting" - echo >&2 "Maybe run 'sage -sh'?" - exit 1 -fi - -echo "Now installing lcalc binary, library and header files..." -rm -fr "$SAGE_LOCAL"/include/libLfunction - -success() { - if [ $? -ne 0 ]; then - echo >&2 "Error building the Lcalc package: '$1'" - exit 1 - fi -} - -cd src/src # Now we are in src/src. +cd src/src if [ "$UNAME" = "Darwin" ]; then export LDFLAGS="$LDFLAGS -Wl,-headerpad_max_install_names" fi -export CXXFLAGS="$CXXFLAGS -std=c++11" -sdh_make install INSTALL_DIR="$SAGE_LOCAL" +export CXXFLAGS +mkdir -p "$SAGE_DESTDIR_LOCAL"/{bin,include,lib} +sdh_make_install INSTALL_DIR="$SAGE_DESTDIR_LOCAL" if [ "$UNAME" = "Darwin" ]; then - install_name_tool -id ${SAGE_LOCAL}/lib/libLfunction.dylib "${SAGE_LOCAL}"/lib/libLfunction.dylib - success "install_name_tool" + install_name_tool -id "${SAGE_LOCAL}/lib/libLfunction.dylib" \ + "${SAGE_DESTDIR_LOCAL}/lib/libLfunction.dylib" || exit $? fi - diff --git a/build/pkgs/lcalc/spkg-legacy-uninstall b/build/pkgs/lcalc/spkg-legacy-uninstall new file mode 100644 index 00000000000..3014990369d --- /dev/null +++ b/build/pkgs/lcalc/spkg-legacy-uninstall @@ -0,0 +1 @@ +rm -fr "$SAGE_LOCAL"/include/libLfunction diff --git a/build/pkgs/libffi/SPKG.txt b/build/pkgs/libffi/SPKG.txt new file mode 100644 index 00000000000..aea62b6fbc7 --- /dev/null +++ b/build/pkgs/libffi/SPKG.txt @@ -0,0 +1,55 @@ += libffi = + +== Description == + +Compilers for high level languages generate code that follow certain +conventions. These conventions are necessary, in part, for separate +compilation to work. One such convention is the "calling convention". +The "calling convention" is essentially a set of assumptions made by the +compiler about where function arguments will be found on entry to a +function. A "calling convention" also specifies where the return value +for a function is found. + +Some programs may not know at the time of compilation what arguments are +to be passed to a function. For instance, an interpreter may be told at +run-time about the number and types of arguments used to call a given +function. Libffi can be used in such programs to provide a bridge from +the interpreter program to compiled code. + +The libffi library provides a portable, high level programming interface +to various calling conventions. This allows a programmer to call any +function specified by a call interface description at run time. + +FFI stands for Foreign Function Interface. A foreign function interface +is the popular name for the interface that allows code written in one +language to call code written in another language. The libffi library +really only provides the lowest, machine dependent layer of a fully +featured foreign function interface. A layer must exist above libffi +that handles type conversions for values passed between the two +languages. + +== License == + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +``Software''), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +== Upstream Contact == + +https://sourceware.org/libffi/ +https://github.com/libffi/libffi diff --git a/build/pkgs/libffi/checksums.ini b/build/pkgs/libffi/checksums.ini new file mode 100644 index 00000000000..fbcc6a81efd --- /dev/null +++ b/build/pkgs/libffi/checksums.ini @@ -0,0 +1,4 @@ +tarball=libffi-VERSION.tar.gz +sha1=280c265b789e041c02e5c97815793dfc283fb1e6 +md5=83b89587607e3eb65c70d361f13bab43 +cksum=691100768 diff --git a/build/pkgs/libffi/dependencies b/build/pkgs/libffi/dependencies new file mode 100644 index 00000000000..3546cda4614 --- /dev/null +++ b/build/pkgs/libffi/dependencies @@ -0,0 +1,5 @@ +# no dependencies + +---------- +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/libffi/package-version.txt b/build/pkgs/libffi/package-version.txt new file mode 100644 index 00000000000..e4604e3afd0 --- /dev/null +++ b/build/pkgs/libffi/package-version.txt @@ -0,0 +1 @@ +3.2.1 diff --git a/build/pkgs/libffi/patches/libffi-3.2.1-disable-multi-os-directory.patch b/build/pkgs/libffi/patches/libffi-3.2.1-disable-multi-os-directory.patch new file mode 100644 index 00000000000..b33fba4e539 --- /dev/null +++ b/build/pkgs/libffi/patches/libffi-3.2.1-disable-multi-os-directory.patch @@ -0,0 +1,89 @@ +Trac #27109: Patch based on the upstream fix at +https://github.com/libffi/libffi/commit/877ea9bf9ac2c98cb858c12f5a6aeeec13cf978f#diff-67e997bcfdac55191033d57a16d1408a + +Ensure that libraries are installed to $SAGE_LOCAL/lib and not +$SAGE_LOCAL/lib/$(gcc -print-multi-os-directory) which on some Linuxes +returns things like "../lib64" +--- libffi-3.2.1-orig/configure.ac 2014-11-12 05:56:51.000000000 -0600 ++++ libffi-3.2.1/configure.ac 2015-10-29 15:53:41.695055040 -0500 +@@ -590,6 +590,10 @@ + AC_DEFINE(USING_PURIFY, 1, [Define this if you are using Purify and want to suppress spurious messages.]) + fi) + ++AC_ARG_ENABLE(multi-os-directory, ++[ --disable-multi-os-directory ++ disable use of gcc --print-multi-os-directory to change the library installation directory]) ++ + # These variables are only ever used when we cross-build to X86_WIN32. + # And we only support this with GCC, so... + if test "x$GCC" = "xyes"; then +@@ -601,11 +605,13 @@ + toolexecdir="${libdir}"/gcc-lib/'$(target_alias)' + toolexeclibdir="${libdir}" + fi +- multi_os_directory=`$CC $CFLAGS -print-multi-os-directory` +- case $multi_os_directory in +- .) ;; # Avoid trailing /. +- ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; +- esac ++ if test x"$enable_multi_os_directory" != x"no"; then ++ multi_os_directory=`$CC $CFLAGS -print-multi-os-directory` ++ case $multi_os_directory in ++ .) ;; # Avoid trailing /. ++ ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; ++ esac ++ fi + AC_SUBST(toolexecdir) + else + toolexeclibdir="${libdir}" +--- libffi-3.2.1-orig/configure 2014-11-12 11:59:57.000000000 +0000 ++++ libffi-3.2.1/configure 2015-10-30 19:50:51.082221000 +0000 +@@ -886,6 +886,7 @@ + enable_structs + enable_raw_api + enable_purify_safety ++enable_multi_os_directory + ' + ac_precious_vars='build_alias + host_alias +@@ -1538,6 +1539,8 @@ + --disable-structs omit code for struct support + --disable-raw-api make the raw api unavailable + --enable-purify-safety purify-safe mode ++ --disable-multi-os-directory ++ disable use of gcc --print-multi-os-directory to change the library installation directory + + Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] +@@ -18714,6 +18717,12 @@ + fi + + ++# Check whether --enable-multi-os-directory was given. ++if test "${enable_multi_os_directory+set}" = set; then : ++ enableval=$enable_multi_os_directory; ++fi ++ ++ + # These variables are only ever used when we cross-build to X86_WIN32. + # And we only support this with GCC, so... + if test "x$GCC" = "xyes"; then +@@ -18725,11 +18734,13 @@ + toolexecdir="${libdir}"/gcc-lib/'$(target_alias)' + toolexeclibdir="${libdir}" + fi +- multi_os_directory=`$CC $CFLAGS -print-multi-os-directory` +- case $multi_os_directory in +- .) ;; # Avoid trailing /. +- ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; +- esac ++ if test x"$enable_multi_os_directory" != x"no"; then ++ multi_os_directory=`$CC $CFLAGS -print-multi-os-directory` ++ case $multi_os_directory in ++ .) ;; # Avoid trailing /. ++ ../*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; ++ esac ++ fi + + else + toolexeclibdir="${libdir}" diff --git a/build/pkgs/libffi/spkg-configure.m4 b/build/pkgs/libffi/spkg-configure.m4 new file mode 100644 index 00000000000..ed6f031cf75 --- /dev/null +++ b/build/pkgs/libffi/spkg-configure.m4 @@ -0,0 +1,9 @@ +SAGE_SPKG_CONFIGURE([libffi], [ + dnl First try checking for libffi with pkg-config + PKG_CHECK_MODULES([LIBFFI], [libffi], [], [ + dnl Fallback to manually grubbing around for headers and libs + AC_CHECK_HEADERS([ffi/ffi.h ffi.h], [sage_spkg_install_libffi=no; break], [sage_spkg_install_libffi=yes]) + AC_SEARCH_LIBS([ffi_call], [ffi], [], [sage_spkg_install_libffi=yes]) + ]) +]) + diff --git a/build/pkgs/libffi/spkg-install b/build/pkgs/libffi/spkg-install new file mode 100644 index 00000000000..26a3f158624 --- /dev/null +++ b/build/pkgs/libffi/spkg-install @@ -0,0 +1,16 @@ +# Trac #27109: Don't append $(gcc -print-multi-os-directory) to the install +# path for libraries +LIBFFI_CONFIGURE="--disable-multi-os-directory $LIBFFI_CONFIGURE" + +if [ "$SAGE_FAT_BINARY" = "yes" ]; then + LIBFFI_CONFIGURE="--enable-portable-binary $LIBFFI_CONFIGURE" +fi + +if [ "$SAGE_DEBUG" = "yes" ]; then + LIBFFI_CONFIGURE="--enable-debug $LIBFFI_CONFIGURE" +fi + +cd src +sdh_configure $LIBFFI_CONFIGURE +sdh_make +sdh_make_install diff --git a/build/pkgs/libffi/type b/build/pkgs/libffi/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/libffi/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/libogg/package-version.txt b/build/pkgs/libogg/package-version.txt index 3a3cd8cc8b0..737c844d998 100644 --- a/build/pkgs/libogg/package-version.txt +++ b/build/pkgs/libogg/package-version.txt @@ -1 +1 @@ -1.3.1 +1.3.1.p0 diff --git a/build/pkgs/libogg/spkg-install b/build/pkgs/libogg/spkg-install index 5be210fc206..ec0dcfa6f10 100644 --- a/build/pkgs/libogg/spkg-install +++ b/build/pkgs/libogg/spkg-install @@ -1,30 +1,8 @@ -if [ "$SAGE_LOCAL" = "" ]; then - echo "SAGE_LOCAL undefined ... exiting"; - echo "Maybe run 'sage -sh'?" - exit 1 -fi - -unset RM +unset RM # This was in the original version of this file but no obvious + # reason is given, so we leave it in for now... cd src -./configure \ - --prefix="$SAGE_LOCAL" \ - --libdir="$SAGE_LOCAL/lib" -if [ $? -ne 0 ]; then - echo "Error configuring libogg" - exit 1 -fi - -$MAKE -if [ $? -ne 0 ]; then - echo "Error building libogg" - exit 1 -fi - -$MAKE -j1 install -if [ $? -ne 0 ]; then - echo "Error installing libogg" - exit 1 -fi - +sdh_configure +sdh_make +sdh_make_install -j1 diff --git a/build/pkgs/lidia/package-version.txt b/build/pkgs/lidia/package-version.txt index 138d71973f7..884cca6514d 100644 --- a/build/pkgs/lidia/package-version.txt +++ b/build/pkgs/lidia/package-version.txt @@ -1 +1 @@ -2.3.0+latte-patches-2014-10-04 +2.3.0+latte-patches-2014-10-04.p0 diff --git a/build/pkgs/lidia/spkg-install b/build/pkgs/lidia/spkg-install index 305715cd739..747095fac2d 100644 --- a/build/pkgs/lidia/spkg-install +++ b/build/pkgs/lidia/spkg-install @@ -1,31 +1,14 @@ cd src/ -if [ "$SAGE_LOCAL" = "" ]; then - echo "SAGE_LOCAL undefined ... exiting"; - echo "Maybe run 'sage -sh'?" - exit 1 -fi - -./configure --with-arithmetic=gmp --with-extra-includes="$SAGE_LOCAL/include" --with-extra-libs="$SAGE_LOCAL/lib" --prefix="$SAGE_LOCAL" --enable-shared=yes --enable-static=no -if [ $? -ne 0 ]; then - echo >&2 "Error configuring lidia." - exit 1 -fi - -$MAKE -if [ $? -ne 0 ]; then - echo >&2 "Error building lidia." - exit 1 -fi - -$MAKE install -if [ $? -ne 0 ]; then - echo "Error installing lidia" - exit 1 -fi +sdh_configure --with-arithmetic=gmp \ + --with-extra-includes="$SAGE_LOCAL/include" \ + --with-extra-libs="$SAGE_LOCAL/lib" \ + --enable-shared=yes --enable-static=no +sdh_make +sdh_make_install # LiDIA 2.2.0 installs its headers into lidia/ but expects them in LiDIA!?! # So we make a symbolic link, just in case. # (On the Mac, nothing is done because of its case-preserving, case-insensitive file system.) -( cd "$SAGE_LOCAL/include" && if [ ! -r LiDIA ] ; then ln -s lidia LiDIA; fi || true ) +( cd "$SAGE_DESTDIR_LOCAL/include" && if [ ! -r LiDIA ] ; then ln -s lidia LiDIA; fi || true ) diff --git a/build/pkgs/lrslib/package-version.txt b/build/pkgs/lrslib/package-version.txt index 6ceb12bb4fd..bf0d57af6fa 100644 --- a/build/pkgs/lrslib/package-version.txt +++ b/build/pkgs/lrslib/package-version.txt @@ -1 +1 @@ -062+autotools-2017-03-03 +062+autotools-2017-03-03.p0 diff --git a/build/pkgs/lrslib/spkg-install b/build/pkgs/lrslib/spkg-install index 26eec3447dc..30dacb8b8e4 100644 --- a/build/pkgs/lrslib/spkg-install +++ b/build/pkgs/lrslib/spkg-install @@ -1,23 +1,4 @@ cd src/ - -if [ "$SAGE_LOCAL" = "" ]; then - echo "SAGE_LOCAL undefined ... exiting"; - echo "Maybe run 'sage -sh'?" - exit 1 -fi - -./configure --prefix=$SAGE_LOCAL - -$MAKE - -if [ $? -ne 0 ]; then - echo "Error building lrslib" - exit 1 -fi - -$MAKE install -if [ $? -ne 0 ]; then - echo "Error installing lrslib" - exit 1 -fi - +sdh_configure +sdh_make +sdh_make_install diff --git a/build/pkgs/markupsafe/checksums.ini b/build/pkgs/markupsafe/checksums.ini index 8c5887c4703..efc25d2353b 100644 --- a/build/pkgs/markupsafe/checksums.ini +++ b/build/pkgs/markupsafe/checksums.ini @@ -1,4 +1,4 @@ tarball=markupsafe-VERSION.tar.gz -sha1=9072e80a7faa0f49805737a48f3d871eb1c48728 -md5=2fcedc9284d50e577b5192e8e3578355 -cksum=1008490675 +sha1=ec0079f4d4fbdc92b6fd4720fa04933350044ad5 +md5=49e3f3230cedb7ae34faf06913db83fc +cksum=1060771740 diff --git a/build/pkgs/markupsafe/package-version.txt b/build/pkgs/markupsafe/package-version.txt index d3827e75a5c..9084fa2f716 100644 --- a/build/pkgs/markupsafe/package-version.txt +++ b/build/pkgs/markupsafe/package-version.txt @@ -1 +1 @@ -1.0 +1.1.0 diff --git a/build/pkgs/matplotlib/checksums.ini b/build/pkgs/matplotlib/checksums.ini index ae9567ba538..e4d2cc22179 100644 --- a/build/pkgs/matplotlib/checksums.ini +++ b/build/pkgs/matplotlib/checksums.ini @@ -1,4 +1,4 @@ tarball=matplotlib-VERSION.tar.bz2 -sha1=891e723c88ec2f5003d09692e9591c66a3c664c9 -md5=7f244740247cec0455b56e4749a99fec -cksum=2094355640 +sha1=51699b1691a4e72277137d27920f1bc497ddbe8c +md5=01d80a43aa613bbe08471550ec538a89 +cksum=1426999787 diff --git a/build/pkgs/matplotlib/package-version.txt b/build/pkgs/matplotlib/package-version.txt index b1b25a5ffae..0244bc35e02 100644 --- a/build/pkgs/matplotlib/package-version.txt +++ b/build/pkgs/matplotlib/package-version.txt @@ -1 +1 @@ -2.2.2 +2.2.3.p0 diff --git a/build/pkgs/matplotlib/patches/avoid_asscalar.patch b/build/pkgs/matplotlib/patches/avoid_asscalar.patch new file mode 100644 index 00000000000..2a3af11e008 --- /dev/null +++ b/build/pkgs/matplotlib/patches/avoid_asscalar.patch @@ -0,0 +1,42 @@ +See https://github.com/matplotlib/matplotlib/pull/12508 + +From 958e60389d0115bdc444b46754d3ed704f684517 Mon Sep 17 00:00:00 2001 +From: Antony Lee +Date: Fri, 12 Oct 2018 21:08:32 +0200 +Subject: [PATCH] Backport PR #12478: MAINT: numpy deprecates asscalar in 1.16 + +--- + lib/matplotlib/colors.py | 2 +- + lib/matplotlib/image.py | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py +index fdb4294b969..32e282f6f56 100644 +--- a/lib/matplotlib/colors.py ++++ b/lib/matplotlib/colors.py +@@ -98,7 +98,7 @@ def _sanitize_extrema(ex): + if ex is None: + return ex + try: +- ret = np.asscalar(ex) ++ ret = ex.item() + except AttributeError: + ret = float(ex) + return ret +diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py +index 3ea0cb70d3e..58a28c8f689 100644 +--- a/lib/matplotlib/image.py ++++ b/lib/matplotlib/image.py +@@ -421,9 +421,9 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, + + A_scaled -= a_min + # a_min and a_max might be ndarray subclasses so use +- # asscalar to avoid errors +- a_min = np.asscalar(a_min.astype(scaled_dtype)) +- a_max = np.asscalar(a_max.astype(scaled_dtype)) ++ # item to avoid errors ++ a_min = a_min.astype(scaled_dtype).item() ++ a_max = a_max.astype(scaled_dtype).item() + + if a_min != a_max: + A_scaled /= ((a_max - a_min) / 0.8) diff --git a/build/pkgs/mistune/checksums.ini b/build/pkgs/mistune/checksums.ini index 1ef4feef2e4..4e33968aaa0 100644 --- a/build/pkgs/mistune/checksums.ini +++ b/build/pkgs/mistune/checksums.ini @@ -1,4 +1,4 @@ tarball=mistune-VERSION.tar.gz -sha1=993c67443f393f9645d5f969492a8a107d9edc5f -md5=a5e4043e93fb8f9082e27f29eeb5e054 -cksum=1029851374 +sha1=fd210c038fa7b0f2dffad6847b17dc139e7dd9fe +md5=fb6ab174ece938dea09f8b2adad771e4 +cksum=4120783541 diff --git a/build/pkgs/mistune/package-version.txt b/build/pkgs/mistune/package-version.txt index ee94dd834b5..b60d71966ae 100644 --- a/build/pkgs/mistune/package-version.txt +++ b/build/pkgs/mistune/package-version.txt @@ -1 +1 @@ -0.8.3 +0.8.4 diff --git a/build/pkgs/mpfrcx/checksums.ini b/build/pkgs/mpfrcx/checksums.ini index 9a5eda3bcd8..86eeedc24ad 100644 --- a/build/pkgs/mpfrcx/checksums.ini +++ b/build/pkgs/mpfrcx/checksums.ini @@ -1,4 +1,4 @@ tarball=mpfrcx-VERSION.tar.gz -sha1=72b5d17ff6a207e580eeda74172625a64df364be -md5=bb8d6d48d73414c81d1e601afd690219 -cksum=686701330 +sha1=33fbf3fdbe69fe163fe4f2ebcc79630b11c329e6 +md5=44287784a8ad9a5367c68e9ae636864f +cksum=1348973008 diff --git a/build/pkgs/mpfrcx/package-version.txt b/build/pkgs/mpfrcx/package-version.txt index 2b7c5ae0184..2eb3c4fe4ee 100644 --- a/build/pkgs/mpfrcx/package-version.txt +++ b/build/pkgs/mpfrcx/package-version.txt @@ -1 +1 @@ -0.4.2 +0.5 diff --git a/build/pkgs/mpfrcx/spkg-install b/build/pkgs/mpfrcx/spkg-install index e61a4eca6be..3c2eafb90a4 100644 --- a/build/pkgs/mpfrcx/spkg-install +++ b/build/pkgs/mpfrcx/spkg-install @@ -1,29 +1,6 @@ cd src -# Configuring -./configure --prefix="$SAGE_LOCAL" --with-gmp="$SAGE_LOCAL" \ - --with-mpfr="$SAGE_LOCAL" --with-mpc="$SAGE_LOCAL" \ - --disable-static --enable-shared -if [ $? -ne 0 ]; then - echo >&2 "Error configuring MPFRCX." - exit 1 -fi - -# Building -$MAKE -if [ $? -ne 0 ]; then - echo >&2 "Error building MPFRCX." - exit 1 -fi - -# Cleaning -echo "Deleting old headers" -rm -f "$SAGE_LOCAL"/include/mpfrcx.h -rm -f "$SAGE_LOCAL"/lib/libmpfrcx.* - -# Installing -$MAKE install -if [ $? -ne 0 ]; then - echo >&2 "Error installing MPFRCX." - exit 1 -fi +sdh_configure --with-gmp="$SAGE_LOCAL" --with-mpfr="$SAGE_LOCAL" \ + --with-mpc="$SAGE_LOCAL" --disable-static --enable-shared +sdh_make +sdh_make_install diff --git a/build/pkgs/mpfrcx/spkg-legacy-uninstall b/build/pkgs/mpfrcx/spkg-legacy-uninstall new file mode 100644 index 00000000000..3e418a0f565 --- /dev/null +++ b/build/pkgs/mpfrcx/spkg-legacy-uninstall @@ -0,0 +1,3 @@ +echo "Deleting old headers" +rm -f "$SAGE_LOCAL"/include/mpfrcx.h +rm -f "$SAGE_LOCAL"/lib/libmpfrcx.* diff --git a/build/pkgs/mpir/spkg-install b/build/pkgs/mpir/spkg-install index 754439000e6..86b84036358 100644 --- a/build/pkgs/mpir/spkg-install +++ b/build/pkgs/mpir/spkg-install @@ -195,28 +195,16 @@ case `uname -m` in ;; esac -# If we're bootstrapping GCC from the GCC spkg, don't build the C++ -# interface (cf. #12782), static libraries and disable fat binary. -# After GCC is built, we will build MPIR again. -if [ "$SAGE_BUILD_TOOLCHAIN" = yes ]; then - echo "Building a reduced version of MPIR to bootstrap GCC." - echo "MPIR will later get rebuilt (with the C++ interface and static libraries" - echo "enabled) using the new compiler." - MPIR_CONFIGURE="$MPIR_CONFIGURE --disable-cxx --disable-static" - SAGE_FAT_BINARY=no +# Also build the static library to be used by e.g. ECM +# unless we are on Cygwin where we can only build a shared +# or a static library but not both: +if [ "$UNAME" = "CYGWIN" ]; then + echo "Building MPIR with the C++ interface and (only) shared libraries." + MPIR_CONFIGURE="--enable-cxx $MPIR_CONFIGURE --disable-static" else - # Also build the static library to be used by e.g. ECM - # unless we are on Cygwin where we can only build a shared - # or a static library but not both: - if [ "$UNAME" = "CYGWIN" ]; then - echo "Building MPIR with the C++ interface and (only) shared libraries." - MPIR_CONFIGURE="--enable-cxx $MPIR_CONFIGURE --disable-static" - else - echo "Building MPIR with the C++ interface and (also) static libraries." - MPIR_CONFIGURE="--enable-cxx --enable-static $MPIR_CONFIGURE" - fi + echo "Building MPIR with the C++ interface and (also) static libraries." + MPIR_CONFIGURE="--enable-cxx --enable-static $MPIR_CONFIGURE" fi -# (Further options to 'configure' are added below.) # If SAGE_FAT_BINARY is enabled, then add --enable-fat to configure # options on Linux x86 systems. On other systems, fat binaries are not diff --git a/build/pkgs/mpmath/checksums.ini b/build/pkgs/mpmath/checksums.ini index 76e65164e6f..6c532f911b9 100644 --- a/build/pkgs/mpmath/checksums.ini +++ b/build/pkgs/mpmath/checksums.ini @@ -1,4 +1,4 @@ tarball=mpmath-VERSION.tar.gz -sha1=1df3f1f930b9b7e752c56857f1ac22a62f25b854 -md5=998f10cb231af62743212ca80693f1b5 -cksum=4039911338 +sha1=3f479408ea65b08bc23eeebe5dac2f2293dfec9d +md5=acb1cdddf38e16084628065b174ddbfe +cksum=3387899135 diff --git a/build/pkgs/mpmath/package-version.txt b/build/pkgs/mpmath/package-version.txt index 3eefcb9dd5b..9084fa2f716 100644 --- a/build/pkgs/mpmath/package-version.txt +++ b/build/pkgs/mpmath/package-version.txt @@ -1 +1 @@ -1.0.0 +1.1.0 diff --git a/build/pkgs/nbconvert/checksums.ini b/build/pkgs/nbconvert/checksums.ini index 8d7ba86f9d9..a1d5374294b 100644 --- a/build/pkgs/nbconvert/checksums.ini +++ b/build/pkgs/nbconvert/checksums.ini @@ -1,4 +1,4 @@ tarball=nbconvert-VERSION.tar.gz -sha1=cab9b6e972e18dce1b1ef9562a7a1d36ede5fade -md5=c128d0d93d02f70a85429a383dae96d2 -cksum=877457445 +sha1=5c78227dbf8f9851d6eccd6715d07cdf63f61f00 +md5=6c3364edede7f46a2824c7f47a863359 +cksum=730416769 diff --git a/build/pkgs/nbconvert/dependencies b/build/pkgs/nbconvert/dependencies index 52cea1eb8bc..c4131d26f55 100644 --- a/build/pkgs/nbconvert/dependencies +++ b/build/pkgs/nbconvert/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | pip entrypoints pygments mistune pandocfilters testpath +$(PYTHON) | pip mistune jinja2 pygments traitlets jupyter_core nbformat entrypoints bleach pandocfilters testpath defusedxml ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/nbconvert/package-version.txt b/build/pkgs/nbconvert/package-version.txt index c7cb1311a64..8a30e8f94a3 100644 --- a/build/pkgs/nbconvert/package-version.txt +++ b/build/pkgs/nbconvert/package-version.txt @@ -1 +1 @@ -5.3.1 +5.4.0 diff --git a/build/pkgs/networkx/dependencies b/build/pkgs/networkx/dependencies index 72dd898b463..0756b6ffa81 100644 --- a/build/pkgs/networkx/dependencies +++ b/build/pkgs/networkx/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) decorator | pip +$(PYTHON) decorator | pip nose ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/nose/type b/build/pkgs/nose/type index 134d9bc32d5..a6a7b9cd726 100644 --- a/build/pkgs/nose/type +++ b/build/pkgs/nose/type @@ -1 +1 @@ -optional +standard diff --git a/build/pkgs/notebook/checksums.ini b/build/pkgs/notebook/checksums.ini index 338b72900e5..ec36811e2e8 100644 --- a/build/pkgs/notebook/checksums.ini +++ b/build/pkgs/notebook/checksums.ini @@ -1,4 +1,4 @@ tarball=notebook-VERSION.tar.gz -sha1=f29b7b861b653b2233bdabb77c797d267680233f -md5=05c075697012ea6ba8af820864ff7094 -cksum=2886893729 +sha1=f6d31d620b2817ca99e9e0f6685543effdc4185f +md5=2fe24af4f90055e6156d15bcc9740d76 +cksum=1913637575 diff --git a/build/pkgs/notebook/package-version.txt b/build/pkgs/notebook/package-version.txt index 64ff7ded70d..bdbab226100 100644 --- a/build/pkgs/notebook/package-version.txt +++ b/build/pkgs/notebook/package-version.txt @@ -1 +1 @@ -5.7.1 +5.7.6 diff --git a/build/pkgs/numpy/checksums.ini b/build/pkgs/numpy/checksums.ini index 0934e9e6e25..4ca4526c0af 100644 --- a/build/pkgs/numpy/checksums.ini +++ b/build/pkgs/numpy/checksums.ini @@ -1,4 +1,4 @@ tarball=numpy-VERSION.zip -sha1=6c9b149c8a24ab792828db997fdfcef8bf7a1bc5 -md5=219ac537d12cf06ed14f478662096ebc -cksum=764418747 +sha1=49787ce8e31aff103a7b182749abc3c0249b7f72 +md5=dafda51934f645d888866f98424521ae +cksum=3657383006 diff --git a/build/pkgs/numpy/package-version.txt b/build/pkgs/numpy/package-version.txt index 6498c4ebe53..41c11ffb730 100644 --- a/build/pkgs/numpy/package-version.txt +++ b/build/pkgs/numpy/package-version.txt @@ -1 +1 @@ -1.15.4.p0 +1.16.1 diff --git a/build/pkgs/numpy/spkg-install b/build/pkgs/numpy/spkg-install index 7e89a3c4fb8..8080a3115e0 100644 --- a/build/pkgs/numpy/spkg-install +++ b/build/pkgs/numpy/spkg-install @@ -21,8 +21,6 @@ export NUMPY_FCONFIG="config_fc --noopt --noarch" ################################################ -rm -rf "$SAGE_LOCAL/lib/python*/site-packages/numpy" - sage-python23 setup.py \ --no-user-cfg \ install \ diff --git a/build/pkgs/numpy/spkg-legacy-uninstall b/build/pkgs/numpy/spkg-legacy-uninstall new file mode 100644 index 00000000000..314f91ae482 --- /dev/null +++ b/build/pkgs/numpy/spkg-legacy-uninstall @@ -0,0 +1 @@ +rm -rf "$SAGE_LOCAL"/lib/python*/site-packages/numpy diff --git a/build/pkgs/openblas/SPKG.txt b/build/pkgs/openblas/SPKG.txt index b1ec2516b2f..b152a3007ec 100644 --- a/build/pkgs/openblas/SPKG.txt +++ b/build/pkgs/openblas/SPKG.txt @@ -2,7 +2,7 @@ == Description == -OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version +OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version. == License == @@ -10,7 +10,9 @@ OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version == SPKG Repository == - https://github.com/xianyi/OpenBLAS +GitHub page: https://github.com/xianyi/OpenBLAS + +Releases: https://github.com/xianyi/OpenBLAS/releases == Upstream Contact == diff --git a/build/pkgs/openblas/checksums.ini b/build/pkgs/openblas/checksums.ini index 8d1f200c053..a4078f02423 100644 --- a/build/pkgs/openblas/checksums.ini +++ b/build/pkgs/openblas/checksums.ini @@ -1,4 +1,4 @@ -tarball=OpenBLAS-VERSION.tar.gz -sha1=e2bd66aa5fcdc7dc1ed37ef3ca6948ebcf4617b9 -md5=7688cfbf657b348d510d9b56137ace40 -cksum=2476883907 +tarball=openblas-VERSION.tar.gz +sha1=3ec3607d37c2ea1f7ec1d255f5f38d437489c24d +md5=579bda57f68ea6e9074bf5780e8620bb +cksum=3784443950 diff --git a/build/pkgs/openblas/package-version.txt b/build/pkgs/openblas/package-version.txt index 92ae9f37665..f5447be62e1 100644 --- a/build/pkgs/openblas/package-version.txt +++ b/build/pkgs/openblas/package-version.txt @@ -1 +1 @@ -0.3.3.p0 +0.3.5.p0 diff --git a/build/pkgs/openblas/patches/38cf5d93647bf5ffb5fe3e17447eba0c157bb305.patch b/build/pkgs/openblas/patches/38cf5d93647bf5ffb5fe3e17447eba0c157bb305.patch deleted file mode 100644 index 688c3d84441..00000000000 --- a/build/pkgs/openblas/patches/38cf5d93647bf5ffb5fe3e17447eba0c157bb305.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 38cf5d93647bf5ffb5fe3e17447eba0c157bb305 Mon Sep 17 00:00:00 2001 -From: "Erik M. Bray" -Date: Sun, 28 Oct 2018 21:16:52 +0000 -Subject: [PATCH] ensure that threading has been initialized in the first place - before calling openblas_set_num_threads - ---- - driver/others/blas_server.c | 5 +++++ - driver/others/blas_server_win32.c | 7 ++++++- - 2 files changed, 11 insertions(+), 1 deletion(-) - -diff --git a/driver/others/blas_server.c b/driver/others/blas_server.c -index 6a25e2d07..e5db1804f 100644 ---- a/driver/others/blas_server.c -+++ b/driver/others/blas_server.c -@@ -850,6 +850,11 @@ void goto_set_num_threads(int num_threads) { - - long i; - -+#ifdef SMP_SERVER -+ // Handle lazy re-init of the thread-pool after a POSIX fork -+ if (unlikely(blas_server_avail == 0)) blas_thread_init(); -+#endif -+ - if (num_threads < 1) num_threads = blas_num_threads; - - #ifndef NO_AFFINITY -diff --git a/driver/others/blas_server_win32.c b/driver/others/blas_server_win32.c -index 02a25ac39..bae344c59 100644 ---- a/driver/others/blas_server_win32.c -+++ b/driver/others/blas_server_win32.c -@@ -478,7 +478,12 @@ int BLASFUNC(blas_thread_shutdown)(void){ - - void goto_set_num_threads(int num_threads) - { -- long i; -+ long i; -+ -+#if defined(SMP_SERVER) && defined(OS_CYGWIN_NT) -+ // Handle lazy re-init of the thread-pool after a POSIX fork -+ if (unlikely(blas_server_avail == 0)) blas_thread_init(); -+#endif - - if (num_threads < 1) num_threads = blas_cpu_number; - diff --git a/build/pkgs/openblas/spkg-install b/build/pkgs/openblas/spkg-install index e78891c4c2a..18e6e8bf925 100644 --- a/build/pkgs/openblas/spkg-install +++ b/build/pkgs/openblas/spkg-install @@ -19,6 +19,9 @@ fi echo "Building OpenBLAS: $MAKE $OPENBLAS_CONFIGURE" +# Ensure USE_TLS=1 ; see https://trac.sagemath.org/ticket/27256 +OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE USE_TLS=1" + if ! (sdh_make libs netlib shared $OPENBLAS_CONFIGURE); then if [[ $OPENBLAS_CONFIGURE == *"TARGET"* ]]; then sdh_die "Error building OpenBLAS" diff --git a/build/pkgs/openssl/checksums.ini b/build/pkgs/openssl/checksums.ini index e1f500c95d3..9376553b983 100644 --- a/build/pkgs/openssl/checksums.ini +++ b/build/pkgs/openssl/checksums.ini @@ -1,4 +1,4 @@ tarball=openssl-VERSION.tar.gz -sha1=e4559f31dca37ce815e0c7135488b747745a056d -md5=7079eb017429e0ffb9efb42bf80ccb21 -cksum=3486773463 +sha1=e9710abf5e95c48ebf47991b10cbb48c09dae102 +md5=4532712e7bcc9414f5bce995e4e13930 +cksum=149755279 diff --git a/build/pkgs/openssl/package-version.txt b/build/pkgs/openssl/package-version.txt index 524cb55242b..3e153f5bb62 100644 --- a/build/pkgs/openssl/package-version.txt +++ b/build/pkgs/openssl/package-version.txt @@ -1 +1 @@ -1.1.1 +1.1.1b diff --git a/build/pkgs/openssl/patches/config.patch b/build/pkgs/openssl/patches/config.patch index 996969acd41..4cb5be0a2da 100644 --- a/build/pkgs/openssl/patches/config.patch +++ b/build/pkgs/openssl/patches/config.patch @@ -1,7 +1,7 @@ diff -ru src/config b/config ---- src/config 2011-11-14 22:12:53.000000000 +0100 -+++ b/config 2012-06-20 21:19:42.753359418 +0200 -@@ -411,8 +411,10 @@ +--- src/config 2019-02-26 14:15:30.000000000 +0000 ++++ b/config 2019-03-05 10:53:04.281408906 +0000 +@@ -371,8 +371,10 @@ # this is where the translation occurs into SSLeay terms # --------------------------------------------------------------------------- @@ -14,7 +14,7 @@ diff -ru src/config b/config GCCVER=`sh -c "gcc -dumpversion" 2>/dev/null` if [ "$GCCVER" != "" ]; then # then strip off whatever prefix egcs prepends the number with... -@@ -486,6 +488,11 @@ +@@ -433,6 +435,11 @@ CCVER=${CCVER:-0} @@ -23,6 +23,6 @@ diff -ru src/config b/config + CC="$userCC" +fi + - # read the output of the embedded GuessOS + # read the output of the embedded GuessOS read GUESSOS diff --git a/build/pkgs/p_group_cohomology/dependencies b/build/pkgs/p_group_cohomology/dependencies index 18ace5fa5d9..1b6f9049929 100644 --- a/build/pkgs/p_group_cohomology/dependencies +++ b/build/pkgs/p_group_cohomology/dependencies @@ -1 +1 @@ -singular meataxe | matplotlib gap xz $(SAGERUNTIME) +$(PYTHON) cython cysignals singular meataxe $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/structure/element.pxd $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/matrix/matrix0.pxd $(SAGE_SRC)/sage/libs/meataxe.pxd $(SAGE_SRC)/sage/rings/morphism.pxd | pip matplotlib gap xz $(SAGERUNTIME) diff --git a/build/pkgs/packaging/checksums.ini b/build/pkgs/packaging/checksums.ini index 48ca3580039..a73a2bf22a1 100644 --- a/build/pkgs/packaging/checksums.ini +++ b/build/pkgs/packaging/checksums.ini @@ -1,4 +1,4 @@ tarball=packaging-VERSION.tar.gz -sha1=8dbd54a645fcc7951fcd6c06e9ac6494a0ada816 -md5=8baf8241d1b6b0a5fae9b00f359976a8 -cksum=851978191 +sha1=8a64f2b9c411b7275ba1c10ceadbd01b6779d21d +md5=b066f2a33524519cf4e97ab69f462479 +cksum=1955944718 diff --git a/build/pkgs/packaging/package-version.txt b/build/pkgs/packaging/package-version.txt index 641f83803e5..0034b6527fe 100644 --- a/build/pkgs/packaging/package-version.txt +++ b/build/pkgs/packaging/package-version.txt @@ -1 +1 @@ -17.1 +18.0 diff --git a/build/pkgs/pari/package-version.txt b/build/pkgs/pari/package-version.txt index 6ceb272eecd..742f74611f1 100644 --- a/build/pkgs/pari/package-version.txt +++ b/build/pkgs/pari/package-version.txt @@ -1 +1 @@ -2.11.1 +2.11.1.p1 diff --git a/build/pkgs/pari/patches/red_montgomery.patch b/build/pkgs/pari/patches/red_montgomery.patch new file mode 100644 index 00000000000..11bf9f3395d --- /dev/null +++ b/build/pkgs/pari/patches/red_montgomery.patch @@ -0,0 +1,21 @@ +commit aa1ee6e0898d177e6bcf49237d82c804bc410985 +Author: Karim Belabas +Date: Tue Nov 27 15:40:16 2018 +0100 + + 47- gmp kernel: off-by-1 error in red_mongomery + + [read uninitialized memory, then ignores result] + +diff --git a/src/kernel/gmp/mp.c b/src/kernel/gmp/mp.c +index 1c30d0a..3a534f5 100644 +--- a/src/kernel/gmp/mp.c ++++ b/src/kernel/gmp/mp.c +@@ -1005,7 +1005,7 @@ red_montgomery(GEN T, GEN N, ulong inv) + } + if (carry) + { /* Td > N overflows (k+1 words), set Td := Td - N */ +- GEN NE = N + k+2; ++ GEN NE = N + k+1; + Td = Te; + Nd = Ne; + t = subll(*++Td, *++Nd); *Td = t; diff --git a/build/pkgs/pari/spkg-install b/build/pkgs/pari/spkg-install index 63a291c5926..91973824259 100644 --- a/build/pkgs/pari/spkg-install +++ b/build/pkgs/pari/spkg-install @@ -2,171 +2,107 @@ ## PARI ########################################### -if [ -z "$SAGE_LOCAL" ]; then - echo "SAGE_LOCAL undefined ... exiting" - echo "Maybe run 'sage -sh'?" - exit 1 -fi - -TOP=`pwd` - cd src # Prepare all variables for building PARI/GP, except for CFLAGS -set_environment() -{ - # Save current working directory (the src directory) - CUR=`pwd` - - # This is needed or there are weird locale problems involving rpath - # with building Sage: - LANG=C - export LANG - - # Pari ignores LDFLAGS when linking libpari-gmp.so, so we trick it: - DLLDFLAGS="$LDFLAGS" - export DLLDFLAGS - - # PARI does not build correctly with LD set (which is set by - # sage-env). PARI actually needs LD set to a compiler to do the - # linking, not to the linker directly. - unset LD - - # Let the user pass extra parameters to PARI's "Configure", e.g. - # to specify desired graphics support (which is disabled by default): - if [ -z "$PARI_CONFIGURE" ]; then - echo "============================================================" - echo "Configuring PARI/GP without graphics support (for plotting)." - echo "If you need it, pass the appropriate option(s) to PARI by" - echo "setting and exporting \$PARI_CONFIGURE prior to building" - echo "Sage (or at least before you build/install the PARI spkg)," - echo "e.g. by typing at the shell prompt:" - echo " export PARI_CONFIGURE=\"--graphic=auto\"" - echo "or" - echo " export PARI_CONFIGURE=\"--with-fltk\"" - echo "Note that PARI doesn't treat it as an error if the requested" - echo "graphics library or the corresponding header files are not" - echo "found; it will then simply disable graphics support." - echo "Please consult the PARI documentation for further details." - echo "============================================================" - - PARI_CONFIGURE="--graphic=none" - else - echo "============================================================" - echo "Configuring PARI/GP with additional user-specified options:" - echo " PARI_CONFIGURE=\"$PARI_CONFIGURE\"" - - # Do NOT add "--graphic=none" if the user provided one of these: - # "--with-fltk[=...]", "--with-qt[=...]" - # Comment by leif: This misbehavoir seems to have been fixed in - # PARI 2.4.3; the following doesn't hurt though: - if ! (echo "$PARI_CONFIGURE" | egrep -- "--with-fltk|--with-qt") \ - >/dev/null; - then - echo "To avoid unexpected behavior, we prepend \"--graphic=none\":" - PARI_CONFIGURE="--graphic=none $PARI_CONFIGURE" - echo " \"$PARI_CONFIGURE\"" - echo "(Disabling graphics can be overridden by user settings.)" - fi - echo "============================================================" - fi - - # Allow the user to enable PARI self-tuning. - # This is time-consuming, but some may want to do it. - # Comment by leif: Also, PARI's Configure calls "make" (instead of $MAKE) - # if we do tuning, so: - # TODO: Replace that in our patched version of Configure! - if [ "$SAGE_TUNE_pari" = yes -o "$SAGE_TUNE_PARI" = yes ]; then - echo - echo 'PARI/GP will be tuned for your system since you set SAGE_TUNE_pari="yes".' - echo 'This can take a long time.' - echo 'WARNING: Tuning PARI/GP is unreliable. You may find your build of PARI' - echo 'fails, or PARI/GP does not work properly once built. We recommend to' - echo 'build this package with SAGE_CHECK="yes".' - echo - PARI_CONFIGURE="$PARI_CONFIGURE --tune" - else - echo - echo 'To minimize Sage build time and to ensure the best reliability, PARI/GP' - echo 'will not be tuned for your system. Experience shows tuning can be' - echo 'unreliable. If you do want to tune PARI/GP, set the environment' - echo 'variable SAGE_TUNE_pari="yes" by typing the following before building' - echo 'Sage (or at least before building/installing PARI/GP):' - echo ' SAGE_TUNE_pari=yes' - echo ' export SAGE_TUNE_pari' - echo 'If you do this, we strongly recommend to also enable checking. For this,' - echo 'type the following:' - echo ' SAGE_CHECK=yes' - echo ' export SAGE_CHECK' - echo - fi - - unset GP_INSTALL_PREFIX # we do not want this to be set by the user - # In addition, a lot of variables used (internally) by PARI might un- - # intentionally get their values from the "global" environment, so it's - # safer to clear them here (not further messing up PARI's scripts): - unset static tune timing_fun error - unset enable_tls - unset with_fltk with_qt - unset with_ncurses_lib - unset with_readline_include with_readline_lib without_readline - unset with_gmp_include with_gmp_lib without_gmp - unset dfltbindir dfltdatadir dfltemacsdir dfltincludedir - unset dfltlibdir dfltmandir dfltsysdatadir dfltobjdir - # The following get set because we pass the respective parameters: - # prefix kernel with_gmp with_readline -} - - -# Build PARI/GP -build() -{ - # Configure PARI/GP, forcing bash instead of /bin/sh. It is not - # strictly necessary to use bash, but it hopefully makes the script - # less system-dependent. Since Sage assumes the existence of bash - # anyway, it doesn't hurt either. -- jdemeyer - # - # Note that "--graphic=none" is (usually) added to PARI_CONFIGURE: - bash ./Configure --prefix="$SAGE_LOCAL" \ - --with-readline="$SAGE_LOCAL" --with-gmp="$SAGE_LOCAL" \ - --with-runtime-perl="/usr/bin/env perl" \ - --kernel=gmp $PARI_CONFIGURE - - if [ $? -ne 0 ]; then - echo >&2 "Error: Configuring PARI with readline and GMP kernel failed." - exit 1 - fi - - if [ ! -f Makefile ]; then - echo >&2 "Error: Unable to configure PARI: No Makefile generated!" - exit 1 - fi - - $MAKE $PARI_MAKEFLAGS gp - if [ $? -ne 0 ]; then - echo >&2 "Error: Building PARI/GP failed." - exit 1 +# This is needed or there are weird locale problems involving rpath +# with building Sage: +LANG=C +export LANG + +# Pari ignores LDFLAGS when linking libpari-gmp.so, so we trick it: +DLLDFLAGS="$LDFLAGS" +export DLLDFLAGS + +# PARI does not build correctly with LD set (which is set by +# sage-env). PARI actually needs LD set to a compiler to do the +# linking, not to the linker directly. +unset LD + +# Let the user pass extra parameters to PARI's "Configure", e.g. +# to specify desired graphics support (which is disabled by default): +if [ -z "$PARI_CONFIGURE" ]; then + echo "============================================================" + echo "Configuring PARI/GP without graphics support (for plotting)." + echo "If you need it, pass the appropriate option(s) to PARI by" + echo "setting and exporting \$PARI_CONFIGURE prior to building" + echo "Sage (or at least before you build/install the PARI spkg)," + echo "e.g. by typing at the shell prompt:" + echo " export PARI_CONFIGURE=\"--graphic=auto\"" + echo "or" + echo " export PARI_CONFIGURE=\"--with-fltk\"" + echo "Note that PARI doesn't treat it as an error if the requested" + echo "graphics library or the corresponding header files are not" + echo "found; it will then simply disable graphics support." + echo "Please consult the PARI documentation for further details." + echo "============================================================" + + PARI_CONFIGURE="--graphic=none" +else + echo "============================================================" + echo "Configuring PARI/GP with additional user-specified options:" + echo " PARI_CONFIGURE=\"$PARI_CONFIGURE\"" + + # Do NOT add "--graphic=none" if the user provided one of these: + # "--with-fltk[=...]", "--with-qt[=...]" + # Comment by leif: This misbehavoir seems to have been fixed in + # PARI 2.4.3; the following doesn't hurt though: + if ! (echo "$PARI_CONFIGURE" | egrep -- "--with-fltk|--with-qt") \ + >/dev/null; + then + echo "To avoid unexpected behavior, we prepend \"--graphic=none\":" + PARI_CONFIGURE="--graphic=none $PARI_CONFIGURE" + echo " \"$PARI_CONFIGURE\"" + echo "(Disabling graphics can be overridden by user settings.)" fi -} - - -install() -{ - echo "Installing PARI/GP..." + echo "============================================================" +fi - # install non-parallel (-j1) because of race conditions - $MAKE -j1 install install-lib-sta - if [ $? -ne 0 ]; then - echo >&2 "Error installing PARI" - exit 1 - fi +# Allow the user to enable PARI self-tuning. +# This is time-consuming, but some may want to do it. +# Comment by leif: Also, PARI's Configure calls "make" (instead of $MAKE) +# if we do tuning, so: +# TODO: Replace that in our patched version of Configure! +if [ "$SAGE_TUNE_pari" = yes -o "$SAGE_TUNE_PARI" = yes ]; then + echo + echo 'PARI/GP will be tuned for your system since you set SAGE_TUNE_pari="yes".' + echo 'This can take a long time.' + echo 'WARNING: Tuning PARI/GP is unreliable. You may find your build of PARI' + echo 'fails, or PARI/GP does not work properly once built. We recommend to' + echo 'build this package with SAGE_CHECK="yes".' + echo + PARI_CONFIGURE="$PARI_CONFIGURE --tune" +else + echo + echo 'To minimize Sage build time and to ensure the best reliability, PARI/GP' + echo 'will not be tuned for your system. Experience shows tuning can be' + echo 'unreliable. If you do want to tune PARI/GP, set the environment' + echo 'variable SAGE_TUNE_pari="yes" by typing the following before building' + echo 'Sage (or at least before building/installing PARI/GP):' + echo ' SAGE_TUNE_pari=yes' + echo ' export SAGE_TUNE_pari' + echo 'If you do this, we strongly recommend to also enable checking. For this,' + echo 'type the following:' + echo ' SAGE_CHECK=yes' + echo ' export SAGE_CHECK' + echo +fi - cd "$CUR" -} +unset GP_INSTALL_PREFIX # we do not want this to be set by the user +# In addition, a lot of variables used (internally) by PARI might un- +# intentionally get their values from the "global" environment, so it's +# safer to clear them here (not further messing up PARI's scripts): +unset static tune timing_fun error +unset enable_tls +unset with_fltk with_qt +unset with_ncurses_lib +unset with_readline_include with_readline_lib without_readline +unset with_gmp_include with_gmp_lib without_gmp +unset dfltbindir dfltdatadir dfltemacsdir dfltincludedir +unset dfltlibdir dfltmandir dfltsysdatadir dfltobjdir -set_environment # Set CFLAGS if [ "$SAGE_DEBUG" = yes ]; then @@ -187,18 +123,23 @@ else fi export CFLAGS -build -install -if [ "$UNAME" = "Darwin" ]; then - pari_shlib="libpari.dylib" -elif [ "$UNAME" = "CYGWIN" ]; then - pari_shlib="libpari.dll" -else - pari_shlib="libpari.so" -fi -if [ ! -f "$SAGE_LOCAL/lib/$pari_shlib" ]; then - echo "Error: PARI's shared library '$pari_shlib' has not been installed!" - exit 1 -fi +# Build PARI/GP +# Configure PARI/GP, forcing bash instead of /bin/sh. It is not +# strictly necessary to use bash, but it hopefully makes the script +# less system-dependent. Since Sage assumes the existence of bash +# anyway, it doesn't hurt either. -- jdemeyer +# +# Note that "--graphic=none" is (usually) added to PARI_CONFIGURE: +bash ./Configure --prefix="$SAGE_LOCAL" \ + --with-readline="$SAGE_LOCAL" --with-gmp="$SAGE_LOCAL" \ + --with-runtime-perl="/usr/bin/env perl" \ + --kernel=gmp $PARI_CONFIGURE || \ + sdh_die "Error configuring PARI with readline and GMP kernel failed." + +sdh_make $PARI_MAKEFLAGS gp + + +# install non-parallel (-j1) because of race conditions +sdh_make_install -j1 install-lib-sta diff --git a/build/pkgs/pathlib2/checksums.ini b/build/pkgs/pathlib2/checksums.ini index fbcd4ee1a83..01d841eedb8 100644 --- a/build/pkgs/pathlib2/checksums.ini +++ b/build/pkgs/pathlib2/checksums.ini @@ -1,4 +1,4 @@ tarball=pathlib2-VERSION.tar.gz -sha1=35fbe0b57663f4dd79e3671e4894ab23d124186c -md5=89c90409d11fd5947966b6a30a47d18c -cksum=4259834680 +sha1=3a902176bb4b5b7f1f112e501409b84c21c7f50c +md5=f9ede5c162ea6fc6a3b1d26db53bb6a2 +cksum=1296606336 diff --git a/build/pkgs/pathlib2/package-version.txt b/build/pkgs/pathlib2/package-version.txt index 276cbf9e285..0bee604df76 100644 --- a/build/pkgs/pathlib2/package-version.txt +++ b/build/pkgs/pathlib2/package-version.txt @@ -1 +1 @@ -2.3.0 +2.3.3 diff --git a/build/pkgs/pickleshare/checksums.ini b/build/pkgs/pickleshare/checksums.ini index 60e98e97533..13537caad36 100644 --- a/build/pkgs/pickleshare/checksums.ini +++ b/build/pkgs/pickleshare/checksums.ini @@ -1,4 +1,4 @@ tarball=pickleshare-VERSION.tar.gz -sha1=415d9b95c157819a3b6e646ae8382352f00c8e10 -md5=6a9e5dd8dfc023031f6b7b3f824cab12 -cksum=50416379 +sha1=c583011994ee0733ea4a6330af81c175180dcc3d +md5=44ab782615894a812ab96669a122a634 +cksum=1895214791 diff --git a/build/pkgs/pickleshare/package-version.txt b/build/pkgs/pickleshare/package-version.txt index 0a1ffad4b4d..8bd6ba8c5c3 100644 --- a/build/pkgs/pickleshare/package-version.txt +++ b/build/pkgs/pickleshare/package-version.txt @@ -1 +1 @@ -0.7.4 +0.7.5 diff --git a/build/pkgs/pillow/checksums.ini b/build/pkgs/pillow/checksums.ini index 7a80dbd857f..83633e72667 100644 --- a/build/pkgs/pillow/checksums.ini +++ b/build/pkgs/pillow/checksums.ini @@ -1,4 +1,4 @@ tarball=Pillow-VERSION.tar.gz -sha1=f070a099690b4a8d1539644c98c7fe65e66c8149 -md5=ac8904e17922c8a699ff7d6cb0cf89cd -cksum=2761365403 +sha1=b1d2d766b82efe28958025e4b3ee109e591cb483 +md5=0da5a4c9c548aa5cfe999302aea8c8f1 +cksum=379384082 diff --git a/build/pkgs/pillow/package-version.txt b/build/pkgs/pillow/package-version.txt index 1dcc89a3546..03f488b076a 100644 --- a/build/pkgs/pillow/package-version.txt +++ b/build/pkgs/pillow/package-version.txt @@ -1 +1 @@ -4.3.0.p0 +5.3.0 diff --git a/build/pkgs/pip/checksums.ini b/build/pkgs/pip/checksums.ini index e66ca6abf34..a11ba827600 100644 --- a/build/pkgs/pip/checksums.ini +++ b/build/pkgs/pip/checksums.ini @@ -1,4 +1,4 @@ tarball=pip-VERSION.tar.gz -sha1=337f4694bfcd4d698d9b02b38a7520fabc42a1d9 -md5=52f75ceb21e96c258f289859a2996b60 -cksum=3433326775 +sha1=1226368a8d39bd8b945517b6f7cb9802b279564e +md5=75cad449ad62c88b22de317a26781714 +cksum=886798891 diff --git a/build/pkgs/pip/package-version.txt b/build/pkgs/pip/package-version.txt index 0034b6527fe..33718932a44 100644 --- a/build/pkgs/pip/package-version.txt +++ b/build/pkgs/pip/package-version.txt @@ -1 +1 @@ -18.0 +18.1 diff --git a/build/pkgs/pip/spkg-install b/build/pkgs/pip/spkg-install index 906ce46b68e..db656d4b4de 100644 --- a/build/pkgs/pip/spkg-install +++ b/build/pkgs/pip/spkg-install @@ -3,7 +3,7 @@ cd src # pip can install itself! But first we need to ensure that the pip # source directory in on the PYTHONPATH -export PYTHONPATH=`cd src && pwd` +export PYTHONPATH="$(pwd)/src" # need to use --upgrade or --ignore-installed; Otherwise pip, which is # importing itself, will think itself is already installed diff --git a/build/pkgs/pkgconfig/checksums.ini b/build/pkgs/pkgconfig/checksums.ini index 01bce43d771..2c33892c2e6 100644 --- a/build/pkgs/pkgconfig/checksums.ini +++ b/build/pkgs/pkgconfig/checksums.ini @@ -1,4 +1,4 @@ tarball=pkgconfig-VERSION.tar.gz -sha1=0d6298425189a359a4f21cdad0d0d4baa9fa2de1 -md5=81a8f6ef3371831d081e03db39e09683 -cksum=1774453423 +sha1=d412ffa23fb016affc0b4d2a0ed656f34d960812 +md5=f3a5314d7364832b26f404eae4722bbb +cksum=261359121 diff --git a/build/pkgs/pkgconfig/package-version.txt b/build/pkgs/pkgconfig/package-version.txt index aae5f783ddf..88c5fb891dc 100644 --- a/build/pkgs/pkgconfig/package-version.txt +++ b/build/pkgs/pkgconfig/package-version.txt @@ -1 +1 @@ -1.2.2.p0 +1.4.0 diff --git a/build/pkgs/pkgconfig/patches/remove_nose.patch b/build/pkgs/pkgconfig/patches/remove_nose.patch deleted file mode 100644 index 30e008f79b4..00000000000 --- a/build/pkgs/pkgconfig/patches/remove_nose.patch +++ /dev/null @@ -1,10 +0,0 @@ -diff -ur old/setup.py src/setup.py ---- old/setup.py 2013-11-06 15:14:54.000000000 +0100 -+++ src/setup.py 2014-02-28 11:33:12.718096602 +0100 -@@ -12,6 +12,5 @@ - packages=['pkgconfig'], - description="Interface Python with pkg-config", - long_description=open('README.rst').read(), -- setup_requires=['nose>=1.0'], - test_suite='test', - ) diff --git a/build/pkgs/plantri/spkg-install b/build/pkgs/plantri/spkg-install index c26e57bc137..2ea192b6130 100644 --- a/build/pkgs/plantri/spkg-install +++ b/build/pkgs/plantri/spkg-install @@ -1,21 +1,5 @@ -if [ -z "$SAGE_LOCAL" ]; then - echo >&2 "SAGE_LOCAL undefined ... exiting" - echo >&2 "Maybe run 'sage --sh'?" - exit 1 -fi - cd src -$MAKE plantri -if [ $? -ne 0 ]; then - echo >&2 "Error building plantri." - exit 1 -fi - -echo >&2 "Copying plantri..." -cp plantri $SAGE_LOCAL/bin/plantri -if [ $? -ne 0 ]; then - echo >&2 "Error installing plantri." - exit 1 -fi +sdh_make plantri +sdh_install plantri $SAGE_LOCAL/bin/ diff --git a/build/pkgs/pplpy/SPKG.txt b/build/pkgs/pplpy/SPKG.txt new file mode 100644 index 00000000000..2e486a634fe --- /dev/null +++ b/build/pkgs/pplpy/SPKG.txt @@ -0,0 +1,17 @@ += pplpy = + +== Description == + +PPL Python wrapper + +This Python package provides a wrapper to the C++ Parma Polyhedra Library (PPL). + +The whole package started as a fork of a tiny part of the Sage software. + +== License == + +GPL version 3 + +== Upstream Contact == + +* https://github.com/videlec/pplpy diff --git a/build/pkgs/pplpy/checksums.ini b/build/pkgs/pplpy/checksums.ini new file mode 100644 index 00000000000..05344a1170d --- /dev/null +++ b/build/pkgs/pplpy/checksums.ini @@ -0,0 +1,4 @@ +tarball=pplpy-VERSION.tar.gz +sha1=34bc063ceb14127e4a9b91a869bd36056ca91dc7 +md5=aeaa68b4b3440914292b93b703f344b9 +cksum=2040399641 diff --git a/build/pkgs/pplpy/dependencies b/build/pkgs/pplpy/dependencies new file mode 100644 index 00000000000..a36dbf85e2b --- /dev/null +++ b/build/pkgs/pplpy/dependencies @@ -0,0 +1,5 @@ +$(PYTHON) $(MP_LIBRARY) gmpy2 cysignals mpfr mpc ppl | pip sphinx + +---------- +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/pplpy/package-version.txt b/build/pkgs/pplpy/package-version.txt new file mode 100644 index 00000000000..b60d71966ae --- /dev/null +++ b/build/pkgs/pplpy/package-version.txt @@ -0,0 +1 @@ +0.8.4 diff --git a/build/pkgs/pplpy/spkg-check b/build/pkgs/pplpy/spkg-check new file mode 100644 index 00000000000..52aeee56eb2 --- /dev/null +++ b/build/pkgs/pplpy/spkg-check @@ -0,0 +1 @@ +cd src && sage-python23 setup.py test diff --git a/build/pkgs/pplpy/spkg-install b/build/pkgs/pplpy/spkg-install new file mode 100644 index 00000000000..3239b905461 --- /dev/null +++ b/build/pkgs/pplpy/spkg-install @@ -0,0 +1,7 @@ +cd src && sdh_pip_install . + +# During spkg-install execution, the compiled files are still in a temporary +# directory and are copied to their destination after the end of the script. +# As sphinx need theses compiled files, the compilation and installation +# of pplpy's documentation is done after the end of spkg-install +# in the spkg-postinst script. diff --git a/build/pkgs/pplpy/spkg-postinst b/build/pkgs/pplpy/spkg-postinst new file mode 100644 index 00000000000..2e668e4b1c5 --- /dev/null +++ b/build/pkgs/pplpy/spkg-postinst @@ -0,0 +1,11 @@ +if [[ "$SAGE_SPKG_INSTALL_DOCS" != no ]] ; then + # Compile pplpy's documentation + cd src + cd docs + $MAKE html + + # install pplpy's documentation + PPLPY_DOCS=$SAGE_SHARE/doc/pplpy + mkdir -p $PPLPY_DOCS + cp -r build/html/* $PPLPY_DOCS +fi diff --git a/build/pkgs/pplpy/spkg-postrm b/build/pkgs/pplpy/spkg-postrm new file mode 100644 index 00000000000..8caa3223637 --- /dev/null +++ b/build/pkgs/pplpy/spkg-postrm @@ -0,0 +1,3 @@ +# Delete pplpy's documentation +echo Remove $SAGE_SHARE/doc/pplpy directory. +rm -rf $SAGE_SHARE/doc/pplpy diff --git a/build/pkgs/pplpy/type b/build/pkgs/pplpy/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/pplpy/type @@ -0,0 +1 @@ +standard diff --git a/build/pkgs/primecount/spkg-install b/build/pkgs/primecount/spkg-install index de130086b40..dcfb550caa5 100644 --- a/build/pkgs/primecount/spkg-install +++ b/build/pkgs/primecount/spkg-install @@ -4,12 +4,6 @@ # ############################################################################### -if [ "$SAGE_LOCAL" = "" ]; then - echo >&2 "Error: SAGE_LOCAL undefined - exiting..." - echo >&2 "Maybe run 'sage -sh'?" - exit 1 -fi - cd src if [ "$SAGE_FAT_BINARY" = yes ]; then @@ -17,12 +11,11 @@ if [ "$SAGE_FAT_BINARY" = yes ]; then fi echo "Configuring primecount." -cmake . -DCMAKE_INSTALL_PREFIX=${SAGE_LOCAL} \ - -DCMAKE_VERBOSE_MAKEFILE=ON \ - -DBUILD_STATIC_LIBS=OFF \ - -DBUILD_SHARED_LIBS=ON \ - -DBUILD_TESTS=ON \ - ${EXTRA_OPTS} +sdh_cmake -DCMAKE_VERBOSE_MAKEFILE=ON \ + -DBUILD_STATIC_LIBS=OFF \ + -DBUILD_SHARED_LIBS=ON \ + -DBUILD_TESTS=ON \ + ${EXTRA_OPTS} sdh_make diff --git a/build/pkgs/prometheus_client/checksums.ini b/build/pkgs/prometheus_client/checksums.ini index b8e6d541d29..04d9f99ffa7 100644 --- a/build/pkgs/prometheus_client/checksums.ini +++ b/build/pkgs/prometheus_client/checksums.ini @@ -1,4 +1,4 @@ tarball=prometheus_client-VERSION.tar.gz -sha1=43aed68fa484883fa53be38f1bf19790ea9a4438 -md5=adfd75da26ae2c3e139e66922a687919 -cksum=3901571410 +sha1=885ba6707492d8ff97e3f612ed266f0273ee8363 +md5=22b08b93951e3c66a65e9b11b9215221 +cksum=1404641856 diff --git a/build/pkgs/prometheus_client/package-version.txt b/build/pkgs/prometheus_client/package-version.txt index 9e11b32fcaa..8f0916f768f 100644 --- a/build/pkgs/prometheus_client/package-version.txt +++ b/build/pkgs/prometheus_client/package-version.txt @@ -1 +1 @@ -0.3.1 +0.5.0 diff --git a/build/pkgs/pygments/checksums.ini b/build/pkgs/pygments/checksums.ini index 6b7ab23a910..01b50aad0f1 100644 --- a/build/pkgs/pygments/checksums.ini +++ b/build/pkgs/pygments/checksums.ini @@ -1,4 +1,4 @@ tarball=Pygments-VERSION.tar.gz -sha1=5c6714bd6fd950c1478889f7b72fc7f6771d5163 -md5=13037baca42f16917cbd5ad2fab50844 -cksum=1747340458 +sha1=88f8da2d10cb21362a9e04b154932892c2695670 +md5=b7d04e2cd87c405938f1e494e2969814 +cksum=332653919 diff --git a/build/pkgs/pygments/package-version.txt b/build/pkgs/pygments/package-version.txt index d2ccf5ed805..2bf1c1ccf36 100644 --- a/build/pkgs/pygments/package-version.txt +++ b/build/pkgs/pygments/package-version.txt @@ -1 +1 @@ -2.2.0.p0 +2.3.1 diff --git a/build/pkgs/pynac/checksums.ini b/build/pkgs/pynac/checksums.ini index 04a0b7bc329..59dc8840178 100644 --- a/build/pkgs/pynac/checksums.ini +++ b/build/pkgs/pynac/checksums.ini @@ -1,4 +1,4 @@ tarball=pynac-VERSION.tar.bz2 -sha1=c3db84cb0d003eaabbdfedd4a6c622fe53214442 -md5=67e1a57621bf7d84ed06ac95428815cf -cksum=3267245430 +sha1=fc7c792fc4646cccea5ef0e24dd5a269f2589e5c +md5=edd4e2cf1f3f6c3269d57fd89790b52a +cksum=2239304387 diff --git a/build/pkgs/pynac/package-version.txt b/build/pkgs/pynac/package-version.txt index 450e18f0f0f..2151cfabcdd 100644 --- a/build/pkgs/pynac/package-version.txt +++ b/build/pkgs/pynac/package-version.txt @@ -1 +1 @@ -0.7.22 +0.7.24 diff --git a/build/pkgs/pyparsing/checksums.ini b/build/pkgs/pyparsing/checksums.ini index fd1a07663d7..32e35affcad 100644 --- a/build/pkgs/pyparsing/checksums.ini +++ b/build/pkgs/pyparsing/checksums.ini @@ -1,4 +1,4 @@ tarball=pyparsing-VERSION.tar.gz -sha1=f8504f4f8baa69de5b63fd2275a0ebf36a2cf74b -md5=0214e42d63af850256962b6744c948d9 -cksum=124369801 +sha1=4c1668f50cf50feff838c1d2172ac034d42ff824 +md5=f855a0a8d0259b36fac1fa6581f401ef +cksum=274928572 diff --git a/build/pkgs/pyparsing/package-version.txt b/build/pkgs/pyparsing/package-version.txt index ccbccc3dc62..276cbf9e285 100644 --- a/build/pkgs/pyparsing/package-version.txt +++ b/build/pkgs/pyparsing/package-version.txt @@ -1 +1 @@ -2.2.0 +2.3.0 diff --git a/build/pkgs/pytz/checksums.ini b/build/pkgs/pytz/checksums.ini index 98188ba9ff0..08b15bb59c5 100644 --- a/build/pkgs/pytz/checksums.ini +++ b/build/pkgs/pytz/checksums.ini @@ -1,4 +1,4 @@ tarball=pytz-VERSION.tar.bz2 -sha1=505c04511467366cd3c1c1daa73d3fdc93966f7e -md5=7006b56c0d68a162d9fe57d4249c3171 -cksum=1633398709 +sha1=8a01d7f19c8b8b189827e026b76c51be4b537b89 +md5=4b91594c440aa20c76ac92043efa75e1 +cksum=591864951 diff --git a/build/pkgs/pytz/package-version.txt b/build/pkgs/pytz/package-version.txt index 7826a721e05..b3d91a9d2f9 100644 --- a/build/pkgs/pytz/package-version.txt +++ b/build/pkgs/pytz/package-version.txt @@ -1 +1 @@ -2017.3 +2018.7 diff --git a/build/pkgs/pyzmq/checksums.ini b/build/pkgs/pyzmq/checksums.ini index 18ba8c44130..5da38896794 100644 --- a/build/pkgs/pyzmq/checksums.ini +++ b/build/pkgs/pyzmq/checksums.ini @@ -1,4 +1,4 @@ tarball=pyzmq-VERSION.tar.gz -sha1=95e87324075adbcd69f28017c2a12e16e176db6e -md5=aecdfc328193fbd81f6dc23228319943 -cksum=1545898385 +sha1=d0e5d7dd59f2398345fc4bacf5ee91241d857f0d +md5=6f5d77cb5ec1617ce9b6e5ad7c6174fb +cksum=3737366397 diff --git a/build/pkgs/pyzmq/package-version.txt b/build/pkgs/pyzmq/package-version.txt index d9e58927a66..59a75133a21 100644 --- a/build/pkgs/pyzmq/package-version.txt +++ b/build/pkgs/pyzmq/package-version.txt @@ -1 +1 @@ -17.1.0 +17.1.2 diff --git a/build/pkgs/r/checksums.ini b/build/pkgs/r/checksums.ini index c10f7971b20..8141fea8382 100644 --- a/build/pkgs/r/checksums.ini +++ b/build/pkgs/r/checksums.ini @@ -1,4 +1,4 @@ tarball=R-VERSION.tar.gz -sha1=99c6c718506c49097f72c9928b7bcee9379bd699 -md5=9d6f73be072531e95884c7965ff80cd8 -cksum=3393167860 +sha1=057ea91daed3e68a12b2a473ee1283cf26f360e2 +md5=3e4b40b2bbd4a2f8133ac45dbef6a485 +cksum=3313280655 diff --git a/build/pkgs/r/package-version.txt b/build/pkgs/r/package-version.txt index f4cca8ae9fe..18547dc1733 100644 --- a/build/pkgs/r/package-version.txt +++ b/build/pkgs/r/package-version.txt @@ -1 +1 @@ -3.4.4.p0 +3.5.2.p0 diff --git a/build/pkgs/r/patches/link.patch b/build/pkgs/r/patches/link.patch deleted file mode 100644 index 8f0dee56130..00000000000 --- a/build/pkgs/r/patches/link.patch +++ /dev/null @@ -1,28 +0,0 @@ -From e4f300cb90c922fbe41efbafb15d41f787fec411 Mon Sep 17 00:00:00 2001 -From: Emmanuel Charpentier -Date: Wed, 14 Mar 2018 19:30:37 +0100 -Subject: [PATCH 6/9] link - -baseRegisterIndex should be declared extern - -Otherwise linking breaks at least on Solaris - ---- - src/include/GraphicsBase.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/include/GraphicsBase.h b/src/include/GraphicsBase.h -index 954eaff..e1122c5 100644 ---- a/src/include/GraphicsBase.h -+++ b/src/include/GraphicsBase.h -@@ -41,6 +41,6 @@ void unregisterBase(void); /* used in devices.c */ - - void Rf_setBaseDevice(Rboolean val, pGEDevDesc dd); /* used in graphics.c */ - --int baseRegisterIndex; -+extern int baseRegisterIndex; - - #endif /* R_GRAPHICSBASE_ */ --- -2.16.1 - diff --git a/build/pkgs/r/patches/parent_sig_handler.patch b/build/pkgs/r/patches/parent_sig_handler.patch deleted file mode 100644 index 0ec9a8c8eb3..00000000000 --- a/build/pkgs/r/patches/parent_sig_handler.patch +++ /dev/null @@ -1,38 +0,0 @@ -From cfdf4fa5f17eb423d07a8c555d36c5c8c5e5988c Mon Sep 17 00:00:00 2001 -From: Emmanuel Charpentier -Date: Wed, 14 Mar 2018 19:30:37 +0100 -Subject: [PATCH 8/9] parent_sig_handler - -make sure the parent_sig_handler function is defined before getting used. - ---- - src/library/parallel/src/fork.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/src/library/parallel/src/fork.c b/src/library/parallel/src/fork.c -index ef04e1f..bc02722 100644 ---- a/src/library/parallel/src/fork.c -+++ b/src/library/parallel/src/fork.c -@@ -227,15 +227,15 @@ static void setup_sig_handler() { - #else - /* sigaction is not viable, so use the "dumb" way - to clean up anything that comes our way */ --static void setup_sig_handler() { -- signal(SIGCHLD, parent_sig_handler); --} -- - static void parent_sig_handler(int sig) { - /* clean up when a child terminates */ - if (sig == SIGCHLD) - clean_zombies(); - } -+ -+static void setup_sig_handler() { -+ signal(SIGCHLD, parent_sig_handler); -+} - #endif - - SEXP mc_fork(SEXP sEstranged) --- -2.16.1 - diff --git a/build/pkgs/ratpoints/package-version.txt b/build/pkgs/ratpoints/package-version.txt index 5675623eed9..efed46a7bd0 100644 --- a/build/pkgs/ratpoints/package-version.txt +++ b/build/pkgs/ratpoints/package-version.txt @@ -1 +1 @@ -2.1.3.p4 +2.1.3.p5 diff --git a/build/pkgs/ratpoints/spkg-install b/build/pkgs/ratpoints/spkg-install index 361438025a1..b6856c4d4ad 100644 --- a/build/pkgs/ratpoints/spkg-install +++ b/build/pkgs/ratpoints/spkg-install @@ -1,10 +1,3 @@ -if [[ -z $SAGE_LOCAL ]]; then - echo >&2 "Error: SAGE_LOCAL undefined - exiting..." - echo >&2 "Maybe run 'sage -sh'?" - exit 1 -fi - - PRIME_SIZE=7 CCFLAGS_NO_SSE="-I$SAGE_LOCAL/include -Wall -O2 -fPIC -DRATPOINTS_MAX_BITS_IN_PRIME=$PRIME_SIZE" @@ -34,38 +27,20 @@ cd src/ ############################# # PLEASE, don't break this again by deleting "libratpoints.a". See trac 8267. -$MAKE libratpoints.a - -if [[ $? -ne 0 ]]; then - if [[ "$UNAME" = "Darwin" ]]; then - echo >&2 "Error building ratpoints." - exit 1 - fi +if ! $MAKE libratpoints.a; then + [ "$UNAME" = "Darwin" ] && sdh_die "Error building ratpoints." echo "Build failed. Trying without SSE2 instructions." CCFLAGS1="$CCFLAGS_NO_SSE" - $MAKE libratpoints.a - if [[ $? -ne 0 ]]; then - echo >&2 "Error building ratpoints." - exit 1 - fi + sdh_make libratpoints.a fi ############################################## # Install (just) the library and its header: # ############################################## -# cp libratpoints.a "$SAGE_LOCAL"/lib/ -# cp ratpoints.h "$SAGE_LOCAL"/include/ - # The following requires that the Makefile got patched; # otherwise one could pass 'INSTALL_DIR=...' on the 'make' # command line: -export INSTALL_DIR="$SAGE_LOCAL" -$MAKE install-lib -if [[ $? -ne 0 ]]; then - echo >&2 "Error installing ratpoints library." - exit 1 -fi - -# TODO: How about 'make test'? Do we need an spkg-check script? - +export INSTALL_DIR="$SAGE_DESTDIR_LOCAL" +mkdir -p "$INSTALL_DIR"/{lib,include} +sdh_make install-lib diff --git a/build/pkgs/rubiks/package-version.txt b/build/pkgs/rubiks/package-version.txt index 3b110567fa5..5052618cbb5 100644 --- a/build/pkgs/rubiks/package-version.txt +++ b/build/pkgs/rubiks/package-version.txt @@ -1 +1 @@ -20070912.p20 +20070912.p21 diff --git a/build/pkgs/rubiks/spkg-install b/build/pkgs/rubiks/spkg-install index 0d087a4f7bc..3ff0398d063 100644 --- a/build/pkgs/rubiks/spkg-install +++ b/build/pkgs/rubiks/spkg-install @@ -2,14 +2,6 @@ ## rubiks ########################################### -if [ -z "$SAGE_LOCAL" ] ; then - echo "SAGE_LOCAL undefined ... exiting" - echo "Maybe run 'sage -sh'?" - exit 1 -fi - -set -e - # Add a sensible default optimisation flag. Change if necessary. OPTIMIZATION_FLAGS="-O2" # Work around a bug in gcc 4.6.0: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48702 @@ -84,13 +76,7 @@ else INSTALL=install; export INSTALL fi - -# remove the old dik binary since the has a name collision -# with polynmake - see #2595 -rm -f $SAGE_LOCAL/bin/cube - cd src echo "Building Rubiks cube solvers" -$MAKE install PREFIX="$SAGE_LOCAL" - +sdh_make_install PREFIX="$SAGE_LOCAL" diff --git a/build/pkgs/sagenb/checksums.ini b/build/pkgs/sagenb/checksums.ini index aeeb94cb4c6..4b75c7b57c7 100644 --- a/build/pkgs/sagenb/checksums.ini +++ b/build/pkgs/sagenb/checksums.ini @@ -1,4 +1,4 @@ tarball=sagenb-VERSION.tar.bz2 -sha1=c18d4fa6f436dd6a97528af868ef9581e36789c4 -md5=15210e641fd9cbf7a65ce667b11b2cca -cksum=3539407445 +sha1=773e0c60ff4f3ec8245ab811fa4e42577e0933cb +md5=5cf62ebf347aea6750fc1b2d4bc9ebe1 +cksum=540029477 diff --git a/build/pkgs/sagenb/package-version.txt b/build/pkgs/sagenb/package-version.txt index 524cb55242b..45a1b3f4452 100644 --- a/build/pkgs/sagenb/package-version.txt +++ b/build/pkgs/sagenb/package-version.txt @@ -1 +1 @@ -1.1.1 +1.1.2 diff --git a/build/pkgs/sagetex/SPKG.txt b/build/pkgs/sagetex/SPKG.txt index c8846cb1bbc..e4bb1dc683f 100644 --- a/build/pkgs/sagetex/SPKG.txt +++ b/build/pkgs/sagetex/SPKG.txt @@ -24,6 +24,8 @@ Francisco, California, 94105, USA. == SPKG Maintainers == Dan Drake (dr.dan.drake at gmail) +and +SageMath developers (sage-devel@googlegroups.com) == Upstream Contact == diff --git a/build/pkgs/sagetex/checksums.ini b/build/pkgs/sagetex/checksums.ini index 15d70cc9dc8..f7be880a133 100644 --- a/build/pkgs/sagetex/checksums.ini +++ b/build/pkgs/sagetex/checksums.ini @@ -1,4 +1,4 @@ tarball=sagetex-VERSION.tar.gz -sha1=b14a1be391d7697b83179d451ea9405a9186c3b6 -md5=89f539ac31dd35555eb4f7959280ff89 -cksum=43653548 +sha1=6327d290b492cabbad5de3544cfd7df6b074d82d +md5=58336f1bc1d1fb77abaafd305093d79a +cksum=1682676854 diff --git a/build/pkgs/sagetex/package-version.txt b/build/pkgs/sagetex/package-version.txt index 9f55b2ccb5f..745f18dc1b7 100644 --- a/build/pkgs/sagetex/package-version.txt +++ b/build/pkgs/sagetex/package-version.txt @@ -1 +1 @@ -3.0 +3.2.p0 diff --git a/build/pkgs/scandir/checksums.ini b/build/pkgs/scandir/checksums.ini index ecec14ee0ed..932fef51502 100644 --- a/build/pkgs/scandir/checksums.ini +++ b/build/pkgs/scandir/checksums.ini @@ -1,4 +1,4 @@ tarball=scandir-VERSION.tar.gz -sha1=1d7e8e19fe754310bbc3c392b079c9d9133e1e95 -md5=037e5f24d1a0e78b17faca72dea9555f -cksum=3680350228 +sha1=64c550daec4ef70aa913e1e046b265ff9914c3e8 +md5=506c4cc5f38c00b301642a9cb0433910 +cksum=3949431906 diff --git a/build/pkgs/scandir/package-version.txt b/build/pkgs/scandir/package-version.txt index d3bdbdf1fda..f8e233b2733 100644 --- a/build/pkgs/scandir/package-version.txt +++ b/build/pkgs/scandir/package-version.txt @@ -1 +1 @@ -1.7 +1.9.0 diff --git a/build/pkgs/scipy/checksums.ini b/build/pkgs/scipy/checksums.ini index 8d78972cfcb..8843cd07074 100644 --- a/build/pkgs/scipy/checksums.ini +++ b/build/pkgs/scipy/checksums.ini @@ -1,4 +1,4 @@ tarball=scipy-VERSION.tar.gz -sha1=965e7ac23ac1bc2809a1fa13d429aea352bdd124 -md5=aa6bcc85276b6f25e17bcfc4dede8718 -cksum=2263485429 +sha1=7e4b5a8c9de029e4eab8735df51b1d8f1e55d346 +md5=e57011507865b0b702aff6077d412e03 +cksum=2206907772 diff --git a/build/pkgs/scipy/package-version.txt b/build/pkgs/scipy/package-version.txt index 9084fa2f716..26aaba0e866 100644 --- a/build/pkgs/scipy/package-version.txt +++ b/build/pkgs/scipy/package-version.txt @@ -1 +1 @@ -1.1.0 +1.2.0 diff --git a/build/pkgs/setuptools/checksums.ini b/build/pkgs/setuptools/checksums.ini index dfc2e850f5a..845ef67e3c0 100644 --- a/build/pkgs/setuptools/checksums.ini +++ b/build/pkgs/setuptools/checksums.ini @@ -1,4 +1,4 @@ tarball=setuptools-VERSION.zip -sha1=dac21f957c047b1b222a54fd2b2a3053c59cbfce -md5=260630ae1a64bafa39dcc53404d63829 -cksum=2213770058 +sha1=74b0dc738f72a21fe11f16af613166fd5694e436 +md5=1fbcbe45c7fb1d21041e676ba68d2dec +cksum=3373762786 diff --git a/build/pkgs/setuptools/package-version.txt b/build/pkgs/setuptools/package-version.txt index e9340fd6f71..9dd3e2460e8 100644 --- a/build/pkgs/setuptools/package-version.txt +++ b/build/pkgs/setuptools/package-version.txt @@ -1 +1 @@ -40.0.0 +40.6.3 diff --git a/build/pkgs/setuptools_scm/checksums.ini b/build/pkgs/setuptools_scm/checksums.ini index 77d0a199425..319eec9fa78 100644 --- a/build/pkgs/setuptools_scm/checksums.ini +++ b/build/pkgs/setuptools_scm/checksums.ini @@ -1,4 +1,4 @@ tarball=setuptools_scm-VERSION.tar.gz -sha1=cce778e7e9aa2c2f2bc96ae621f671e6d21b019d -md5=f17493d53f0d842bb0152f214775640b -cksum=1736410138 +sha1=cffffd63429761edece3957321a50fbdb364f043 +md5=52a8dee23c9e5f7d7d18094563db516c +cksum=3085521574 diff --git a/build/pkgs/setuptools_scm/package-version.txt b/build/pkgs/setuptools_scm/package-version.txt index 04cc99945d2..fd2a01863fd 100644 --- a/build/pkgs/setuptools_scm/package-version.txt +++ b/build/pkgs/setuptools_scm/package-version.txt @@ -1 +1 @@ -1.15.6 +3.1.0 diff --git a/build/pkgs/sirocco/package-version.txt b/build/pkgs/sirocco/package-version.txt index cd5ac039d67..c9eae59d88c 100644 --- a/build/pkgs/sirocco/package-version.txt +++ b/build/pkgs/sirocco/package-version.txt @@ -1 +1 @@ -2.0 +2.0.p0 diff --git a/build/pkgs/sirocco/spkg-install b/build/pkgs/sirocco/spkg-install index a83420aa820..9ee5b9f1566 100644 --- a/build/pkgs/sirocco/spkg-install +++ b/build/pkgs/sirocco/spkg-install @@ -1,19 +1,5 @@ cd src -./configure --prefix="$SAGE_LOCAL" --libdir="$SAGE_LOCAL/lib" -if [ $? -ne 0 ]; then - echo >&2 "Error configuring sirocco." - exit 1 -fi - -$MAKE -if [ $? -ne 0 ]; then - echo >&2 "Error building sirocco." - exit 1 -fi - -$MAKE -j1 install -if [ $? -ne 0 ]; then - echo >&2 "Error installing sirocco." - exit 1 -fi +sdh_configure +sdh_make +sdh_make_install -j1 diff --git a/build/pkgs/six/checksums.ini b/build/pkgs/six/checksums.ini index f7ca5c5e0b4..bd9ae609393 100644 --- a/build/pkgs/six/checksums.ini +++ b/build/pkgs/six/checksums.ini @@ -1,4 +1,4 @@ tarball=six-VERSION.tar.gz -sha1=3647372a0e104e7b53bd477762392024e1083ac0 -md5=d12789f9baf7e9fb2524c0c64f1773f8 -cksum=3627973757 +sha1=1957b44942be21822414f4dde936e6c40b687565 +md5=9ae5d1feed8c0215f4ae4adcd9207fcb +cksum=4154572121 diff --git a/build/pkgs/six/package-version.txt b/build/pkgs/six/package-version.txt index 1cac385c6cb..0eed1a29efd 100644 --- a/build/pkgs/six/package-version.txt +++ b/build/pkgs/six/package-version.txt @@ -1 +1 @@ -1.11.0 +1.12.0 diff --git a/build/pkgs/sphinxcontrib_websupport/checksums.ini b/build/pkgs/sphinxcontrib_websupport/checksums.ini index 3fd54d78afd..1f0d8d40396 100644 --- a/build/pkgs/sphinxcontrib_websupport/checksums.ini +++ b/build/pkgs/sphinxcontrib_websupport/checksums.ini @@ -1,4 +1,4 @@ tarball=sphinxcontrib-websupport-VERSION.tar.gz -sha1=b7ef06bff3d9ec8b5f3786180174f720b9525c84 -md5=84df26463b1ba65b07f926dbe2055665 -cksum=4055160413 +sha1=03216c11167b75d2c1b08e34041ad2019c3e7dc9 +md5=ca6435e7b4eb9408df4f54972361e9d3 +cksum=1372914473 diff --git a/build/pkgs/sphinxcontrib_websupport/package-version.txt b/build/pkgs/sphinxcontrib_websupport/package-version.txt index 7dea76edb3d..9084fa2f716 100644 --- a/build/pkgs/sphinxcontrib_websupport/package-version.txt +++ b/build/pkgs/sphinxcontrib_websupport/package-version.txt @@ -1 +1 @@ -1.0.1 +1.1.0 diff --git a/build/pkgs/sqlite/checksums.ini b/build/pkgs/sqlite/checksums.ini index 1095b6310f6..9e0ea2f68fa 100644 --- a/build/pkgs/sqlite/checksums.ini +++ b/build/pkgs/sqlite/checksums.ini @@ -1,4 +1,4 @@ tarball=sqlite-autoconf-VERSION.tar.gz -sha1=2fb24ec12001926d5209d2da90d252b9825366ac -md5=96b5648d542e8afa6ab7ffb8db8ddc3d -cksum=1556846983 +sha1=6cdb46a153b0e88f8a5fd80e29b3966885f39ea4 +md5=cb72c5f93235cd56b18ee2aa1504cdaf +cksum=1443188914 diff --git a/build/pkgs/sqlite/package-version.txt b/build/pkgs/sqlite/package-version.txt index a5e894e3794..5a91ca745fb 100644 --- a/build/pkgs/sqlite/package-version.txt +++ b/build/pkgs/sqlite/package-version.txt @@ -1 +1 @@ -3220000 +3270100 diff --git a/build/pkgs/subprocess32/checksums.ini b/build/pkgs/subprocess32/checksums.ini index b01fa9d0f86..1833f20506d 100644 --- a/build/pkgs/subprocess32/checksums.ini +++ b/build/pkgs/subprocess32/checksums.ini @@ -1,4 +1,4 @@ tarball=subprocess32-VERSION.tar.gz -sha1=75a8664ba54663016315dae17510af97c5a96953 -md5=824c801e479d3e916879aae3e9c15e16 -cksum=270770299 +sha1=bfc293afad55733195927a236fd57c099db231b3 +md5=afa0510115f483d668e25aa30502d9bc +cksum=3131639977 diff --git a/build/pkgs/subprocess32/fix_config.py b/build/pkgs/subprocess32/fix_config.py index e73c52f3140..0ed5933e23a 100644 --- a/build/pkgs/subprocess32/fix_config.py +++ b/build/pkgs/subprocess32/fix_config.py @@ -14,7 +14,6 @@ # subprocess32 will eventually be installed. -import os from sysconfig import get_path from subprocess import check_output diff --git a/build/pkgs/subprocess32/package-version.txt b/build/pkgs/subprocess32/package-version.txt index e00541606dd..444877d48fb 100644 --- a/build/pkgs/subprocess32/package-version.txt +++ b/build/pkgs/subprocess32/package-version.txt @@ -1 +1 @@ -3.2.7.p0 +3.5.3 diff --git a/build/pkgs/symmetrica/package-version.txt b/build/pkgs/symmetrica/package-version.txt index 7ad69113631..7197fe846bb 100644 --- a/build/pkgs/symmetrica/package-version.txt +++ b/build/pkgs/symmetrica/package-version.txt @@ -1 +1 @@ -2.0.p10 +2.0.p11 diff --git a/build/pkgs/symmetrica/spkg-install b/build/pkgs/symmetrica/spkg-install index 33260a14702..bc5d8e5f26c 100644 --- a/build/pkgs/symmetrica/spkg-install +++ b/build/pkgs/symmetrica/spkg-install @@ -1,38 +1,11 @@ -if [ -z "$SAGE_LOCAL" ] ; then - echo >&2 "Error: SAGE_LOCAL undefined - exiting..." - echo >&2 "Maybe run 'sage -sh'?" - exit 1 -fi - -export CFLAGS="-O2 -g $CFLAGS -fPIC -DFAST -DALLTRUE" - - cd src - # Patching the upstream makefile doesn't make sense, # as it has (syntactically) nothing in common with ours. -cp -f ../patches/makefile makefile -if [ $? -ne 0 ]; then - echo >&2 "Error copying over patched Makefile." - exit 1 -fi - -$MAKE -if [ $? -ne 0 ]; then - echo >&2 "Error building Symmetrica." - exit 1 -fi +cp -f ../patches/makefile makefile || exit $? -cp -f libsymmetrica.a "$SAGE_LOCAL"/lib/ -if [ $? -ne 0 ]; then - echo >&2 "Error installing the Symmetrica library." - exit 1 -fi +export CFLAGS="-O2 -g $CFLAGS -fPIC -DFAST -DALLTRUE" -mkdir -p "$SAGE_LOCAL"/include/symmetrica && -cp -f *.h "$SAGE_LOCAL"/include/symmetrica/ -if [ $? -ne 0 ]; then - echo >&2 "Error installing Symmetrica's header files." - exit 1 -fi +sdh_make +sdh_install libsymmetrica.a "$SAGE_LOCAL/lib" +sdh_install *.h "$SAGE_LOCAL/include/symmetrica" diff --git a/build/pkgs/tdlib/package-version.txt b/build/pkgs/tdlib/package-version.txt index 9e11b32fcaa..af2629893df 100644 --- a/build/pkgs/tdlib/package-version.txt +++ b/build/pkgs/tdlib/package-version.txt @@ -1 +1 @@ -0.3.1 +0.3.1.p0 diff --git a/build/pkgs/tdlib/spkg-install b/build/pkgs/tdlib/spkg-install index 55193e12dd3..9ee5b9f1566 100644 --- a/build/pkgs/tdlib/spkg-install +++ b/build/pkgs/tdlib/spkg-install @@ -1,17 +1,5 @@ -if [ "$SAGE_LOCAL" = "" ]; then - echo "SAGE_LOCAL undefined ... exiting"; - echo "Maybe run 'sage -sh'?" - exit 1 -fi - cd src -./configure \ - --prefix="$SAGE_LOCAL" - -$MAKE install -j1 -if [ $? -ne 0 ]; then - echo "Error installing tdlib" - exit 1 -fi - +sdh_configure +sdh_make +sdh_make_install -j1 diff --git a/build/pkgs/testpath/checksums.ini b/build/pkgs/testpath/checksums.ini index 0ff988f02ae..ba35e50c47b 100644 --- a/build/pkgs/testpath/checksums.ini +++ b/build/pkgs/testpath/checksums.ini @@ -1,4 +1,4 @@ tarball=testpath-VERSION.tar.gz -sha1=f0b56f062f30555ca6f6844c7048cb20cd8c5a1f -md5=2cd5ed5522fda781bb497c9d80ae2fc9 -cksum=1697586731 +sha1=be61bdab22bda48fa1e289cdbe8b47edbab9a1c6 +md5=562d0e1b02fc5cbcb8406955bcd7249f +cksum=1727601183 diff --git a/build/pkgs/testpath/package-version.txt b/build/pkgs/testpath/package-version.txt index 9e11b32fcaa..2b7c5ae0184 100644 --- a/build/pkgs/testpath/package-version.txt +++ b/build/pkgs/testpath/package-version.txt @@ -1 +1 @@ -0.3.1 +0.4.2 diff --git a/build/pkgs/typing/checksums.ini b/build/pkgs/typing/checksums.ini index 67f9d4ae8b5..a421db5e1c5 100644 --- a/build/pkgs/typing/checksums.ini +++ b/build/pkgs/typing/checksums.ini @@ -1,4 +1,4 @@ tarball=typing-VERSION.tar.gz -sha1=e41396acf24c6563205bf0755cec4449ef041925 -md5=143af0bf3afd1887622771f2f1ffe8e1 -cksum=721080509 +sha1=8414f7e523f1f286f72392e9f8929d346df6f6a2 +md5=64614206b4bdc0864fc0e0bccd69efc9 +cksum=2256549185 diff --git a/build/pkgs/typing/package-version.txt b/build/pkgs/typing/package-version.txt index b72762837ea..4f2c1d15f6d 100644 --- a/build/pkgs/typing/package-version.txt +++ b/build/pkgs/typing/package-version.txt @@ -1 +1 @@ -3.6.2 +3.6.6 diff --git a/build/pkgs/valgrind/checksums.ini b/build/pkgs/valgrind/checksums.ini index 2fbed01184c..242642cedef 100644 --- a/build/pkgs/valgrind/checksums.ini +++ b/build/pkgs/valgrind/checksums.ini @@ -1,4 +1,4 @@ tarball=valgrind-VERSION.tar.bz2 -sha1=aec0b8cd042ec36c8cce4f6027b98627ab202f26 -md5=7c311a72a20388aceced1aa5573ce970 -cksum=968601795 +sha1=182afd405b92ddb6f52c6729e848eacf4b1daf46 +md5=74175426afa280184b62591b58c671b3 +cksum=2472830850 diff --git a/build/pkgs/valgrind/package-version.txt b/build/pkgs/valgrind/package-version.txt index 30291cba223..f982feb41bd 100644 --- a/build/pkgs/valgrind/package-version.txt +++ b/build/pkgs/valgrind/package-version.txt @@ -1 +1 @@ -3.10.0 +3.14.0 diff --git a/build/pkgs/werkzeug/checksums.ini b/build/pkgs/werkzeug/checksums.ini index 07b80d44ef4..409b4650988 100644 --- a/build/pkgs/werkzeug/checksums.ini +++ b/build/pkgs/werkzeug/checksums.ini @@ -1,4 +1,4 @@ tarball=Werkzeug-VERSION.tar.gz -sha1=b58b07e7c967b2c4cb4cfa4be644b0ae8acffd7f -md5=780967186f9157e88f2bfbfa6f07a893 -cksum=3715338387 +sha1=4b979fb960c5b5507ccb8a705931fa217013483d +md5=6d20b5be2d245be4ac7706cc390d130c +cksum=1712124090 diff --git a/build/pkgs/werkzeug/package-version.txt b/build/pkgs/werkzeug/package-version.txt index 4c43386fd5d..930e3000bdc 100644 --- a/build/pkgs/werkzeug/package-version.txt +++ b/build/pkgs/werkzeug/package-version.txt @@ -1 +1 @@ -0.11.10.p0 +0.14.1 diff --git a/build/pkgs/widgetsnbextension/checksums.ini b/build/pkgs/widgetsnbextension/checksums.ini index e006dc18338..7a19aaf9729 100644 --- a/build/pkgs/widgetsnbextension/checksums.ini +++ b/build/pkgs/widgetsnbextension/checksums.ini @@ -1,4 +1,4 @@ tarball=widgetsnbextension-VERSION.tar.gz -sha1=6eca02076eb37940feb5ea0cbdc5be4935a3cfaa -md5=6a06320d23c4d2589a05d86a9e34b9a7 -cksum=3630158558 +sha1=6f6d6106423907dfcb74ee1a5bcc571647cd5589 +md5=a165830e095877a9c576c817656850e9 +cksum=2498508081 diff --git a/build/pkgs/widgetsnbextension/package-version.txt b/build/pkgs/widgetsnbextension/package-version.txt index 944880fa15e..4d9d11cf505 100644 --- a/build/pkgs/widgetsnbextension/package-version.txt +++ b/build/pkgs/widgetsnbextension/package-version.txt @@ -1 +1 @@ -3.2.0 +3.4.2 diff --git a/build/pkgs/zn_poly/dependencies b/build/pkgs/zn_poly/dependencies index e512cac7614..9a77ea16f78 100644 --- a/build/pkgs/zn_poly/dependencies +++ b/build/pkgs/zn_poly/dependencies @@ -1,7 +1,4 @@ -$(MP_LIBRARY) | $(PYTHON) - -zn_poly really does depend on Python, despite this is far from obvious. -The 'configure' script in zn_poly calls Python to make a 'makefile'. +$(MP_LIBRARY) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/zn_poly/package-version.txt b/build/pkgs/zn_poly/package-version.txt index f374f6662e9..2305b1d26e3 100644 --- a/build/pkgs/zn_poly/package-version.txt +++ b/build/pkgs/zn_poly/package-version.txt @@ -1 +1 @@ -0.9.1 +0.9.1.p0 diff --git a/build/pkgs/zn_poly/patches/python3.patch b/build/pkgs/zn_poly/patches/python3.patch new file mode 100644 index 00000000000..b61d2014c97 --- /dev/null +++ b/build/pkgs/zn_poly/patches/python3.patch @@ -0,0 +1,433 @@ +commit f2bada31fd09f09c744d8ff0e1fab82c53dbf830 +Author: Jeroen Demeyer +Date: Tue Feb 12 15:08:39 2019 +0100 + + Make makemakefile.py compatible with Python 3 + +diff --git a/makemakefile.py b/makemakefile.py +index fa2b851..acb6084 100644 +--- a/makemakefile.py ++++ b/makemakefile.py +@@ -147,213 +147,221 @@ cpp_libs = libs + " -L" + ntl_lib_dir + " -lntl" + + import time + +-print "#" +-print "# Do not edit directly -- this file was auto-generated" +-print "# by makemakefile.py on " + time.strftime("%a, %d %b %Y %H:%M:%S +0000", +- time.gmtime()) +-print "#" +-print "# (makemakefile.py patched for Sage, 04/2012)" +-print +- +-print +-print "CC ?= gcc" +-print "CPP ?= cpp" +-print "CFLAGS = " + cflags +-print "CPPFLAGS = " + cppflags +-print "LDFLAGS = " + ldflags +-print "INCLUDES = " + includes # These are options to the C preprocessor. +-print "LIBS = " + libs # These are linker options passed to the compiler. +-print +-print "AR ?= ar" +-print "RANLIB ?= ranlib" +-print +-print "SHARED_FLAG ?= -shared" +-print "SONAME_FLAG ?= -soname" # '-h' for the Sun/Solaris linker +- +-print +-print "CXX ?= g++" # The C++ compiler. +-print "CXXFLAGS = " + cxxflags # Options passed to the C++ compiler. +-print "CPP_INCLUDES = " + cpp_includes +-print "CPP_LIBS = " + cpp_libs +- +-print +-print "HEADERS = " + " ".join(install_headers + other_headers) +-print "LIBOBJS = " + " ".join([x + ".o" for x in lib_modules]) +-print "TESTOBJS = " + " ".join([x + "-DEBUG.o" for x in +- lib_modules + test_modules + testprof_modules]) +-print "PROFOBJS = " + " ".join([x + ".o" for x in +- lib_modules + prof_modules + noncpp_prof_modules + testprof_modules]) +-print "CPP_PROFOBJS = " + " ".join([x + ".o" for x in +- lib_modules + prof_modules + cpp_prof_modules + testprof_modules]) +-print "TUNEOBJS = " + " ".join([x + ".o" for x in +- lib_modules + tune_modules + testprof_modules + prof_modules + +- noncpp_prof_modules if x not in ("src/tuning", "profile/prof_main")]) +-print "ZN_POLY_TUNING = " + str(int(zn_poly_tuning)) +-print "ZN_POLY_VERSION = " + version +-print "ZN_POLY_ABI_VERSION = " + abi_version +- +-print +-print "all: libzn_poly.a" +-print +-print "test: test/test" +-print "tune: tune/tune" +-print +-print "check: test" +-print "\ttest/test -quick all" +-print +-print "install:" +-print "\tmkdir -p %s/include/zn_poly" % prefix +-print "\tmkdir -p %s/lib" % prefix +-print "\tcp libzn_poly.a %s/lib" % prefix +-print "\tcp include/zn_poly.h %s/include/zn_poly" % prefix +-print "\tcp include/wide_arith.h %s/include/zn_poly" % prefix +-print +-print "clean:" +-print "\trm -f *.o" +-print "\trm -f test/*.o" +-print "\trm -f profile/*.o" +-print "\trm -f tune/*.o" +-print "\trm -f src/tuning.c" +-print "\trm -f src/*.o" +-print "\trm -f demo/bernoulli/*.o" +-print "\trm -f libzn_poly.a" +-print "\trm -f libzn_poly.dylib" +-print "\trm -f libzn_poly*.so*" +-print "\trm -f libzn_poly*.dll.a" +-print "\trm -f cygzn_poly.dll" +-print "\trm -f test/test" +-print "\trm -f tune/tune" ++now = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()) ++print( ++"""# ++# Do not edit directly -- this file was auto-generated ++# by {} on {} ++# ++# (makemakefile.py patched for Sage, 04/2012) ++""".format(__file__, now)) ++ ++ ++print( ++""" ++CC ?= gcc ++CPP ?= cpp ++CFLAGS = {} ++CPPFLAGS = {} ++LDFLAGS = {} ++INCLUDES = {} # These are options to the C preprocessor. ++LIBS = {} # These are linker options passed to the compiler. ++ ++AR ?= ar ++RANLIB ?= ranlib ++ ++SHARED_FLAG ?= -shared ++SONAME_FLAG ?= -soname # '-h' for the Sun/Solaris linker ++""".format(cflags, cppflags, ldflags, includes, libs)) ++ ++ ++print( ++"""CXX ?= g++ # The C++ compiler. ++CXXFLAGS = {} # Options passed to the C++ compiler. ++CPP_INCLUDES = {} ++CPP_LIBS = {} ++""".format(cxxflags, cpp_includes, cpp_libs)) ++ ++ ++print( ++"""HEADERS = {} ++LIBOBJS = {} ++TESTOBJS = {} ++PROFOBJS = {} ++CPP_PROFOBJS = {} ++TUNEOBJS = {}""".format( ++ " ".join(install_headers + other_headers), ++ " ".join([x + ".o" for x in lib_modules]), ++ " ".join([x + "-DEBUG.o" for x in ++ lib_modules + test_modules + testprof_modules]), ++ " ".join([x + ".o" for x in ++ lib_modules + prof_modules + noncpp_prof_modules + testprof_modules]), ++ " ".join([x + ".o" for x in ++ lib_modules + prof_modules + cpp_prof_modules + testprof_modules]), ++ " ".join([x + ".o" for x in ++ lib_modules + tune_modules + testprof_modules + prof_modules + ++ noncpp_prof_modules if x not in ("src/tuning", "profile/prof_main")]) ++)) ++ ++ ++print( ++"""ZN_POLY_TUNING = {} ++ZN_POLY_VERSION = {} ++ZN_POLY_ABI_VERSION = {} ++""".format(int(zn_poly_tuning), version, abi_version)) ++ ++ ++print( ++"""all: libzn_poly.a ++ ++test: test/test ++tune: tune/tune ++ ++check: test ++\ttest/test -quick all ++ ++install: ++\tmkdir -p {prefix}/include/zn_poly ++\tmkdir -p {prefix}/lib ++\tcp libzn_poly.a {prefix}/lib ++\tcp include/zn_poly.h {prefix}/include/zn_poly ++\tcp include/wide_arith.h {prefix}/include/zn_poly ++""".format(prefix=prefix)) ++ ++ ++print( ++"""clean: ++\trm -f *.o ++\trm -f test/*.o ++\trm -f profile/*.o ++\trm -f tune/*.o ++\trm -f src/tuning.c ++\trm -f src/*.o ++\trm -f demo/bernoulli/*.o ++\trm -f libzn_poly.a ++\trm -f libzn_poly.dylib ++\trm -f libzn_poly*.so* ++\trm -f libzn_poly*.dll.a ++\trm -f cygzn_poly.dll ++\trm -f test/test ++\trm -f tune/tune""") + for x in prof_progs: +- print "\trm -f " + x +- print "\trm -f " + x + "-ntl" ++ print("\trm -f " + x) ++ print("\trm -f " + x + "-ntl") + for x in demo_progs: +- print "\trm -f " + x +-print +-print "distclean: clean" +-print "\trm -f makefile" +-print +-print "dist: distclean" +-print "\ttar --exclude-vcs --exclude=.gitignore -czf zn_poly-$(ZN_POLY_VERSION).tar.gz *" +- +- +-print +-print +-print "##### library targets" +-print +-print "ifeq ($(ZN_POLY_TUNING), 1)" +-print "src/tuning.c: tune/tune" +-print "\ttune/tune > src/tuning.c" +-print "else" +-print "src/tuning.c: tune/tuning.c" +-print "\tcp tune/tuning.c src/tuning.c" +-print "endif" +-print +-print "libzn_poly.a: $(LIBOBJS)" +-print "\t$(AR) -r libzn_poly.a $(LIBOBJS)" +-print "\t$(RANLIB) libzn_poly.a" +-print +-print "# TODO: Put '-single_module -fPIC -dynamiclib' into $(SHARED_FLAG)" +-print "# and use that; also support $(SO_EXTENSION)..." +-print "libzn_poly.dylib: $(LIBOBJS)" +-print "\t$(CC) $(LDFLAGS) -single_module -fPIC -dynamiclib -o libzn_poly.dylib " \ +- "$(LIBOBJS) $(LIBS)" +-print +-print "# Left for compatibility with previous versions of Sage's 'spkg-install':" +-print "libzn_poly.dylib64: $(LIBOBJS)" +-print "\t$(CC) -m64 -single_module -fPIC -dynamiclib -o libzn_poly.dylib $(LIBOBJS) $(LIBS)" +-print +-print "cygzn_poly.dll: $(LIBOBJS)" +-print "\t$(CC) $(SHARED_FLAG) $(LDFLAGS) " \ +- "-Wl,--out-implib,libzn_poly-$(ZN_POLY_VERSION).dll.a " \ +- "-o cygzn_poly.dll $(LIBOBJS) $(LIBS)" +-print +-print "libzn_poly-$(ZN_POLY_VERSION).dll.a: cygzn_poly.dll" +-print +-print "libzn_poly.dll.a: libzn_poly-$(ZN_POLY_VERSION).dll.a" +-print "\tln -sf libzn_poly-$(ZN_POLY_VERSION).dll.a libzn_poly.dll.a" +-print "\tln -sf libzn_poly-$(ZN_POLY_VERSION).dll.a libzn_poly-$(ZN_POLY_ABI_VERSION).dll.a" +-print +-print "libzn_poly.so: libzn_poly-$(ZN_POLY_VERSION).so" +-print "\tln -sf libzn_poly-$(ZN_POLY_VERSION).so libzn_poly.so" +-print "\tln -sf libzn_poly-$(ZN_POLY_VERSION).so libzn_poly-$(ZN_POLY_ABI_VERSION).so" +- +-print +-print "libzn_poly-$(ZN_POLY_VERSION).so: $(LIBOBJS)" +-print "\t$(CC) $(SHARED_FLAG) $(LDFLAGS) -Wl,-soname,libzn_poly-$(ZN_POLY_ABI_VERSION).so " \ +- "-o libzn_poly-$(ZN_POLY_VERSION).so $(LIBOBJS) $(LIBS)" +- +-print +-print +-print "##### test program" +-print +-print "test/test: $(TESTOBJS) $(HEADERS)" +-print "\t$(CC) -g $(LDFLAGS) -o test/test $(TESTOBJS) $(LIBS)" +- +-print +-print +-print "##### profiling programs" +-print ++ print("\trm -f " + x) ++print( ++""" ++distclean: clean ++\trm -f makefile ++ ++dist: distclean ++\ttar --exclude-vcs --exclude=.gitignore -czf zn_poly-$(ZN_POLY_VERSION).tar.gz * ++ ++ ++##### library targets ++ ++ifeq ($(ZN_POLY_TUNING), 1) ++src/tuning.c: tune/tune ++\ttune/tune > src/tuning.c ++else ++src/tuning.c: tune/tuning.c ++\tcp tune/tuning.c src/tuning.c ++endif ++ ++libzn_poly.a: $(LIBOBJS) ++\t$(AR) -r libzn_poly.a $(LIBOBJS) ++\t$(RANLIB) libzn_poly.a ++ ++# TODO: Put '-single_module -fPIC -dynamiclib' into $(SHARED_FLAG) ++# and use that; also support $(SO_EXTENSION)... ++libzn_poly.dylib: $(LIBOBJS) ++\t$(CC) $(LDFLAGS) -single_module -fPIC -dynamiclib -o libzn_poly.dylib $(LIBOBJS) $(LIBS) ++ ++# Left for compatibility with previous versions of Sage's 'spkg-install': ++libzn_poly.dylib64: $(LIBOBJS) ++\t$(CC) -m64 -single_module -fPIC -dynamiclib -o libzn_poly.dylib $(LIBOBJS) $(LIBS) ++ ++cygzn_poly.dll: $(LIBOBJS) ++\t$(CC) $(SHARED_FLAG) $(LDFLAGS) -Wl,--out-implib,libzn_poly-$(ZN_POLY_VERSION).dll.a -o cygzn_poly.dll $(LIBOBJS) $(LIBS) ++ ++libzn_poly-$(ZN_POLY_VERSION).dll.a: cygzn_poly.dll ++ ++libzn_poly.dll.a: libzn_poly-$(ZN_POLY_VERSION).dll.a ++\tln -sf libzn_poly-$(ZN_POLY_VERSION).dll.a libzn_poly.dll.a ++\tln -sf libzn_poly-$(ZN_POLY_VERSION).dll.a libzn_poly-$(ZN_POLY_ABI_VERSION).dll.a ++ ++libzn_poly.so: libzn_poly-$(ZN_POLY_VERSION).so ++\tln -sf libzn_poly-$(ZN_POLY_VERSION).so libzn_poly.so ++\tln -sf libzn_poly-$(ZN_POLY_VERSION).so libzn_poly-$(ZN_POLY_ABI_VERSION).so ++ ++libzn_poly-$(ZN_POLY_VERSION).so: $(LIBOBJS) ++\t$(CC) $(SHARED_FLAG) $(LDFLAGS) -Wl,-soname,libzn_poly-$(ZN_POLY_ABI_VERSION).so -o libzn_poly-$(ZN_POLY_VERSION).so $(LIBOBJS) $(LIBS) ++ ++ ++##### test program ++ ++test/test: $(TESTOBJS) $(HEADERS) ++\t$(CC) -g $(LDFLAGS) -o test/test $(TESTOBJS) $(LIBS) ++ ++ ++##### profiling programs ++""") ++ + for x in prof_progs: +- print "%s-main.o: %s-main.c $(HEADERS)" % (x, x) +- print "\t$(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -DNDEBUG -o %s-main.o -c %s-main.c" \ +- % (x, x) +- print +- print "%s: %s-main.o $(PROFOBJS)" % (x, x) +- print "\t$(CC) $(CFLAGS) $(LDFLAGS) -o %s %s-main.o $(PROFOBJS) $(LIBS)" \ +- % (x, x) +- print +- print "%s-main-ntl.o: %s-main.c $(HEADERS)" % (x, x) +- print "\t$(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -DPROFILE_NTL -DNDEBUG " \ +- "-o %s-main-ntl.o -c %s-main.c" % (x, x) +- print +- print "%s-ntl: %s-main-ntl.o $(CPP_PROFOBJS)" % (x, x) +- print "\t$(CXX) $(CXXFLAGS) $(LDFLAGS) -o %s-ntl %s-main-ntl.o " \ +- "$(CPP_PROFOBJS) $(CPP_LIBS)" % (x, x) +- print +- +-print +-print +-print "##### tuning utility" +-print +-print "tune/tune: $(TUNEOBJS)" +-print "\t$(CC) $(CFLAGS) $(LDFLAGS) -o tune/tune $(TUNEOBJS) $(LIBS)" +- +- +-print +-print +-print "##### demo programs" ++ print( ++"""{0}-main.o: {0}-main.c $(HEADERS) ++\t$(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -DNDEBUG -o {0}-main.o -c {0}-main.c ++ ++{0}: {0}-main.o $(PROFOBJS) ++\t$(CC) $(CFLAGS) $(LDFLAGS) -o {0} {0}-main.o $(PROFOBJS) $(LIBS) ++ ++{0}-main-ntl.o: {0}-main.c $(HEADERS) ++\t$(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -DPROFILE_NTL -DNDEBUG -o {0}-main-ntl.o -c {0}-main.c ++ ++{0}-ntl: {0}-main-ntl.o $(CPP_PROFOBJS) ++\t$(CXX) $(CXXFLAGS) $(LDFLAGS) -o {0}-ntl {0}-main-ntl.o $(CPP_PROFOBJS) $(CPP_LIBS) ++""".format(x)) ++ ++ ++print( ++""" ++ ++##### tuning utility ++ ++tune/tune: $(TUNEOBJS) ++\t$(CC) $(CFLAGS) $(LDFLAGS) -o tune/tune $(TUNEOBJS) $(LIBS) ++ ++ ++##### demo programs ++""") + for x in demo_progs: +- print +- print "%s: %s.o $(LIBOBJS)" % (x, x) +- print "\t$(CC) $(CFLAGS) $(LDFLAGS) -o %s %s.o $(LIBOBJS) $(LIBS)" % (x, x) ++ print( ++"""{0}: {0}.o $(LIBOBJS) ++\t$(CC) $(CFLAGS) $(LDFLAGS) -o {0} {0}.o $(LIBOBJS) $(LIBS) ++""".format(x)) + + +-print +-print +-print "##### object files (with debug code)" ++print("\n##### object files (with debug code)\n") + for x in lib_modules + test_modules + testprof_modules + demo_progs: +- print +- print "%s-DEBUG.o: %s.c $(HEADERS)" % (x, x) +- print "\t$(CC) -g $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -DDEBUG -o %s-DEBUG.o -c %s.c" \ +- % (x, x) +- +-print +-print +-print "##### object files (no debug code)" +-for x in lib_modules + prof_modules + testprof_modules + \ +- tune_modules + demo_progs: +- print +- print "%s.o: %s.c $(HEADERS)" % (x, x) +- print "\t$(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -DNDEBUG -o %s.o -c %s.c" % (x, x) +- +-print +-print +-print "##### object files (C++, no debug code)" +-for x in cpp_prof_modules: +- print +- print "%s.o: %s.c $(HEADERS)" % (x, x) +- print "\t$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(CPP_INCLUDES) -DNDEBUG -o %s.o -c %s.c" \ +- % (x, x) ++ print( ++"""{0}-DEBUG.o: {0}.c $(HEADERS) ++\t$(CC) -g $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -DDEBUG -o {0}-DEBUG.o -c {0}.c ++""".format(x)) ++ + ++print("\n##### object files (no debug code)\n") ++for x in (lib_modules + prof_modules + testprof_modules + ++ tune_modules + demo_progs): ++ print( ++"""{0}.o: {0}.c $(HEADERS) ++\t$(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -DNDEBUG -o {0}.o -c {0}.c ++""".format(x)) + +-### end of file ++ ++print("\n##### object files (C++, no debug code)\n") ++for x in cpp_prof_modules: ++ print( ++"""{0}.o: {0}.c $(HEADERS) ++\t$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(CPP_INCLUDES) -DNDEBUG -o {0}.o -c {0}.c ++""".format(x)) diff --git a/build/pkgs/zn_poly/patches/python_2_6_format_support.patch b/build/pkgs/zn_poly/patches/python_2_6_format_support.patch new file mode 100644 index 00000000000..f8a59665487 --- /dev/null +++ b/build/pkgs/zn_poly/patches/python_2_6_format_support.patch @@ -0,0 +1,72 @@ +diff --git a/makemakefile.py b/makemakefile.py +index acb6084..9c0fb96 100644 +--- a/makemakefile.py ++++ b/makemakefile.py +@@ -151,7 +151,7 @@ now = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()) + print( + """# + # Do not edit directly -- this file was auto-generated +-# by {} on {} ++# by {0} on {1} + # + # (makemakefile.py patched for Sage, 04/2012) + """.format(__file__, now)) +@@ -161,11 +161,11 @@ print( + """ + CC ?= gcc + CPP ?= cpp +-CFLAGS = {} +-CPPFLAGS = {} +-LDFLAGS = {} +-INCLUDES = {} # These are options to the C preprocessor. +-LIBS = {} # These are linker options passed to the compiler. ++CFLAGS = {0} ++CPPFLAGS = {1} ++LDFLAGS = {2} ++INCLUDES = {3} # These are options to the C preprocessor. ++LIBS = {4} # These are linker options passed to the compiler. + + AR ?= ar + RANLIB ?= ranlib +@@ -177,19 +177,19 @@ SONAME_FLAG ?= -soname # '-h' for the Sun/Solaris linker + + print( + """CXX ?= g++ # The C++ compiler. +-CXXFLAGS = {} # Options passed to the C++ compiler. +-CPP_INCLUDES = {} +-CPP_LIBS = {} ++CXXFLAGS = {0} # Options passed to the C++ compiler. ++CPP_INCLUDES = {1} ++CPP_LIBS = {2} + """.format(cxxflags, cpp_includes, cpp_libs)) + + + print( +-"""HEADERS = {} +-LIBOBJS = {} +-TESTOBJS = {} +-PROFOBJS = {} +-CPP_PROFOBJS = {} +-TUNEOBJS = {}""".format( ++"""HEADERS = {0} ++LIBOBJS = {1} ++TESTOBJS = {2} ++PROFOBJS = {3} ++CPP_PROFOBJS = {4} ++TUNEOBJS = {5}""".format( + " ".join(install_headers + other_headers), + " ".join([x + ".o" for x in lib_modules]), + " ".join([x + "-DEBUG.o" for x in +@@ -205,9 +205,9 @@ TUNEOBJS = {}""".format( + + + print( +-"""ZN_POLY_TUNING = {} +-ZN_POLY_VERSION = {} +-ZN_POLY_ABI_VERSION = {} ++"""ZN_POLY_TUNING = {0} ++ZN_POLY_VERSION = {1} ++ZN_POLY_ABI_VERSION = {2} + """.format(int(zn_poly_tuning), version, abi_version)) + + diff --git a/build/pkgs/zn_poly/spkg-install b/build/pkgs/zn_poly/spkg-install index 7664200ecb2..169aef83d17 100644 --- a/build/pkgs/zn_poly/spkg-install +++ b/build/pkgs/zn_poly/spkg-install @@ -33,23 +33,19 @@ unset SHARED_FLAG # Currently leave the Makefile default ('-shared'); for safety cd src/ -# use 2to3 if we are running on python3 -if python -c 'import sys; sys.exit(sys.version_info.major != 3)'; then - 2to3 -n -w --no-diffs makemakefile.py -fi - ############################################################################### # Configure, tune, build and test zn_poly: ############################################################################### -echo "Now configuring zn_poly..." +echo "Now generating Makefile for zn_poly..." # Note: The '--cppflags' and '--cxxflags' options are added by our patch to # 'makemakefile.py', and aren't available with vanilla upstream. # Moreover, the generated Makefile now takes CC, CXX and CPP from the # environment, so no need to pass them later explicitly to 'make'. -./configure --prefix="$SAGE_LOCAL" --cflags="$CFLAGS" --ldflags="$LDFLAGS" \ - --cppflags="$CPPFLAGS" --cxxflags="$CXXFLAGS" \ - --gmp-prefix="$SAGE_LOCAL" || sdh_die "Error configuring zn_poly." +sage-system-python makemakefile.py >Makefile \ + --prefix="$SAGE_LOCAL" --cflags="$CFLAGS" --ldflags="$LDFLAGS" \ + --cppflags="$CPPFLAGS" --cxxflags="$CXXFLAGS" \ + --gmp-prefix="$SAGE_LOCAL" || sdh_die "Error generating Makefile." echo "Now building zn_poly with its tuning parameters..." sdh_make diff --git a/build/pkgs/zope_interface/checksums.ini b/build/pkgs/zope_interface/checksums.ini index 3ca9aace182..2c713d14909 100644 --- a/build/pkgs/zope_interface/checksums.ini +++ b/build/pkgs/zope_interface/checksums.ini @@ -1,4 +1,4 @@ tarball=zope.interface-VERSION.tar.gz -sha1=5d25841d8d4c4cce043119351fd9944d38f8422a -md5=8700a4f527c1203b34b10c2b4e7a6912 -cksum=2027953480 +sha1=e4dd98256b168e7888abbf6798789c775f5eae35 +md5=a3b24f9d079bae5e13dd7a88aa512112 +cksum=1864918591 diff --git a/build/pkgs/zope_interface/package-version.txt b/build/pkgs/zope_interface/package-version.txt index 9e3a93350d3..6016e8addc4 100644 --- a/build/pkgs/zope_interface/package-version.txt +++ b/build/pkgs/zope_interface/package-version.txt @@ -1 +1 @@ -4.4.3 +4.6.0 diff --git a/build/sage_bootstrap/uncompress/tar_file.py b/build/sage_bootstrap/uncompress/tar_file.py index 57621527acc..cf707e78a3a 100644 --- a/build/sage_bootstrap/uncompress/tar_file.py +++ b/build/sage_bootstrap/uncompress/tar_file.py @@ -68,6 +68,7 @@ def chmod(self, tarinfo, targetpath): """Apply ``self.umask`` instead of the permissions in the TarInfo.""" tarinfo = copy.copy(tarinfo) tarinfo.mode &= ~self.umask + tarinfo.mode |= stat.S_IWUSR tarinfo.mode &= ~(stat.S_ISUID | stat.S_ISGID) return super(SageBaseTarFile, self).chmod(tarinfo, targetpath) diff --git a/build/sage_bootstrap/uninstall.py b/build/sage_bootstrap/uninstall.py index 96bedc804df..6ae13b41897 100644 --- a/build/sage_bootstrap/uninstall.py +++ b/build/sage_bootstrap/uninstall.py @@ -70,33 +70,37 @@ def uninstall(spkg_name, sage_local, keep_files=False, verbose=False): # Find all stamp files for the package; there should be only one, but if # there is somehow more than one we'll work with the most recent and delete # the rest - stamp_files = glob.glob(pth.join(spkg_inst, '{0}-*'.format(spkg_name))) - - if len(stamp_files) > 1: - stamp_files.sort(key=pth.getmtime) - elif not stamp_files: - print("No record that '{0}' was ever installed; skipping " - "uninstall".format(spkg_name), file=sys.stderr) - return - - stamp_file = stamp_files[-1] + pattern = pth.join(spkg_inst, '{0}-*'.format(spkg_name)) + stamp_files = sorted(glob.glob(pattern), key=pth.getmtime) if keep_files: - print("Removing stamp file '{0}' but keeping package files".format( - stamp_file)) + print("Removing stamp file but keeping package files") remove_stamp_files(stamp_files) return - try: - with open(stamp_file) as f: - spkg_meta = json.load(f) - except (OSError, ValueError): - spkg_meta = {} + if stamp_files: + stamp_file = stamp_files[-1] + else: + stamp_file = None + + spkg_meta = {} + if stamp_file: + try: + with open(stamp_file) as f: + spkg_meta = json.load(f) + except (OSError, ValueError): + pass if 'files' not in spkg_meta: - print("Old-style or corrupt stamp file '{0}'".format(stamp_file), - file=sys.stderr) + if stamp_file: + print("Old-style or corrupt stamp file '{0}'" + .format(stamp_file), file=sys.stderr) + else: + print("Package '{0}' is currently not installed" + .format(spkg_name), file=sys.stderr) + # Run legacy uninstaller even if there is no stamp file: the + # package may be partially installed without a stamp file legacy_uninstall(spkg_name, verbose=verbose) else: files = spkg_meta['files'] @@ -118,8 +122,7 @@ def legacy_uninstall(spkg_name, verbose=False): spkg_dir = pth.join(PKGS, spkg_name) legacy_uninstall = pth.join(spkg_dir, 'spkg-legacy-uninstall') - if not (pth.isfile(legacy_uninstall) and - os.access(legacy_uninstall, os.X_OK)): + if not pth.isfile(legacy_uninstall): print("No legacy uninstaller found for '{0}'; nothing to " "do".format(spkg_name), file=sys.stderr) return @@ -131,7 +134,7 @@ def legacy_uninstall(spkg_name, verbose=False): # Any errors from this, including a non-zero return code will # bubble up and exit the uninstaller - subprocess.check_call([legacy_uninstall]) + subprocess.check_call(['bash', legacy_uninstall]) def modern_uninstall(spkg_name, sage_local, files, verbose=False): @@ -227,8 +230,7 @@ def rmdir(dirname): def remove_stamp_files(stamp_files, verbose=False): # Finally, if all went well, delete all the stamp files. for stamp_file in stamp_files: - if verbose: - print('rm "{}"'.format(stamp_file)) + print("Removing stamp file '{0}'".format(stamp_file)) os.remove(stamp_file) diff --git a/configure.ac b/configure.ac index f727a46d082..a25133efe52 100644 --- a/configure.ac +++ b/configure.ac @@ -216,6 +216,18 @@ then AC_MSG_ERROR([Exiting, as the macro processor 'm4' can not be found.]) fi +m4_ifndef([PKG_PROG_PKG_CONFIG], [m4_errprint( +[Error: could not locate the pkg-config autoconf macros. These are +usually located in /usr/share/aclocal/pkg.m4. If your macros are +in a different location, try setting the environment variable +ACLOCAL="aclocal -I/other/macro/dir" before running ./bootstrap +]) +dnl Exit autoconf with exit code 16 in this case. This will be +dnl caught by the bootstrap script. +m4_exit(16)]) + +PKG_PROG_PKG_CONFIG + AC_CHECK_PROG(found_ranlib, ranlib, yes, no) if test x$found_ranlib != xyes then @@ -311,7 +323,6 @@ AC_PROG_CXX() AC_PROG_FC() AC_SUBST(CC) -AC_SUBST(CXX) AC_SUBST(FC) # On darwin, also set the objective C/C++ compilers diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 00000000000..9e9eaedaaad --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,948 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# Copyright (c) 2016, 2018 Krzesimir Nowak +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 10 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], + [$1], [14], [ax_cxx_compile_alternatives="14 1y"], + [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + AC_SUBST(HAVE_CXX$1) +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 +) + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) + + +dnl Tests for new features in C++17 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201703L + +#error "This is not a C++17 compiler" + +#else + +#include +#include +#include + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_structured_bindings + { + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus < 201703L + +]]) diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4 index 516da37e822..1733fd85f95 100644 --- a/m4/ax_cxx_compile_stdcxx_11.m4 +++ b/m4/ax_cxx_compile_stdcxx_11.m4 @@ -1,26 +1,23 @@ -# ============================================================================ -# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html -# ============================================================================ +# ============================================================================= +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================= # # SYNOPSIS # -# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) +# AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 -# standard; if necessary, add switches to CXXFLAGS to enable support. +# standard; if necessary, add switches to CXX and CXXCPP to enable +# support. # -# The first argument, if specified, indicates whether you insist on an -# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -# -std=c++11). If neither is specified, you get whatever works, with -# preference for an extended mode. -# -# The second argument, if specified 'mandatory' or if left unspecified, -# indicates that baseline C++11 support is required and that the macro -# should error out if no mode with that support is found. If specified -# 'optional', then configuration proceeds regardless, after defining -# HAVE_CXX11 if and only if a supporting mode is found. +# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX +# macro with the version set to C++11. The two optional arguments are +# forwarded literally as the second and third argument respectively. +# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for +# more information. If you want to use this macro, you also need to +# download the ax_cxx_compile_stdcxx.m4 file. # # LICENSE # @@ -29,144 +26,14 @@ # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov # Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 13 - -m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - struct Base { - virtual void f() {} - }; - struct Child : public Base { - virtual void f() override {} - }; - - typedef check> right_angle_brackets; - - int a; - decltype(a) b; - - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); - - auto d = a; - auto l = [](){}; - // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable] - struct use_l { use_l() { l(); } }; - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { - func(0); - } - } - - // Check for C++11 attribute support - void noret [[noreturn]] () { throw 0; } -]]) - -AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl - m4_if([$1], [], [], - [$1], [ext], [], - [$1], [noext], [], - [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl - m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], - [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], - [$2], [optional], [ax_cxx_compile_cxx11_required=false], - [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) - AC_LANG_PUSH([C++])dnl - ac_success=no - AC_CACHE_CHECK(whether $CXX supports C++11 features by default, - ax_cv_cxx_compile_cxx11, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], - [ax_cv_cxx_compile_cxx11=yes], - [ax_cv_cxx_compile_cxx11=no])]) - if test x$ax_cv_cxx_compile_cxx11 = xyes; then - ac_success=yes - fi - - m4_if([$1], [noext], [], [dnl - if test x$ac_success = xno; then - for switch in -std=gnu++11 -std=gnu++0x; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, - $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes - break - fi - done - fi]) - - m4_if([$1], [ext], [], [dnl - if test x$ac_success = xno; then - dnl HP's aCC needs +std=c++11 according to: - dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf - dnl Cray's crayCC needs "-h std=c++11" - for switch in -std=c++11 -std=c++0x +std=c++11 "-h std=c++11"; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, - $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes - break - fi - done - fi]) - AC_LANG_POP([C++]) - if test x$ax_cxx_compile_cxx11_required = xtrue; then - if test x$ac_success = xno; then - AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) - fi - else - if test x$ac_success = xno; then - HAVE_CXX11=0 - AC_MSG_NOTICE([No compiler with C++11 support was found]) - else - HAVE_CXX11=1 - AC_DEFINE(HAVE_CXX11,1, - [define if the compiler supports basic C++11 syntax]) - fi +#serial 18 - AC_SUBST(HAVE_CXX11) - fi -]) +AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])]) diff --git a/m4/sage_spkg_collect.m4 b/m4/sage_spkg_collect.m4 index 20fe870ff41..304d1988b15 100644 --- a/m4/sage_spkg_collect.m4 +++ b/m4/sage_spkg_collect.m4 @@ -72,11 +72,11 @@ AC_MSG_RESULT([]) # Usage: newest_version $pkg # Print version number of latest package $pkg newest_version() { - PKG=$[1] - if test -f "$SAGE_ROOT/build/pkgs/$PKG/package-version.txt" ; then - cat "$SAGE_ROOT/build/pkgs/$PKG/package-version.txt" + SPKG=$[1] + if test -f "$SAGE_ROOT/build/pkgs/$SPKG/package-version.txt" ; then + cat "$SAGE_ROOT/build/pkgs/$SPKG/package-version.txt" else - echo "$PKG" + echo "$SPKG" fi } @@ -113,74 +113,74 @@ SAGE_SCRIPT_PACKAGES='\ for DIR in $SAGE_ROOT/build/pkgs/*; do test -d "$DIR" || continue - PKG_TYPE_FILE="$DIR/type" - if test -f "$PKG_TYPE_FILE"; then - PKG_TYPE=`cat $PKG_TYPE_FILE` + SPKG_TYPE_FILE="$DIR/type" + if test -f "$SPKG_TYPE_FILE"; then + SPKG_TYPE=`cat $SPKG_TYPE_FILE` else - AC_MSG_ERROR(["$PKG_TYPE_FILE" is missing.]) + AC_MSG_ERROR(["$SPKG_TYPE_FILE" is missing.]) fi - PKG_NAME=$(basename $DIR) - PKG_VERSION=$(newest_version $PKG_NAME) + SPKG_NAME=$(basename $DIR) + SPKG_VERSION=$(newest_version $SPKG_NAME) in_sdist=no # Check consistency of 'DIR/type' file - case "$PKG_TYPE" in + case "$SPKG_TYPE" in base) ;; - standard) - SAGE_STANDARD_PACKAGES+=" $PKG_NAME \\"$'\n' + standard) + SAGE_STANDARD_PACKAGES+=" $SPKG_NAME \\"$'\n' in_sdist=yes ;; optional) - if test -f $SAGE_SPKG_INST/$PKG_NAME-*; then - SAGE_OPTIONAL_INSTALLED_PACKAGES+=" $PKG_NAME \\"$'\n' + if test -f $SAGE_SPKG_INST/$SPKG_NAME-*; then + SAGE_OPTIONAL_INSTALLED_PACKAGES+=" $SPKG_NAME \\"$'\n' fi; ;; experimental) ;; script) ;; pip) ;; *) - AC_MSG_ERROR([The content of "$PKG_TYPE_FILE" must be 'base', 'standard', 'optional', 'experimental', 'script', or 'pip']) + AC_MSG_ERROR([The content of "$SPKG_TYPE_FILE" must be 'base', 'standard', 'optional', 'experimental', 'script', or 'pip']) ;; esac - SAGE_PACKAGE_VERSIONS+="vers_$PKG_NAME = $PKG_VERSION"$'\n' + SAGE_PACKAGE_VERSIONS+="vers_$SPKG_NAME = $SPKG_VERSION"$'\n' - # If $sage_spkg_install_{PKG_NAME} is set to no, then set inst_ to + # If $sage_spkg_install_{SPKG_NAME} is set to no, then set inst_ to # some dummy file to skip the installation. Note that an explicit - # "./sage -i PKG_NAME" will still install the package. - if test "$PKG_NAME" != "$PKG_VERSION"; then - sage_spkg_install="sage_spkg_install_${PKG_NAME}" + # "./sage -i SPKG_NAME" will still install the package. + if test "$SPKG_NAME" != "$SPKG_VERSION"; then + sage_spkg_install="sage_spkg_install_${SPKG_NAME}" if test "${!sage_spkg_install}" != no ; then - SAGE_BUILT_PACKAGES+=" $PKG_NAME \\"$'\n' - AC_MSG_RESULT([ $PKG_NAME-$PKG_VERSION]) + SAGE_BUILT_PACKAGES+=" $SPKG_NAME \\"$'\n' + AC_MSG_RESULT([ $SPKG_NAME-$SPKG_VERSION]) else - SAGE_DUMMY_PACKAGES+=" $PKG_NAME \\"$'\n' - AC_MSG_RESULT([ $PKG_NAME-$PKG_VERSION not installed (configure check)]) + SAGE_DUMMY_PACKAGES+=" $SPKG_NAME \\"$'\n' + AC_MSG_RESULT([ $SPKG_NAME-$SPKG_VERSION will not be installed (configure check)]) fi fi # Packages that should be included in the source distribution # This includes all standard packages and two special cases - case "$PKG_NAME" in + case "$SPKG_NAME" in mpir|python2) in_sdist=yes ;; esac if test "$in_sdist" = yes; then - SAGE_SDIST_PACKAGES+=" $PKG_NAME \\"$'\n' + SAGE_SDIST_PACKAGES+=" $SPKG_NAME \\"$'\n' fi # Determine package dependencies - DEP_FILE="$SAGE_ROOT/build/pkgs/$PKG_NAME/dependencies" + DEP_FILE="$SAGE_ROOT/build/pkgs/$SPKG_NAME/dependencies" if test -f "$DEP_FILE"; then # - the # symbol is treated as comment which is removed DEPS=`sed 's/^ *//; s/ *#.*//; q' $DEP_FILE` else - case "$PKG_TYPE" in + case "$SPKG_TYPE" in optional) DEPS=' | $(STANDARD_PACKAGES)' # default for optional packages ;; @@ -196,18 +196,18 @@ for DIR in $SAGE_ROOT/build/pkgs/*; do esac fi - SAGE_PACKAGE_DEPENDENCIES+="deps_$PKG_NAME = $DEPS"$'\n' + SAGE_PACKAGE_DEPENDENCIES+="deps_$SPKG_NAME = $DEPS"$'\n' # Determine package build rules - case "$PKG_TYPE" in + case "$SPKG_TYPE" in pip) - SAGE_PIP_PACKAGES+=" $PKG_NAME \\"$'\n' + SAGE_PIP_PACKAGES+=" $SPKG_NAME \\"$'\n' ;; script) - SAGE_SCRIPT_PACKAGES+=" $PKG_NAME \\"$'\n' + SAGE_SCRIPT_PACKAGES+=" $SPKG_NAME \\"$'\n' ;; *) - SAGE_NORMAL_PACKAGES+=" $PKG_NAME \\"$'\n' + SAGE_NORMAL_PACKAGES+=" $SPKG_NAME \\"$'\n' ;; esac done diff --git a/src/bin/math-readline b/src/bin/math-readline index 5a1390609d4..22c70518800 100755 --- a/src/bin/math-readline +++ b/src/bin/math-readline @@ -5,8 +5,9 @@ # See # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/363500 -import sys, signal, subprocess -import readline +import sys +import signal +import subprocess from six.moves import input def child_exited(*args): diff --git a/src/bin/sage b/src/bin/sage index 065b965b4bb..b314b20dfb6 100755 --- a/src/bin/sage +++ b/src/bin/sage @@ -118,6 +118,7 @@ usage_advanced() { echo " -ipython [...] -- run Sage's IPython using the default environment (not" echo " Sage), passing additional options to IPython" echo " -ipython3 [...] -- same as above, but using Python 3" + echo " -jupyter [...] -- run Sage's Jupyter with given arguments" echo " -kash [...] -- run Sage's Kash with given arguments" command -v kash &>/dev/null || \ echo " (not installed currently, run sage -i kash)" @@ -131,6 +132,8 @@ usage_advanced() { command -v polymake &>/dev/null || \ echo " (not installed currently, run sage -i polymake)" echo " -python [...] -- run the Python interpreter" + echo " -python2 [...] -- run the Python 2 interpreter" + echo " -python3 [...] -- run the Python 3 interpreter" echo " -R [...] -- run Sage's R with given arguments" echo " -scons [...] -- run Sage's scons" echo " -sh [...] -- run \$SHELL ($SHELL) with Sage environment variables" @@ -631,6 +634,11 @@ if [ "$1" = '-ipython3' -o "$1" = '--ipython3' ]; then exec ipython3 "$@" fi +if [ "$1" = '-jupyter' -o "$1" = '--jupyter' ]; then + shift + exec jupyter "$@" +fi + if [ "$1" = '-git' -o "$1" = '--git' ]; then shift exec git "$@" diff --git a/src/bin/sage-coverage b/src/bin/sage-coverage index 1fe1383664e..d73df95ab96 100755 --- a/src/bin/sage-coverage +++ b/src/bin/sage-coverage @@ -4,7 +4,6 @@ from __future__ import print_function import os import sys -import token from tokenize import * import argparse diff --git a/src/bin/sage-cython b/src/bin/sage-cython index e38222ca763..526c68b5903 100755 --- a/src/bin/sage-cython +++ b/src/bin/sage-cython @@ -1,5 +1,10 @@ #!/usr/bin/env python +# This script is a deprecated wrapper around the "cython" program. +# It is deprecated since Trac #27041 (Sage 8.7) because one should +# simply use "cython" directly. We display deprecation messages whenever +# "sage-cython" does something different from plain "cython". + import os import sys args = sys.argv[1:] @@ -12,24 +17,16 @@ SAGE_SRC = os.environ["SAGE_SRC"] pyx_file = os.path.abspath(args[-1]) if len(args) else None include_sage_flags = False -if pyx_file and pyx_file.endswith('.spyx'): - sys.stderr.write("WARNING: running sage --cython on .spyx files is deprecated, use the .pyx extension instead\n") - spyx_file = pyx_file - pyx_file = pyx_file[:-5] + '.pyx' - args[-1] = pyx_file - f = open(pyx_file, 'w') - f.write("include 'sage/ext/stdsage.pxi'\ninclude 'sage/ext/cdefs.pxi'\ninclude 'cysignals/signals.pxi'\n\n") - f.write(open(spyx_file).read()) - f.close() - include_sage_flags = True - if pyx_file and pyx_file.startswith(SAGE_SRC): + sys.stderr.write("WARNING: in the future, sage --cython will not add special flags for files in Sage sources.\n") include_sage_flags = True if '-sage' in args: + sys.stderr.write("WARNING: sage --cython -sage is deprecated.\n") include_sage_flags = True args.remove('-sage') elif '-no-sage' in args: + sys.stderr.write("WARNING: sage --cython -no-sage is deprecated, remove the -no-sage flag.\n") include_sage_flags = False args.remove('-no-sage') diff --git a/src/bin/sage-dist-helpers b/src/bin/sage-dist-helpers index 7b472b92a52..8ed0fc5ee9e 100644 --- a/src/bin/sage-dist-helpers +++ b/src/bin/sage-dist-helpers @@ -58,6 +58,13 @@ # If $SAGE_DESTDIR is not set then the command is run with $SAGE_SUDO, if # set. # +# - sdh_cmake [...] +# +# Runs `cmake` in the current directory with the given arguments, as well as +# additional arguments passed to cmake (assuming packages are using the +# GNUInstallDirs module) so that `CMAKE_INSTALL_PREFIX` and +# `CMAKE_INSTALL_LIBDIR` are set correctly. +# # - sdh_install [-T] SRC [SRC...] DEST # # Copies one or more files or directories given as SRC (recursively in the @@ -194,6 +201,25 @@ sdh_pip_install() { } +sdh_cmake() { + echo "Configuring $PKG_NAME with cmake" + cmake . -DCMAKE_INSTALL_PREFIX="${SAGE_LOCAL}" \ + -DCMAKE_INSTALL_LIBDIR=lib \ + "$@" + if [ $? -ne 0 ]; then + if [ -f "$(pwd)/CMakeFiles/CMakeOutput.log" ]; then + sdh_die <<_EOF_ +Error configuring $PKG_NAME with cmake +See the file + $(pwd)/CMakeFiles/CMakeOutput.log +for details. +_EOF_ + fi + sdh_die "Error configuring $PKG_NAME with cmake" + fi +} + + sdh_install() { local T=0 local src=() diff --git a/src/bin/sage-location b/src/bin/sage-location index 306cb33fdbf..54dbe783ca2 100755 --- a/src/bin/sage-location +++ b/src/bin/sage-location @@ -2,7 +2,6 @@ from __future__ import print_function -import glob import os import sys diff --git a/src/bin/sage-notebook b/src/bin/sage-notebook index 38b680da5d5..83109e627c9 100755 --- a/src/bin/sage-notebook +++ b/src/bin/sage-notebook @@ -10,7 +10,6 @@ import textwrap logging.basicConfig() logger = logging.getLogger() -from sage.env import SAGE_ROOT from sage.misc.banner import banner diff --git a/src/bin/sage-pkg b/src/bin/sage-pkg index 3d6fac0a30d..1b79001c110 100755 --- a/src/bin/sage-pkg +++ b/src/bin/sage-pkg @@ -2,8 +2,10 @@ from __future__ import print_function -import os, sys -from subprocess import Popen, PIPE, check_call, CalledProcessError +import os +import sys +from subprocess import check_call, CalledProcessError + def tar_file(dir, no_compress=False): """ diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 9a68545d221..18ef79cf6d0 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='8.6' -SAGE_RELEASE_DATE='2019-01-15' -SAGE_VERSION_BANNER='SageMath version 8.6, Release Date: 2019-01-15' +SAGE_VERSION='8.7' +SAGE_RELEASE_DATE='2019-03-23' +SAGE_VERSION_BANNER='SageMath version 8.7, Release Date: 2019-03-23' diff --git a/src/doc/ca/intro/conf.py b/src/doc/ca/intro/conf.py index 63c3ec62000..f77af7c5435 100644 --- a/src/doc/ca/intro/conf.py +++ b/src/doc/ca/intro/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/common/conf.py b/src/doc/common/conf.py index 7ded51f1fec..70dd17f271f 100644 --- a/src/doc/common/conf.py +++ b/src/doc/common/conf.py @@ -13,39 +13,93 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['inventory_builder', 'multidocs', - 'sage_autodoc', 'sphinx.ext.graphviz', - 'sphinx.ext.inheritance_diagram', 'sphinx.ext.todo', - 'sphinx.ext.extlinks', 'matplotlib.sphinxext.plot_directive'] +extensions = ['inventory_builder', 'multidocs', 'sage_autodoc', + 'sphinx.ext.graphviz', 'sphinx.ext.inheritance_diagram', + 'sphinx.ext.todo', 'sphinx.ext.extlinks', + 'matplotlib.sphinxext.plot_directive'] # This code is executed before each ".. PLOT::" directive in the Sphinx # documentation. It defines a 'sphinx_plot' function that displays a Sage object # through mathplotlib, so that it will be displayed in the HTML doc plot_html_show_source_link = False plot_pre_code = """ -def sphinx_plot(plot): +def sphinx_plot(graphics, **kwds): import matplotlib.image as mpimg from sage.misc.temporary_file import tmp_filename import matplotlib.pyplot as plt if os.environ.get('SAGE_SKIP_PLOT_DIRECTIVE', 'no') != 'yes': - import matplotlib as mpl - mpl.rcParams['image.interpolation'] = 'bilinear' - mpl.rcParams['image.resample'] = False - mpl.rcParams['figure.figsize'] = [8.0, 6.0] - mpl.rcParams['figure.dpi'] = 80 - mpl.rcParams['savefig.dpi'] = 100 - fn = tmp_filename(ext=".png") - plot.plot().save(fn) - img = mpimg.imread(fn) - plt.imshow(img) + ## Option handling is taken from Graphics.save + options = dict() + if isinstance(graphics, sage.plot.graphics.Graphics): + options.update(graphics.SHOW_OPTIONS) + options.update(graphics._extra_kwds) + options.update(kwds) + else: + graphics = graphics.plot(**kwds) + dpi = options.pop('dpi', None) + transparent = options.pop('transparent', None) + fig_tight = options.pop('fig_tight', None) + figsize = options.pop('figsize', None) + ## figsize handling is taken from Graphics.matplotlib() + if figsize is not None and not isinstance(figsize, (list, tuple)): + # in this case, figsize is a number and should be positive + try: + figsize = float(figsize) # to pass to mpl + except TypeError: + raise TypeError("figsize should be a positive number, not {0}".format(figsize)) + if figsize > 0: + default_width, default_height=rcParams['figure.figsize'] + figsize=(figsize, default_height*figsize/default_width) + else: + raise ValueError("figsize should be positive, not {0}".format(figsize)) + + if figsize is not None: + # then the figsize should be two positive numbers + if len(figsize) != 2: + raise ValueError("figsize should be a positive number " + "or a list of two positive numbers, not {0}".format(figsize)) + figsize = (float(figsize[0]),float(figsize[1])) # floats for mpl + if not (figsize[0] > 0 and figsize[1] > 0): + raise ValueError("figsize should be positive numbers, " + "not {0} and {1}".format(figsize[0],figsize[1])) + + plt.figure(figsize=figsize) + figure = plt.gcf() + if isinstance(graphics, sage.plot.graphics.GraphicsArray): + ## from GraphicsArray.save + rows = graphics.nrows() + cols = graphics.ncols() + for i, g in enumerate(graphics): + subplot = figure.add_subplot(rows, cols, i + 1) + g_options = copy(options) + g_options.update(g.SHOW_OPTIONS) + g_options.update(g._extra_kwds) + g_options.pop('dpi', None) + g_options.pop('transparent', None) + g_options.pop('fig_tight', None) + g.matplotlib(figure=figure, sub=subplot, **g_options) + elif isinstance(graphics, sage.plot.graphics.Graphics): + graphics.matplotlib(figure=figure, figsize=figsize, **options) + else: + # 3d graphics via png + import matplotlib as mpl + mpl.rcParams['image.interpolation'] = 'bilinear' + mpl.rcParams['image.resample'] = False + mpl.rcParams['figure.figsize'] = [8.0, 6.0] + mpl.rcParams['figure.dpi'] = 80 + mpl.rcParams['savefig.dpi'] = 100 + fn = tmp_filename(ext=".png") + graphics.save(fn) + img = mpimg.imread(fn) + plt.imshow(img) plt.margins(0) - plt.axis("off") plt.tight_layout(pad=0) from sage.all_cmdline import * """ plot_html_show_formats = False +plot_formats = ['svg', 'pdf', 'png'] # We do *not* fully initialize intersphinx since we call it by hand # in find_sage_dangling_links. @@ -123,7 +177,8 @@ def sphinx_plot(plot): intersphinx_mapping = { 'python': ('https://docs.python.org/', os.path.join(SAGE_DOC_SRC, "common", - "python{}.inv".format(python_version)))} + "python{}.inv".format(python_version))), + 'pplpy': (os.path.join(SAGE_SHARE, "doc", "pplpy"), None)} def set_intersphinx_mappings(app): """ @@ -613,10 +668,10 @@ def call_intersphinx(app, env, node, contnode): sage: thematic_index = os.path.join(SAGE_DOC, "html", "en", "thematic_tutorials", "index.html") # optional - dochtml sage: for line in open(thematic_index).readlines(): # optional - dochtml ....: if "padics" in line: - ....: sys.stdout.write(line) + ....: _ = sys.stdout.write(line)
  • Introduction to the -adics
  • """ - debug_inf(app, "???? Trying intersphinx for %s"%node['reftarget']) + debug_inf(app, "???? Trying intersphinx for %s" % node['reftarget']) builder = app.builder res = sphinx.ext.intersphinx.missing_reference( app, env, node, contnode) @@ -628,9 +683,9 @@ def call_intersphinx(app, env, node, contnode): here = os.path.dirname(os.path.join(builder.outdir, node['refdoc'])) res['refuri'] = os.path.relpath(res['refuri'], here) - debug_inf(app, "++++ Found at %s"%res['refuri']) + debug_inf(app, "++++ Found at %s" % res['refuri']) else: - debug_inf(app, "---- Intersphinx: %s not Found"%node['reftarget']) + debug_inf(app, "---- Intersphinx: %s not Found" % node['reftarget']) return res def find_sage_dangling_links(app, env, node, contnode): @@ -644,7 +699,7 @@ def find_sage_dangling_links(app, env, node, contnode): try: doc = node['refdoc'] except KeyError: - debug_inf(app, "-- no refdoc in node %s"%node) + debug_inf(app, "-- no refdoc in node %s" % node) return None debug_inf(app, "Searching %s from %s"%(reftarget, doc)) @@ -672,15 +727,20 @@ def find_sage_dangling_links(app, env, node, contnode): basename = reftarget.split(".")[0] try: target_module = getattr(sys.modules['sage.all'], basename).__module__ + debug_inf(app, "++ found %s using sage.all in %s" % (basename, target_module)) except AttributeError: - debug_inf(app, "-- %s not found in sage.all"%(basename)) - return None + try: + target_module = getattr(sys.modules[node['py:module']], basename).__module__ + debug_inf(app, "++ found %s in this module" % (basename,)) + except AttributeError: + debug_inf(app, "-- %s not found in sage.all or this module" % (basename)) + return None + except KeyError: + target_module = None if target_module is None: target_module = "" debug_inf(app, "?? found in None !!!") - debug_inf(app, "++ found %s using sage.all in %s"%(basename, target_module)) - newtarget = target_module+'.'+reftarget node['reftarget'] = newtarget diff --git a/src/doc/de/a_tour_of_sage/conf.py b/src/doc/de/a_tour_of_sage/conf.py index b0842e2dfac..e84e90f2823 100644 --- a/src/doc/de/a_tour_of_sage/conf.py +++ b/src/doc/de/a_tour_of_sage/conf.py @@ -14,7 +14,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/de/thematische_anleitungen/conf.py b/src/doc/de/thematische_anleitungen/conf.py index 64bd041d3ea..06da30677e8 100644 --- a/src/doc/de/thematische_anleitungen/conf.py +++ b/src/doc/de/thematische_anleitungen/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/de/tutorial/conf.py b/src/doc/de/tutorial/conf.py index 3748cbf293b..b6762642b91 100644 --- a/src/doc/de/tutorial/conf.py +++ b/src/doc/de/tutorial/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/de/tutorial/interfaces.rst b/src/doc/de/tutorial/interfaces.rst index be8922852df..68e4ea2994f 100644 --- a/src/doc/de/tutorial/interfaces.rst +++ b/src/doc/de/tutorial/interfaces.rst @@ -172,7 +172,7 @@ die GAP-Schnittstelle aufzurufen: sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.group_id() [120, 34] sage: n = G.order(); n diff --git a/src/doc/de/tutorial/tour_groups.rst b/src/doc/de/tutorial/tour_groups.rst index db3a9441688..0f27fb297a6 100644 --- a/src/doc/de/tutorial/tour_groups.rst +++ b/src/doc/de/tutorial/tour_groups.rst @@ -23,7 +23,7 @@ Liste der Erzeuger wie folgt angeben. [Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.random_element() # random output (1,5,3)(2,4) sage: print(latex(G)) diff --git a/src/doc/en/a_tour_of_sage/conf.py b/src/doc/en/a_tour_of_sage/conf.py index 15eb4c88f63..cf0d96182ee 100644 --- a/src/doc/en/a_tour_of_sage/conf.py +++ b/src/doc/en/a_tour_of_sage/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/en/constructions/conf.py b/src/doc/en/constructions/conf.py index abead3b8710..3a3e83309cb 100644 --- a/src/doc/en/constructions/conf.py +++ b/src/doc/en/constructions/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/en/constructions/groups.rst b/src/doc/en/constructions/groups.rst index 30d8da423ed..43b945a8600 100644 --- a/src/doc/en/constructions/groups.rst +++ b/src/doc/en/constructions/groups.rst @@ -205,19 +205,19 @@ the ``gap`` command. Here's an example:: sage: G = PermutationGroup(['(1,2,3)(4,5)', '(3,4)']) sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) A similar syntax for matrix groups also works:: sage: G = SL(2, GF(5) ) sage: G.center() - Matrix group over Finite Field of size 5 with 1 generators ( + Subgroup with 1 generators ( [4 0] [0 4] - ) + ) of Special Linear Group of degree 2 over Finite Field of size 5 sage: G = PSL(2, 5 ) sage: G.center() - Subgroup of (The projective special linear group of degree 2 over Finite Field of size 5) generated by [()] + Subgroup generated by [()] of (The projective special linear group of degree 2 over Finite Field of size 5) .. NOTE:: ``center`` can be spelled either way in GAP, not so in Sage. diff --git a/src/doc/en/constructions/linear_codes.rst b/src/doc/en/constructions/linear_codes.rst index d5a4e994b59..969713263ad 100644 --- a/src/doc/en/constructions/linear_codes.rst +++ b/src/doc/en/constructions/linear_codes.rst @@ -264,6 +264,7 @@ reverse of ``berlekamp_massey``). 8/15 sage: lfsr_connection_polynomial(s) x^4 + x + 1 + sage: from sage.matrix.berlekamp_massey import berlekamp_massey sage: berlekamp_massey(s) x^4 + x^3 + 1 diff --git a/src/doc/en/constructions/modular_forms.rst b/src/doc/en/constructions/modular_forms.rst index 08bfeb266d1..49519e26252 100644 --- a/src/doc/en/constructions/modular_forms.rst +++ b/src/doc/en/constructions/modular_forms.rst @@ -93,7 +93,7 @@ of Full Modular Symbols for :math:`\Gamma_0(1)` of weight Modular Symbols space of dimension 4 for Gamma_1(6) of weight 3 with sign 0 and over Rational Field sage: M.basis() - ([X,(0,5)], [X,(3,2)], [X,(4,5)], [X,(5,4)]) + ([X,(0,5)], [X,(3,5)], [X,(4,5)], [X,(5,5)]) sage: M._compute_hecke_matrix_prime(2).charpoly() x^4 - 17*x^2 + 16 sage: M.integral_structure() diff --git a/src/doc/en/developer/conf.py b/src/doc/en/developer/conf.py index 653a8af95aa..62b5399b39d 100644 --- a/src/doc/en/developer/conf.py +++ b/src/doc/en/developer/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/en/developer/git_trac.rst b/src/doc/en/developer/git_trac.rst index d18160a39de..8342965484c 100644 --- a/src/doc/en/developer/git_trac.rst +++ b/src/doc/en/developer/git_trac.rst @@ -100,6 +100,23 @@ make sure that it is not readable by other users on your system. For example, by running ``chmod 0600 .git/config`` if your home directory is not already private. +Instead of a username and password you may also configure authentication via +a generated token by passing ``--token=`` instead of ``--pass``:: + + [user@localhost sage]$ git trac config --user= --token= + +This is required if you authenticate to Trac with your GitHub account, as +you do not have a Trac password. Logged in users can find their token +under `the token tab in preferences on the trac site `_ . + +If both a token and a username/password are configured, the token-based +authentication takes precedence. + +If you do not want to store your trac username/password/token on disk you +can temporarily override it with the environment variables +``TRAC_USERNAME``, ``TRAC_PASSWORD``, and ``TRAC_TOKEN`` respectively. +These take precedence over any other configuration. + If there is no SSH key listed then you haven't uploaded your SSH public key to the trac server. You should do that now following the instructions to :ref:`section-trac-ssh-key`, if you want to upload diff --git a/src/doc/en/developer/packaging.rst b/src/doc/en/developer/packaging.rst index b4e0357b837..94f1599a1a8 100644 --- a/src/doc/en/developer/packaging.rst +++ b/src/doc/en/developer/packaging.rst @@ -129,12 +129,13 @@ build and/or install the package. If no ``spkg-build`` exists, then the ``spkg-install`` is responsible for both steps, though separating them is encouraged where possible. -It is also possible to include a similar script named ``spkg-postinst`` to run -additional steps after the package has been installed into ``$SAGE_LOCAL``. It -is encouraged to put such steps in a separate ``spkg-postinst`` script rather -than combinging them with ``spkg-install``. This is because since -:trac:`24106`, ``spkg-install`` does not necessarily install packages directly -to ``$SAGE_LOCAL``. However, by the time ``spkg-postinst`` is run, the +It is also possible to include similar scripts named ``spkg-preinst`` or +``spkg-postinst`` to run additional steps before or after the package has been +installed into ``$SAGE_LOCAL``. It is encouraged to put steps which modify +already installed files in a separate ``spkg-postinst`` script rather than +combinging them with ``spkg-install``. This is because since :trac:`24106`, +``spkg-install`` does not necessarily install packages directly to +``$SAGE_LOCAL``. However, by the time ``spkg-postinst`` is run, the installation to ``$SAGE_LOCAL`` is complete. These scripts should *not* be prefixed with a shebang line (``#!...``) and diff --git a/src/doc/en/developer/reviewer_checklist.rst b/src/doc/en/developer/reviewer_checklist.rst index 0a446fc85eb..271290e3dc8 100644 --- a/src/doc/en/developer/reviewer_checklist.rst +++ b/src/doc/en/developer/reviewer_checklist.rst @@ -66,8 +66,14 @@ The following should generally be checked while reading and testing the code: claims to speed up some computation, does the ticket contain code examples to illustrate the claim? The ticket should explain how the speedup is achieved. -- **Manuals**: Does the reference manual build without errors (check both html - and pdf)? See :ref:`chapter-sage_manuals` to learn how to build the manuals. +- **Build the manuals**: Does the reference manual build without + errors (check both html and pdf)? See :ref:`chapter-sage_manuals` to + learn how to build the manuals. + +- **Look at the manuals**: Does the reference manual look okay? The + changes may have typos that allow the documentation to build without + apparent errors but that may cause badly formatted output or broken + hyperlinks. - **Run the tests**: Do all doctests pass without errors? Unrelated components of Sage may be affected by the change. Check all tests in the whole library, diff --git a/src/doc/en/developer/trac.rst b/src/doc/en/developer/trac.rst index 621ce8d6f38..37fe01b2656 100644 --- a/src/doc/en/developer/trac.rst +++ b/src/doc/en/developer/trac.rst @@ -35,11 +35,9 @@ order to post anything to Sage's Trac. Now, if you have a GitHub account, you may log in using it to create and comment on tickets, and edit wiki pages on Sage's Trac. -A manual account request is currently only necessary if you prefer not to use -GitHub, if you wish to use the ``git trac`` git plugin (the ``git trac`` plugin -is useful for beginners, but is not be necessary for experienced git users), or -you want to log into the old `Sage Wiki `_. This may -change as well in the future. +A manual account request is currently only necessary if you prefer not to +use GitHub or if you want to log into the old `Sage Wiki +`_. This may change as well in the future. To obtain a non-GitHub account, send an email to ``sage-trac-account@googlegroups.com`` containing: @@ -50,9 +48,9 @@ To obtain a non-GitHub account, send an email to * and reason for needing a trac account Your trac account also grants you access to the `sage wiki -`_. Make sure you understand the review process, and the -procedures for opening and closing tickets before making changes. The remainder -of this chapter contains various guidelines on using the trac server. +`_. Make sure you understand the review process, and +the procedures for opening and closing tickets before making changes. The +remainder of this chapter contains various guidelines on using the trac server. Trac authentication through SSH =============================== diff --git a/src/doc/en/faq/conf.py b/src/doc/en/faq/conf.py index 47447f324c1..343dddedfc4 100644 --- a/src/doc/en/faq/conf.py +++ b/src/doc/en/faq/conf.py @@ -16,7 +16,8 @@ import os import sys -sys.path.append(os.environ["SAGE_DOC_SRC"]) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/en/installation/conf.py b/src/doc/en/installation/conf.py index 69f2dadef30..968c67255b7 100644 --- a/src/doc/en/installation/conf.py +++ b/src/doc/en/installation/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/en/installation/index.rst b/src/doc/en/installation/index.rst index 9463dfa1a06..c469d62db38 100644 --- a/src/doc/en/installation/index.rst +++ b/src/doc/en/installation/index.rst @@ -40,7 +40,7 @@ installing it: elementary SageMath computations. - `Docker images `_: SageMath in a - container for more expericenced users. + container for more experienced users. The rest of this document describes how to install SageMath from pre-built binaries and from sources. diff --git a/src/doc/en/introspect/conf.py b/src/doc/en/introspect/conf.py index 31815272f53..4c632676036 100644 --- a/src/doc/en/introspect/conf.py +++ b/src/doc/en/introspect/conf.py @@ -3,7 +3,8 @@ # See sagenb.notebook.cell.Cell.set_introspect_html() for details. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * extensions = ['sphinx.ext.autodoc', 'sphinx.ext.mathjax', 'sphinx.ext.todo', diff --git a/src/doc/en/prep/Quickstarts/Abstract-Algebra.rst b/src/doc/en/prep/Quickstarts/Abstract-Algebra.rst index 041d6f98763..5f68529c087 100644 --- a/src/doc/en/prep/Quickstarts/Abstract-Algebra.rst +++ b/src/doc/en/prep/Quickstarts/Abstract-Algebra.rst @@ -61,17 +61,17 @@ We can access a lot of information about groups, such as: sage: for K in D.conjugacy_classes_subgroups(): ....: print(K) - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [()] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(2,8)(3,7)(4,6)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,2)(3,8)(4,7)(5,6)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(2,8)(3,7)(4,6), (1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,2)(3,8)(4,7)(5,6), (1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(2,8)(3,7)(4,6), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,2,3,4,5,6,7,8), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,2)(3,8)(4,7)(5,6), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(2,8)(3,7)(4,6), (1,2,3,4,5,6,7,8), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] + Subgroup generated by [()] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(2,8)(3,7)(4,6)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,2)(3,8)(4,7)(5,6)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(2,8)(3,7)(4,6), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,2)(3,8)(4,7)(5,6), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(2,8)(3,7)(4,6), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,2,3,4,5,6,7,8), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,2)(3,8)(4,7)(5,6), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(2,8)(3,7)(4,6), (1,2,3,4,5,6,7,8), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) In the previous cell we once again did a for loop over a set of objects rather than just a list of numbers. This can be very powerful. @@ -79,19 +79,19 @@ rather than just a list of numbers. This can be very powerful. :: sage: D.stabilizer(3) - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,5)(2,4)(6,8)] + Subgroup generated by [(1,5)(2,4)(6,8)] of (Dihedral group of order 16 as a permutation group) :: sage: for K in D.normal_subgroups(): ....: print(K) - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,2,3,4,5,6,7,8), (1,8)(2,7)(3,6)(4,5)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,2,3,4,5,6,7,8), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8), (1,8)(2,7)(3,6)(4,5)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(2,8)(3,7)(4,6), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [(1,5)(2,6)(3,7)(4,8)] - Subgroup of (Dihedral group of order 16 as a permutation group) generated by [()] + Subgroup generated by [(1,2,3,4,5,6,7,8), (1,8)(2,7)(3,6)(4,5)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,2,3,4,5,6,7,8), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8), (1,8)(2,7)(3,6)(4,5)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(2,8)(3,7)(4,6), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [(1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group) + Subgroup generated by [()] of (Dihedral group of order 16 as a permutation group) We can access specific subgroups if we know the generators as a permutation group. diff --git a/src/doc/en/prep/conf.py b/src/doc/en/prep/conf.py index 14a0d1b0deb..d13fbb82f65 100644 --- a/src/doc/en/prep/conf.py +++ b/src/doc/en/prep/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * diff --git a/src/doc/en/reference/coercion/index.rst b/src/doc/en/reference/coercion/index.rst index 82b427a6493..5137254c21d 100644 --- a/src/doc/en/reference/coercion/index.rst +++ b/src/doc/en/reference/coercion/index.rst @@ -209,8 +209,8 @@ be obtained and queried. sage: parent(1 + 1/2) Rational Field - sage: cm = sage.structure.element.get_coercion_model(); cm - + sage: cm = coercion_model; cm + sage: cm.explain(ZZ, QQ) Coercion on left operand via Natural morphism: diff --git a/src/doc/en/reference/combinat/media/k-rim.JPG b/src/doc/en/reference/combinat/media/k-rim.JPG new file mode 100644 index 00000000000..87bc1d747cc Binary files /dev/null and b/src/doc/en/reference/combinat/media/k-rim.JPG differ diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 6d87ac9e2e4..859be86ceae 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -112,7 +112,6 @@ Comprehensive Module list sage/combinat/designs/subhypergraph_search sage/combinat/designs/twographs sage/combinat/diagram_algebras - sage/combinat/dict_addition sage/combinat/dlx sage/combinat/dyck_word sage/combinat/e_one_star @@ -323,7 +322,6 @@ Comprehensive Module list sage/combinat/species/__init__ sage/combinat/species/all sage/combinat/species/characteristic_species - sage/combinat/species/combinatorial_logarithm sage/combinat/species/composition_species sage/combinat/species/cycle_species sage/combinat/species/empty_species diff --git a/src/doc/en/reference/curves/index.rst b/src/doc/en/reference/curves/index.rst index dd206bb6843..928f4a927de 100644 --- a/src/doc/en/reference/curves/index.rst +++ b/src/doc/en/reference/curves/index.rst @@ -97,7 +97,6 @@ The following relate to elliptic curves over local nonarchimedean fields. sage/schemes/elliptic_curves/ell_local_data sage/schemes/elliptic_curves/kodaira_symbol sage/schemes/elliptic_curves/ell_tate_curve - sage/schemes/elliptic_curves/padics Analytic properties over `\CC`. diff --git a/src/doc/en/reference/function_fields/index.rst b/src/doc/en/reference/function_fields/index.rst index fa39b438361..5e30af66b4c 100644 --- a/src/doc/en/reference/function_fields/index.rst +++ b/src/doc/en/reference/function_fields/index.rst @@ -6,6 +6,8 @@ algebraic function fields over arbitrary constant fields. Advanced computations, like computing the genus or a basis of the Riemann-Roch space of a divisor, are available for global function fields. +A reference for the basic theory of algebraic function fields is [Stich2009]_. + .. toctree:: :maxdepth: 1 @@ -13,6 +15,10 @@ a divisor, are available for global function fields. sage/rings/function_field/element sage/rings/function_field/order sage/rings/function_field/ideal + sage/rings/function_field/place + sage/rings/function_field/divisor + sage/rings/function_field/differential + sage/rings/function_field/valuation_ring sage/rings/function_field/maps sage/rings/function_field/constructor diff --git a/src/doc/en/reference/libs/index.rst b/src/doc/en/reference/libs/index.rst index 382fbcc4aa1..17d4bc0be31 100644 --- a/src/doc/en/reference/libs/index.rst +++ b/src/doc/en/reference/libs/index.rst @@ -80,8 +80,8 @@ libSingular sage/libs/singular/ring sage/libs/singular/groebner_strategy -libGAP ------- +GAP +--- .. toctree:: :maxdepth: 2 diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 293749ab78d..75737b64239 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -65,6 +65,10 @@ REFERENCES: *Combinatorics of non-ambiguous trees*, :arxiv:`1305.3716` +.. [AE1993] \A. Apostolico, A. Ehrenfeucht, Efficient detection of + quasiperiodicities in strings, + Theoret. Comput. Sci. 119 (1993) 247--265. + .. [AGHJLPR2017] Benjamin Assarf, Ewgenij Gawrilow, Katrin Herr, Michael Joswig, Benjamin Lorenz, Andreas Paffenholz, and Thomas Rehn, Computing convex hulls and counting integer points with @@ -131,7 +135,7 @@ REFERENCES: Steenrod algebra," Proc. Cambridge Philos. Soc. 76 (1974), 45-52. -.. [AM2000] \S. Ariki and A. Mathas. +.. [AM2000] \S. Ariki and A. Mathas. *The number of simple modules of the Hecke algebras of type G(r,1,n)*. Math. Z. 233 (2000), no. 3, 601–623. :mathscinet:`MR1750939` @@ -160,6 +164,10 @@ REFERENCES: multipartitions*. Osaka J. Math. **38** (2001), 827–837. :mathscinet:`MR1864465` +.. [Arn2002] \P. Arnoux, Sturmian sequences, in Substitutions in Dynamics, + N. Pytheas Fogg (Ed.), Arithmetics, and Combinatorics (Lecture + Notes in Mathematics, Vol. 1794), 2002. + .. [AS-Bessel] \F. W. J. Olver: 9. Bessel Functions of Integer Order, in Abramowitz and Stegun: Handbook of Mathematical Functions. http://people.math.sfu.ca/~cbm/aands/page_355.htm @@ -204,6 +212,12 @@ REFERENCES: .. [Ava2017] \R. Avanzi, *The QARMA block cipher family*; in ToSC, (2017.1), pp. 4-44. +.. [AZZ2005] V. Anne, L.Q. Zamboni, I. Zorca, Palindromes and Pseudo- + Palindromes in Episturmian and Pseudo-Palindromic + Infinite Words, in : S. Brlek, C. Reutenauer (Eds.), + Words 2005, Publications du LaCIM, Vol. 36 (2005) + 91--100. + .. _ref-B: **B** @@ -239,6 +253,11 @@ REFERENCES: .. [BeBo2009] Olivier Bernardi and Nicolas Bonichon, *Intervals in Catalan lattices and realizers of triangulations*, JCTA 116 (2009) +.. [BBGL2008] \A. Blondin Massé, S. Brlek, A. Garon, and S. Labbé, + Combinatorial properties of f -palindromes in the + Thue-Morse sequence. Pure Math. Appl., + 19(2-3):39--52, 2008. + .. [BBISHAR2015] \S. Banik, A. Bogdanov, T. Isobe, K. Shibutani, H. Hiwatari, \T. Akishita, and F. Regazzoni, *Midori: A block cipher for low energy*; in ASIACRYPT, (2015), pp. 411-436. @@ -325,6 +344,10 @@ REFERENCES: *A study of the DVD content scrambling system (CSS) algorithm*; in Proceedings of ISSPIT, (2004), pp. 353-356. +.. [BDLV2006] \S. Brlek, S. Dulucq, A. Ladouceur, L. Vuillon, Combinatorial + properties of smooth infinite words, Theoret. Comput. Sci. 352 + (2006) 306--317. + .. [BDP2013] Thomas Brüstle, Grégoire Dupont, Matthieu Pérotin *On Maximal Green Sequences* :arxiv:`1205.2050` @@ -366,6 +389,11 @@ REFERENCES: .. [Ber1991] \C. Berger, "Une version effective du théorème de Hurewicz", https://tel.archives-ouvertes.fr/tel-00339314/en/. +.. [Ber2007] Jean Berstel. Sturmian and episturmian words (a survey of + some recent results). In S. Bozapalidis and G. Rahonis, + editors, CAI 2007,volume 4728 of Lecture Notes in + Computer Science, pages 23-47. Springer-Verlag, 2007. + .. [Ber2008] \W. Bertram : *Differential Geometry, Lie Groups and Symmetric Spaces over General Base Fields and Rings*, Memoirs of the American Mathematical Society, vol. 192 @@ -419,6 +447,13 @@ REFERENCES: Stein. strassen_window_multiply_c. strassen.pyx, Sage 3.0, 2008. http://www.sagemath.org +.. [BHNR2004] \S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the + Palindromic Complexity of Infinite Words, + in J. Berstel, J. Karhumaki, D. Perrin, Eds, + Combinatorics on Words with Applications, International + Journal of Foundation of Computer Science, Vol. 15, + No. 2 (2004) 293--306. + .. [Big1999] Stephen J. Bigelow. The Burau representation is not faithful for `n = 5`. Geom. Topol., 3:397--404, 1999. @@ -470,18 +505,34 @@ REFERENCES: M. Robshaw, Y. Seurin, C. Vikkelsoe. *PRESENT: An Ultra-Lightweight Block Cipher*; in Proceedings of CHES 2007; LNCS 7427; pp. 450-466; Springer Verlag 2007; available at - http://www.crypto.rub.de/imperia/md/content/texte/publications/conferences/present_ches2007.pdf + :doi:`10.1007/978-1-4419-5906-5_605` .. [BKW2011] \J. Brundan, A. Kleshchev, and W. Wang, *Graded Specht modules*, J. Reine Angew. Math., **655** (2011), 61-87. :mathscinet:`MR2806105` +.. [BL1994] Bernhard Beckermann, George Labahn. "A Uniform Approach for the + Fast Computation of Matrix-Type Padé Approximants". SIAM J. Matrix + Anal. Appl. 15 (1994) 804-823. + http://dx.doi.org/10.1137/S0895479892230031 + +.. [BMP2007] \S. Brlek, G. Melançon, G. Paquin, Properties of the + extremal infinite smooth words, Discrete + Math. Theor. Comput. Sci. 9 (2007) 33--49. + +.. [BMPS2018] Jonah Blasiak, Jennifer Morse, Anna Pun, and Daniel Summers. + *Catalan functions and k-schur positivity* + :arxiv:`1804.03701` + .. [BL2000] Anders Björner and Frank H. Lutz, "Simplicial manifolds, bistellar flips and a 16-vertex triangulation of the Poincaré homology 3-sphere", Experiment. Math. 9 (2000), no. 2, 275-289. +.. [BL2003] \S. Brlek, A. Ladouceur, A note on differentiable palindromes, + Theoret. Comput. Sci. 302 (2003) 167--178. + .. [BL2008] Corentin Boissy and Erwan Lanneau, *Dynamics and geometry of the Rauzy-Veech induction for quadratic differentials* (:arxiv:`0710.5614`) to appear in Ergodic Theory and @@ -491,6 +542,12 @@ REFERENCES: with differential uniformity of 4*, Proceedings of the Conference BFCA, Copenhagen, 2008. +.. [BLRS2009] \J. Berstel, A. Lauve, C. Reutenauer, F. Saliola, + Combinatorics on words: Christoffel words and + repetitions in words, CRM Monograph Series, 27. American + Mathematical Society, Providence, RI, 2009. xii+147 + pp. ISBN: 978-0-8218-4480-9 + .. [BLV1999] Bernhard Beckermann, George Labahn, and Gilles Villard. "Shifted normal forms of polynomial matrices". In ISSAC'99, pages 189-196. ACM, 1999. https://doi.org/10.1145/309831.309929 . @@ -503,6 +560,9 @@ REFERENCES: generators for inseparable algebraic extensions. Bulletin of the American Mathematical Society 46, no. 2 (1940): 182-186. +.. [BM1977] \R. S. Boyer, J. S. Moore, A fast string searching + algorithm, Communications of the ACM 20 (1977) 762--772. + .. [BM2008] John Adrian Bondy and U.S.R. Murty, "Graph theory", Volume 244 of Graduate Texts in Mathematics, 2nd edition, Springer, 2008. @@ -515,6 +575,16 @@ REFERENCES: LMS Journal of Computation and Mathematics, Volume 15 (2012), pp 400-417. +.. [BMBFLR2008] A. Blondin-Massé, S. Brlek, A. Frosini, S. Labbé, + S. Rinaldi, *Reconstructing words from a fixed + palindromic length sequence*, Proc. TCS 2008, 5th IFIP + International Conference on Theoretical Computer + Science (September 8-10 2008, Milano, Italia). + +.. [BMBL2008] A. Blondin-Massé, S. Brlek, S. Labbé, *Palindromic + lacunas of the Thue-Morse word*, Proc. GASCOM 2008 (June + 16-20 2008, Bibbiena, Arezzo-Italia), 53--67. + .. [BMS2006] Bugeaud, Mignotte, and Siksek. "Classical and modular approaches to exponential Diophantine equations: I. Fibonacci and Lucas perfect powers." Annals @@ -561,6 +631,10 @@ REFERENCES: number of elements in the mutation classes of* `\tilde{A}_n`-*quivers*; :arxiv:`0906.0487` +.. [BPS2008] Lubomira Balkova, Edita Pelantova, and Wolfgang Steiner. + *Sequences with constant number of return + words*. Monatsh. Math, 155 (2008) 251-263. + .. [BPU2016] Alex Biryukov, Léo Perrin, Aleksei Udovenko, *Reverse-Engineering the S-Box of Streebog, Kuznyechik and STRIBOBr1*; in EuroCrypt'16, pp. 372-402. @@ -649,6 +723,11 @@ REFERENCES: representation of the Riemann map and Ahlfors map via the Kerzman-Stein equation". Involve 3-4 (2010), 405-420. +.. [BDLGZ2009] \M. Bucci et al. A. De Luca, A. Glen, L. Q. Zamboni, + A connection between palindromic and factor complexity + using return words," Advances in Applied Mathematics + 42 (2009) 60-74. + .. [BUVO2007] Johannes Buchmann, Ullrich Vollmer: Binary Quadratic Forms, An Algorithmic Approach, Algorithms and Computation in Mathematics, Volume 20, Springer (2007) @@ -671,6 +750,11 @@ REFERENCES: vol. 308, no. 1, July 1988. http://www.ams.org/journals/tran/1988-308-01/S0002-9947-1988-0946427-X/S0002-9947-1988-0946427-X.pdf +.. [BW1994] \M. Burrows, D.J. Wheeler, "A block-sorting lossless data + compression algorithm", HP Lab Technical Report, 1994, + available at + http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-124.html + .. [BW1996] Anders Bjorner and Michelle L. Wachs. *Shellable nonpure complexes and posets. I*. Trans. of Amer. Math. Soc. **348** No. 4. (1996) @@ -731,6 +815,14 @@ REFERENCES: .. [CFI1992] Cai, JY., Fürer, M. & Immerman, N. Combinatorica (1992) 12: 389. :doi:`10.1007/BF01305232` +.. [CFL1958] \K.-T. Chen, R.H. Fox, R.C. Lyndon, Free differential calculus, + IV. The quotient groups of the lower central series, Ann. of Math. + 68 (1958) 81--95. + +.. [CFZ2000] \J. Cassaigne, S. Ferenczi, L.Q. Zamboni, Imbalances in + Arnoux-Rauzy sequences, Ann. Inst. Fourier (Grenoble) + 50 (2000) 1265--1276. + .. [CFZ2002] Chapoton, Fomin, Zelevinsky - Polytopal realizations of generalized associahedra, :arxiv:`math/0202004`. @@ -804,7 +896,7 @@ REFERENCES: .. [CL2013] Maria Chlouveraki and Sofia Lambropoulou. *The Yokonuma-Hecke algebras and the HOMFLYPT polynomial*. (2015) :arxiv:`1204.1871v4`. - + .. [Cle1872] Alfred Clebsch, *Theorie der binären algebraischen Formen*, Teubner, 1872. @@ -910,8 +1002,9 @@ REFERENCES: .. [Cre2003] Cressman, Ross. *Evolutionary dynamics and extensive form games*. MIT Press, 2003. -.. [Crossproduct] Algebraic Properties of the Cross Product - :wikipedia:`Cross_product` +.. [Cro1983] \M. Crochemore, Recherche linéaire d'un carré dans un mot, + C. R. Acad. Sci. Paris Sér. I Math. 296 (1983) 14 + 781--784. .. [CRS2016] Dean Crnković, Sanja Rukavina, and Andrea Švob. *Strongly regular graphs from orthogonal groups* `O^+(6,2)` *and* `O^-(6,2)`. @@ -1004,6 +1097,9 @@ REFERENCES: *Constructing homomorphisms between Verma modules*. Journal of Lie Theory. **15** (2005) pp. 415-428. +.. [Dej1972] \F. Dejean. Sur un théorème de Thue. J. Combinatorial Theory + Ser. A 13:90--99, 1972. + .. [Den2012] Tom Denton. Canonical Decompositions of Affine Permutations, Affine Codes, and Split `k`-Schur Functions. Electronic Journal of Combinatorics, 2012. @@ -1070,6 +1166,10 @@ REFERENCES: *Cyclotomic q-Schur algebras*, Math. Z, **229** (1998), 385-416. :mathscinet:`MR1658581` +.. [DJP2001] \X. Droubay, J. Justin, G. Pirillo, *Episturmian words + and some constructions of de Luca and Rauzy*, + Theoret. Comput. Sci. 255 (2001) 539--553. + .. [DLHK2007] \J. A. De Loera, D. C. Haws, M. Köppe, Ehrhart polynomials of matroid polytopes and polymatroids. Discrete & Computational Geometry, Volume @@ -1141,6 +1241,12 @@ REFERENCES: Connection Table* (preprint); in Cryptology ePrint Archive, (2018), 631. +.. [Dur1998] \F. Durand, *A characterization of substitutive sequences + using return words*, Discrete Math. 179 (1998) 89-101. + +.. [Duv1983] J.-P. Duval, Factorizing words over an ordered alphabet, + J. Algorithms 4 (1983) 363--381. + .. [DW1995] Andreas W.M. Dress and Walter Wenzel, *A Simple Proof of an Identity Concerning Pfaffians of Skew Symmetric Matrices*, Advances in Mathematics, volume 112, Issue 1, @@ -1294,6 +1400,11 @@ REFERENCES: Conjugating Sets and Automorphism Groups of Rational Functions. Journal of Algebra, 423 (2014), 1161-1190. +.. [Fog2002] \N. Pytheas Fogg, *Substitutions in Dynamics, Arithmetics, + and Combinatorics*, Lecture Notes in Mathematics 1794, + Springer Verlag. V. Berthé, S. Ferenczi, C. Mauduit + and A. Siegel, Eds. (2002). + .. [Fom1994] Sergey V. Fomin, "Duality of graded graphs". Journal of Algebraic Combinatorics Volume 3, Number 4 (1994), pp. 357-404. @@ -1349,6 +1460,10 @@ REFERENCES: Finite Mutation Type Via Unfoldings*, Int Math Res Notices (2012) 2012 (8): 1768-1804. +.. [Fuchs1994] \J. Fuchs. *Fusion Rules for Conformal Field Theory*. + Fortsch. Phys. **42** (1994), no. 1, pp. 1-48. + :doi:`10.1002/prop.2190420102`, :arXiv:`hep-th/9306162`. + .. [Fu1993] Wiliam Fulton, *Introduction to Toric Varieties*, Princeton University Press, 1993. @@ -1356,9 +1471,8 @@ REFERENCES: *Young Tableaux*. Cambridge University Press, 1997. -.. [Fuchs1994] \J. Fuchs. *Fusion Rules for Conformal Field Theory*. - Fortsch. Phys. **42** (1994), no. 1, pp. 1-48. - :doi:`10.1002/prop.2190420102`, :arXiv:`hep-th/9306162`. +.. [FV2002] \I. Fagnot, L. Vuillon, Generalized balances in Sturmian + words, Discrete Applied Mathematics 121 (2002), 83--101. .. [FY2004] Eva Maria Feichtner and Sergey Yuzvinsky. *Chow rings of toric varieties defined by atomic lattices*. Inventiones @@ -1448,6 +1562,9 @@ REFERENCES: Lecture Notes in Comput. Sci., vol. 4151, Springer, Berlin, 2006, pp. 219–221, https://doi.org/10.1007/11832225_20 +.. [GJ2007] \A. Glen, J. Justin, Episturmian words: a survey, Preprint, + 2007, :arxiv:`0801.1655`. + .. [GJK+2014] Dimitar Grantcharov, Ji Hye Jung, Seok-Jin Kang, Masaki Kashiwara, Myungho Kim. *Crystal bases for the quantum queer superalgebra and semistandard decomposition tableaux.*; Trans. Amer. Math. Soc., @@ -1471,6 +1588,9 @@ REFERENCES: *Cellular algebras*. Invent. Math. 123 (1996), 1–34. :mathscinet:`MR1376244` +.. [GLR2008] \A. Glen, F. Levé, G. Richomme, Quasiperiodic and Lyndon + episturmian words, Preprint, 2008, :arxiv:`0805.0730`. + .. [GLSV2014] \V. Grosso, G. Leurent, F.-X. Standaert, and K. Varici: *LS-Designs: Bitslice Encryption for Efficient Masked Software Implementations*, in FSE, 2014. @@ -1496,6 +1616,10 @@ REFERENCES: *KLEIN: A new family of lightweight block ciphers*; in RFIDSec, (2011), p. 1-18. +.. [GN2018] Pascal Giorgi and Vincent Neiger. Certification of Minimal + Approximant Bases. In ISSAC 2018, pages 167-174. + https://doi.org/10.1145/3208976.3208991 + .. [Go1967] Solomon Golomb, Shift register sequences, Aegean Park Press, Laguna Hills, Ca, 1967 @@ -1669,6 +1793,10 @@ REFERENCES: hypersurfaces. *Adv. Theor. Math. Phys.*, 6(3):457-506, 2002. :arxiv:`math/0010082v2` [math.AG]. +.. [HM2011] Florent Hivert and Olivier Mallet. `Combinatorics of k-shapes + and Genocchi numbers `_, + in FPSAC 2011, Reykjav´k, Iceland DMTCS proc. AO, 2011, 493-504. + .. [Hoc] Winfried Hochstaettler, "About the Tic-Tac-Toe Matroid", preprint. @@ -1738,10 +1866,10 @@ REFERENCES: .. [HRW2015] \J. Haglund, J. B. Remmel, A. T. Wilson. *The Delta Conjecture*. Preprint, :arxiv:`1509.07058`. -.. [HS1968] Donald G. Higman and Charles C. Sims. - *A simple group of order 44,352,000*. - Mathematische Zeitschrift 105(2): 110-113, 1968. - :doi:`10.1007/BF01110435`. +.. [HS1968] Donald G. Higman and Charles C. Sims. + *A simple group of order 44,352,000*. + Mathematische Zeitschrift 105(2): 110-113, 1968. + :doi:`10.1007/BF01110435`. .. [HS2018] \B. Hutz, M. Stoll. "Smallest representatives of `SL(2,\ZZ)`-orbits of binary forms and endomorphisms of P1", @@ -1774,6 +1902,9 @@ REFERENCES: .. [Huy2005] \D. Huybrechts : *Complex Geometry*, Springer (Berlin) (2005). +.. [HZ1999] \C. Holton, L. Q. Zamboni, *Descendants of primitive + substitutions*, Theory Comput. Syst. 32 (1999) 133-157. + .. _ref-I: **I** @@ -1781,6 +1912,9 @@ REFERENCES: .. [IJ1960] Igusa, Jun-ichi. *Arithmetic variety of moduli for genus two*. Ann. of Math. (2) 72 1960 612--649. +.. [II1983] \M. Imase and M. Itoh. "A design for directed graphs with minimum + diameter", *IEEE Trans. Comput.*, vol. C-32, pp. 782-784, 1983. + .. [IK2010] Kenji Iohara and Yoshiyuki Koga. *Representation Theory of the Virasoro Algebra*. Springer, (2010). @@ -1848,6 +1982,11 @@ REFERENCES: Math. Theor. Comput. Sci. Proc., AK, Assoc. Discrete Math. Theor. Comput. Sci., Nancy, 2009, pp. 491–502 +.. [JNSV2016] Claude-Pierre Jeannerod, Vincent Neiger, Eric Schost, and Gilles + Villard. Fast Computation of Minimal Interpolation Bases in Popov + Form for Arbitrary Shifts. In Proceedings ISSAC 2016 (pages + 295-302). https://doi.org/10.1145/2930889.2930928 + .. [Joh1990] \D.L. Johnson. *Presentations of Groups*. Cambridge University Press. (1990). @@ -1870,6 +2009,9 @@ REFERENCES: .. [Joy2006] \D. Joyner, *On quadratic residue codes and hyperelliptic curves*, (preprint 2006) +.. [JP2002] \J. Justin, G. Pirillo, Episturmian words and episturmian + morphisms, Theoret. Comput. Sci. 276 (2002) 281--313. + .. [JPdA15] \N. Jacon and L. Poulain d'Andecy. *An isomorphism theorem for Yokonuma-Hecke algebras and applications to link invariants*. (2015) :arxiv:`1501.06389v3`. @@ -1879,6 +2021,10 @@ REFERENCES: J. Algebra. **324** (2010). 2512-2542. :doi:`10.1016/j.bbr.2011.03.031`, :arxiv:`0909.2442`. +.. [JV2000] \J. Justin, L. Vuillon, *Return words in Sturmian and + episturmian words*, Theor. Inform. Appl. 34 (2000) + 343--356. + .. _ref-K: **K** @@ -1921,6 +2067,10 @@ REFERENCES: .. [Kat1991] Nicholas M. Katz, *Exponential sums and differential equations*, Princeton University Press, Princeton NJ, 1991. +.. [Kau1968] \W. H. Kautz. "Bounds on directed (d, k) graphs". Theory of + cellular logic networks and machines, AFCRL-68-0668, SRI Project + 7258, Final Rep., pp. 20-28, 1968. + .. [Kaw2009] Kawahira, Tomoki. *An algorithm to draw external rays of the Mandelbrot set*, Nagoya University, 23 Apr. 2009. math.titech.ac.jp/~kawahira/programs/mandel-exray.pdf @@ -2169,6 +2319,10 @@ REFERENCES: **L** +.. [Lab2008] S. Labbé, Propriétés combinatoires des `f`-palindromes, + Mémoire de maîtrise en Mathématiques, Montréal, UQAM, + 2008, 109 pages. + .. [Lam2004] Thomas Lam, *Growth diagrams, domino insertion and sign-imbalance*. Journal of Combinatorial Theory, Series A Volume 107, Number 1 (2004), pp. 87-115. @@ -2251,6 +2405,10 @@ REFERENCES: Algebra 207 (2006), no 1, pages 1-18. Preprint: :arxiv:`math/0504296v2`. +.. [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` + .. [LLM2014] Lee, Li, Mills, A combinatorial formula for certain elements in the upper cluster algebra, :arxiv:`1409.8177` @@ -2258,6 +2416,10 @@ REFERENCES: Affine insertion and Pieri rules for the affine Grassmannian, Memoirs of the AMS, 208 (2010), no. 977, :arxiv:`math.CO/0609110` +.. [LLMS2013] Thomas Lam, Luc Lapointe, Jennifer Morse, and Mark Shimozono (2013). + *The poset of k-shapes and branching rules for k-Schur functions* + `_. Memoirs of the American Mathematical Society, 223(1050), 1-113. DOI: 10.1090/S0065-9266-2012-00655-1 + .. [LLMSSZ2013] Thomas Lam, Luc Lapointe, Jennifer Morse, Anne Schilling, Mark Shimozono and Mike Zabrocki. *k-Schur functions and affine Schubert calculus*. @@ -2269,6 +2431,10 @@ REFERENCES: **181** (1996), pp 205-263. :mathscinet:`MR1410572` +.. [LLT] \A. Lascoux, B. Leclerc, and J.Y. Thibon. *The Plactic Monoid*. + Survey article available at + [http://www-igm.univ-mlv.fr/~jyt/ARTICLES/plactic.ps] + .. [LLYCL2005] \H. J. Lee, S. J. Lee, J. H. Yoon, D. H. Cheon, and J. I. Lee, *The SEED Encryption Algorithm*; in RFC 4269, (2005). @@ -2309,6 +2475,16 @@ REFERENCES: `q`-analogues". Mathematische Zeitschrift. **271** (2012). Issue 3-4. 819-865. :doi:`10.1007/s00209-011-0892-9`, :arxiv:`1002.3715`. +.. [Lot1983] \M. Lothaire, *Combinatorics on Words*, vol. 17 of + Encyclopedia of Mathematics and its Applications, + Addison-Wesley, Reading, Massachusetts (1983) + +.. [Lot1997] \M. Lothaire, Combinatorics on Words, Cambridge University + Press, (1997). + +.. [Lot2002] \M. Lothaire, *Algebraic combinatorics on + words*. Cambridge University Press (2002). + .. [Lot2005] \M. Lothaire, *Applied combinatorics on words*. Cambridge University Press (2005). @@ -2366,6 +2542,9 @@ REFERENCES: groups*. Australian Mathematical Society Lecture Series, 2009. +.. [DeLuca2006] \A. De Luca, *Pseudopalindrome closure operators in free + monoids*, Theoret. Comput. Sci. 362 (2006) 282--300. + .. [Lut2002] Frank H. Lutz, Császár's Torus, Electronic Geometry Model No. 2001.02.069 (2002). http://www.eg-models.de/models/Classical_Models/2001.02.069/_direct_link.html @@ -2406,15 +2585,17 @@ REFERENCES: **M** -.. [Mac1987] Maciej M. SysŁo, - *Minimizing the jump number for partially-ordered sets: a - graph-theoretic approach, II*. - Discrete Mathematics, - Volume 63, Issues 2-3, 1987, Pages 279-295. +.. [Mac1995] \I. G. Macdonald, Symmetric functions and Hall + polynomials, second ed., The Clarendon Press, Oxford + University Press, New York, 1995, With contributions + by A. Zelevinsky, Oxford Science Publications. .. [MagmaHGM] *Hypergeometric motives* in Magma, http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf +.. [Mar2004] \S. Marcus, Quasiperiodic infinite words, + Bull. Eur. Assoc. Theor. Comput. Sci. 82 (2004) 170-174. + .. [Mas1994] James L. Massey, *SAFER K-64: A byte-oriented block-ciphering algorithm*; in FSE’93, Volume 809 of LNCS, pages 1-17. @@ -2493,6 +2674,9 @@ REFERENCES: .. [McM1992] John McMillan. *Games, strategies, and managers*. Oxford University Press. +.. [Me1997] \G. Melançon, *Factorizing infinite words using Maple*, + MapleTech journal, vol. 4, no. 1, 1997, pp. 34-42. + .. [MeNoTh11] Frederic Menous, Jean-Christophe Novelli, Jean-Yves Thibon, *Mould calculus, polyhedral cones, and characters of combinatorial Hopf algebras*, @@ -2551,6 +2735,9 @@ REFERENCES: `P^s_t` bases for the Steenrod algebra," J. Pure Appl. Algebra 125 (1998), no. 1-3, 235-260. +.. [Mon2010] \T. Monteil, The asymptotic language of smooth curves, talk + at LaCIM2010. + .. [MoPa1994] \P. Morton and P. Patel. The Galois theory of periodic points of polynomial maps. Proc. London Math. Soc., 68 (1994), 225-263. @@ -2595,6 +2782,10 @@ REFERENCES: Int. Math. Res. Not. (2015). :doi:`10.1093/imrn/rnv194`, :arxiv:`1408.0320`. +.. [MSSY2001] Mateescu, A., Salomaa, A., Salomaa, K. and Yu, S., *A + sharpening of the Parikh mapping*. Theoret. Informatics Appl. 35 + (2001) 551-564. + .. [MSZ2013] Michael Maschler, Solan Eilon, and Zamir Shmuel. *Game Theory*. Cambridge: Cambridge University Press, (2013). ISBN 9781107005488. @@ -2794,6 +2985,12 @@ REFERENCES: .. [Prototype_pattern] Prototype pattern, :wikipedia:`Prototype_pattern` +.. [PeSt2011] E. Pelantová, Š. Starosta, Infinite words rich and + almost rich in generalized palindromes, in: G. Mauri, + A. Leporati (Eds.), Developments in Language Theory, + volume 6795 of Lecture Notes in Computer Science, + Springer-Verlag, Berlin, Heidelberg, 2011, pp. 406--416 + .. [PS2011] \R. Pollack, and G. Stevens. *Overconvergent modular symbols and p-adic L-functions.* Annales scientifiques de l'École normale supérieure. @@ -2898,6 +3095,14 @@ REFERENCES: polynomials. Mathematical Programming, Series B, 129 (2011) 5-31. +.. [RPK1980] \S. M. Reddy, D. K. Pradhan, and J. Kuhl. "Directed graphs with + minimal diameter and maximal connectivity", School Eng., Oakland + Univ., Rochester MI, Tech. Rep., July 1980. + +.. [RPK1983] \S. Reddy, P. Raghavan, and J. Kuhl. "A Class of Graphs for + Processor Interconnection". *IEEE International Conference on Parallel + Processing*, pages 154-157, Los Alamitos, Ca., USA, August 1983. + .. [Rob1991] Tom Roby, "Applications and extensions of Fomin's generalization of the Robinson-Schensted correspondence to differential posets". Ph.D. Thesis, M.I.T., @@ -3000,6 +3205,9 @@ REFERENCES: operations, Ann. of Math. Stud. 50 (Princeton University Press, 1962). +.. [Ser1985] \C. Series. The geometry of Markoff numbers. The + Mathematical Intelligencer, 7(3):20--29, 1985. + .. [Ser1992] \J.-P. Serre : *Lie Algebras and Lie Groups*, 2nd ed., Springer (Berlin) (1992); :doi:`10.1007/978-3-540-70634-2` @@ -3158,6 +3366,13 @@ REFERENCES: Cambridge University Press (1999). http://math.mit.edu/~rstan/ec/ +.. [Star2011] Š. Starosta, *On Theta-palindromic Richness*, + Theoret. Comp. Sci. 412 (2011) 1111--1121 + +.. [Sei2002] \T. R. Seifullin, *Computation of determinants, adjoint + matrices, and characteristic polynomials without division* + :doi:`10.1023/A:1021878507303` + .. [Stan2009] Richard Stanley, *Promotion and evacuation*, Electron. J. Combin. 16 (2009), no. 2, Special volume in honor of @@ -3169,6 +3384,9 @@ REFERENCES: Mathematical Society, Vol. 355, No. 12 (Dec., 2003), pp. 4807--4823 +.. [Stich2009] Stichtenoth, Henning. *Algebraic function fields and codes*. + Vol. 254. Springer Science & Business Media, 2009. + .. [Sti2006] Douglas R. Stinson. *Cryptography: Theory and Practice*. 3rd edition, Chapman \& Hall/CRC, 2006. @@ -3247,6 +3465,9 @@ REFERENCES: and Hand Mohrmann, eds., volume 3, *Geometrie, erster Teil, zweite Hälfte*, pp. 1--139, Teubner, Leipzig, 1922 +.. [SU2009] \J. Smillie and C. Ulcigrai. Symbolic coding for linear + trajectories in the regular octagon, :arxiv:`0905.0871`, 2009. + .. [Swe1969] Moss Sweedler. Hopf algebras. W.A. Benjamin, Math Lec Note Ser., 1969. @@ -3254,6 +3475,12 @@ REFERENCES: Jennings. *A linear approximation method for the Shapley value.* Artificial Intelligence 172.14 (2008): 1673-1699. +.. [Sys1987] Maciej M. SysŁo, + *Minimizing the jump number for partially-ordered sets: a + graph-theoretic approach, II*. + Discrete Mathematics, + Volume 63, Issues 2-3, 1987, Pages 279-295. + .. [SYYTIYTT2002] \T. Shimoyama, H. Yanami, K. Yokoyama, M. Takenaka, K. Itoh, \J. Yajima, N. Torii, and H. Tanaka, *The block cipher SC2000*; in FSE, (2001), pp. 312-327. diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index f7c00f9236a..5668f1f7dbe 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -132,7 +132,6 @@ This base class provides a lot more methods than a general parent:: '_zero_ideal', 'algebraic_closure', 'base_extend', - 'cardinality', 'class_group', 'coerce_map_from_c', 'content', @@ -152,7 +151,6 @@ This base class provides a lot more methods than a general parent:: 'integral_closure', 'is_commutative', 'is_field', - 'is_finite', 'is_integral_domain', 'is_integrally_closed', 'is_noetherian', diff --git a/src/doc/en/thematic_tutorials/conf.py b/src/doc/en/thematic_tutorials/conf.py index f466fd7ef5f..9d9afac6fde 100644 --- a/src/doc/en/thematic_tutorials/conf.py +++ b/src/doc/en/thematic_tutorials/conf.py @@ -15,7 +15,8 @@ import os import sys -sys.path.append(os.environ["SAGE_DOC_SRC"]) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/birds_other.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/birds_other.rst index c3f5cabcded..7c244596f1a 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/birds_other.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/birds_other.rst @@ -89,9 +89,20 @@ dimension of the cuspidal subspace. Gamma_H(13) with H generated by [3] of weight 4 with sign 0 and over Rational Field sage: M.basis() - ([X^2,(0,1)], [X^2,(0,7)], [X^2,(2,5)], [X^2,(2,8)], [X^2,(2,9)], - [X^2,(2,10)], [X^2,(2,11)], [X^2,(2,12)], [X^2,(4,0)], [X^2,(4,3)], - [X^2,(4,6)], [X^2,(4,8)], [X^2,(4,12)], [X^2,(7,1)]) + ([X^2,(0,4)], + [X^2,(0,7)], + [X^2,(4,10)], + [X^2,(4,11)], + [X^2,(4,12)], + [X^2,(7,3)], + [X^2,(7,5)], + [X^2,(7,6)], + [X^2,(7,7)], + [X^2,(7,8)], + [X^2,(7,9)], + [X^2,(7,10)], + [X^2,(7,11)], + [X^2,(7,12)]) sage: factor(charpoly(M.T(2))) (x - 7) * (x + 7) * (x - 9)^2 * (x + 5)^2 * (x^2 - x - 4)^2 * (x^2 + 9)^2 diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py index fce24770852..d057dc7ef7a 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/en/thematic_tutorials/geometry/polyhedra_quickref.rst b/src/doc/en/thematic_tutorials/geometry/polyhedra_quickref.rst index 065a910ce81..77463619150 100644 --- a/src/doc/en/thematic_tutorials/geometry/polyhedra_quickref.rst +++ b/src/doc/en/thematic_tutorials/geometry/polyhedra_quickref.rst @@ -76,6 +76,7 @@ List of Polyhedron methods :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.backend` | gives the backend used :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.base_ring` | gives the base ring used + :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.change_ring` | changes the base ring **Transforming polyhedra** diff --git a/src/doc/en/thematic_tutorials/group_theory.rst b/src/doc/en/thematic_tutorials/group_theory.rst index 868aefacb1d..f115e8401ba 100644 --- a/src/doc/en/thematic_tutorials/group_theory.rst +++ b/src/doc/en/thematic_tutorials/group_theory.rst @@ -586,12 +586,12 @@ subgroups. :: sage: C20 = CyclicPermutationGroup(20) sage: C20.conjugacy_classes_subgroups() - [Subgroup of (Cyclic group of order 20 as a permutation group) generated by [()], - Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,11)(2,12)(3,13)(4,14)(5,15)(6,16)(7,17)(8,18)(9,19)(10,20)], - Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,6,11,16)(2,7,12,17)(3,8,13,18)(4,9,14,19)(5,10,15,20), (1,11)(2,12)(3,13)(4,14)(5,15)(6,16)(7,17)(8,18)(9,19)(10,20)], - Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20)], - Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,3,5,7,9,11,13,15,17,19)(2,4,6,8,10,12,14,16,18,20), (1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20)], - Subgroup of (Cyclic group of order 20 as a permutation group) generated by [(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20), (1,3,5,7,9,11,13,15,17,19)(2,4,6,8,10,12,14,16,18,20), (1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20)]] + [Subgroup generated by [()] of (Cyclic group of order 20 as a permutation group), + Subgroup generated by [(1,11)(2,12)(3,13)(4,14)(5,15)(6,16)(7,17)(8,18)(9,19)(10,20)] of (Cyclic group of order 20 as a permutation group), + Subgroup generated by [(1,6,11,16)(2,7,12,17)(3,8,13,18)(4,9,14,19)(5,10,15,20), (1,11)(2,12)(3,13)(4,14)(5,15)(6,16)(7,17)(8,18)(9,19)(10,20)] of (Cyclic group of order 20 as a permutation group), + Subgroup generated by [(1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20)] of (Cyclic group of order 20 as a permutation group), + Subgroup generated by [(1,3,5,7,9,11,13,15,17,19)(2,4,6,8,10,12,14,16,18,20), (1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20)] of (Cyclic group of order 20 as a permutation group), + Subgroup generated by [(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20), (1,3,5,7,9,11,13,15,17,19)(2,4,6,8,10,12,14,16,18,20), (1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20)] of (Cyclic group of order 20 as a permutation group)] Be careful, this command uses some more advanced ideas and will not usually list *all* of the subgroups of a group. Here we are relying on @@ -644,22 +644,22 @@ suitable `g`. As an illustration, the code below: sage: K = DihedralGroup(12) sage: sg = K.conjugacy_classes_subgroups() sage: sg - [Subgroup of (Dihedral group of order 24 as a permutation group) generated by [()], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,7)(2,8)(3,9)(4,10)(5,11)(6,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,5,9)(2,6,10)(3,7,11)(4,8,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,7)(2,8)(3,9)(4,10)(5,11)(6,12), (1,10,7,4)(2,11,8,5)(3,12,9,6)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), (1,10,7,4)(2,11,8,5)(3,12,9,6)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2,3,4,5,6,7,8,9,10,11,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)], - Subgroup of (Dihedral group of order 24 as a permutation group) generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,2,3,4,5,6,7,8,9,10,11,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)]] + [Subgroup generated by [()] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(1,7)(2,8)(3,9)(4,10)(5,11)(6,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(2,12)(3,11)(4,10)(5,9)(6,8)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(1,5,9)(2,6,10)(3,7,11)(4,8,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(1,7)(2,8)(3,9)(4,10)(5,11)(6,12), (1,10,7,4)(2,11,8,5)(3,12,9,6)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,5,9)(2,6,10)(3,7,11)(4,8,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,5,9)(2,6,10)(3,7,11)(4,8,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,7)(2,8)(3,9)(4,10)(5,11)(6,12), (1,10,7,4)(2,11,8,5)(3,12,9,6)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(1,2,3,4,5,6,7,8,9,10,11,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(1,2)(3,12)(4,11)(5,10)(6,9)(7,8), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)] of (Dihedral group of order 24 as a permutation group), + Subgroup generated by [(2,12)(3,11)(4,10)(5,9)(6,8), (1,2,3,4,5,6,7,8,9,10,11,12), (1,3,5,7,9,11)(2,4,6,8,10,12), (1,5,9)(2,6,10)(3,7,11)(4,8,12)] of (Dihedral group of order 24 as a permutation group)] sage: print("An order two subgroup:\n{}".format(sg[1].list())) An order two subgroup: diff --git a/src/doc/en/thematic_tutorials/numerical_sage/conf.py b/src/doc/en/thematic_tutorials/numerical_sage/conf.py index e853f37925c..69eec5d744f 100644 --- a/src/doc/en/thematic_tutorials/numerical_sage/conf.py +++ b/src/doc/en/thematic_tutorials/numerical_sage/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/en/thematic_tutorials/sandpile.rst b/src/doc/en/thematic_tutorials/sandpile.rst index 630083c75ff..819518cb845 100644 --- a/src/doc/en/thematic_tutorials/sandpile.rst +++ b/src/doc/en/thematic_tutorials/sandpile.rst @@ -86,18 +86,18 @@ and two have gone to vertex 3, since the edge from 1 to 3 has weight `2`. Vertex 3 in the new configuration is now unstable. The Sage code for this example follows. :: - sage: g = {'sink':{}, - ....: 1:{'sink':1, 2:1, 3:2}, + sage: g = {0:{}, + ....: 1:{0:1, 2:1, 3:2}, ....: 2:{1:1, 3:1}, ....: 3:{1:1, 2:1}} - sage: S = Sandpile(g, 'sink') # create the sandpile + sage: S = Sandpile(g, 0) # create the sandpile sage: S.show(edge_labels=true) # display the graph Create the configuration:: sage: c = SandpileConfig(S, {1:5, 2:0, 3:1}) sage: S.out_degree() - {1: 4, 2: 2, 3: 2, 'sink': 0} + {0: 0, 1: 4, 2: 2, 3: 2} Fire vertex `1`:: @@ -162,12 +162,12 @@ Laplacian. **Example.** (Continued.) :: sage: S.vertices() # the ordering of the vertices - [1, 2, 3, 'sink'] + [0, 1, 2, 3] sage: S.laplacian() - [ 4 -1 -2 -1] - [-1 2 -1 0] - [-1 -1 2 0] [ 0 0 0 0] + [-1 4 -1 -2] + [ 0 -1 2 -1] + [ 0 -1 -1 2] sage: S.reduced_laplacian() [ 4 -1 -2] [-1 2 -1] @@ -3595,14 +3595,14 @@ boolean EXAMPLES:: - sage: S = Sandpile({'a':[1,'b'], 'b':[1,'a'], 1:['a']},'a') - sage: c = SandpileConfig(S, {'b':1, 1:2}) + sage: S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') + sage: c = SandpileConfig(S, {'b':1, 'c':2}) sage: c - {1: 2, 'b': 1} + {'b': 1, 'c': 2} sage: c.values() - [2, 1] + [1, 2] sage: S.nonsink_vertices() - [1, 'b'] + ['b', 'c'] --- @@ -4675,14 +4675,14 @@ boolean EXAMPLES:: - sage: S = Sandpile({'a':[1,'b'], 'b':[1,'a'], 1:['a']},'a') - sage: D = SandpileDivisor(S, {'a':0, 'b':1, 1:2}) + sage: S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') + sage: D = SandpileDivisor(S, {'a':0, 'b':1, 'c':2}) sage: D - {'a': 0, 1: 2, 'b': 1} + {'a': 0, 'b': 1, 'c': 2} sage: D.values() - [2, 0, 1] + [0, 1, 2] sage: S.vertices() - [1, 'a', 'b'] + ['a', 'b', 'c'] --- diff --git a/src/doc/en/thematic_tutorials/tutorial-programming-python.rst b/src/doc/en/thematic_tutorials/tutorial-programming-python.rst index f0db90cdd6a..fb7c09fc293 100644 --- a/src/doc/en/thematic_tutorials/tutorial-programming-python.rst +++ b/src/doc/en/thematic_tutorials/tutorial-programming-python.rst @@ -213,7 +213,7 @@ Creating Lists I: [Square brackets] sage: L [3, [5, 1, 4, 2, 3], 17, 17, 3, 51] -**Exercise:** Create the list :math:`[63, 12, -10, \text{``a''}, 12]`, +**Exercise:** Create the list ``[63, 12, -10, "a", 12]``, assign it to the variable ``L``, and print the list. :: diff --git a/src/doc/en/tutorial/conf.py b/src/doc/en/tutorial/conf.py index 0be5db38ace..f5a512dda7a 100644 --- a/src/doc/en/tutorial/conf.py +++ b/src/doc/en/tutorial/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/en/tutorial/interfaces.rst b/src/doc/en/tutorial/interfaces.rst index c4b281caf9f..4ddbb146db3 100644 --- a/src/doc/en/tutorial/interfaces.rst +++ b/src/doc/en/tutorial/interfaces.rst @@ -168,7 +168,7 @@ GAP interface as follows: sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.group_id() [120, 34] sage: n = G.order(); n diff --git a/src/doc/en/tutorial/tour_groups.rst b/src/doc/en/tutorial/tour_groups.rst index c1ee7563381..60f9a0dbd49 100644 --- a/src/doc/en/tutorial/tour_groups.rst +++ b/src/doc/en/tutorial/tour_groups.rst @@ -22,7 +22,7 @@ generators, as in the following example. [Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.random_element() # random output (1,5,3)(2,4) sage: print(latex(G)) diff --git a/src/doc/en/website/conf.py b/src/doc/en/website/conf.py index 4164c62f75a..53a521ef218 100644 --- a/src/doc/en/website/conf.py +++ b/src/doc/en/website/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/es/a_tour_of_sage/conf.py b/src/doc/es/a_tour_of_sage/conf.py index f5bb30005e7..1e536d4ede4 100644 --- a/src/doc/es/a_tour_of_sage/conf.py +++ b/src/doc/es/a_tour_of_sage/conf.py @@ -15,7 +15,8 @@ import sys import os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/es/tutorial/conf.py b/src/doc/es/tutorial/conf.py index dd484f09cae..e361a063a2f 100644 --- a/src/doc/es/tutorial/conf.py +++ b/src/doc/es/tutorial/conf.py @@ -13,7 +13,8 @@ import sys import os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/es/tutorial/tour_groups.rst b/src/doc/es/tutorial/tour_groups.rst index e57a3c72637..70845eb05c2 100644 --- a/src/doc/es/tutorial/tour_groups.rst +++ b/src/doc/es/tutorial/tour_groups.rst @@ -25,7 +25,7 @@ generadores: Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [(3,4), (1,2,3)(4,5)], Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [(1,5,3), (1,5)(3,4), (1,5)(2,4)]] sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.random_element() # random output (resultado aleatorio) (1,5,3)(2,4) sage: print(latex(G)) diff --git a/src/doc/fr/a_tour_of_sage/conf.py b/src/doc/fr/a_tour_of_sage/conf.py index 6bcc3442694..5d362719c4b 100644 --- a/src/doc/fr/a_tour_of_sage/conf.py +++ b/src/doc/fr/a_tour_of_sage/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/fr/tutorial/conf.py b/src/doc/fr/tutorial/conf.py index 35b9ad147f3..121541d40ef 100644 --- a/src/doc/fr/tutorial/conf.py +++ b/src/doc/fr/tutorial/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/fr/tutorial/interfaces.rst b/src/doc/fr/tutorial/interfaces.rst index c4a01e8d58f..647189f65d7 100644 --- a/src/doc/fr/tutorial/interfaces.rst +++ b/src/doc/fr/tutorial/interfaces.rst @@ -171,7 +171,7 @@ l'interface GAP comme suit : sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.group_id() [120, 34] sage: n = G.order(); n diff --git a/src/doc/fr/tutorial/tour_groups.rst b/src/doc/fr/tutorial/tour_groups.rst index 97cd4b65a52..3cd92ef2ce7 100644 --- a/src/doc/fr/tutorial/tour_groups.rst +++ b/src/doc/fr/tutorial/tour_groups.rst @@ -23,7 +23,7 @@ une liste de générateurs, comme dans l'exemple suivant. [Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.random_element() # sortie aléatoire (random) (1,5,3)(2,4) sage: print(latex(G)) diff --git a/src/doc/hu/a_tour_of_sage/conf.py b/src/doc/hu/a_tour_of_sage/conf.py index 00608e9b1f6..4e8f4817e17 100644 --- a/src/doc/hu/a_tour_of_sage/conf.py +++ b/src/doc/hu/a_tour_of_sage/conf.py @@ -14,7 +14,8 @@ # out serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/it/a_tour_of_sage/conf.py b/src/doc/it/a_tour_of_sage/conf.py index 060efcad64a..ffc0de001b9 100644 --- a/src/doc/it/a_tour_of_sage/conf.py +++ b/src/doc/it/a_tour_of_sage/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/ja/a_tour_of_sage/conf.py b/src/doc/ja/a_tour_of_sage/conf.py index 05c56543540..dfa03db1c89 100644 --- a/src/doc/ja/a_tour_of_sage/conf.py +++ b/src/doc/ja/a_tour_of_sage/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/ja/tutorial/conf.py b/src/doc/ja/tutorial/conf.py index 75344a9cf36..c136e8d5e85 100644 --- a/src/doc/ja/tutorial/conf.py +++ b/src/doc/ja/tutorial/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/ja/tutorial/interfaces.rst b/src/doc/ja/tutorial/interfaces.rst index 33baf859736..1254d297be7 100644 --- a/src/doc/ja/tutorial/interfaces.rst +++ b/src/doc/ja/tutorial/interfaces.rst @@ -149,7 +149,7 @@ Sageには GAP 4.4.10が付属しており,群論を始めとする計算離 sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.group_id() [120, 34] sage: n = G.order(); n diff --git a/src/doc/ja/tutorial/tour_groups.rst b/src/doc/ja/tutorial/tour_groups.rst index 059313a253a..a2518600d34 100644 --- a/src/doc/ja/tutorial/tour_groups.rst +++ b/src/doc/ja/tutorial/tour_groups.rst @@ -20,10 +20,10 @@ Sageでは,置換群,有限古典群(例えば :math:`SU(n,q)`),有限行 sage: G.is_abelian() False sage: G.derived_series() # 結果は変化しがち - [Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [(3,4), (1,2,3)(4,5)], - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [(1,3,5), (1,5)(3,4), (1,5)(2,4)]] + [Subgroup generated by [(3,4), (1,2,3)(4,5)] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]), + Subgroup generated by [(1,3,5), (1,5)(3,4), (1,5)(2,4)] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.random_element() # random 出力は変化する (1,5,3)(2,4) sage: print(latex(G)) diff --git a/src/doc/pt/a_tour_of_sage/conf.py b/src/doc/pt/a_tour_of_sage/conf.py index c781fcaa9dc..3cbd4c99cb9 100644 --- a/src/doc/pt/a_tour_of_sage/conf.py +++ b/src/doc/pt/a_tour_of_sage/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/pt/tutorial/conf.py b/src/doc/pt/tutorial/conf.py index 2909bc587aa..c2ce9a5e8b7 100644 --- a/src/doc/pt/tutorial/conf.py +++ b/src/doc/pt/tutorial/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/pt/tutorial/interfaces.rst b/src/doc/pt/tutorial/interfaces.rst index 463a31f459d..8515f18a74c 100644 --- a/src/doc/pt/tutorial/interfaces.rst +++ b/src/doc/pt/tutorial/interfaces.rst @@ -170,7 +170,7 @@ a interface do GAP da seguinte forma: sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.group_id() [120, 34] sage: n = G.order(); n diff --git a/src/doc/pt/tutorial/tour_groups.rst b/src/doc/pt/tutorial/tour_groups.rst index a60c2d5d9f7..b86e52d3d52 100644 --- a/src/doc/pt/tutorial/tour_groups.rst +++ b/src/doc/pt/tutorial/tour_groups.rst @@ -23,7 +23,7 @@ geradores, como no seguinte exemplo. [Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.random_element() # random output (1,5,3)(2,4) sage: print(latex(G)) diff --git a/src/doc/ru/tutorial/conf.py b/src/doc/ru/tutorial/conf.py index 90d498be30c..3100349ad3b 100644 --- a/src/doc/ru/tutorial/conf.py +++ b/src/doc/ru/tutorial/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/doc/ru/tutorial/interfaces.rst b/src/doc/ru/tutorial/interfaces.rst index 375515be91d..2210f9c0a5b 100644 --- a/src/doc/ru/tutorial/interfaces.rst +++ b/src/doc/ru/tutorial/interfaces.rst @@ -165,7 +165,7 @@ Sage поставляется с GAP для вычислений в област sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.group_id() [120, 34] sage: n = G.order(); n diff --git a/src/doc/ru/tutorial/tour_groups.rst b/src/doc/ru/tutorial/tour_groups.rst index 38b8e7b1f30..1e1ca3b382e 100644 --- a/src/doc/ru/tutorial/tour_groups.rst +++ b/src/doc/ru/tutorial/tour_groups.rst @@ -22,7 +22,7 @@ Sage поддерживает вычисления с группами пере [Permutation Group with generators [(1,2,3)(4,5), (3,4)], Permutation Group with generators [(1,5)(3,4), (1,5)(2,4), (1,3,5)]] sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.random_element() # random output (1,5,3)(2,4) sage: print(latex(G)) diff --git a/src/doc/tr/a_tour_of_sage/conf.py b/src/doc/tr/a_tour_of_sage/conf.py index 2c426406e1b..b2615603799 100644 --- a/src/doc/tr/a_tour_of_sage/conf.py +++ b/src/doc/tr/a_tour_of_sage/conf.py @@ -12,7 +12,8 @@ # serve to show the default. import sys, os -sys.path.append(os.environ['SAGE_DOC_SRC']) +from sage.env import SAGE_DOC_SRC +sys.path.append(SAGE_DOC_SRC) from common.conf import * # General information about the project. diff --git a/src/ext/doctest/python3-known-passing.txt b/src/ext/doctest/python3-known-passing.txt new file mode 100644 index 00000000000..e420bd10e77 --- /dev/null +++ b/src/ext/doctest/python3-known-passing.txt @@ -0,0 +1,44 @@ +src/sage/algebras/steenrod/ +src/sage/arith/ +src/sage/calculus/ +src/sage/coding/ +src/sage/combinat/designs/ +src/sage/combinat/posets/ +src/sage/combinat/rigged_configurations/ +src/sage/combinat/sf/ +src/sage/combinat/species/ +src/sage/combinat/words/ +src/sage/databases/ +src/sage/docs/ +src/sage/features/ +src/sage/finance/ +src/sage/games/ +src/sage/game_theory/ +src/sage/groups/lie_gps/ +src/sage/groups/matrix_gps/ +src/sage/interacts/ +src/sage/knots/ +src/sage/libs/gsl/ +src/sage/lfunctions/ +src/sage/logic/ +src/sage/manifolds/ +src/sage/media/ +src/sage/modular/modsym/ +src/sage/monoids/ +src/sage/parallel/ +src/sage/plot/ +src/sage/probability/ +src/sage/quadratic_forms/ +src/sage/quivers/ +src/sage/rings/asymptotic/ +src/sage/rings/number_field/ +src/sage/rings/function_field/ +src/sage/sandpiles/ +src/sage/sat/ +src/sage/schemes/toric/ +src/sage/server/ +src/sage/stats/ +src/sage/structure/ +src/sage/tensor/ +src/sage/typeset/ +src/sage_setup/ diff --git a/src/ext/graphs/graph_plot_js.html b/src/ext/graphs/graph_plot_js.html index 568e11c35f5..ad2c7e165ac 100644 --- a/src/ext/graphs/graph_plot_js.html +++ b/src/ext/graphs/graph_plot_js.html @@ -183,7 +183,7 @@ } // Curved edges else { - p = third_point_of_curved_edge(d.source,d.target,d.curve) + var p = third_point_of_curved_edge(d.source,d.target,d.curve) return line([{'x':d.source.x,'y':d.source.y}, {'x':p[0],'y':p[1]}, {'x':d.target.x,'y':d.target.y}]) @@ -217,8 +217,6 @@ // Returns the coordinates of a point located at distance d from the // barycenter of two points pa, pb. function third_point_of_curved_edge(pa,pb,d){ - var dx = pb.x - pa.x, - dy = pb.y - pa.y; var ox=pa.x,oy=pa.y,dx=pb.x,dy=pb.y; var cx=(dx+ox)/2,cy=(dy+oy)/2; var ny=-(dx-ox),nx=dy-oy; diff --git a/src/mac-app/loading-page.html b/src/mac-app/loading-page.html index 837bc68c418..a35b2b5f429 100644 --- a/src/mac-app/loading-page.html +++ b/src/mac-app/loading-page.html @@ -85,9 +85,9 @@ var randomcontentsearch=new RegExp(this.masterclass, "i") //check for CSS class="randomcontent groupX" (x=integer) for (var i=0; iThe SageNB server or Jupyter is currently starting. Please wait...

    If you think you have waited long enough...

    -

    Try View Log under the Server menu (or at the root of the menubar item's menu) which may give you some clues as to why it has not started. It should show the URL (including token) for accessing the Jupyter interface in case it doesn't open automatically.

    +

    Try View Log under the Server menu (or at the root of the menubar item's menu) which may give you some clues as to why it has not started. It should show the URL (including token) for accessing the Jupyter interface in case it does not open automatically.

    If the problem persists email for support, ask a question on the question and answer site or try one of the other many avenues of support.

    @@ -191,7 +191,7 @@

    Did you know?

    Sage can be integrated with LaTeX using SageTeX.

    -

    If you find that LaTeX doesn't work, try +

    If you find that LaTeX does not work, try adding os.environ["PATH"]+=":/usr/texbin:/usr/local/bin" to $HOME/.sage/init.sage

    You can use Sage @@ -201,7 +201,7 @@

    Did you know?

    calculation.

    Sage can be used - to solve + to solve a Rubik's cube.

    You can start an interactive GAP session in the middle of a sage session @@ -209,14 +209,14 @@

    Did you know?

    for gp_console, singular_console, maxima_console, r_console, and so forth.

    -

    Reading the Sage Tutorial is an +

    Reading the Sage Tutorial is an enjoyable way to spend an evening.

    The Sage interactive shell is based on IPython so it can be customized in the same way. In particular see the directory $HOME/.sage/ipython/.

    You can add your own tips about Sage to - the wiki.

    + the wiki.

    Sometimes the best way to find a bug is to explain it to a rubber duck in enough detail for the duck to understand.

    diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index 8e8c65598a9..c0358d546d7 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -46,6 +46,7 @@ ` - :class:`algebras.QuantumGL ` +- :class:`algebras.QSym ` - :class:`algebras.Partition ` - :class:`algebras.PlanarPartition ` - :class:`algebras.QuantumGroup @@ -102,6 +103,7 @@ lazy_import('sage.combinat.fqsym', 'FreeQuasisymmetricFunctions', 'MalvenutoReutenauer') lazy_import('sage.combinat.chas.wqsym', 'WordQuasiSymmetricFunctions', 'WQSym') lazy_import('sage.combinat.chas.fsym', 'FreeSymmetricFunctions', 'FSym') +lazy_import('sage.combinat.ncsf_qsym.qsym', 'QuasiSymmetricFunctions', 'QSym') lazy_import('sage.combinat.grossman_larson_algebras', 'GrossmanLarsonAlgebra', 'GrossmanLarson') lazy_import('sage.algebras.quantum_matrix_coordinate_algebra', 'QuantumMatrixCoordinateAlgebra', 'QuantumMatrixCoordinate') diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index 540b4e5e243..fbb39bede59 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -809,6 +809,7 @@ def monoid(self): def g_algebra(self, relations, names=None, order='degrevlex', check=True): """ The `G`-Algebra derived from this algebra by relations. + By default is assumed, that two variables commute. .. TODO:: diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index f401951fbcf..f2e96343578 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -608,9 +608,9 @@ def merge(self, other): sage: S = algebras.FreeZinbiel(QQ, 'z,t') sage: z,t = S.gens() - sage: x + t - Z[t] + Z[x] - sage: parent(x + t) + sage: x * t + Z[xt] + sage: parent(x * t) Free Zinbiel algebra on generators (Z[z], Z[t], Z[x], Z[y]) over Rational Field """ diff --git a/src/sage/algebras/lie_algebras/affine_lie_algebra.py b/src/sage/algebras/lie_algebras/affine_lie_algebra.py index f747df7edf7..71a2dc8af37 100644 --- a/src/sage/algebras/lie_algebras/affine_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/affine_lie_algebra.py @@ -124,8 +124,8 @@ class AffineLieAlgebra(FinitelyGeneratedLieAlgebra): 0 sage: f0.bracket(f2) (E[3*alpha[1] + alpha[2]])#t^-1 - sage: A[h1+3*h2, A[[[f0, f2], f1], [f1,f2]] + f1] - (E[-alpha[1]])#t^0 + (2*E[alpha[1]])#t^-1 + sage: A[h1+3*h2, A[[[f0, f2], f1], [f1,f2]] + f1] - f1 + (2*E[alpha[1]])#t^-1 We can construct its derived subalgebra, the affine Lie algebra of type `G_2^{(1)}`. In this case, there is no canonical derivation, diff --git a/src/sage/algebras/lie_algebras/free_lie_algebra.py b/src/sage/algebras/lie_algebras/free_lie_algebra.py index 15233231586..7b188647b96 100644 --- a/src/sage/algebras/lie_algebras/free_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/free_lie_algebra.py @@ -151,7 +151,8 @@ def monomial(self, x): if isinstance(x, list): return super(FreeLieBasis_abstract, self)._element_constructor_(x) else: - x = LieGenerator(x) + i = self._indices.index(x) + x = LieGenerator(x, i) return self.element_class(self, {x: self.base_ring().one()}) def _construct_UEA(self): @@ -351,7 +352,7 @@ def _repr_(self): sage: LieAlgebra(QQ, 3, 'x') Free Lie algebra generated by (x0, x1, x2) over Rational Field """ - n = tuple(map(LieGenerator, self._names)) # To remove those stupid quote marks + n = tuple(map(LieGenerator, self._names, range(len(self._names)))) # To remove those stupid quote marks return "Free Lie algebra generated by {} over {}".format(n, self.base_ring()) def _construct_UEA(self): @@ -479,7 +480,8 @@ def _generate_hall_set(self, k): if k <= 0: return () if k == 1: - return tuple(map(LieGenerator, self.variable_names())) + return tuple(map(LieGenerator, self.variable_names(), + range(len(self.variable_names())))) if k == 2: basis = self._generate_hall_set(1) ret = [] @@ -630,6 +632,18 @@ class Lyndon(FreeLieBasis_abstract): (in degree `1`) or a :class:`~sage.algebras.lie_algebras.lie_algebra_element.LyndonBracket` (in degree `> 1`). + + TESTS: + + We check that :trac:`27069` is fixed:: + + sage: Lzxy = LieAlgebra(QQ, ['z','x','y']).Lyndon() + sage: z,x,y = Lzxy.gens(); z,x,y + (z, x, y) + sage: z.bracket(x) + [z, x] + sage: y.bracket(z) + -[z, y] """ def __init__(self, lie): r""" @@ -725,7 +739,7 @@ def _is_basis_element(self, l, r): sage: all(Lyn._is_basis_element(*x.list()[0][0]) for x in Lyn.graded_basis(4)) True """ - w = tuple(l.to_word() + r.to_word()) + w = tuple(l._index_word + r._index_word) if not is_lyndon(w): return False b = self._standard_bracket(w) @@ -737,17 +751,23 @@ def _standard_bracket(self, lw): Return the standard bracketing (a :class:`LieObject`) of a Lyndon word ``lw`` using the Lie bracket. + INPUT: + + - ``lw`` -- tuple of positive integers that correspond to + the indices of the generators + EXAMPLES:: sage: L = LieAlgebra(QQ, 'x', 3) sage: Lyn = L.Lyndon() - sage: Lyn._standard_bracket(('x0', 'x0', 'x1')) + sage: Lyn._standard_bracket((0, 0, 1)) [x0, [x0, x1]] - sage: Lyn._standard_bracket(('x0', 'x1', 'x1')) + sage: Lyn._standard_bracket((0, 1, 1)) [[x0, x1], x1] """ if len(lw) == 1: - return LieGenerator(lw[0]) + i = lw[0] + return LieGenerator(self._indices[i], i) for i in range(1, len(lw)): if is_lyndon(lw[i:]): @@ -803,13 +823,14 @@ def graded_basis(self, k): names = self.variable_names() one = self.base_ring().one() if k == 1: - return tuple(self.element_class(self, {LieGenerator(n): one}) for n in names) + return tuple(self.element_class(self, {LieGenerator(n, k): one}) + for k,n in enumerate(names)) from sage.combinat.combinat_cython import lyndon_word_iterator n = len(self._indices) ret = [] for lw in lyndon_word_iterator(n, k): - b = self._standard_bracket(tuple([names[i] for i in lw])) + b = self._standard_bracket(tuple(lw)) ret.append(self.element_class(self, {b: one})) return tuple(ret) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pxd b/src/sage/algebras/lie_algebras/lie_algebra_element.pxd index 0988343c5cf..ca2caaf2191 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pxd +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pxd @@ -45,6 +45,7 @@ cdef class UntwistedAffineLieAlgebraElement(Element): cdef class LieObject(SageObject): cdef tuple _word + cdef public tuple _index_word cpdef tuple to_word(self) cdef class LieGenerator(LieObject): diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index e81bc6c966c..d056b6841eb 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -22,7 +22,8 @@ from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE from sage.misc.misc import repr_lincomb from sage.combinat.free_module import CombinatorialFreeModule -from sage.structure.element cimport have_same_parent, coercion_model, parent +from sage.structure.element cimport have_same_parent, parent +from sage.structure.coerce cimport coercion_model from sage.cpython.wrapperdescr cimport wrapperdescr_fastcall from sage.structure.element_wrapper cimport ElementWrapper from sage.structure.richcmp cimport richcmp, richcmp_not_equal @@ -1146,8 +1147,8 @@ cdef class UntwistedAffineLieAlgebraElement(Element): sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) - sage: e0.bracket(e1) + d + e1 + c + 3*d - (E[alpha[1]])#t^0 + (-h1)#t^1 + c + 4*d + sage: e0.bracket(e1) + d + c + 3*d + (-h1)#t^1 + c + 4*d """ cdef UntwistedAffineLieAlgebraElement rt = other return type(self)(self._parent, add(self._t_dict, rt._t_dict), @@ -1162,8 +1163,8 @@ cdef class UntwistedAffineLieAlgebraElement(Element): sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) - sage: e0.bracket(e1) + d - e1 + c - 3*d - (-E[alpha[1]])#t^0 + (-h1)#t^1 + c + -2*d + sage: d - e1 + c - 3*d + (-E[alpha[1]])#t^0 + c + -2*d sage: 4*c - e0.bracket(f0) (h1)#t^0 sage: 4*c - e0.bracket(f0) - h1 @@ -1187,8 +1188,8 @@ cdef class UntwistedAffineLieAlgebraElement(Element): sage: L = lie_algebras.Affine(QQ, ['A',1,1]) sage: e1,f1,h1,e0,f0,c,d = list(L.lie_algebra_generators()) sage: x = e0.bracket(e1) + d + e1 + c + 3*d - sage: -x - (-E[alpha[1]])#t^0 + (h1)#t^1 + -1*c + -4*d + sage: -x + e1 + (h1)#t^1 + -1*c + -4*d """ return type(self)(self._parent, negate(self._t_dict), -self._c_coeff, -self._d_coeff) @@ -1485,34 +1486,36 @@ cdef class LieObject(SageObject): """ raise NotImplementedError + cdef class LieGenerator(LieObject): """ A wrapper around an object so it can ducktype with and do comparison operations with :class:`LieBracket`. """ - def __init__(self, name): + def __init__(self, name, index): """ - Initalize ``self``. + Initialize ``self``. EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator - sage: x = LieGenerator('x') + sage: x = LieGenerator('x', 0) sage: TestSuite(x).run() """ self._word = (name,) self._name = name + self._index_word = (index,) def __reduce__(self): """ EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator - sage: x = LieGenerator('x') + sage: x = LieGenerator('x', 0) sage: loads(dumps(x)) == x True """ - return (LieGenerator, (self._name,)) + return (LieGenerator, (self._name, self._index_word[0])) def _repr_(self): """ @@ -1521,7 +1524,7 @@ cdef class LieGenerator(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator - sage: LieGenerator('x') + sage: LieGenerator('x', 0) x """ return self._name @@ -1535,7 +1538,7 @@ cdef class LieGenerator(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator - sage: x = LieGenerator('x') + sage: x = LieGenerator('x', 0) sage: hash(x) == hash('x') True """ @@ -1548,15 +1551,15 @@ cdef class LieGenerator(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: x == y False sage: x < y True sage: y < x False - sage: z = LieGenerator('x') + sage: z = LieGenerator('x', 0) sage: x == z True sage: z = LieBracket(x, y) @@ -1576,7 +1579,7 @@ cdef class LieGenerator(LieObject): # when the comparison ``self < rhs`` returns a # NotImplemented error.) if isinstance(rhs, LieGenerator): - return richcmp(self._name, (rhs)._name, op) + return richcmp(self._index_word[0], (rhs)._index_word[0], op) return op == Py_NE def _im_gens_(self, codomain, im_gens, names): @@ -1609,7 +1612,7 @@ cdef class LieGenerator(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator - sage: x = LieGenerator('x') + sage: x = LieGenerator('x', 0) sage: x.to_word() ('x',) """ @@ -1626,14 +1629,15 @@ cdef class LieBracket(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: z = LieBracket(x, y) sage: TestSuite(z).run() """ self._left = l self._right = r self._word = () + self._index_word = self._left._index_word + self._right._index_word self._hash = -1 def __reduce__(self): @@ -1641,8 +1645,8 @@ cdef class LieBracket(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: z = LieBracket(x, y) sage: loads(dumps(z)) == z True @@ -1656,8 +1660,8 @@ cdef class LieBracket(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: LieBracket(x, y) [x, y] """ @@ -1670,8 +1674,8 @@ cdef class LieBracket(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: z = LieBracket(x, y) sage: latex(z) \left[ x , y \right] @@ -1686,8 +1690,8 @@ cdef class LieBracket(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: z = LieBracket(x, y) sage: z[0] x @@ -1711,9 +1715,9 @@ cdef class LieBracket(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') - sage: z = LieGenerator('z') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) + sage: z = LieGenerator('z', 2) sage: b = LieBracket(x, y) sage: c = LieBracket(y, x) sage: b == c @@ -1751,9 +1755,9 @@ cdef class LieBracket(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') - sage: z = LieGenerator('z') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) + sage: z = LieGenerator('z', 2) sage: b = LieBracket(x, y) sage: hash(b) == hash(b) True @@ -1823,8 +1827,8 @@ cdef class LieBracket(LieObject): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: b = LieBracket(x, y) sage: c = LieBracket(b, x) sage: c.to_word() @@ -1851,8 +1855,8 @@ cdef class GradedLieBracket(LieBracket): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, GradedLieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: b = GradedLieBracket(x, y, 2) sage: TestSuite(b).run() """ @@ -1864,8 +1868,8 @@ cdef class GradedLieBracket(LieBracket): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, GradedLieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: b = GradedLieBracket(x, y, 2) sage: loads(dumps(b)) == b True @@ -1879,9 +1883,9 @@ cdef class GradedLieBracket(LieBracket): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, GradedLieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') - sage: z = LieGenerator('z') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) + sage: z = LieGenerator('z', 2) sage: b = GradedLieBracket(x, y, 2) sage: b < x False @@ -1911,9 +1915,9 @@ cdef class GradedLieBracket(LieBracket): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, GradedLieBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') - sage: z = LieGenerator('z') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) + sage: z = LieGenerator('z', 2) sage: b = GradedLieBracket(x, y, 2) sage: hash(b) == hash(b) True @@ -1940,13 +1944,13 @@ cdef class LyndonBracket(GradedLieBracket): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LyndonBracket - sage: x,y,z = [LieGenerator(letter) for letter in ['x', 'y', 'z']] + sage: x,y,z = [LieGenerator(letter, ind) for letter,ind in zip(['x', 'y', 'z'],range(3))] sage: LyndonBracket(x, LyndonBracket(y, z, 2), 3) < LyndonBracket(LyndonBracket(y, z, 2), x, 3) True """ if not isinstance(rhs, LieObject): return op == Py_NE - return richcmp(self.to_word(), (rhs).to_word(), op) + return richcmp(self._index_word, (rhs)._index_word, op) def __hash__(self): """ @@ -1955,12 +1959,13 @@ cdef class LyndonBracket(GradedLieBracket): EXAMPLES:: sage: from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, LyndonBracket - sage: x = LieGenerator('x') - sage: y = LieGenerator('y') + sage: x = LieGenerator('x', 0) + sage: y = LieGenerator('y', 1) sage: b = LyndonBracket(x, y, 2) - sage: hash(b) == hash((x, y)) + sage: hash(b) == hash((0, 1)) True """ if self._hash == -1: - self._hash = hash(self.to_word()) + self._hash = hash(self._index_word) return self._hash + diff --git a/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py b/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py index 35ea3f2164f..38499448de8 100644 --- a/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py @@ -22,6 +22,7 @@ from sage.rings.integer_ring import ZZ from collections import defaultdict + class NilpotentLieAlgebra_dense(LieAlgebraWithStructureCoefficients): r""" A nilpotent Lie algebra `L` over a base ring. @@ -67,6 +68,7 @@ class NilpotentLieAlgebra_dense(LieAlgebraWithStructureCoefficients): ....: ('Y','Z'): {'T': 1}}, nilpotent=True) sage: TestSuite(L).run() """ + @staticmethod def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, category=None, **kwds): @@ -156,6 +158,7 @@ def _repr_(self): """ return "Nilpotent %s" % (super(NilpotentLieAlgebra_dense, self)._repr_()) + class FreeNilpotentLieAlgebra(NilpotentLieAlgebra_dense): r""" Return the free nilpotent Lie algebra of step ``s`` with ``r`` generators. @@ -302,6 +305,13 @@ class FreeNilpotentLieAlgebra(NilpotentLieAlgebra_dense): sage: l = [LieAlgebra(QQ, 3, step=k) for k in range(1, 4)] sage: [L.dimension() for L in l] [3, 6, 14] + + Verify that a free nilpotent Lie algebra of step `>2` with `>10` + generators can be created, see :trac:`27018` (see also :trac:`27069`):: + + sage: L = LieAlgebra(QQ, 11, step=3) + sage: L.dimension() == 11 + (11^2-11)/2 + (11^3-11)/3 + True """ @staticmethod def __classcall_private__(cls, R, r, s, names=None, naming=None, category=None, **kwds): @@ -323,7 +333,7 @@ def __classcall_private__(cls, R, r, s, names=None, naming=None, category=None, category = cat.Graded().Stratified().or_subcategory(category) return super(FreeNilpotentLieAlgebra, cls).__classcall__( - cls, R,r, s, names=tuple(names), naming=naming, + cls, R, r, s, names=tuple(names), naming=naming, category=category, **kwds) def __init__(self, R, r, s, names, naming, category, **kwds): @@ -349,10 +359,10 @@ def __init__(self, R, r, s, names, naming, category, **kwds): from sage.algebras.lie_algebras.lie_algebra import LieAlgebra free_gen_names = ['F%d' % k for k in range(r)] - free_gen_names_inv = {val: i+1 for i,val in enumerate(free_gen_names)} + free_gen_names_inv = {val: i + 1 for i, val in enumerate(free_gen_names)} L = LieAlgebra(R, free_gen_names).Lyndon() - basis_by_deg = {d: [] for d in range(1, s+1)} + basis_by_deg = {d: [] for d in range(1, s + 1)} for d in range(1, s + 1): for X in L.graded_basis(d): # convert brackets of form [X_1, [X_1, X_2]] to words (1,1,2) @@ -389,18 +399,18 @@ def __init__(self, R, r, s, names, naming, category, **kwds): if dx == dy: for i, val in enumerate(basis_by_deg[dx]): X_ind, X = val - for Y_ind, Y in basis_by_deg[dy][i+1:]: + for Y_ind, Y in basis_by_deg[dy][i + 1:]: Z = L[X, Y] if not Z.is_zero(): s_coeff[(X_ind, Y_ind)] = {W_ind: Z[W.leading_support()] - for W_ind, W in basis_by_deg[dx+dy]} + for W_ind, W in basis_by_deg[dx + dy]} else: for X_ind, X in basis_by_deg[dx]: for Y_ind, Y in basis_by_deg[dy]: Z = L[X, Y] if not Z.is_zero(): s_coeff[(X_ind, Y_ind)] = {W_ind: Z[W.leading_support()] - for W_ind, W in basis_by_deg[dx+dy]} + for W_ind, W in basis_by_deg[dx + dy]} names, index_set = standardize_names_index_set(names, index_set) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( diff --git a/src/sage/algebras/lie_algebras/quotient.py b/src/sage/algebras/lie_algebras/quotient.py index 3fe674b0935..e4ba075fb38 100644 --- a/src/sage/algebras/lie_algebras/quotient.py +++ b/src/sage/algebras/lie_algebras/quotient.py @@ -142,7 +142,7 @@ class LieQuotient_finite_dimensional_with_basis(LieAlgebraWithStructureCoefficie ....: quots.append(L) sage: [Q.dimension() for Q in quots] [5, 4, 3, 2, 1, 0] - sage: all([Lp is Ln.ambient() for Lp, Ln in zip(quots,quots[1:])]) + sage: all(Lp is Ln.ambient() for Lp, Ln in zip(quots,quots[1:])) True sage: X = quots[-2].an_element() sage: lifts = [X] @@ -150,7 +150,7 @@ class LieQuotient_finite_dimensional_with_basis(LieAlgebraWithStructureCoefficie sage: for Q in quots: ....: X = Q.lift(X) ....: lifts.append(X) - sage: all([X.parent() is L for X, L in zip(lifts,quots)]) + sage: all(X.parent() is L for X, L in zip(lifts,quots)) True Verify a quotient construction when the basis ordering and indices ordering diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index 26181b25249..490398553c9 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -331,6 +331,22 @@ def __init__(self, R): IndexedGenerators.__init__(self, ZZ, prefix='d', bracket='[', sorting_key=_basis_key) + def _basis_key(self, m): + """ + Return a key for sorting for the index ``m``. + + TESTS:: + + sage: d = lie_algebras.VirasoroAlgebra(QQ) + sage: d._basis_key(3) + 3 + sage: d._basis_key('c') + +Infinity + sage: d._basis_key(4) < d._basis_key('c') + True + """ + return _basis_key(m) + def _repr_term(self, m): """ Return a string representation of the term indexed by ``m``. diff --git a/src/sage/algebras/quantum_groups/fock_space.py b/src/sage/algebras/quantum_groups/fock_space.py index 7ddd35546a8..4a341d70f2a 100644 --- a/src/sage/algebras/quantum_groups/fock_space.py +++ b/src/sage/algebras/quantum_groups/fock_space.py @@ -1586,7 +1586,7 @@ def __getitem__(self, i): sage: A[2,2,2,1] Traceback (most recent call last): ... - ValueError: (2, 2, 2, 1) is not an element of 3-Regular Partitions + ValueError: [2, 2, 2, 1] is not an element of 3-Regular Partitions sage: F = FockSpace(3, [0, 0]) sage: A = F.A() diff --git a/src/sage/algebras/quantum_groups/q_numbers.py b/src/sage/algebras/quantum_groups/q_numbers.py index d1b9926337e..00642a44589 100644 --- a/src/sage/algebras/quantum_groups/q_numbers.py +++ b/src/sage/algebras/quantum_groups/q_numbers.py @@ -165,7 +165,7 @@ def q_binomial(n, k, q=None): division is not implemented in the ring containing `q`, then it will not work. - EXAMPLES: + EXAMPLES:: sage: from sage.algebras.quantum_groups.q_numbers import q_binomial sage: q_binomial(2, 1) diff --git a/src/sage/algebras/quantum_groups/representations.py b/src/sage/algebras/quantum_groups/representations.py index 7f06a2d39aa..94466b7f6bb 100644 --- a/src/sage/algebras/quantum_groups/representations.py +++ b/src/sage/algebras/quantum_groups/representations.py @@ -278,13 +278,17 @@ class AdjointRepresentation(CyclicRepresentation): sage: A = AdjointRepresentation(R, K) sage: A V(-Lambda[0] + Lambda[4]) + + Sort the summands uniformly in Python 2 and Python 3:: + + sage: A.print_options(sorting_key=lambda x: str(x)) sage: v = A.an_element(); v 3*B[(-Lambda[0] + Lambda[3] - Lambda[4],)] - + 2*B[(Lambda[0] - Lambda[1] + Lambda[4],)] - + 2*B[(-Lambda[0] + Lambda[4],)] + + 2*B[(-Lambda[0] + Lambda[4],)] + 2*B[(Lambda[0] + - Lambda[1] + Lambda[4],)] sage: v.e(0) - 2*B[(Lambda[0] - Lambda[1] + Lambda[4],)] - + 3*B[(Lambda[0] - Lambda[1] + Lambda[3] - Lambda[4],)] + 3*B[(Lambda[0] - Lambda[1] + Lambda[3] - Lambda[4],)] + + 2*B[(Lambda[0] - Lambda[1] + Lambda[4],)] sage: v.f(0) 2*B[(-Lambda[0] + Lambda[4],)] diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index 455bbaffe23..e7fe85eea3f 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -1159,7 +1159,7 @@ def product_on_basis(self, t1, t2): TESTS:: - sage: all([Adem(Milnor.Sq(n) ** 3)._repr_() == (Adem.Sq(n) ** 3)._repr_() for n in range(10)]) + sage: all(Adem(Milnor.Sq(n) ** 3)._repr_() == (Adem.Sq(n) ** 3)._repr_() for n in range(10)) True sage: Wall = SteenrodAlgebra(basis='wall') sage: Wall(Adem.Sq(4,4) * Milnor.Sq(4)) == Adem(Wall.Sq(4,4) * Milnor.Sq(4)) @@ -1167,7 +1167,7 @@ def product_on_basis(self, t1, t2): sage: A3 = SteenrodAlgebra(p=3, basis='adem') sage: M3 = SteenrodAlgebra(p=3, basis='milnor') - sage: all([A3(M3.P(n) * M3.Q(0) * M3.P(n))._repr_() == (A3.P(n) * A3.Q(0) * A3.P(n))._repr_() for n in range(5)]) + sage: all(A3(M3.P(n) * M3.Q(0) * M3.P(n))._repr_() == (A3.P(n) * A3.Q(0) * A3.P(n))._repr_() for n in range(5)) True sage: EA = SteenrodAlgebra(generic=True) @@ -1258,10 +1258,10 @@ def coproduct_on_basis(self, t, algorithm=None): TESTS:: - sage: all([A.coproduct_on_basis((n,1), algorithm='milnor') == A.coproduct_on_basis((n,1), algorithm='adem') for n in range(9)]) # long time + sage: all(A.coproduct_on_basis((n,1), algorithm='milnor') == A.coproduct_on_basis((n,1), algorithm='adem') for n in range(9)) # long time True sage: A7 = SteenrodAlgebra(p=7, basis='adem') - sage: all([A7.coproduct_on_basis((0,n,1), algorithm='milnor') == A7.coproduct_on_basis((0,n,1), algorithm='adem') for n in range(9)]) # long time + sage: all(A7.coproduct_on_basis((0,n,1), algorithm='milnor') == A7.coproduct_on_basis((0,n,1), algorithm='adem') for n in range(9)) # long time True """ def coprod_list(t): @@ -1470,10 +1470,10 @@ def antipode_on_basis(self, t): TESTS:: sage: Milnor = SteenrodAlgebra() - sage: all([x.antipode().antipode() == x for x in Milnor.basis(11)]) # long time + sage: all(x.antipode().antipode() == x for x in Milnor.basis(11)) # long time True sage: A5 = SteenrodAlgebra(p=5, basis='adem') - sage: all([x.antipode().antipode() == x for x in A5.basis(25)]) + sage: all(x.antipode().antipode() == x for x in A5.basis(25)) True sage: H = SteenrodAlgebra(profile=[2,2,1]) sage: H.Sq(1,2).antipode() in H @@ -2036,20 +2036,20 @@ def _coerce_map_from_(self, S): if not self._generic: self_prec = len(self._profile) S_prec = len(S._profile) - return all([self.profile(i) >= S.profile(i) - for i in range(1, max(self_prec, S_prec)+1)]) + return all(self.profile(i) >= S.profile(i) + for i in range(1, max(self_prec, S_prec)+1)) self_prec = len(self._profile[0]) S_prec = len(S._profile[0]) - return (all([self.profile(i) >= S.profile(i) - for i in range(1, max(self_prec, S_prec)+1)]) - and all([self.profile(i, 1) >= S.profile(i, 1) - for i in range(1, max(self_prec, S_prec)+1)])) + return (all(self.profile(i) >= S.profile(i) + for i in range(1, max(self_prec, S_prec)+1)) + and all(self.profile(i, 1) >= S.profile(i, 1) + for i in range(1, max(self_prec, S_prec)+1))) if (isinstance(S, CombinatorialFreeModule) and S.dimension() < Infinity and p == S.base_ring().characteristic()): from .steenrod_algebra_misc import get_basis_name try: get_basis_name(S.prefix(), S.base_ring().characteristic()) - # return all([a in self for a in S.basis()]) + # return all(a in self for a in S.basis()) return True except ValueError: return False @@ -2153,8 +2153,8 @@ def __contains__(self, x): pass A = SteenrodAlgebra(p=p, basis=self.basis_name(), generic=self._generic) if self._has_nontrivial_profile(): - return all([self._check_profile_on_basis(mono) - for mono in A(x).support()]) + return all(self._check_profile_on_basis(mono) + for mono in A(x).support()) return True # trivial profile, so True return False @@ -2258,17 +2258,17 @@ def _check_profile_on_basis(self, t): profile=self._profile, truncation_type=self._truncation_type, generic=self._generic) - return all([A._check_profile_on_basis(a[0]) - for a in self._milnor_on_basis(t)]) + return all(A._check_profile_on_basis(a[0]) + for a in self._milnor_on_basis(t)) from sage.rings.infinity import Infinity p = self.prime() if not self._has_nontrivial_profile(): return True if not self._generic: - return all([self.profile(i+1) == Infinity - or t[i] < 2**self.profile(i+1) - for i in range(len(t))]) + return all(self.profile(i+1) == Infinity + or t[i] < 2**self.profile(i+1) + for i in range(len(t))) # p odd: if any(self.profile(i, 1) != 2 for i in t[0]): return False @@ -2838,10 +2838,10 @@ def is_commutative(self): return False if not self._generic: n = max(self._profile) - return all([self.profile(i) == 0 for i in range(1, n)]) + return all(self.profile(i) == 0 for i in range(1, n)) n = max(self._profile[0]) - return (all([self.profile(i,0) == 0 for i in range(1, n)]) - and all([self.profile(i,1) == 1 for i in range(n)])) + return (all(self.profile(i,0) == 0 for i in range(1, n)) + and all(self.profile(i,1) == 1 for i in range(n))) def is_finite(self): r""" @@ -3197,11 +3197,11 @@ def degree(self): TESTS:: - sage: all([x.degree() == 10 for x in SteenrodAlgebra(basis='woody').basis(10)]) + sage: all(x.degree() == 10 for x in SteenrodAlgebra(basis='woody').basis(10)) True - sage: all([x.degree() == 11 for x in SteenrodAlgebra(basis='woodz').basis(11)]) + sage: all(x.degree() == 11 for x in SteenrodAlgebra(basis='woodz').basis(11)) True - sage: all([x.degree() == x.milnor().degree() for x in SteenrodAlgebra(basis='wall').basis(11)]) + sage: all(x.degree() == x.milnor().degree() for x in SteenrodAlgebra(basis='wall').basis(11)) True sage: a = SteenrodAlgebra(basis='pst').basis(10)[0] sage: a.degree() == a.change_basis('arnonc').degree() @@ -3209,15 +3209,15 @@ def degree(self): sage: b = SteenrodAlgebra(basis='comm').basis(12)[1] sage: b.degree() == b.change_basis('adem').change_basis('arnona').degree() True - sage: all([x.degree() == 9 for x in SteenrodAlgebra(basis='comm').basis(9)]) + sage: all(x.degree() == 9 for x in SteenrodAlgebra(basis='comm').basis(9)) True - sage: all([x.degree() == 8 for x in SteenrodAlgebra(basis='adem').basis(8)]) + sage: all(x.degree() == 8 for x in SteenrodAlgebra(basis='adem').basis(8)) True - sage: all([x.degree() == 7 for x in SteenrodAlgebra(basis='milnor').basis(7)]) + sage: all(x.degree() == 7 for x in SteenrodAlgebra(basis='milnor').basis(7)) True - sage: all([x.degree() == 24 for x in SteenrodAlgebra(p=3).basis(24)]) + sage: all(x.degree() == 24 for x in SteenrodAlgebra(p=3).basis(24)) True - sage: all([x.degree() == 40 for x in SteenrodAlgebra(p=5, basis='serre-cartan').basis(40)]) + sage: all(x.degree() == 40 for x in SteenrodAlgebra(p=5, basis='serre-cartan').basis(40)) True """ if len(self.support()) == 0: @@ -3382,6 +3382,39 @@ def coproduct(self, algorithm='milnor'): 1 # Q_1 P(1) + P(1) # Q_1 + Q_1 # P(1) + Q_1 P(1) # 1 sage: a.coproduct(algorithm='adem') 1 # Q_1 P(1) + P(1) # Q_1 + Q_1 # P(1) + Q_1 P(1) # 1 + + Once you have an element of the tensor product, you may + want to extract the tensor factors of its summands. :: + + sage: b = Sq(2).coproduct() + sage: b + 1 # Sq(2) + Sq(1) # Sq(1) + Sq(2) # 1 + sage: supp = sorted(b.support()); supp + [((), (2,)), ((1,), (1,)), ((2,), ())] + sage: Sq(*supp[0][0]) + 1 + sage: Sq(*supp[0][1]) + Sq(2) + sage: [(Sq(*x), Sq(*y)) for (x,y) in supp] + [(1, Sq(2)), (Sq(1), Sq(1)), (Sq(2), 1)] + + The ``support`` of an element does not include the + coefficients, so at odd primes it may be better to use + ``monomial_coefficients``:: + + sage: A3 = SteenrodAlgebra(p=3) + sage: b = (A3.P(1)**2).coproduct() + sage: b + 2*1 # P(2) + 2*P(1) # P(1) + 2*P(2) # 1 + sage: sorted(b.support()) + [(((), ()), ((), (2,))), (((), (1,)), ((), (1,))), (((), (2,)), ((), ()))] + sage: b.monomial_coefficients() + {(((), ()), ((), (2,))): 2, + (((), (1,)), ((), (1,))): 2, + (((), (2,)), ((), ())): 2} + sage: mc = b.monomial_coefficients() + sage: sorted([(A3.monomial(x), A3.monomial(y), mc[x,y]) for (x,y) in mc]) + [(1, P(2), 2), (P(1), P(1), 2), (P(2), 1, 2)] """ A = self.parent() return A.coproduct(self, algorithm=algorithm) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 00a8fc413f5..4719a9e2933 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -110,7 +110,7 @@ def repr_from_monomials(monomials, term_repr, use_latex=False): sage: c*(a*a + 2)*b (-x - 2)*e1*e2 - 4*x - 8 sage: latex(c*(a*a + 2)*b) - \left( - x - 2 \right) e_{1} e_{2} - 4 x - 8 + \left( -x - 2 \right) e_{1} e_{2} - 4 x - 8 """ if not monomials: if use_latex: diff --git a/src/sage/all.py b/src/sage/all.py index 242ea9e9ed4..c4b6d249e56 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -114,7 +114,7 @@ from sage.functions.all import * from sage.calculus.all import * -import sage.tests.all as tests +lazy_import('sage.tests', 'all', as_='tests', deprecation=27337) from sage.cpython.all import * from sage.crypto.all import * diff --git a/src/sage/arith/functions.pyx b/src/sage/arith/functions.pyx index defadd05042..1c184b02a9e 100644 --- a/src/sage/arith/functions.pyx +++ b/src/sage/arith/functions.pyx @@ -16,7 +16,7 @@ from cysignals.signals cimport sig_check from sage.libs.gmp.mpz cimport mpz_lcm, mpz_set_ui from sage.rings.integer cimport Integer -from sage.structure.element cimport coercion_model +from sage.structure.coerce cimport coercion_model def lcm(a, b=None): diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 999ee92e824..c6c53a64bac 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -184,8 +184,8 @@ def algdep(z, degree, known_bits=None, use_bits=None, known_digits=None, use_dig sage: from numpy import int8, float64 sage: algdep(float64(1.888888888888888), int8(1)) 9*x - 17 - sage: from gmpy2 import mpz, mpfr # optional - gmpy2 - sage: algdep(mpfr(1.888888888888888), mpz(1)) # optional - gmpy2 + sage: from gmpy2 import mpz, mpfr + sage: algdep(mpfr(1.888888888888888), mpz(1)) 9*x - 17 """ if proof and not height_bound: @@ -341,8 +341,8 @@ def bernoulli(n, algorithm='default', num_threads=1): sage: from numpy import int8 sage: bernoulli(int8(12)) -691/2730 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: bernoulli(mpz(12)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: bernoulli(mpz(12)) -691/2730 @@ -426,8 +426,8 @@ def factorial(n, algorithm='gmp'): sage: from numpy import int8 sage: factorial(int8(4)) 24 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: factorial(mpz(4)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: factorial(mpz(4)) 24 @@ -600,8 +600,8 @@ def is_prime_power(n, get_data=False): Traceback (most recent call last): ... TypeError: unable to convert 'foo' to an integer - sage: from gmpy2 import mpz # optional - gmpy2 - sage: is_prime_power(mpz(389)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: is_prime_power(mpz(389)) True sage: from numpy import int16 sage: is_prime_power(int16(389)) @@ -657,8 +657,8 @@ def is_pseudoprime_power(n, get_data=False): sage: from numpy import int16 sage: is_pseudoprime_power(int16(1024)) True - sage: from gmpy2 import mpz # optional - gmpy2 - sage: is_pseudoprime_power(mpz(1024)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: is_pseudoprime_power(mpz(1024)) True """ return ZZ(n).is_prime_power(proof=False, get_data=get_data) @@ -725,8 +725,8 @@ def valuation(m, *args, **kwds): sage: from numpy import int16 sage: valuation(int16(512), int16(2)) 9 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: valuation(mpz(512), mpz(2)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: valuation(mpz(512), mpz(2)) 9 """ try: @@ -826,8 +826,8 @@ def prime_powers(start, stop=None): sage: from numpy import int8 sage: prime_powers(int8(20)) [2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 19] - sage: from gmpy2 import mpz # optional - gmpy2 - sage: prime_powers(mpz(20)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: prime_powers(mpz(20)) [2, 3, 4, 5, 7, 8, 9, 11, 13, 16, 17, 19] """ start = ZZ(start) @@ -917,8 +917,8 @@ def eratosthenes(n): sage: from numpy import int8 sage: eratosthenes(int8(3)) [2, 3] - sage: from gmpy2 import mpz # optional - gmpy2 - sage: eratosthenes(mpz(3)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: eratosthenes(mpz(3)) [2, 3] """ n = int(n) @@ -1013,8 +1013,8 @@ def primes(start, stop=None, proof=None): sage: from numpy import int8 sage: list(primes(int8(13))) [2, 3, 5, 7, 11] - sage: from gmpy2 import mpz # optional - gmpy2 - sage: list(primes(mpz(13))) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: list(primes(mpz(13))) [2, 3, 5, 7, 11] """ from sage.rings.infinity import infinity @@ -1085,8 +1085,8 @@ def next_prime_power(n): sage: from numpy import int8 sage: next_prime_power(int8(10)) 11 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: next_prime_power(mpz(10)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: next_prime_power(mpz(10)) 11 """ return ZZ(n).next_prime_power() @@ -1117,8 +1117,8 @@ def next_probable_prime(n): sage: from numpy import int8 sage: next_probable_prime(int8(19)) 23 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: next_probable_prime(mpz(19)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: next_probable_prime(mpz(19)) 23 """ return ZZ(n).next_probable_prime() @@ -1166,8 +1166,8 @@ def next_prime(n, proof=None): sage: from numpy import int8 sage: next_prime(int8(3)) 5 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: next_probable_prime(mpz(3)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: next_probable_prime(mpz(3)) 5 """ return ZZ(n).next_prime(proof) @@ -1209,8 +1209,8 @@ def previous_prime(n): sage: from numpy import int8 sage: previous_prime(int8(7)) 5 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: previous_prime(mpz(7)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: previous_prime(mpz(7)) 5 """ n = ZZ(n)-1 @@ -1288,8 +1288,8 @@ def previous_prime_power(n): sage: from numpy import int8 sage: previous_prime_power(int8(10)) 9 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: previous_prime_power(mpz(10)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: previous_prime_power(mpz(10)) 9 """ return ZZ(n).previous_prime_power() @@ -1394,19 +1394,21 @@ def random_prime(n, proof=None, lbound=2): if prime_test(p): return p - def divisors(n): """ - Returns a list of all positive integer divisors of the nonzero - integer n. + Return the list of all divisors (up to units) of this element + of a unique factorization domain. - INPUT: + For an integer, the list of all positive integer divisors + of this integer, sorted in increasing order, is returned. + INPUT: - ``n`` - the element + EXAMPLES: - EXAMPLES:: + Divisors of integers:: sage: divisors(-3) [1, 3] @@ -1425,7 +1427,8 @@ def divisors(n): ... ValueError: n must be nonzero sage: divisors(2^3 * 3^2 * 17) - [1, 2, 3, 4, 6, 8, 9, 12, 17, 18, 24, 34, 36, 51, 68, 72, 102, 136, 153, 204, 306, 408, 612, 1224] + [1, 2, 3, 4, 6, 8, 9, 12, 17, 18, 24, 34, 36, 51, 68, 72, + 102, 136, 153, 204, 306, 408, 612, 1224] This function works whenever one has unique factorization:: @@ -1433,9 +1436,11 @@ def divisors(n): sage: divisors(K.ideal(7)) [Fractional ideal (1), Fractional ideal (a), Fractional ideal (7)] sage: divisors(K.ideal(3)) - [Fractional ideal (1), Fractional ideal (3), Fractional ideal (-a + 2), Fractional ideal (-a - 2)] + [Fractional ideal (1), Fractional ideal (3), + Fractional ideal (-a + 2), Fractional ideal (-a - 2)] sage: divisors(K.ideal(35)) - [Fractional ideal (1), Fractional ideal (5), Fractional ideal (a), Fractional ideal (7), Fractional ideal (5*a), Fractional ideal (35)] + [Fractional ideal (1), Fractional ideal (5), Fractional ideal (a), + Fractional ideal (7), Fractional ideal (5*a), Fractional ideal (35)] TESTS:: @@ -1444,8 +1449,8 @@ def divisors(n): sage: import numpy sage: divisors(numpy.int8(100)) [1, 2, 4, 5, 10, 20, 25, 50, 100] - sage: import gmpy2 # optional - gmpy2 - sage: divisors(gmpy2.mpz(100)) # optional - gmpy2 + sage: import gmpy2 + sage: divisors(gmpy2.mpz(100)) [1, 2, 4, 5, 10, 20, 25, 50, 100] sage: divisors([]) Traceback (most recent call last): @@ -1534,8 +1539,8 @@ class Sigma: sage: from numpy import int8 sage: sigma(int8(100),int8(4)) 106811523 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: sigma(mpz(100),mpz(4)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: sigma(mpz(100),mpz(4)) 106811523 """ def __repr__(self): @@ -1718,10 +1723,10 @@ def gcd(a, b=None, **kwargs): sage: from numpy import int8 sage: GCD(int8(97),int8(100)) 1 - sage: from gmpy2 import mpq, mpz # optional - gmpy2 - sage: GCD(mpq(2/3), mpq(4/5)) # optional - gmpy2 + sage: from gmpy2 import mpq, mpz + sage: GCD(mpq(2/3), mpq(4/5)) 2/15 - sage: GCD((mpz(2), mpz(4))) # optional - gmpy2 + sage: GCD((mpz(2), mpz(4))) 2 """ # Most common use case first: @@ -1816,8 +1821,8 @@ def xlcm(m, n): sage: from numpy import int16 sage: xlcm(int16(120), int16(36)) (360, 40, 9) - sage: from gmpy2 import mpz # optional - gmpy2 - sage: xlcm(mpz(120), mpz(36)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: xlcm(mpz(120), mpz(36)) (360, 40, 9) """ m = py_scalar_to_element(m) @@ -1907,10 +1912,10 @@ def xgcd(a, b): (4, 1, 0) sage: xgcd(int8(4),int8(8)) (4, 1, 0) - sage: from gmpy2 import mpz # optional - gmpy2 - sage: xgcd(mpz(4), mpz(8)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: xgcd(mpz(4), mpz(8)) (4, 1, 0) - sage: xgcd(4, mpz(8)) # optional - gmpy2 + sage: xgcd(4, mpz(8)) (4, 1, 0) TESTS: @@ -2040,8 +2045,8 @@ def inverse_mod(a, m): sage: from numpy import int8 sage: inverse_mod(int8(5),int8(14)) 3 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: inverse_mod(mpz(5),mpz(14)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: inverse_mod(mpz(5),mpz(14)) 3 """ try: @@ -2136,8 +2141,8 @@ def power_mod(a,n,m): sage: from numpy import int32 sage: power_mod(int32(2),int32(390),int32(391)) 285 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: power_mod(mpz(2),mpz(390),mpz(391)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: power_mod(mpz(2),mpz(390),mpz(391)) mpz(285) """ if m==0: @@ -2255,8 +2260,8 @@ def rational_reconstruction(a, m, algorithm='fast'): sage: from numpy import int32 sage: rational_reconstruction(int32(3), int32(292393)) 3 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: rational_reconstruction(mpz(3), mpz(292393)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: rational_reconstruction(mpz(3), mpz(292393)) 3 """ if algorithm == 'fast': @@ -2294,8 +2299,8 @@ def mqrr_rational_reconstruction(u, m, T): sage: from numpy import int16 sage: mqrr_rational_reconstruction(int16(21),int16(3100),int16(13)) (21, 1) - sage: from gmpy2 import mpz # optional - gmpy2 - sage: mqrr_rational_reconstruction(mpz(21),mpz(3100),mpz(13)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: mqrr_rational_reconstruction(mpz(21),mpz(3100),mpz(13)) (21, 1) """ u = py_scalar_to_element(u) @@ -2362,8 +2367,8 @@ def trial_division(n, bound=None): sage: from numpy import int8 sage: trial_division(int8(91)) 7 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: trial_division(mpz(91)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: trial_division(mpz(91)) 7 """ if bound is None: @@ -2521,8 +2526,8 @@ def factor(n, proof=None, int_=False, algorithm='pari', verbose=0, **kwds): sage: import numpy sage: factor(numpy.int8(30)) 2 * 3 * 5 - sage: import gmpy2 # optional - gmpy2 - sage: factor(gmpy2.mpz(30)) # optional - gmpy2 + sage: import gmpy2 + sage: factor(gmpy2.mpz(30)) 2 * 3 * 5 TESTS:: @@ -2583,8 +2588,8 @@ def radical(n, *args, **kwds): sage: from numpy import int8 sage: radical(int8(50)) 10 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: radical(mpz(50)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: radical(mpz(50)) 10 """ try: @@ -2601,18 +2606,21 @@ def radical(n, *args, **kwds): def prime_divisors(n): """ - The prime divisors of ``n``. + Return the list of prime divisors (up to units) of this element + of a unique factorization domain. INPUT: - - ``n`` -- any object which can be factored + - ``n`` -- any object which can be decomposed into prime factors OUTPUT: A list of prime factors of ``n``. For integers, this list is sorted in increasing order. - EXAMPLES:: + EXAMPLES: + + Prime divisors of positive integers:: sage: prime_divisors(1) [] @@ -2638,15 +2646,15 @@ def prime_divisors(n): sage: from numpy import int8 sage: prime_divisors(int8(-100)) [2, 5] - sage: from gmpy2 import mpz # optional - gmpy2 - sage: prime_divisors(mpz(-100)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: prime_divisors(mpz(-100)) [2, 5] """ try: return n.prime_divisors() except AttributeError: pass - return [p for p,_ in factor(n)] + return [p for p, _ in factor(n)] prime_factors = prime_divisors @@ -2669,8 +2677,8 @@ def odd_part(n): sage: from numpy import int8 sage: odd_part(int8(5)) 5 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: odd_part(mpz(5)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: odd_part(mpz(5)) 5 """ if not isinstance(n, Integer): @@ -2711,8 +2719,8 @@ def prime_to_m_part(n,m): sage: from numpy import int16 sage: prime_to_m_part(int16(240), int16(2)) 15 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: prime_to_m_part(mpz(240), mpz(2)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: prime_to_m_part(mpz(240), mpz(2)) 15 """ return ZZ(n).prime_to_m_part(m) @@ -2767,8 +2775,8 @@ def is_square(n, root=False): sage: from numpy import int8 sage: is_square(int8(4)) True - sage: from gmpy2 import mpz # optional - gmpy2 - sage: is_square(mpz(4)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: is_square(mpz(4)) True Tests with Polynomial:: @@ -2796,7 +2804,6 @@ def is_square(n, root=False): return False, None return m() - def is_squarefree(n): """ Test whether ``n`` is square free. @@ -2840,10 +2847,10 @@ def is_squarefree(n): False sage: is_squarefree(int8(101)) True - sage: from gmpy2 import mpz # optional - gmpy2 - sage: is_squarefree(mpz(100)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: is_squarefree(mpz(100)) False - sage: is_squarefree(mpz(101)) # optional - gmpy2 + sage: is_squarefree(mpz(101)) True """ e = py_scalar_to_element(n) @@ -2927,8 +2934,8 @@ class Euler_Phi: sage: from numpy import int8 sage: euler_phi(int8(37)) 36 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: euler_phi(mpz(37)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: euler_phi(mpz(37)) 36 AUTHORS: @@ -3109,10 +3116,10 @@ def crt(a,b,m=None,n=None): sage: import numpy sage: crt(numpy.int8(2), numpy.int8(3), numpy.int8(7), numpy.int8(11)) 58 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: crt(mpz(2), mpz(3), mpz(7), mpz(11)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: crt(mpz(2), mpz(3), mpz(7), mpz(11)) 58 - sage: crt(mpz(2), 3, mpz(7), numpy.int8(11)) # optional - gmpy2 + sage: crt(mpz(2), 3, mpz(7), numpy.int8(11)) 58 """ if isinstance(a, list): @@ -3133,11 +3140,7 @@ def crt(a,b,m=None,n=None): raise ValueError("No solution to crt problem since gcd(%s,%s) does not divide %s-%s" % (m, n, a, b)) from sage.arith.functions import lcm - try: - x = a + q*alpha*m - except TypeError: - # Maybe a coercion problem with m type (operand `*`) - x = a + q*alpha*py_scalar_to_element(m) + x = a + q*alpha*py_scalar_to_element(m) return x % lcm(m, n) @@ -3205,8 +3208,8 @@ def CRT_list(v, moduli): sage: from numpy import int8 sage: CRT_list([int8(2),int8(3),int8(2)], [int8(3),int8(5),int8(7)]) 23 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: CRT_list([mpz(2),mpz(3),mpz(2)], [mpz(3),mpz(5),mpz(7)]) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: CRT_list([mpz(2),mpz(3),mpz(2)], [mpz(3),mpz(5),mpz(7)]) 23 """ if not isinstance(v,list) or not isinstance(moduli,list): @@ -3499,8 +3502,8 @@ def binomial(x, m, **kwds): sage: import numpy sage: binomial(numpy.int32(20), numpy.int32(10)) 184756 - sage: import gmpy2 # optional - gmpy2 - sage: binomial(gmpy2.mpz(20), gmpy2.mpz(10)) # optional - gmpy2 + sage: import gmpy2 + sage: binomial(gmpy2.mpz(20), gmpy2.mpz(10)) mpz(184756) """ try: @@ -3587,8 +3590,8 @@ def multinomial(*ks): sage: from numpy import int8 sage: multinomial(int8(3), int8(2)) 10 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: multinomial(mpz(3), mpz(2)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: multinomial(mpz(3), mpz(2)) mpz(10) AUTHORS: @@ -3636,8 +3639,8 @@ def binomial_coefficients(n): sage: from numpy import int8 sage: sorted(binomial_coefficients(int8(3)).items()) [((0, 3), 1), ((1, 2), 3), ((2, 1), 3), ((3, 0), 1)] - sage: from gmpy2 import mpz # optional - gmpy2 - sage: sorted(binomial_coefficients(mpz(3)).items()) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: sorted(binomial_coefficients(mpz(3)).items()) [((0, 3), 1), ((1, 2), 3), ((2, 1), 3), ((3, 0), 1)] AUTHORS: @@ -3712,8 +3715,8 @@ def multinomial_coefficients(m, n): sage: from numpy import int8 sage: sorted(multinomial_coefficients(int8(2), int8(5)).items()) [((0, 5), 1), ((1, 4), 5), ((2, 3), 10), ((3, 2), 10), ((4, 1), 5), ((5, 0), 1)] - sage: from gmpy2 import mpz # optional - gmpy2 - sage: sorted(multinomial_coefficients(mpz(2), mpz(5)).items()) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: sorted(multinomial_coefficients(mpz(2), mpz(5)).items()) [((0, 5), 1), ((1, 4), 5), ((2, 3), 10), ((3, 2), 10), ((4, 1), 5), ((5, 0), 1)] """ if not m: @@ -3801,8 +3804,8 @@ def kronecker_symbol(x,y): sage: from numpy import int8 sage: kronecker_symbol(int8(13),int8(21)) -1 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: kronecker_symbol(mpz(13),mpz(21)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: kronecker_symbol(mpz(13),mpz(21)) -1 """ x = QQ(x).numerator() * QQ(x).denominator() @@ -3852,8 +3855,8 @@ def legendre_symbol(x,p): sage: from numpy import int8 sage: legendre_symbol(int8(2),int8(3)) -1 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: legendre_symbol(mpz(2),mpz(3)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: legendre_symbol(mpz(2),mpz(3)) -1 """ x = QQ(x).numerator() * QQ(x).denominator() @@ -3907,8 +3910,8 @@ def jacobi_symbol(a,b): sage: from numpy import int16 sage: jacobi_symbol(int16(10),int16(777)) -1 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: jacobi_symbol(mpz(10),mpz(777)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: jacobi_symbol(mpz(10),mpz(777)) -1 """ @@ -4013,8 +4016,8 @@ def primitive_root(n, check=True): sage: from numpy import int8 sage: primitive_root(int8(-46)) 5 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: primitive_root(mpz(-46)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: primitive_root(mpz(-46)) 5 """ if not check: @@ -4069,8 +4072,8 @@ def nth_prime(n): sage: from numpy import int8 sage: nth_prime(int8(10)) 29 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: nth_prime(mpz(10)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: nth_prime(mpz(10)) 29 """ if n <= 0: @@ -4103,8 +4106,8 @@ def quadratic_residues(n): sage: from numpy import int8 sage: quadratic_residues(int8(11)) [0, 1, 3, 4, 5, 9] - sage: from gmpy2 import mpz # optional - gmpy2 - sage: quadratic_residues(mpz(11)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: quadratic_residues(mpz(11)) [0, 1, 3, 4, 5, 9] """ n = abs(int(n)) @@ -4166,8 +4169,8 @@ class Moebius: sage: from numpy import int8 sage: moebius(int8(-5)) -1 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: moebius(mpz(-5)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: moebius(mpz(-5)) -1 """ def __call__(self, n): @@ -4352,8 +4355,8 @@ def continuant(v, n=None): sage: from numpy import int8 sage: continuant([int8(1),int8(2),int8(3)]) 10 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: continuant([mpz(1),mpz(2),mpz(3)]) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: continuant([mpz(1),mpz(2),mpz(3)]) mpz(10) AUTHORS: @@ -4396,8 +4399,8 @@ def number_of_divisors(n): sage: from numpy import int8 sage: number_of_divisors(int8(100)) 9 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: number_of_divisors(mpz(100)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: number_of_divisors(mpz(100)) 9 """ m = ZZ(n) @@ -4460,8 +4463,8 @@ def hilbert_symbol(a, b, p, algorithm="pari"): sage: from numpy import int8 sage: hilbert_symbol(int8(2),int8(3),int8(5),algorithm='all') 1 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: hilbert_symbol(mpz(2),mpz(3),mpz(5),algorithm='all') # optional - gmpy2 + sage: from gmpy2 import mpz + sage: hilbert_symbol(mpz(2),mpz(3),mpz(5),algorithm='all') 1 AUTHORS: @@ -4551,8 +4554,8 @@ def hilbert_conductor(a, b): sage: from numpy import int8 sage: hilbert_conductor(int8(-3), int8(-17)) 17 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: hilbert_conductor(mpz(-3), mpz(-17)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: hilbert_conductor(mpz(-3), mpz(-17)) 17 AUTHOR: @@ -4615,8 +4618,8 @@ def hilbert_conductor_inverse(d): sage: from numpy import int8 sage: hilbert_conductor_inverse(int8(30)) (-3, -10) - sage: from gmpy2 import mpz # optional - gmpy2 - sage: hilbert_conductor_inverse(mpz(30)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: hilbert_conductor_inverse(mpz(30)) (-3, -10) """ Z = ZZ @@ -4748,8 +4751,8 @@ def falling_factorial(x, a): sage: from numpy import int8 sage: falling_factorial(int8(10), int8(3)) 720 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: falling_factorial(mpz(10), mpz(3)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: falling_factorial(mpz(10), mpz(3)) 720 AUTHORS: @@ -4853,8 +4856,8 @@ def rising_factorial(x, a): sage: from numpy import int8 sage: rising_factorial(int8(10), int8(3)) 1320 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: rising_factorial(mpz(10), mpz(3)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: rising_factorial(mpz(10), mpz(3)) 1320 AUTHORS: @@ -4890,8 +4893,8 @@ def integer_ceil(x): sage: from numpy import float32 sage: integer_ceil(float32(5.4)) 6 - sage: from gmpy2 import mpfr # optional - gmpy2 - sage: integer_ceil(mpfr(5.4)) # optional - gmpy2 + sage: from gmpy2 import mpfr + sage: integer_ceil(mpfr(5.4)) 6 """ try: @@ -4936,8 +4939,8 @@ def integer_floor(x): sage: from numpy import float32 sage: integer_floor(float32(5.4)) 5 - sage: from gmpy2 import mpfr # optional - gmpy2 - sage: integer_floor(mpfr(5.4)) # optional - gmpy2 + sage: from gmpy2 import mpfr + sage: integer_floor(mpfr(5.4)) 5 """ try: @@ -4999,8 +5002,8 @@ def two_squares(n): sage: from numpy import int16 sage: two_squares(int16(389)) (10, 17) - sage: from gmpy2 import mpz # optional - gmpy2 - sage: two_squares(mpz(389)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: two_squares(mpz(389)) (10, 17) ALGORITHM: @@ -5123,8 +5126,8 @@ def three_squares(n): sage: from numpy import int16 sage: three_squares(int16(389)) (1, 8, 18) - sage: from gmpy2 import mpz # optional - gmpy2 - sage: three_squares(mpz(389)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: three_squares(mpz(389)) (1, 8, 18) ALGORITHM: @@ -5254,8 +5257,8 @@ def four_squares(n): sage: from numpy import int16 sage: four_squares(int16(389)) (0, 1, 8, 18) - sage: from gmpy2 import mpz # optional - gmpy2 - sage: four_squares(mpz(389)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: four_squares(mpz(389)) (0, 1, 8, 18) """ n = ZZ(n) @@ -5348,8 +5351,8 @@ def sum_of_k_squares(k,n): sage: from numpy import int16 sage: sum_of_k_squares(int16(2), int16(9634)) (15, 97) - sage: from gmpy2 import mpz # optional - gmpy2 - sage: sum_of_k_squares(mpz(2), mpz(9634)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: sum_of_k_squares(mpz(2), mpz(9634)) (15, 97) """ n = ZZ(n) @@ -5419,8 +5422,8 @@ def subfactorial(n): sage: from numpy import int8 sage: subfactorial(int8(8)) 14833 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: subfactorial(mpz(8)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: subfactorial(mpz(8)) 14833 AUTHORS: @@ -5464,10 +5467,10 @@ def is_power_of_two(n): True sage: is_power_of_two(int8(24)) False - sage: from gmpy2 import mpz # optional - gmpy2 - sage: is_power_of_two(mpz(16)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: is_power_of_two(mpz(16)) True - sage: is_power_of_two(mpz(24)) # optional - gmpy2 + sage: is_power_of_two(mpz(24)) False """ return ZZ(n).popcount() == 1 @@ -5495,8 +5498,8 @@ def differences(lis, n=1): sage: from numpy import int8 sage: differences([int8(1),int8(4),int8(6),int8(19)]) [3, 2, 13] - sage: from gmpy2 import mpz # optional - gmpy2 - sage: differences([mpz(1),mpz(4),mpz(6),mpz(19)]) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: differences([mpz(1),mpz(4),mpz(6),mpz(19)]) [mpz(3), mpz(2), mpz(13)] AUTHORS: @@ -5622,8 +5625,8 @@ def fundamental_discriminant(D): sage: from numpy import int8 sage: fundamental_discriminant(int8(102)) 408 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: fundamental_discriminant(mpz(102)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: fundamental_discriminant(mpz(102)) 408 """ D = ZZ(D) @@ -5634,16 +5637,22 @@ def fundamental_discriminant(D): def squarefree_divisors(x): """ - Iterator over the squarefree divisors (up to units) of the element x. + Return an iterator over the squarefree divisors (up to units) + of this ring element. Depends on the output of the prime_divisors function. + Squarefree divisors of an integer are not necessarily + yielded in increasing order. + INPUT: - x -- an element of any ring for which the prime_divisors function works. - EXAMPLES:: + EXAMPLES: + + Integers with few prime divisors:: sage: list(squarefree_divisors(7)) [1, 7] @@ -5652,6 +5661,11 @@ def squarefree_divisors(x): sage: list(squarefree_divisors(12)) [1, 2, 3, 6] + Squarefree divisors are not yielded in increasing order:: + + sage: list(squarefree_divisors(30)) + [1, 2, 3, 6, 5, 10, 15, 30] + TESTS: Check that the first divisor (i.e. `1`) is a Sage integer (see @@ -5668,8 +5682,8 @@ def squarefree_divisors(x): sage: from numpy import int8 sage: list(squarefree_divisors(int8(12))) [1, 2, 3, 6] - sage: from gmpy2 import mpz # optional - gmpy2 - sage: list(squarefree_divisors(mpz(12))) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: list(squarefree_divisors(mpz(12))) [1, 2, 3, 6] """ for a in powerset(prime_divisors(x)): @@ -5766,8 +5780,8 @@ def dedekind_sum(p, q, algorithm='default'): sage: from numpy import int8 sage: dedekind_sum(int8(5), int8(7), algorithm='default') -1/14 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: dedekind_sum(mpz(5), mpz(7), algorithm='default') # optional - gmpy2 + sage: from gmpy2 import mpz + sage: dedekind_sum(mpz(5), mpz(7), algorithm='default') -1/14 REFERENCES: diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index ce5cc576aa0..dbb5076884c 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1249,6 +1249,15 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): sage: lim(sin(1/x), x = 0) ind + We can use other packages than maxima:: + + sage: (x / (x+2^x+cos(x))).limit(x=-infinity, algorithm='fricas') # optional - fricas + 1 + sage: limit(e^(-1/x), x=0, dir='right', algorithm='fricas') # optional - fricas + 0 + sage: limit(e^(-1/x), x=0, dir='left', algorithm='fricas') # optional - fricas + +Infinity + TESTS:: sage: lim(x^2, x=2, dir='nugget') @@ -1257,6 +1266,11 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): ValueError: dir must be one of None, 'plus', '+', 'above', 'right', 'minus', '-', 'below', 'left' + sage: x.limit(x=3, algorithm='nugget') + Traceback (most recent call last): + ... + ValueError: Unknown algorithm: nugget + We check that :trac:`3718` is fixed, so that Maxima gives correct limits for the floor function:: @@ -1312,6 +1326,23 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): sage: (1/(x-3)).limit(x=3, dir='below') -Infinity + + From :trac:`14677`:: + + sage: f = (x^x-sin(x)^sin(x))/(x^3*log(x)) + sage: limit(f, x=0, algorithm='fricas') # optional - fricas + und + + sage: limit(f, x=0, dir='right', algorithm='fricas') # optional - fricas + 1/6 + + From :trac:`26497`:: + + sage: mu, y, sigma = var("mu, y, sigma") + sage: f = 1/2*sqrt(2)*e^(-1/2*(mu - log(y))^2/sigma^2)/(sqrt(pi)*sigma*y) + sage: limit(f, y=0, algorithm='fricas') # optional - fricas + 0 + """ if not isinstance(ex, Expression): ex = SR(ex) @@ -1326,23 +1357,25 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): if taylor and algorithm == 'maxima': algorithm = 'maxima_taylor' - if dir not in [None, 'plus', '+', 'right', 'minus', '-', 'left', - 'above', 'below']: - raise ValueError("dir must be one of None, 'plus', '+', 'above', 'right', 'minus', '-', 'below', 'left'") + dir_plus = ['plus', '+', 'above', 'right'] + dir_minus = ['minus', '-', 'below', 'left'] + dir_both = [None] + dir_plus + dir_minus + if dir not in dir_both: + raise ValueError("dir must be one of " + ", ".join(map(repr, dir_both))) if algorithm == 'maxima': if dir is None: l = maxima.sr_limit(ex, v, a) - elif dir in ['plus', '+', 'right', 'above']: + elif dir in dir_plus: l = maxima.sr_limit(ex, v, a, 'plus') - elif dir in ['minus', '-', 'left', 'below']: + elif dir in dir_minus: l = maxima.sr_limit(ex, v, a, 'minus') elif algorithm == 'maxima_taylor': if dir is None: l = maxima.sr_tlimit(ex, v, a) - elif dir in ['plus', '+', 'right', 'above']: + elif dir in dir_plus: l = maxima.sr_tlimit(ex, v, a, 'plus') - elif dir in ['minus', '-', 'left', 'below']: + elif dir in dir_minus: l = maxima.sr_tlimit(ex, v, a, 'minus') elif algorithm == 'sympy': if dir is None: @@ -1350,6 +1383,20 @@ def limit(ex, dir=None, taylor=False, algorithm='maxima', **argv): l = sympy.limit(ex._sympy_(), v._sympy_(), a._sympy_()) else: raise NotImplementedError("sympy does not support one-sided limits") + elif algorithm == 'fricas': + from sage.interfaces.fricas import fricas + eq = fricas.equation(v._fricas_(), a._fricas_()) + f = ex._fricas_() + if dir is None: + l = fricas.limit(f, eq).sage() + if isinstance(l, dict): + l = maxima("und") + elif dir in dir_plus: + l = fricas.limit(f, eq, '"right"').sage() + elif dir in dir_minus: + l = fricas.limit(f, eq, '"left"').sage() + else: + raise ValueError("Unknown algorithm: %s" % algorithm) #return l.sage() return ex.parent()(l) diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 174fc40257f..6ffaa5428c1 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -346,13 +346,13 @@ class ode_solver(object): self.params = params self.solution = [] - def __setattr__(self,name,value): - if(hasattr(self,'solution')): - object.__setattr__(self,'solution',[]) - object.__setattr__(self,name,value) + def __setattr__(self, name, value): + if hasattr(self, 'solution'): + object.__setattr__(self, 'solution', []) + object.__setattr__(self, name, value) - def interpolate_solution(self,i=0): - pts = [(t,y[i]) for t,y in self.solution] + def interpolate_solution(self, i=0): + pts = [(t, y[i]) for t, y in self.solution] return sage.calculus.interpolation.spline(pts) def plot_solution(self, i=0, filename=None, interpolate=False, **kwds): diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index aeac544a5ba..d58ef0ce311 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -339,7 +339,7 @@ class inheritance from ``C.parent_class``. ....: Parent.__init__(self, category=Ds()) ....: def g(self): ....: return "myparent" - ....: class Element: + ....: class Element(object): ....: pass sage: D = myparent() sage: D.__class__ @@ -1721,13 +1721,12 @@ def element_class(self): sage: Algebras(ZZ['t']).element_class is Algebras(ZZ['t','x']).element_class True - These classes are constructed with ``__slots__ = []``, so they - behave like extension types:: + These classes are constructed with ``__slots__ = ()``, so + instances may not have a ``__dict__``:: sage: E = FiniteEnumeratedSets().element_class - sage: from sage.structure.misc import is_extension_type - sage: is_extension_type(E) - True + sage: E.__dictoffset__ + 0 .. SEEALSO:: :meth:`parent_class` """ @@ -2784,7 +2783,7 @@ def _make_named_class(self, name, method_provider, cache = False, **options): and Category of quotient fields and Category of metric spaces sage: RR.category() - Join of Category of fields and Category of complete metric spaces + Join of Category of fields and Category of infinite sets and Category of complete metric spaces sage: Modules(QQ).parent_class is Modules(RR).parent_class False diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index 6c52d0300df..ed1c7d5cce8 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -15,11 +15,12 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.latex import latex from sage.misc.unknown import Unknown from .category import JoinCategory, Category, CategoryWithParameters from sage.misc.lazy_import import lazy_import lazy_import('sage.categories.objects', 'Objects') +lazy_import('sage.misc.latex', 'latex') + #################################################################### # Different types of categories diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 7fce1513037..28a74890900 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -2189,7 +2189,7 @@ def additional_structure(self): .. SEEALSO:: :meth:`Category.additional_structure`. - EXAMPLES: + EXAMPLES:: sage: Sets().Finite().additional_structure() sage: Monoids().additional_structure() diff --git a/src/sage/categories/covariant_functorial_construction.py b/src/sage/categories/covariant_functorial_construction.py index ff195d2266a..0e4da5929f9 100644 --- a/src/sage/categories/covariant_functorial_construction.py +++ b/src/sage/categories/covariant_functorial_construction.py @@ -629,7 +629,7 @@ def additional_structure(self): - :meth:`Category.additional_structure`. - :meth:`is_construction_defined_by_base`. - EXAMPLES: + EXAMPLES:: sage: Modules(ZZ).Graded().additional_structure() Category of graded modules over Integer Ring diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index ded9d58d2df..e23587a2767 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -16,7 +16,7 @@ from sage.misc.cachefunc import cached_method, cached_in_parent_method from sage.misc.lazy_import import LazyImport from sage.misc.constant_function import ConstantFunction -from sage.misc.misc import attrcall, uniq +from sage.misc.misc import attrcall from sage.categories.category_singleton import Category_singleton from sage.categories.enumerated_sets import EnumeratedSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -1926,14 +1926,15 @@ def bruhat_upper_covers(self): sage: set(S) == set(C) True """ - Covers = [] + Covers = set() for i in self.parent().index_set(): if i in self.descents(side='right'): - Covers += [ x.apply_simple_reflection(i, side='right') for x in self.apply_simple_reflection(i,side='right').bruhat_upper_covers() - if i not in x.descents(side='right') ] + Covers.update(x.apply_simple_reflection(i, side='right') + for x in self.apply_simple_reflection(i,side='right').bruhat_upper_covers() + if i not in x.descents(side='right')) else: - Covers += [ self.apply_simple_reflection(i,side='right') ] - return uniq(Covers) + Covers.add(self.apply_simple_reflection(i,side='right')) + return sorted(Covers) @cached_in_parent_method def bruhat_lower_covers_reflections(self): @@ -1994,17 +1995,16 @@ def bruhat_upper_covers_reflections(self): sage: w = W.from_reduced_word([3,1,2,1]) sage: w.bruhat_upper_covers_reflections() [(s1*s2*s3*s2*s1, s3), (s2*s3*s1*s2*s1, s2*s3*s2), (s3*s4*s1*s2*s1, s4), (s4*s3*s1*s2*s1, s1*s2*s3*s4*s3*s2*s1)] - """ - - Covers = [] + Covers = set() for i in self.parent().index_set(): wi = self.apply_simple_reflection(i) if i in self.descents(): - Covers += [(u.apply_simple_reflection(i), r.apply_conjugation_by_simple_reflection(i)) for u, r in wi.bruhat_upper_covers_reflections() if i not in u.descents()] + Covers.update((u.apply_simple_reflection(i), r.apply_conjugation_by_simple_reflection(i)) + for u, r in wi.bruhat_upper_covers_reflections() if i not in u.descents()) else: - Covers += [(wi, self.parent().simple_reflection(i))] - return uniq(Covers) + Covers.add((wi, self.parent().simple_reflection(i))) + return sorted(Covers) def cover_reflections(self, side='right'): r""" diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 6a8b8d90c1c..8d63153f1cd 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -248,6 +248,7 @@ def an_element(self): """ return self.first() + @cached_method def weight_lattice_realization(self): """ Return the weight lattice realization used to express weights diff --git a/src/sage/categories/division_rings.py b/src/sage/categories/division_rings.py index d1fd34ea057..cd26f46acae 100644 --- a/src/sage/categories/division_rings.py +++ b/src/sage/categories/division_rings.py @@ -50,7 +50,7 @@ def extra_super_categories(self): The :ref:`axioms-deduction-rules` section in the documentation of axioms - EXAMPLES: + EXAMPLES:: sage: DivisionRings().extra_super_categories() (Category of domains,) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 4ab498bd0d3..dc59403082f 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -12,13 +12,13 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import LazyImport from sage.categories.category_with_axiom import CategoryWithAxiom -from sage.categories.category_singleton import Category_singleton from sage.categories.sets_cat import Sets from sage.categories.sets_cat import EmptySetError from sage.categories.cartesian_product import CartesianProductsCategory from sage.misc.lazy_import import lazy_import lazy_import("sage.rings.integer", "Integer") + class EnumeratedSets(CategoryWithAxiom): """ The category of enumerated sets @@ -553,7 +553,7 @@ def _list_from_iterator(self): sage: Q.is_finite() Traceback (most recent call last): ... - AttributeError: 'super' object has no attribute 'is_finite' + AttributeError: 'QuotientRing_generic_with_category' object has no attribute 'is_finite' sage: Q.list() # indirect test Traceback (most recent call last): ... diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py index 32adbf03890..1b36fbf15b5 100644 --- a/src/sage/categories/fields.py +++ b/src/sage/categories/fields.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Fields """ @@ -768,3 +769,35 @@ def factor(self): raise ArithmeticError("factorization of {!r} is not defined".format(self)) from sage.structure.factorization import Factorization return Factorization([], self) # No factor; "self" as unit + + def inverse_of_unit(self): + r""" + Return the inverse of this element. + + EXAMPLES:: + + sage: NumberField(x^7+2,'a')(2).inverse_of_unit() + 1/2 + + Trying to invert the zero element typically raises a + ``ZeroDivisionError``:: + + sage: QQ(0).inverse_of_unit() + Traceback (most recent call last): + ... + ZeroDivisionError: rational division by zero + + To catch that exception in a way that also works for non-units + in more general rings, use something like:: + + sage: try: + ....: QQ(0).inverse_of_unit() + ....: except ArithmeticError: + ....: pass + + Also note that some “fields” allow one to invert the zero element:: + + sage: RR(0).inverse_of_unit() + +infinity + """ + return ~self diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 349df9ab554..a4b6cbe036e 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -789,7 +789,7 @@ def maximal_degree(self): .. SEEALSO:: :meth:`homogeneous_degree` - EXAMPLES: + EXAMPLES:: sage: A = ModulesWithBasis(ZZ).Filtered().example() sage: x = A(Partition((3,2,1))) diff --git a/src/sage/categories/finite_complex_reflection_groups.py b/src/sage/categories/finite_complex_reflection_groups.py index 2b56b1ddd33..4e7644f8562 100644 --- a/src/sage/categories/finite_complex_reflection_groups.py +++ b/src/sage/categories/finite_complex_reflection_groups.py @@ -191,7 +191,7 @@ def _test_degrees(self, **options): - ``options`` -- any keyword arguments accepted by :meth:`_tester` - EXAMPLES: + EXAMPLES:: sage: from sage.categories.complex_reflection_groups import ComplexReflectionGroups sage: W = ComplexReflectionGroups().Finite().example(); W # optional - gap3 @@ -246,7 +246,7 @@ def _test_codegrees(self, **options): - ``options`` -- any keyword arguments accepted by :meth:`_tester` - EXAMPLES: + EXAMPLES:: sage: from sage.categories.complex_reflection_groups import ComplexReflectionGroups sage: W = ComplexReflectionGroups().Finite().example(); W # optional - gap3 @@ -872,7 +872,7 @@ def generalized_noncrossing_partitions(self, m, c=None, positive=False): chains = NC.chains() NCm = set() iter = chains.breadth_first_search_iterator() - chain = next(iter) + next(iter) chain = next(iter) while len(chain) <= m: chain.append(c) diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index ff38fc9f2ce..da7ef8fbd31 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -121,17 +121,13 @@ def is_self_dual(self): # Two quick checks before full isomorphic test. if sorted(self._hasse_diagram.in_degree()) != sorted(self._hasse_diagram.out_degree()): return False - levels_orig=[len(x) for x in self._hasse_diagram.level_sets()] - dual_poset_hasse=self._hasse_diagram.reverse() - levels_dual=[len(x) for x in dual_poset_hasse.level_sets()] + levels_orig = [len(x) for x in self._hasse_diagram.level_sets()] + dual_poset_hasse = self._hasse_diagram.reverse() + levels_dual = [len(x) for x in dual_poset_hasse.level_sets()] if levels_orig != levels_dual: return False return self._hasse_diagram.is_isomorphic(dual_poset_hasse) - from sage.misc.superseded import deprecated_function_alias - is_selfdual = deprecated_function_alias(24048, is_self_dual) - - ########################################################################## # Properties of morphisms @@ -300,21 +296,25 @@ def order_ideal_generators(self, ideal, direction='down'): ordered by inclusion, and compute an order ideal there:: sage: P = Poset((Subsets([1,2,3]), attrcall("issubset"))) - sage: I = P.order_ideal([Set([1,2]), Set([2,3]), Set([1])]); I - [{}, {3}, {2}, {2, 3}, {1}, {1, 2}] + sage: I = P.order_ideal([Set([1,2]), Set([2,3]), Set([1])]) + sage: sorted(sorted(p) for p in I) + [[], [1], [1, 2], [2], [2, 3], [3]] Then, we retrieve the generators of this ideal:: - sage: P.order_ideal_generators(I) - {{1, 2}, {2, 3}} + sage: gen = P.order_ideal_generators(I) + sage: sorted(sorted(p) for p in gen) + [[1, 2], [2, 3]] If ``direction`` is 'up', then this instead computes the minimal generators for an order filter:: - sage: I = P.order_filter([Set([1,2]), Set([2,3]), Set([1])]); I - [{2, 3}, {1}, {1, 2}, {1, 3}, {1, 2, 3}] - sage: P.order_ideal_generators(I, direction='up') - {{2, 3}, {1}} + sage: I = P.order_filter([Set([1,2]), Set([2,3]), Set([1])]) + sage: sorted(sorted(p) for p in I) + [[1], [1, 2], [1, 2, 3], [1, 3], [2, 3]] + sage: gen = P.order_ideal_generators(I, direction='up') + sage: sorted(sorted(p) for p in gen) + [[1], [2, 3]] Complexity: `O(n+m)` where `n` is the cardinality of `I`, and `m` the number of upper covers of elements of `I`. @@ -339,10 +339,12 @@ def order_filter_generators(self, filter): EXAMPLES:: sage: P = Poset((Subsets([1,2,3]), attrcall("issubset"))) - sage: I = P.order_filter([Set([1,2]), Set([2,3]), Set([1])]); I - [{2, 3}, {1}, {1, 2}, {1, 3}, {1, 2, 3}] - sage: P.order_filter_generators(I) - {{2, 3}, {1}} + sage: I = P.order_filter([Set([1,2]), Set([2,3]), Set([1])]) + sage: sorted(sorted(p) for p in I) + [[1], [1, 2], [1, 2, 3], [1, 3], [2, 3]] + sage: gen = P.order_filter_generators(I) + sage: sorted(sorted(p) for p in gen) + [[1], [2, 3]] .. SEEALSO:: :meth:`order_ideal_generators` """ @@ -1342,15 +1344,19 @@ def panyushev_orbits(self, element_constructor = set): EXAMPLES:: sage: P = Poset( ( [1,2,3], [ [1,3], [2,3] ] ) ) - sage: P.panyushev_orbits() - [[{2}, {1}], [set(), {1, 2}, {3}]] - sage: P.panyushev_orbits(element_constructor=list) - [[[2], [1]], [[], [1, 2], [3]]] - sage: P.panyushev_orbits(element_constructor=frozenset) - [[frozenset({2}), frozenset({1})], - [frozenset(), frozenset({1, 2}), frozenset({3})]] - sage: P.panyushev_orbits(element_constructor=tuple) - [[(2,), (1,)], [(), (1, 2), (3,)]] + sage: orb = P.panyushev_orbits() + sage: sorted(sorted(o) for o in orb) + [[set(), {1, 2}, {3}], [{2}, {1}]] + sage: orb = P.panyushev_orbits(element_constructor=list) + sage: sorted(sorted(o) for o in orb) + [[[], [1, 2], [3]], [[1], [2]]] + sage: orb = P.panyushev_orbits(element_constructor=frozenset) + sage: sorted(sorted(o) for o in orb) + [[frozenset(), frozenset({1, 2}), frozenset({3})], + [frozenset({2}), frozenset({1})]] + sage: orb = P.panyushev_orbits(element_constructor=tuple) + sage: sorted(sorted(o) for o in orb) + [[(), (1, 2), (3,)], [(1,), (2,)]] sage: P = Poset( {} ) sage: P.panyushev_orbits() [[set()]] @@ -1399,12 +1405,14 @@ def rowmotion_orbits(self, element_constructor = set): sage: P = Poset( {1: [2, 3], 2: [], 3: [], 4: [2]} ) sage: sorted(len(o) for o in P.rowmotion_orbits()) [3, 5] - sage: sorted(P.rowmotion_orbits(element_constructor=list)) - [[[1, 3], [4], [1], [4, 1, 3], [4, 1, 2]], [[4, 1], [4, 1, 2, 3], []]] - sage: sorted(P.rowmotion_orbits(element_constructor=tuple)) - [[(1, 3), (4,), (1,), (4, 1, 3), (4, 1, 2)], [(4, 1), (4, 1, 2, 3), ()]] + sage: orb = P.rowmotion_orbits(element_constructor=list) + sage: sorted(sorted(e) for e in orb) + [[[], [4, 1], [4, 1, 2, 3]], [[1], [1, 3], [4], [4, 1, 2], [4, 1, 3]]] + sage: orb = P.rowmotion_orbits(element_constructor=tuple) + sage: sorted(sorted(e) for e in orb) + [[(), (4, 1), (4, 1, 2, 3)], [(1,), (1, 3), (4,), (4, 1, 2), (4, 1, 3)]] sage: P = Poset({}) - sage: sorted(P.rowmotion_orbits(element_constructor=tuple)) + sage: P.rowmotion_orbits(element_constructor=tuple) [[()]] """ pan_orbits = self.panyushev_orbits(element_constructor = list) @@ -1852,24 +1860,24 @@ def order_ideals_lattice(self, as_ideals=True, facade=None): [[0, 1], [0, 2], [1, 4], [2, 3], [3, 4]] sage: J = P.order_ideals_lattice(); J Finite lattice containing 8 elements - sage: list(J) - [{}, {0}, {0, 2}, {0, 2, 3}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}, {0, 1, 2, 3, 4}] + sage: sorted(sorted(e) for e in J) + [[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4], [0, 2], [0, 2, 3]] As a lattice on antichains:: sage: J2 = P.order_ideals_lattice(False); J2 Finite lattice containing 8 elements - sage: list(J2) - [(0,), (1, 2), (1, 3), (1,), (2,), (3,), (4,), ()] + sage: sorted(J2) + [(), (0,), (1,), (1, 2), (1, 3), (2,), (3,), (4,)] TESTS:: sage: J = posets.DiamondPoset(4, facade = True).order_ideals_lattice(); J Finite lattice containing 6 elements - sage: list(J) - [{}, {0}, {0, 2}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}] - sage: J.cover_relations() - [[{}, {0}], [{0}, {0, 2}], [{0}, {0, 1}], [{0, 2}, {0, 1, 2}], [{0, 1}, {0, 1, 2}], [{0, 1, 2}, {0, 1, 2, 3}]] + sage: sorted(sorted(e) for e in J) + [[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 2]] + sage: sorted(sorted(sorted(e) for e in c) for c in J.cover_relations()) + [[[], [0]], [[0], [0, 1]], [[0], [0, 2]], [[0, 1], [0, 1, 2]], [[0, 1, 2], [0, 1, 2, 3]], [[0, 1, 2], [0, 2]]] sage: P = Poset({1:[2]}) sage: J_facade = P.order_ideals_lattice() diff --git a/src/sage/categories/functor.pyx b/src/sage/categories/functor.pyx index cf6314e47e5..91fe24f29e4 100644 --- a/src/sage/categories/functor.pyx +++ b/src/sage/categories/functor.pyx @@ -17,7 +17,7 @@ AUTHORS: """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 David Kohel and # William Stein # @@ -30,8 +30,8 @@ AUTHORS: # See the GNU General Public License for more details; the full text # is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import from . import category @@ -382,7 +382,7 @@ cdef class Functor(SageObject): if is_Morphism(x): return self._apply_functor_to_morphism(x) y = self._apply_functor(self._coerce_into_domain(x)) - if not ((y in self.__codomain) or (y in self.__codomain.hom_category())): + if not ((y in self.__codomain) or (y in self.__codomain.Homsets())): raise TypeError("%s is ill-defined, since it sends x (=%s) to something that is not in %s." % (repr(self), x, self.__codomain)) return y @@ -524,7 +524,7 @@ class ForgetfulFunctor_generic(Functor): """ Return whether ``self`` is not equal to ``other``. - EXAMPLES: + EXAMPLES:: sage: F1 = ForgetfulFunctor(FiniteFields(),Fields()) sage: F1 != F1 diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 2d2a82658bc..af2813dc834 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -280,7 +280,6 @@ def bracket(self, lhs, rhs): sage: L.bracket(L, q+p) Ideal (p1 + q1) of Heisenberg algebra of rank 1 over Rational Field """ - from sage.categories.lie_algebras import LieAlgebras if lhs in LieAlgebras: if rhs in LieAlgebras: return lhs.product_space(rhs) diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index b3cd846b076..ed71a2c1e9d 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -347,7 +347,7 @@ class Algebras(AlgebrasCategory): def extra_super_categories(self): """ - EXAMPLES: + EXAMPLES:: sage: Magmas().Commutative().Algebras(QQ).extra_super_categories() [Category of commutative magmas] @@ -407,7 +407,7 @@ class Algebras(AlgebrasCategory): def extra_super_categories(self): """ - EXAMPLES: + EXAMPLES:: sage: Magmas().Commutative().Algebras(QQ).extra_super_categories() [Category of commutative magmas] @@ -722,7 +722,7 @@ class Algebras(AlgebrasCategory): def extra_super_categories(self): """ - EXAMPLES: + EXAMPLES:: sage: Magmas().Commutative().Algebras(QQ).extra_super_categories() [Category of commutative magmas] diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index a9790dcff4b..0c472e8c24c 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -27,7 +27,6 @@ from sage.ext.stdsage cimport HAS_DICTIONARY from sage.arith.power cimport generic_power from sage.sets.pythonclass cimport Set_PythonType from sage.misc.constant_function import ConstantFunction -from sage.misc.superseded import deprecated_function_alias from sage.structure.element cimport parent from cpython.object cimport PyObject_RichCompare @@ -1825,11 +1824,10 @@ cdef class FormalCompositeMap(Map): sage: (f*g).then() == f True """ - if len(self.__list) == 2: return self.__list[1] + if len(self.__list) == 2: + return self.__list[1] return FormalCompositeMap(self.__list[1:]) - second = deprecated_function_alias(16291, then) - def is_injective(self): """ Tell whether ``self`` is injective. diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 1cbc8ada1fd..3455c70422e 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1276,27 +1276,17 @@ def __getitem__(self, m): EXAMPLES:: - sage: p = Partition([2,1]) - sage: q = Partition([1,1,1]) - sage: s = SymmetricFunctions(QQ).schur() - sage: a = s(p) - sage: a._coefficient_fast([2,1]) - Traceback (most recent call last): - ... - TypeError: unhashable type: 'list' - - :: - - sage: a._coefficient_fast(p) - 1 - sage: a._coefficient_fast(q) + sage: W. = DifferentialWeylAlgebra(QQ) + sage: x[((0,0,0),(0,0,0))] 0 - sage: a[p] + sage: x[((1,0,0),(0,0,0))] 1 - sage: a[q] - 0 """ - return self.monomial_coefficients(copy=False).get(m, self.base_ring().zero()) + res = self.monomial_coefficients(copy=False).get(m) + if res is None: + return self.base_ring().zero() + else: + return res def coefficient(self, m): """ diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index 6219ba6953f..92119863418 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -509,17 +509,18 @@ def is_central(self): EXAMPLES:: - sage: SG4=SymmetricGroupAlgebra(ZZ,4) + sage: SG4 = SymmetricGroupAlgebra(ZZ,4) sage: SG4(1).is_central() True sage: SG4(Permutation([1,3,2,4])).is_central() False - sage: A=GroupAlgebras(QQ).example(); A + sage: A = GroupAlgebras(QQ).example(); A Algebra of Dihedral group of order 8 as a permutation group over Rational Field sage: sum(i for i in A.basis()).is_central() True """ - return all([i*self == self*i for i in self.parent().algebra_generators()]) + return all(i * self == self * i + for i in self.parent().algebra_generators()) class CartesianProducts(CartesianProductsCategory): """ diff --git a/src/sage/categories/objects.py b/src/sage/categories/objects.py index a6552505670..0b72e0f5d6f 100644 --- a/src/sage/categories/objects.py +++ b/src/sage/categories/objects.py @@ -8,11 +8,10 @@ # 2008-2013 Nicolas M. Thiery # # 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.misc.superseded import deprecated_function_alias from sage.categories.category_singleton import Category_singleton from sage.categories.homsets import HomsetsCategory @@ -91,13 +90,6 @@ def Homsets(self): sage: Rings().Homsets() Category of homsets of unital magmas and additive unital additive magmas - This used to be called ``hom_category``:: - - sage: Sets().hom_category() - doctest:...: DeprecationWarning: hom_category is deprecated. Please use Homsets instead. - See http://trac.sagemath.org/10668 for details. - Category of homsets of sets - .. NOTE:: Background Information, code, documentation, and tests about the @@ -148,8 +140,6 @@ def Homsets(self): """ return HomsetsCategory.category_of(self) - hom_category = deprecated_function_alias(10668, Homsets) - @cached_method def Endsets(self): r""" diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 023439eaca0..8475ab36c18 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -2563,7 +2563,7 @@ def merge(self, other): sage: Rlist = [R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11] sage: from sage.categories.pushout import pushout sage: pushouts = [R0,R0,R0,R1,R0,R1,R0,R1,R0,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R1,R0,R1,R2,R2,R2,R3,R0,R1,R2,R3,R3,R3,R1,R1,R3,R3,R3,R3,R1,R1,R3,R3,R3,R3,R0,R1,R2,R3,R4,R4,R0,R1,R2,R3,R3,R5,R1,R1,R3,R3,R5,R5,R1,R1,R3,R3,R3,R5,R0,R1,R0,R1,R0,R1,R6,R6,R6,R7,R7,R7,R1,R1,R1,R1,R1,R1,R7,R7,R7,R7,R7,R7,R0,R1,R2,R3,R2,R3,R6,R7,R8,R9,R10,R9,R1,R1,R3,R3,R3,R3,R7,R7,R9,R9,R10,R9,R1,R1,R3,R3,R3,R3,R7,R7,R10,R10,R10,R10,R1,R1,R3,R3,R5,R5,R7,R7,R9,R9,R10,R11] - sage: all([R is S for R, S in zip(pushouts, [pushout(a, b) for a in Rlist for b in Rlist])]) + sage: all(R is S for R, S in zip(pushouts, [pushout(a, b) for a in Rlist for b in Rlist])) True :: @@ -2579,7 +2579,7 @@ def merge(self, other): sage: Plist = [P2,P3,P4,P5,P6,P7] sage: from sage.categories.pushout import pushout sage: pushouts = [P2,P3,P4,P5,P6,P7,P3,P3,P5,P5,P7,P7,P4,P5,P4,P5,P6,P7,P5,P5,P5,P5,P7,P7,P6,P7,P6,P7,P6,P7,P7,P7,P7,P7,P7,P7] - sage: all([P is Q for P, Q in zip(pushouts, [pushout(a, b) for a in Plist for b in Plist])]) + sage: all(P is Q for P, Q in zip(pushouts, [pushout(a, b) for a in Plist for b in Plist])) True """ if self == other: # both are Completion functors with the same p diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 459bf9a882b..aef4dba5e73 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1,15 +1,15 @@ r""" Sets """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008 Teresa Gomez-Diaz (CNRS) # 2008-2014 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from __future__ import print_function, absolute_import from six.moves import range @@ -19,11 +19,9 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import lazy_import, LazyImport from sage.misc.lazy_format import LazyFormat -from sage.misc.superseded import deprecated_function_alias from sage.categories.category import Category from sage.categories.category_singleton import Category_singleton # Do not use sage.categories.all here to avoid initialization loop -from sage.categories.morphism import SetMorphism from sage.categories.sets_with_partial_maps import SetsWithPartialMaps from sage.categories.subquotients import SubquotientsCategory from sage.categories.quotients import QuotientsCategory @@ -36,6 +34,7 @@ from sage.categories.category_with_axiom import CategoryWithAxiom lazy_import('sage.sets.cartesian_product', 'CartesianProduct') + def print_compare(x, y): """ Helper method used in @@ -58,9 +57,10 @@ def print_compare(x, y): """ if x == y: - return LazyFormat("%s == %s")%(x, y) + return LazyFormat("%s == %s") % (x, y) else: - return LazyFormat("%s != %s")%(x, y) + return LazyFormat("%s != %s") % (x, y) + class EmptySetError(ValueError): """ @@ -80,6 +80,7 @@ class EmptySetError(ValueError): """ pass + class Sets(Category_singleton): r""" The category of sets. @@ -249,7 +250,7 @@ def _call_(self, X, enumerated_set=False): def example(self, choice = None): """ - Returns examples of objects of ``Sets()``, as per + Return examples of objects of ``Sets()``, as per :meth:`Category.example() `. @@ -938,8 +939,6 @@ def Facade(self): """ return self._with_axiom('Facade') - Facades = deprecated_function_alias(17073, Facade) - class ParentMethods: # TODO: simplify the _element_constructor_ definition logic # TODO: find a nicer mantra for conditionally defined methods @@ -1102,12 +1101,10 @@ def _test_an_element(self, **options): rebuilt_element = self(an_element) except NotImplementedError: tester.info("\n The set doesn't seems to implement __call__; skipping test of construction idempotency") - pass else: tester.assertEqual(rebuilt_element, an_element, "element construction is not idempotent") - - def _test_elements(self, tester = None, **options): + def _test_elements(self, tester=None, **options): """ Run generic tests on element(s) of ``self``. @@ -1234,11 +1231,10 @@ def _test_elements_eq_symmetric(self, **options): """ tester = self._tester(**options) S = list(tester.some_elements()) + [None, 0] - n = tester._max_runs from sage.misc.misc import some_tuples - for x,y in some_tuples(S, 2, tester._max_runs): + for x, y in some_tuples(S, 2, tester._max_runs): tester.assertEqual(x==y, y==x, - LazyFormat("non symmetric equality: %s but %s")%( + LazyFormat("non symmetric equality: %s but %s") % ( print_compare(x, y), print_compare(y, x))) def _test_elements_eq_transitive(self, **options): @@ -1458,6 +1454,7 @@ def construction(self): return None CartesianProduct = CartesianProduct + def cartesian_product(*parents, **kwargs): """ Return the Cartesian product of the parents. @@ -2408,8 +2405,6 @@ def cartesian_projection(self, i): """ return self.parent().cartesian_projection(i)(self) - summand_projection = deprecated_function_alias(10963, cartesian_projection) - def cartesian_factors(self): """ Return the Cartesian factors of ``self``. @@ -2435,8 +2430,6 @@ def cartesian_factors(self): for i in self.parent()._sets_keys()) #return Family(self._sets.keys(), self.projection) - summand_split = deprecated_function_alias(10963, cartesian_factors) - class Algebras(AlgebrasCategory): def extra_super_categories(self): @@ -2647,7 +2640,7 @@ def inject_shorthands(self, shorthands=None, verbose=True): Defining e as shorthand for Symmetric Functions over Integer Ring in the elementary basis Defining f as shorthand for Symmetric Functions over Integer Ring in the forgotten basis Defining h as shorthand for Symmetric Functions over Integer Ring in the homogeneous basis - Defining ht as shorthand for Symmetric Functions over Integer Ring in the induced trivial character basis + Defining ht as shorthand for Symmetric Functions over Integer Ring in the induced trivial symmetric group character basis Defining m as shorthand for Symmetric Functions over Integer Ring in the monomial basis Defining o as shorthand for Symmetric Functions over Integer Ring in the orthogonal basis Defining p as shorthand for Symmetric Functions over Integer Ring in the powersum basis diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 642f8950ed6..ede70b82377 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -1982,7 +1982,8 @@ cdef class PartitionStack: # Returns an integer whose bits represent which columns are minimal cell # representatives. # -# EXAMPLES: +# EXAMPLES:: +# # sage: import sage.coding.binary_code # sage: from sage.coding.binary_code import * # sage: P = PartitionStack(2, 6) @@ -2041,7 +2042,8 @@ cdef class PartitionStack: # Returns an integer whose bits represent which columns are fixed. For # efficiency, mcrs is the output of min_cell_reps. # -# EXAMPLES: +# EXAMPLES:: +# # sage: import sage.coding.binary_code # sage: from sage.coding.binary_code import * # sage: P = PartitionStack(2, 6) @@ -2100,7 +2102,8 @@ cdef class PartitionStack: # """ # Returns an integer representing the first, smallest nontrivial cell of columns. # -# EXAMPLES: +# EXAMPLES:: +# # sage: import sage.coding.binary_code # sage: from sage.coding.binary_code import * # sage: P = PartitionStack(2, 6) @@ -2309,7 +2312,8 @@ cdef class PartitionStack: # Split column v out, placing it before the rest of the cell it was in. # Returns the location of the split column. # -# EXAMPLES: +# EXAMPLES:: +# # sage: import sage.coding.binary_code # sage: from sage.coding.binary_code import * # sage: P = PartitionStack(2, 6) diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index e24a245a064..185ffbce00c 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -105,8 +105,8 @@ def _is_a_splitting(S1, S2, n, return_automorphism=False): ....: res,aut= _is_a_splitting(P[0],P[1],7,return_automorphism=True) ....: if res: ....: print((aut, P)) - (6, {{1, 2, 3}, {4, 5, 6}}) (3, {{1, 2, 4}, {3, 5, 6}}) + (6, {{1, 2, 3}, {4, 5, 6}}) (6, {{1, 3, 5}, {2, 4, 6}}) (6, {{1, 4, 5}, {2, 3, 6}}) diff --git a/src/sage/coding/codecan/autgroup_can_label.pyx b/src/sage/coding/codecan/autgroup_can_label.pyx index fa0eb6576d0..7effe07522e 100644 --- a/src/sage/coding/codecan/autgroup_can_label.pyx +++ b/src/sage/coding/codecan/autgroup_can_label.pyx @@ -50,7 +50,7 @@ EXAMPLES:: sage: LinearCode(P.get_transporter()*C.generator_matrix()) == P.get_canonical_form() True sage: A = P.get_autom_gens() - sage: all( [ LinearCode(a*C.generator_matrix()) == C for a in A]) + sage: all(LinearCode(a*C.generator_matrix()) == C for a in A) True sage: P.get_autom_order() == GL(3, GF(3)).order() True @@ -90,19 +90,20 @@ and to the action of the symmetric group only:: sage: P.get_autom_order() == C.permutation_automorphism_group().order() True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Thomas Feulner # # 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 sage.coding.codecan.codecan import PartitionRefinementLinearCode from sage.combinat.permutation import Permutation from sage.functions.other import factorial + def _cyclic_shift(n, p): r""" If ``p`` is a list of pairwise distinct coordinates in ``range(n)``, @@ -563,7 +564,7 @@ class LinearCodeAutGroupCanLabel: sage: C = codes.HammingCode(GF(2), 3).dual_code() sage: A = LinearCodeAutGroupCanLabel(C).get_autom_gens() sage: Gamma = C.generator_matrix().echelon_form() - sage: all([(g*Gamma).echelon_form() == Gamma for g in A]) + sage: all((g*Gamma).echelon_form() == Gamma for g in A) True """ return self._PGammaL_autom_gens + self._trivial_autom_gens @@ -599,7 +600,7 @@ class LinearCodeAutGroupCanLabel: sage: A = LinearCodeAutGroupCanLabel(C).get_PGammaL_gens() sage: Gamma = C.generator_matrix() sage: N = [ x.monic() for x in Gamma.columns() ] - sage: all([ (g[0]*n.apply_map(g[1])).monic() in N for n in N for g in A]) + sage: all((g[0]*n.apply_map(g[1])).monic() in N for n in N for g in A) True """ Gamma = self.C.generator_matrix() diff --git a/src/sage/coding/grs.py b/src/sage/coding/grs.py index ae10d82d93b..c27534a6274 100644 --- a/src/sage/coding/grs.py +++ b/src/sage/coding/grs.py @@ -611,7 +611,7 @@ def ReedSolomonCode(base_field, length, dimension, primitive_root=None): one will be computed and can be recovered as ``C.evaluation_points()[1]`` where `C` is the code returned by this method. - EXAMPLES: + EXAMPLES:: sage: C = codes.ReedSolomonCode(GF(7), 6, 3); C [6, 3, 4] Reed-Solomon Code over GF(7) diff --git a/src/sage/coding/information_set_decoder.py b/src/sage/coding/information_set_decoder.py index 20bd5da5a46..6602f5653e2 100644 --- a/src/sage/coding/information_set_decoder.py +++ b/src/sage/coding/information_set_decoder.py @@ -548,7 +548,10 @@ def calibrate(self): 0.0008162108571427874 """ from sage.all import sample, mean, random_vector, random_matrix, randint - import time + try: + from time import process_time + except ImportError: + from time import clock as process_time C = self.code() G = C.generator_matrix() n, k = C.length(), C.dimension() @@ -557,7 +560,7 @@ def calibrate(self): q = F.cardinality() Fstar = F.list()[1:] def time_information_set_steps(): - before = time.clock() + before = process_time() while True: I = sample(range(n), k) Gi = G.matrix_from_columns(I) @@ -565,17 +568,17 @@ def time_information_set_steps(): Gi_inv = Gi.inverse() except ZeroDivisionError: continue - return time.clock() - before + return process_time() - before def time_search_loop(p): y = random_vector(F, n) g = random_matrix(F, p, n).rows() scalars = [ [ Fstar[randint(0,q-2)] for i in range(p) ] for s in range(100) ] - before = time.clock() + before = process_time() for m in scalars: e = y - sum(m[i]*g[i] for i in range(p)) errs = e.hamming_weight() - return (time.clock() - before)/100. + return (process_time() - before)/100. T = mean([ time_information_set_steps() for s in range(5) ]) P = [ time_search_loop(p) for p in range(tau+1) ] diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 204f25b2318..22dfeb2af9b 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -1314,11 +1314,11 @@ def _to_ordered_tree(self, bijection="left", root=None): [[[[]], [[]]], [[]], []] """ close_root = False - if(root is None): + if root is None: from sage.combinat.ordered_tree import OrderedTree root = OrderedTree().clone() close_root = True - if(self): + if self: left, right = self[0], self[1] if bijection == "left": root = left._to_ordered_tree(bijection=bijection, root=root) @@ -4506,7 +4506,7 @@ def random_element(self): TESTS:: sage: B = BinaryTrees(19, full=True) - sage: all([B.random_element() in B for i in range(20)]) + sage: all(B.random_element() in B for i in range(20)) True """ from sage.combinat.dyck_word import CompleteDyckWords_size diff --git a/src/sage/combinat/chas/wqsym.py b/src/sage/combinat/chas/wqsym.py index ecbedb9fcd5..77a00baee90 100644 --- a/src/sage/combinat/chas/wqsym.py +++ b/src/sage/combinat/chas/wqsym.py @@ -803,7 +803,7 @@ def star_involution(self): :meth:`algebraic_complement`, :meth:`coalgebraic_complement` - EXAMPLES: + EXAMPLES:: sage: WQSym = algebras.WQSym(ZZ) sage: X = WQSym.X() @@ -2138,7 +2138,7 @@ def algebraic_complement(self): Assume that `V` is an (additive) abelian group, and that `I` is a poset. For each `i \in I`, let `M_i` be an element of `V`. Also, let `\omega` be an involution of the set `I` - (not necesssarily order-preserving or order-reversing), + (not necessarily order-preserving or order-reversing), and let `\omega'` be an involutive group endomorphism of `V` such that each `i \in I` satisfies `\omega'(M_i) = M_{\omega(i)}`. diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index 33d6a23d7b4..78ac631a330 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -1252,7 +1252,7 @@ def free_vertices(self): sage: S.free_vertices() ['a', 'c', 'e'] - sage: S=ClusterSeed(DiGraph([[5, 'b']])) + sage: S = ClusterSeed(DiGraph([[5, 'b']])) sage: S.free_vertices() [5, 'b'] """ diff --git a/src/sage/combinat/cluster_algebra_quiver/interact.py b/src/sage/combinat/cluster_algebra_quiver/interact.py index ce2f0e23998..ec34a97aabe 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 html, latex +from sage.misc.all 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/mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py index e1f1198dadd..e95f73748bb 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py @@ -10,13 +10,13 @@ - Christian Stump """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Gregg Musiker # Christian Stump # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function from six.moves import range @@ -73,7 +73,7 @@ def is_mutation_finite(M, nr_of_checks=None): return True, None if nr_of_checks is None: nr_of_checks = 1000 * n - k = 0 + k = random.randint(0, n - 1) path = [] for i in range(nr_of_checks): # avoid mutating back in the same direction @@ -110,7 +110,7 @@ def _triangles(dg): [([(1, 0), (0, 2), (2, 1)], True)] """ E = dg.edges(labels=False) - V = dg.vertices() + V = list(dg) trians = [] flat_trians = [] for e in E: @@ -175,7 +175,7 @@ def _all_induced_cycles_iter( dg ): if len(cycle) > 4: sg = dg.subgraph(cycle) is_oriented = True - V = sg.vertices() + V = list(sg) while is_oriented and V: v = V.pop() if not sg.in_degree(v) == 1: @@ -218,7 +218,7 @@ def _reset_dg(dg, vertices, dict_in_out, del_vertices): sage: from sage.combinat.cluster_algebra_quiver.mutation_type import _reset_dg sage: dg = ClusterQuiver(['A',[2,2],1]).digraph(); dg Digraph on 4 vertices - sage: vertices = dg.vertices() + sage: vertices = list(dg) sage: dict_in_out = {} sage: for v in vertices: dict_in_out[v] = (dg.in_degree(v), dg.out_degree(v), dg.degree(v)) sage: _reset_dg(dg,vertices, dict_in_out, [1]) @@ -303,7 +303,8 @@ def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list, # Now, tries to connect up the quiver components (keeping in mind ['D',3] - ['A',3] equivalence) if hope_letter == 'D' and mut_type._letter == 'A' and mut_type._rank == 3 and not mut_type._twist: hope_letter = 'A' - if conn_vert_list: conn_verts = list( set(dg.vertices()).difference(conn_verts) ) + if conn_vert_list: + conn_verts = list(set(dg).difference(conn_verts)) if mut_type._letter == hope_letter and not mut_type._twist and conn_vert.issubset(conn_verts): if len(check_letter)>1: check_twist = 1 @@ -333,7 +334,7 @@ def _connected_mutation_type(dg): # defining some shorthands n = dg.order() edges = dg.edges() - vertices = dg.vertices() + vertices = list(dg) # initializing lists of the edges with labels (2,-1) or (1,-2); (4,-1) or (1,-4); or (2,-2), respectively exc_labels = [] exc_labels41 = [] @@ -485,7 +486,6 @@ def _connected_mutation_type(dg): if dict_in_out[label2[0]][2] == 1 or dict_in_out[label2[1]][2] == 1: label1, label2 = label2, label1 if dict_in_out[label1[0]][2] == 1: - v = label1[0] if label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1],label2[0],1): v1,v2 = label3[1],label2[0] _reset_dg( dg, vertices, dict_in_out, [label2[1]] ) @@ -507,7 +507,6 @@ def _connected_mutation_type(dg): else: return _false_return() elif dict_in_out[label1[1]][2] == 1: - v = label1[1] if label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1],label3[0],1): v1,v2 = label2[1],label3[0] _reset_dg( dg, vertices, dict_in_out, [label3[1]] ) @@ -542,9 +541,8 @@ def _connected_mutation_type(dg): if dict_in_out[label2[0]][2] == 1 or dict_in_out[label2[1]][2] == 1: label1, label2 = label2, label1 if dict_in_out[label1[1]][2] == 1: - v = label1[0] if label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1],label2[0],1): - v1,v2 = label3[1],label2[0] + v1, v2 = label3[1], label2[0] _reset_dg( dg, vertices, dict_in_out, [label2[1]] ) if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0: return _false_return() @@ -553,7 +551,7 @@ def _connected_mutation_type(dg): else: return _check_special_BC_cases( dg, n, ['CC'],[1],['A'] ) elif label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1],label3[0],1): - v1,v2 = label2[1], label3[0] + v1, v2 = label2[1], label3[0] _reset_dg( dg, vertices, dict_in_out, [label3[1]] ) if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0: return _false_return() @@ -564,9 +562,8 @@ def _connected_mutation_type(dg): else: return _false_return() elif dict_in_out[label1[0]][2] == 1: - v = label1[1] if label3[1] == label2[0] and dict_in_out[label3[1]][2] == 2 and dg.has_edge(label2[1],label3[0],1): - v1,v2 = label2[1],label3[0] + v1, v2 = label2[1], label3[0] _reset_dg( dg, vertices, dict_in_out, [label3[1]] ) if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0: return _false_return() @@ -575,7 +572,7 @@ def _connected_mutation_type(dg): else: return _check_special_BC_cases( dg, n, ['BB'],[1],['A'] ) elif label2[1] == label3[0] and dict_in_out[label2[1]][2] == 2 and dg.has_edge(label3[1],label2[0],1): - v1,v2 = label3[1],label2[0] + v1, v2 = label3[1], label2[0] _reset_dg( dg, vertices, dict_in_out, [label2[1]] ) if len( set(dg.neighbors_out(v2)).intersection(dg.neighbors_in(v1)) ) > 0: return _false_return() @@ -832,7 +829,7 @@ def _connected_mutation_type_AAtildeD(dg, ret_conn_vert=False): 'unknown' """ # naming the vertices - vertices = dg.vertices() + vertices = list(dg) n = dg.order() # Test if ClusterQuiver(dg) is of type D_n Type 1, i.e. A_{n-2} plus two leaves @@ -1458,32 +1455,31 @@ def _random_tests(mt, k, mut_class=None, nr_mut=5): elif ran2 == 6: c,d = 2,-2 elif ran2 == 7: c,d = 1,-4 elif ran2 == 8: c,d = 4,-1 - M[i,j],M[j,i] = c,d - if M.is_skew_symmetrizable( positive=True ): + M[i, j], M[j, i] = c, d + if M.is_skew_symmetrizable(positive=True): skew_sym = True else: - M[i,j],M[j,i] = a,b + M[i, j], M[j, i] = a, b # we now have a new matrix M # and a new digraph db - dg = _matrix_to_digraph( M ) - mt = _connected_mutation_type( dg ) + dg = _matrix_to_digraph(M) + mt = _connected_mutation_type(dg) mut = -1 # we perform nr_mut many mutations - for i in range(nr_mut): + for k in range(nr_mut): # while making sure that we do not mutate back mut_tmp = mut while mut == mut_tmp: mut = random.randint(0, dg.order() - 1) dg_new = _digraph_mutate(dg, mut) - M = _edge_list_to_matrix(dg.edges(), list(range(dg.order())), []) - mt_new = _connected_mutation_type( dg_new ) - if not mt == mt_new: + mt_new = _connected_mutation_type(dg_new) + if mt != mt_new: print("FOUND ERROR!") - M1 = _edge_list_to_matrix( dg.edges(), list(range(dg.order())), [] ) - print(M1) - print("has mutation type " + str( mt ) + " while it has mutation type " + str(mt_new) + " after mutating at " + str(mut) + ":") - M2 = _edge_list_to_matrix( dg_new.edges(), list(range(dg.order())), [] ) - print(M2) + print(_edge_list_to_matrix(dg.edges(), + list(range(dg.order())), [])) + print("has mutation type " + str(mt) + " while it has mutation type " + str(mt_new) + " after mutating at " + str(mut) + ":") + print(_edge_list_to_matrix(dg_new.edges(), + list(range(dg.order())), [])) return dg, dg_new else: dg = dg_new diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 0ac168f75fd..99eca0e1127 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -361,29 +361,25 @@ def __init__(self, data, frozen=None, user_labels=None): # constructs a quiver from a digraph elif isinstance(data, DiGraph): if frozen is None: - m = self._m = 0 - nlist = self._nlist = data.vertices() - n = self._n = data.order() - m - mlist = self._mlist = [] - - elif isinstance(frozen, list): - frozen = set(frozen) - if not frozen.issubset(data.vertex_iterator()): - raise ValueError("the optional list of frozen elements" - " must be vertices of the digraph") - else: - nlist = self._nlist = sorted(x for x in data.vertex_iterator() if x not in frozen) - mlist = self._mlist = list(frozen) - m = self._m = len(frozen) - n = self._n = data.order() - m - labelDict = {x: i for i, x in enumerate(nlist + mlist)} - - else: - raise ValueError("the optional parameter 'frozen' must be" - " a list of vertices of the digraph") - - dg = copy( data ) - dg_labelling = False + frozen = [] + if not isinstance(frozen, (list, tuple)): + raise ValueError("'frozen' must be a list of vertices") + frozen = set(frozen) + if not frozen.issubset(data.vertex_iterator()): + raise ValueError("frozen elements must be vertices") + + mlist = self._mlist = list(frozen) + m = self._m = len(mlist) + + try: + nlist = sorted(x for x in data if x not in frozen) + except TypeError: + nlist = sorted([x for x in data if x not in frozen], key=str) + self._nlist = nlist + n = self._n = len(nlist) + labelDict = {x: i for i, x in enumerate(nlist + mlist)} + + dg = copy(data) if data.has_loops(): raise ValueError("the input DiGraph contains a loop") @@ -391,14 +387,12 @@ def __init__(self, data, frozen=None, user_labels=None): if any((b, a) in edges for (a, b) in edges): raise ValueError("the input DiGraph contains two-cycles") + dg_labelling = False if not set(dg.vertex_iterator()) == set(range(n + m)): + # relabelling to integers # frozen vertices must be preserved - if m != 0: - dg_labelling = nlist + mlist - dg.relabel(labelDict) - else: - dg_labelling = dg.vertices() - dg.relabel() + dg_labelling = nlist + mlist + dg.relabel(labelDict) multiple_edges = dg.multiple_edges() if multiple_edges: @@ -446,7 +440,7 @@ def __init__(self, data, frozen=None, user_labels=None): self._digraph = dg self._vertex_dictionary = {} if dg_labelling is not False: - self.relabel(dg_labelling) + self.relabel(dg_labelling) # relabelling back self._M = M self._M.set_immutable() @@ -469,7 +463,7 @@ def __init__(self, data, frozen=None, user_labels=None): raise ValueError("the input data was not recognized") # stopgap for bugs arising from coefficients - if self._m != 0: + if self._m: from sage.misc.stopgap import stopgap stopgap("Having frozen nodes is known to produce wrong answers", 22381) @@ -825,7 +819,7 @@ def digraph(self): sage: ClusterQuiver(['A',1]).digraph() Digraph on 1 vertex - sage: ClusterQuiver(['A',1]).digraph().vertices() + sage: list(ClusterQuiver(['A',1]).digraph()) [0] sage: ClusterQuiver(['A',1]).digraph().edges() [] @@ -1011,18 +1005,18 @@ def mutation_type(self): mutation_type.append( mut_type_part ) # the empty quiver case - if len( mutation_type ) == 0: - Warning('Quiver has no vertices') + if len(mutation_type) == 0: mutation_type = None # the connected quiver case - elif len( mutation_type ) == 1: + elif len(mutation_type) == 1: mutation_type = mutation_type[0] # the reducible quiver case - elif len( mutation_type ) > 1: - if any( isinstance(mut_type_part, str) for mut_type_part in mutation_type ): + elif len(mutation_type) > 1: + if any(isinstance(mut_type_part, str) + for mut_type_part in mutation_type): pass else: - mutation_type = QuiverMutationType( mutation_type ) + mutation_type = QuiverMutationType(mutation_type) self._mutation_type = mutation_type return self._mutation_type @@ -1368,8 +1362,10 @@ def mutate(self, data, inplace=True): [-1 0 -1] [ 0 1 0] - sage: Q2 = ClusterQuiver(DiGraph([['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'e']]), - ....: frozen=['c']); Q2.b_matrix() + sage: dg = DiGraph() + sage: dg.add_vertices(['a','b','c','d','e']) + sage: dg.add_edges([['a','b'], ['b','c'], ['c','d'], ['d','e']]) + sage: Q2 = ClusterQuiver(dg, frozen=['c']); Q2.b_matrix() [ 0 1 0 0] [-1 0 0 0] [ 0 0 0 1] @@ -1385,7 +1381,7 @@ def mutate(self, data, inplace=True): sage: dg = DiGraph([['a', 'b'], ['b', 'c']], format='list_of_edges') sage: Q = ClusterQuiver(dg);Q Quiver on 3 vertices - sage: Q.mutate(['a','b'],inplace = False).digraph().edges() + sage: Q.mutate(['a','b'],inplace=False).digraph().edges() [('a', 'b', (1, -1)), ('c', 'b', (1, -1))] TESTS:: @@ -1433,9 +1429,9 @@ def mutate(self, data, inplace=True): for v in seq: dg = _digraph_mutate(dg, v, frozen=mlist) - M = _edge_list_to_matrix(dg.edge_iterator(), nlist, mlist) + if inplace: - self._M = M + self._M = _edge_list_to_matrix(dg.edge_iterator(), nlist, mlist) self._M.set_immutable() self._digraph = dg else: @@ -1988,7 +1984,7 @@ def relabel(self, relabelling, inplace=True): quiver = ClusterQuiver(self) # Instantiation variables - old_vertices = quiver.digraph().vertices() + old_vertices = list(quiver.digraph()) digraph_labels = {} dict_labels = {} 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 f70567d0c6e..1c78c9df4b5 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -2334,19 +2334,14 @@ def _bipartite_graph_to_digraph(g): sage: _bipartite_graph_to_digraph(G) Digraph on 2 vertices """ - if not g.is_bipartite(): - raise ValueError('The input graph is not bipartite.') - - order = g.bipartite_sets() + sources = g.bipartite_sets()[0] dg = DiGraph() - for edge in g.edges(): - if edge[0] in order[0]: - dg.add_edge( edge[0], edge[1], edge[2] ) + dg.add_vertices(g) + for a, b, c in g.edge_iterator(): + if a in sources: + dg.add_edge(a, b, c) else: - dg.add_edge( edge[1], edge[0], edge[2] ) - for vert in g.vertex_iterator(): - if vert not in dg.vertices(): - dg.add_vertex(vert) + dg.add_edge(b, a, c) return dg @@ -2368,6 +2363,7 @@ def _is_mutation_type(data): except Exception: return False + def _mutation_type_error(data): r""" Output an error message because data which is not a valid quiver mutation diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index dcef4309eee..4830f6ee3e5 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -177,7 +177,7 @@ def bell_number(n, algorithm='flint', **options): - ``'flint'`` -- Wrap FLINT's ``arith_bell_number`` - - ``'gap'`` -- Wrap libGAP's ``Bell`` + - ``'gap'`` -- Wrap GAP's ``Bell`` - ``'mpmath'`` -- Wrap mpmath's ``bell`` diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index c60366bc039..132866ea55c 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -30,7 +30,6 @@ from sage.arith.all import binomial from .combinat import CombinatorialClass from .integer_vector import IntegerVectors -from sage.misc.misc import uniq def Combinations(mset, k=None): @@ -209,8 +208,7 @@ def __contains__(self, x): except TypeError: return False - return all(i in self.mset for i in x) and len(uniq(x)) == len(x) - + return all(i in self.mset for i in x) and len(set(x)) == len(x) def __repr__(self): """ @@ -345,10 +343,9 @@ def __iter__(self): sage: Combinations(['a','a','b'],2).list() # indirect doctest [['a', 'a'], ['a', 'b']] """ - items = map(self.mset.index, self.mset) - indices = uniq(sorted(items)) # this consumes "items" in python3 + items = [self.mset.index(x) for x in self.mset] + indices = sorted(set(items)) counts = [0] * len(indices) - items = map(self.mset.index, self.mset) for i in items: counts[indices.index(i)] += 1 for iv in IntegerVectors(self.k, len(indices), outer=counts): diff --git a/src/sage/combinat/constellation.py b/src/sage/combinat/constellation.py index 74feb217311..d80e7a43e00 100644 --- a/src/sage/combinat/constellation.py +++ b/src/sage/combinat/constellation.py @@ -1241,13 +1241,13 @@ class Constellations_p(UniqueRepresentation, Parent): sage: C.first() Constellation of length 3 and degree 4 g0 (1)(2,3,4) - g1 (1,3,4)(2) - g2 (1,3)(2,4) + g1 (1,2,3)(4) + g2 (1,2)(3,4) sage: C.last() Constellation of length 3 and degree 4 - g0 (1,3,2)(4) + g0 (1,4,3)(2) g1 (1,4,2)(3) - g2 (1,3)(2,4) + g2 (1,2)(3,4) Note that the cardinality can also be computed using characters of the symmetric group (Frobenius formula):: @@ -1381,21 +1381,21 @@ def __iter__(self): sage: for c in C: print(c) Constellation of length 3 and degree 4 g0 (1)(2,3,4) - g1 (1,3,4)(2) - g2 (1,3)(2,4) + g1 (1,2,3)(4) + g2 (1,2)(3,4) Constellation of length 3 and degree 4 g0 (1)(2,3,4) g1 (1,4,2)(3) g2 (1,4)(2,3) ... Constellation of length 3 and degree 4 - g0 (1,3,2)(4) - g1 (1,3,4)(2) + g0 (1,4,3)(2) + g1 (1,2,3)(4) g2 (1,4)(2,3) Constellation of length 3 and degree 4 - g0 (1,3,2)(4) + g0 (1,4,3)(2) g1 (1,4,2)(3) - g2 (1,3)(2,4) + g2 (1,2)(3,4) sage: C = Constellations([(3,1),(3,1),(2,2)], domain='abcd') sage: for c in sorted(C): print(c) diff --git a/src/sage/combinat/crystals/kirillov_reshetikhin.py b/src/sage/combinat/crystals/kirillov_reshetikhin.py index cedb1959d01..f446058d904 100644 --- a/src/sage/combinat/crystals/kirillov_reshetikhin.py +++ b/src/sage/combinat/crystals/kirillov_reshetikhin.py @@ -2,7 +2,7 @@ Kirillov-Reshetikhin Crystals """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Anne Schilling # 2014-2018 Travis Scrimshaw # @@ -16,11 +16,10 @@ # The full text of the GPL is available at: # # https://www.gnu.org/licenses/ -#**************************************************************************** +# *************************************************************************** # Acknowledgment: most of the design and implementation of this # library is heavily inspired from MuPAD-Combinat. -#**************************************************************************** -# python3 +# *************************************************************************** from __future__ import division, print_function from six.moves import range @@ -50,6 +49,7 @@ from sage.combinat.partition import Partition, Partitions from sage.combinat.integer_vector import IntegerVectors + def KirillovReshetikhinCrystalFromLSPaths(cartan_type, r, s=1): r""" Single column Kirillov-Reshetikhin crystals. @@ -140,6 +140,7 @@ def KirillovReshetikhinCrystalFromLSPaths(cartan_type, r, s=1): weight = s*La[r] return CrystalOfProjectedLevelZeroLSPaths(weight) + def KirillovReshetikhinCrystal(cartan_type, r, s, model='KN'): r""" Return the Kirillov-Reshetikhin crystal `B^{r,s}` of the given type @@ -333,7 +334,6 @@ def KirillovReshetikhinCrystal(cartan_type, r, s, model='KN'): from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations return RiggedConfigurations(cartan_type, [[r,s]]) if model == 'LSPaths': - from sage.combinat.crystals.kirillov_reshetikhin import KirillovReshetikhinCrystalFromLSPaths return KirillovReshetikhinCrystalFromLSPaths(cartan_type, r, s) raise ValueError("invalid model") @@ -425,6 +425,7 @@ def KashiwaraNakashimaTableaux(cartan_type, r, s): else: raise NotImplementedError + class KirillovReshetikhinGenericCrystal(AffineCrystalFromClassical): r""" Generic class for Kirillov-Reshetikhin crystal `B^{r,s}` of the given type. @@ -574,6 +575,7 @@ def kirillov_reshetikhin_tableaux(self): from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableaux return KirillovReshetikhinTableaux(self.cartan_type(), self._r, self._s) + class KirillovReshetikhinGenericCrystalElement(AffineCrystalFromClassicalElement): """ Abstract class for all Kirillov-Reshetikhin crystal elements. @@ -665,6 +667,7 @@ def lusztig_involution(self): li = self.lift().lusztig_involution() return self.parent().retract(li) + KirillovReshetikhinGenericCrystal.Element = KirillovReshetikhinGenericCrystalElement class KirillovReshetikhinCrystalFromPromotion(KirillovReshetikhinGenericCrystal, @@ -700,6 +703,7 @@ def __init__(self, cartan_type, r, s): self.dynkin_diagram_automorphism(0), KirillovReshetikhinCrystals()) + class KirillovReshetikhinCrystalFromPromotionElement(AffineCrystalFromClassicalAndPromotionElement, KirillovReshetikhinGenericCrystalElement): """ @@ -707,8 +711,10 @@ class KirillovReshetikhinCrystalFromPromotionElement(AffineCrystalFromClassicalA """ pass + KirillovReshetikhinCrystalFromPromotion.Element = KirillovReshetikhinCrystalFromPromotionElement + class KR_type_A(KirillovReshetikhinCrystalFromPromotion): r""" Class of Kirillov-Reshetikhin crystals of type `A_n^{(1)}`. @@ -799,6 +805,7 @@ def dynkin_diagram_automorphism(self, i): aut = list(range(1, self.cartan_type().rank())) + [0] return aut[i] + class KR_type_vertical(KirillovReshetikhinCrystalFromPromotion): r""" Class of Kirillov-Reshetikhin crystals `B^{r,s}` of type @@ -1003,6 +1010,7 @@ def from_pm_diagram_to_highest_weight_vector(self, pm): u = u.f(i) return u + class KR_type_E6(KirillovReshetikhinCrystalFromPromotion): r""" Class of Kirillov-Reshetikhin crystals of type `E_6^{(1)}` for `r=1,2,6`. @@ -1148,7 +1156,7 @@ def hw_auxiliary(self): [[(-1,), (-1, 3)]]) """ return tuple([x for x in self.classical_decomposition() - if all(x.epsilon(i) == 0 for i in [2,3,4,5])]) + if all(x.epsilon(i) == 0 for i in [2, 3, 4, 5])]) @cached_method def highest_weight_dict(self): @@ -1200,16 +1208,16 @@ def automorphism_on_affine_weight(self, weight): EXAMPLES:: sage: K = crystals.KirillovReshetikhin(['E',6,1],2,1) - sage: [[x[0], K.automorphism_on_affine_weight(x[0])] - ....: for x in K.highest_weight_dict().values()] - [[(-1, 0, 0, 1, 0, 0, -1), (-1, -1, 0, 0, 0, 1, 0)], + sage: sorted([x[0], K.automorphism_on_affine_weight(x[0])] + ....: for x in K.highest_weight_dict().values()) + [[(-2, 0, 1, 0, 0, 0, 0), (0, -2, 0, 1, 0, 0, 0)], + [(-1, 0, 0, 1, 0, 0, -1), (-1, -1, 0, 0, 0, 1, 0)], [(0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0)], [(0, 0, 0, 0, 0, 0, 0), (0, 0, 0, 0, 0, 0, 0)], - [(-2, 0, 1, 0, 0, 0, 0), (0, -2, 0, 1, 0, 0, 0)], [(0, 0, 0, 0, 0, 1, -2), (-2, 0, 1, 0, 0, 0, 0)]] """ f = self.dynkin_diagram_automorphism - return tuple( [weight[f(f(i))] for i in self.index_set()] ) + return tuple([weight[f(f(i))] for i in self.index_set()]) @cached_method def promotion_on_highest_weight_vectors(self): @@ -1294,6 +1302,7 @@ def promotion_inverse(self): #return lambda x : p(p(x)) return p * p + class KR_type_C(KirillovReshetikhinGenericCrystal): r""" Class of Kirillov-Reshetikhin crystals `B^{r,s}` of type `C_n^{(1)}` @@ -1537,6 +1546,7 @@ def phi0(self): b = self.parent().to_ambient_crystal()(self) return b.phi(1) + KR_type_C.Element = KR_type_CElement @@ -2226,7 +2236,7 @@ def highest_weight_dict(self): sage: K.highest_weight_dict() {(3, 1, 1): [+++, [[1]]], (3, 3, 3): [+++, [[1], [2], [3]]]} """ - return {tuple([2*i[1] for i in x.classical_weight()]): x + return {tuple([2*i[1] for i in sorted(x.classical_weight())]): x for x in self.module_generators} @cached_method @@ -2248,7 +2258,7 @@ def ambient_highest_weight_dict(self): (3, 2, 2): [[1, 1, 1], [2, 2], [3, 3]], (3, 3, 3): [[1, 1, 1], [2, 2, 2], [3, 3, 3]]} """ - return {tuple([i[1] for i in x.classical_weight()]): x + return {tuple([i[1] for i in sorted(x.classical_weight())]): x for x in self.ambient_crystal().module_generators} def similarity_factor(self): @@ -3443,7 +3453,7 @@ class CrystalOfTableaux_E7(CrystalOfTableaux): ` `B^{7,s}`. """ def module_generator(self, shape): - """ + r""" Return the module generator of ``self`` with shape ``shape``. .. NOTE:: @@ -3496,7 +3506,7 @@ def classical_decomposition(self): @cached_method def A7_decomposition(self): - """ + r""" Return the decomposition of ``self`` into `A_7` highest weight crystals. @@ -4179,4 +4189,3 @@ def is_isomorphism(self): is_strict = is_isomorphism __bool__ = is_isomorphism __nonzero__ = is_isomorphism - diff --git a/src/sage/combinat/crystals/letters.pxd b/src/sage/combinat/crystals/letters.pxd new file mode 100644 index 00000000000..4b9598127cd --- /dev/null +++ b/src/sage/combinat/crystals/letters.pxd @@ -0,0 +1,78 @@ +from sage.structure.element cimport Element + +cdef class Letter(Element): + cdef readonly int value + +cdef class EmptyLetter(Element): + cdef readonly str value + cpdef e(self, int i) + cpdef f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + +cdef class Crystal_of_letters_type_A_element(Letter): + cpdef Letter e(self, int i) + cpdef Letter f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + +cdef class Crystal_of_letters_type_B_element(Letter): + cpdef Letter e(self, int i) + cpdef Letter f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + +cdef class Crystal_of_letters_type_C_element(Letter): + cpdef Letter e(self, int i) + cpdef Letter f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + +cdef class Crystal_of_letters_type_D_element(Letter): + cpdef Letter e(self, int i) + cpdef Letter f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + +cdef class Crystal_of_letters_type_G_element(Letter): + cpdef Letter e(self, int i) + cpdef Letter f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + +cdef class LetterTuple(Element): + cdef readonly tuple value + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + +cdef class Crystal_of_letters_type_E6_element(LetterTuple): + cpdef LetterTuple e(self, int i) + cpdef LetterTuple f(self, int i) + +cdef class Crystal_of_letters_type_E6_element_dual(LetterTuple): + cpdef LetterTuple lift(self) + cpdef LetterTuple retract(self, LetterTuple p) + cpdef LetterTuple e(self, int i) + cpdef LetterTuple f(self, int i) + +cdef class Crystal_of_letters_type_E7_element(LetterTuple): + cpdef LetterTuple e(self, int i) + cpdef LetterTuple f(self, int i) + +cdef class BKKLetter(Letter): + cpdef Letter e(self, int i) + cpdef Letter f(self, int i) + +cdef class QueerLetter_element(Letter): + cpdef Letter e(self, int i) + cpdef Letter f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + +cdef class LetterWrapped(Element): + cdef readonly Element value + cpdef tuple _to_tuple(self) + cpdef LetterWrapped e(self, int i) + cpdef LetterWrapped f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) diff --git a/src/sage/combinat/crystals/letters.pyx b/src/sage/combinat/crystals/letters.pyx index b6724ef785f..69cbe8ff9bf 100644 --- a/src/sage/combinat/crystals/letters.pyx +++ b/src/sage/combinat/crystals/letters.pyx @@ -354,8 +354,6 @@ cdef class Letter(Element): sage: C(1) != C(-1) True """ - cdef readonly int value - def __init__(self, parent, int value): """ EXAMPLES:: @@ -504,11 +502,11 @@ cdef class Letter(Element): if op == Py_LT: return self._parent.lt_elements(self, x) if op == Py_GT: - return x.parent().lt_elements(x, self) + return x._parent.lt_elements(x, self) if op == Py_LE: return self.value == x.value or self._parent.lt_elements(self, x) if op == Py_GE: - return self.value == x.value or x.parent().lt_elements(x, self) + return self.value == x.value or x._parent.lt_elements(x, self) return False cdef class EmptyLetter(Element): @@ -522,8 +520,6 @@ cdef class EmptyLetter(Element): Used in the rigged configuration bijections. """ - cdef readonly str value - def __init__(self, parent): """ Initialize ``self``. @@ -623,7 +619,7 @@ cdef class EmptyLetter(Element): sage: C('E').weight() (0, 0, 0) """ - return self.parent().weight_lattice_realization().zero() + return self._parent.weight_lattice_realization().zero() cpdef e(self, int i): """ @@ -1304,8 +1300,6 @@ cdef class LetterTuple(Element): """ Abstract class for type `E` letters. """ - cdef readonly tuple value - def __init__(self, parent, tuple value): """ Initialize ``self``. @@ -2785,8 +2779,6 @@ cdef class LetterWrapped(Element): Element which uses another crystal implementation and converts those elements to a tuple with `\pm i`. """ - cdef readonly Element value - def __init__(self, parent, Element value): """ Initialize ``self``. @@ -2940,7 +2932,7 @@ cdef class LetterWrapped(Element): cdef Element ret = self.value.e(i) if ret is None: return None - return type(self)(self.parent(), ret) + return type(self)(self._parent, ret) cpdef LetterWrapped f(self, int i): r""" @@ -2956,7 +2948,7 @@ cdef class LetterWrapped(Element): cdef Element ret = self.value.f(i) if ret is None: return None - return type(self)(self.parent(), ret) + return type(self)(self._parent, ret) cpdef int epsilon(self, int i): r""" diff --git a/src/sage/combinat/crystals/monomial_crystals.py b/src/sage/combinat/crystals/monomial_crystals.py index 1a5aeedc5c8..3e74b89dbd2 100644 --- a/src/sage/combinat/crystals/monomial_crystals.py +++ b/src/sage/combinat/crystals/monomial_crystals.py @@ -75,15 +75,15 @@ `i < j` and `c_{ij} = 0` if `i>j`. """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 # # Arthur Lubovsky (alubovsky at albany dot edu) # Ben Salisbury (ben dot salisbury at cmich dot edu) # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from copy import copy from sage.structure.element import Element @@ -219,9 +219,9 @@ def __hash__(self): sage: M = crystals.infinity.NakajimaMonomials(['C',5]) sage: m1 = M.module_generators[0].f(1) - sage: hash(m1) - 4715601665014767730 # 64-bit - -512614286 # 32-bit + sage: m2 = M.module_generators[0].f(2) + sage: hash(m1) != hash(m2) + True """ return hash(frozenset(tuple(six.iteritems(self._Y)))) @@ -1164,16 +1164,16 @@ class CrystalOfNakajimaMonomials(InfinityCrystalOfNakajimaMonomials): sage: c = matrix([[0,1,0],[0,0,1],[1,0,0]]) sage: La = RootSystem(['A',2,1]).weight_lattice(extended=True).fundamental_weights() sage: M = crystals.NakajimaMonomials(2*La[1], c=c) - sage: list(M.subcrystal(max_depth=3)) - [Y(1,0)^2, - Y(0,1) Y(1,0) Y(1,1)^-1 Y(2,0), - Y(0,2)^-1 Y(1,0) Y(2,0) Y(2,2), - Y(0,1)^2 Y(1,1)^-2 Y(2,0)^2, - Y(0,0) Y(0,1) Y(1,0) Y(2,1)^-1, + sage: sorted(M.subcrystal(max_depth=3), key=str) + [Y(0,0) Y(0,1) Y(1,0) Y(2,1)^-1, + Y(0,0) Y(0,1)^2 Y(1,1)^-1 Y(2,0) Y(2,1)^-1, Y(0,0) Y(0,2)^-1 Y(1,0) Y(1,1) Y(2,1)^-1 Y(2,2), Y(0,1) Y(0,2)^-1 Y(1,1)^-1 Y(2,0)^2 Y(2,2), - Y(0,0) Y(0,1)^2 Y(1,1)^-1 Y(2,0) Y(2,1)^-1, - Y(1,0) Y(1,3) Y(2,0) Y(2,3)^-1] + Y(0,1) Y(1,0) Y(1,1)^-1 Y(2,0), + Y(0,1)^2 Y(1,1)^-2 Y(2,0)^2, + Y(0,2)^-1 Y(1,0) Y(2,0) Y(2,2), + Y(1,0) Y(1,3) Y(2,0) Y(2,3)^-1, + Y(1,0)^2] """ @staticmethod def __classcall_private__(cls, cartan_type, La=None, c=None): diff --git a/src/sage/combinat/crystals/mv_polytopes.py b/src/sage/combinat/crystals/mv_polytopes.py index 55fb7a259ef..25fdd16c3f3 100644 --- a/src/sage/combinat/crystals/mv_polytopes.py +++ b/src/sage/combinat/crystals/mv_polytopes.py @@ -140,19 +140,19 @@ def _polytope_vertices(self, P): sage: MV = crystals.infinity.MVPolytopes(['C', 3]) sage: b = MV.module_generators[0].f_string([1,2,1,2]) - sage: sorted(b._polytope_vertices(MV.weight_lattice_realization()), key=list) - [(0, 0, 0), (2, 0, -2), (0, 2, -2)] + sage: sorted(b._polytope_vertices(MV.weight_lattice_realization()), key=attrcall('to_vector')) + [(0, 0, 0), (0, 2, -2), (2, 0, -2)] sage: MV = crystals.infinity.MVPolytopes(['D', 4]) sage: b = MV.module_generators[0].f_string([1,2,3,4]) sage: P = RootSystem(['D',4]).weight_lattice() - sage: sorted(b._polytope_vertices(P), key=list) # long time - [0, - -Lambda[1] + Lambda[3] + Lambda[4], - Lambda[1] - Lambda[2] + Lambda[3] + Lambda[4], + sage: sorted(b._polytope_vertices(P), key=attrcall('to_vector')) # long time + [-Lambda[1] + Lambda[3] + Lambda[4], -2*Lambda[2] + 2*Lambda[3] + 2*Lambda[4], + -Lambda[2] + 2*Lambda[4], -Lambda[2] + 2*Lambda[3], - -Lambda[2] + 2*Lambda[4]] + 0, + Lambda[1] - Lambda[2] + Lambda[3] + Lambda[4]] """ pbw_data = self._pbw_datum.parent W = pbw_data.weyl_group diff --git a/src/sage/combinat/crystals/spins.pxd b/src/sage/combinat/crystals/spins.pxd new file mode 100644 index 00000000000..4ca5f8a7082 --- /dev/null +++ b/src/sage/combinat/crystals/spins.pxd @@ -0,0 +1,21 @@ +from sage.structure.element cimport Element + +cdef class Spin(Element): + cdef bint* _value + cdef int _n + cdef long _hash + + cdef Spin _new_c(self, bint* value) + +cdef class Spin_crystal_type_B_element(Spin): + cpdef Spin e(self, int i) + cpdef Spin f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + +cdef class Spin_crystal_type_D_element(Spin): + cpdef Spin e(self, int i) + cpdef Spin f(self, int i) + cpdef int epsilon(self, int i) + cpdef int phi(self, int i) + diff --git a/src/sage/combinat/crystals/spins.py b/src/sage/combinat/crystals/spins.py deleted file mode 100644 index 78e87fa6ea4..00000000000 --- a/src/sage/combinat/crystals/spins.py +++ /dev/null @@ -1,527 +0,0 @@ -r""" -Spin Crystals - -These are the crystals associated with the three spin -representations: the spin representations of odd orthogonal groups -(or rather their double covers); and the `+` and `-` spin -representations of the even orthogonal groups. - -We follow Kashiwara and Nakashima (Journal of Algebra 165, 1994) in -representing the elements of the spin crystal by sequences of signs -`\pm`. -""" -#TODO: Do we want the following two representations? -# -#Two other representations are available as attributes -#:meth:`Spin.internal_repn` and :meth:`Spin.signature` of the crystal element. -# -#- A numerical internal representation, an integer `n` such that if `n-1` -# is written in binary and the `1`'s are replaced by ``-``, the `0`'s by -# ``+`` -# -#- The signature, which is a list in which ``+`` is replaced by `+1` and -# ``-`` by `-1`. - - -#***************************************************************************** -# Copyright (C) 2007 Anne Schilling -# Nicolas Thiery -# Daniel Bump -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# The full text of the GPL is available at: -# -# http://www.gnu.org/licenses/ -#**************************************************************************** -from __future__ import print_function - -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent -from sage.categories.classical_crystals import ClassicalCrystals -from sage.combinat.crystals.letters import LetterTuple -from sage.combinat.root_system.cartan_type import CartanType -from sage.combinat.tableau import Tableau - - -######################### -# Type B spin -######################### - -def CrystalOfSpins(ct): - r""" - Return the spin crystal of the given type `B`. - - This is a combinatorial model for the crystal with highest weight - `Lambda_n` (the `n`-th fundamental weight). It has - `2^n` elements, here called Spins. See also - :func:`~sage.combinat.crystals.letters.CrystalOfLetters`, - :func:`~sage.combinat.crystals.spins.CrystalOfSpinsPlus`, - and :func:`~sage.combinat.crystals.spins.CrystalOfSpinsMinus`. - - INPUT: - - - ``['B', n]`` - A Cartan type `B_n`. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: C.list() - [+++, ++-, +-+, -++, +--, -+-, --+, ---] - sage: C.cartan_type() - ['B', 3] - - :: - - sage: [x.signature() for x in C] - ['+++', '++-', '+-+', '-++', '+--', '-+-', '--+', '---'] - - TESTS:: - - sage: crystals.TensorProduct(C,C,generators=[[C.list()[0],C.list()[0]]]).cardinality() - 35 - """ - ct = CartanType(ct) - if ct[0] == 'B': - return GenericCrystalOfSpins(ct, Spin_crystal_type_B_element, "spins") - else: - raise NotImplementedError - -######################### -# Type D spins -######################### - -def CrystalOfSpinsPlus(ct): - r""" - Return the plus spin crystal of the given type D. - - This is the crystal with highest weight `Lambda_n` (the - `n`-th fundamental weight). - - INPUT: - - - ``['D', n]`` - A Cartan type `D_n`. - - EXAMPLES:: - - sage: D = crystals.SpinsPlus(['D',4]) - sage: D.list() - [++++, ++--, +-+-, -++-, +--+, -+-+, --++, ----] - - :: - - sage: [x.signature() for x in D] - ['++++', '++--', '+-+-', '-++-', '+--+', '-+-+', '--++', '----'] - - TESTS:: - - sage: TestSuite(D).run() - """ - ct = CartanType(ct) - if ct[0] == 'D': - return GenericCrystalOfSpins(ct, Spin_crystal_type_D_element, "plus") - else: - raise NotImplementedError - -def CrystalOfSpinsMinus(ct): - r""" - Return the minus spin crystal of the given type D. - - This is the crystal with highest weight `Lambda_{n-1}` - (the `(n-1)`-st fundamental weight). - - INPUT: - - - ``['D', n]`` - A Cartan type `D_n`. - - EXAMPLES:: - - sage: E = crystals.SpinsMinus(['D',4]) - sage: E.list() - [+++-, ++-+, +-++, -+++, +---, -+--, --+-, ---+] - sage: [x.signature() for x in E] - ['+++-', '++-+', '+-++', '-+++', '+---', '-+--', '--+-', '---+'] - - TESTS:: - - sage: len(crystals.TensorProduct(E,E,generators=[[E[0],E[0]]]).list()) - 35 - sage: D = crystals.SpinsPlus(['D',4]) - sage: len(crystals.TensorProduct(D,E,generators=[[D.list()[0],E.list()[0]]]).list()) - 56 - """ - ct = CartanType(ct) - if ct[0] == 'D': - return GenericCrystalOfSpins(ct, Spin_crystal_type_D_element, "minus") - else: - raise NotImplementedError - -class GenericCrystalOfSpins(UniqueRepresentation, Parent): - """ - A generic crystal of spins. - """ - def __init__(self, ct, element_class, case): - """ - EXAMPLES:: - - sage: E = crystals.SpinsMinus(['D',4]) - sage: TestSuite(E).run() - """ - self._cartan_type = CartanType(ct) - if case == "spins": - self.rename("The crystal of spins for type %s"%ct) - elif case == "plus": - self.rename("The plus crystal of spins for type %s"%ct) - else: - self.rename("The minus crystal of spins for type %s"%ct) - - self.Element = element_class - Parent.__init__(self, category = ClassicalCrystals()) - - if case == "minus": - generator = [1]*(ct[1]-1) - generator.append(-1) - else: - generator = [1]*ct[1] - self.module_generators = (self.element_class(self, tuple(generator)),) - - def _element_constructor_(self, value): - """ - Construct an element of ``self`` from ``value``. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: x = C((1,1,1)); x - +++ - sage: y = C([1,1,1]); y - +++ - sage: x == y - True - """ - return self.element_class(self, tuple(value)) - - def digraph(self): - """ - Return the directed graph associated to ``self``. - - EXAMPLES:: - - sage: crystals.Spins(['B',3]).digraph() - Digraph on 8 vertices - """ - try: - return self._digraph - except AttributeError: - pass - self._digraph = super(GenericCrystalOfSpins, self).digraph() - self._digraph.copy(immutable=True) - return self._digraph - - def lt_elements(self, x,y): - r""" - Return ``True`` if and only if there is a path from ``x`` to ``y`` - in the crystal graph. - - Because the crystal graph is classical, it is a directed acyclic - graph which can be interpreted as a poset. This function implements - the comparison function of this poset. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: x = C([1,1,1]) - sage: y = C([-1,-1,-1]) - sage: C.lt_elements(x,y) - True - sage: C.lt_elements(y,x) - False - sage: C.lt_elements(x,x) - False - """ - if x.parent() is not self or y.parent() is not self: - raise ValueError("both elements must be in this crystal") - try: - GC = self._digraph_closure - except AttributeError: - GC = self.digraph().transitive_closure() - self._digraph_closure = GC - if GC.has_edge(x,y): - return True - return False - -class Spin(LetterTuple): - """ - A spin letter in the crystal of spins. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: c = C([1,1,1]) - sage: TestSuite(c).run() - - sage: C([1,1,1]).parent() - The crystal of spins for type ['B', 3] - - sage: c = C([1,1,1]) - sage: c._repr_() - '+++' - - sage: D = crystals.Spins(['B',4]) - sage: a = C([1,1,1]) - sage: b = C([-1,-1,-1]) - sage: c = D([1,1,1,1]) - sage: a == a - True - sage: a == b - False - sage: b == c - False - """ - def signature(self): - """ - Return the signature of ``self``. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: C([1,1,1]).signature() - '+++' - sage: C([1,1,-1]).signature() - '++-' - """ - sword = "" - for x in range(self.parent().cartan_type().n): - sword += "+" if self.value[x] == 1 else "-" - return sword - - def _repr_(self): - """ - Represents the spin elements in terms of its signature. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: b = C([1,1,-1]) - sage: b - ++- - sage: b._repr_() - '++-' - """ - return self.signature() - - def _repr_diagram(self): - """ - Return a representation of ``self`` as a diagram. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: b = C([1,1,-1]) - sage: print(b._repr_diagram()) - + - + - - - """ - return '\n'.join(self.signature()) - - def pp(self): - """ - Pretty print ``self`` as a column. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: b = C([1,1,-1]) - sage: b.pp() - + - + - - - """ - print(self._repr_diagram()) - - def _latex_(self): - r""" - Gives the latex output of a spin column. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: b = C([1,1,-1]) - sage: print(b._latex_()) - {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} - \raisebox{-.6ex}{$\begin{array}[b]{*{1}c}\cline{1-1} - \lr{-}\\\cline{1-1} - \lr{+}\\\cline{1-1} - \lr{+}\\\cline{1-1} - \end{array}$} - } - """ - return Tableau([[i] for i in reversed(self.signature())])._latex_() - - def epsilon(self, i): - r""" - Return `\varepsilon_i` of ``self``. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: [[C[m].epsilon(i) for i in range(1,4)] for m in range(8)] - [[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], - [0, 0, 1], [1, 0, 1], [0, 1, 0], [0, 0, 1]] - """ - if self.e(i) is None: - return 0 - return 1 - - def phi(self, i): - r""" - Return `\varphi_i` of ``self``. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: [[C[m].phi(i) for i in range(1,4)] for m in range(8)] - [[0, 0, 1], [0, 1, 0], [1, 0, 1], [0, 0, 1], - [1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 0, 0]] - """ - if self.f(i) is None: - return 0 - return 1 - -class Spin_crystal_type_B_element(Spin): - r""" - Type B spin representation crystal element - """ - def e(self, i): - r""" - Returns the action of `e_i` on self. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: [[C[m].e(i) for i in range(1,4)] for m in range(8)] - [[None, None, None], [None, None, +++], [None, ++-, None], [+-+, None, None], - [None, None, +-+], [+--, None, -++], [None, -+-, None], [None, None, --+]] - """ - assert i in self.index_set() - rank = self.parent().cartan_type().n - if i < rank: - if self.value[i-1] == -1 and self.value[i] == 1: - ret = [self.value[x] for x in range(rank)] - ret[i-1] = 1 - ret[i] = -1 - return self.__class__(self.parent(), tuple(ret)) - elif i == rank: - if self.value[i-1] == -1: - ret = [self.value[x] for x in range(rank)] - ret[i-1] = 1 - return self.__class__(self.parent(), tuple(ret)) - - return None - - def f(self, i): - r""" - Returns the action of `f_i` on self. - - EXAMPLES:: - - sage: C = crystals.Spins(['B',3]) - sage: [[C[m].f(i) for i in range(1,4)] for m in range(8)] - [[None, None, ++-], [None, +-+, None], [-++, None, +--], [None, None, -+-], - [-+-, None, None], [None, --+, None], [None, None, ---], [None, None, None]] - """ - assert i in self.index_set() - rank = self.parent().cartan_type().n - if i < rank: - if self.value[i-1] == 1 and self.value[i] == -1: - ret = [self.value[x] for x in range(rank)] - ret[i-1] = -1 - ret[i] = 1 - return self.__class__(self.parent(), tuple(ret)) - elif i == rank: - if self.value[i-1] == 1: - ret = [self.value[x] for x in range(rank)] - ret[i-1] = -1 - return self.__class__(self.parent(), tuple(ret)) - - return None - -class Spin_crystal_type_D_element(Spin): - r""" - Type D spin representation crystal element - """ - def e(self, i): - r""" - Returns the action of `e_i` on self. - - EXAMPLES:: - - sage: D = crystals.SpinsPlus(['D',4]) - sage: [[D.list()[m].e(i) for i in range(1,4)] for m in range(8)] - [[None, None, None], [None, None, None], [None, ++--, None], [+-+-, None, None], - [None, None, +-+-], [+--+, None, -++-], [None, -+-+, None], [None, None, None]] - - :: - - sage: E = crystals.SpinsMinus(['D',4]) - sage: [[E[m].e(i) for i in range(1,4)] for m in range(8)] - [[None, None, None], [None, None, +++-], [None, ++-+, None], [+-++, None, None], - [None, None, None], [+---, None, None], [None, -+--, None], [None, None, --+-]] - """ - assert i in self.index_set() - rank = self.parent().cartan_type().n - if i < rank: - if self.value[i-1] == -1 and self.value[i] == 1: - ret = [self.value[x] for x in range(rank)] - ret[i-1] = 1 - ret[i] = -1 - return self.__class__(self.parent(), tuple(ret)) - elif i == rank: - if self.value[i-2] == -1 and self.value[i-1] == -1: - ret = [self.value[x] for x in range(rank)] - ret[i-2] = 1 - ret[i-1] = 1 - return self.__class__(self.parent(), tuple(ret)) - - return None - - def f(self, i): - r""" - Returns the action of `f_i` on self. - - EXAMPLES:: - - sage: D = crystals.SpinsPlus(['D',4]) - sage: [[D.list()[m].f(i) for i in range(1,4)] for m in range(8)] - [[None, None, None], [None, +-+-, None], [-++-, None, +--+], [None, None, -+-+], - [-+-+, None, None], [None, --++, None], [None, None, None], [None, None, None]] - - :: - - sage: E = crystals.SpinsMinus(['D',4]) - sage: [[E[m].f(i) for i in range(1,4)] for m in range(8)] - [[None, None, ++-+], [None, +-++, None], [-+++, None, None], [None, None, None], - [-+--, None, None], [None, --+-, None], [None, None, ---+], [None, None, None]] - """ - assert i in self.index_set() - rank = self.parent().cartan_type().n - if i < rank: - if self.value[i-1] == 1 and self.value[i] == -1: - ret = [self.value[x] for x in range(rank)] - ret[i-1] = -1 - ret[i] = 1 - return self.__class__(self.parent(), tuple(ret)) - elif i == rank: - if self.value[i-2] == 1 and self.value[i-1] == 1: - ret = [self.value[x] for x in range(rank)] - ret[i-2] = -1 - ret[i-1] = -1 - return self.__class__(self.parent(), tuple(ret)) - - return None diff --git a/src/sage/combinat/crystals/spins.pyx b/src/sage/combinat/crystals/spins.pyx new file mode 100644 index 00000000000..6c6d57aa4bf --- /dev/null +++ b/src/sage/combinat/crystals/spins.pyx @@ -0,0 +1,754 @@ +# -*- coding: utf-8 -*- +r""" +Spin Crystals + +These are the crystals associated with the three spin +representations: the spin representations of odd orthogonal groups +(or rather their double covers); and the `+` and `-` spin +representations of the even orthogonal groups. + +We follow Kashiwara and Nakashima (Journal of Algebra 165, 1994) in +representing the elements of the spin crystal by sequences of signs +`\pm`. +""" +#TODO: Do we want the following two representations? +# +#Two other representations are available as attributes +#:meth:`Spin.internal_repn` and :meth:`Spin.signature` of the crystal element. +# +#- A numerical internal representation, an integer `n` such that if `n-1` +# is written in binary and the `1`'s are replaced by ``-``, the `0`'s by +# ``+`` +# +#- The signature, which is a list in which ``+`` is replaced by `+1` and +# ``-`` by `-1`. + + +#***************************************************************************** +# Copyright (C) 2007 Anne Schilling +# Nicolas Thiery +# Daniel Bump +# 2019 Travis Scrimshaw +# +# Distributed under the terms of the GNU General Public License (GPL) +# +# This code is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# The full text of the GPL is available at: +# +# http://www.gnu.org/licenses/ +#**************************************************************************** +from __future__ import print_function + +from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, Py_GT +from cysignals.memory cimport sig_malloc, sig_free +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent cimport Parent +from sage.structure.element cimport Element, parent +from sage.categories.classical_crystals import ClassicalCrystals +from sage.combinat.root_system.cartan_type import CartanType +from sage.combinat.tableau import Tableau +from sage.rings.integer_ring import ZZ +from sage.typeset.ascii_art import AsciiArt +from sage.typeset.unicode_art import UnicodeArt + + +######################### +# Type B spin +######################### + +def CrystalOfSpins(ct): + r""" + Return the spin crystal of the given type `B`. + + This is a combinatorial model for the crystal with highest weight + `Lambda_n` (the `n`-th fundamental weight). It has + `2^n` elements, here called Spins. See also + :func:`~sage.combinat.crystals.letters.CrystalOfLetters`, + :func:`~sage.combinat.crystals.spins.CrystalOfSpinsPlus`, + and :func:`~sage.combinat.crystals.spins.CrystalOfSpinsMinus`. + + INPUT: + + - ``['B', n]`` - A Cartan type `B_n`. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: C.list() + [+++, ++-, +-+, -++, +--, -+-, --+, ---] + sage: C.cartan_type() + ['B', 3] + + :: + + sage: [x.signature() for x in C] + ['+++', '++-', '+-+', '-++', '+--', '-+-', '--+', '---'] + + TESTS:: + + sage: crystals.TensorProduct(C,C,generators=[[C.list()[0],C.list()[0]]]).cardinality() + 35 + """ + ct = CartanType(ct) + if ct[0] == 'B': + return GenericCrystalOfSpins(ct, Spin_crystal_type_B_element, "spins") + else: + raise NotImplementedError + +######################### +# Type D spins +######################### + +def CrystalOfSpinsPlus(ct): + r""" + Return the plus spin crystal of the given type D. + + This is the crystal with highest weight `Lambda_n` (the + `n`-th fundamental weight). + + INPUT: + + - ``['D', n]`` - A Cartan type `D_n`. + + EXAMPLES:: + + sage: D = crystals.SpinsPlus(['D',4]) + sage: D.list() + [++++, ++--, +-+-, -++-, +--+, -+-+, --++, ----] + + :: + + sage: [x.signature() for x in D] + ['++++', '++--', '+-+-', '-++-', '+--+', '-+-+', '--++', '----'] + + TESTS:: + + sage: TestSuite(D).run() + """ + ct = CartanType(ct) + if ct[0] == 'D': + return GenericCrystalOfSpins(ct, Spin_crystal_type_D_element, "plus") + else: + raise NotImplementedError + +def CrystalOfSpinsMinus(ct): + r""" + Return the minus spin crystal of the given type D. + + This is the crystal with highest weight `Lambda_{n-1}` + (the `(n-1)`-st fundamental weight). + + INPUT: + + - ``['D', n]`` - A Cartan type `D_n`. + + EXAMPLES:: + + sage: E = crystals.SpinsMinus(['D',4]) + sage: E.list() + [+++-, ++-+, +-++, -+++, +---, -+--, --+-, ---+] + sage: [x.signature() for x in E] + ['+++-', '++-+', '+-++', '-+++', '+---', '-+--', '--+-', '---+'] + + TESTS:: + + sage: len(crystals.TensorProduct(E,E,generators=[[E[0],E[0]]]).list()) + 35 + sage: D = crystals.SpinsPlus(['D',4]) + sage: len(crystals.TensorProduct(D,E,generators=[[D.list()[0],E.list()[0]]]).list()) + 56 + """ + ct = CartanType(ct) + if ct[0] == 'D': + return GenericCrystalOfSpins(ct, Spin_crystal_type_D_element, "minus") + else: + raise NotImplementedError + +class GenericCrystalOfSpins(UniqueRepresentation, Parent): + """ + A generic crystal of spins. + """ + def __init__(self, ct, element_class, case): + """ + EXAMPLES:: + + sage: E = crystals.SpinsMinus(['D',4]) + sage: TestSuite(E).run() + """ + self._cartan_type = CartanType(ct) + if case == "spins": + self.rename("The crystal of spins for type %s"%ct) + elif case == "plus": + self.rename("The plus crystal of spins for type %s"%ct) + else: + self.rename("The minus crystal of spins for type %s"%ct) + + self.Element = element_class + Parent.__init__(self, category=ClassicalCrystals()) + + if case == "minus": + generator = [1]*(ct[1]-1) + generator.append(-1) + else: + generator = [1]*ct[1] + self.module_generators = (self.element_class(self, tuple(generator)),) + + def _element_constructor_(self, value): + """ + Construct an element of ``self`` from ``value``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: x = C((1,1,1)); x + +++ + sage: y = C([1,1,1]); y + +++ + sage: x == y + True + """ + return self.element_class(self, tuple(value)) + + @lazy_attribute + def _digraph_closure(self): + """ + The transitive closure of the digraph associated to ``self``. + + EXAMPLES:: + + sage: crystals.Spins(['B',4])._digraph_closure + Transitive closure of : Digraph on 16 vertices + """ + return self.digraph().transitive_closure() + + def lt_elements(self, x, y): + r""" + Return ``True`` if and only if there is a path from ``x`` to ``y`` + in the crystal graph. + + Because the crystal graph is classical, it is a directed acyclic + graph which can be interpreted as a poset. This function implements + the comparison function of this poset. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: x = C([1,1,1]) + sage: y = C([-1,-1,-1]) + sage: C.lt_elements(x, y) + True + sage: C.lt_elements(y, x) + False + sage: C.lt_elements(x, x) + False + """ + if parent(x) is not self or parent(y) is not self: + raise ValueError("both elements must be in this crystal") + return self._digraph_closure.has_edge(x, y) + +cdef class Spin(Element): + """ + A spin letter in the crystal of spins. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: c = C([1,1,1]) + sage: c + +++ + sage: c.parent() + The crystal of spins for type ['B', 3] + + sage: D = crystals.Spins(['B',4]) + sage: a = C([1,1,1]) + sage: b = C([-1,-1,-1]) + sage: c = D([1,1,1,1]) + sage: a == a + True + sage: a == b + False + sage: b == c + False + """ + # cdef bint* self._value # A + is a 0/False and a - is a 1/True + + def __init__(self, parent, tuple val): + """ + Initialize ``self``. + + TESTS:: + + sage: C = crystals.Spins(['B',3]) + sage: c = C([1,1,1]) + sage: TestSuite(c).run() + """ + cdef int i + self._n = parent.cartan_type().rank() + self._value = sig_malloc(self._n*sizeof(bint)) + for i in range(self._n): + self._value[i] = (val[i] != 1) + Element.__init__(self, parent) + + cdef Spin _new_c(self, bint* value): + r""" + Fast creation of a spin element. + """ + cdef Spin ret = type(self).__new__(type(self)) + ret._parent = self._parent + ret._n = self._n + ret._value = value + ret._hash = 0 + return ret + + def __dealloc__(self): + """ + Deallocate ``self``. + + TESTS:: + + sage: C = crystals.Spins(['B',3]) + sage: c = C([1,1,1]) + sage: del c + """ + sig_free(self._value) + + def __hash__(self): + """ + Return the hash of ``self``. + + TESTS:: + + sage: C = crystals.Spins(['B',3]) + sage: len(set(C)) == len(set([hash(x) for x in C])) + True + """ + cdef int i + if self._hash == 0: + self._hash = hash(tuple([-1 if self._value[i] else 1 for i in range(self._n)])) + return self._hash + + def __reduce__(self): + r""" + Used to pickle ``self``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: a = C([1,-1,1]) + sage: a.__reduce__() + (The crystal of spins for type ['B', 3], ((1, -1, 1),)) + """ + tup = tuple([-1 if self._value[i] else 1 for i in range(self._n)]) + return (self._parent, (tup,)) + + cpdef _richcmp_(left, right, int op): + """ + Return ``True`` if ``left`` compares with ``right`` based on ``op``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: x = C([1,1,1]) + sage: y = C([-1,-1,-1]) + sage: x < y + True + sage: x >= y + False + sage: x < x + False + sage: x <= x + True + sage: x != y + True + sage: x == y + False + """ + cdef Spin self, x + cdef int i + self = left + x = right + if op == Py_EQ: + for i in range(self._n): + if self._value[i] != x._value[i]: + return False + return True + if op == Py_NE: + for i in range(self._n): + if self._value[i] != x._value[i]: + return True + return False + if op == Py_LT: + return self._parent._digraph_closure.has_edge(self, x) + if op == Py_GT: + return x._parent._digraph_closure.has_edge(x, self) + if op == Py_LE: + return self == x or self._parent._digraph_closure.has_edge(self, x) + if op == Py_GE: + return self == x or x._parent._digraph_closure.has_edge(x, self) + return False + + @property + def value(self): + r""" + Return ``self`` as a tuple with `+1` and `-1`. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: C([1,1,1]).value + (1, 1, 1) + sage: C([1,1,-1]).value + (1, 1, -1) + """ + cdef int i + one = ZZ.one() + return tuple([-one if self._value[i] else one for i in range(self._n)]) + + def signature(self): + """ + Return the signature of ``self``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: C([1,1,1]).signature() + '+++' + sage: C([1,1,-1]).signature() + '++-' + """ + cdef int i + cdef str sword = "" + for i in range(self._n): + sword += "+" if self._value[i] != 1 else "-" + return sword + + _repr_ = signature + + def _repr_diagram(self): + """ + Return a representation of ``self`` as a diagram. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: b = C([1,1,-1]) + sage: print(b._repr_diagram()) + + + + + - + """ + return '\n'.join(self.signature()) + + def _ascii_art_(self): + """ + Return an ascii art representation of ``self``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: b = C([1,1,-1]) + sage: ascii_art(b) + + + + + - + """ + return AsciiArt(list(self.signature())) + + def _unicode_art_(self): + """ + Return a unicode art representation of ``self``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: b = C([1,1,-1]) + sage: unicode_art(b) + + + + + - + """ + return UnicodeArt(list(self.signature())) + + def pp(self): + """ + Pretty print ``self`` as a column. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: b = C([1,1,-1]) + sage: b.pp() + + + + + - + """ + print(self._repr_diagram()) + + def _latex_(self): + r""" + Gives the latex output of a spin column. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: b = C([1,1,-1]) + sage: print(b._latex_()) + {\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}} + \raisebox{-.6ex}{$\begin{array}[b]{*{1}c}\cline{1-1} + \lr{-}\\\cline{1-1} + \lr{+}\\\cline{1-1} + \lr{+}\\\cline{1-1} + \end{array}$} + } + """ + return Tableau([[i] for i in reversed(self.signature())])._latex_() + + def weight(self): + """ + Return the weight of ``self``. + + EXAMPLES:: + + sage: [v.weight() for v in crystals.Spins(['B',3])] + [(1/2, 1/2, 1/2), (1/2, 1/2, -1/2), + (1/2, -1/2, 1/2), (-1/2, 1/2, 1/2), + (1/2, -1/2, -1/2), (-1/2, 1/2, -1/2), + (-1/2, -1/2, 1/2), (-1/2, -1/2, -1/2)] + """ + WLR = self._parent.weight_lattice_realization() + cdef int i + mone = -WLR.base_ring().one() + # The ambient space is indexed by 0,...,n-1 + return WLR._from_dict({i: mone**int(self._value[i]) / 2 for i in range(self._n)}, + remove_zeros=False, coerce=False) + +cdef class Spin_crystal_type_B_element(Spin): + r""" + Type B spin representation crystal element + """ + cpdef Spin e(self, int i): + r""" + Return the action of `e_i` on ``self``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: [[C[m].e(i) for i in range(1,4)] for m in range(8)] + [[None, None, None], [None, None, +++], [None, ++-, None], [+-+, None, None], + [None, None, +-+], [+--, None, -++], [None, -+-, None], [None, None, --+]] + """ + if i < 1 or i > self._n: + raise ValueError("i is not in the index set") + cdef int j + cdef bint* ret + if i == self._n: + if self._value[i-1]: + ret = sig_malloc(self._n*sizeof(bint)) + for j in range(self._n): + ret[j] = self._value[j] + ret[i-1] = False + return self._new_c(ret) + return None + + if self._value[i-1] and not self._value[i]: + ret = sig_malloc(self._n*sizeof(bint)) + for j in range(self._n): + ret[j] = self._value[j] + ret[i-1] = False + ret[i] = True + return self._new_c(ret) + return None + + cpdef Spin f(self, int i): + r""" + Return the action of `f_i` on ``self``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: [[C[m].f(i) for i in range(1,4)] for m in range(8)] + [[None, None, ++-], [None, +-+, None], [-++, None, +--], [None, None, -+-], + [-+-, None, None], [None, --+, None], [None, None, ---], [None, None, None]] + """ + if i < 1 or i > self._n: + raise ValueError("i is not in the index set") + cdef int j + cdef bint* ret + if i == self._n: + if not self._value[i-1]: + ret = sig_malloc(self._n*sizeof(bint)) + for j in range(self._n): + ret[j] = self._value[j] + ret[i-1] = True + return self._new_c(ret) + return None + + if self._value[i] and not self._value[i-1]: + ret = sig_malloc(self._n*sizeof(bint)) + for j in range(self._n): + ret[j] = self._value[j] + ret[i-1] = True + ret[i] = False + return self._new_c(ret) + return None + + cpdef int epsilon(self, int i): + r""" + Return `\varepsilon_i` of ``self``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: [[C[m].epsilon(i) for i in range(1,4)] for m in range(8)] + [[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], + [0, 0, 1], [1, 0, 1], [0, 1, 0], [0, 0, 1]] + """ + if i < 1 or i > self._n: + raise ValueError("i is not in the index set") + if i == self._n: + return self._value[i-1] + return self._value[i-1] and not self._value[i] + + cpdef int phi(self, int i): + r""" + Return `\varphi_i` of ``self``. + + EXAMPLES:: + + sage: C = crystals.Spins(['B',3]) + sage: [[C[m].phi(i) for i in range(1,4)] for m in range(8)] + [[0, 0, 1], [0, 1, 0], [1, 0, 1], [0, 0, 1], + [1, 0, 0], [0, 1, 0], [0, 0, 1], [0, 0, 0]] + """ + if i < 1 or i > self._n: + raise ValueError("i is not in the index set") + if i == self._n: + return not self._value[i-1] + return self._value[i] and not self._value[i-1] + +cdef class Spin_crystal_type_D_element(Spin): + r""" + Type D spin representation crystal element + """ + cpdef Spin e(self, int i): + r""" + Return the action of `e_i` on ``self``. + + EXAMPLES:: + + sage: D = crystals.SpinsPlus(['D',4]) + sage: [[D.list()[m].e(i) for i in range(1,4)] for m in range(8)] + [[None, None, None], [None, None, None], [None, ++--, None], [+-+-, None, None], + [None, None, +-+-], [+--+, None, -++-], [None, -+-+, None], [None, None, None]] + + :: + + sage: E = crystals.SpinsMinus(['D',4]) + sage: [[E[m].e(i) for i in range(1,4)] for m in range(8)] + [[None, None, None], [None, None, +++-], [None, ++-+, None], [+-++, None, None], + [None, None, None], [+---, None, None], [None, -+--, None], [None, None, --+-]] + """ + if i < 1 or i > self._n: + raise ValueError("i is not in the index set") + cdef int j + cdef bint* ret + if i == self._n: + if self._value[i-1] and self._value[i-2]: + ret = sig_malloc(self._n*sizeof(bint)) + for j in range(self._n): + ret[j] = self._value[j] + ret[i-1] = False + ret[i-2] = False + return self._new_c(ret) + return None + + if self._value[i-1] and not self._value[i]: + ret = sig_malloc(self._n*sizeof(bint)) + for j in range(self._n): + ret[j] = self._value[j] + ret[i-1] = False + ret[i] = True + return self._new_c(ret) + return None + + cpdef Spin f(self, int i): + r""" + Return the action of `f_i` on ``self``. + + EXAMPLES:: + + sage: D = crystals.SpinsPlus(['D',4]) + sage: [[D.list()[m].f(i) for i in range(1,4)] for m in range(8)] + [[None, None, None], [None, +-+-, None], [-++-, None, +--+], [None, None, -+-+], + [-+-+, None, None], [None, --++, None], [None, None, None], [None, None, None]] + + :: + + sage: E = crystals.SpinsMinus(['D',4]) + sage: [[E[m].f(i) for i in range(1,4)] for m in range(8)] + [[None, None, ++-+], [None, +-++, None], [-+++, None, None], [None, None, None], + [-+--, None, None], [None, --+-, None], [None, None, ---+], [None, None, None]] + """ + if i < 1 or i > self._n: + raise ValueError("i is not in the index set") + cdef int j + cdef bint* ret + if i == self._n: + if not self._value[i-1] and not self._value[i-2]: + ret = sig_malloc(self._n*sizeof(bint)) + for j in range(self._n): + ret[j] = self._value[j] + ret[i-1] = True + ret[i-2] = True + return self._new_c(ret) + return None + + if self._value[i] and not self._value[i-1]: + ret = sig_malloc(self._n*sizeof(bint)) + for j in range(self._n): + ret[j] = self._value[j] + ret[i-1] = True + ret[i] = False + return self._new_c(ret) + return None + + cpdef int epsilon(self, int i): + r""" + Return `\varepsilon_i` of ``self``. + + EXAMPLES:: + + sage: C = crystals.SpinsMinus(['D',4]) + sage: [[C[m].epsilon(i) for i in C.index_set()] for m in range(8)] + [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0], + [0, 0, 0, 1], [1, 0, 0, 1], [0, 1, 0, 0], [0, 0, 1, 0]] + """ + if i < 1 or i > self._n: + raise ValueError("i is not in the index set") + if i == self._n: + return self._value[i-1] and self._value[i-2] + return self._value[i-1] and not self._value[i] + + cpdef int phi(self, int i): + r""" + Return `\varphi_i` of ``self``. + + EXAMPLES:: + + sage: C = crystals.SpinsPlus(['D',4]) + sage: [[C[m].phi(i) for i in C.index_set()] for m in range(8)] + [[0, 0, 0, 1], [0, 1, 0, 0], [1, 0, 1, 0], [0, 0, 1, 0], + [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0]] + """ + if i < 1 or i > self._n: + raise ValueError("i is not in the index set") + if i == self._n: + return not self._value[i-1] and not self._value[i-2] + return self._value[i] and not self._value[i-1] + diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index 283c3a699f1..775daf2b8b6 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -29,6 +29,7 @@ from sage.structure.element_wrapper import ElementWrapper from sage.categories.crystals import Crystals from sage.categories.finite_crystals import FiniteCrystals +from sage.categories.regular_supercrystals import RegularSuperCrystals from sage.combinat.root_system.cartan_type import CartanType from sage.rings.integer import Integer from sage.rings.infinity import infinity @@ -99,6 +100,16 @@ class Subcrystal(UniqueRepresentation, Parent): .. TODO:: Include support for subcrystals which only contains certain arrows. + + TESTS: + + Check that the subcrystal respects being in the category + of supercrystals (:trac:`27368`):: + + sage: T = crystals.Tableaux(['A',[1,1]], [2,1]) + sage: S = T.subcrystal(max_depth=3) + sage: S.category() + Category of regular super crystals """ @staticmethod def __classcall_private__(cls, ambient, contained=None, generators=None, @@ -131,6 +142,8 @@ def __classcall_private__(cls, ambient, contained=None, generators=None, category = Crystals().or_subcategory(category) if ambient in FiniteCrystals() or isinstance(contained, frozenset): category = category.Finite() + if ambient in RegularSuperCrystals(): + category = category & RegularSuperCrystals() if virtualization is not None: if scaling_factors is None: diff --git a/src/sage/combinat/debruijn_sequence.pyx b/src/sage/combinat/debruijn_sequence.pyx index 0c08d5e4a26..db8fda9e5c0 100644 --- a/src/sage/combinat/debruijn_sequence.pyx +++ b/src/sage/combinat/debruijn_sequence.pyx @@ -330,7 +330,7 @@ class DeBruijnSequences(UniqueRepresentation, Parent): - ``seq`` -- A sequence of integers. - EXAMPLES: + EXAMPLES:: sage: Sequences = DeBruijnSequences(2, 3) sage: Sequences.an_element() in Sequences diff --git a/src/sage/combinat/designs/all.py b/src/sage/combinat/designs/all.py index 3264c956aa1..8c121836734 100644 --- a/src/sage/combinat/designs/all.py +++ b/src/sage/combinat/designs/all.py @@ -1,13 +1,33 @@ """ Combinatorial design features that are imported by default in the interpreter namespace + +Test for deprecations of imports into global namespace:: + + sage: designs_from_XML + doctest:warning...: + DeprecationWarning: + Importing designs_from_XML from here is deprecated. If you need to use it, please import it directly from sage.combinat.designs.ext_rep + See https://trac.sagemath.org/27066 for details. + ... + + sage: designs_from_XML_url + doctest:warning...: + DeprecationWarning: + Importing designs_from_XML_url from here is deprecated. If you need to use it, please import it directly from sage.combinat.designs.ext_rep + See https://trac.sagemath.org/27066 for details. + ... """ from __future__ import absolute_import -from .block_design import (BlockDesign) +from sage.misc.lazy_import import lazy_import -from .ext_rep import (designs_from_XML, designs_from_XML_url) +lazy_import("sage.combinat.designs.ext_rep", ['designs_from_XML', + 'designs_from_XML_url'], + deprecation=27066) -from .incidence_structures import (IncidenceStructure) +from .block_design import BlockDesign + +from .incidence_structures import IncidenceStructure from .incidence_structures import IncidenceStructure as Hypergraph @@ -16,3 +36,5 @@ trivial_covering_design) from . import design_catalog as designs + +del absolute_import diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 34e49a157fd..9a979aa77ae 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -55,7 +55,7 @@ from six import itervalues from six.moves import range -from sage.misc.cachefunc import cached_method +from sage.misc.cachefunc import cached_function from sage.categories.sets_cat import EmptySetError import sage.arith.all as arith @@ -1146,7 +1146,7 @@ def are_hadamard_difference_set_parameters(v, k, lmbda): N2 = N*N return v == 4*N2 and k == 2*N2 - N and lmbda == N2 - N -@cached_method +@cached_function def hadamard_difference_set_product_parameters(N): r""" Check whether a product construction is available for Hadamard difference diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 9d1385fe2b3..a9e446dc56e 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -70,7 +70,7 @@ class IncidenceStructure(object): defines the ground set as the union of the blocks:: sage: H = IncidenceStructure([['a','b','c'],['c','d','e']]) - sage: H.ground_set() + sage: sorted(H.ground_set()) ['a', 'b', 'c', 'd', 'e'] - ``blocks`` -- (i.e. edges, i.e. sets) the blocks defining the incidence @@ -205,10 +205,7 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, self._points = list(range(points)) self._point_to_index = None else: - # if points are tuple, sort None before int types and str after int types - sortkey = lambda e: [(0 if x is None else 2 if isinstance(x, str) else 1, x) for x in e]\ - if isinstance(e, tuple) else e - self._points = sorted(points, key=sortkey) + self._points = list(points) if self._points == list(range(len(points))) and all(isinstance(x, (int, Integer)) for x in self._points): self._point_to_index = None else: diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index c51bf78b41d..d94f4ba6c9d 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -110,11 +110,11 @@ REFERENCES: .. [Stinson2004] Douglas R. Stinson, - Combinatorial designs: construction and analysis, + *Combinatorial designs: construction and analysis*, Springer, 2004. .. [ColDin01] Charles Colbourn, Jeffrey Dinitz, - Mutually orthogonal latin squares: a brief survey of constructions, + *Mutually orthogonal latin squares: a brief survey of constructions*, Volume 95, Issues 1-2, Pages 9-48, Journal of Statistical Planning and Inference, Springer, 1 May 2001. @@ -126,6 +126,7 @@ from six import iteritems from six.moves import zip +from sage.rings.integer import Integer from sage.categories.sets_cat import EmptySetError from sage.misc.unknown import Unknown from sage.env import COMBINATORIAL_DESIGN_DATA_DIR @@ -205,7 +206,7 @@ def are_mutually_orthogonal_latin_squares(l, verbose=False): return is_orthogonal_array(list(zip(*[[x for R in M for x in R] for M in l])),k,n, verbose=verbose, terminology="MOLS") -def mutually_orthogonal_latin_squares(k,n, partitions = False, check = True, existence=False): +def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): r""" Return `k` Mutually Orthogonal `n\times n` Latin Squares (MOLS). @@ -219,7 +220,7 @@ def mutually_orthogonal_latin_squares(k,n, partitions = False, check = True, exi - ``n`` (integer) -- size of the latin square. - - ``partition`` (boolean) -- a Latin Square can be seen as 3 partitions of + - ``partitions`` (boolean) -- a Latin Square can be seen as 3 partitions of the `n^2` cells of the array into `n` sets of size `n`, respectively : * The partition of rows @@ -230,25 +231,10 @@ def mutually_orthogonal_latin_squares(k,n, partitions = False, check = True, exi These partitions have the additional property that any two sets from different partitions intersect on exactly one element. - When ``partition`` is set to ``True``, this function returns a list of `k+2` + When ``partitions`` is set to ``True``, this function returns a list of `k+2` partitions satisfying this intersection property instead of the `k+2` MOLS (though the data is exactly the same in both cases). - - ``existence`` (boolean) -- instead of building the design, return: - - - ``True`` -- meaning that Sage knows how to build the design - - - ``Unknown`` -- meaning that Sage does not know how to build the - design, but that the design may exist (see :mod:`sage.misc.unknown`). - - - ``False`` -- meaning that the design does not exist. - - .. NOTE:: - - When ``k=None`` and ``existence=True`` the function returns an - integer, i.e. the largest `k` such that we can build a `k` MOLS of - order `n`. - - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to @@ -334,10 +320,19 @@ def mutually_orthogonal_latin_squares(k,n, partitions = False, check = True, exi sage: designs.mutually_orthogonal_latin_squares(3, 1) [[0], [0], [0]] + + Wrong input for `k`:: + sage: designs.mutually_orthogonal_latin_squares(None, 1) Traceback (most recent call last): ... - ValueError: there are no bound on k when 0<=n<=1 + TypeError: k must be a positive integer + + sage: designs.mutually_orthogonal_latin_squares(-1, 1) + Traceback (most recent call last): + ... + ValueError: k must be positive + sage: designs.mutually_orthogonal_latin_squares(2,10) [ [1 8 9 0 2 4 6 3 5 7] [1 7 6 5 0 9 8 2 3 4] @@ -356,58 +351,40 @@ def mutually_orthogonal_latin_squares(k,n, partitions = False, check = True, exi from sage.matrix.constructor import Matrix from .database import MOLS_constructions - # Is k is None we find the largest available if k is None: - from sage.misc.superseded import deprecation - deprecation(17034,"please use designs.orthogonal_arrays.largest_available_k instead of k=None") - if n == 0 or n == 1: - if existence: - from sage.rings.infinity import Infinity - return Infinity - raise ValueError("there are no bound on k when 0<=n<=1") - - k = orthogonal_array(None,n,existence=True) - 2 - if existence: - return k - - if existence: - from sage.misc.superseded import deprecation - deprecation(17034,"please use designs.orthogonal_arrays.is_available/exists instead of existence=True") + raise TypeError('k must be a positive integer') + try: + Integer(k) + except TypeError: + raise + if k < 0: + raise ValueError('k must be positive') if n == 1: - if existence: - return True - matrices = [Matrix([[0]])]*k + matrices = [Matrix([[0]])] * k elif k >= n: - if existence: - return False raise EmptySetError("There exist at most n-1 MOLS of size n if n>=2.") elif n in MOLS_constructions and k <= MOLS_constructions[n][0]: - if existence: - return True _, construction = MOLS_constructions[n] matrices = construction()[:k] - elif orthogonal_array(k+2,n,existence=True) is not Unknown: + elif orthogonal_array(k + 2, n, existence=True) is not Unknown: # Forwarding non-existence results - if orthogonal_array(k+2,n,existence=True): - if existence: - return True + if orthogonal_array(k + 2, n, existence=True): + pass else: - if existence: - return False - raise EmptySetError("There does not exist {} MOLS of order {}!".format(k,n)) + raise EmptySetError("There does not exist {} MOLS of order {}!".format(k, n)) # make sure that the first two columns are "11, 12, ..., 1n, 21, 22, ..." - OA = sorted(orthogonal_array(k+2,n,check=False)) + OA = sorted(orthogonal_array(k + 2, n, check=False)) # We first define matrices as lists of n^2 values matrices = [[] for _ in range(k)] for L in OA: - for i in range(2,k+2): + for i in range(2, k + 2): matrices[i-2].append(L[i]) # The real matrices @@ -415,9 +392,7 @@ def mutually_orthogonal_latin_squares(k,n, partitions = False, check = True, exi matrices = [Matrix(M) for M in matrices] else: - if existence: - return Unknown - raise NotImplementedError("I don't know how to build {} MOLS of order {}".format(k,n)) + raise NotImplementedError("I don't know how to build {} MOLS of order {}".format(k, n)) if check: assert are_mutually_orthogonal_latin_squares(matrices) @@ -438,7 +413,8 @@ def mutually_orthogonal_latin_squares(k,n, partitions = False, check = True, exi else: return matrices -def latin_square_product(M,N,*others): + +def latin_square_product(M, N, *others): r""" Return the product of two (or more) latin squares. @@ -553,7 +529,6 @@ def MOLS_table(start,stop=None,compare=False,width=None): # choose an appropriate width (needs to be >= 3 because "+oo" should fit) if width is None: - from sage.rings.integer import Integer width = max(3, Integer(stop-1).ndigits(10)) print(" " * (width + 2) + " ".join("{i:>{width}}".format(i=i,width=width) diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index 45962de3a6f..83fff792d62 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -383,11 +383,11 @@ def OA_and_oval(q): # We build the TD by relabelling the point set, and removing those which # contain x. r = {} - B = list(B) - # (this is to make sure that the first set containing x in B is the one - # which contains no other oval point) - B.sort(key=lambda b:int(any([xx in oval for xx in b]))) + # Make sure that the first set containing x in B is the one + # which contains no other oval point + B = sorted(B, key=lambda b: any(xx in oval for xx in b)) + BB = [] for b in B: if x in b: @@ -803,13 +803,14 @@ def thwart_lemma_4_1(k,n,m,explain_construction=False): q = n K = FiniteField(q, 'x') - relabel = {x:i for i,x in enumerate(K)} - PG = DesarguesianProjectivePlaneDesign(q,check=False,point_coordinates=False).blocks(copy=False) + relabel = {x: i for i, x in enumerate(K)} + PG = DesarguesianProjectivePlaneDesign(q, check=False, + point_coordinates=False).blocks() if q % 3 == 0: t = K.one() - elif q%3 == 1: - t = K.multiplicative_generator()**((q-1)//3) + elif q % 3 == 1: + t = K.multiplicative_generator()**((q - 1)//3) else: raise ValueError("q(={}) must be congruent to 0 or 1 mod 3".format(q)) diff --git a/src/sage/combinat/designs/twographs.py b/src/sage/combinat/designs/twographs.py index 0e541eba34a..696c33b008a 100644 --- a/src/sage/combinat/designs/twographs.py +++ b/src/sage/combinat/designs/twographs.py @@ -93,12 +93,11 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, incidence_matrix=incidence_matrix, name=name, check=False, copy=copy) if check: # it is a very slow, O(|points|^4), test... - from sage.combinat.designs.twographs import is_twograph assert is_twograph(self), "the structure is not a 2-graph!" def is_regular_twograph(self, alpha=False): r""" - Tests if the :class:`TwoGraph` is regular, i.e. is a 2-design. + Test if the :class:`TwoGraph` is regular, i.e. is a 2-design. Namely, each pair of elements of :meth:`ground_set` is contained in exactly ``alpha`` triples. diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index de9668b9bc8..4578c4e980b 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1442,12 +1442,12 @@ def symmetric_diagrams(self, l=None, perm=None): sage: import sage.combinat.diagram_algebras as da sage: bd = da.BrauerDiagrams(4) sage: bd.symmetric_diagrams(l=1, perm=[2,1]) - [{{-4, -3}, {-2, 1}, {-1, 2}, {3, 4}}, - {{-4, -2}, {-3, 1}, {-1, 3}, {2, 4}}, - {{-4, 1}, {-3, -2}, {-1, 4}, {2, 3}}, + [{{-4, -2}, {-3, 1}, {-1, 3}, {2, 4}}, + {{-4, -3}, {-2, 1}, {-1, 2}, {3, 4}}, {{-4, -1}, {-3, 2}, {-2, 3}, {1, 4}}, {{-4, 2}, {-3, -1}, {-2, 4}, {1, 3}}, - {{-4, 3}, {-3, 4}, {-2, -1}, {1, 2}}] + {{-4, 3}, {-3, 4}, {-2, -1}, {1, 2}}, + {{-4, 1}, {-3, -2}, {-1, 4}, {2, 3}}] TESTS:: diff --git a/src/sage/combinat/dict_addition.pyx b/src/sage/combinat/dict_addition.pyx deleted file mode 100644 index e5f91d12bfa..00000000000 --- a/src/sage/combinat/dict_addition.pyx +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Pointwise addition of dictionaries - -This module is deprecated in favor of :mod:`sage.data_structures.blas_dict`. - -EXAMPLES:: - - sage: from sage.combinat.dict_addition import dict_addition, dict_linear_combination - sage: D = { 0:1, 1:1 }; D - {0: 1, 1: 1} - - sage: dict_addition( D for _ in range(5) ) - doctest:warning - ... - DeprecationWarning: dict_addition is deprecated. Please use sage.data_structures.blas_dict.sum instead. - See http://trac.sagemath.org/20680 for details. - {0: 5, 1: 5} - - sage: dict_linear_combination( (D,i) for i in range(5) ) - doctest:warning - ... - DeprecationWarning: dict_linear_combination is deprecated. Please use sage.data_structures.blas_dict.linear_combination instead. - See http://trac.sagemath.org/20680 for details. - {0: 10, 1: 10} -""" -#***************************************************************************** -# Copyright (C) 2010 Christian Stump -# 2016 Travis Scrimshaw -# 2016 Nicolas M. Thiéry -# -# This 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/ -#***************************************************************************** -from __future__ import absolute_import - -from sage.misc.superseded import deprecated_function_alias -import sage.data_structures.blas_dict as blas - -dict_addition = deprecated_function_alias(20680, blas.sum) -dict_linear_combination = deprecated_function_alias(20680, blas.linear_combination) diff --git a/src/sage/combinat/enumeration_mod_permgroup.pxd b/src/sage/combinat/enumeration_mod_permgroup.pxd index 407cadd18bf..2f457429ccf 100644 --- a/src/sage/combinat/enumeration_mod_permgroup.pxd +++ b/src/sage/combinat/enumeration_mod_permgroup.pxd @@ -1,10 +1,9 @@ from sage.structure.list_clone cimport ClonableIntArray -from cpython cimport bool cpdef list all_children(ClonableIntArray v, int max_part) cpdef int lex_cmp_partial(ClonableIntArray t1, ClonableIntArray t2, int step) cpdef int lex_cmp(ClonableIntArray t1, ClonableIntArray t2) -cpdef bool is_canonical(list sgs, ClonableIntArray v) +cpdef bint is_canonical(list sgs, ClonableIntArray v) except -1 cpdef ClonableIntArray canonical_representative_of_orbit_of(list sgs, ClonableIntArray v) cpdef list canonical_children(list sgs, ClonableIntArray v, int max_part) cpdef set orbit(list sgs, ClonableIntArray v) diff --git a/src/sage/combinat/enumeration_mod_permgroup.pyx b/src/sage/combinat/enumeration_mod_permgroup.pyx index 476f05f841e..8f563da95b7 100644 --- a/src/sage/combinat/enumeration_mod_permgroup.pyx +++ b/src/sage/combinat/enumeration_mod_permgroup.pyx @@ -9,9 +9,8 @@ Tools for enumeration modulo the action of a permutation group # The full text of the GPL is available at: # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.list_clone cimport ClonableIntArray + from sage.groups.perm_gps.permgroup_element cimport PermutationGroupElement -from cpython cimport bool cpdef list all_children(ClonableIntArray v, int max_part): r""" @@ -136,7 +135,8 @@ cpdef int lex_cmp(ClonableIntArray v1, ClonableIntArray v2): return -1 return 1 -cpdef bool is_canonical(list sgs, ClonableIntArray v): + +cpdef bint is_canonical(list sgs, ClonableIntArray v) except -1: r""" Returns ``True`` if the integer vector `v` is maximal with respect to the lexicographic order in its orbit under the action of the @@ -182,6 +182,7 @@ cpdef bool is_canonical(list sgs, ClonableIntArray v): to_analyse = new_to_analyse return True + cpdef ClonableIntArray canonical_representative_of_orbit_of(list sgs, ClonableIntArray v): r""" Returns the maximal vector for the lexicographic order living in diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index eea637898b4..c14373e0832 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -807,9 +807,7 @@ The arguments used when calling a hook have changed in :trac:`16538` from ``hook(state, process)`` to - ``hook(process, state, output)``. If you are using - an old-style hook, a deprecation warning is displayed. - + ``hook(process, state, output)``. Detecting sequences with same number of `0` and `1` --------------------------------------------------- @@ -936,6 +934,7 @@ import collections import itertools +from copy import copy, deepcopy from sage.calculus.var import var from sage.functions.trig import atan2 @@ -1739,8 +1738,6 @@ def __deepcopy__(self, memo): sage: deepcopy(A) 'A' """ - from copy import deepcopy - try: label = self._deepcopy_relabel_ except AttributeError: @@ -1798,10 +1795,8 @@ def deepcopy(self, memo=None): sage: B.initial_probability is A.initial_probability False """ - from copy import deepcopy return deepcopy(self, memo) - def relabeled(self, label, memo=None): """ Returns a deep copy of the state with a new label. @@ -1823,9 +1818,7 @@ def relabeled(self, label, memo=None): sage: A = FSMState('A') sage: A.relabeled('B') 'B' - """ - from copy import deepcopy self._deepcopy_relabel_ = label new = deepcopy(self, memo) del self._deepcopy_relabel_ @@ -1902,7 +1895,7 @@ def __hash__(self): def _repr_(self): """ - Returns the string "label". + Return the string "label". INPUT: @@ -1912,6 +1905,10 @@ def _repr_(self): A string. + .. TODO:: + + When the label is a frozenset, py2 and py3 disagree. + TESTS:: sage: from sage.combinat.finite_state_machine import FSMState @@ -1920,7 +1917,6 @@ def _repr_(self): """ return repr(self.label()) - def __eq__(left, right): """ Returns True if two states are the same, i.e., if they have @@ -2391,7 +2387,6 @@ def __deepcopy__(self, memo): sage: deepcopy(t) Transition from 'A' to 'B': 0|- """ - from copy import deepcopy new = FSMTransition(deepcopy(self.from_state, memo), deepcopy(self.to_state, memo), deepcopy(self.word_in, memo), @@ -2421,10 +2416,8 @@ def deepcopy(self, memo=None): sage: deepcopy(t) Transition from 'A' to 'B': 0|- """ - from copy import deepcopy return deepcopy(self, memo) - def __hash__(self): """ Since transitions are mutable, they should not be hashable, so @@ -3441,12 +3434,9 @@ def deepcopy(self, memo=None): True sage: C.transitions()[0].to_state is C.state('A') True - """ - from copy import deepcopy return deepcopy(self, memo) - def _copy_from_other_(self, other, memo=None, empty=False): """ Copy all data from other to self, to be used in the constructor. @@ -3469,7 +3459,6 @@ def _copy_from_other_(self, other, memo=None, empty=False): sage: A == B True """ - from copy import deepcopy if memo is None: memo = {} self.input_alphabet = deepcopy(other.input_alphabet, memo) @@ -3596,8 +3585,6 @@ def relabeled(self, memo=None, labels=None): ... TypeError: labels must be None, a callable or a dictionary. """ - from copy import deepcopy - self._deepcopy_relabel_ = True self._deepcopy_labels_ = labels new = deepcopy(self, memo) @@ -3643,10 +3630,7 @@ def induced_sub_finite_state_machine(self, states): sage: sub_FSM.transitions()[0].from_state is sub_FSM.state(0) True - """ - from copy import deepcopy - good_states = set() for state in states: if not self.has_state(state): @@ -4051,12 +4035,10 @@ def __bool__(self): sage: bool(FiniteStateMachine()) False """ - return len(self._states_) > 0 - + return bool(self._states_) __nonzero__ = __bool__ - def __eq__(left, right): """ Returns ``True`` if the two finite state machines are equal, @@ -4359,9 +4341,9 @@ def _repr_(self): Finite state machine with 2 states """ - if len(self._states_)==0: + if not self._states_: return "Empty finite state machine" - if len(self._states_)==1: + if len(self._states_) == 1: return "Finite state machine with 1 state" else: return "Finite state machine with %s states" % len(self._states_) @@ -5494,12 +5476,9 @@ def states(self): sage: FSM = Automaton([('1', '2', 1), ('2', '2', 0)]) sage: FSM.states() ['1', '2'] - """ - from copy import copy return copy(self._states_) - def iter_states(self): """ Returns an iterator of the states. @@ -6389,8 +6368,6 @@ class is created and is used during the processing. sage: T.process([3]) (False, None, None) """ - from copy import copy - # set default values options = copy(self._process_default_options_) options.update(kwargs) @@ -7325,7 +7302,7 @@ def accessible_components(self): sage: F.accessible_components() Automaton with 3 states """ - from copy import deepcopy + if len(self.initial_states()) == 0: return deepcopy(self) @@ -7839,7 +7816,6 @@ def kleene_star(self): RuntimeError: State 0 is in an epsilon cycle (no input), but output is written. """ - from copy import deepcopy result = deepcopy(self) for initial in result.iter_initial_states(): for final in result.iter_final_states(): @@ -8694,8 +8670,6 @@ def projection(self, what='input'): Transition from 'A' to 'A': 1|-, Transition from 'B' to 'B': 0|-] """ - from copy import copy, deepcopy - new = Automaton() # TODO: use empty_copy() in order to # preserve on_duplicate_transition and future extensions. @@ -8808,8 +8782,6 @@ def transposition(self, reverse_output_labels=True): NotImplementedError: Transposition for transducers with final output words is not implemented. """ - from copy import deepcopy - if reverse_output_labels: rewrite_output = lambda word: list(reversed(word)) else: @@ -9051,7 +9023,6 @@ def completion(self, sink=None): sage: G.state(2) is s True """ - from copy import deepcopy result = deepcopy(self) if result.is_complete(): return result @@ -9531,7 +9502,6 @@ def merged_transitions(self): sage: T2 is T1 True """ - from copy import deepcopy def key(transition): return (transition.to_state, transition.word_out) @@ -9856,13 +9826,10 @@ def with_final_word_out(self, letters, allow_non_final=True): ... ValueError: letters is not allowed to be an empty list. """ - from copy import deepcopy - new = deepcopy(self) new.construct_final_word_out(letters, allow_non_final) return new - def construct_final_word_out(self, letters, allow_non_final=True): """ This is an inplace version of :meth:`.with_final_word_out`. See @@ -11336,14 +11303,13 @@ def _repr_(self): Automaton with 2 states """ - if len(self._states_)==0: + if not self._states_: return "Empty automaton" - if len(self._states_)==1: + if len(self._states_) == 1: return "Automaton with 1 state" else: return "Automaton with %s states" % len(self._states_) - def _latex_transition_label_(self, transition, format_function=None): r""" @@ -12106,8 +12072,6 @@ class is created and is used during the processing. :meth:`~FiniteStateMachine.__call__`, :class:`FSMProcessIterator`. """ - from copy import copy - # set default values options = copy(self._process_default_options_) options.update(kwargs) @@ -12394,8 +12358,6 @@ def with_output(self, word_out_function=None): sage: B.with_output(lambda t: [c.upper() for c in t.word_in]).input_projection() == B True """ - from copy import copy - if word_out_function is None: word_out_function = lambda transition: copy(transition.word_in) new = Transducer() @@ -12547,14 +12509,13 @@ def _repr_(self): Transducer with 2 states """ - if len(self._states_)==0: + if not self._states_: return "Empty transducer" - if len(self._states_)==1: + if len(self._states_) == 1: return "Transducer with 1 state" else: return "Transducer with %s states" % len(self._states_) - def _latex_transition_label_(self, transition, format_function=None): r""" @@ -12991,13 +12952,10 @@ def simplification(self): Transition from (1,) to (0,): 0|0, Transition from (1,) to (1,): 1|1] """ - from copy import deepcopy - fsm = deepcopy(self) fsm.prepone_output() return fsm.quotient(fsm.equivalence_classes()) - def process(self, *args, **kwargs): """ Return whether the transducer accepts the input, the state @@ -13294,8 +13252,6 @@ class is created and is used during the processing. ... TypeError: No input tape given. """ - from copy import copy - # set default values options = copy(self._process_default_options_) options.update(kwargs) @@ -13512,15 +13468,12 @@ def __deepcopy__(self, memo): sage: TC2.tape_cache_manager is TC3.tape_cache_manager True """ - from copy import deepcopy - new = type(self)(self.tape_cache_manager, self.tape, self.tape_ended, self.position, self.is_multitape) new.cache = deepcopy(self.cache, memo) return new - def deepcopy(self, memo=None): """ Returns a deepcopy of ``self``. @@ -13550,10 +13503,8 @@ def deepcopy(self, memo=None): sage: TC2.cache is TC3.cache False """ - from copy import deepcopy return deepcopy(self, memo) - def read(self, track_number): """ Reads one letter from the given track of the input tape into @@ -14077,13 +14028,10 @@ def __deepcopy__(self, memo): sage: TC3._visited_states_ {1} """ - from copy import copy - new = super(_FSMTapeCacheDetectEpsilon_, self).__deepcopy__(memo) new._visited_states_ = copy(self._visited_states_) return new - def _transition_possible_test_(self, word_in): """ This helper function tests whether ``word_in`` equals ``epsilon``, @@ -14799,9 +14747,7 @@ def _push_branches_(self, state, tape_cache, outputs): +-- tape at 0, [[]] + at state 'c' +-- tape at 0, [[]] - """ - from copy import deepcopy - + """ self._push_branch_(state, tape_cache, outputs) if not self.check_epsilon_transitions: return @@ -14824,7 +14770,6 @@ def _push_branches_(self, state, tape_cache, outputs): new_out = [o + list(eps_out) for o in outputs] self._push_branch_(eps_state, deepcopy(tape_cache), new_out) - def __next__(self): """ Makes one step in processing the input tape. @@ -14903,11 +14848,10 @@ def __next__(self): ....: print("{} {}".format(state, process)) sage: N.state(0).hook = h_old sage: N.process([0, 0]) - doctest:...: DeprecationWarning: The hook of state 0 cannot - be processed: It seems that you are using an old-style hook, - which is deprecated. - See http://trac.sagemath.org/16538 for details. - (False, 0, [1, 1]) + Traceback (most recent call last): + ... + ValueError: invalid input + sage: def h_new(process, state, outputs): ....: print("{} {}".format(state, outputs)) sage: N.state(0).hook = h_new @@ -14917,7 +14861,6 @@ def __next__(self): 0 [[1, 1]] (False, 0, [1, 1]) """ - from copy import deepcopy import heapq if not self._current_: @@ -14933,11 +14876,7 @@ def step(current_state, input_tape, outputs): state_said_finished = False if hasattr(current_state, 'hook'): if len(sage_getargspec(current_state.hook).args) == 2: - from sage.misc.superseded import deprecation - deprecation(16538, 'The hook of state %s cannot be ' - 'processed: It seems that you are using an ' - 'old-style hook, which is deprecated. ' - % (current_state,)) + raise ValueError('invalid input') else: try: self._current_branch_input_tape_ = input_tape # for preview_word diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 57af2125f87..45cd7d48f3b 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -315,9 +315,6 @@ def __classcall_private__(cls, base_ring, basis_keys=None, category=None, base_ring, basis_keys, category=category, prefix=prefix, names=names, **keywords) - # We make this explicitly a Python class so that the methods, - # specifically _mul_, from category framework still works. -- TCS - # We also need to deal with the old pickles too. -- TCS Element = IndexedFreeModuleElement @lazy_attribute diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 82970dea410..1bf18b77bd3 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -3388,7 +3388,7 @@ def from_minimal_schnyder_wood(graph): voisins_in[u] = restricted_embedding[u][1:] else: voisins_in[u] = list(restricted_embedding[u]) - voisins_in[u].reverse() # pour les avoir dans le bon sens + voisins_in[u].reverse() # To have them in the right order graph0.set_embedding(restricted_embedding) diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index efeafb294c2..547c5c579d1 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -42,7 +42,6 @@ from sage.combinat.root_system.weyl_group import WeylGroup from sage.combinat.core import Core from sage.rings.all import ZZ -from sage.misc.misc import uniq from sage.functions.generalized import sgn from sage.misc.flatten import flatten from sage.combinat.skew_partition import SkewPartition @@ -918,7 +917,11 @@ def residues_of_entries(self, v): sage: t.residues_of_entries(1) [2, 3] """ - return uniq([(j - i)%(self.k+1) for i in range(len(self)) for j in range(len(self[i])) if self[i][j] == v]) + S = set((j - i) % (self.k+1) + for i in range(len(self)) + for j in range(len(self[i])) + if self[i][j] == v) + return sorted(S) def dictionary_of_coordinates_at_residues(self, v): r""" @@ -2517,7 +2520,7 @@ def _is_valid_marked( self ): T = self.to_standard_list() size = Core([len(t) for t in T], self.k+1).length() inner_size = Core([y for y in (len([x for x in row if x is None]) for row in T) if y > 0], self.k+1).length() - if len(uniq([v for v in flatten(list(T)) if v in ZZ and v<0]))!=size-inner_size: + if len(set(v for v in flatten(list(T)) if v in ZZ and v < 0)) != size - inner_size: return False # TT does not have exactly self.size() marked cells for i in range(len(T)): for j in range(len(T[i])): @@ -3174,7 +3177,7 @@ def height_of_ribbon(self, v): sage: StrongTableau([],4).height_of_ribbon(1) 0 """ - return len(uniq([c[0] for c in self.cells_of_marked_ribbon(v)])) + return len(set(c[0] for c in self.cells_of_marked_ribbon(v))) def number_of_connected_components(self, v): r""" diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index 1dce9080e06..2c949f97e97 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -576,11 +576,11 @@ cdef class dancing_linksWrapper: def one_solution(self, ncpus=None, column=None): r""" - Return the first solution found after splitting the problem to - allow parallel computation. + Return the first solution found. - Usefull when it is very hard just to find one solution to a given - problem. + This method allows parallel computations which might be useful for + some kind of problems when it is very hard just to find one + solution. INPUT: @@ -588,13 +588,21 @@ cdef class dancing_linksWrapper: subprocesses to use at the same time. If ``None``, it detects the number of effective CPUs in the system using :func:`sage.parallel.ncpus.ncpus()`. + If ``ncpus=1``, the first solution is searched serially. - ``column`` -- integer (default: ``None``), the column used to split - the problem, if ``None`` a random column is chosen + the problem (see :meth:`restrict`). If ``None``, a random column + is chosen. This argument is ignored if ``ncpus=1``. OUTPUT: list of rows or ``None`` if no solution is found + .. NOTE:: + + For some case, increasing the number of cpus makes it + faster. For other instances, ``ncpus=1`` is faster. It all + depends on problem which is considered. + EXAMPLES:: sage: from sage.combinat.matrices.dancing_links import dlx_solver @@ -646,6 +654,9 @@ cdef class dancing_linksWrapper: sage: any(p.intersection(q) for p,q in combinations(subsets, 2)) False """ + if ncpus == 1: + return self.get_solution() if self.search() else None + if column is None: from random import randrange column = randrange(self.ncols()) @@ -721,6 +732,25 @@ cdef class dancing_linksWrapper: [7, 8], [15]] + If ``ncpus=1``, the computation is not done in parallel:: + + sage: sorted(sorted(s) for s in dlx.all_solutions(ncpus=1)) + [[1, 2, 3, 4], + [1, 2, 10], + [1, 3, 9], + [1, 4, 8], + [1, 14], + [2, 3, 7], + [2, 4, 6], + [2, 13], + [3, 4, 5], + [3, 12], + [4, 11], + [5, 10], + [6, 9], + [7, 8], + [15]] + TESTS: When no solution is found:: @@ -735,6 +765,14 @@ cdef class dancing_linksWrapper: sage: [d.all_solutions(column=i) for i in range(6)] [[], [], [], [], [], []] """ + if ncpus == 1: + if self._x.search_is_started(): + self.reinitialize() + L = [] + while self.search(): + L.append(self.get_solution()) + return L + if column is None: from random import randrange column = randrange(self.ncols()) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index bec5e98bcda..3f5eda9c0d7 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -719,20 +719,19 @@ def RSHCD_324(e): sage: for e in [1,-1]: # long time ....: M = RSHCD_324(e) ....: print("{} {} {}".format(M==M.T,is_hadamard_matrix(M),all([M[i,i]==1 for i in range(324)]))) - ....: print(set(map(sum,M))) + ....: print(list(set(sum(x) for x in M))) True True True - set([18]) + [18] True True True - set([-18]) + [-18] REFERENCE: .. [CP16] \N. Cohen, D. Pasechnik, - Implementing Brouwer's database of strongly regular graphs, + *Implementing Brouwer's database of strongly regular graphs*, Designs, Codes, and Cryptography, 2016 :doi:`10.1007/s10623-016-0264-x` """ - from sage.graphs.generators.smallgraphs import JankoKharaghaniTonchevGraph as JKTG M = JKTG().adjacency_matrix() M = J(324) - 2*M @@ -983,11 +982,10 @@ def GS_skew_hadamard_smallcases(n, existence=False, check=True): 92 x 92 dense matrix over Integer Ring... sage: GS_skew_hadamard_smallcases(100) """ - from sage.combinat.matrices.hadamard_matrix import\ - williamson_goethals_seidel_skew_hadamard_matrix as WGS + WGS = williamson_goethals_seidel_skew_hadamard_matrix def pmtoZ(s): - return [1 if x == '+' else -1 for x in s] + return [1 if x == '+' else -1 for x in s] if existence: return n in [36, 52, 92] @@ -1209,6 +1207,7 @@ def symmetric_conference_matrix(n, check=True): assert (C==C.T and C**2==(n-1)*I(n)) return C + def szekeres_difference_set_pair(m, check=True): r""" Construct Szekeres `(2m+1,m,1)`-cyclic difference family @@ -1248,16 +1247,18 @@ def szekeres_difference_set_pair(m, check=True): t = F.multiplicative_generator()**2 G = F.cyclotomic_cosets(t, cosets=[F.one()])[0] sG = set(G) - A = filter(lambda a: a-F.one() in sG, G) - B = filter(lambda b: b+F.one() in sG, G) + A = [a for a in G if a - F.one() in sG] + B = [b for b in G if b + F.one() in sG] if check: from itertools import product, chain - assert(len(list(A)) == len(list(B)) == m) - if m>1: - assert(sG==set([xy[0]/xy[1] for xy in chain(product(A,A), product(B,B))])) - assert(all(F.one()/b+F.one() in sG for b in B)) - assert(not any(F.one()/a-F.one() in sG for a in A)) - return G,A,B + assert(len(A) == len(B) == m) + if m > 1: + assert(sG == set([xy[0] / xy[1] + for xy in chain(product(A, A), product(B, B))])) + assert(all(F.one() / b + F.one() in sG for b in B)) + assert(not any(F.one() / a - F.one() in sG for a in A)) + return G, A, B + def typeI_matrix_difference_set(G,A): r""" diff --git a/src/sage/combinat/matrices/latin.py b/src/sage/combinat/matrices/latin.py index ac2d2148b2d..2aa9da35ab2 100644 --- a/src/sage/combinat/matrices/latin.py +++ b/src/sage/combinat/matrices/latin.py @@ -141,7 +141,6 @@ from sage.groups.perm_gps.permgroup import PermutationGroup from sage.arith.all import is_prime from sage.rings.finite_rings.finite_field_constructor import FiniteField -from sage.misc.misc import uniq from sage.misc.flatten import flatten from .dlxcpp import DLXCPP @@ -201,7 +200,6 @@ def dumps(self): sage: back_circulant(2) == loads(dumps(back_circulant(2))) True """ - return dumps(self.square) def __str__(self): @@ -475,8 +473,7 @@ def is_empty_column(self, c): sage: L.is_empty_column(0) True """ - - return uniq(self.column(c)) == [-1] + return list(set(self.column(c))) == [-1] def is_empty_row(self, r): """ @@ -492,8 +489,7 @@ def is_empty_row(self, r): sage: L.is_empty_row(0) True """ - - return uniq(self.row(r)) == [-1] + return list(set(self.row(r))) == [-1] def nr_distinct_symbols(self): """ @@ -513,10 +509,8 @@ def nr_distinct_symbols(self): sage: L.nr_distinct_symbols() 2 """ - - symbols = uniq(flatten([list(x) for x in list(self.square)])) + symbols = set(flatten([list(x) for x in list(self.square)])) symbols = [x for x in symbols if x >= 0] - return len(symbols) def apply_isotopism(self, row_perm, col_perm, sym_perm): @@ -1193,7 +1187,7 @@ def disjoint_mate_dlxcpp_rows_and_map(self, allow_subtrade): # If this is an empty cell of self then we do nothing. if self[r, c] < 0: continue - for e in uniq(list(valsrow) + list(valscol)): + for e in sorted(set(list(valsrow) + list(valscol))): # These should be constants c_OFFSET = e + c*n r_OFFSET = e + r*n + n*n @@ -1254,8 +1248,6 @@ def find_disjoint_mates(self, nr_to_find = None, allow_subtrade = False): assert self.nrows() == self.ncols() - n = self.nrows() - dlx_rows, cmap = self.disjoint_mate_dlxcpp_rows_and_map(allow_subtrade) nr_found = 0 @@ -1628,6 +1620,7 @@ def beta1(rce, T1, T2): raise PairNotBitrade + def beta2(rce, T1, T2): """ Find the unique (r, x, e) in T2 such that (r, c, e) is in T1. @@ -2200,7 +2193,6 @@ def LatinSquare_generator(L_start, check_assertions = False): from copy import copy L = copy(L_start) - L_rce = L L_cer = LatinSquare(n, n) L_erc = LatinSquare(n, n) @@ -2834,8 +2826,6 @@ def dlxcpp_find_completions(P, nr_to_find = None): """ assert P.nrows() == P.ncols() - n = P.nrows() - dlx_rows, cmap = dlxcpp_rows_and_map(P) SOLUTIONS = {} @@ -2843,7 +2833,8 @@ def dlxcpp_find_completions(P, nr_to_find = None): x.sort() SOLUTIONS[tuple(x)] = True - if nr_to_find is not None and len(SOLUTIONS) >= nr_to_find: break + if nr_to_find is not None and len(SOLUTIONS) >= nr_to_find: + break comps = [] diff --git a/src/sage/combinat/multiset_partition_into_sets_ordered.py b/src/sage/combinat/multiset_partition_into_sets_ordered.py index 85804441f1c..6ca6954a2e9 100755 --- a/src/sage/combinat/multiset_partition_into_sets_ordered.py +++ b/src/sage/combinat/multiset_partition_into_sets_ordered.py @@ -2769,6 +2769,7 @@ def _base_iterator(constraints): # else return None + def _iterator_weight(weight): """ An iterator for the ordered multiset partitions into sets with weight given by @@ -2807,33 +2808,28 @@ def _iterator_weight(weight): (frozenset({1}), frozenset({3}), frozenset({1})), (frozenset({1, 3}), frozenset({1})), (frozenset({3}), frozenset({1}), frozenset({1}))] + sage: list(_iterator_weight([])) + [()] """ + # "weight" should be a dict mapping keys to weights if isinstance(weight, (list, tuple)): - weight = {k+1: val for k,val in enumerate(weight) if val > 0} - if isinstance(weight, dict): - multiset = tuple([k for k in sorted(weight) for _ in range(weight[k])]) + weight = {k+1: val for k, val in enumerate(weight) if val} + + # We first map the arbitrary keys to integers to combat unreliable + # sorting behavior. + keys = tuple(set(weight)) + multiset = [] + for i, key in enumerate(keys): + multiset += [i] * weight[key] + + # We build ordered multiset partitions into sets of `X` by + # permutation + deconcatenation + for alpha in Permutations_mset(multiset): + co = _break_at_descents(alpha, weak=True) + for A in OrderedMultisetPartitionIntoSets(co).finer(strong=True): + B = tuple([frozenset([keys[i] for i in block]) for block in A]) + yield B - if not multiset: - yield () - else: - # We build ordered multiset partitions into sets of `X` by permutation + deconcatenation - # We first standardize the multiset to combat unreliable sorting behavior. - em = enumerate(set(multiset)) - key_to_indx = {} - indx_to_key = {} - for (i,key) in em: - key_to_indx[key] = i - indx_to_key[i] = key - std_multiset = [] - for a in multiset: - std_multiset.append(key_to_indx[a]) - std_multiset = sorted(std_multiset) - - for alpha in Permutations_mset(std_multiset): - co = _break_at_descents(alpha, weak=True) - for A in OrderedMultisetPartitionIntoSets(co).finer(strong=True): - B = tuple([frozenset([indx_to_key[i] for i in block]) for block in A]) - yield B def _iterator_size(size, length=None, alphabet=None): r""" diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index d8b1bc21388..ae7d830ed58 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -37,7 +37,7 @@ .. [HLNT09] \F. Hivert, J.-G. Luque, J.-C. Novelli, J.-Y. Thibon, *The (1-E)-transform in combinatorial Hopf algebras*. :arxiv:`math/0912.0184v2` - + .. [LMvW13] Kurt Luoto, Stefan Mykytiuk and Stephanie van Willigenburg, *An introduction to quasisymmetric Schur functions -- Hopf algebras, quasisymmetric functions, and Young composition tableaux*, @@ -69,13 +69,13 @@ - Chris Berg - Darij Grinberg """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Jason Bandlow , # 2012 Franco Saliola , # 2012 Chris Berg # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import six from sage.misc.bindable_class import BindableClass @@ -93,10 +93,11 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.ncsf_qsym.generic_basis_code import BasesOfQSymOrNCSF -from sage.combinat.ncsf_qsym.combinatorics import (number_of_fCT, number_of_SSRCT, +from sage.combinat.ncsf_qsym.combinatorics import (number_of_fCT, number_of_SSRCT, compositions_order, coeff_pi, coeff_lp, coeff_sp, coeff_ell) from sage.combinat.ncsf_qsym.ncsf import NonCommutativeSymmetricFunctions from sage.combinat.words.word import Word +from sage.combinat.tableau import StandardTableaux from sage.misc.cachefunc import cached_method @@ -183,6 +184,7 @@ class QuasiSymmetricFunctions(UniqueRepresentation, Parent): sage: QSym.category() Join of Category of hopf algebras over Rational Field and Category of graded algebras over Rational Field + and Category of commutative algebras over Rational Field and Category of monoids with realizations and Category of coalgebras over Rational Field with realizations @@ -533,6 +535,8 @@ class QuasiSymmetricFunctions(UniqueRepresentation, Parent): Quasisymmetric functions over the Rational Field sage: QSym.base_ring() Rational Field + sage: algebras.QSym(QQ) is QSym + True """ def __init__(self, R): """ @@ -550,7 +554,7 @@ def __init__(self, R): # change the line below to assert(R in Rings()) once MRO issues from #15536, #15475 are resolved assert(R in Fields() or R in Rings()) # side effect of this statement assures MRO exists for R self._base = R # Won't be needed once CategoryObject won't override base_ring - category = GradedHopfAlgebras(R) # TODO: .Commutative() + category = GradedHopfAlgebras(R).Commutative() self._category = category Parent.__init__(self, category = category.WithRealizations()) @@ -592,6 +596,11 @@ def __init__(self, R): Sym_m_to_M.register_as_coercion() self.to_symmetric_function = Sym_m_to_M.section() + Sym_s_to_F = Sym.s().module_morphism(Fundamental._from_schur_on_basis, + unitriangular='upper', + codomain=Fundamental, category=category) + Sym_s_to_F.register_as_coercion() + def _repr_(self): r""" EXAMPLES:: @@ -2181,6 +2190,34 @@ def __init__(self, QSym): prefix='F', bracket=False, category=QSym.Bases()) + + def _from_schur_on_basis(self, la): + r""" + Maps the Schur symmetric function indexed by ``la`` to the + Fundamental basis. + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).schur() + sage: F = QuasiSymmetricFunctions(QQ).Fundamental() + sage: F(s[2,2]-s[3,1]) # indirect doctest + F[1, 2, 1] - F[1, 3] - F[3, 1] + + sage: F._from_schur_on_basis(Partition([])) + F[] + + sage: F._from_schur_on_basis(Partition([2,2,2])) + F[1, 1, 2, 1, 1] + F[1, 2, 1, 2] + F[1, 2, 2, 1] + F[2, 1, 2, 1] + F[2, 2, 2] + """ + C = self._indices + res = 0 + n = la.size() + for T in StandardTableaux(la): + des = T.standard_descents() + comp = C.from_descents([d-1 for d in des], n) + res += self.monomial(comp) + return res + def dual(self): r""" Return the dual basis to the Fundamental basis. This is the ribbon @@ -2864,8 +2901,8 @@ def _from_monomial_transition_matrix(self, n): # ZZ is faster than over QQ for inverting a matrix from sage.rings.all import ZZ MS = MatrixSpace(ZZ, len(CO)) - return (MS([[number_of_SSRCT(al,be) for al in CO] for be in CO]).inverse(), - CO) + M = MS([[number_of_SSRCT(al, be) for al in CO] for be in CO]) + return (M.inverse_of_unit(), CO) @cached_method def _from_monomial_on_basis(self, comp): @@ -3556,6 +3593,7 @@ def _precompute_cache(self, n, to_self_cache, from_self_cache, transition_matric # "inverse_transition = ~transition_matrix_n" because that # tends to cast the entries of the matrix into a quotient # field even if this is unnecessary. + # MAYBE use .inverse_of_unit() ? # TODO: This still looks fragile when the base ring is weird! # Possibly work over ZZ in this method? @@ -4038,4 +4076,3 @@ def _to_Monomial_on_basis(self, I): z = R(I.to_partition().centralizer_size()) Monomial = self.realization_of().Monomial() return Monomial._from_dict({J: z / coeff_sp(I,J) for J in I.fatter()}) - diff --git a/src/sage/combinat/parallelogram_polyomino.py b/src/sage/combinat/parallelogram_polyomino.py index 2601162d214..11a5e648899 100644 --- a/src/sage/combinat/parallelogram_polyomino.py +++ b/src/sage/combinat/parallelogram_polyomino.py @@ -1020,10 +1020,10 @@ def check(self): for i in range(len(upper_path)-1): p_up[1-upper_path[i]] += 1 p_down[1-lower_path[i]] += 1 - if(p_up[0] <= p_down[0] or p_down[1] <= p_up[1]): + if (p_up[0] <= p_down[0] or p_down[1] <= p_up[1]): raise ValueError("the lower and upper paths are crossing") - p_up[1-upper_path[-1]] += 1 - p_down[1-lower_path[-1]] += 1 + p_up[1 - upper_path[-1]] += 1 + p_down[1 - lower_path[-1]] += 1 if (p_up[0] != p_down[0] or p_up[1] != p_down[1]): raise ValueError("the two paths have distinct ends") @@ -1338,7 +1338,7 @@ def _to_ordered_tree_via_dyck(self): See :meth:`_to_dyck_delest_viennot` for the exact references. See also :meth:`to_ordered_tree()`. - EXAMPLES: + EXAMPLES:: sage: pp = ParallelogramPolyomino([[0, 1], [1, 0]]) sage: pp._to_ordered_tree_via_dyck() diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index b29a4118a50..4673cff8b2b 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -27,7 +27,6 @@ - If given coordinates of the form ``(r, c)``, then use Python's \*-operator. - - Throughout this documentation, for a partition `\lambda` we will denote its conjugate partition by `\lambda^{\prime}`. For more on conjugate partitions, see :meth:`Partition.conjugate()`. @@ -62,6 +61,8 @@ all in the category framework except ``PartitionsRestricted`` (which will eventually be removed). Cleaned up documentation. +- Matthew Lancellotti (2018-09-14): Added a bunch of "k" methods to Partition. + EXAMPLES: There are `5` partitions of the integer `4`:: @@ -280,10 +281,10 @@ # **************************************************************************** from __future__ import print_function, absolute_import +from copy import copy import six -from six.moves import range +from six.moves import range, zip -from sage.interfaces.all import gap from sage.libs.all import pari from sage.libs.flint.arith import number_of_partitions as flint_number_of_partitions @@ -310,7 +311,7 @@ from sage.rings.integer import Integer from sage.rings.infinity import infinity -from .combinat import CombinatorialClass, CombinatorialElement +from .combinat import CombinatorialElement from . import tableau from . import permutation from . import composition @@ -322,7 +323,7 @@ from sage.combinat.combinatorial_map import combinatorial_map from sage.groups.perm_gps.permgroup import PermutationGroup from sage.graphs.dot2tex_utils import have_dot2tex - +from sage.functions.other import binomial class Partition(CombinatorialElement): r""" @@ -521,6 +522,9 @@ def __init__(self, parent, mu): """ Initialize ``self``. + We assume that ``mu`` is a weakly decreasing list of + non-negative elements in ``ZZ``. + EXAMPLES:: sage: p = Partition([3,1]) @@ -534,28 +538,18 @@ def __init__(self, parent, mu): Traceback (most recent call last): ... ValueError: [3, 1, 7] is not an element of Partitions + """ if isinstance(mu, Partition): - # Since we are (suppose to be) immutable, we can share the underlying data + # since we are (suppose to be) immutable, we can share the underlying data CombinatorialElement.__init__(self, parent, mu._list) - return - - elif not mu: - CombinatorialElement.__init__(self, parent, mu) - - elif (all(mu[i] in NN and mu[i] >= mu[i+1] for i in range(len(mu)-1)) - and mu[-1] in NN): - if mu[-1] == 0: # From the above checks, the last value must be == 0 or > 0 - # strip all trailing zeros - temp = len(mu) - 1 - while temp > 0 and mu[temp-1] == 0: - temp -= 1 - CombinatorialElement.__init__(self, parent, mu[:temp]) - else: - CombinatorialElement.__init__(self, parent, mu) - else: - raise ValueError("%s is not a valid partition"%repr(mu)) + if mu and not mu[-1]: + # direct callers might assume that mu is not modified + mu = mu[:-1] + while mu and not mu[-1]: + mu.pop() + CombinatorialElement.__init__(self, parent, mu) @cached_method def __hash__(self): @@ -1253,6 +1247,489 @@ def sign(self): """ return (-1)**(self.size()-self.length()) + def k_size(self, k): + r""" + Given a partition ``self`` and a ``k``, return the size of the + `k`-boundary. + + This is the same as the length method + :meth:`sage.combinat.core.Core.length` of the + :class:`sage.combinat.core.Core` object, with the exception that here we + don't require ``self`` to be a `k+1`-core. + + EXAMPLES:: + + sage: Partition([2, 1, 1]).k_size(1) + 2 + sage: Partition([2, 1, 1]).k_size(2) + 3 + sage: Partition([2, 1, 1]).k_size(3) + 3 + sage: Partition([2, 1, 1]).k_size(4) + 4 + + .. SEEALSO:: + + :meth:`k_boundary`, :meth:`SkewPartition.size` + """ + return self.k_boundary(k).size() + + def boundary(self): + r""" + Return the integer coordinates of points on the boundary of ``self``. + + For the following description, picture the Ferrer's diagram of ``self`` + using the French convention. Recall that the French convention puts + the longest row on the bottom and the shortest row on the top. In + addition, interpret the Ferrer's diagram as 1 x 1 cells in the Euclidean + plane. So if ``self`` was the partition [3, 1], the lower-left vertices + of the 1 x 1 cells in the Ferrer's diagram would be (0, 0), (1, 0), + (2, 0), and (0, 1). + + The boundary of a partition is the set `\{ \text{NE}(d) \mid \forall + d\:\text{diagonal} \}`. That is, for every diagonal line `y = x + b` + where `b \in \mathbb{Z}`, we find the northeasternmost (NE) point on + that diagonal which is also in the Ferrer's diagram. + + The boundary will go from bottom-right to top-left. + + EXAMPLES: + + Consider the partition (1) depicted as a square on a cartesian plane + with vertices (0, 0), (1, 0), (1, 1), and (0, 1). Three of those + vertices in the appropriate order form the boundary:: + + sage: Partition([1]).boundary() + [(1, 0), (1, 1), (0, 1)] + + The partition (3, 1) can be visualized as three squares on a cartisian + plane. The coordinates of the appropriate vertices form the boundary:: + + sage: Partition([3, 1]).boundary() + [(3, 0), (3, 1), (2, 1), (1, 1), (1, 2), (0, 2)] + + TESTS:: + + sage: Partition([1]).boundary() + [(1, 0), (1, 1), (0, 1)] + sage: Partition([2, 1]).boundary() + [(2, 0), (2, 1), (1, 1), (1, 2), (0, 2)] + sage: Partition([3, 1]).boundary() + [(3, 0), (3, 1), (2, 1), (1, 1), (1, 2), (0, 2)] + sage: Partition([2, 1, 1]).boundary() + [(2, 0), (2, 1), (1, 1), (1, 2), (1, 3), (0, 3)] + + .. SEEALSO:: + + :meth:`k_rim`. You might have been looking for :meth:`k_boundary` + instead. + """ + def horizontal_piece(xy, bdy): + (start_x, start_y) = xy + if not bdy: + h_piece = [(start_x, start_y)] + else: + stop_x = bdy[-1][0] + y = start_y # y never changes + h_piece = [(x, y) for x in range(start_x, stop_x)] + h_piece = list(reversed(h_piece)) + return h_piece + bdy = [] + for i, part in enumerate(self): + (cell_x, cell_y) = (part - 1, i) + (x, y) = (cell_x + 1, cell_y + 1) + bdy += horizontal_piece((x, y - 1), bdy) + bdy.append((x, y)) + # add final "top-left" horizontal piece + (top_left_x, top_left_y) = (0, len(self)) + bdy += horizontal_piece((top_left_x, top_left_y), bdy) + return bdy + + def k_rim(self, k): + r""" + Return the ``k``-rim of ``self`` as a list of integer coordinates. + + The `k`-rim of a partition is the "line between" (or "intersection of") + the `k`-boundary and the `k`-interior. (Section 2.3 of [HM2011]_) + + It will be output as an ordered list of integer coordinates, where the + origin is `(0, 0)`. It will start at the top-left of the `k`-rim (using + French convention) and end at the bottom-right. + + EXAMPLES: + + Consider the partition (3, 1) split up into its 1-interior and + 1-boundary: + + .. image:: ../../media/k-rim.JPG + :height: 180px + :align: center + + The line shown in bold is the 1-rim, and that information is equivalent + to the integer coordinates of the points that occur along that line:: + + sage: Partition([3, 1]).k_rim(1) + [(3, 0), (2, 0), (2, 1), (1, 1), (0, 1), (0, 2)] + + TESTS:: + + sage: Partition([1]).k_rim(0) + [(1, 0), (1, 1), (0, 1)] + sage: Partition([3, 1]).k_rim(0) + [(3, 0), (3, 1), (2, 1), (1, 1), (1, 2), (0, 2)] + sage: Partition([3, 1]).k_rim(1) + [(3, 0), (2, 0), (2, 1), (1, 1), (0, 1), (0, 2)] + sage: Partition([3, 1]).k_rim(2) + [(3, 0), (2, 0), (1, 0), (1, 1), (0, 1), (0, 2)] + sage: Partition([3, 1]).k_rim(3) + [(3, 0), (2, 0), (1, 0), (1, 1), (0, 1), (0, 2)] + + .. SEEALSO:: + + :meth:`k_interior`, :meth:`k_boundary`, :meth:`boundary` + """ + interior_rim = self.k_interior(k).boundary() + # get leftmost vertical line + interior_top_left_y = interior_rim[-1][1] + v_piece = [(0, y) for y in range(interior_top_left_y+1, len(self)+1)] + # get bottommost horizontal line + interior_bottom_right_x = interior_rim[0][0] + if self: + ptn_bottom_right_x = self[0] + else: + ptn_bottom_right_x = 0 + h_piece = [(x, 0) for x in + range(ptn_bottom_right_x, interior_bottom_right_x, -1)] + # glue together with boundary + rim = h_piece + interior_rim + v_piece + return rim + + def k_row_lengths(self, k): + r""" + Return the ``k``-row-shape of the partition ``self``. + + This is equivalent to taking the `k`-boundary of the partition and then + returning the row-shape of that. We do *not* discard rows of length 0. + (Section 2.2 of [LLMS2013]_) + + EXAMPLES:: + + sage: Partition([6, 1]).k_row_lengths(2) + [2, 1] + + sage: Partition([4, 4, 4, 3, 2]).k_row_lengths(2) + [0, 1, 1, 1, 2] + + .. SEEALSO:: + + :meth:`k_column_lengths`, :meth:`k_boundary`, + :meth:`SkewPartition.row_lengths`, + :meth:`SkewPartition.column_lengths` + """ + return self.k_boundary(k).row_lengths() + + def k_column_lengths(self, k): + r""" + Return the ``k``-column-shape of the partition ``self``. + + This is the 'column' analog of :meth:`k_row_lengths`. + + EXAMPLES:: + + sage: Partition([6, 1]).k_column_lengths(2) + [1, 0, 0, 0, 1, 1] + + sage: Partition([4, 4, 4, 3, 2]).k_column_lengths(2) + [1, 1, 1, 2] + + .. SEEALSO:: + + :meth:`k_row_lengths`, :meth:`k_boundary`, + :meth:`SkewPartition.row_lengths`, + :meth:`SkewPartition.column_lengths` + """ + return self.k_boundary(k).column_lengths() + + def has_rectangle(self, h, w): + r""" + Return ``True`` if the Ferrer's diagram of ``self`` has ``h`` + (*or more*) rows of length ``w`` (*exactly*). + + INPUT: + + - ``h`` -- An integer `h \geq 1`. The (*minimum*) height of the + rectangle. + + - ``w`` -- An integer `w \geq 1`. The width of the rectangle. + + EXAMPLES:: + + sage: Partition([3, 3, 3, 3]).has_rectangle(2, 3) + True + sage: Partition([3, 3]).has_rectangle(2, 3) + True + sage: Partition([4, 3]).has_rectangle(2, 3) + False + sage: Partition([3]).has_rectangle(2, 3) + False + + TESTS:: + + sage: Partition([1, 1, 1]).has_rectangle(4, 1) + False + sage: Partition([1, 1, 1]).has_rectangle(3, 1) + True + sage: Partition([1, 1, 1]).has_rectangle(2, 1) + True + sage: Partition([1, 1, 1]).has_rectangle(1, 2) + False + sage: Partition([3]).has_rectangle(1, 3) + True + sage: Partition([3]).has_rectangle(1, 2) + False + sage: Partition([3]).has_rectangle(2, 3) + False + + .. SEEALSO:: + + :meth:`has_k_rectangle` + """ + assert h >= 1 + assert w >= 1 + num_rows_of_len_w = self.to_exp(w)[w - 1] + return num_rows_of_len_w >= h + + def has_k_rectangle(self, k): + r""" + Return ``True`` if the Ferrer's diagram of ``self`` contains `k-i+1` + rows (*or more*) of length `i` (*exactly*) for any `i` in `[1, k]`. + + This is mainly a helper function for :meth:`is_k_reducible` and + :meth:`is_k_irreducible`, the only difference between this function and + :meth:`is_k_reducible` being that this function allows any partition as + input while :meth:`is_k_reducible` requires the input to be `k`-bounded. + + EXAMPLES: + + The partition [1, 1, 1] has at least 2 rows of length 1:: + + sage: Partition([1, 1, 1]).has_k_rectangle(2) + True + + The partition [1, 1, 1] does *not* have 4 rows of length 1, 3 rows of + length 2, 2 rows of length 3, nor 1 row of length 4:: + + sage: Partition([1, 1, 1]).has_k_rectangle(4) + False + + TESTS:: + + sage: Partition([1]).has_k_rectangle(1) + True + sage: Partition([1]).has_k_rectangle(2) + False + sage: Partition([1, 1, 1]).has_k_rectangle(3) + True + sage: Partition([1, 1, 1]).has_k_rectangle(2) + True + sage: Partition([1, 1, 1]).has_k_rectangle(4) + False + sage: Partition([3]).has_k_rectangle(3) + True + sage: Partition([3]).has_k_rectangle(2) + False + sage: Partition([3]).has_k_rectangle(4) + False + + .. SEEALSO:: + + :meth:`is_k_irreducible`, :meth:`is_k_reducible`, + :meth:`has_rectangle` + """ + return any(self.has_rectangle(a, b) for (a, b) in + [(k-i+1, i) for i in range(1, k+1)]) + + def is_k_bounded(self, k): + r""" + Return ``True`` if the partition ``self`` is bounded by ``k``. + + EXAMPLES:: + + sage: Partition([4, 3, 1]).is_k_bounded(4) + True + sage: Partition([4, 3, 1]).is_k_bounded(7) + True + sage: Partition([4, 3, 1]).is_k_bounded(3) + False + """ + assert k >= 0 + if self.is_empty(): + return True + else: + return self[0] <= k + + def is_k_reducible(self, k): + r""" + Return ``True`` if the partition ``self`` is ``k``-reducible. + + A `k`-bounded partition is `k`-*reducible* if its Ferrer's diagram + contains `k-i+1` rows (or more) of length `i` (exactly) for some + `i \in [1, k]`. + + (Also, a `k`-bounded partition is `k`-reducible if and only if it is not `k`-irreducible.) + + EXAMPLES: + + The partition [1, 1, 1] has at least 2 rows of length 1:: + + sage: Partition([1, 1, 1]).is_k_reducible(2) + True + + The partition [1, 1, 1] does *not* have 4 rows of length 1, 3 rows of + length 2, 2 rows of length 3, nor 1 row of length 4:: + + sage: Partition([1, 1, 1]).is_k_reducible(4) + False + + .. SEEALSO:: + + :meth:`is_k_irreducible`, :meth:`has_k_rectangle` + """ + if not self.is_k_bounded(k): + raise ValueError('we only talk about k-reducible / k-irreducible for k-bounded partitions') + return self.has_k_rectangle(k) + + def is_k_irreducible(self, k): + r""" + Return ``True`` if the partition ``self`` is ``k``-irreducible. + + A `k`-bounded partition is `k`-*irreducible* if its Ferrer's diagram + does *not* contain `k-i+1` rows (or more) of length `i` (exactly) for + every `i \in [1, k]`. + + (Also, a `k`-bounded partition is `k`-irreducible if and only if it is + not `k`-reducible.) + + EXAMPLES: + + The partition [1, 1, 1] has at least 2 rows of length 1:: + + sage: Partition([1, 1, 1]).is_k_irreducible(2) + False + + The partition [1, 1, 1] does *not* have 4 rows of length 1, 3 rows of + length 2, 2 rows of length 3, nor 1 row of length 4:: + + sage: Partition([1, 1, 1]).is_k_irreducible(4) + True + + .. SEEALSO:: + + :meth:`is_k_reducible`, :meth:`has_k_rectangle` + """ + return not self.is_k_reducible(k) + + def is_symmetric(self): + r""" + Return ``True`` if the partition ``self`` equals its own transpose. + + EXAMPLES:: + + sage: Partition([2, 1]).is_symmetric() + True + sage: Partition([3, 1]).is_symmetric() + False + """ + return self == self.conjugate() + + def next_within_bounds(self, min=[], max=None, partition_type=None): + r""" + Get the next partition lexicographically that contains ``min`` and is + contained in ``max``. + + INPUT: + + - ``min`` -- (default ``[]``, the empty partition) The + 'minimum partition' that ``next_within_bounds(self)`` must contain. + + - ``max`` -- (default ``None``) The 'maximum partition' that + ``next_within_bounds(self)`` must be contained in. If set to ``None``, + then there is no restriction. + + - ``partition_type`` -- (default ``None``) The type of partitions + allowed. For example, 'strict' for strictly decreasing partitions, or + ``None`` to allow any valid partition. + + EXAMPLES:: + + sage: m = [1, 1] + sage: M = [3, 2, 1] + sage: Partition([1, 1]).next_within_bounds(min=m, max=M) + [1, 1, 1] + sage: Partition([1, 1, 1]).next_within_bounds(min=m, max=M) + [2, 1] + sage: Partition([2, 1]).next_within_bounds(min=m, max=M) + [2, 1, 1] + sage: Partition([2, 1, 1]).next_within_bounds(min=m, max=M) + [2, 2] + sage: Partition([2, 2]).next_within_bounds(min=m, max=M) + [2, 2, 1] + sage: Partition([2, 2, 1]).next_within_bounds(min=m, max=M) + [3, 1] + sage: Partition([3, 1]).next_within_bounds(min=m, max=M) + [3, 1, 1] + sage: Partition([3, 1, 1]).next_within_bounds(min=m, max=M) + [3, 2] + sage: Partition([3, 2]).next_within_bounds(min=m, max=M) + [3, 2, 1] + sage: Partition([3, 2, 1]).next_within_bounds(min=m, max=M) == None + True + + .. SEEALSO:: + + :meth:`next` + """ + # make sure min <= self <= max + if max is not None: + assert _Partitions(max).contains(_Partitions(self)) + assert _Partitions(self).contains(_Partitions(min)) + # check for empty max + if max is not None and _Partitions(max).is_empty(): + return None + # convert partitions to lists to make them mutable + p = list(self) + min = list(min) + # if there is no max, the next partition just tacks a '1' on to the end! + if max is None: + return _Partitions(p + [1]) + # extend p and min to include 0's at the end + p = p + [0] * (len(max) - len(p)) + min = min + [0] * (len(max) - len(min)) + # finally, run the algo to find next_p + next_p = copy(p) + def condition(a, b): + if partition_type in ('strict', 'strictly decreasing'): + return a < b - 1 + elif partition_type in (None, 'weak', 'weakly decreasing'): + return a < b + else: + raise ValueError('unrecognized partition type') + for r in range(len(p) - 1, -1, -1): + if r == 0: + if (max is None or p[r] < max[r]): + next_p[r] += 1 + break + else: + return None + else: + if (max is None or p[r] < max[r]) and condition(p[r], p[r-1]): + next_p[r] += 1 + break + else: + next_p[r] = min[r] + continue + return _Partitions(next_p) + def row_standard_tableaux(self): """ Return the :class:`row standard tableaux @@ -2192,7 +2669,7 @@ def initial_column_tableau(self): r""" Return the initial column tableau of shape ``self``. - The initial column taleau of shape self is the standard tableau + The initial column taleau of shape self is the standard tableau that has the numbers `1` to `n`, where `n` is the :meth:`size` of ``self``, entered in order from top to bottom and then left to right down the columns of ``self``. @@ -2472,7 +2949,7 @@ def degree(self, e): sage: Partition([4,3]).degree(7) 0 - Therefore, the Gram determinant of `S(5,3)` when the Hecke parameter + Therefore, the Gram determinant of `S(5,3)` when the Hecke parameter `q` is "generic" is .. MATH:: @@ -2493,7 +2970,7 @@ def prime_degree(self, p): OUTPUT: - A non-negative integer + A non-negative integer The degree of a partition `\lambda` is the sum of the `e`-:meth:`degree` of the standard tableaux of shape `\lambda`, for @@ -2512,7 +2989,7 @@ def prime_degree(self, p): sage: Partition([4,3]).prime_degree(7) 0 - THerefore, the Gram determinant of `S(5,3)` when `q = 1` is + Therefore, the Gram determinant of `S(5,3)` when `q = 1` is `2^{36} 3^{15} 5^{13}`. Compare with :meth:`degree`. """ ps = [p] @@ -3290,7 +3767,7 @@ def block(self, e, multicharge=(0,)): a element of the positive root lattice of the corresponding Kac-Moody algebra. See [DJM1998]_ and [BK2009]_ for more details. - This is a useful statistics because two Specht modules for a + This is a useful statistics because two Specht modules for a Hecke algebra of type `A` belong to the same block if and only if they correspond to same element `\beta` of the root lattice, given above. @@ -3325,14 +3802,14 @@ def defect(self, e, multicharge=(0,)): The `e`-defect is the number of (connected) `e`-rim hooks that can be removed from the partition. - The defect of a partition is given by + The defect of a partition is given by .. MATH:: \text{defect}(\beta) = (\Lambda, \beta) - \tfrac12(\beta, \beta), where `\Lambda = \sum_r \Lambda_{\kappa_r}` for the multicharge - `(\kappa_1, \ldots, \kappa_{\ell})` and + `(\kappa_1, \ldots, \kappa_{\ell})` and `\beta = \sum_{(r,c)} \alpha_{(c-r) \pmod e}`, with the sum being over the cells in the partition. @@ -3863,23 +4340,38 @@ def quotient(self, length): def is_core(self, k): r""" - Tests whether the partition is a `k`-core or not. Visuallly, this can - be checked by trying to remove border strips of size `k` from ``self``. - If this is not possible, then ``self`` is a `k`-core. + Return ``True`` if the Partition ``self`` is a ``k``-core. A partition is said to be a *`k`-core* if it has no hooks of length `k`. Equivalently, a partition is said to be a `k`-core if it is its own `k`-core (where the latter is defined as in :meth:`core`). - EXAMPLES:: + Visually, this can be checked by trying to remove border strips of size + `k` from ``self``. If this is not possible, then ``self`` is a + `k`-core. - sage: p = Partition([12,8,5,5,2,2,1]) - sage: p.is_core(4) + EXAMPLES: + + In the partition (2, 1), a hook length of 2 does not occur, but a hook + length of 3 does:: + + sage: p = Partition([2, 1]) + sage: p.is_core(2) + True + sage: p.is_core(3) + False + + sage: q = Partition([12, 8, 5, 5, 2, 2, 1]) + sage: q.is_core(4) False - sage: p.is_core(5) + sage: q.is_core(5) True - sage: p.is_core(0) + sage: q.is_core(0) True + + .. SEEALSO:: + + :meth:`core`, :class:`Core` """ return not k in self.hooks() @@ -5434,18 +5926,31 @@ def _element_constructor_(self, lst): ([4, 4, 2, 2, 1]) sage: P(elt) [4, 4, 2, 2, 1] + + TESTS:: + + sage: Partition([3/2]) + Traceback (most recent call last): + ... + ValueError: all parts of [3/2] should be nonnegative integers + """ if isinstance(lst, PartitionTuple): if lst.level() != 1: - raise ValueError('%s is not an element of %s'%(lst, self)) + raise ValueError('%s is not an element of %s' % (lst, self)) lst = lst[0] if lst.parent() is self: return lst + try: + lst = list(map(ZZ, lst)) + except TypeError: + raise ValueError('all parts of %s should be nonnegative integers' % repr(lst)) + if lst in self: - # Trailing zeros are removed in the element constructor + # trailing zeros are removed in Partition.__init__ return self.element_class(self, lst) - raise ValueError('%s is not an element of %s'%(lst, self)) + raise ValueError('%s is not an element of %s' % (lst, self)) def __contains__(self, x): """ @@ -5474,12 +5979,23 @@ def __contains__(self, x): True sage: Partition([3/1, 2]) in P True + + Check that non-integers and non-lists are excluded:: + + sage: P = Partitions() + sage: [2,1.5] in P + False + + sage: 0 in P + False + """ if isinstance(x, Partition): return True if isinstance(x, (list, tuple)): - return len(x) == 0 or (x[-1] in NN and - all(x[i] in NN and x[i] >= x[i+1] for i in range(len(x)-1))) + return not x or (all((a in ZZ) and (a >= b) for a, b in zip(x, x[1:])) + and (x[-1] in ZZ) and (x[-1] >= 0)) + return False def subset(self, *args, **kwargs): r""" @@ -5802,7 +6318,7 @@ def __contains__(self, x): sage: [] in P True """ - return len(x) == 0 or (x[0] <= self.k and Partitions.__contains__(self, x)) + return not x or (x[0] <= self.k and x in _Partitions) def _repr_(self): """ @@ -5987,7 +6503,8 @@ def cardinality(self, algorithm='flint'): return bober_number_of_partitions(self.n) elif algorithm == 'gap': - return ZZ(gap.eval("NrPartitions(%s)" % (ZZ(self.n)))) + from sage.libs.gap.libgap import libgap + return ZZ(libgap.NrPartitions(ZZ(self.n))) elif algorithm == 'pari': return ZZ(pari(ZZ(self.n)).numbpart()) @@ -6515,9 +7032,9 @@ def cardinality(self): """ # GAP complains if you give it an empty list if self.parts: - return ZZ(gap.eval("NrRestrictedPartitions(%s,%s)" % (ZZ(self.n), self.parts))) - else: - return Integer(self.n == 0) + from sage.libs.gap.libgap import libgap + return ZZ(libgap.NrRestrictedPartitions(ZZ(self.n), self.parts)) + return Integer(self.n == 0) def first(self): """ @@ -6982,6 +7499,33 @@ def list(self): return [self.element_class(self, [x for x in p if x!=0]) for p in l] + def cardinality(self): + """ + Return the cardinality of ``self``. + + EXAMPLES:: + + sage: PartitionsInBox(2, 3).cardinality() + 10 + + TESTS: + + Check the corner case:: + + sage: PartitionsInBox(0, 0).cardinality() + 1 + + sage: PartitionsInBox(0, 1).cardinality() + 1 + + sage: all(PartitionsInBox(a, b).cardinality() == + ....: len(PartitionsInBox(a, b).list()) + ....: for a in range(6) for b in range(6)) + True + + """ + return binomial(self.h + self.w, self.w) + class Partitions_constraints(IntegerListsLex): """ For unpickling old constrained ``Partitions_constraints`` objects created @@ -7640,12 +8184,13 @@ def list(self): sage: OrderedPartitions(3,2).list() [[2, 1], [1, 2]] """ + from sage.interfaces.all import gap n = self.n k = self.k - if self.k is None: - ans=gap.eval("OrderedPartitions(%s)"%(ZZ(n))) + if k is None: + ans=gap.eval("OrderedPartitions(%s)" % (ZZ(n))) else: - ans=gap.eval("OrderedPartitions(%s,%s)"%(ZZ(n),ZZ(k))) + ans=gap.eval("OrderedPartitions(%s,%s)" % (ZZ(n), ZZ(k))) result = eval(ans.replace('\n','')) result.reverse() return result @@ -7665,12 +8210,13 @@ def cardinality(self): sage: OrderedPartitions(15).cardinality() 16384 """ + from sage.libs.gap.libgap import libgap n = self.n k = self.k if k is None: - ans=gap.eval("NrOrderedPartitions(%s)"%(n)) + ans = libgap.NrOrderedPartitions(n) else: - ans=gap.eval("NrOrderedPartitions(%s,%s)"%(n,k)) + ans = libgap.NrOrderedPartitions(n, k) return ZZ(ans) ########################## @@ -7684,9 +8230,9 @@ class PartitionsGreatestLE(UniqueRepresentation, IntegerListsLex): EXAMPLES:: - sage: PartitionsGreatestLE(10,2) + sage: PartitionsGreatestLE(10, 2) Partitions of 10 having parts less than or equal to 2 - sage: PartitionsGreatestLE(10,2).list() + sage: PartitionsGreatestLE(10, 2).list() [[2, 2, 2, 2, 2], [2, 2, 2, 2, 1, 1], [2, 2, 2, 1, 1, 1, 1], @@ -7694,11 +8240,11 @@ class PartitionsGreatestLE(UniqueRepresentation, IntegerListsLex): [2, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] - sage: [4,3,2,1] in PartitionsGreatestLE(10,2) + sage: [4,3,2,1] in PartitionsGreatestLE(10, 2) False - sage: [2,2,2,2,2] in PartitionsGreatestLE(10,2) + sage: [2,2,2,2,2] in PartitionsGreatestLE(10, 2) True - sage: PartitionsGreatestLE(10,2).first().parent() + sage: PartitionsGreatestLE(10, 2).first().parent() Partitions... """ @@ -7708,12 +8254,12 @@ def __init__(self, n, k): TESTS:: - sage: p = PartitionsGreatestLE(10,2) + sage: p = PartitionsGreatestLE(10, 2) sage: p.n, p.k (10, 2) sage: TestSuite(p).run() """ - IntegerListsLex.__init__(self, n, max_slope = 0, min_part=1, max_part = k) + IntegerListsLex.__init__(self, n, max_slope=0, min_part=1, max_part=k) self.n = n self.k = k @@ -7726,7 +8272,26 @@ def _repr_(self): sage: PartitionsGreatestLE(10, 2) # indirect doctest Partitions of 10 having parts less than or equal to 2 """ - return "Partitions of %s having parts less than or equal to %s"%(self.n, self.k) + return "Partitions of %s having parts less than or equal to %s" % (self.n, self.k) + + def cardinality(self): + """ + Return the cardinality of ``self``. + + EXAMPLES:: + + sage: PartitionsGreatestLE(9, 5).cardinality() + 23 + + TESTS:: + + sage: all(PartitionsGreatestLE(n, a).cardinality() == + ....: len(PartitionsGreatestLE(n, a).list()) + ....: for n in range(20) for a in range(6)) + True + + """ + return sum(number_of_partitions_length(self.n, i) for i in range(self.k+1)) Element = Partition options = Partitions.options @@ -7738,28 +8303,38 @@ def _repr_(self): class PartitionsGreatestEQ(UniqueRepresentation, IntegerListsLex): """ The class of all (unordered) "restricted" partitions of the integer `n` - having its greatest part equal to the integer `k`. + having all its greatest parts equal to the integer `k`. EXAMPLES:: - sage: PartitionsGreatestEQ(10,2) + sage: PartitionsGreatestEQ(10, 2) Partitions of 10 having greatest part equal to 2 - sage: PartitionsGreatestEQ(10,2).list() + sage: PartitionsGreatestEQ(10, 2).list() [[2, 2, 2, 2, 2], [2, 2, 2, 2, 1, 1], [2, 2, 2, 1, 1, 1, 1], [2, 2, 1, 1, 1, 1, 1, 1], [2, 1, 1, 1, 1, 1, 1, 1, 1]] - sage: [4,3,2,1] in PartitionsGreatestEQ(10,2) + sage: [4,3,2,1] in PartitionsGreatestEQ(10, 2) False - sage: [2,2,2,2,2] in PartitionsGreatestEQ(10,2) + sage: [2,2,2,2,2] in PartitionsGreatestEQ(10, 2) True - sage: [1]*10 in PartitionsGreatestEQ(10,2) + + The empty partition has no maximal part, but it is contained in + the set of partitions with any specified maximal part:: + + sage: PartitionsGreatestEQ(0, 2).list() + [[]] + + TESTS:: + + sage: [1]*10 in PartitionsGreatestEQ(10, 2) False - sage: PartitionsGreatestEQ(10,2).first().parent() + sage: PartitionsGreatestEQ(10, 2).first().parent() Partitions... + """ def __init__(self, n, k): @@ -7768,12 +8343,12 @@ def __init__(self, n, k): TESTS:: - sage: p = PartitionsGreatestEQ(10,2) + sage: p = PartitionsGreatestEQ(10, 2) sage: p.n, p.k (10, 2) sage: TestSuite(p).run() """ - IntegerListsLex.__init__(self, n, max_slope = 0, max_part=k, floor = [k]) + IntegerListsLex.__init__(self, n, max_slope=0, max_part=k, floor=[k]) self.n = n self.k = k @@ -7783,10 +8358,31 @@ def _repr_(self): TESTS:: - sage: PartitionsGreatestEQ(10,2) # indirect doctest + sage: PartitionsGreatestEQ(10, 2) # indirect doctest Partitions of 10 having greatest part equal to 2 """ - return "Partitions of %s having greatest part equal to %s"%(self.n, self.k) + return "Partitions of %s having greatest part equal to %s" % (self.n, self.k) + + def cardinality(self): + """ + Return the cardinality of ``self``. + + EXAMPLES:: + + sage: PartitionsGreatestEQ(10, 2).cardinality() + 5 + + TESTS:: + + sage: all(PartitionsGreatestEQ(n, a).cardinality() == + ....: len(PartitionsGreatestEQ(n, a).list()) + ....: for n in range(20) for a in range(6)) + True + + """ + if not self.n: + return 1 + return number_of_partitions_length(self.n, self.k) Element = Partition options = Partitions.options @@ -8243,8 +8839,8 @@ def number_of_partitions_length(n, k, algorithm='hybrid'): return number_of_partitions(n - k) # Fall back to GAP - - return ZZ(gap.eval( "NrPartitions({},{})".format(ZZ(n), ZZ(k)) )) + from sage.libs.gap.libgap import libgap + return ZZ(libgap.NrPartitions(ZZ(n), ZZ(k))) ########## diff --git a/src/sage/combinat/partition_kleshchev.py b/src/sage/combinat/partition_kleshchev.py index b817db841e1..0715c7e2f5f 100644 --- a/src/sage/combinat/partition_kleshchev.py +++ b/src/sage/combinat/partition_kleshchev.py @@ -1521,22 +1521,52 @@ def __iter__(self): sage: it = iter(KleshchevPartitions(2, [0,1], convention='LS')) sage: [next(it) for _ in range(10)] - [([], []), ([1], []), ([], [1]), ([1], [1]), ([], [1, 1]), - ([1], [1, 1]), ([1, 1], [1]), ([], [2, 1]), - ([], [1, 1, 1]), ([1], [1, 1, 1])] + [([], []), + ([1], []), + ([], [1]), + ([1], [1]), + ([], [1, 1]), + ([1, 1], [1]), + ([1], [1, 1]), + ([], [2, 1]), + ([], [1, 1, 1]), + ([2, 1], [1])] sage: it = iter(KleshchevPartitions(2, [0,1], convention='RS')) sage: [next(it) for _ in range(10)] - [([], []), ([1], []), ([], [1]), ([1, 1], []), ([1], [1]), - ([1, 1, 1], []), ([2, 1], []), ([1], [1, 1]), - ([1, 1], [1]), ([1, 1, 1, 1], [])] + [([], []), + ([1], []), + ([], [1]), + ([1, 1], []), + ([1], [1]), + ([2, 1], []), + ([1, 1, 1], []), + ([1, 1], [1]), + ([1], [1, 1]), + ([2, 1, 1], [])] sage: it = iter(KleshchevPartitions(2, [0,1], convention='LG')) sage: [next(it) for _ in range(10)] - [([], []), ([1], []), ([], [1]), ([2], []), ([1], [1]), - ([3], []), ([2, 1], []), ([1], [2]), ([2], [1]), ([4], [])] + [([], []), + ([1], []), + ([], [1]), + ([2], []), + ([1], [1]), + ([3], []), + ([2, 1], []), + ([2], [1]), + ([1], [2]), + ([4], [])] sage: it = iter(KleshchevPartitions(2, [0,1], convention='RG')) sage: [next(it) for _ in range(10)] - [([], []), ([1], []), ([], [1]), ([1], [1]), ([], [2]), - ([1], [2]), ([2], [1]), ([], [2, 1]), ([], [3]), ([1], [3])] + [([], []), + ([1], []), + ([], [1]), + ([1], [1]), + ([], [2]), + ([2], [1]), + ([1], [2]), + ([], [3]), + ([], [2, 1]), + ([2, 1], [1])] sage: it = iter(KleshchevPartitions(3, [0,1,2])) sage: [next(it) for _ in range(10)] @@ -1563,9 +1593,9 @@ def __iter__(self): for mu in cur: yield mu mu_list = mu.to_list() - for cell in mu.cogood_cells().values(): + for cell in sorted(mu.cogood_cells().values()): data = [list(p) for p in mu_list] - k,r,c = cell + k, r, c = cell if c == 0: data[k].append(1) else: @@ -1590,6 +1620,7 @@ def _an_element_(self): """ return self[12] + class KleshchevPartitions_size(KleshchevPartitions): """ Kleshchev partitions of a fixed size. diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index d549bbd8c6d..188630b46ca 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -258,7 +258,6 @@ from sage.graphs.digraph import DiGraph import itertools from .combinat import CombinatorialElement, catalan_number -from sage.misc.misc import uniq from sage.misc.cachefunc import cached_method from .backtrack import GenericBacktracker from sage.combinat.combinatorial_map import combinatorial_map @@ -2479,7 +2478,7 @@ def fundamental_transformation_inverse(self): transformation. The inverse of the fundamental transformation is a - bijection from the set of all permutations of + bijection from the set of all permutations of `\{1, 2, \ldots, n\}` to itself, which transforms any such permutation `w` as follows: Let `I = \{ i_1 < i_2 < \cdots < i_k \}` be the set of @@ -4095,7 +4094,7 @@ def permutohedron_join(self, other, side="right"): must_be_right = [f for f in self[u + 1:] if f < i] v = other.index(i) must_be_right += [f for f in other[v + 1:] if f < i] - must_be_right = uniq(sorted(must_be_right)) + must_be_right = sorted(set(must_be_right)) for j, q in enumerate(xs): if q in must_be_right: xs = xs[:j] + [i] + xs[j:] @@ -5222,7 +5221,7 @@ class Permutations(UniqueRepresentation, Parent): :: sage: p = Permutations(4, avoiding=[1,3,2]); p - Standard permutations of 4 avoiding [1, 3, 2] + Standard permutations of 4 avoiding [[1, 3, 2]] sage: p.list() [[4, 1, 2, 3], [4, 2, 1, 3], @@ -5281,6 +5280,13 @@ def __classcall_private__(cls, n=None, k=None, **kwargs): number_of_arguments += 1 if number_of_arguments == 0: + if 'avoiding' in kwargs: + a = kwargs['avoiding'] + if len(a) == 0: + return StandardPermutations_all() + if a in StandardPermutations_all(): + a = (a,) + return StandardPermutations_all_avoiding(a) return StandardPermutations_all() if number_of_arguments != 1: @@ -5291,6 +5297,10 @@ def __classcall_private__(cls, n=None, k=None, **kwargs): if k is None: if 'avoiding' in kwargs: a = kwargs['avoiding'] + if not a: + return StandardPermutations_n(n) + if len(a) == 1 and a[0] != 1: + a = a[0] if a in StandardPermutations_all(): if a == [1,2]: return StandardPermutations_avoiding_12(n) @@ -5967,7 +5977,7 @@ def __contains__(self, x): if len(x) != self.k: return False s = list(self._set) - return all(i in s for i in x) and len(uniq(x)) == len(x) + return all(i in s for i in x) and len(set(x)) == len(x) def _repr_(self): """ @@ -8284,9 +8294,104 @@ def list(self, distinct=False): ############################################### #Avoiding +class StandardPermutations_all_avoiding(StandardPermutations_all): + """ + All standard permutations avoiding a set of patterns. + """ + @staticmethod + def __classcall_private__(cls, a): + """ + Normalize arguments to ensure a unique representation. + + TESTS:: + + sage: P1 = Permutations(avoiding=([2,1,3],[1,2,3])) + sage: P2 = Permutations(avoiding=[[2,1,3],[1,2,3]]) + sage: P1 is P2 + True + """ + a = tuple(map(Permutation, a)) + return super(StandardPermutations_all_avoiding, cls).__classcall__(cls, a) + + def __init__(self, a): + """ + TESTS:: + + sage: P = Permutations(avoiding=[[2,1,3],[1,2,3]]) + sage: TestSuite(P).run(max_runs=25) + """ + Permutations.__init__(self, category=InfiniteEnumeratedSets()) + self._a = a + + def patterns(self): + """ + Return the patterns avoided by this class of permutations. + + EXAMPLES:: + + sage: P = Permutations(avoiding=[[2,1,3],[1,2,3]]) + sage: P.patterns() + ([2, 1, 3], [1, 2, 3]) + """ + return self._a + + def _repr_(self): + """ + EXAMPLES:: + + sage: Permutations(avoiding=[[2,1,3],[1,2,3]]) + Standard permutations avoiding [[2, 1, 3], [1, 2, 3]] + """ + return "Standard permutations avoiding %s"%(list(self._a)) + + def __contains__(self, x): + """ + TESTS:: + + sage: [1,3,2] in Permutations(avoiding=[1,3,2]) + False + sage: [1,3,2] in Permutations(avoiding=[[1,3,2]]) + False + sage: [2,1,3] in Permutations(avoiding=[[1,3,2],[1,2,3]]) + True + sage: [2,1,3] in Permutations(avoiding=[]) + True + """ + if not super(StandardPermutations_all_avoiding, self).__contains__(x): + return False + x = Permutations()(x) + return all(x.avoids(p) for p in self._a) + + def __iter__(self): + """ + Iterate over ``self``. + + TESTS:: + + sage: it = iter(Permutations(avoiding=[[2,1,3],[1,2,3]])) + sage: [next(it) for i in range(10)] + [[], + [1], + [1, 2], + [2, 1], + [1, 3, 2], + [2, 3, 1], + [3, 1, 2], + [3, 2, 1], + [1, 4, 3, 2], + [2, 4, 3, 1]] + """ + n = 0 + while True: + for x in itertools.permutations(range(1, n + 1)): + x = self.element_class(self, x) + if all(x.avoids(p) for p in self._a): + yield x + n += 1 + class StandardPermutations_avoiding_generic(StandardPermutations_n_abstract): """ - Generic class for subset of permutations avoiding a particular pattern. + Generic class for subset of permutations avoiding a set of patterns. """ @staticmethod def __classcall_private__(cls, n, a): @@ -8295,8 +8400,8 @@ def __classcall_private__(cls, n, a): TESTS:: - sage: P1 = Permutations(3, avoiding=([2, 1, 3],[1,2,3])) - sage: P2 = Permutations(3, avoiding=[[2, 1, 3],[1,2,3]]) + sage: P1 = Permutations(3, avoiding=([2,1,3],[1,2,3])) + sage: P2 = Permutations(3, avoiding=[[2,1,3],[1,2,3]]) sage: P1 is P2 True """ @@ -8307,13 +8412,61 @@ def __init__(self, n, a): """ EXAMPLES:: - sage: P = Permutations(3, avoiding=[[2, 1, 3],[1,2,3]]) + sage: P = Permutations(3, avoiding=[[2,1,3],[1,2,3]]) sage: TestSuite(P).run() sage: type(P) """ StandardPermutations_n_abstract.__init__(self, n) - self.a = a + self._a = a + + @property + def a(self): + r""" + ``self.a`` is deprecated; use :meth:`patterns` instead. + + TESTS:: + + sage: P = Permutations(3, avoiding=[[2,1,3],[1,2,3]]) + sage: P.a + doctest:...: DeprecationWarning: The attribute a for the list of patterns to avoid is deprecated, use the method patterns instead. + See https://trac.sagemath.org/26810 for details. + ([2, 1, 3], [1, 2, 3]) + """ + from sage.misc.superseded import deprecation + deprecation(26810, "The attribute a for the list of patterns to avoid is " + "deprecated, use the method patterns instead.") + return self.patterns() + + def patterns(self): + """ + Return the patterns avoided by this class of permutations. + + EXAMPLES:: + + sage: P = Permutations(3, avoiding=[[2,1,3],[1,2,3]]) + sage: P.patterns() + ([2, 1, 3], [1, 2, 3]) + """ + return self._a + + def __contains__(self, x): + """ + TESTS:: + + sage: [1,3,2] in Permutations(3, avoiding=[1,3,2]) + False + sage: [1,3,2] in Permutations(3, avoiding=[[1,3,2]]) + False + sage: [2,1,3] in Permutations(3, avoiding=[[1,3,2],[1,2,3]]) + True + sage: [2,1,3] in Permutations(3, avoiding=[]) + True + """ + if not super(StandardPermutations_avoiding_generic, self).__contains__(x): + return False + x = Permutations()(x) + return all(x.avoids(p) for p in self._a) def _repr_(self): """ @@ -8322,7 +8475,7 @@ def _repr_(self): sage: Permutations(3, avoiding=[[2, 1, 3],[1,2,3]]) Standard permutations of 3 avoiding [[2, 1, 3], [1, 2, 3]] """ - return "Standard permutations of %s avoiding %s"%(self.n, list(self.a)) + return "Standard permutations of %s avoiding %s"%(self.n, list(self._a)) def __iter__(self): """ @@ -8334,7 +8487,7 @@ def __iter__(self): [[]] """ if self.n > 0: - return iter(PatternAvoider(self, self.a)) + return iter(PatternAvoider(self, self._a)) return iter([self.element_class(self, [])]) def cardinality(self): @@ -8358,7 +8511,7 @@ def __init__(self, n): sage: P = Permutations(3, avoiding=[1, 2]) sage: TestSuite(P).run() """ - StandardPermutations_avoiding_generic.__init__(self, n, Permutations()([1, 2])) + super(StandardPermutations_avoiding_12, self).__init__(n, (Permutations()([1, 2]),)) def __iter__(self): """ @@ -8389,7 +8542,7 @@ def __init__(self, n): sage: P = Permutations(3, avoiding=[2, 1]) sage: TestSuite(P).run() """ - StandardPermutations_avoiding_generic.__init__(self, n, Permutations()([2, 1])) + super(StandardPermutations_avoiding_21, self).__init__(n, (Permutations()([2, 1]),)) def __iter__(self): """ @@ -8420,7 +8573,7 @@ def __init__(self, n): sage: P = Permutations(3, avoiding=[1, 3, 2]) sage: TestSuite(P).run() """ - StandardPermutations_avoiding_generic.__init__(self, n, Permutations()([1, 3, 2])) + super(StandardPermutations_avoiding_132, self).__init__(n, (Permutations()([1, 3, 2]),)) def cardinality(self): """ @@ -8492,7 +8645,7 @@ def __init__(self, n): sage: P = Permutations(3, avoiding=[2, 1, 3]) sage: TestSuite(P).run() """ - StandardPermutations_avoiding_generic.__init__(self, n, Permutations()([1, 2, 3])) + super(StandardPermutations_avoiding_123, self).__init__(n, (Permutations()([1, 2, 3]),)) def cardinality(self): """ @@ -8563,7 +8716,7 @@ def __init__(self, n): sage: P = Permutations(3, avoiding=[3, 2, 1]) sage: TestSuite(P).run() """ - StandardPermutations_avoiding_generic.__init__(self, n, Permutations()([3, 2, 1])) + super(StandardPermutations_avoiding_321, self).__init__(n, (Permutations()([3, 2, 1]),)) def cardinality(self): """ @@ -8594,7 +8747,7 @@ def __init__(self, n): sage: P = Permutations(3, avoiding=[2, 3, 1]) sage: TestSuite(P).run() """ - StandardPermutations_avoiding_generic.__init__(self, n, Permutations()([2, 3, 1])) + super(StandardPermutations_avoiding_231, self).__init__(n, (Permutations()([2, 3, 1]),)) def cardinality(self): """ @@ -8626,7 +8779,7 @@ def __init__(self, n): sage: P = Permutations(3, avoiding=[3, 1, 2]) sage: TestSuite(P).run() """ - super(StandardPermutations_avoiding_312, self).__init__(n, Permutations()([3, 1, 2])) + super(StandardPermutations_avoiding_312, self).__init__(n, (Permutations()([3, 1, 2]),)) def cardinality(self): """ @@ -8658,7 +8811,7 @@ def __init__(self, n): sage: P = Permutations(3, avoiding=[2, 1, 3]) sage: TestSuite(P).run() """ - super(StandardPermutations_avoiding_213, self).__init__(n, Permutations()([2, 1, 3])) + super(StandardPermutations_avoiding_213, self).__init__(n, (Permutations()([2, 1, 3]),)) def cardinality(self): """ diff --git a/src/sage/combinat/permutation_cython.pxd b/src/sage/combinat/permutation_cython.pxd index b8b503765f4..9f19d942604 100644 --- a/src/sage/combinat/permutation_cython.pxd +++ b/src/sage/combinat/permutation_cython.pxd @@ -1,10 +1,9 @@ -from cpython cimport array -import array +from cpython.array cimport array cdef void reset_swap(int n, int *c, int *o) cdef int next_swap(int n, int *c, int *o) -cpdef bint next_perm(array.array l) -cpdef list map_to_list(array.array l, values, int n) +cpdef bint next_perm(array l) +cpdef map_to_list(array l, tuple values, int n) cpdef list left_action_same_n(list l, list r) cpdef list right_action_same_n(list l, list r) cpdef list left_action_product(list l, list r) diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index 918c14b7e45..554dee80e29 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -39,14 +39,8 @@ cimport cython from cpython.object cimport PyObject -from cysignals.memory cimport sig_malloc, sig_free +from cysignals.memory cimport check_allocarray, sig_free -cdef extern from "Python.h": - void Py_INCREF(PyObject *) - PyObject * PyInt_FromLong(long ival) - list PyList_New(Py_ssize_t size) - void PyList_SET_ITEM(list l, Py_ssize_t, PyObject *) - PyObject * PyTuple_GET_ITEM(PyObject *op, Py_ssize_t i) ######################################################### # @@ -125,9 +119,9 @@ cdef int next_swap(int n, int *c, int *o): c[j] = q return j - offset + s + def permutation_iterator_transposition_list(int n): """ - Returns a list of transposition indices to enumerate the permutations on `n` letters by adjacent transpositions. Assumes zero-based lists. We artificially limit the @@ -157,45 +151,26 @@ def permutation_iterator_transposition_list(int n): ....: L.append(copy(Q)) sage: print(L) [[1, 2, 3, 4], [1, 3, 2, 4], [3, 1, 2, 4], [3, 2, 1, 4], [2, 3, 1, 4], [2, 1, 3, 4]] - """ - - cdef int *c - cdef int *o - cdef int N, m - cdef list T - if n <= 1: return [] if n > 12: raise ValueError("Cowardly refusing to enumerate the permutations " "on more than 12 letters.") + # Compute N = n! - 1 + cdef Py_ssize_t N = n + cdef Py_ssize_t i + for i in range(2, n): + N *= i + N -= 1 - m = n-1 - N = n - while m > 1: - N *= m - m -= 1 - - c = sig_malloc(2*n*sizeof(int)) - if c is NULL: - raise MemoryError("Failed to allocate memory in " - "permutation_iterator_transposition_list") - o = c + n - + cdef int* c = check_allocarray(n, 2 * sizeof(int)) + cdef int* o = c + n try: - T = PyList_New(N-1) - except Exception: + reset_swap(n, c, o) + return [next_swap(n, c, o) for i in range(N)] + finally: sig_free(c) - raise MemoryError("Failed to allocate memory in " - "permutation_iterator_transposition_list") - - reset_swap(n,c,o) - for m in range(N-1): - PyList_SET_ITEM(T, m, PyInt_FromLong(next_swap(n,c,o))) - sig_free(c) - - return T ##################################################################### @@ -203,7 +178,7 @@ def permutation_iterator_transposition_list(int n): @cython.wraparound(False) @cython.boundscheck(False) -cpdef bint next_perm(array.array l): +cpdef bint next_perm(array l): """ Obtain the next permutation under lex order of ``l`` by mutating ``l``. @@ -282,7 +257,9 @@ cpdef bint next_perm(array.array l): return True -cpdef list map_to_list(array.array l, values, int n): + +@cython.boundscheck(False) +cpdef map_to_list(array l, tuple values, int n): """ Build a list by mapping the array ``l`` using ``values``. @@ -311,13 +288,9 @@ cpdef list map_to_list(array.array l, values, int n): ['a', 'b', 'a', 'd', 'd', 'a', 'b'] """ cdef int i - cdef list ret = PyList_New(n) - cdef PyObject * t - for i in range(n): - t = PyTuple_GET_ITEM( values, l.data.as_uints[i]) - Py_INCREF(t) - PyList_SET_ITEM(ret, i, t) - return ret + cdef unsigned int* ind = l.data.as_uints + return [values[ind[i]] for i in range(n)] + ##################################################################### ## Multiplication functions for permutations diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index a02b0825622..3999697697e 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -5,8 +5,7 @@ {INDEX_OF_FUNCTIONS} """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Peter Jipsen # Copyright (C) 2008 Franco Saliola # @@ -14,8 +13,8 @@ # 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 __future__ import print_function from six.moves import range @@ -25,6 +24,7 @@ from sage.rings.integer_ring import ZZ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method +from sage.misc.rest_index_of_methods import gen_rest_table_index class LatticeError(ValueError): @@ -63,6 +63,7 @@ def __str__(self): """ return "no {} for {} and {}".format(self.fail, self.x, self.y) + class HasseDiagram(DiGraph): """ The Hasse diagram of a poset. This is just a transitively-reduced, @@ -93,7 +94,7 @@ def _repr_(self): sage: H._repr_() 'Hasse diagram of a poset containing 4 elements' """ - return "Hasse diagram of a poset containing %s elements"%self.order() + return "Hasse diagram of a poset containing %s elements" % self.order() def linear_extension(self): r""" @@ -161,15 +162,16 @@ def greedy_rec(H, linext): S = [] if linext: - S = [x for x in H.neighbors_out(linext[-1]) if all(low in linext for low in H.neighbors_in(x))] + S = [x for x in H.neighbors_out(linext[-1]) + if all(low in linext for low in H.neighbors_in(x))] if not S: S_ = set(self).difference(set(linext)) - S = [x for x in S_ if - not any(low in S_ for low in self.neighbors_in(x))] + S = [x for x in S_ + if not any(low in S_ for low in self.neighbors_in(x))] for e in S: # Python3-todo: use yield from - for tmp in greedy_rec(H, linext+[e]): + for tmp in greedy_rec(H, linext + [e]): yield tmp return greedy_rec(self, []) @@ -226,12 +228,15 @@ def supergreedy_rec(H, linext): if not k: # Start from new minimal element S = [x for x in self.sources() if x not in linext] else: - S = [x for x in self.neighbors_out(linext[k-1]) if x not in linext and all(low in linext for low in self.neighbors_in(x))] + S = [x for x in self.neighbors_out(linext[k - 1]) + if x not in linext and + all(low in linext + for low in self.neighbors_in(x))] k -= 1 for e in S: - # Python3-todo: use yield from - for tmp in supergreedy_rec(H, linext+[e]): + # Python3-todo: use yield from + for tmp in supergreedy_rec(H, linext + [e]): yield tmp return supergreedy_rec(self, []) @@ -271,8 +276,8 @@ def cover_relations_iterator(self): sage: list(H.cover_relations_iterator()) [(0, 2), (0, 3), (1, 3), (1, 4), (2, 5), (3, 5), (4, 5)] """ - for u,v,l in self.edge_iterator(): - yield (u,v) + for u, v, l in self.edge_iterator(): + yield (u, v) def cover_relations(self): r""" @@ -313,8 +318,7 @@ def is_lequal(self, i, j): sage: H.is_lequal(z,z) True """ - return i == j or \ - (i < j and j in self.breadth_first_search(i)) + return i == j or (i < j and j in self.breadth_first_search(i)) def is_less_than(self, x, y): r""" @@ -340,7 +344,7 @@ def is_less_than(self, x, y): if x == y: return False else: - return self.is_lequal(x,y) + return self.is_lequal(x, y) def is_gequal(self, x, y): r""" @@ -365,7 +369,7 @@ def is_gequal(self, x, y): sage: Q.is_gequal(z,z) True """ - return self.is_lequal(y,x) + return self.is_lequal(y, x) def is_greater_than(self, x, y): """ @@ -390,7 +394,7 @@ def is_greater_than(self, x, y): sage: Q.is_greater_than(z,z) False """ - return self.is_less_than(y,x) + return self.is_less_than(y, x) def minimal_elements(self): """ @@ -526,9 +530,9 @@ def is_chain(self): """ if self.cardinality() == 0: return True - return (self.num_edges()+1 == self.num_verts() and # Hasse Diagram is a tree - all(d<=1 for d in self.out_degree()) and # max outdegree is <= 1 - all(d<=1 for d in self.in_degree())) # max indegree is <= 1 + return (self.num_edges() + 1 == self.num_verts() and # tree + all(d <= 1 for d in self.out_degree()) and + all(d <= 1 for d in self.in_degree())) def is_antichain_of_poset(self, elms): """ @@ -545,9 +549,7 @@ def is_antichain_of_poset(self, elms): False """ from itertools import combinations - from sage.misc.misc import uniq - - elms_sorted = uniq(elms) + elms_sorted = sorted(set(elms)) return not any(self.is_lequal(a, b) for a, b in combinations(elms_sorted, 2)) @@ -572,7 +574,7 @@ def dual(self): False """ H = self.reverse() - H.relabel(perm=list(range(H.num_verts()-1, -1, -1)), inplace=True) + H.relabel(perm=list(range(H.num_verts() - 1, -1, -1)), inplace=True) return HasseDiagram(H) def _precompute_intervals(self): @@ -649,7 +651,7 @@ def interval(self, x, y): sage: I == set(H.interval(2,7)) True """ - return [z for z in range(x, y+1) if + return [z for z in range(x, y + 1) if self.is_lequal(x, z) and self.is_lequal(z, y)] closed_interval = interval @@ -671,7 +673,7 @@ def open_interval(self, x, y): sage: H.open_interval(7,2) [] """ - ci = self.interval(x,y) + ci = self.interval(x, y) if len(ci) == 0: return [] else: @@ -735,14 +737,15 @@ def rank_function(self): sage: f = H.rank_function() sage: s = dumps(H) """ - if(self._rank is None): + if self._rank is None: return None - return self._rank.__getitem__ # the rank function is just the getitem of the list + # the rank function is just the getitem of the list + return self._rank.__getitem__ @lazy_attribute def _rank(self): r""" - Builds the rank function of the poset, if it exists, i.e. + Build the rank function of the poset, if it exists, i.e. an array ``d`` where ``d[object] = self.rank_function()(object)`` A *rank function* of a poset `P` is a function `r` @@ -767,15 +770,16 @@ def _rank(self): """ # rank[i] is the rank of point i. It is equal to None until the rank of # i is computed - rank = [None]*self.order() + rank = [None] * self.order() not_found = set(self.vertex_iterator()) while not_found: y = not_found.pop() rank[y] = 0 # We set some vertex to have rank 0 component = set([y]) queue = set([y]) - while queue: # look at the neighbors of y and set the ranks; - # then look at the neighbors of the neighbors ... + while queue: + # look at the neighbors of y and set the ranks; + # then look at the neighbors of the neighbors ... y = queue.pop() for x in self.neighbors_out(y): if rank[x] is None: @@ -795,10 +799,10 @@ def _rank(self): for j in component: rank[j] -= m not_found.difference_update(component) - #now, all ranks are set. + # now, all ranks are set. return rank - def rank(self,element=None): + def rank(self, element=None): r""" Return the rank of ``element``, or the rank of the poset if ``element`` is ``None``. (The rank of a poset is the length of @@ -819,7 +823,7 @@ def rank(self,element=None): 1 """ if element is None: - return len(self.level_sets())-1 + return len(self.level_sets()) - 1 else: return self.rank_function()(element) @@ -842,7 +846,7 @@ def is_ranked(self): """ return bool(self.rank_function()) - def covers(self,x,y): + def covers(self, x, y): """ Return True if y covers x and False otherwise. @@ -854,9 +858,9 @@ def covers(self,x,y): sage: Q.covers(Q(1),Q(4)) False """ - return self.has_edge(x,y) + return self.has_edge(x, y) - def upper_covers_iterator(self,element): + def upper_covers_iterator(self, element): r""" Return the list of elements that cover ``element``. @@ -872,7 +876,7 @@ def upper_covers_iterator(self,element): for x in self.neighbor_out_iterator(element): yield x - def lower_covers_iterator(self,element): + def lower_covers_iterator(self, element): r""" Return the list of elements that are covered by ``element``. @@ -916,7 +920,7 @@ def cardinality(self): """ return self.order() - def moebius_function(self,i,j): # dumb algorithm + def moebius_function(self, i, j): # dumb algorithm r""" Return the value of the Möbius function of the poset on the elements ``i`` and ``j``. @@ -932,23 +936,22 @@ def moebius_function(self,i,j): # dumb algorithm ....: print("Bug in moebius_function!") """ try: - return self._moebius_function_values[(i,j)] + return self._moebius_function_values[(i, j)] except AttributeError: self._moebius_function_values = {} - return self.moebius_function(i,j) + return self.moebius_function(i, j) except KeyError: if i == j: - self._moebius_function_values[(i,j)] = 1 + self._moebius_function_values[(i, j)] = 1 elif i > j: - self._moebius_function_values[(i,j)] = 0 + self._moebius_function_values[(i, j)] = 0 else: - ci = self.closed_interval(i,j) - if len(ci) == 0: - self._moebius_function_values[(i,j)] = 0 + ci = self.interval(i, j) + if not ci: + self._moebius_function_values[(i, j)] = 0 else: - self._moebius_function_values[(i,j)] = \ - -sum([self.moebius_function(i,k) for k in ci[:-1]]) - return self._moebius_function_values[(i,j)] + self._moebius_function_values[(i, j)] = -sum(self.moebius_function(i, k) for k in ci[:-1]) + return self._moebius_function_values[(i, j)] def moebius_function_matrix(self): r""" @@ -963,6 +966,10 @@ def moebius_function_matrix(self): The result is cached in :meth:`_moebius_function_matrix`. + .. TODO:: + + Use an inversion algorithm for triangular matrices. + EXAMPLES:: sage: from sage.combinat.posets.hasse_diagram import HasseDiagram @@ -987,14 +994,14 @@ def moebius_function_matrix(self): sage: H.moebius_function == H._moebius_function_from_matrix True """ - if not hasattr(self,'_moebius_function_matrix'): - self._moebius_function_matrix = self.lequal_matrix().inverse().change_ring(ZZ) + if not hasattr(self, '_moebius_function_matrix'): + self._moebius_function_matrix = self.lequal_matrix().inverse_of_unit() self._moebius_function_matrix.set_immutable() self.moebius_function = self._moebius_function_from_matrix return self._moebius_function_matrix # Redefine self.moebius_function - def _moebius_function_from_matrix(self, i,j): + def _moebius_function_from_matrix(self, i, j): r""" Return the value of the Möbius function of the poset on the elements ``i`` and ``j``. @@ -1012,7 +1019,7 @@ def _moebius_function_from_matrix(self, i,j): This uses ``self._moebius_function_matrix``, as computed by :meth:`moebius_function_matrix`. """ - return self._moebius_function_matrix[i,j] + return self._moebius_function_matrix[i, j] @cached_method def coxeter_transformation(self): @@ -1036,7 +1043,7 @@ def coxeter_transformation(self): sage: M**8 == 1 True """ - return - self.lequal_matrix()*self.moebius_function_matrix().transpose() + return - self.lequal_matrix() * self.moebius_function_matrix().transpose() def order_filter(self, elements): r""" @@ -1120,7 +1127,7 @@ def _leq_matrix(self): D = {} for i in range(n): for v in self.breadth_first_search(i): - D[(i,v)] = 1 + D[(i, v)] = 1 M = matrix(ZZ, n, n, D, sparse=True) M.set_immutable() # Redefine self.is_lequal @@ -1155,7 +1162,7 @@ def lequal_matrix(self): """ return self._leq_matrix - def _alternate_is_lequal(self,i,j): + def _alternate_is_lequal(self, i, j): r""" Return ``True`` if ``i`` is less than or equal to ``j`` in ``self``, and ``False`` otherwise. @@ -1187,7 +1194,7 @@ def _alternate_is_lequal(self,i,j): sage: H._alternate_is_lequal(z,z) True """ - return bool(self._leq_matrix[i,j]) + return bool(self._leq_matrix[i, j]) def prime_elements(self): r""" @@ -1433,9 +1440,9 @@ def _join(self): join = [[n for x in range(n)] for x in range(n)] uc = [self.neighbors_out(x) for x in range(n)] # uc = upper covers - for x in range(n-1, -1, -1): + for x in range(n - 1, -1, -1): join[x][x] = x - for y in range(n-1, x, -1): + for y in range(n - 1, x, -1): T = [join[y][z] for z in uc[x]] q = min(T) @@ -1602,19 +1609,19 @@ def vertical_decomposition(self, return_list=False): return [] else: return None - result = [] # Never take the bottom element to list. + result = [] # Never take the bottom element to list. m = 0 - for i in range(n-1): + for i in range(n - 1): for j in self.outgoing_edge_iterator(i): m = max(m, j[1]) - if m == i+1: + if m == i + 1: if not return_list: - if m < n-1: + if m < n - 1: return m else: return None result.append(m) - result.pop() # Remove the top element. + result.pop() # Remove the top element. return result def is_complemented(self): @@ -1792,7 +1799,7 @@ def orthocomplementations_iterator(self): if n == 1: yield [0] return - if n % 2 == 1: + if n % 2: return dual_isomorphism = self.is_isomorphic(self.reverse(), certificate=True)[1] @@ -1813,7 +1820,7 @@ def orthocomplementations_iterator(self): for e in range(n): # Fix following after ticket #20727 comps[e] = [x for x in range(n) if - self._meet[e, x] == 0 and self._join[e, x] == n-1 and + self._meet[e, x] == 0 and self._join[e, x] == n - 1 and x in orbits[orbit_number[dual_isomorphism[e]]]] # Fitting is done by this recursive function: @@ -1822,7 +1829,8 @@ def recursive_fit(orthocomplements, unbinded): yield orthocomplements else: next_to_fit = unbinded[0] - possible_values = [x for x in comps[next_to_fit] if not x in orthocomplements] + possible_values = [x for x in comps[next_to_fit] + if x not in orthocomplements] for x in self.lower_covers_iterator(next_to_fit): if orthocomplements[x] is not None: possible_values = [y for y in possible_values if self.has_edge(y, orthocomplements[x])] @@ -1958,7 +1966,7 @@ def antichains_iterator(self): # antichains_queues never grows longer than self.cardinality(). # Indeed, if a appears before b in antichains_queues, then # the largest element of a is strictly smaller than that of b. - antichains_queues = [([], list(range(self.cardinality()-1, -1, -1)))] + antichains_queues = [([], list(range(self.cardinality() - 1, -1, -1)))] leq = self.lequal_matrix() while antichains_queues: (antichain, queue) = antichains_queues.pop() @@ -1969,7 +1977,7 @@ def antichains_iterator(self): while queue: x = queue.pop() new_antichain = antichain + [x] - new_queue = [t for t in queue if not (leq[t,x] or leq[x,t])] + new_queue = [t for t in queue if not (leq[t, x] or leq[x, t])] antichains_queues.append((new_antichain, new_queue)) def are_incomparable(self, i, j): @@ -1990,7 +1998,7 @@ def are_incomparable(self, i, j): [(1, 2), (1, 3), (2, 1), (3, 1)] """ mat = self._leq_matrix - return not mat[i,j] and not mat[j,i] + return not mat[i, j] and not mat[j, i] def are_comparable(self, i, j): """ @@ -2010,12 +2018,11 @@ def are_comparable(self, i, j): [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 4), (2, 0), (2, 2), (2, 3), (2, 4), (3, 0), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)] """ mat = self._leq_matrix - return bool(mat[i,j]) or bool(mat[j,i]) + return bool(mat[i, j]) or bool(mat[j, i]) - def antichains(self, element_class = list): + def antichains(self, element_class=list): """ - Return all antichains of ``self``, organized as a - prefix tree + Return all antichains of ``self``, organized as a prefix tree INPUT: @@ -2037,10 +2044,7 @@ def antichains(self, element_class = list): TESTS:: - sage: TestSuite(A).run(skip = "_test_pickling") - - .. note:: It's actually the pickling of the cached method - :meth:`coxeter_transformation` that fails ... + sage: TestSuite(A).run() TESTS:: @@ -2052,7 +2056,7 @@ def antichains(self, element_class = list): from sage.combinat.subsets_pairwise import PairwiseCompatibleSubsets return PairwiseCompatibleSubsets(self.vertices(), self.are_incomparable, - element_class = element_class) + element_class=element_class) def chains(self, element_class=list, exclude=None): """ @@ -2108,12 +2112,12 @@ def chains(self, element_class=list, exclude=None): """ from sage.combinat.subsets_pairwise import PairwiseCompatibleSubsets if not(exclude is None): - vertices = [u for u in self.vertex_iterator() if not u in exclude] + vertices = [u for u in self.vertex_iterator() if u not in exclude] else: vertices = self.vertices() return PairwiseCompatibleSubsets(vertices, self.are_comparable, - element_class = element_class) + element_class=element_class) def _trivial_nonregular_congruence(self): """ @@ -2155,9 +2159,9 @@ def _trivial_nonregular_congruence(self): return None if self.out_degree(0) == 1: return (0, 1) - if self.in_degree(n-1) == 1: - return (n-2, n-1) - for v in range(1, n-1): + if self.in_degree(n - 1) == 1: + return (n - 2, n - 1) + for v in range(1, n - 1): if self.in_degree(v) == 1 and self.out_degree(v) == 1: v_ = next(self.neighbor_out_iterator(v)) if self.in_degree(v_) == 1 and self.out_degree(v_) == 1: @@ -2206,7 +2210,7 @@ def sublattices_iterator(self, elms, min_e): gens.add(self._join[x, g]) current_set.add(g) else: - for x in self.sublattices_iterator(current_set, e+1): + for x in self.sublattices_iterator(current_set, e + 1): yield x def maximal_sublattices(self): @@ -2325,8 +2329,10 @@ def frattini_sublattice(self): """ # Just a direct computation, no optimization at all. n = self.cardinality() - if n == 0 or n == 2: return [] - if n == 1: return [0] + if n == 0 or n == 2: + return [] + if n == 1: + return [0] max_sublats = self.maximal_sublattices() return [e for e in range(self.cardinality()) if all(e in ms for ms in max_sublats)] @@ -2414,19 +2420,19 @@ def skeleton(self): n = len(p_atoms) mt = self._meet pos = [0] * n - meets = [self.order()-1] * n - result = [self.order()-1] + meets = [self.order() - 1] * n + result = [self.order() - 1] i = 0 while i >= 0: - new_meet = mt[meets[i-1], p_atoms[pos[i]]] + new_meet = mt[meets[i - 1], p_atoms[pos[i]]] result.append(new_meet) - if pos[i] == n-1: + if pos[i] == n - 1: i -= 1 - pos[i] = pos[i]+1 + pos[i] += 1 else: meets[i] = new_meet - pos[i+1] = pos[i]+1 + pos[i + 1] = pos[i] + 1 i += 1 return result @@ -2471,8 +2477,10 @@ def is_convex_subset(self, S): if b >= s_max or b in S: continue # Now b not in S, b > a and a in S. - neighbors = lambda v_: [v for v in self.neighbor_out_iterator(v_) - if v <= s_max and v not in ok] + + def neighbors(v_): + return [v for v in self.neighbor_out_iterator(v_) + if v <= s_max and v not in ok] for c in self.depth_first_search(b, neighbors=neighbors): if c in S: # Now c in S, b not in S, a in S, a < b < c. return False @@ -2520,8 +2528,8 @@ def neutral_elements(self): if n < 5: return set(range(n)) - todo = set(range(1, n-1)) - neutrals = set([0, n-1]) + todo = set(range(1, n - 1)) + neutrals = set([0, n - 1]) notneutrals = set() all_elements = set(range(n)) @@ -2537,13 +2545,13 @@ def is_neutral(a): join_ax = jn[a, x] for y in todo: if (mt[mt[join_ax, jn[a, y]], jn[x, y]] != - jn[jn[meet_ax, mt[a, y]], mt[x, y]]): + jn[jn[meet_ax, mt[a, y]], mt[x, y]]): notneutrals.add(x) notneutrals.add(y) return False for y in notneutrals: if (mt[mt[join_ax, jn[a, y]], jn[x, y]] != - jn[jn[meet_ax, mt[a, y]], mt[x, y]]): + jn[jn[meet_ax, mt[a, y]], mt[x, y]]): notneutrals.add(x) return False for x in noncomp.difference(todo): @@ -2551,12 +2559,12 @@ def is_neutral(a): join_ax = jn[a, x] for y in todo: if (mt[mt[join_ax, jn[a, y]], jn[x, y]] != - jn[jn[meet_ax, mt[a, y]], mt[x, y]]): + jn[jn[meet_ax, mt[a, y]], mt[x, y]]): notneutrals.add(y) return False for y in notneutrals: if (mt[mt[join_ax, jn[a, y]], jn[x, y]] != - jn[jn[meet_ax, mt[a, y]], mt[x, y]]): + jn[jn[meet_ax, mt[a, y]], mt[x, y]]): return False return True @@ -2756,7 +2764,7 @@ def fill_to_interval(S): """ Return the smallest interval containing elements in the set S. """ - m = n-1 + m = n - 1 for e in S: m = mt[m, e] j = 0 @@ -2832,15 +2840,14 @@ def fill_to_interval(S): # [a, b] block we just used. while c is not None: newblock = cong.find(c) - I = self.interval(c, d) - for i in I: + for i in self.interval(c, d): cong.union(newblock, i) C = cong.root_to_elements_dict()[cong.find(newblock)] mins = [i for i in C if all(i_ not in C for i_ in self.neighbor_in_iterator(i))] maxs = [i for i in C if all(i_ not in C for i_ in self.neighbor_out_iterator(i))] c = None # To stop loop, if this is not changed below. if len(mins) > 1 or len(maxs) > 1: - c = n-1 + c = n - 1 for m in mins: c = self._meet[c, m] d = 0 @@ -2890,7 +2897,7 @@ def find_nontrivial_congruence(self): irr = [(v, self.neighbors_in(v)[0]) for v in join_irreducibles] else: irr = [(self.neighbors_out(v)[0], v) for v in meet_irreducibles] - irr.sort(key=lambda x: x[0]-x[1]) + irr.sort(key=lambda x: x[0] - x[1]) tried = [] for pair in irr: cong = self.congruence([pair], stop_pairs=tried) @@ -3048,5 +3055,5 @@ def is_congruence_normal(self): return True -from sage.misc.rest_index_of_methods import gen_rest_table_index + __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(HasseDiagram)) diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index b3d00244a7f..bc7f6aeba29 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -3500,8 +3500,7 @@ def day_doubling(self, S): # subset S, but we assume that the user made an error # if S is not also connected. - from sage.misc.misc import uniq - S = uniq(S) + S = sorted(set(S)) S_ = [self._element_to_vertex(e) for e in S] if not self._hasse_diagram.is_convex_subset(S_): raise ValueError("subset S is not convex") diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index 4076887a686..20d929c432a 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -772,7 +772,7 @@ def RandomLattice(n, p, properties=None): A lattice on `n` elements. When ``properties`` is ``None``, the probability `p` roughly measures number of covering relations of the lattice. To create interesting examples, make - the probability near one, something like `0.98..0.999`. + the probability a little below one, for example `0.9`. Currently parameter ``p`` has no effect only when ``properties`` is not ``None``. @@ -1082,11 +1082,10 @@ def SymmetricGroupBruhatIntervalPoset(start, end): sage: P2 = posets.SymmetricGroupBruhatIntervalPoset([1,2,3,4], [4,2,3,1]) sage: ranks1 = [P1.rank(v) for v in P1] sage: ranks2 = [P2.rank(v) for v in P2] - sage: [ranks1.count(i) for i in uniq(ranks1)] + sage: [ranks1.count(i) for i in sorted(set(ranks1))] [1, 3, 5, 4, 1] - sage: [ranks2.count(i) for i in uniq(ranks2)] + sage: [ranks2.count(i) for i in sorted(set(ranks2))] [1, 3, 5, 6, 4, 1] - """ start = Permutation(start) end = Permutation(end) @@ -1196,13 +1195,14 @@ def TetrahedralPoset(n, *colors, **labels): try: n = Integer(n) except TypeError: - raise TypeError("n must be an integer.") + raise TypeError("n must be an integer") if n < 2: - raise ValueError("n must be greater than 2.") + raise ValueError("n must be greater than 2") for c in colors: - if(c not in ('green', 'red', 'yellow', 'orange', 'silver', 'blue')): + if c not in ('green', 'red', 'yellow', 'orange', 'silver', 'blue'): raise ValueError("Color input must be from the following: 'green', 'red', 'yellow', 'orange', 'silver', and 'blue'.") - elem=[(i,j,k) for i in range (n) for j in range (n-i) for k in range (n-i-j)] + elem = [(i, j, k) for i in range(n) + for j in range(n-i) for k in range(n-i-j)] rels = [] elem_labels = {} if 'labels' in labels: @@ -1213,23 +1213,23 @@ def TetrahedralPoset(n, *colors, **labels): labelcount += 1 for c in colors: for (i,j,k) in elem: - if(i+j+k < n-1): - if(c=='green'): + if i+j+k < n-1: + if c == 'green': rels.append([(i,j,k),(i+1,j,k)]) - if(c=='red'): + if c == 'red': rels.append([(i,j,k),(i,j,k+1)]) - if(c=='yellow'): + if c == 'yellow': rels.append([(i,j,k),(i,j+1,k)]) - if(j0): - if(c=='orange'): + if j < n-1 and k > 0: + if c == 'orange': rels.append([(i,j,k),(i,j+1,k-1)]) - if(i0): - if(c=='silver'): + if i < n-1 and j > 0: + if c == 'silver': rels.append([(i,j,k),(i+1,j-1,k)]) - if(i0): - if(c=='blue'): + if i < n-1 and k > 0: + if c == 'blue': rels.append([(i,j,k),(i+1,j,k-1)]) - return Poset([elem,rels], elem_labels) + return Poset([elem, rels], elem_labels) # shard intersection order import sage.combinat.shard_order @@ -1464,29 +1464,17 @@ def YoungsLatticePrincipalOrderIdeal(lam): [[2], [2, 1]], [[2, 1], [2, 2]]] """ - from sage.misc.flatten import flatten - from sage.combinat.partition import Partition - - def lower_covers(l): - """ - Nested function returning those partitions obtained - from the partition `l` by removing - a single cell. - """ - return [l.remove_cell(c[0], c[1]) for c in l.removable_cells()] - - def contained_partitions(l): - """ - Nested function returning those partitions contained in - the partition `l` - """ - if l == Partition([]): - return l - return flatten([l, [contained_partitions(m) - for m in lower_covers(l)]]) + ideal = {} + level = [lam] + while level: + new_level = set() + for mu in level: + down = mu.down_list() + ideal[mu] = down + new_level.update(down) + level = new_level - ideal = list(set(contained_partitions(lam))) - H = DiGraph(dict([[p, lower_covers(p)] for p in ideal])) + H = DiGraph(ideal) return LatticePoset(H.reverse()) @staticmethod @@ -1786,34 +1774,21 @@ def _random_lattice(n, p): for i in range(1, n): - # First add some random element as a lower cover. - # Alone it can't change a semilattice to non-semilattice, - # so we don't check it. - new = i-1-floor(i*sqrt(random())) - lc_list = [new] - maxs.discard(new) - max_meets = {m:meets[m][new] for m in maxs} - - while random() < p and 0 not in lc_list: - # An ad hoc solution. srqt(random()) instead of randint(0, i) - # make number of coatoms closer to number of atoms. - new = i-1-floor(i*sqrt(random())) - - # Check that lc_list + new is an antichain. - if any(meets[new][lc] in [new, lc] for lc in lc_list): - continue - - # Check that new has a unique meet with any maximal element. - for m in maxs: - meet_m = meets[m][new] - if meets[meet_m][max_meets[m]] not in [meet_m, max_meets[m]]: - break - - else: # So, we found a new lower cover for i. + # Look for an admissible lower cover for the next element i + while True: + # Generate a random antichain + lc_list = [i-1-floor(i*sqrt(random()))] + while random() < p and 0 not in lc_list: + new = i-1-floor(i*sqrt(random())) + if any(meets[new][lc] in [new, lc] for lc in lc_list): + continue lc_list.append(new) - for m in maxs: - max_meets[m] = max(max_meets[m], meets[m][new]) - maxs.discard(new) + # Check whether it is admissible as a new lower cover + if all(any(all(meets[m][meets[a][a1]] == meets[m][a1] for a1 in lc_list if a1 != a) for a in lc_list) for m in maxs): + break + + # We've found a suitable lower cover for i + maxs.difference_update(lc_list) # Now compute new row and column to meet matrix. meets[i][i] = i @@ -1979,6 +1954,7 @@ def _random_distributive_lattice(n): H = HasseDiagram(D) return D + def _random_stone_lattice(n): """ Return a random Stone lattice on `n` elements. @@ -2008,7 +1984,7 @@ def _random_stone_lattice(n): from sage.misc.misc_c import prod from copy import copy - factors = sum([[f[0]]*f[1] for f in factor(n)], []) + factors = sum([[f[0]] * f[1] for f in factor(n)], []) sage.misc.prandom.shuffle(factors) part_lengths = list(Partitions(len(factors)).random_element()) @@ -2020,9 +1996,9 @@ def _random_stone_lattice(n): result = DiGraph(1) for p in parts: - g = _random_distributive_lattice(p-1) + g = _random_distributive_lattice(p - 1) g = copy(Poset(g).order_ideals_lattice(as_ideals=False)._hasse_diagram) - g.add_edge('bottom', 0) + g.add_edge(-1, 0) result = result.cartesian_product(g) result.relabel() diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 388a4c4b68b..cf36950a716 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -78,6 +78,7 @@ :meth:`~FinitePoset.is_eulerian` | Return ``True`` if the poset is Eulerian. :meth:`~FinitePoset.is_incomparable_chain_free` | Return ``True`` if the poset is (m+n)-free. :meth:`~FinitePoset.is_slender` | Return ``True`` if the poset is slender. + :meth:`~FinitePoset.is_sperner` | Return ``True`` if the poset is Sperner. :meth:`~FinitePoset.is_join_semilattice` | Return ``True`` is the poset has a join operation. :meth:`~FinitePoset.is_meet_semilattice` | Return ``True`` if the poset has a meet operation. @@ -272,10 +273,10 @@ # python3 from __future__ import division, print_function, absolute_import -from six.moves import range +from six.moves import range, builtins from six import iteritems -import copy +from copy import copy, deepcopy from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod @@ -300,6 +301,7 @@ from sage.misc.superseded import deprecated_function_alias from sage.combinat.subset import Subsets + def Poset(data=None, element_labels=None, cover_relations=False, linear_extension=False, category=None, facade=None, key=None): r""" Construct a finite poset from various forms of input data. @@ -681,7 +683,7 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio elif data is None: # type 0 D = DiGraph() elif isinstance(data, DiGraph): # type 4 - D = copy.deepcopy(data) + D = deepcopy(data) elif isinstance(data, dict): # type 3: dictionary of upper covers D = DiGraph(data, format="dict_of_lists") elif isinstance(data, (list, tuple)): # types 1, 2, 3 (list/tuple) @@ -1464,14 +1466,10 @@ def sorted(self, l, allow_incomparable=True, remove_duplicates=False): sage: P.sorted([], allow_incomparable=False, remove_duplicates=False) [] """ - from sage.misc.misc import uniq - v = [self._element_to_vertex(x) for x in l] - if remove_duplicates: - o = uniq(v) - else: - o = sorted(v) + v = set(v) + o = sorted(v) if not allow_incomparable: H = self._hasse_diagram @@ -2322,7 +2320,7 @@ def is_incomparable_chain_free(self, m, n=None): chain_pairs = [tuple(chain_pair) for chain_pair in m] except TypeError: raise TypeError("%s is not a tuple of tuples." % str(tuple(m))) - if not all(len(chain_pair) is 2 for chain_pair in chain_pairs): + if not all(len(chain_pair) == 2 for chain_pair in chain_pairs): raise ValueError("%r is not a tuple of length-2 tuples." % str(tuple(m))) chain_pairs = sorted(chain_pairs, key=min) else: @@ -3204,7 +3202,7 @@ def jump_number(self, certificate=False): It is known that every poset has a greedy linear extension -- an extension `[e_1, e_2, \ldots, e_n]` where every `e_{i+1}` is an upper cover of `e_i` if that is possible -- with the smallest - possible number of jumps; see [Mac1987]_. + possible number of jumps; see [Sys1987]_. Hence it suffices to test only those. We do that by backtracking. @@ -3384,7 +3382,7 @@ def rank(self, element=None): or the rank of the poset if ``element`` is ``None``. (The rank of a poset is the length of the longest chain of - elements of the poset.) + elements of the poset. This is sometimes called the length of a poset.) EXAMPLES:: @@ -3785,9 +3783,13 @@ def coxeter_smith_form(self, algorithm='singular'): INPUT: - - ``algorithm`` -- either ``'singular'`` (default) or ``'sage'`` + - ``algorithm`` -- optional (default ``'singular'``), possible + values are ``'singular'``, ``'sage'``, ``'gap'``, + ``'pari'``, ``'maple'``, ``'magma'``, ``'fricas'`` - Beware that using ``'sage'`` is much slower. + Beware that speed depends very much on the choice of + algorithm. Sage is rather slow, Singular is faster and Pari is + fast at least for small sizes. OUTPUT: @@ -3808,29 +3810,73 @@ def coxeter_smith_form(self, algorithm='singular'): sage: prod(P.coxeter_smith_form()) == P.coxeter_polynomial() True + TESTS:: + + sage: P = posets.PentagonPoset() + sage: P.coxeter_smith_form(algorithm='sage') + [1, 1, 1, 1, x^5 + x^4 + x + 1] + sage: P.coxeter_smith_form(algorithm='gap') + [1, 1, 1, 1, x^5 + x^4 + x + 1] + sage: P.coxeter_smith_form(algorithm='pari') + [1, 1, 1, 1, x^5 + x^4 + x + 1] + sage: P.coxeter_smith_form(algorithm='fricas') # optional - fricas + [1, 1, 1, 1, x^5 + x^4 + x + 1] + sage: P.coxeter_smith_form(algorithm='maple') # optional - maple + [1, 1, 1, 1, x^5 + x^4 + x + 1] + sage: P.coxeter_smith_form(algorithm='magma') # optional - magma + [1, 1, 1, 1, x^5 + x^4 + x + 1] + .. SEEALSO:: :meth:`coxeter_transformation`, :meth:`coxeter_matrix` """ - from sage.interfaces.singular import singular c0 = self.coxeter_transformation() x = polygen(QQ, 'x') # not possible to use ZZ for the moment - if algorithm == 'sage': # *very slow* - return (x - c0).smith_form()[0].diagonal() - - if algorithm == 'singular': # quite faster + if algorithm == 'singular': # quite faster than sage + from sage.interfaces.singular import singular singular.LIB('jacobson.lib') sing_m = singular(x - c0) L = sing_m.smith().sage().diagonal() return sorted([u / u.lc() for u in L], key=lambda p: p.degree()) - if algorithm == 'magma': # faster, not working for the moment + if algorithm == 'sage': # *very slow* + return (x - c0).smith_form(transformation=False).diagonal() + + if algorithm == 'magma': # also quite fast from sage.interfaces.magma import magma elem = magma('ElementaryDivisors') return elem.evaluate(x - c0).sage() + if algorithm == 'gap': + from sage.libs.gap.libgap import libgap + gap_m = libgap(x - c0) + elem = gap_m.ElementaryDivisorsMat() + return elem.sage() + + if algorithm == 'pari': # maybe fast, at least for small size + from sage.libs.pari import pari + pari_m = pari(x - c0) + elem = pari_m.matsnf(2) + A = x.parent() + return sorted((A(f) for f in elem), + key=lambda p: p.degree()) + + if algorithm == 'maple': + from sage.interfaces.maple import maple + maple_m = maple(x - c0) + maple.load("MatrixPolynomialAlgebra") + maple.load("ArrayTools") + elem = maple.SmithForm(maple_m).Diagonal() + A = x.parent() + return [A(f.sage()) for f in elem] + + if algorithm == 'fricas': + from sage.interfaces.fricas import fricas + fm = fricas(x-c0) + return list(fricas(fm.name()+"::Matrix(UP(x, FRAC INT))").smith().diagonal().sage()) + def is_meet_semilattice(self, certificate=False): r""" Return ``True`` if the poset has a meet operation, and @@ -4056,11 +4102,12 @@ def isomorphic_subposets(self, other): sage: C2 = Poset({0:[1]}) sage: C3 = Poset({'a':['b'], 'b':['c']}) - sage: for x in C3.isomorphic_subposets(C2): - ....: print(x.cover_relations()) - [['b', 'c']] - [['a', 'c']] + sage: L = sorted(x.cover_relations() for x in C3.isomorphic_subposets(C2)) + sage: for x in L: print(x) [['a', 'b']] + [['a', 'c']] + [['b', 'c']] + sage: D = Poset({1:[2,3], 2:[4], 3:[4]}) sage: N5 = posets.PentagonPoset() sage: len(N5.isomorphic_subposets(D)) @@ -4071,19 +4118,15 @@ def isomorphic_subposets(self, other): If this function takes too much time, try using :meth:`isomorphic_subposets_iterator`. """ - from sage.misc.misc import uniq - if not hasattr(other, 'hasse_diagram'): raise TypeError("'other' is not a finite poset") L = self._hasse_diagram.transitive_closure().subgraph_search_iterator(other._hasse_diagram.transitive_closure(), induced=True) # Since subgraph_search_iterator returns labelled copies, we # remove duplicates. - return [self.subposet([self._list[i] for i in x]) for x in uniq([frozenset(y) for y in L])] + return [self.subposet([self._list[i] for i in x]) for x in sorted(set(frozenset(y) for y in L))] - from six.moves import builtins # Caveat: list is overridden by the method list above!!! - - def antichains(self, element_constructor = builtins.list): + def antichains(self, element_constructor=builtins.list): """ Return the antichains of the poset. @@ -4978,7 +5021,7 @@ def star_product(self, other, labels='pairs'): sage: XYZ = Poset({'x': ['y'], 'y': ['z']}) sage: ABC.star_product(XYZ).list() [(0, 'a'), (0, 'b'), (1, 'y'), (1, 'z')] - sage: ABC.star_product(XYZ, labels='integers').list() + sage: sorted(ABC.star_product(XYZ, labels='integers')) [0, 1, 2, 3] TESTS:: @@ -5364,11 +5407,9 @@ def without_bounds(self): ... TypeError: the poset is missing either top or bottom """ - from copy import copy - if self.is_bounded(): g = copy(self._hasse_diagram) - g.delete_vertices([0, g.order()-1]) + g.delete_vertices([0, g.order() - 1]) g.relabel(self._vertex_to_element) return Poset(g, facade=self._is_facade) raise TypeError('the poset is missing either top or bottom') @@ -5709,10 +5750,8 @@ def subposet(self, elements): ... TypeError: 'sage.rings.integer.Integer' object is not iterable """ - from sage.misc.misc import uniq - H = self._hasse_diagram - elms = uniq([self._element_to_vertex(e) for e in elements]) + elms = sorted(set(self._element_to_vertex(e) for e in elements)) if not elms: return Poset() @@ -6268,8 +6307,8 @@ def maximal_antichains(self): EXAMPLES:: sage: P=Poset({'a':['b', 'c'], 'b':['d','e']}) - sage: P.maximal_antichains() - [['a'], ['c', 'b'], ['c', 'e', 'd']] + sage: [sorted(anti) for anti in P.maximal_antichains()] + [['a'], ['b', 'c'], ['c', 'd', 'e']] sage: posets.PentagonPoset().maximal_antichains() [[0], [1, 2], [1, 3], [4]] @@ -7220,6 +7259,48 @@ def is_slender(self, certificate=False): return (True, None) return True + def is_sperner(self): + """ + Return ``True`` if the poset is Sperner, and ``False`` otherwise. + + The poset is expected to be ranked. + + A poset is Sperner, if no antichain is larger than the largest + rank level (one of the sets of elements of the same rank) in + the poset. + + See :wikipedia:`Sperner_property_of_a_partially_ordered_set` + + .. SEEALSO:: :meth:`width`, :meth:`dilworth_decomposition` + + EXAMPLES:: + + sage: posets.SetPartitions(3).is_sperner() + True + + sage: P = Poset({0:[3,4,5],1:[5],2:[5]}) + sage: P.is_sperner() + False + + TESTS:: + + sage: posets.PentagonPoset().is_sperner() + Traceback (most recent call last): + ... + ValueError: the poset is not ranked + + sage: P = Poset() + sage: P.is_sperner() + True + """ + if not self.is_ranked(): + raise ValueError("the poset is not ranked") + if not self.cardinality(): + return True + W = self.width() + N = max(len(level) for level in self._hasse_diagram.level_sets()) + return W <= N + def is_eulerian(self, k=None, certificate=False): """ Return ``True`` if the poset is Eulerian, and ``False`` otherwise. @@ -7970,6 +8051,7 @@ def is_induced_subposet(self, other): return (set(self).issubset(set(other)) and other.subposet(self).hasse_diagram() == self.hasse_diagram()) + FinitePoset._dual_class = FinitePoset # ------- Posets ------- @@ -8081,6 +8163,7 @@ def cardinality(self, from_iterator=False): else: return super(FinitePosets_n, self).cardinality() + # For backward compatibility of pickles of the former Posets() Posets_all = Posets diff --git a/src/sage/combinat/rigged_configurations/all.py b/src/sage/combinat/rigged_configurations/all.py index 71635f041a9..3a9573a929f 100644 --- a/src/sage/combinat/rigged_configurations/all.py +++ b/src/sage/combinat/rigged_configurations/all.py @@ -3,5 +3,9 @@ """ from __future__ import absolute_import -from .rigged_configurations import RiggedConfigurations +from sage.misc.lazy_import import lazy_import +lazy_import('sage.combinat.rigged_configurations.rigged_configurations', + 'RiggedConfigurations') + +del absolute_import diff --git a/src/sage/combinat/rigged_configurations/bij_infinity.py b/src/sage/combinat/rigged_configurations/bij_infinity.py index 04e7494805a..7717c8691a2 100644 --- a/src/sage/combinat/rigged_configurations/bij_infinity.py +++ b/src/sage/combinat/rigged_configurations/bij_infinity.py @@ -12,7 +12,7 @@ Preprint. :arxiv:`1505.07040`. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -24,8 +24,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations @@ -39,11 +39,11 @@ RCToKRTBijectionTypeC) from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux from sage.combinat.crystals.letters import CrystalOfLetters -from sage.combinat.root_system.cartan_type import CartanType from sage.categories.morphism import Morphism from sage.categories.homset import Hom from sage.misc.flatten import flatten + class FromTableauIsomorphism(Morphism): r""" Crystal isomorphism of `B(\infty)` in the tableau model to the diff --git a/src/sage/combinat/rigged_configurations/kleber_tree.py b/src/sage/combinat/rigged_configurations/kleber_tree.py index d5c8e83a15f..7bf1e624b12 100644 --- a/src/sage/combinat/rigged_configurations/kleber_tree.py +++ b/src/sage/combinat/rigged_configurations/kleber_tree.py @@ -50,7 +50,7 @@ ((2, 0, 1, 1, 0, 0, 0), (0, 1, 1, 0, 0, 0, 0))] """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011, 2012 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -62,8 +62,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from six.moves import range import itertools @@ -74,14 +74,12 @@ from sage.misc.misc_c import prod from sage.arith.all import binomial from sage.rings.integer import Integer -from sage.rings.all import ZZ from sage.structure.parent import Parent from sage.structure.element import Element from sage.structure.unique_representation import UniqueRepresentation from sage.structure.richcmp import richcmp_not_equal, richcmp from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.modules.free_module import FreeModule from sage.combinat.root_system.cartan_type import CartanType diff --git a/src/sage/combinat/rigged_configurations/rc_crystal.py b/src/sage/combinat/rigged_configurations/rc_crystal.py index 1b5983b7d56..148da8de04a 100644 --- a/src/sage/combinat/rigged_configurations/rc_crystal.py +++ b/src/sage/combinat/rigged_configurations/rc_crystal.py @@ -445,7 +445,6 @@ def from_virtual(self, vrc): n = self._cartan_type.rank() partitions = [None] * n riggings = [None] * n - vac_nums = [None] * n vindex = self._folded_ct._folding.index_set() for a in range(n): index = vindex.index(sigma[a][0]) diff --git a/src/sage/combinat/rigged_configurations/rigged_configurations.py b/src/sage/combinat/rigged_configurations/rigged_configurations.py index f7ccce515d1..64453dea3a1 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configurations.py +++ b/src/sage/combinat/rigged_configurations/rigged_configurations.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2010-09-26): Initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010-2012 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -18,8 +18,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import itertools @@ -65,8 +65,8 @@ def KirillovReshetikhinCrystal(cartan_type, r, s): sage: K1 is KirillovReshetikhinCrystal(['A',6,2], 2, 1) True """ - from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations - return RiggedConfigurations(cartan_type, [[r,s]]) + return RiggedConfigurations(cartan_type, [[r, s]]) + # Note on implementation, this class is used for simply-laced types only class RiggedConfigurations(UniqueRepresentation, Parent): @@ -795,9 +795,9 @@ def _calc_vacancy_number(self, partitions, a, i, **options): """ vac_num = 0 if "B" in options: - for tableau in options["B"]: - if len(tableau) == self._rc_index[a]: - vac_num += min(i, len(tableau[0])) + for tab in options["B"]: + if len(tab) == self._rc_index[a]: + vac_num += min(i, len(tab[0])) elif "L" in options: L = options["L"] if a in L: @@ -1135,9 +1135,9 @@ def _calc_vacancy_number(self, partitions, a, i, **options): """ vac_num = 0 if "B" in options: - for tableau in options["B"]: - if len(tableau) == self._rc_index[a]: - vac_num += min(i, len(tableau[0])) + for tab in options["B"]: + if len(tab) == self._rc_index[a]: + vac_num += min(i, len(tab[0])) elif "L" in options: L = options["L"] if a in L: @@ -1484,9 +1484,9 @@ def _calc_vacancy_number(self, partitions, a, i, **options): """ vac_num = 0 if "B" in options: - for tableau in options["B"]: - if len(tableau) == self._rc_index[a]: - vac_num += min(i, len(tableau[0])) + for tab in options["B"]: + if len(tab) == self._rc_index[a]: + vac_num += min(i, len(tab[0])) elif "L" in options: L = options["L"] if a in L: @@ -1637,9 +1637,9 @@ def _calc_vacancy_number(self, partitions, a, i, **options): vac_num = 0 if "B" in options: - for tableau in options["B"]: - if len(tableau) == self._rc_index[a]: - vac_num += min(i, len(tableau[0])) + for tab in options["B"]: + if len(tab) == self._rc_index[a]: + vac_num += min(i, len(tab[0])) elif "L" in options: L = options["L"] if a in L: diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 9b2aecc386b..dde4935744d 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -2530,7 +2530,6 @@ def __reduce__(self): True """ - from .cartan_type import CartanType return (CartanType, (self.letter, self.n)) def __hash__(self): @@ -2725,11 +2724,11 @@ def _repr_(self, compact = False): letter = 'A' n *= 2 if compact: - return '%s%s^%s'%(letter, n, aff) + return '%s%s^%s' % (letter, n, aff) if compact: - return '%s%s~'%(letter, n) + return '%s%s~' % (letter, n) else: - return "['%s', %s, %s]"%(letter, n, aff) + return "['%s', %s, %s]" % (letter, n, aff) def __reduce__(self): """ @@ -2742,7 +2741,6 @@ def __reduce__(self): True """ - from sage.combinat.root_system.cartan_type import CartanType return (CartanType, (self.letter, self.n, self.affine)) def __getitem__(self, i): diff --git a/src/sage/combinat/root_system/dynkin_diagram.py b/src/sage/combinat/root_system/dynkin_diagram.py index 0cf7daaf598..809afeecb6f 100644 --- a/src/sage/combinat/root_system/dynkin_diagram.py +++ b/src/sage/combinat/root_system/dynkin_diagram.py @@ -525,9 +525,14 @@ def dual(self): result._cartan_type = self._cartan_type.dual() if not self._cartan_type is None else None return result - def relabel(self, relabelling, inplace=False, **kwds): + def relabel(self, *args, **kwds): """ - Return the relabelling Dynkin diagram of ``self``. + Return the relabelled Dynkin diagram of ``self``. + + INPUT: see :meth:`~sage.graphs.generic_graph.GenericGraph.relabel` + + There is one difference: the default value for ``inplace`` is + ``False`` instead of ``True``. EXAMPLES:: @@ -541,29 +546,65 @@ def relabel(self, relabelling, inplace=False, **kwds): 1 2 3 C3 + sage: _ = D.relabel({1:0, 2:4, 3:1}, inplace=True) + sage: D + O---O=<=O + 0 4 1 + C3 relabelled by {1: 0, 2: 4, 3: 1} + sage: D = DynkinDiagram(['A', [1,2]]) - sage: Dp = D.relabel({-1:4, 0:-3, 1:3, 2:2}); Dp + sage: Dp = D.relabel({-1:4, 0:-3, 1:3, 2:2}) + sage: Dp O---X---O---O 4 -3 3 2 A1|2 relabelled by {-1: 4, 0: -3, 1: 3, 2: 2} sage: Dp.odd_isotropic_roots() (-3,) + + sage: D = DynkinDiagram(['D', 5]) + sage: G, perm = D.relabel(range(5), return_map=True) + sage: G + O 4 + | + | + O---O---O---O + 0 1 2 3 + D5 relabelled by {1: 0, 2: 1, 3: 2, 4: 3, 5: 4} + sage: perm + {1: 0, 2: 1, 3: 2, 4: 3, 5: 4} + + sage: perm = D.relabel(range(5), return_map=True, inplace=True) + sage: D + O 4 + | + | + O---O---O---O + 0 1 2 3 + D5 relabelled by {1: 0, 2: 1, 3: 2, 4: 3, 5: 4} + sage: perm + {1: 0, 2: 1, 3: 2, 4: 3, 5: 4} """ + return_map = kwds.pop("return_map", False) + inplace = kwds.pop("inplace", False) if inplace: - DiGraph.relabel(self, relabelling, inplace, **kwds) G = self else: - # We must make a copy of ourselves first because of DiGraph's - # relabel default behavior is to do so in place, and if not - # then it recurses on itself with no argument for inplace - G = self.copy().relabel(relabelling, inplace=True, **kwds) - if isinstance(relabelling, dict): - relabelling = relabelling.__getitem__ - new_odds = [relabelling(i) for i in self._odd_isotropic_roots] + # We need to copy self because we want to return the + # permutation and that works when relabelling in place. + G = self.copy() + + perm = DiGraph.relabel(G, *args, inplace=True, return_map=True, **kwds) + new_odds = [perm[i] for i in self._odd_isotropic_roots] G._odd_isotropic_roots = tuple(new_odds) if self._cartan_type is not None: - G._cartan_type = self._cartan_type.relabel(relabelling) - return G + G._cartan_type = self._cartan_type.relabel(perm.__getitem__) + if return_map: + if inplace: + return perm + else: + return G, perm + else: + return G def subtype(self, index_set): """ diff --git a/src/sage/combinat/root_system/fundamental_group.py b/src/sage/combinat/root_system/fundamental_group.py index 21185a6cdcf..7c097ad7fe3 100644 --- a/src/sage/combinat/root_system/fundamental_group.py +++ b/src/sage/combinat/root_system/fundamental_group.py @@ -5,15 +5,15 @@ - Mark Shimozono (2013) initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Mark Shimozono # # This 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.combinat.root_system.cartan_type import CartanType from sage.categories.groups import Groups from sage.misc.cachefunc import cached_method @@ -23,14 +23,14 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.sets.family import Family from sage.combinat.root_system.root_system import RootSystem -from sage.rings.finite_rings.integer_mod import Mod from sage.categories.category import Category from sage.categories.enumerated_sets import EnumeratedSets from sage.rings.integer_ring import ZZ from sage.sets.family import LazyFamily -def FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix='pi', general_linear=None): +def FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix='pi', + general_linear=None): r""" Factory for the fundamental group of an extended affine Weyl group. @@ -199,7 +199,8 @@ def FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix='pi', general_ return FundamentalGroupGL(cartan_type, prefix) else: raise ValueError("General Linear Fundamental group is untwisted type A") - return FundamentalGroupOfExtendedAffineWeylGroup_Class(cartan_type,prefix,finite=True) + return FundamentalGroupOfExtendedAffineWeylGroup_Class(cartan_type, prefix, + finite=True) class FundamentalGroupElement(MultiplicativeGroupElement): @@ -213,11 +214,6 @@ def __init__(self, parent, x): sage: x = FundamentalGroupOfExtendedAffineWeylGroup(['A',4,1], prefix="f").an_element() sage: TestSuite(x).run() """ - try: - if x.parent() == parent: - return x - except AttributeError: - pass if x not in parent.special_nodes(): raise ValueError("%s is not a special node" % x) self._value = x @@ -330,7 +326,9 @@ def act_on_affine_lattice(self, wt): """ return wt.map_support(self.parent().action(self.value())) -class FundamentalGroupOfExtendedAffineWeylGroup_Class(UniqueRepresentation, Parent): + +class FundamentalGroupOfExtendedAffineWeylGroup_Class(UniqueRepresentation, + Parent): r""" The group of length zero elements in the extended affine Weyl group. """ @@ -360,11 +358,14 @@ def leading_support(beta): special_node = cartan_type.special_node() self._special_nodes = cartan_type.special_nodes() - # initialize dictionaries with the entries for the distinguished special node + # initialize dictionaries with the entries for the + # distinguished special node + # dictionary of inverse elements inverse_dict = {} inverse_dict[special_node] = special_node - # dictionary for the action of special automorphisms by permutations of the affine Dynkin nodes + # dictionary for the action of special automorphisms by + # permutations of the affine Dynkin nodes auto_dict = {} for i in cartan_type.index_set(): auto_dict[special_node,i] = i @@ -373,7 +374,8 @@ def leading_support(beta): reduced_words_dict[0] = tuple([]) if cartan_type.dual().is_untwisted_affine(): - # this combines the computations for an untwisted affine type and its affine dual + # this combines the computations for an untwisted affine + # type and its affine dual cartan_type = cartan_type.dual() if cartan_type.is_untwisted_affine(): cartan_type_classical = cartan_type.classical() @@ -393,16 +395,17 @@ def leading_support(beta): auto_dict[i,special_node] = i for j in I: if j == idual: - auto_dict[i,j] = special_node + auto_dict[i, j] = special_node else: - auto_dict[i,j] = leading_support(w0i.action(alpha[j])) + auto_dict[i, j] = leading_support(w0i.action(alpha[j])) - self._action = Family(self._special_nodes, lambda i: Family(cartan_type.index_set(), lambda j: auto_dict[i,j])) + self._action = Family(self._special_nodes, lambda i: Family(cartan_type.index_set(), lambda j: auto_dict[i, j])) self._dual_node = Family(self._special_nodes, inverse_dict.__getitem__) self._reduced_words = Family(self._special_nodes, reduced_words_dict.__getitem__) if finite: - cat = Category.join((Groups().Commutative().Finite(),EnumeratedSets())) + cat = Category.join((Groups().Commutative().Finite(), + EnumeratedSets())) else: cat = Groups().Commutative().Infinite() Parent.__init__(self, category = cat) @@ -460,7 +463,7 @@ def _repr_(self): sage: FundamentalGroupOfExtendedAffineWeylGroup(['A',3,1]) # indirect doctest Fundamental group of type ['A', 3, 1] """ - return "Fundamental group of type %s"%self.cartan_type() + return "Fundamental group of type %s" % self.cartan_type() def special_nodes(self): r""" @@ -594,6 +597,7 @@ def reduced_word(self, i): """ return self._reduced_words[i] + class FundamentalGroupGLElement(FundamentalGroupElement): def act_on_classical_ambient(self, wt): r""" @@ -612,6 +616,7 @@ def act_on_classical_ambient(self, wt): """ return wt.map_support(self.parent().action(self.value())) + class FundamentalGroupGL(FundamentalGroupOfExtendedAffineWeylGroup_Class): r""" Fundamental group of `GL_n`. It is just the integers with extra privileges. @@ -644,7 +649,7 @@ def one(self): sage: FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1], general_linear=True).one() pi[0] """ - return self(ZZ(0)) + return self(ZZ.zero()) def product(self, x, y): r""" @@ -661,7 +666,7 @@ def product(self, x, y): sage: F(1)*F(3)^(-1) pi[-2] """ - return self(x.value()+y.value()) + return self(x.value() + y.value()) def _repr_(self): r""" @@ -673,7 +678,7 @@ def _repr_(self): sage: FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1], general_linear=True) # indirect doctest Fundamental group of GL(3) """ - return "Fundamental group of GL(%s)"%self._n + return "Fundamental group of GL(%s)" % self._n def family(self): r""" @@ -725,7 +730,7 @@ def group_generators(self): sage: FundamentalGroupOfExtendedAffineWeylGroup(['A',2,1], general_linear=True).group_generators() (pi[1],) """ - return tuple([self(ZZ(1))]) + return (self(ZZ.one()),) def action(self, i): r""" @@ -740,7 +745,7 @@ def action(self, i): sage: F.action(-4)(2) 1 """ - return lambda j: ZZ(Mod(i + j, self._n)) + return lambda j: (i + j) % self._n def dual_node(self, i): r""" @@ -772,7 +777,7 @@ def reduced_word(self, i): sage: F.reduced_word(10) (1, 2) """ - i = ZZ(Mod(i, self._n)) + i = i % self._n if i == 0: return tuple([]) om = self.cartan_type().classical().root_system().weight_lattice().fundamental_weight(i) diff --git a/src/sage/combinat/root_system/reflection_group_complex.py b/src/sage/combinat/root_system/reflection_group_complex.py index 9b5d5552755..ec66acca1b7 100644 --- a/src/sage/combinat/root_system/reflection_group_complex.py +++ b/src/sage/combinat/root_system/reflection_group_complex.py @@ -1906,8 +1906,8 @@ def coxeter_number(self, chi=None): sage: W = ReflectionGroup(["H",4]) # optional - gap3 sage: W.coxeter_number() # optional - gap3 30 - sage: all([W.coxeter_number(chi).is_integer() # optional - gap3 - ....: for chi in W.irreducible_characters()]) + sage: all(W.coxeter_number(chi).is_integer() # optional - gap3 + ....: for chi in W.irreducible_characters()) True sage: W = ReflectionGroup(14) # optional - gap3 sage: W.coxeter_number() # optional - gap3 diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index f2ad00ba47f..96cbbcd9431 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -34,15 +34,15 @@ download by hand from `Jean Michel's website `_. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011-2016 Christian Stump # # This 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 __future__ import print_function from six.moves import range @@ -55,6 +55,7 @@ from sage.misc.sage_eval import sage_eval from sage.combinat.root_system.reflection_group_element import RealReflectionGroupElement + def ReflectionGroup(*args,**kwds): r""" Construct a finite (complex or real) reflection group as a Sage @@ -141,12 +142,12 @@ def ReflectionGroup(*args,**kwds): # precheck for valid input data if not (isinstance(X, (CartanType_abstract,tuple)) or (X in ZZ and 4 <= X <= 37)): - raise ValueError(error_msg%X) + raise ValueError(error_msg % X) # transforming two reducible types and an irreducible type if isinstance(X, CartanType_abstract): if not X.is_finite(): - raise ValueError(error_msg%X) + raise ValueError(error_msg % X) if hasattr(X,"cartan_type"): X = X.cartan_type() if X.is_irreducible(): @@ -200,7 +201,7 @@ def ReflectionGroup(*args,**kwds): if isinstance(index_set, (list, tuple)): kwds[index_set_kwd] = tuple(index_set) else: - raise ValueError('the keyword %s must be a list or tuple'%index_set_kwd) + raise ValueError('the keyword %s must be a list or tuple' % index_set_kwd) if len(W_types) == 1: if is_complex is True: @@ -217,6 +218,7 @@ def ReflectionGroup(*args,**kwds): hyperplane_index_set=kwds.get('hyperplane_index_set', None), reflection_index_set=kwds.get('reflection_index_set', None)) + @cached_function def is_chevie_available(): r""" @@ -241,6 +243,7 @@ def is_chevie_available(): ##################################################################### ## Classes + class RealReflectionGroup(ComplexReflectionGroup): """ A real reflection group given as a permutation group. @@ -289,7 +292,7 @@ def _repr_(self): type_str += self._irrcomp_repr_(W_type) type_str += ' x ' type_str = type_str[:-3] - return 'Reducible real reflection group of rank %s and type %s'%(self._rank,type_str) + return 'Reducible real reflection group of rank %s and type %s' % (self._rank, type_str) def iteration(self, algorithm="breadth", tracking_words=True): r""" @@ -508,17 +511,18 @@ def reflection_to_positive_root(self, r): EXAMPLES:: - sage: W = ReflectionGroup(['A',2]) # optional - gap3 - sage: for r in W.reflections(): print(W.reflection_to_positive_root(r)) # optional - gap3 + sage: W = ReflectionGroup(['A',2]) # optional - gap3 + sage: for r in W.reflections(): # optional - gap3 + ....: print(W.reflection_to_positive_root(r)) (1, 0) (0, 1) (1, 1) """ Phi = self.roots() - N = len(Phi) / 2 - for i in range(1, N+1): + N = len(Phi) // 2 + for i in range(1, N + 1): if r(i) == i + N: - return Phi[i-1] + return Phi[i - 1] raise AssertionError("there is a bug in reflection_to_positive_root") @cached_method @@ -565,11 +569,11 @@ def fundamental_weights(self): m = self.cartan_matrix().transpose().inverse() Delta = tuple(self.simple_roots()) zero = Delta[0].parent().zero() - weights = [sum([m[i,j] * sj for j,sj in enumerate(Delta)], zero) + weights = [sum([m[i, j] * sj for j, sj in enumerate(Delta)], zero) for i in range(len(Delta))] for weight in weights: weight.set_immutable() - return Family({ind:weights[i] for i,ind in enumerate(self._index_set)}) + return Family({ind:weights[i] for i, ind in enumerate(self._index_set)}) def fundamental_weight(self, i): r""" @@ -600,11 +604,11 @@ def coxeter_diagram(self): V = self.index_set() S = self.simple_reflections() E = [] - for i,j in combinations(V, 2): - o = (S[i]*S[j]).order() + for i, j in combinations(V, 2): + o = (S[i] * S[j]).order() if o >= 3: - E.append((i,j,o)) - return Graph([V,E], format='vertices_and_edges', immutable=True) + E.append((i, j, o)) + return Graph([V, E], format='vertices_and_edges', immutable=True) @cached_method def coxeter_matrix(self): @@ -742,6 +746,7 @@ def left_coset_representatives(self): """ return [ (~w) for w in self.right_coset_representatives() ] + class IrreducibleRealReflectionGroup(RealReflectionGroup, IrreducibleComplexReflectionGroup): def _repr_(self): r""" @@ -758,8 +763,7 @@ def _repr_(self): Irreducible real reflection group of rank 2 and type I2(7) """ type_str = self._irrcomp_repr_(self._type[0]) - return 'Irreducible real reflection group of rank %s and type %s'%(self._rank,type_str) + return 'Irreducible real reflection group of rank %s and type %s' % (self._rank,type_str) class Element(RealReflectionGroup.Element, IrreducibleComplexReflectionGroup.Element): pass - diff --git a/src/sage/combinat/root_system/type_dual.py b/src/sage/combinat/root_system/type_dual.py index 38688b9b5fb..37fc398f2c1 100644 --- a/src/sage/combinat/root_system/type_dual.py +++ b/src/sage/combinat/root_system/type_dual.py @@ -1,15 +1,14 @@ """ Root system data for dual Cartan types """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008-2009 Anne Schilling # Copyright (C) 2008-2013 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** -from __future__ import print_function -from __future__ import absolute_import +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import print_function, absolute_import from sage.misc.misc import attrcall from sage.misc.cachefunc import cached_method @@ -604,7 +603,7 @@ def _repr_(self, compact=False): return 'A%s^2'%(self.classical().rank()*2-1) return "['A', %s, 2]"%(self.classical().rank()*2-1) elif self._type.type() == 'BC': - dual_str = '+' + dual_str = '+' # UNUSED ? elif self._type.type() == 'C': if compact: return 'D%s^2'%(self.rank()) diff --git a/src/sage/combinat/root_system/type_reducible.py b/src/sage/combinat/root_system/type_reducible.py index 96c46e0f495..1ca2745cb60 100644 --- a/src/sage/combinat/root_system/type_reducible.py +++ b/src/sage/combinat/root_system/type_reducible.py @@ -1,16 +1,15 @@ """ Root system data for reducible Cartan types """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** -from __future__ import print_function -from __future__ import absolute_import +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import print_function, absolute_import from sage.misc.cachefunc import cached_method from sage.combinat.root_system.cartan_type import CartanType_abstract, CartanType_simple, CartanType_finite, CartanType_simply_laced, CartanType_crystallographic @@ -163,9 +162,10 @@ def __hash__(self): r""" EXAMPLES:: - sage: hash(CartanType(['A',1],['B',2])) - 1110723648 # 32-bit - -6896789355307447232 # 64-bit + sage: ct0 = CartanType(['A',1],['B',2]) + sage: ct1 = CartanType(['A',2],['B',3]) + sage: hash(ct0) != hash(ct1) + True """ return hash(repr(self._types)) diff --git a/src/sage/combinat/root_system/type_relabel.py b/src/sage/combinat/root_system/type_relabel.py index bc7f09308de..a00b415e50f 100644 --- a/src/sage/combinat/root_system/type_relabel.py +++ b/src/sage/combinat/root_system/type_relabel.py @@ -406,6 +406,22 @@ def type(self): """ return self._type.type() + def coxeter_diagram(self): + """ + Return the Coxeter diagram for ``self``. + + EXAMPLES:: + + sage: ct = CartanType(['H', 3]).relabel({1:3,2:2,3:1}) + sage: G = ct.coxeter_diagram(); G + Graph on 3 vertices + sage: G.edges() + [(1, 2, 5), (2, 3, 3)] + """ + result = self._type.coxeter_diagram().copy() + result.relabel(self._relabelling) + return result + ########################################################################### class AmbientSpace(ambient_space.AmbientSpace): diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 81c6b2b8b01..d842394de99 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -364,7 +364,7 @@ def graft_list(self, other): sage: x = RootedTree([[[], []], []]) sage: y = RootedTree([[], []]) - sage: len(uniq(x.graft_list(y))) + sage: len(set(x.graft_list(y))) 4 """ resu = [] diff --git a/src/sage/combinat/set_partition.py b/src/sage/combinat/set_partition.py index 92eff8f532e..6e94bc133f5 100644 --- a/src/sage/combinat/set_partition.py +++ b/src/sage/combinat/set_partition.py @@ -46,19 +46,17 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.rings.infinity import infinity from sage.rings.integer import Integer -from sage.combinat.misc import IterableFunctionCall from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.combinat_cython import (set_partition_iterator, set_partition_iterator_blocks) -import sage.combinat.subset as subset from sage.combinat.partition import Partition, Partitions -from sage.combinat.set_partition_ordered import OrderedSetPartitions from sage.combinat.combinat import bell_number, stirling_number2 from sage.combinat.permutation import Permutation from sage.functions.other import factorial from sage.misc.prandom import random, randint from sage.probability.probability_distribution import GeneralDiscreteDistribution from sage.sets.disjoint_set import DisjointSet +from sage.combinat.posets.hasse_diagram import HasseDiagram @add_metaclass(InheritComparisonClasscallMetaclass) class AbstractSetPartition(ClonableArray): @@ -112,6 +110,15 @@ def __eq__(self, y): sage: D = P([[1], [2, 4], [3]]) sage: A == D False + + Note that this may give incorrect answers if the base set is not totally ordered:: + + sage: a,b = frozenset([0,1]), frozenset([2,3]) + sage: p1 = SetPartition([[a], [b]]) + sage: p2 = SetPartition([[b], [a]]) + sage: p1 == p2 + False + """ if not isinstance(y, AbstractSetPartition): return False @@ -136,6 +143,14 @@ def __ne__(self, y): sage: D = P([[1], [2, 4], [3]]) sage: A != D True + + Note that this may give incorrect answers if the base set is not totally ordered:: + + sage: a,b = frozenset([0,1]), frozenset([2,3]) + sage: p1 = SetPartition([[a], [b]]) + sage: p2 = SetPartition([[b], [a]]) + sage: p1 != p2 + True """ return not (self == y) @@ -368,7 +383,7 @@ def standard_form(self): EXAMPLES:: sage: [x.standard_form() for x in SetPartitions(4, [2,2])] - [[[1, 2], [3, 4]], [[1, 3], [2, 4]], [[1, 4], [2, 3]]] + [[[1, 2], [3, 4]], [[1, 4], [2, 3]], [[1, 3], [2, 4]]] TESTS:: @@ -505,12 +520,12 @@ class SetPartition(AbstractSetPartition): `[2, 1, 1]`:: sage: SetPartitions(4, [2,1,1]).list() - [{{1}, {2}, {3, 4}}, - {{1}, {2, 4}, {3}}, - {{1}, {2, 3}, {4}}, + [{{1}, {2, 4}, {3}}, + {{1}, {2}, {3, 4}}, {{1, 4}, {2}, {3}}, {{1, 3}, {2}, {4}}, - {{1, 2}, {3}, {4}}] + {{1, 2}, {3}, {4}}, + {{1}, {2, 3}, {4}}] Since :trac:`14140`, we can create a set partition directly by :class:`SetPartition`, which creates the base set by taking the @@ -698,19 +713,19 @@ def _latex_(self): \draw[color=red] (4) to [out=115,in=65] (3); \end{tikzpicture} - sage: p = SetPartition([['a','c'],['b',1],[20]]) + sage: p = SetPartition([['a','c'],['b','d'],['e']]) sage: p.set_latex_options(plot='cyclic', color='blue', fill=True, tikz_scale=2) sage: latex(p) \begin{tikzpicture}[scale=2] \draw (0,0) circle [radius=1cm]; - \node[label=90:1] (0) at (90:1cm) {}; - \node[label=18:20] (1) at (18:1cm) {}; - \node[label=-54:a] (2) at (-54:1cm) {}; - \node[label=-126:b] (3) at (-126:1cm) {}; - \node[label=-198:c] (4) at (-198:1cm) {}; - \draw[-,thick,color=blue,fill=blue,fill opacity=0.1] (2.center) -- (4.center) -- cycle; - \draw[-,thick,color=blue,fill=blue,fill opacity=0.1] (0.center) -- (3.center) -- cycle; - \draw[-,thick,color=blue,fill=blue,fill opacity=0.1] (1.center) -- cycle; + \node[label=90:a] (0) at (90:1cm) {}; + \node[label=18:b] (1) at (18:1cm) {}; + \node[label=-54:c] (2) at (-54:1cm) {}; + \node[label=-126:d] (3) at (-126:1cm) {}; + \node[label=-198:e] (4) at (-198:1cm) {}; + \draw[-,thick,color=blue,fill=blue,fill opacity=0.1] (0.center) -- (2.center) -- cycle; + \draw[-,thick,color=blue,fill=blue,fill opacity=0.1] (1.center) -- (3.center) -- cycle; + \draw[-,thick,color=blue,fill=blue,fill opacity=0.1] (4.center) -- cycle; \fill[color=black] (0) circle (1.5pt); \fill[color=black] (1) circle (1.5pt); \fill[color=black] (2) circle (1.5pt); @@ -969,10 +984,10 @@ def to_restricted_growth_word_blocks(self): """ w = [0] * self.size() - # we can assume that the blocks are sorted by minimal element + # we can assume that the blocks are sorted by minimal element for i, B in enumerate(self): for j in B: - w[j-1] = i + w[j-1] = i return w def to_restricted_growth_word_intertwining(self): @@ -1958,10 +1973,10 @@ class SetPartitions(UniqueRepresentation, Parent): EXAMPLES:: sage: S = [1,2,3,4] - sage: SetPartitions(S,2) + sage: SetPartitions(S, 2) Set partitions of {1, 2, 3, 4} with 2 parts sage: SetPartitions([1,2,3,4], [3,1]).list() - [{{1}, {2, 3, 4}}, {{1, 3, 4}, {2}}, {{1, 2, 4}, {3}}, {{1, 2, 3}, {4}}] + [{{1}, {2, 3, 4}}, {{1, 2, 3}, {4}}, {{1, 2, 4}, {3}}, {{1, 3, 4}, {2}}] sage: SetPartitions(7, [3,3,1]).cardinality() 70 @@ -2491,41 +2506,6 @@ def from_rook_placement_psi(self, rooks, n): P = sorted(P, key=lambda B: (-len(B), min(B))) return self.element_class(self, P) - def _iterator_part(self, part): - """ - Return an iterator for the set partitions with block sizes - corresponding to the partition ``part``. - - INPUT: - - - ``part`` -- a :class:`Partition` object - - EXAMPLES:: - - sage: S = SetPartitions(3) - sage: it = S._iterator_part(Partition([1,1,1])) - sage: sorted(map(list, next(it))) - [[1], [2], [3]] - sage: S21 = SetPartitions(3,Partition([2,1])) - sage: len(list(S._iterator_part(Partition([2,1])))) == S21.cardinality() - True - """ - nonzero = [] - expo = [0] + part.to_exp() - - for i in range(len(expo)): - if expo[i] != 0: - nonzero.append([i, expo[i]]) - - taillesblocs = [(x[0])*(x[1]) for x in nonzero] - - blocs = OrderedSetPartitions(self._set, taillesblocs) - - for b in blocs: - lb = [IterableFunctionCall(_listbloc, nonzero[i][0], nonzero[i][1], b[i]) for i in range(len(nonzero))] - for x in itertools.product(*lb): - yield _union(x) - def is_less_than(self, s, t): r""" Check if `s < t` in the refinement ordering on set partitions. @@ -2752,6 +2732,10 @@ def random_element(self): sage: S = SetPartitions(10) sage: S.random_element() {{1, 4, 9}, {2, 5, 7}, {3}, {6}, {8, 10}} + + sage: S = SetPartitions(["a", "b", "c"]) + sage: S.random_element() + {{'a'}, {'b', 'c'}} """ base_set = list(self.base_set()) N = len(base_set) @@ -2769,7 +2753,7 @@ def random_element(self): else: p[b] = [base_set[i]] - return SetPartition(p.values()) + return self.element_class(self, p.values(), check=False) def cardinality(self): """ @@ -2799,6 +2783,9 @@ def __iter__(self): sage: SetPartitions(3).list() [{{1, 2, 3}}, {{1, 2}, {3}}, {{1, 3}, {2}}, {{1}, {2, 3}}, {{1}, {2}, {3}}] + + sage: SetPartitions(["a", "b"]).list() + [{{'a', 'b'}}, {{'a'}, {'b'}}] """ for sp in set_partition_iterator(sorted(self._set)): yield self.element_class(self, sp, check=False) @@ -2811,6 +2798,9 @@ def base_set(self): sage: SetPartitions(3).base_set() {1, 2, 3} + + sage: SetPartitions(["a", "b", "c"]).base_set() + {'a', 'c', 'b'} """ return Set(self._set) @@ -2848,13 +2838,17 @@ def __classcall_private__(cls, s, parts): def __init__(self, s, parts): """ + Initialize the data structure. + + We can assume here that `parts` is a :cls:`Partition`. + TESTS:: sage: S = SetPartitions(4, [2,2]) sage: TestSuite(S).run() """ SetPartitions_set.__init__(self, s) - self.parts = parts + self._parts = parts def _repr_(self): """ @@ -2863,7 +2857,35 @@ def _repr_(self): sage: SetPartitions(4, [2,2]) Set partitions of {1, 2, 3, 4} with sizes in [2, 2] """ - return "Set partitions of %s with sizes in %s"%(Set(self._set), self.parts) + return "Set partitions of %s with sizes in %s"%(Set(self._set), self._parts) + + @property + def parts(self): + r""" + ``self.parts`` is deprecated; use :meth:`shape` instead. + + TESTS:: + + sage: SetPartitions(5, [2,2,1]).parts + doctest:...: DeprecationWarning: The attribute parts for the partition of block sizes is deprecated, use the method shape instead. + See https://trac.sagemath.org/25865 for details. + [2, 2, 1] + """ + from sage.misc.superseded import deprecation + deprecation(25865, "The attribute parts for the partition of block sizes is deprecated," + " use the method shape instead.") + return self.shape() + + def shape(self): + r""" + Return the partition of block sizes of the set partitions in ``self``. + + EXAMPLES:: + + sage: SetPartitions(5, [2,2,1]).shape() + [2, 2, 1] + """ + return self._parts def cardinality(self): r""" @@ -2901,16 +2923,58 @@ def cardinality(self): remaining_subset_size = Integer(len(self._set)) cardinal = Integer(1) - for subset_size in self.parts: + for subset_size in self._parts: cardinal *= remaining_subset_size.binomial(subset_size) remaining_subset_size -= subset_size repetitions = (Integer(rep).factorial() - for rep in self.parts.to_exp_dict().values() + for rep in self._parts.to_exp_dict().values() if rep != 1) cardinal /= prod(repetitions) return Integer(cardinal) + def _set_partition_poset(self): + r""" + Return the Hasse diagram of a poset whose linear extensions correspond + to the set partitions with specified block sizes. + + TESTS:: + + sage: P = SetPartitions(["a", "b", "c", "d", "e"], [2,2,1])._set_partition_poset() + sage: P.cover_relations() + [(1, 2), (1, 3), (3, 4)] + + sage: n = 9 + sage: all(SetPartitions(n, mu).cardinality() == + ....: len(list(SetPartitions(n, mu)._set_partition_poset().linear_extensions())) + ....: for mu in Partitions(n)) + True + + """ + c = self._parts.to_exp_dict() + covers = dict() + i = 0 + for s in sorted(c): + # s is the block size + # each block is one tree in the poset + for m in range(c[s]): + # m is the multiplicity of blocks with size s + # + # the first element in each non-final block has an + # additional cover + first = i + if s == 1: + covers[i] = [] + else: + for j in range(s-1): + covers[i] = [i+1] + i += 1 + i += 1 + if m < c[s]-1: + covers[first].append(i) + return HasseDiagram(covers) + + def __iter__(self): """ An iterator for all the set partitions of the given set with @@ -2919,10 +2983,34 @@ def __iter__(self): EXAMPLES:: sage: SetPartitions(3, [2,1]).list() - [{{1}, {2, 3}}, {{1, 3}, {2}}, {{1, 2}, {3}}] + [{{1}, {2, 3}}, {{1, 2}, {3}}, {{1, 3}, {2}}] + + sage: SetPartitions(["a", "b", "c"], [2,1]).list() + [{{'a'}, {'b', 'c'}}, {{'a', 'c'}, {'b'}}, {{'a', 'b'}, {'c'}}] + + TESTS:: + + sage: n = 8 + sage: all(SetPartitions(n, mu).cardinality() == len(list(SetPartitions(n, mu))) for mu in Partitions(n)) + True + """ - for sp in self._iterator_part(self.parts): - yield self.element_class(self, sp) + # Ruskey, Combinatorial Generation, sec. 5.10.1 and Knuth TAOCP 4A 7.2.1.5, Exercise 6 + k = len(self._parts) + n = len(self._set) + s = list(self._set) + P = self._set_partition_poset() + + sums = [0] + for b in sorted(self._parts): + sums.append(sums[-1] + b) + + for ext in P.linear_extensions(): + pi = [None]*n + for i in range(n): + pi[ext[i]] = s[i] + sp = [[pi[j] for j in range(sums[i], sums[i+1])] for i in range(k)] + yield self.element_class(self, sp, check=False) def __contains__(self, x): """ @@ -2940,7 +3028,7 @@ def __contains__(self, x): """ if not SetPartitions_set.__contains__(self, x): return False - return sorted(map(len, x)) == list(reversed(self.parts)) + return sorted(map(len, x)) == list(reversed(self._parts)) class SetPartitions_setn(SetPartitions_set): """ @@ -3036,6 +3124,9 @@ def __iter__(self): {{1}, {2, 3, 4}}, {{1, 2}, {3, 4}}, {{1, 2, 3}, {4}}] + + sage: SetPartitions(["a", "b", "c"], 2).list() + [{{'a', 'c'}, {'b'}}, {{'a'}, {'b', 'c'}}, {{'a', 'b'}, {'c'}}] """ for sp in set_partition_iterator_blocks(sorted(self._set), self._k): yield self.element_class(self, sp, check=False) @@ -3069,6 +3160,10 @@ def random_element(self): sage: S = SetPartitions(10, 4) sage: S.random_element() {{1, 2, 4, 6, 9, 10}, {3}, {5, 7}, {8}} + + sage: SetPartitions(["a", "b", "c"], 2).random_element() + {{'a'}, {'b', 'c'}} + """ def re(N, k): if N == 0: @@ -3086,69 +3181,8 @@ def re(N, k): N = len(base_set) k = self._k p = re(N, k) - return SetPartition([[base_set[e] for e in b] for b in p]) - -def _listbloc(n, nbrepets, listint=None): - r""" - Decompose a set of `n \times n` ``brepets`` integers (the list - ``listint``) in ``nbrepets`` parts. - - It is used in the algorithm to generate all set partitions. - - .. WARNING:: - - Internal function that is not to be called by the user. - - EXAMPLES:: - - sage: list(sage.combinat.set_partition._listbloc(2,1)) - [{{1, 2}}] - sage: l = [Set([Set([3, 4]), Set([1, 2])]), Set([Set([2, 4]), Set([1, 3])]), Set([Set([2, 3]), Set([1, 4])])] - sage: list(sage.combinat.set_partition._listbloc(2,2,[1,2,3,4])) == l - True - """ - if isinstance(listint, (int, Integer)) or listint is None: - listint = Set(range(1,n+1)) + return self.element_class(self, [[base_set[e] for e in b] for b in p], check=False) - if nbrepets == 1: - yield Set([listint]) - return - - l = sorted(listint) - smallest = Set(l[:1]) - new_listint = Set(l[1:]) - - f = lambda u, v: u.union(_set_union([smallest,v])) - - for ssens in subset.Subsets(new_listint, n-1): - for z in _listbloc(n, nbrepets-1, new_listint-ssens): - yield f(z,ssens) - -def _union(s): - """ - TESTS:: - - sage: s = Set([ Set([1,2]), Set([3,4]) ]) - sage: sage.combinat.set_partition._union(s) - {1, 2, 3, 4} - """ - result = Set([]) - for ss in s: - result = result.union(ss) - return result - -def _set_union(s): - """ - TESTS:: - - sage: s = Set([ Set([1,2]), Set([3,4]) ]) - sage: sage.combinat.set_partition._set_union(s) - {{1, 2, 3, 4}} - """ - result = Set([]) - for ss in s: - result = result.union(ss) - return Set([result]) def cyclic_permutations_of_set_partition(set_part): """ diff --git a/src/sage/combinat/sf/all.py b/src/sage/combinat/sf/all.py index a57415fa027..f2436ee65f8 100644 --- a/src/sage/combinat/sf/all.py +++ b/src/sage/combinat/sf/all.py @@ -13,4 +13,8 @@ lazy_import('sage.combinat.sf.kfpoly', 'KostkaFoulkesPolynomial') -from .ns_macdonald import NonattackingFillings, AugmentedLatticeDiagramFilling, LatticeDiagram +lazy_import('sage.combinat.sf.ns_macdonald', ['NonattackingFillings', + 'AugmentedLatticeDiagramFilling', + 'LatticeDiagram']) + +del absolute_import diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index f099ca30dbf..06de9631c12 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -118,21 +118,56 @@ def _other_to_self(self, sexpr): sexpr -= sexpr.coefficient(mup) * self._self_to_other_on_basis(mup) return out + def _b_power_k(self, k): + r""" + An expression involving Moebius inversion in the powersum generators. + + For a positive value of ``k``, this expression is + + .. MATH:: + + \frac{1}{k} \sum_{d|k} \mu(d/k) p_d. + + INPUT: + + - ``k`` -- a positive integer + + OUTPUT: -class character_basis(generic_character): + - an expression in the powersum basis of the symmetric functions + + EXAMPLES:: + + sage: st = SymmetricFunctions(QQ).st() + sage: st._b_power_k(1) + p[1] + sage: st._b_power_k(2) + -1/2*p[1] + 1/2*p[2] + sage: st._b_power_k(6) + 1/6*p[1] - 1/6*p[2] - 1/6*p[3] + 1/6*p[6] + + """ + if k == 1: + return self._p([1]) + if k > 0: + return ~k * self._p.linear_combination((self._p([d]),moebius(k//d)) + for d in divisors(k)) + + +class induced_trivial_character_basis(generic_character): r""" - General code for a character basis (irreducible and induced trivial). + The induced trivial symmetric group character basis of + the symmetric functions. This is a basis of the symmetric functions that has the property that ``self(la).character_to_frobenius_image(n)`` - is equal to ``other([n-sum(la)]+la)``. + is equal to ``h([n-sum(la)]+la)``. - It should also have the property that the (outer) structure + It has the property that the (outer) structure constants are the analogue of the stable Kronecker - coefficients on the ``other`` basis (where ``other`` is either the - Schur or homogeneous bases). + coefficients on the complete basis. - These bases are introduced in [OZ2015]_. + This basis is introduced in [OZ2015]_. EXAMPLES:: @@ -165,8 +200,12 @@ class character_basis(generic_character): st[1] + st[1, 1] + st[2] + st[2, 1] + st[3] sage: s[4,2].kronecker_product(s[5,1]) s[3, 2, 1] + s[3, 3] + s[4, 1, 1] + s[4, 2] + s[5, 1] + + TESTS:: + + sage: TestSuite(ht).run() """ - def __init__(self, Sym, other_basis, bname, pfix): + def __init__(self, Sym, pfix): r""" Initialize the basis and register coercions. @@ -175,35 +214,143 @@ def __init__(self, Sym, other_basis, bname, pfix): INPUT: - ``Sym`` -- an instance of the symmetric function algebra - - ``other_basis`` -- a basis of Sym - - ``bname`` -- the name for this basis (convention: ends in "character") - ``pfix`` -- a prefix to use for the basis EXAMPLES:: sage: Sym = SymmetricFunctions(QQ) sage: ht = SymmetricFunctions(QQ).ht(); ht - Symmetric Functions over Rational Field in the induced trivial character basis - sage: st = SymmetricFunctions(QQ).st(); st - Symmetric Functions over Rational Field in the irreducible symmetric group character basis - sage: TestSuite(ht).run() + Symmetric Functions over Rational Field in the induced trivial + symmetric group character basis """ - SFA_generic.__init__(self, Sym, basis_name=bname, prefix=pfix, graded=False) - self._other = other_basis - self.module_morphism(self._self_to_other_on_basis, - codomain=self._other).register_as_coercion() + SFA_generic.__init__(self, Sym, + basis_name="induced trivial symmetric group character", + prefix=pfix, graded=False) + self._other = Sym.complete() + self._p = Sym.powersum() + + self.module_morphism(self._self_to_power_on_basis, + codomain=Sym.powersum()).register_as_coercion() + from sage.categories.morphism import SetMorphism self.register_coercion(SetMorphism(Hom(self._other, self), self._other_to_self)) + def _b_bar_power_k_r(self, k, r): + r""" + An expression involving Moebius inversion in the powersum generators. + + For a positive value of ``k``, this expression is + + .. MATH:: + + \sum_{j=0}^r (-1)^{r-j}k^j\binom{r,j} + \left( \frac{1}{k} \sum_{d|k} \mu(d/k) p_d \right)_k. + + INPUT: + + - ``k``, ``r`` -- positive integers + + OUTPUT: + + - an expression in the powersum basis of the symmetric functions + + EXAMPLES:: + + sage: ht = SymmetricFunctions(QQ).ht() + sage: ht._b_bar_power_k_r(1,1) + p[1] + sage: ht._b_bar_power_k_r(2,2) + 2*p[1] + p[1, 1] - 2*p[2] - 2*p[2, 1] + p[2, 2] + sage: ht._b_bar_power_k_r(3,2) + 3*p[1] + p[1, 1] - 3*p[3] - 2*p[3, 1] + p[3, 3] + + """ + p = self._p + return k**r * p.prod( self._b_power_k(k)-j for j in range(r) ) + + def _b_bar_power_gamma(self, gamma): + r""" + An expression involving Moebius inversion in the powersum generators. + + For a partition `\gamma = (1^{m_1}, 2^{m_2}, \ldots, r^{m_r})`, + this expression is + + .. MATH:: + + {\mathbf p}_{\ga} = \sum_{k \geq 1} {\mathbf p}_{k^{m_k}}, + + where + + .. MATH:: + + {\mathbf p}_{k^r} = \sum_{j=0}^r (-1)^{r-j}k^j\binom{r,j} + \left( \frac{1}{k} \sum_{d|k} \mu(d/k) p_d \right)_k. + + INPUT: + + - ``gamma`` -- a partition + + OUTPUT: + + - an expression in the powersum basis of the symmetric functions + + EXAMPLES:: + + sage: ht = SymmetricFunctions(QQ).ht() + sage: ht._b_bar_power_gamma(Partition([2,2,1])) + 2*p[1, 1] + p[1, 1, 1] - 2*p[2, 1] - 2*p[2, 1, 1] + p[2, 2, 1] + sage: ht._b_bar_power_gamma(Partition([1,1,1])) + 2*p[1] - 3*p[1, 1] + p[1, 1, 1] + sage: ht._b_bar_power_gamma(Partition([3,3,1])) + 3*p[1, 1] + p[1, 1, 1] - 3*p[3, 1] - 2*p[3, 1, 1] + p[3, 3, 1] + + """ + return self._p.prod( self._b_bar_power_k_r(Integer(k),Integer(r)) + for (k,r) in six.iteritems(gamma.to_exp_dict()) ) + + def _self_to_power_on_basis(self, lam): + r""" + An expansion of the induced trivial character in the powersum basis. + + The formula for the induced trivial character basis indexed by the + partition ``lam`` is given by the formula + + .. MATH:: + + \sum_{\gamma} \left\langle h_\lambda, p_\gamma \right\rangle + \frac{{\overline {\mathbf p}}_\gamma}{z_\gamma}, + + where `{\overline {\mathbf p}}_\gamma` is the + power sum expression calculated in the method + :meth:`_b_bar_power_gamma`. + + INPUT: + + - ``lam`` -- a partition + + OUTPUT: + + - an expression in the power sum basis + + EXAMPLES:: + + sage: ht = SymmetricFunctions(QQ).ht() + sage: ht._self_to_power_on_basis([2,1]) + p[1] - 2*p[1, 1] + 1/2*p[1, 1, 1] + 1/2*p[2, 1] + sage: ht._self_to_power_on_basis([1,1,1]) + 2*p[1] - 3*p[1, 1] + p[1, 1, 1] + + """ + return self._p.sum( c*self._b_bar_power_gamma(ga) + for (ga, c) in self._p(self._other(lam)) ) + @cached_method def _self_to_other_on_basis(self, lam): r""" - Convert a character-basis element to the ``self._other`` basis. + An expansion of the induced trivial character basis in complete basis. - This is a recursive procedure that is calculated - by the assumption that the leading term of ``self(lam)`` - is ``other(lam)`` and - ``evalsf(self(lam),n) == other([n-sum(lam)]+lam)``. + Compute the complete expansion by first computing it in the + powersum basis and the coercing to the complete basis. INPUT: @@ -211,7 +358,7 @@ def _self_to_other_on_basis(self, lam): OUTPUT: - - an expression in the ``self._other`` basis + - an expression in the complete (other) basis EXAMPLES:: @@ -219,9 +366,6 @@ def _self_to_other_on_basis(self, lam): sage: ht = SymmetricFunctions(QQ).ht() sage: ht._self_to_other_on_basis(Partition([2,1])) h[1] - 2*h[1, 1] + h[2, 1] - sage: st = SymmetricFunctions(QQ).st() - sage: st._self_to_other_on_basis(Partition([2,1])) - 3*s[1] - 2*s[1, 1] - 2*s[2] + s[2, 1] TESTS:: @@ -237,12 +381,8 @@ def _self_to_other_on_basis(self, lam): sage: all(h(st(h[la])) == h[la] for i in range(5) for la in Partitions(i)) True """ - if not lam: - return self._other([]) - n = sum(lam) + lam[0] - sim = self._other(self._other(lam).character_to_frobenius_image(n)) - return self._other(lam) - sum(c*self._self_to_other_on_basis(Partition(mu[1:])) - for (mu,c) in sim if mu[1:] != lam) + return self._other(self._self_to_power_on_basis(lam)) + class irreducible_character_basis(generic_character): r""" @@ -254,9 +394,8 @@ class irreducible_character_basis(generic_character): is equal to ``s([n-sum(la)]+la)``. It should also have the property that the (outer) structure - constants are the analogue of the stable kronecker - coefficients on the Schur basis (where ``other`` is either the - Schur or homogeneous bases). + constants are the analogue of the stable Kronecker + coefficients on the Schur basis. This basis is introduced in [OZ2015]_. @@ -306,7 +445,7 @@ def __init__(self, Sym, pfix): sage: Sym = SymmetricFunctions(QQ) sage: ht = SymmetricFunctions(QQ).ht(); ht Symmetric Functions over Rational Field in the induced trivial - character basis + symmetric group character basis sage: st = SymmetricFunctions(QQ).st(); st Symmetric Functions over Rational Field in the irreducible symmetric group character basis @@ -323,44 +462,9 @@ def __init__(self, Sym, pfix): self.register_coercion(SetMorphism(Hom(self._other, self), self._other_to_self)) - def _b_power_k(self, k): - r""" - An expression involving moebius inversion in the powersum generators. - - For a positive value of ``k``, this expression is - - .. MATH:: - - \frac{1}{k} \sum_{d|k} \mu(d/k) p_d. - - INPUT: - - - ``k`` -- a positive integer - - OUTPUT: - - - an expression in the powersum basis of the symmetric functions - - EXAMPLES:: - - sage: st = SymmetricFunctions(QQ).st() - sage: st._b_power_k(1) - p[1] - sage: st._b_power_k(2) - -1/2*p[1] + 1/2*p[2] - sage: st._b_power_k(6) - 1/6*p[1] - 1/6*p[2] - 1/6*p[3] + 1/6*p[6] - - """ - if k == 1: - return self._p([1]) - if k > 0: - return ~k * self._p.sum(moebius(k/d)*self._p([d]) - for d in divisors(k)) - def _b_power_k_r(self, k, r): r""" - An expression involving moebius inversion in the powersum generators. + An expression involving Moebius inversion in the powersum generators. For a positive value of ``k``, this expression is @@ -395,9 +499,9 @@ def _b_power_k_r(self, k, r): def _b_power_gamma(self, gamma): r""" - An expression involving moebius inversion in the powersum generators. + An expression involving Moebius inversion in the powersum generators. - For a partition `\gamma = (1^{m_1}, 2^{m_2}, \ldots r^{m_r})`, + For a partition `\gamma = (1^{m_1}, 2^{m_2}, \ldots, r^{m_r})`, this expression is .. MATH:: @@ -409,7 +513,7 @@ def _b_power_gamma(self, gamma): .. MATH:: {\mathbf p}_{k^r} = \sum_{j=0}^r (-1)^{r-j}k^j\binom{r,j} - \left( \frac{1}{k} \sum_{d|k} \mu(d/k) p_d \right)_k~. + \left( \frac{1}{k} \sum_{d|k} \mu(d/k) p_d \right)_k. INPUT: @@ -422,12 +526,12 @@ def _b_power_gamma(self, gamma): EXAMPLES:: sage: st = SymmetricFunctions(QQ).st() - sage: st._b_power_k_r(1,1) - -p[] + p[1] - sage: st._b_power_k_r(2,2) + sage: st._b_power_gamma(Partition([2,2])) p[] + 4*p[1] + p[1, 1] - 4*p[2] - 2*p[2, 1] + p[2, 2] - sage: st._b_power_k_r(3,2) - p[] + 5*p[1] + p[1, 1] - 5*p[3] - 2*p[3, 1] + p[3, 3] + sage: st._b_power_gamma(Partition([1,1,1])) + -p[] + 8*p[1] - 6*p[1, 1] + p[1, 1, 1] + sage: st._b_power_gamma(Partition([3,1])) + p[] - p[1, 1] - p[3] + p[3, 1] """ return self._p.prod( self._b_power_k_r(Integer(k),Integer(r)) diff --git a/src/sage/combinat/sf/hall_littlewood.py b/src/sage/combinat/sf/hall_littlewood.py index a46da3face0..fc037cecf03 100644 --- a/src/sage/combinat/sf/hall_littlewood.py +++ b/src/sage/combinat/sf/hall_littlewood.py @@ -2,12 +2,6 @@ Hall-Littlewood Polynomials Notation used in the definitions follows mainly [Mac1995]_. - -REFERENCES: - -.. [Mac1995] \I. G. Macdonald, Symmetric functions and Hall polynomials, second ed., - The Clarendon Press, Oxford University Press, New York, 1995, With contributions - by A. Zelevinsky, Oxford Science Publications. """ from __future__ import absolute_import #***************************************************************************** diff --git a/src/sage/combinat/sf/hecke.py b/src/sage/combinat/sf/hecke.py index fc7aaf66a0c..70894078229 100644 --- a/src/sage/combinat/sf/hecke.py +++ b/src/sage/combinat/sf/hecke.py @@ -8,7 +8,7 @@ - Travis Scrimshaw (2017-08): Initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -20,18 +20,12 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import from sage.combinat.partition import _Partitions, Partitions from sage.combinat.sf.multiplicative import SymmetricFunctionAlgebra_multiplicative -from sage.matrix.all import matrix -from sage.categories.morphism import SetMorphism -from sage.categories.homset import Hom -from sage.categories.modules_with_basis import ModulesWithBasis -from sage.rings.integer_ring import ZZ class HeckeCharacter(SymmetricFunctionAlgebra_multiplicative): @@ -168,8 +162,8 @@ def __init__(self, sym, q='q'): self._p = sym.power() # temporary until Hom(GradedHopfAlgebrasWithBasis work better) - category = ModulesWithBasis(self._sym.base_ring()) - self .register_coercion(self._p._module_morphism(self._p_to_qbar_on_basis, + # category = ModulesWithBasis(self._sym.base_ring()) + self.register_coercion(self._p._module_morphism(self._p_to_qbar_on_basis, codomain=self)) self._p.register_coercion(self._module_morphism(self._qbar_to_p_on_basis, codomain=self._p)) diff --git a/src/sage/combinat/sf/k_dual.py b/src/sage/combinat/sf/k_dual.py index 15f2aee8200..b88de0b326a 100644 --- a/src/sage/combinat/sf/k_dual.py +++ b/src/sage/combinat/sf/k_dual.py @@ -39,7 +39,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.constant_function import ConstantFunction from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis -from sage.rings.all import Integer +from sage.rings.all import Integer, ZZ from sage.cpython.getattr import raw_getattr @@ -80,11 +80,11 @@ def __init__(self, Sym, k, t='t'): sage: F[1,2] Traceback (most recent call last): ... - ValueError: [1, 2] is not a valid partition + ValueError: [1, 2] is not an element of 3-Bounded Partitions sage: F[4,2] Traceback (most recent call last): ... - ValueError: Partition is not 3-bounded + ValueError: [4, 2] is not an element of 3-Bounded Partitions sage: km[2,1]*km[2,1] 4*m3[2, 2, 1, 1] + 6*m3[2, 2, 2] + 2*m3[3, 2, 1] + 2*m3[3, 3] sage: HLPk = Q.kHallLittlewoodP() @@ -573,7 +573,7 @@ def ambient(self): """ return self.realization_of()._sym - def __getitem__(self, c, *rest): + def __getitem__(self, c): r""" Implements shorthand for accessing basis elements. @@ -591,15 +591,10 @@ def __getitem__(self, c, *rest): sage: F[[]] F3[] """ - if isinstance(c, Partition): - assert len(rest) == 0 + if c in ZZ: + c = self._kbounded_partitions([c]) else: - if len(rest) or isinstance(c, (int, Integer)): - c = self._kbounded_partitions.element_class(self._kbounded_partitions, [c] + list(rest)) - else: - c = self._kbounded_partitions.element_class(self._kbounded_partitions, list(c)) - if c and c[0] > self.k: - raise ValueError("Partition is not %d-bounded" % self.k) + c = self._kbounded_partitions(c) return self.monomial(c) def _repr_term(self, c): diff --git a/src/sage/combinat/sf/kfpoly.py b/src/sage/combinat/sf/kfpoly.py index 1457830286f..e6dcf05ae11 100644 --- a/src/sage/combinat/sf/kfpoly.py +++ b/src/sage/combinat/sf/kfpoly.py @@ -5,7 +5,7 @@ which can be found at http://www.math.lsa.umich.edu/~jrs/maple.html . """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Mike Hansen , # 2007 John Stembridge # @@ -18,8 +18,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import print_function from sage.combinat.partition import _Partitions @@ -28,9 +28,6 @@ from sage.rings.integer_ring import ZZ -import six - - def KostkaFoulkesPolynomial(mu, nu, t=None): r""" Returns the Kostka-Foulkes polynomial `K_{\mu, \nu}(t)`. @@ -151,41 +148,41 @@ def schur_to_hl(mu, t=None): sage: schur_to_hl([1,1,1]) {[1, 1, 1]: 1} sage: a = schur_to_hl([2,1]) - sage: for mc in sorted(six.iteritems(a)): print(mc) + sage: for mc in sorted(a.items()): print(mc) ([1, 1, 1], t^2 + t) ([2, 1], 1) sage: a = schur_to_hl([3]) - sage: for mc in sorted(six.iteritems(a)): print(mc) + sage: for mc in sorted(a.items()): print(mc) ([1, 1, 1], t^3) ([2, 1], t) ([3], 1) sage: a = schur_to_hl([4]) - sage: for mc in sorted(six.iteritems(a)): print(mc) + sage: for mc in sorted(a.items()): print(mc) ([1, 1, 1, 1], t^6) ([2, 1, 1], t^3) ([2, 2], t^2) ([3, 1], t) ([4], 1) sage: a = schur_to_hl([3,1]) - sage: for mc in sorted(six.iteritems(a)): print(mc) + sage: for mc in sorted(a.items()): print(mc) ([1, 1, 1, 1], t^5 + t^4 + t^3) ([2, 1, 1], t^2 + t) ([2, 2], t) ([3, 1], 1) sage: a = schur_to_hl([2,2]) - sage: for mc in sorted(six.iteritems(a)): print(mc) + sage: for mc in sorted(a.items()): print(mc) ([1, 1, 1, 1], t^4 + t^2) ([2, 1, 1], t) ([2, 2], 1) sage: a = schur_to_hl([2,1,1]) - sage: for mc in sorted(six.iteritems(a)): print(mc) + sage: for mc in sorted(a.items()): print(mc) ([1, 1, 1, 1], t^3 + t^2 + t) ([2, 1, 1], 1) sage: a = schur_to_hl([1,1,1,1]) - sage: for mc in sorted(six.iteritems(a)): print(mc) + sage: for mc in sorted(a.items()): print(mc) ([1, 1, 1, 1], 1) sage: a = schur_to_hl([2,2,2]) - sage: for mc in sorted(six.iteritems(a)): print(mc) + sage: for mc in sorted(a.items()): print(mc) ([1, 1, 1, 1, 1, 1], t^9 + t^7 + t^6 + t^5 + t^3) ([2, 1, 1, 1, 1], t^4 + t^2) ([2, 2, 1, 1], t) diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index e4a4f3b57ab..7ec00a47cc9 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -15,7 +15,7 @@ :arxiv:`math/9809122v3` [math.q-alg] """ from __future__ import absolute_import -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki # @@ -28,8 +28,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.unique_representation import UniqueRepresentation from . import sfa import sage.combinat.ribbon_tableau as ribbon_tableau @@ -250,7 +250,8 @@ def _llt_generic(self, skp, stat): if skp in _Partitions: m = (sum(skp) / self.level()).floor() if m == 0: - raise ValueError("level (%=) must divide %s "%(sum(skp), self.level())) + raise ValueError("level (%s=) must divide %s " % (sum(skp), + self.level())) mu = Partitions( ZZ(sum(skp) / self.level()) ) elif isinstance(skp, list) and skp[0] in sage.combinat.skew_partition.SkewPartitions(): diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 86c8f369daa..a8d7b6792a2 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -55,12 +55,10 @@ from sage.categories.homset import Hom from sage.categories.modules_with_basis import ModulesWithBasis from . import sfa -from sage.combinat.partition import Partition, Partitions_n, _Partitions -from sage.combinat.skew_partition import SkewPartitions +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.fraction_field import FractionField from sage.misc.cachefunc import cached_function import functools @@ -79,6 +77,7 @@ _qt_kostka_cache = {} + class Macdonald(UniqueRepresentation): def __repr__(self): diff --git a/src/sage/combinat/sf/new_kschur.py b/src/sage/combinat/sf/new_kschur.py index 1a93d146b15..16358a10a1d 100644 --- a/src/sage/combinat/sf/new_kschur.py +++ b/src/sage/combinat/sf/new_kschur.py @@ -1,7 +1,7 @@ """ `k`-Schur Functions """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Jason Bandlow , # 2012 Anne Schilling # @@ -14,9 +14,9 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** -from sage.rings.all import Integer +# https://www.gnu.org/licenses/ +# **************************************************************************** +from sage.rings.all import Integer, ZZ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.categories.realizations import Realizations, Category_realization_of_parent @@ -24,7 +24,6 @@ from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis from sage.categories.graded_coalgebras import GradedCoalgebras from sage.categories.graded_coalgebras_with_basis import GradedCoalgebrasWithBasis -from sage.categories.magmas import Magmas from sage.categories.tensor import tensor from sage.combinat.partition import Partition, Partitions from sage.combinat.sf.sf import SymmetricFunctions @@ -371,7 +370,7 @@ def _convert_map_from_(self,Q): return self.retract * P._internal_coerce_map_from(Q) return None - def __getitem__(self, c, *rest): + def __getitem__(self, c): r""" Implements shorthand for accessing basis elements. @@ -401,14 +400,11 @@ def __getitem__(self, c, *rest): ... TypeError: do not know how to make [4, 1] an element of 3-bounded Symmetric Functions over Rational Field with t=1 in the 3-Schur basis """ - if isinstance(c, Partition): - if rest: - raise ValueError("Can only accept a partition") - else: - if rest or isinstance(c, (int, Integer)): - c = Partition([c] + list(rest)) + if not isinstance(c, Partition): + if c in ZZ: + c = Partition([c]) else: - c = Partition(list(c)) + c = Partition(c) if c not in self._indices: raise TypeError("do not know how to make %s an element of %s" % (c, self)) diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 374ebfae5e3..cf4ebbd4f82 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -5,8 +5,7 @@ - Travis Scrimshaw (2013-11-10): Initial version """ -from __future__ import absolute_import -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -18,14 +17,15 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import absolute_import + from . import sfa import sage.libs.lrcalc.lrcalc as lrcalc from sage.combinat.partition import Partitions from sage.misc.cachefunc import cached_method -from sage.rings.all import ZZ, QQ, Integer -from sage.matrix.all import matrix + class SymmetricFunctionAlgebra_orthogonal(sfa.SymmetricFunctionAlgebra_generic): r""" diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 56ed1a51351..d193157aa3e 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -1,8 +1,7 @@ """ Schur symmetric functions """ -from __future__ import absolute_import -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki # @@ -15,13 +14,14 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import absolute_import from six.moves import zip from . import classical import sage.libs.lrcalc.lrcalc as lrcalc -from sage.rings.all import ZZ, QQ, Integer + class SymmetricFunctionAlgebra_schur(classical.SymmetricFunctionAlgebra_classical): def __init__(self, Sym): diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 0f87acb9e59..fae63ee793f 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -135,7 +135,7 @@ class SymmetricFunctions(UniqueRepresentation, Parent): sage: p['something'] Traceback (most recent call last): ... - ValueError: ['s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g'] is not an element of Partitions + ValueError: all parts of 'something' should be nonnegative integers sage: p.basis()['something'] p'something' @@ -1047,7 +1047,7 @@ def induced_trivial_character(self): EXAMPLES:: sage: SymmetricFunctions(QQ).induced_trivial_character() - Symmetric Functions over Rational Field in the induced trivial character basis + Symmetric Functions over Rational Field in the induced trivial symmetric group character basis sage: ht = SymmetricFunctions(QQ).ht() sage: h = SymmetricFunctions(QQ).h() sage: h(ht([3,2]).character_to_frobenius_image(9)) @@ -1064,10 +1064,12 @@ def induced_trivial_character(self): sage: [ht([1]).eval_at_permutation_roots(rho) for rho in Partitions(5)] [0, 1, 0, 2, 1, 3, 5] """ - from .character import character_basis - return character_basis(self, self.h(), "induced trivial character", 'ht') + from .character import induced_trivial_character_basis + return induced_trivial_character_basis(self, 'ht') + ht = induced_trivial_character + def forgotten(self): r""" The forgotten basis of the Symmetric Functions (or the basis dual to diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 639917f2376..78853299d0d 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -222,7 +222,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, uniq +from sage.misc.all import prod from copy import copy from functools import reduce @@ -1566,7 +1566,7 @@ def __init__(self, Sym, basis_name=None, prefix=None, graded=True): _print_style = 'lex' # Todo: share this with ncsf and over algebras with basis indexed by word-like elements - def __getitem__(self, c, *rest): + def __getitem__(self, c): r""" This method implements the abuses of notations ``p[2,1]``, ``p[[2,1]]``, ``p[Partition([2,1])]``. @@ -1589,16 +1589,21 @@ def __getitem__(self, c, *rest): s[2, 1] sage: s[Partition([2,1])] s[2, 1] + + TESTS: + + Check that a single number which is in ``ZZ`` can be used:: + + sage: s = SymmetricFunctions(QQ).s() + sage: s[QQbar(2)] + s[2] """ C = self.basis().keys() - if isinstance(c, C.element_class): - if rest: - raise ValueError("invalid number of arguments") - else: - if rest or isinstance(c, (int, Integer)): - c = C([c] + list(rest)) + if not isinstance(c, C.element_class): + if c in ZZ: + c = C([c]) else: - c = C(list(c)) + c = C(c) return self.monomial(c) def _change_by_proportionality(self, x, function): @@ -2365,7 +2370,7 @@ def _inner_plethysm_pk_g(self, k, g, cache): p = self.realization_of().p() res = 0 - degrees = uniq([ sum(m) for m in g.support() ]) + degrees = sorted(set(sum(m) for m in g.support())) for d in degrees: for mu in Partitions_n(d): mu_k = mu.power(k) @@ -2432,7 +2437,7 @@ def _inner_plethysm_pnu_g(self, p_x, cache, nu): if not nu._list: s = self.realization_of().s() degrees = [ part.size() for part in p_x.support() ] - degrees = uniq(degrees) + degrees = sorted(set(degrees)) if 0 in degrees: ext = self([]) else: diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index f1454372ca7..f4133eb6bfd 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -5,8 +5,7 @@ - Travis Scrimshaw (2013-11-10): Initial version """ -from __future__ import absolute_import -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -18,14 +17,15 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import absolute_import + from . import sfa import sage.libs.lrcalc.lrcalc as lrcalc from sage.combinat.partition import Partitions from sage.misc.cachefunc import cached_method -from sage.rings.all import ZZ, QQ, Integer -from sage.matrix.all import matrix + class SymmetricFunctionAlgebra_symplectic(sfa.SymmetricFunctionAlgebra_generic): r""" diff --git a/src/sage/combinat/shifted_primed_tableau.py b/src/sage/combinat/shifted_primed_tableau.py index 1f5471f5247..c273f54f23c 100644 --- a/src/sage/combinat/shifted_primed_tableau.py +++ b/src/sage/combinat/shifted_primed_tableau.py @@ -2199,7 +2199,6 @@ def _add_strip(sub_tab, full_tab, length): if cliff == 0: row += 1 primed_strip.append(0) - pass primed_strip.extend([int(primed_list[i] > j) for j in range(cliff)]) row += cliff diff --git a/src/sage/combinat/sloane_functions.py b/src/sage/combinat/sloane_functions.py index d1049bcb209..2a39a5c8af7 100644 --- a/src/sage/combinat/sloane_functions.py +++ b/src/sage/combinat/sloane_functions.py @@ -381,7 +381,7 @@ def _eval(self, n): sage: sloane.A000001._eval(5000) Traceback (most recent call last): ... - ValueError: libGAP: Error, the library of groups of size 5000 is not available + GAPError: Error, the library of groups of size 5000 is not available """ if n <= 50: return self._small[n-1] @@ -5610,16 +5610,12 @@ def __init__(self): INPUT: - - - ``n`` - positive integer = 2 - + - ``n`` - positive integer >= 2 OUTPUT: - - ``integer`` - function value - EXAMPLES:: sage: a = sloane.A001909;a @@ -5674,16 +5670,12 @@ def __init__(self): INPUT: - - - ``n`` - positive integer = 3 - + - ``n`` - positive integer >= 3 OUTPUT: - - ``integer`` - function value - EXAMPLES:: sage: a = sloane.A001910;a @@ -9486,19 +9478,14 @@ def __init__(self): B_n = \sum{k=0}^{n} S(n, k) . - INPUT: - - - ``n`` - integer = 0 - + - ``n`` - integer >= 0 OUTPUT: - - ``integer`` - `B_n` - EXAMPLES:: sage: a = sloane.A000110; a @@ -9546,18 +9533,13 @@ def __init__(self): C_n = \sum{k=0}^{n} (-1)^k S(n, k) . - INPUT: - - - ``n`` - integer = 0 - + - ``n`` -- integer >= 0 OUTPUT: - - - ``integer`` - `C_n` - + - ``integer`` -- `C_n` EXAMPLES:: diff --git a/src/sage/combinat/species/__init__.py b/src/sage/combinat/species/__init__.py index ab08c7a78fd..fcd4cab28c1 100644 --- a/src/sage/combinat/species/__init__.py +++ b/src/sage/combinat/species/__init__.py @@ -48,5 +48,4 @@ - :ref:`sage.combinat.species.structure` - :ref:`sage.combinat.species.misc` -- :ref:`sage.combinat.species.combinatorial_logarithm` """ diff --git a/src/sage/combinat/species/combinatorial_logarithm.py b/src/sage/combinat/species/combinatorial_logarithm.py deleted file mode 100644 index 89a69f3117d..00000000000 --- a/src/sage/combinat/species/combinatorial_logarithm.py +++ /dev/null @@ -1,65 +0,0 @@ -r""" -Combinatorial Logarithm - -This file provides the cycle index series for the virtual species `\Omega`, -the 'combinatorial logarithm', defined to be the compositional inverse of -the species `E^{+}` of nonempty sets: - -.. MATH:: - - \Omega \circ E^{+} = E^{+} \circ \Omega = X. - -.. warning:: - - This module is now deprecated. Please use - :meth:`sage.combinat.species.generating_series.CycleIndexSeriesRing.exponential` - instead of :func:`CombinatorialLogarithmSeries`. - -AUTHORS: - -- Andrew Gainer-Dewar (2013): initial version - -""" -#***************************************************************************** -# Copyright (C) 2013 Andrew Gainer-Dewar -# -# 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/ -#***************************************************************************** - -from sage.combinat.species.generating_series import LogarithmCycleIndexSeries -from sage.rings.all import QQ -from sage.misc.cachefunc import cached_function -from sage.misc.superseded import deprecation - -@cached_function -def CombinatorialLogarithmSeries(R=QQ): - r""" - Return the cycle index series of the virtual species `\Omega`, the compositional inverse - of the species `E^{+}` of nonempty sets. - - The notion of virtual species is treated thoroughly in [BLL]_. The specific algorithm used - here to compute the cycle index of `\Omega` is found in [Labelle]_. - - EXAMPLES: - - The virtual species `\Omega` is 'properly virtual', in the sense that its cycle index - has negative coefficients:: - - sage: from sage.combinat.species.combinatorial_logarithm import CombinatorialLogarithmSeries - sage: CombinatorialLogarithmSeries().coefficients(4) - doctest:...: DeprecationWarning: CombinatorialLogarithmSeries is deprecated, use CycleIndexSeriesRing(R).logarithm_series() or CycleIndexSeries().logarithm() instead - See http://trac.sagemath.org/14846 for details. - [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] - - Its defining property is that `\Omega \circ E^{+} = E^{+} \circ \Omega = X` (that is, that - composition with `E^{+}` in both directions yields the multiplicative identity `X`):: - - sage: Eplus = sage.combinat.species.set_species.SetSpecies(min=1).cycle_index_series() - sage: CombinatorialLogarithmSeries().compose(Eplus).coefficients(4) - [0, p[1], 0, 0] - """ - deprecation(14846, "CombinatorialLogarithmSeries is deprecated, use CycleIndexSeriesRing(R).logarithm_series() or CycleIndexSeries().logarithm() instead") - return LogarithmCycleIndexSeries(R) diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index b2baa299ccf..2aee6e3cd60 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -1069,8 +1069,8 @@ def compositional_inverse(self): The compositional inverse `\Omega` of the species `E_{+}` of nonempty sets can be handled much more efficiently - using specialized methods. These are implemented in - :class:`~sage.combinat.species.combinatorial_logarithm.CombinatorialLogarithmSeries`. + using specialized methods. See + :func:`~sage.combinat.species.generating_series.LogarithmCycleIndexSeries` AUTHORS: diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index 90b9733e434..5e9fcbca393 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -178,7 +178,6 @@ def automorphism_group(self): [{2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}] """ from sage.groups.all import PermutationGroupElement, PermutationGroup - from sage.misc.misc import uniq from sage.combinat.species.misc import change_support left, right = self._list @@ -197,7 +196,7 @@ def automorphism_group(self): gens = l_aut.gens() + r_aut.gens() gens = [g for g in gens if g != identity] - gens = uniq(gens) if gens else [[]] + gens = sorted(set(gens)) if gens else [[]] return PermutationGroup(gens) diff --git a/src/sage/combinat/species/series.py b/src/sage/combinat/species/series.py index 629cce9c762..03d4205011a 100644 --- a/src/sage/combinat/species/series.py +++ b/src/sage/combinat/species/series.py @@ -14,7 +14,7 @@ In particular, the relevant section for this file can be found at http://www.risc.uni-linz.ac.at/people/hemmecke/AldorCombinat/combinatse9.html. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Mike Hansen , # # Distributed under the terms of the GNU General Public License (GPL) @@ -26,8 +26,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import from .stream import Stream, Stream_class @@ -91,7 +91,7 @@ def __repr__(self): sage: LazyPowerSeriesRing(QQ) Lazy Power Series Ring over Rational Field """ - return "Lazy Power Series Ring over %s"%self.base_ring() + return "Lazy Power Series Ring over %s" % self.base_ring() def __eq__(self, x): """ @@ -239,11 +239,11 @@ def __call__(self, x=None, order=unk): x = BR(x) return self.term(x, 0) - raise TypeError("do not know how to coerce %s into self"%x) + raise TypeError("do not know how to coerce %s into self" % x) def zero(self): """ - Returns the zero power series. + Return the zero power series. EXAMPLES:: @@ -255,7 +255,7 @@ def zero(self): def identity_element(self): """ - Returns the one power series. + Return the one power series. EXAMPLES:: @@ -303,13 +303,13 @@ def term(self, r, n): elif n == 1: res._name = repr(r) + "*" + self._name else: - res._name = "%s*%s^%s"%(repr(r), self._name, n) + res._name = "%s*%s^%s" % (repr(r), self._name, n) return res def _new_initial(self, order, stream): """ - Returns a new power series with specified order. + Return a new power series with specified order. INPUT: @@ -596,7 +596,7 @@ def __repr__(self): else: l = baserepr + " + " + repr_lincomb([(x+"^"+str(i), self._stream[n-1]) for i in range(n, n+3)]) + " + ..." else: - l = baserepr + " + O(x^%s)"%n if n > 0 else "O(1)" + l = baserepr + " + O(x^%s)" % n if n > 0 else "O(1)" else: l = 'Uninitialized lazy power series' return l @@ -739,7 +739,7 @@ def compute_coefficients(self, i): def coefficients(self, n): """ - Returns the first n coefficients of self. + Return the first n coefficients of self. EXAMPLES:: @@ -752,7 +752,7 @@ def coefficients(self, n): def is_zero(self): """ - Returns True if and only if self is zero. + Return True if and only if self is zero. EXAMPLES:: @@ -918,7 +918,7 @@ def define(self, x): def coefficient(self, n): """ - Returns the coefficient of xn in self. + Return the coefficient of xn in self. EXAMPLES:: @@ -938,7 +938,7 @@ def coefficient(self, n): def get_aorder(self): """ - Returns the approximate order of self. + Return the approximate order of self. EXAMPLES:: @@ -952,7 +952,7 @@ def get_aorder(self): def get_order(self): """ - Returns the order of self. + Return the order of self. EXAMPLES:: @@ -966,7 +966,7 @@ def get_order(self): def get_stream(self): """ - Returns self's underlying Stream object. + Return self's underlying Stream object. EXAMPLES:: @@ -1198,8 +1198,7 @@ def __pow__(self, n): def __call__(self, y): """ - Returns the composition of this power series and the power series - y. + Return the composition of this power series and the power series y. EXAMPLES:: @@ -1267,7 +1266,7 @@ def _compose_gen(self, y, ao): def tail(self): """ - Returns the power series whose coefficients obtained by subtracting + Return the power series whose coefficients obtained by subtracting the constant term from this series and then dividing by x. EXAMPLES:: @@ -1283,7 +1282,7 @@ def tail(self): def iterator(self, n=0, initial=None): """ - Returns an iterator for the coefficients of self starting at n. + Return an iterator for the coefficients of self starting at n. EXAMPLES:: @@ -1308,7 +1307,7 @@ def iterator(self, n=0, initial=None): def _power_gen(self): """ - Returns a generator for all the powers self^k starting with k = 1. + Return a generator for all the powers self^k starting with k = 1. EXAMPLES:: @@ -1388,8 +1387,7 @@ def derivative(self): def _diff_gen(self, ao): """ - Returns an iterator for the coefficients of the derivative of - self. + Return an iterator for the coefficients of the derivative of self. EXAMPLES:: @@ -1601,7 +1599,7 @@ def exponential(self): def __getitem__(self, i): """ - Returns the ith coefficient of self. + Return the ith coefficient of self. EXAMPLES:: @@ -1618,10 +1616,11 @@ def __getitem__(self, i): ######################### def restricted(self, min=None, max=None): """ - Returns the power series restricted to the coefficients starting at - min and going up to, but not including max. If min is not - specified, then it is assumed to be zero. If max is not specified, - then it is assumed to be infinity. + Return the power series restricted to the coefficients starting at + ``min`` and going up to, but not including ``max``. + + If ``min`` is not specified, then it is assumed to be zero. If + ``max`` is not specified, then it is assumed to be infinity. EXAMPLES:: @@ -1637,10 +1636,13 @@ def restricted(self, min=None, max=None): [0, 0, 1, 1, 1, 1, 0, 0, 0, 0] """ from six.moves import builtins + if ((min is None and max is None) or (max is None and self.get_aorder() >= min)): return self + if min is None: + min = 0 return self._new(partial(self._restricted_gen, min, max), lambda ao: builtins.max(ao, min), self) diff --git a/src/sage/combinat/subset.py b/src/sage/combinat/subset.py index 8a1818add98..b747886284b 100644 --- a/src/sage/combinat/subset.py +++ b/src/sage/combinat/subset.py @@ -42,6 +42,7 @@ from sage.sets.set import Set, Set_object_enumerated from sage.arith.all import binomial +from sage.misc.misc import _stable_uniq as uniq from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from . import combination @@ -232,19 +233,14 @@ def __init__(self, s): sage: TestSuite(S).run(skip=["_test_elements"]) sage: S = sage.sets.set.Set_object_enumerated([1,2]) - sage: TestSuite(S).run() # todo: not implemented + sage: TestSuite(S).run() """ Parent.__init__(self, category=EnumeratedSets().Finite()) if s not in EnumeratedSets(): - from sage.misc.misc import uniq from sage.sets.finite_enumerated_set import FiniteEnumeratedSet - s = list(s) - us = uniq(s) - if len(us) == len(s): - s = FiniteEnumeratedSet(s) - else: - s = FiniteEnumeratedSet(us) - self._s = s + L = list(uniq(s)) + s = FiniteEnumeratedSet(L) + self._s = s @property def _ls(self): diff --git a/src/sage/combinat/subsets_pairwise.py b/src/sage/combinat/subsets_pairwise.py index 647f82e11dc..7c6adde7eec 100644 --- a/src/sage/combinat/subsets_pairwise.py +++ b/src/sage/combinat/subsets_pairwise.py @@ -31,7 +31,7 @@ class PairwiseCompatibleSubsets(SearchForest): .. warning:: The current name is suboptimal and is subject to change. Suggestions for a good name, and a good user entry - point are welcome. Maybe ``Subsets(..., independant = predicate)``. + point are welcome. Maybe ``Subsets(..., independent = predicate)``. EXAMPLES: diff --git a/src/sage/combinat/superpartition.py b/src/sage/combinat/superpartition.py index c40f52ff363..3c65b5f8373 100644 --- a/src/sage/combinat/superpartition.py +++ b/src/sage/combinat/superpartition.py @@ -89,7 +89,7 @@ from sage.structure.global_options import GlobalOptions from sage.rings.all import ZZ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.misc.all import uniq + @richcmp_method @add_metaclass(InheritComparisonClasscallMetaclass) @@ -701,7 +701,7 @@ def add_horizontal_border_strip_star(self, h): # TODO: Check that this is not suppose to be # a tuple of size 1 + [(i) for i in circ_list if row_changed[i[0]] == 0]] - if len(uniq([k for (j,k) in new_sp[1]])) == len(new_sp[1]): + if len(set([k for (j,k) in new_sp[1]])) == len(new_sp[1]): out += [SuperPartition.from_circled_diagram(*new_sp)] return out diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index cae3a7148df..65553c934af 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -107,7 +107,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 uniq, prod +from sage.misc.all import prod from sage.misc.misc import powerset from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets @@ -1908,7 +1908,7 @@ def leq(self, secondtab): - ``secondtab`` -- a tableau of the same shape as ``self`` - EXAMPLES: + EXAMPLES:: sage: T = Tableau([[1, 2], [3]]) sage: S = Tableau([[1, 3], [3]]) @@ -1998,7 +1998,7 @@ def k_weight(self, k): if new_s == []: res.append(0) continue - x = uniq([ (i-j)%(k+1) for i,j in new_s ]) + x = set((i-j) % (k+1) for i, j in new_s) res.append(len(x)) return res @@ -3441,7 +3441,7 @@ def symmetric_group_action_on_values(self, perm): there are no more opening parentheses standing left of closing parentheses. Then, let `a` be the number of opening parentheses in the word, and `b` the number of closing - parentheses (notice that all opening parentheses are left of + parentheses (notice that all opening parentheses are right of all closing parentheses). Replace the first `a` parentheses by the letters `i`, and replace the remaining `b` parentheses by the letters `i+1`. Let `w'` be the resulting word. Let @@ -3449,11 +3449,11 @@ def symmetric_group_action_on_values(self, perm): word `w'`. This tableau `T'` can be shown to be semistandard. We define the image of `T` under the action of the simple transposition `s_i = (i, i+1) \in S_n` to be this tableau `T'`. - It can be shown that these actions `s_1, s_2, \ldots, s_{n-1}` - satisfy the Moore-Coxeter relations of `S_n`, and thus this - extends to a unique action of the symmetric group `S_n` on - the set of semistandard tableaux with ceiling `n`. This is the - Lascoux-Schuetzenberger action. + It can be shown that these actions of the transpositions + `s_1, s_2, \ldots, s_{n-1}` satisfy the Moore-Coxeter relations + of `S_n`, and thus this extends to a unique action of the + symmetric group `S_n` on the set of semistandard tableaux with + ceiling `n`. This is the Lascoux-Schuetzenberger action. This action of the symmetric group `S_n` on the set of all semistandard tableaux of given shape `\lambda` with entries @@ -8131,6 +8131,19 @@ def random_element(self): ########################## def unmatched_places(w, open, close): """ + Given a word ``w`` and two letters ``open`` and + ``close`` to be treated as opening and closing + parentheses (respectively), return a pair ``(xs, ys)`` + that encodes the positions of the unmatched + parentheses after the standard parenthesis matching + procedure is applied to ``w``. + + More precisely, ``xs`` will be the list of all ``i`` + such that ``w[i]`` is an unmatched closing parenthesis, + while ``ys`` will be the list of all ``i`` such that + ``w[i]`` is an unmatched opening parenthesis. Both + lists returned are in increasing order. + EXAMPLES:: sage: from sage.combinat.tableau import unmatched_places @@ -8164,6 +8177,17 @@ def unmatched_places(w, open, close): def symmetric_group_action_on_values(word, perm): """ + Return the image of the word ``word`` under the + Lascoux-Schuetzenberger action of the permutation + ``perm``. + + See :meth:`Tableau.symmetric_group_action_on_values` + for the definition of the Lascoux-Schuetzenberger + action on semistandard tableaux. The transformation that + the reading word of the tableau undergoes in said + definition is precisely the Lascoux-Schuetzenberger + action on words. + EXAMPLES:: sage: from sage.combinat.tableau import symmetric_group_action_on_values @@ -8201,7 +8225,7 @@ def symmetric_group_action_on_values(word, perm): for i in places_l[:dif]: w[i] = r else: - for i in places_r[nbr-dif:ma]: + for i in places_r[nbr-dif:]: w[i] = l return w diff --git a/src/sage/combinat/tiling.py b/src/sage/combinat/tiling.py index 2f8713a78b3..a99bcdfc45d 100644 --- a/src/sage/combinat/tiling.py +++ b/src/sage/combinat/tiling.py @@ -947,7 +947,7 @@ def translated_copies(self, box): Polyomino: [(3, 4, 0), (4, 4, 0), (4, 5, 0), (4, 5, 1), (4, 6, 0)], Color: deeppink Polyomino: [(3, 5, 0), (4, 5, 0), (4, 6, 0), (4, 6, 1), (4, 7, 0)], Color: deeppink - This method is independant of the translation of the polyomino:: + This method is independent of the translation of the polyomino:: sage: q = Polyomino([(0,0,0), (1,0,0)]) sage: list(q.translated_copies((2,2,1))) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 8e96f71a07f..645c3a4b8ae 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -1107,7 +1107,8 @@ def good_suffix_table(self): Return a table of the maximum skip you can do in order not to miss a possible occurrence of ``self`` in a word. - This is a part of the Boyer-Moore algorithm to find factors. See [1]. + This is a part of the Boyer-Moore algorithm to find factors. + See [BM1977]_. EXAMPLES:: @@ -1115,11 +1116,6 @@ def good_suffix_table(self): [5, 5, 5, 5, 3, 3, 1] sage: Word('12412').good_suffix_table() [3, 3, 3, 3, 3, 1] - - REFERENCES: - - - [1] R.S. Boyer, J.S. Moore, A fast string searching algorithm, - Communications of the ACM 20 (1977) 762--772. """ l = self.length() p = self.reversal().prefix_function_table() @@ -1451,7 +1447,7 @@ def topological_entropy(self, n): increases: `H_{top}(u)=\lim_{n\to\infty}\frac{\log_d(p_u(n))}{n}` where `d` denotes the cardinality of the alphabet and `p_u(n)` is the complexity function, i.e. the number of factors of length `n` - in the sequence `u` [1]. + in the sequence `u` [Fog2002]_. INPUT: @@ -1501,13 +1497,6 @@ def topological_entropy(self, n): sage: w = W(range(20)) sage: w.topological_entropy(3) 1/3*log(18)/log(20) - - REFERENCES: - - [1] N. Pytheas Fogg, Substitutions in Dynamics, Arithmetics, - and Combinatorics, Lecture Notes in Mathematics 1794, Springer - Verlag. V. Berthe, S. Ferenczi, C. Mauduit and A. Siegel, Eds. - (2002). """ d = self.parent().alphabet().cardinality() if d is Infinity: @@ -1630,10 +1619,11 @@ def reduced_rauzy_graph(self, n): .. NOTE:: In the case of infinite recurrent non-periodic words, this - definition corresponds to the following one that can be found in - [1] and [2] where a simple path is a path that begins with a - special factor, ends with a special factor and contains no - other vertices that are special: + definition corresponds to the following one that can be + found in [BDLGZ2009]_ and [BPS2008]_ where a simple path is a + path that begins with a special factor, ends with a + special factor and contains no other vertices that are + special: The reduced Rauzy graph of factors of length `n` is obtained from `G_n` by replacing each simple path `P=v_1 v_2 ... @@ -1694,15 +1684,6 @@ def reduced_rauzy_graph(self, n): Julien Leroy (March 2010): initial version - REFERENCES: - - - [1] M. Bucci et al. A. De Luca, A. Glen, L. Q. Zamboni, A - connection between palindromic and factor complexity using - return words," Advances in Applied Mathematics 42 (2009) 60-74. - - - [2] L'ubomira Balkova, Edita Pelantova, and Wolfgang Steiner. - Sequences with constant number of return words. Monatsh. Math, - 155 (2008) 251-263. """ from sage.graphs.digraph import DiGraph from copy import copy @@ -2428,8 +2409,8 @@ def is_palindrome(self, f=None): Let `f : \Sigma \rightarrow \Sigma` be an involution that extends to a morphism on `\Sigma^*`. We say that `w\in\Sigma^*` is a - *`f`-palindrome* if `w=f(\tilde{w})` [1]. Also called - *`f`-pseudo-palindrome* [2]. + *`f`-palindrome* if `w=f(\tilde{w})` [Lab2008]_. Also called + *`f`-pseudo-palindrome* [AZZ2005]_. INPUT: @@ -2522,16 +2503,6 @@ def is_palindrome(self, f=None): False sage: Y('abab').is_palindrome(E) True - - REFERENCES: - - - [1] S. Labbé, Propriétés combinatoires des `f`-palindromes, - Mémoire de maîtrise en Mathématiques, Montréal, UQAM, 2008, - 109 pages. - - [2] V. Anne, L.Q. Zamboni, I. Zorca, Palindromes and Pseudo- - Palindromes in Episturmian and Pseudo-Palindromic Infinite Words, - in : S. Brlek, C. Reutenauer (Eds.), Words 2005, Publications du - LaCIM, Vol. 36 (2005) 91--100. """ l = self.length() if f is None: @@ -2651,13 +2622,13 @@ def lps(self, f=None, l=None): def palindromic_lacunas_study(self, f=None): r""" Return interesting statistics about longest (``f``-)palindromic suffixes - and lacunas of ``self`` (see [1] and [2]). + and lacunas of ``self`` (see [BMBL2008]_ and [BMBFLR2008]_). Note that a word `w` has at most `|w| + 1` different palindromic factors - (see [3]). For `f`-palindromes (or pseudopalidromes or theta-palindromes), + (see [DJP2001]_). For `f`-palindromes (or pseudopalidromes or theta-palindromes), the maximum number of `f`-palindromic factors is `|w|+1-g_f(w)`, where `g_f(w)` is the number of pairs `\{a, f(a)\}` such that `a` is a letter, - `a` is not equal to `f(a)`, and `a` or `f(a)` occurs in `w`, see [4]. + `a` is not equal to `f(a)`, and `a` or `f(a)` occurs in `w`, see [Star2011]_. INPUT: @@ -2696,21 +2667,6 @@ def palindromic_lacunas_study(self, f=None): set([word: , word: ba, word: baba, word: ab, word: bbabaa, word: abbabaab]) sage: c == set([Word(), Word('ba'), Word('baba'), Word('ab'), Word('bbabaa'), Word('abbabaab')]) True - - REFERENCES: - - - [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic lacunas - of the Thue-Morse word, Proc. GASCOM 2008 (June 16-20 2008, - Bibbiena, Arezzo-Italia), 53--67. - - [2] A. Blondin-Massé, S. Brlek, A. Frosini, S. Labbé, S. Rinaldi, - Reconstructing words from a fixed palindromic length sequence, - Proc. TCS 2008, 5th IFIP International Conference on Theoretical - Computer Science (September 8-10 2008, Milano, Italia), accepted. - - [3] X. Droubay, J. Justin, G. Pirillo, Episturmian words and - some constructions of de Luca and Rauzy, Theoret. Comput. Sci. - 255 (2001) 539--553. - - [4] Š. Starosta, On Theta-palindromic Richness, Theoret. Comp. - Sci. 412 (2011) 1111--1121 """ #Initialize the results of computations palindromes = set() @@ -2741,7 +2697,7 @@ def lengths_lps(self, f=None): Return the list of the length of the longest palindromic suffix (lps) for each non-empty prefix of ``self``. - It corresponds to the function `G_w` defined in [1]. + It corresponds to the function `G_w` defined in [BMBFLR2008]_. INPUT: @@ -2775,14 +2731,6 @@ def lengths_lps(self, f=None): sage: f = WordMorphism({5:[8],8:[5]}) sage: Word([5,8,5,5,8,8,5,5,8,8,5,8,5]).lengths_lps(f) [0, 2, 2, 0, 2, 4, 6, 4, 6, 8, 10, 12, 4] - - REFERENCES: - - - [1] A. Blondin-Massé, S. Brlek, A. Frosini, S. Labbé, - S. Rinaldi, Reconstructing words from a fixed palindromic length - sequence, Proc. TCS 2008, 5th IFIP International Conference on - Theoretical Computer Science (September 8-10 2008, Milano, - Italia), accepted. """ return self.palindromic_lacunas_study(f=f)[0] @@ -2791,7 +2739,7 @@ def lacunas(self, f=None): Return the list of all the lacunas of ``self``. A *lacuna* is a position in a word where the longest (`f`-)palindromic - suffix is not unioccurrent (see [1]). + suffix is not unioccurrent (see [BMBL2008]_). INPUT: @@ -2814,12 +2762,6 @@ def lacunas(self, f=None): sage: f = WordMorphism({0:[1],1:[0]}) sage: words.ThueMorseWord()[:50].lacunas(f) [0, 2, 4, 12, 16, 17, 18, 19, 48, 49] - - REFERENCES: - - - [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic lacunas - of the Thue-Morse word, Proc. GASCOM 2008 (June 16-20 2008, - Bibbiena, Arezzo-Italia), 53--67. """ return self.palindromic_lacunas_study(f=f)[1] @@ -2829,7 +2771,7 @@ def lengths_unioccurrent_lps(self, f=None): (``f``)-palindromic suffixes (lps) for each non-empty prefix of ``self.`` No unioccurrent lps are indicated by ``None``. - It corresponds to the function `H_w` defined in [1] and [2]. + It corresponds to the function `H_w` defined in [BMBL2008]_ and [BMBFLR2008]_. INPUT: @@ -2858,16 +2800,6 @@ def lengths_unioccurrent_lps(self, f=None): sage: f = WordMorphism({1:[0],0:[1]}) sage: t[:15].lengths_unioccurrent_lps(f) [None, 2, None, 2, None, 4, 6, 8, 4, 6, 4, 6, None, 4, 6] - - REFERENCES: - - - [1] A. Blondin-Massé, S. Brlek, S. Labbé, Palindromic lacunas of - the Thue-Morse word, Proc. GASCOM 2008 (June 16-20 2008, Bibbiena, - Arezzo-Italia), 53--67. - - [2] A. Blondin-Massé, S. Brlek, A. Frosini, S. Labbé, S. Rinaldi, - Reconstructing words from a fixed palindromic length sequence, - Proc. TCS 2008, 5th IFIP International Conference on Theoretical - Computer Science (September 8-10 2008, Milano, Italia), accepted. """ l = self.lengths_lps(f=f) for i in self.lacunas(f=f): @@ -3168,7 +3100,7 @@ def defect(self, f=None): the maximum number of possible palindromic factors in a word of length `|w|` and the actual number of palindromic factors contained in `w`. It is well known that the maximum number of palindromic factors in `w` - is `|w|+1` (see [DJP01]_). + is `|w|+1` (see [DJP2001]_). An optional involution on letters ``f`` can be given. In that case, the *f-palindromic defect* (or *pseudopalindromic defect*, or @@ -3179,7 +3111,7 @@ def defect(self, f=None): the number of pairs `\{a, f(a)\}` such that `a` is a letter, `a` is not equal to `f(a)`, and `a` or `f(a)` occurs in `w`. In the case of usual palindromes (i.e., for ``f`` not given or equal to the identity), - `g_f(w) = 0` for all `w`. See [BHNR04]_ for usual palindromes and [Sta11]_ + `g_f(w) = 0` for all `w`. See [BHNR2004]_ for usual palindromes and [Star2011]_ for f-palindromes. INPUT: @@ -3201,7 +3133,7 @@ def defect(self, f=None): sage: Word('abcacba').defect() 1 - It is known that Sturmian words (see [DJP01]_) have zero defect:: + It is known that Sturmian words (see [DJP2001]_) have zero defect:: sage: words.FibonacciWord()[:100].defect() 0 @@ -3216,7 +3148,7 @@ def defect(self, f=None): It is even conjectured that the defect of an aperiodic word which is a fixed point of a primitive morphism is either `0` or infinite - (see [BBGL08]_):: + (see [BBGL2008]_):: sage: w = words.ThueMorseWord() sage: w[:50].defect() @@ -3260,25 +3192,6 @@ def defect(self, f=None): 0 sage: Word('abbabaabbaababba').defect() 2 - - REFERENCES: - - .. [BBGL08] \A. Blondin Massé, S. Brlek, A. Garon, and S. Labbé, - Combinatorial properties of f -palindromes in the Thue-Morse - sequence. Pure Math. Appl., 19(2-3):39--52, 2008. - - .. [BHNR04] \S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the - Palindromic Complexity of Infinite Words, in J. Berstel, J. - Karhumaki, D. Perrin, Eds, Combinatorics on Words with Applications, - International Journal of Foundation of Computer Science, Vol. 15, - No. 2 (2004) 293--306. - - .. [DJP01] \X. Droubay, J. Justin, G. Pirillo, Episturmian words and some - constructions of de Luca and Rauzy, Theoret. Comput. Sci. 255, - (2001), no. 1--2, 539--553. - - .. [Sta11] \Š. Starosta, On Theta-palindromic Richness, Theoret. Comp. - Sci. 412 (2011) 1111--1121 """ g_w = 0 if f is not None: @@ -3302,8 +3215,9 @@ def is_full(self, f=None): r""" Return ``True`` if ``self`` has defect `0`, and ``False`` otherwise. - A word is *full* (or *rich*) if its defect is zero (see [1]). - If ``f`` is given, then the ``f``-palindromic defect is used (see [2]). + A word is *full* (or *rich*) if its defect is zero (see [BHNR2004]_). + + If ``f`` is given, then the ``f``-palindromic defect is used (see [PeSt2011]_). INPUT: @@ -3357,20 +3271,6 @@ def is_full(self, f=None): True sage: p(words.FibonacciWord()[:150]).is_full(f) True - - REFERENCES: - - - [1] S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the Palindromic - Complexity of Infinite Words, in J. Berstel, J. Karhumaki, - D. Perrin, Eds, Combinatorics on Words with Applications, - International Journal of Foundation of Computer Science, Vol. 15, - No. 2 (2004) 293--306. - - - [2] E. Pelantová, Š. Starosta, Infinite words rich and almost rich - in generalized palindromes, in: G. Mauri, A. Leporati (Eds.), - Developments in Language Theory, volume 6795 of Lecture Notes - in Computer Science, Springer-Verlag, Berlin, Heidelberg, 2011, - pp. 406--416 """ return self.defect(f=f) == 0 @@ -3381,7 +3281,7 @@ def palindromic_closure(self, side='right', f=None): Return the shortest palindrome having ``self`` as a prefix (or as a suffix if ``side`` is ``'left'``). - See [1]. + See [DeLuca2006]_. INPUT: @@ -3428,11 +3328,6 @@ def palindromic_closure(self, side='right', f=None): Traceback (most recent call last): ... ValueError: b not in alphabet! - - REFERENCES: - - - [1] A. de Luca, A. De Luca, Pseudopalindrome closure operators - in free monoids, Theoret. Comput. Sci. 362 (2006) 282--300. """ if f is None: if side == 'right': @@ -3464,7 +3359,8 @@ def is_symmetric(self, f=None): ``False`` otherwise. A word is *symmetric* (resp. `f`-*symmetric*) if it is the - product of two palindromes (resp. `f`-palindromes). See [1] and [2]. + product of two palindromes (resp. `f`-palindromes). + See [BHNR2004]_ and [DeLuca2006]_. INPUT: @@ -3484,19 +3380,8 @@ def is_symmetric(self, f=None): sage: f = WordMorphism('a->b,b->a') sage: Word('aabbbaababba').is_symmetric(f) True - - REFERENCES: - - - [1] S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the Palindromic - Complexity of Infinite Words, in J. Berstel, J. Karhumaki, - D. Perrin, Eds, Combinatorics on Words with Applications, - International Journal of Foundation of Computer Science, Vol. 15, - No. 2 (2004) 293--306. - - [2] A. de Luca, A. De Luca, Pseudopalindrome closure operators - in free monoids, Theoret. Comput. Sci. 362 (2006) 282--300. """ - - square = self*self + square = self * self return square.lps_lengths(f)[-1] >= self.length() def length_border(self): @@ -3548,7 +3433,7 @@ def minimal_period(self): Let `A` be an alphabet. An integer `p\geq 1` is a *period* of a word `w=a_1a_2\cdots a_n` where `a_i\in A` if `a_i=a_{i+p}` for `i=1,\ldots,n-p`. The smallest period of `w` is called *the* - period of `w`. See Chapter 1 of [1]. + period of `w`. See Chapter 1 of [Lot2002]_. EXAMPLES:: @@ -3568,12 +3453,6 @@ def minimal_period(self): 1 sage: Word().minimal_period() 1 - - REFERENCES: - - - [1] M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of - Encyclopedia of Mathematics and its Applications, Cambridge - University Press, U.K., 2002. """ if self.is_empty(): return 1 @@ -3584,7 +3463,7 @@ def order(self): Return the order of ``self``. Let `p(w)` be the period of a word `w`. The positive rational number - `|w|/p(w)` is the *order* of `w`. See Chapter 8 of [1]. + `|w|/p(w)` is the *order* of `w`. See Chapter 8 of [Lot2002]_. OUTPUT: @@ -3602,12 +3481,6 @@ def order(self): 2 sage: Word().order() 0 - - REFERENCES: - - - [1] M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of - Encyclopedia of Mathematics and its Applications, Cambridge - University Press, U.K., 2002. """ from sage.rings.rational import Rational return Rational((self.length(),self.minimal_period())) @@ -3617,7 +3490,7 @@ def critical_exponent(self): Return the critical exponent of ``self``. The *critical exponent* of a word is the supremum of the order of - all its (finite) factors. See [1]. + all its (finite) factors. See [Dej1972]_. .. NOTE:: @@ -3652,11 +3525,6 @@ def critical_exponent(self): Traceback (most recent call last): ... ValueError: no critical exponent for empty word - - REFERENCES: - - .. [Dejean] \F. Dejean. Sur un théorème de Thue. J. Combinatorial Theory - Ser. A 13:90--99, 1972. """ if not self: raise ValueError("no critical exponent for empty word") @@ -3935,7 +3803,7 @@ def is_subword_of(self, other): Return ``True`` if ``self`` is a subword of ``other``, and ``False`` otherwise. A finite word `u` is a *subword* of a finite word `v` if `u` is a - subsequence of `v`. See Chapter 6 on Subwords in [1]. + subsequence of `v`. See Chapter 6 on Subwords in [Lot1997]_. Some references define subword as a consecutive subsequence. Use :meth:`is_factor` if this is what you need. @@ -3965,12 +3833,6 @@ def is_subword_of(self, other): :meth:`longest_common_subword` :meth:`nb_subword_occurrences_in` :meth:`is_factor` - - REFERENCES: - - - [1] M. Lothaire, Combinatorics on Words, Cambridge University - Press, (1997). - """ its = iter(self) try: @@ -3998,7 +3860,7 @@ def is_lyndon(self): lexicographically smaller than each of its proper conjugates for the given order on its alphabet. - See for instance [1]. + See for instance [Lot1983]_. EXAMPLES:: @@ -4028,13 +3890,6 @@ def is_lyndon(self): sage: phi = WordMorphism({'a':2,'b':3,'c':1}) sage: set(map(phi, lw)) == set(LyndonWords(3,8)) True - - REFERENCES: - - - [1] M. Lothaire, Combinatorics On Words, vol. 17 of Encyclopedia - of Mathematics and its Applications, Addison-Wesley, Reading, - Massachusetts, 1983. - """ if self.is_empty(): return False @@ -4065,7 +3920,7 @@ def lyndon_factorization(self): The *Lyndon factorization* of a finite word `w` is the unique factorization of `w` as a non-increasing product of Lyndon words, i.e., `w = l_1\cdots l_n` where each `l_i` is a Lyndon word and - `l_1\geq \cdots \geq l_n`. See for instance [1]. + `l_1\geq \cdots \geq l_n`. See for instance [Duv1983]_. OUTPUT: @@ -4102,14 +3957,7 @@ def lyndon_factorization(self): sage: w == prod(w.lyndon_factorization()) True - REFERENCES: - - - [1] J.-P. Duval, Factorizing words over an ordered alphabet, - J. Algorithms 4 (1983) 363--381. - - - [2] G. Melancon, Factorizing infinite words using Maple, - MapleTech journal, vol. 4, no. 1, 1997, pp. 34-42. - + See [Me1997]_. """ key = self.parent().sortkey_letters # We compute the indexes of the factorization. @@ -4637,7 +4485,7 @@ def nb_subword_occurrences_in(self, other): This corresponds to the notion of `binomial coefficient` of two finite words whose properties are presented in the chapter of - Lothaire's book written by Sakarovitch and Simon [1]. + Lothaire's book written by Sakarovitch and Simon [Lot1997]_. INPUT: @@ -4657,7 +4505,7 @@ def nb_subword_occurrences_in(self, other): .. NOTE:: - This code, based on [2], actually compute the number of + This code, based on [MSSY2001]_, actually compute the number of occurrences of all prefixes of ``self`` as subwords in all prefixes of ``other``. In particular, its complexity is bounded by ``len(self) * len(other)``. @@ -4683,18 +4531,10 @@ def nb_subword_occurrences_in(self, other): sage: v,u = Word([]), words.ThueMorseWord()[:1000] sage: v.nb_subword_occurrences_in(u) 1 - - REFERENCES: - - - [1] M. Lothaire, Combinatorics on Words, Cambridge University - Press, (1997). - - [2] Mateescu, A., Salomaa, A., Salomaa, K. and Yu, S., A - sharpening of the Parikh mapping. Theoret. Informatics Appl. 35 - (2001) 551-564. """ # record the position of letters in self pos = defaultdict(list) - for i,a in enumerate(self): + for i, a in enumerate(self): pos[a].append(i) for a in pos: pos[a].reverse() @@ -4733,7 +4573,8 @@ def return_words(self, fact): Return the set of return words of ``fact`` in ``self``. This is the set of all factors starting by the given factor and ending - just before the next occurrence of this factor. See [1] and [2]. + just before the next occurrence of this factor. + See [Dur1998]_ and [HZ1999]_. INPUT: @@ -4757,13 +4598,6 @@ def return_words(self, fact): sage: TM = words.ThueMorseWord()[:1000] sage: sorted(TM.return_words(Word([0]))) [word: 0, word: 01, word: 011] - - REFERENCES: - - - [1] F. Durand, A characterization of substitutive sequences using - return words, Discrete Math. 179 (1998) 89-101. - - [2] C. Holton, L.Q. Zamboni, Descendants of primitive substitutions, - Theory Comput. Syst. 32 (1999) 133-157. """ return set(self.return_words_iterator(fact)) @@ -4772,7 +4606,8 @@ def complete_return_words(self, fact): Return the set of complete return words of ``fact`` in ``self``. This is the set of all factors starting by the given factor and ending - just after the next occurrence of this factor. See for instance [1]. + just after the next occurrence of this factor. + See for instance [JV2000]_. INPUT: @@ -4791,11 +4626,6 @@ def complete_return_words(self, fact): set() sage: Word('121212').complete_return_words(Word('1212')) {word: 121212} - - REFERENCES: - - - [1] J. Justin, L. Vuillon, Return words in Sturmian and - episturmian words, Theor. Inform. Appl. 34 (2000) 343--356. """ return set(self.complete_return_words_iterator(fact)) @@ -4803,17 +4633,12 @@ def return_words_derivate(self, fact): r""" Return the word generated by mapping a letter to each occurrence of the return words for the given factor dropping any dangling prefix and - suffix. See for instance [1]. + suffix. See for instance [Dur1998]_. EXAMPLES:: sage: Word('12131221312313122').return_words_derivate(Word('1')) word: 123242 - - REFERENCES: - - - [1] F. Durand, A characterization of substitutive sequences using - return words, Discrete Math. 179 (1998) 89--101. """ tab = {} ret = [tab.setdefault(w, len(tab)) + 1 for w in self._return_words_list(fact)] @@ -4827,7 +4652,7 @@ def is_quasiperiodic(self): A finite or infinite word `w` is *quasiperiodic* if it can be constructed by concatenations and superpositions of one of its proper factors `u`, which is called a *quasiperiod* of `w`. - See for instance [1], [2], and [3]. + See for instance [AE1993]_, [Mar2004]_, and [GLR2008]_. EXAMPLES:: @@ -4841,16 +4666,6 @@ def is_quasiperiodic(self): False sage: Word('abaaba').is_quasiperiodic() True - - REFERENCES: - - - [1] A. Apostolico, A. Ehrenfeucht, Efficient detection of - quasiperiodicities in strings, Theoret. Comput. Sci. 119 (1993) - 247--265. - - [2] S. Marcus, Quasiperiodic infinite words, Bull. Eur. Assoc. - Theor. Comput. Sci. 82 (2004) 170-174. - - [3] A. Glen, F. Levé, G. Richomme, Quasiperiodic and Lyndon - episturmian words, Preprint, 2008, :arxiv:`0805.0730`. """ l = self.length() if l <= 1: @@ -4870,7 +4685,8 @@ def quasiperiods(self): Let `w` be a finite or infinite word. A *quasiperiod* of `w` is a proper factor `u` of `w` such that the occurrences of `u` in `w` entirely cover `w`, i.e., every position of `w` falls within some - occurrence of `u` in `w`. See for instance [1], [2], and [3]. + occurrence of `u` in `w`. See for instance [AE1993]_, [Mar2004]_, + and [GLR2008]_. EXAMPLES:: @@ -4880,16 +4696,6 @@ def quasiperiods(self): [word: aba] sage: Word('abacaba').quasiperiods() [] - - REFERENCES: - - - [1] A. Apostolico, A. Ehrenfeucht, Efficient detection of - quasiperiodicities in strings, Theoret. Comput. Sci. 119 (1993) - 247--265. - - [2] S. Marcus, Quasiperiodic infinite words, Bull. Eur. Assoc. - Theor. Comput. Sci. 82 (2004) 170-174. - - [3] A. Glen, F. Levé, G. Richomme, Quasiperiodic and Lyndon - episturmian words, Preprint, 2008, :arxiv:`0805.0730`. """ l = self.length() if l <= 1: @@ -4912,7 +4718,7 @@ def crochemore_factorization(self): of `w` with each `x_i` satisfying either: C1. `x_i` is a letter that does not appear in `u = x_1\ldots x_{i-1}`; C2. `x_i` is the longest prefix of `v = x_i\ldots x_n` that also has an occurrence beginning - within `u = x_1\ldots x_{i-1}`. See [1]. + within `u = x_1\ldots x_{i-1}`. See [Cro1983]_. EXAMPLES:: @@ -4931,11 +4737,6 @@ def crochemore_factorization(self): (0, 1, 0101, 1) sage: mul(x.crochemore_factorization()) == x True - - REFERENCES: - - - [1] M. Crochemore, Recherche linéaire d'un carré dans un mot, - C. R. Acad. Sci. Paris Sér. I Math. 296 (1983) 14 781--784. """ T = self.implicit_suffix_tree() cuts = T.LZ_decomposition() @@ -5020,7 +4821,7 @@ def overlap_partition(self, other, delay=0, p=None, involution=None) : where `u = u_0 u_1 \cdots u_{n-1}`, `v = v_0v_1\cdots v_{m-1}` are two words on the alphabet `A` and `d` is an integer. - The equivalence relation defined by `R` is inspired from [1]. + The equivalence relation defined by `R` is inspired from [Lab2008]_. INPUT: @@ -5166,12 +4967,6 @@ def overlap_partition(self, other, delay=0, p=None, involution=None) : sage: inv = lambda x:-x sage: w.overlap_partition(w, 2, involution=inv) {{-4, -2, 0, 2, 4}, {-5, -3, -1, 1, 3, 5}} - - REFERENCES: - - - [1] S. Labbé, Propriétés combinatoires des `f`-palindromes, - Mémoire de maîtrise en Mathématiques, Montréal, UQAM, 2008, - 109 pages. """ if not isinstance(delay, (int, Integer)): raise TypeError("delay (=%s) must be an integer"%delay) @@ -5424,18 +5219,7 @@ def charge(self, check=True): tableau in Sage, and seems to be the more common convention in the literature. - REFERENCES: - - [1] Ian Macdonald, *Symmetric Functions and Hall Polynomials* second - edition, 1995, Oxford University Press - - [2] A. Lascoux, L. Lapointe, and J. Morse. *Tableau atoms and a new - Macdonald positivity conjecture.* Duke Math Journal, **116 (1)**, - 2003. :arxiv:`math/0008073` - - [3] A. Lascoux, B. Leclerc, and J.Y. Thibon. *The Plactic Monoid*. - Survey article available at - [http://www-igm.univ-mlv.fr/~jyt/ARTICLES/plactic.ps] + See [Mac1995]_, [LLM2003]_, and [LLT]_. TESTS:: @@ -5492,7 +5276,7 @@ def BWT(self): The *Burrows-Wheeler transform* of a finite word `w` is obtained from `w` by first listing the conjugates of `w` in lexicographic order and then concatenating the final letters of the conjugates in this - order. See [1]. + order. See [BW1994]_. EXAMPLES:: @@ -5508,12 +5292,6 @@ def BWT(self): word: sage: Word('a').BWT() word: a - - REFERENCES: - - - [1] M. Burrows, D.J. Wheeler, "A block-sorting lossless data - compression algorithm", HP Lab Technical Report, 1994, available - at http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-124.html """ if self.is_empty(): return self @@ -5553,10 +5331,7 @@ def iterated_left_palindromic_closure(self, f=None): ... TypeError: self (=a->b, b->b) is not an endomorphism - REFERENCES: - - - A. de Luca, A. De Luca, Pseudopalindrome closure operators - in free monoids, Theoret. Comput. Sci. 362 (2006) 282--300. + See [DeLuca2006]_. """ if f is None: return self.reversal().iterated_right_palindromic_closure(f=f) @@ -5581,13 +5356,13 @@ def balance(self): Return the balance of ``self``. The balance of a word is the smallest number `q` such that ``self`` is - `q`-balanced [1]. + `q`-balanced [FV2002]_. A finite or infinite word `w` is said to be `q`-*balanced* if for any two factors `u`, `v` of `w` of the same length, the difference between the number of `x`'s in each of `u` and `v` is at most `q` for all letters `x` in the alphabet of `w`. A `1`-balanced word is - simply said to be balanced. See Chapter 2 of [2]. + simply said to be balanced. See Chapter 2 of [Lot2002]_. OUTPUT: @@ -5628,14 +5403,6 @@ def balance(self): 1 sage: Word('1112').balance() 1 - - REFERENCES: - - - [1] I. Fagnot, L. Vuillon, Generalized balances in Sturmian words, - Discrete Applied Mathematics 121 (2002), 83--101. - - [2] M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of - Encyclopedia of Mathematics and its Applications, Cambridge - University Press, U.K., 2002. """ alphabet = self.letters() best = 0 @@ -5665,8 +5432,8 @@ def is_balanced(self, q=1): any two factors `u`, `v` of `w` of the same length, the difference between the number of `x`'s in each of `u` and `v` is at most `q` for all letters `x` in the alphabet of `w`. A `1`-balanced word is - simply said to be balanced. See for instance [1] and Chapter 2 of - [2]. + simply said to be balanced. See for instance [CFZ2000]_ and Chapter + 2 of [Lot2002]_. INPUT: @@ -5707,15 +5474,6 @@ def is_balanced(self, q=1): Traceback (most recent call last): ... TypeError: the balance level must be a positive integer - - REFERENCES: - - - [1] J. Cassaigne, S. Ferenczi, L.Q. Zamboni, Imbalances in - Arnoux-Rauzy sequences, Ann. Inst. Fourier (Grenoble) 50 (2000) - 1265--1276. - - [2] M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of - Encyclopedia of Mathematics and its Applications, Cambridge - University Press, U.K., 2002. """ if not isinstance(q, (int, Integer)) or q <= 0: raise TypeError("the balance level must be a positive integer") @@ -6046,15 +5804,7 @@ def is_sturmian_factor(self): sage: words.KolakoskiWord()[:1000].is_sturmian_factor() False - REFERENCES: - - .. [Arn2002] \P. Arnoux, Sturmian sequences, in Substitutions in Dynamics, - N. Pytheas Fogg (Ed.), Arithmetics, and Combinatorics (Lecture - Notes in Mathematics, Vol. 1794), 2002. - .. [Ser1985] \C. Series. The geometry of Markoff numbers. The Mathematical - Intelligencer, 7(3):20--29, 1985. - .. [SU2009] \J. Smillie and C. Ulcigrai. Symbolic coding for linear - trajectories in the regular octagon, :arxiv:`0905.0871`, 2009. + See [Arn2002]_, [Ser1985]_, and [SU2009]_. AUTHOR: @@ -6111,10 +5861,7 @@ def is_tangent(self): sage: words.KolakoskiWord()[:1000].is_tangent() False - REFERENCES: - - .. [Mon2010] \T. Monteil, The asymptotic language of smooth curves, talk - at LaCIM2010. + See [Mon2010]_. AUTHOR: @@ -6604,13 +6351,7 @@ def phi(self): word: a22222 sage: w = Word([2,3,1,1,2,1,2,3,1,2,2,3,1,2]) - REFERENCES: - - - S. Brlek, A. Ladouceur, A note on differentiable palindromes, - Theoret. Comput. Sci. 302 (2003) 167--178. - - S. Brlek, S. Dulucq, A. Ladouceur, L. Vuillon, Combinatorial - properties of smooth infinite words, Theoret. Comput. Sci. 352 - (2006) 306--317. + See [BL2003]_ and [BDLV2006]_. """ if self.is_empty(): return self @@ -6676,7 +6417,7 @@ def is_smooth_prefix(self): `A_k^\omega` is said to be *smooth* if and only if for all positive integers `m`, `\Delta^m(w)` is in `A_k^\omega`, where `\Delta(w)` is the word obtained from `w` by composing the length of consecutive - runs of the same letter in `w`. See for instance [1] and [2]. + runs of the same letter in `w`. See for instance [BL2003]_ and [BDLV2006]_. INPUT: @@ -6694,14 +6435,6 @@ def is_smooth_prefix(self): True sage: W([1, 2, 1, 2, 1, 2]).is_smooth_prefix() False - - REFERENCES: - - - [1] S. Brlek, A. Ladouceur, A note on differentiable palindromes, - Theoret. Comput. Sci. 302 (2003) 167--178. - - [2] S. Brlek, S. Dulucq, A. Ladouceur, L. Vuillon, Combinatorial - properties of smooth infinite words, Theoret. Comput. Sci. 352 - (2006) 306--317. """ m = self W = self.parent() @@ -6748,7 +6481,7 @@ def standard_factorization(self): standard factorization `w = uv`, then `u` and `v` are also Lyndon words and `u < v`. - See for instance [1], [2] and [3]. + See for instance [CFL1958]_, [Duv1983]_ and [Lot2002]_. INPUT: @@ -6793,17 +6526,6 @@ def standard_factorization(self): ... ValueError: Standard factorization not defined on words of length less than 2 - - REFERENCES: - - - [1] K.-T. Chen, R.H. Fox, R.C. Lyndon, Free differential calculus, - IV. The quotient groups of the lower central series, Ann. of Math. - 68 (1958) 81--95. - - [2] J.-P. Duval, Factorizing words over an ordered alphabet, - J. Algorithms 4 (1983) 363--381. - - [3] M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of - Encyclopedia of Mathematics and its Applications, Cambridge - University Press, U.K., 2002. """ selflen = self.length() if selflen < 2: @@ -7167,7 +6889,7 @@ def is_christoffel(self): Equivalently, `w` is a Christoffel word iff `w` is a symmetric non-empty word and `w[1:n-1]` is a palindrome. - See for instance [1]_ and [2]_. + See for instance [Ber2007]_ and [BLRS2009]_. INPUT: @@ -7201,18 +6923,6 @@ def is_christoffel(self): True sage: Word('aaaaaaaaa').is_christoffel() False - - REFERENCES: - - .. [1] Jean Berstel. Sturmian and episturmian words (a survey of - some recent results). In S. Bozapalidis and G. Rahonis, editors, - CAI 2007,volume 4728 of Lecture Notes in Computer Science, - pages 23-47. Springer-Verlag, 2007. - .. [2] \J. Berstel, A. Lauve, C. R., F. Saliola, Combinatorics on - words: Christoffel words and repetitions in words, CRM Monograph - Series, 27. American Mathematical Society, Providence, RI, 2009. - xii+147 pp. ISBN: 978-0-8218-4480-9 - """ if len(self) == 0 or len(self.letters()) > 2 or (self.is_palindrome() and len(self) > 1): return False diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index c0f71defbd6..6110c992787 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -53,6 +53,9 @@ sage: m('y', 3) word: ysxyssxyxsxssysxyssxyss +See more examples in the documentation of the call method +(``m.__call__?``). + Infinite fixed point of morphism:: sage: fix = m.fixed_point('x') @@ -230,52 +233,56 @@ class WordMorphism(SageObject): r""" WordMorphism class - EXAMPLES:: - - sage: n = WordMorphism({0:[0,2,2,1],1:[0,2],2:[2,2,1]}) - sage: m = WordMorphism('x->xyxsxss,s->xyss,y->ys') - - Power of a morphism:: + INPUT: - sage: n^2 - WordMorphism: 0->022122122102, 1->0221221, 2->22122102 + - ``data`` -- dict or str or an instance of WordMorphism, the map + giving the image of letters + - ``domain`` -- (optional:``None``) set of words over a given + alphabet. If ``None``, the domain alphabet is computed from ``data`` + and is *sorted*. + - ``codomain`` -- (optional:``None``) set of words over a given + alphabet. If ``None``, the codomain alphabet is computed from + ``data`` and is *sorted*. - Image under a morphism:: + .. NOTE:: - sage: m('y') - word: ys - sage: m('xxxsy') - word: xyxsxssxyxsxssxyxsxssxyssys + When the domain or the codomain are not explicitely given, it is + expected that the letters are comparable because the alphabets of + the domain and of the codomain are sorted. - Iterated image under a morphism:: + EXAMPLES: - sage: m('y', 3) - word: ysxyssxyxsxssysxyssxyss + From a dictionary:: - See more examples in the documentation of the call method - (``m.__call__?``). + sage: n = WordMorphism({0:[0,2,2,1],1:[0,2],2:[2,2,1]}) + sage: n + WordMorphism: 0->0221, 1->02, 2->221 - Infinite fixed point of morphism:: + From a string with ``'->'`` as separation:: - sage: fix = m.fixed_point('x') - sage: fix - word: xyxsxssysxyxsxssxyssxyxsxssxyssxyssysxys... - sage: fix.length() - +Infinity + sage: m = WordMorphism('x->xyxsxss,s->xyss,y->ys') + sage: m + WordMorphism: s->xyss, x->xyxsxss, y->ys + sage: m.domain() + Finite words over {'s', 'x', 'y'} + sage: m.codomain() + Finite words over {'s', 'x', 'y'} - Incidence matrix:: + Specifying the domain and codomain:: - sage: matrix(m) - [2 3 1] - [1 3 0] - [1 1 1] + sage: W = FiniteWords([0,1,2]) + sage: d = {0:[0,1], 1:[0,1,0], 2:[0]} + sage: m = WordMorphism(d, domain=W, codomain=W) + sage: m([0]).parent() + Finite words over {0, 1, 2} - Many other functionalities...:: + When the alphabet is non-sortable, the domain and/or codomain must be + explicitely given:: - sage: m.is_identity() - False - sage: m.is_endomorphism() - True + sage: W = FiniteWords(['a',6]) + sage: d = {'a':['a',6,'a'],6:[6,6,6,'a']} + sage: WordMorphism(d, domain=W, codomain=W) + WordMorphism: 6->666a, a->a6a TESTS:: @@ -337,8 +344,6 @@ def __init__(self, data, domain=None, codomain=None): WordMorphism: a->ab, b->ba sage: WordMorphism({2:[4,5,6],3:[1,2,3]}) WordMorphism: 2->456, 3->123 - sage: WordMorphism({'a':['a',6,'a'],6:[6,6,6,'a']}) - WordMorphism: 6->666a, a->a6a The image of a letter can be a set, but the order is not preserved:: @@ -1263,8 +1268,8 @@ def image(self, letter): :: - sage: s = WordMorphism({0:[1,2], 'a':(2,3,4), 'z':[9,8,7]}) - sage: s.image(0) + sage: s = WordMorphism({'b':[1,2], 'a':(2,3,4), 'z':[9,8,7]}) + sage: s.image('b') word: 12 sage: s.image('a') word: 234 @@ -1809,7 +1814,7 @@ def fixed_point(self, letter): - ``word`` - the fixed point of ``self`` beginning with ``letter``. - EXAMPLES: + EXAMPLES:: sage: W = FiniteWords('abc') @@ -2303,7 +2308,7 @@ def list_of_conjugates(self): if self.is_empty(): return [self] - #Construire la liste c des morphismes conjugues + # Build the list c of conjugate morphisms c = [] m = self c.append(m) @@ -2319,7 +2324,7 @@ def list_of_conjugates(self): break c.insert(0, m) - #Construire la liste d des morphismes distincts + # Build the list d of distinct morphisms d = [] for m in c: if m not in d: diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 88baeb34d66..5438329319a 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -1237,7 +1237,7 @@ def StandardEpisturmianWord(self, directive_word): Note that an infinite word is *episturmian* if it has the same set of factors as some epistandard word. - See for instance [DJP01]_, [JP02]_, and [GJ07]_. + See for instance [DJP2001]_, [JP2002]_, and [GJ2007]_. INPUT: @@ -1266,14 +1266,6 @@ def StandardEpisturmianWord(self, directive_word): Traceback (most recent call last): ... TypeError: directive_word is not a word, so it cannot be used to build an episturmian word - - REFERENCES: - - .. [JP02] \J. Justin, G. Pirillo, Episturmian words and episturmian - morphisms, Theoret. Comput. Sci. 276 (2002) 281--313. - - .. [GJ07] \A. Glen, J. Justin, Episturmian words: a survey, Preprint, - 2007, :arxiv:`0801.1655`. """ if not isinstance(directive_word, Word_class): raise TypeError("directive_word is not a word, so it cannot be used to build an episturmian word") @@ -1325,7 +1317,7 @@ def MinimalSmoothPrefix(self, n): This function finds and returns the minimal smooth prefix of length ``n``. - See [BMP07]_ for a definition. + See [BMP2007]_ for a definition. INPUT: @@ -1344,12 +1336,6 @@ def MinimalSmoothPrefix(self, n): sage: words.MinimalSmoothPrefix(10) word: 1212212112 - - REFERENCES: - - .. [BMP07] \S. Brlek, G. Melançon, G. Paquin, Properties of the extremal - infinite smooth words, Discrete Math. Theor. Comput. Sci. 9 (2007) - 33--49. """ tab = [] W = FiniteWords([1, 2]) @@ -1930,7 +1916,7 @@ def PalindromicDefectWord(self, k=1, alphabet='ab'): r""" Return the finite word `w = a b^k a b^{k-1} a a b^{k-1} a b^{k} a`. - As described by Brlek, Hamel, Nivat and Reutenauer in [BHNR04]_, this + As described by Brlek, Hamel, Nivat and Reutenauer in [BHNR2004]_, this finite word `w` is such that the infinite periodic word `w^{\omega}` has palindromic defect ``k``. diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index 046a0474b3e..44bd3cc1d4c 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -593,7 +593,7 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr when reloading. Also, most iterators do not support copying and should not support pickling by extension. - EXAMPLES: + EXAMPLES:: sage: W = FiniteWords() diff --git a/src/sage/combinat/yang_baxter_graph.py b/src/sage/combinat/yang_baxter_graph.py index 6ba755f7ab6..f24ac2f9923 100644 --- a/src/sage/combinat/yang_baxter_graph.py +++ b/src/sage/combinat/yang_baxter_graph.py @@ -273,7 +273,7 @@ def __iter__(self): sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator sage: ops = [SwapIncreasingOperator(i) for i in range(4)] sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops) - sage: uniq(Y.__iter__()) + sage: sorted(set(Y)) [(1, 0, 2, 1, 0), (1, 2, 0, 1, 0), (1, 2, 1, 0, 0), (2, 1, 0, 1, 0), (2, 1, 1, 0, 0)] """ return self._digraph.vertex_iterator() diff --git a/src/sage/cpython/debug.pyx b/src/sage/cpython/debug.pyx index 4299552c633..cd1c068f682 100644 --- a/src/sage/cpython/debug.pyx +++ b/src/sage/cpython/debug.pyx @@ -26,6 +26,16 @@ cdef extern from "sage/cpython/debugimpl.c": from .getattr cimport AttributeErrorMessage +# Determine subtype_traverse, subtype_clear, subtype_dealloc functions +# for type_debug(). These are the default tp_traverse, tp_clear and +# tp_dealloc functions for heap types (= Python classes). +cdef: + X = type("X", (), {}) # heap type + void* subtype_traverse "subtype_traverse" = (X).tp_traverse + void* subtype_clear "subtype_clear" = (X).tp_clear + void* subtype_dealloc "subtype_dealloc" = (X).tp_dealloc + + def shortrepr(obj, max=50): """ Return ``repr(obj)`` bounded to ``max`` characters. If the string diff --git a/src/sage/cpython/debugimpl.c b/src/sage/cpython/debugimpl.c index 2478f3f7471..7a003c177e0 100644 --- a/src/sage/cpython/debugimpl.c +++ b/src/sage/cpython/debugimpl.c @@ -92,6 +92,9 @@ static void print_object(void* pyobj) else pointer_check_constant(tp->attr, PyObject_GenericSetAttr) \ else pointer_check_constant(tp->attr, _Py_HashPointer) \ else pointer_check_constant(tp->attr, PyObject_HashNotImplemented) \ + else pointer_check_constant(tp->attr, subtype_traverse) \ + else pointer_check_constant(tp->attr, subtype_clear) \ + else pointer_check_constant(tp->attr, subtype_dealloc) \ else \ { \ PyObject* mro = tp->tp_mro; \ diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index b09ddbaf0ef..e66b5cb76d1 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -1223,6 +1223,53 @@ cdef class BooleanFunction(SageObject): V = VectorSpace(GF(2), nvars) return V.subspace(l) + def derivative(self, u): + """ + Return the derivative in direction of ``u`` + + INPUT: + + - ``u`` -- either an integer or a tuple/list of `\GF{2}` elements + of length equal to the number of variables + + + The derivative of `f` in direction of `u` is defined as + `x \mapsto f(x) + f(x + u)`. + + EXAMPLES:: + + sage: from sage.crypto.boolean_function import BooleanFunction + sage: f = BooleanFunction([0,1,0,1,0,1,0,1]) + sage: f.derivative(1).algebraic_normal_form() + 1 + sage: u = [1,0,0] + sage: f.derivative(u).algebraic_normal_form() + 1 + sage: v = vector(GF(2), u) + sage: f.derivative(u).algebraic_normal_form() + 1 + sage: f.derivative(8).algebraic_normal_form() + Traceback (most recent call last): + ... + IndexError: index out of bound + """ + from sage.structure.element import is_Vector + nvars = self._nvariables + + if isinstance(u, (tuple, list)): + v = ZZ(u, base=2) + elif is_Vector(u): + if u.base_ring() != GF(2): + raise TypeError("base ring of input vector must be GF(2)") + elif u.parent().dimension() != nvars: + raise TypeError("input vector must be an element of a vector space with dimension %d" % (nvars,)) + v = ZZ(u.list(), base=2) + else: + v = u + + return BooleanFunction([self(x) ^ self(x ^ v) + for x in range(1 << nvars)]) + def __setitem__(self, i, y): """ Set a value of the function. diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index 77ce1293e24..a6850ffa9a1 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -1506,7 +1506,7 @@ def inverse_key(self, A): m = self.block_length() MatZZ = MatrixSpace(ZZ, m) AZ = MatZZ([ [ A[i, j].lift() for j in range(m) ] for i in range(m) ]) - AZ_adj = AZ.adjoint() + AZ_adj = AZ.adjugate() u, r, s = xgcd(A.det().lift(), S.ngens()) if u != 1: raise ValueError("Argument:\n\n%s\n\nis not invertible." % (A)) diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index eb8e704c3af..84da16e3401 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -160,7 +160,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x)) Traceback (most recent call last): ... - TypeError: unable to convert cos(x) to an integer + TypeError: self must be a numeric expression sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1) Traceback (most recent call last): ... diff --git a/src/sage/crypto/lfsr.py b/src/sage/crypto/lfsr.py index 0c2aee7853e..216233f6694 100644 --- a/src/sage/crypto/lfsr.py +++ b/src/sage/crypto/lfsr.py @@ -122,7 +122,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ########################################################################### import copy @@ -131,6 +131,7 @@ from sage.rings.all import Integer, PolynomialRing from sage.rings.finite_rings.finite_field_constructor import is_FiniteField + def lfsr_sequence(key, fill, n): r""" This function creates an LFSR sequence. @@ -152,6 +153,7 @@ def lfsr_sequence(key, fill, n): sage: fill = [l,l,o,l]; key = [1,o,o,l]; n = 20 sage: L = lfsr_sequence(key,fill,20); L [1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0] + sage: from sage.matrix.berlekamp_massey import berlekamp_massey sage: g = berlekamp_massey(L); g x^4 + x^3 + 1 sage: (1)/(g.reverse()+O(x^20)) @@ -247,6 +249,7 @@ def lfsr_connection_polynomial(s): [1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0] sage: lfsr_connection_polynomial(s) x^4 + x + 1 + sage: from sage.matrix.berlekamp_massey import berlekamp_massey sage: berlekamp_massey(s) x^4 + x^3 + 1 diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index b87682c661a..be3624d6edb 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -90,7 +90,7 @@ from sage.functions.log import log from sage.functions.other import sqrt, floor, ceil -from sage.misc.functional import cyclotomic_polynomial +from sage.misc.functional import cyclotomic_polynomial, round from sage.misc.randstate import set_random_seed from sage.misc.prandom import randint from sage.modules.free_module import FreeModule @@ -105,6 +105,7 @@ from sage.stats.distributions.discrete_gaussian_integer import DiscreteGaussianDistributionIntegerSampler from sage.stats.distributions.discrete_gaussian_polynomial import DiscreteGaussianDistributionPolynomialSampler + class UniformSampler(SageObject): """ Uniform sampling in a range of integers. @@ -312,7 +313,7 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None): self.__s = vector(self.K, self.n, [self.D() for _ in range(n)]) else: try: - lb, ub = map(ZZ,secret_dist) + lb, ub = map(ZZ, secret_dist) self.__s = vector(self.K, self.n, [randint(lb,ub) for _ in range(n)]) except (IndexError, TypeError): raise TypeError("Parameter secret_dist=%s not understood."%(secret_dist)) @@ -740,9 +741,8 @@ def samples(m, n, lwe, seed=None, balanced=False, **kwds): if isinstance(lwe, type): lwe = lwe(n, m=m, **kwds) else: - lwe = lwe if lwe.n != n: - raise ValueError("Passed LWE instance has n=%d, but n=%d was passed to this function."%(lwe.n, n)) + raise ValueError("Passed LWE instance has n=%d, but n=%d was passed to this function." % (lwe.n, n)) if balanced is False: f = lambda a_c: a_c @@ -750,6 +750,7 @@ def samples(m, n, lwe, seed=None, balanced=False, **kwds): f = balance_sample return [f(lwe()) for _ in range(m)] + def balance_sample(s, q=None): r""" Given ``(a,c) = s`` return a tuple ``(a',c')`` where ``a'`` is an integer @@ -767,7 +768,7 @@ def balance_sample(s, q=None): EXAMPLES:: sage: from sage.crypto.lwe import balance_sample, samples, Regev - sage: list(map(balance_sample, samples(10, 5, Regev))) + sage: [balance_sample(s) for s in samples(10, 5, Regev)] [((-9, -4, -4, 4, -4), 4), ((-8, 11, 12, -11, -11), -7), ... ((-11, 12, 0, -6, -3), 7), ((-7, 14, 8, 11, -8), -12)] @@ -776,7 +777,7 @@ def balance_sample(s, q=None): sage: from sage.crypto.lwe import balance_sample, DiscreteGaussianDistributionPolynomialSampler, RingLWE, samples sage: D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], 8, 5) sage: rlwe = RingLWE(20, 257, D) - sage: list(map(balance_sample, samples(10, 8, rlwe))) + sage: [balance_sample(s) for s in samples(10, 8, rlwe)] [((-64, 107, -91, -24, 120, 54, 38, -35), (-84, 121, 28, -99, 91, 54, -60, 11)), ... ((-40, -117, 35, -69, -11, 10, 122, 48), (-80, -2, 119, -91, 27, 66, 121, -1))] diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index 5ca4e3c9301..f6be8840faa 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -775,8 +775,8 @@ def _GF_to_hex(self, GF): return ''.join([self._GF_to_hex(el) for col in GF.columns() for el in col]) elif isinstance(GF, list): - if not all([g.parent().is_field() and g.parent().is_finite() and - g.parent().order() == 2**8 for g in GF]): + if not all(g.parent().is_field() and g.parent().is_finite() and + g.parent().order() == 2**8 for g in GF): msg = "The elements of keyword 'GF' must all be from {0}" raise TypeError(msg.format(self._F)) return ''.join([self._GF_to_hex(el) for el in GF]) @@ -901,8 +901,8 @@ def _GF_to_bin(self, GF): return ''.join([self._GF_to_bin(el) for col in GF.columns() for el in col]) elif isinstance(GF, list): - if not all([g.parent().is_field() and g.parent().is_finite() and - g.parent().order() == 2**8 for g in GF]): + if not all(g.parent().is_field() and g.parent().is_finite() and + g.parent().order() == 2**8 for g in GF): msg = "The elements of keyword 'GF' must all be from {0}" raise TypeError(msg.format(self._F)) return ''.join([self._GF_to_bin(el) for el in GF]) @@ -1400,10 +1400,10 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, raise TypeError(msg) if keys is not None and (not isinstance(keys, list) or \ len(keys) != self._Nr + 1 or \ - not all([isinstance(k, Matrix) for k in keys]) or \ - not all([k.dimensions() == (4, self._Nb) for k in keys]) or \ - not all([k.base_ring().is_finite() and k.base_ring().is_field() - and k.base_ring().order() == 256 for k in keys]) ): + not all(isinstance(k, Matrix) for k in keys) or \ + not all(k.dimensions() == (4, self._Nb) for k in keys) or \ + not all(k.base_ring().is_finite() and k.base_ring().is_field() + and k.base_ring().order() == 256 for k in keys) ): msg = ("keys must be a length {0} array of 4 by {1} matrices" " over {2}") raise TypeError(msg.format(self._Nr, self._Nb, self._F)) @@ -1534,7 +1534,7 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): ....: rgf.mix_columns_poly_constr(), algorithm='decrypt') sage: g = rgf.compose(rgf.sub_bytes_poly_constr(), ....: rgf.mix_columns_poly_constr()) - sage: all([f(i,j) == g(i,j) for i in range(4) for j in range(4)]) + sage: all(f(i,j) == g(i,j) for i in range(4) for j in range(4)) True We can change the keyword attributes of the ``__call__`` methods of @@ -2210,8 +2210,8 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): the ``polynomial_constr`` method and helps ensure that each ``Round_Component_Poly_Constr`` object will act similarly. :: - sage: all([rgf._mix_columns_pc(i, j) == rcpc(i, j) - ....: for i in range(4) for j in range(4)]) + sage: all(rgf._mix_columns_pc(i, j) == rcpc(i, j) + ....: for i in range(4) for j in range(4)) True Since all keyword arguments of ``polynomial_constr`` must have a @@ -2313,8 +2313,8 @@ def __call__(self, row, col, algorithm='encrypt', **kwargs): ....: rgf._shift_rows_pc, rgf, "Shift Rows") sage: rcpc(1, 2) a13 - sage: all([rcpc(i, j) == rgf._shift_rows_pc(i, j) - ....: for i in range(4) for j in range(4)]) + sage: all(rcpc(i, j) == rgf._shift_rows_pc(i, j) + ....: for i in range(4) for j in range(4)) True """ if row not in range(4): diff --git a/src/sage/crypto/sbox.py b/src/sage/crypto/sbox.py index bef5f34e7ff..ed0978dba04 100644 --- a/src/sage/crypto/sbox.py +++ b/src/sage/crypto/sbox.py @@ -470,6 +470,56 @@ def __iter__(self): for i in range(2**self.input_size()): yield self(i) + def derivative(self, u): + """ + Return the derivative in direction of ``u`` + + INPUT: + + - ``u`` -- either an integer or a tuple/list of `\GF{2}` elements + of length equal to ``m`` + + + The derivative of `F` in direction of `u` is defined as + `x \mapsto F(x) + F(x + u)`. + + EXAMPLES:: + + sage: from sage.crypto.sbox import SBox + sage: s = SBox(0,1,2,3) + sage: s.derivative(1) + (1, 1, 1, 1) + sage: u = [1,0] + sage: s.derivative(u) + (1, 1, 1, 1) + sage: v = vector(GF(2), [1,0]) + sage: s.derivative(v) + (1, 1, 1, 1) + sage: s.derivative(4) + Traceback (most recent call last): + ... + IndexError: list index out of range + sage: from sage.crypto.sboxes import PRESENT + sage: PRESENT.derivative(1).max_degree() < PRESENT.max_degree() + True + """ + from sage.structure.element import is_Vector + nvars = self.m + + if isinstance(u, (tuple, list)): + v = ZZ(u, base=2) + elif is_Vector(u): + if u.base_ring() != GF(2): + raise TypeError("base ring of input vector must be GF(2)") + elif u.parent().dimension() != nvars: + raise TypeError("input vector must be an element of a vector space with dimension %d" % (nvars,)) + v = ZZ(u.list(), base=2) + else: + v = u + + return SBox([self(x) ^ self(x ^ v) + for x in range(1 << self.input_size())]) + @cached_method def difference_distribution_table(self): """ diff --git a/src/sage/data_structures/bounded_integer_sequences.pyx b/src/sage/data_structures/bounded_integer_sequences.pyx index 782f9bf1a62..1ca0f7955ed 100644 --- a/src/sage/data_structures/bounded_integer_sequences.pyx +++ b/src/sage/data_structures/bounded_integer_sequences.pyx @@ -677,7 +677,7 @@ cdef class BoundedIntegerSequence: sage: BoundedIntegerSequence(2^64+1, L) Traceback (most recent call last): ... - OverflowError: long int too large to convert + OverflowError: ... int too large to convert... We are testing the corner case of the maximal possible bound:: @@ -690,7 +690,7 @@ cdef class BoundedIntegerSequence: sage: BoundedIntegerSequence(100, [2^256]) Traceback (most recent call last): ... - OverflowError: long int too large to convert + OverflowError: ... int too large to convert... sage: BoundedIntegerSequence(100, [100]) Traceback (most recent call last): ... @@ -701,7 +701,7 @@ cdef class BoundedIntegerSequence: sage: BoundedIntegerSequence(2^256, [200]) Traceback (most recent call last): ... - OverflowError: long int too large to convert + OverflowError: ... int too large to convert... """ if bound <= 0: @@ -886,7 +886,7 @@ cdef class BoundedIntegerSequence: sage: S[2^63] Traceback (most recent call last): ... - OverflowError: long int too large to convert to int + OverflowError: ... int too large to convert to ... :: diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 35355f5567b..512f51566ff 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -140,14 +140,14 @@ Classes and their Methods ========================= """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Daniel Krenn # # 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 __future__ import print_function from six import itervalues @@ -3223,20 +3223,21 @@ def merge(self, key=None, reverse=False): +-- null | +-- successors: (1, 3, 'abe'), (2, 1, 'c') | +-- no predecessors - sage: for k in P.keys(): + sage: for k in sorted(P.keys()): ....: Q = copy(P) ....: Q.merge(k) ....: print('merging %s: %s' % (k, Q)) - merging (1, 2): poset((1, 2, 'ae'), (1, 3, 'b'), + merging (1, 1): poset((1, 1, 'a'), (1, 2, 'e'), (1, 3, 'b'), (2, 1, 'c'), (2, 2, 'f'), (4, 4, 'd')) - merging (1, 3): poset((1, 3, 'abe'), (2, 1, 'c'), + merging (1, 2): poset((1, 2, 'ae'), (1, 3, 'b'), (2, 1, 'c'), + (2, 2, 'f'), (4, 4, 'd')) + merging (1, 3): poset((1, 3, 'abe'), (2, 1, 'c'), (2, 2, 'f'), + (4, 4, 'd')) + merging (2, 1): poset((1, 2, 'e'), (1, 3, 'b'), (2, 1, 'ac'), (2, 2, 'f'), (4, 4, 'd')) - merging (4, 4): poset((4, 4, 'abcdef')) - merging (2, 1): poset((1, 2, 'e'), (1, 3, 'b'), - (2, 1, 'ac'), (2, 2, 'f'), (4, 4, 'd')) merging (2, 2): poset((1, 3, 'b'), (2, 2, 'acef'), (4, 4, 'd')) - merging (1, 1): poset((1, 1, 'a'), (1, 2, 'e'), (1, 3, 'b'), - (2, 1, 'c'), (2, 2, 'f'), (4, 4, 'd')) + merging (4, 4): poset((4, 4, 'abcdef')) + sage: Q = copy(P) sage: Q.merge(); Q poset((4, 4, 'abcdef')) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 5bd5fff2637..e6af9e020d6 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -411,12 +411,9 @@ class FindStat(SageObject): sage: p = findstat({pi: pi.length() for pi in l}, depth=0); p # optional -- internet, random 0: (St000018: The number of inversions of a permutation., [], 873) - Note however, that the results of these two queries are not - necessarily the same, because we compare queries by the data - sent, and the ordering of the data might be different:: - - sage: p == q # optional -- internet - False + Note however, that the results of these two queries need not + compare equal, because we compare queries by the data + sent, and the ordering of the data might be different. Another possibility is to send a collection and a function. In this case, the function is applied to the first few objects of @@ -548,59 +545,63 @@ def query_by_dict(query, collection=None): depth=depth)._find_by_values(max_values=max_values) def query_by_iterable(query, collection=None): - # either a pair (list of objects, list of integers) - # or a list of such or (object, integer) pairs - - # values must always be converted to lists because - # otherwise we get a trailing comma when printing - if (len(query) == 2 and - isinstance(query[1], (list, tuple)) and - len(query[1]) != 0 and - isinstance(query[1][0], (int, Integer))): + # either a pair (objects, values) + # or an iterable of such or (object, integer) pairs + + # we must convert to lists because we want to allow + # iterables for the values + query = list(query) + if len(query) == 2: + try: + query[1] = list(map(Integer, query[1])) + except TypeError: + pass # just a single pair, i.e., a pure distribution query + else: + collection, to_str = get_collection(collection, query[0][0]) + data = [(query[0], list(map(to_str, query[0])), query[1])] + if len(data[0][1]) != len(data[0][2]): + raise ValueError("FindStat expects the same number of objects as values.") + if len(set(data[0][1])) != len(data[0][2]): + raise ValueError("FindStat expects that every object occurs at most once.") + + return FindStatStatistic(id=0, data=data, + collection=collection, + depth=depth)._find_by_values(max_values=max_values) - (collection, to_str) = get_collection(collection, query[0][0]) - data = [(query[0], map(to_str, query[0]), map(Integer, query[1]))] - if len(data[0][0]) != len(data[0][2]): - raise ValueError("FindStat expects the same number of objects as values.") - if len(set(data[0][1])) != len(data[0][2]): - raise ValueError("FindStat expects that every object occurs at most once.") + key, value = query[0] + try: + query[0][1] = list(value) + collection, to_str = get_collection(collection, key[0]) + except TypeError: + collection, to_str = get_collection(collection, key) + data = [] + is_statistic = True + for key, value in query: + try: + value = list(map(Integer, value)) + if len(key) != len(value): + raise ValueError("FindStat expects the same number of objects as values.") + if len(value) != 1: + is_statistic = False + data += [(key, list(map(to_str, key)), value)] + except TypeError: + data += [([key], [to_str(key)], [Integer(value)])] + + all_elements = [e for (elements, elements_str, value) in data for e in elements_str] + if len(set(all_elements)) != len(all_elements): + raise ValueError("FindStat expects that every object occurs at most once.") + + if is_statistic: return FindStatStatistic(id=0, data=data, collection=collection, + first_terms=query, depth=depth)._find_by_values(max_values=max_values) else: - (key, value) = query[0] - if isinstance(value, (list, tuple)): - (collection, to_str) = get_collection(collection, key[0]) - else: - (collection, to_str) = get_collection(collection, key) - - data = [] - is_statistic = True - for (key, value) in query: - if isinstance(value, (list, tuple)): - if len(key) != len(value): - raise ValueError("FindStat expects the same number of objects as values.") - if len(value) != 1: - is_statistic = False - data += [(key, map(to_str, key), map(Integer, value))] - else: - data += [([key], [to_str(key)], [Integer(value)])] - - all_elements = [e for (elements, elements_str, values) in data for e in elements_str] - if len(set(all_elements)) != len(all_elements): - raise ValueError("FindStat expects that every object occurs at most once.") - - if is_statistic: - return FindStatStatistic(id=0, data=data, - collection=collection, - first_terms=query, - depth=depth)._find_by_values(max_values=max_values) - else: - return FindStatStatistic(id=0, data=data, - collection=collection, - depth=depth)._find_by_values(max_values=max_values) + return FindStatStatistic(id=0, data=data, + collection=collection, + depth=depth)._find_by_values(max_values=max_values) if query_2 is None: if isinstance(query_1, str): @@ -966,9 +967,9 @@ def _find_by_id(self): else: raise - self._description = self._raw[FINDSTAT_STATISTIC_DESCRIPTION].encode("utf-8") - self._name = self._raw[FINDSTAT_STATISTIC_NAME].encode("utf-8") - self._references = self._raw[FINDSTAT_STATISTIC_REFERENCES].encode("utf-8") + self._description = self._raw[FINDSTAT_STATISTIC_DESCRIPTION] + self._name = self._raw[FINDSTAT_STATISTIC_NAME] + self._references = self._raw[FINDSTAT_STATISTIC_REFERENCES] self._collection = FindStatCollection(self._raw[FINDSTAT_STATISTIC_COLLECTION]) self._code = self._raw[FINDSTAT_STATISTIC_CODE] self._sage_code = self._raw[FINDSTAT_STATISTIC_SAGE_CODE] @@ -1044,7 +1045,7 @@ def _find_by_values(self, max_values=FINDSTAT_MAX_VALUES): stat_str = "\n".join(["\n".join(keys) + "\n====> " + values for (keys, values) in stat]) verbose("Sending the following data to FindStat\r\n %s" % stat_str, caller_name='FindStat') - values = urlencode({"freedata": stat_str, "depth": str(self._depth), "caller": "Sage"}) + values = urlencode({"freedata": stat_str, "depth": str(self._depth), "caller": "Sage"}).encode("utf-8") verbose("Fetching URL %s with encoded data %s" % (url, values), caller_name='FindStat') request = Request(url, data=values) @@ -1602,7 +1603,8 @@ def references(self): 1: [[OEIS:A005118]] 2: [[oeis:A246865]] """ - l = [ref.strip() for ref in self._references.split(FINDSTAT_SEPARATOR_REFERENCES)] + sp = self._references.split(FINDSTAT_SEPARATOR_REFERENCES) + l = [ref.strip() for ref in sp] return FancyTuple([ref for ref in l if ref != ""]) def set_references(self, value): @@ -1925,6 +1927,9 @@ class FindStatCollection(Element): sage: FindStatCollection(DyckWords(2)) # optional -- internet Cc0005: Dyck paths + sage: FindStatCollection(DyckWords) # optional -- internet + Cc0005: Dyck paths + .. SEEALSO:: :class:`FindStatCollections` @@ -2343,6 +2348,11 @@ class FindStatCollections(Parent, UniqueRepresentation): # several fields are initialised with 'None', they are updated # upon the first call to this class _findstat_collections = { + 1: [None, None, None, Permutation, Permutations, None, + lambda x: x.size(), + lambda x, l: x.size() in l, + str, + lambda x: Permutation(literal_eval(x))], 24: [None, None, None, Word_class, lambda x: Words([0,1], x), None, lambda x: x.length(), lambda x, l: x.length() in l, @@ -2351,7 +2361,7 @@ class FindStatCollections(Parent, UniqueRepresentation): 17: [None, None, None, AlternatingSignMatrix, AlternatingSignMatrices, None, lambda x: x.to_matrix().nrows(), lambda x, l: x.to_matrix().nrows() in l, - lambda x: str(map(list, list(x._matrix))), + lambda x: str(list(map(list, x.to_matrix().rows()))), lambda x: AlternatingSignMatrix(literal_eval(x))], 10: [None, None, None, BinaryTree, BinaryTrees, None, lambda x: x.node_number(), @@ -2365,8 +2375,8 @@ class FindStatCollections(Parent, UniqueRepresentation): lambda X: "( "+X._repr_()+", "+str(X.k())+" )", lambda x: (lambda pi, k: Core(pi, k))(*literal_eval(x))], 5: [None, None, None, DyckWord, DyckWords, None, - lambda x: (x.length()/2), - lambda x, l: (x.length()/2) in l, + lambda x: Integer(x.length()/2), + lambda x, l: Integer(x.length()/2) in l, lambda x: str(list(DyckWord(x))), lambda x: DyckWord(literal_eval(x))], 22: [None, None, None, CartanType_abstract, _finite_irreducible_cartan_types_by_rank, @@ -2412,11 +2422,6 @@ class FindStatCollections(Parent, UniqueRepresentation): lambda x, l: x.size() in l, str, lambda x: PerfectMatching(literal_eval(x))], - 1: [None, None, None, Permutation, Permutations, None, - lambda x: x.size(), - lambda x, l: x.size() in l, - str, - lambda x: Permutation(literal_eval(x))], 14: [None, None, None, FinitePoset, posets, None, lambda x: x.cardinality(), lambda x, l: x.cardinality() in l, @@ -2547,13 +2552,13 @@ def _element_constructor_(self, entry): if isinstance(entry, string_types): # find by name in _findstat_collections - for (id, c) in iteritems(self._findstat_collections): + for id, c in self._findstat_collections.items(): if entry.upper() in (c[0].upper(), c[1].upper(), c[2].upper()): return self.element_class(self, id, c, None) elif isinstance(entry, (int, Integer)): # find by id in _findstat_collections - for (id, c) in iteritems(self._findstat_collections): + for id, c in self._findstat_collections.items(): if entry == id: return self.element_class(self, id, c, None) @@ -2566,7 +2571,7 @@ def _element_constructor_(self, entry): # CartanType. # first check whether the class fits: - for (id, c) in self._findstat_collections.iteritems(): + for (id, c) in self._findstat_collections.items(): # this will work rarely, often c[4] is even a function! if entry == c[4]: return self.element_class(self, id, c, None) @@ -2574,18 +2579,18 @@ def _element_constructor_(self, entry): P = entry.parent() if P is c[3] or P.Element is c[3]: return self.element_class(self, id, c, None) - except AttributeError: + except (TypeError, AttributeError): pass # now check whether entry is an instance: - for (id, c) in self._findstat_collections.iteritems(): + for (id, c) in self._findstat_collections.items(): if isinstance(entry, c[3]): return self.element_class(self, id, c, None) # check whether entry is iterable (it's not a string!) try: obj = next(iter(entry)) - for (id, c) in iteritems(self._findstat_collections): + for (id, c) in self._findstat_collections.items(): if isinstance(obj, c[3]): return self.element_class(self, id, c, entry) @@ -2931,11 +2936,11 @@ class FindStatMaps(Parent, UniqueRepresentation): domain and codomain:: sage: from sage.databases.findstat import FindStatMap, FindStatMaps - sage: for m in sorted(FindStatMaps(), key=lambda m: (m.domain(), m.codomain)): # optional -- internet, random + sage: for m in sorted(FindStatMaps(), key=lambda m: (m.domain(), m.codomain())): # optional -- internet, random ....: print(m.domain().name().ljust(30)+" "+m.codomain().name().ljust(30)+" "+m.name()) - Permutation Standard tableau Robinson-Schensted insertion tableau - Permutation Integer partition Robinson-Schensted tableau shape - Permutation Binary tree to increasing tree + Permutation Permutation cactus evacuation + Permutation Permutation complement + Permutation Permutation cycle-as-one-line notation ... """ diff --git a/src/sage/databases/jones.py b/src/sage/databases/jones.py index 7ffd4b31a14..3790a855036 100644 --- a/src/sage/databases/jones.py +++ b/src/sage/databases/jones.py @@ -233,7 +233,7 @@ def get(self, S, var='a'): S = list(S) except TypeError: S = [S] - if not all([p.is_prime() for p in S]): + if not all(p.is_prime() for p in S): raise ValueError("S must be a list of primes") S.sort() s = tuple(S) diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index 04dd9c4cf81..aca06281f68 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -927,7 +927,7 @@ def natural_object(self): :: sage: av = oeis('A087778') ; av # optional -- internet - A087778: Decimal expansion of Avogadro's constant. + A087778: Decimal expansion of Avogadro's ... sage: av.natural_object() # optional -- internet 6.022141000000000?e23 @@ -1808,9 +1808,14 @@ def __repr__(self): 2: two 3: three 4: 4 + + sage: t = FancyTuple(['Français', 'Español', '中文']) ; t + 0: Français + 1: Español + 2: 中文 """ length = len(str(len(self) - 1)) - return '\n'.join((('{0:>%d}' % length).format(str(i)) + ': ' + str(self[i]) for i in range(len(self)))) + return '\n'.join('{0:>{1}}: {2}'.format(i, length, item) for i, item in enumerate(self)) def __getslice__(self, i, j): r""" @@ -1847,9 +1852,15 @@ def __getitem__(self, x): True sage: ft[-1] == 'ç' True + + Check that :trac:`26997` is fixed:: + + sage: FancyTuple([[1,2,3],(4,5,6)]) + 0: [1, 2, 3] + 1: (4, 5, 6) """ res = tuple.__getitem__(self, x) - if isinstance(res, tuple): + if isinstance(x, slice): res = FancyTuple(res) return res diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 96143a66f45..8438b96d13b 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -692,9 +692,13 @@ def add_files(self): 'sagenb' """ opj = os.path.join - from sage.env import SAGE_SRC, SAGE_DOC_SRC, SAGE_ROOT - DOT_GIT = opj(SAGE_ROOT, '.git') - have_git = os.path.exists(DOT_GIT) + from sage.env import SAGE_SRC, SAGE_DOC_SRC, SAGE_ROOT, SAGE_ROOT_GIT + # SAGE_ROOT_GIT can be None on distributions which typically + # only have the SAGE_LOCAL install tree but not SAGE_ROOT + if SAGE_ROOT_GIT is not None: + have_git = os.path.isdir(SAGE_ROOT_GIT) + else: + have_git = False def all_files(): self.files.append(opj(SAGE_SRC, 'sage')) @@ -714,7 +718,7 @@ def all_files(): self.log("Doctesting files changed since last git commit") import subprocess change = subprocess.check_output(["git", - "--git-dir=" + DOT_GIT, + "--git-dir=" + SAGE_ROOT_GIT, "--work-tree=" + SAGE_ROOT, "status", "--porcelain"]) @@ -1062,7 +1066,7 @@ def run_val_gdb(self, testing=False): sage: DD = DocTestDefaults(valgrind=True, optional="all", timeout=172800) sage: DC = DocTestController(DD, ["hello_world.py"]) sage: DC.run_val_gdb(testing=True) - exec valgrind --tool=memcheck --leak-resolution=high --leak-check=full --num-callers=25 --suppressions="$SAGE_LOCAL/lib/valgrind/sage.supp" --log-file=".../valgrind/sage-memcheck.%p" python "$SAGE_LOCAL/bin/sage-runtests" --serial --timeout=172800 --optional=all hello_world.py + exec valgrind --tool=memcheck --leak-resolution=high --leak-check=full --num-callers=25 --suppressions="$SAGE_EXTCODE/valgrind/pyalloc.supp" --suppressions="$SAGE_EXTCODE/valgrind/sage.supp" --suppressions="$SAGE_EXTCODE/valgrind/sage-additional.supp" --log-file=".../valgrind/sage-memcheck.%p" python "$SAGE_LOCAL/bin/sage-runtests" --serial --timeout=172800 --optional=all hello_world.py """ try: sage_cmd = self._assemble_cmd() @@ -1092,7 +1096,9 @@ def run_val_gdb(self, testing=False): flags = os.getenv("SAGE_MEMCHECK_FLAGS") if flags is None: flags = "--leak-resolution=high --leak-check=full --num-callers=25 " - flags += '''--suppressions="%s" '''%(os.path.join("$SAGE_LOCAL","lib","valgrind","sage.supp")) + flags += '''--suppressions="%s" '''%(os.path.join("$SAGE_EXTCODE","valgrind","pyalloc.supp")) + flags += '''--suppressions="%s" '''%(os.path.join("$SAGE_EXTCODE","valgrind","sage.supp")) + flags += '''--suppressions="%s" '''%(os.path.join("$SAGE_EXTCODE","valgrind","sage-additional.supp")) elif opt.massif: toolname = "massif" flags = os.getenv("SAGE_MASSIF_FLAGS", "--depth=6 ") @@ -1199,13 +1205,14 @@ def run(self): else: self.test_safe_directory() self.create_run_id() - from sage.env import SAGE_ROOT - DOT_GIT = os.path.join(SAGE_ROOT, '.git') - if os.path.isdir(DOT_GIT): + from sage.env import SAGE_ROOT_GIT + # SAGE_ROOT_GIT can be None on distributions which typically + # only have the SAGE_LOCAL install tree but not SAGE_ROOT + if (SAGE_ROOT_GIT is not None) and os.path.isdir(SAGE_ROOT_GIT): import subprocess try: branch = subprocess.check_output(["git", - "--git-dir=" + DOT_GIT, + "--git-dir=" + SAGE_ROOT_GIT, "rev-parse", "--abbrev-ref", "HEAD"]) diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 02e18e67e7b..4b222dd1db9 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -169,7 +169,7 @@ def init_sage(): from sage.cpython._py2_random import Random sage.misc.randstate.DEFAULT_PYTHON_RANDOM = Random - import sage.all_cmdline + import sage.repl.ipython_kernel.all_jupyter sage.interfaces.quit.invalidate_all() # Disable cysignals debug messages in doctests: this is needed to @@ -673,6 +673,16 @@ def compiler(example): raise except BaseException: exception = sys.exc_info() + # On Python 2, the exception lives in sys.exc_info() as + # long we are in the same stack frame. To ensure that + # sig_occurred() works correctly, we need to clear the + # exception. This is not an issue on Python 3, where the + # exception is cleared as soon as we are outside of the + # "except" clause. + try: + sys.exc_clear() + except AttributeError: + pass # Python 3 finally: if self.debugger is not None: self.debugger.set_continue() # ==== Example Finished ==== @@ -699,8 +709,7 @@ def compiler(example): # The example raised an exception: check if it was expected. else: - exc_info = exception - exc_msg = traceback.format_exception_only(*exc_info[:2])[-1] + exc_msg = traceback.format_exception_only(*exception[:2])[-1] if six.PY3 and example.exc_msg is not None: # On Python 3 the exception repr often includes the @@ -709,7 +718,7 @@ def compiler(example): # normalize Python 3 exceptions to match tests written to # Python 2 # See https://trac.sagemath.org/ticket/24271 - exc_cls = exc_info[0] + exc_cls = exception[0] exc_name = exc_cls.__name__ if exc_cls.__module__: exc_fullname = (exc_cls.__module__ + '.' + @@ -736,7 +745,7 @@ def compiler(example): break if not quiet: - got += doctest._exception_traceback(exc_info) + got += doctest._exception_traceback(exception) # If `example.exc_msg` is None, then we weren't expecting # an exception. @@ -770,7 +779,7 @@ def compiler(example): elif outcome is BOOM: if not quiet: self.report_unexpected_exception(out, test, example, - exc_info) + exception) failures += 1 else: assert False, ("unknown outcome", outcome) @@ -2497,7 +2506,9 @@ def _run(self, runner, options, results): if self.source.basename.startswith("sagenb."): import sage.all_notebook as sage_all else: - import sage.all_cmdline as sage_all + # Import Jupyter globals to doctest the Jupyter + # implementation of widgets and interacts + import sage.repl.ipython_kernel.all_jupyter as sage_all dict_all = sage_all.__dict__ # Remove '__package__' item from the globals since it is not # always in the globals in an actual Sage session. diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index c9f28508d9a..4f9ee15fd50 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -28,7 +28,6 @@ from six import text_type import re -import sys import doctest import collections from sage.repl.preparse import preparse, strip_string_literals @@ -54,13 +53,18 @@ # Use this real interval field for doctest tolerances. It allows large # numbers like 1e1000, it parses strings with spaces like RIF(" - 1 ") -# out of the box and it is slightly more precise than Python's 53 bits. +# out of the box and it carries a lot of precision. The latter is +# useful for testing libraries using arbitrary precision but not +# guaranteed rounding such as PARI. We use 1044 bits of precision, +# which should be good to deal with tolerances on numbers computed with +# 1024 bits of precision. +# # The interval approach also means that we do not need to worry about # rounding errors and it is also very natural to see a number with # tolerance as an interval. # We need to import from sage.all to avoid circular imports. from sage.all import RealIntervalField -RIFtol = RealIntervalField(64) +RIFtol = RealIntervalField(1044) # This is the correct pattern to match ISO/IEC 6429 ANSI escape sequences: @@ -358,7 +362,7 @@ def parse_tolerance(source, want): sage: marked.rel_tol 0 sage: marked.abs_tol - 0.010000000000000000000? + 0.010000000000000000000...? """ safe, literals, state = strip_string_literals(source) first_line = safe.split('\n', 1)[0] @@ -730,7 +734,7 @@ def parse(self, string, *args): sage: type(ex.want) sage: ex.want.tol - 2.000000000000000000?e-11 + 2.000000000000000000...?e-11 You can use continuation lines:: @@ -850,7 +854,7 @@ class SageOutputChecker(doctest.OutputChecker): sage: type(ex.want) sage: ex.want.tol - 2.000000000000000000?e-11 + 2.000000000000000000...?e-11 sage: OC.check_output(ex.want, '0.893515349287690', optflag) True sage: OC.check_output(ex.want, '0.8935153492877', optflag) @@ -1129,7 +1133,7 @@ def output_difference(self, example, got, optionflags): sage: zerotol = doctest.Example('',MarkedOutput("0.0\n").update(tol=.1)) sage: zeroabs = doctest.Example('',MarkedOutput("0.0\n").update(abs_tol=.1)) sage: zerorel = doctest.Example('',MarkedOutput("0.0\n").update(rel_tol=.1)) - sage: tlist = doctest.Example('',MarkedOutput("[10.0, 10.0, 10.0, 10.0, 10.0, 10.0]\n").update(abs_tol=1.0)) + sage: tlist = doctest.Example('',MarkedOutput("[10.0, 10.0, 10.0, 10.0, 10.0, 10.0]\n").update(abs_tol=0.987)) sage: zero = "0.0" sage: nf = "9.5" sage: ten = "10.05" @@ -1145,7 +1149,7 @@ def output_difference(self, example, got, optionflags): Got: 9.5 Tolerance exceeded: - 10.0 vs 9.5, tolerance 5e-01 > 1e-01 + 10.0 vs 9.5, tolerance 5e-1 > 1e-1 sage: print(OC.output_difference(tentol,zero,optflag)) Expected: @@ -1153,7 +1157,7 @@ def output_difference(self, example, got, optionflags): Got: 0.0 Tolerance exceeded: - 10.0 vs 0.0, tolerance 1e+00 > 1e-01 + 10.0 vs 0.0, tolerance 1e0 > 1e-1 sage: print(OC.output_difference(tentol,eps,optflag)) Expected: @@ -1161,7 +1165,7 @@ def output_difference(self, example, got, optionflags): Got: -0.05 Tolerance exceeded: - 10.0 vs -0.05, tolerance 1e+00 > 1e-01 + 10.0 vs -0.05, tolerance 2e0 > 1e-1 sage: print(OC.output_difference(tlist,L,optflag)) Expected: @@ -1169,8 +1173,8 @@ def output_difference(self, example, got, optionflags): Got: [9.9, 8.7, 10.3, 11.2, 10.8, 10.0] Tolerance exceeded in 2 of 6: - 10.0 vs 8.7, tolerance 1e+00 > 1e+00 - 10.0 vs 11.2, tolerance 1e+00 > 1e+00 + 10.0 vs 8.7, tolerance 2e0 > 9.87e-1 + 10.0 vs 11.2, tolerance 2e0 > 9.87e-1 TESTS:: @@ -1180,7 +1184,7 @@ def output_difference(self, example, got, optionflags): Got: 0.0 Tolerance exceeded: - 10.0 vs 0.0, tolerance 1e+01 > 1e-01 + 10.0 vs 0.0, tolerance 1e1 > 1e-1 sage: print(OC.output_difference(tenrel,zero,optflag)) Expected: @@ -1188,7 +1192,7 @@ def output_difference(self, example, got, optionflags): Got: 0.0 Tolerance exceeded: - 10.0 vs 0.0, tolerance 1e+00 > 1e-01 + 10.0 vs 0.0, tolerance 1e0 > 1e-1 sage: print(OC.output_difference(tenrel,eps,optflag)) Expected: @@ -1196,7 +1200,7 @@ def output_difference(self, example, got, optionflags): Got: -0.05 Tolerance exceeded: - 10.0 vs -0.05, tolerance 1e+00 > 1e-01 + 10.0 vs -0.05, tolerance 2e0 > 1e-1 sage: print(OC.output_difference(zerotol,ten,optflag)) Expected: @@ -1204,7 +1208,7 @@ def output_difference(self, example, got, optionflags): Got: 10.05 Tolerance exceeded: - 0.0 vs 10.05, tolerance 1e+01 > 1e-01 + 0.0 vs 10.05, tolerance 2e1 > 1e-1 sage: print(OC.output_difference(zeroabs,ten,optflag)) Expected: @@ -1212,7 +1216,7 @@ def output_difference(self, example, got, optionflags): Got: 10.05 Tolerance exceeded: - 0.0 vs 10.05, tolerance 1e+01 > 1e-01 + 0.0 vs 10.05, tolerance 2e1 > 1e-1 sage: print(OC.output_difference(zerorel,eps,optflag)) Expected: @@ -1220,7 +1224,7 @@ def output_difference(self, example, got, optionflags): Got: -0.05 Tolerance exceeded: - 0.0 vs -0.05, tolerance inf > 1e-01 + 0.0 vs -0.05, tolerance +infinity > 1e-1 sage: print(OC.output_difference(zerorel,ten,optflag)) Expected: @@ -1228,7 +1232,7 @@ def output_difference(self, example, got, optionflags): Got: 10.05 Tolerance exceeded: - 0.0 vs 10.05, tolerance inf > 1e-01 + 0.0 vs 10.05, tolerance +infinity > 1e-1 """ got = self.human_readable_escape_sequences(got) want = example.want @@ -1238,30 +1242,35 @@ def output_difference(self, example, got, optionflags): diff += "\n" want_str = [g[0] for g in float_regex.findall(want)] got_str = [g[0] for g in float_regex.findall(got)] - want_values = [RIFtol(g) for g in want_str] - want_intervals = [self.add_tolerance(v, want) for v in want_values] - got_values = [RIFtol(g) for g in got_str] - if len(want_values) == len(got_values): - def failstr(astr, bstr, actual, desired): - return " %s vs %s, tolerance %.0e > %.0e"%(astr, bstr, RIFtol(actual).center(), RIFtol(desired).center()) - - fails = [] - for a, ainterval, b, astr, bstr in zip(want_values, want_intervals, got_values, want_str, got_str): - if not ainterval.overlaps(b): + if len(want_str) == len(got_str): + failures = [] + def fail(x, y, actual, desired): + failstr = " {} vs {}, tolerance {} > {}".format(x, y, + RIFtol(actual).upper().str(digits=1, no_sci=False), + RIFtol(desired).center().str(digits=15, skip_zeroes=True, no_sci=False) + ) + failures.append(failstr) + + for wstr, gstr in zip(want_str, got_str): + w = RIFtol(wstr) + g = RIFtol(gstr) + if not g.overlaps(self.add_tolerance(w, want)): if want.tol: - if a == 0: - fails.append(failstr(astr, bstr, abs(b), want.tol)) + if not w: + fail(wstr, gstr, abs(g), want.tol) else: - fails.append(failstr(astr, bstr, abs(1 - b/a), want.tol)) + fail(wstr, gstr, abs(1 - g/w), want.tol) elif want.abs_tol: - fails.append(failstr(astr, bstr, abs(a - b), want.abs_tol)) + fail(wstr, gstr, abs(g - w), want.abs_tol) else: - fails.append(failstr(astr, bstr, abs(1 - b/a), want.rel_tol)) + fail(wstr, gstr, abs(1 - g/w), want.rel_tol) - if fails: - if len(want_values) == 1: + if failures: + if len(want_str) == 1: diff += "Tolerance exceeded:\n" else: - diff += "Tolerance exceeded in %s of %s:\n"%(len(fails), len(want_values)) - diff += "\n".join(fails) + "\n" + diff += "Tolerance exceeded in %s of %s:\n"%(len(failures), len(want_str)) + diff += "\n".join(failures) + "\n" + elif "..." in want: + diff += "Note: combining tolerance (# tol) with ellipsis (...) is not supported\n" return diff diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index cea41627ac9..21a616d8d15 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -33,7 +33,7 @@ from .parsing import SageDocTestParser from .util import NestedName from sage.structure.dynamic_class import dynamic_class -from sage.env import SAGE_SRC, SAGE_LOCAL +from sage.env import SAGE_SRC, SAGE_LIB # Python file parsing triple_quotes = re.compile(r"\s*[rRuU]*((''')|(\"\"\"))") @@ -89,7 +89,7 @@ def get_basename(path): # If the file is in the sage library, we can use our knowledge of # the directory structure dev = SAGE_SRC - sp = os.path.join(SAGE_LOCAL, 'lib', 'python', 'site-packages') + sp = SAGE_LIB if path.startswith(dev): # there will be a branch name i = path.find(os.path.sep, len(dev)) diff --git a/src/sage/doctest/test.py b/src/sage/doctest/test.py index 825cad42e33..4038c3e097b 100644 --- a/src/sage/doctest/test.py +++ b/src/sage/doctest/test.py @@ -99,7 +99,16 @@ Got: Hello 1.0 Tolerance exceeded: - 0.999999 vs 1.0, tolerance 1e-06 > 1e-06 + 0.999999 vs 1.0, tolerance 2e-6 > 1e-6 + ********************************************************************** + File "tolerance.rst", line ..., in sage.doctest.tests.tolerance + Failed example: + print("Hello 1.0") # rel tol 1e-6 + Expected: + Hello ... + Got: + Hello 1.0 + Note: combining tolerance (# tol) with ellipsis (...) is not supported ********************************************************************** ... 1 diff --git a/src/sage/doctest/tests/interrupt_diehard.rst b/src/sage/doctest/tests/interrupt_diehard.rst index c1ba5713809..40be282d8dd 100644 --- a/src/sage/doctest/tests/interrupt_diehard.rst +++ b/src/sage/doctest/tests/interrupt_diehard.rst @@ -1,6 +1,7 @@ Save the current PID to the file given by :envvar:DOCTEST_TEST_PID_FILE:: - sage: open(os.environ['DOCTEST_TEST_PID_FILE'], "w").write(str(os.getpid())) + sage: with open(os.environ['DOCTEST_TEST_PID_FILE'], "w") as file: + ....: file.write(str(os.getpid())) Interrupt the doctester (the parent process) while blocking the quit signal (used to kill this process):: diff --git a/src/sage/doctest/tests/tolerance.rst b/src/sage/doctest/tests/tolerance.rst index ee18534eae7..fd9949ce2ba 100644 --- a/src/sage/doctest/tests/tolerance.rst +++ b/src/sage/doctest/tests/tolerance.rst @@ -24,3 +24,8 @@ Wrong number and ordinary doctest failure (both errors are reported):: sage: print("Hello 1.0") # rel tol 1e-6 Goodbye 0.999999 + +Hiding numbers under ellipsis (...) is not supported:: + + sage: print("Hello 1.0") # rel tol 1e-6 + Hello ... diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index a2aa6ee4edb..174a7c9a1ea 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -259,14 +259,14 @@ def __classcall_private__(cls, morphism_or_polys, domain=None): polys = [morphism_or_polys] PR = get_coercion_model().common_parent(*polys) - fraction_field = any([is_FractionField(poly.parent()) for poly in polys]) + fraction_field = any(is_FractionField(poly.parent()) for poly in polys) if fraction_field: K = PR.base_ring().fraction_field() # Replace base ring with its fraction field PR = PR.ring().change_ring(K).fraction_field() polys = [PR(poly) for poly in polys] else: - quotient_ring = any([is_QuotientRing(poly.parent()) for poly in polys]) + quotient_ring = any(is_QuotientRing(poly.parent()) for poly in polys) # If any of the list entries lies in a quotient ring, we try # to lift all entries to a common polynomial ring. if quotient_ring: diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index fb5a9d12dfc..62f910a7bba 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -3882,7 +3882,7 @@ def reduced_form(self, **kwds): sage: f.reduced_form(prec=50, smallest_coeffs=False) #needs 2 periodic Traceback (most recent call last): ... - ValueError: accuracy of Newton's root not within tolerance(0.000066950849420871 > 1e-06), increase precision + ValueError: accuracy of Newton's root not within tolerance(0.000066... > 1e-06), increase precision sage: f.reduced_form(smallest_coeffs=False) ( Dynamical System of Projective Space of dimension 1 over Rational Field @@ -3933,7 +3933,7 @@ def reduced_form(self, **kwds): sage: f.reduced_form(prec=30, smallest_coeffs=False) Traceback (most recent call last): ... - ValueError: accuracy of Newton's root not within tolerance(0.000087401733 > 1e-06), increase precision + ValueError: accuracy of Newton's root not within tolerance(0.00008... > 1e-06), increase precision sage: f.reduced_form(smallest_coeffs=False) ( Dynamical System of Projective Space of dimension 1 over Rational Field diff --git a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py index a161bf01371..3fd02434d64 100644 --- a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py +++ b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py @@ -114,7 +114,8 @@ def random_WehlerK3Surface(PP): Q += BR.random_element() * CR.gen(a[0]) * CR.gen(a[1]) * CR.gen(3+b[0]) * CR.gen(3+b[1]) #We can always change coordinates to make L diagonal L = CR.gen(0) * CR.gen(3) + CR.gen(1) * CR.gen(4) + CR.gen(2) * CR.gen(5) - return(WehlerK3Surface([L,Q])) + return WehlerK3Surface([L, Q]) + class WehlerK3Surface_ring(AlgebraicScheme_subscheme_product_projective): r""" @@ -458,7 +459,7 @@ def Lxa(self, a): PSYC = PSY.coordinate_ring() #Define projection homomorphism p = ASC.hom([a[0],a[1],a[2]] + list(PSY.gens()), PSYC) - return((p(self.L))) + return p(self.L) def Qxa(self, a): r""" @@ -495,7 +496,7 @@ def Qxa(self, a): PSYC = PSY.coordinate_ring() #Define projection homomorphism p = ASC.hom([a[0], a[1], a[2]] + list(PSY.gens()), PSYC) - return(p(self.Q)) + return p(self.Q) def Sxa(self, a): r""" @@ -979,7 +980,7 @@ def degenerate_primes(self,check = True): X = self.change_ring(GF(p)) if not X.is_degenerate(): bad_primes.remove(p) - return(bad_primes) + return bad_primes def is_smooth(self): r""" @@ -1115,11 +1116,11 @@ def sigmaX(self, P, **kwds): except (TypeError, NotImplementedError, AttributeError): raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(P, self)) pt = list(P[0]) + [0, 0, 0] - if(P[1][0] != 0): + if P[1][0] != 0: [a,b,c] = [P[1][0]*self.Gpoly(1, 0)(*pt),\ -1*P[1][0]*self.Hpoly(1, 0, 1)(*pt) - P[1][1]*self.Gpoly(1, 0)(*pt),\ -P[1][0]*self.Hpoly(1, 0, 2)(*pt) - P[1][2]*self.Gpoly(1, 0)(*pt)] - elif(P[1][1] != 0): + elif P[1][1] != 0: [a,b,c] = [-1*P[1][1]*self.Hpoly(1, 0, 1)(*pt)-P[1][0]*self.Gpoly(1, 1)(*pt),\ P[1][1]*self.Gpoly(1, 1)(*pt),\ -P[1][1]*self.Hpoly(1, 1, 2)(*pt)-P[1][2]*self.Gpoly(1, 1)(*pt)] @@ -1357,11 +1358,11 @@ def sigmaY(self,P, **kwds): except (TypeError, NotImplementedError, AttributeError): raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented"%(P, self)) pt = [0, 0, 0] + list(P[1]) - if(P[0][0] != 0): + if P[0][0] != 0: [a, b, c] = [P[0][0]*self.Gpoly(0, 0)(*pt), \ -1*P[0][0]*self.Hpoly(0, 0, 1)(*pt) - P[0][1]*self.Gpoly(0, 0)(*pt), \ -P[0][0]*self.Hpoly(0, 0, 2)(*pt) - P[0][2]*self.Gpoly(0, 0)(*pt)] - elif(P[0][1] != 0): + elif P[0][1] != 0: [a, b, c] = [-1*P[0][1]*self.Hpoly(0, 0, 1)(*pt) - P[0][0]*self.Gpoly(0, 1)(*pt),\ P[0][1]*self.Gpoly(0, 1)(*pt), \ -P[0][1]*self.Hpoly(0, 1, 2)(*pt) - P[0][2]*self.Gpoly(0, 1)(*pt)] @@ -1848,7 +1849,7 @@ def canonical_height_plus(self, P, N, badprimes=None, prec=100): h = self.lambda_plus(P, 0, N, m, n, prec) for p in badprimes: h += self.lambda_plus(P, p, N, m, n, prec) - return(h) + return h def canonical_height_minus(self, P, N, badprimes=None, prec=100): r""" @@ -1912,7 +1913,7 @@ def canonical_height_minus(self, P, N, badprimes=None, prec=100): h = self.lambda_minus(P, 0, N, m, n, prec) for p in badprimes: h += self.lambda_minus(P, p, N, m, n, prec) - return(h) + return h def canonical_height(self, P, N, badprimes=None, prec=100): r""" @@ -1964,8 +1965,8 @@ def canonical_height(self, P, N, badprimes=None, prec=100): """ if badprimes is None: badprimes = self.degenerate_primes() - return(self.canonical_height_plus(P, N,badprimes,prec) + - self.canonical_height_minus(P, N,badprimes,prec)) + return (self.canonical_height_plus(P, N, badprimes, prec) + + self.canonical_height_minus(P, N, badprimes, prec)) def fiber(self, p, component): r""" @@ -2077,7 +2078,7 @@ def fiber(self, p, component): Points.append([A2, One, C2] + P) else: return [] - elif(self.Gpoly(component, 2)(P0) != 0): + elif self.Gpoly(component, 2)(P0) != 0: T0 = (self.Hpoly(component, 0, 2)(P0)**2 - 4*self.Gpoly(component, 0)(P0)*self.Gpoly(component, 2)(P0)) T1 = (self.Hpoly(component, 1, 2)(P0)**2 - 4*self.Gpoly(component, 1)(P0)*self.Gpoly(component, 2)(P0)) if (T0.is_square() and T1.is_square()): @@ -2099,7 +2100,7 @@ def fiber(self, p, component): Points.append([A2, B2, One] + P) else: return [] - elif(self.Hpoly(component, 0, 1)(P0) != 0): + elif self.Hpoly(component, 0, 1)(P0) != 0: if component == 1: Points.append(P+[Zero, One, Zero]) Points.append(P+[-self.Hpoly(component, 0, 1)(P0),Zero,-self.Hpoly(component, 1, 2)(P0)]) @@ -2110,14 +2111,14 @@ def fiber(self, p, component): Points.append([-self.Hpoly(component, 0, 1)(P0),Zero,-self.Hpoly(component, 1, 2)(P0)] + P) Points.append([One,Zero,Zero]+P) Points.append([Zero,-self.Hpoly(component, 0, 1)(P0),-self.Hpoly(component, 0, 2)(P0)] + P) - elif(self.Hpoly(component, 0, 2)(P0) != 0): + elif self.Hpoly(component, 0, 2)(P0) != 0: if component == 1: Points.append(P+[Zero, Zero, One]) Points.append(P+[-self.Hpoly(component, 0, 2)(P0),-self.Hpoly(component, 1, 2)(P0), Zero]) else: Points.append([Zero, Zero, One]+P) Points.append([-self.Hpoly(component, 0, 2)(P0),-self.Hpoly(component, 1, 2)(P0), Zero]+ P) - elif(self.Hpoly(component, 1, 2)(P0) != 0): + elif self.Hpoly(component, 1, 2)(P0) != 0: if component == 1: Points.append(P + [Zero, Zero, One]) Points.append(P + [Zero, One, Zero]) @@ -2133,7 +2134,7 @@ def fiber(self, p, component): Y = self.point(x, False) if not Y in fiber: fiber.append(Y) - return(fiber) + return fiber def nth_iterate_phi(self, P, n, **kwds): r""" @@ -2191,14 +2192,14 @@ def nth_iterate_phi(self, P, n, **kwds): raise TypeError("iterate number must be an integer") #Since phi and psi are inverses and automorphisms if n < 0: - return(self.nth_iterate_psi(P, abs(n), **kwds)) + return self.nth_iterate_psi(P, abs(n), **kwds) if n == 0: - return(self) + return self else: Q = self.phi(P, **kwds) for i in range(2, n+1): Q = self.phi(Q, **kwds) - return(Q) + return Q def nth_iterate_psi(self, P, n, **kwds): r""" @@ -2245,14 +2246,14 @@ def nth_iterate_psi(self, P, n, **kwds): raise TypeError("iterate number must be an integer") #Since phi and psi and inverses if n < 0: - return(self.nth_iterate_phi(P, abs(n), **kwds)) + return self.nth_iterate_phi(P, abs(n), **kwds) if n == 0: - return(self) + return self else: Q = self.psi(P, **kwds) for i in range(2, n+1): Q = self.psi(Q, **kwds) - return(Q) + return Q def orbit_phi(self,P,N, **kwds): r""" @@ -2302,7 +2303,7 @@ def orbit_phi(self,P,N, **kwds): if N[0] < 0 or N[1] < 0: raise TypeError("orbit bounds must be non-negative") if N[0] > N[1]: - return([]) + return [] Q = self(copy(P)) for i in range(1, N[0] + 1): Q = self.phi(Q, **kwds) @@ -2358,7 +2359,7 @@ def orbit_psi(self, P, N, **kwds): if N[0] < 0 or N[1] < 0: raise TypeError("orbit bounds must be non-negative") if N[0] > N[1]: - return([]) + return [] Q = self(copy(P)) for i in range(1, N[0] + 1): Q = self.psi(Q, **kwds) @@ -2452,7 +2453,7 @@ def is_symmetric_orbit(self,orbit): if P[0] == Q[0] or P[1] == Q[1]: sym = True i += 1 - return(sym) + return sym class WehlerK3Surface_field( WehlerK3Surface_ring): @@ -2494,20 +2495,20 @@ def getPx2(): for i in getPx1(): for j in getPx1(): A = i + j - if(self.L(A) == 0 and self.Q(A) == 0): + if self.L(A) == 0 and self.Q(A) == 0: Count += 1 for k in getPx2(): A = i + k - if(self.L(A) == 0 and self.Q(A) == 0): + if self.L(A) == 0 and self.Q(A) == 0: Count += 1 B = i + Ypoint - if(self.L(B) == 0 and self.Q(B) == 0): + if self.L(B) == 0 and self.Q(B) == 0: Count += 1 #Create all possible Px2 Values for i in getPx2(): for j in getPx1(): A = i + j - if (self.L(A) == 0 and self.Q(A) == 0): + if self.L(A) == 0 and self.Q(A) == 0: Count += 1 for k in getPx2(): A = i + k diff --git a/src/sage/dynamics/cellular_automata/solitons.py b/src/sage/dynamics/cellular_automata/solitons.py index 5208d9a692b..5113084f8d6 100644 --- a/src/sage/dynamics/cellular_automata/solitons.py +++ b/src/sage/dynamics/cellular_automata/solitons.py @@ -7,15 +7,15 @@ - Travis Scrimshaw (2018-02-03): Periodic version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 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.structure.sage_object import SageObject from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux @@ -25,6 +25,7 @@ from sage.typeset.ascii_art import ascii_art from sage.rings.integer_ring import ZZ + class SolitonCellularAutomata(SageObject): r""" Soliton cellular automata. @@ -499,7 +500,7 @@ def evolve(self, carrier_capacity=None, carrier_index=None, number=None): if len(carrier_index) != len(carrier_capacity): raise ValueError("carrier_index and carrier_capacity" " must have the same length") - for i,r in zip(carrier_capacity, carrier_index): + for i, r in zip(carrier_capacity, carrier_index): self.evolve(i, r) return if isinstance(carrier_index, (list, tuple)): @@ -1020,6 +1021,7 @@ def latex_states(self, num=None, as_array=True, box_width='5pt'): self.evolve() vacuum = self._vacuum_elt + def compact_repr(b): if as_array and b == vacuum: return "\\makebox[%s]{.}"%box_width @@ -1077,13 +1079,15 @@ def print_state_evolution(self, num): | | | | | | | 3 3 2 1 1 1 1 """ - u = self.state_evolution(num) # Also evolves as necessary + u = self.state_evolution(num) # Also evolves as necessary final = self._states[num+1] vacuum = self._vacuum_elt state = [vacuum]*(len(final) - len(self._states[num])) + list(self._states[num]) carrier = KirillovReshetikhinTableaux(self._cartan_type, *self._evolutions[num]) + def simple_repr(x): return ''.join(repr(x).strip('[]').split(', ')) + def carrier_repr(x): if carrier._tableau_height == 1: return sum((ascii_art(repr(b)) if repr(b)[0] != '-' @@ -1091,6 +1095,7 @@ def carrier_repr(x): for b in x), ascii_art('')) return ascii_art(''.join(repr(x).strip('[]').split(', '))) + def cross_repr(i): ret = ascii_art( """ @@ -1125,32 +1130,7 @@ def latex_state_evolution(self, num, scale=1): \node (i0) at (0.0,0.9) {$1$}; \node (i1) at (2.48,0.9) {$1$}; \node (i2) at (4.96,0.9) {$3$}; - \node (i3) at (7.44,0.9) {$1$}; - \node (i4) at (9.92,0.9) {$2$}; - \node (i5) at (12.4,0.9) {$3$}; - \node (t0) at (0.0,-1) {$1$}; - \node (t1) at (2.48,-1) {$3$}; - \node (t2) at (4.96,-1) {$2$}; - \node (t3) at (7.44,-1) {$3$}; - \node (t4) at (9.92,-1) {$1$}; - \node (t5) at (12.4,-1) {$1$}; - \node (u0) at (-1.24,0) {$111$}; - \node (u1) at (1.24,0) {$111$}; - \node (u2) at (3.72,0) {$113$}; - \node (u3) at (6.2,0) {$112$}; - \node (u4) at (8.68,0) {$123$}; - \node (u5) at (11.16,0) {$113$}; - \node (u6) at (13.64,0) {$111$}; - \draw[->] (i0) -- (t0); - \draw[->] (u1) -- (u0); - \draw[->] (i1) -- (t1); - \draw[->] (u2) -- (u1); - \draw[->] (i2) -- (t2); - \draw[->] (u3) -- (u2); - \draw[->] (i3) -- (t3); - \draw[->] (u4) -- (u3); - \draw[->] (i4) -- (t4); - \draw[->] (u5) -- (u4); + ... \draw[->] (i5) -- (t5); \draw[->] (u6) -- (u5); \end{tikzpicture} @@ -1167,6 +1147,7 @@ def latex_state_evolution(self, num, scale=1): vacuum = self._vacuum_elt initial = [vacuum]*(len(final) - len(self._states[num])) + list(self._states[num]) cs = len(u[0]) * 0.08 + 1 # carrier scaling + def simple_repr(x): return ''.join(repr(x).strip('[]').split(', ')) ret = '\\begin{{tikzpicture}}[scale={}]\n'.format(scale) @@ -1182,6 +1163,7 @@ def simple_repr(x): ret += '\\end{tikzpicture}' return LatexExpr(ret) + class PeriodicSolitonCellularAutomata(SolitonCellularAutomata): r""" A periodic soliton cellular automata. @@ -1401,7 +1383,7 @@ def evolve(self, carrier_capacity=None, carrier_index=None, number=None): if len(carrier_index) != len(carrier_capacity): raise ValueError("carrier_index and carrier_capacity" " must have the same length") - for i,r in zip(carrier_capacity, carrier_index): + for i, r in zip(carrier_capacity, carrier_index): self.evolve(i, r) return if isinstance(carrier_index, (list, tuple)): @@ -1477,4 +1459,3 @@ def __eq__(self, other): """ return (isinstance(other, PeriodicSolitonCellularAutomata) and SolitonCellularAutomata.__eq__(self, other)) - diff --git a/src/sage/env.py b/src/sage/env.py index 3a64c2df7b4..061b94f3f1c 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -5,190 +5,273 @@ - \R. Andrew Ohana (2012): Initial version. +Verify that Sage can be started without any ``SAGE_`` environment +variables:: + + sage: env = {k:v for (k,v) in os.environ.items() if not k.startswith("SAGE_")} + sage: import subprocess + sage: cmd = "from sage.all import SAGE_ROOT; print(SAGE_ROOT)" + sage: res = subprocess.call(["python", "-c", cmd], env=env) # long time + None """ -######################################################################## + +#***************************************************************************** # Copyright (C) 2013 R. Andrew Ohana +# Copyright (C) 2019 Jeroen Demeyer # -# 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/ -######################################################################## +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +#***************************************************************************** + from __future__ import absolute_import +import sage import glob import os import socket -import site +import sys +import sysconfig from . import version -opj = os.path.join -# set default values for sage environment variables -# every variable can be overwritten by os.environ +# All variables set by var() appear in this SAGE_ENV dict and also +# appear as module global (contained in __all__). SAGE_ENV = dict() +__all__ = ['sage_include_directories', 'cython_aliases'] + + +def join(*args): + """ + Join paths like ``os.path.join`` except that the result is ``None`` + if any of the components is ``None``. + + EXAMPLES:: + + sage: from sage.env import join + sage: print(join("hello", "world")) + hello/world + sage: print(join("hello", None)) + None + """ + if any(a is None for a in args): + return None + return os.path.join(*args) -# Helper to build the SAGE_ENV dictionary -def _add_variable_or_fallback(key, fallback, force=False): + +def var(key, *fallbacks, **kwds): """ Set ``SAGE_ENV[key]``. - If ``key`` is an environment variable, this is the - value. Otherwise, the ``fallback`` is used. + If ``key`` is an environment variable, this is the value. + Otherwise, the ``fallbacks`` are tried until one is found which + is not ``None``. If the environment variable is not set and all + fallbacks are ``None``, then the final value is ``None``. INPUT: - ``key`` -- string. - - ``fallback`` -- anything. + - ``fallbacks`` -- tuple containing ``str`` or ``None`` values. - - ``force`` -- boolean (optional, default is ``False``). Whether - to always use the fallback, regardless of environment variables. + - ``force`` -- boolean (optional, default is ``False``). If + ``True``, skip the environment variable and only use the + fallbacks. EXAMPLES:: sage: import os, sage.env sage: sage.env.SAGE_ENV = dict() sage: os.environ['SAGE_FOO'] = 'foo' - sage: sage.env._add_variable_or_fallback('SAGE_FOO', '---$SAGE_URL---') + sage: sage.env.var('SAGE_FOO', 'unused') sage: sage.env.SAGE_FOO 'foo' sage: sage.env.SAGE_ENV['SAGE_FOO'] 'foo' - If the environment variable does not exist, the fallback is - used. Previously-declared variables are replaced if they are - prefixed with a dollar sign:: + If the environment variable does not exist, the fallbacks (if any) + are used. In most typical uses, there is exactly one fallback:: sage: _ = os.environ.pop('SAGE_BAR', None) # ensure that SAGE_BAR does not exist - sage: sage.env._add_variable_or_fallback('SAGE_BAR', '---$SAGE_FOO---') + sage: sage.env.var('SAGE_BAR', 'bar') sage: sage.env.SAGE_BAR - '---foo---' + 'bar' sage: sage.env.SAGE_ENV['SAGE_BAR'] - '---foo---' + 'bar' + + Test multiple fallbacks:: + + sage: sage.env.var('SAGE_BAR', None, 'yes', 'no') + sage: sage.env.SAGE_BAR + 'yes' + + If all fallbacks are ``None``, the result is ``None``:: - Test that :trac:`23758` has been resolved:: + sage: sage.env.var('SAGE_BAR') + sage: print(sage.env.SAGE_BAR) + None + sage: sage.env.var('SAGE_BAR', None) + sage: print(sage.env.SAGE_BAR) + None - sage: sage.env._add_variable_or_fallback('SAGE_BA', '---hello---') - sage: sage.env._add_variable_or_fallback('SAGE_QUX', '$SAGE_BAR') - sage: sage.env.SAGE_ENV['SAGE_QUX'] - '---foo---' + Test the ``force`` keyword:: + + sage: os.environ['SAGE_FOO'] = 'foo' + sage: sage.env.var('SAGE_FOO', 'forced', force=True) + sage: sage.env.SAGE_FOO + 'forced' + sage: sage.env.var('SAGE_FOO', 'forced', force=False) + sage: sage.env.SAGE_FOO + 'foo' """ - global SAGE_ENV - import six - try: - import os - value = os.environ[key] - except KeyError: - value = fallback - if force: - value = fallback - if isinstance(value, six.string_types): - # Now do the variable replacement. First treat 'value' as if - # it were a path and do the substitution on each of the - # components. This is to avoid the sloppiness in the second - # round of substitutions: if VAR and VAR_NEW are both in - # SAGE_ENV, then when doing substitution on the string - # "$VAR_NEW/a/b", we want to match VAR_NEW, not VAR, if - # possible. - for sep in set([os.path.sep, '/']): - components = [] - for s in value.split(sep): - if s.startswith('$'): - components.append(SAGE_ENV.get(s[1:], s)) - else: - components.append(s) - value = sep.join(components) - # Now deal with any remaining substitutions. The following is - # sloppy, as mentioned above: if $VAR and $VAR_NEW are both in - # SAGE_ENV, the substitution for "$VAR_NEw" depends on which - # of the two appears first when iterating over - # SAGE_ENV.items(). - for k,v in SAGE_ENV.items(): - if isinstance(v, six.string_types): - value = value.replace('$'+k, v) + if kwds.get("force"): + value = None + else: + value = os.environ.get(key) + # Try all fallbacks in order as long as we don't have a value + for f in fallbacks: + if value is not None: + break + value = f SAGE_ENV[key] = value globals()[key] = value + __all__.append(key) + # system info -_add_variable_or_fallback('UNAME', os.uname()[0]) -_add_variable_or_fallback('HOSTNAME', socket.gethostname()) -_add_variable_or_fallback('LOCAL_IDENTIFIER','$HOSTNAME.%s'%os.getpid()) +var('UNAME', os.uname()[0]) +var('HOSTNAME', socket.gethostname()) +var('LOCAL_IDENTIFIER', "{}.{}".format(HOSTNAME, os.getpid())) + +# version info +var('SAGE_VERSION', version.version) +var('SAGE_DATE', version.date) +var('SAGE_VERSION_BANNER', version.banner) # bunch of sage directories and files -_add_variable_or_fallback('SAGE_ROOT', None) -_add_variable_or_fallback('SAGE_LOCAL', None) -_add_variable_or_fallback('SAGE_ETC', opj('$SAGE_LOCAL', 'etc')) -_add_variable_or_fallback('SAGE_INC', opj('$SAGE_LOCAL', 'include')) -_add_variable_or_fallback('SAGE_SHARE', opj('$SAGE_LOCAL', 'share')) +var('SAGE_LOCAL', os.path.abspath(sys.prefix)) +var('SAGE_ETC', join(SAGE_LOCAL, 'etc')) +var('SAGE_INC', join(SAGE_LOCAL, 'include')) +var('SAGE_SHARE', join(SAGE_LOCAL, 'share')) +var('SAGE_DOC', join(SAGE_SHARE, 'doc', 'sage')) +var('SAGE_SPKG_INST', join(SAGE_LOCAL, 'var', 'lib', 'sage', 'installed')) +var('SAGE_LIB', os.path.dirname(os.path.dirname(sage.__file__))) + +var('SAGE_ROOT') # no fallback for SAGE_ROOT +var('SAGE_SRC', join(SAGE_ROOT, 'src'), SAGE_LIB) +var('SAGE_DOC_SRC', join(SAGE_SRC, 'doc')) +var('SAGE_PKGS', join(SAGE_ROOT, 'build', 'pkgs')) +var('SAGE_ROOT_GIT', join(SAGE_ROOT, '.git')) + +var('DOT_SAGE', join(os.environ.get('HOME'), '.sage')) +var('SAGE_STARTUP_FILE', join(DOT_SAGE, 'init.sage')) + +# installation directories for various packages +var('SAGE_EXTCODE', join(SAGE_SHARE, 'sage', 'ext')) +var('CONWAY_POLYNOMIALS_DATA_DIR', join(SAGE_SHARE, 'conway_polynomials')) +var('GRAPHS_DATA_DIR', join(SAGE_SHARE, 'graphs')) +var('ELLCURVE_DATA_DIR', join(SAGE_SHARE, 'ellcurves')) +var('POLYTOPE_DATA_DIR', join(SAGE_SHARE, 'reflexive_polytopes')) +var('GAP_ROOT_DIR', join(SAGE_SHARE, 'gap')) +var('THEBE_DIR', join(SAGE_SHARE, 'thebe')) +var('COMBINATORIAL_DESIGN_DATA_DIR', join(SAGE_SHARE, 'combinatorial_designs')) +var('CREMONA_MINI_DATA_DIR', join(SAGE_SHARE, 'cremona')) +var('CREMONA_LARGE_DATA_DIR', join(SAGE_SHARE, 'cremona')) +var('JMOL_DIR', join(SAGE_SHARE, 'jmol')) +var('JSMOL_DIR', join(SAGE_SHARE, 'jsmol')) +var('MATHJAX_DIR', join(SAGE_SHARE, 'mathjax')) +var('THREEJS_DIR', join(SAGE_SHARE, 'threejs')) +var('MAXIMA_FAS') + +# misc +var('SAGE_BANNER', '') +var('SAGE_IMPORTALL', 'yes') -_add_variable_or_fallback('SAGE_SRC', opj('$SAGE_ROOT', 'src')) -try: - sitepackages_dirs = site.getsitepackages() -except AttributeError: # in case of use inside virtualenv - sitepackages_dirs = [os.path.join(os.path.dirname(site.__file__), - 'site-packages')] -_add_variable_or_fallback('SITE_PACKAGES', sitepackages_dirs) +def _get_shared_lib_filename(libname, *additional_libnames): + """ + Return the full path to a shared library file installed in the standard + location for the system within the ``LIBDIR`` prefix (or + ``$SAGE_LOCAL/lib`` in the case of manual build of Sage). -_add_variable_or_fallback('SAGE_LIB', SITE_PACKAGES[0]) + This can also be passed more than one library name (e.g. for cases where + some library may have multiple names depending on the platform) in which + case the first one found is returned. -# Used by sage/misc/package.py. Should be SAGE_SRC_ROOT in VPATH. -_add_variable_or_fallback('SAGE_PKGS', opj('$SAGE_ROOT', 'build', 'pkgs')) + This supports most *NIX variants (in which ``lib.so`` is found + under ``$SAGE_LOCAL/lib``), macOS (same, but with the ``.dylib`` + extension), and Cygwin (under ``$SAGE_LOCAL/bin/cyg.dll``, + or ``$SAGE_LOCAL/bin/cyg-*.dll`` for versioned DLLs). + For distributions like Debian that use a multiarch layout, we also try the + multiarch lib paths (i.e. ``/usr/lib//``). -_add_variable_or_fallback('SAGE_EXTCODE', opj('$SAGE_SHARE', 'sage', 'ext')) -_add_variable_or_fallback('SAGE_LOGS', opj('$SAGE_ROOT', 'logs', 'pkgs')) -_add_variable_or_fallback('SAGE_SPKG_INST', opj('$SAGE_LOCAL', 'var', 'lib', 'sage', 'installed')) -_add_variable_or_fallback('SAGE_DOC_SRC', opj('$SAGE_SRC', 'doc')) -_add_variable_or_fallback('SAGE_DOC', opj('$SAGE_SHARE', 'doc', 'sage')) -_add_variable_or_fallback('DOT_SAGE', opj(os.environ.get('HOME','$SAGE_ROOT'), '.sage')) -_add_variable_or_fallback('SAGE_DOT_GIT', opj('$SAGE_ROOT', '.git')) -_add_variable_or_fallback('SAGE_DISTFILES', opj('$SAGE_ROOT', 'upstream')) + Returns ``None`` if the file does not exist. -# misc -_add_variable_or_fallback('SAGE_URL', 'http://sage.math.washington.edu/sage/') -_add_variable_or_fallback('REALM', 'sage.math.washington.edu') -_add_variable_or_fallback('TRAC_SERVER_URI', 'https://trac.sagemath.org') -_add_variable_or_fallback('SAGE_REPO_AUTHENTICATED', 'ssh://git@trac.sagemath.org:2222/sage.git') -_add_variable_or_fallback('SAGE_REPO_ANONYMOUS', 'git://trac.sagemath.org/sage.git') -_add_variable_or_fallback('SAGE_VERSION', version.version) -_add_variable_or_fallback('SAGE_DATE', version.date) -_add_variable_or_fallback('SAGE_VERSION_BANNER', version.banner) -_add_variable_or_fallback('SAGE_BANNER', '') -_add_variable_or_fallback('SAGE_IMPORTALL', 'yes') - -# additional packages locations -_add_variable_or_fallback('CONWAY_POLYNOMIALS_DATA_DIR', opj('$SAGE_SHARE','conway_polynomials')) -_add_variable_or_fallback('GRAPHS_DATA_DIR', opj('$SAGE_SHARE','graphs')) -_add_variable_or_fallback('ELLCURVE_DATA_DIR',opj('$SAGE_SHARE','ellcurves')) -_add_variable_or_fallback('POLYTOPE_DATA_DIR',opj('$SAGE_SHARE','reflexive_polytopes')) -_add_variable_or_fallback('GAP_ROOT_DIR', opj('$SAGE_SHARE','gap')) -_add_variable_or_fallback('THEBE_DIR', opj('$SAGE_SHARE','thebe')) -_add_variable_or_fallback('COMBINATORIAL_DESIGN_DATA_DIR', opj('$SAGE_SHARE', 'combinatorial_designs')) -_add_variable_or_fallback('CREMONA_MINI_DATA_DIR', opj('$SAGE_SHARE', 'cremona')) -_add_variable_or_fallback('CREMONA_LARGE_DATA_DIR', opj('$SAGE_SHARE', 'cremona')) -_add_variable_or_fallback('JMOL_DIR', opj('$SAGE_SHARE', 'jmol')) -_add_variable_or_fallback('JSMOL_DIR', opj('$SAGE_SHARE', 'jsmol')) -_add_variable_or_fallback('MATHJAX_DIR', opj('$SAGE_SHARE', 'mathjax')) -_add_variable_or_fallback('THREEJS_DIR', opj('$SAGE_SHARE', 'threejs')) -_add_variable_or_fallback('MAXIMA_FAS', None) + EXAMPLES:: + + sage: import sys + sage: from fnmatch import fnmatch + sage: from sage.env import _get_shared_lib_filename + sage: lib_filename = _get_shared_lib_filename("Singular", + ....: "singular-Singular") + sage: if sys.platform == 'cygwin': + ....: pattern = "*/cygSingular-*.dll" + ....: elif sys.platform == 'darwin': + ....: pattern = "*/libSingular.dylib" + ....: else: + ....: pattern = "*/lib*Singular.so" + sage: fnmatch(lib_filename, pattern) + True + sage: _get_shared_lib_filename("an_absurd_lib") is None + True + """ + + for libname in (libname,) + additional_libnames: + if sys.platform == 'cygwin': + bindir = sysconfig.get_config_var('BINDIR') + pats = ['cyg{}.dll'.format(libname), 'cyg{}-*.dll'.format(libname)] + filenames = [] + for pat in pats: + filenames += glob.glob(os.path.join(bindir, pat)) + + # Note: This is not very robust, since if there are multi DLL + # versions for the same library this just selects one more or less + # at arbitrary. However, practically speaking, on Cygwin, there + # will only ever be one version + if filenames: + return filenames[-1] + else: + if sys.platform == 'darwin': + ext = 'dylib' + else: + ext = 'so' + + libdirs = [sysconfig.get_config_var('LIBDIR')] + multilib = sysconfig.get_config_var('MULTILIB') + if multilib: + libdirs.insert(0, os.path.join(libdirs[0], multilib)) + + for libdir in libdirs: + basename = 'lib{}.{}'.format(libname, ext) + filename = os.path.join(libdir, basename) + if os.path.exists(filename): + return filename + + # Just return None if no files were found + return None # locate singular shared object -if UNAME[:6] == "CYGWIN": - SINGULAR_SO = ([None] + glob.glob(os.path.join( - SAGE_LOCAL, "bin", "cygSingular-*.dll")))[-1] -else: - if UNAME == "Darwin": - extension = "dylib" - else: - extension = "so" - # library name changed from libsingular to libSingular btw 3.x and 4.x - SINGULAR_SO = SAGE_LOCAL+"/lib/libSingular."+extension +# On Debian it's libsingular-Singular so try that as well +SINGULAR_SO = _get_shared_lib_filename('Singular', 'singular-Singular') +var('SINGULAR_SO', SINGULAR_SO) -_add_variable_or_fallback('SINGULAR_SO', SINGULAR_SO) +# locate libgap shared object +GAP_SO= _get_shared_lib_filename('gap','') +var('GAP_SO', GAP_SO) # post process if ' ' in DOT_SAGE: @@ -197,7 +280,7 @@ def _add_variable_or_fallback(key, fallback, force=False): # to have a space in it. Fortunately, users also have # write privileges to c:\cygwin\home, so we just put # .sage there. - _add_variable_or_fallback('DOT_SAGE', "/home/.sage", force=True) + var('DOT_SAGE', "/home/.sage", force=True) else: print("Your home directory has a space in it. This") print("will probably break some functionality of Sage. E.g.,") @@ -216,16 +299,6 @@ def _add_variable_or_fallback(key, fallback, force=False): if m: CYGWIN_VERSION = tuple(map(int, m.group(1).split('.'))) - del m - del _uname, re - -# things that need DOT_SAGE -_add_variable_or_fallback('PYTHON_EGG_CACHE', opj('$DOT_SAGE', '.python-eggs')) -_add_variable_or_fallback('SAGE_STARTUP_FILE', opj('$DOT_SAGE', 'init.sage')) - -# delete temporary variables used for setting up sage.env -del opj, os, socket, version, site - def sage_include_directories(use_sources=False): """ @@ -243,35 +316,37 @@ def sage_include_directories(use_sources=False): EXAMPLES: - Expected output while using sage - - :: + Expected output while using Sage:: sage: import sage.env sage: sage.env.sage_include_directories() ['.../include', + '.../python.../site-packages/sage/ext', '.../include/python...', - '.../python.../numpy/core/include', - '.../python.../site-packages', - '.../python.../site-packages/sage/ext'] + '.../python.../numpy/core/include'] + + To check that C/C++ files are correctly found, we verify that we can + always find the include file ``sage/cpython/cython_metaclass.h``, + with both values for ``use_sources``:: + + sage: file = os.path.join("sage", "cpython", "cython_metaclass.h") + sage: dirs = sage.env.sage_include_directories(use_sources=True) + sage: any(os.path.isfile(os.path.join(d, file)) for d in dirs) + True + sage: dirs = sage.env.sage_include_directories(use_sources=False) + sage: any(os.path.isfile(os.path.join(d, file)) for d in dirs) + True """ - import os, numpy + import numpy import distutils.sysconfig - opj = os.path.join - - include_directories = [SAGE_INC, - distutils.sysconfig.get_python_inc(), - numpy.get_include()] - - if use_sources : - include_directories.extend([SAGE_SRC, - opj(SAGE_SRC, 'sage', 'ext')]) - else: - include_directories.extend([SAGE_LIB, - opj(SAGE_LIB, 'sage', 'ext')]) + TOP = SAGE_SRC if use_sources else SAGE_LIB - return include_directories + return [SAGE_INC, + TOP, + os.path.join(TOP, 'sage', 'ext'), + distutils.sysconfig.get_python_inc(), + numpy.get_include()] def cython_aliases(): diff --git a/src/sage/ext/cdefs.pxi b/src/sage/ext/cdefs.pxi deleted file mode 100644 index ac215196007..00000000000 --- a/src/sage/ext/cdefs.pxi +++ /dev/null @@ -1,20 +0,0 @@ -""" -Deprecated include file - -TESTS:: - - sage: cython('include "sage/ext/cdefs.pxi"') - doctest:...: DeprecationWarning: the file "cdefs.pxi" is deprecated, cimport the functions that you need - See http://trac.sagemath.org/23855 for details. -""" - -from sage.misc.superseded import deprecation -deprecation(23855, 'the file "cdefs.pxi" is deprecated, cimport the functions that you need') - - -from libc.stdio cimport * -from libc.string cimport strlen, strcpy, memset, memcpy, memcmp - -from libc.math cimport sqrt, frexp, ldexp - -from sage.libs.gmp.all cimport * diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 2a32e093f33..bcebd37d985 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -1125,7 +1125,8 @@ cdef class ExpressionConstant(Expression): r""" An Expression that represents an arbitrary constant. - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb(3)) @@ -1192,7 +1193,8 @@ cdef class ExpressionVariable(Expression): r""" An Expression that represents a variable. - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb.var(x)) @@ -1258,7 +1260,8 @@ cdef class ExpressionCall(Expression): r""" An Expression that represents a function call. - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb.call(sin, x)) @@ -1346,7 +1349,8 @@ cdef class ExpressionIPow(Expression): r""" A power Expression with an integer exponent. - EXAMPLES: + EXAMPLES:: + sage: from sage.ext.fast_callable import ExpressionTreeBuilder sage: etb = ExpressionTreeBuilder(vars=(x,)) sage: type(etb.var('x')^17) @@ -1605,7 +1609,7 @@ class IntegerPowerFunction(object): sage: square(I) -1 sage: square(RIF(-1, 1)).str(style='brackets') - '[0.00000000000000000 .. 1.0000000000000000]' + '[0.0000000000000000 .. 1.0000000000000000]' sage: IntegerPowerFunction(-1) (^(-1)) sage: IntegerPowerFunction(-1)(22/7) @@ -2500,4 +2504,3 @@ cdef class Wrapper: if isinstance(op, tuple) and op[0] == 'py_call': py_calls.append(op[1]) return py_calls - diff --git a/src/sage/ext/memory_allocator.pxd b/src/sage/ext/memory_allocator.pxd index bea992477d9..2e1fd267c51 100644 --- a/src/sage/ext/memory_allocator.pxd +++ b/src/sage/ext/memory_allocator.pxd @@ -1,14 +1,131 @@ cimport cython +from libc.stdint cimport uintptr_t + + +cdef extern from *: + int unlikely(int) nogil # defined by Cython + + +cdef inline void* align(void* ptr, size_t alignment): + """ + Round up ``ptr`` to the nearest multiple of ``alignment``, which + must be a power of 2 + """ + cdef uintptr_t x = ptr + x = (x + alignment - 1) & ~(alignment - 1) + return x + @cython.final cdef class MemoryAllocator: cdef size_t n cdef size_t size - cdef void ** pointers - cdef void * static_pointers[16] # If n <= 16, store pointers here + cdef void** pointers + cdef void* static_pointers[16] # If n <= 16, store pointers here + + cdef void* malloc(self, size_t size) except? NULL + cdef void* calloc(self, size_t nmemb, size_t size) except? NULL + cdef void* allocarray(self, size_t nmemb, size_t size) except? NULL + cdef void* realloc(self, void* ptr, size_t size) except? NULL + cdef void* reallocarray(self, void* ptr, size_t nmemb, + size_t size) except? NULL - cdef void * malloc(self, size_t size) except? NULL - cdef void * calloc(self, size_t nmemb, size_t size) except? NULL - cdef void * allocarray(self, size_t nmemb, size_t size) except? NULL cdef int resize(self, size_t new_size) except -1 - cdef inline int enlarge_if_needed(self) except -1 + cdef void** find_pointer(self, void* ptr) except NULL + + cdef inline int enlarge_if_needed(self) except -1: + r""" + Enlarge the list of pointers if needed such that there is at + least one free entry. + """ + if unlikely(self.n >= self.size): + return self.resize(self.size * 2) + + cdef inline void* aligned_malloc(self, size_t alignment, + size_t size) except? NULL: + r""" + Returns new aligned pointer. Stores it to be automatically freed later. + + Alignment must be a power of two. + + .. NOTE:: + + If you want to allocate multiple (small) aligned arrays with the + same alignment and really want to be memory efficient, you can + allocate one large aligned array instead. + + TESTS:: + + sage: cython(''' + ....: from sage.ext.memory_allocator cimport MemoryAllocator + ....: cdef MemoryAllocator mem = MemoryAllocator() + ....: cdef void* ptr + ....: for i in range(12): + ....: ptr = mem.aligned_malloc(2**i, 4048) + ....: assert ptr == ( ptr) & ~(2**i-1) + ....: ''') + """ + cdef size_t extra = alignment - 1 + return align(self.malloc(size + extra), alignment) + + cdef inline void* aligned_calloc(self, size_t alignment, size_t nmemb, + size_t size) except? NULL: + r""" + Returns new aligned pointer. Stores it to be automatically freed later. + + Alignment must be a power of two. + + .. NOTE:: + + If you want to allocate multiple (small) aligned arrays with the + same alignment and really want to be memory efficient, you can + allocate one large aligned array instead. + + TESTS:: + + sage: cython(''' + ....: from sage.ext.memory_allocator cimport MemoryAllocator + ....: cdef MemoryAllocator mem = MemoryAllocator() + ....: cdef void* ptr + ....: for i in range(12): + ....: ptr = mem.aligned_calloc(2**i, i, 2**i) + ....: assert ptr == ( ptr) & ~(2**i-1) + ....: ''') + """ + # Find extra such that (nmemb + extra) * size >= nmemb * size + alignment - 1 + # ⇔ extra * size >= alignment - 1 + # ⇔ extra >= ceil( (alignment - 1) / size) + # ⇔ extra >= (alignment - 1 + size - 1) // size + cdef size_t extra = (alignment + size - 2) // size + return align(self.calloc(nmemb + extra, size), alignment) + + cdef inline void* aligned_allocarray(self, size_t alignment, size_t nmemb, + size_t size) except? NULL: + r""" + Returns new aligned pointer. Stores it to be automatically freed later. + + Alignment must be a power of two. + + .. NOTE:: + + If you want to allocate multiple (small) aligned arrays with the + same alignment and really want to be memory efficient, you can + allocate one large aligned array instead. + + TESTS:: + + sage: cython(''' + ....: from sage.ext.memory_allocator cimport MemoryAllocator + ....: cdef MemoryAllocator mem = MemoryAllocator() + ....: cdef void* ptr + ....: for i in range(12): + ....: ptr = mem.aligned_allocarray(2**i, i, 2**i) + ....: assert ptr == ( ptr) & ~(2**i-1) + ....: ''') + """ + # Find extra such that (nmemb + extra) * size >= nmemb * size + alignment - 1 + # ⇔ extra * size >= alignment - 1 + # ⇔ extra >= ceil( (alignment - 1) / size) + # ⇔ extra >= (alignment - 1 + size - 1) // size + cdef size_t extra = (alignment + size - 2) // size + return align(self.allocarray(nmemb + extra, size), alignment) diff --git a/src/sage/ext/memory_allocator.pyx b/src/sage/ext/memory_allocator.pyx index 4015429f655..a5609cf40b3 100644 --- a/src/sage/ext/memory_allocator.pyx +++ b/src/sage/ext/memory_allocator.pyx @@ -1,8 +1,5 @@ from cysignals.memory cimport * -cdef extern from *: - int unlikely(int) nogil # Defined by Cython - cdef class MemoryAllocator: r""" @@ -15,10 +12,16 @@ cdef class MemoryAllocator: ....: ''' ....: from sage.ext.memory_allocator cimport MemoryAllocator ....: cdef MemoryAllocator mem = MemoryAllocator() + ....: cdef void* ptr ....: for n in range(100): - ....: mem.malloc(n) + ....: ptr = mem.malloc(n) + ....: mem.realloc(ptr, 2*n) ....: mem.calloc(n, n) - ....: mem.allocarray(n, n) + ....: ptr = mem.allocarray(n, n) + ....: mem.reallocarray(ptr, n + 1, n) + ....: mem.aligned_malloc(32, (n//32 + 1)*32) + ....: mem.aligned_calloc(16, n, 16) + ....: mem.aligned_allocarray(8, n, 8) ....: ''') """ def __cinit__(self): @@ -50,52 +53,106 @@ cdef class MemoryAllocator: cdef size_t i if self.pointers == self.static_pointers: # Case 1: allocate pointers for the first time - self.pointers = check_allocarray(new_size, sizeof(void*)) + self.pointers = check_allocarray(new_size, sizeof(void*)) for i in range(self.n): self.pointers[i] = self.static_pointers[i] else: # Case 2: resize pointers - self.pointers = check_reallocarray(self.pointers, new_size, sizeof(void*)) + self.pointers = check_reallocarray(self.pointers, new_size, sizeof(void*)) self.size = new_size - cdef inline int enlarge_if_needed(self) except -1: + cdef void** find_pointer(self, void* ptr) except NULL: r""" - Enlarge the list of pointers if needed such that there is at - least one free entry. + Return the address in the list of stored pointers where ``ptr`` + is stored. If ``ptr`` is not found in the existing pointers and + ``ptr`` is not ``NULL``, then an exception is raised. If ``ptr`` + is ``NULL``, then we simply add ``NULL`` as an additional + pointer and return the address of that. """ - if unlikely(self.n >= self.size): - return self.resize(self.size * 2) + cdef size_t i = 0 + for i in range(self.n): + if self.pointers[i] == ptr: + return &self.pointers[i] + if ptr != NULL: + raise ValueError("given pointer not found in MemoryAllocator") + self.enlarge_if_needed() + addr = &self.pointers[self.n] + self.n += 1 + return addr - cdef void * malloc(self, size_t size) except? NULL: + cdef void* malloc(self, size_t size) except? NULL: r""" Returns a new pointer and stores it to be automatically freed later. """ self.enlarge_if_needed() - cdef void * val = check_malloc(size) + cdef void* val = check_malloc(size) self.pointers[self.n] = val self.n += 1 return val - cdef void * calloc(self, size_t nmemb, size_t size) except? NULL: + cdef void* calloc(self, size_t nmemb, size_t size) except? NULL: r""" Returns a new pointer and stores it to be automatically freed later. """ self.enlarge_if_needed() - cdef void * val = check_calloc(nmemb, size) + cdef void* val = check_calloc(nmemb, size) self.pointers[self.n] = val self.n += 1 return val - cdef void * allocarray(self, size_t nmemb, size_t size) except? NULL: + cdef void* allocarray(self, size_t nmemb, size_t size) except? NULL: r""" Returns a new pointer and stores it to be automatically freed later. """ self.enlarge_if_needed() - cdef void * val = check_allocarray(nmemb, size) + cdef void* val = check_allocarray(nmemb, size) self.pointers[self.n] = val self.n += 1 return val + cdef void* realloc(self, void* ptr, size_t size) except? NULL: + r""" + Re-allocates `ptr` and automatically frees it later. + + TESTS:: + + sage: cython(''' + ....: from sage.ext.memory_allocator cimport MemoryAllocator + ....: def test_realloc_good(): + ....: cdef MemoryAllocator mem = MemoryAllocator() + ....: ptr = mem.malloc(20) + ....: mem.realloc(ptr, 21) + ....: def test_realloc_NULL(): + ....: cdef MemoryAllocator mem = MemoryAllocator() + ....: mem.realloc(NULL, 21) + ....: def test_realloc_bad(): + ....: cdef MemoryAllocator mem = MemoryAllocator() + ....: cdef MemoryAllocator mem2 = MemoryAllocator() + ....: ptr = mem.malloc(20) + ....: mem2.realloc(ptr, 21) + ....: ''') + sage: test_realloc_good() + sage: test_realloc_NULL() + sage: test_realloc_bad() + Traceback (most recent call last): + ... + ValueError: given pointer not found in MemoryAllocator + """ + cdef void** addr = self.find_pointer(ptr) + cdef void* val = check_realloc(ptr, size) + addr[0] = val + return val + + cdef void* reallocarray(self, void* ptr, size_t nmemb, + size_t size) except? NULL: + r""" + Re-allocates `ptr` and automatically frees it later. + """ + cdef void** addr = self.find_pointer(ptr) + cdef void* val = check_reallocarray(ptr, nmemb, size) + addr[0] = val + return val + def __dealloc__(self): r""" Free the allocated resources diff --git a/src/sage/ext/stdsage.pxi b/src/sage/ext/stdsage.pxi deleted file mode 100644 index 5c573beef6a..00000000000 --- a/src/sage/ext/stdsage.pxi +++ /dev/null @@ -1,34 +0,0 @@ -""" -Deprecated C helper code for Cython modules - -TESTS:: - - sage: cython('include "sage/ext/stdsage.pxi"') - doctest:...: DeprecationWarning: the file "stdsage.pxi" is deprecated, cimport the functions that you need - See http://trac.sagemath.org/23855 for details. -""" -#***************************************************************************** -# Copyright (C) 2015 Jeroen Demeyer -# -# 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/ -#***************************************************************************** - -from sage.misc.superseded import deprecation -deprecation(23855, 'the file "stdsage.pxi" is deprecated, cimport the functions that you need') - - -include "memory.pxi" - -from cysignals.memory cimport sig_malloc as sage_malloc -from cysignals.memory cimport sig_realloc as sage_realloc -from cysignals.memory cimport sig_calloc as sage_calloc -from cysignals.memory cimport sig_free as sage_free -from cysignals.memory cimport ( - check_allocarray, check_reallocarray, - check_malloc, check_realloc, check_calloc) - -from sage.ext.stdsage cimport PY_NEW, HAS_DICTIONARY -from sage.ext.memory import init_memory_functions diff --git a/src/sage/finance/markov_multifractal_cython.pyx b/src/sage/finance/markov_multifractal_cython.pyx index 7dc3a263642..59adc8ecf7d 100644 --- a/src/sage/finance/markov_multifractal_cython.pyx +++ b/src/sage/finance/markov_multifractal_cython.pyx @@ -28,7 +28,8 @@ def simulations(Py_ssize_t n, Py_ssize_t k, OUTPUT: list of lists - EXAMPLES: + EXAMPLES:: + sage: set_random_seed(0) sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,1.0,0.95,3) sage: import sage.finance.markov_multifractal_cython @@ -71,10 +72,3 @@ def simulations(Py_ssize_t n, Py_ssize_t k, S.append(t) return S - - - - - - - diff --git a/src/sage/functions/exp_integral.py b/src/sage/functions/exp_integral.py index 760c03a88d8..113c1db293c 100644 --- a/src/sage/functions/exp_integral.py +++ b/src/sage/functions/exp_integral.py @@ -51,6 +51,7 @@ from sage.symbolic.function import BuiltinFunction from sage.symbolic.expression import Expression from sage.structure.all import parent +from sage.misc.latex import latex from sage.libs.mpmath import utils as mpmath_utils mpmath_utils_call = mpmath_utils.call # eliminate some overhead in _evalf_ @@ -157,7 +158,6 @@ def __init__(self): """ BuiltinFunction.__init__(self, "exp_integral_e", nargs=2, - latex_name=r'exp_integral_e', conversions=dict(maxima='expintegral_e', sympy='expint')) @@ -223,6 +223,17 @@ def _evalf_(self, n, z, parent=None, algorithm=None): import mpmath return mpmath_utils.call(mpmath.expint, n, z, parent=parent) + def _print_latex_(self, n, z): + """ + Custom ``_print_latex_`` method. + + EXAMPLES:: + + sage: latex(exp_integral_e(1, -x - 1)) + E_{1}\left(-x - 1\right) + """ + return r"E_{{{}}}\left({}\right)".format(latex(n), latex(z)) + def _derivative_(self, n, z, diff_param=None): """ If `n` is an integer strictly larger than 0, then the derivative of @@ -310,7 +321,6 @@ def __init__(self): """ BuiltinFunction.__init__(self, "exp_integral_e1", nargs=1, - latex_name=r'exp_integral_e1', conversions=dict(maxima='expintegral_e1', sympy='E1')) @@ -327,6 +337,18 @@ def _evalf_(self, z, parent=None, algorithm=None): import mpmath return mpmath_utils_call(mpmath.e1, z, parent=parent) + + def _print_latex_(self, z): + """ + Custom ``_print_latex_`` method. + + EXAMPLES:: + + sage: latex(exp_integral_e1(2)) + E_{1}\left(2\right) + """ + return r"E_{{1}}\left({}\right)".format(latex(z)) + def _derivative_(self, z, diff_param=None): """ The derivative of `E_1(z)` is `-e^{-z}/z`. diff --git a/src/sage/functions/gamma.py b/src/sage/functions/gamma.py index 119de6b15b0..8f0ae04e929 100644 --- a/src/sage/functions/gamma.py +++ b/src/sage/functions/gamma.py @@ -494,7 +494,7 @@ def __init__(self): :class:`Function_gamma_inc` """ BuiltinFunction.__init__(self, "gamma_inc_lower", nargs=2, latex_name=r"\gamma", - conversions={'maxima':'gamma_greek', 'mathematica':'Gamma', + conversions={'maxima':'gamma_greek', 'maple':'GAMMA', 'sympy':'lowergamma', 'giac':'igamma'}) def _eval_(self, x, y): @@ -599,6 +599,24 @@ def _derivative_(self, x, y, diff_param=None): else: return exp(-y)*y**(x - 1) + def _mathematica_init_evaled_(self, *args): + r""" + EXAMPLES:: + + sage: gamma_inc_lower(4/3, 1)._mathematica_() # indirect doctest, optional - mathematica + Gamma[4/3, 0, 1] + """ + args_mathematica = [] + for a in args: + if isinstance(a, str): + args_mathematica.append(a) + elif hasattr(a, '_mathematica_init_'): + args_mathematica.append(a._mathematica_init_()) + else: + args_mathematica.append(str(a)) + x, z = args_mathematica + return "Gamma[%s,0,%s]" % (x, z) + # synonym. gamma_inc_lower = Function_gamma_inc_lower() @@ -684,6 +702,30 @@ def gamma(a, *args, **kwds): # two functions with different number of arguments and the same name symbol_table['functions']['gamma'] = gamma + +def _mathematica_gamma(*args): + r""" + EXAMPLES:: + + sage: gamma(4/3)._mathematica_().sage() # indirect doctest, optional - mathematica + gamma(4/3) + sage: gamma(4/3, 1)._mathematica_().sage() # indirect doctest, optional - mathematica + gamma(4/3, 1) + sage: mathematica('Gamma[4/3, 0, 1]').sage() # indirect doctest, optional - mathematica + gamma(4/3) - gamma(4/3, 1) + """ + if not args or len(args) > 3: + raise TypeError("Mathematica function Gamma takes 1 to 3 arguments" + " (%s given)" % (len(args))) + elif len(args) == 3: + return gamma_inc(args[0], args[1]) - gamma_inc(args[0], args[2]) + else: + return gamma(*args) + + +register_symbol(_mathematica_gamma, dict(mathematica='Gamma')) + + class Function_psi1(GinacFunction): def __init__(self): r""" diff --git a/src/sage/functions/generalized.py b/src/sage/functions/generalized.py index 62e4bce15aa..ffc9e078097 100644 --- a/src/sage/functions/generalized.py +++ b/src/sage/functions/generalized.py @@ -316,7 +316,7 @@ def __init__(self): - ``x`` - a real number or a symbolic expression - EXAMPLES: + EXAMPLES:: sage: unit_step(-1) 0 @@ -405,7 +405,7 @@ def __init__(self): r""" The sgn function, ``sgn(x)``. - EXAMPLES: + EXAMPLES:: sage: sgn(-1) -1 diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index 0f817a74b4c..e4f723dc297 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -23,6 +23,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + class Function_exp(GinacFunction): r""" The exponential function, `\exp(x) = e^x`. @@ -232,7 +233,7 @@ def __init__(self): """ GinacFunction.__init__(self, 'log', latex_name=r'\log', conversions=dict(maxima='log', fricas='log', - mathematica='Log')) + mathematica='Log', giac='ln')) ln = function_log = Function_log1() @@ -247,6 +248,13 @@ class Function_log2(GinacFunction): sage: from sage.functions.log import logb sage: logb(1000,10) 3 + + TESTS:: + + sage: logb(7, 2) + log(7)/log(2) + sage: logb(int(7), 2) + log(7)/log(2) """ def __init__(self): """ @@ -1274,11 +1282,11 @@ def _evalf_(self, z, m, parent=None, algorithm=None): return harmonic_m1._evalf_(z, parent, algorithm) from sage.functions.transcendental import zeta, hurwitz_zeta - return zeta(m) - hurwitz_zeta(m,z+1) + return zeta(m) - hurwitz_zeta(m, z + 1) def _maxima_init_evaled_(self, n, z): """ - EXAMPLES: + EXAMPLES:: sage: maxima_calculus(harmonic_number(x,2)) gen_harmonic_number(2,_SAGE_VAR_x) @@ -1448,7 +1456,7 @@ def _derivative_(self, z, diff_param=None): 1/6*pi^2 - harmonic_number(x, 2) """ from sage.functions.transcendental import zeta - return zeta(2)-harmonic_number(z,2) + return zeta(2) - harmonic_number(z, 2) def _print_latex_(self, z): """ diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 386ba4df02e..263f51191d1 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -602,7 +602,7 @@ def _eval_special_values_(self, n, x): Values known for special values of x. For details see [AS1964]_ 22.4 (p. 777) - EXAMPLES: + EXAMPLES:: sage: var('n') n diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index c6fe2aef5f3..91c32415461 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1860,11 +1860,11 @@ def _print_latex_(self, ex, var, to, direction=''): sage: t = var('t') sage: latex(limit(exp_integral_e(1/2, I*t - I*x)*sqrt(-t + x),t=x,dir='-')) - \lim_{t \to x^-}\, \sqrt{-t + x} exp_integral_e\left(\frac{1}{2}, i \, t - i \, x\right) + \lim_{t \to x^-}\, \sqrt{-t + x} E_{\frac{1}{2}}\left(i \, t - i \, x\right) sage: latex(limit(exp_integral_e(1/2, I*t - I*x)*sqrt(-t + x),t=x,dir='+')) - \lim_{t \to x^+}\, \sqrt{-t + x} exp_integral_e\left(\frac{1}{2}, i \, t - i \, x\right) + \lim_{t \to x^+}\, \sqrt{-t + x} E_{\frac{1}{2}}\left(i \, t - i \, x\right) sage: latex(limit(exp_integral_e(1/2, I*t - I*x)*sqrt(-t + x),t=x)) - \lim_{t \to x}\, \sqrt{-t + x} exp_integral_e\left(\frac{1}{2}, i \, t - i \, x\right) + \lim_{t \to x}\, \sqrt{-t + x} E_{\frac{1}{2}}\left(i \, t - i \, x\right) """ if repr(direction) == 'minus': dir_str = '^-' diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index c763045c533..a66a0a461b1 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -2213,12 +2213,12 @@ def _is_NE(self, a, b, p1_support, p2_support, M1, M2): False """ # Check that supports are obeyed - if not(all([a[i] > 0 for i in p1_support]) and - all([b[j] > 0 for j in p2_support]) and - all([a[i] == 0 for i in range(len(a)) - if i not in p1_support]) and - all([b[j] == 0 for j in range(len(b)) - if j not in p2_support])): + if not(all(a[i] > 0 for i in p1_support) and + all(b[j] > 0 for j in p2_support) and + all(a[i] == 0 for i in range(len(a)) + if i not in p1_support) and + all(b[j] == 0 for j in range(len(b)) + if j not in p2_support)): return False # Check that have pair of best responses diff --git a/src/sage/games/all.py b/src/sage/games/all.py index 721408b737c..d8066fd6190 100644 --- a/src/sage/games/all.py +++ b/src/sage/games/all.py @@ -1,5 +1,20 @@ +""" +Test for deprecations of imports into global namespace:: + + sage: backtrack_all + doctest:warning...: + DeprecationWarning: + Importing backtrack_all from here is deprecated. If you need to use it, please import it directly from sage.games.sudoku_backtrack + See https://trac.sagemath.org/27066 for details. + ... +""" from __future__ import absolute_import +from sage.misc.lazy_import import lazy_import + +lazy_import("sage.games.sudoku_backtrack", 'backtrack_all', deprecation=27066) + from .sudoku import Sudoku, sudoku -from .sudoku_backtrack import backtrack_all from .hexad import Minimog + +del absolute_import diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 50fa1d6b823..5893711d30b 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -189,7 +189,10 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** + +# Use python-3.x versions of print() and range(). from __future__ import print_function +from six.moves import range import collections import copy @@ -201,8 +204,8 @@ from sage.geometry.polyhedron.constructor import Polyhedron from sage.geometry.polyhedron.base import is_Polyhedron from sage.geometry.hasse_diagram import lattice_from_incidences -from sage.geometry.toric_lattice import ToricLattice, is_ToricLattice, \ - is_ToricLatticeQuotient +from sage.geometry.toric_lattice import (ToricLattice, is_ToricLattice, + is_ToricLatticeQuotient) from sage.geometry.toric_plotter import ToricPlotter, label_list from sage.graphs.digraph import DiGraph from sage.matrix.all import column_matrix, matrix, MatrixSpace @@ -211,9 +214,9 @@ from sage.rings.all import QQ, RR, ZZ from sage.structure.all import SageObject, parent from sage.structure.richcmp import richcmp_method, richcmp -from sage.libs.ppl import C_Polyhedron, Generator_System, Constraint_System, \ - Linear_Expression, ray as PPL_ray, point as PPL_point, \ - Poly_Con_Relation +from ppl import (C_Polyhedron, Generator_System, Constraint_System, + Linear_Expression, ray as PPL_ray, point as PPL_point, + Poly_Con_Relation) from sage.geometry.integral_points import parallelotope_points @@ -450,7 +453,7 @@ def Cone(rays, lattice=None, check=True, normalize=True): def _Cone_from_PPL(cone, lattice, original_rays=None): r""" - Construct a cone from a :class:`~sage.libs.ppl.Polyhedron`. + Construct a cone from a :class:`~ppl.polyhedron.Polyhedron`. This is a private function and not intended to be exposed to the end user. It is used internally by :func:`Cone` and in @@ -458,7 +461,7 @@ def _Cone_from_PPL(cone, lattice, original_rays=None): INPUT: - - ``cone`` -- a :class:`~sage.libs.ppl.Polyhedron` having the + - ``cone`` -- a :class:`~ppl.polyhedron.Polyhedron` having the origin as its single point. - ``lattice`` -- :class:`ToricLattice @@ -1365,9 +1368,10 @@ class ConvexRationalPolyhedralCone(IntegralRayCollection, In both cases, the following keyword parameter may be specified in addition: - ``PPL`` -- either ``None`` (default) or a - :class:`~sage.libs.ppl.C_Polyhedron` representing the cone. This + :class:`~ppl.polyhedron.C_Polyhedron` representing the cone. This serves only to cache the polyhedral data if you know it - already. The polyhedron will be set immutable. + already. The constructor does not make a copy so the ``PPL`` object + should not be modified afterwards. OUTPUT: @@ -1427,7 +1431,6 @@ def __init__(self, rays=None, lattice=None, ambient.lattice()) if not PPL is None: self._PPL_C_Polyhedron = PPL - self._PPL_C_Polyhedron.set_immutable() def _sage_input_(self, sib, coerced): """ @@ -1449,7 +1452,7 @@ def _PPL_cone(self): OUTPUT: - A :class:`~sage.libs.ppl.C_Polyhedron` representing the cone. + A :class:`~ppl.polyhedron.C_Polyhedron` representing the cone. EXAMPLES:: @@ -1479,7 +1482,6 @@ def _PPL_cone(self): for r in self.rays(): gs.insert( PPL_ray(Linear_Expression(r,0)) ) self._PPL_C_Polyhedron = C_Polyhedron(gs) - self._PPL_C_Polyhedron.set_immutable() return self._PPL_C_Polyhedron def __contains__(self, point): @@ -2956,7 +2958,7 @@ def is_isomorphic(self, other): sage: cone1 = Cone([(1,0), (0, 3)]) sage: m = matrix(ZZ, [(1, -5), (-1, 4)]) # a GL(2,ZZ)-matrix - sage: cone2 = Cone([m*r for r in cone1.rays()]) + sage: cone2 = Cone( m*r for r in cone1.rays() ) sage: cone1.is_isomorphic(cone2) True @@ -3341,7 +3343,7 @@ def strict_quotient(self): L._latex_name, L._latex_dual_name) else: S = ZZ**Q.dimension() - rays = [Q(ray) for ray in self.rays() if not Q(ray).is_zero()] + rays = ( Q(ray) for ray in self if not Q(ray).is_zero() ) quotient = Cone(rays, S, check=False) quotient._is_strictly_convex = True return quotient @@ -3467,7 +3469,7 @@ def solid_restriction(self): # have at least one non-zero coordinate; otherwise they would # lie outside of the span of our cone. And they don't, because # they generate the cone. - rays = [ S(subL.coordinates(ray)) for ray in self ] + rays = ( S(subL.coordinates(ray)) for ray in self ) return Cone(rays, lattice=S, check=False) def _split_ambient_lattice(self): @@ -3507,7 +3509,7 @@ def _split_ambient_lattice(self): n = N.dimension() basis = self.rays().basis() r = len(basis) - Nsigma = matrix(ZZ, r, n, [N.coordinates(v) for v in basis]) + Nsigma = matrix(ZZ, r, n, ( N.coordinates(v) for v in basis )) D, U, V = Nsigma.smith_form() # D = U*N*V <=> N = Uinv*D*Vinv basis = (V.inverse() * N.basis_matrix()).rows() # spanned lattice N_sigma @@ -3746,7 +3748,7 @@ def orthogonal_sublattice(self, *args, **kwds): except AttributeError: N = self.lattice() basis = self.rays().basis() - Nsigma = column_matrix(ZZ, [N.coordinates(v) for v in basis]) + Nsigma = column_matrix(ZZ, (N.coordinates(v) for v in basis)) D, U, V = Nsigma.smith_form() # D = U * Nsigma * V M = self.dual_lattice() self._orthogonal_sublattice = M.submodule_with_basis( @@ -4019,14 +4021,14 @@ def semigroup_generators(self): sage: A.elementary_divisors() [1, 1, 1, 0] sage: cone3d = Cone([(3,0,-1), (1,-1,0), (0,1,0), (0,0,1)]) - sage: rays = [ A*vector(v) for v in cone3d.rays() ] + sage: rays = ( A*vector(v) for v in cone3d.rays() ) sage: gens = Cone(rays).semigroup_generators(); sorted(gens) [N(-2, -1, 0, 17), N(0, 1, -2, 0), N(1, -1, 1, 15), N(3, -4, 5, 45), N(3, 0, 1, -2)] - sage: set(map(tuple,gens)) == set([ tuple(A*r) for r in cone3d.semigroup_generators() ]) + sage: set(map(tuple,gens)) == set( tuple(A*r) for r in cone3d.semigroup_generators() ) True TESTS:: @@ -4072,16 +4074,16 @@ def semigroup_generators(self): origin = self.nrays() # last one in pc pc = PointConfiguration(tuple(self.rays()) + (N(0),), star=origin) triangulation = pc.triangulate() - subcones = [ Cone([self.ray(i) for i in simplex if i!=origin], + subcones = ( Cone(( self.ray(i) for i in simplex if i!=origin ), lattice=N, check=False) - for simplex in triangulation ] + for simplex in triangulation ) gens = set() for cone in subcones: gens.update(cone.semigroup_generators()) return tuple(gens) gens = list(parallelotope_points(self.rays(), N)) + list(self.rays()) - gens = [v for v in gens if gcd(v) == 1] + gens = ( v for v in gens if gcd(v) == 1 ) return PointCollection(gens, N) @cached_method @@ -4597,7 +4599,7 @@ def discrete_complementarity_set(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=6) sage: dcs = K.discrete_complementarity_set() - sage: sum([ (s*x).abs() for (x,s) in dcs ]) + sage: sum( (s*x).abs() for (x,s) in dcs ) 0 """ # Return an immutable tuple instead of a mutable list because @@ -4709,7 +4711,7 @@ def lyapunov_like_basis(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=8) sage: LL = K.lyapunov_like_basis() - sage: all([ L.is_lyapunov_like_on(K) for L in LL ]) + sage: all( L.is_lyapunov_like_on(K) for L in LL ) True The Lyapunov-like transformations on a cone and its dual are @@ -4719,10 +4721,10 @@ def lyapunov_like_basis(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=8) sage: LL1 = K.lyapunov_like_basis() - sage: LL2 = [L.transpose() for L in K.dual().lyapunov_like_basis()] + sage: LL2 = (L.transpose() for L in K.dual().lyapunov_like_basis()) sage: V = VectorSpace(K.lattice().base_field(), K.lattice_dim()^2) - sage: LL1_vecs = [ V(m.list()) for m in LL1 ] - sage: LL2_vecs = [ V(m.list()) for m in LL2 ] + sage: LL1_vecs = ( V(m.list()) for m in LL1 ) + sage: LL2_vecs = ( V(m.list()) for m in LL2 ) sage: V.span(LL1_vecs) == V.span(LL2_vecs) True @@ -4733,10 +4735,10 @@ def lyapunov_like_basis(self): sage: K = random_cone(max_ambient_dim=4) sage: LL = K.lyapunov_like_basis() sage: W = VectorSpace(K.lattice().base_field(), K.lattice_dim()**2) - sage: LL_W = W.span([ W(m.list()) for m in LL ]) - sage: brackets = [ W((L1*L2 - L2*L1).list()) for L1 in LL - ....: for L2 in LL ] - sage: all([ b in LL_W for b in brackets ]) + sage: LL_W = W.span( W(m.list()) for m in LL ) + sage: brackets = ( W((L1*L2 - L2*L1).list()) for L1 in LL + ....: for L2 in LL ) + sage: all( b in LL_W for b in brackets ) True """ # Matrices are not vectors in Sage, so we have to convert them @@ -4747,12 +4749,12 @@ def lyapunov_like_basis(self): # These tensor products contain a basis for the orthogonal # complement of the Lyapunov-like transformations on this cone. - tensor_products = [ s.tensor_product(x) - for (x,s) in self.discrete_complementarity_set() ] + tensor_products = ( s.tensor_product(x) + for (x,s) in self.discrete_complementarity_set() ) # Convert those tensor products to long vectors. W = VectorSpace(F, n**2) - perp_vectors = [ W(tp.list()) for tp in tensor_products ] + perp_vectors = ( W(tp.list()) for tp in tensor_products ) # Now find the Lyapunov-like transformations (as long vectors). LL_vectors = W.span(perp_vectors).complement() @@ -4902,7 +4904,7 @@ def lyapunov_rank(self): sage: K1 = random_cone(max_ambient_dim=8) sage: n = K1.lattice_dim() sage: A = random_matrix(QQ, n, algorithm='unimodular') - sage: K2 = Cone( [ A*r for r in K1.rays() ], lattice=K1.lattice()) + sage: K2 = Cone( ( A*r for r in K1 ), lattice=K1.lattice()) sage: K1.lyapunov_rank() == K2.lyapunov_rank() True @@ -4965,7 +4967,7 @@ def lyapunov_rank(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=8) sage: L = ToricLattice(K.lattice_dim() + 1) - sage: K = Cone([ r.list() + [0] for r in K.rays() ], lattice=L) + sage: K = Cone([ r.list() + [0] for r in K ], lattice=L) sage: K.lyapunov_rank() >= K.lattice_dim() True """ @@ -5042,9 +5044,9 @@ def random_element(self, ring=ZZ): sage: set_random_seed() sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) - sage: all([ x >= 0 for x in K.random_element() ]) + sage: all( x >= 0 for x in K.random_element() ) True - sage: all([ x >= 0 for x in K.random_element(ring=QQ) ]) + sage: all( x >= 0 for x in K.random_element(ring=QQ) ) True If ``ring`` is not ``ZZ`` or ``QQ``, an error is raised:: @@ -5097,9 +5099,9 @@ def random_element(self, ring=ZZ): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=8) - sage: K.contains(sum([K.random_element() for i in range(10)])) + sage: K.contains(sum(K.random_element() for i in range(10))) True - sage: K.contains(sum([K.random_element(QQ) for i in range(10)])) + sage: K.contains(sum(K.random_element(QQ) for i in range(10))) True The sum of random elements of a cone belongs to its ambient @@ -5108,9 +5110,9 @@ def random_element(self, ring=ZZ): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=8) sage: V = K.lattice().vector_space() - sage: sum([K.random_element() for i in range(10)]) in V + sage: sum(K.random_element() for i in range(10)) in V True - sage: sum([K.random_element(ring=QQ) for i in range(10)]) in V + sage: sum(K.random_element(ring=QQ) for i in range(10)) in V True By default, the sum of random elements of the cone should live @@ -5118,7 +5120,7 @@ def random_element(self, ring=ZZ): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=8) - sage: sum([K.random_element() for i in range(10)]) in K.lattice() + sage: sum(K.random_element() for i in range(10)) in K.lattice() True """ if not ring in [ZZ, QQ]: @@ -5135,7 +5137,7 @@ def random_element(self, ring=ZZ): L = L.vector_space() # Scale each generator by a random nonnegative factor. - terms = [ ring.random_element().abs()*L(g) for g in self ] + terms = ( ring.random_element().abs()*L(g) for g in self ) # Make sure we return a lattice element or vector. Without the # explicit conversion, we return ``0`` when we have no rays. @@ -5278,7 +5280,7 @@ def positive_operators_gens(self, K2=None): sage: K2 = random_cone(max_ambient_dim=3) sage: pi_gens = K1.positive_operators_gens(K2) sage: L = ToricLattice(K1.lattice_dim() * K2.lattice_dim()) - sage: pi_cone = Cone([ g.list() for g in pi_gens ], + sage: pi_cone = Cone(( g.list() for g in pi_gens ), ....: lattice=L, ....: check=False) sage: P = matrix(K2.lattice_dim(), @@ -5295,7 +5297,7 @@ def positive_operators_gens(self, K2=None): sage: K = random_cone(max_ambient_dim=3) sage: pi_gens = K.positive_operators_gens() sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_cone = Cone([ g.list() for g in pi_gens ], + sage: pi_cone = Cone(( g.list() for g in pi_gens ), ....: lattice=L, ....: check=False) sage: actual = pi_cone.dual().linear_subspace() @@ -5319,7 +5321,7 @@ def positive_operators_gens(self, K2=None): sage: l = K.lineality() sage: pi_gens = K.positive_operators_gens() sage: L = ToricLattice(n**2) - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: actual = pi_cone.dual().lineality() @@ -5337,7 +5339,7 @@ def positive_operators_gens(self, K2=None): sage: l = K.lineality() sage: pi_gens = K.positive_operators_gens() sage: L = ToricLattice(n**2) - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: actual = pi_cone.dim() @@ -5354,7 +5356,7 @@ def positive_operators_gens(self, K2=None): True sage: L = ToricLattice(n^2) sage: pi_gens = K.positive_operators_gens() - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: pi_cone.dim() == n^2 @@ -5364,7 +5366,7 @@ def positive_operators_gens(self, K2=None): sage: K.is_full_space() True sage: pi_gens = K.positive_operators_gens() - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: pi_cone.dim() == n^2 @@ -5372,7 +5374,7 @@ def positive_operators_gens(self, K2=None): sage: K = Cone([(1,0),(0,1),(0,-1)]) sage: pi_gens = K.positive_operators_gens() - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: check=False) sage: pi_cone.dim() == 3 True @@ -5385,7 +5387,7 @@ def positive_operators_gens(self, K2=None): sage: n = K.lattice_dim() sage: pi_gens = K.positive_operators_gens() sage: L = ToricLattice(n**2) - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: actual = pi_cone.lineality() @@ -5402,7 +5404,7 @@ def positive_operators_gens(self, K2=None): True sage: L = ToricLattice(n^2) sage: pi_gens = K.positive_operators_gens() - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: pi_cone.lineality() == n^2 @@ -5412,7 +5414,7 @@ def positive_operators_gens(self, K2=None): sage: K.is_full_space() True sage: pi_gens = K.positive_operators_gens() - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: pi_cone.lineality() == n^2 @@ -5420,7 +5422,7 @@ def positive_operators_gens(self, K2=None): sage: K = Cone([(1,0),(0,1),(0,-1)]) sage: pi_gens = K.positive_operators_gens() - sage: pi_cone = Cone([g.list() for g in pi_gens], check=False) + sage: pi_cone = Cone((g.list() for g in pi_gens), check=False) sage: pi_cone.lineality() == 2 True @@ -5431,7 +5433,7 @@ def positive_operators_gens(self, K2=None): sage: K = random_cone(max_ambient_dim=3) sage: pi_gens = K.positive_operators_gens() sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: K.is_proper() == pi_cone.is_proper() @@ -5444,13 +5446,13 @@ def positive_operators_gens(self, K2=None): sage: K = random_cone(max_ambient_dim=3) sage: L = ToricLattice(K.lattice_dim()**2) sage: p = SymmetricGroup(K.lattice_dim()).random_element().matrix() - sage: pK = Cone([ p*k for k in K ], K.lattice(), check=False) + sage: pK = Cone(( p*k for k in K ), K.lattice(), check=False) sage: pi_gens = pK.positive_operators_gens() - sage: actual = Cone([g.list() for g in pi_gens], + sage: actual = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: pi_gens = K.positive_operators_gens() - sage: expected = Cone([(p*g*p.inverse()).list() for g in pi_gens], + sage: expected = Cone(((p*g*p.inverse()).list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: actual.is_equivalent(expected) @@ -5469,11 +5471,11 @@ def positive_operators_gens(self, K2=None): sage: L = ToricLattice(n*m) sage: W = VectorSpace(F, n*m) sage: pi_gens = K1.positive_operators_gens(K2) - sage: pi_fwd = Cone([g.list() for g in pi_gens], + sage: pi_fwd = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: pi_gens = K2.dual().positive_operators_gens(K1.dual()) - sage: pi_back = Cone([g.list() for g in pi_gens], + sage: pi_back = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: M_fwd = MatrixSpace(F, m, n) @@ -5488,6 +5490,7 @@ def positive_operators_gens(self, K2=None): The Lyapunov rank of the positive operators is the product of the Lyapunov ranks of the associated cones if both are proper:: + sage: set_random_seed() sage: K1 = random_cone(max_ambient_dim=3, ....: strictly_convex=True, ....: solid=True) @@ -5496,7 +5499,7 @@ def positive_operators_gens(self, K2=None): ....: solid=True) sage: pi_gens = K1.positive_operators_gens(K2) sage: L = ToricLattice(K1.lattice_dim() * K2.lattice_dim()) - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: beta1 = K1.lyapunov_rank() @@ -5508,6 +5511,7 @@ def positive_operators_gens(self, K2=None): cone can be computed from the Lyapunov-like operators on the cones with respect to which the operators are positive:: + sage: set_random_seed() sage: K1 = random_cone(max_ambient_dim=3, ....: strictly_convex=True, ....: solid=True) @@ -5521,17 +5525,16 @@ def positive_operators_gens(self, K2=None): sage: L = ToricLattice(m*n) sage: M1 = MatrixSpace(F, m, m) sage: M2 = MatrixSpace(F, n, n) - sage: LL_K1 = [ M1(x.list()) - ....: for x in K1.dual().lyapunov_like_basis() ] - sage: LL_K2 = [ M2(x.list()) for x in K2.lyapunov_like_basis() ] - sage: tps = [ s.tensor_product(x) for x in LL_K1 for s in LL_K2 ] + sage: tps = ( M2(s.list()).tensor_product(M1(x.list())) + ....: for x in K1.dual().lyapunov_like_basis() + ....: for s in K2.lyapunov_like_basis() ) sage: W = VectorSpace(F, (m**2)*(n**2)) - sage: expected = span(F, [ W(x.list()) for x in tps ]) - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: expected = span(F, ( W(x.list()) for x in tps )) + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) sage: LL_pi = pi_cone.lyapunov_like_basis() - sage: actual = span(F, [ W(x.list()) for x in LL_pi ]) + sage: actual = span(F, ( W(x.list()) for x in LL_pi )) sage: actual == expected True """ @@ -5545,12 +5548,12 @@ def positive_operators_gens(self, K2=None): n = self.lattice_dim() m = K2.lattice_dim() - tensor_products = [ s.tensor_product(x) for x in self - for s in K2.dual() ] + tensor_products = ( s.tensor_product(x) for x in self + for s in K2.dual() ) # Convert those tensor products to long vectors. W = VectorSpace(F, n*m) - vectors = [ W(tp.list()) for tp in tensor_products ] + vectors = ( W(tp.list()) for tp in tensor_products ) check = True if self.is_proper() and K2.is_proper(): @@ -5636,10 +5639,10 @@ def cross_positive_operators_gens(self): [0 0], [1 0], [0 0], [ 0 0], [0 1], [ 0 -1] ] sage: K = Cone([(1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)]) - sage: all([ c[i][j] >= 0 for c in K.cross_positive_operators_gens() - ....: for i in range(c.nrows()) - ....: for j in range(c.ncols()) - ....: if i != j ]) + sage: all( c[i][j] >= 0 for c in K.cross_positive_operators_gens() + ....: for i in range(c.nrows()) + ....: for j in range(c.ncols()) + ....: if i != j ) True The trivial cone in a trivial space has no cross-positive @@ -5683,10 +5686,10 @@ def cross_positive_operators_gens(self): sage: K = Cone([(1,0),(-1,0),(0,1),(0,-1)]) sage: K.is_full_space() True - sage: lls = span([ vector(l.list()) - ....: for l in K.lyapunov_like_basis() ]) - sage: cs = span([ vector(c.list()) - ....: for c in K.cross_positive_operators_gens() ]) + sage: lls = span( vector(l.list()) + ....: for l in K.lyapunov_like_basis() ) + sage: cs = span( vector(c.list()) + ....: for c in K.cross_positive_operators_gens() ) sage: cs == lls True @@ -5698,7 +5701,7 @@ def cross_positive_operators_gens(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=3) sage: cp_gens = K.cross_positive_operators_gens() - sage: all([ L.is_cross_positive_on(K) for L in cp_gens ]) + sage: all( L.is_cross_positive_on(K) for L in cp_gens ) True The lineality space of the cone of cross-positive operators is @@ -5708,11 +5711,11 @@ def cross_positive_operators_gens(self): sage: K = random_cone(max_ambient_dim=3) sage: L = ToricLattice(K.lattice_dim()**2) sage: cp_gens = K.cross_positive_operators_gens() - sage: cp_cone = Cone([g.list() for g in cp_gens], + sage: cp_cone = Cone((g.list() for g in cp_gens), ....: lattice=L, ....: check=False) - sage: ll_basis = [ vector(l.list()) - ....: for l in K.lyapunov_like_basis() ] + sage: ll_basis = ( vector(l.list()) + ....: for l in K.lyapunov_like_basis() ) sage: lls = L.vector_space().span(ll_basis) sage: cp_cone.linear_subspace() == lls True @@ -5727,10 +5730,10 @@ def cross_positive_operators_gens(self): sage: pi_gens = K.positive_operators_gens() sage: cp_gens = K.cross_positive_operators_gens() sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_cone = Cone([g.list() for g in pi_gens], + sage: pi_cone = Cone((g.list() for g in pi_gens), ....: lattice=L, ....: check=False) - sage: cp_cone = Cone([g.list() for g in cp_gens], + sage: cp_cone = Cone((g.list() for g in cp_gens), ....: lattice=L, ....: check=False) sage: pi_cone.dim() == cp_cone.dim() @@ -5749,7 +5752,7 @@ def cross_positive_operators_gens(self): True sage: L = ToricLattice(n^2) sage: cp_gens = K.cross_positive_operators_gens() - sage: cp_cone = Cone([g.list() for g in cp_gens], + sage: cp_cone = Cone((g.list() for g in cp_gens), ....: lattice=L, ....: check=False) sage: cp_cone.dim() == n^2 @@ -5759,7 +5762,7 @@ def cross_positive_operators_gens(self): sage: K.is_full_space() True sage: cp_gens = K.cross_positive_operators_gens() - sage: cp_cone = Cone([g.list() for g in cp_gens], + sage: cp_cone = Cone((g.list() for g in cp_gens), ....: lattice=L, ....: check=False) sage: cp_cone.dim() == n^2 @@ -5767,7 +5770,7 @@ def cross_positive_operators_gens(self): sage: K = Cone([(1,0),(0,1),(0,-1)]) sage: cp_gens = K.cross_positive_operators_gens() - sage: cp_cone = Cone([g.list() for g in cp_gens ], check=False) + sage: cp_cone = Cone(( g.list() for g in cp_gens ), check=False) sage: cp_cone.dim() == 3 True @@ -5778,13 +5781,13 @@ def cross_positive_operators_gens(self): sage: K = random_cone(max_ambient_dim=3) sage: L = ToricLattice(K.lattice_dim()**2) sage: p = SymmetricGroup(K.lattice_dim()).random_element().matrix() - sage: pK = Cone([ p*k for k in K ], K.lattice(), check=False) + sage: pK = Cone(( p*k for k in K ), K.lattice(), check=False) sage: cp_gens = pK.cross_positive_operators_gens() - sage: actual = Cone([g.list() for g in cp_gens], + sage: actual = Cone((g.list() for g in cp_gens), ....: lattice=L, ....: check=False) sage: cp_gens = K.cross_positive_operators_gens() - sage: expected = Cone([(p*g*p.inverse()).list() for g in cp_gens], + sage: expected = Cone(((p*g*p.inverse()).list() for g in cp_gens), ....: lattice=L, ....: check=False) sage: actual.is_equivalent(expected) @@ -5800,11 +5803,11 @@ def cross_positive_operators_gens(self): sage: L = ToricLattice(n**2) sage: W = VectorSpace(F, n**2) sage: cp_gens = K.cross_positive_operators_gens() - sage: cp_cone = Cone([g.list() for g in cp_gens], + sage: cp_cone = Cone((g.list() for g in cp_gens), ....: lattice=L, ....: check=False) sage: cp_gens = K.dual().cross_positive_operators_gens() - sage: cp_star = Cone([g.list() for g in cp_gens], + sage: cp_star = Cone((g.list() for g in cp_gens), ....: lattice=L, ....: check=False) sage: M = MatrixSpace(F, n) @@ -5823,12 +5826,12 @@ def cross_positive_operators_gens(self): # These tensor products contain generators for the dual cone of # the cross-positive operators. - tensor_products = [ s.tensor_product(x) - for (x,s) in self.discrete_complementarity_set() ] + tensor_products = ( s.tensor_product(x) + for (x,s) in self.discrete_complementarity_set() ) # Turn our matrices into long vectors... W = VectorSpace(F, n**2) - vectors = [ W(m.list()) for m in tensor_products ] + vectors = ( W(m.list()) for m in tensor_products ) check = True if self.is_proper(): @@ -5898,7 +5901,7 @@ def Z_operators_gens(self): sage: set_random_seed() sage: K = random_cone(max_ambient_dim=3) sage: Z_gens = K.Z_operators_gens() - sage: all([ L.is_Z_operator_on(K) for L in Z_gens ]) + sage: all( L.is_Z_operator_on(K) for L in Z_gens ) True """ return [ -cp for cp in self.cross_positive_operators_gens() ] diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py index ce88cb3883c..37b660fa834 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py @@ -667,7 +667,7 @@ def SL2R_to_SO21(A): Integer(1)/Integer(2)*b**2 + Integer(1)/Integer(2)*c**2 + Integer(1)/Integer(2)*d**2 ] - B = matrix(3, [real(c) for c in components]) + B = matrix(3, [real(comp) for comp in components]) #B = B.apply_map(attrcall('real')) if A.det() > 0: @@ -677,6 +677,7 @@ def SL2R_to_SO21(A): # the lightcone. This fixes that issue. return -B + def SO21_to_SL2R(M): r""" A homomorphism from `SO(2, 1)` to `SL(2, \RR)`. diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py b/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py index 0a5a8d3024f..4838a90548b 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py @@ -40,7 +40,7 @@ sage: HyperbolicPlane().PD().get_point(1/2 + I/2) Point in PD 1/2*I + 1/2 """ -#*********************************************************************** +# ********************************************************************** # # Copyright (C) 2013 Greg Laun # @@ -49,13 +49,12 @@ # 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 __future__ import division from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.misc.abstract_method import abstract_method from sage.categories.sets_cat import Sets from sage.categories.realizations import Realizations, Category_realization_of_parent from sage.geometry.hyperbolic_space.hyperbolic_model import ( diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index 4d1987b8642..62be7d0b892 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -334,7 +334,6 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.rings.all import QQ, ZZ from sage.misc.cachefunc import cached_method -from sage.misc.misc import uniq from sage.matrix.constructor import matrix, vector from sage.modules.free_module import VectorSpace from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -3030,7 +3029,7 @@ def _element_constructor_(self, *args, **kwds): hyperplanes = [AA(_) for _ in arg] hyperplanes = [h.primitive(signed) for h in hyperplanes] n = len(hyperplanes) - hyperplanes = tuple(uniq(hyperplanes)) + hyperplanes = set(hyperplanes) if warn_duplicates and n != len(hyperplanes): from warnings import warn warn('Input contained {0} hyperplanes, but only {1} are distinct.'.format(n, len(hyperplanes))) @@ -3038,13 +3037,12 @@ def _element_constructor_(self, *args, **kwds): if check: if signed and not not_char2: raise ValueError('cannot be signed in characteristic 2') - hyperplane_set = set(hyperplanes) for h in hyperplanes: if h.A() == 0: raise ValueError('linear expression must be non-constant to define a hyperplane') - if not_char2 and -h in hyperplane_set: + if not_char2 and -h in hyperplanes: raise ValueError('arrangement cannot simultaneously have h and -h as hyperplane') - return self.element_class(self, hyperplanes) + return self.element_class(self, tuple(sorted(hyperplanes))) @cached_method def ngens(self): diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index 6dcd9a66a20..79a5af805f3 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -363,7 +363,7 @@ def plot_hyperplane(hyperplane, **kwds): sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) Graphics3d Object """ - if hyperplane.base_ring().characteristic() != 0: + if hyperplane.base_ring().characteristic(): raise NotImplementedError('base field must have characteristic zero') elif hyperplane.dimension() not in [0, 1, 2]: # dimension of hyperplane, not ambient space raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3') @@ -424,56 +424,49 @@ def plot_hyperplane(hyperplane, **kwds): elif hyperplane.dimension() == 1: # a line in the plane pnt = hyperplane.point() w = hyperplane.linear_part().matrix() - x, y = hyperplane.A() - d = hyperplane.b() t = SR.var('t') if ranges_set: - if type(ranges) in [list,tuple]: + if isinstance(ranges, (list, tuple)): t0, t1 = ranges else: # ranges should be a single positive number t0, t1 = -ranges, ranges else: # default t0, t1 = -3, 3 - p = parametric_plot(pnt+t*w[0], (t,t0,t1), **kwds) + p = parametric_plot(pnt + t * w[0], (t, t0, t1), **kwds) if has_hyp_label: if has_offset: b0, b1 = label_offset else: b0, b1 = 0, 0.2 - label = text(label,(pnt[0]+b0,pnt[1]+b1), + label = text(label,(pnt[0] + b0, pnt[1] + b1), color=label_color,fontsize=label_fontsize) p += label elif hyperplane.dimension() == 2: # a plane in 3-space pnt = hyperplane.point() w = hyperplane.linear_part().matrix() - a, b, c = hyperplane.A() - d = hyperplane.b() - s,t = SR.var('s t') + s, t = SR.var('s t') if ranges_set: - if type(ranges) in [list,tuple]: + if isinstance(ranges, (list, tuple)): s0, s1 = ranges[0] t0, t1 = ranges[1] - else: # ranges should be a single positive integers + else: # ranges should be a single positive integers s0, s1 = -ranges, ranges t0, t1 = -ranges, ranges - else: # default + else: # default s0, s1 = -3, 3 t0, t1 = -3, 3 - p = parametric_plot3d(pnt+s*w[0]+t*w[1],(s,s0,s1),(t,t0,t1),**kwds) + p = parametric_plot3d(pnt+s*w[0]+t*w[1], (s,s0,s1), (t,t0,t1), **kwds) if has_hyp_label: if has_offset: b0, b1, b2 = label_offset else: b0, b1, b2 = 0, 0, 0 - label = text3d(label,(pnt[0]+b0,pnt[1]+b1,pnt[2]+b2), - color=label_color,fontsize=label_fontsize) + label = text3d(label,(pnt[0]+b0, pnt[1]+b1, pnt[2]+b2), + color=label_color, fontsize=label_fontsize) p += label return p - - - def legend_3d(hyperplane_arrangement, hyperplane_colors, length): r""" Create plot of a 3d legend for an arrangement of planes in 3-space. The diff --git a/src/sage/geometry/integral_points.pyx b/src/sage/geometry/integral_points.pyx index 27b869f004f..6640e85e6f9 100644 --- a/src/sage/geometry/integral_points.pyx +++ b/src/sage/geometry/integral_points.pyx @@ -23,7 +23,7 @@ from sage.rings.all import QQ, RR, ZZ 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, uniq +from sage.misc.all 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 @@ -367,7 +367,7 @@ cpdef rectangular_box_points(list box_min, list box_max, - ``polyhedron`` -- A :class:`~sage.geometry.polyhedron.base.Polyhedron_base`, a PPL - :class:`~sage.libs.ppl.C_Polyhedron`, or ``None`` (default). + :class:`~ppl.polyhedron.C_Polyhedron`, or ``None`` (default). - ``count_only`` -- Boolean (default: ``False``). Whether to return only the total number of vertices, and not their @@ -492,7 +492,7 @@ cpdef rectangular_box_points(list box_min, list box_max, Using a PPL polyhedron:: - sage: from sage.libs.ppl import Variable, Generator_System, C_Polyhedron, point + sage: from ppl import Variable, Generator_System, C_Polyhedron, point sage: gs = Generator_System() sage: x = Variable(0); y = Variable(1); z = Variable(2) sage: gs.insert(point(0*x + 1*y + 0*z)) @@ -1135,7 +1135,7 @@ cdef class InequalityCollection: EXAMPLES:: - sage: from sage.libs.ppl import Variable, Generator_System, C_Polyhedron, point + sage: from ppl import Variable, Generator_System, C_Polyhedron, point sage: gs = Generator_System() sage: x = Variable(0); y = Variable(1); z = Variable(2) sage: gs.insert(point(0*x + 0*y + 1*z)) @@ -1156,8 +1156,8 @@ cdef class InequalityCollection: cdef list A cdef int index for index,c in enumerate(polyhedron.minimized_constraints()): - A = perm_action(permutation, list(c.coefficients())) - b = c.inhomogeneous_term() + A = perm_action(permutation, [Integer(mpz) for mpz in c.coefficients()]) + b = Integer(c.inhomogeneous_term()) try: H = Inequality_int(A, b, max_abs_coordinates, index) self.ineqs_int.append(H) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 5a6bd2062f4..e5779419289 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -117,7 +117,7 @@ from sage.geometry.toric_lattice import ToricLattice, is_ToricLattice from sage.graphs.graph import DiGraph, Graph from sage.groups.perm_gps.permgroup_element import PermutationGroupElement -from sage.libs.ppl import (C_Polyhedron, Generator_System, Linear_Expression, +from ppl import (C_Polyhedron, Generator_System, Linear_Expression, point as PPL_point) from sage.matrix.constructor import matrix from sage.structure.element import is_Matrix @@ -523,7 +523,6 @@ def __init__(self, points=None, compute_vertices=None, if compute_vertices: P = C_Polyhedron(Generator_System( [PPL_point(Linear_Expression(p, 0)) for p in points])) - P.set_immutable() self._PPL.set_cache(P) vertices = P.minimized_generators() if len(vertices) != len(points): @@ -736,10 +735,10 @@ def _compute_facets(self): constants = [] for c in self._PPL().minimized_constraints(): if c.is_inequality(): - n = N.element_class(N, c.coefficients()) + n = N.element_class(N, [Integer(mpz) for mpz in c.coefficients()]) n.set_immutable() normals.append(n) - constants.append(c.inhomogeneous_term()) + constants.append(Integer(c.inhomogeneous_term())) # Sort normals if facets are vertices if (self.dim() == 1 and normals[0] * self.vertex(0) + constants[0] != 0): @@ -823,7 +822,7 @@ def _contains(self, point, region='whole polytope'): need_strict = region.endswith("interior") N = self.dual_lattice() for c in self._PPL().minimized_constraints(): - pr = N(c.coefficients()) * point + c.inhomogeneous_term() + pr = N([Integer(mpz) for mpz in c.coefficients()]) * point + Integer(c.inhomogeneous_term()) if c.is_equality(): if pr != 0: return False @@ -968,7 +967,7 @@ def _PPL(self): OUTPUT: - - :class:`~sage.libs.ppl.C_Polyhedron` + - :class:`~ppl.polyhedron.C_Polyhedron` EXAMPLES:: @@ -995,7 +994,6 @@ def _PPL(self): """ P = C_Polyhedron(Generator_System( [PPL_point(Linear_Expression(v, 0)) for v in self.vertices()])) - P.set_immutable() return P def _pullback(self, data): @@ -1683,7 +1681,7 @@ def contains(self, *args): if len(point) == 1: point = point[0] return self._contains(point) - + @cached_method def dim(self): r""" @@ -3922,7 +3920,7 @@ def traverse_boundary(self): Needed for plot3d function of polytopes. - EXAMPLES: + EXAMPLES:: sage: p = lattice_polytope.cross_polytope(2).polar() sage: p.traverse_boundary() @@ -5039,7 +5037,7 @@ def _palp_canonical_order(V, PM_max, permutations): p_c = PermutationGroupElement((1 + i, 1 + k))*p_c # Create array of possible NFs. permutations = [p_c * l[1] for l in permutations.values()] - Vs = [(V.column_matrix().with_permuted_columns(sig).hermite_form(), sig) + Vs = [(V.column_matrix().with_permuted_columns(sig).hermite_form(), sig) for sig in permutations] Vmin = min(Vs, key=lambda x:x[0]) vertices = [V.module()(_) for _ in Vmin[0].columns()] diff --git a/src/sage/geometry/newton_polygon.py b/src/sage/geometry/newton_polygon.py index f9cc867b7a7..1c168e55cf5 100644 --- a/src/sage/geometry/newton_polygon.py +++ b/src/sage/geometry/newton_polygon.py @@ -59,7 +59,7 @@ def _repr_(self): """ Return a string representation of this Newton polygon. - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,5) ]); NP @@ -96,7 +96,7 @@ def vertices(self, copy=True): The list of vertices of this Newton polygon (or a copy of it if ``copy`` is set to True) - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,5) ]); NP @@ -127,7 +127,7 @@ def last_slope(self): Returns the last (infinite) slope of this Newton polygon if it is infinite and ``+Infinity`` otherwise. - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP1 = NewtonPolygon([ (0,0), (1,1), (2,8), (3,5) ], last_slope=3) @@ -138,7 +138,7 @@ def last_slope(self): sage: NP2.last_slope() +Infinity - We check that the last slope of a sum (resp. a produit) is the + We check that the last slope of a sum (resp. a product) is the minimum of the last slopes of the summands (resp. the factors):: sage: (NP1 + NP2).last_slope() @@ -168,7 +168,7 @@ def slopes(self, repetition=True): If ``repetition`` is True, each slope is repeated a number of times equal to its length. Otherwise, it appears only one time. - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (3,6) ]); NP @@ -204,7 +204,7 @@ def _add_(self, other): The Newton polygon, which is the convex hull of this Newton polygon and ``other`` - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP1 = NewtonPolygon([ (0,0), (1,1), (2,6) ]); NP1 @@ -235,7 +235,7 @@ def _mul_(self, other): If ``self`` and ``other`` are respective Newton polygons of some polynomials `f` and `g` the self*other is the Newton polygon of the product `fg` - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP1 = NewtonPolygon([ (0,0), (1,1), (2,6) ]); NP1 @@ -276,7 +276,7 @@ def __pow__(self, exp, ignored=None): If ``self`` is the Newton polygon of a polynomial `f`, then ``self^exp`` is the Newton polygon of `f^{exp}`. - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,6) ]); NP @@ -300,7 +300,7 @@ def __lshift__(self, i): This Newton polygon shifted by the vector `(0,i)` - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,6) ]); NP @@ -324,7 +324,7 @@ def __rshift__(self, i): This Newton polygon shifted by the vector `(0,-i)` - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,6) ]); NP @@ -348,7 +348,7 @@ def __call__(self, x): The value of this Newton polygon at abscissa `x` - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (3,6) ]); NP @@ -460,7 +460,7 @@ def plot(self, **kwargs): All usual rendering options (color, thickness, etc.) are available. - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,6) ]) @@ -497,7 +497,7 @@ def reverse(self, degree=None): The image this Newton polygon under the symmetry '(x,y) \mapsto (degree-x, y)` - EXAMPLES: + EXAMPLES:: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,5) ]) diff --git a/src/sage/geometry/polyhedron/backend_ppl.py b/src/sage/geometry/polyhedron/backend_ppl.py index fb028ea78ed..b4dcb8dc70e 100644 --- a/src/sage/geometry/polyhedron/backend_ppl.py +++ b/src/sage/geometry/polyhedron/backend_ppl.py @@ -4,14 +4,14 @@ from __future__ import absolute_import from sage.rings.all import ZZ, QQ +from sage.rings.integer import Integer from sage.arith.functions import LCM_list from sage.misc.functional import denominator -from sage.matrix.constructor import matrix -from sage.libs.ppl import ( +from ppl import ( C_Polyhedron, Constraint_System, Generator_System, - Variable, Linear_Expression, - line, ray, point ) - + Linear_Expression, + line, ray, point +) from .base import Polyhedron_base from .base_QQ import Polyhedron_QQ from .base_ZZ import Polyhedron_ZZ @@ -161,16 +161,17 @@ def _init_Vrepresentation_from_ppl(self, minimize): gs = self._ppl_polyhedron.minimized_generators() parent = self.parent() for g in gs: + coefficients = [Integer(mpz) for mpz in g.coefficients()] if g.is_point(): - d = g.divisor() + d = Integer(g.divisor()) if d.is_one(): - parent._make_Vertex(self, g.coefficients()) + parent._make_Vertex(self, coefficients) else: - parent._make_Vertex(self, [x/d for x in g.coefficients()]) + parent._make_Vertex(self, [x/d for x in coefficients]) elif g.is_ray(): - parent._make_Ray(self, g.coefficients()) + parent._make_Ray(self, coefficients) elif g.is_line(): - parent._make_Line(self, g.coefficients()) + parent._make_Line(self, coefficients) else: assert False self._Vrepresentation = tuple(self._Vrepresentation) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index bfc5a5b297d..cdf98457734 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -356,7 +356,9 @@ def _delete(self): consistent state any more and neither the polyhedron nor its H/V-representation objects may be used any more. - .. SEEALSO:: :meth:`~sage.geometry.polyhedron.parent.Polyhedra_base.recycle` + .. SEEALSO:: + + :meth:`~sage.geometry.polyhedron.parent.Polyhedra_base.recycle` EXAMPLES:: @@ -422,6 +424,93 @@ def base_extend(self, base_ring, backend=None): new_parent = self.parent().base_extend(base_ring, backend) return new_parent(self) + def change_ring(self, base_ring, backend=None): + """ + Return the polyhedron obtained by coercing the entries of the + vertices/lines/rays of this polyhedron into the given ring. + + This method can also be used to change the backend. + + INPUT: + + - ``base_ring`` -- the new base ring. + + - ``backend`` -- the new backend or ``None`` (default), see + :func:`~sage.geometry.polyhedron.constructor.Polyhedron`. + If ``None`` (the default), use the same defaulting behavior + as described there; it is not attempted to keep the same + backend. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[(1,0), (0,1)], rays=[(1,1)], base_ring=QQ); P + A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 1 ray + sage: P.change_ring(ZZ) + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 2 vertices and 1 ray + sage: P.change_ring(ZZ) == P + True + + sage: P = Polyhedron(vertices=[(-1.3,0), (0,2.3)], base_ring=RDF); P.vertices() + (A vertex at (-1.3, 0.0), A vertex at (0.0, 2.3)) + sage: P.change_ring(QQ).vertices() + (A vertex at (-13/10, 0), A vertex at (0, 23/10)) + sage: P == P.change_ring(QQ) + True + sage: P.change_ring(ZZ) + Traceback (most recent call last): + ... + TypeError: cannot change the base ring to the Integer Ring (cannot coerce -1.3 into the Integer Ring) + + sage: P = polytopes.regular_polygon(3); P + A 2-dimensional polyhedron in AA^2 defined as the convex hull of 3 vertices + sage: P.vertices() + (A vertex at (0.?e-16, 1.000000000000000?), + A vertex at (0.866025403784439?, -0.500000000000000?), + A vertex at (-0.866025403784439?, -0.500000000000000?)) + sage: P.change_ring(QQ) + Traceback (most recent call last): + ... + TypeError: cannot change the base ring to the Rational Field (cannot coerce 0.866025403784439? into the Rational Field) + + .. WARNING:: + + The base ring ``RDF`` should be used with care. As it is + not an exact ring, certain computations may break or + silently produce wrong results, for example changing the + base ring from an exact ring into ``RDF`` may cause a + loss of data:: + + sage: P = Polyhedron([[2/3,0],[6666666666666667/10^16,0]], base_ring=AA); P + A 1-dimensional polyhedron in AA^2 defined as the convex hull of 2 vertices + sage: P.change_ring(RDF) + A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex + sage: P == P.change_ring(RDF) + False + """ + + from sage.categories.all import Rings + from sage.rings.all import RDF, RR + + if base_ring not in Rings: + raise ValueError("invalid base ring") + + if not base_ring.is_exact(): + if base_ring is RR: + base_ring = RDF + elif base_ring is not RDF: + raise ValueError("the only allowed inexact ring is 'RDF' with backend 'cdd'") + + try: + vertices = [[base_ring(x) for x in vertex] for vertex in self.vertices_list()] + rays = [[base_ring(x) for x in ray] for ray in self.rays_list()] + lines = [[base_ring(x) for x in line] for line in self.lines_list()] + + except(TypeError, ValueError): + raise TypeError("cannot change the base ring to the {0} (cannot coerce {1} into the {0})".format(base_ring, x)) + + new_parent = self.parent().change_ring(base_ring, backend) + return new_parent([vertices, rays, lines], None) + def _richcmp_(self, other, op): """ Compare ``self`` and ``other``. @@ -2300,7 +2389,9 @@ def center(self): """ Return the average of the vertices. - See also :meth:`representative_point`. + .. SEEALSO:: + + :meth:`representative_point`. OUTPUT: @@ -2329,7 +2420,9 @@ def representative_point(self): """ Return a "generic" point. - See also :meth:`center`. + .. SEEALSO:: + + :meth:`center`. OUTPUT: @@ -2665,7 +2758,7 @@ def normal_fan(self): .. SEEALSO:: - :meth:`~sage.geometry.polyhedron.base.face_fan`. + :meth:`face_fan`. EXAMPLES:: @@ -2720,7 +2813,7 @@ def face_fan(self): .. SEEALSO:: - :meth:`~sage.geometry.polyhedron.base.normal_fan`. + :meth:`normal_fan`. EXAMPLES:: @@ -4671,9 +4764,9 @@ def projection(self): """ Return a projection object. - See also - :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.schlegel_projection` - for a more interesting projection. + .. SEEALSO:: + + :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.schlegel_projection` for a more interesting projection. OUTPUT: @@ -5144,14 +5237,16 @@ def integrate(self, polynomial, **kwds): raise NotImplementedError("The polytope must be full-dimensional.") else: from sage.interfaces.latte import integrate - return integrate(self.cdd_Hrepresentation(), polynomial, cdd=True) + return integrate(self.cdd_Hrepresentation(), polynomial, + cdd=True, **kwds) def contains(self, point): """ Test whether the polyhedron contains the given ``point``. - See also :meth:`interior_contains` and - :meth:`relative_interior_contains`. + .. SEEALSO:: + + :meth:`interior_contains`, :meth:`relative_interior_contains`. INPUT: @@ -5229,8 +5324,9 @@ def interior_contains(self, point): Test whether the interior of the polyhedron contains the given ``point``. - See also :meth:`contains` and - :meth:`relative_interior_contains`. + .. SEEALSO:: + + :meth:`contains`, :meth:`relative_interior_contains`. INPUT: @@ -5285,7 +5381,9 @@ def relative_interior_contains(self, point): Test whether the relative interior of the polyhedron contains the given ``point``. - See also :meth:`contains` and :meth:`interior_contains`. + .. SEEALSO:: + + :meth:`contains`, :meth:`interior_contains`. INPUT: @@ -6588,7 +6686,7 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, - ``as_affine_map`` (boolean, default = False) -- If ``False``, return a polyhedron. If ``True``, return the affine transformation, that sends the embedded polytope to a fulldimensional one. - It is given as a pair ``(A,b)``, where A is a linear transformation + It is given as a pair ``(A, b)``, where A is a linear transformation and ``b`` is a vector, and the affine transformation sends ``v`` to ``A(v)+b``. @@ -6651,6 +6749,11 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, sage: S = polytopes.simplex(); S A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices + sage: S.vertices() + (A vertex at (0, 0, 0, 1), + A vertex at (0, 0, 1, 0), + A vertex at (0, 1, 0, 0), + A vertex at (1, 0, 0, 0)) sage: A = S.affine_hull(); A A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices sage: A.vertices() @@ -6752,7 +6855,7 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, sage: Pentagon = polytopes.dodecahedron().faces(2)[0].as_polyhedron() sage: Pnormal = Pentagon.affine_hull(orthonormal=True, extend=True) sage: Pgonal = Pentagon.affine_hull(orthogonal=True) - sage: A,b = Pentagon.affine_hull(orthogonal = True, as_affine_map=True) + sage: A, b = Pentagon.affine_hull(orthogonal=True, as_affine_map=True) sage: Adet = (A.matrix().transpose()*A.matrix()).det() sage: Pnormal.volume() 1.53406271079097? @@ -6766,7 +6869,7 @@ def affine_hull(self, as_affine_map=False, orthogonal=False, orthonormal=False, An other example with ``as_affine_map=True``:: sage: P = polytopes.permutahedron(4) - sage: A,b = P.affine_hull(orthonormal=True, as_affine_map=True, extend=True) + sage: A, b = P.affine_hull(orthonormal=True, as_affine_map=True, extend=True) sage: Q = P.affine_hull(orthonormal=True, extend=True) sage: Q.center() (0.7071067811865475?, 1.224744871391589?, 1.732050807568878?) diff --git a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py index f3fc6f54125..4309d09a1e0 100644 --- a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py +++ b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py @@ -105,14 +105,12 @@ def __call__(self, x): LatticePolytope_PPL, LatticePolytope_PPL_class) if isinstance(x, LatticePolytope_PPL_class): if x.is_empty(): - from sage.libs.ppl import C_Polyhedron + from ppl import C_Polyhedron return LatticePolytope_PPL(C_Polyhedron(self._b.degree(), 'empty')) return LatticePolytope_PPL(*[self(v) for v in x.vertices()]) - pass - v = self._A*x+self._b + v = self._A * x + self._b v.set_immutable() - return v def _repr_(self): diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 7a22786cecd..a0357c5c11e 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -395,7 +395,7 @@ def icosahedron(self, exact=True, base_ring=None, backend=None): sage: ico = polytopes.icosahedron(exact=False) sage: ico.base_ring() Real Double Field - sage: ico.volume() + sage: ico.volume() # known bug (trac 18214) 2.181694990... A version using `AA `:: @@ -1155,7 +1155,7 @@ def truncated_dodecahedron(self, exact=True, base_ring=None, backend=None): fully work unfortunately, see https://github.com/cddlib/cddlib/pull/7 for a detailed discussion of this case:: - sage: td = polytopes.truncated_dodecahedron(exact=False) + sage: td = polytopes.truncated_dodecahedron(exact=False) # random doctest:warning ... UserWarning: This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies. @@ -1370,7 +1370,7 @@ def truncated_icosidodecahedron(self, exact=True, base_ring=None, backend=None): The implementation using floating point approximations is much faster:: - sage: ti = polytopes.truncated_icosidodecahedron(exact=False) + sage: ti = polytopes.truncated_icosidodecahedron(exact=False) # random sage: ti.f_vector() (1, 120, 180, 62, 1) sage: ti.base_ring() @@ -1602,7 +1602,7 @@ def grand_antiprism(self, exact=True, backend=None): Computation with approximated coordinates is much faster:: - sage: gap = polytopes.grand_antiprism(exact=False) + sage: gap = polytopes.grand_antiprism(exact=False) # random sage: gap A 4-dimensional polyhedron in RDF^4 defined as the convex hull of 100 vertices sage: gap.f_vector() diff --git a/src/sage/geometry/polyhedron/misc.py b/src/sage/geometry/polyhedron/misc.py index 7512f0dd1d7..7f85c3ca7e8 100644 --- a/src/sage/geometry/polyhedron/misc.py +++ b/src/sage/geometry/polyhedron/misc.py @@ -1,26 +1,19 @@ r""" Miscellaneous helper functions """ - - -######################################################################## +# ********************************************************************** # Copyright (C) 2008 Marshall Hampton # Copyright (C) 2011 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ -######################################################################## - - - - +# https://www.gnu.org/licenses/ +# ********************************************************************** -######################################################################### def _to_space_separated_string(l): """ - Converts a container to a space-separated string. + Convert a container to a space-separated string. INPUT: @@ -36,14 +29,9 @@ def _to_space_separated_string(l): sage: P._to_space_separated_string([2,3]) '2 3' """ - s = ''; - for x in l: - if len(s)>0: s += ' ' - s += repr(x) - return s + return ' '.join(repr(x) for x in l) -######################################################################### def _set_to_None_if_empty(x): """ Helper function to clean up arguments: Returns None if x==None or @@ -57,13 +45,14 @@ def _set_to_None_if_empty(x): sage: P._set_to_None_if_empty([1]) [1] """ - if x is None: return x + if x is None: + return x x = list(x) - if len(x)==0: return None + if not x: + return None return x -######################################################################### def _make_listlist(x): """ Helper function to clean up arguments. @@ -86,11 +75,11 @@ def _make_listlist(x): sage: P._make_listlist([(1,2),[3,4]]) [[1, 2], [3, 4]] """ - if x is None: return [] + if x is None: + return [] return [list(y) for y in x] -######################################################################### def _common_length_of(l1, l2=None, l3=None): """ The arguments are containers or ``None``. The function applies @@ -107,10 +96,13 @@ def _common_length_of(l1, l2=None, l3=None): sage: P._common_length_of([[1,2,3],[1,3,34]]) (2, 3) """ - args = []; - if l1 is not None: args.append(l1) - if l2 is not None: args.append(l2) - if l3 is not None: args.append(l3) + args = [] + if l1 is not None: + args.append(l1) + if l2 is not None: + args.append(l2) + if l3 is not None: + args.append(l3) length = None num = 0 diff --git a/src/sage/geometry/polyhedron/palp_database.py b/src/sage/geometry/polyhedron/palp_database.py index db6d60a1e89..17acd87b864 100644 --- a/src/sage/geometry/polyhedron/palp_database.py +++ b/src/sage/geometry/polyhedron/palp_database.py @@ -29,16 +29,18 @@ """ from __future__ import print_function +import os + from subprocess import Popen, PIPE +import six + from sage.structure.sage_object import SageObject -from sage.matrix.all import matrix -from sage.rings.all import Integer, ZZ +from sage.rings.all import ZZ from sage.interfaces.process import terminate from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL -from sage.geometry.polyhedron.constructor import Polyhedron ######################################################################### @@ -107,13 +109,13 @@ def __init__(self, dim, data_basename=None, output='Polyhedron'): if data_basename is not None: self._data_basename = data_basename else: - import os from sage.env import POLYTOPE_DATA_DIR self._data_basename = os.path.join(POLYTOPE_DATA_DIR, - 'Full'+str(dim)+'d', 'zzdb') + 'Full{}d'.format(dim), 'zzdb') info = self._data_basename + '.info' if not os.path.exists(info): - raise ValueError('Cannot find PALP database: '+info) + raise ValueError('Cannot find PALP database: {}'.format(info)) + from sage.geometry.polyhedron.parent import Polyhedra self._polyhedron_parent = Polyhedra(ZZ, dim) self._output = output.lower() @@ -133,7 +135,17 @@ def _palp_Popen(self): sage: polygons._palp_Popen() """ - return Popen(["class.x", "-b2a", "-di", self._data_basename], stdout=PIPE) + + if six.PY2: + encoding_kwargs = {} + else: + encoding_kwargs = { + 'encoding': 'utf-8', + 'errors': 'surrogateescape' + } + + return Popen(["class.x", "-b2a", "-di", self._data_basename], + stdout=PIPE, **encoding_kwargs) def _read_vertices(self, stdout, rows, cols): r""" @@ -148,13 +160,13 @@ def _read_vertices(self, stdout, rows, cols): sage: from sage.geometry.polyhedron.palp_database import PALPreader sage: polygons = PALPreader(2) sage: palp = polygons._palp_Popen() - sage: palp.stdout.readline().decode('utf-8') - u'2 3 \n' + sage: palp.stdout.readline() + '2 3 \n' sage: polygons._read_vertices(palp.stdout, 2, 3) [[1, 0], [0, 1], [-1, -1]] """ - m = [ [] for col in range(0,cols) ] - for row in range(0,rows): + m = [[] for col in range(0, cols)] + for row in range(0, rows): for col,x in enumerate(stdout.readline().split()): m[col].append(ZZ(x)) return m @@ -172,14 +184,14 @@ def _read_vertices_transposed(self, stdout, rows, cols): sage: from sage.geometry.polyhedron.palp_database import PALPreader sage: polygons = PALPreader(2) sage: palp = polygons._palp_Popen() - sage: palp.stdout.readline().decode('utf-8') - u'2 3 \n' + sage: palp.stdout.readline() + '2 3 \n' sage: polygons._read_vertices_transposed(palp.stdout, 2, 3) [[1, 0, -1], [0, 1, -1]] """ m = [] - for row in range(0,rows): - m.append( [ ZZ(x) for x in stdout.readline().split() ] ) + for row in range(0, rows): + m.append([ZZ(x) for x in stdout.readline().split()]) return m def _iterate_list(self, start, stop, step): @@ -212,25 +224,26 @@ def _iterate_list(self, start, stop, step): palp_out = palp.stdout i = 0 while True: - l = str(palp_out.readline().decode("utf-8")).strip() - if l=='' or l.startswith('#'): + l = palp_out.readline().strip() + if l == '' or l.startswith('#'): return # EOF - l=l.split() - dim = ZZ(l[0]); # dimension - n = ZZ(l[1]); # number of vertices - if i>=start and (i-start) % step == 0: + l = l.split() + dim = ZZ(l[0]) # dimension + n = ZZ(l[1]) # number of vertices + if i >= start and (i - start) % step == 0: if dim == self._dim: vertices = self._read_vertices(palp_out, dim, n) - elif n == self._dim: # PALP sometimes returns transposed data #@!#@ + elif n == self._dim: + # PALP sometimes returns transposed data #@!#@ vertices = self._read_vertices_transposed(palp_out, dim, n) else: raise ValueError('PALP output dimension mismatch.') yield vertices else: - for row in range(0,dim): + for row in range(0, dim): palp_out.readline() i += 1 - if stop is not None and i>=stop: + if stop is not None and i >= stop: return def _iterate_Polyhedron(self, start, stop, step): @@ -256,7 +269,7 @@ def _iterate_Polyhedron(self, start, stop, step): """ parent = self._polyhedron_parent for vertices in self._iterate_list(start, stop, step): - p = parent.element_class(parent, [vertices,[],[]], None) + p = parent.element_class(parent, [vertices, [], []], None) yield p def _iterate_PPL(self, start, stop, step): @@ -308,8 +321,9 @@ def _iterate_PointCollection(self, start, stop, step): in Ambient free module of rank 2 over the principal ideal domain Integer Ring """ from sage.modules.free_module import FreeModule - N = FreeModule(ZZ, self._dim) from sage.geometry.point_collection import PointCollection + + N = FreeModule(ZZ, self._dim) for vertices in self._iterate_list(start, stop, step): yield PointCollection(vertices, module=N) @@ -347,7 +361,7 @@ def _iterate(self, output=None): elif output == 'list': return self._iterate_list else: - raise TypeError('Unknown output format (='+str(self._output)+').') + raise TypeError('Unknown output format (={}).'.format(self._output)) def __iter__(self): """ @@ -384,7 +398,7 @@ def __getitem__(self, item): return iterator(item.start, item.stop, item.step) else: try: - return next(iterator(item, item+1, 1)) + return next(iterator(item, item + 1, 1)) except StopIteration: raise IndexError('Index out of range.') @@ -428,14 +442,15 @@ def __init__(self, h11, h21, data_basename=None, **kwds): """ dim = 4 if data_basename is None: - import os from sage.env import POLYTOPE_DATA_DIR data_basename = os.path.join(POLYTOPE_DATA_DIR, 'Hodge4d', 'all') info = data_basename + '.vinfo' if not os.path.exists(info): - raise ValueError('Cannot find PALP database: '+info+ - '. Did you install the polytopes_db_4d optional spkg?') + raise ValueError( + 'Cannot find PALP database: {}. Did you install the ' + 'polytopes_db_4d optional spkg?'.format(info)) + PALPreader.__init__(self, dim, data_basename=data_basename, **kwds) self._h11 = h11 self._h21 = h21 @@ -455,9 +470,15 @@ def _palp_Popen(self): sage: polygons._palp_Popen() # optional - polytopes_db_4d """ - return Popen(['class-4d.x', '-He', - 'H'+str(self._h21)+':'+str(self._h11)+'L100000000', - '-di', self._data_basename], stdout=PIPE) - - + if six.PY2: + encoding_kwargs = {} + else: + encoding_kwargs = { + 'encoding': 'utf-8', + 'errors': 'surrogateescape' + } + return Popen(['class-4d.x', '-He', + 'H{}:{}L100000000'.format(self._h21, self._h11), + '-di', self._data_basename], stdout=PIPE, + **encoding_kwargs) diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index f98c446984f..b0b3a1b20c2 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -575,6 +575,25 @@ def base_extend(self, base_ring, backend=None): elif base_ring.has_coerce_map_from(self.base_ring()): return Polyhedra(base_ring, self.ambient_dim(), backend=backend) + def change_ring(self, base_ring, backend=None): + """ + Return the parent with the new base ring. + + INPUT: + + - ``base_ring``, ``backend`` -- see + :func:`~sage.geometry.polyhedron.constructor.Polyhedron`. + + EXAMPLES:: + + sage: from sage.geometry.polyhedron.parent import Polyhedra + sage: Polyhedra(ZZ,3).change_ring(QQ) + Polyhedra in QQ^3 + sage: Polyhedra(ZZ,3).an_element().change_ring(QQ) + A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices + """ + return Polyhedra(base_ring, self.ambient_dim(), backend=backend) + def _coerce_base_ring(self, other): r""" Return the common base rincg for both ``self`` and ``other``. diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py index b45c2dabe2c..5fbed845a02 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py @@ -22,8 +22,7 @@ from sage.misc.all import cached_method, cached_function from sage.modules.all import (vector, zero_vector) from sage.matrix.constructor import (matrix, zero_matrix, block_matrix) -from sage.libs.ppl import (C_Polyhedron, Generator_System_iterator, - Poly_Con_Relation) +from ppl import C_Polyhedron, Poly_Con_Relation from sage.geometry.polyhedron.lattice_euclidean_group_element import ( LatticeEuclideanGroupElement) from sage.geometry.polyhedron.ppl_lattice_polytope import ( @@ -303,8 +302,7 @@ def find_isomorphism(self, polytope): return self._find_isomorphism_degenerate(polytope) polytope_origin = polytope_vertices[0] - origin_P = C_Polyhedron(next(Generator_System_iterator( - polytope.minimized_generators()))) + origin_P = C_Polyhedron(next(iter(polytope.minimized_generators()))) neighbors = [] for c in polytope.minimized_constraints(): diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py index 9e0e9432f91..6ef35e87342 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py @@ -13,7 +13,7 @@ :func:`~sage.geometry.polyhedron.constructor.Polyhedron` with ``base_ring=ZZ``. -The class derives from the PPL :class:`sage.libs.ppl.C_Polyhedron` +The class derives from the PPL :class:`ppl.polyhedron.C_Polyhedron` class, so you can work with the underlying generator and constraint objects. However, integral points are generally represented by `\ZZ`-vectors. In the following, we always use *generator* to refer @@ -56,35 +56,28 @@ - Volker Braun: initial version, 2012 """ -######################################################################## +#***************************************************************************** # Copyright (C) 2012 Volker Braun # -# Distributed under the terms of the GNU General Public License (GPL) -# -# http://www.gnu.org/licenses/ -######################################################################## -from __future__ import print_function -from __future__ import absolute_import +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +#***************************************************************************** + +from __future__ import absolute_import, print_function import copy -from sage.rings.integer import GCD_list +from sage.rings.integer import GCD_list, Integer from sage.rings.integer_ring import ZZ -from sage.misc.all import union, cached_method, prod, uniq -from sage.modules.all import ( - vector, zero_vector ) -from sage.matrix.constructor import ( - matrix, column_matrix, diagonal_matrix ) -from sage.libs.ppl import ( - C_Polyhedron, Linear_Expression, Variable, - point, ray, line, - Generator, Generator_System, Generator_System_iterator ) -from sage.libs.ppl import ( +from sage.misc.all import cached_method +from sage.modules.all import vector +from sage.matrix.constructor import matrix +from ppl import ( C_Polyhedron, Linear_Expression, Variable, point, ray, line, Generator, Generator_System, - Constraint_System, - Poly_Con_Relation ) - - + Constraint_System, Poly_Con_Relation ) ######################################################################## @@ -128,7 +121,7 @@ def LatticePolytope_PPL(*args): sage: LatticePolytope_PPL((0,0),(1,0),(0,1)) A 2-dimensional lattice polytope in ZZ^2 with 3 vertices - sage: from sage.libs.ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable + sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable sage: p = point(Linear_Expression([2,3],0)); p point(2/1, 3/1) sage: LatticePolytope_PPL(p) @@ -145,9 +138,9 @@ def LatticePolytope_PPL(*args): sage: LatticePolytope_PPL((0,0),(1/2,1)) Traceback (most recent call last): ... - TypeError: no conversion of this rational to integer + TypeError: unable to convert rational 1/2 to an integer - sage: from sage.libs.ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable + sage: from ppl import point, Generator_System, C_Polyhedron, Linear_Expression, Variable sage: p = point(Linear_Expression([2,3],0), 5); p point(2/5, 3/5) sage: LatticePolytope_PPL(p) @@ -166,7 +159,7 @@ def LatticePolytope_PPL(*args): if len(args)==1 and isinstance(args[0], C_Polyhedron): polyhedron = args[0] polytope_class = _class_for_LatticePolytope(polyhedron.space_dimension()) - if not all(p.is_point() and p.divisor().is_one() for p in polyhedron.generators()): + if not all(p.is_point() and p.divisor() == 1 for p in polyhedron.generators()): raise TypeError('polyhedron has non-integral generators') return polytope_class(polyhedron) if len(args)==1 \ @@ -178,13 +171,13 @@ def LatticePolytope_PPL(*args): gs = Generator_System() for v in vertices: if isinstance(v, Generator): - if (not v.is_point()) or (not v.divisor().is_one()): + if (not v.is_point()) or v.divisor() != 1: raise TypeError('generator is not a lattice polytope generator') gs.insert(v) else: gs.insert(point(Linear_Expression(v, 0))) if not gs.empty(): - dim = next(Generator_System_iterator(gs)).space_dimension() + dim = next(iter(gs)).space_dimension() polytope_class = _class_for_LatticePolytope(dim) return polytope_class(gs) @@ -204,7 +197,7 @@ class LatticePolytope_PPL_class(C_Polyhedron): A 2-dimensional lattice polytope in ZZ^2 with 3 vertices """ - def _repr_(self): + def __repr__(self): """ Return the string representation @@ -218,7 +211,7 @@ def _repr_(self): sage: P = LatticePolytope_PPL((0,0),(1,0),(0,1)) sage: P A 2-dimensional lattice polytope in ZZ^2 with 3 vertices - sage: P._repr_() + sage: P.__repr__() 'A 2-dimensional lattice polytope in ZZ^2 with 3 vertices' sage: LatticePolytope_PPL() @@ -315,7 +308,7 @@ def bounding_box(self): raise ValueError('empty polytope is not allowed') for i in range(0, self.space_dimension()): x = Variable(i) - coords = [ v.coefficient(x) for v in self.generators() ] + coords = [Integer(v.coefficient(x)) for v in self.generators()] max_coord = max(coords) min_coord = min(coords) box_max.append(max_coord) @@ -531,7 +524,7 @@ def vertices_saturating(self, constraint): sage: p.vertices_saturating(ieq) ((0, 0), (0, 1)) """ - from sage.libs.ppl import C_Polyhedron, Poly_Con_Relation + from ppl import C_Polyhedron, Poly_Con_Relation result = [] for i,v in enumerate(self.minimized_generators()): v = C_Polyhedron(v) @@ -589,7 +582,6 @@ def fibration_generator(self, dim): [A 2-dimensional lattice polytope in ZZ^4 with 3 vertices] """ assert self.is_full_dimensional() - codim = self.space_dimension() - dim # "points" are the potential vertices of the fiber. They are # in the $codim$-skeleton of the polytope, which is contained # in the points that saturate at least $dim$ equations. @@ -1009,8 +1001,8 @@ def restricted_automorphism_group(self, vertex_labels=None): # good coordinates for the vertices v_list = [] for v in self.minimized_generators(): - assert v.divisor().is_one() - v_coords = (1,) + v.coefficients() + assert v.divisor() == 1 + v_coords = (1,) + tuple(Integer(mpz) for mpz in v.coefficients()) v_list.append(vector(v_coords)) # Finally, construct the graph @@ -1268,5 +1260,3 @@ def embed_in_reflexive_polytope(self, output='hom'): else: raise ValueError('output='+str(output)+' is not valid.') - - diff --git a/src/sage/geometry/triangulation/base.pyx b/src/sage/geometry/triangulation/base.pyx index 1ca2f15ddb8..a435f61a97b 100644 --- a/src/sage/geometry/triangulation/base.pyx +++ b/src/sage/geometry/triangulation/base.pyx @@ -23,7 +23,6 @@ from sage.structure.sage_object cimport SageObject from sage.structure.parent cimport Parent from sage.categories.sets_cat import Sets from sage.matrix.constructor import matrix -from sage.misc.misc import uniq from sage.misc.cachefunc import cached_method from .functions cimport binomial @@ -438,7 +437,7 @@ cdef class PointConfiguration_base(Parent): self._ambient_dim = len(projective_points[0])-1 assert all(len(p) == self._ambient_dim+1 for p in projective_points), \ 'The given point coordinates must all have the same length.' - assert len(uniq(projective_points)) == len(projective_points), \ + assert len(set(projective_points)) == len(projective_points), \ 'Not all points are pairwise distinct.' proj = matrix(projective_points).transpose() diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index 5642c33eb19..a80d9111e4d 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -29,14 +29,16 @@ See :mod:`sage.geometry.triangulation.point_configuration` for more details. """ - -######################################################################## +#***************************************************************************** # Copyright (C) 2010 Volker Braun # -# Distributed under the terms of the GNU General Public License (GPL) -# +# This 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 six import iteritems from sage.structure.richcmp import richcmp @@ -70,8 +72,8 @@ def triangulation_render_2d(triangulation, **kwds): sage: triang.plot(axes=False, aspect_ratio=1) # indirect doctest Graphics object consisting of 12 graphics primitives """ - from sage.plot.all import point2d, line2d, arrow, polygon2d - points = [ point.reduced_affine() for point in triangulation.point_configuration() ] + from sage.plot.all import point2d, line2d, polygon2d + points = [point.reduced_affine() for point in triangulation.point_configuration()] coord = [ [p[0], p[1]] for p in points ] plot_points = sum([ point2d(p, zorder=2, pointsize=10, **kwds) @@ -134,7 +136,7 @@ def triangulation_render_3d(triangulation, **kwds): sage: triang.plot(axes=False) # indirect doctest Graphics3d Object """ - from sage.plot.plot3d.all import point3d, line3d, arrow3d, polygon3d + from sage.plot.plot3d.all import point3d, line3d, polygon3d points = [ point.reduced_affine() for point in triangulation.point_configuration() ] coord = [ [p[0], p[1], p[2] ] for p in points ] plot_points = sum([ point3d(p, size=15, @@ -764,9 +766,8 @@ def normal_cone(self): """ if not self.point_configuration().base_ring().is_subring(QQ): raise NotImplementedError('Only base rings ZZ and QQ are supported') - from sage.libs.ppl import Variable, Constraint, Constraint_System, Linear_Expression, C_Polyhedron + from ppl import Constraint_System, Linear_Expression, C_Polyhedron from sage.matrix.constructor import matrix - from sage.misc.misc import uniq from sage.arith.all import lcm pc = self.point_configuration() cs = Constraint_System() @@ -775,7 +776,7 @@ def normal_cone(self): p = set(s0).difference(facet).pop() q = set(s1).difference(facet).pop() origin = pc.point(p).reduced_affine_vector() - base_indices = [ i for i in s0 if i!=p ] + base_indices = [i for i in s0 if i != p] base = matrix([ pc.point(i).reduced_affine_vector()-origin for i in base_indices ]) sol = base.solve_left( pc.point(q).reduced_affine_vector()-origin ) relation = [0]*pc.n_points() diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index 940bcaf6986..92ebb6f009c 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -177,19 +177,17 @@ # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from __future__ import print_function from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.element import Element from sage.misc.cachefunc import cached_method from sage.combinat.combination import Combinations from sage.rings.all import QQ, ZZ from sage.matrix.constructor import matrix from sage.modules.all import vector -from sage.groups.perm_gps.permgroup import PermutationGroup from copy import copy import sys @@ -507,11 +505,11 @@ def __iter__(self): sage: p = PointConfiguration([[1,1], [2,2], [3,3]]) sage: list(p) # indirect doctest [P(1, 1), P(2, 2), P(3, 3)] - sage: [ p[i] for i in range(0,p.n_points()) ] + sage: [ p[i] for i in range(p.n_points()) ] [P(1, 1), P(2, 2), P(3, 3)] sage: list(p.points()) [P(1, 1), P(2, 2), P(3, 3)] - sage: [ p.point(i) for i in range(0,p.n_points()) ] + sage: [ p.point(i) for i in range(p.n_points()) ] [P(1, 1), P(2, 2), P(3, 3)] """ for p in self.points(): @@ -1178,7 +1176,7 @@ def restricted_automorphism_group(self): # backends. It should probably be set back to sparse = False as soon as # the backends are fixed. G = Graph(sparse=True) - for i in range(0,len(v_list)): + for i in range(len(v_list)): for j in range(i+1,len(v_list)): v_i = v_list[i] v_j = v_list[j] @@ -1246,10 +1244,10 @@ def face_interior(self, dim=None, codim=None): except AttributeError: pass - d = [ self.face_codimension(i) for i in range(0,self.n_points()) ] + d = [ self.face_codimension(i) for i in range(self.n_points()) ] - return tuple( tuple(i for i in range(0,self.n_points()) if d[i]==codim ) - for codim in range(0,self.dim()+1) ) + return tuple( tuple(i for i in range(self.n_points()) if d[i]==codim ) + for codim in range(self.dim()+1) ) def exclude_points(self, point_idx_list): @@ -1278,7 +1276,7 @@ def exclude_points(self, point_idx_list): sage: p.exclude_points( p.face_interior(codim=1) ).points() (P(-1, 0), P(0, 0), P(1, -1), P(1, 1)) """ - points = [ self.point(i) for i in range(0,self.n_points()) + points = [ self.point(i) for i in range(self.n_points()) if not i in point_idx_list ] return PointConfiguration(points, projective=False, @@ -1406,16 +1404,15 @@ def circuits_support(self): [(0, 3, 4), (0, 1, 2), (1, 2, 3, 4)] """ n = len(self) - U = [ self[i].reduced_projective() for i in range(0,n) ] + U = [self[i].reduced_projective() for i in range(n)] # the index set of U - I = set(range(0,n)) + I = set(range(n)) # The (indices of) known independent elements of U - independent_k = [ (i,) for i in range(0,n) ] + independent_k = [(i,) for i in range(n)] supports_k = [] - supports = () # supports of circuits - for k in range(2, self.dim()+3): + for k in range(2, self.dim() + 3): # possibly linear dependent subsets supports_knext = set() @@ -1496,21 +1493,20 @@ def circuits(self): pass n = len(self) - U = [ self[i].reduced_projective() for i in range(0,n) ] + U = [self[i].reduced_projective() for i in range(n)] Circuits = () for support in self.circuits_support(): m = matrix([ U[i] for i in support ]).transpose() ker = m.right_kernel().basis()[0] assert len(ker)==len(support) - Cplus = [ support[i] for i in range(0,len(support)) if ker[i]>0 ] - Cminus = [ support[i] for i in range(0,len(support)) if ker[i]<0 ] - Czero = set( range(0,n) ).difference(support) + Cplus = [ support[i] for i in range(len(support)) if ker[i]>0 ] + Cminus = [ support[i] for i in range(len(support)) if ker[i]<0 ] + Czero = set( range(n) ).difference(support) Circuits += ( (tuple(Cplus), tuple(Czero), tuple(Cminus)), ) self._circuits = Circuits return Circuits - def positive_circuits(self, *negative): r""" Returns the positive part of circuits with fixed negative part. @@ -1586,14 +1582,14 @@ def bistellar_flips(self): for C in self.circuits(): Cpos = list(C[0]) Cneg = list(C[2]) - support = sorted(Cpos+Cneg) - Tpos = [ Cpos+Cneg[0:i]+Cneg[i+1:len(Cneg)] for i in range(0,len(Cneg)) ] - Tneg = [ Cneg+Cpos[0:i]+Cpos[i+1:len(Cpos)] for i in range(0,len(Cpos)) ] - flips.append( (self.element_class(Tpos, parent=self, check=False), - self.element_class(Tneg, parent=self, check=False)) ) + Tpos = [Cpos + Cneg[0:i] + Cneg[i+1:len(Cneg)] + for i in range(len(Cneg))] + Tneg = [Cneg + Cpos[0:i] + Cpos[i+1:len(Cpos)] + for i in range(len(Cpos))] + flips.append((self.element_class(Tpos, parent=self, check=False), + self.element_class(Tneg, parent=self, check=False))) return tuple(flips) - def lexicographic_triangulation(self): r""" Return the lexicographic triangulation. @@ -1641,7 +1637,7 @@ def lexicographic_triangulation(self): lex_supp = sorted(lex_supp, key=lambda x:-len(x)) basepts = copy(lex_supp) - for i in range(0,len(lex_supp)-1): + for i in range(len(lex_supp)-1): for j in range(i+1,len(lex_supp)): if set(lex_supp[j]).issubset(set(lex_supp[i])): try: @@ -1674,7 +1670,7 @@ def make_cotriang(basepts): return triangulation triangulation = make_cotriang(basepts) - I = frozenset(range(0,self.n_points())) + I = frozenset(range(self.n_points())) triangulation = [ tuple(I.difference(t)) for t in triangulation ] return self(triangulation) @@ -1920,7 +1916,7 @@ def contained_simplex(self, large=True, initial_point=None, point_order=None): points.remove(p) else: p = points.pop() - edge = p.reduced_affine_vector()-origin.reduced_affine_vector() + edge = p.reduced_affine_vector() - origin.reduced_affine_vector() if edges and (ker * edge).is_zero(): continue vertices.append(p) @@ -2062,7 +2058,7 @@ def facets_of_simplex(simplex): facets.update(new_facets) # construct the triangulation - triangulation = [[p.index() for p in simplex] for simplex in simplices] + triangulation = [[p.index() for p in simplx] for simplx in simplices] return self(triangulation) pushing_triangulation = placing_triangulation diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index e8f8b24ea2f..75ed5c7efc7 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -210,8 +210,10 @@ cpdef edge_connectivity(g): sage: from sage.graphs.base.boost_graph import edge_connectivity sage: g = graphs.GridGraph([2,2]) - sage: edge_connectivity(g) + sage: edge_connectivity(g) # py2 (2, [((0, 1), (1, 1)), ((0, 1), (0, 0))]) + sage: edge_connectivity(g) # py3 + (2, [((0, 0), (0, 1)), ((0, 0), (1, 0))]) """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph @@ -537,10 +539,14 @@ cpdef bandwidth_heuristics(g, algorithm='cuthill_mckee'): sage: from sage.graphs.base.boost_graph import bandwidth_heuristics sage: bandwidth_heuristics(graphs.PathGraph(10)) (1, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) - sage: bandwidth_heuristics(graphs.GridGraph([3,3])) + sage: bandwidth_heuristics(graphs.GridGraph([3,3])) # py2 (3, [(2, 2), (2, 1), (1, 2), (2, 0), (1, 1), (0, 2), (1, 0), (0, 1), (0, 0)]) - sage: bandwidth_heuristics(graphs.GridGraph([3,3]), algorithm='king') + sage: bandwidth_heuristics(graphs.GridGraph([3,3]), algorithm='king') # py2 (3, [(2, 2), (2, 1), (1, 2), (2, 0), (1, 1), (0, 2), (1, 0), (0, 1), (0, 0)]) + sage: bandwidth_heuristics(graphs.GridGraph([3,3])) # py3 + (3, [(0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2), (2, 1), (1, 2), (2, 2)]) + sage: bandwidth_heuristics(graphs.GridGraph([3,3]), algorithm='king') # py3 + (3, [(0, 0), (1, 0), (0, 1), (2, 0), (1, 1), (0, 2), (2, 1), (1, 2), (2, 2)]) TESTS: diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index 2170c92704e..08b5a917ed7 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -1295,7 +1295,7 @@ cdef class CGraphBackend(GenericGraphBackend): sage: G.add_edge(1,1,'b') sage: G.add_edge(1,1) sage: G.add_edge(1,1) - sage: G.edges() + sage: G.edges_incident() [(1, 1, None), (1, 1, None), (1, 1, 'b'), (1, 1, 'b'), (1, 2, 'a'), (1, 2, 'a'), (1, 2, 'a')] sage: G.degree(1) 11 @@ -1638,9 +1638,21 @@ cdef class CGraphBackend(GenericGraphBackend): sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_graph") sage: list(P._backend.iterator_in_nbrs(0)) [1, 4, 5] + + TESTS:: + + sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_graph") + sage: list(P._backend.iterator_in_nbrs(63)) + Traceback (most recent call last): + ... + LookupError: vertex (63) is not a vertex of the graph """ + cdef int u_int cdef int v_int = self.get_vertex(v) + if v_int == -1 or not bitset_in((self._cg).active_vertices, v_int): + raise LookupError("vertex ({0}) is not a vertex of the graph".format(v)) + # Sparse if self._cg_rev is not None: for u_int in self._cg_rev.out_neighbors(v_int): @@ -1676,9 +1688,19 @@ cdef class CGraphBackend(GenericGraphBackend): sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_graph") sage: list(P._backend.iterator_out_nbrs(0)) [1, 4, 5] + + TESTS:: + + sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_graph") + sage: list(P._backend.iterator_out_nbrs(-41)) + Traceback (most recent call last): + ... + LookupError: vertex (-41) is not a vertex of the graph """ - cdef u_int + cdef int u_int cdef int v_int = self.get_vertex(v) + if v_int == -1 or not bitset_in((self._cg).active_vertices, v_int): + raise LookupError("vertex ({0}) is not a vertex of the graph".format(v)) for u_int in self._cg.out_neighbors(v_int): yield self.vertex_label(u_int) @@ -2292,7 +2314,7 @@ cdef class CGraphBackend(GenericGraphBackend): sage: g = graphs.PetersenGraph() sage: paths = g._backend.shortest_path_all_vertices(0) - sage: all([ len(paths[v]) == 0 or len(paths[v])-1 == g.distance(0,v) for v in g]) + sage: all((len(paths[v]) == 0 or len(paths[v])-1 == g.distance(0,v)) for v in g) True sage: g._backend.shortest_path_all_vertices(0, distance_flag=True) {0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2} @@ -2439,8 +2461,10 @@ cdef class CGraphBackend(GenericGraphBackend): ....: "Nurnberg": ["Wurzburg","Stuttgart","Munchen"], ....: "Stuttgart": ["Nurnberg"], ....: "Erfurt": ["Wurzburg"]}, implementation="c_graph") - sage: list(G.depth_first_search("Frankfurt")) - ['Frankfurt', 'Wurzburg', 'Nurnberg', 'Munchen', 'Kassel', 'Augsburg', 'Karlsruhe', 'Mannheim', 'Stuttgart', 'Erfurt'] + sage: list(G.depth_first_search("Stuttgart")) # py2 + ['Stuttgart', 'Nurnberg', 'Wurzburg', 'Frankfurt', 'Kassel', 'Munchen', 'Augsburg', 'Karlsruhe', 'Mannheim', 'Erfurt'] + sage: list(G.depth_first_search("Stuttgart")) # py3 + ['Stuttgart', 'Nurnberg', ...] """ return Search_iterator(self, v, @@ -2510,20 +2534,11 @@ cdef class CGraphBackend(GenericGraphBackend): sage: list(G.breadth_first_search(0)) [0, 1, 4, 5, 2, 6, 3, 9, 7, 8] - Visiting German cities using breadth-first search:: + Visiting European countries using breadth-first search:: - sage: G = Graph({"Mannheim": ["Frankfurt","Karlsruhe"], - ....: "Frankfurt": ["Mannheim","Wurzburg","Kassel"], - ....: "Kassel": ["Frankfurt","Munchen"], - ....: "Munchen": ["Kassel","Nurnberg","Augsburg"], - ....: "Augsburg": ["Munchen","Karlsruhe"], - ....: "Karlsruhe": ["Mannheim","Augsburg"], - ....: "Wurzburg": ["Frankfurt","Erfurt","Nurnberg"], - ....: "Nurnberg": ["Wurzburg","Stuttgart","Munchen"], - ....: "Stuttgart": ["Nurnberg"], - ....: "Erfurt": ["Wurzburg"]}, implementation="c_graph") - sage: list(G.breadth_first_search("Frankfurt")) - ['Frankfurt', 'Mannheim', 'Kassel', 'Wurzburg', 'Karlsruhe', 'Munchen', 'Erfurt', 'Nurnberg', 'Augsburg', 'Stuttgart'] + sage: G = graphs.EuropeMap(continental=True) + sage: list(G.breadth_first_search("Portugal")) + ['Portugal', 'Spain', ..., 'Greece'] """ return Search_iterator(self, v, @@ -2628,7 +2643,7 @@ cdef class CGraphBackend(GenericGraphBackend): component:: sage: g = digraphs.ButterflyGraph(3) - sage: all([[v] == g.strongly_connected_component_containing_vertex(v) for v in g]) + sage: all([v] == g.strongly_connected_component_containing_vertex(v) for v in g) True """ cdef set ans = set(self.depth_first_search(v)) diff --git a/src/sage/graphs/base/dense_graph.pyx b/src/sage/graphs/base/dense_graph.pyx index c4fc21f4e8d..ba7e2b9125c 100644 --- a/src/sage/graphs/base/dense_graph.pyx +++ b/src/sage/graphs/base/dense_graph.pyx @@ -691,7 +691,8 @@ cdef class DenseGraphBackend(CGraphBackend): objects:: sage: G.add_vertex((0, 1, 2)) - sage: G.vertices() + sage: sorted(list(G), + ....: key=lambda x: (isinstance(x, tuple), x)) [0, ... 29, diff --git a/src/sage/graphs/base/graph_backends.pyx b/src/sage/graphs/base/graph_backends.pyx index 076b1ffc557..090bf6c6fdc 100644 --- a/src/sage/graphs/base/graph_backends.pyx +++ b/src/sage/graphs/base/graph_backends.pyx @@ -872,77 +872,3 @@ class NetworkXGraphDeprecated(SageObject): G = networkx.Graph(new_adj) return G - -class NetworkXDiGraphDeprecated(SageObject): - """ - Class for unpickling old networkx.XDiGraph formats - - TESTS:: - - sage: import sage.graphs.base.graph_backends - """ - - def __init__(self): - """ - Issue deprecation warnings for the old networkx XDiGraph formats - - EXAMPLES:: - - sage: from sage.graphs.base.graph_backends import NetworkXDiGraphDeprecated - sage: NetworkXDiGraphDeprecated() - doctest:... - - """ - from sage.misc.superseded import deprecation - deprecation(10900, "Your digraph object is saved in an old format since networkx "+ - "was updated to 1.0.1. You can re-save your digraph by typing "+ - "digraph.save(filename) to make this warning go away.") - - def mutate(self): - """ - Change the old networkx XDiGraph format into the new one. - - OUTPUT: - - - The networkx.DiGraph or networkx.MultiDiGraph corresponding to the - unpickled data. - - EXAMPLES:: - - sage: from sage.graphs.base.graph_backends import NetworkXDiGraphDeprecated as NXDGD - sage: X = NXDGD() - sage: X.adj = {1: {2: 7}, 2: {1: [7, 8], 3: [4, 5, 6, 7]}} - sage: X.multiedges = True - sage: G = X.mutate() - sage: G.edges() - OutMultiEdgeDataView([(1, 2), (2, 1), (2, 3)]) - sage: G.edges(data=True) - OutMultiEdgeDataView([(1, 2, {'weight': 7}), - (2, 1, {8: {}, 7: {}}), - (2, 3, {4: {}, 5: {}, 6: {}, 7: {}})]) - - """ - import networkx - new_adj = {} - - for node1, edges in self.adj.iteritems(): - new_adj[node1] = {} - for node2, weights in edges.iteritems(): - new_adj[node1][node2] = {} - if weights is not None: - try: - for weight in weights: - new_adj[node1][node2][weight] = {} - except TypeError: - new_adj[node1][node2]['weight'] = weights - - if self.multiedges: - G = networkx.MultiDiGraph(new_adj) - else: - G = networkx.DiGraph(new_adj) - - return G - -from sage.misc.persist import register_unpickle_override -register_unpickle_override('networkx.xgraph','XGraph', NetworkXGraphDeprecated) -register_unpickle_override('networkx.xdigraph','XDiGraph', NetworkXDiGraphDeprecated) diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx index 49e48d6e706..3de5a2352c0 100644 --- a/src/sage/graphs/base/sparse_graph.pyx +++ b/src/sage/graphs/base/sparse_graph.pyx @@ -1384,7 +1384,7 @@ cdef class SparseGraphBackend(CGraphBackend): objects:: sage: G.add_vertex((0,1,2)) - sage: sorted(G.vertices(), + sage: sorted(list(G), ....: key=lambda x: (isinstance(x, tuple), x)) [0, ... @@ -1403,7 +1403,7 @@ cdef class SparseGraphBackend(CGraphBackend): """ Initialize a sparse graph with n vertices. - EXAMPLES: + EXAMPLES:: sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9) sage: D.add_edge(0,1,None,False) diff --git a/src/sage/graphs/base/static_sparse_graph.pxd b/src/sage/graphs/base/static_sparse_graph.pxd index cd0a40856b6..7fb0fa7725d 100644 --- a/src/sage/graphs/base/static_sparse_graph.pxd +++ b/src/sage/graphs/base/static_sparse_graph.pxd @@ -1,4 +1,4 @@ -from cpython cimport PyObject +from cpython.object cimport PyObject from libc.stdint cimport uint32_t, uint64_t, UINT32_MAX from sage.data_structures.bitset cimport * @@ -36,4 +36,4 @@ cdef uint32_t simple_BFS(short_digraph g, uint32_t *distances, uint32_t *predecessors, uint32_t *waiting_list, - bitset_t seen) \ No newline at end of file + bitset_t seen) diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 7c0c41812a0..4af6f31d116 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -700,8 +700,8 @@ def tarjan_strongly_connected_components(G): sage: D.strongly_connected_components() [[3], [0, 1, 2], [6], [5], [4]] sage: D = DiGraph([('a','b'), ('b','c'), ('c', 'd'), ('d', 'b'), ('c', 'e')]) - sage: D.strongly_connected_components() - [['e'], ['c', 'b', 'd'], ['a']] + sage: [sorted(scc) for scc in D.strongly_connected_components()] + [['e'], ['b', 'c', 'd'], ['a']] TESTS: diff --git a/src/sage/graphs/bliss.pyx b/src/sage/graphs/bliss.pyx index 6fc734a165e..d593029f57a 100644 --- a/src/sage/graphs/bliss.pyx +++ b/src/sage/graphs/bliss.pyx @@ -30,7 +30,6 @@ AUTHORS: import numpy from operator import itemgetter -from cpython cimport PyObject from libc.limits cimport LONG_MAX from cysignals.memory cimport check_calloc, sig_free @@ -89,7 +88,7 @@ cdef void add_gen(void *user_param, unsigned int n, const unsigned int *aut): for i in range(n): done[i] = False - gens, int_to_vertex = user_param + gens, int_to_vertex = user_param while True: while cur < n and done[cur]: @@ -540,11 +539,11 @@ cdef automorphism_group_gens_from_edge_list(int Vnr, Vout, Vin, int Lnr=1, label if directed: d = bliss_digraph_from_labelled_edges(Vnr, Lnr, Vout, Vin, labels, partition) - d.find_automorphisms(s, add_gen, data) + d.find_automorphisms(s, add_gen, data) del d else: g = bliss_graph_from_labelled_edges(Vnr, Lnr, Vout, Vin, labels, partition) - g.find_automorphisms(s, add_gen, data) + g.find_automorphisms(s, add_gen, data) del g return [[cyc for cyc in gen if cyc[0] is not None] for gen in gens] @@ -683,16 +682,6 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): 12 sage: automorphism_group(gg,[[0],[1,2,3,4]]).cardinality() # optional - bliss 6 - - Making sure that #25426 is fixed: - - sage: j = matrix([(3, 2, 1, 0, 0), - ....: (2, 2, 0, 1, 0), - ....: (1, 0, 3, 0, 2), - ....: (0, 1, 0, 2, 1), - ....: (0, 0, 2, 1, 2)]) - sage: j.automorphisms_of_rows_and_columns() - [((), ()), ((1,3)(2,5), (1,3)(2,5))] """ # We need this to convert the numbers from to # . This assertion should be true simply for memory reasons. @@ -736,7 +725,8 @@ cpdef automorphism_group(G, partition=None, use_edge_labels=True): gens = automorphism_group_gens_from_edge_list(Vnr, Vout, Vin, Lnr, labels, int2vert, partition, directed) from sage.groups.perm_gps.permgroup import PermutationGroup - return PermutationGroup(gens, domain=sorted(G)) + return PermutationGroup(gens, domain=list(G)) + ##################################################### # old direct interactions graphs <-> bliss graphs diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index 2e75b1ae8d4..e6648e8b01f 100755 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -581,14 +581,14 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): sage: from sage.graphs.centrality import centrality_closeness_top_k sage: g = graphs.PathGraph(10) sage: centrality_closeness_top_k(g, 4, 1) - Final performance ratio: 0.711111111111 + Final performance ratio: 0.711111111111... [(0.36, 5), (0.36, 4), (0.3333333333333333, 6), (0.3333333333333333, 3)] sage: g = digraphs.Path(10) sage: centrality_closeness_top_k(g, 5, 1) - Final performance ratio: 0.422222222222 + Final performance ratio: 0.422222222222... [(0.2, 0), (0.19753086419753085, 1), (0.19444444444444442, 2), diff --git a/src/sage/graphs/comparability.pyx b/src/sage/graphs/comparability.pyx index 30d34cfd1a4..0306ea0350c 100644 --- a/src/sage/graphs/comparability.pyx +++ b/src/sage/graphs/comparability.pyx @@ -256,8 +256,10 @@ def greedy_is_comparability(g, no_certificate = False, equivalence_class = False sage: g = graphs.PetersenGraph() sage: is_comparability(g) False - sage: is_comparability(g, no_certificate = True) + sage: is_comparability(g, no_certificate=True) # py2 (False, [0, 4, 9, 6, 1, 0]) + sage: is_comparability(g, no_certificate=True) # py3 + (False, [2, 1, 0, 4, 3, 2]) But the Bull graph is:: @@ -280,7 +282,7 @@ def greedy_is_comparability(g, no_certificate = False, equivalence_class = False # We add an edge between two vertices of h if they represent # opposed equivalence classes - for u,v in g.edges(labels = False): + for u,v in g.edge_iterator(labels=False): for i,s in enumerate(equivalence_classes[v]): if u in s: @@ -351,13 +353,17 @@ def greedy_is_comparability_with_certificate(g, certificate = False): The 5-cycle or the Petersen Graph are not transitively orientable:: sage: from sage.graphs.comparability import greedy_is_comparability_with_certificate as is_comparability - sage: is_comparability(graphs.CycleGraph(5), certificate = True) + sage: is_comparability(graphs.CycleGraph(5), certificate=True) # py2 (False, [1, 2, 3, 4, 0, 1]) + sage: is_comparability(graphs.CycleGraph(5), certificate=True) # py3 + (False, [2, 1, 0, 4, 3, 2]) sage: g = graphs.PetersenGraph() sage: is_comparability(g) False - sage: is_comparability(g, certificate = True) + sage: is_comparability(g, certificate=True) # py2 (False, [0, 4, 9, 6, 1, 0]) + sage: is_comparability(g, certificate=True) # py3 + (False, [2, 1, 0, 4, 3, 2]) But the Bull graph is:: @@ -486,7 +492,7 @@ def is_comparability_MILP(g, certificate=False, solver=None, verbose=0): d.add_vertices(g) o = p.get_values(o) - for u,v in g.edges(labels=False): + for u,v in g.edge_iterator(labels=False): if o[u,v] > .5: d.add_edge(u,v) else: @@ -701,8 +707,8 @@ def is_permutation(g, algorithm="greedy", certificate=False, check=True, return False, co_certif # Building the two orderings - tmp = co_certif.edges(labels=False) - for u,v in certif.edges(labels=False): + tmp = co_certif.edges(labels=False, sort=False) + for u,v in certif.edge_iterator(labels=False): co_certif.add_edge(v,u) certif.add_edges(tmp) diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index 831a4ab0451..21bad3214f9 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -380,10 +380,12 @@ def blocks_and_cut_vertices(G, algorithm="Tarjan_Boost", sort=False): ([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0]) sage: rings.blocks_and_cut_vertices() ([[0, 1, 4, 2, 3], [0, 6, 9, 7, 8]], [0]) - sage: blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage", sort=True) + sage: B, C = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage", sort=True) + sage: B, C ([[0, 1, 2, 3, 4], [0, 6, 7, 8, 9]], [0]) - sage: blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage", sort=False) - ([[0, 1, 2, 3, 4], [8, 9, 0, 6, 7]], [0]) + sage: B2, C2 = blocks_and_cut_vertices(rings, algorithm="Tarjan_Sage", sort=False) + sage: Set(map(Set, B)) == Set(map(Set, B2)) and set(C) == set(C2) + True The Petersen graph is biconnected, hence has no cut vertices:: @@ -2256,19 +2258,19 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0): sage: for u,v in G.edges(labels=False, sort=False): ....: G.add_path([u, G.add_vertex(), G.add_vertex(), v]) sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") - sage: Counter(u[0] for u in T) - Counter({'P': 15, 'S': 15, 'R': 1}) + sage: sorted(Counter(u[0] for u in T).items()) + [('P', 15), ('R', 1), ('S', 15)] sage: T = G.spqr_tree(algorithm="cleave") - sage: Counter(u[0] for u in T) - Counter({'P': 15, 'S': 15, 'R': 1}) + sage: sorted(Counter(u[0] for u in T).items()) + [('P', 15), ('R', 1), ('S', 15)] sage: for u,v in G.edges(labels=False, sort=False): ....: G.add_path([u, G.add_vertex(), G.add_vertex(), v]) sage: T = G.spqr_tree(algorithm="Hopcroft_Tarjan") - sage: Counter(u[0] for u in T) - Counter({'S': 75, 'P': 60, 'R': 1}) - sage: T = G.spqr_tree(algorithm="cleave") # long time - sage: Counter(u[0] for u in T) # long time - Counter({'S': 75, 'P': 60, 'R': 1}) + sage: sorted(Counter(u[0] for u in T).items()) + [('P', 60), ('R', 1), ('S', 75)] + sage: T = G.spqr_tree(algorithm="cleave") # long time + sage: sorted(Counter(u[0] for u in T).items()) # long time + [('P', 60), ('R', 1), ('S', 75)] TESTS:: @@ -2413,7 +2415,7 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0): try: if block[1].has_edge(e): Tree.add_edge(block, P_block) - except: + except LookupError: continue if num == 2: # When 2 S or R blocks are separated by a 2-cut without edge, we @@ -2437,7 +2439,7 @@ def spqr_tree(G, algorithm="Hopcroft_Tarjan", solver=None, verbose=0): if block[1].has_edge(e): Tree.add_edge(block, P_block) break - except: + except LookupError: continue return Tree @@ -2794,7 +2796,10 @@ cdef class TriconnectivitySPQR: ....: (6, 7), (8, 9), (8, 11), (8, 12), (9, 10), (9, 11), (9, 12), ....: (10, 11), (10, 12)]) sage: tric = TriconnectivitySPQR(G) - sage: tric.print_triconnected_components() + sage: T = tric.get_spqr_tree() + sage: G.is_isomorphic(spqr_tree_to_graph(T)) + True + sage: tric.print_triconnected_components() # py2 Polygon: [(6, 7, None), (5, 6, None), (7, 5, 'newVEdge0')] Bond: [(7, 5, 'newVEdge0'), (5, 7, 'newVEdge1'), (5, 7, None)] Polygon: [(5, 7, 'newVEdge1'), (4, 7, None), (5, 4, 'newVEdge2')] @@ -2822,6 +2827,9 @@ cdef class TriconnectivitySPQR: sage: G = Graph([(1, 2), (1, 5), (1, 5), (2, 3), (2, 3), (3, 4), (4, 5)], multiedges=True) sage: tric = TriconnectivitySPQR(G) + sage: T = tric.get_spqr_tree() + sage: G.is_isomorphic(spqr_tree_to_graph(T)) + True sage: tric.print_triconnected_components() Bond: [(1, 5, None), (1, 5, None), (1, 5, 'newVEdge0')] Bond: [(2, 3, None), (2, 3, None), (2, 3, 'newVEdge1')] @@ -3998,12 +4006,16 @@ cdef class TriconnectivitySPQR: An example from [Hopcroft1973]_:: sage: from sage.graphs.connectivity import TriconnectivitySPQR + sage: from sage.graphs.connectivity import spqr_tree_to_graph sage: G = Graph([(1, 2), (1, 4), (1, 8), (1, 12), (1, 13), (2, 3), ....: (2, 13), (3, 4), (3, 13), (4, 5), (4, 7), (5, 6), (5, 7), (5, 8), ....: (6, 7), (8, 9), (8, 11), (8, 12), (9, 10), (9, 11), (9, 12), ....: (10, 11), (10, 12)]) sage: tric = TriconnectivitySPQR(G) - sage: tric.print_triconnected_components() + sage: T = tric.get_spqr_tree() + sage: G.is_isomorphic(spqr_tree_to_graph(T)) + True + sage: tric.print_triconnected_components() # py2 Polygon: [(6, 7, None), (5, 6, None), (7, 5, 'newVEdge0')] Bond: [(7, 5, 'newVEdge0'), (5, 7, 'newVEdge1'), (5, 7, None)] Polygon: [(5, 7, 'newVEdge1'), (4, 7, None), (5, 4, 'newVEdge2')] @@ -4016,6 +4028,19 @@ cdef class TriconnectivitySPQR: Bond: [(1, 4, None), (1, 4, 'newVEdge9'), (1, 4, 'newVEdge10')] Polygon: [(1, 4, 'newVEdge10'), (3, 4, None), (1, 3, 'newVEdge11')] Triconnected: [(2, 3, None), (2, 13, None), (1, 2, None), (1, 3, 'newVEdge11'), (1, 13, None), (3, 13, None)] + sage: tric.print_triconnected_components() # py3 + Triconnected: [(8, 9, None), (9, 12, None), (9, 11, None), (8, 11, None), (10, 11, None), (9, 10, None), (10, 12, None), (8, 12, 'newVEdge0')] + Bond: [(8, 12, None), (8, 12, 'newVEdge0'), (8, 12, 'newVEdge1')] + Polygon: [(6, 7, None), (5, 6, None), (7, 5, 'newVEdge2')] + Bond: [(7, 5, 'newVEdge2'), (5, 7, 'newVEdge3'), (5, 7, None)] + Polygon: [(5, 7, 'newVEdge3'), (4, 7, None), (5, 4, 'newVEdge4')] + Bond: [(5, 4, 'newVEdge4'), (4, 5, 'newVEdge5'), (4, 5, None)] + Polygon: [(4, 5, 'newVEdge5'), (5, 8, None), (1, 4, 'newVEdge9'), (1, 8, 'newVEdge10')] + Triconnected: [(1, 2, None), (2, 13, None), (1, 13, None), (3, 13, None), (2, 3, None), (1, 3, 'newVEdge7')] + Polygon: [(1, 3, 'newVEdge7'), (3, 4, None), (1, 4, 'newVEdge8')] + Bond: [(1, 4, None), (1, 4, 'newVEdge8'), (1, 4, 'newVEdge9')] + Bond: [(1, 8, None), (1, 8, 'newVEdge10'), (1, 8, 'newVEdge11')] + Polygon: [(8, 12, 'newVEdge1'), (1, 8, 'newVEdge11'), (1, 12, None)] """ # The types are {0: "Bond", 1: "Polygon", 2: "Triconnected"} cdef list prefix = ["Bond", "Polygon", "Triconnected"] diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 2066cfa223d..6d1f93b7237 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -1274,26 +1274,17 @@ def in_degree_iterator(self, vertices=None, labels=False): EXAMPLES:: sage: D = graphs.Grid2dGraph(2,4).to_directed() - sage: for i in D.in_degree_iterator(): - ....: print(i) - 3 - 3 - 2 - 2 - 3 - 2 - 2 - 3 - sage: for i in D.in_degree_iterator(labels=True): - ....: print(i) - ((0, 1), 3) - ((1, 2), 3) - ((0, 0), 2) - ((0, 3), 2) - ((1, 1), 3) - ((1, 3), 2) - ((1, 0), 2) - ((0, 2), 3) + sage: sorted(D.in_degree_iterator()) + [2, 2, 2, 2, 3, 3, 3, 3] + sage: sorted(D.in_degree_iterator(labels=True)) + [((0, 0), 2), + ((0, 1), 3), + ((0, 2), 3), + ((0, 3), 2), + ((1, 0), 2), + ((1, 1), 3), + ((1, 2), 3), + ((1, 3), 2)] """ if vertices is None: vertices = self.vertex_iterator() @@ -1354,26 +1345,17 @@ def out_degree_iterator(self, vertices=None, labels=False): EXAMPLES:: sage: D = graphs.Grid2dGraph(2,4).to_directed() - sage: for i in D.out_degree_iterator(): - ....: print(i) - 3 - 3 - 2 - 2 - 3 - 2 - 2 - 3 - sage: for i in D.out_degree_iterator(labels=True): - ....: print(i) - ((0, 1), 3) - ((1, 2), 3) - ((0, 0), 2) - ((0, 3), 2) - ((1, 1), 3) - ((1, 3), 2) - ((1, 0), 2) - ((0, 2), 3) + sage: sorted(D.out_degree_iterator()) + [2, 2, 2, 2, 3, 3, 3, 3] + sage: sorted(D.out_degree_iterator(labels=True)) + [((0, 0), 2), + ((0, 1), 3), + ((0, 2), 3), + ((0, 3), 2), + ((1, 0), 2), + ((1, 1), 3), + ((1, 2), 3), + ((1, 3), 2)] """ if vertices is None: vertices = self.vertex_iterator() @@ -1598,8 +1580,8 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, solver Loops are part of the feedback edge set (:trac:`23989`):: sage: D = digraphs.DeBruijn(2, 2) - sage: D.loops(labels=None) - [('11', '11'), ('00', '00')] + sage: sorted(D.loops(labels=None)) + [('00', '00'), ('11', '11')] sage: FAS = D.feedback_edge_set(value_only=False) sage: all(l in FAS for l in D.loops(labels=None)) True @@ -1917,11 +1899,11 @@ def reverse_edge(self, u, v=None, label=None, inplace=True, multiedges=None): sage: D.edges() [(2, 1, 'label')] sage: D.add_edge((1, 2), 'label') - sage: D.edges() - [(2, 1, 'label'), ((1, 2), 'label', None)] + sage: D.edges(sort=False) + [((1, 2), 'label', None), (2, 1, 'label')] sage: D.reverse_edge((1, 2), 'label') - sage: D.edges() - [(2, 1, 'label'), ('label', (1, 2), None)] + sage: D.edges(sort=False) + [('label', (1, 2), None), (2, 1, 'label')] TESTS:: @@ -2126,17 +2108,22 @@ def _all_paths_iterator(self, vertex, ending_vertices=None, sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) sage: pi = g._all_paths_iterator('a') - sage: for _ in range(5): print(next(pi)) + sage: for _ in range(5): # py2 + ....: print(next(pi)) # py2 ['a', 'a'] ['a', 'b'] ['a', 'a', 'a'] ['a', 'a', 'b'] ['a', 'b', 'c'] + sage: pi = g._all_paths_iterator('a') + sage: [len(next(pi)) - 1 for _ in range(5)] + [1, 1, 2, 2, 2] :: sage: pi = g._all_paths_iterator('b') - sage: for _ in range(5): print(next(pi)) + sage: for _ in range(5): + ....: print(next(pi)) ['b', 'c'] ['b', 'c', 'd'] ['b', 'c', 'd', 'c'] @@ -2149,45 +2136,58 @@ def _all_paths_iterator(self, vertex, ending_vertices=None, finite but may take a long time to compute:: sage: pi = g._all_paths_iterator('a', simple=True) - sage: list(pi) + sage: sorted(pi) [['a', 'a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd']] sage: pi = g._all_paths_iterator('d', simple=True) - sage: list(pi) + sage: sorted(pi) [['d', 'c'], ['d', 'c', 'd']] It is possible to specify the allowed ending vertices:: sage: pi = g._all_paths_iterator('a', ending_vertices=['c']) - sage: for _ in range(5): print(next(pi)) + sage: for _ in range(5): # py2 + ....: print(next(pi)) # py2 ['a', 'b', 'c'] ['a', 'a', 'b', 'c'] ['a', 'a', 'a', 'b', 'c'] ['a', 'b', 'c', 'd', 'c'] ['a', 'a', 'a', 'a', 'b', 'c'] + sage: pi = g._all_paths_iterator('a', ending_vertices=['c']) + sage: [len(next(pi)) - 1 for _ in range(5)] + [2, 3, 4, 4, 5] sage: pi = g._all_paths_iterator('a', ending_vertices=['a', 'b']) - sage: for _ in range(5): print(next(pi)) + sage: for _ in range(5): # py2 + ....: print(next(pi)) # py2 ['a', 'a'] ['a', 'b'] ['a', 'a', 'a'] ['a', 'a', 'b'] ['a', 'a', 'a', 'a'] + sage: pi = g._all_paths_iterator('a', ending_vertices=['a', 'b']) + sage: [len(next(pi)) - 1 for _ in range(5)] + [1, 1, 2, 2, 3] One can bound the length of the paths:: sage: pi = g._all_paths_iterator('d', max_length=3) - sage: list(pi) + sage: sorted(pi) [['d', 'c'], ['d', 'c', 'd'], ['d', 'c', 'd', 'c']] Or include the trivial empty path:: sage: pi = g._all_paths_iterator('a', max_length=3, trivial=True) - sage: list(pi) + sage: sorted(list(pi), key=lambda x:(len(x), x)) [['a'], ['a', 'a'], ['a', 'b'], ['a', 'a', 'a'], ['a', 'a', 'b'], ['a', 'b', 'c'], ['a', 'a', 'a', 'a'], ['a', 'a', 'a', 'b'], ['a', 'a', 'b', 'c'], ['a', 'b', 'c', 'd']] + sage: pi = g._all_paths_iterator('a', max_length=3, trivial=True) + sage: [len(p) - 1 for p in pi] + [0, 1, 1, 2, 2, 2, 3, 3, 3, 3] """ if ending_vertices is None: ending_vertices = self + else: + ending_vertices = frozenset(ending_vertices) if max_length is None: from sage.rings.infinity import Infinity max_length = Infinity @@ -2214,8 +2214,9 @@ def _all_paths_iterator(self, vertex, ending_vertices=None, # not exit the new vertex again, so we do not consider it # for further extension, but just yield it immediately. See # trac #12385. + frozen_path = frozenset(path) for neighbor in self.neighbor_out_iterator(path[-1]): - if neighbor not in path: + if neighbor not in frozen_path: queue.append(path + [neighbor]) elif ( neighbor == path[0] and neighbor in ending_vertices ): @@ -2274,7 +2275,8 @@ def all_paths_iterator(self, starting_vertices=None, ending_vertices=None, sage: g = DiGraph({'a': ['a', 'b'], 'b': ['c'], 'c': ['d'], 'd': ['c']}, loops=True) sage: pi = g.all_paths_iterator() - sage: for _ in range(7): print(next(pi)) + sage: for _ in range(7): # py2 + ....: print(next(pi)) # py2 ['a', 'a'] ['a', 'b'] ['b', 'c'] @@ -2282,18 +2284,26 @@ def all_paths_iterator(self, starting_vertices=None, ending_vertices=None, ['d', 'c'] ['a', 'a', 'a'] ['a', 'a', 'b'] + sage: pi = g.all_paths_iterator() + sage: [len(next(pi)) - 1 for _ in range(7)] + [1, 1, 1, 1, 1, 2, 2] It is possible to precise the allowed starting and/or ending vertices:: sage: pi = g.all_paths_iterator(starting_vertices=['a']) - sage: for _ in range(5): print(next(pi)) + sage: for _ in range(5): # py2 + ....: print(next(pi)) # py2 ['a', 'a'] ['a', 'b'] ['a', 'a', 'a'] ['a', 'a', 'b'] ['a', 'b', 'c'] + sage: pi = g.all_paths_iterator(starting_vertices=['a']) + sage: [len(next(pi)) - 1 for _ in range(5)] + [1, 1, 2, 2, 2] sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b']) - sage: for _ in range(5): print(next(pi)) + sage: for _ in range(5): + ....: print(next(pi)) ['a', 'b'] ['a', 'a', 'b'] ['a', 'a', 'a', 'b'] @@ -2304,37 +2314,49 @@ def all_paths_iterator(self, starting_vertices=None, ending_vertices=None, :meth:`all_simple_paths`):: sage: pi = g.all_paths_iterator(simple=True) - sage: list(pi) + sage: sorted(list(pi), key=lambda x:(len(x), x)) [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], - ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], - ['d', 'c', 'd'], ['a', 'b', 'c', 'd']] + ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], + ['a', 'b', 'c', 'd']] + sage: pi = g.all_paths_iterator(simple=True) + sage: [len(p) - 1 for p in pi] + [1, 1, 1, 1, 1, 2, 2, 2, 2, 3] Or simply bound the length of the enumerated paths:: sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b', 'c'], max_length=6) - sage: list(pi) - [['a', 'b'], ['a', 'a', 'b'], ['a', 'b', 'c'], - ['a', 'a', 'a', 'b'], ['a', 'a', 'b', 'c'], - ['a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'b', 'c'], - ['a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'b'], - ['a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'b', 'c', 'd', 'c'], + sage: sorted(list(pi), key=lambda x:(len(x), x)) + [['a', 'b'], ['a', 'a', 'b'], ['a', 'b', 'c'], ['a', 'a', 'a', 'b'], + ['a', 'a', 'b', 'c'], ['a', 'a', 'a', 'a', 'b'], + ['a', 'a', 'a', 'b', 'c'], ['a', 'b', 'c', 'd', 'c'], + ['a', 'a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'a', 'b', 'c'], + ['a', 'a', 'b', 'c', 'd', 'c'], ['a', 'a', 'a', 'a', 'a', 'a', 'b'], ['a', 'a', 'a', 'a', 'a', 'b', 'c'], ['a', 'a', 'a', 'b', 'c', 'd', 'c'], ['a', 'b', 'c', 'd', 'c', 'd', 'c']] + sage: pi = g.all_paths_iterator(starting_vertices=['a'], ending_vertices=['b', 'c'], max_length=6) + sage: [len(p) - 1 for p in pi] + [1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6] By default, empty paths are not enumerated, but it may be parametrized:: sage: pi = g.all_paths_iterator(simple=True, trivial=True) - sage: list(pi) + sage: sorted(list(pi), key=lambda x:(len(x), x)) [['a'], ['b'], ['c'], ['d'], ['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], ['a', 'b', 'c', 'd']] + sage: pi = g.all_paths_iterator(simple=True, trivial=True) + sage: [len(p) - 1 for p in pi] + [0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3] sage: pi = g.all_paths_iterator(simple=True, trivial=False) - sage: list(pi) + sage: sorted(list(pi), key=lambda x:(len(x), x)) [['a', 'a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'c'], - ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], - ['d', 'c', 'd'], ['a', 'b', 'c', 'd']] + ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'c'], ['d', 'c', 'd'], + ['a', 'b', 'c', 'd']] + sage: pi = g.all_paths_iterator(simple=True, trivial=False) + sage: [len(p) - 1 for p in pi] + [1, 1, 1, 1, 1, 2, 2, 2, 2, 3] """ if starting_vertices is None: starting_vertices = self diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index 730f497f33b..6a08789ca48 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -19,25 +19,26 @@ :widths: 30, 70 :delim: | - :meth:`~DiGraphGenerators.ButterflyGraph` | Returns a n-dimensional butterfly graph. - :meth:`~DiGraphGenerators.Circuit` | Returns the circuit on `n` vertices. - :meth:`~DiGraphGenerators.Circulant` | Returns a circulant digraph on `n` vertices from a set of integers. + :meth:`~DiGraphGenerators.ButterflyGraph` | Return a `n`-dimensional butterfly graph. + :meth:`~DiGraphGenerators.Circuit` | Return the circuit on `n` vertices. + :meth:`~DiGraphGenerators.Circulant` | Return a circulant digraph on `n` vertices from a set of integers. :meth:`~DiGraphGenerators.Complete` | Return a complete digraph on `n` vertices. - :meth:`~DiGraphGenerators.DeBruijn` | Returns the De Bruijn digraph with parameters `k,n`. - :meth:`~DiGraphGenerators.GeneralizedDeBruijn` | Returns the generalized de Bruijn digraph of order `n` and degree `d`. - :meth:`~DiGraphGenerators.ImaseItoh` | Returns the digraph of Imase and Itoh of order `n` and degree `d`. - :meth:`~DiGraphGenerators.Kautz` | Returns the Kautz digraph of degree `d` and diameter `D`. + :meth:`~DiGraphGenerators.DeBruijn` | Return the De Bruijn digraph with parameters `k,n`. + :meth:`~DiGraphGenerators.GeneralizedDeBruijn` | Return the generalized de Bruijn digraph of order `n` and degree `d`. + :meth:`~DiGraphGenerators.ImaseItoh` | Return the digraph of Imase and Itoh of order `n` and degree `d`. + :meth:`~DiGraphGenerators.Kautz` | Return the Kautz digraph of degree `d` and diameter `D`. + :meth:`~DiGraphGenerators.nauty_directg` | Return an iterator yielding digraphs using nauty's ``directg`` program. :meth:`~DiGraphGenerators.Paley` | Return a Paley digraph on `q` vertices. - :meth:`~DiGraphGenerators.Path` | Returns a directed path on `n` vertices. + :meth:`~DiGraphGenerators.Path` | Return a directed path on `n` vertices. :meth:`~DiGraphGenerators.RandomDirectedGNC` | Returns a random GNC (growing network with copying) digraph with `n` vertices. :meth:`~DiGraphGenerators.RandomDirectedGNM` | Returns a random labelled digraph on `n` nodes and `m` arcs. :meth:`~DiGraphGenerators.RandomDirectedGNP` | Returns a random digraph on `n` nodes. :meth:`~DiGraphGenerators.RandomDirectedGN` | Returns a random GN (growing network) digraph with `n` vertices. :meth:`~DiGraphGenerators.RandomDirectedGNR` | Returns a random GNR (growing network with redirection) digraph. :meth:`~DiGraphGenerators.RandomSemiComplete` | Return a random semi-complete digraph of order `n`. - :meth:`~DiGraphGenerators.RandomTournament` | Returns a random tournament on `n` vertices. - :meth:`~DiGraphGenerators.TransitiveTournament`| Returns a transitive tournament on `n` vertices. - :meth:`~DiGraphGenerators.tournaments_nauty` | Returns all tournaments on `n` vertices using Nauty. + :meth:`~DiGraphGenerators.RandomTournament` | Return a random tournament on `n` vertices. + :meth:`~DiGraphGenerators.TransitiveTournament`| Return a transitive tournament on `n` vertices. + :meth:`~DiGraphGenerators.tournaments_nauty` | Iterator over all tournaments on `n` vertices using Nauty. AUTHORS: @@ -62,12 +63,14 @@ ################################################################################ from __future__ import print_function, division from six.moves import range +from six import PY2 from sage.cpython.string import bytes_to_str import sys from sage.misc.randstate import current_randstate from sage.graphs.digraph import DiGraph - +from sage.graphs.graph import Graph +import subprocess class DiGraphGenerators(): r""" @@ -223,23 +226,24 @@ class DiGraphGenerators(): """ def ButterflyGraph(self, n, vertices='strings'): - """ - Returns a n-dimensional butterfly graph. The vertices consist of - pairs (v,i), where v is an n-dimensional tuple (vector) with binary - entries (or a string representation of such) and i is an integer in - [0..n]. A directed edge goes from (v,i) to (w,i+1) if v and w are - identical except for possibly v[i] != w[i]. + r""" + Return a `n`-dimensional butterfly graph. - A butterfly graph has `(2^n)(n+1)` vertices and - `n2^{n+1}` edges. + The vertices consist of pairs `(v, i)`, where `v` is an `n`-dimensional + tuple (vector) with binary entries (or a string representation of such) + and `i` is an integer in `[0..n]`. A directed edge goes from `(v, i)` to + `(w, i + 1)` if `v` and `w` are identical except for possibly when `v[i] + \neq w[i]`. - INPUT: + A butterfly graph has `(2^n)(n+1)` vertices and `n2^{n+1}` edges. + INPUT: - - ``vertices`` - 'strings' (default) or 'vectors', - specifying whether the vertices are zero-one strings or actually - tuples over GF(2). + - ``n`` -- integer; + - ``vertices`` -- string (default: ``'strings'``); specifies whether the + vertices are zero-one strings (default) or tuples over GF(2) + (``vertices='vectors'``) EXAMPLES:: @@ -277,46 +281,61 @@ def ButterflyGraph(self, n, vertices='strings'): (((1, 1), 0), ((1, 1), 1)), (((1, 1), 1), ((1, 0), 2)), (((1, 1), 1), ((1, 1), 2))] + + TESTS:: + + sage: digraphs.ButterflyGraph(0) + 0-dimensional Butterfly: Digraph on 0 vertices + sage: digraphs.ButterflyGraph(-1) + Traceback (most recent call last): + ... + ValueError: the number of dimensions must be positive """ + if n == 0: + return DiGraph(name="0-dimensional Butterfly") + if n < 0: + raise ValueError("the number of dimensions must be positive") + # We could switch to Sage integers to handle arbitrary n. - if vertices=='strings': - if n>=31: - raise NotImplementedError("vertices='strings' is only valid for n<=30.") + if vertices == 'strings': + if n >= 31: + raise NotImplementedError("vertices='strings' is only valid for n <= 30") from sage.graphs.generic_graph_pyx import int_to_binary_string butterfly = {} for v in range(2 ** n): + bv = int_to_binary_string(v) + # pad and reverse the string + padded_bv = ('0' * (n - len(bv)) + bv)[::-1] for i in range(n): w = v w ^= (1 << i) # push 1 to the left by i and xor with w - bv = int_to_binary_string(v) bw = int_to_binary_string(w) - # pad and reverse the strings - padded_bv = ('0'*(n-len(bv))+bv)[::-1] - padded_bw = ('0'*(n-len(bw))+bw)[::-1] - butterfly[(padded_bv,i)]=[(padded_bv,i+1), (padded_bw,i+1)] - elif vertices=='vectors': + padded_bw = ('0' * (n - len(bw)) + bw)[::-1] + butterfly[(padded_bv, i)] = [(padded_bv, i + 1), (padded_bw, i + 1)] + elif vertices == 'vectors': from sage.modules.free_module import VectorSpace from sage.rings.finite_rings.finite_field_constructor import FiniteField from copy import copy butterfly = {} - for v in VectorSpace(FiniteField(2),n): + for v in VectorSpace(FiniteField(2), n): + # We must call tuple since vectors are mutable. To obtain a + # vector from the tuple tv, just call vector(tv). + tv = tuple(v) for i in range(n): - w=copy(v) - w[i] += 1 # Flip the ith bit - # We must call tuple since vectors are mutable. To obtain - # a vector from the tuple t, just call vector(t). - butterfly[(tuple(v),i)]=[(tuple(v),i+1), (tuple(w),i+1)] + w = copy(v) + w[i] += 1 # Flip the ith bit + butterfly[(tv, i)] = [(tv, i + 1), (tuple(w), i + 1)] else: - raise NotImplementedError("vertices must be 'strings' or 'vectors'.") - return DiGraph(butterfly) + raise NotImplementedError("vertices must be 'strings' or 'vectors'") + return DiGraph(butterfly, name="{}-dimensional Butterfly".format(n)) - def Path(self,n): + def Path(self, n): r""" - Returns a directed path on `n` vertices. + Return a directed path on `n` vertices. INPUT: - - ``n`` (integer) -- number of vertices in the path. + - ``n`` -- integer; number of vertices in the path EXAMPLES:: @@ -328,13 +347,12 @@ def Path(self,n): sage: g.automorphism_group().cardinality() 1 """ - g = DiGraph(n) - g.name("Path") + g = DiGraph(n, name="Path") if n: g.add_path(list(range(n))) - g.set_pos({i:(i,0) for i in range(n)}) + g.set_pos({i: (i,0) for i in range(n)}) return g def Paley(self, q): @@ -392,7 +410,7 @@ def Paley(self, q): def TransitiveTournament(self, n): r""" - Returns a transitive tournament on `n` vertices. + Return a transitive tournament on `n` vertices. In this tournament there is an edge from `i` to `j` if `iA" indicates a successful initiation of the program with some - information on the arguments, while a line beginning with ">E" - indicates an error with the input. + - ``debug`` -- boolean (default: ``False``); if ``True`` the first line + of genbg's output to standard error is captured and the first call to + the generator's ``next()`` function will return this line as a string. + A line leading with ">A" indicates a successful initiation of the + program with some information on the arguments, while a line beginning + with ">E" indicates an error with the input. - - ``options`` (string) -- anything else that should be forwarded as - input to Nauty's genbg. See its documentation for more information : + - ``options`` -- string; anything else that should be forwarded as input + to Nauty's genbg. See its documentation for more information : ``_. - - .. NOTE:: - - To use this method you must first install the Nauty spkg. - EXAMPLES:: sage: for g in digraphs.tournaments_nauty(4): @@ -528,22 +539,20 @@ def tournaments_nauty(self, n, sage: [len(list(tournaments(x, strongly_connected = True))) for x in range(1,9)] [1, 0, 1, 1, 6, 35, 353, 6008] """ - import subprocess - nauty_input = options if min_out_degree is None: min_out_degree = 0 if max_out_degree is None: - max_out_degree = n-1 + max_out_degree = n - 1 - nauty_input += " -d"+str(min_out_degree) - nauty_input += " -D"+str(max_out_degree) + nauty_input += " -d" + str(min_out_degree) + nauty_input += " -D" + str(max_out_degree) if strongly_connected: nauty_input += " -c" - nauty_input += " "+str(n) +" " + nauty_input += " " + str(n) + " " sp = subprocess.Popen("gentourng {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, @@ -565,18 +574,123 @@ def tournaments_nauty(self, n, j = 1 for b in s[:-1]: if b == '0': - G.add_edge(i,j) + G.add_edge(i, j) else: - G.add_edge(j,i) + G.add_edge(j, i) - if j == n-1: + if j == n - 1: i += 1 - j = i+1 + j = i + 1 else: j += 1 yield G + def nauty_directg(self, graphs, options="", debug=False): + r""" + Return an iterator yielding digraphs using nauty's ``directg`` program. + + Description from directg --help: + Read undirected graphs and orient their edges in all possible ways. + Edges can be oriented in either or both directions (3 possibilities). + Isomorphic directed graphs derived from the same input are suppressed. + If the input graphs are non-isomorphic then the output graphs are also. + + INPUT: + + - ``graphs`` -- a :class:`Graph` or an iterable containing :class:`Graph` + the graph6 string of these graphs is used as an input for ``directg``. + + - ``options`` (str) -- a string passed to directg as if it was run at + a system command line. Available options from directg --help:: + + -e# | -e#:# specify a value or range of the total number of arcs + -o orient each edge in only one direction, never both + -f# Use only the subgroup that fixes the first # vertices setwise + -V only output graphs with nontrivial groups (including exchange of + isolated vertices). The -f option is respected. + -s#/# Make only a fraction of the orientations: The first integer is + the part number (first is 0) and the second is the number of + parts. Splitting is done per input graph independently. + + - ``debug`` (boolean) -- default: ``False`` - if ``True`` + directg standard error and standard output are displayed. + + EXAMPLES:: + + sage: gen = graphs.nauty_geng("-c 3") + sage: dgs = list(digraphs.nauty_directg(gen)) + sage: len(dgs) + 13 + sage: dgs[0] + Digraph on 3 vertices + sage: dgs[0]._bit_vector() + '001001000' + sage: len(list(digraphs.nauty_directg(graphs.PetersenGraph(), options="-o"))) + 324 + + TESTS:: + + sage: g = digraphs.nauty_directg(graphs.PetersenGraph(), options="-o -G") + sage: next(g) + Traceback (most recent call last): + ... + ValueError: directg output options [-u|-T|-G] are not allowed + sage: next(digraphs.nauty_directg(graphs.nauty_geng("-c 3"), + ....: options="-o", debug=True)) + &BH? + &BGO + &B?o + &BX? + &BP_ + + Digraph on 3 vertices + + .. SEEALSO:: + + - :meth:`~sage.graphs.graph.Graph.orientations` + """ + if '-u' in options or '-T' in options or '-G' in options: + raise ValueError("directg output options [-u|-T|-G] are not allowed") + + if isinstance(graphs, Graph): + graphs = [graphs] + elif not graphs: + return + + if '-q' not in options: + options += ' -q' + + if PY2: + enc_kwargs = {} + else: + enc_kwargs = {'encoding': 'latin-1'} + + # Build directg input (graphs6 format) + input = ''.join(g.graph6_string()+'\n' for g in graphs) + sub = subprocess.Popen('directg {0}'.format(options), + shell=True, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.STDOUT, + **enc_kwargs) + out, err = sub.communicate(input=input) + + if debug: + if err: + print(err) + + if out: + print(out) + + for l in out.split('\n'): + # directg return graphs in the digraph6 format. + # digraph6 is very similar with the dig6 format used in sage : + # digraph6_string = '&' + dig6_string + # digraph6 specifications: + # http://users.cecs.anu.edu.au/~bdm/data/formats.txt + if l and l[0] == '&': + yield DiGraph(l[1:], format='dig6') def Complete(self, n, loops=False): r""" @@ -584,10 +698,10 @@ def Complete(self, n, loops=False): INPUT: - - ``n`` (integer) -- number of vertices. + - ``n`` -- integer; number of vertices - - ``loops`` (boolean) -- whether to add loops or not, i.e., edges from - `u` to itself. + - ``loops`` -- boolean (default: ``False``); whether to add loops or + not, i.e., edges from `u` to itself .. SEEALSO:: @@ -611,22 +725,22 @@ def Complete(self, n, loops=False): ... ValueError: the number of vertices cannot be strictly negative """ - G = DiGraph(n, name="Complete digraph"+(" with loops" if loops else ''), loops=loops) + G = DiGraph(n, name="Complete digraph" + (" with loops" if loops else ''), loops=loops) if loops: - G.add_edges((u,u) for u in range(n)) + G.add_edges((u, u) for u in range(n)) - G.add_edges((u,v) for u in range(n) for v in range(n) if u!=v) + G.add_edges((u, v) for u in range(n) for v in range(n) if u != v) G._circle_embedding(list(range(n))) return G - def Circuit(self,n): + def Circuit(self, n): r""" - Returns the circuit on `n` vertices + Return the circuit on `n` vertices. - The circuit is an oriented ``CycleGraph`` + The circuit is an oriented ``CycleGraph``. EXAMPLES: @@ -636,30 +750,28 @@ def Circuit(self,n): sage: len(circuit.strongly_connected_components()) == 1 True """ - g = DiGraph(n) - g.name("Circuit") + g = DiGraph(n, name="Circuit") - if n==0: - return g - elif n == 1: + if n == 1: g.allow_loops(True) - g.add_edge(0,0) - return g - else: - g.add_edges([(i,i+1) for i in range(n-1)]) - g.add_edge(n-1,0) + g.add_edge(0, 0) return g + elif n: + g.add_edges(zip(range(n - 1), range(1, n))) + g.add_edge(n - 1, 0) + return g - def Circulant(self,n,integers): + def Circulant(self, n, integers): r""" - Returns a circulant digraph on `n` vertices from a set of integers. + Return a circulant digraph on `n` vertices from a set of integers. INPUT: - - ``n`` (integer) -- number of vertices. + - ``n`` -- integer; number of vertices - - ``integers`` -- the list of integers such that there is an edge from - `i` to `j` if and only if ``(j-i)%n in integers``. + - ``integers`` -- iterable container (list, set, etc.) of integers such + that there is an edge from `i` to `j` if and only if ``(j-i)%n in + integers`` EXAMPLES:: @@ -671,11 +783,11 @@ def Circulant(self,n,integers): sage: digraphs.Circulant(13,[3,5,7,"hey"]) Traceback (most recent call last): ... - ValueError: The list must contain only relative integers. + ValueError: the list must contain only integers sage: digraphs.Circulant(3,[3,5,7,3.4]) Traceback (most recent call last): ... - ValueError: The list must contain only relative integers. + ValueError: the list must contain only integers """ from sage.rings.integer_ring import ZZ @@ -683,21 +795,21 @@ def Circulant(self,n,integers): loops = False for i in integers: if not i in ZZ: - raise ValueError("The list must contain only relative integers.") - if (i%n) == 0: + raise ValueError("the list must contain only integers") + if not i % n: loops = True - G = DiGraph(n, name="Circulant graph ("+str(integers)+")", loops=loops) + G = DiGraph(n, name="Circulant graph (" + str(integers) + ")", loops=loops) G._circle_embedding(list(range(n))) for v in range(n): - G.add_edges([(v,(v+j)%n) for j in integers]) + G.add_edges((v, (v + j) % n) for j in integers) return G - def DeBruijn(self, k, n, vertices = 'strings'): + def DeBruijn(self, k, n, vertices='strings'): r""" - Returns the De Bruijn digraph with parameters `k,n`. + Return the De Bruijn digraph with parameters `k,n`. The De Bruijn digraph with parameters `k,n` is built upon a set of vertices equal to the set of words of length `n` from a dictionary of @@ -709,19 +821,18 @@ def DeBruijn(self, k, n, vertices = 'strings'): INPUT: - - ``k`` -- Two possibilities for this parameter : - - An integer equal to the cardinality of the alphabet to use, that - is the degree of the digraph to be produced. - - An iterable object to be used as the set of letters. The degree - of the resulting digraph is the cardinality of the set of - letters. + - ``k`` -- two possibilities for this parameter : + - An integer equal to the cardinality of the alphabet to use, that + is, the degree of the digraph to be produced. + - An iterable object to be used as the set of letters. The degree + of the resulting digraph is the cardinality of the set of letters. - - ``n`` -- An integer equal to the length of words in the De Bruijn - digraph when ``vertices == 'strings'``, and also to the diameter of - the digraph. + - ``n`` -- integer; length of words in the De Bruijn digraph when + ``vertices == 'strings'``, and also the diameter of the digraph. - - ``vertices`` -- 'strings' (default) or 'integers', specifying whether - the vertices are words build upon an alphabet or integers. + - ``vertices`` -- string (default: ``'strings'``); whether the vertices + are words over an alphabet (default) or integers + (``vertices='string'``) EXAMPLES: @@ -781,47 +892,50 @@ def DeBruijn(self, k, n, vertices = 'strings'): A = Words(list(range(k)) if isinstance(k, Integer) else k, 1) g = DiGraph(loops=True) - if n == 0 : + if not n: g.allow_multiple_edges(True) v = W[0] + vs = v.string_rep() for a in A: - g.add_edge(v.string_rep(), v.string_rep(), a.string_rep()) + g.add_edge(vs, vs, a.string_rep()) else: for w in W: ww = w[1:] + ws = w.string_rep() for a in A: - g.add_edge(w.string_rep(), (ww*a).string_rep(), a.string_rep()) + g.add_edge(ws, (ww * a).string_rep(), a.string_rep()) elif vertices == 'integers': d = k if isinstance(k, Integer) else len(list(k)) - if d == 0: + if not d: g = DiGraph(loops=True, multiedges=True) else: - g = digraphs.GeneralizedDeBruijn(d**n, d) + g = digraphs.GeneralizedDeBruijn(d ** n, d) else: raise ValueError('unknown type for vertices') - g.name( "De Bruijn digraph (k=%s, n=%s)"%(k,n) ) + g.name("De Bruijn digraph (k={}, n={})".format(k, n)) return g def GeneralizedDeBruijn(self, n, d): r""" - Returns the generalized de Bruijn digraph of order `n` and degree `d`. + Return the generalized de Bruijn digraph of order `n` and degree `d`. - The generalized de Bruijn digraph has been defined in [RPK80]_ - [RPK83]_. It has vertex set `V=\{0, 1,..., n-1\}` and there is an arc - from vertex `u \in V` to all vertices `v \in V` such that - `v \equiv (u*d + a) \mod{n}` with `0 \leq a < d`. + The generalized de Bruijn digraph was defined in [RPK1980]_ [RPK1983]_. + It has vertex set `V=\{0, 1,..., n-1\}` and there is an arc from vertex + `u \in V` to all vertices `v \in V` such that `v \equiv (u*d + a) + \mod{n}` with `0 \leq a < d`. - When `n = d^{D}`, the generalized de Bruijn digraph is isomorphic to the - de Bruijn digraph of degree `d` and diameter `D`. + When `n = d^{D}`, the generalized de Bruijn digraph is isomorphic to + the de Bruijn digraph of degree `d` and diameter `D`. INPUT: - - ``n`` -- is the number of vertices of the digraph + - ``n`` -- integer; number of vertices of the digraph (must be at least + one) - - ``d`` -- is the degree of the digraph + - ``d`` -- integer; degree of the digraph (must be at least one) .. SEEALSO:: @@ -842,60 +956,49 @@ def GeneralizedDeBruijn(self, n, d): sage: G = digraphs.GeneralizedDeBruijn(2, 0) Traceback (most recent call last): ... - ValueError: The generalized de Bruijn digraph is defined for degree at least one. + ValueError: degree must be greater than or equal to one An exception is raised when the order of the graph is less than one:: sage: G = digraphs.GeneralizedDeBruijn(0, 2) Traceback (most recent call last): ... - ValueError: The generalized de Bruijn digraph is defined for at least one vertex. - - - REFERENCES: - - .. [RPK80] \S. M. Reddy, D. K. Pradhan, and J. Kuhl. Directed graphs with - minimal diameter and maximal connectivity, School Eng., Oakland Univ., - Rochester MI, Tech. Rep., July 1980. - - .. [RPK83] \S. Reddy, P. Raghavan, and J. Kuhl. A Class of Graphs for - Processor Interconnection. *IEEE International Conference on Parallel - Processing*, pages 154-157, Los Alamitos, Ca., USA, August 1983. + ValueError: order must be greater than or equal to one """ if n < 1: - raise ValueError("The generalized de Bruijn digraph is defined for at least one vertex.") + raise ValueError("order must be greater than or equal to one") if d < 1: - raise ValueError("The generalized de Bruijn digraph is defined for degree at least one.") + raise ValueError("degree must be greater than or equal to one") - GB = DiGraph(loops = True) - GB.allow_multiple_edges(True) + GB = DiGraph(n, loops=True, multiedges=True, + name="Generalized de Bruijn digraph (n={}, d={})".format(n, d)) for u in range(n): - for a in range(u*d, u*d+d): - GB.add_edge(u, a%n) - - GB.name( "Generalized de Bruijn digraph (n=%s, d=%s)"%(n,d) ) + for a in range(u * d, u * d + d): + GB.add_edge(u, a % n) return GB def ImaseItoh(self, n, d): r""" - Returns the digraph of Imase and Itoh of order `n` and degree `d`. + Return the Imase-Itoh digraph of order `n` and degree `d`. - The digraph of Imase and Itoh has been defined in [II83]_. It has vertex - set `V=\{0, 1,..., n-1\}` and there is an arc from vertex `u \in V` to - all vertices `v \in V` such that `v \equiv (-u*d-a-1) \mod{n}` with - `0 \leq a < d`. + The Imase-Itoh digraph was defined in [II1983]_. It has vertex set + `V=\{0, 1,..., n-1\}` and there is an arc from vertex `u \in V` to all + vertices `v \in V` such that `v \equiv (-u*d-a-1) \mod{n}` with `0 \leq + a < d`. - When `n = d^{D}`, the digraph of Imase and Itoh is isomorphic to the de - Bruijn digraph of degree `d` and diameter `D`. When `n = d^{D-1}(d+1)`, - the digraph of Imase and Itoh is isomorphic to the Kautz digraph - [Kautz68]_ of degree `d` and diameter `D`. + When `n = d^{D}`, the Imase-Itoh digraph is isomorphic to the de Bruijn + digraph of degree `d` and diameter `D`. When `n = d^{D-1}(d+1)`, the + Imase-Itoh digraph is isomorphic to the Kautz digraph [Kau1968]_ of + degree `d` and diameter `D`. INPUT: - - ``n`` -- is the number of vertices of the digraph + - ``n`` -- integer; number of vertices of the digraph (must be greater + than or equal to two) - - ``d`` -- is the degree of the digraph + - ``d`` -- integer; degree of the digraph (must be greater than or + equal to one) EXAMPLES:: @@ -919,68 +1022,62 @@ def ImaseItoh(self, n, d): sage: G = digraphs.ImaseItoh(2, 0) Traceback (most recent call last): ... - ValueError: The digraph of Imase and Itoh is defined for degree at least one. + ValueError: degree must be greater than or equal to one An exception is raised when the order of the graph is less than two:: sage: G = digraphs.ImaseItoh(1, 2) Traceback (most recent call last): ... - ValueError: The digraph of Imase and Itoh is defined for at least two vertices. - - - REFERENCE: - - .. [II83] \M. Imase and M. Itoh. A design for directed graphs with - minimum diameter, *IEEE Trans. Comput.*, vol. C-32, pp. 782-784, 1983. + ValueError: order must be greater than or equal to two """ if n < 2: - raise ValueError("The digraph of Imase and Itoh is defined for at least two vertices.") + raise ValueError("order must be greater than or equal to two") if d < 1: - raise ValueError("The digraph of Imase and Itoh is defined for degree at least one.") + raise ValueError("degree must be greater than or equal to one") - II = DiGraph(loops = True) - II.allow_multiple_edges(True) + II = DiGraph(n, loops=True, multiedges=True, + name="Imase and Itoh digraph (n={}, d={})".format(n, d)) for u in range(n): - for a in range(-u*d-d, -u*d): + for a in range(-u * d - d, -u * d): II.add_edge(u, a % n) - - II.name( "Imase and Itoh digraph (n=%s, d=%s)"%(n,d) ) return II - def Kautz(self, k, D, vertices = 'strings'): + def Kautz(self, k, D, vertices='strings'): r""" - Returns the Kautz digraph of degree `d` and diameter `D`. + Return the Kautz digraph of degree `d` and diameter `D`. - The Kautz digraph has been defined in [Kautz68]_. The Kautz digraph of - degree `d` and diameter `D` has `d^{D-1}(d+1)` vertices. This digraph is - build upon a set of vertices equal to the set of words of length `D` - from an alphabet of `d+1` letters such that consecutive letters are - differents. There is an arc from vertex `u` to vertex `v` if `v` can be + The Kautz digraph has been defined in [Kau1968]_. The Kautz digraph of + degree `d` and diameter `D` has `d^{D-1}(d+1)` vertices. This digraph + is built from a set of vertices equal to the set of words of length `D` + over an alphabet of `d+1` letters such that consecutive letters are + different. There is an arc from vertex `u` to vertex `v` if `v` can be obtained from `u` by removing the leftmost letter and adding a new letter, distinct from the rightmost letter of `u`, at the right end. The Kautz digraph of degree `d` and diameter `D` is isomorphic to the - digraph of Imase and Itoh [II83]_ of degree `d` and order - `d^{D-1}(d+1)`. + Imase-Itoh digraph [II1983]_ of degree `d` and order `d^{D-1}(d+1)`. See the :wikipedia:`Kautz_graph` for more information. INPUT: - - ``k`` -- Two possibilities for this parameter : - - An integer equal to the degree of the digraph to be produced, that - is the cardinality minus one of the alphabet to use. - - An iterable object to be used as the set of letters. The degree of - the resulting digraph is the cardinality of the set of letters + - ``k`` -- two possibilities for this parameter. In either case the + degree must be at least one: + + - An integer equal to the degree of the digraph to be produced, + that is, the cardinality of the alphabet to be used minus one. + - An iterable object to be used as the set of letters. The degree + of the resulting digraph is the cardinality of the set of letters minus one. - - ``D`` -- An integer equal to the diameter of the digraph, and also to - the length of a vertex label when ``vertices == 'strings'``. + - ``D`` -- integer; diameter of the digraph, and length of a vertex + label when ``vertices == 'strings'`` (must be at least one) - - ``vertices`` -- 'strings' (default) or 'integers', specifying whether - the vertices are words build upon an alphabet or integers. + - ``vertices`` -- string (default: ``'strings'``); whether the vertices + are words over an alphabet (default) or integers + (``vertices='strings'``) EXAMPLES:: @@ -1009,19 +1106,20 @@ def Kautz(self, k, D, vertices = 'strings'): sage: G = digraphs.Kautz(0, 2) Traceback (most recent call last): ... - ValueError: Kautz digraphs are defined for degree at least one + ValueError: degree must be greater than or equal to one sage: G = digraphs.Kautz(['a'], 2) Traceback (most recent call last): ... - ValueError: Kautz digraphs are defined for degree at least one + ValueError: degree must be greater than or equal to one - An exception is raised when the diameter of the graph is less than one:: + An exception is raised when the diameter of the graph is less than + one:: sage: G = digraphs.Kautz(2, 0) Traceback (most recent call last): ... - ValueError: Kautz digraphs are defined for diameter at least one + ValueError: diameter must be greater than or equal to one :trac:`22355`:: @@ -1042,50 +1140,47 @@ def Kautz(self, k, D, vertices = 'strings'): Traceback (most recent call last): ... ValueError: unknown type for vertices - - REFERENCE: - - .. [Kautz68] \W. H. Kautz. Bounds on directed (d, k) graphs. Theory of - cellular logic networks and machines, AFCRL-68-0668, SRI Project 7258, - Final Rep., pp. 20-28, 1968. """ if D < 1: - raise ValueError("Kautz digraphs are defined for diameter at least one") + raise ValueError("diameter must be greater than or equal to one") from sage.combinat.words.words import Words from sage.rings.integer import Integer if vertices == 'strings': - my_alphabet = Words([str(i) for i in range(k+1)] if isinstance(k, Integer) else k, 1) + my_alphabet = Words([str(i) for i in range(k + 1)] if isinstance(k, + Integer) else k, 1) if my_alphabet.alphabet().cardinality() < 2: - raise ValueError("Kautz digraphs are defined for degree at least one") + raise ValueError("degree must be greater than or equal to one") # We start building the set of vertices V = [i for i in my_alphabet] - for i in range(D-1): + for i in range(D - 1): VV = [] for w in V: - VV += [w*a for a in my_alphabet if not w.has_suffix(a) ] + VV += [w * a for a in my_alphabet if not w.has_suffix(a)] V = VV # We now build the set of arcs G = DiGraph() for u in V: + us = u.string_rep() for a in my_alphabet: if not u.has_suffix(a): - G.add_edge(u.string_rep(), (u[1:]*a).string_rep(), a.string_rep()) + G.add_edge(us, (u[1:] * a).string_rep(), + a.string_rep()) elif vertices == 'integers': - d = k if isinstance(k, Integer) else (len(list(k))-1) + d = k if isinstance(k, Integer) else (len(list(k)) - 1) if d < 1: - raise ValueError("Kautz digraphs are defined for degree at least one") - G = digraphs.ImaseItoh( (d+1)*(d**(D-1)), d) + raise ValueError("degree must be greater than or equal to one") + G = digraphs.ImaseItoh((d + 1) * (d ** (D - 1)), d) else: raise ValueError('unknown type for vertices') - G.name( "Kautz digraph (k={}, D={})".format(k, D) ) + G.name("Kautz digraph (k={}, D={})".format(k, D)) return G def RandomDirectedGN(self, n, kernel=lambda x:x, seed=None): diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 3a81c36b91f..19e29eb1151 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -828,7 +828,7 @@ cdef uint32_t * c_eccentricity_bounding(G, vertex_list=None) except NULL: return LB -def eccentricity(G, algorithm="standard"): +def eccentricity(G, algorithm="standard", vertex_list=None): r""" Return the vector of eccentricities in G. @@ -844,12 +844,24 @@ def eccentricity(G, algorithm="standard"): ``'standard'`` which performs a BFS from each vertex and ``'bounds'`` which uses the fast algorithm proposed in [TK13]_ for undirected graphs. + - ``vertex_list`` -- list (default: ``None``); a list of `n` vertices + specifying a mapping from `(0, \ldots, n-1)` to vertex labels in `G`. When + set, ``ecc[i]`` is the eccentricity of vertex ``vertex_list[i]``. When + ``vertex_list`` is ``None``, ``ecc[i]`` is the eccentricity of vertex + ``G.vertices()[i]``. + EXAMPLES:: sage: from sage.graphs.distances_all_pairs import eccentricity sage: g = graphs.PetersenGraph() sage: eccentricity(g) [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] + sage: g.add_edge(0, g.add_vertex()) + sage: V = list(g) + sage: eccentricity(g, vertex_list=V) + [2, 2, 3, 3, 2, 2, 3, 3, 3, 3, 3] + sage: eccentricity(g, vertex_list=V[::-1]) + [3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 2] TESTS: @@ -887,6 +899,15 @@ def eccentricity(G, algorithm="standard"): Traceback (most recent call last): ... ValueError: unknown algorithm 'Nice Jazz Festival', please contribute + + Invalid value for parameter vertex_list:: + + sage: from sage.graphs.distances_all_pairs import eccentricity + sage: g = graphs.PathGraph(2) + sage: eccentricity(g, vertex_list=[0, 1, 2]) + Traceback (most recent call last): + ... + ValueError: parameter vertex_list is incorrect for this graph """ from sage.rings.infinity import Infinity cdef int n = G.order() @@ -899,8 +920,15 @@ def eccentricity(G, algorithm="standard"): elif not G.is_connected(): return [Infinity] * n + cdef list int_to_vertex + if vertex_list is None: + int_to_vertex = G.vertices() + elif len(vertex_list) == n and set(vertex_list) == set(G): + int_to_vertex = vertex_list + else: + raise ValueError("parameter vertex_list is incorrect for this graph") + cdef uint32_t* ecc - cdef list int_to_vertex = G.vertices() if algorithm == "bounds": ecc = c_eccentricity_bounding(G, vertex_list=int_to_vertex) elif algorithm == "standard": @@ -1510,11 +1538,16 @@ def floyd_warshall(gg, paths=True, distances=False): sage: g = graphs.Grid2dGraph(2,2) sage: from sage.graphs.distances_all_pairs import floyd_warshall - sage: print(floyd_warshall(g)) + sage: print(floyd_warshall(g)) # py2 {(0, 1): {(0, 1): None, (1, 0): (0, 0), (0, 0): (0, 1), (1, 1): (0, 1)}, - (1, 0): {(0, 1): (0, 0), (1, 0): None, (0, 0): (1, 0), (1, 1): (1, 0)}, - (0, 0): {(0, 1): (0, 0), (1, 0): (0, 0), (0, 0): None, (1, 1): (0, 1)}, - (1, 1): {(0, 1): (1, 1), (1, 0): (1, 1), (0, 0): (0, 1), (1, 1): None}} + (1, 0): {(0, 1): (0, 0), (1, 0): None, (0, 0): (1, 0), (1, 1): (1, 0)}, + (0, 0): {(0, 1): (0, 0), (1, 0): (0, 0), (0, 0): None, (1, 1): (0, 1)}, + (1, 1): {(0, 1): (1, 1), (1, 0): (1, 1), (0, 0): (0, 1), (1, 1): None}} + sage: print(floyd_warshall(g)) # py3 + {(0, 0): {(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 1)}, + (0, 1): {(0, 1): None, (0, 0): (0, 1), (1, 0): (0, 0), (1, 1): (0, 1)}, + (1, 0): {(1, 0): None, (0, 0): (1, 0), (0, 1): (0, 0), (1, 1): (1, 0)}, + (1, 1): {(1, 1): None, (0, 0): (0, 1), (0, 1): (1, 1), (1, 0): (1, 1)}} Checking the distances are correct :: diff --git a/src/sage/graphs/generators/chessboard.py b/src/sage/graphs/generators/chessboard.py index 4d4b9e3c6be..7660327078f 100644 --- a/src/sage/graphs/generators/chessboard.py +++ b/src/sage/graphs/generators/chessboard.py @@ -36,7 +36,7 @@ def ChessboardGraphGenerator(dim_list, This function allows to generate many kinds of graphs corresponding to legal movements on a `d`-dimensional chessboard: Queen Graph, King Graph, Knight Graphs, Bishop Graph, and many generalizations. It also allows to avoid - redondant code. + redundant code. INPUT: diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 9328c31f50c..7fcc462c080 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -371,13 +371,13 @@ def OrthogonalPolarGraph(m, q, sign="+"): ... ValueError: sign must be equal to either '' or '+' when m is odd """ - from sage.graphs.generators.classical_geometries import _orthogonal_polar_graph G = _orthogonal_polar_graph(m, q, sign=sign) - if m % 2 != 0: + if m % 2: sign = "" G.name("Orthogonal Polar Graph O" + ("^" + sign if sign else "") + str((m, q))) return G + def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): r""" Returns the Graph `NO^{\epsilon,\perp}_{m}(q)` @@ -484,13 +484,12 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign="+", perp=None): ValueError: for m even q must be 2 or 3 """ - from sage.graphs.generators.classical_geometries import _orthogonal_polar_graph - p, k = is_prime_power(q,get_data=True) - if k==0: + p, k = is_prime_power(q, get_data=True) + if k == 0: raise ValueError('q must be a prime power') dec = '' if m % 2 == 0: - if q in [2,3]: + 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") @@ -762,7 +761,7 @@ def UnitaryDualPolarGraph(m, q): sage: graphs.UnitaryDualPolarGraph(6,6) Traceback (most recent call last): ... - ValueError: libGAP: Error, must be a prime or a finite field + GAPError: Error, must be a prime or a finite field """ from sage.libs.gap.libgap import libgap G = _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q), @@ -803,7 +802,7 @@ def SymplecticDualPolarGraph(m, q): sage: graphs.SymplecticDualPolarGraph(6,6) Traceback (most recent call last): ... - ValueError: libGAP: Error, must be a prime or a finite field + GAPError: Error, must be a prime or a finite field REFERENCE: @@ -1212,7 +1211,7 @@ def normalize(v): # make sure the 1st non-0 coordinate is 1. I_ks[O.index(tuple(Pi))].append(i) # perform the adjustment of the edges, as described. - G.relabel() + G.relabel(range(G.order())) cliques = [] for i,j in hyperoval_matching: Pij = set(I_ks[i]+I_ks[j]) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index ac7ea9374d1..a1a472b06b2 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -129,7 +129,6 @@ def KneserGraph(n,k): return g -from sage.graphs.graph import Graph def FurerGadget(k, prefix=None): r""" @@ -170,41 +169,40 @@ def FurerGadget(k, prefix=None): Furer gadget of order 3, without any prefix. :: sage: G, p = graphs.FurerGadget(3) - sage: G.vertices() - [(), (0, 1), (0, 2), (0, 'a'), (0, 'b'), (1, 2), (1, 'a'), - (1, 'b'), (2, 'a'), (2, 'b')] - sage: G.edges() + sage: sorted(G, key=str) + [(), (0, 'a'), (0, 'b'), (0, 1), (0, 2), + (1, 'a'), (1, 'b'), (1, 2), (2, 'a'), (2, 'b')] + sage: sorted(G.edge_iterator(), key=str) [((), (0, 'b'), None), ((), (1, 'b'), None), - ((), (2, 'b'), None), ((0, 1), (0, 'a'), None), - ((0, 1), (1, 'a'), None), ((0, 1), (2, 'b'), None), - ((0, 2), (0, 'a'), None), ((0, 2), (1, 'b'), None), - ((0, 2), (2, 'a'), None), ((0, 'b'), (1, 2), None), + ((), (2, 'b'), None), ((0, 'b'), (1, 2), None), + ((0, 1), (0, 'a'), None), ((0, 1), (1, 'a'), None), + ((0, 1), (2, 'b'), None), ((0, 2), (0, 'a'), None), + ((0, 2), (1, 'b'), None), ((0, 2), (2, 'a'), None), ((1, 2), (1, 'a'), None), ((1, 2), (2, 'a'), None)] Furer gadget of order 3, with a prefix. :: sage: G, p = graphs.FurerGadget(3, 'Prefix') - sage: G.vertices() - [('Prefix', ()), ('Prefix', (0, 1)), ('Prefix', (0, 2)), - ('Prefix', (0, 'a')), ('Prefix', (0, 'b')), ('Prefix', (1, 2)), - ('Prefix', (1, 'a')), ('Prefix', (1, 'b')), ('Prefix', (2, 'a')), + sage: sorted(G, key=str) + [('Prefix', ()), ('Prefix', (0, 'a')), ('Prefix', (0, 'b')), + ('Prefix', (0, 1)), ('Prefix', (0, 2)), ('Prefix', (1, 'a')), + ('Prefix', (1, 'b')), ('Prefix', (1, 2)), ('Prefix', (2, 'a')), ('Prefix', (2, 'b'))] - sage: G.edges() + sage: sorted(G.edge_iterator(), key=str) [(('Prefix', ()), ('Prefix', (0, 'b')), None), (('Prefix', ()), ('Prefix', (1, 'b')), None), (('Prefix', ()), ('Prefix', (2, 'b')), None), + (('Prefix', (0, 'b')), ('Prefix', (1, 2)), None), (('Prefix', (0, 1)), ('Prefix', (0, 'a')), None), (('Prefix', (0, 1)), ('Prefix', (1, 'a')), None), (('Prefix', (0, 1)), ('Prefix', (2, 'b')), None), (('Prefix', (0, 2)), ('Prefix', (0, 'a')), None), (('Prefix', (0, 2)), ('Prefix', (1, 'b')), None), (('Prefix', (0, 2)), ('Prefix', (2, 'a')), None), - (('Prefix', (0, 'b')), ('Prefix', (1, 2)), None), (('Prefix', (1, 2)), ('Prefix', (1, 'a')), None), (('Prefix', (1, 2)), ('Prefix', (2, 'a')), None)] """ from itertools import repeat as rep, chain, combinations - from sage.graphs.graph import DiGraph if k <= 0: raise ValueError("The order of the Furer gadget must be greater than zero") G = Graph() @@ -230,6 +228,7 @@ def FurerGadget(k, prefix=None): partition.append(powerset) return G, partition + def CaiFurerImmermanGraph(G, twisted=False): r""" Return the a Cai-Furer-Immerman graph from `G`, possibly a twisted @@ -280,20 +279,19 @@ def CaiFurerImmermanGraph(G, twisted=False): sage: G = graphs.CycleGraph(4) sage: CFI, p = graphs.CaiFurerImmermanGraph(G) - sage: CFI.vertices() - [(0, ()), (0, (0, 1)), (0, (0, 'a')), (0, (0, 'b')), - (0, (1, 'a')), (0, (1, 'b')), (1, ()), (1, (0, 1)), - (1, (0, 'a')), (1, (0, 'b')), (1, (1, 'a')), (1, (1, 'b')), - (2, ()), (2, (0, 1)), (2, (0, 'a')), (2, (0, 'b')), - (2, (1, 'a')), (2, (1, 'b')), (3, ()), (3, (0, 1)), - (3, (0, 'a')), (3, (0, 'b')), (3, (1, 'a')), (3, (1, 'b'))] - sage: CFI.edges() + sage: sorted(CFI, key=str) + [(0, ()), (0, (0, 'a')), (0, (0, 'b')), (0, (0, 1)), (0, (1, 'a')), + (0, (1, 'b')), (1, ()), (1, (0, 'a')), (1, (0, 'b')), (1, (0, 1)), + (1, (1, 'a')), (1, (1, 'b')), (2, ()), (2, (0, 'a')), (2, (0, 'b')), + (2, (0, 1)), (2, (1, 'a')), (2, (1, 'b')), (3, ()), (3, (0, 'a')), + (3, (0, 'b')), (3, (0, 1)), (3, (1, 'a')), (3, (1, 'b'))] + sage: sorted(CFI.edge_iterator(), key=str) [((0, ()), (0, (0, 'b')), None), ((0, ()), (0, (1, 'b')), None), - ((0, (0, 1)), (0, (0, 'a')), None), - ((0, (0, 1)), (0, (1, 'a')), None), ((0, (0, 'a')), (1, (0, 'a')), None), ((0, (0, 'b')), (1, (0, 'b')), None), + ((0, (0, 1)), (0, (0, 'a')), None), + ((0, (0, 1)), (0, (1, 'a')), None), ((0, (1, 'a')), (3, (0, 'a')), None), ((0, (1, 'b')), (3, (0, 'b')), None), ((1, ()), (1, (0, 'b')), None), @@ -312,13 +310,11 @@ def CaiFurerImmermanGraph(G, twisted=False): ((3, ()), (3, (1, 'b')), None), ((3, (0, 1)), (3, (0, 'a')), None), ((3, (0, 1)), (3, (1, 'a')), None)] - """ isConnected = G.is_connected() newG = Graph() total_partition = [] edge_index = {} - ps_partition = [] for v in G: Fk, p = FurerGadget(G.degree(v), v) total_partition += p @@ -340,7 +336,7 @@ def CaiFurerImmermanGraph(G, twisted=False): isConnected = False newG.add_edge(edge_va, edge_ua) newG.add_edge(edge_vb, edge_ub) - if(twisted and G.is_connected()): + if twisted and G.is_connected(): s = " twisted" else: s = "" @@ -416,6 +412,7 @@ def EgawaGraph(p, s): g.add_edge(v,u) return g + def HammingGraph(n, q, X=None): r""" Returns the Hamming graph with parameters ``n``, ``q`` over ``X``. @@ -1489,16 +1486,16 @@ def FuzzyBallGraph(partition, q): EXAMPLES:: - sage: graphs.FuzzyBallGraph([3,1],2).adjacency_matrix() - [0 1 1 1 1 1 1 0] - [1 0 1 1 1 1 1 0] - [1 1 0 1 1 1 1 0] - [1 1 1 0 1 1 0 1] - [1 1 1 1 0 1 0 0] - [1 1 1 1 1 0 0 0] - [1 1 1 0 0 0 0 0] - [0 0 0 1 0 0 0 0] - + sage: F = graphs.FuzzyBallGraph([3,1],2) + sage: F.adjacency_matrix(vertices=list(F)) + [0 0 1 1 1 0 0 0] + [0 0 0 0 0 1 0 0] + [1 0 0 1 1 1 1 1] + [1 0 1 0 1 1 1 1] + [1 0 1 1 0 1 1 1] + [0 1 1 1 1 0 1 1] + [0 0 1 1 1 1 0 1] + [0 0 1 1 1 1 1 0] Pick positive integers `m` and `k` and a nonnegative integer `q`. All the FuzzyBallGraphs constructed from partitions of `m` with @@ -1507,7 +1504,7 @@ def FuzzyBallGraph(partition, q): sage: m=4; q=2; k=2 sage: g_list=[graphs.FuzzyBallGraph(p,q) for p in Partitions(m, length=k)] - sage: set([g.laplacian_matrix(normalized=True).charpoly() for g in g_list]) # long time (7s on sage.math, 2011) + sage: set([g.laplacian_matrix(normalized=True, vertices=list(g)).charpoly() for g in g_list]) # long time (7s on sage.math, 2011) {x^8 - 8*x^7 + 4079/150*x^6 - 68689/1350*x^5 + 610783/10800*x^4 - 120877/3240*x^3 + 1351/100*x^2 - 931/450*x} """ from sage.graphs.generators.basic import CompleteGraph @@ -2237,13 +2234,13 @@ def SwitchedSquaredSkewHadamardMatrixGraph(n): sage: twograph_descendant(g.complement(),0).is_strongly_regular(parameters=True) (225, 112, 55, 56) """ - from sage.graphs.generators.families import SquaredSkewHadamardMatrixGraph G = SquaredSkewHadamardMatrixGraph(n).complement() - G.add_vertex((4*n-1)**2) + G.add_vertex((4 * n - 1)**2) G.seidel_switching(list(range((4 * n - 1) * (2 * n - 1)))) G.name("switch skewhad^2+*_" + str((n))) return G + def HanoiTowerGraph(pegs, disks, labels=True, positions=True): r""" Returns the graph whose vertices are the states of the diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 1ec711615ca..15f2c5391b3 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -129,37 +129,34 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage'): raise ValueError("'algorithm' must be equal to 'networkx' or to 'Sage'.") def RandomBarabasiAlbert(n, m, seed=None): - u""" + r""" Return a random graph created using the Barabasi-Albert preferential attachment model. - A graph with m vertices and no edges is initialized, and a graph of n - vertices is grown by attaching new vertices each with m edges that are + A graph with `m` vertices and no edges is initialized, and a graph of `n` + vertices is grown by attaching new vertices each with `m` edges that are attached to existing vertices, preferentially with high degree. INPUT: - - ``n`` - number of vertices in the graph - - - ``m`` - number of edges to attach from each new node + - ``n`` -- number of vertices in the graph - - ``seed`` - a ``random.Random`` seed or a Python ``int`` for the random - number generator (default: ``None``). + - ``m`` -- number of edges to attach from each new node + - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random + number generator (default: ``None``) EXAMPLES: - We show the edge list of a random graph on 6 nodes with m = 2. + We show the edge list of a random graph on 6 nodes with `m = 2`:: - :: - - sage: graphs.RandomBarabasiAlbert(6,2).edges(labels=False) - [(0, 2), (0, 3), (0, 5), (1, 2), (2, 3), (2, 4), (3, 4), (3, 5)] # 32-bit - [(0, 2), (0, 3), (1, 2), (1, 4), (1, 5), (2, 3), (2, 4), (3, 5)] # 64-bit + sage: G = graphs.RandomBarabasiAlbert(6,2) + sage: G.order(), G.size() + (6, 8) + sage: G.degree_sequence() # random + [4, 3, 3, 2, 2, 2] - We plot a random graph on 12 nodes with m = 3. - - :: + We plot a random graph on 12 nodes with `m = 3`:: sage: ba = graphs.RandomBarabasiAlbert(12,3) sage: ba.show() # long time @@ -179,11 +176,15 @@ def RandomBarabasiAlbert(n, m, seed=None): sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time + When `m = 1`, the generated graph is a tree:: + + sage: graphs.RandomBarabasiAlbert(6, 1).is_tree() + True """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx - return Graph(networkx.barabasi_albert_graph(n,m,seed=seed)) + return Graph(networkx.barabasi_albert_graph(n, m, seed=seed)) def RandomBipartite(n1, n2, p, set_position=False): r""" @@ -674,44 +675,60 @@ def RandomGNM(n, m, dense=False, seed=None): return Graph(networkx.gnm_random_graph(n, m, seed=seed)) def RandomNewmanWattsStrogatz(n, k, p, seed=None): - """ - Returns a Newman-Watts-Strogatz small world random graph on n - vertices. + r""" + Return a Newman-Watts-Strogatz small world random graph on `n` vertices. - From the NetworkX documentation: First create a ring over n nodes. - Then each node in the ring is connected with its k nearest - neighbors. Then shortcuts are created by adding new edges as - follows: for each edge u-v in the underlying "n-ring with k nearest - neighbors"; with probability p add a new edge u-w with - randomly-chosen existing node w. In contrast with - watts_strogatz_graph(), no edges are removed. + From the NetworkX documentation: first create a ring over `n` nodes. Then + each node in the ring is connected with its `k` nearest neighbors. Then + shortcuts are created by adding new edges as follows: for each edge `u-v` in + the underlying "`n`-ring with `k` nearest neighbors"; with probability `p` + add a new edge `u-w` with randomly-chosen existing node `w`. In contrast + with ``networkx.watts_strogatz_graph()``, no edges are removed. INPUT: - - ``n`` - number of vertices. + - ``n`` -- number of vertices - - ``k`` - each vertex is connected to its k nearest - neighbors + - ``k`` -- each vertex is connected to its `k` nearest neighbors - - ``p`` - the probability of adding a new edge for - each edge + - ``p`` -- the probability of adding a new edge for each edge - - ``seed`` - a ``random.Random`` seed or a Python ``int`` for the random - number generator (default: ``None``). + - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random + number generator (default: ``None``) + EXAMPLES: - EXAMPLES: We show the edge list of a random graph on 7 nodes with 2 - "nearest neighbors" and probability `p = 0.2`:: + We check that the generated graph contains a cycle of order `n`:: - sage: graphs.RandomNewmanWattsStrogatz(7, 2, 0.2).edges(labels=False) - [(0, 1), (0, 5), (0, 6), (1, 2), (2, 3), (3, 4), (3, 5), (4, 5), (5, 6)] # 32-bit - [(0, 1), (0, 4), (0, 6), (1, 2), (1, 4), (2, 3), (3, 4), (4, 5), (5, 6)] # 64-bit + sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0.2) + sage: G.order(), G.size() + (7, 9) + sage: C7 = graphs.CycleGraph(7) + sage: G.subgraph_search(C7) + Subgraph of (): Graph on 7 vertices + sage: G.diameter() <= C7.diameter() + True :: sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) sage: G.show() # long time + TESTS: + + We check that when `k = 2` and `p = 0`, the generated graph is a cycle:: + + sage: G = graphs.RandomNewmanWattsStrogatz(7, 2, 0) + sage: G.is_cycle() + True + + We check that when `k = 4` and `p = 0`, the generated graph is a circulant + graph of parameters ``[1, 2]``:: + + sage: G = graphs.RandomNewmanWattsStrogatz(7, 4, 0) + sage: G.is_isomorphic(graphs.CirculantGraph(7, [1, 2])) + True + REFERENCE: .. [NWS99] Newman, M.E.J., Watts, D.J. and Strogatz, S.H. Random @@ -724,47 +741,45 @@ def RandomNewmanWattsStrogatz(n, k, p, seed=None): return Graph(networkx.newman_watts_strogatz_graph(n, k, p, seed=seed)) def RandomHolmeKim(n, m, p, seed=None): - """ - Returns a random graph generated by the Holme and Kim algorithm for + r""" + Return a random graph generated by the Holme and Kim algorithm for graphs with power law degree distribution and approximate average clustering. INPUT: - - ``n`` - number of vertices. - - - ``m`` - number of random edges to add for each new - node. + - ``n`` -- number of vertices - - ``p`` - probability of adding a triangle after - adding a random edge. + - ``m`` -- number of random edges to add for each new node - - ``seed`` - a ``random.Random`` seed or a Python ``int`` for the random - number generator (default: ``None``). + - ``p`` -- probability of adding a triangle after adding a random edge + - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random + number generator (default: ``None``) - From the NetworkX documentation: The average clustering has a hard - time getting above a certain cutoff that depends on m. This cutoff - is often quite low. Note that the transitivity (fraction of - triangles to possible triangles) seems to go down with network - size. It is essentially the Barabasi-Albert growth model with an - extra step that each random edge is followed by a chance of making - an edge to one of its neighbors too (and thus a triangle). This - algorithm improves on B-A in the sense that it enables a higher - average clustering to be attained if desired. It seems possible to - have a disconnected graph with this algorithm since the initial m - nodes may not be all linked to a new node on the first iteration - like the BA model. + From the NetworkX documentation: the average clustering has a hard time + getting above a certain cutoff that depends on `m`. This cutoff is often + quite low. Note that the transitivity (fraction of triangles to possible + triangles) seems to go down with network size. It is essentially the + Barabasi-Albert growth model with an extra step that each random edge is + followed by a chance of making an edge to one of its neighbors too (and thus + a triangle). This algorithm improves on B-A in the sense that it enables a + higher average clustering to be attained if desired. It seems possible to + have a disconnected graph with this algorithm since the initial `m` nodes + may not be all linked to a new node on the first iteration like the BA + model. - EXAMPLES: We show the edge list of a random graph on 8 nodes with 2 - random edges per node and a probability `p = 0.5` of - forming triangles. + EXAMPLES: - :: + We check that a random graph on 8 nodes with 2 random edges per node and a + probability `p = 0.5` of forming triangles contains a triangle:: - sage: graphs.RandomHolmeKim(8, 2, 0.5).edges(labels=False) - [(0, 2), (0, 3), (0, 5), (1, 2), (1, 4), (1, 5), (1, 6), (2, 3), (2, 4), (2, 6), (5, 7), (6, 7)] # 32-bit - [(0, 2), (0, 3), (0, 4), (0, 5), (0, 7), (1, 2), (1, 3), (1, 6), (2, 4), (2, 6), (3, 5), (4, 7)] # 64-bit + sage: G = graphs.RandomHolmeKim(8, 2, 0.5) + sage: G.order(), G.size() + (8, 12) + sage: C3 = graphs.CycleGraph(3) + sage: G.subgraph_search(C3) + Subgraph of (): Graph on 3 vertices :: @@ -1184,7 +1199,6 @@ def RandomChordalGraph(n, algorithm="growing", k=None, l=None, f=None, s=None): return Graph(n, name="Random Chordal Graph") # 1. Generate a random tree of order n - from sage.graphs.generators.random import RandomTree T = RandomTree(n) # 2. Generate n non-empty subtrees of T: {T1,...,Tn} @@ -1341,36 +1355,36 @@ def RandomTree(n): return g + def RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None): """ - Returns a tree with a power law degree distribution. Returns False - on failure. + Return a tree with a power law degree distribution, or ``False`` on failure. - From the NetworkX documentation: A trial power law degree sequence - is chosen and then elements are swapped with new elements from a - power law distribution until the sequence makes a tree (size = order - - 1). + From the NetworkX documentation: a trial power law degree sequence is chosen + and then elements are swapped with new elements from a power law + distribution until the sequence makes a tree (size = order - 1). INPUT: - - ``n`` - number of vertices + - ``n`` -- number of vertices - - ``gamma`` - exponent of power law + - ``gamma`` -- exponent of power law distribution - - ``tries`` - number of attempts to adjust sequence to - make a tree + - ``tries`` -- number of attempts to adjust sequence to make a tree - - ``seed`` - a ``random.Random`` seed or a Python ``int`` for the random - number generator (default: ``None``). + - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random + number generator (default: ``None``) - EXAMPLES: We show the edge list of a random graph with 10 nodes and - a power law exponent of 2. + EXAMPLES: - :: + We check that the generated graph is a tree:: - sage: graphs.RandomTreePowerlaw(10, 3).edges(labels=False) - [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (5, 8), (6, 7), (6, 9)] + sage: G = graphs.RandomTreePowerlaw(10, 3) + sage: G.is_tree() + True + sage: G.order(), G.size() + (10, 9) :: @@ -1389,29 +1403,28 @@ def RandomTreePowerlaw(n, gamma=3, tries=1000, seed=None): def RandomRegular(d, n, seed=None): r""" - Return a random d-regular graph on n vertices, or returns False on - failure. + Return a random `d`-regular graph on `n` vertices, or ``False`` on failure. - Since every edge is incident to two vertices, n\*d must be even. + Since every edge is incident to two vertices, `n\times d` must be even. INPUT: - - ``n`` - number of vertices + - ``d`` -- degree - - ``d`` - degree - - - ``seed`` - a ``random.Random`` seed or a Python ``int`` for the random - number generator (default: ``None``). + - ``n`` -- number of vertices + - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random + number generator (default: ``None``) - EXAMPLES: We show the edge list of a random graph with 8 nodes each - of degree 3. + EXAMPLES: - :: + We check that a random graph with 8 nodes each of degree 3 is 3-regular:: - sage: graphs.RandomRegular(3, 8).edges(labels=False) - [(0, 2), (0, 4), (0, 5), (1, 5), (1, 6), (1, 7), (2, 4), (2, 7), (3, 4), (3, 5), (3, 6), (6, 7)] # 32-bit - [(0, 3), (0, 5), (0, 6), (1, 2), (1, 3), (1, 7), (2, 4), (2, 6), (3, 6), (4, 5), (4, 7), (5, 7)] # 64-bit + sage: G = graphs.RandomRegular(3, 8) + sage: G.is_regular(k=3) + True + sage: G.degree_histogram() + [0, 0, 0, 8] :: @@ -1434,37 +1447,35 @@ def RandomRegular(d, n, seed=None): import networkx try: N = networkx.random_regular_graph(d, n, seed=seed) - if N is False: return False + if N is False: + return False return Graph(N, sparse=True) except Exception: return False def RandomShell(constructor, seed=None): """ - Returns a random shell graph for the constructor given. + Return a random shell graph for the constructor given. INPUT: - - ``constructor`` - a list of 3-tuples (n,m,d), each - representing a shell + - ``constructor`` -- a list of 3-tuples `(n, m, d)`, each representing a + shell, where: - - ``n`` - the number of vertices in the shell + - ``n`` -- the number of vertices in the shell - - ``m`` - the number of edges in the shell + - ``m`` -- the number of edges in the shell - - ``d`` - the ratio of inter (next) shell edges to - intra shell edges - - - ``seed`` - a ``random.Random`` seed or a Python ``int`` for the random - number generator (default: ``None``). + - ``d`` -- the ratio of inter (next) shell edges to intra shell edges + - ``seed`` -- a ``random.Random`` seed or a Python ``int`` for the random + number generator (default: ``None``) EXAMPLES:: sage: G = graphs.RandomShell([(10,20,0.8),(20,40,0.8)]) - sage: G.edges(labels=False) - [(0, 2), (0, 3), (0, 6), (0, 7), (0, 9), (0, 27), (1, 4), (1, 8), (3, 4), (3, 6), (3, 9), (4, 5), (4, 8), (4, 14), (5, 6), (5, 7), (6, 15), (7, 8), (7, 9), (7, 19), (10, 21), (10, 24), (11, 19), (11, 22), (11, 27), (12, 15), (13, 20), (13, 27), (14, 15), (14, 17), (14, 21), (15, 17), (15, 22), (15, 26), (16, 18), (17, 26), (17, 28), (18, 20), (18, 21), (18, 25), (18, 26), (19, 20), (19, 22), (19, 26), (19, 28), (21, 28), (22, 23), (23, 27), (24, 25), (24, 27), (25, 27), (25, 28)] # 32-bit - [(0, 7), (0, 8), (0, 9), (1, 3), (1, 4), (1, 5), (1, 7), (1, 9), (1, 27), (2, 5), (2, 9), (2, 15), (2, 21), (3, 6), (3, 8), (3, 9), (4, 6), (4, 7), (6, 7), (8, 21), (10, 26), (12, 17), (12, 18), (12, 20), (12, 25), (12, 26), (13, 14), (13, 19), (14, 16), (14, 18), (14, 19), (14, 22), (14, 24), (15, 21), (16, 17), (16, 25), (16, 26), (16, 28), (17, 19), (17, 29), (18, 24), (18, 26), (19, 28), (20, 27), (20, 29), (22, 24), (22, 27), (22, 29), (23, 24), (23, 26), (24, 27), (26, 29)] # 64-bit + sage: G.order(), G.size() + (30, 52) sage: G.show() # long time """ if seed is None: diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 86fa1d7e72d..dcc688b735f 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -20,6 +20,9 @@ # import from Sage library from sage.graphs.graph import Graph +from sage.rings.rational_field import QQ +from sage.functions.other import sqrt + from math import sin, cos, pi ####################################################################### @@ -431,7 +434,6 @@ def Cell600(embedding=1): sage: g.is_vertex_transitive() # long time True """ - from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring import polygen from sage.rings.number_field.number_field import NumberField from sage.modules.free_module import VectorSpace @@ -507,7 +509,6 @@ def Cell120(): sage: g.is_vertex_transitive() # long time True """ - from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring import polygen from sage.rings.number_field.number_field import NumberField from sage.modules.free_module import VectorSpace @@ -680,7 +681,7 @@ def HallJankoGraph(from_string=True): TESTS:: sage: gg = graphs.HallJankoGraph(from_string=False) # long time - sage: g == gg # long time + sage: g == gg # long time True """ @@ -755,7 +756,7 @@ def HallJankoGraph(from_string=True): gap.eval("G := Group([g1,g2]);") edges = gap('Orbit(G,[1,5],OnSets)').sage() g = Graph([(int(u), int(v)) for u,v in edges]) - g.relabel() + g.relabel(range(100)) g._circle_embedding(list(range(100))) g.name("Hall-Janko graph") @@ -2697,6 +2698,48 @@ def GoldnerHararyGraph(): return Graph(edge_dict, pos = pos, name="Goldner-Harary graph") +def GolombGraph(): + r""" + Return the Golomb graph. + + See the :wikipedia:`Golomb_graph` for more information. + + EXAMPLES: + + The Golomb graph is a planar and Hamiltonian graph with 10 vertices + and 18 edges. It has chromatic number 4, diameter 3, radius 2 and + girth 3. It can be drawn in the plane as a unit distance graph:: + + sage: G = graphs.GolombGraph(); G + Golomb graph: Graph on 10 vertices + sage: pos = G.get_pos() + sage: dist2 = lambda u,v:(u[0]-v[0])**2 + (u[1]-v[1])**2 + sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) + True + """ + edge_dict = { + 0: [1, 2, 3], + 1: [2, 5], + 2: [7], + 3: [4, 8, 9], + 4: [5, 9], + 5: [6, 9], + 6: [7, 9], + 7: [8, 9], + 8: [9]} + pos_dict = { + 0: [QQ('1/6'), QQ('1/6') * sqrt(11)], + 1: [QQ('1/12') * sqrt(33) - QQ('1/12'), - sqrt(QQ('1/72') * sqrt(33) + QQ('7/72'))], + 2: [- QQ('1/12') * sqrt(33) - QQ('1/12'), - sqrt(- QQ('1/72') * sqrt(33) + QQ('7/72'))], + 3: [1, 0], + 4: [QQ('1/2'), - QQ('1/2') * sqrt(3)], + 5: [- QQ('1/2'), - QQ('1/2') * sqrt(3)], + 6: [-1, 0], + 7: [- QQ('1/2'), QQ('1/2') * sqrt(3)], + 8: [QQ('1/2'), QQ('1/2') * sqrt(3)], + 9: [0, 0]} + return Graph(edge_dict, pos=pos_dict, name="Golomb graph") + def GrayGraph(embedding=1): r""" Return the Gray graph. @@ -3063,11 +3106,9 @@ def HigmanSimsGraph(relabel=True): # Rename to integer vertex labels, creating dictionary # Or not, and create identity mapping if relabel: - vmap = HS.relabel(return_map=True) + vmap = HS.relabel(range(100), return_map=True) else: - vmap={} - for v in vlist: - vmap[v] = v + vmap = {v: v for v in vlist} # Layout vertices in a circle # In the order given in vlist # Using labels from vmap @@ -3115,21 +3156,21 @@ def HoffmanSingletonGraph(): sage: HS.layout()[1] (-0.844..., 0.535...) - sage: graphs.HoffmanSingletonGraph().layout()[1] + sage: HS = graphs.HoffmanSingletonGraph() + sage: HS.layout()[1] (-0.904..., 0.425...) - """ - H = Graph({ \ - 'q00':['q01'], 'q01':['q02'], 'q02':['q03'], 'q03':['q04'], 'q04':['q00'], \ - 'q10':['q11'], 'q11':['q12'], 'q12':['q13'], 'q13':['q14'], 'q14':['q10'], \ - 'q20':['q21'], 'q21':['q22'], 'q22':['q23'], 'q23':['q24'], 'q24':['q20'], \ - 'q30':['q31'], 'q31':['q32'], 'q32':['q33'], 'q33':['q34'], 'q34':['q30'], \ - 'q40':['q41'], 'q41':['q42'], 'q42':['q43'], 'q43':['q44'], 'q44':['q40'], \ - 'p00':['p02'], 'p02':['p04'], 'p04':['p01'], 'p01':['p03'], 'p03':['p00'], \ - 'p10':['p12'], 'p12':['p14'], 'p14':['p11'], 'p11':['p13'], 'p13':['p10'], \ - 'p20':['p22'], 'p22':['p24'], 'p24':['p21'], 'p21':['p23'], 'p23':['p20'], \ - 'p30':['p32'], 'p32':['p34'], 'p34':['p31'], 'p31':['p33'], 'p33':['p30'], \ - 'p40':['p42'], 'p42':['p44'], 'p44':['p41'], 'p41':['p43'], 'p43':['p40']}) + H = Graph({ + 'q00':['q01'], 'q01':['q02'], 'q02':['q03'], 'q03':['q04'], 'q04':['q00'], + 'q10':['q11'], 'q11':['q12'], 'q12':['q13'], 'q13':['q14'], 'q14':['q10'], + 'q20':['q21'], 'q21':['q22'], 'q22':['q23'], 'q23':['q24'], 'q24':['q20'], + 'q30':['q31'], 'q31':['q32'], 'q32':['q33'], 'q33':['q34'], 'q34':['q30'], + 'q40':['q41'], 'q41':['q42'], 'q42':['q43'], 'q43':['q44'], 'q44':['q40'], + 'p00':['p02'], 'p02':['p04'], 'p04':['p01'], 'p01':['p03'], 'p03':['p00'], + 'p10':['p12'], 'p12':['p14'], 'p14':['p11'], 'p11':['p13'], 'p13':['p10'], + 'p20':['p22'], 'p22':['p24'], 'p24':['p21'], 'p21':['p23'], 'p23':['p20'], + 'p30':['p32'], 'p32':['p34'], 'p34':['p31'], 'p31':['p33'], 'p33':['p30'], + 'p40':['p42'], 'p42':['p44'], 'p44':['p41'], 'p41':['p43'], 'p43':['p40']}) for j in range(5): for i in range(5): for k in range(5): @@ -3158,7 +3199,7 @@ def HoffmanSingletonGraph(): if len(v): s = int(v[0]) l+=1 - map = H.relabel(return_map=True) + map = H.relabel(range(50), return_map=True) pos_dict = {} for i in range(50): x = float(cos((pi/2) + ((2*pi)/50)*i)) @@ -3720,12 +3761,11 @@ def MoserSpindle(): r""" Return the Moser spindle. - For more information, see this `MathWorld article on the Moser spindle - `_. + For more information, see the :wikipedia:`Moser_spindle`. EXAMPLES: - The Moser spindle is a planar graph having 7 vertices and 11 edges. :: + The Moser spindle is a planar graph having 7 vertices and 11 edges:: sage: G = graphs.MoserSpindle(); G Moser spindle: Graph on 7 vertices @@ -3736,7 +3776,7 @@ def MoserSpindle(): sage: G.size() 11 - It is a Hamiltonian graph with radius 2, diameter 2, and girth 3. :: + It is a Hamiltonian graph with radius 2, diameter 2, and girth 3:: sage: G.is_hamiltonian() True @@ -3747,9 +3787,14 @@ def MoserSpindle(): sage: G.girth() 3 - The Moser spindle has chromatic number 4 and its automorphism group is - isomorphic to the dihedral group `D_4`. :: + The Moser spindle can be drawn in the plane as a unit distance graph, + has chromatic number 4, and its automorphism group is isomorphic to + the dihedral group `D_4`:: + sage: pos = G.get_pos() + sage: all(sum((ui-vi)**2 for ui, vi in zip(pos[u], pos[v])) == 1 + ....: for u, v in G.edge_iterator(labels=None)) + True sage: G.chromatic_number() 4 sage: ag = G.automorphism_group() @@ -3757,19 +3802,23 @@ def MoserSpindle(): True """ edge_dict = { - 0: [1,4,5,6], - 1: [2,5], - 2: [3,5], - 3: [4,6], + 0: [1, 4, 6], + 1: [2, 5], + 2: [3, 5], + 3: [4, 5, 6], 4: [6]} pos_dict = { - 0: [0, 2], - 1: [-1.90211303259031, 0.618033988749895], - 2: [-1.17557050458495, -1.61803398874989], - 3: [1.17557050458495, -1.61803398874989], - 4: [1.90211303259031, 0.618033988749895], - 5: [1, 0], - 6: [-1, 0]} + 0: [QQ('1/2'), 0], + 1: [- QQ('1/2'), 0], + 2: [- QQ('1/12') * sqrt(33) - QQ('1/4'), + QQ('1/2') * sqrt( QQ('1/6') * sqrt(33) + QQ('17/6'))], + 3: [0, QQ('1/2') * sqrt(11)], + 4: [QQ('1/12') * sqrt(33) + QQ('1/4'), + QQ('1/2') * sqrt( QQ('1/6') * sqrt(33) + QQ('17/6'))], + 5: [QQ('1/12') * sqrt(33) - QQ('1/4'), + QQ('1/2') * sqrt(- QQ('1/6') * sqrt(33) + QQ('17/6'))], + 6: [- QQ('1/12') * sqrt(33) + QQ('1/4'), + QQ('1/2') * sqrt(- QQ('1/6') * sqrt(33) + QQ('17/6'))]} return Graph(edge_dict, pos=pos_dict, name="Moser spindle") @@ -4186,8 +4235,9 @@ def SousselierGraph(): Return the Sousselier Graph. The Sousselier graph is a hypohamiltonian graph on 16 vertices and 27 - edges. For more information, see the corresponding `Wikipedia page (in - French) `_. + edges. For more information, see :wikipedia:`Sousselier_graph` or + the corresponding French + `Wikipedia page `_. EXAMPLES:: @@ -4571,15 +4621,15 @@ def WatkinsSnarkGraph(): g._circle_embedding(list(range(5)), shift=.25, radius=1.1) return g + def WienerArayaGraph(): r""" Return the Wiener-Araya Graph. The Wiener-Araya Graph is a planar hypohamiltonian graph on 42 vertices and 67 edges. For more information, see the `Wolfram Page on the Wiener-Araya - Graph `_ or its - `(french) Wikipedia page - `_. + Graph `_ or + :wikipedia:`Wiener-Araya_graph`. EXAMPLES:: @@ -4631,6 +4681,7 @@ def WienerArayaGraph(): g.relabel() return g + def _EllipticLinesProjectivePlaneScheme(k): r""" Pseudo-cyclic association scheme for action of `O(3,2^k)` on elliptic lines @@ -4855,7 +4906,7 @@ def JankoKharaghaniTonchevGraph(): for i,b in ((1,B1),(163,B163)): for j in map(lambda x: x[0], st.OrbitsDomain(b)): Gamma.add_edges(map(tuple,G.Orbit(libgap.Set([i,j]), libgap.OnSets))) - Gamma.relabel() + Gamma.relabel(range(Gamma.order())) return Gamma def IoninKharaghani765Graph(): diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index ddf503b65f9..cecd642afed 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -147,7 +147,8 @@ :meth:`~GenericGraph.clustering_coeff` | Return the clustering coefficient for each vertex in nbunch :meth:`~GenericGraph.cluster_transitivity` | Return the transitivity (fraction of transitive triangles) of the graph. :meth:`~GenericGraph.szeged_index` | Return the Szeged index of the graph. - + :meth:`~GenericGraph.katz_centrality` | Return the katz centrality of the vertex u of the graph. + :meth:`~GenericGraph.katz_matrix` | Return the katz matrix of the graph. **Automorphism group:** @@ -432,6 +433,8 @@ from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from sage.rings.rational import Rational +from sage.matrix.constructor import matrix +from sage.rings.rational_field import QQ to_hex = LazyImport('matplotlib.colors', 'to_hex') @@ -1205,7 +1208,7 @@ def __copy__(self): A new graph instance that is as close as possible to the original graph. The output is always mutable. - EXAMPLES: + EXAMPLES:: sage: g = Graph({0: [1, 2, 3], 2: [4]}, immutable=True) sage: g.weighted(list(range(5))) @@ -1939,25 +1942,29 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None): EXAMPLES:: - sage: G = graphs.CubeGraph(3) + sage: G = graphs.PetersenGraph() sage: G.incidence_matrix() - [0 1 0 0 0 1 0 1 0 0 0 0] - [0 0 0 1 0 1 1 0 0 0 0 0] - [1 1 1 0 0 0 0 0 0 0 0 0] - [1 0 0 1 1 0 0 0 0 0 0 0] - [0 0 0 0 0 0 0 1 0 0 1 1] - [0 0 0 0 0 0 1 0 0 1 0 1] - [0 0 1 0 0 0 0 0 1 0 1 0] - [0 0 0 0 1 0 0 0 1 1 0 0] + [1 1 1 0 0 0 0 0 0 0 0 0 0 0 0] + [1 0 0 1 1 0 0 0 0 0 0 0 0 0 0] + [0 0 0 1 0 1 1 0 0 0 0 0 0 0 0] + [0 0 0 0 0 1 0 1 1 0 0 0 0 0 0] + [0 1 0 0 0 0 0 1 0 1 0 0 0 0 0] + [0 0 1 0 0 0 0 0 0 0 1 1 0 0 0] + [0 0 0 0 1 0 0 0 0 0 0 0 1 1 0] + [0 0 0 0 0 0 1 0 0 0 1 0 0 0 1] + [0 0 0 0 0 0 0 0 1 0 0 1 1 0 0] + [0 0 0 0 0 0 0 0 0 1 0 0 0 1 1] sage: G.incidence_matrix(oriented=True) - [ 0 -1 0 0 0 -1 0 -1 0 0 0 0] - [ 0 0 0 -1 0 1 -1 0 0 0 0 0] - [-1 1 -1 0 0 0 0 0 0 0 0 0] - [ 1 0 0 1 -1 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 1 0 0 -1 -1] - [ 0 0 0 0 0 0 1 0 0 -1 0 1] - [ 0 0 1 0 0 0 0 0 -1 0 1 0] - [ 0 0 0 0 1 0 0 0 1 1 0 0] + [-1 -1 -1 0 0 0 0 0 0 0 0 0 0 0 0] + [ 1 0 0 -1 -1 0 0 0 0 0 0 0 0 0 0] + [ 0 0 0 1 0 -1 -1 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 1 0 -1 -1 0 0 0 0 0 0] + [ 0 1 0 0 0 0 0 1 0 -1 0 0 0 0 0] + [ 0 0 1 0 0 0 0 0 0 0 -1 -1 0 0 0] + [ 0 0 0 0 1 0 0 0 0 0 0 0 -1 -1 0] + [ 0 0 0 0 0 0 1 0 0 0 1 0 0 0 -1] + [ 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0] + [ 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1] sage: G = digraphs.Circulant(4, [1, 3]) sage: G.incidence_matrix() @@ -2201,14 +2208,16 @@ def weighted_adjacency_matrix(self, sparse=True, vertices=None): M = matrix(self.num_verts(), D, sparse=sparse) return M - def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, **kwds): + def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, signless=False, **kwds): r""" Return the Kirchhoff matrix (a.k.a. the Laplacian) of the graph. - The Kirchhoff matrix is defined to be `D - M`, where `D` is the diagonal - degree matrix (each diagonal entry is the degree of the corresponding - vertex), and `M` is the adjacency matrix. If ``normalized`` is - ``True``, then the returned matrix is `D^{-1/2}(D-M)D^{-1/2}`. + The Kirchhoff matrix is defined to be `D + M` if signless and `D - M` + otherwise, where `D` is the diagonal degree matrix (each diagonal entry + is the degree of the corresponding vertex), and `M` is the adjacency + matrix. If ``normalized`` is ``True``, then the returned matrix is + `D^{-1/2}(D+M)D^{-1/2}` if signless and `D^{-1/2}(D-M)D^{-1/2}` + otherwise. (In the special case of DiGraphs, `D` is defined as the diagonal in-degree matrix or diagonal out-degree matrix according to the value of @@ -2234,20 +2243,26 @@ def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, **kwd the corresponding vertex - Else, each diagonal entry of `D` is equal to the out-degree of the - corresponding vertex. + corresponding vertex By default, ``indegree`` is set to ``True`` - ``normalized`` -- boolean (default: ``False``); - - If ``True``, the returned matrix is `D^{-1/2}(D-M)D^{-1/2}`, a - normalized version of the Laplacian matrix. - More accurately, the normalizing matrix used is equal to `D^{-1/2}` - only for non-isolated vertices. If vertex `i` is isolated, then - diagonal entry `i` in the matrix is 1, rather than a division by - zero. + - If ``True``, the returned matrix is `D^{-1/2}(D+M)D^{-1/2}` for + signless and `D^{-1/2}(D-M)D^{-1/2}` otherwise, a normalized + version of the Laplacian matrix. More accurately, the normalizing + matrix used is equal to `D^{-1/2}` only for non-isolated vertices. + If vertex `i` is isolated, then diagonal entry `i` in the matrix is + 1, rather than a division by zero + + - Else, the matrix `D+M` for signless and `D-M` otherwise is returned + + - ``signless`` -- boolean (default: ``False``); - - Else, the matrix `D-M` is returned + - If ``True``, `D+M` is used in calculation of Kirchhoff matrix + + - Else, `D-M` is used in calculation of Kirchhoff matrix Note that any additional keywords will be passed on to either the ``adjacency_matrix`` or ``weighted_adjacency_matrix`` method. @@ -2276,11 +2291,21 @@ def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, **kwd [-1/6*sqrt(3)*sqrt(2) 1 -1/2 0] [-1/6*sqrt(3)*sqrt(2) -1/2 1 0] [ -1/3*sqrt(3) 0 0 1] - - sage: Graph({0: [], 1: [2]}).laplacian_matrix(normalized=True) + sage: M = G.kirchhoff_matrix(weighted=True, signless=True); M + [8 1 3 4] + [1 3 2 0] + [3 2 5 0] + [4 0 0 4] + + sage: G = Graph({0: [], 1: [2]}) + sage: G.laplacian_matrix(normalized=True) [ 0 0 0] [ 0 1 -1] [ 0 -1 1] + sage: G.laplacian_matrix(normalized=True,signless=True) + [0 0 0] + [0 1 1] + [0 1 1] A weighted directed graph with loops, changing the variable ``indegree`` :: @@ -2351,10 +2376,15 @@ def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, **kwd if normalized: Dsqrt = diagonal_matrix([1 / sqrt(D[i,i]) if D[i,i] else 1 \ for i in range(D.nrows())]) - return Dsqrt * (D - M) * Dsqrt + if signless: + return Dsqrt * (D + M) * Dsqrt + else: + return Dsqrt * (D - M) * Dsqrt else: - return D - M - + if signless: + return D + M + else: + return D - M laplacian_matrix = kirchhoff_matrix ### Attributes @@ -3880,8 +3910,13 @@ def eulerian_circuit(self, return_vertices=False, labels=True, path=False): TESTS:: - sage: Graph({'H': ['G','L','L','D'], 'L': ['G','D']}).eulerian_circuit(labels=False) - [('H', 'D'), ('D', 'L'), ('L', 'G'), ('G', 'H'), ('H', 'L'), ('L', 'H')] + sage: G = Graph([['D', 'G', 'H', 'L'], + ....: [('D', 'H'), ('D', 'L'), ('G', 'H'), ('G', 'L'), ('H', 'L'), ('H', 'L')]], + ....: multiedges=True) + sage: G.eulerian_circuit(labels=False) # py2 + [('H', 'L'), ('L', 'G'), ('G', 'H'), ('H', 'L'), ('L', 'D'), ('D', 'H')] + sage: G.eulerian_circuit(labels=False) # py3 + [('D', 'L'), ('L', 'H'), ('H', 'L'), ('L', 'G'), ('G', 'H'), ('H', 'D')] sage: Graph({0: [0, 1, 1, 1, 1]}).eulerian_circuit(labels=False) [(0, 1), (1, 0), (0, 1), (1, 0), (0, 0)] """ @@ -4047,8 +4082,8 @@ def min_spanning_tree(self, Boruvka's algorithm:: - sage: g.min_spanning_tree(algorithm='Boruvka') - [(0, 1, None), (1, 2, None), (2, 3, None), (0, 4, None), (0, 5, None), (1, 6, None), (2, 7, None), (3, 8, None), (4, 9, None)] + sage: sorted(g.min_spanning_tree(algorithm='Boruvka')) + [(0, 1, None), (0, 4, None), (0, 5, None), (1, 2, None), (1, 6, None), (2, 3, None), (2, 7, None), (3, 8, None), (4, 9, None)] Prim's algorithm:: @@ -4426,12 +4461,14 @@ def cycle_basis(self, output='vertex'): A cycle basis in Petersen's Graph :: sage: g = graphs.PetersenGraph() - sage: g.cycle_basis() + sage: g.cycle_basis() # py2 [[1, 2, 7, 5, 0], [8, 3, 2, 7, 5], [4, 3, 2, 7, 5, 0], [4, 9, 7, 5, 0], [8, 6, 9, 7, 5], [1, 6, 9, 7, 5, 0]] + sage: g.cycle_basis() # py3 + [[1, 6, 8, 5, 0], [4, 9, 6, 8, 5, 0], [7, 9, 6, 8, 5], [4, 3, 8, 5, 0], [1, 2, 3, 8, 5, 0], [7, 2, 3, 8, 5]] One can also get the result as a list of lists of edges:: - sage: g.cycle_basis(output='edge') + sage: g.cycle_basis(output='edge') # py2 [[(1, 2, None), (2, 7, None), (7, 5, None), (5, 0, None), (0, 1, None)], [(8, 3, None), (3, 2, None), (2, 7, None), (7, 5, None), (5, 8, None)], [(4, 3, None), (3, 2, None), @@ -4440,6 +4477,15 @@ def cycle_basis(self, output='vertex'): (0, 4, None)], [(8, 6, None), (6, 9, None), (9, 7, None), (7, 5, None), (5, 8, None)], [(1, 6, None), (6, 9, None), (9, 7, None), (7, 5, None), (5, 0, None), (0, 1, None)]] + sage: g.cycle_basis(output='edge') # py3 + [[(1, 6, None), (6, 8, None), (8, 5, None), (5, 0, None), + (0, 1, None)], [(4, 9, None), (9, 6, None), (6, 8, None), + (8, 5, None), (5, 0, None), (0, 4, None)], [(7, 9, None), + (9, 6, None), (6, 8, None), (8, 5, None), (5, 7, None)], + [(4, 3, None), (3, 8, None), (8, 5, None), (5, 0, None), + (0, 4, None)], [(1, 2, None), (2, 3, None), (3, 8, None), + (8, 5, None), (5, 0, None), (0, 1, None)], [(7, 2, None), + (2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None)]] Checking the given cycles are algebraically free:: @@ -4452,7 +4498,7 @@ def cycle_basis(self, output='vertex'): sage: m = g.size() sage: edge_space = VectorSpace(FiniteField(2), m) sage: edge_vector = dict(zip(g.edges(labels=False, sort=False), edge_space.basis())) - sage: for (u, v), vec in edge_vector.items(): + sage: for (u, v), vec in list(edge_vector.items()): ....: edge_vector[(v, u)] = vec Defining a lambda function associating a vector to the vertices of a @@ -4478,14 +4524,20 @@ def cycle_basis(self, output='vertex'): Disconnected graph:: sage: G.add_cycle(["Hey", "Wuuhuu", "Really ?"]) - sage: G.cycle_basis() - [['Really ?', 'Hey', 'Wuuhuu'], [0, 2], [2, 1, 0]] - sage: G.cycle_basis(output='edge') - [[('Really ?', 'Hey', None), - ('Hey', 'Wuuhuu', None), + sage: [sorted(c) for c in G.cycle_basis()] + [['Hey', 'Really ?', 'Wuuhuu'], [0, 2], [0, 1, 2]] + sage: [sorted(c) for c in G.cycle_basis(output='edge')] # py2 + [[('Hey', 'Wuuhuu', None), + ('Really ?', 'Hey', None), ('Wuuhuu', 'Really ?', None)], [(0, 2, 'a'), (2, 0, 'b')], - [(2, 1, 'd'), (1, 0, 'c'), (0, 2, 'b')]] + [(0, 2, 'b'), (1, 0, 'c'), (2, 1, 'd')]] + sage: [sorted(c) for c in G.cycle_basis(output='edge')] # py3 + [[('Hey', 'Really ?', None), + ('Really ?', 'Wuuhuu', None), + ('Wuuhuu', 'Hey', None)], + [(0, 2, 'a'), (2, 0, 'b')], + [(0, 2, 'b'), (1, 0, 'c'), (2, 1, 'd')]] Graph that allows multiple edges but does not contain any:: @@ -5087,7 +5139,7 @@ def is_drawn_free_of_edge_crossings(self): q1, q2 = self._pos[edge2[0]], self._pos[edge2[1]] db = Rational(q2[1] - q1[1]) da = Rational(q2[0] - q1[0]) - if(da * dy == db * dx): + if da * dy == db * dx: if dx: t1 = Rational(q1[0] - p1[0]) / dx t2 = Rational(q2[0] - p1[0]) / dx @@ -5199,7 +5251,9 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal sage: cube.genus(circular=['01','10']) 0 sage: cube.genus(circular=['01','10'], on_embedding=True) - 0 + Traceback (most recent call last): + ... + ValueError: on_embedding is not a valid option when circular is defined sage: cube.genus(circular=['01','10'], maximal=True) Traceback (most recent call last): ... @@ -5250,6 +5304,8 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal raise ValueError("'circular' is expected to be a list") if maximal: raise NotImplementedError("cannot compute the maximal genus of a genus respecting a boundary") + if on_embedding is not None: + raise ValueError("on_embedding is not a valid option when circular is defined") boundary = circular if hasattr(G, '_embedding'): del(G._embedding) @@ -6170,7 +6226,7 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, return_value.append(self.edge_boundary(reachable_from_s)) if vertices: - return_value.append([reachable_from_s, list(set(self.vertices()).difference(reachable_from_s))]) + return_value.append([reachable_from_s, list(set(self).difference(reachable_from_s))]) return return_value @@ -8737,7 +8793,7 @@ def _ford_fulkerson(self, s, t, use_edge_labels=False, integer=False, value_only # edge is strictly less than its capacity, or when there exists a back # arc with non-null flow residual = DiGraph() - residual.add_vertices(self.vertices()) + residual.add_vertices(self) # Initializing the variables if directed: @@ -9037,7 +9093,7 @@ def _build_flow_graph(self, flow, integer): sage: flow_graph.edges() [('000', '001', 1)] """ - + from sage.misc.functional import round from sage.graphs.digraph import DiGraph g = DiGraph() @@ -9076,7 +9132,7 @@ def _build_flow_graph(self, flow, integer): # returning a graph with the same embedding, the corresponding name, etc ... h = self.subgraph(edges=[], immutable=False) - h.delete_vertices([v for v in self if (v not in g) or not g.degree(v)]) + h.delete_vertices(v for v in self if (v not in g) or not g.degree(v)) h.add_edges(g.edge_iterator()) return h @@ -9745,8 +9801,8 @@ def vertex_boundary(self, vertices1, vertices2=None): sage: G = graphs.CubeGraph(4) sage: l = ['0111', '0000', '0001', '0011', '0010', '0101', '0100', '1111', '1101', '1011', '1001'] - sage: G.vertex_boundary(['0000', '1111'], l) - ['0111', '0001', '0010', '0100', '1101', '1011'] + sage: sorted(G.vertex_boundary(['0000', '1111'], l)) + ['0001', '0010', '0100', '0111', '1011', '1101'] :: @@ -9829,10 +9885,17 @@ def set_vertex(self, vertex, object): sage: T.set_vertex(1, graphs.FlowerSnark()) sage: T.get_vertex(1) Flower Snark: Graph on 20 vertices + sage: T.set_vertex(4, 'foo') + Traceback (most recent call last): + ... + ValueError: vertex (4) not in the graph """ if hasattr(self, '_assoc') is False: self._assoc = {} + if not self.has_vertex(vertex): + raise ValueError('vertex (%s) not in the graph' % str(vertex)) + self._assoc[vertex] = object def get_vertex(self, vertex): @@ -9941,18 +10004,18 @@ def neighbor_iterator(self, vertex): EXAMPLES:: - sage: G = graphs.CubeGraph(3) - sage: for i in G.neighbor_iterator('010'): - ....: print(i) - 011 - 000 - 110 + sage: G = graphs.PetersenGraph() + sage: for i in G.neighbor_iterator(0): + ....: print(i) + 1 + 4 + 5 sage: D = G.to_directed() - sage: for i in D.neighbor_iterator('010'): - ....: print(i) - 011 - 000 - 110 + sage: for i in D.neighbor_iterator(0): + ....: print(i) + 1 + 4 + 5 :: @@ -11477,11 +11540,17 @@ def degree(self, vertices=None, labels=False): sage: D = digraphs.DeBruijn(4, 2) sage: D.delete_vertex('20') - sage: print(D.degree()) + sage: print(D.degree()) # py2 [6, 7, 7, 7, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8, 8] - sage: print(D.degree(vertices=list(D))) + sage: print(D.degree(vertices=list(D))) # py2 [6, 7, 7, 7, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8, 8] - sage: print(D.degree(vertices=D.vertices())) + sage: print(D.degree(vertices=D.vertices())) # py2 + [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] + sage: print(D.degree()) # py3 + [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] + sage: print(D.degree(vertices=list(D))) # py3 + [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] + sage: print(D.degree(vertices=D.vertices())) # py3 [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] """ if labels: @@ -11581,50 +11650,84 @@ def degree_iterator(self, vertices=None, labels=False): EXAMPLES:: sage: G = graphs.Grid2dGraph(3, 4) - sage: for i in G.degree_iterator(): - ....: print(i) + sage: for i in G.degree_iterator(): # py2 + ....: print(i) # py2 3 4 2 ... 2 4 - sage: for i in G.degree_iterator(labels=True): - ....: print(i) + sage: for i in G.degree_iterator(): # py3 + ....: print(i) # py3 + 2 + 3 + 3 + ... + 3 + 2 + sage: for i in G.degree_iterator(labels=True): # py2 + ....: print(i) # py2 ((0, 1), 3) ((1, 2), 4) ((0, 0), 2) ... ((0, 3), 2) ((1, 1), 4) + sage: for i in G.degree_iterator(labels=True): # py3 + ....: print(i) # py3 + ((0, 0), 2) + ((0, 1), 3) + ((0, 2), 3) + ... + ((2, 2), 3) + ((2, 3), 2) :: sage: D = graphs.Grid2dGraph(2,4).to_directed() - sage: for i in D.degree_iterator(): - ....: print(i) + sage: for i in D.degree_iterator(): # py2 + ....: print(i) # py2 6 6 ... 4 6 - sage: for i in D.degree_iterator(labels=True): - ....: print(i) + sage: for i in D.degree_iterator(): # py3 + ....: print(i) # py3 + 4 + 6 + ... + 6 + 4 + sage: for i in D.degree_iterator(labels=True): # py2 + ....: print(i) # py2 ((0, 1), 6) ((1, 2), 6) ... ((1, 0), 4) ((0, 2), 6) + sage: for i in D.degree_iterator(labels=True): # py3 + ....: print(i) # py3 + ((0, 0), 4) + ((0, 1), 6) + ... + ((1, 2), 6) + ((1, 3), 4) When ``vertices=None`` yields values in the order of ``list(D)``:: sage: V = list(D) sage: D = digraphs.DeBruijn(4, 2) sage: D.delete_vertex('20') - sage: print(list(D.degree_iterator())) + sage: print(list(D.degree_iterator())) # py2 [6, 7, 7, 7, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8, 8] - sage: print([D.degree(v) for v in D]) + sage: print([D.degree(v) for v in D]) # py2 [6, 7, 7, 7, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8, 8] + sage: print(list(D.degree_iterator())) # py3 + [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] + sage: print([D.degree(v) for v in D]) # py3 + [7, 7, 6, 7, 8, 8, 7, 8, 8, 7, 8, 8, 8, 7, 8] """ if vertices is None: vertices = self @@ -12002,6 +12105,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm if edges is not None: edges_to_keep_labeled = frozenset(e for e in edges if len(e) == 3) edges_to_keep_unlabeled = frozenset(e for e in edges if len(e) == 2) + edges_to_keep = [] if self._directed: for u, v, l in self.edge_iterator(vertices): @@ -12213,7 +12317,7 @@ def subgraph_search(self, G, induced=False): .. NOTE:: - This method does not take vertex/edge labels into account. + The vertex labels and the edge labels in the graph are ignored. .. SEEALSO:: @@ -12298,12 +12402,36 @@ def subgraph_search(self, G, induced=False): sage: k3.subgraph_search(p3, induced=True) is None True + If the graph has labels, the labels are just ignored:: + + sage: g.set_vertex(0, 'foo') + sage: c = g.subgraph_search(graphs.PathGraph(5)) + sage: c.get_vertices() + {0: 'foo', 1: None, 2: None, 3: None, 4: None} + TESTS: Inside of a small graph (:trac:`13906`):: sage: Graph(5).subgraph_search(Graph(1)) Graph on 1 vertex + + For labelled edges (:trac:`14999`):: + + sage: G = graphs.CompleteGraph(10) + sage: C = G.subgraph_search(graphs.CycleGraph(4)) + sage: C.size() + 4 + sage: C.edges() + [(0, 1, None), (0, 3, None), (1, 2, None), (2, 3, None)] + + sage: for (u,v) in G.edges(labels=False): + ....: G.set_edge_label(u, v, u) + + sage: C = G.subgraph_search(graphs.CycleGraph(4)) + sage: C.edges() + [(0, 1, 0), (0, 3, 0), (1, 2, 1), (2, 3, 2)] + """ from sage.graphs.generic_graph_pyx import SubgraphSearch from sage.graphs.graph_generators import GraphGenerators @@ -12327,7 +12455,7 @@ def subgraph_search(self, G, induced=False): else: Gcopy = copy(G) Gcopy.relabel(g) - return self.subgraph(vertices=Gcopy, edges=Gcopy.edges(sort=False)) + return self.subgraph(vertices=Gcopy, edges=Gcopy.edges(labels=False, sort=False)) return None @@ -12344,7 +12472,7 @@ def subgraph_search_count(self, G, induced=False): .. NOTE:: - This method does not take vertex/edge labels into account. + The vertex labels and the edge labels in the graph are ignored. ALGORITHM: @@ -12397,6 +12525,12 @@ def subgraph_search_count(self, G, induced=False): sage: g.subgraph_search_count(graphs.EmptyGraph()) 1 + If the graph has vertex labels or edge labels, the label is just ignored:: + + sage: g.set_vertex(0, 'foo') + sage: g.subgraph_search_count(graphs.PathGraph(5)) + 240 + TESTS: Inside of a small graph (:trac:`13906`):: @@ -12432,7 +12566,7 @@ def subgraph_search_iterator(self, G, induced=False): .. NOTE:: - This method does not take vertex/edge labels into account. + The vertex labels and the edge labels in the graph are ignored. ALGORITHM: @@ -12471,6 +12605,18 @@ def subgraph_search_iterator(self, G, induced=False): [3, 2, 1] [4, 3, 2] + If the graph has vertex labels or edge labels, the label is just ignored:: + + sage: g.set_vertex(0, 'foo') + sage: for p in g.subgraph_search_iterator(graphs.PathGraph(3)): + ....: print(p) + [0, 1, 2] + [1, 2, 3] + [2, 1, 0] + [2, 3, 4] + [3, 2, 1] + [4, 3, 2] + TESTS: Inside of a small graph (:trac:`13906`):: @@ -13806,20 +13952,20 @@ def cluster_transitivity(self): def distance(self, u, v, by_weight=False): """ - Returns the (directed) distance from u to v in the (di)graph, i.e. - the length of the shortest path from u to v. + Return the (directed) distance from ``u`` to ``v`` in the (di)graph. + + The distance is the length of the shortest path from ``u`` to ``v``. - This method simply calls - :meth:`~GenericGraph.shortest_path_length`, + This method simply calls :meth:`~GenericGraph.shortest_path_length`, with default arguments. For more information, and for more option, we refer to that method. INPUT: - - ``by_weight`` - if ``False``, the graph is considered unweighted, and - the distance is the number of edges in a shortest path. If ``True``, - the distance is the sum of edge labels (which are assumed to be - numbers). + - ``by_weight`` -- boolean (default: ``False``); if ``False``, the graph + is considered unweighted, and the distance is the number of edges in a + shortest path. If ``True``, the distance is the sum of edge labels + (which are assumed to be numbers). EXAMPLES:: @@ -13840,27 +13986,28 @@ def distance(self, u, v, by_weight=False): sage: G.distance(0, 3, by_weight=True) 3 """ - return self.shortest_path_length(u, v, by_weight = by_weight) + return self.shortest_path_length(u, v, by_weight=by_weight) def distance_all_pairs(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" - Returns the distances between all pairs of vertices. + Return the distances between all pairs of vertices. INPUT: - - ``by_weight`` (boolean) - if ``True``, the edges in the graph are - weighted; if ``False``, all edges have weight 1. + - ``by_weight`` boolean (default: `False``); if ``True``, the edges in + the graph are weighted; if ``False``, all edges have weight 1. - - ``algorithm`` (string) - one of the following algorithms: + - ``algorithm`` -- string (default: ``None``); one of the following + algorithms: - - ``'BFS'`` - the computation is done through a BFS centered on each + - ``'BFS'``: the computation is done through a BFS centered on each vertex successively. Works only if ``by_weight==False``. - - ``'Floyd-Warshall-Cython'`` - the Cython implementation of + - ``'Floyd-Warshall-Cython'``: the Cython implementation of the Floyd-Warshall algorithm. Works only if ``by_weight==False``. - - ``'Floyd-Warshall-Python'`` - the Python implementation of + - ``'Floyd-Warshall-Python'``: the Python implementation of the Floyd-Warshall algorithm. Works also with weighted graphs, even with negative weights (but no negative cycle is allowed). @@ -13879,13 +14026,14 @@ def distance_all_pairs(self, by_weight=False, algorithm=None, ``by_weight`` is ``False``, ``'Dijkstra_Boost'`` if all weights are positive, ``'Floyd-Warshall-Cython'`` otherwise. - - ``weight_function`` (function) - a function that takes as input an - edge ``(u, v, l)`` and outputs its weight. If not ``None``, - ``by_weight`` is automatically set to ``True``. If ``None`` and - ``by_weight`` is ``True``, we use the edge label ``l`` as a weight. + - ``weight_function`` -- function (default: ``None``); a function that + takes as input an edge ``(u, v, l)`` and outputs its weight. If not + ``None``, ``by_weight`` is automatically set to ``True``. If ``None`` + and ``by_weight`` is ``True``, we use the edge label ``l`` as a + weight. - - ``check_weight`` (boolean) - if ``True``, we check that the - weight_function outputs a number for each edge. + - ``check_weight`` -- boolean (default: ``True``); whether to check that + the ``weight_function`` outputs a number for each edge. OUTPUT: @@ -13893,17 +14041,16 @@ def distance_all_pairs(self, by_weight=False, algorithm=None, .. NOTE:: - There is a Cython version of this method that is usually - much faster for large graphs, as most of the time is - actually spent building the final double - dictionary. Everything on the subject is to be found in the - :mod:`~sage.graphs.distances_all_pairs` module. + There is a Cython version of this method that is usually much faster + for large graphs, as most of the time is actually spent building the + final double dictionary. Everything on the subject is to be found in + the :mod:`~sage.graphs.distances_all_pairs` module. .. NOTE:: - This algorithm simply calls - :meth:`GenericGraph.shortest_path_all_pairs`, and we suggest to look - at that method for more information and examples. + This algorithm simply calls + :meth:`GenericGraph.shortest_path_all_pairs`, and we suggest to look + at that method for more information and examples. EXAMPLES: @@ -14009,7 +14156,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, sage: G.eccentricity(7) 2 sage: G.eccentricity([7,8,9]) - [3, 4, 2] + [2, 3, 4] sage: G.eccentricity([7,8,9], with_labels=True) == {8: 3, 9: 4, 7: 2} True sage: G = Graph( { 0 : [], 1 : [], 2 : [1] } ) @@ -14102,24 +14249,28 @@ def weight_function(e): if by_weight: raise ValueError("algorithm 'BFS' does not work with weights") from sage.graphs.distances_all_pairs import eccentricity - + algo = 'standard' if self.is_directed() else 'bounds' if with_labels: - return dict(zip(self.vertices(), eccentricity(self))) + vertex_list = list(self) + return dict(zip(vertex_list, eccentricity(self, algorithm=algo, vertex_list=vertex_list))) else: - return eccentricity(self, algorithm='standard' if self.is_directed() else 'bounds') + return eccentricity(self, algorithm=algo) + if algorithm in ['Floyd-Warshall-Python', 'Floyd-Warshall-Cython', 'Johnson_Boost']: dist_dict = self.shortest_path_all_pairs(by_weight, algorithm, weight_function, check_weight)[0] algorithm = 'From_Dictionary' + v = self.vertices() + elif algorithm in ['Floyd-Warshall-Python', 'Floyd-Warshall-Cython', 'Johnson_Boost']: raise ValueError("algorithm '" + algorithm + "' works only if all" + " eccentricities are needed") if not isinstance(v, list): v = [v] - e = {} + ecc = {} from sage.rings.infinity import Infinity @@ -14135,18 +14286,18 @@ def weight_function(e): check_weight=check_weight) if len(length) != self.num_verts(): - e[u] = Infinity + ecc[u] = Infinity else: - e[u] = max(length.values()) + ecc[u] = max(length.values()) if with_labels: - return e + return ecc else: - if len(e) == 1: + if len(ecc) == 1: # return single value - v, = e.values() + v, = ecc.values() return v - return list(itervalues(e)) + return [ecc[u] for u in v] def radius(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): @@ -14400,31 +14551,27 @@ def center(self, by_weight=False, algorithm=None, weight_function=None, def distance_graph(self, dist): r""" - Returns the graph on the same vertex set as - the original graph but vertices are adjacent - in the returned graph if and only if they are - at specified distances in the original graph. + Return the graph on the same vertex set as the original graph but + vertices are adjacent in the returned graph if and only if they are at + specified distances in the original graph. INPUT: - - ``dist`` is a nonnegative integer or - a list of nonnegative integers. - ``Infinity`` may be used here to describe - vertex pairs in separate components. + - ``dist`` -- a nonnegative integer or a list of nonnegative integers; + specified distance(s) for the connecting vertices. ``Infinity`` may + be used here to describe vertex pairs in separate components. OUTPUT: - The returned value is an undirected graph. The - vertex set is identical to the calling graph, but edges - of the returned graph join vertices whose distance in - the calling graph are present in the input ``dist``. - Loops will only be present if distance 0 is included. If - the original graph has a position dictionary specifying - locations of vertices for plotting, then this information - is copied over to the distance graph. In some instances - this layout may not be the best, and might even be confusing - when edges run on top of each other due to symmetries - chosen for the layout. + The returned value is an undirected graph. The vertex set is identical + to the calling graph, but edges of the returned graph join vertices + whose distance in the calling graph are present in the input ``dist``. + Loops will only be present if distance 0 is included. If the original + graph has a position dictionary specifying locations of vertices for + plotting, then this information is copied over to the distance graph. + In some instances this layout may not be the best, and might even be + confusing when edges run on top of each other due to symmetries chosen + for the layout. EXAMPLES:: @@ -14439,11 +14586,11 @@ def distance_graph(self, dist): [0 1 0 1 0 0] [1 0 1 0 0 0] - To obtain the graph where vertices are adjacent if their - distance apart is ``d`` or less use a ``range()`` command - to create the input, using ``d+1`` as the input to ``range``. - Notice that this will include distance 0 and hence place a loop - at each vertex. To avoid this, use ``range(1,d+1)``. :: + To obtain the graph where vertices are adjacent if their distance apart + is ``d`` or less use a ``range()`` command to create the input, using + ``d + 1`` as the input to ``range``. Notice that this will include + distance 0 and hence place a loop at each vertex. To avoid this, use + ``range(1, d + 1)``:: sage: G = graphs.OddGraph(4) sage: d = G.diameter() @@ -14455,8 +14602,8 @@ def distance_graph(self, dist): sage: H.is_isomorphic(graphs.CompleteGraph(n)) True - A complete collection of distance graphs will have - adjacency matrices that sum to the matrix of all ones. :: + A complete collection of distance graphs will have adjacency matrices + that sum to the matrix of all ones:: sage: P = graphs.PathGraph(20) sage: all_ones = sum([P.distance_graph(i).am() for i in range(20)]) @@ -14464,15 +14611,15 @@ def distance_graph(self, dist): True Four-bit strings differing in one bit is the same as - four-bit strings differing in three bits. :: + four-bit strings differing in three bits:: sage: G = graphs.CubeGraph(4) sage: H = G.distance_graph(3) sage: G.is_isomorphic(H) True - The graph of eight-bit strings, adjacent if different - in an odd number of bits. :: + The graph of eight-bit strings, adjacent if different in an odd number + of bits:: sage: G = graphs.CubeGraph(8) # long time sage: H = G.distance_graph([1,3,5,7]) # long time @@ -14481,8 +14628,8 @@ def distance_graph(self, dist): sage: degrees == H.degree_histogram() # long time True - An example of using ``Infinity`` as the distance in - a graph that is not connected. :: + An example of using ``Infinity`` as the distance in a graph that is not + connected:: sage: G = graphs.CompleteGraph(3) sage: H = G.disjoint_union(graphs.CompleteGraph(2)) @@ -14496,7 +14643,7 @@ def distance_graph(self, dist): TESTS: - Empty input, or unachievable distances silently yield empty graphs. :: + Empty input, or unachievable distances silently yield empty graphs:: sage: G = graphs.CompleteGraph(5) sage: G.distance_graph([]).num_edges() @@ -14505,7 +14652,7 @@ def distance_graph(self, dist): sage: G.distance_graph(23).num_edges() 0 - It is an error to provide a distance that is not an integer type. :: + It is an error to provide a distance that is not an integer type:: sage: G = graphs.CompleteGraph(5) sage: G.distance_graph('junk') @@ -14513,13 +14660,13 @@ def distance_graph(self, dist): ... TypeError: unable to convert 'junk' to an integer - It is an error to provide a negative distance. :: + It is an error to provide a negative distance:: sage: G = graphs.CompleteGraph(5) sage: G.distance_graph(-3) Traceback (most recent call last): ... - ValueError: Distance graph for a negative distance (d=-3) is not defined + ValueError: distance graph for a negative distance (d=-3) is not defined AUTHOR: @@ -14537,12 +14684,10 @@ def distance_graph(self, dist): else: dint = ZZ(d) if dint < 0: - raise ValueError('Distance graph for a negative distance (d=%d) is not defined' % dint) + raise ValueError('distance graph for a negative distance (d=%d) is not defined' % dint) distances.append(dint) # Build a graph on the same vertex set, with loops for distance 0 - vertices = {} - for v in self.vertex_iterator(): - vertices[v] = {} + vertices = {v: {} for v in self} positions = copy(self.get_pos()) if ZZ(0) in distances: looped = True @@ -14558,16 +14703,18 @@ def distance_graph(self, dist): # Create the appropriate edges d = self.distance_all_pairs() - for u in self.vertex_iterator(): - for v in self.vertex_iterator(): + for u in self: + for v in self: if d[u].get(v, Infinity) in distances: - D.add_edge(u,v) + D.add_edge(u, v) return D def girth(self): """ - Computes the girth of the graph. For directed graphs, computes the - girth of the undirected graph. + Return the girth of the graph. + + For directed graphs, computes the girth of the undirected graph, + i.e. ``Graph(self)``. The girth is the length of the shortest cycle in the graph. Graphs without cycles have infinite girth. @@ -14585,7 +14732,6 @@ def girth(self): sage: next(graphs.trees(9)).girth() +Infinity - .. SEEALSO:: * :meth:`~sage.graphs.graph.Graph.odd_girth` -- computes @@ -14593,10 +14739,10 @@ def girth(self): TESTS: - Prior to :trac:`12243`, the girth computation assumed - vertices were integers (and failed). The example below - tests the computation for graphs with vertices that are - not integers. In this example the vertices are sets. :: + Prior to :trac:`12243`, the girth computation assumed vertices were + integers (and failed). The example below tests the computation for + graphs with vertices that are not integers. In this example the vertices + are sets:: sage: G = graphs.OddGraph(3) sage: type(G.vertices()[0]) @@ -14631,44 +14777,44 @@ def girth(self): sage: g.girth() 2 """ - # Cases where girth <= 2 if self.has_loops(): return 1 if self.is_directed(): - if any(self.has_edge(v,u) for u,v in self.edges(labels = False)): + if any(self.has_edge(v, u) for u, v in self.edge_iterator(labels=False)): return 2 else: if self.has_multiple_edges(): return 2 n = self.num_verts() - best = n+1 + best = n + 1 seen = {} - for w in self.vertex_iterator(): + for w in self: seen[w] = None span = set([w]) depth = 1 thisList = set([w]) - while 2*depth <= best and 3 < best: + while 2 * depth <= best and 3 < best: nextList = set() for v in thisList: - for u in self.neighbors(v): - if u in seen: continue + for u in self.neighbor_iterator(v): + if u in seen: + continue if not u in span: span.add(u) nextList.add(u) else: if u in thisList: - best = depth*2-1 + best = depth * 2 - 1 break if u in nextList: - best = depth*2 - if best == 2*depth-1: + best = depth * 2 + if best == 2 * depth - 1: break thisList = nextList depth += 1 - if best == n+1: + if best == n + 1: from sage.rings.infinity import Infinity return Infinity return best @@ -14739,39 +14885,41 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, endpoints=False, seed=None, exact=False, algorithm=None): r""" - Returns the betweenness centrality (fraction of number of - shortest paths that go through each vertex) as a dictionary - keyed by vertices. The betweenness is normalized by default to - be in range (0,1). + Return the betweenness centrality. + + The betweenness centrality of a vertex is the fraction of number of + shortest paths that go through each vertex. The betweenness is + normalized by default to be in range (0,1). - Measures of the centrality of a vertex within a graph determine - the relative importance of that vertex to its graph. Vertices - that occur on more shortest paths between other vertices have - higher betweenness than vertices that occur on less. + Measures of the centrality of a vertex within a graph determine the + relative importance of that vertex to its graph. Vertices that occur on + more shortest paths between other vertices have higher betweenness than + vertices that occur on less. INPUT: - - ``normalized`` - boolean (default True) - if set to False, - result is not normalized. + - ``normalized`` -- boolean (default: ``True``); if set to ``False``, + result is not normalized. - - ``k`` - integer or None (default None) - if set to an integer, use - ``k`` node samples to estimate betweenness. Higher values give better + - ``k`` -- integer (default: ``None``); if set to an integer, use ``k`` + node samples to estimate betweenness. Higher values give better approximations. Not available when ``algorithm="Sage"``. - - ``weight`` - None or string. If set to a string, use that attribute of - the nodes as weight. ``weight = True`` is equivalent to ``weight = - "weight"``. Not available when ``algorithm="Sage"``. + - ``weight`` -- string (default: ``None``); if set to a string, use that + attribute of the nodes as weight. ``weight = True`` is equivalent to + ``weight = "weight"``. Not available when ``algorithm="Sage"``. - - ``endpoints`` - Boolean. If set to True it includes the endpoints in - the shortest paths count. Not available when ``algorithm="Sage"``. + - ``endpoints`` -- boolean (default: ``False``); if set to ``True`` it + includes the endpoints in the shortest paths count. Not available when + ``algorithm="Sage"``. - - ``exact`` (boolean, default: ``False``) -- whether to compute over + - ``exact`` -- boolean (default: ``False``); whether to compute over rationals or on ``double`` C variables. Not available when ``algorithm="NetworkX"``. - - ``algorithm`` (default: ``None``) -- can be either ``"Sage"`` (see - :mod:`~sage.graphs.centrality`), ``"NetworkX"`` or ``"None"``. In the - latter case, Sage's algorithm will be used whenever possible. + - ``algorithm`` -- string (default: ``None``); can be either ``"Sage"`` + (see :mod:`~sage.graphs.centrality`), ``"NetworkX"`` or ``"None"``. In + the latter case, Sage's algorithm will be used whenever possible. .. SEEALSO:: @@ -14826,7 +14974,7 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, if algorithm == "Sage": from .centrality import centrality_betweenness - return centrality_betweenness(self, normalize = normalized,exact=exact) + return centrality_betweenness(self, normalize=normalized, exact=exact) elif algorithm == "NetworkX": import networkx return networkx.betweenness_centrality(self.networkx_graph(copy=False), @@ -14842,41 +14990,40 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" - Returns the closeness centrality of all vertices in variable ``vert``. + Return the closeness centrality of all vertices in ``vert``. In a (strongly) connected graph, the closeness centrality of a vertex - `v` is equal - to the inverse of the average distance between `v` and other vertices. - If the graph is disconnected, the closeness centrality of `v` is - multiplied by the fraction of reachable vertices in the graph: - this way, central vertices should also reach several other vertices - in the graph [OLJ14]_. In formulas, + `v` is equal to the inverse of the average distance between `v` and + other vertices. If the graph is disconnected, the closeness centrality + of `v` is multiplied by the fraction of reachable vertices in the graph: + this way, central vertices should also reach several other vertices in + the graph [OLJ14]_. In formulas, .. MATH:: c(v)=\frac{r(v)-1}{\sum_{w \in R(v)} d(v,w)}\frac{r(v)-1}{n-1} - where `R(v)` is the set of vertices reachable from `v`, and - `r(v)` is the cardinality of `R(v)`. + where `R(v)` is the set of vertices reachable from `v`, and `r(v)` is + the cardinality of `R(v)`. - 'Closeness - centrality may be defined as the total graph-theoretic distance of - a given vertex from all other vertices... Closeness is an inverse - measure of centrality in that a larger value indicates a less - central actor while a smaller value indicates a more central - actor,' [Borgatti95]_. + 'Closeness centrality may be defined as the total graph-theoretic + distance of a given vertex from all other vertices... Closeness is an + inverse measure of centrality in that a larger value indicates a less + central actor while a smaller value indicates a more central actor,' + [Borgatti95]_. For more information, see the :wikipedia:`Centrality`. INPUT: - - ``vert`` - the vertex or the list of vertices we want to analyze. If + - ``vert`` -- the vertex or the list of vertices we want to analyze. If ``None`` (default), all vertices are considered. - - ``by_weight`` (boolean) - if ``True``, the edges in the graph are - weighted; if ``False``, all edges have weight 1. + - ``by_weight`` -- boolean (default: ``False``); if ``True``, the edges + in the graph are weighted, and otherwise all edges have weight 1 - - ``algorithm`` (string) - one of the following algorithms: + - ``algorithm`` -- string (default: ``None``); one of the following + algorithms: - ``'BFS'``: performs a BFS from each vertex that has to be analyzed. Does not work with edge weights. @@ -14887,30 +15034,30 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, - ``'Dijkstra_Boost'``: the Dijkstra algorithm, implemented in Boost (works only with positive weights). - - ``'Floyd-Warshall-Cython'`` - the Cython implementation of - the Floyd-Warshall algorithm. Works only if ``by_weight==False`` and - all centralities are needed. + - ``'Floyd-Warshall-Cython'``: the Cython implementation of the + Floyd-Warshall algorithm. Works only if ``by_weight==False`` and all + centralities are needed. - - ``'Floyd-Warshall-Python'`` - the Python implementation of - the Floyd-Warshall algorithm. Works only if all centralities are - needed, but it can deal with weighted graphs, even - with negative weights (but no negative cycle is allowed). + - ``'Floyd-Warshall-Python'``: the Python implementation of the + Floyd-Warshall algorithm. Works only if all centralities are needed, + but it can deal with weighted graphs, even with negative weights + (but no negative cycle is allowed). - - ``'Johnson_Boost'``: the Johnson algorithm, implemented in - Boost (works also with negative weights, if there is no negative - cycle). + - ``'Johnson_Boost'``: the Johnson algorithm, implemented in Boost + (works also with negative weights, if there is no negative cycle). - ``None`` (default): Sage chooses the best algorithm: ``'BFS'`` if ``by_weight`` is ``False``, ``'Dijkstra_Boost'`` if all weights are positive, ``'Johnson_Boost'`` otherwise. - - ``weight_function`` (function) - a function that takes as input an - edge ``(u, v, l)`` and outputs its weight. If not ``None``, - ``by_weight`` is automatically set to ``True``. If ``None`` and - ``by_weight`` is ``True``, we use the edge label ``l`` as a weight. + - ``weight_function`` -- function (default: ``None``); a function that + takes as input an edge ``(u, v, l)`` and outputs its weight. If not + ``None``, ``by_weight`` is automatically set to ``True``. If ``None`` + and ``by_weight`` is ``True``, we use the edge label ``l`` as a + weight. - - ``check_weight`` (boolean) - if ``True``, we check that the - weight_function outputs a number for each edge. + - ``check_weight`` -- boolean (default: ``True``); if ``True``, we check + that the ``weight_function`` outputs a number for each edge. OUTPUT: @@ -15002,8 +15149,8 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, ....: c6 = g.centrality_closeness(algorithm='Johnson_Boost') ....: assert(len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6)) ....: c = [c1,c2,c3,c4,c5,c6] - ....: for (ci,cj) in itertools.combinations(c, 2): - ....: assert(sum([abs(ci[v] - cj[v]) for v in g.vertices() if g.degree(v) != 0]) < 1e-12) + ....: for ci, cj in itertools.combinations(c, 2): + ....: assert(sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12) Directed graphs:: @@ -15021,8 +15168,8 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, ....: c6 = g.centrality_closeness(algorithm='Johnson_Boost') ....: assert(len(c1)==len(c2)==len(c3)==len(c4)==len(c5)==len(c6)) ....: c = [c1,c2,c3,c4,c5,c6] - ....: for (ci,cj) in itertools.combinations(c, 2): - ....: assert(sum([abs(ci[v] - cj[v]) for v in g.vertices() if g.out_degree(v) != 0]) < 1e-12) + ....: for ci, cj in itertools.combinations(c, 2): + ....: assert(sum(abs(ci[v] - cj[v]) for v in g if g.out_degree(v)) < 1e-12) Weighted graphs:: @@ -15040,16 +15187,16 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, ....: c4 = g.centrality_closeness(by_weight=True, algorithm='Johnson_Boost') ....: assert(len(c1)==len(c2)==len(c3)==len(c4)) ....: c = [c1,c2,c3,c4] - ....: for (ci,cj) in itertools.combinations(c, 2): - ....: assert(sum([abs(ci[v] - cj[v]) for v in g.vertices() if g.degree(v) != 0]) < 1e-12) + ....: for ci, cj in itertools.combinations(c, 2): + ....: assert(sum(abs(ci[v] - cj[v]) for v in g if g.degree(v)) < 1e-12) """ if weight_function is not None: by_weight=True elif by_weight: - weight_function = lambda e:e[2] + weight_function = lambda e: e[2] onlyone = False - if vert in self.vertices(): + if vert in self: v_iter = iter([vert]) onlyone = True elif vert is None: @@ -15059,18 +15206,18 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, if algorithm is None: if not by_weight: - algorithm='BFS' + algorithm = 'BFS' else: for e in self.edge_iterator(): try: if float(weight_function(e)) < 0: - algorithm='Johnson_Boost' + algorithm = 'Johnson_Boost' break except (ValueError, TypeError): - raise ValueError("The weight function cannot find the" + - " weight of " + str(e) + ".") + raise ValueError("the weight function cannot find the" + + " weight of " + str(e)) if algorithm is None: - algorithm='Dijkstra_Boost' + algorithm = 'Dijkstra_Boost' if algorithm == 'NetworkX': if by_weight and check_weight: @@ -15078,26 +15225,26 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, import networkx if by_weight: if self.is_directed(): - G = networkx.DiGraph([(e[0], e[1], dict(weight=weight_function(e))) for e in self.edge_iterator()]) + G = networkx.DiGraph([(e[0], e[1], {'weight': weight_function(e)}) for e in self.edge_iterator()]) else: - G = networkx.Graph([(e[0], e[1], dict(weight=weight_function(e))) for e in self.edge_iterator()]) + G = networkx.Graph([(e[0], e[1], {'weight': weight_function(e)}) for e in self.edge_iterator()]) else: G = self.networkx_graph(copy=False) - G.add_nodes_from(self.vertices()) + G.add_nodes_from(self) degree = self.out_degree if self.is_directed() else self.degree if vert is None: - closeness = networkx.closeness_centrality(G, vert, reverse=True, distance = 'weight' if by_weight else None) - return {v:c for v,c in iteritems(closeness) if degree(v) != 0} + closeness = networkx.closeness_centrality(G, vert, reverse=True, distance='weight' if by_weight else None) + return {v: c for v, c in iteritems(closeness) if degree(v)} closeness = {} for x in v_iter: - if degree(x) != 0: + if degree(x): closeness[x] = networkx.closeness_centrality(G, x, reverse=True, distance='weight' if by_weight else None) if onlyone: return closeness.get(vert, None) else: return closeness - elif algorithm=="Johnson_Boost": + elif algorithm == "Johnson_Boost": from sage.graphs.base.boost_graph import johnson_closeness_centrality self.weighted(by_weight) closeness = johnson_closeness_centrality(self, weight_function) @@ -16769,28 +16916,27 @@ def breadth_first_search(self, start, ignore_direction=False, INPUT: - - ``start`` -- vertex or list of vertices from which to start - the traversal. + - ``start`` -- vertex or list of vertices from which to start the + traversal - - ``ignore_direction`` -- (default ``False``) only applies to + - ``ignore_direction`` -- boolean (default ``False``); only applies to directed graphs. If ``True``, searches across edges in either direction. - - ``distance`` -- the maximum distance from the ``start`` nodes - to traverse. The ``start`` nodes are distance zero from - themselves. + - ``distance`` -- integer (default: ``None``); the maximum distance from + the ``start`` nodes to traverse. The ``start`` nodes are at distance + zero from themselves. - - ``neighbors`` -- a function giving the neighbors of a vertex. - The function should take a vertex and return a list of - vertices. For a graph, ``neighbors`` is by default the - :meth:`.neighbors` function of the graph. For a digraph, - the ``neighbors`` function defaults to the + - ``neighbors`` -- function (default: ``None``); a function that inputs + a vertex and return a list of vertices. For an undirected graph, + ``neighbors`` is by default the :meth:`.neighbors` function. For a + digraph, the ``neighbors`` function defaults to the :meth:`~DiGraph.neighbor_out_iterator` function of the graph. - - ``report_distance`` -- (default ``False``) If ``True``, - reports pairs (vertex, distance) where distance is the - distance from the ``start`` nodes. If ``False`` only the - vertices are reported. + - ``report_distance`` -- boolean (default ``False``); if ``True``, + reports pairs ``(vertex, distance)`` where ``distance`` is the + distance from the ``start`` nodes. If ``False`` only the vertices are + reported. .. SEEALSO:: @@ -16804,57 +16950,57 @@ def breadth_first_search(self, start, ignore_direction=False, EXAMPLES:: - sage: G = Graph( { 0: [1], 1: [2], 2: [3], 3: [4], 4: [0]} ) + sage: G = Graph({0: [1], 1: [2], 2: [3], 3: [4], 4: [0]}) sage: list(G.breadth_first_search(0)) [0, 1, 4, 2, 3] By default, the edge direction of a digraph is respected, but this can be overridden by the ``ignore_direction`` parameter:: - sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) + sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) sage: list(D.breadth_first_search(0)) [0, 1, 2, 3, 4, 5, 6, 7] sage: list(D.breadth_first_search(0, ignore_direction=True)) [0, 1, 2, 3, 7, 4, 5, 6] - You can specify a maximum distance in which to search. A - distance of zero returns the ``start`` vertices:: + You can specify a maximum distance in which to search. A distance of + zero returns the ``start`` vertices:: - sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) - sage: list(D.breadth_first_search(0,distance=0)) + sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) + sage: list(D.breadth_first_search(0, distance=0)) [0] - sage: list(D.breadth_first_search(0,distance=1)) + sage: list(D.breadth_first_search(0, distance=1)) [0, 1, 2, 3] Multiple starting vertices can be specified in a list:: - sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) + sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) sage: list(D.breadth_first_search([0])) [0, 1, 2, 3, 4, 5, 6, 7] - sage: list(D.breadth_first_search([0,6])) + sage: list(D.breadth_first_search([0, 6])) [0, 6, 1, 2, 3, 7, 4, 5] - sage: list(D.breadth_first_search([0,6],distance=0)) + sage: list(D.breadth_first_search([0, 6], distance=0)) [0, 6] - sage: list(D.breadth_first_search([0,6],distance=1)) + sage: list(D.breadth_first_search([0, 6], distance=1)) [0, 6, 1, 2, 3, 7] - sage: list(D.breadth_first_search(6,ignore_direction=True,distance=2)) + sage: list(D.breadth_first_search(6, ignore_direction=True, distance=2)) [6, 3, 7, 0, 5] - More generally, you can specify a ``neighbors`` function. For - example, you can traverse the graph backwards by setting - ``neighbors`` to be the :meth:`.neighbors_in` function of the graph:: + More generally, you can specify a ``neighbors`` function. For example, + you can traverse the graph backwards by setting ``neighbors`` to be the + :meth:`.neighbors_in` function of the graph:: - sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) - sage: list(D.breadth_first_search(5,neighbors=D.neighbors_in, distance=2)) + sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) + sage: list(D.breadth_first_search(5, neighbors=D.neighbors_in, distance=2)) [5, 1, 2, 0] - sage: list(D.breadth_first_search(5,neighbors=D.neighbors_out, distance=2)) + sage: list(D.breadth_first_search(5, neighbors=D.neighbors_out, distance=2)) [5, 7, 0] - sage: list(D.breadth_first_search(5,neighbors=D.neighbors, distance=2)) + sage: list(D.breadth_first_search(5 ,neighbors=D.neighbors, distance=2)) [5, 1, 2, 7, 0, 4, 6] - It is possible (:trac:`16470`) using the keyword - ``report_distance`` to get pairs (vertex, distance) encoding - the distance to the starting vertices:: + It is possible (:trac:`16470`) using the keyword ``report_distance`` to + get pairs ``(vertex, distance)`` encoding the distance from the starting + vertices:: sage: G = graphs.PetersenGraph() sage: list(G.breadth_first_search(0, report_distance=True)) @@ -16863,18 +17009,18 @@ def breadth_first_search(self, start, ignore_direction=False, sage: list(G.breadth_first_search(0, report_distance=False)) [0, 1, 4, 5, 2, 6, 3, 9, 7, 8] - sage: D = DiGraph({0:[1, 3], 1:[0, 2], 2:[0, 3], 3:[4]}) + sage: D = DiGraph({0: [1, 3], 1: [0, 2], 2: [0, 3], 3: [4]}) sage: D.show() sage: list(D.breadth_first_search(4, neighbors=D.neighbor_in_iterator, report_distance=True)) [(4, 0), (3, 1), (0, 2), (2, 2), (1, 3)] sage: C = graphs.CycleGraph(4) - sage: list(C.breadth_first_search([0,1], report_distance=True)) + sage: list(C.breadth_first_search([0, 1], report_distance=True)) [(0, 0), (1, 0), (3, 1), (2, 1)] TESTS:: - sage: D = DiGraph({1:[0], 2:[0]}) + sage: D = DiGraph({1: [0], 2: [0]}) sage: list(D.breadth_first_search(0)) [0] sage: list(D.breadth_first_search(0, ignore_direction=True)) @@ -16885,7 +17031,8 @@ def breadth_first_search(self, start, ignore_direction=False, raise ValueError("distance must be a non-negative integer, not {0}".format(distance)) # Preferably use the Cython implementation - if neighbors is None and not isinstance(start, list) and distance is None and hasattr(self._backend,"breadth_first_search") and not report_distance: + if (neighbors is None and not isinstance(start, list) and distance is None + and hasattr(self._backend, "breadth_first_search") and not report_distance): for v in self._backend.breadth_first_search(start, ignore_direction=ignore_direction): yield v else: @@ -16894,14 +17041,14 @@ def breadth_first_search(self, start, ignore_direction=False, neighbors = self.neighbor_iterator else: neighbors = self.neighbor_out_iterator - seen = set([]) + seen = set() if isinstance(start, list): queue = [(v, 0) for v in start] else: queue = [(start, 0)] # Non-existing start vertex is detected later if distance > 0. - if distance == 0: + if not distance: for v in queue: if not v[0] in self: raise LookupError("start vertex ({0}) is not a vertex of the graph".format(v[0])) @@ -16932,20 +17079,19 @@ def depth_first_search(self, start, ignore_direction=False, INPUT: - - ``start`` - vertex or list of vertices from which to start - the traversal + - ``start`` -- vertex or list of vertices from which to start the + traversal - - ``ignore_direction`` - (default False) only applies to - directed graphs. If True, searches across edges in either + - ``ignore_direction`` -- boolean (default ``False``); only applies to + directed graphs. If ``True``, searches across edges in either direction. - - ``distance`` - Deprecated. Broken, do not use. + - ``distance`` -- Deprecated. Broken, do not use. - - ``neighbors`` - a function giving the neighbors of a vertex. - The function should take a vertex and return a list of - vertices. For a graph, ``neighbors`` is by default the - :meth:`.neighbors` function of the graph. For a digraph, - the ``neighbors`` function defaults to the + - ``neighbors`` -- function (default: ``None``); a function that inputs + a vertex and return a list of vertices. For an undirected graph, + ``neighbors`` is by default the :meth:`.neighbors` function. For a + digraph, the ``neighbors`` function defaults to the :meth:`~DiGraph.neighbor_out_iterator` function of the graph. .. SEEALSO:: @@ -16960,15 +17106,15 @@ def depth_first_search(self, start, ignore_direction=False, EXAMPLES:: - sage: G = Graph( { 0: [1], 1: [2], 2: [3], 3: [4], 4: [0]} ) + sage: G = Graph({0: [1], 1: [2], 2: [3], 3: [4], 4: [0]}) sage: list(G.depth_first_search(0)) [0, 4, 3, 2, 1] - By default, the edge direction of a digraph is respected, but this - can be overridden by the ``ignore_direction`` parameter:: + By default, the edge direction of a digraph is respected, but this can + be overridden by the ``ignore_direction`` parameter:: - sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) + sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) sage: list(D.depth_first_search(0)) [0, 3, 6, 7, 2, 5, 1, 4] sage: list(D.depth_first_search(0, ignore_direction=True)) @@ -16976,19 +17122,19 @@ def depth_first_search(self, start, ignore_direction=False, Multiple starting vertices can be specified in a list:: - sage: D = DiGraph( { 0: [1,2,3], 1: [4,5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) + sage: D = DiGraph({0: [1, 2, 3], 1: [4, 5], 2: [5], 3: [6], 5: [7], 6: [7], 7: [0]}) sage: list(D.depth_first_search([0])) [0, 3, 6, 7, 2, 5, 1, 4] - sage: list(D.depth_first_search([0,6])) + sage: list(D.depth_first_search([0, 6])) [0, 3, 6, 7, 2, 5, 1, 4] - More generally, you can specify a ``neighbors`` function. For - example, you can traverse the graph backwards by setting - ``neighbors`` to be the :meth:`.neighbors_in` function of the graph:: + More generally, you can specify a ``neighbors`` function. For example, + you can traverse the graph backwards by setting ``neighbors`` to be the + :meth:`.neighbors_in` function of the graph:: sage: D = digraphs.Path(10) - sage: D.add_path([22,23,24,5]) - sage: D.add_path([5,33,34,35]) + sage: D.add_path([22, 23, 24, 5]) + sage: D.add_path([5, 33, 34, 35]) sage: list(D.depth_first_search(5, neighbors=D.neighbors_in)) [5, 4, 3, 2, 1, 0, 24, 23, 22] sage: list(D.breadth_first_search(5, neighbors=D.neighbors_in)) @@ -17000,7 +17146,7 @@ def depth_first_search(self, start, ignore_direction=False, TESTS:: - sage: D = DiGraph({1:[0], 2:[0]}) + sage: D = DiGraph({1: [0], 2: [0]}) sage: list(D.depth_first_search(0)) [0] sage: list(D.depth_first_search(0, ignore_direction=True)) @@ -17012,16 +17158,17 @@ def depth_first_search(self, start, ignore_direction=False, deprecation(19227, "Parameter 'distance' is broken. Do not use.") # Preferably use the Cython implementation - if neighbors is None and not isinstance(start,list) and distance is None and hasattr(self._backend,"depth_first_search"): - for v in self._backend.depth_first_search(start, ignore_direction = ignore_direction): + if (neighbors is None and not isinstance(start, list) and distance is None + and hasattr(self._backend, "depth_first_search")): + for v in self._backend.depth_first_search(start, ignore_direction=ignore_direction): yield v else: if neighbors is None: if not self._directed or ignore_direction: - neighbors=self.neighbor_iterator + neighbors = self.neighbor_iterator else: - neighbors=self.neighbor_out_iterator - seen = set([]) + neighbors = self.neighbor_out_iterator + seen = set() if isinstance(start, list): # Reverse the list so that the initial vertices come out in the same order queue = [(v, 0) for v in reversed(start)] @@ -17033,10 +17180,10 @@ def depth_first_search(self, start, ignore_direction=False, if v not in seen: yield v seen.add(v) - if distance is None or d + TESTS: @@ -19924,7 +20091,7 @@ def _keys_for_vertices(self): sage: g.add_vertex("a") sage: s = g.graphviz_string() """ - label = {v: 'node_{0}'.format(i) for i, v in enumerate(self.vertices())} + label = {v: 'node_{0}'.format(i) for i, v in enumerate(self)} def get_label(vertex): return label[vertex] return get_label @@ -20249,17 +20416,37 @@ def graphviz_string(self, **options): The following digraph has tuples as vertices:: - sage: print(digraphs.ButterflyGraph(1).graphviz_string()) + sage: print(DiGraph(graphs.Grid2dGraph(2,2)).graphviz_string()) # py2 digraph { - node_3 [label="('1', 1)"]; - node_0 [label="('0', 0)"]; - node_2 [label="('1', 0)"]; - node_1 [label="('0', 1)"]; + node_0 [label="(0, 1)"]; + node_1 [label="(1, 0)"]; + node_2 [label="(0, 0)"]; + node_3 [label="(1, 1)"]; + node_0 -> node_2; node_0 -> node_3; + node_1 -> node_2; + node_1 -> node_3; + node_2 -> node_0; + node_2 -> node_1; + node_3 -> node_0; + node_3 -> node_1; + } + sage: print(DiGraph(graphs.Grid2dGraph(2,2)).graphviz_string()) # py3 + digraph { + node_0 [label="(0, 0)"]; + node_1 [label="(0, 1)"]; + node_2 [label="(1, 0)"]; + node_3 [label="(1, 1)"]; + node_0 -> node_1; + node_0 -> node_2; + node_1 -> node_0; + node_1 -> node_3; + node_2 -> node_0; node_2 -> node_3; - node_2 -> node_1; + node_3 -> node_1; + node_3 -> node_2; } The following digraph has vertices with newlines in their string @@ -20832,13 +21019,13 @@ def eigenspaces(self, laplacian=False): ### Automorphism and isomorphism - def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, complete_partial_function = True, immutable = None): + def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, complete_partial_function=True, immutable=None): r""" Relabels the vertices of ``self`` INPUT: - - ``perm`` -- a function, dictionary, list, permutation, or + - ``perm`` -- a function, dictionary, iterable, permutation, or ``None`` (default: ``None``) - ``inplace`` -- a boolean (default: ``True``) @@ -20861,9 +21048,11 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, relabeled to ``f(v)``. If ``perm`` is a dictionary ``d``, then each vertex ``v`` (which should - be a key of ``d``) is relabeled to ``d[v]``. Similarly, if ``perm`` is - a list or tuple ``l`` of length ``n``, then the first vertex returned by - ``G.vertices()`` is relabeled to ``l[0]``, the second to ``l[1]``, ... + be a key of ``d``) is relabeled to ``d[v]``. + + If ``perm`` is a list (or more generally, any iterable) of + length ``n``, then the first vertex returned by ``G.vertices()`` + is relabeled to ``l[0]``, the second to ``l[1]``, ... If ``perm`` is a permutation, then each vertex ``v`` is relabeled to ``perm(v)``. Caveat: this assumes that the @@ -20873,7 +21062,8 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, If ``perm`` is ``None``, the graph is relabeled to be on the vertices `\{0,1,...,n-1\}`. This is *not* any kind of canonical - labeling, but neither a random relabeling. + labeling, but it is consistent (relabeling twice will give the + same result). If ``inplace`` is ``True``, the graph is modified in place and ``None`` is returned. Otherwise a relabeled copy of the graph @@ -20915,9 +21105,9 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, [0 0 1] [1 1 0] - Relabeling using a tuple:: + Relabeling using an iterable:: - sage: G.relabel((0,2,1), inplace=False).am() + sage: G.relabel(iter((0,2,1)), inplace=False).am() [0 0 1] [0 0 1] [1 1 0] @@ -20968,7 +21158,21 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, sage: G.edges() [] - Relabeling to simpler labels:: + Recovering the relabeling with ``return_map``:: + + sage: G = graphs.CubeGraph(3) + sage: G.relabel(range(8), return_map=True) + {'000': 0, + '001': 1, + '010': 2, + '011': 3, + '100': 4, + '101': 5, + '110': 6, + '111': 7} + + When no permutation is given, the relabeling is done to integers + from 0 to N-1 but in an arbitrary order:: sage: G = graphs.CubeGraph(3) sage: G.vertices() @@ -20977,11 +21181,11 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, sage: G.vertices() [0, 1, 2, 3, 4, 5, 6, 7] - Recovering the relabeling with ``return_map``:: + In the above case, the mapping is arbitrary but consistent:: - sage: G = graphs.CubeGraph(3) - sage: expecting = {'000': 0, '001': 1, '010': 2, '011': 3, '100': 4, '101': 5, '110': 6, '111': 7} - sage: G.relabel(return_map=True) == expecting + sage: map1 = G.relabel(inplace=False, return_map=True) + sage: map2 = G.relabel(inplace=False, return_map=True) + sage: map1 == map2 True :: @@ -21015,8 +21219,8 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, sage: g = Graph({1:[2,3]}) sage: rel = {1:'a', 2:'b'} sage: g.relabel(rel) - sage: g.vertices() - [3, 'a', 'b'] + sage: set(g) == {3, 'a', 'b'} + True sage: rel {1: 'a', 2: 'b'} @@ -21061,37 +21265,39 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, # If perm is not a dictionary, we build one ! if perm is None: - - # vertices() returns a sorted list: - # this guarantees consistent relabeling - perm = {v: i for i, v in enumerate(self.vertices())} + # enumerate(self) guarantees a consistent but otherwise + # arbitrary relabeling + perm = {v: i for i, v in enumerate(self)} complete_partial_function = False check_input = False elif isinstance(perm, dict): - # If all vertices do not have a new label, the code will touch the # dictionary. Let us keep the one we received from the user clean ! - perm = copy(perm) - - elif isinstance(perm, (list, tuple)): - perm = dict(zip(self.vertices(),perm)) + perm = dict(perm) elif isinstance(perm, PermutationGroupElement): n = self.order() ddict = {} - for i in range(1,n): - ddict[i] = perm(i)%n + for i in range(1, n): + ddict[i] = perm(i) % n if n > 0: - ddict[0] = perm(n)%n + ddict[0] = perm(n) % n perm = ddict - elif callable(perm): - perm = dict( [ i, perm(i) ] for i in self.vertices() ) - complete_partial_function = False - else: - raise TypeError("Type of perm is not supported for relabeling.") + # Check for generic iterable/callable + try: + it = iter(perm) + except TypeError: + if not callable(perm): + raise + # callable + perm = {v: perm(v) for v in self} + complete_partial_function = False + else: + # iterable + perm = dict(zip(self.vertices(), it)) # Whether to complete the relabeling function if some vertices do not # appear in the permutation. @@ -21105,12 +21311,9 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True, if len(set(perm.values())) < len(perm): raise NotImplementedError("Non injective relabeling") - for v in perm: - if v in self: - try: - hash(perm[v]) - except TypeError: - raise ValueError("perm dictionary must be of the format {a:a1, b:b1, ...} where a,b,... are vertices and a1,b1,... are hashable") + # Check hashability of values + for t in perm.values(): + hash(t) self._backend.relabel(perm, self._directed) @@ -21215,7 +21418,6 @@ def is_equitable(self, partition, quotient_matrix=False): False """ from sage.misc.flatten import flatten - from sage.misc.misc import uniq if sorted(flatten(partition, max_level=1)) != self.vertices(): raise TypeError("Partition (%s) is not valid for this graph: vertices are incorrect."%partition) if any(len(cell)==0 for cell in partition): @@ -21230,7 +21432,7 @@ def is_equitable(self, partition, quotient_matrix=False): cell_i = partition[i] cell_j = partition[j] degrees = [self.degree_to_cell(u, cell_j) for u in cell_i] - if len(uniq(degrees)) > 1: + if len(set(degrees)) > 1: return False if self._directed: M[i, j] = degrees[0][0] @@ -21241,30 +21443,28 @@ def is_equitable(self, partition, quotient_matrix=False): for cell1 in partition: for cell2 in partition: degrees = [self.degree_to_cell(u, cell2) for u in cell1] - if len(uniq(degrees)) > 1: + if len(set(degrees)) > 1: return False return True def coarsest_equitable_refinement(self, partition, sparse=True): - """ - Returns the coarsest partition which is finer than the input + r""" + Return the coarsest partition which is finer than the input partition, and equitable with respect to self. - A partition is equitable with respect to a graph if for every pair - of cells C1, C2 of the partition, the number of edges from a vertex - of C1 to C2 is the same, over all vertices in C1. + A partition is equitable with respect to a graph if for every pair of + cells `C_1`, `C_2` of the partition, the number of edges from a vertex + of `C_1` to `C_2` is the same, over all vertices in `C_1`. - A partition P1 is finer than P2 (P2 is coarser than P1) if every - cell of P1 is a subset of a cell of P2. + A partition `P_1` is finer than `P_2` (`P_2` is coarser than `P_1`) if + every cell of `P_1` is a subset of a cell of `P_2`. INPUT: + - ``partition`` -- a list of lists - - ``partition`` - a list of lists - - - ``sparse`` - (default False) whether to use sparse - or dense representation- for small graphs, use dense for speed - + - ``sparse`` -- boolean (default: ``False``); whether to use sparse or + dense representation - for small graphs, use dense for speed EXAMPLES:: @@ -21276,7 +21476,7 @@ def coarsest_equitable_refinement(self, partition, sparse=True): sage: Pi = [verts[:1], verts[1:]] sage: Pi [['000'], ['001', '010', '011', '100', '101', '110', '111']] - sage: G.coarsest_equitable_refinement(Pi) + sage: [sorted(cell) for cell in G.coarsest_equitable_refinement(Pi)] [['000'], ['011', '101', '110'], ['111'], ['001', '010', '100']] Note that given an equitable partition, this function returns that @@ -21294,41 +21494,43 @@ def coarsest_equitable_refinement(self, partition, sparse=True): sage: ss.coarsest_equitable_refinement(prt) Traceback (most recent call last): ... - TypeError: Partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], [(2, 3), (3, 4)]]) is not valid for this graph: vertices are incorrect. + TypeError: partition ([[(0, 1)], [(0, 2), (0, 3), (0, 4), (1, 2), (1, 4)], [(2, 3), (3, 4)]]) is not valid for this graph: vertices are incorrect :: sage: ss = (graphs.WheelGraph(5)).line_graph(labels=False) sage: ss.coarsest_equitable_refinement(prt) - [[(0, 1)], [(1, 2), (1, 4)], [(0, 3)], [(0, 2), (0, 4)], [(2, 3), (3, 4)]] + [[(0, 1)], [(1, 2), (1, 4)], [(0, 3)], [(0, 4), (0, 2)], [(2, 3), (3, 4)]] ALGORITHM: Brendan D. McKay's Master's Thesis, University of Melbourne, 1976. """ from sage.misc.flatten import flatten - if sorted(flatten(partition, max_level=1)) != self.vertices(): - raise TypeError("Partition (%s) is not valid for this graph: vertices are incorrect."%partition) - if any(len(cell)==0 for cell in partition): - raise TypeError("Partition (%s) is not valid for this graph: there is a cell of length 0."%partition) + if set(flatten(partition, max_level=1)) != set(self): + raise TypeError("partition (%s) is not valid for this graph: vertices are incorrect"%partition) + if any(len(cell) == 0 for cell in partition): + raise TypeError("partition (%s) is not valid for this graph: there is a cell of length 0"%partition) if self.has_multiple_edges(): - raise TypeError("Refinement function does not support multiple edges.") + raise TypeError("refinement function does not support multiple edges") G = copy(self) - perm_to = G.relabel(return_map=True) + perm_from = list(G) + perm_to = {v: i for i, v in enumerate(perm_from)} + G.relabel(perm=perm_to) partition = [[perm_to[b] for b in cell] for cell in partition] - perm_from = {} - for v in self: - perm_from[perm_to[v]] = v - n = G.num_verts() + n = G.order() if sparse: from sage.graphs.base.sparse_graph import SparseGraph CG = SparseGraph(n) else: from sage.graphs.base.dense_graph import DenseGraph CG = DenseGraph(n) - for i in range(n): - for j in range(n): - if G.has_edge(i,j): - CG.add_arc(i,j) + if G.is_directed(): + for i, j in G.edge_iterator(labels=False): + CG.add_arc(i, j) + else: + for i, j in G.edge_iterator(labels=False): + CG.add_arc(i, j) + CG.add_arc(j, i) from sage.groups.perm_gps.partn_ref.refinement_graphs import coarsest_equitable_refinement result = coarsest_equitable_refinement(CG, partition, G._directed) @@ -21467,8 +21669,10 @@ def automorphism_group(self, partition=None, verbosity=0, sage: G = graphs.PetersenGraph() sage: G.automorphism_group(return_group=False, orbits=True,algorithm='sage') [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]] - sage: G.automorphism_group(partition=[[0],list(range(1,10))], return_group=False, orbits=True,algorithm='sage') - [[0], [2, 3, 6, 7, 8, 9], [1, 4, 5]] + sage: orb = G.automorphism_group(partition=[[0],list(range(1,10))], + ....: return_group=False, orbits=True,algorithm='sage') + sage: sorted([sorted(o) for o in orb], key=len) + [[0], [1, 4, 5], [2, 3, 6, 7, 8, 9]] sage: C = graphs.CubeGraph(3) sage: orb = C.automorphism_group(orbits=True, return_group=False,algorithm='sage') sage: [sorted(o) for o in orb] @@ -21492,32 +21696,38 @@ def automorphism_group(self, partition=None, verbosity=0, sage: g.automorphism_group(partition=[[0,1,2],[3,4,5]],algorithm='sage') Traceback (most recent call last): ... - KeyError: 6 + KeyError: ... Labeled automorphism group:: - sage: digraphs.DeBruijn(3,2).automorphism_group(algorithm='sage') - Permutation Group with generators [('02','10','21')('00','11','22')('01','12','20'), ('02','01')('10','20')('21','12')('22','11')] sage: d = digraphs.DeBruijn(3,2) + sage: A = d.automorphism_group(algorithm='sage') + sage: A_target = PermutationGroup(["('02','10','21')('00','11','22')('01','12','20')", + ....: "('02','01')('10','20')('21','12')('22','11')"]) + sage: A.is_isomorphic(A_target) + True sage: d.allow_multiple_edges(True) - sage: d.add_edge(d.edges()[0]) - sage: d.automorphism_group(algorithm='sage') - Permutation Group with generators [('02','01')('10','20')('21','12')('22','11')] + sage: d.add_edge(('00', '00', '0')) + sage: A = d.automorphism_group(algorithm='sage') + sage: A_target = PermutationGroup(["('01','02')('10','20')('11','22')('12','21')"]) + sage: A.is_isomorphic(A_target) + True The labeling is correct:: sage: g = graphs.PetersenGraph() sage: ag = g.automorphism_group() - sage: for u,v in g.edges(labels = False): - ....: if len(ag.orbit((u,v),action="OnPairs")) != 30: - ....: print("ARggggggggggggg !!!") + sage: all(len(ag.orbit(e, action="OnPairs")) == 30 + ....: for e in g.edge_iterator(labels=False)) + True Empty group, correct domain:: - sage: Graph({'a':['a'], 'b':[]}).automorphism_group() + sage: ag = Graph({'a':['a'], 'b':[]}).automorphism_group() + sage: ag Permutation Group with generators [()] - sage: Graph({'a':['a'], 'b':[]}).automorphism_group().domain() - {'a', 'b'} + sage: sorted(ag.domain()) + ['a', 'b'] We can check that the subgroups are labelled correctly (:trac:`15656`):: @@ -21525,8 +21735,8 @@ def automorphism_group(self, partition=None, verbosity=0, sage: G1 = Graph(':H`ECw@HGXGAGUG`e') sage: G = G1.automorphism_group() sage: G.subgroups() - [Subgroup of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)]) generated by [()], - Subgroup of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)]) generated by [(0,7)(1,4)(2,3)(6,8)]] + [Subgroup generated by [()] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)]), + Subgroup generated by [(0,7)(1,4)(2,3)(6,8)] of (Permutation Group with generators [(0,7)(1,4)(2,3)(6,8)])] """ from sage.features.bliss import Bliss have_bliss = Bliss().is_present() @@ -21577,9 +21787,7 @@ def automorphism_group(self, partition=None, verbosity=0, if edge_labels or self.has_multiple_edges(): G, partition, relabeling = graph_isom_equivalent_non_edge_labeled_graph(self, partition, return_relabeling=True, ignore_edge_labels=(not edge_labels)) G_vertices = sum(partition, []) - G_to = {} - for i,u in enumerate(G_vertices): - G_to[u] = i + G_to = {u: i for i,u in enumerate(G_vertices)} from sage.graphs.all import Graph, DiGraph DoDG = DiGraph if self._directed else Graph H = DoDG(len(G_vertices), implementation='c_graph', loops=G.allows_loops()) @@ -21593,9 +21801,7 @@ def automorphism_group(self, partition=None, verbosity=0, a,b,c = A else: a,b = A - b_new = {} - for v in G_to: - b_new[v] = b[G_to[v]] + b_new = {v: b[G_to[v]] for v in G_to} b = b_new # b is a translation of the labellings acting_vertices = {} @@ -21611,8 +21817,8 @@ def automorphism_group(self, partition=None, verbosity=0, real_aut_gp = [] n = self.order() for gen in a: - gen_restr = [0]*n - for v in self.vertex_iterator(): + gen_restr = [0] * n + for v in self: gen_restr[acting_vertices[v]] = gen[acting_vertices[v]] if gen_restr not in real_aut_gp: real_aut_gp.append(gen_restr) @@ -21623,9 +21829,7 @@ def automorphism_group(self, partition=None, verbosity=0, b = translation_d else: G_vertices = sum(partition, []) - G_to = {} - for i,u in enumerate(G_vertices): - G_to[u] = i + G_to = {u: i for i,u in enumerate(G_vertices)} from sage.graphs.all import Graph, DiGraph DoDG = DiGraph if self._directed else Graph H = DoDG(len(G_vertices), implementation='c_graph', loops=self.allows_loops()) @@ -21641,9 +21845,7 @@ def automorphism_group(self, partition=None, verbosity=0, a,b,c = A else: a,b = A - b_new = {} - for v in G_to: - b_new[v] = b[G_to[v]] + b_new = {v: b[G_to[v]] for v in G_to} b = b_new else: a = search_tree(GC, partition, dict_rep=False, lab=False, dig=dig, verbosity=verbosity, order=order) @@ -21656,21 +21858,19 @@ def automorphism_group(self, partition=None, verbosity=0, # We translate the integer permutations into a collection of # cycles. from sage.combinat.permutation import Permutation - gens = [Permutation([x+1 for x in aa]).to_cycles() for aa in a] + gens = [Permutation(x+1 for x in aa).to_cycles() for aa in a] # We relabel the cycles using the vertices' names instead of integers n = self.order() - int_to_vertex = {((i+1) if i != n else 1):v for v,i in iteritems(b)} - gens = [ [ tuple([int_to_vertex[i] for i in cycle]) for cycle in gen] for gen in gens] - output.append(PermutationGroup(gens = gens, domain = int_to_vertex.values())) + int_to_vertex = {((i + 1) if i != n else 1): v for v, i in iteritems(b)} + gens = [[tuple(int_to_vertex[i] for i in cycle) for cycle in gen] for gen in gens] + output.append(PermutationGroup(gens=gens, domain=int_to_vertex.values())) else: output.append(PermutationGroup([[]], domain=list(self))) if order: output.append(c) if orbits: - G_from = {} - for v in G_to: - G_from[G_to[v]] = v + G_from = {G_to[v]: v for v in G_to} from sage.groups.perm_gps.partn_ref.refinement_graphs import get_orbits output.append([[G_from[v] for v in W] for W in get_orbits(a, self.num_verts())]) @@ -21900,60 +22100,76 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False TESTS:: - sage: g1 = '~?A[~~{ACbCwV_~__OOcCW_fAA{CF{CCAAAC__bCCCwOOV___~____OOOOcCCCW___fAAAA'+\ - ....: '{CCCF{CCCCAAAAAC____bCCCCCwOOOOV_____~_O@ACG_@ACGOo@ACG?{?`A?GV_GO@AC}@?_OGC'+\ - ....: 'C?_OI@?K?I@?_OM?_OGD?F_A@OGC@{A@?_OG?O@?gCA?@_GCA@O?B_@OGCA?BoA@?gC?@{A?GO`?'+\ - ....: '??_GO@AC??E?O`?CG??[?O`A?G??{?GO`A???|A?_GOC`AC@_OCGACEAGS?HA?_SA`aO@G?cOC_N'+\ - ....: 'G_C@AOP?GnO@_GACOE?g?`OGACCOGaGOc?HA?`GORCG_AO@B?K@[`A?OCI@A@By?_K@?SCABA?H?'+\ - ....: 'SA?a@GC`CH?Q?C_c?cGRC@G_AOCOa@Ax?QC?_GOo_CNg@A?oC@CaCGO@CGA_O`?GSGPAGOC_@OO_'+\ - ....: 'aCHaG?cO@CB?_`Ax?GQC?_cAOCG^OGAC@_D?IGO`?D?O_I?HAOO`AGOHA?cC?oAO`AW_Q?HCACAC'+\ - ....: 'GO`[_OCHA?_cCACG^O_@CAGO`A?GCOGc@?I?OQOC?IGC_o@CAGCCE?A@DBG_OA@C_CP?OG_VA_CO'+\ - ....: 'G@D?_OA_DFgA@CO?aH?Ga@?a?_I?S@A@@Oa@?@P@GCO_AACO_a_?`K_GCQ@?cAOG_OGAwQ@?K?cC'+\ - ....: 'GH?I?ABy@C?G_S@@GCA@C`?OI?_D?OP@G?IGGP@O_AGCP?aG?GCPAX?cA?OGSGCGCAGCJ`?oAGCC'+\ - ....: 'HAA?A_CG^O@CAG_GCSCAGCCGOCG@OA_`?`?g_OACG_`CAGOAO_H?a_?`AXA?OGcAAOP?a@?CGVAC'+\ - ....: 'OG@_AGG`OA_?O`|?Ga?COKAAGCA@O`A?a?S@?HCG`?_?gO`AGGaC?PCAOGI?A@GO`K_CQ@?GO_`O'+\ - ....: 'GCAACGVAG@_COOCQ?g?I?O`ByC?G_P?O`A?H@G?_P?`OAGC?gD?_C@_GCAGDG_OA@CCPC?AOQ??g'+\ - ....: '_R@_AGCO____OCC_@OAbaOC?g@C_H?AOOC@?a`y?PC?G`@OOH??cOG_OOAG@_COAP?WA?_KAGC@C'+\ - ....: '_CQ@?HAACH??c@P?_AWGaC?P?gA_C_GAD?I?Awa?S@?K?`C_GAOGCS?@|?COGaA@CAAOQ?AGCAGO'+\ - ....: 'ACOG@_G_aC@_G@CA@@AHA?OGc?WAAH@G?P?_?cH_`CAGOGACc@@GA?S?CGVCG@OA_CICAOOC?PO?'+\ - ....: 'OG^OG_@CAC_cC?AOP?_OICG@?oAGCO_GO_GB@?_OG`AH?cA?OH?`P??cC_O?SCGR@O_AGCAI?Q?_'+\ - ....: 'GGS?D?O`[OI?_D@@CCA?cCA_?_O`By?_PC?IGAGOQ?@A@?aO`A?Q@?K?__`_E?_GCA@CGO`C_GCQ'+\ - ....: '@A?gAOQ?@C?DCACGR@GCO_AGPA@@GAA?A_CO`Aw_I?S@?SCB@?OC_?_P@ACNgOC@A?aCGOCAGCA@'+\ - ....: 'CA?H@GG_C@AOGa?OOG_O?g_OA?oDC_AO@GOCc?@P?_A@D??cC``O?cGAOGD?@OA_CAGCA?_cwKA?'+\ - ....: '`?OWGG?_PO?I?S?H@?^OGAC@_Aa@CAGC?a@?_Q?@H?_OCHA?OQA_P?_G_O?WA?_IG_Q?HC@A@ADC'+\ - ....: 'A?AI?AC_?QAWOHA?cAGG_I?S?G_OG@GA?`[D?O_IA?`GGCS?OA_?c@?Q?^OAC@_G_Ca@CA@?OGCO'+\ - ....: 'H@G@A@?GQC?_Q@GP?_OG?IGGB?OCGaG?cO@A__QGC?E?A@CH@G?GRAGOC_@GGOW@O?O_OGa?_c?G'+\ - ....: 'V@CGA_OOaC?a_?a?A_CcC@?CNgA?oC@GGE@?_OH?a@?_?QA`A@?QC?_KGGO_OGCAa@?A?_KCGPC@'+\ - ....: 'G_AOAGPGC?D@?a_A?@GGO`KH?Q?C_QGAA_?gOG_OA?_GG`AwH?SA?`?cAI?A@D?I?@?QA?`By?K@'+\ - ....: '?O`GGACA@CGCA@CC_?WO`?`A?OCH?`OCA@COG?I?oC@ACGPCG_AO@_aAA?Aa?g?GD@G?CO`AWOc?'+\ - ....: 'HA?OcG_?g@OGCAAAOC@ACJ_`OGACAGCS?CAGI?A`@?OCACG^' - sage: g2 = '~?A[??osR?WARSETCJ_QWASehOXQg`QwChK?qSeFQ_sTIaWIV?XIR?KAC?B?`?COCG?o?O_'+\ - ....: '@_?`??B?`?o@_O_WCOCHC@_?`W?E?AD_O?WCCeO?WCSEGAGAIaA@_?aw?OK?ER?`?@_HQXA?B@Q_'+\ - ....: 'pA?a@Qg_`?o?h[?GOK@IR?@A?BEQcoCG?K\IB?GOCWiTC?GOKWIV??CGEKdH_H_?CB?`?DC??_WC'+\ - ....: 'G?SO?AP?O_?g_?D_?`?C__?D_?`?CCo??@_O_XDC???WCGEGg_??a?`G_aa??E?AD_@cC??K?CJ?'+\ - ....: '@@K?O?WCCe?aa?G?KAIB?Gg_A?a?ag_@DC?OK?CV??EOO@?o?XK??GH`A?B?Qco?Gg`A?B@Q_o?C'+\ - ....: 'SO`?P?hSO?@DCGOK?IV???K_`A@_HQWC??_cCG?KXIRG?@D?GO?WySEG?@D?GOCWiTCC??a_CGEK'+\ - ....: 'DJ_@??K_@A@bHQWAW?@@K??_WCG?g_?CSO?A@_O_@P??Gg_?Ca?`?@P??Gg_?D_?`?C__?EOO?Ao'+\ - ....: '?O_AAW?@@K???WCGEPP??Gg_??B?`?pDC??aa??AGACaAIG?@DC??K?CJ?BGG?@cC??K?CJ?@@K?'+\ - ....: '?_e?G?KAAR?PP??Gg_A?B?a_oAIG?@DC?OCOCTC?Gg_?CSO@?o?P[??X@??K__A@_?qW??OR??GH'+\ - ....: '`A?B?Qco?Gg_?CSO`?@_hOW?AIG?@DCGOCOITC??PP??Gg`A@_@Qw??@cC??qACGE?dH_O?AAW?@'+\ - ....: '@GGO?WqSeO?AIG?@D?GO?WySEG?@DC??a_CGAKTIaA??PP??Gg@A@b@Qw?O?BGG?@c?GOKXIR?KA'+\ - ....: 'C?H_?CCo?A@_O_?WCG@P??Gg_?CB?`?COCG@P??Gg_?Ca?`?E?AC?g_?CSO?Ao?O_@_?`@GG?@cC'+\ - ....: '??k?CG??WCGOR??GH_??B?`?o@_O`DC??aa???KACB?a?`AIG?@DC??COCHC@_?`AIG?@DC??K?C'+\ - ....: 'J??o?O`cC??qA??E?AD_O?WC?OR??GH_A?B?_cq?B?_AIG?@DC?O?WCSEGAGA?Gg_?CSO@?P?PSO'+\ - ....: 'OK?C?PP??Gg_A@_?aw?OK?C?X@??K__A@_?qWCG?K??GH_?CCo`?@_HQXA?B??AIG?@DCGO?WISE'+\ - ....: 'GOCO??PP??Gg`A?a@Qg_`?o??@DC??aaCGE?DJ_@A@_??BGG?@cCGOK@IR?@A?BO?AAW?@@GGO?W'+\ - ....: 'qSe?`?@g?@DC??a_CG?K\IB?GOCQ??PP??Gg@A?bDQg_@A@_O?AIG?@D?GOKWIV??CGE@??K__?E'+\ - ....: 'O?`?pchK?_SA_OI@OGD?gCA_SA@OI?c@H?Q?c_H?QOC_HGAOCc?QOC_HGAOCc@GAQ?c@H?QD?gCA'+\ - ....: '_SA@OI@?gD?_SA_OKA_SA@OI@?gD?_SA_OI@OHI?c_H?QOC_HGAOCc@GAQ?eC_H?QOC_HGAOCc@G'+\ - ....: 'AQ?c@XD?_SA_OI@OGD?gCA_SA@PKGO`A@ACGSGO`?`ACICGO_?ACGOcGO`?O`AC`ACHACGO???^?'+\ - ....: '????}Bw????Fo^???????Fo?}?????Bw?^?Bw?????GO`AO`AC`ACGACGOcGO`??aCGO_O`ADACG'+\ - ....: 'OGO`A@ACGOA???@{?N_@{?????Fo?}????OFo????N_}????@{????Bw?OACGOgO`A@ACGSGO`?`'+\ - ....: 'ACG?OaCGO_GO`AO`AC`ACGACGO_@G???Fo^?????}Bw????Fo??AC@{?????Fo?}?Fo?????^??A'+\ - ....: 'OGO`AO`AC@ACGQCGO_GO`A?HAACGOgO`A@ACGOGO`A`ACG?GQ??^?Bw?????N_@{?????Fo?QC??'+\ - ....: 'Fo^?????}????@{Fo???CHACGO_O`ACACGOgO`A@ACGO@AOcGO`?O`AC`ACGACGOcGO`?@GQFo??'+\ - ....: '??N_????^@{????Bw??`GRw?????N_@{?????Fo?}???HAO_OI@OGD?gCA_SA@OI@?gDK_??C@GA'+\ - ....: 'Q?c@H?Q?c_H?QOC_HEW????????????????????????~~~~~' + sage: g1 = '~?A[~~{ACbCwV_~__OOcCW_fAA{CF{CCAAAC__bCCCwOOV___~___'+\ + ....: '_OOOOcCCCW___fAAAA{CCCF{CCCCAAAAAC____bCCCCCwOOOOV_____~_O'+\ + ....: '@ACG_@ACGOo@ACG?{?`A?GV_GO@AC}@?_OGCC?_OI@?K?I@?_OM?_OGD?F'+\ + ....: '_A@OGC@{A@?_OG?O@?gCA?@_GCA@O?B_@OGCA?BoA@?gC?@{A?GO`???_G'+\ + ....: 'O@AC??E?O`?CG??[?O`A?G??{?GO`A???|A?_GOC`AC@_OCGACEAGS?HA?'+\ + ....: '_SA`aO@G?cOC_NG_C@AOP?GnO@_GACOE?g?`OGACCOGaGOc?HA?`GORCG_'+\ + ....: 'AO@B?K@[`A?OCI@A@By?_K@?SCABA?H?SA?a@GC`CH?Q?C_c?cGRC@G_AO'+\ + ....: 'COa@Ax?QC?_GOo_CNg@A?oC@CaCGO@CGA_O`?GSGPAGOC_@OO_aCHaG?cO'+\ + ....: '@CB?_`Ax?GQC?_cAOCG^OGAC@_D?IGO`?D?O_I?HAOO`AGOHA?cC?oAO`A'+\ + ....: 'W_Q?HCACACGO`[_OCHA?_cCACG^O_@CAGO`A?GCOGc@?I?OQOC?IGC_o@C'+\ + ....: 'AGCCE?A@DBG_OA@C_CP?OG_VA_COG@D?_OA_DFgA@CO?aH?Ga@?a?_I?S@'+\ + ....: 'A@@Oa@?@P@GCO_AACO_a_?`K_GCQ@?cAOG_OGAwQ@?K?cCGH?I?ABy@C?G'+\ + ....: '_S@@GCA@C`?OI?_D?OP@G?IGGP@O_AGCP?aG?GCPAX?cA?OGSGCGCAGCJ`'+\ + ....: '?oAGCCHAA?A_CG^O@CAG_GCSCAGCCGOCG@OA_`?`?g_OACG_`CAGOAO_H?'+\ + ....: 'a_?`AXA?OGcAAOP?a@?CGVACOG@_AGG`OA_?O`|?Ga?COKAAGCA@O`A?a?'+\ + ....: 'S@?HCG`?_?gO`AGGaC?PCAOGI?A@GO`K_CQ@?GO_`OGCAACGVAG@_COOCQ'+\ + ....: '?g?I?O`ByC?G_P?O`A?H@G?_P?`OAGC?gD?_C@_GCAGDG_OA@CCPC?AOQ?'+\ + ....: '?g_R@_AGCO____OCC_@OAbaOC?g@C_H?AOOC@?a`y?PC?G`@OOH??cOG_O'+\ + ....: 'OAG@_COAP?WA?_KAGC@C_CQ@?HAACH??c@P?_AWGaC?P?gA_C_GAD?I?Aw'+\ + ....: 'a?S@?K?`C_GAOGCS?@|?COGaA@CAAOQ?AGCAGOACOG@_G_aC@_G@CA@@AH'+\ + ....: 'A?OGc?WAAH@G?P?_?cH_`CAGOGACc@@GA?S?CGVCG@OA_CICAOOC?PO?OG'+\ + ....: '^OG_@CAC_cC?AOP?_OICG@?oAGCO_GO_GB@?_OG`AH?cA?OH?`P??cC_O?'+\ + ....: 'SCGR@O_AGCAI?Q?_GGS?D?O`[OI?_D@@CCA?cCA_?_O`By?_PC?IGAGOQ?'+\ + ....: '@A@?aO`A?Q@?K?__`_E?_GCA@CGO`C_GCQ@A?gAOQ?@C?DCACGR@GCO_AG'+\ + ....: 'PA@@GAA?A_CO`Aw_I?S@?SCB@?OC_?_P@ACNgOC@A?aCGOCAGCA@CA?H@G'+\ + ....: 'G_C@AOGa?OOG_O?g_OA?oDC_AO@GOCc?@P?_A@D??cC``O?cGAOGD?@OA_'+\ + ....: 'CAGCA?_cwKA?`?OWGG?_PO?I?S?H@?^OGAC@_Aa@CAGC?a@?_Q?@H?_OCH'+\ + ....: 'A?OQA_P?_G_O?WA?_IG_Q?HC@A@ADCA?AI?AC_?QAWOHA?cAGG_I?S?G_O'+\ + ....: 'G@GA?`[D?O_IA?`GGCS?OA_?c@?Q?^OAC@_G_Ca@CA@?OGCOH@G@A@?GQC'+\ + ....: '?_Q@GP?_OG?IGGB?OCGaG?cO@A__QGC?E?A@CH@G?GRAGOC_@GGOW@O?O_'+\ + ....: 'OGa?_c?GV@CGA_OOaC?a_?a?A_CcC@?CNgA?oC@GGE@?_OH?a@?_?QA`A@'+\ + ....: '?QC?_KGGO_OGCAa@?A?_KCGPC@G_AOAGPGC?D@?a_A?@GGO`KH?Q?C_QGA'+\ + ....: 'A_?gOG_OA?_GG`AwH?SA?`?cAI?A@D?I?@?QA?`By?K@?O`GGACA@CGCA@'+\ + ....: 'CC_?WO`?`A?OCH?`OCA@COG?I?oC@ACGPCG_AO@_aAA?Aa?g?GD@G?CO`A'+\ + ....: 'WOc?HA?OcG_?g@OGCAAAOC@ACJ_`OGACAGCS?CAGI?A`@?OCACG^' + sage: g2 = '~?A[??osR?WARSETCJ_QWASehOXQg`QwChK?qSeFQ_sTIaWIV?XIR'+\ + ....: '?KAC?B?`?COCG?o?O_@_?`??B?`?o@_O_WCOCHC@_?`W?E?AD_O?WCCeO?'+\ + ....: 'WCSEGAGAIaA@_?aw?OK?ER?`?@_HQXA?B@Q_pA?a@Qg_`?o?h[?GOK@IR?'+\ + ....: '@A?BEQcoCG?K\\IB?GOCWiTC?GOKWIV??CGEKdH_H_?CB?`?DC??_WCG?S'+\ + ....: 'O?AP?O_?g_?D_?`?C__?D_?`?CCo??@_O_XDC???WCGEGg_??a?`G_aa??'+\ + ....: 'E?AD_@cC??K?CJ?@@K?O?WCCe?aa?G?KAIB?Gg_A?a?ag_@DC?OK?CV??E'+\ + ....: 'OO@?o?XK??GH`A?B?Qco?Gg`A?B@Q_o?CSO`?P?hSO?@DCGOK?IV???K_`'+\ + ....: 'A@_HQWC??_cCG?KXIRG?@D?GO?WySEG?@D?GOCWiTCC??a_CGEKDJ_@??K'+\ + ....: '_@A@bHQWAW?@@K??_WCG?g_?CSO?A@_O_@P??Gg_?Ca?`?@P??Gg_?D_?`'+\ + ....: '?C__?EOO?Ao?O_AAW?@@K???WCGEPP??Gg_??B?`?pDC??aa??AGACaAIG'+\ + ....: '?@DC??K?CJ?BGG?@cC??K?CJ?@@K??_e?G?KAAR?PP??Gg_A?B?a_oAIG?'+\ + ....: '@DC?OCOCTC?Gg_?CSO@?o?P[??X@??K__A@_?qW??OR??GH`A?B?Qco?Gg'+\ + ....: '_?CSO`?@_hOW?AIG?@DCGOCOITC??PP??Gg`A@_@Qw??@cC??qACGE?dH_'+\ + ....: 'O?AAW?@@GGO?WqSeO?AIG?@D?GO?WySEG?@DC??a_CGAKTIaA??PP??Gg@'+\ + ....: 'A@b@Qw?O?BGG?@c?GOKXIR?KAC?H_?CCo?A@_O_?WCG@P??Gg_?CB?`?CO'+\ + ....: 'CG@P??Gg_?Ca?`?E?AC?g_?CSO?Ao?O_@_?`@GG?@cC??k?CG??WCGOR??'+\ + ....: 'GH_??B?`?o@_O`DC??aa???KACB?a?`AIG?@DC??COCHC@_?`AIG?@DC??'+\ + ....: 'K?CJ??o?O`cC??qA??E?AD_O?WC?OR??GH_A?B?_cq?B?_AIG?@DC?O?WC'+\ + ....: 'SEGAGA?Gg_?CSO@?P?PSOOK?C?PP??Gg_A@_?aw?OK?C?X@??K__A@_?qW'+\ + ....: 'CG?K??GH_?CCo`?@_HQXA?B??AIG?@DCGO?WISEGOCO??PP??Gg`A?a@Qg'+\ + ....: '_`?o??@DC??aaCGE?DJ_@A@_??BGG?@cCGOK@IR?@A?BO?AAW?@@GGO?Wq'+\ + ....: 'Se?`?@g?@DC??a_CG?K\\IB?GOCQ??PP??Gg@A?bDQg_@A@_O?AIG?@D?G'+\ + ....: 'OKWIV??CGE@??K__?EO?`?pchK?_SA_OI@OGD?gCA_SA@OI?c@H?Q?c_H?'+\ + ....: 'QOC_HGAOCc?QOC_HGAOCc@GAQ?c@H?QD?gCA_SA@OI@?gD?_SA_OKA_SA@'+\ + ....: 'OI@?gD?_SA_OI@OHI?c_H?QOC_HGAOCc@GAQ?eC_H?QOC_HGAOCc@GAQ?c'+\ + ....: '@XD?_SA_OI@OGD?gCA_SA@PKGO`A@ACGSGO`?`ACICGO_?ACGOcGO`?O`A'+\ + ....: 'C`ACHACGO???^?????}Bw????Fo^???????Fo?}?????Bw?^?Bw?????GO'+\ + ....: '`AO`AC`ACGACGOcGO`??aCGO_O`ADACGOGO`A@ACGOA???@{?N_@{?????'+\ + ....: 'Fo?}????OFo????N_}????@{????Bw?OACGOgO`A@ACGSGO`?`ACG?OaCG'+\ + ....: 'O_GO`AO`AC`ACGACGO_@G???Fo^?????}Bw????Fo??AC@{?????Fo?}?F'+\ + ....: 'o?????^??AOGO`AO`AC@ACGQCGO_GO`A?HAACGOgO`A@ACGOGO`A`ACG?G'+\ + ....: 'Q??^?Bw?????N_@{?????Fo?QC??Fo^?????}????@{Fo???CHACGO_O`A'+\ + ....: 'CACGOgO`A@ACGO@AOcGO`?O`AC`ACGACGOcGO`?@GQFo????N_????^@{?'+\ + ....: '???Bw??`GRw?????N_@{?????Fo?}???HAO_OI@OGD?gCA_SA@OI@?gDK_'+\ + ....: '??C@GAQ?c@H?Q?c_H?QOC_HEW????????????????????????~~~~~' sage: G1 = Graph(g1) sage: G2 = Graph(g2) sage: G1.is_isomorphic(G2) @@ -22023,8 +22239,7 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False (False, None) """ - - if self.order() == other.order() == 0: + if not self.order() and not other.order(): return (True, None) if certificate else True if (self.is_directed() != other.is_directed() or self.order() != other.order() or @@ -22053,11 +22268,11 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False partition2 = sum(partition2,[]) other_vertices = partition2 else: - G = self; partition = [self_vertices] - G2 = other; partition2 = other_vertices - G_to = {} - for i,u in enumerate(self_vertices): - G_to[u] = i + G = self + partition = [self_vertices] + G2 = other + partition2 = other_vertices + G_to = {u: i for i,u in enumerate(self_vertices)} from sage.graphs.all import Graph, DiGraph DoDG = DiGraph if self._directed else Graph H = DoDG(len(self_vertices), implementation='c_graph', loops=G.allows_loops()) @@ -22067,9 +22282,7 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False G = HB.c_graph()[0] partition = [[G_to[vv] for vv in cell] for cell in partition] GC = G - G2_to = {} - for i,u in enumerate(other_vertices): - G2_to[u] = i + G2_to = {u: i for i,u in enumerate(other_vertices)} H2 = DoDG(len(other_vertices), implementation='c_graph', loops=G2.allows_loops()) H2B = H2._backend for u,v in G2.edge_iterator(labels=False): @@ -22618,6 +22831,227 @@ def is_self_complementary(self): from sage.graphs.connectivity import vertex_connectivity from sage.graphs.base.static_dense_graph import connected_subgraph_iterator + def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): + r""" + Return the Katz matrix of the graph. + + Katz centrality of a node is a measure of centrality in a graph + network. Katz centrality computes the relative influence of a node + within a network. Connections made with distant neighbors are, however + penalized by an attenuation factor `\alpha`. + + Adding the values in the Katz matrix of all columns in a particular row + gives the Katz centrality measure of the vertex represented by that + particular row. Katz centrality measures influence by taking into + account the total number of walks between a pair of nodes. + + See the :wikipedia:`Katz_centrality` for more information. + + INPUT: + + - ``alpha`` -- a nonnegative real number, must be less than the + reciprocal of the spectral radius of the graph (the maximum + absolute eigenvalue of the adjacency matrix) + + - ``nonedgesonly`` -- boolean (default: ``True``); if ``True``, value + for each edge present in the graph is set to zero. + + - ``vertices`` -- list (default: ``None``); the ordering of the + vertices defining how they should appear in the matrix. By default, + the ordering given by :meth:`GenericGraph.vertices` is used. + + OUTPUT: the Katz matrix of the graph with parameter alpha + + EXAMPLES: + + We find the Katz matrix of an undirected 4-cycle. :: + + sage: G = graphs.CycleGraph(4) + sage: G.katz_matrix(1/20) + [1/198 5/99 1/198 5/99] + [ 5/99 1/198 5/99 1/198] + [1/198 5/99 1/198 5/99] + [ 5/99 1/198 5/99 1/198] + + We find the Katz matrix of an undirected 4-cycle with all entries + other than those which correspond to non-edges zeroed out. :: + + sage: G.katz_matrix(1/20, True) + [ 0 0 1/198 0] + [ 0 0 0 1/198] + [1/198 0 0 0] + [ 0 1/198 0 0] + + This will give an error if alpha<=0 or alpha>=1/spectral_radius = 1/max + (A.eigenvalues()). + + We find the Katz matrix in a fan on 6 vertices. :: + + sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) + sage: H.katz_matrix(1/10) + [ 169/2256 545/4512 25/188 605/4512 25/188 545/4512 485/4512] + [ 545/4512 7081/297792 4355/37224 229/9024 595/37224 4073/297792 109/9024] + [ 25/188 4355/37224 172/4653 45/376 125/4653 595/37224 5/376] + [ 605/4512 229/9024 45/376 337/9024 45/376 229/9024 121/9024] + [ 25/188 595/37224 125/4653 45/376 172/4653 4355/37224 5/376] + [ 545/4512 4073/297792 595/37224 229/9024 4355/37224 7081/297792 109/9024] + [ 485/4512 109/9024 5/376 121/9024 5/376 109/9024 97/9024] + + .. SEEALSO:: + + * :meth:`~katz_centrality` + * :wikipedia:`Katz_centrality` + + TESTS:: + + sage: (graphs.CompleteGraph(4)).katz_matrix(1/4) + [3/5 4/5 4/5 4/5] + [4/5 3/5 4/5 4/5] + [4/5 4/5 3/5 4/5] + [4/5 4/5 4/5 3/5] + sage: (graphs.CompleteGraph(4)).katz_matrix(1/4, nonedgesonly=True) + [0 0 0 0] + [0 0 0 0] + [0 0 0 0] + [0 0 0 0] + sage: (graphs.PathGraph(4)).katz_matrix(1/4, nonedgesonly=False) + [15/209 60/209 16/209 4/209] + [60/209 31/209 64/209 16/209] + [16/209 64/209 31/209 60/209] + [ 4/209 16/209 60/209 15/209] + sage: (graphs.PathGraph(4)).katz_matrix(1/4, nonedgesonly=True) + [ 0 0 16/209 4/209] + [ 0 0 0 16/209] + [16/209 0 0 0] + [ 4/209 16/209 0 0] + """ + if alpha <= 0: + raise ValueError('the parameter alpha must be strictly positive') + + n = self.order() + if n == 0 : + raise ValueError('graph is empty') + if vertices is None: + vertices = self.vertices() + elif (len(vertices) != n or + set(vertices) != set(self)): + raise ValueError("``vertices`` must be a permutation of the vertices") + + A = self.adjacency_matrix(vertices=vertices) + + spectral_radius = max([abs(eigen) for eigen in A.eigenvalues()]) + + if spectral_radius == 0: + raise ValueError('the spectral radius of the graph must not be zero') + if alpha >= 1/spectral_radius: + raise ValueError('the parameter alpha must be less than the reciprocal of the spectral radius of the graph') + + In = matrix.identity(n) + K = (In - alpha * A.transpose()).inverse() - In + if nonedgesonly: + onesmat = matrix(QQ, n, n, lambda i, j: 1) + Missing = onesmat - A - In + return K.elementwise_product(Missing) + else: + return K + + def katz_centrality(self, alpha , u=None): + r""" + Return the Katz centrality of vertex `u`. + + Katz centrality of a node is a measure of centrality in a graph + network. Katz centrality computes the relative influence of a node + within a network. Connections made with distant neighbors are, however + penalized by an attenuation factor `\alpha`. + + See the :wikipedia:`Katz_centrality` for more information. + + INPUT: + + - ``alpha`` -- a nonnegative real number, must be less than the + reciprocal of the spectral radius of the graph (the maximum absolute + eigenvalue of the adjacency matrix). + + - ``u`` -- the vertex whose Katz centrality needs to be measured + (default: ``None``) + + OUTPUT: a list containing the Katz centrality of each vertex if u=None + otherwise Katz centrality of the vertex u. + + EXAMPLES: + + We compute the Katz centrality of a 4-cycle (note that by symmetry, + all 4 vertices have the same centrality) :: + + sage: G = graphs.CycleGraph(4) + sage: G.katz_centrality(1/20) + {0: 1/9, 1: 1/9, 2: 1/9, 3: 1/9} + + Note that in the below example the nodes having indegree `0` also have + the Katz centrality value as `0`, as these nodes are not influenced by + other nodes. :: + + sage: G = DiGraph({1: [10], 2:[10,11], 3:[10,11], 4:[], 5:[11, 4], 6:[11], 7:[10,11], 8:[10,11], 9:[10], 10:[11, 5, 8], 11:[6]}) + sage: G.katz_centrality(.85) + {1: 0.000000000000000, + 2: 0.000000000000000, + 3: 0.000000000000000, + 4: 16.7319819819820, + 5: 18.6846846846847, + 6: 173.212076941807, + 7: 0.000000000000000, + 8: 18.6846846846847, + 9: 0.000000000000000, + 10: 20.9819819819820, + 11: 202.778914049184} + + + .. SEEALSO:: + + * :meth:`~katz_matrix` + * :wikipedia:`Katz_centrality` + + TESTS:: + + sage: graphs.PathGraph(3).katz_centrality(1/20) + {0: 11/199, 1: 21/199, 2: 11/199} + sage: graphs.PathGraph(4).katz_centrality(1/20) + {0: 21/379, 1: 41/379, 2: 41/379, 3: 21/379} + sage: graphs.PathGraph(3).katz_centrality(1/20,2) + 11/199 + sage: graphs.PathGraph(4).katz_centrality(1/20,3) + 21/379 + sage: (graphs.PathGraph(3) + graphs.PathGraph(4)).katz_centrality(1/20) + {0: 11/199, 1: 21/199, 2: 11/199, 3: 21/379, 4: 41/379, 5: 41/379, 6: 21/379} + + """ + n = self.order() + if n == 0: + raise ValueError('graph is empty') + + if u and u not in self: + raise ValueError("vertex ({0}) is not a vertex of the graph".format(repr(u))) + + if u: + if self.is_connected(): + G = self + else: + G = self.subgraph(self.connected_component_containing_vertex(u, sort=False)) + verts = list(G) + M = G.katz_matrix(alpha, nonedgesonly=False, vertices=verts) + return sum(M[verts.index(u)]) + + if self.is_connected(): + verts = list(self) + M = self.katz_matrix(alpha, nonedgesonly=False, vertices=verts) + return {u: sum(M[i]) for i, u in enumerate(verts)} + else: + K = {} + for g in self.connected_components_subgraphs(): + verts = list(g) + M = g.katz_matrix(alpha, nonedgesonly=False, vertices=verts) + K.update({u: sum(M[i]) for i, u in enumerate(verts)}) + return K def tachyon_vertex_plot(g, bgcolor=(1,1,1), vertex_colors=None, @@ -22741,22 +23175,22 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab sage: G.add_edge(1,2,'string') sage: G.add_edge(2,123) sage: g = graph_isom_equivalent_non_edge_labeled_graph(G, partition=[[0,123],[1,2]]); g - [Graph on 6 vertices, [[0, 3], [1, 2], [4], [5]]] + [Graph on 6 vertices, [[1, 0], [2, 3], [4], [5]]] sage: g = graph_isom_equivalent_non_edge_labeled_graph(G); g [Graph on 6 vertices, [[0, 1, 2, 3], [4], [5]]] sage: g[0].edges() - [(0, 4, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 5, None)] + [(0, 3, None), (1, 4, None), (2, 4, None), (2, 5, None), (3, 5, None)] sage: g = graph_isom_equivalent_non_edge_labeled_graph(G,standard_label='string',return_edge_labels=True); g [Graph on 6 vertices, [[0, 1, 2, 3], [5], [4]], [[[None, 1]], [[0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 1], [8, 1], [9, 1]], [['string', 1]]]] sage: g[0].edges() - [(0, 4, None), (1, 2, None), (1, 4, None), (2, 5, None), (3, 5, None)] + [(0, 5, None), (1, 4, None), (2, 3, None), (2, 4, None), (3, 5, None)] sage: graph_isom_equivalent_non_edge_labeled_graph(G,inplace=True) [[[0, 1, 2, 3], [4], [5]]] sage: G.edges() - [(0, 4, None), (1, 4, None), (1, 5, None), (2, 3, None), (2, 5, None)] + [(0, 3, None), (1, 4, None), (2, 4, None), (2, 5, None), (3, 5, None)] TESTS: @@ -22808,20 +23242,25 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab if inplace: g._backend = G._backend elif not inplace: - G = copy( g ) + G = copy(g) else: G = g G_order = G.order() - V = list(range(G_order)) - if G.vertices() != V: - relabel_dict = G.relabel(return_map=True) + # Do not relabel if the set of vertices is equal to the set + # range(n). This helps to ensure that *equal* graphs on range(n) + # yield *equal* (not just isomorphic) canonical labelings. This + # is just a convenience, there is no mathematical meaning. + if set(G) != set(range(G_order)): + relabel_dict = G.relabel(return_map=True, inplace=True) else: - relabel_dict = dict( (i,i) for i in range(G_order) ) + # Do not relabel but ensure that labels are Python ints + relabel_dict = {i: int(i) for i in G} + if partition is None: - partition = [V] + partition = [G.vertices()] else: - partition = [ [ relabel_dict[i] for i in part ] for part in partition ] + partition = [[relabel_dict[i] for i in part] for part in partition] if G._directed: edge_iter = G._backend.iterator_in_edges(G,True) diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index d03e483e2f5..e7f53d4c339 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -571,8 +571,8 @@ cdef class SubgraphSearch: The algorithm is a brute-force search. Let `V(H) = \{h_1,\dots,h_k\}`. It first tries to find in `G` a possible - representant of `h_1`, then a representant of `h_2` compatible - with `h_1`, then a representant of `h_3` compatible with the first + representative of `h_1`, then a representative of `h_2` compatible + with `h_1`, then a representative of `h_3` compatible with the first two, etc. This way, most of the time we need to test far less than `k! @@ -734,7 +734,7 @@ cdef class SubgraphSearch: self.stack[0] = 0 self.stack[1] = -1 - # Number of representants we have already found. Set to 1 as vertex 0 + # Number of representatives we have already found. Set to 1 as vertex 0 # is already part of the partial copy of H in G. self.active = 1 @@ -841,7 +841,7 @@ cdef class SubgraphSearch: # as long as there is a non-void partial copy of H in G while self.active >= 0: # If we are here and found nothing yet, we try the next possible - # vertex as a representant of the active i-th vertex of H. + # vertex as a representative of the active i-th vertex of H. self.i = self.stack[self.active] + 1 # Looking for a vertex that is not busy and compatible with the # partial copy we have of H. @@ -868,7 +868,7 @@ cdef class SubgraphSearch: else: self.i += 1 - # If we have found a good representant of H's i-th vertex in G + # If we have found a good representative of H's i-th vertex in G if self.i < self.ng: # updating the last vertex of the stack @@ -890,7 +890,7 @@ cdef class SubgraphSearch: # we begin the search of the next vertex at 0 self.stack[self.active] = -1 - # If we found no representant for the i-th vertex, it + # If we found no representative for the i-th vertex, it # means that we cannot extend the current copy of H so we # update the status of stack[active] and prepare to change # the previous vertex. @@ -1231,7 +1231,7 @@ cpdef tuple find_hamiltonian(G, long max_iter=100000, long reset_bound=30000, (False, [0, 1, 2, 3]) sage: fh(G, find_path=True) (False, [0, 1, 2, 3]) - + """ from sage.misc.prandom import randint cdef int n = G.order() diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index c2ba7d3c21f..7a6dda41244 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -80,6 +80,9 @@ - David Coudert (2018-10-07): cleaning +- Amanda Francis, Caitlin Lienkaemper, Kate Collins, Rajat Mittal (2019-03-10): + methods for computing effective resistance + Graph Format ------------ @@ -2024,7 +2027,7 @@ def apex_vertices(self, k=None): vertex is the unique apex vertex :: sage: G = graphs.Grid2dGraph(4,4) - sage: G.apex_vertices() == G.vertices() + sage: set(G.apex_vertices()) == set(G.vertices()) True sage: G.add_edges([('universal',v) for v in G]) sage: G.apex_vertices() @@ -2049,13 +2052,14 @@ def apex_vertices(self, k=None): Neighbors of an apex of degree 2 are apex:: sage: G = graphs.Grid2dGraph(5,5) - sage: G.add_path([(1,1),'x',(3,3)]) + sage: v = (666, 666) + sage: G.add_path([(1, 1), v, (3, 3)]) sage: G.is_planar() False - sage: G.degree('x') + sage: G.degree(v) 2 - sage: G.apex_vertices() - ['x', (2, 2), (3, 3), (1, 1)] + sage: sorted(G.apex_vertices()) + [(1, 1), (2, 2), (3, 3), (666, 666)] TESTS: @@ -2086,7 +2090,8 @@ def apex_vertices(self, k=None): # Easy cases: null graph, subgraphs of K_5 and K_3,3 if self.order() <= 5 or (self.order() <= 6 and self.is_bipartite()): - return self.vertices()[:k] + it = self.vertex_iterator() + return [next(it) for _ in range(k)] if not self.is_connected(): @@ -2097,20 +2102,25 @@ def apex_vertices(self, k=None): P = [H for H in self.connected_components_subgraphs() if not H.is_planar()] if not P: # The graph is planar - return self.vertices()[:k] + it = self.vertex_iterator() + return [next(it) for _ in range(k)] elif len(P) > 1: return [] else: # We proceed with the non planar component - H = Graph(P[0].edges(labels=0), immutable=False, loops=False, multiedges=False) if P[0].is_immutable() else P[0] + if P[0].is_immutable(): + H = Graph(P[0].edges(labels=0, sort=False), immutable=False, loops=False, multiedges=False) + else: + H = P[0] elif self.is_planar(): # A planar graph is apex. - return self.vertices()[:k] + it = self.vertex_iterator() + return [next(it) for _ in range(k)] else: # We make a basic copy of the graph since we will modify it - H = Graph(self.edges(labels=0), immutable=False, loops=False, multiedges=False) + H = Graph(self.edges(labels=0, sort=False), immutable=False, loops=False, multiedges=False) # General case: basic implementation @@ -2779,7 +2789,7 @@ def treewidth(self, k=None, certificate=False, algorithm=None): if k is not None and k >= g.order() - 1: if certificate: from sage.sets.set import Set - return Graph({Set(g.vertices()):[]}, name="Tree decomposition") + return Graph({Set(g): []}, name="Tree decomposition") return True # TDLIB @@ -2807,8 +2817,9 @@ def treewidth(self, k=None, certificate=False, algorithm=None): return all(cc.treewidth(k) for cc in g.connected_components_subgraphs()) else: T = [cc.treewidth(certificate=True) for cc in g.connected_components_subgraphs()] - tree = Graph([sum([t.vertices() for t in T],[]), sum([t.edges(labels=False) for t in T],[])], - format='vertices_and_edges', name="Tree decomposition") + tree = Graph([sum([list(t) for t in T], []), + sum([t.edges(labels=False, sort=False) for t in T], [])], + format='vertices_and_edges', name="Tree decomposition") v = next(T[0].vertex_iterator()) for t in T[1:]: tree.add_edge(next(t.vertex_iterator()),v) @@ -2850,7 +2861,7 @@ def rec(cut, cc): # Removing v may have disconnected cc. We iterate on its # connected components - for cci in g.subgraph(ccv).connected_components(): + for cci in g.subgraph(ccv).connected_components(sort=False): # The recursive subcalls. We remove on-the-fly the vertices # from the cut which play no role in separating the @@ -2873,7 +2884,7 @@ def rec(cut, cc): return False # Main call to rec function, i.e. rec({v}, V-{v}) - V = g.vertices() + V = list(g) v = frozenset([V.pop()]) TD = rec(v, frozenset(V)) @@ -2896,7 +2907,7 @@ def rec(cut, cc): changed = True while changed: changed = False - for v in G.vertices(): + for v in G.vertices(sort=False): for u in G.neighbor_iterator(v): if u.issuperset(v): G.merge_vertices([u, v]) # the new vertex is named 'u' @@ -3685,7 +3696,7 @@ def bounded_outdegree_orientation(self, bound, solver=None, verbose=False): if not n: return DiGraph() - vertices = self.vertices() + vertices = list(self) vertices_id = {y: x for x,y in enumerate(vertices)} b = {} @@ -4146,10 +4157,14 @@ def coloring(self, algorithm="DLX", hex_colors=False, solver=None, verbose=0): EXAMPLES:: sage: G = Graph("Fooba") - sage: P = G.coloring(algorithm="MILP"); P - [[2, 1, 3], [0, 6, 5], [4]] - sage: P = G.coloring(algorithm="DLX"); P - [[1, 2, 3], [0, 5, 6], [4]] + sage: P = G.coloring(algorithm="MILP") + sage: Q = G.coloring(algorithm="DLX") + sage: def are_equal_colorings(A, B): + ....: return Set(map(Set, A)) == Set(map(Set, B)) + sage: are_equal_colorings(P, [[1, 2, 3], [0, 5, 6], [4]]) + True + sage: are_equal_colorings(P, Q) + True sage: G.plot(partition=P) Graphics object consisting of 16 graphics primitives sage: G.coloring(hex_colors=True, algorithm="MILP") @@ -4446,10 +4461,10 @@ def matching(self, value_only=False, algorithm="Edmonds", and LP formulation:: sage: g = Graph([(0,1,0), (1,2,999), (2,3,-5)]) - sage: g.matching() + sage: sorted(g.matching()) + [(0, 1, 0), (2, 3, -5)] + sage: sorted(g.matching(algorithm="LP")) [(0, 1, 0), (2, 3, -5)] - sage: g.matching(algorithm="LP") - [(2, 3, -5), (0, 1, 0)] When ``use_edge_labels`` is set to ``True``, with Edmonds' algorithm and LP formulation:: @@ -4969,7 +4984,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0): # Boolean variable in two dimension whose first element is a vertex and # whose second element is one of the sets given as arguments. - # When true, indicated that the vertex is the representant of the + # When true, indicated that the vertex is the representative of the # corresponding set classss = p.new_variable(binary=True) @@ -4979,7 +4994,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0): for v in f: lists[v].append(i) - # a classss has exactly one representant + # a classss has exactly one representative p.add_constraint(p.sum(classss[v,i] for v in f), max=1, min=1) # A vertex represents at most one classss (vertex_taken is binary), and @@ -4987,7 +5002,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0): for v in self: p.add_constraint(p.sum(classss[v,i] for i in lists[v]) - vertex_taken[v], max=0) - # Two adjacent vertices can not both be representants of a set + # Two adjacent vertices can not both be representatives of a set for u,v in self.edge_iterator(labels=None): p.add_constraint(vertex_taken[u] + vertex_taken[v], max=1) @@ -5102,7 +5117,7 @@ def minor(self, H, solver=None, verbose=0): # rs = Representative set of a vertex # for h in H, v in G is such that rs[h,v] == 1 if and only if v - # is a representant of h in self + # is a representative of h in self rs = p.new_variable(binary=True) for v in self: @@ -5520,7 +5535,7 @@ def twograph(self): sage: p=graphs.chang_graphs() sage: T8 = graphs.CompleteGraph(8).line_graph() sage: C = T8.seidel_switching([(0,1,None),(2,3,None),(4,5,None),(6,7,None)],inplace=False) - sage: T8.twograph()==C.twograph() + sage: T8.twograph() == C.twograph() True sage: T8.is_isomorphic(C) False @@ -5541,7 +5556,7 @@ def twograph(self): -- ditto, but much faster. """ from sage.combinat.designs.twographs import TwoGraph - G = self.relabel(inplace=False) + G = self.relabel(range(self.order()), inplace=False) T = [] # Triangles @@ -5683,7 +5698,7 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose p.set_objective(None) ####################### - # Vertex representant # + # Vertex representative # ####################### # # v_repr[h,g] = 1 if vertex h from H is represented by vertex @@ -5691,7 +5706,7 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose v_repr = p.new_variable(binary=True) - # Exactly one representant per vertex of H + # Exactly one representative per vertex of H for h in H: p.add_constraint(p.sum(v_repr[h,g] for g in G), min=1, max=1) @@ -5716,7 +5731,7 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose ################################### # # For any edge (h1,h2) in H, we have a corresponding path in G - # between the representants of h1 and h2. Which means there is + # between the representatives of h1 and h2. Which means there is # a flow of intensity 1 from one to the other. # We are then writing a flow problem for each edge of H. # @@ -5741,7 +5756,7 @@ def flow_balance(C, v): for v in G: # The flow balance depends on whether the vertex v is a - # representant of h1 or h2 in G, or a representant of none + # representative of h1 or h2 in G, or a representative of none p.add_constraint(flow_balance((h1,h2),v) == v_repr[h1,v] - v_repr[h2,v]) ############################# @@ -6623,9 +6638,9 @@ def ear_decomposition(self): Ear decomposition of a biconnected graph:: - sage: g = graphs.CubeGraph(2) + sage: g = graphs.CycleGraph(4) sage: g.ear_decomposition() - [['00', '01', '11', '10', '00']] + [[0, 3, 2, 1, 0]] Ear decomposition of a connected but not biconnected graph:: @@ -6677,8 +6692,9 @@ def ear_decomposition(self): # Dfs tree traversal. traversed = set() - # Dict to store parent vertex of all the visited vertices. - parent = {} + # Dictionary to store parent vertex of all the visited vertices. + # Initialized for the first vertex to be visited. + parent = {next(self.vertex_iterator()): None} # List to store visit_time of vertices in Dfs traversal. value = {} @@ -6686,10 +6702,6 @@ def ear_decomposition(self): # List to store all the chains and cycles of the input graph G. chains = [] - vertices = self.vertices() - - parent[vertices[0]] = None - # DFS() : Function that performs depth first search on input graph G and # stores DFS tree in parent array format. def DFS(v): @@ -6727,7 +6739,7 @@ def traverse(start, pointer): chains.append(chain) # Perform ear decomposition on each connected component of input graph. - for v in vertices: + for v in self: if v not in seen: # Start the depth first search from first vertex DFS(v) @@ -6836,21 +6848,22 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): [[0, 4], [1, 2, 3, 4]] sage: C.cliques_containing_vertex(cliques=E) {0: [[0, 4]], 1: [[1, 2, 3, 4]], 2: [[1, 2, 3, 4]], 3: [[1, 2, 3, 4]], 4: [[0, 4], [1, 2, 3, 4]]} - sage: F = graphs.Grid2dGraph(2,3) - sage: F.cliques_containing_vertex() - {(0, 0): [[(0, 1), (0, 0)], [(1, 0), (0, 0)]], - (0, 1): [[(0, 1), (0, 0)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]], - (0, 2): [[(0, 1), (0, 2)], [(1, 2), (0, 2)]], - (1, 0): [[(1, 0), (0, 0)], [(1, 0), (1, 1)]], - (1, 1): [[(0, 1), (1, 1)], [(1, 2), (1, 1)], [(1, 0), (1, 1)]], - (1, 2): [[(1, 2), (1, 1)], [(1, 2), (0, 2)]]} - sage: F.cliques_containing_vertex(vertices=[(0, 1), (1, 2)]) - {(0, 1): [[(0, 1), (0, 0)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]], (1, 2): [[(1, 2), (1, 1)], [(1, 2), (0, 2)]]} + sage: G = Graph({0:[1,2,3], 1:[2], 3:[0,1]}) sage: G.show(figsize=[2,2]) sage: G.cliques_containing_vertex() {0: [[0, 1, 2], [0, 1, 3]], 1: [[0, 1, 2], [0, 1, 3]], 2: [[0, 1, 2]], 3: [[0, 1, 3]]} + Since each clique of a 2 dimensional grid corresponds to an edge, the + number of cliques in which a vertex is involved equals its degree:: + + sage: F = graphs.Grid2dGraph(2,3) + sage: d = F.cliques_containing_vertex() + sage: all(F.degree(u) == len(cliques) for u,cliques in d.items()) + True + sage: F.cliques_containing_vertex(vertices=[(0, 1)]) + {(0, 1): [[(0, 1), (0, 0)], [(0, 1), (0, 2)], [(0, 1), (1, 1)]]} + """ import networkx return networkx.cliques_containing_node(self.networkx_graph(copy=False), vertices, cliques) @@ -7648,9 +7661,9 @@ def gomory_hu_tree(self, algorithm=None): if not self.is_connected(): g = Graph() for cc in self.connected_components_subgraphs(): - g = g.union(cc._gomory_hu_tree(frozenset(cc.vertices()), algorithm=algorithm)) + g = g.union(cc._gomory_hu_tree(frozenset(cc.vertex_iterator()), algorithm=algorithm)) else: - g = self._gomory_hu_tree(frozenset(self.vertices()), algorithm=algorithm) + g = self._gomory_hu_tree(frozenset(self.vertex_iterator()), algorithm=algorithm) if self.get_pos() is not None: g.set_pos(dict(self.get_pos())) @@ -7721,9 +7734,8 @@ def two_factor_petersen(self, solver=None, verbose=0): # a sink (-1,v) and a source (1,v) # Any edge (u,v) in the digraph is then added as ((-1,u),(1,v)) - from sage.graphs.graph import Graph g = Graph() - g.add_edges(((-1, u), (1, v)) for u,v in d.edge_iterator(labels=None)) + g.add_edges(((-1, u), (1, v)) for u, v in d.edge_iterator(labels=None)) # This new bipartite graph is now edge_colored from sage.graphs.graph_coloring import edge_coloring @@ -8022,19 +8034,21 @@ def perfect_matchings(self, labels=False): EXAMPLES:: sage: G=graphs.GridGraph([2,3]) - sage: list(G.perfect_matchings()) - [[((0, 0), (0, 1)), ((0, 2), (1, 2)), ((1, 0), (1, 1))], - [((0, 1), (0, 2)), ((1, 1), (1, 2)), ((0, 0), (1, 0))], - [((0, 1), (1, 1)), ((0, 2), (1, 2)), ((0, 0), (1, 0))]] + sage: for m in G.perfect_matchings(): + ....: print(sorted(m)) + [((0, 0), (0, 1)), ((0, 2), (1, 2)), ((1, 0), (1, 1))] + [((0, 0), (1, 0)), ((0, 1), (0, 2)), ((1, 1), (1, 2))] + [((0, 0), (1, 0)), ((0, 1), (1, 1)), ((0, 2), (1, 2))] sage: G = graphs.CompleteGraph(4) - sage: list(G.perfect_matchings(labels=True)) - [[(0, 1, None), (2, 3, None)], - [(0, 2, None), (1, 3, None)], - [(0, 3, None), (1, 2, None)]] + sage: for m in G.perfect_matchings(labels=True): + ....: print(sorted(m)) + [(0, 1, None), (2, 3, None)] + [(0, 2, None), (1, 3, None)] + [(0, 3, None), (1, 2, None)] sage: G = Graph([[1,-1,'a'], [2,-2, 'b'], [1,-2,'x'], [2,-1,'y']]) - sage: list(G.perfect_matchings(labels=True)) + sage: sorted(sorted(m) for m in G.perfect_matchings(labels=True)) [[(-2, 1, 'x'), (-1, 2, 'y')], [(-2, 2, 'b'), (-1, 1, 'a')]] sage: G = graphs.CompleteGraph(8) @@ -8172,6 +8186,316 @@ def has_perfect_matching(self, algorithm="Edmonds", solver=None, verbose=0): else: raise ValueError('algorithm must be set to "Edmonds", "LP_matching" or "LP"') + @doc_index("Leftovers") + def effective_resistance(self, i, j): + r""" + Return the effective resistance between nodes `i` and `j`. + + The resistance distance between vertices `i` and `j` of a simple + connected graph `G` is defined as the effective resistance between the + two vertices on an electrical network constructed from `G` replacing + each edge of the graph by a unit (1 ohm) resistor. + + See the :wikipedia:`Resistance_distance` for more information. + + INPUT: + + - ``i``, ``j`` -- vertices of the graph + + OUTPUT: rational number denoting resistance between nodes `i` and `j` + + EXAMPLES: + + Effective resitances in a straight linear 2-tree on 6 vertices :: + + sage: G=Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) + sage: G.effective_resistance(0,1) + 34/55 + sage: G.effective_resistance(0,3) + 49/55 + sage: G.effective_resistance(1,4) + 9/11 + sage: G.effective_resistance(0,5) + 15/11 + + Effective resistances in a fan on 6 vertices :: + + sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) + sage: H.effective_resistance(1,5) + 6/5 + sage: H.effective_resistance(1,3) + 49/55 + + .. SEEALSO:: + + * :meth:`effective_resistance_matrix` -- + a similar method giving a matrix full of all effective + resistances between all nodes + + * :meth:`least_effective_resistance` -- + gives node pairs with least effective resistances + + * See :wikipedia:`Resistance_distance` for more details. + + TESTS:: + + sage: G = graphs.CompleteGraph(4) + sage: all(G.effective_resistance(u, v) == 1/2 for u,v in G.edge_iterator(labels=False)) + True + sage: Graph(1).effective_resistance(0,0) + 0 + sage: G = Graph([(0,1),(1,2)]) + sage: G.effective_resistance(0,2) + 2 + sage: G = Graph([(0,1),(1,2),(2,0)]) + sage: G.effective_resistance(0,2) + 2/3 + sage: G = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)]) + sage: r = G.effective_resistance(0,3) + sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) + True + """ + from sage.matrix.constructor import matrix + if i not in self: + raise ValueError("vertex ({0}) is not a vertex of the graph".format(repr(i))) + elif j not in self: + raise ValueError("vertex ({0}) is not a vertex of the graph".format(repr(j))) + + if i == j : + return 0 + + self._scream_if_not_simple() + if not self.is_connected(): + raise ValueError('the Graph is not a connected graph') + + vert = list(self) + i1 = vert.index(i) + i2 = vert.index(j) + n = self.order() + L = self.laplacian_matrix(vertices=vert) + M = L.pseudoinverse() + Id = matrix.identity(n) + sigma = matrix(Id[i1] - Id[i2]) + diff = sigma * M * sigma.transpose() + + return diff[0, 0] + + @doc_index("Leftovers") + def effective_resistance_matrix(self, vertices=None, nonedgesonly=True): + r""" + Return a matrix whose (`i` , `j`) entry gives the effective resistance + between vertices `i` and `j`. + + The resistance distance between vertices `i` and `j` of a simple + connected graph `G` is defined as the effective resistance between the + two vertices on an electrical network constructed from `G` replacing + each edge of the graph by a unit (1 ohm) resistor. + + INPUT: + + - ``nonedgesonly`` -- boolean (default: ``True``); if ``True`` assign + zero resistance to pairs of adjacent vertices. + + - ``vertices`` -- list (default: ``None``); the ordering of the + vertices defining how they should appear in the matrix. By default, + the ordering given by :meth:`GenericGraph.vertices` is used. + + OUTPUT: matrix + + EXAMPLES: + + The effective resitance matrix for a straight linear 2-tree counting + only non-adjacent vertex pairs :: + + sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) + sage: G.effective_resistance_matrix() + [ 0 0 0 49/55 59/55 15/11] + [ 0 0 0 0 9/11 59/55] + [ 0 0 0 0 0 49/55] + [49/55 0 0 0 0 0] + [59/55 9/11 0 0 0 0] + [15/11 59/55 49/55 0 0 0] + + The same effective resistance matrix, this time including adjacent + vertices :: + + sage: G.effective_resistance_matrix(nonedgesonly=False) + [ 0 34/55 34/55 49/55 59/55 15/11] + [34/55 0 26/55 31/55 9/11 59/55] + [34/55 26/55 0 5/11 31/55 49/55] + [49/55 31/55 5/11 0 26/55 34/55] + [59/55 9/11 31/55 26/55 0 34/55] + [15/11 59/55 49/55 34/55 34/55 0] + + This example illustrates the common neighbors matrix for a fan on 6 + vertices counting only non-adjacent vertex pairs :: + + sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) + sage: H.effective_resistance_matrix() + [ 0 0 0 0 0 0 0] + [ 0 0 0 49/55 56/55 6/5 89/55] + [ 0 0 0 0 4/5 56/55 81/55] + [ 0 49/55 0 0 0 49/55 16/11] + [ 0 56/55 4/5 0 0 0 81/55] + [ 0 6/5 56/55 49/55 0 0 89/55] + [ 0 89/55 81/55 16/11 81/55 89/55 0] + + .. SEEALSO:: + + * :meth:`least_effective_resistance` -- + gives node pairs with least effective resistances + + * :meth:`effective_resistance` -- + computes effective resistance for a single node pair + + * See :wikipedia:`Resistance_Distance` for more details. + + TESTS:: + + sage: graphs.CompleteGraph(4).effective_resistance_matrix() + [0 0 0 0] + [0 0 0 0] + [0 0 0 0] + [0 0 0 0] + + sage: G = Graph(multiedges=True, sparse=True) + sage: G.add_edges([(0, 1)] * 3) + sage: G.effective_resistance_matrix() + Traceback (most recent call last): + ... + ValueError: This method is not known to work on graphs with + multiedges. Perhaps this method can be updated to handle them, but + in the meantime if you want to use it please disallow multiedges + using allow_multiple_edges(). + + sage: graphs.CompleteGraph(4).effective_resistance_matrix(nonedgesonly=False) + [ 0 1/2 1/2 1/2] + [1/2 0 1/2 1/2] + [1/2 1/2 0 1/2] + [1/2 1/2 1/2 0] + sage: Graph(1).effective_resistance_matrix() + [0] + sage: Graph().effective_resistance_matrix() + Traceback (most recent call last): + ... + ValueError: unable to compute effective resistance for an empty Graph object + sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) + sage: G.effective_resistance_matrix() + [0 0 0 0] + [0 0 0 1] + [0 0 0 0] + [0 1 0 0] + sage: G = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(1,2),(2,3),(3,4),(4,5),(5,1)]) + sage: r = G.effective_resistance_matrix(nonedgesonly=False)[0,3] + sage: r == fibonacci(2*(5-3)+1)*fibonacci(2*3-1)/fibonacci(2*5) + True + """ + from sage.matrix.constructor import matrix + from sage.rings.rational_field import QQ + + n = self.order() + if not n: + raise ValueError('unable to compute effective resistance for an empty Graph object') + if vertices is None: + vertices = self.vertices() + self._scream_if_not_simple() + if not self.is_connected(): + raise ValueError('the Graph is not a connected graph') + + L = self.laplacian_matrix(vertices=vertices) + M = L.pseudoinverse() + d = matrix(M.diagonal()).transpose() + onesvec = matrix(QQ, n, 1, lambda i, j: 1) + S = d * onesvec.transpose() + onesvec * d.transpose() - 2 * M + onesmat = matrix(QQ, n, n, lambda i, j: 1) + if nonedgesonly: + B = onesmat - self.adjacency_matrix(vertices=vertices) - matrix.identity(n) + S = S.elementwise_product(B) + + return S + + @doc_index("Leftovers") + def least_effective_resistance(self, nonedgesonly=True): + r""" + Return a list of pairs of nodes with the least effective resistance. + + The resistance distance between vertices `i` and `j` of a simple + connected graph `G` is defined as the effective resistance between the + two vertices on an electrical network constructed from `G` replacing + each edge of the graph by a unit (1 ohm) resistor. + + INPUT: + + - ``nonedgesonly`` -- Boolean (default: `True`); if true, assign zero + resistance to pairs of adjacent vertices + + OUTPUT: list + + EXAMPLES: + + Pairs of non-adjacent nodes with least effective resitance in a + straight linear 2-tree on 6 vertices:: + + sage: G = Graph([(0,1),(0,2),(1,2),(1,3),(3,5),(2,4),(2,3),(3,4),(4,5)]) + sage: G.least_effective_resistance() + [(1, 4)] + + Pairs of (adjacent or non-adjacent) nodes with least effective + resitance in a straight linear 2-tree on 6 vertices :: + + sage: G.least_effective_resistance(nonedgesonly = False) + [(2, 3)] + + Pairs of non-adjacent nodes with least effective resitance in a fan on + 6 vertices counting only non-adjacent vertex pairs :: + + sage: H = Graph([(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(1,2),(2,3),(3,4),(4,5)]) + sage: H.least_effective_resistance() + [(2, 4)] + + .. SEEALSO:: + + * :meth:`effective_resistance_matrix` -- + a similar method giving a matrix full of all effective + resistances + + * :meth:`effective_resistance` -- + compuetes effective resistance for a single node pair + + * See :wikipedia:`Resistance_distance` for more details. + + + TESTS:: + + sage: graphs.CompleteGraph(4).least_effective_resistance() + [] + sage: graphs.CompleteGraph(4).least_effective_resistance(nonedgesonly=False) + [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] + sage: Graph(1).least_effective_resistance() + [] + sage: G = Graph([(0,1),(1,2),(2,3),(3,0),(0,2)]) + sage: G.least_effective_resistance() + [(1, 3)] + """ + n = self.order() + if not n: + raise ValueError('unable to compute least resistance on empty Graph') + self._scream_if_not_simple() + if not self.is_connected(): + raise ValueError('the Graph is not a connected graph') + if nonedgesonly and self.is_clique(): + return [] + verts = list(self) + verttoidx = {u: i for i, u in enumerate(verts)} + S = self.effective_resistance_matrix(vertices=verts, nonedgesonly=nonedgesonly) + if nonedgesonly: + edges = self.complement().edges(labels=False) + else: + edges = [(verts[i], verts[j]) for i in range(n) for j in range(i + 1, n)] + + rmin = min(S[(verttoidx[e[0]], verttoidx[e[1]])] for e in edges) + return [e for e in edges if S[(verttoidx[e[0]], verttoidx[e[1]])] == rmin] + # Aliases to functions defined in other modules from sage.graphs.weakly_chordal import is_long_hole_free, is_long_antihole_free, is_weakly_chordal from sage.graphs.asteroidal_triples import is_asteroidal_triple_free diff --git a/src/sage/graphs/graph_coloring.py b/src/sage/graphs/graph_coloring.py index 87bd38d66a7..29a437aa84a 100644 --- a/src/sage/graphs/graph_coloring.py +++ b/src/sage/graphs/graph_coloring.py @@ -158,9 +158,9 @@ def all_graph_colorings(G, n, count_only=False, hex_colors=False, vertex_color_d {0: 0, 1: 1, 2: 0} {0: 1, 1: 0, 2: 1} sage: for c in all_graph_colorings(G, 2, hex_colors=True): - ....: print(c) - {'#00ffff': [1], '#ff0000': [0, 2]} - {'#ff0000': [1], '#00ffff': [0, 2]} + ....: print(sorted(c.items())) + [('#00ffff', [1]), ('#ff0000', [0, 2])] + [('#00ffff', [0, 2]), ('#ff0000', [1])] sage: for c in all_graph_colorings(G, 2, hex_colors=True, vertex_color_dict=True): ....: print(c) {0: '#ff0000', 1: '#00ffff', 2: '#ff0000'} @@ -270,8 +270,8 @@ def first_coloring(G, n=0, hex_colors=False): sage: from sage.graphs.graph_coloring import first_coloring sage: G = Graph({0: [1, 2, 3], 1: [2]}) - sage: first_coloring(G, 3) - [[1, 3], [0], [2]] + sage: sorted(first_coloring(G, 3)) + [[0], [1, 3], [2]] """ G._scream_if_not_simple(allow_multiple_edges=True) o = G.order() @@ -1524,11 +1524,39 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, solver=Non sage: d = acyclic_edge_coloring(g, hex_colors=True) sage: sorted(d) ['#0066ff', '#00ff66', '#cbff00', '#cc00ff', '#ff0000'] + + The acyclic chromatic index of a graph without edge is 0 (:trac:`27079`):: + + sage: from sage.graphs.graph_coloring import acyclic_edge_coloring + sage: g = Graph(3) + sage: acyclic_edge_coloring(g, k=None, value_only=True) + 0 + sage: acyclic_edge_coloring(g, k=None, hex_colors=True) + {} + sage: acyclic_edge_coloring(g, k=None, hex_colors=False) + [] + + Empty graph (:trac:`27079`):: + + sage: from sage.graphs.graph_coloring import acyclic_edge_coloring + sage: acyclic_edge_coloring(Graph(), k=None, value_only=True) + 0 """ g._scream_if_not_simple(allow_multiple_edges=True) from sage.rings.integer import Integer from sage.combinat.subset import Subsets + from sage.plot.colors import rainbow + + if not g.order() or not g.size(): + if k == 0: + k = 2 + if value_only: + return 0 if k is None else k + else: + if k is None: + return {} if hex_colors else [] + return {c: [] for c in rainbow(k)} if hex_colors else [copy(g) for _ in range(k)] if k is None: k = max(g.degree()) @@ -1549,8 +1577,6 @@ def acyclic_edge_coloring(g, hex_colors=False, value_only=False, k=0, solver=Non elif not k: k = max(g.degree()) + 2 - from sage.plot.colors import rainbow - p = MixedIntegerLinearProgram(solver=solver) # c is a binary variable such that c[i,(u,v)] = 1 if and only if (u,v) is @@ -1594,7 +1620,10 @@ def E(x, y): except MIPSolverException: if k == max(g.degree()) + 2: - raise RuntimeError("It looks like you have found a counterexample to a very old conjecture. Please do not loose it ! Please publish it, and send a post to sage-devel to warn us. We implore you!") + raise RuntimeError("It looks like you have found a counterexample to " + "a very old conjecture. Please do not loose it ! " + "Please publish it, and send a post to sage-devel " + "to warn us. We implore you!") else: raise ValueError("this graph can not be colored with the given number of colors") diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index 1607bb7266b..2261db3c434 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -920,21 +920,6 @@ def _gen_interact_func(self, display, **kwds): This is a helper method for the ``interactive_query`` method and should not be called directly. - - EXAMPLES:: - - sage: D = GraphDatabase() - sage: D.interactive_query(display_cols=['graph6', 'num_vertices', 'degree_sequence'], num_edges=['<=', 5], max_degree=3) - ... - - :: - - sage: G = GraphDatabase() - sage: f = G._gen_interact_func(display=['graph6'], num_vertices=3) - sage: type(f) - <... 'function'> - sage: interact(f) - ... """ from sagenb.notebook.interact import input_grid arg = ['%s=%s'%(word, kwds[word]) for word in kwds] diff --git a/src/sage/graphs/graph_decompositions/bandwidth.pyx b/src/sage/graphs/graph_decompositions/bandwidth.pyx index d8a86d90136..20a1339ec5a 100644 --- a/src/sage/graphs/graph_decompositions/bandwidth.pyx +++ b/src/sage/graphs/graph_decompositions/bandwidth.pyx @@ -95,13 +95,13 @@ This module contains the following methods :delim: | :meth:`bandwidth` | Compute the bandwidth of an undirected graph - :meth:`~sage.graphs.base.boost_graph.bandwidth_heuristics` | Uses Boost heuristics to approximate the bandwidth of the input graph + :meth:`~sage.graphs.base.boost_graph.bandwidth_heuristics` | Use Boost heuristics to approximate the bandwidth of the input graph Functions --------- """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Nathann Cohen # # This program is free software: you can redistribute it and/or modify @@ -109,7 +109,7 @@ Functions # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from libc.stdint cimport uint16_t from cysignals.signals cimport sig_check @@ -133,10 +133,10 @@ def bandwidth(G, k=None): INPUT: - - ``G`` (a graph) + - ``G`` -- a graph - - ``k`` -- set to an integer value to test whether `bw(G)\leq k`, or to - ``None`` (default) to compute `bw(G)`. + - ``k`` -- integer (default: ``None``); set to an integer value to test + whether `bw(G)\leq k`, or to ``None`` (default) to compute `bw(G)` OUTPUT: @@ -203,20 +203,19 @@ def bandwidth(G, k=None): sage: bandwidth(digraphs.Circuit(5)) Traceback (most recent call last): ... - ValueError: This method only works on undirected graphs + ValueError: this method only works on undirected graphs sage: bandwidth(Graph(graphs.PetersenGraph(), weighted=True)) Traceback (most recent call last): ... - ValueError: This method only works on unweighted graphs + ValueError: this method only works on unweighted graphs """ if G.is_directed(): - raise ValueError("This method only works on undirected graphs") + raise ValueError("this method only works on undirected graphs") if G.weighted(): - raise ValueError("This method only works on unweighted graphs") + raise ValueError("this method only works on unweighted graphs") # Trivial cases if G.order() <= 1: - from sage.matrix.constructor import Matrix if k is None: return 0, list(G) else: @@ -226,7 +225,7 @@ def bandwidth(G, k=None): max_k = 0 if k is None else k order = [] for GG in G.connected_components_subgraphs(): - ans = bandwidth(GG,k=k) + ans = bandwidth(GG, k=k) if not ans: return False if k is None: @@ -244,39 +243,39 @@ def bandwidth(G, k=None): cdef MemoryAllocator mem = MemoryAllocator() - cdef unsigned short ** d = mem.allocarray(n, sizeof(unsigned short *)) - cdef unsigned short * distances = mem.allocarray(n*n, sizeof(unsigned short )) - cdef index_t * current = mem.allocarray(n, sizeof(index_t)) - cdef index_t * ordering = mem.allocarray(n, sizeof(index_t)) - cdef index_t * left_to_order = mem.allocarray(n, sizeof(index_t)) - cdef index_t * index_array_tmp = mem.allocarray(n, sizeof(index_t)) - cdef range_t * range_arrays = mem.allocarray(n*n, sizeof(range_t)) - cdef range_t ** ith_range_array = mem.allocarray(n, sizeof(range_t *)) - cdef range_t * range_array_tmp = mem.allocarray(n, sizeof(range_t)) - - cdef int i,j,kk + cdef unsigned short ** d = mem.allocarray(n, sizeof(unsigned short *)) + cdef unsigned short * distances = mem.allocarray(n*n, sizeof(unsigned short)) + cdef index_t * current = mem.allocarray(n, sizeof(index_t)) + cdef index_t * ordering = mem.allocarray(n, sizeof(index_t)) + cdef index_t * left_to_order = mem.allocarray(n, sizeof(index_t)) + cdef index_t * index_array_tmp = mem.allocarray(n, sizeof(index_t)) + cdef range_t * range_arrays = mem.allocarray(n*n, sizeof(range_t)) + cdef range_t ** ith_range_array = mem.allocarray(n, sizeof(range_t *)) + cdef range_t * range_array_tmp = mem.allocarray(n, sizeof(range_t)) + + cdef int i, j, kk # compute the distance matrix all_pairs_shortest_path_BFS(G, NULL, distances, NULL, vertex_list=int_to_vertex) # fill d so that d[i][j] works for i in range(n): - d[i] = distances + i*n + d[i] = distances + i * n # ith_range_array for i in range(n): - ith_range_array[i] = range_arrays + i*n + ith_range_array[i] = range_arrays + i * n # initialize left_to_order for i in range(n): left_to_order[i] = i if k is None: - for kk in range((n-1)//G.diameter(),n): - if bandwidth_C(n,kk,d,current,ordering,left_to_order,index_array_tmp,ith_range_array,range_array_tmp): + for kk in range((n - 1) // G.diameter(), n): + if bandwidth_C(n, kk, d, current, ordering, left_to_order, index_array_tmp, ith_range_array, range_array_tmp): ans = True break else: - ans = bool(bandwidth_C(n,k,d,current,ordering,left_to_order,index_array_tmp,ith_range_array,range_array_tmp)) + ans = bool(bandwidth_C(n, k, d, current, ordering, left_to_order, index_array_tmp, ith_range_array, range_array_tmp)) if ans: order = [int_to_vertex[ordering[i]] for i in range(n)] @@ -289,30 +288,30 @@ def bandwidth(G, k=None): cdef bint bandwidth_C(int n, int k, unsigned short ** d, - index_t * current, # choice of vertex for the current position - index_t * ordering, # the actual ordering of vertices - index_t * left_to_order, # begins with the assigned vertices, ends with the others - index_t * index_array_tmp, # tmp space - range_t ** ith_range_array, # array of ranges, for every step of the algorithm - range_t * range_array_tmp):# tmp space - - cdef int i,v - cdef int pi # the position for which a vertex is being chosen - cdef int vi # the vertex being tested at position pi + index_t * current, # choice of vertex for the current position + index_t * ordering, # the actual ordering of vertices + index_t * left_to_order, # begins with the assigned vertices, ends with the others + index_t * index_array_tmp, # tmp space + range_t ** ith_range_array, # array of ranges, for every step of the algorithm + range_t * range_array_tmp): # tmp space + + cdef int i, v + cdef int pi # the position for which a vertex is being chosen + cdef int vi # the vertex being tested at position pi cdef int radius current[0] = -1 # At first any vertex can be anywhere for v in range(n): ith_range_array[0][v].m = 0 - ith_range_array[0][v].M = n-1 + ith_range_array[0][v].M = n - 1 i = 0 while True: sig_check() # There are (n-i) choices for vertex i, as i-1 have already been - # determined. Thus, i<=current[i]= |p_v-p_{vi}| (see module documentation) for v in range(n): - radius = k*d[v][vi] - ith_range_array[i+1][v].m = max( ith_range_array[i][v].m,pi-radius) - ith_range_array[i+1][v].M = min( ith_range_array[i][v].M,pi+radius) + radius = k * d[v][vi] + ith_range_array[i + 1][v].m = max( ith_range_array[i][v].m, pi - radius) + ith_range_array[i + 1][v].M = min( ith_range_array[i][v].M, pi + radius) # Check the feasibility of a matching with the updated intervals of # admissible positions (see module doc). # # If it is possible we explore deeper, otherwise we undo the changes as # pi is not a good position for vi after all. - if is_matching_feasible(n,ith_range_array[i+1],range_array_tmp, index_array_tmp): + if is_matching_feasible(n, ith_range_array[i + 1], range_array_tmp, index_array_tmp): i += 1 - current[i] = i-1 + current[i] = i - 1 else: # swap back left_to_order[i], left_to_order[current[i]] = left_to_order[current[i]], left_to_order[i] @@ -373,16 +372,16 @@ cdef bint is_matching_feasible(int n, range_t * range_array, range_t * range_arr INPUT: - - ``n`` (integer) -- number of points + - ``n`` -- integer; number of points - ``range_array`` -- associates to every point an interval in which the - point must be given a position. + point must be given a position - ``range_array_tmp`` -- temporary spaces with the same characteristics as ``range_array`` - ``index_array_tmp`` -- temporary space to associate an integer to every - point. + point OUTPUT: @@ -390,10 +389,10 @@ cdef bint is_matching_feasible(int n, range_t * range_array, range_t * range_arr ``range_array``. """ # Heuristic: check if some vertex has an empty range, that's an easy 'no'. - cdef int v,M,m,j + cdef int v, M, m, j for v in range(n): if range_array[v].M < range_array[v].m: - #print range_array[v].m, range_array[v].M + # print range_array[v].m, range_array[v].M return 0 index_array_tmp[v] = 0 @@ -404,8 +403,8 @@ cdef bint is_matching_feasible(int n, range_t * range_array, range_t * range_arr index_array_tmp[range_array[v].M] += 1 # Step 2: sorted table - for v in range(1,n): - index_array_tmp[v] += index_array_tmp[v-1] + for v in range(1, n): + index_array_tmp[v] += index_array_tmp[v - 1] for v in range(n): M = range_array[v].M @@ -421,8 +420,8 @@ cdef bint is_matching_feasible(int n, range_t * range_array, range_t * range_arr for v in range(n): sig_check() - for j in range(range_array_tmp[v].m, range_array_tmp[v].M+1): - if not index_array_tmp[j]: + for j in range(range_array_tmp[v].m, range_array_tmp[v].M + 1): + if index_array_tmp[j] == 0: index_array_tmp[j] = 1 break else: diff --git a/src/sage/graphs/graph_decompositions/cutwidth.pyx b/src/sage/graphs/graph_decompositions/cutwidth.pyx index 7ca9c0cd8ab..fce1bd4c7c8 100644 --- a/src/sage/graphs/graph_decompositions/cutwidth.pyx +++ b/src/sage/graphs/graph_decompositions/cutwidth.pyx @@ -185,7 +185,7 @@ from sage.rings.integer_ring import ZZ def width_of_cut_decomposition(G, L): r""" - Returns the width of the cut decomposition induced by the linear ordering + Return the width of the cut decomposition induced by the linear ordering `L` of the vertices of `G`. If `G` is an instance of :mod:`Graph `, this function @@ -231,27 +231,28 @@ def width_of_cut_decomposition(G, L): sage: cutwidth.width_of_cut_decomposition(Graph(), ['a','b']) Traceback (most recent call last): ... - ValueError: The input linear vertex ordering L is not valid for G. + ValueError: the input linear vertex ordering L is not valid for G """ if not is_valid_ordering(G, L): - raise ValueError("The input linear vertex ordering L is not valid for G.") - elif G.order()<=1: + raise ValueError("the input linear vertex ordering L is not valid for G") + elif G.order() <= 1: return 0 - position = {u:i for i,u in enumerate(L)} + cdef int i, x, y + cdef dict position = {u: i for i,u in enumerate(L)} # We count for each position `i` the number of edges going from vertices at # positions in `0..i` to vertices at positions in `i+1..n-1`, for each # `x\leq iy: - x,y = y,x + cdef list cpt = [0] * G.order() + for u, v in G.edge_iterator(labels=None): + x, y = position[u], position[v] + if x > y: + x, y = y, x # Edge (u,v) contributes 1 to the number of edges going from vertices at # positions `0..i` to vertices at positions `i+1..n-1` for each `x\leq - # i` of the class :class:`MixedIntegerLinearProgram`. - - ``verbose`` (boolean) -- whether to display information on the - computations. + - ``verbose`` -- booleant (default: ``False``); whether to display + information on the computations. OUTPUT: @@ -334,7 +335,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False): ....: ve, le = cutwidth(G, algorithm="exponential") ....: vm, lm = cutwidth(G, algorithm="MILP", solver='GLPK') ....: if ve != vm: - ....: print("Something goes wrong!") + ....: raise ValueError("Something goes wrong!") Given a wrong algorithm:: @@ -342,7 +343,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False): sage: cutwidth(graphs.PathGraph(2), algorithm="SuperFast") Traceback (most recent call last): ... - ValueError: Algorithm "SuperFast" has not been implemented yet. Please contribute. + ValueError: algorithm "SuperFast" has not been implemented yet, please contribute Given anything else than a Graph:: @@ -350,7 +351,7 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False): sage: cutwidth(range(4)) Traceback (most recent call last): ... - ValueError: The parameter must be a Graph. + ValueError: the first parameter must be a Graph Giving a wrong type cut off:: @@ -358,53 +359,57 @@ def cutwidth(G, algorithm="exponential", cut_off=0, solver=None, verbose=False): sage: cutwidth(Graph(), cut_off='toto') Traceback (most recent call last): ... - ValueError: The specified cut off parameter must be an integer. + ValueError: the specified cut off parameter must be an integer """ from sage.graphs.graph import Graph if not isinstance(G, Graph): - raise ValueError('The parameter must be a Graph.') + raise ValueError('the first parameter must be a Graph') if not cut_off in ZZ: - raise ValueError("The specified cut off parameter must be an integer.") + raise ValueError("the specified cut off parameter must be an integer") elif G.size() <= cut_off: # We have a trivial solution - return width_of_cut_decomposition(G, G.vertices()), G.vertices() + return width_of_cut_decomposition(G, list(G)), list(G) + cdef list CC if not G.is_connected(): - # The graph has several connected components. We solve the problem on - # each of them and concatenate the partial orderings. The cutwidth is - # the maximum over all these subgraphs. - cw, L = 0, [] - for V in G.connected_components(): - - # We build the connected subgraph - H = G.subgraph(V) - if H.size() <= max(cw, cut_off): - # We can directly add these vertices to the solution - L.extend(V) + CC = G.connected_components_subgraphs() + else: + CC = [G] - else: - # We do a recursive call on H - cwH,LH = cutwidth(H, algorithm = algorithm, - cut_off = max(cut_off,cw), - solver = solver, verbose = verbose) + # If the graph has several connected components. We solve the problem on + # each of them and concatenate the partial orderings. The cutwidth is the + # maximum over all these subgraphs. + cdef int cw = 0 + cdef list L = [] + cdef int cwH + cdef list LH + cdef int this_cut_off = cut_off - # We update the cutwidth and ordering - cw = max(cw, cwH) - L.extend(LH) + for H in CC: - return cw, L + if H.size() <= this_cut_off: + # We can directly add the vertices to the solution + L.extend(H) - # We have a connected graph and we call the desired algorithm - if algorithm == "exponential": - return cutwidth_dyn(G, lower_bound=cut_off) + else: + # We have a connected graph and we call the desired algorithm + if algorithm == "exponential": + cwH, LH = cutwidth_dyn(G, lower_bound=this_cut_off) - elif algorithm == "MILP": - return cutwidth_MILP(G, lower_bound=cut_off, solver=solver, verbose=verbose) + elif algorithm == "MILP": + cwH, LH = cutwidth_MILP(G, lower_bound=this_cut_off, solver=solver, verbose=verbose) - else: - raise ValueError('Algorithm "{}" has not been implemented yet. Please contribute.'.format(algorithm)) + else: + raise ValueError('algorithm "{}" has not been implemented yet, please contribute'.format(algorithm)) + + # We update the cutwidth and ordering + cw = max(cw, cwH) + L.extend(LH) + this_cut_off = max(cw, this_cut_off) + + return cw, L ################################################################################ @@ -425,9 +430,9 @@ def cutwidth_dyn(G, lower_bound=0): - ``G`` -- a Graph - - ``lower_bound`` -- (default: 0) the algorithm returns immediately if it - finds a solution lower or equal to ``lower_bound`` (in which case it may - not be optimal). + - ``lower_bound`` -- integer (default: 0); the algorithm returns immediately + if it finds a solution lower or equal to ``lower_bound`` (in which case it + may not be optimal). OUTPUT: @@ -448,7 +453,7 @@ def cutwidth_dyn(G, lower_bound=0): sage: cutwidth.cutwidth_dyn([]) Traceback (most recent call last): ... - ValueError: The parameter must be a Graph. + ValueError: the parameter must be a Graph Giving a too large Graph:: @@ -456,7 +461,7 @@ def cutwidth_dyn(G, lower_bound=0): sage: cutwidth.cutwidth_dyn(graphs.PathGraph(40)) Traceback (most recent call last): ... - ValueError: The graph should have at most 31 vertices ! + ValueError: the graph should have at most 31 vertices Giving a wrong type lower bound:: @@ -464,27 +469,28 @@ def cutwidth_dyn(G, lower_bound=0): sage: cutwidth.cutwidth_dyn(Graph(), lower_bound='toto') Traceback (most recent call last): ... - ValueError: The specified lower bound must be an integer. + ValueError: the specified lower bound must be an integer """ from sage.graphs.graph import Graph if not isinstance(G, Graph): - raise ValueError("The parameter must be a Graph.") + raise ValueError("the parameter must be a Graph") if G.order() >= 32: - raise ValueError("The graph should have at most 31 vertices !") + raise ValueError("the graph should have at most 31 vertices") if not lower_bound in ZZ: - raise ValueError("The specified lower bound must be an integer.") + raise ValueError("the specified lower bound must be an integer") cdef FastDigraph g = FastDigraph(G) cdef unsigned int mem = 1 << g.n - cdef uint8_t * neighborhoods = check_allocarray(mem, sizeof(uint8_t)) + cdef uint8_t* neighborhoods = check_allocarray(mem, sizeof(uint8_t)) memset(neighborhoods, -1, mem) cdef int i, k + cdef list order try: for k in range(lower_bound, G.size()): @@ -499,8 +505,8 @@ def cutwidth_dyn(G, lower_bound=0): order = find_order(g, neighborhoods, k) return k, [g.int_to_vertices[i] for i in order] -cdef inline int exists(FastDigraph g, uint8_t * neighborhoods, int S, int cost_S, int v, int k): - """ +cdef inline int exists(FastDigraph g, uint8_t* neighborhoods, int S, int cost_S, int v, int k): + r""" Check whether an ordering with the given cost `k` exists, and updates data in the neighborhoods array at the same time. See the module's documentation. @@ -508,34 +514,34 @@ cdef inline int exists(FastDigraph g, uint8_t * neighborhoods, int S, int cost_S - ``g`` -- a FastDiGraph - - ``neighborhoods`` -- an array of size `2^(g.n)` storing for each subset + - ``neighborhoods`` -- an array of size `2^(g.n)`; stores for each subset `X\subseteq V` of vertices of the graph the number of edges from `X` to - `V\setminus X`. + `V\setminus X` - - ``S`` -- an integer encoding the predecessor subset of vertices (from - which is issued the current call). + - ``S`` -- integer; encodes the predecessor subset of vertices (from which + is issued the current call) - - ``cost_S`` -- the number of edges from `S` to `V\setminus S`. + - ``cost_S`` -- integer; the number of edges from `S` to `V\setminus S` - - ``v`` -- a vertex such that the current subset of vertices is - `current==S\cup\{v\}`. + - ``v`` -- integer; a vertex such that the current subset of vertices is + `current==S\cup\{v\}` - - ``k`` -- the maximum admissible cost for a solution. + - ``k`` -- integer; the maximum admissible cost for a solution """ cdef int current = S | 1<-1: + if neighborhoods[current] == -1: # The number of edges from `current` to `V\setminus current` is the # number of edges from `S` to `V\setminus S`, minus the number of edges # from `S` to vertex `v`, plus the number of edges from `v` to # `V\setminus (S\cup \{v\})`. This can be computed adding the degree of # `c` to `cost_S`, and then removing twice the number of edges from `S` # to `v`. - neighborhoods[current] = cost_S + g.degree[v] - 2*popcount32(S&g.graph[v]) + neighborhoods[current] = cost_S + g.degree[v] - 2 * popcount32(S & g.graph[v]) # If the cost of this set is too high, there is no point in going further. # Same thing if the current set is the whole vertex set. - if neighborhoods[current] > k or (current == (1< k or (current == (1 << g.n) - 1): return neighborhoods[current] # Minimum of the costs of the outneighbors, initialized with large constant. @@ -547,7 +553,7 @@ cdef inline int exists(FastDigraph g, uint8_t * neighborhoods, int S, int cost_S # For each possible extension of the current set witha vertex, check whether # there exists a cheap path toward {1..n}, and update the cost. for i in range(g.n): - if (current >> i)&1: # if i in S + if (current >> i) & 1: # if i in S continue mini = min(mini, exists(g, neighborhoods, current, neighborhoods[current], i, k)) @@ -579,20 +585,20 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0): - ``G`` -- a Graph - - ``lower_bound`` -- (default: 0) the algorithm searches for a solution with - cost larger or equal to ``lower_bound``. If the given bound is larger than - the optimal solution the returned solution might not be optimal. If the - given bound is too high, the algorithm might not be able to find a - feasible solution. + - ``lower_bound`` -- integer (default: 0); the algorithm searches for a + solution with cost larger or equal to ``lower_bound``. If the given bound + is larger than the optimal solution the returned solution might not be + optimal. If the given bound is too high, the algorithm might not be able + to find a feasible solution. - - ``solver`` -- (default: ``None``) Specify a Linear Program (LP) solver to - be used. If set to ``None``, the default one is used. For more information - on LP solvers and which default solver is used, see the method + - ``solver`` -- string (default: ``None``); specify a Linear Program (LP) + solver to be used. If set to ``None``, the default one is used. For more + information on LP solvers and which default solver is used, see the method :meth:`solve` of the class :class:`MixedIntegerLinearProgram`. - - ``verbose`` -- integer (default: ``0``). Sets the level of verbosity. Set + - ``verbose`` -- integer (default: ``0``); sets the level of verbosity. Set to 0 by default, which means quiet. OUTPUT: @@ -658,11 +664,11 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0): sage: cutwidth_MILP([]) Traceback (most recent call last): ... - ValueError: The first input parameter must be a Graph. + ValueError: the first input parameter must be a Graph """ from sage.graphs.graph import Graph if not isinstance(G, Graph): - raise ValueError("The first input parameter must be a Graph.") + raise ValueError("the first input parameter must be a Graph") from sage.numerical.mip import MixedIntegerLinearProgram p = MixedIntegerLinearProgram(maximization=False, solver=solver) @@ -673,43 +679,42 @@ def cutwidth_MILP(G, lower_bound=0, solver=None, verbose=0): z = p.new_variable(integer=True, nonnegative=True) N = G.order() - V = G.vertices() # All vertices at different positions - for v in V: - for k in range(N-1): - p.add_constraint( p.sum( x[v,i] for i in range(k) ) <= k*x[v,k] ) - p.add_constraint( x[v,N-1] == 1 ) + for v in G: + for k in range(N - 1): + p.add_constraint(p.sum(x[v,i] for i in range(k)) <= k * x[v,k]) + p.add_constraint(x[v,N-1] == 1) for k in range(N): - p.add_constraint( p.sum( x[v,k] for v in V ) == k+1 ) + p.add_constraint(p.sum(x[v,k] for v in G) == k + 1) # Edge uv counts at position i if one of u or v is placed at a position in # [0,i] and the other is placed at a position in [i+1,n]. for u,v in G.edge_iterator(labels=None): for i in range(N): - p.add_constraint( x[u,i] - x[v,i] <= y[u,v,i] ) - p.add_constraint( x[v,i] - x[u,i] <= y[u,v,i] ) + p.add_constraint(x[u,i] - x[v,i] <= y[u,v,i]) + p.add_constraint(x[v,i] - x[u,i] <= y[u,v,i]) # Lower bound on the solution - p.add_constraint( lower_bound <= z['z'] ) + p.add_constraint(lower_bound <= z['z']) # Objective - p.add_constraint( z['z'] <= G.size() ) + p.add_constraint(z['z'] <= G.size()) for i in range(N): - p.add_constraint( p.sum( y[u,v,i] for u,v in G.edge_iterator(labels=None) ) <= z['z'] ) + p.add_constraint(p.sum(y[u,v,i] for u,v in G.edge_iterator(labels=None)) <= z['z']) - p.set_objective( z['z'] ) + p.set_objective(z['z']) - obj = p.solve( log=verbose ) + obj = p.solve(log=verbose) # We now extract the ordering and the cost of the solution - cw = int( p.get_values(z)['z'] ) - val_x = p.get_values( x ) - seq = [] - to_see = set(V) + val_x = p.get_values(x) + cdef int cw = int(p.get_values(z)['z']) + cdef list seq = [] + cdef set to_see = set(G) for k in range(N): for u in to_see: - if val_x[u,k] > 0: + if val_x[u,k]: seq.append(u) to_see.discard(u) break diff --git a/src/sage/graphs/graph_decompositions/vertex_separation.pyx b/src/sage/graphs/graph_decompositions/vertex_separation.pyx index 5bdd26c0528..8a2714a7483 100644 --- a/src/sage/graphs/graph_decompositions/vertex_separation.pyx +++ b/src/sage/graphs/graph_decompositions/vertex_separation.pyx @@ -39,15 +39,15 @@ This is a result of Kinnersley [Kin92]_ and Bodlaender [Bod98]_. :widths: 30, 70 :delim: | - :meth:`pathwidth` | Computes the pathwidth of ``self`` (and provides a decomposition) - :meth:`path_decomposition` | Returns the pathwidth of the given graph and the ordering of the vertices resulting in a corresponding path decomposition - :meth:`vertex_separation` | Returns an optimal ordering of the vertices and its cost for vertex-separation - :meth:`vertex_separation_exp` | Computes the vertex separation of `G` using an exponential time and space algorithm - :meth:`vertex_separation_MILP` | Computes the vertex separation of `G` and the optimal ordering of its vertices using an MILP formulation - :meth:`vertex_separation_BAB` | Computes the vertex separation of `G` and the optimal ordering of its vertices using a branch and bound algorithm - :meth:`lower_bound` | Returns a lower bound on the vertex separation of `G` + :meth:`pathwidth` | Compute the pathwidth of ``self`` (and provides a decomposition) + :meth:`path_decomposition` | Return the pathwidth of the given graph and the ordering of the vertices resulting in a corresponding path decomposition + :meth:`vertex_separation` | Return an optimal ordering of the vertices and its cost for vertex-separation + :meth:`vertex_separation_exp` | Compute the vertex separation of `G` using an exponential time and space algorithm + :meth:`vertex_separation_MILP` | Compute the vertex separation of `G` and the optimal ordering of its vertices using an MILP formulation + :meth:`vertex_separation_BAB` | Compute the vertex separation of `G` and the optimal ordering of its vertices using a branch and bound algorithm + :meth:`lower_bound` | Return a lower bound on the vertex separation of `G` :meth:`is_valid_ordering` | Test if the linear vertex ordering `L` is valid for (di)graph `G` - :meth:`width_of_path_decomposition` | Returns the width of the path decomposition induced by the linear ordering `L` of the vertices of `G` + :meth:`width_of_path_decomposition` | Return the width of the path decomposition induced by the linear ordering `L` of the vertices of `G` :meth:`linear_ordering_to_path_decomposition`| Return the path decomposition encoded in the ordering `L` @@ -199,8 +199,8 @@ L}_{P+v}(V)} c(L)` holds in two (non exhaustive) cases: v\in N^+(S)\text{ and }N^+(v)\setminus(S\cup N^+(S)) = \{w\} \end{cases} -In other words, if we find a vertex `v` satisfying the above conditions, the best -possible ordering with prefix `P` has the same cost as the best possible +In other words, if we find a vertex `v` satisfying the above conditions, the +best possible ordering with prefix `P` has the same cost as the best possible ordering with prefix `P+v`. So we can greedily extend the prefix with vertices satisfying the conditions which results in a significant reduction of the search space. @@ -272,7 +272,7 @@ Methods ------- """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Nathann Cohen # # This program is free software: you can redistribute it and/or modify @@ -280,7 +280,7 @@ Methods # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from __future__ import absolute_import, print_function @@ -300,7 +300,7 @@ from sage.graphs.base.static_dense_graph cimport dense_graph_init def lower_bound(G): r""" - Returns a lower bound on the vertex separation of `G` + Return a lower bound on the vertex separation of `G`. INPUT: @@ -333,7 +333,7 @@ def lower_bound(G): sage: lower_bound(range(2)) Traceback (most recent call last): ... - ValueError: The parameter must be a Graph or a DiGraph. + ValueError: the parameter must be a Graph or a DiGraph Given a too large graph:: @@ -341,33 +341,33 @@ def lower_bound(G): sage: lower_bound(graphs.PathGraph(50)) Traceback (most recent call last): ... - ValueError: The (di)graph can have at most 31 vertices. + ValueError: the (di)graph can have at most 31 vertices """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph if not isinstance(G, Graph) and not isinstance(G, DiGraph): - raise ValueError("The parameter must be a Graph or a DiGraph.") + raise ValueError("the parameter must be a Graph or a DiGraph") if G.order() >= 32: - raise ValueError("The (di)graph can have at most 31 vertices.") + raise ValueError("the (di)graph can have at most 31 vertices") cdef FastDigraph FD = FastDigraph(G) cdef int * g = FD.graph cdef int n = FD.n # minimums[i] is means to store the value of c'_{i+1} - minimums = check_malloc(n) + cdef uint8_t* minimums = check_malloc(n * sizeof(uint8_t)) cdef unsigned int i # They are initialized to n - for 0<= i< n: + for i in range(n): minimums[i] = n cdef uint8_t tmp, tmp_count # We go through all sets - for 1<= i< (1< (1 << n)): tmp_count = popcount32(i) tmp = compute_out_neighborhood_cardinality(FD, i) @@ -375,14 +375,14 @@ def lower_bound(G): minimums[tmp_count-1] = minimum(minimums[tmp_count-1], tmp) # We compute the maximum of all those values - for 1<= i< n: + for i in range(1, n): minimums[0] = maximum(minimums[0], minimums[i]) - cdef int min = minimums[0] + cdef int lb = minimums[0] sig_free(minimums) - return min + return lb ################################################################### # Method for turning an ordering to a path decomposition and back # @@ -404,7 +404,8 @@ def linear_ordering_to_path_decomposition(G, L): EXAMPLES: - The bags of an optimal path decomposition of a path-graph have two vertices each:: + The bags of an optimal path decomposition of a path-graph have two vertices + each:: sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation sage: from sage.graphs.graph_decompositions.vertex_separation import linear_ordering_to_path_decomposition @@ -412,10 +413,10 @@ def linear_ordering_to_path_decomposition(G, L): sage: pw, L = vertex_separation(g, algorithm = "BAB"); pw 1 sage: h = linear_ordering_to_path_decomposition(g, L) - sage: h.vertices() - [{0, 1}, {3, 4}, {2, 3}, {1, 2}] - sage: h.edges(labels=None) - [({0, 1}, {1, 2}), ({2, 3}, {3, 4}), ({1, 2}, {2, 3})] + sage: sorted(h, key=str) + [{0, 1}, {1, 2}, {2, 3}, {3, 4}] + sage: sorted(h.edge_iterator(labels=None), key=str) + [({0, 1}, {1, 2}), ({1, 2}, {2, 3}), ({2, 3}, {3, 4})] Giving a non-optimal linear ordering:: @@ -427,17 +428,17 @@ def linear_ordering_to_path_decomposition(G, L): sage: h = linear_ordering_to_path_decomposition(g, L) sage: h.vertices() [{0, 2, 3, 4}, {0, 1, 2}] - + The bags of the path decomposition of a cycle have three vertices each:: sage: g = graphs.CycleGraph(6) sage: pw, L = vertex_separation(g, algorithm = "BAB"); pw 2 sage: h = linear_ordering_to_path_decomposition(g, L) - sage: h.vertices() - [{1, 2, 5}, {2, 3, 4}, {0, 1, 5}, {2, 4, 5}] - sage: h.edges(labels=None) - [({1, 2, 5}, {2, 4, 5}), ({0, 1, 5}, {1, 2, 5}), ({2, 4, 5}, {2, 3, 4})] + sage: sorted(h, key=str) + [{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {2, 4, 5}] + sage: sorted(h.edge_iterator(labels=None), key=str) + [({0, 1, 5}, {1, 2, 5}), ({1, 2, 5}, {2, 4, 5}), ({2, 4, 5}, {2, 3, 4})] TESTS:: @@ -462,14 +463,14 @@ def linear_ordering_to_path_decomposition(G, L): if not is_valid_ordering(G, L): raise ValueError("the input linear vertex ordering L is not valid for G") - cdef set seen = set() # already treated vertices + cdef set seen = set() # already treated vertices cdef set covered = set() # vertices in the neighborhood of seen but not in seen - cdef list bags = list() # The bags of the path decomposition + cdef list bags = list() # The bags of the path decomposition # We build the bags of the path-decomposition, and avoid adding useless bags for u in L: seen.add(u) - covered.update(G.neighbors(u)) + covered.update(G.neighbor_iterator(u)) covered.difference_update(seen) new_bag = covered.union([u]) if bags: @@ -486,8 +487,6 @@ def linear_ordering_to_path_decomposition(G, L): H.add_path([Set(bag) for bag in bags]) return H - - ################################################################## # Front end methods for path decomposition and vertex separation # ################################################################## @@ -495,17 +494,19 @@ def linear_ordering_to_path_decomposition(G, L): def pathwidth(self, k=None, certificate=False, algorithm="BAB", verbose=False, max_prefix_length=20, max_prefix_number=10**6): """ - Computes the pathwidth of ``self`` (and provides a decomposition) + Compute the pathwidth of ``self`` (and provides a decomposition) INPUT: - - ``k`` (integer) -- the width to be considered. When ``k`` is an integer, - the method checks that the graph has pathwidth `\leq k`. If ``k`` is - ``None`` (default), the method computes the optimal pathwidth. + - ``k`` -- integer (default: ``None``); the width to be considered. When + ``k`` is an integer, the method checks that the graph has pathwidth + `\leq k`. If ``k`` is ``None`` (default), the method computes the optimal + pathwidth. - - ``certificate`` -- whether to return the path-decomposition itself. + - ``certificate`` -- boolean (default: ``False``); whether to return the + path-decomposition itself - - ``algorithm`` -- (default: ``"BAB"``) Specify the algorithm to use among + - ``algorithm`` -- string (default: ``"BAB"``); algorithm to use among: - ``"BAB"`` -- Use a branch-and-bound algorithm. This algorithm has no size restriction but could take a very long time on large graphs. It can @@ -519,17 +520,17 @@ def pathwidth(self, k=None, certificate=False, algorithm="BAB", verbose=False, - ``MILP`` -- Use a mixed integer linear programming formulation. This algorithm has no size restriction but could take a very long time. - - ``verbose`` (boolean) -- whether to display information on the - computations. - - - ``max_prefix_length`` -- (default: 20) limits the length of the stored - prefixes to prevent storing too many prefixes. This parameter is used only - when ``algorithm=="BAB"``. + - ``verbose`` -- boolean (default: ``False``); whether to display + information on the computations - - ``max_prefix_number`` -- (default: 10**6) upper bound on the number of - stored prefixes used to prevent using too much memory. This parameter is + - ``max_prefix_length`` -- integer (default: 20); limits the length of the + stored prefixes to prevent storing too many prefixes. This parameter is used only when ``algorithm=="BAB"``. + - ``max_prefix_number`` -- integer (default: 10**6); upper bound on the + number of stored prefixes used to prevent using too much memory. This + parameter is used only when ``algorithm=="BAB"``. + OUTPUT: Return the pathwidth of ``self``. When ``k`` is specified, it returns @@ -551,8 +552,8 @@ def pathwidth(self, k=None, certificate=False, algorithm="BAB", verbose=False, sage: g.pathwidth() 2 sage: pw, decomp = g.pathwidth(certificate=True) - sage: decomp.vertices() - [{1, 2, 5}, {2, 3, 4}, {0, 1, 5}, {2, 4, 5}] + sage: sorted(decomp, key=str) + [{0, 1, 5}, {1, 2, 5}, {2, 3, 4}, {2, 4, 5}] The pathwidth of a Petersen graph is 5:: @@ -582,7 +583,7 @@ def pathwidth(self, k=None, certificate=False, algorithm="BAB", verbose=False, sage: pathwidth(Graph(), algorithm="SuperFast") Traceback (most recent call last): ... - ValueError: Algorithm "SuperFast" has not been implemented yet. Please contribute. + ValueError: algorithm "SuperFast" has not been implemented yet, please contribute """ from sage.graphs.graph import Graph if not isinstance(self, Graph): @@ -601,17 +602,17 @@ def pathwidth(self, k=None, certificate=False, algorithm="BAB", verbose=False, return (pw <= k, linear_ordering_to_path_decomposition(self, L)) if certificate else pw <= k -def path_decomposition(G, algorithm = "BAB", cut_off=None, upper_bound=None, verbose = False, +def path_decomposition(G, algorithm="BAB", cut_off=None, upper_bound=None, verbose=False, max_prefix_length=20, max_prefix_number=10**6): r""" - Returns the pathwidth of the given graph and the ordering of the vertices + Return the pathwidth of the given graph and the ordering of the vertices resulting in a corresponding path decomposition. INPUT: - ``G`` -- a Graph - - ``algorithm`` -- (default: ``"BAB"``) Specify the algorithm to use among + - ``algorithm`` -- string (default: ``"BAB"``); algorithm to use among: - ``"BAB"`` -- Use a branch-and-bound algorithm. This algorithm has no size restriction but could take a very long time on large graphs. It can @@ -625,29 +626,29 @@ def path_decomposition(G, algorithm = "BAB", cut_off=None, upper_bound=None, ver - ``MILP`` -- Use a mixed integer linear programming formulation. This algorithm has no size restriction but could take a very long time. - - ``upper_bound`` -- (default: ``None``) This is parameter is used by the + - ``upper_bound`` -- integer (default: ``None``); parameter used by the ``"BAB"`` algorithm. If specified, the algorithm searches for a solution with ``width < upper_bound``. It helps cutting branches. However, if the given upper bound is too low, the algorithm may not be able to find a solution. - - ``cut_off`` -- (default: None) This is parameter is used by the ``"BAB"`` - algorithm. This bound allows us to stop the search as soon as a solution - with width at most ``cut_off`` is found, if any. If this bound cannot be - reached, the best solution found is returned, unless a too low + - ``cut_off`` -- integer (default: ``None``); parameter used by the + ``"BAB"`` algorithm. This bound allows us to stop the search as soon as a + solution with width at most ``cut_off`` is found, if any. If this bound + cannot be reached, the best solution found is returned, unless a too low ``upper_bound`` is given. - - ``verbose`` (boolean) -- whether to display information on the - computations. + - ``verbose`` -- boolean (default: ``False``); whether to display + information on the computations - - ``max_prefix_length`` -- (default: 20) limits the length of the stored - prefixes to prevent storing too many prefixes. This parameter is used only - when ``algorithm=="BAB"``. - - - ``max_prefix_number`` -- (default: 10**6) upper bound on the number of - stored prefixes used to prevent using too much memory. This parameter is + - ``max_prefix_length`` -- integer (default: 20); limits the length of the + stored prefixes to prevent storing too many prefixes. This parameter is used only when ``algorithm=="BAB"``. + - ``max_prefix_number`` -- integer (default: 10**6); upper bound on the + number of stored prefixes used to prevent using too much memory. This + parameter is used only when ``algorithm=="BAB"``. + OUTPUT: A pair ``(cost, ordering)`` representing the optimal ordering of the @@ -678,7 +679,7 @@ def path_decomposition(G, algorithm = "BAB", cut_off=None, upper_bound=None, ver sage: path_decomposition(DiGraph()) Traceback (most recent call last): ... - ValueError: The parameter must be a Graph. + ValueError: the parameter must be a Graph Given a wrong algorithm:: @@ -686,29 +687,29 @@ def path_decomposition(G, algorithm = "BAB", cut_off=None, upper_bound=None, ver sage: path_decomposition(Graph(), algorithm="SuperFast") Traceback (most recent call last): ... - ValueError: Algorithm "SuperFast" has not been implemented yet. Please contribute. + ValueError: algorithm "SuperFast" has not been implemented yet, please contribute """ from sage.graphs.graph import Graph if not isinstance(G, Graph): - raise ValueError("The parameter must be a Graph.") + raise ValueError("the parameter must be a Graph") return vertex_separation(G, algorithm=algorithm, cut_off=cut_off, upper_bound=upper_bound, verbose=verbose, max_prefix_length=max_prefix_length, max_prefix_number=max_prefix_number) -def vertex_separation(G, algorithm = "BAB", cut_off=None, upper_bound=None, verbose = False, +def vertex_separation(G, algorithm="BAB", cut_off=None, upper_bound=None, verbose=False, max_prefix_length=20, max_prefix_number=10**6): r""" - Returns an optimal ordering of the vertices and its cost for + Return an optimal ordering of the vertices and its cost for vertex-separation. INPUT: - ``G`` -- a Graph or a DiGraph - - ``algorithm`` -- (default: ``"BAB"``) Specify the algorithm to use among + - ``algorithm`` -- string (default: ``"BAB"``); algorithm to use among: - ``"BAB"`` -- Use a branch-and-bound algorithm. This algorithm has no size restriction but could take a very long time on large graphs. It can @@ -722,29 +723,29 @@ def vertex_separation(G, algorithm = "BAB", cut_off=None, upper_bound=None, verb - ``MILP`` -- Use a mixed integer linear programming formulation. This algorithm has no size restriction but could take a very long time. - - ``upper_bound`` -- (default: ``None``) This is parameter is used by the + - ``upper_bound`` -- integer (default: ``None``); parameter used by the ``"BAB"`` algorithm. If specified, the algorithm searches for a solution with ``width < upper_bound``. It helps cutting branches. However, if the given upper bound is too low, the algorithm may not be able to find a solution. - - ``cut_off`` -- (default: None) This is parameter is used by the ``"BAB"`` - algorithm. This bound allows us to stop the search as soon as a solution - with width at most ``cut_off`` is found, if any. If this bound cannot be - reached, the best solution found is returned, unless a too low + - ``cut_off`` -- integer (default: ``None``); parameter used by the + ``"BAB"`` algorithm. This bound allows us to stop the search as soon as a + solution with width at most ``cut_off`` is found, if any. If this bound + cannot be reached, the best solution found is returned, unless a too low ``upper_bound`` is given. - - ``verbose`` (boolean) -- whether to display information on the - computations. - - - ``max_prefix_length`` -- (default: 20) limits the length of the stored - prefixes to prevent storing too many prefixes. This parameter is used only - when ``algorithm=="BAB"``. + - ``verbose`` -- boolean (default: ``False``); whether to display + information on the computations - - ``max_prefix_number`` -- (default: 10**6) upper bound on the number of - stored prefixes used to prevent using too much memory. This parameter is + - ``max_prefix_length`` -- integer (default: 20); limits the length of the + stored prefixes to prevent storing too many prefixes. This parameter is used only when ``algorithm=="BAB"``. + - ``max_prefix_number`` -- integer (default: 10**6); upper bound on the + number of stored prefixes used to prevent using too much memory. This + parameter is used only when ``algorithm=="BAB"``. + OUTPUT: A pair ``(cost, ordering)`` representing the optimal ordering of the @@ -798,7 +799,7 @@ def vertex_separation(G, algorithm = "BAB", cut_off=None, upper_bound=None, verb sage: vertex_separation(Graph(), algorithm="SuperFast") Traceback (most recent call last): ... - ValueError: Algorithm "SuperFast" has not been implemented yet. Please contribute. + ValueError: algorithm "SuperFast" has not been implemented yet, please contribute Given anything else than a Graph or a DiGraph:: @@ -806,7 +807,7 @@ def vertex_separation(G, algorithm = "BAB", cut_off=None, upper_bound=None, verb sage: vertex_separation(range(4)) Traceback (most recent call last): ... - ValueError: The parameter must be a Graph or a DiGraph. + ValueError: the parameter must be a Graph or a DiGraph """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph @@ -826,8 +827,10 @@ def vertex_separation(G, algorithm = "BAB", cut_off=None, upper_bound=None, verb CC = scc_digraph.topological_sort()[::-1] else: - raise ValueError('The parameter must be a Graph or a DiGraph.') + raise ValueError('the parameter must be a Graph or a DiGraph') + if cut_off is None: + cut_off = 0 if CC: # The graph has several (strongly) connected components. We solve the @@ -837,7 +840,7 @@ def vertex_separation(G, algorithm = "BAB", cut_off=None, upper_bound=None, verb vs, L = 0, [] for V in CC: - if len(V)==1: + if len(V) == 1: # We can directly add this vertex to the solution L.extend(V) @@ -845,14 +848,14 @@ def vertex_separation(G, algorithm = "BAB", cut_off=None, upper_bound=None, verb # We build the (strongly) connected subgraph and do a recursive # call to get its vertex separation and corresponding ordering H = G.subgraph(V) - vsH,LH = vertex_separation(H, algorithm = algorithm, - cut_off = cut_off, - upper_bound = upper_bound, - verbose = verbose, - max_prefix_length = max_prefix_length, - max_prefix_number = max_prefix_number) - - if vsH==-1: + vsH,LH = vertex_separation(H, algorithm=algorithm, + cut_off=cut_off, + upper_bound=upper_bound, + verbose=verbose, + max_prefix_length=max_prefix_length, + max_prefix_number=max_prefix_number) + + if vsH == -1: # We have not been able to find a solution. This case # happens when a too low upper bound is given. return -1, [] @@ -867,37 +870,36 @@ def vertex_separation(G, algorithm = "BAB", cut_off=None, upper_bound=None, verb return vs, L - # We have a (strongly) connected graph and we call the desired algorithm if algorithm == "exponential": - return vertex_separation_exp(G, verbose = verbose) + return vertex_separation_exp(G, verbose=verbose) elif algorithm == "MILP": - return vertex_separation_MILP(G, verbosity = (1 if verbose else 0)) + return vertex_separation_MILP(G, verbosity=(1 if verbose else 0)) elif algorithm == "BAB": return vertex_separation_BAB(G, cut_off=cut_off, upper_bound=upper_bound, verbose=verbose, - max_prefix_length=max_prefix_length, max_prefix_number = max_prefix_number) + max_prefix_length=max_prefix_length, max_prefix_number=max_prefix_number) else: - raise ValueError('Algorithm "{}" has not been implemented yet. Please contribute.'.format(algorithm)) + raise ValueError('algorithm "{}" has not been implemented yet, please contribute'.format(algorithm)) ################################ # Exact exponential algorithms # ################################ -def vertex_separation_exp(G, verbose = False): +def vertex_separation_exp(G, verbose=False): r""" - Returns an optimal ordering of the vertices and its cost for + Return an optimal ordering of the vertices and its cost for vertex-separation. INPUT: - - ``G`` -- a Graph or a DiGraph. + - ``G`` -- a Graph or a DiGraph - - ``verbose`` (boolean) -- whether to display information on the - computations. + - ``verbose`` -- boolean (default: ``False``); whether to display + information on the computations OUTPUT: @@ -927,14 +929,16 @@ def vertex_separation_exp(G, verbose = False): sage: vertex_separation_exp(range(3)) Traceback (most recent call last): ... - ValueError: The parameter must be a Graph or a DiGraph. + ValueError: the parameter must be a Graph or a DiGraph Graphs with non-integer vertices:: sage: from sage.graphs.graph_decompositions.vertex_separation import vertex_separation_exp sage: D=digraphs.DeBruijn(2,3) - sage: vertex_separation_exp(D) + sage: vertex_separation_exp(D) # py2 (2, ['010', '110', '111', '011', '001', '000', '100', '101']) + sage: vertex_separation_exp(D) # py3 + (2, ['000', '001', '100', '010', '101', '011', '110', '111']) Given a too large graph:: @@ -942,15 +946,15 @@ def vertex_separation_exp(G, verbose = False): sage: vertex_separation_exp(graphs.PathGraph(50)) Traceback (most recent call last): ... - ValueError: The graph should have at most 31 vertices ! + ValueError: the graph should have at most 31 vertices """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph if not isinstance(G, Graph) and not isinstance(G, DiGraph): - raise ValueError("The parameter must be a Graph or a DiGraph.") + raise ValueError("the parameter must be a Graph or a DiGraph") if G.order() >= 32: - raise ValueError("The graph should have at most 31 vertices !") + raise ValueError("the graph should have at most 31 vertices") cdef FastDigraph g = FastDigraph(G) @@ -963,7 +967,7 @@ def vertex_separation_exp(G, verbose = False): memset(neighborhoods, -1, mem) - cdef int i,j , k + cdef int i, j, k for k in range(g.n): if verbose: print("Looking for a strategy of cost", str(k)) @@ -980,24 +984,24 @@ def vertex_separation_exp(G, verbose = False): sig_free(neighborhoods) - return k, list( g.int_to_vertices[i] for i in order ) + return k, [g.int_to_vertices[i] for i in order] ############################################################################## # Actual algorithm, breadh-first search and updates of the costs of the sets # ############################################################################## -# Check whether an ordering with the given cost exists, and updates data in the -# neighborhoods array at the same time. See the module's documentation - -cdef inline int exists(FastDigraph g, uint8_t * neighborhoods, int current, int cost): - +cdef inline int exists(FastDigraph g, uint8_t* neighborhoods, int current, int cost): + """ + Check whether an ordering with the given cost exists, and updates data in + the neighborhoods array at the same time. See the module's documentation. + """ # If this is true, it means the set has not been evaluated yet - if neighborhoods[current] == -1: + if neighborhoods[current] == -1: neighborhoods[current] = compute_out_neighborhood_cardinality(g, current) # If the cost of this set is too high, there is no point in going further. # Same thing if the current set is the whole vertex set. - if neighborhoods[current] > cost or (current == (1< cost or (current == (1 << g.n) - 1): return neighborhoods[current] # Minimum of the costs of the outneighbors @@ -1006,13 +1010,12 @@ cdef inline int exists(FastDigraph g, uint8_t * neighborhoods, int current, int cdef int i cdef int next_set - for i in range(g.n): - if (current >> i)&1: + if (current >> i) & 1: continue # For each of the out-neighbors next_set of current - next_set = current | 1<> i)&1: + if (current >> i) & 1: continue # Find the next set with small cost (we know it exists) - next_set = current | 1<b: + if a > b: return a else: return b @@ -1114,7 +1118,7 @@ def is_valid_ordering(G, L): sage: vertex_separation.is_valid_ordering(2, []) Traceback (most recent call last): ... - ValueError: The input parameter must be a Graph or a DiGraph. + ValueError: the input parameter must be a Graph or a DiGraph Giving anything else than a list:: @@ -1123,14 +1127,14 @@ def is_valid_ordering(G, L): sage: vertex_separation.is_valid_ordering(G, {}) Traceback (most recent call last): ... - ValueError: The second parameter must be of type 'list'. + ValueError: the second parameter must be of type 'list' """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph if not isinstance(G, Graph) and not isinstance(G, DiGraph): - raise ValueError("The input parameter must be a Graph or a DiGraph.") + raise ValueError("the input parameter must be a Graph or a DiGraph") if not isinstance(L, list): - raise ValueError("The second parameter must be of type 'list'.") + raise ValueError("the second parameter must be of type 'list'") return set(L) == set(G) @@ -1141,7 +1145,7 @@ def is_valid_ordering(G, L): def width_of_path_decomposition(G, L): r""" - Returns the width of the path decomposition induced by the linear ordering + Return the width of the path decomposition induced by the linear ordering `L` of the vertices of `G`. If `G` is an instance of :mod:`Graph `, this function @@ -1211,16 +1215,16 @@ def width_of_path_decomposition(G, L): sage: vertex_separation.width_of_path_decomposition(G, ['a','b']) Traceback (most recent call last): ... - ValueError: The input linear vertex ordering L is not valid for G. + ValueError: the input linear vertex ordering L is not valid for G """ if not is_valid_ordering(G, L): - raise ValueError("The input linear vertex ordering L is not valid for G.") + raise ValueError("the input linear vertex ordering L is not valid for G") neighbors = G.neighbors_out if G.is_directed() else G.neighbors - vsL = 0 - S = set() - neighbors_of_S_in_V_minus_S = set() + cdef int vsL = 0 + cdef set S = set() + cdef set neighbors_of_S_in_V_minus_S = set() for u in L: @@ -1232,11 +1236,11 @@ def width_of_path_decomposition(G, L): # We add the (out-)neighbors of u to the neighbors of S for v in neighbors(u): - if (not v in S): + if v not in S: neighbors_of_S_in_V_minus_S.add(v) # We update the cost of the vertex separation - vsL = max( vsL, len(neighbors_of_S_in_V_minus_S) ) + vsL = max(vsL, len(neighbors_of_S_in_V_minus_S)) return vsL @@ -1245,9 +1249,9 @@ def width_of_path_decomposition(G, L): # MILP formulation for vertex separation # ########################################## -def vertex_separation_MILP(G, integrality = False, solver = None, verbosity = 0): +def vertex_separation_MILP(G, integrality=False, solver=None, verbosity=0): r""" - Computes the vertex separation of `G` and the optimal ordering of its + Compute the vertex separation of `G` and the optimal ordering of its vertices using an MILP formulation. This function uses a mixed integer linear program (MILP) for determining an @@ -1260,20 +1264,20 @@ def vertex_separation_MILP(G, integrality = False, solver = None, verbosity = 0) - ``G`` -- a Graph or a DiGraph - - ``integrality`` -- (default: ``False``) Specify if variables `x_v^t` and - `u_v^t` must be integral or if they can be relaxed. This has no impact on - the validity of the solution, but it is sometimes faster to solve the - problem using binary variables only. + - ``integrality`` -- boolean (default: ``False``); specify if variables + `x_v^t` and `u_v^t` must be integral or if they can be relaxed. This has + no impact on the validity of the solution, but it is sometimes faster to + solve the problem using binary variables only. - - ``solver`` -- (default: ``None``) Specify a Linear Program (LP) solver to - be used. If set to ``None``, the default one is used. For more information - on LP solvers and which default solver is used, see the method + - ``solver`` -- string (default: ``None``); specify a Linear Program (LP) + solver to be used. If set to ``None``, the default one is used. For more + information on LP solvers and which default solver is used, see the method :meth:`solve` of the class :class:`MixedIntegerLinearProgram`. - - ``verbose`` -- integer (default: ``0``). Sets the level of verbosity. Set - to 0 by default, which means quiet. + - ``verbosity`` -- integer (default: ``0``); sets the level of + verbosity. Set to 0 by default, which means quiet. OUTPUT: @@ -1310,7 +1314,7 @@ def vertex_separation_MILP(G, integrality = False, solver = None, verbosity = 0) ....: ve, le = vertex_separation.vertex_separation(G) ....: vm, lm = vertex_separation.vertex_separation_MILP(G) ....: if ve != vm: - ....: print("The solution is not optimal!") + ....: raise ValueError("the solution is not optimal") Comparison with different values of the integrality parameter:: @@ -1320,7 +1324,7 @@ def vertex_separation_MILP(G, integrality = False, solver = None, verbosity = 0) ....: va, la = vertex_separation.vertex_separation_MILP(G, integrality=False) ....: vb, lb = vertex_separation.vertex_separation_MILP(G, integrality=True) ....: if va != vb: - ....: print("The integrality parameter changes the result!") + ....: raise ValueError("the integrality parameter changes the result") Giving anything else than a Graph or a DiGraph:: @@ -1328,12 +1332,12 @@ def vertex_separation_MILP(G, integrality = False, solver = None, verbosity = 0) sage: vertex_separation.vertex_separation_MILP([]) Traceback (most recent call last): ... - ValueError: The first input parameter must be a Graph or a DiGraph. + ValueError: the first input parameter must be a Graph or a DiGraph """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph if not isinstance(G, Graph) and not isinstance(G, DiGraph): - raise ValueError("The first input parameter must be a Graph or a DiGraph.") + raise ValueError("the first input parameter must be a Graph or a DiGraph") from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException p = MixedIntegerLinearProgram(maximization=False, solver=solver) @@ -1352,62 +1356,62 @@ def vertex_separation_MILP(G, integrality = False, solver = None, verbosity = 0) # (3) y[v,t] <= y[v,t+1] for all v in V, and for t:=0..N-2 for v in V: for t in range(N - 1): - p.add_constraint( x[v,t] - x[v,t+1] <= 0 ) - p.add_constraint( y[v,t] - y[v,t+1] <= 0 ) + p.add_constraint(x[v,t] - x[v,t+1] <= 0) + p.add_constraint(y[v,t] - y[v,t+1] <= 0) # (4) y[v,t] <= x[w,t] for all v in V, for all w in N^+(v), and for all t:=0..N-1 for v in V: for w in neighbors_out(v): for t in range(N): - p.add_constraint( y[v,t] - x[w,t] <= 0 ) + p.add_constraint(y[v,t] - x[w,t] <= 0) # (5) sum_{v in V} y[v,t] == t+1 for t:=0..N-1 for t in range(N): - p.add_constraint( p.sum([ y[v,t] for v in V ]) == t+1 ) + p.add_constraint(p.sum(y[v,t] for v in V) == t + 1) # (6) u[v,t] >= x[v,t]-y[v,t] for all v in V, and for all t:=0..N-1 for v in V: for t in range(N): - p.add_constraint( x[v,t] - y[v,t] - u[v,t] <= 0 ) + p.add_constraint(x[v,t] - y[v,t] - u[v,t] <= 0) # (7) z >= sum_{v in V} u[v,t] for all t:=0..N-1 for t in range(N): - p.add_constraint( p.sum([ u[v,t] for v in V ]) - z['z'] <= 0 ) + p.add_constraint(p.sum(u[v,t] for v in V) - z['z'] <= 0) # (8)(9) 0 <= x[v,t] and u[v,t] <= 1 if not integrality: for v in V: for t in range(N): - p.add_constraint( 0 <= x[v,t] <= 1 ) - p.add_constraint( 0 <= u[v,t] <= 1 ) + p.add_constraint(x[v,t], min=0, max=1) + p.add_constraint(u[v,t], min=0, max=1) # (10) y[v,t] in {0,1} - p.set_binary( y ) + p.set_binary(y) # (11) 0 <= z <= |V| - p.add_constraint( z['z'] <= N ) + p.add_constraint(z['z'] <= N) # (1) Minimize z - p.set_objective( z['z'] ) + p.set_objective(z['z']) try: - obj = p.solve( log=verbosity ) + obj = p.solve(log=verbosity) except MIPSolverException: if integrality: - raise ValueError("Unbounded or unexpected error") + raise ValueError("unbounded or unexpected error") else: - raise ValueError("Unbounded or unexpected error. Try with 'integrality = True'.") + raise ValueError("unbounded or unexpected error, try with 'integrality = True'") - taby = p.get_values( y ) - tabz = p.get_values( z ) + taby = p.get_values(y) + tabz = p.get_values(z) # since exactly one vertex is processed per step, we can reconstruct the sequence seq = [] for t in range(N): for v in V: - if (taby[v,t] > 0) and (not v in seq): + if taby[v,t] and v not in seq: seq.append(v) break - vs = int(round( tabz['z'] )) + vs = int(round(tabz['z'])) return vs, seq @@ -1416,11 +1420,11 @@ def vertex_separation_MILP(G, integrality = False, solver = None, verbosity = 0) ########################################## def vertex_separation_BAB(G, - cut_off = None, - upper_bound = None, - max_prefix_length = 20, - max_prefix_number = 10**6, - verbose = False): + cut_off=None, + upper_bound=None, + max_prefix_length=20, + max_prefix_number=10**6, + verbose=False): r""" Branch and Bound algorithm for the vertex separation. @@ -1434,31 +1438,31 @@ def vertex_separation_BAB(G, - ``G`` -- a Graph or a DiGraph. - - ``cut_off`` -- (default: None) bound to consider in the branch and bound - algorithm. This allows us to stop the search as soon as a solution with - width at most ``cut_off`` is found, if any. If this bound cannot be - reached, the best solution found is returned, unless a too low + - ``cut_off`` -- integer (default: ``None``); bound to consider in the + branch and bound algorithm. This allows us to stop the search as soon as a + solution with width at most ``cut_off`` is found, if any. If this bound + cannot be reached, the best solution found is returned, unless a too low ``upper_bound`` is given. - - ``upper_bound`` -- (default: None) if specified, the algorithm searches - for a solution with ``width < upper_bound``. It helps cutting branches. - However, if the given upper bound is too low, the algorithm may not be - able to find a solution. + - ``upper_bound`` -- integer (default: ``None``); if specified, the + algorithm searches for a solution with ``width < upper_bound``. It helps + cutting branches. However, if the given upper bound is too low, the + algorithm may not be able to find a solution. - - ``max_prefix_length`` -- (default: 20) limits the length of the stored - prefixes to prevent storing too many prefixes. + - ``max_prefix_length`` -- integer (default: 20); limits the length of the + stored prefixes to prevent storing too many prefixes - - ``max_prefix_number`` -- (default: 10**6) upper bound on the number of - stored prefixes used to prevent using too much memory. + - ``max_prefix_number`` -- integer (default: 10**6); upper bound on the + number of stored prefixes used to prevent using too much memory - - ``verbose`` -- (default: False) display some information when set to True. + - ``verbose`` -- boolean (default: ``False``); display some information when + set to ``True`` OUTPUT: - ``width`` -- the computed vertex separation - - ``seq`` -- an ordering of the vertices of width ``width``. - + - ``seq`` -- an ordering of the vertices of width ``width`` EXAMPLES: @@ -1518,12 +1522,12 @@ def vertex_separation_BAB(G, sage: from sage.graphs.graph_decompositions import vertex_separation as VS sage: G = graphs.MycielskiGraph(5) - sage: vs, seq = VS.vertex_separation_BAB(G, cut_off=11); vs - 11 - sage: vs, seq = VS.vertex_separation_BAB(G, cut_off=10); vs - 10 - sage: vs, seq = VS.vertex_separation_BAB(G, cut_off=9); vs - 10 + sage: VS.vertex_separation_BAB(G, cut_off=11)[0] <= 11 + True + sage: VS.vertex_separation_BAB(G, cut_off=10)[0] <= 10 + True + sage: VS.vertex_separation_BAB(G, cut_off=9)[0] <= 9 + False Testing for the existence of a solution with width strictly less than ``upper_bound``:: @@ -1555,7 +1559,7 @@ def vertex_separation_BAB(G, sage: VS.vertex_separation_BAB(range(5)) Traceback (most recent call last): ... - ValueError: The input parameter must be a Graph or a DiGraph. + ValueError: the input parameter must be a Graph or a DiGraph Giving an empty Graph or DiGraph:: @@ -1571,21 +1575,21 @@ def vertex_separation_BAB(G, sage: VS.vertex_separation_BAB(digraphs.Circuit(3), upper_bound=0) Traceback (most recent call last): ... - ValueError: The input upper bound must be at least 1. + ValueError: the input upper bound must be at least 1 """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph if not isinstance(G, DiGraph) and not isinstance(G, Graph): - raise ValueError("The input parameter must be a Graph or a DiGraph.") + raise ValueError("the input parameter must be a Graph or a DiGraph") cdef int n = G.order() - if n==0: + if not n: return 0, [] cut_off = 0 if cut_off is None else cut_off upper_bound = n if upper_bound is None else upper_bound if upper_bound < 1: - raise ValueError("The input upper bound must be at least 1.") + raise ValueError("the input upper bound must be at least 1") # ==> Allocate and initialize some data structures @@ -1600,16 +1604,16 @@ def vertex_separation_BAB(G, # We need 2 bitsets here + 3 per call to vertex_separation_BAB_C, so overall # 3*n + 2. We use another binary matrix as a pool of bitsets. cdef binary_matrix_t bm_pool - binary_matrix_init(bm_pool, 3*n+2, n) + binary_matrix_init(bm_pool, 3 * n + 2, n) - cdef int * prefix = sig_malloc(n * sizeof(int)) + cdef int * prefix = sig_malloc(n * sizeof(int)) cdef int * positions = sig_malloc(n * sizeof(int)) - if prefix==NULL or positions==NULL: + if not prefix or not positions: sig_free(prefix) sig_free(positions) binary_matrix_free(H) binary_matrix_free(bm_pool) - raise MemoryError("Unable to allocate data structures.") + raise MemoryError("unable to allocate data structures") cdef list best_seq = list(range(n)) for i in range(n): @@ -1617,28 +1621,28 @@ def vertex_separation_BAB(G, positions[i] = i cdef int width = upper_bound - cdef list order = list() + cdef list order = [] cdef set prefix_storage = set() try: # ==> Call the cython method sig_on() - width = vertex_separation_BAB_C(H = H, - n = n, - prefix = prefix, - positions = positions, - best_seq = best_seq, - level = 0, - b_prefix = bm_pool.rows[3*n], - b_prefix_and_neighborhood = bm_pool.rows[3*n+1], - cut_off = cut_off, - upper_bound = upper_bound, - current_cost = 0, - bm_pool = bm_pool, - prefix_storage = prefix_storage, - max_prefix_length = max_prefix_length, - max_prefix_number = max_prefix_number, - verbose = verbose) + width = vertex_separation_BAB_C(H=H, + n=n, + prefix=prefix, + positions=positions, + best_seq=best_seq, + level=0, + b_prefix=bm_pool.rows[3 * n], + b_prefix_and_neighborhood=bm_pool.rows[3 * n + 1], + cut_off=cut_off, + upper_bound=upper_bound, + current_cost=0, + bm_pool=bm_pool, + prefix_storage=prefix_storage, + max_prefix_length=max_prefix_length, + max_prefix_number=max_prefix_number, + verbose=verbose) sig_off() @@ -1653,34 +1657,34 @@ def vertex_separation_BAB(G, binary_matrix_free(H) binary_matrix_free(bm_pool) - return (width if width Test termination - if level==n: + if level == n: if current_cost < upper_bound: for i in range(n): best_seq[i] = prefix[i] @@ -1744,16 +1749,15 @@ cdef int vertex_separation_BAB_C(binary_matrix_t H, return current_cost - cdef int delta_i, j, v, select_it cdef list delta = list() cdef int loc_level = level # ==> Allocate local data structures - cdef bitset_s *loc_b_prefix = bm_pool.rows[3*level] - cdef bitset_s *loc_b_pref_and_neigh = bm_pool.rows[3*level+1] - cdef bitset_s *b_tmp = bm_pool.rows[3*level+2] + cdef bitset_s *loc_b_prefix = bm_pool.rows[3 * level] + cdef bitset_s *loc_b_pref_and_neigh = bm_pool.rows[3 * level + 1] + cdef bitset_s *b_tmp = bm_pool.rows[3 * level + 2] bitset_copy(loc_b_prefix, b_prefix) bitset_copy(loc_b_pref_and_neigh, b_prefix_and_neighborhood) @@ -1766,7 +1770,7 @@ cdef int vertex_separation_BAB_C(binary_matrix_t H, select_it = 0 i = loc_level - while i Test termination # - if loc_level==n: + if loc_level == n: if current_cost < upper_bound: for i in range(n): best_seq[i] = prefix[i] @@ -1808,7 +1812,6 @@ cdef int vertex_separation_BAB_C(binary_matrix_t H, return current_cost - # ==> Test if the prefix is in prefix_storage # # The set S of vertices of a prefix P is in prefix_storage if the branch @@ -1816,28 +1819,26 @@ cdef int vertex_separation_BAB_C(binary_matrix_t H, # case, there is no need to continue exploration for the current branch. cdef frozenset frozen_prefix - if loc_level<=max_prefix_length: - frozen_prefix = frozenset([prefix[i] for i in range(loc_level)]) + if loc_level <= max_prefix_length: + frozen_prefix = frozenset(prefix[i] for i in range(loc_level)) if frozen_prefix in prefix_storage: return upper_bound - # ==> Sort and Prune # # We compute for each remaining vertex v a lower bound on the width of any # ordering with prefix prefix+v - for i from loc_level <= i < n: + for i in range(loc_level, n): j = prefix[i] bitset_union(b_tmp, loc_b_pref_and_neigh, H.rows[j]) bitset_difference(b_tmp, b_tmp, loc_b_prefix) bitset_discard(b_tmp, j) delta_i = bitset_len(b_tmp) if delta_i < upper_bound: - delta.append( (delta_i, j) ) + delta.append((delta_i, j)) delta.sort() - # ==> Recursion for delta_i, i in delta: @@ -1852,22 +1853,22 @@ cdef int vertex_separation_BAB_C(binary_matrix_t H, _my_invert_positions(prefix, positions, positions[i], loc_level) bitset_add(loc_b_prefix, i) - cost_i = vertex_separation_BAB_C(H = H, - n = n, - prefix = prefix, - positions = positions, - best_seq = best_seq, - level = loc_level+1, - b_prefix = loc_b_prefix, - b_prefix_and_neighborhood = b_tmp, - cut_off = cut_off, - upper_bound = upper_bound, - current_cost = delta_i, - bm_pool = bm_pool, - prefix_storage = prefix_storage, - max_prefix_length = max_prefix_length, - max_prefix_number = max_prefix_number, - verbose = verbose) + cost_i = vertex_separation_BAB_C(H=H, + n=n, + prefix=prefix, + positions=positions, + best_seq=best_seq, + level=loc_level + 1, + b_prefix=loc_b_prefix, + b_prefix_and_neighborhood=b_tmp, + cut_off=cut_off, + upper_bound=upper_bound, + current_cost=delta_i, + bm_pool=bm_pool, + prefix_storage=prefix_storage, + max_prefix_length=max_prefix_length, + max_prefix_number=max_prefix_number, + verbose=verbose) bitset_discard(loc_b_prefix, i) @@ -1882,7 +1883,9 @@ cdef int vertex_separation_BAB_C(binary_matrix_t H, # If the prefix P is such that c(P)<\min_{L\in{\cal L}_P(V)} c(L), no other # prefix P' on the same set S=V(P) of vertices can lead to a better # solution. - if loc_level<=max_prefix_length and current_cost= d for i,d in enumerate(sorted(x.degree()))]) - extra_property = lambda x: degree_sequence == sorted(x.degree()) + def property(x): + D = sorted(x.degree()) + return all(degree_sequence[i] >= d for i, d in enumerate(D)) + def extra_property(x): + return degree_sequence == sorted(x.degree()) else: - property = lambda x: all([degree_sequence[i] >= d for i,d in enumerate(sorted(x.degree() + [0]*(vertices-x.num_verts()) ))]) - extra_property = lambda x: x.num_verts() == vertices and degree_sequence == sorted(x.degree()) + def property(x): + D = sorted(x.degree() + [0] * (vertices - x.num_verts())) + return all(degree_sequence[i] >= d for i, d in enumerate(D)) + def extra_property(x): + if x.num_verts() != vertices: + return False + return degree_sequence == sorted(x.degree()) elif size is not None: - extra_property = lambda x: x.size() == size + def extra_property(x): + return x.size() == size else: - extra_property = lambda x: True + def extra_property(x): + return True if augment == 'vertices': if vertices is None: @@ -1956,6 +1968,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None FranklinGraph = staticmethod(sage.graphs.generators.smallgraphs.FranklinGraph) FruchtGraph = staticmethod(sage.graphs.generators.smallgraphs.FruchtGraph) GoldnerHararyGraph = staticmethod(sage.graphs.generators.smallgraphs.GoldnerHararyGraph) + GolombGraph = staticmethod(sage.graphs.generators.smallgraphs.GolombGraph) GossetGraph = staticmethod(sage.graphs.generators.smallgraphs.GossetGraph) GrayGraph = staticmethod(sage.graphs.generators.smallgraphs.GrayGraph) GrotzschGraph = staticmethod(sage.graphs.generators.smallgraphs.GrotzschGraph) diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index c0ee1994f88..824cf0bd7f5 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -1333,14 +1333,14 @@ def dot2tex_picture(self): sage: print(g.latex_options().dot2tex_picture()) # optional - dot2tex graphviz \begin{tikzpicture}[>=latex,line join=bevel,] %% - \node (node_3) at (...bp,...bp) [draw,draw=none] {$\left(1, 1\right)$}; + \node (node_3) at (...bp,...bp) [draw,draw=none] {$\left(0, 1\right)$}; \node (node_2) at (...bp,...bp) [draw,draw=none] {$\left(1, 0\right)$}; - \node (node_1) at (...bp,...bp) [draw,draw=none] {$\left(0, 1\right)$}; - \node (node_0) at (...bp,...bp) [draw,draw=none] {$\left(0, 0\right)$}; - \draw [black,->] (node_0) ..controls (...bp,...bp) and (...bp,...bp) .. (node_3); - \draw [black,->] (node_2) ..controls (...bp,...bp) and (...bp,...bp) .. (node_1); - \draw [black,->] (node_0) ..controls (...bp,...bp) and (...bp,...bp) .. (node_1); + \node (node_1) at (...bp,...bp) [draw,draw=none] {$\left(0, 0\right)$}; + \node (node_0) at (...bp,...bp) [draw,draw=none] {$\left(1, 1\right)$}; + \draw [black,->] (node_1) ..controls (...bp,...bp) and (...bp,...bp) .. (node_3); \draw [black,->] (node_2) ..controls (...bp,...bp) and (...bp,...bp) .. (node_3); + \draw [black,->] (node_2) ..controls (...bp,...bp) and (...bp,...bp) .. (node_0); + \draw [black,->] (node_1) ..controls (...bp,...bp) and (...bp,...bp) .. (node_0); % \end{tikzpicture} @@ -1515,6 +1515,19 @@ def tkz_picture(self): \begin{tikzpicture} ... \end{tikzpicture} + + With the empty graph, an empty tikzfigure is output. :: + + sage: from sage.graphs.graph_latex import check_tkz_graph + sage: check_tkz_graph() # random - depends on TeX installation + sage: g = Graph() + sage: opts = g.latex_options() + sage: print(opts.tkz_picture()) + \begin{tikzpicture} + % + % + % + \end{tikzpicture} """ # This routine does not handle multiple edges # It will properly handle digraphs where a pair of vertices has an edge @@ -1583,7 +1596,7 @@ def tkz_picture(self): xmax = max(i[0] for i in pos.values()) ymax = max(i[1] for i in pos.values()) else: - xmax, ymax = 0, 0 + xmin, xmax, ymin, ymax = 0, 0, 0, 0 # Linear scaling factors that will be used to scale the image to fit # into the bordered region. Purely horizontal, or purely vertical, diff --git a/src/sage/graphs/graph_plot_js.py b/src/sage/graphs/graph_plot_js.py index 4786ca24c82..b145920c33b 100644 --- a/src/sage/graphs/graph_plot_js.py +++ b/src/sage/graphs/graph_plot_js.py @@ -189,6 +189,19 @@ def gen_html_code(G, :trac:`17370`:: sage: filename = gen_html_code(graphs.CompleteBipartiteGraph(4, 5)) + + In the generated html code, the source (resp. target) of a link is the index + of the node in the list defining the names of the nodes. We check that the + order is correct (:trac:`27460`):: + + sage: filename = gen_html_code(DiGraph({1: [10]})) + sage: with open(filename, 'r') as f: + ....: data = f.read() + sage: nodes = data.partition('"nodes":')[2]; nodes + ...[{..."name": "10"...}, {..."name": "1"...}]... + sage: links = data.partition('"links":')[2] + sage: '"source": 1' in links and '"target": 0' in links + True """ directed = G.is_directed() multiple_edges = G.has_multiple_edges() @@ -206,9 +219,8 @@ def gen_html_code(G, color[v_to_id[v]] = i # Vertex list - nodes = [] - for v in G.vertices(): - nodes.append({"name": str(v), "group": str(color[v_to_id[v]])}) + # Data for vertex v must be at position v_to_id[v] in list nodes + nodes = [{"name": str(v), "group": str(color[v_to_id[v]])} for v in G] # Edge colors. edge_color_default = "#aaa" @@ -258,6 +270,7 @@ def gen_html_code(G, curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 # Adding the edge to the list + # The source (resp. target) is the index of u (resp. v) in list nodes edges.append({"source": v_to_id[u], "target": v_to_id[v], "strength": 0, diff --git a/src/sage/graphs/hyperbolicity.pyx b/src/sage/graphs/hyperbolicity.pyx index c893a07ef2b..be41b4a5d06 100644 --- a/src/sage/graphs/hyperbolicity.pyx +++ b/src/sage/graphs/hyperbolicity.pyx @@ -1152,55 +1152,55 @@ def hyperbolicity(G, sage: from sage.graphs.hyperbolicity import hyperbolicity sage: G = graphs.Grid2dGraph(3, 3) - sage: hyperbolicity(G, algorithm='BCCM') + sage: L,C,U = hyperbolicity(G, algorithm='BCCM'); L,sorted(C),U (2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2) - sage: hyperbolicity(G, algorithm='CCL') + sage: L,C,U = hyperbolicity(G, algorithm='CCL'); L,sorted(C),U (2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2) - sage: hyperbolicity(G, algorithm='basic') + sage: L,C,U = hyperbolicity(G, algorithm='basic'); L,sorted(C),U (2, [(0, 0), (0, 2), (2, 0), (2, 2)], 2) Hyperbolicity of a PetersenGraph:: sage: from sage.graphs.hyperbolicity import hyperbolicity sage: G = graphs.PetersenGraph() - sage: hyperbolicity(G, algorithm='BCCM') + sage: L,C,U = hyperbolicity(G, algorithm='BCCM'); L,sorted(C),U (1/2, [6, 7, 8, 9], 1/2) - sage: hyperbolicity(G, algorithm='CCL') + sage: L,C,U = hyperbolicity(G, algorithm='CCL'); L,sorted(C),U (1/2, [0, 1, 2, 3], 1/2) - sage: hyperbolicity(G, algorithm='CCL+') + sage: L,C,U = hyperbolicity(G, algorithm='CCL+'); L,sorted(C),U (1/2, [0, 1, 2, 3], 1/2) - sage: hyperbolicity(G, algorithm='CCL+FA') + sage: L,C,U = hyperbolicity(G, algorithm='CCL+FA'); L,sorted(C),U (1/2, [0, 1, 2, 3], 1/2) - sage: hyperbolicity(G, algorithm='basic') + sage: L,C,U = hyperbolicity(G, algorithm='basic'); L,sorted(C),U (1/2, [0, 1, 2, 3], 1/2) - sage: hyperbolicity(G, algorithm='dom') + sage: L,C,U = hyperbolicity(G, algorithm='dom'); L,sorted(C),U (0, [0, 1, 2, 6], 1) Asking for an approximation in a grid graph:: sage: from sage.graphs.hyperbolicity import hyperbolicity sage: G = graphs.Grid2dGraph(2, 10) - sage: hyperbolicity(G, algorithm='CCL', approximation_factor=1.5) - (1, [(0, 0), (0, 9), (1, 0), (1, 9)], 3/2) - sage: hyperbolicity(G, algorithm='CCL+', approximation_factor=1.5) - (1, [(0, 0), (0, 9), (1, 0), (1, 9)], 1) - sage: hyperbolicity(G, algorithm='CCL', approximation_factor=4) - (1, [(0, 0), (0, 9), (1, 0), (1, 9)], 4) - sage: hyperbolicity(G, algorithm='CCL', additive_gap=2) - (1, [(0, 0), (0, 9), (1, 0), (1, 9)], 3) - sage: hyperbolicity(G, algorithm='dom') - (1, [(0, 1), (0, 8), (1, 0), (1, 9)], 5) + sage: L,C,U = hyperbolicity(G, algorithm='CCL', approximation_factor=1.5); L,U + (1, 3/2) + sage: L,C,U = hyperbolicity(G, algorithm='CCL+', approximation_factor=1.5); L,U + (1, 1) + sage: L,C,U = hyperbolicity(G, algorithm='CCL', approximation_factor=4); L,U + (1, 4) + sage: L,C,U = hyperbolicity(G, algorithm='CCL', additive_gap=2); L,U + (1, 3) + sage: L,C,U = hyperbolicity(G, algorithm='dom'); L,U + (1, 5) Asking for an approximation in a cycle graph:: sage: from sage.graphs.hyperbolicity import hyperbolicity sage: G = graphs.CycleGraph(10) - sage: hyperbolicity(G, algorithm='CCL', approximation_factor=1.5) - (2, [0, 2, 5, 7], 5/2) - sage: hyperbolicity(G, algorithm='CCL+FA', approximation_factor=1.5) - (2, [0, 2, 5, 7], 5/2) - sage: hyperbolicity(G, algorithm='CCL+FA', additive_gap=1) - (2, [0, 2, 5, 7], 5/2) + sage: L,C,U = hyperbolicity(G, algorithm='CCL', approximation_factor=1.5); L,U + (2, 5/2) + sage: L,C,U = hyperbolicity(G, algorithm='CCL+FA', approximation_factor=1.5); L,U + (2, 5/2) + sage: L,C,U = hyperbolicity(G, algorithm='CCL+FA', additive_gap=1); L,U + (2, 5/2) Comparison of results:: @@ -1239,7 +1239,7 @@ def hyperbolicity(G, sage: from sage.graphs.hyperbolicity import hyperbolicity sage: G = graphs.PetersenGraph() * 2 sage: G.add_edge(0, 11) - sage: hyperbolicity(G) + sage: L,C,U = hyperbolicity(G); L,sorted(C),U (1/2, [6, 7, 8, 9], 1/2) TESTS: @@ -1475,7 +1475,7 @@ def hyperbolicity(G, certificate = [int_to_vertex[i] for i in certif] # Last, we return the computed value and the certificate - return ZZ(hyp)/2, sorted(certificate), ZZ(hyp_UB)/2 + return ZZ(hyp)/2, certificate, ZZ(hyp_UB)/2 ###################################################################### diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index e96eba12752..a6c2dafddfa 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -50,7 +50,7 @@ def strong_orientations_iterator(G): Therefore, this function generates all partial orientations of the non-tree edges and then launches a helper function corresponding to the generation algorithm described in [CGMRV16]_. - In order to avoid trivial symetries, the orientation of an arbitrary edge + In order to avoid trivial symmetries, the orientation of an arbitrary edge is fixed before the start of the enumeration process. INPUT: @@ -64,7 +64,7 @@ def strong_orientations_iterator(G): .. NOTE:: Works only for simple graphs (no multiple edges). - To avoid symetries an orientation of an arbitrary edge is fixed. + To avoid symmetries an orientation of an arbitrary edge is fixed. EXAMPLES: @@ -191,7 +191,7 @@ def _strong_orientations_of_a_mixed_graph(Dg, V, E): - an iterator which will produce all strong orientations of the input partially directed graph. - EXAMPLES: + EXAMPLES:: sage: from sage.graphs.orientations import _strong_orientations_of_a_mixed_graph sage: g = graphs.CycleGraph(5) diff --git a/src/sage/graphs/planarity.pyx b/src/sage/graphs/planarity.pyx index 188f4539480..2214aa9f0cc 100644 --- a/src/sage/graphs/planarity.pyx +++ b/src/sage/graphs/planarity.pyx @@ -29,29 +29,32 @@ cdef extern from "planarity/graph.h": cdef int gp_SortVertices(graphP theGraph) def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular=False): - """ - Calls Boyer's planarity algorithm to determine whether g is - planar. If kuratowski is False, returns True if g is planar, - False otherwise. If kuratowski is True, returns a tuple, first - entry is a boolean (whether or not the graph is planar) and second - entry is a Kuratowski subgraph, i.e. an edge subdivision of - `K_5` or `K_{3,3}` (if not planar) or ``None`` (if planar). Also, will set - an ``_embedding`` attribute for the graph ``g`` if ``set_embedding`` is set - to True. + r""" + Check whether ``g`` is planar using Boyer's planarity algorithm. + + If ``kuratowski`` is ``False``, returns ``True`` if ``g`` is planar, + ``False`` otherwise. If ``kuratowski`` is ``True``, returns a tuple, first + entry is a boolean (whether or not the graph is planar) and second entry is + a Kuratowski subgraph, i.e. an edge subdivision of `K_5` or `K_{3,3}` (if + not planar) or ``None`` (if planar). Also, will set an ``_embedding`` + attribute for the graph ``g`` if ``set_embedding`` is set to ``True``. INPUT: - - ``kuratowski`` -- If ``True``, return a tuple of a boolean and either - ``None`` or a Kuratowski subgraph (i.e. an edge subdivision of `K_5` - or `K_{3,3}`) + - ``kuratowski`` -- boolean (default: ``False``); when set to ``True``, + return a tuple of a boolean and either ``None`` or a Kuratowski subgraph + (i.e. an edge subdivision of `K_5` or `K_{3,3}`). When set to ``False``, + returns ``True`` if ``g`` is planar, ``False`` otherwise. - - ``set_pos`` -- if ``True``, uses Schnyder's algorithm to determine - positions + - ``set_pos`` -- boolean (default: ``False``); whether to use Schnyder's + algorithm to determine and set positions - - ``set_embedding`` -- if ``True``, records the combinatorial embedding - returned (see g.get_embedding()) + - ``set_embedding`` -- boolean (default: ``False``); whether to record the + combinatorial embedding returned (see + :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding`) - - ``circular`` -- if ``True``, test for circular planarity + - ``circular`` -- boolean (default: ``False``); whether to test for circular + planarity EXAMPLES:: @@ -87,28 +90,26 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= raise ValueError("is_planar() cannot set vertex positions for a disconnected graph") # First take care of a trivial cases - if g.size() == 0: # There are no edges + if not g.size(): + # There are no edges if set_embedding: - g._embedding = dict((v, []) for v in g.vertices()) + g._embedding = {v: [] for v in g} return (True, None) if kuratowski else True - if len(g) == 2 and g.is_connected(): # P_2 is too small to be triangulated - u,v = g.vertices() + if g.order() == 2 and g.is_connected(): + # P_2 is too small to be triangulated + u,v = list(g) if set_embedding: - g._embedding = { u: [v], v: [u] } + g._embedding = {u: [v], v: [u]} if set_pos: - g._pos = { u: [0,0], v: [0,1] } + g._pos = {u: [0, 0], v: [0, 1]} return (True, None) if kuratowski else True - # create to and from mappings to relabel vertices to the set {1,...,n} + # Create to and from mappings to relabel vertices to the set {1,...,n} # (planarity 3 uses 1-based array indexing, with 0 representing NIL) cdef int i - listto = g.vertices() - ffrom = {} - for vvv in listto: - ffrom[vvv] = listto.index(vvv) + 1 - to = {} - for i from 0 <= i < len(listto): - to[i + 1] = listto[i] + cdef list listto = list(g) + cdef dict ffrom = {vvv: i + 1 for i, vvv in enumerate(listto)} + cdef dict to = {i + 1: vvv for i, vvv in enumerate(listto)} g.relabel(ffrom) cdef graphP theGraph @@ -116,11 +117,11 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= cdef int status status = gp_InitGraph(theGraph, g.order()) if status != OK: - raise RuntimeError("gp_InitGraph status is not ok.") - for u, v, _ in g.edge_iterator(): + raise RuntimeError("gp_InitGraph status is not ok") + for u, v in g.edge_iterator(labels=False): status = gp_AddEdge(theGraph, u, 0, v, 0) if status == NOTOK: - raise RuntimeError("gp_AddEdge status is not ok.") + raise RuntimeError("gp_AddEdge status is not ok") elif status == NONEMBEDDABLE: # We now know that the graph is nonplanar. if not kuratowski: @@ -132,16 +133,16 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= status = gp_Embed(theGraph, EMBEDFLAGS_PLANAR) gp_SortVertices(theGraph) - # use to and from mappings to relabel vertices back from the set {1,...,n} + # Use to and from mappings to relabel vertices back from the set {1,...,n} g.relabel(to) if status == NOTOK: - raise RuntimeError("Status is not ok.") + raise RuntimeError("status is not ok") elif status == NONEMBEDDABLE: # Kuratowski subgraph isolator g_dict = {} from sage.graphs.graph import Graph - for i from 0 < i <= theGraph.N: + for i in range(1, theGraph.N + 1): linked_list = [] j = theGraph.V[i].link[1] while j: @@ -160,7 +161,7 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= if set_embedding: emb_dict = {} #for i in range(theGraph.N): - for i from 0 < i <= theGraph.N: + for i in range(1, theGraph.N + 1): linked_list = [] j = theGraph.V[i].link[1] while j: @@ -181,7 +182,7 @@ def is_planar(g, kuratowski=False, set_pos=False, set_embedding=False, circular= emb_dict = {} #for i in range(theGraph.N): - for i from 0 < i <= theGraph.N: + for i in range(1, theGraph.N + 1): linked_list = [] j = theGraph.V[i].link[0] while j: diff --git a/src/sage/graphs/schnyder.py b/src/sage/graphs/schnyder.py index a28eda874f6..9e765ae91ea 100644 --- a/src/sage/graphs/schnyder.py +++ b/src/sage/graphs/schnyder.py @@ -220,7 +220,8 @@ def _normal_label(g, comb_emb, external_face): v1_neighbors += v_neighbors - Set([v1]) contractible = [] for w in g.neighbors(v1): - if(len(v1_neighbors.intersection(Set(g.neighbors(w))))) == 2 and w not in [v1, v2, v3]: + if (len(v1_neighbors.intersection(Set(g.neighbors(w)))) == 2 + and w not in [v1, v2, v3]): contractible.append(w) # expansion phase: diff --git a/src/sage/graphs/spanning_tree.pyx b/src/sage/graphs/spanning_tree.pyx index c017fdb6480..2992f9fa9b7 100644 --- a/src/sage/graphs/spanning_tree.pyx +++ b/src/sage/graphs/spanning_tree.pyx @@ -185,8 +185,11 @@ cpdef kruskal(G, wfunction=None, bint check=False): ....: "c":{"d":7, "f":4, "i":2}, "d":{"e":9, "f":14}, ....: "e":{"f":10}, "f":{"g":2}, "g":{"h":1, "i":6}, "h":{"i":7}}) sage: G.weighted(True) - sage: sorted(kruskal(G, check=True)) - [('a', 'b', 4), ('a', 'h', 8), ('c', 'd', 7), ('c', 'f', 4), ('c', 'i', 2), ('d', 'e', 9), ('f', 'g', 2), ('g', 'h', 1)] + sage: T = Graph(kruskal(G, check=True), format='list_of_edges') + sage: sum(T.edge_labels()) + 37 + sage: T.is_tree() + True An example with custom edge labels:: diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 55a14287563..4131230754a 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1477,8 +1477,10 @@ def is_twograph_descendant_of_srg(int v, int k0, int l, int mu): sage: from sage.graphs.strongly_regular_db import is_twograph_descendant_of_srg sage: t = is_twograph_descendant_of_srg(27, 10, 1, 5); t (.la at... - sage: g = t[0](*t[1:]); g + sage: g = t[0](*t[1:]); g # py2 descendant of complement(Johnson graph with parameters 8,2) at {5, 7}: Graph on 27 vertices + sage: g = t[0](*t[1:]); g # py3 + descendant of complement(Johnson graph with parameters 8,2) at {0, 1}: Graph on 27 vertices sage: g.is_strongly_regular(parameters=True) (27, 10, 1, 5) sage: t = is_twograph_descendant_of_srg(5,5,5,5); t @@ -2231,19 +2233,19 @@ def SRG_196_91_42_42(): from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.graphs.generators.intersection import IntersectionGraph k = 7 - G = IntegerModRing(91) - A = map(G,{0, 10, 27, 28, 31, 43, 50}) - B = map(G,{0, 11, 20, 25, 49, 55, 57}) - H = map(G,[13*i for i in range(k)]) - U = list(map(frozenset, [[x + z for x in A] for z in G])) - V = list(map(frozenset, [[x + z for x in B] for z in G])) - W = list(map(frozenset, [[x + z for x in H] for z in G])) + R = IntegerModRing(91) + A = list(map(R, [0, 10, 27, 28, 31, 43, 50])) + B = list(map(R, [0, 11, 20, 25, 49, 55, 57])) + H = list(map(R, [13 * i for i in range(k)])) + U = list(map(frozenset, [[x + z for x in A] for z in R])) + V = list(map(frozenset, [[x + z for x in B] for z in R])) + W = list(map(frozenset, [[x + z for x in H] for z in R])) G = IntersectionGraph(U + V + W) G.seidel_switching(U) - G.add_edges((-1,x) for x in U) - G.relabel() + G.add_edges((-1, x) for x in U) + G.relabel(perm={u: i for i, u in enumerate(G)}) G.name('RSHCD+') return G @@ -2620,25 +2622,27 @@ def SRG_176_90_38_54(): EXAMPLES:: sage: from sage.graphs.strongly_regular_db import SRG_176_90_38_54 - sage: G = SRG_176_90_38_54() + sage: G = SRG_176_90_38_54(); G + a Seidel switching of Distance graph for distance 2 in : Graph on 176 vertices sage: G.is_strongly_regular(parameters=True) (176, 90, 38, 54) """ from sage.graphs.generators.basic import CompleteGraph from sage.misc.flatten import flatten g = SRG_175_72_20_36() - g.relabel() + g.relabel(range(175)) # c=filter(lambda x: len(x)==5, g.cliques_maximal()) # r=flatten(Hypergraph(c).packing()[:18]) # takes 3s, so we put the answer here - r=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,28,29,32,\ - 38,39,41,42,43,47,49,50,51,52,53,55,57,61,63,65,67,69,72,75,77,79,81,84,87,88,\ - 89,92,95,96,97,99,101,102,104,105,107,112,114,117,118,123,125,129,132,139,140,\ - 141,144,146,147,153,154,162,165,166,167,170,172,173,174] - j=g.disjoint_union(CompleteGraph(1)) - j.relabel() - j.seidel_switching(r) - j.name('a Seidel switching of '+SRG_175_72_20_36().name()) - return j + r = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23, + 24,25,28,29,32,38,39,41,42,43,47,49,50,51,52,53,55,57,61,63,65, + 67,69,72,75,77,79,81,84,87,88,89,92,95,96,97,99,101,102,104, + 105,107,112,114,117,118,123,125,129,132,139,140,141,144,146, + 147,153,154,162,165,166,167,170,172,173,174] + g.add_vertex() + g.seidel_switching(r) + g.name('a Seidel switching of ' + g.name()) + return g + def SRG_630_85_20_10(): r""" @@ -3096,7 +3100,7 @@ def _build_small_srg_database(): parameters of the graph of words of `C`. Another relevant reference is Sect.9.8.3 of [BH12]_. - EXAMPLES: + EXAMPLES:: sage: from sage.graphs.strongly_regular_db import _build_small_srg_database sage: _build_small_srg_database() diff --git a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py index f07e778884b..58b8189d2ef 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py +++ b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py @@ -101,7 +101,7 @@ class AdditiveAbelianGroupWrapperElement(addgp.AdditiveAbelianGroupElement): def __init__(self, parent, vector, element=None, check=False): r""" - EXAMPLES: + EXAMPLES:: sage: from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper sage: G = AdditiveAbelianGroupWrapper(QQbar, [sqrt(QQbar(2)), sqrt(QQbar(3))], [0, 0]) diff --git a/src/sage/groups/class_function.py b/src/sage/groups/class_function.py index f509be5b79a..aeb79390957 100644 --- a/src/sage/groups/class_function.py +++ b/src/sage/groups/class_function.py @@ -74,7 +74,7 @@ class function on the conjugacy classes, in that order. ### GAP Interface-based Class Function ### ### This is old code that should be deleted once we have transitioned -### everything to libGAP. +### everything to using the library interface to GAP. ### ##################################################################### @@ -721,7 +721,7 @@ def restrict(self, H): Character of Symmetric group of order 5! as a permutation group sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: chi.restrict(H) - Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)] + Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of (Symmetric group of order 5! as a permutation group) sage: chi.restrict(H).values() [3, -3, -3, -1, 0, 0] """ @@ -748,7 +748,7 @@ def induct(self, G): sage: G = SymmetricGroup(5) sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: xi = H.trivial_character(); xi - Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)] + Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of (Symmetric group of order 5! as a permutation group) sage: xi.induct(G) Character of Symmetric group of order 5! as a permutation group sage: xi.induct(G).values() @@ -802,7 +802,7 @@ def adams_operation(self, k): ##################################################################### ### -### libGAP-based Class function +### Class function using the GAP library ### ##################################################################### @@ -1450,7 +1450,7 @@ def restrict(self, H): Character of Symmetric group of order 5! as a permutation group sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: chi.restrict(H) - Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)] + Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of (Symmetric group of order 5! as a permutation group) sage: chi.restrict(H).values() [3, -3, -3, -1, 0, 0] """ @@ -1482,7 +1482,7 @@ def induct(self, G): sage: G = SymmetricGroup(5) sage: H = G.subgroup([(1,2,3), (1,2), (4,5)]) sage: xi = H.trivial_character(); xi - Character of Subgroup of (Symmetric group of order 5! as a permutation group) generated by [(4,5), (1,2), (1,2,3)] + Character of Subgroup generated by [(4,5), (1,2), (1,2,3)] of (Symmetric group of order 5! as a permutation group) sage: xi.induct(G) Character of Symmetric group of order 5! as a permutation group sage: xi.induct(G).values() diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index f27f334527c..d3ae1a0c590 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1263,7 +1263,7 @@ def semidirect_product(self, H, hom, check=True, reduced=False): sage: D.semidirect_product(C, bad_hom) Traceback (most recent call last): ... - ValueError: libGAP: Error, and must be lists of same length + GAPError: Error, and must be lists of same length """ from sage.groups.free_group import FreeGroup, _lexi_gen @@ -1280,7 +1280,8 @@ def semidirect_product(self, H, hom, check=True, reduced=False): # check for automorphism validity in images of operation defining homomorphism, # and construct the defining homomorphism. if check: - if not all([a in libgap.List(libgap.AutomorphismGroup(GAP_H)) for a in GAP_aut_imgs]): + if not all(a in libgap.List(libgap.AutomorphismGroup(GAP_H)) + for a in GAP_aut_imgs): raise ValueError("images of input homomorphism must be automorphisms") GAP_def_hom = libgap.GroupHomomorphismByImages(GAP_self, auto_grp, self_gens, GAP_aut_imgs) else: diff --git a/src/sage/groups/finitely_presented_named.py b/src/sage/groups/finitely_presented_named.py index c8075f99d0f..248c96e511e 100644 --- a/src/sage/groups/finitely_presented_named.py +++ b/src/sage/groups/finitely_presented_named.py @@ -181,7 +181,7 @@ def FinitelyGeneratedAbelianPresentation(int_list): sage: gg = (C2.direct_product(C4)[0]).direct_product(C8)[0] sage: gg.is_isomorphic(G.as_permutation_group()) True - sage: all([groups.presentation.FGAbelian([i]).as_permutation_group().is_isomorphic(groups.presentation.Cyclic(i).as_permutation_group()) for i in [2..35]]) + sage: all(groups.presentation.FGAbelian([i]).as_permutation_group().is_isomorphic(groups.presentation.Cyclic(i).as_permutation_group()) for i in [2..35]) True """ from sage.groups.free_group import _lexi_gen @@ -363,9 +363,10 @@ def DiCyclicPresentation(n): sage: Q = groups.presentation.DiCyclic(2) sage: Q.as_permutation_group().is_isomorphic(QuaternionGroup()) True - sage: all([groups.presentation.DiCyclic(i).as_permutation_group( - ....: ).is_isomorphic(groups.permutation.DiCyclic(i)) for i in [5,8,12,2^5]]) - True + sage: for i in [5, 8, 12, 32]: + ....: A = groups.presentation.DiCyclic(i).as_permutation_group() + ....: B = groups.permutation.DiCyclic(i) + ....: assert A.is_isomorphic(B) sage: groups.presentation.DiCyclic(1) Traceback (most recent call last): ... diff --git a/src/sage/groups/group.pyx b/src/sage/groups/group.pyx index 61a1728ec57..7e70a3de136 100644 --- a/src/sage/groups/group.pyx +++ b/src/sage/groups/group.pyx @@ -213,7 +213,7 @@ cdef class Group(Parent): An element of the group. - EXAMPLES: + EXAMPLES:: sage: G = AbelianGroup([2,3,4,5]) sage: G.an_element() diff --git a/src/sage/groups/libgap_mixin.py b/src/sage/groups/libgap_mixin.py index f91a66f6e47..c014dafed67 100644 --- a/src/sage/groups/libgap_mixin.py +++ b/src/sage/groups/libgap_mixin.py @@ -1,8 +1,8 @@ """ -Mix-in Class for libGAP-based Groups +Mix-in Class for GAP-based Groups This class adds access to GAP functionality to groups such that parent -and element have a ``gap()`` method that returns a libGAP object for +and element have a ``gap()`` method that returns a GAP object for the parent/element. If your group implementation uses libgap, then you should add @@ -222,36 +222,40 @@ def center(self): sage: G = SU(3,GF(2)) sage: G.center() - Matrix group over Finite Field in a of size 2^2 with 1 generators ( + Subgroup with 1 generators ( [a 0 0] [0 a 0] [0 0 a] - ) + ) of Special Unitary Group of degree 3 over Finite Field in a of size 2^2 sage: GL(2,GF(3)).center() - Matrix group over Finite Field of size 3 with 1 generators ( + Subgroup with 1 generators ( [2 0] [0 2] - ) + ) of General Linear Group of degree 2 over Finite Field of size 3 sage: GL(3,GF(3)).center() - Matrix group over Finite Field of size 3 with 1 generators ( + Subgroup with 1 generators ( [2 0 0] [0 2 0] [0 0 2] - ) + ) of General Linear Group of degree 3 over Finite Field of size 3 sage: GU(3,GF(2)).center() - Matrix group over Finite Field in a of size 2^2 with 1 generators ( + Subgroup with 1 generators ( [a + 1 0 0] [ 0 a + 1 0] [ 0 0 a + 1] - ) + ) of General Unitary Group of degree 3 over Finite Field in a of size 2^2 sage: A = Matrix(FiniteField(5), [[2,0,0], [0,3,0], [0,0,1]]) sage: B = Matrix(FiniteField(5), [[1,0,0], [0,1,0], [0,1,1]]) sage: MatrixGroup([A,B]).center() - Matrix group over Finite Field of size 5 with 1 generators ( + Subgroup with 1 generators ( [1 0 0] [0 1 0] [0 0 1] + ) of Matrix group over Finite Field of size 5 with 2 generators ( + [2 0 0] [1 0 0] + [0 3 0] [0 1 0] + [0 0 1], [0 1 1] ) """ G = self.gap() @@ -273,19 +277,27 @@ def intersection(self, other): sage: len(G) # isomorphic to S_3 6 sage: G.intersection(GL(3,ZZ)) - Matrix group over Rational Field with 1 generators ( + Subgroup with 1 generators ( [ 1 0 0] [-2 -1 2] [ 0 0 1] + ) of Matrix group over Rational Field with 2 generators ( + [ 0 1/2 0] [ 0 1/2 0] + [ 2 0 0] [ -2 -1 2] + [ 0 0 1], [ 0 0 1] ) sage: GL(3,ZZ).intersection(G) - Matrix group over Integer Ring with 1 generators ( + Subgroup with 1 generators ( [ 1 0 0] [-2 -1 2] [ 0 0 1] - ) + ) of General Linear Group of degree 3 over Integer Ring sage: G.intersection(SL(3,ZZ)) - Matrix group over Rational Field with 0 generators () + Subgroup with 0 generators () of Matrix group over Rational Field with 2 generators ( + [ 0 1/2 0] [ 0 1/2 0] + [ 2 0 0] [ -2 -1 2] + [ 0 0 1], [ 0 0 1] + ) """ G = self.gap() H = other.gap() diff --git a/src/sage/groups/libgap_morphism.py b/src/sage/groups/libgap_morphism.py index 2545a20a412..7e89603ed2b 100644 --- a/src/sage/groups/libgap_morphism.py +++ b/src/sage/groups/libgap_morphism.py @@ -1,5 +1,5 @@ r""" -Group homomorphisms for groups with a libGAP backend +Group homomorphisms for groups with a GAP backend EXAMPLES:: @@ -38,7 +38,7 @@ class GroupMorphism_libgap(Morphism): r""" - This wraps libGAP group homomorphisms. + This wraps GAP group homomorphisms. Checking if the input defines a group homomorphism can be expensive if the group is large. @@ -57,7 +57,7 @@ class GroupMorphism_libgap(Morphism): sage: A.hom([g^2 for g in A.gens()]) Group endomorphism of Abelian group with gap, generator orders (2, 4) - Homomorphisms can be defined between different kinds of libGAP groups:: + Homomorphisms can be defined between different kinds of GAP groups:: sage: G = MatrixGroup([Matrix(ZZ, 2, [0,1,1,0])]) sage: f = A.hom([G.0, G(1)]) @@ -76,7 +76,7 @@ class GroupMorphism_libgap(Morphism): From: Free Group on generators {a, b} To: Finitely presented group < a, b | a, b^3 > - Homomorphisms can be defined between libGAP groups and permutation groups:: + Homomorphisms can be defined between GAP groups and permutation groups:: sage: S = Sp(4,3) sage: P = PSp(4,3) @@ -142,9 +142,12 @@ class GroupMorphism_libgap(Morphism): sage: a = G.gens()[0]^2 sage: phi = G.hom([a]) sage: phi.kernel() - Matrix group over Finite Field of size 7 with 1 generators ( + Subgroup with 1 generators ( [6 0] [0 1] + ) of Matrix group over Finite Field of size 7 with 1 generators ( + [3 0] + [0 1] ) sage: F = GF(7); MS = MatrixSpace(F,2,2) @@ -172,9 +175,12 @@ class GroupMorphism_libgap(Morphism): The following tests against :trac:`10659`:: sage: phi(H) # indirect doctest - Matrix group over Finite Field of size 7 with 1 generators ( + Subgroup with 1 generators ( [4 0] [0 1] + ) of Matrix group over Finite Field of size 7 with 1 generators ( + [3 0] + [0 1] ) sage: F = GF(5); MS = MatrixSpace(F,2,2) sage: g = MS([1,1,0,1]) @@ -352,14 +358,14 @@ def kernel(self): sage: P = PSp(6,3) sage: pr = Hom(S, P).natural_map() sage: pr.kernel() - Matrix group over Finite Field of size 3 with 1 generators ( + Subgroup with 1 generators ( [2 0 0 0 0 0] [0 2 0 0 0 0] [0 0 2 0 0 0] [0 0 0 2 0 0] [0 0 0 0 2 0] [0 0 0 0 0 2] - ) + ) of Symplectic Group of degree 6 over Finite Field of size 3 """ dom = self.domain() return dom._subgroup_constructor(self.gap().Kernel()) @@ -400,9 +406,7 @@ def pushforward(self, J, *args, **kwds): sage: pr = Hom(G, P).natural_map() sage: GS = G.subgroup([G.gen(0)]) sage: pr.pushforward(GS) - Subgroup of (The projective general unitary group of degree 3 - over Finite Field of size 2) generated by - [(3,4,5)(10,18,14)(11,19,15)(12,20,16)(13,21,17)] + Subgroup generated by [(3,4,5)(10,18,14)(11,19,15)(12,20,16)(13,21,17)] of (The projective general unitary group of degree 3 over Finite Field of size 2) """ dom = self.domain() codom = self.codomain() @@ -461,7 +465,7 @@ def _call_(self, g): [1 0 0 0 0 0], [-1 0 0 0 0 0] ] sage: f(O) # long time - Matrix group over Rational Field with 6 generators + Subgroup with 6 generators of Weyl Group of type ['D', 6] (as a matrix group acting on the ambient space) sage: f(O).gens() # long time ( [1 0 0 0 0 0] [1 0 0 0 0 0] [1 0 0 0 0 0] [ 0 0 0 0 -1 0] @@ -533,17 +537,17 @@ def preimage(self, S): sage: pr = Hom(S, P).natural_map() sage: PS = P.subgroup([P.gen(0)]) sage: pr.preimage(PS) - Matrix group over Finite Field of size 3 with 2 generators ( + Subgroup with 2 generators ( [2 0 0 0] [1 0 0 0] [0 2 0 0] [0 2 0 0] [0 0 2 0] [0 0 2 0] [0 0 0 2], [0 0 0 1] - ) + ) of Symplectic Group of degree 4 over Finite Field of size 3 """ phi = self.gap() from sage.groups.perm_gps.permgroup import PermutationGroup_generic if not isinstance(S, (ParentLibGAP, PermutationGroup_generic)): - raise TypeError("%s must be a libGAP or permutation group of %s"%(S, self)) + raise TypeError("%s must be a GAP or permutation group of %s"%(S, self)) if not self.codomain().gap().IsSubgroup(S.gap()).sage(): raise ValueError("%s must be a subgroup of %s"%(S, self)) preimage = phi.PreImage(S.gap()) diff --git a/src/sage/groups/libgap_wrapper.pyx b/src/sage/groups/libgap_wrapper.pyx index 0cc181cb684..aa623c8dae8 100644 --- a/src/sage/groups/libgap_wrapper.pyx +++ b/src/sage/groups/libgap_wrapper.pyx @@ -5,7 +5,7 @@ This module provides helper class for wrapping GAP groups via :mod:`~sage.libs.gap.libgap`. See :mod:`~sage.groups.free_group` for an example how they are used. -The parent class keeps track of the libGAP element object, to use it +The parent class keeps track of the GAP element object, to use it in your Python parent you have to derive both from the suitable group parent and :class:`ParentLibGAP` :: @@ -234,7 +234,7 @@ class ParentLibGAP(SageObject): sage: diagonals = itertools.product((1,-1), repeat=3) sage: subgroup_gens = [diagonal_matrix(L) for L in diagonals] sage: G.subgroup(subgroup_gens) - Matrix group over Rational Field with 8 generators + Subgroup with 8 generators of Matrix group over Rational Field with 48 generators """ generators = [ g if isinstance(g, GapElement) else self(g).gap() @@ -292,7 +292,7 @@ class ParentLibGAP(SageObject): A :class:`~sage.libs.gap.element.GapElement` - EXAMPLES: + EXAMPLES:: sage: G = FreeGroup(2) sage: G._gap_gens() diff --git a/src/sage/groups/lie_gps/nilpotent_lie_group.py b/src/sage/groups/lie_gps/nilpotent_lie_group.py index e334c2875ef..78001d2e9be 100644 --- a/src/sage/groups/lie_gps/nilpotent_lie_group.py +++ b/src/sage/groups/lie_gps/nilpotent_lie_group.py @@ -911,7 +911,7 @@ def _repr_(self): Supports printing in exponential coordinates of the first and second kinds, depending on the default coordinate system. - EXAMPLES: + EXAMPLES:: sage: L = LieAlgebra(QQ, 2, step=2) sage: G = L.lie_group('H') diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index e3dc2bd1ace..15793019c5b 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -21,10 +21,10 @@ sage: SL2Z = SL(2,ZZ) sage: S, T = SL2Z.gens() sage: SL2Z.subgroup([T^2]) - Matrix group over Integer Ring with 1 generators ( + Subgroup with 1 generators ( [1 2] [0 1] - ) + ) of Special Linear Group of degree 2 over Integer Ring AUTHORS: @@ -48,6 +48,7 @@ - Volker Braun (2013-1) port to new Parent, libGAP. - Sebastian Oehms (2018-07): Added _permutation_group_element_ (Trac #25706) +- Sebastian Oehms (2019-01): Revision of :trac:`25706` (:trac:`26903`and :trac:`27143`). """ ############################################################################## @@ -205,6 +206,7 @@ def QuaternionMatrixGroupGF3(): jay = MS([2,1,1,1]) return MatrixGroup([aye, jay]) + def MatrixGroup(*gens, **kwds): r""" Return the matrix group with given generators. @@ -512,7 +514,7 @@ def __reduce__(self): return (MatrixGroup, tuple(g.matrix() for g in self.gens()) + ({'check':False},)) - def as_permutation_group(self, algorithm=None): + def as_permutation_group(self, algorithm=None, seed=None): r""" Return a permutation group representation for the group. @@ -527,13 +529,19 @@ def as_permutation_group(self, algorithm=None): - ``algorithm`` -- ``None`` or ``'smaller'``. In the latter case, try harder to find a permutation representation of small degree. + - ``seed`` -- ``None`` or an integer specifying the seed + to fix results depending on pseudo-random-numbers. Here + it makes sense to be used with respect to the ``'smaller'`` + option, since gap produces random output in that context. OUTPUT: A permutation group isomorphic to ``self``. The ``algorithm='smaller'`` option tries to return an isomorphic group of low degree, but is not guaranteed to find the - smallest one. + smallest one and must not even differ from the one obtained + without the option. In that case repeating the invocation + may help (see the example below). EXAMPLES:: @@ -550,25 +558,42 @@ def as_permutation_group(self, algorithm=None): sage: G = MatrixGroup(GG.GeneratorsOfGroup()) sage: G.cardinality() 21499084800 - sage: set_random_seed(0); current_randstate().set_seed_gap() sage: P = G.as_permutation_group() + sage: Psmaller = G.as_permutation_group(algorithm="smaller", seed=6) + sage: P == Psmaller # see the note below + True + sage: Psmaller = G.as_permutation_group(algorithm="smaller") + sage: P == Psmaller + False sage: P.cardinality() 21499084800 - sage: P.degree() # random output + sage: P.degree() 144 - sage: set_random_seed(3); current_randstate().set_seed_gap() - sage: Psmaller = G.as_permutation_group(algorithm="smaller") sage: Psmaller.cardinality() 21499084800 - sage: Psmaller.degree() # random output - 108 + sage: Psmaller.degree() + 80 + + .. NOTE:: - In this case, the "smaller" option returned an isomorphic group of - lower degree. The above example used GAP's library of irreducible - maximal finite ("imf") integer matrix groups to construct the - MatrixGroup G over GF(7). The section "Irreducible Maximal Finite - Integral Matrix Groups" in the GAP reference manual has more - details. + In this case, the "smaller" option returned an isomorphic + group of lower degree. The above example used GAP's library + of irreducible maximal finite ("imf") integer matrix groups + to construct the MatrixGroup G over GF(7). The section + "Irreducible Maximal Finite Integral Matrix Groups" in the + GAP reference manual has more details. + + .. NOTE:: + + Concerning the option ``algorithm='smaller'`` you should note + the following from GAP documentation: "The methods used might + involve the use of random elements and the permutation + representation (or even the degree of the representation) is + not guaranteed to be the same for different calls of + SmallerDegreePermutationRepresentation." + + To obtain a reproducible result the optional argument ``seed`` + may be used as in the example above. TESTS:: @@ -580,8 +605,8 @@ def as_permutation_group(self, algorithm=None): The above example in GL(12,Z), reduced modulo 7:: - sage: MS = MatrixSpace( GF(7), 12, 12) - sage: G = MatrixGroup(map(MS, GG.GeneratorsOfGroup())) + sage: MS = MatrixSpace(GF(7), 12, 12) + sage: G = MatrixGroup([MS(g) for g in GG.GeneratorsOfGroup()]) sage: G.cardinality() 21499084800 sage: P = G.as_permutation_group() @@ -593,12 +618,12 @@ def as_permutation_group(self, algorithm=None): sage: Sp(6,3).as_permutation_group().cardinality() 9170703360 - Check that ``_permutation_group_morphism`` works (:trac:`25706`):: + Check that :trac:`25706` still works after :trac:`26903`:: sage: MG = GU(3,2).as_matrix_group() - sage: PG = MG.as_permutation_group() # this constructs the morphism + sage: PG = MG.as_permutation_group() sage: mg = MG.an_element() - sage: MG._permutation_group_morphism(mg) + sage: PG(mg) (1,2,6,19,35,33)(3,9,26,14,31,23)(4,13,5)(7,22,17)(8,24,12)(10,16,32,27,20,28)(11,30,18)(15,25,36,34,29,21) """ # Note that the output of IsomorphismPermGroup() depends on @@ -607,21 +632,15 @@ def as_permutation_group(self, algorithm=None): from sage.groups.perm_gps.permgroup import PermutationGroup if not self.is_finite(): raise NotImplementedError("Group must be finite.") + if seed is not None: + from sage.libs.gap.libgap import libgap + libgap.set_seed(ZZ(seed)) iso=self._libgap_().IsomorphismPermGroup() if algorithm == "smaller": iso=iso.Image().SmallerDegreePermutationRepresentation() - PG = PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), \ - canonicalize=False) # applying gap() - as PermutationGroup is not libGAP - - def permutation_group_map(element): - return PG(iso.ImageElm(element.gap()).sage()) - - from sage.categories.homset import Hom - self._permutation_group_morphism = Hom(self, PG)(permutation_group_map) - - return PG + return PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), \ + canonicalize=False) - _permutation_group_ = as_permutation_group def module_composition_factors(self, algorithm=None): r""" diff --git a/src/sage/groups/matrix_gps/isometries.py b/src/sage/groups/matrix_gps/isometries.py index ca297186555..3a3c35d0dbc 100644 --- a/src/sage/groups/matrix_gps/isometries.py +++ b/src/sage/groups/matrix_gps/isometries.py @@ -237,7 +237,7 @@ def _get_action_(self, S, op, self_on_left): if is_FGP_Module(S): if S.is_submodule(T): V = S.V() - if all([V==V*f.matrix() for f in self.gens()]): + if all(V == V * f.matrix() for f in self.gens()): return GroupActionOnQuotientModule(self, S) return None diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index a5af99a441b..2e19fcabfab 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -35,6 +35,8 @@ - Simon King (2010-05): Improve invariant_generators by using GAP for the construction of the Reynolds operator in Singular. + +- Sebastian Oehms (2018-07): Add :meth:`subgroup` and :meth:`ambient` see :trac:`25894` """ # **************************************************************************** @@ -102,6 +104,8 @@ class MatrixGroup_base(Group): method. """ + _ambient = None # internal attribute to register the ambient group in case this instance is a subgroup + def _check_matrix(self, x, *args): """ Check whether the matrix ``x`` defines a group element. @@ -166,6 +170,82 @@ def as_matrix_group(self): from sage.groups.matrix_gps.finitely_generated import MatrixGroup return MatrixGroup(self.gens()) + + def subgroup(self, generators, check=True): + """ + Return the subgroup generated by the given generators. + + INPUT: + + - ``generators`` -- a list/tuple/iterable of group elements of self + - ``check`` -- boolean (optional, default: ``True``). Whether to check that each matrix is invertible. + + OUTPUT: The subgroup generated by ``generators`` as an instance of FinitelyGeneratedMatrixGroup_gap + + EAMPLES:: + + sage: UCF = UniversalCyclotomicField() + sage: G = GL(3, UCF) + sage: e3 = UCF.gen(3); e5 =UCF.gen(5) + sage: m = matrix(UCF, 3,3, [[e3, 1, 0], [0, e5, 7],[4, 3, 2]]) + sage: S = G.subgroup([m]); S + Subgroup with 1 generators ( + [E(3) 1 0] + [ 0 E(5) 7] + [ 4 3 2] + ) of General Linear Group of degree 3 over Universal Cyclotomic Field + + sage: CF3 = CyclotomicField(3) + sage: G = GL(3, CF3) + sage: e3 = CF3.gen() + sage: m = matrix(CF3, 3,3, [[e3, 1, 0], [0, ~e3, 7],[4, 3, 2]]) + sage: S = G.subgroup([m]); S + Subgroup with 1 generators ( + [ zeta3 1 0] + [ 0 -zeta3 - 1 7] + [ 4 3 2] + ) of General Linear Group of degree 3 over Cyclotomic Field of order 3 and degree 2 + + TESTS:: + + sage: TestSuite(G).run() + sage: TestSuite(S).run() + """ + # this method enlarges the method with same name of ParentLibGAP to cases where the ambient group is not inheritet from ParentLibGAP. + if isinstance(self, ParentLibGAP): + return ParentLibGAP.subgroup(self, generators) + + for g in generators: + if g not in self: + raise ValueError("generator %s is not in the group"%(g)) + + from sage.groups.matrix_gps.finitely_generated import MatrixGroup + subgroup = MatrixGroup(generators, check=check) + subgroup._ambient = self + return subgroup + + def ambient(self): + """ + Return the ambient group of a subgroup. + + OUTPUT: + + A group containing ``self``. If ``self`` has not been defined + as a subgroup, we just return ``self``. + + EXAMPLES:: + + sage: G = GL(2,QQ) + sage: m = matrix(QQ, 2,2, [[3, 0],[~5,1]]) + sage: S = G.subgroup([m]) + sage: S.ambient() is G + True + """ + if self._ambient is None: + return self + else: + return self._ambient + def _repr_(self): """ Return a string representation. @@ -184,14 +264,37 @@ def _repr_(self): [1 2] [1 1] [4 1], [0 1] ) + + case of being a subroup:: + + sage: CF3 = CyclotomicField(3) + sage: G = GL(2, CF3) + sage: e3 = CF3.gen() + sage: m = matrix(CF3, 2,2, [[e3, 1], [0, ~e3]]) + sage: S = G.subgroup([m]); S + Subgroup with 1 generators ( + [ zeta3 1] + [ 0 -zeta3 - 1] + ) of General Linear Group of degree 2 over Cyclotomic Field of order 3 and degree 2 """ - if self.ngens() > 5: - return 'Matrix group over {0} with {1} generators'.format( - self.base_ring(), self.ngens()) + ambient_group = self._ambient + + if ambient_group == None: + if self.ngens() > 5: + return 'Matrix group over {0} with {1} generators'.format( + self.base_ring(), self.ngens()) + else: + from sage.repl.display.util import format_list + return 'Matrix group over {0} with {1} generators {2}'.format( + self.base_ring(), self.ngens(), format_list(self.gens())) else: - from sage.repl.display.util import format_list - return 'Matrix group over {0} with {1} generators {2}'.format( - self.base_ring(), self.ngens(), format_list(self.gens())) + if self.ngens() > 5: + return 'Subgroup with {0} generators of {1}'.format( + self.ngens(), ambient_group) + else: + from sage.repl.display.util import format_list + return 'Subgroup with {0} generators {1} of {2}'.format( + self.ngens(), format_list(self.gens()), ambient_group) def _repr_option(self, key): """ @@ -608,10 +711,10 @@ def _subgroup_constructor(self, libgap_subgroup): sage: SL2Z = SL(2,ZZ) sage: S, T = SL2Z.gens() sage: G = SL2Z.subgroup([T^2]); G # indirect doctest - Matrix group over Integer Ring with 1 generators ( + Subgroup with 1 generators ( [1 2] [0 1] - ) + ) of Special Linear Group of degree 2 over Integer Ring sage: G.ambient() is SL2Z True """ diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 35c8101112d..80d781be4a7 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -171,12 +171,13 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): if not invariant_form.is_symmetric(): raise ValueError("invariant_form must be symmetric") - inserted_text = 'with respect to symmetrc form' try: - if not invariant_form.is_positive_definite(): - inserted_text = 'with respect to non positive definite symmetrc form' - except: - pass + if invariant_form.is_positive_definite(): + inserted_text = "with respect to positive definite symmetric form" + else: + inserted_text = "with respect to non positive definite symmetric form" + except ValueError: + inserted_text = "with respect to symmetric form" name = '{0} Orthogonal Group of degree {1} over {2} {3}\n{4}'.format( prefix, degree, ring, inserted_text,invariant_form) @@ -295,6 +296,11 @@ def GO(n, R, e=0, var='a', invariant_form=None): NotImplementedError: invariant_form for finite groups is fixed by GAP sage: 5+5 10 + sage: R. = ZZ[] + sage: GO(2, R, invariant_form=[[x,0],[0,1]]) + General Orthogonal Group of degree 2 over Univariate Polynomial Ring in x over Integer Ring with respect to symmetric form + [x 0] + [0 1] TESTS:: @@ -441,7 +447,7 @@ class OrthogonalMatrixGroup_generic(NamedMatrixGroup_generic): sage: m=matrix(CF3, 3,3, [[1,e3,0],[e3,2,0],[0,0,1]]) sage: G = SO(3, CF3, invariant_form=m) sage: latex(G) - \text{SO}_{3}(\Bold{Q}(\zeta_{3}))\text{ with respect to non positive definite symmetrc form }\left(\begin{array}{rrr} + \text{SO}_{3}(\Bold{Q}(\zeta_{3}))\text{ with respect to non positive definite symmetric form }\left(\begin{array}{rrr} 1 & \zeta_{3} & 0 \\ \zeta_{3} & 2 & 0 \\ 0 & 0 & 1 diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index 7f0f3715f7c..cefb9b5223b 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -118,15 +118,16 @@ def _UG(n, R, special, var='a', invariant_form=None): if not invariant_form.is_hermitian(): raise ValueError("invariant_form must be hermitian") - inserted_text = 'with respect to hermitian form' try: - if not invariant_form.is_positive_definite(): - inserted_text = 'with respect to non positive definite hermitian form' - except: - pass + if invariant_form.is_positive_definite(): + inserted_text = "with respect to positive definite hermitian form" + else: + inserted_text = "with respect to non positive definite hermitian form" + except ValueError: + inserted_text = "with respect to hermitian form" name = '{0} Unitary Group of degree {1} over {2} {3}\n{4}'.format(prefix, - degree, ring, inserted_text,invariant_form) + degree, ring, inserted_text, invariant_form) ltx = r'\text{{{0}U}}_{{{1}}}({2})\text{{ {3} }}{4}'.format(latex_prefix, degree, latex(ring), inserted_text, latex(invariant_form)) else: @@ -375,7 +376,7 @@ class UnitaryMatrixGroup_generic(NamedMatrixGroup_generic): sage: m=matrix(CF3, 3,3, [[1,e3,0],[e3.conjugate(),2,0],[0,0,1]]) sage: G = SU(3, CF3, invariant_form=m) sage: latex(G) - \text{SU}_{3}(\Bold{Q}(\zeta_{3}))\text{ with respect to hermitian form }\left(\begin{array}{rrr} + \text{SU}_{3}(\Bold{Q}(\zeta_{3}))\text{ with respect to positive definite hermitian form }\left(\begin{array}{rrr} 1 & \zeta_{3} & 0 \\ -\zeta_{3} - 1 & 2 & 0 \\ 0 & 0 & 1 diff --git a/src/sage/groups/perm_gps/cubegroup.py b/src/sage/groups/perm_gps/cubegroup.py index f449a7bd989..23372d86d69 100644 --- a/src/sage/groups/perm_gps/cubegroup.py +++ b/src/sage/groups/perm_gps/cubegroup.py @@ -85,29 +85,28 @@ 2002. """ -#************************************************************************************** +# ***************************************************************************** # Copyright (C) 2006 David Joyner # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#************************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from __future__ import print_function from six.moves import range -from sage.groups.perm_gps.permgroup import PermutationGroup, PermutationGroup_generic +from sage.groups.perm_gps.permgroup import PermutationGroup_generic import random from sage.structure.sage_object import SageObject from sage.structure.richcmp import richcmp, richcmp_method -from sage.rings.all import RationalField, Integer, RDF -#from sage.matrix.all import MatrixSpace +from sage.rings.all import RDF from sage.interfaces.all import gap from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.plot.polygon import polygon from sage.plot.text import text pi = RDF.pi() - +from sage.rings.rational_field import QQ from sage.plot.plot3d.shapes import Box from sage.plot.plot3d.texture import Texture @@ -131,7 +130,7 @@ ######################################################### #written by Tom Boothby, placed in the public domain -def xproj(x,y,z,r): +def xproj(x, y, z, r): r""" Return the `x`-projection of `(x,y,z)` rotated by `r`. @@ -144,7 +143,8 @@ def xproj(x,y,z,r): """ return (y*r[1] - x*r[3])*r[2] -def yproj(x,y,z,r): + +def yproj(x, y, z, r): r""" Return the `y`-projection of `(x,y,z)` rotated by `r`. @@ -157,7 +157,8 @@ def yproj(x,y,z,r): """ return z*r[2] - (x*r[1] + y*r[2])*r[0] -def rotation_list(tilt,turn): + +def rotation_list(tilt, turn): r""" Return a list `[\sin(\theta), \sin(\phi), \cos(\theta), \cos(\phi)]` of rotations where `\theta` is ``tilt`` and `\phi` is ``turn``. @@ -169,7 +170,9 @@ def rotation_list(tilt,turn): [0.49999999999999994, 0.7071067811865475, 0.8660254037844387, 0.7071067811865476] """ from sage.functions.all import sin, cos - return [ sin(tilt*pi/180.0), sin(turn*pi/180.0), cos(tilt*pi/180.0), cos(turn*pi/180.0) ] + return [sin(tilt*pi/180.0), sin(turn*pi/180.0), + cos(tilt*pi/180.0), cos(turn*pi/180.0)] + def polygon_plot3d(points, tilt=30, turn=30, **kwargs): r""" @@ -191,8 +194,9 @@ def polygon_plot3d(points, tilt=30, turn=30, **kwargs): sage: from sage.groups.perm_gps.cubegroup import polygon_plot3d,green sage: P = polygon_plot3d([[1,3,1],[2,3,1],[2,3,2],[1,3,2],[1,3,1]],rgbcolor=green) """ - rot = rotation_list(tilt,turn) - points2 = [(xproj(x,y,z,rot), yproj(x,y,z,rot)) for (x,y,z) in points ] + rot = rotation_list(tilt, turn) + points2 = [(xproj(x, y, z, rot), yproj(x, y, z, rot)) + for (x, y, z) in points] return polygon(points2, **kwargs) ########################################################### @@ -214,6 +218,7 @@ def inv_list(lst): """ return [lst.index(i) + 1 for i in range(1, 1 + len(lst))] + face_polys = { ### bottom layer L, F, R, B 'ldb': [[-3,0],[-2,0], [-2,1], [-3,1]], #square labeled 14 @@ -276,6 +281,7 @@ def inv_list(lst): 'ubr': [[2,6],[3,6], [3,5], [2,5]], #square labeled 3 } + def create_poly(face, color): """ Create the polygon given by ``face`` with color ``color``. @@ -354,6 +360,7 @@ def index2singmaster(facet): """ return singmaster_indices[facet] + def color_of_square(facet, colors=['lpurple', 'yellow', 'red', 'green', 'orange', 'blue']): """ Return the color the facet has in the solved state. @@ -364,7 +371,8 @@ def color_of_square(facet, colors=['lpurple', 'yellow', 'red', 'green', 'orange' sage: color_of_square(41) 'blue' """ - return colors[(facet-1) // 8] + return colors[(facet - 1) // 8] + cubie_center_list = { # centers of the cubies on the F,U, R faces @@ -394,6 +402,7 @@ def color_of_square(facet, colors=['lpurple', 'yellow', 'red', 'green', 'orange' 32: [1//2, 5//2, 1//2], # rbd } + def cubie_centers(label): r""" Return the cubie center list element given by ``label``. @@ -406,7 +415,8 @@ def cubie_centers(label): """ return cubie_center_list[label] -def cubie_colors(label,state0): + +def cubie_colors(label, state0): r""" Return the color of the cubie given by ``label`` at ``state0``. @@ -446,6 +456,7 @@ def cubie_colors(label,state0): if label == 31: return [clr_any,clr_any,named_colors[color_of_square(state[31-1])]] # rd, if label == 32: return [clr_any,clr_any,named_colors[color_of_square(state[32-1])]] #rbd, + def plot3d_cubie(cnt, clrs): r""" Plot the front, up and right face of a cubie centered at cnt and @@ -459,17 +470,19 @@ def plot3d_cubie(cnt, clrs): sage: clrF = blue; clrU = red; clrR = green sage: P = plot3d_cubie([1/2,1/2,1/2],[clrF,clrU,clrR]) """ - x = cnt[0]-1/2; y = cnt[1]-1/2; z = cnt[2]-1/2 + half = QQ((1, 2)) + x = cnt[0] - half + y = cnt[1] - half + z = cnt[2] - half #ptsD = [[x+0,y+0,0+z],[x+1,y+0,0+z],[x+1,y+1,0+z],[x+0,y+1,0+z],[x+0,y+0,0+z]] ptsF = [[x+1,y+0,0+z],[x+1,y+1,0+z],[x+1,y+1,1+z],[x+1,y+0,1+z],[x+1,y+0,0+z]] #ptsB = [[x+0,y+0,0+z],[x+0,y+1,0+z],[x+0,y+1,1+z],[x+0,y+0,1+z],[x+0,y+0,0+z]] ptsU = [[x+0,y+0,1+z],[x+1,y+0,1+z],[x+1,y+1,1+z],[x+0,y+1,1+z],[x+0,y+0,1+z]] #ptsL = [[x+0,y+0,0+z],[x+1,y+0,0+z],[x+1,y+0,1+z],[x+0,y+0,1+z],[x+0,y+0,0+z]] ptsR = [[x+0,y+1,0+z],[x+1,y+1,0+z],[x+1,y+1,1+z],[x+0,y+1,1+z],[x+0,y+1,0+z]] - PR = polygon_plot3d(ptsR,rgbcolor=clrs[2]) - PU = polygon_plot3d(ptsU,rgbcolor=clrs[1]) - PF = polygon_plot3d(ptsF,rgbcolor=clrs[0]) - P = PR+PF+PU + P = polygon_plot3d(ptsR, rgbcolor=clrs[2]) + P += polygon_plot3d(ptsU, rgbcolor=clrs[1]) + P += polygon_plot3d(ptsF, rgbcolor=clrs[0]) P.axes(show=False) return P @@ -960,9 +973,6 @@ def plot3d_cube(self,mv,title=True): """ g = self.parse(mv) state = self.facets(g) - clr_any = white - shown_labels = list(range(1, 9)) + list(range(17, 33)) - clr = [color_of_square(state[c-1]) for c in shown_labels] cubiesR = [plot3d_cubie(cubie_centers(c),cubie_colors(c,state)) for c in [32,31,30,29,28,27,26,25]] cubeR = sum(cubiesR) cubiesU = [plot3d_cubie(cubie_centers(c),cubie_colors(c,state)) for c in range(1,9)] @@ -1064,8 +1074,6 @@ def solve(self,state, algorithm='default'): g.word_problem([b,d,f,l,r,u]), though the output will be less intuitive). """ - from sage.groups.perm_gps.permgroup import PermutationGroup - from sage.interfaces.all import gap try: g = self.parse(state) except TypeError: @@ -1079,7 +1087,7 @@ def solve(self,state, algorithm='default'): sol = str(soln) names = self.gen_names() for i in range(6): - sol = sol.replace("x%s" % (i+1), names[i]) + sol = sol.replace("x%s" % (i + 1), names[i]) return sol diff --git a/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx b/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx index ecffa82b7cd..35c441ab0c7 100644 --- a/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +++ b/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx @@ -353,7 +353,7 @@ cdef agcl_work_space *allocate_agcl_work_space(int n): work_space.orbits_of_subgroup is NULL or \ work_space.orbits_of_permutation is NULL or \ work_space.first_ps is NULL: - deallocate_agcl_work_space(work_space) + sig_free(work_space) return NULL work_space.perm_stack = int_array diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx index 31938b8944e..b4aa2bcbcf8 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx @@ -115,7 +115,8 @@ cdef class LinearBinaryCodeStruct(BinaryCodeStruct): partition -- an optional list of lists partition of the columns. default is the unit partition. - EXAMPLES: + EXAMPLES:: + sage: from sage.groups.perm_gps.partn_ref.refinement_binary import LinearBinaryCodeStruct sage: B = LinearBinaryCodeStruct(matrix(GF(2),[[1,0,1],[0,1,1]])) @@ -301,7 +302,8 @@ cdef class LinearBinaryCodeStruct(BinaryCodeStruct): """ Calculate whether self is isomorphic to other. - EXAMPLES: + EXAMPLES:: + sage: from sage.groups.perm_gps.partn_ref.refinement_binary import LinearBinaryCodeStruct sage: B = LinearBinaryCodeStruct(Matrix(GF(2), [[1,1,1,1,0,0],[0,0,1,1,1,1]])) @@ -463,7 +465,8 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): partition -- an optional list of lists partition of the columns. default is the unit partition. - EXAMPLES: + EXAMPLES:: + sage: from sage.groups.perm_gps.partn_ref.refinement_binary import NonlinearBinaryCodeStruct sage: B = NonlinearBinaryCodeStruct(Matrix(GF(2), [[1,0,0,0],[0,0,1,0]])) @@ -562,7 +565,8 @@ cdef class NonlinearBinaryCodeStruct(BinaryCodeStruct): """ Calculate whether self is isomorphic to other. - EXAMPLES: + EXAMPLES:: + sage: from sage.groups.perm_gps.partn_ref.refinement_binary import NonlinearBinaryCodeStruct sage: B = NonlinearBinaryCodeStruct(Matrix(GF(2), [[1,1,1,1,0,0],[0,0,1,1,1,1]])) diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pyx index ef000ae8a3c..55b6799792f 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pyx @@ -33,7 +33,6 @@ from libc.string cimport memcmp from .data_structures cimport * include "sage/data_structures/bitset.pxi" from sage.rings.integer cimport Integer -from sage.misc.misc import uniq from sage.matrix.constructor import Matrix from .refinement_binary cimport NonlinearBinaryCodeStruct, refine_by_bip_degree from .double_coset cimport double_coset @@ -49,10 +48,10 @@ cdef class MatrixStruct: cdef NonlinearBinaryCodeStruct S_temp self.matrix = matrix - self.symbols = uniq(self.matrix.list()) - if 0 in self.symbols: - self.symbols.remove(0) - self.nsymbols = len(self.symbols) + symbols = set(self.matrix.list()) + symbols.discard(0) + self.symbols = sorted(symbols) + self.nsymbols = len(symbols) self.symbol_structs = [] num_rows = sig_malloc(self.nsymbols * sizeof(int)) @@ -65,8 +64,9 @@ cdef class MatrixStruct: for i from 0 <= i < self.nsymbols: num_rows[i] = 0 for row in self.matrix.rows(): - row = uniq(row.list()) - if 0 in row: row.remove(0) + row = set(row.list()) + if 0 in row: + row.remove(0) for s in row: num_rows[self.symbols.index(s)] += 1 for i from 0 <= i < self.nsymbols: diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx index 3eebaf91c89..22cc10c4862 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx @@ -378,17 +378,15 @@ def sets_isom_py(generators, set1, set2): False sage: sets_isom_py([[2,3,0,1]], [0,1,3], [1,2,3]) [2, 3, 0, 1] - - """ - from sage.misc.misc import uniq - set1 = uniq(set1) - set2 = uniq(set2) - if len(generators) == 0: + set1 = set(set1) + set2 = set(set2) + if not generators: if set1 == set2: return list(xrange(max(set1) + 1)) else: return False + cdef int i, j, n = len(generators[0]), n_gens = len(generators) cdef StabilizerChain *supergroup = SC_new(n) cdef int *gens = sig_malloc(n*n_gens * sizeof(int)) diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index a161b419cf9..7727769e9f1 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -361,7 +361,7 @@ class PermutationGroup_generic(FiniteGroup): sage: G Permutation Group with generators [(3,4), (1,2,3)(4,5)] sage: G.center() - Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) sage: G.group_id() [120, 34] sage: n = G.order(); n @@ -384,8 +384,6 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, - ``canonicalize`` - bool (default: ``True``); if ``True``, sort generators and remove duplicates - - ``domain`` - a (sorted) list of integers; (default: ``None``) - OUTPUT: - A permutation group. @@ -400,7 +398,7 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, sage: A4.__init__([[(1,2,3)],[(2,3,4)]]); A4 Permutation Group with generators [(2,3,4), (1,2,3)] sage: A4.center() - Subgroup of (Permutation Group with generators [(2,3,4), (1,2,3)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(2,3,4), (1,2,3)]) sage: A4.category() Category of finite enumerated permutation groups sage: TestSuite(A4).run() @@ -873,6 +871,19 @@ def _coerce_map_from_(self, G): ....: if f is not None and g is not None: ....: h = G3.coerce_map_from(G1) ....: assert h(elt) == g(f(elt)) + + Check that :trac:`26903` is fixed:: + + sage: G = SO(4,3,-1) + sage: P = G.as_permutation_group(algorithm='smaller', seed=5) + sage: P1 = G.as_permutation_group() + sage: P == P1 + False + sage: g1, g2, g3 = G.gens() + sage: P(g1*g2) + (1,9,7,6)(2,10)(3,11)(4,5,8,12) + sage: P1(g1*g2) + (1,4,13,11)(2,5,14,18)(3,15,8,16)(6,7)(9,20,19,12)(10,17) """ if isinstance(G, PermutationGroup_subgroup): if G._ambient_group is self: @@ -882,16 +893,16 @@ def _coerce_map_from_(self, G): if isinstance(G, PermutationGroup_generic): if G.is_subgroup(self): return True - if hasattr(G, "_permutation_group_"): - # see if this permutation group has been constructed by an as_permutation_group method (Trac #25706) - PG = G._permutation_group_() - # _permutation_group_element is a morphism - if hasattr(G, '_permutation_group_morphism'): - if PG is self: - return G._permutation_group_morphism - if self.has_coerce_map_from(PG): - return self.coerce_map_from(PG) * G._permutation_group_morphism - + from sage.groups.libgap_wrapper import ParentLibGAP + if isinstance(G, ParentLibGAP): + from sage.categories.homset import Hom + try: + nat = Hom(G, self).natural_map() + from sage.groups.libgap_morphism import GroupMorphism_libgap + if isinstance(nat, GroupMorphism_libgap): + return nat + except TypeError: + pass return super(PermutationGroup_generic, self)._coerce_map_from_(G) def list(self): @@ -1582,9 +1593,9 @@ def stabilizer(self, point, action="OnPoints"): sage: G = PermutationGroup([ [(3,4)], [(1,3)] ]) sage: G.stabilizer(1) - Subgroup of (Permutation Group with generators [(3,4), (1,3)]) generated by [(3,4)] + Subgroup generated by [(3,4)] of (Permutation Group with generators [(3,4), (1,3)]) sage: G.stabilizer(3) - Subgroup of (Permutation Group with generators [(3,4), (1,3)]) generated by [(1,4)] + Subgroup generated by [(1,4)] of (Permutation Group with generators [(3,4), (1,3)]) The stabilizer of a set of points:: @@ -1598,24 +1609,24 @@ def stabilizer(self, point, action="OnPoints"): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]]) sage: G.stabilizer(10) - Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3,4), (1,2)(3,4)] + Subgroup generated by [(2,3,4), (1,2)(3,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) sage: G.stabilizer(1) - Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3)(4,10), (2,10,4)] + Subgroup generated by [(2,3)(4,10), (2,10,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) sage: G = PermutationGroup([[(2,3,4)],[(6,7)]]) sage: G.stabilizer(1) - Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7), (2,3,4)] + Subgroup generated by [(6,7), (2,3,4)] of (Permutation Group with generators [(6,7), (2,3,4)]) sage: G.stabilizer(2) - Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7)] + Subgroup generated by [(6,7)] of (Permutation Group with generators [(6,7), (2,3,4)]) sage: G.stabilizer(3) - Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7)] + Subgroup generated by [(6,7)] of (Permutation Group with generators [(6,7), (2,3,4)]) sage: G.stabilizer(4) - Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7)] + Subgroup generated by [(6,7)] of (Permutation Group with generators [(6,7), (2,3,4)]) sage: G.stabilizer(5) - Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(6,7), (2,3,4)] + Subgroup generated by [(6,7), (2,3,4)] of (Permutation Group with generators [(6,7), (2,3,4)]) sage: G.stabilizer(6) - Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(2,3,4)] + Subgroup generated by [(2,3,4)] of (Permutation Group with generators [(6,7), (2,3,4)]) sage: G.stabilizer(7) - Subgroup of (Permutation Group with generators [(6,7), (2,3,4)]) generated by [(2,3,4)] + Subgroup generated by [(2,3,4)] of (Permutation Group with generators [(6,7), (2,3,4)]) sage: G.stabilizer(8) Traceback (most recent call last): ... @@ -1625,13 +1636,13 @@ def stabilizer(self, point, action="OnPoints"): sage: G = PermutationGroup([ [('c','d')], [('a','c')] ], domain='abcd') sage: G.stabilizer('a') - Subgroup of (Permutation Group with generators [('c','d'), ('a','c')]) generated by [('c','d')] + Subgroup generated by [('c','d')] of (Permutation Group with generators [('c','d'), ('a','c')]) sage: G.stabilizer('b') - Subgroup of (Permutation Group with generators [('c','d'), ('a','c')]) generated by [('c','d'), ('a','c')] + Subgroup generated by [('c','d'), ('a','c')] of (Permutation Group with generators [('c','d'), ('a','c')]) sage: G.stabilizer('c') - Subgroup of (Permutation Group with generators [('c','d'), ('a','c')]) generated by [('a','d')] + Subgroup generated by [('a','d')] of (Permutation Group with generators [('c','d'), ('a','c')]) sage: G.stabilizer('d') - Subgroup of (Permutation Group with generators [('c','d'), ('a','c')]) generated by [('a','c')] + Subgroup generated by [('a','c')] of (Permutation Group with generators [('c','d'), ('a','c')]) TESTS:: @@ -2117,10 +2128,10 @@ def center(self): sage: G = PermutationGroup([[(1,2,3,4)]]) sage: G.center() - Subgroup of (Permutation Group with generators [(1,2,3,4)]) generated by [(1,2,3,4)] + Subgroup generated by [(1,2,3,4)] of (Permutation Group with generators [(1,2,3,4)]) sage: G = PermutationGroup([[(1,2,3,4)], [(1,2)]]) sage: G.center() - Subgroup of (Permutation Group with generators [(1,2), (1,2,3,4)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(1,2), (1,2,3,4)]) """ return self.subgroup(gap_group=self._gap_().Center()) @@ -2133,9 +2144,9 @@ def socle(self): sage: G=SymmetricGroup(4) sage: G.socle() - Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,2)(3,4), (1,4)(2,3)] + Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of (Symmetric group of order 4! as a permutation group) sage: G.socle().socle() - Subgroup of (Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,2)(3,4), (1,4)(2,3)]) generated by [(1,2)(3,4), (1,4)(2,3)] + Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of (Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of (Symmetric group of order 4! as a permutation group)) """ return self.subgroup(gap_group=self._gap_().Socle()) @@ -2150,10 +2161,10 @@ def frattini_subgroup(self): sage: G=PermutationGroup([[(1,2,3,4)],[(2,4)]]) sage: G.frattini_subgroup() - Subgroup of (Permutation Group with generators [(2,4), (1,2,3,4)]) generated by [(1,3)(2,4)] + Subgroup generated by [(1,3)(2,4)] of (Permutation Group with generators [(2,4), (1,2,3,4)]) sage: G=SymmetricGroup(4) sage: G.frattini_subgroup() - Subgroup of (Symmetric group of order 4! as a permutation group) generated by [()] + Subgroup generated by [()] of (Symmetric group of order 4! as a permutation group) """ return self.subgroup(gap_group=self._gap_().FrattiniSubgroup()) @@ -2169,10 +2180,10 @@ def fitting_subgroup(self): sage: G=PermutationGroup([[(1,2,3,4)],[(2,4)]]) sage: G.fitting_subgroup() - Subgroup of (Permutation Group with generators [(2,4), (1,2,3,4)]) generated by [(2,4), (1,2,3,4), (1,3)] + Subgroup generated by [(2,4), (1,2,3,4), (1,3)] of (Permutation Group with generators [(2,4), (1,2,3,4)]) sage: G=PermutationGroup([[(1,2,3,4)],[(1,2)]]) sage: G.fitting_subgroup() - Subgroup of (Permutation Group with generators [(1,2), (1,2,3,4)]) generated by [(1,2)(3,4), (1,3)(2,4)] + Subgroup generated by [(1,2)(3,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2), (1,2,3,4)]) """ return self.subgroup(gap_group=self._gap_().FittingSubgroup()) @@ -2187,10 +2198,10 @@ def solvable_radical(self): sage: G=SymmetricGroup(4) sage: G.solvable_radical() - Subgroup of (Symmetric group of order 4! as a permutation group) generated by [(1,2), (1,2,3,4)] + Subgroup generated by [(1,2), (1,2,3,4)] of (Symmetric group of order 4! as a permutation group) sage: G=SymmetricGroup(5) sage: G.solvable_radical() - Subgroup of (Symmetric group of order 5! as a permutation group) generated by [()] + Subgroup generated by [()] of (Symmetric group of order 5! as a permutation group) """ return self.subgroup(gap_group=self._gap_().RadicalGroup()) @@ -2545,8 +2556,7 @@ def semidirect_product(self, N, mapping, check=True): sage: S1.is_isomorphic(DiCyclicGroup(6)) False sage: S1.center() - Subgroup of (Permutation Group with generators - [(5,6,7), (1,2,3,4)(6,7), (1,3)]) generated by [(1,3)(2,4)] + Subgroup generated by [(1,3)(2,4)] of (Permutation Group with generators [(5,6,7), (1,2,3,4)(6,7), (1,3)]) sage: len(S1.conjugacy_classes_representatives()) 9 @@ -2661,8 +2671,7 @@ def holomorph(self): sage: A.is_abelian() False sage: A.center() - Subgroup of (Permutation Group with generators - [(5,6,7,8,9), (1,2,4,3)(6,7,9,8)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(5,6,7,8,9), (1,2,4,3)(6,7,9,8)]) sage: A Permutation Group with generators [(5,6,7,8,9), (1,2,4,3)(6,7,9,8)] @@ -2710,7 +2719,7 @@ def subgroup(self, gens=None, gap_group=None, domain=None, category=None, canoni sage: G = PermutationGroup([(1,2,3),(3,4,5)]) sage: g = G((1,2,3)) sage: G.subgroup([g]) - Subgroup of (Permutation Group with generators [(3,4,5), (1,2,3)]) generated by [(1,2,3)] + Subgroup generated by [(1,2,3)] of (Permutation Group with generators [(3,4,5), (1,2,3)]) """ if gap_group is None: gap_group = self.gap().Subgroup([self(g).gap() for g in gens]) @@ -2742,7 +2751,7 @@ def _subgroup_constructor(self, libgap_group): sage: type(Hgap) sage: H = G._subgroup_constructor(Hgap); H - Subgroup of (The projective general unitary group of degree 3 over Finite Field of size 2) generated by [(1,6,21,12,20,17)(2,10,15,9,11,5)(3,14,8)(4,18)(7,16)] + Subgroup generated by [(1,6,21,12,20,17)(2,10,15,9,11,5)(3,14,8)(4,18)(7,16)] of (The projective general unitary group of degree 3 over Finite Field of size 2) """ gens = [gen.sage() for gen in libgap_group.GeneratorsOfGroup()] return self.subgroup(gens=gens, gap_group=libgap_group) @@ -3322,13 +3331,23 @@ def conjugacy_classes_subgroups(self): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) sage: cl = G.conjugacy_classes_subgroups() sage: cl - [Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [()], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2)(3,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,3)(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2)(3,4), (1,4)(2,3)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,3)(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4), (1,3)(2,4)], Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,2)(3,4), (1,4)(2,3)]] + [Subgroup generated by [()] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(1,2)(3,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(1,2)(3,4), (1,4)(2,3)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(2,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(1,2,3,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]), + Subgroup generated by [(2,4), (1,2)(3,4), (1,4)(2,3)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)])] :: sage: G = SymmetricGroup(3) sage: G.conjugacy_classes_subgroups() - [Subgroup of (Symmetric group of order 3! as a permutation group) generated by [()], Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(2,3)], Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2,3)], Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(2,3), (1,2,3)]] + [Subgroup generated by [()] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,2,3)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3), (1,2,3)] of (Symmetric group of order 3! as a permutation group)] AUTHORS: @@ -3370,19 +3389,19 @@ def subgroups(self): sage: G = SymmetricGroup(3) sage: G.subgroups() - [Subgroup of (Symmetric group of order 3! as a permutation group) generated by [()], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(2,3)], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2)], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,3)], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2,3)], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(2,3), (1,2,3)]] + [Subgroup generated by [()] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,2)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,3)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,2,3)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3), (1,2,3)] of (Symmetric group of order 3! as a permutation group)] sage: G = CyclicPermutationGroup(14) sage: G.subgroups() - [Subgroup of (Cyclic group of order 14 as a permutation group) generated by [()], - Subgroup of (Cyclic group of order 14 as a permutation group) generated by [(1,8)(2,9)(3,10)(4,11)(5,12)(6,13)(7,14)], - Subgroup of (Cyclic group of order 14 as a permutation group) generated by [(1,3,5,7,9,11,13)(2,4,6,8,10,12,14)], - Subgroup of (Cyclic group of order 14 as a permutation group) generated by [(1,2,3,4,5,6,7,8,9,10,11,12,13,14), (1,3,5,7,9,11,13)(2,4,6,8,10,12,14)]] + [Subgroup generated by [()] of (Cyclic group of order 14 as a permutation group), + Subgroup generated by [(1,8)(2,9)(3,10)(4,11)(5,12)(6,13)(7,14)] of (Cyclic group of order 14 as a permutation group), + Subgroup generated by [(1,3,5,7,9,11,13)(2,4,6,8,10,12,14)] of (Cyclic group of order 14 as a permutation group), + Subgroup generated by [(1,2,3,4,5,6,7,8,9,10,11,12,13,14), (1,3,5,7,9,11,13)(2,4,6,8,10,12,14)] of (Cyclic group of order 14 as a permutation group)] AUTHOR: @@ -3684,7 +3703,7 @@ def cosets(self, S, side='right'): sage: A.cosets(S) Traceback (most recent call last): ... - ValueError: Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2)] is not a subgroup of Alternating group of order 3!/2 as a permutation group + ValueError: Subgroup generated by [(1,2)] of (Symmetric group of order 3! as a permutation group) is not a subgroup of Alternating group of order 3!/2 as a permutation group AUTHOR: @@ -3744,13 +3763,13 @@ def normalizer(self, g): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) sage: g = G([(1,3)]) sage: G.normalizer(g) - Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,3)] + Subgroup generated by [(2,4), (1,3)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) sage: g = G([(1,2,3,4)]) sage: G.normalizer(g) - Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,2,3,4), (1,3)(2,4)] + Subgroup generated by [(2,4), (1,2,3,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) sage: H = G.subgroup([G([(1,2,3,4)])]) sage: G.normalizer(H) - Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,2,3,4), (1,3)(2,4)] + Subgroup generated by [(2,4), (1,2,3,4), (1,3)(2,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) """ return self.subgroup(gap_group=self._gap_().Normalizer(g)) @@ -3763,13 +3782,13 @@ def centralizer(self, g): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4)]]) sage: g = G([(1,3)]) sage: G.centralizer(g) - Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(2,4), (1,3)] + Subgroup generated by [(2,4), (1,3)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) sage: g = G([(1,2,3,4)]) sage: G.centralizer(g) - Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4)] + Subgroup generated by [(1,2,3,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) sage: H = G.subgroup([G([(1,2,3,4)])]) sage: G.centralizer(H) - Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4)] + Subgroup generated by [(1,2,3,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) """ return self.subgroup(gap_group=self._gap_().Centralizer(g)) @@ -4355,7 +4374,7 @@ def composition_series(self): sage: G = PermutationGroup([[(1,2,3),(4,5)], [(1,2)]]) sage: CS = G.composition_series() sage: CS[3] - Subgroup of (Permutation Group with generators [(1,2), (1,2,3)(4,5)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(1,2), (1,2,3)(4,5)]) """ current_randstate().set_seed_gap() CS = self._gap_().CompositionSeries() @@ -4537,9 +4556,9 @@ def sylow_subgroup(self, p): sage: G = PermutationGroup(['(1,2,3)', '(2,3)']) sage: G.sylow_subgroup(2) - Subgroup of (Permutation Group with generators [(2,3), (1,2,3)]) generated by [(2,3)] + Subgroup generated by [(2,3)] of (Permutation Group with generators [(2,3), (1,2,3)]) sage: G.sylow_subgroup(5) - Subgroup of (Permutation Group with generators [(2,3), (1,2,3)]) generated by [()] + Subgroup generated by [()] of (Permutation Group with generators [(2,3), (1,2,3)]) TESTS: @@ -4547,8 +4566,7 @@ def sylow_subgroup(self, p): large subgroups (:trac:`5491`):: sage: PSL(10,2).sylow_subgroup(7) - Subgroup of... - + Subgroup generated by... """ return self.subgroup(gap_group=self._gap_().SylowSubgroup(p)) @@ -4564,7 +4582,7 @@ def upper_central_series(self): sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: G.upper_central_series() - [Subgroup of (Permutation Group with generators [(3,4), (1,2,3)(4,5)]) generated by [()]] + [Subgroup generated by [()] of (Permutation Group with generators [(3,4), (1,2,3)(4,5)])] """ current_randstate().set_seed_gap() UCS = self._gap_().UpperCentralSeriesOfGroup() @@ -4583,7 +4601,7 @@ class PermutationGroup_subgroup(PermutationGroup_generic): sage: gens = G.gens() sage: H = DihedralGroup(4) sage: H.subgroup(gens) - Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] + Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group) sage: K = H.subgroup(gens) sage: K.list() [(), (1,3)(2,4), (1,4,3,2), (1,2,3,4)] @@ -4625,7 +4643,7 @@ def __init__(self, ambient, gens=None, gap_group=None, domain=None, [(1,2,3,4)] sage: S = G.subgroup(gens) sage: S - Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] + Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group) sage: S.list() [(), (1,3)(2,4), (1,4,3,2), (1,2,3,4)] sage: S.ambient_group() @@ -4703,7 +4721,7 @@ def __richcmp__(self, other, op): sage: G Symmetric group of order 6! as a permutation group sage: G3 - Subgroup of (Symmetric group of order 6! as a permutation group) generated by [(1,2), (1,2,3,4,5,6)] + Subgroup generated by [(1,2), (1,2,3,4,5,6)] of (Symmetric group of order 6! as a permutation group) sage: G is G3 False sage: G == G3 # as permutation groups @@ -4751,11 +4769,11 @@ def _repr_(self): sage: gens = H.gens() sage: S = PermutationGroup_subgroup(G, list(gens)) sage: S - Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] + Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group) sage: S._repr_() - 'Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)]' + 'Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group)' """ - s = "Subgroup of (%s) generated by %s"%(self.ambient_group(), self.gens()) + s = "Subgroup generated by %s of (%s)"%(self.gens(), self.ambient_group()) return s def _latex_(self): @@ -4812,7 +4830,7 @@ def is_normal(self, other=None): sage: S = SymmetricGroup(['a','b','c']) sage: H = S.subgroup([('a', 'b', 'c')]); H - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [('a','b','c')] + Subgroup generated by [('a','b','c')] of (Symmetric group of order 3! as a permutation group) sage: H.is_normal() True diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 21aa0ce31f4..a0355e4aa4b 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -12,6 +12,8 @@ AUTHORS: - Sebastian Oehms (2018-11): Added :meth:`gap` as synonym to :meth:`_gap_` (compatibility to libgap framework, see :trac:`26750`) +- Sebastian Oehms (2019-02): Implemented :meth:`gap` properly (:trac:`27234`) + There are several ways to define a permutation group element: - Define a permutation group `G`, then use ``G.gens()`` @@ -600,7 +602,23 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): # for compatibility with sage.groups.libgap_wrapper.ElementLibGAP # see sage.groups.perm_gps.permgroup.PermutationGroup_generic.gap - gap = _gap_ + def gap(self): + """ + Returns self as a libgap element + + EXAMPLES:: + + sage: P = PGU(8,2) + sage: p, q = P.gens() + sage: p_libgap = p.gap() + sage: p_pexpect = gap(p) + sage: p_libgap == p_pexpect + True + sage: type(p_libgap) == type(p_pexpect) + False + """ + from sage.libs.gap.libgap import libgap + return libgap(self) def _gap_init_(self): """ diff --git a/src/sage/groups/perm_gps/permgroup_morphism.py b/src/sage/groups/perm_gps/permgroup_morphism.py index b4fb75c35b9..b6e494ee5cb 100644 --- a/src/sage/groups/perm_gps/permgroup_morphism.py +++ b/src/sage/groups/perm_gps/permgroup_morphism.py @@ -15,9 +15,9 @@ sage: g = G([(1,2,3,4)]) sage: phi = PermutationGroupMorphism_im_gens(G, H, map(H, G.gens())) sage: phi.image(G) - Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] + Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group) sage: phi.kernel() - Subgroup of (Cyclic group of order 4 as a permutation group) generated by [()] + Subgroup generated by [()] of (Cyclic group of order 4 as a permutation group) sage: phi.image(g) (1,2,3,4) sage: phi(g) @@ -69,7 +69,7 @@ def kernel(self): sage: g = G([(1,2,3,4)]) sage: phi = PermutationGroupMorphism_im_gens(G, H, [1]) sage: phi.kernel() - Subgroup of (Cyclic group of order 4 as a permutation group) generated by [(1,2,3,4)] + Subgroup generated by [(1,2,3,4)] of (Cyclic group of order 4 as a permutation group) :: @@ -94,7 +94,7 @@ def image(self, J): sage: g = G([(1,2,3,4)]) sage: phi = PermutationGroupMorphism_im_gens(G, H, map(H, G.gens())) sage: phi.image(G) - Subgroup of (Dihedral group of order 8 as a permutation group) generated by [(1,2,3,4)] + Subgroup generated by [(1,2,3,4)] of (Dihedral group of order 8 as a permutation group) sage: phi.image(g) (1,2,3,4) @@ -105,7 +105,7 @@ def image(self, J): sage: H = D[0] sage: pr1 = D[3] sage: pr1.image(G) - Subgroup of (The projective special linear group of degree 2 over Finite Field of size 7) generated by [(3,7,5)(4,8,6), (1,2,6)(3,4,8)] + Subgroup generated by [(3,7,5)(4,8,6), (1,2,6)(3,4,8)] of (The projective special linear group of degree 2 over Finite Field of size 7) sage: G.is_isomorphic(pr1.image(G)) True """ @@ -160,7 +160,7 @@ def __init__(self, G, H, gap_hom): sage: H = G.subgroup([G([(1,2,3,4)])]) sage: PermutationGroupMorphism_from_gap(H, G, gap.Identity) Permutation group morphism: - From: Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) generated by [(1,2,3,4)] + From: Subgroup generated by [(1,2,3,4)] of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4)]) To: Permutation Group with generators [(1,2)(3,4), (1,2,3,4)] Defn: Identity """ diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index c92a7d9d2a2..75008aa9315 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -403,13 +403,11 @@ def young_subgroup(self, comp): sage: S = SymmetricGroup(8) sage: c = Composition([2,2,2,2]) sage: S.young_subgroup(c) - Subgroup of (Symmetric group of order 8! as a permutation group) - generated by [(7,8), (5,6), (3,4), (1,2)] + Subgroup generated by [(7,8), (5,6), (3,4), (1,2)] of (Symmetric group of order 8! as a permutation group) sage: S = SymmetricGroup(['a','b','c']) sage: S.young_subgroup([2,1]) - Subgroup of (Symmetric group of order 3! as a permutation group) - generated by [('a','b')] + Subgroup generated by [('a','b')] of (Symmetric group of order 3! as a permutation group) sage: Y = S.young_subgroup([2,2,2,2,2]) Traceback (most recent call last): @@ -1032,7 +1030,7 @@ def __init__(self, n): TESTS:: sage: G.category() # optional - gap_packages internet - Category of finite permutation groups + Category of finite enumerated permutation groups sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", "_test_enumerated_set_iter_list"]) # optional - gap_packages internet """ from sage.interfaces.gap import gap @@ -1065,7 +1063,7 @@ def __init__(self): TESTS:: sage: G.category() # optional - gap_packages internet - Category of finite permutation groups + Category of finite enumerated permutation groups sage: TestSuite(G).run(skip=["_test_enumerated_set_contains", "_test_enumerated_set_iter_list"]) # optional - gap_packages internet """ gap.load_package("atlasrep") @@ -3026,8 +3024,9 @@ def __str__(self): """ return "The Suzuki group over %s" % self.base_ring() + class ComplexReflectionGroup(PermutationGroup_unique): - """ + r""" A finite complex reflection group as a permutation group. We can realize `G(m,1,n)` as `m` copies of the symmetric group diff --git a/src/sage/groups/perm_gps/symgp_conjugacy_class.py b/src/sage/groups/perm_gps/symgp_conjugacy_class.py index 96489dfd5c7..349c9800dd5 100644 --- a/src/sage/groups/perm_gps/symgp_conjugacy_class.py +++ b/src/sage/groups/perm_gps/symgp_conjugacy_class.py @@ -139,12 +139,12 @@ def __iter__(self): sage: for x in C: x (2,3,4) (2,4,3) - (1,3,4) - (1,4,3) - (1,2,4) - (1,4,2) (1,2,3) (1,3,2) + (1,2,4) + (1,4,2) + (1,3,4) + (1,4,3) """ if self._set: for x in self._set: @@ -213,12 +213,12 @@ def __iter__(self): sage: for x in C: x [1, 3, 4, 2] [1, 4, 2, 3] - [3, 2, 4, 1] - [4, 2, 1, 3] - [2, 4, 3, 1] - [4, 1, 3, 2] [2, 3, 1, 4] [3, 1, 2, 4] + [2, 4, 3, 1] + [4, 1, 3, 2] + [3, 2, 4, 1] + [4, 2, 1, 3] """ if self._set: for x in self._set: @@ -317,21 +317,20 @@ def conjugacy_class_iterator(part, S=None): sage: from sage.groups.perm_gps.symgp_conjugacy_class import conjugacy_class_iterator sage: for p in conjugacy_class_iterator([2,2]): print(p) [(1, 2), (3, 4)] - [(1, 3), (2, 4)] [(1, 4), (2, 3)] + [(1, 3), (2, 4)] In order to get permutations, one just has to wrap:: sage: S = SymmetricGroup(5) sage: for p in conjugacy_class_iterator([3,2]): print(S(p)) - (1,2)(3,4,5) - (1,2)(3,5,4) (1,3)(2,4,5) (1,3)(2,5,4) + (1,2)(3,4,5) + (1,2)(3,5,4) ... - (1,4,2)(3,5) - (1,2,3)(4,5) - (1,3,2)(4,5) + (1,4)(2,3,5) + (1,4)(2,5,3) Check that the number of elements is the number of elements in the conjugacy class:: @@ -346,7 +345,7 @@ def conjugacy_class_iterator(part, S=None): sage: next(it) [('a', 'c'), ('b', 'e'), ('d', 'f')] sage: next(it) - [('a', 'c'), ('b', 'd'), ('e', 'f')] + [('a', 'f'), ('c', 'b'), ('e', 'd')] """ n = sum(part) if part not in _Partitions: diff --git a/src/sage/homology/cell_complex.py b/src/sage/homology/cell_complex.py index 129917f2916..8613c4eec3c 100644 --- a/src/sage/homology/cell_complex.py +++ b/src/sage/homology/cell_complex.py @@ -230,7 +230,7 @@ def _n_cells_sorted(self, n, subcomplex=None): sage: K = SimplicialComplex([[1,2,3], [2,3,4]]) sage: Z._n_cells_sorted(2, subcomplex=K) [(1, 2, 4), (1, 3, 4)] - sage: S = SimplicialComplex([[complex(i), complex(1)]], sort_facets=False) + sage: S = SimplicialComplex([[complex(i), complex(1)]]) sage: S._n_cells_sorted(0) [((1+0j),), (1j,)] """ diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index da793f4b093..fdfaaf619f2 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -139,8 +139,8 @@ def __init__(self, matrices, C, D, check=True): if d != D.degree_of_differential(): raise ValueError('degree of differential does not match') - from sage.misc.misc import uniq - degrees = uniq(list(C.differential()) + list(D.differential())) + degrees = list(C.differential()) + list(D.differential()) + degrees = sorted(set(degrees)) initial_matrices = dict(matrices) matrices = dict() for i in degrees: diff --git a/src/sage/homology/delta_complex.py b/src/sage/homology/delta_complex.py index f339d480454..00f6bb8136a 100644 --- a/src/sage/homology/delta_complex.py +++ b/src/sage/homology/delta_complex.py @@ -426,8 +426,7 @@ def subcomplex(self, data): """ if isinstance(data, (list, tuple)): data = dict(zip(range(len(data)), data)) - else: - data = data + # new_dict: dictionary for constructing the subcomplex new_dict = {} # new_data: dictionary of all cells in the subcomplex: store diff --git a/src/sage/homology/simplicial_complex.py b/src/sage/homology/simplicial_complex.py index 946eda090a4..639a0448e9a 100644 --- a/src/sage/homology/simplicial_complex.py +++ b/src/sage/homology/simplicial_complex.py @@ -32,6 +32,13 @@ `S` is one of the subsets in `K`, then so is every subset of `S`. The subsets `S` are called the 'simplices' of `K`. +.. NOTE:: + + In Sage, the elements of the vertex set are determined + automatically: `V` is defined to be the union of the sets in + `K`. So in Sage's implementation of simplicial complexes, every + vertex is included in some face. + A simplicial complex `K` can be viewed as a purely combinatorial object, as described above, but it also gives rise to a topological space `|K|` (its *geometric realization*) as follows: first, the @@ -55,16 +62,9 @@ multiplied by the `(n-1)`-simplex obtained by omitting vertex `v_i`. In the implementation here, the vertex set must be finite. To define a -simplicial complex, specify its vertex set: this should be a list, -tuple, or set, or it can be a non-negative integer `n`, in which case -the vertex set is `(0, ..., n)`. Also specify the facets: the maximal -faces. - -.. NOTE:: - - The elements of the vertex set are not automatically contained in - the simplicial complex: each one is only included if and only if it - is a vertex of at least one of the specified facets. +simplicial complex, specify its *facets*: the maximal subsets (with +respect to inclusion) of the vertex set belonging to `K`. Each facet +can be specifed as a list, a tuple, or a set. .. NOTE:: @@ -83,10 +83,6 @@ sage: X = SimplicialComplex([[0,1], [1,2], [2,3], [3,0]]) sage: X Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1), (0, 3), (1, 2), (2, 3)} - sage: X.stanley_reisner_ring() - Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3 over Integer Ring by the ideal (x1*x3, x0*x2) - sage: X.is_pure() - True Sage can perform a number of operations on simplicial complexes, such as the join and the product, and it can also compute homology:: @@ -108,8 +104,11 @@ [1, 4, 4] sage: X.face_poset() Finite poset containing 8 elements - sage: X.stanley_reisner_ring() - Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3 over Integer Ring by the ideal (x1*x3, x0*x2) + sage: x0, x1, x2, x3 = X.stanley_reisner_ring().gens() + sage: x0*x2 == x1*x3 == 0 + True + sage: X.is_pure() + True Mutability (see :trac:`12587`):: @@ -321,7 +320,7 @@ def rename_vertex(n, keep, left=True): sage: rename_vertex(3, [5, 6, 7], left=False) 'R3' """ - lookup = dict(zip(keep, range(len(keep)))) + lookup = {i:v for v,i in enumerate(keep)} try: return lookup[n] except KeyError: @@ -829,7 +828,7 @@ class SimplicialComplex(Parent, GenericCellComplex): :param maximality_check: see below :type maximality_check: boolean; optional, default ``True`` :param sort_facets: see below - :type sort_facets: boolean or sorting key; optional, default ``True`` + :type sort_facets: dict :param name_check: see below :type name_check: boolean; optional, default ``False`` :param is_mutable: Set to ``False`` to make this immutable @@ -841,7 +840,9 @@ class SimplicialComplex(Parent, GenericCellComplex): ``maximal_faces`` should be a list or tuple or set (indeed, anything which may be converted to a set) whose elements are lists (or tuples, etc.) of vertices. Maximal faces are also known as - 'facets'. + 'facets'. ``maximal_faces`` can also be a list containing a single + non-negative integer `n`, in which case this constructs the + simplicial complex with a single `n`-simplex as the only facet. Alternatively, the maximal faces can be defined from a monotone boolean function on the subsets of a set `X`. While defining ``maximal_faces=None``, @@ -858,11 +859,16 @@ class SimplicialComplex(Parent, GenericCellComplex): this class may fail if faces which are claimed to be maximal are in fact not. - If ``sort_facets`` is ``True``, sort the vertices. You can also - specify a sorting key as ``sort_facets``, which is then used to sort. - If the vertices in different facets are not ordered compatibly (e.g., - if you have facets ``(1, 3, 5)`` and ``(5, 3, 8)``), then homology - calculations may have unpredictable results. + ``sort_facets``: if not set to ``None``, the default, this should + be a dictionary, used for sorting the vertices in each facet. The + keys must be the vertices for the simplicial complex, and the + values should be distinct sortable objects, for example + integers. This should not need to be specified except in very + special circumstances; currently the only use in the Sage library + is when defining the product of a simplicial complex with itself: + in this case, the vertices in the product must be sorted + compatibly with the vertices in each factor so that the diagonal + map is properly defined. If ``name_check`` is ``True``, check the names of the vertices to see if they can be easily converted to generators of a polynomial ring @@ -877,15 +883,11 @@ class SimplicialComplex(Parent, GenericCellComplex): Simplicial complex with vertex set (0, 2, 3) and facets {(0, 2), (0, 3)} sage: SimplicialComplex([[0,2], [0,3], [0]], maximality_check=False) Simplicial complex with vertex set (0, 2, 3) and facets {(0,), (0, 2), (0, 3)} - sage: S = SimplicialComplex((('a', 'b'), ['a', 'c'], ('b', 'c'))) - sage: S - Simplicial complex with vertex set ('a', 'b', 'c') and facets {('a', 'b'), ('a', 'c'), ('b', 'c')} - Finally, if there is only one argument and it is a - simplicial complex, return that complex. If it is an object with - a built-in conversion to simplicial complexes (via a - ``_simplicial_`` method), then the resulting simplicial complex is - returned:: + Finally, if the first argument is a simplicial complex, return + that complex. If it is an object with a built-in conversion to + simplicial complexes (via a ``_simplicial_`` method), then the + resulting simplicial complex is returned:: sage: S = SimplicialComplex([[0,2], [0,3], [0,6]]) sage: SimplicialComplex(S) == S @@ -897,6 +899,15 @@ class SimplicialComplex(Parent, GenericCellComplex): sage: Ts.homology() {0: 0, 1: Z x Z, 2: Z} + In the situation where the first argument is a simplicial complex + or another object with a built-in conversion, most of the other + arguments are ignored. The only exception is ``is_mutable``:: + + sage: S.is_mutable() + True + sage: SimplicialComplex(S, is_mutable=False).is_mutable() + False + From a characteristic monotone boolean function, e.g. the simplicial complex of all subsets `S\subseteq \{0,1,2,3,4\}` such that `sum(S)\leq 4`:: @@ -910,11 +921,6 @@ class SimplicialComplex(Parent, GenericCellComplex): sage: SimplicialComplex(from_characteristic_function=(f, l.ground_set())) Simplicial complex with 21 vertices and 168 facets - The vertices can be sorted with a custom key:: - - sage: SimplicialComplex([10], sort_facets=str) - Simplicial complex with 11 vertices and facets {(0, 1, 10, 2, 3, 4, 5, 6, 7, 8, 9)} - TESTS: Check that we can make mutable copies (see :trac:`14142`):: @@ -943,7 +949,7 @@ def __init__(self, maximal_faces=None, from_characteristic_function=None, maximality_check=True, - sort_facets=True, + sort_facets=None, name_check=False, is_mutable=True, is_immutable=False, @@ -956,8 +962,8 @@ def __init__(self, sage: SimplicialComplex([[0,2], [0,3], [0]]) Simplicial complex with vertex set (0, 2, 3) and facets {(0, 2), (0, 3)} - sage: SimplicialComplex((('a', 'b'), ('a', 'c'), ('b', 'c'))) - Simplicial complex with vertex set ('a', 'b', 'c') and facets {('a', 'b'), ('a', 'c'), ('b', 'c')} + sage: SimplicialComplex((('a', 'b'), ['a', 'c'], ('b', 'c'))) == SimplicialComplex((('a', 'b'), ('b', 'c'), ('a', 'c'))) + True TESTS:: @@ -972,7 +978,7 @@ def __init__(self, Test that we have fixed a problem revealed in :trac:`20718`; see also :trac:`20720`:: - sage: SimplicialComplex([2], sort_facets=False) + sage: SimplicialComplex([2]) Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)} sage: S = SimplicialComplex((('a', 'b'), ('a', 'c'), ('b', 'c'))) @@ -982,12 +988,19 @@ def __init__(self, sage: TestSuite(S).run() sage: TestSuite(S3).run() - :: + Test ``sort_facets``:: - sage: SimplicialComplex([2], sort_facets="bogus") + sage: S = SimplicialComplex((('a', 'b'), ('a', 'c'), ('b', 'c')), sort_facets=True) Traceback (most recent call last): ... - TypeError: sort_facets should be a boolean or callable, not 'bogus' + TypeError: sort_facets must be a dict + sage: S = SimplicialComplex((('a', 'b'), ('a', 'c'), ('b', 'c')), sort_facets={'a': 1, 6: 3, 'c': 2}) + Traceback (most recent call last): + ... + ValueError: the set of keys of sort_facets must equal the set of vertices + sage: S = SimplicialComplex((('a', 'b'), ('a', 'c'), ('b', 'c')), sort_facets={'a': 1, 'b': 3, 'c': 2}) + sage: S._vertex_to_index['b'] + 3 """ if (maximal_faces is not None and from_characteristic_function is not None): @@ -1016,7 +1029,6 @@ def __init__(self, if maximal_faces: vertex_set = reduce(union, maximal_faces) if C is not None: - self._vertex_set = copy(C.vertices()) self._facets = list(C.facets()) self._faces = copy(C._faces) self._gen_dict = copy(C._gen_dict) @@ -1024,8 +1036,8 @@ def __init__(self, self.__contractible = copy(C.__contractible) self.__enlarged = copy(C.__enlarged) self._graph = copy(C._graph) - self._is_mutable = True - self._sorted = False + self._is_mutable = is_mutable + self._vertex_to_index = copy(C._vertex_to_index) return try: @@ -1036,16 +1048,6 @@ def __init__(self, else: vertex_set = range(n + 1) - if sort_facets is True: - vertex_set = sorted(vertex_set) - elif callable(sort_facets): - vertex_set = sorted(vertex_set, key=sort_facets) - elif not sort_facets: - # Ensure that sort_facets is either a callable or boolean - sort_facets = False - else: - raise TypeError("sort_facets should be a boolean or callable, not {!r}" - .format(sort_facets)) vertices = tuple(vertex_set) gen_dict = {} @@ -1070,28 +1072,35 @@ def __init__(self, if maximality_check: # Sorting is useful to filter maximal faces maximal_simplices.sort(key=lambda x: x.dimension(), reverse=True) + # Translate vertices to numbers, for use in sorting + # facets. Having a consistent ordering for the vertices in + # each facet is necessary for homology computations. + if sort_facets: + if not isinstance(sort_facets, dict): + raise TypeError("sort_facets must be a dict") + if set(sort_facets.keys()) != set(vertices): + raise ValueError("the set of keys of sort_facets must equal the set of vertices") + vertex_to_index = sort_facets + else: + vertex_to_index = {v: i for i, v in enumerate(vertices)} + for face in maximal_simplices: # check whether each given face is actually maximal if (maximality_check and any(face.is_face(other) for other in good_faces)): continue - if sort_facets is True: - face = Simplex(sorted(face.tuple())) - elif sort_facets is not False: - face = Simplex(sorted(face.tuple(), key=sort_facets)) + # This sorting is crucial for homology computations: + face = Simplex(sorted(face.tuple(), key=vertex_to_index.__getitem__)) good_faces.append(face) # if no maximal faces, add the empty face as a facet if len(maximal_simplices) == 0: good_faces.append(Simplex(-1)) # now record the attributes for self - # self._vertex_set: the tuple formed by the vertices - self._vertex_set = vertices + # self._vertex_to_index: dictionary to convert vertices to integers + self._vertex_to_index = vertex_to_index # self._facets: unsorted list of facets self._facets = good_faces - # self._sorted: True if the vertex set should be sorted or - # sorting key. This gets used by the add_face method. - self._sorted = sort_facets # self._faces: dictionary of dictionaries of faces. The main # dictionary is keyed by subcomplexes, and each value is a # dictionary keyed by dimension. This should be empty until @@ -1210,10 +1219,10 @@ def vertices(self): sage: S = SimplicialComplex([[i] for i in range(16)] + [[0,1], [1,2]]) sage: S Simplicial complex with 16 vertices and 15 facets - sage: S.vertices() - (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) + sage: sorted(S.vertices()) + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] """ - return self._vertex_set + return tuple(self._vertex_to_index) def _an_element_(self): """ @@ -1317,7 +1326,7 @@ def faces(self, subcomplex=None): # Make the subcomplex immutable if it is not if subcomplex is not None and subcomplex._is_mutable: subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, - sort_facets=False, is_mutable=False) + is_mutable=False) if subcomplex not in self._faces: # Faces is the dictionary of faces in self but not in @@ -1601,18 +1610,10 @@ def flip_graph(self): sage: S1 = simplicial_complexes.Sphere(1) sage: S2 = simplicial_complexes.Sphere(2) sage: G = (S1.wedge(S1)).flip_graph() - sage: G.vertices(); G.edges(labels=False) - [(0, 'L1'), (0, 'L2'), (0, 'R1'), (0, 'R2'), ('L1', 'L2'), ('R1', 'R2')] - [((0, 'L1'), (0, 'L2')), - ((0, 'L1'), (0, 'R1')), - ((0, 'L1'), (0, 'R2')), - ((0, 'L1'), ('L1', 'L2')), - ((0, 'L2'), (0, 'R1')), - ((0, 'L2'), (0, 'R2')), - ((0, 'L2'), ('L1', 'L2')), - ((0, 'R1'), (0, 'R2')), - ((0, 'R1'), ('R1', 'R2')), - ((0, 'R2'), ('R1', 'R2'))] + sage: len(G.vertices()) + 6 + sage: len(G.edges()) + 10 sage: (S1.wedge(S2)).flip_graph() is None True @@ -1708,10 +1709,7 @@ def is_pseudomanifold(self): # construct a graph with one vertex for each facet, one edge # when two facets intersect in a (d-1)-simplex, and see # whether that graph is connected. - V = [f.set() for f in self.facets()] - E = (lambda a, b: len(a.intersection(b)) == d) - g = Graph([V, E]) - return g.is_connected() + return self.flip_graph().is_connected() def product(self, right, rename_vertices=True, is_mutable=True): """ @@ -1747,10 +1745,12 @@ def product(self, right, rename_vertices=True, is_mutable=True): sage: S = SimplicialComplex([[0,1], [1,2], [0,2]]) # circle sage: K = SimplicialComplex([[0,1]]) # edge - sage: S.product(K).vertices() # cylinder - ('L0R0', 'L0R1', 'L1R0', 'L1R1', 'L2R0', 'L2R1') - sage: S.product(K, rename_vertices=False).vertices() - ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)) + sage: Cyl = S.product(K) # cylinder + sage: sorted(Cyl.vertices()) + ['L0R0', 'L0R1', 'L1R0', 'L1R1', 'L2R0', 'L2R1'] + sage: Cyl2 = S.product(K, rename_vertices=False) + sage: sorted(Cyl2.vertices()) + [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)] sage: T = S.product(S) # torus sage: T Simplicial complex with 9 vertices and 18 facets @@ -1770,7 +1770,21 @@ def product(self, right, rename_vertices=True, is_mutable=True): for f in self._facets: for g in right._facets: facets.extend(f.product(g, rename_vertices)) - return SimplicialComplex(facets, is_mutable=is_mutable) + if self != right: + return SimplicialComplex(facets, is_mutable=is_mutable) + else: + # Need to sort the vertices compatibly with the sorting in + # self, so that the diagonal map is defined properly. + V = self._vertex_to_index + L = len(V) + d = {} + for v in V.keys(): + for w in V.keys(): + if rename_vertices: + d['L' + str(v) + 'R' + str(w)] = V[v] * L + V[w] + else: + d[(v,w)] = V[v] * L + V[w] + return SimplicialComplex(facets, is_mutable=is_mutable, sort_facets=d) def join(self, right, rename_vertices=True, is_mutable=True): """ @@ -1837,8 +1851,13 @@ def cone(self, is_mutable=True): EXAMPLES:: sage: S = SimplicialComplex([[0], [1]]) - sage: S.cone() - Simplicial complex with vertex set ('L0', 'L1', 'R0') and facets {('L0', 'R0'), ('L1', 'R0')} + sage: CS = S.cone() + sage: sorted(CS.vertices()) + ['L0', 'L1', 'R0'] + sage: len(CS.facets()) + 2 + sage: CS.facets() == set([Simplex(['L0', 'R0']), Simplex(['L1', 'R0'])]) + True """ return self.join(SimplicialComplex([["0"]], is_mutable=is_mutable), rename_vertices = True) @@ -1888,8 +1907,8 @@ def suspension(self, n=1, is_mutable=True): only adds one. :: sage: T = simplicial_complexes.Torus() - sage: T.join(S0).vertices() # 9 vertices - ('L0', 'L1', 'L2', 'L3', 'L4', 'L5', 'L6', 'R0', 'R1') + sage: sorted(T.join(S0).vertices()) # 9 vertices + ['L0', 'L1', 'L2', 'L3', 'L4', 'L5', 'L6', 'R0', 'R1'] sage: T.suspension().vertices() # 8 vertices (0, 1, 2, 3, 4, 5, 6, 7) """ @@ -2064,7 +2083,7 @@ def chain_complex(self, subcomplex=None, augmented=False, # Use an immutable copy of the subcomplex if not subcomplex._is_mutable: subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, - sort_facets=False, is_mutable=False) + is_mutable=False) # now construct the range of dimensions in which to compute if dimensions is None: dimensions = range(self.dimension() + 1) @@ -2501,12 +2520,22 @@ def add_face(self, face): if not self._is_mutable: raise ValueError("This simplicial complex is not mutable") - if self._sorted is True: - new_face = Simplex(sorted(face)) - elif self._sorted is False: - new_face = Simplex(face) + vertex_to_index = self._translation_to_numeric() + + # Update vertex_to_index by giving each new vertex a larger + # entry than the existing ones. + if vertex_to_index: + idx = max(vertex_to_index.values()) + 1 else: - new_face = Simplex(sorted(face, key=self._sorted)) + idx = 0 + new_vertices = [] + for v in face: + if v not in self.vertices(): + new_vertices.append(v) + vertex_to_index[v] = idx + idx += 1 + + new_face = Simplex(sorted(face, key=vertex_to_index.__getitem__)) face_is_maximal = True for other in self._facets: @@ -2523,10 +2552,10 @@ def add_face(self, face): self._facets = Facets # Update the vertex set - self._vertex_set = tuple(reduce(union, [self._vertex_set, new_face])) + self._vertex_to_index = vertex_to_index # Update self._faces. - all_new_faces = SimplicialComplex([new_face], sort_facets=self._sorted).faces() + all_new_faces = SimplicialComplex([new_face]).faces() for L in self._faces: L_complex = self._faces[L] for dim in range(new_face.dimension()+1): @@ -2597,11 +2626,20 @@ def remove_face(self, face, check=False): sage: T.remove_face((1,2)) sage: len(T._faces) 1 + + Check that the face to be removed can be given with a + different vertex ordering:: + + sage: S = SimplicialComplex([[1,2], [1,3]]) + sage: S.remove_face([3,1]) + sage: S + Simplicial complex with vertex set (1, 2, 3) and facets {(3,), (1, 2)} """ if not self._is_mutable: raise ValueError("This simplicial complex is not mutable") - simplex = Simplex(face) + getindex = self._translation_to_numeric().__getitem__ + simplex = Simplex(sorted(face, key=getindex)) facets = self.facets() if all([not simplex.is_face(F) for F in facets]): # face is not in self @@ -2639,7 +2677,10 @@ def remove_face(self, face, check=False): # Recreate the vertex set from sage.misc.misc import union - self._vertex_set = tuple(reduce(union, self._facets)) + vertices = tuple(reduce(union, self._facets)) + for v in self.vertices(): + if v not in vertices: + del self._vertex_to_index[v] # Update self._faces. # Note: can't iterate over self._faces, because the dictionary @@ -3382,9 +3423,9 @@ def stanley_reisner_ring(self, base_ring=ZZ): EXAMPLES:: - sage: X = SimplicialComplex([[0,1], [1,2], [2,3], [0,3]]) + sage: X = SimplicialComplex([[0,1,2], [0,2,3]]) sage: X.stanley_reisner_ring() - Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3 over Integer Ring by the ideal (x1*x3, x0*x2) + Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3 over Integer Ring by the ideal (x1*x3) sage: Y = SimplicialComplex([[0,1,2,3,4]]); Y Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 2, 3, 4)} sage: Y.add_face([0,1,2,3,4]) @@ -3748,7 +3789,6 @@ def _enlarge_subcomplex(self, subcomplex, verbose=False): if subcomplex is not None and subcomplex._is_mutable: subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, - sort_facets=False, is_mutable=False) if subcomplex in self.__enlarged: @@ -3780,8 +3820,10 @@ def _enlarge_subcomplex(self, subcomplex, verbose=False): if verbose: print(" now constructing a simplicial complex with %s vertices and %s facets" % (len(self.vertices()), len(new_facets))) L = SimplicialComplex(new_facets, maximality_check=False, - sort_facets=False, is_mutable=self._is_mutable) + is_mutable=self._is_mutable) self.__enlarged[subcomplex] = L + # Use the same sorting on the vertices in L as in the ambient complex. + L._vertex_to_index = self._vertex_to_index return L def _cubical_(self): @@ -3869,9 +3911,7 @@ def connected_component(self, simplex=None): sage: X = S1.disjoint_union(S1) sage: X == X.connected_component() False - sage: v0 = X.vertices()[0] - sage: v1 = X.vertices()[-1] - sage: X.connected_component(Simplex([v0])) == X.connected_component(Simplex([v1])) + sage: X.connected_component(Simplex(['L0'])) == X.connected_component(Simplex(['R0'])) False sage: S0 = simplicial_complexes.Sphere(0) @@ -3954,12 +3994,10 @@ def fundamental_group(self, base_point=None, simplify=True): Traceback (most recent call last): ... ValueError: this complex is not connected, so you must specify a base point - sage: v0 = list(K.vertices())[0] - sage: K.fundamental_group(base_point=v0) + sage: K.fundamental_group(base_point='L0') Finitely presented group < e | > - sage: v1 = list(K.vertices())[-1] - sage: K.fundamental_group(base_point=v1) - Finitely presented group < e0 | e0^2 > + sage: K.fundamental_group(base_point='R0').order() + 2 Some other examples:: @@ -3967,8 +4005,13 @@ def fundamental_group(self, base_point=None, simplify=True): Finitely presented group < e0, e1 | > sage: simplicial_complexes.Torus().fundamental_group() Finitely presented group < e1, e4 | e4^-1*e1^-1*e4*e1 > - sage: simplicial_complexes.MooreSpace(5).fundamental_group() - Finitely presented group < e3 | e3^5 > + + sage: G = simplicial_complexes.MooreSpace(5).fundamental_group() + sage: G.ngens() + 1 + sage: x = G.gen(0) + sage: [(x**n).is_one() for n in range(1,6)] + [False, False, False, False, True] """ if not self.is_connected(): if base_point is None: @@ -3977,23 +4020,41 @@ def fundamental_group(self, base_point=None, simplify=True): from sage.groups.free_group import FreeGroup from sage.interfaces.gap import gap - spanning_tree = [e[:2] for e in self.graph().min_spanning_tree()] - gens = [tuple(e) for e in self._n_cells_sorted(1) if tuple(e) not in spanning_tree] - + G = self.graph() + # If the vertices and edges of G are not sortable, e.g., a mix + # of str and int, Sage+Python 3 may raise a TypeError when + # trying to find the spanning tree. So create a graph + # isomorphic to G but with sortable vertices. Use a copy of G, + # because self.graph() is cached, and relabeling its vertices + # would relabel the cached version. + int_to_v = dict(enumerate(G.vertex_iterator())) + v_to_int = {v: i for i, v in int_to_v.items()} + G2 = G.copy(immutable=False) + G2.relabel(v_to_int) + spanning_tree = G2.min_spanning_tree() + gens = [(int_to_v[e[0]], int_to_v[e[1]]) for e in G2.edges() + if e not in spanning_tree] if len(gens) == 0: return gap.TrivialGroup() - gens_dict = dict(zip(gens, range(len(gens)))) + # Edges in the graph may be sorted differently than in the + # simplicial complex, so convert the edges to frozensets so we + # don't have to worry about it. Convert spanning_tree to a set + # to make lookup faster. + spanning_tree = set(frozenset((int_to_v[e[0]], int_to_v[e[1]])) + for e in spanning_tree) + gens_dict = {frozenset(g): i for i, g in enumerate(gens)} FG = FreeGroup(len(gens), 'e') rels = [] for f in self._n_cells_sorted(2): bdry = [tuple(e) for e in f.faces()] z = dict() for i in range(3): - if bdry[i] in spanning_tree: + x = frozenset(bdry[i]) + if (x in spanning_tree): z[i] = FG.one() else: - z[i] = FG.gen(gens_dict[bdry[i]]) + z[i] = FG.gen(gens_dict[x]) rels.append(z[0]*z[1].inverse()*z[2]) if simplify: return FG.quotient(rels).simplified() @@ -4026,34 +4087,43 @@ def is_isomorphic(self, other, certificate=False): We check that :trac:`20751` is fixed:: - sage: C1 = SimplicialComplex([[1,2,3], [1,2,4], [1,3,4]]) - sage: C2 = SimplicialComplex([['j','k','l'], ['j','l','m'], ['j','k','m']]) + sage: C1 = SimplicialComplex([[1,2,3], [2,4], [3,5], [5,6]]) + sage: C2 = SimplicialComplex([['a','b','c'], ['b','d'], ['c','e'], ['e','f']]) sage: C1.is_isomorphic(C2, certificate=True) - (True, {1: 'j', 2: 'k', 3: 'l', 4: 'm'}) + (True, {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f'}) """ # Check easy invariants agree if (sorted(x.dimension() for x in self._facets) != sorted(x.dimension() for x in other._facets) - or len(self._vertex_set) != len(other._vertex_set)): + or len(self.vertices()) != len(other.vertices())): return False g1 = Graph() g2 = Graph() - g1.add_edges((v, f) for f in self._facets for v in f) - g2.add_edges((v, f) for f in other._facets for v in f) - g1.add_edges(("fake_vertex", v, "special_edge") - for v in self._vertex_set) - g2.add_edges(("fake_vertex", v, "special_edge") - for v in other._vertex_set) + # With Python 3, "is_isomorphic" for graphs works best if the + # vertices and edges are sortable. So we translate them all to + # ints and then if a certificate is needed, we translate + # back at the end. + self_to_int = {v: i for i, v in enumerate(list(self.vertices()) + list(self._facets))} + other_to_int = {v: i for i, v in enumerate(list(other.vertices()) + list(other._facets))} + g1.add_edges((self_to_int[v], self_to_int[f], "generic edge") for f in self._facets for v in f) + g2.add_edges((other_to_int[v], other_to_int[f], "generic edge") for f in other._facets for v in f) + fake = -1 + g1.add_edges((fake, self_to_int[v], "special_edge") + for v in self.vertices()) + g2.add_edges((fake, other_to_int[v], "special_edge") + for v in other.vertices()) if not certificate: return g1.is_isomorphic(g2, edge_labels=True) isisom, tr = g1.is_isomorphic(g2, edge_labels=True, certificate=True) if isisom: for f in self.facets(): - tr.pop(f) - tr.pop("fake_vertex") + tr.pop(self_to_int[f]) + tr.pop(fake) - return isisom, tr + int_to_self = {idx: x for x, idx in self_to_int.items()} + int_to_other = {idx: x for x, idx in other_to_int.items()} + return isisom, {int_to_self[i]: int_to_other[tr[i]] for i in tr} def automorphism_group(self): r""" @@ -4083,8 +4153,8 @@ def automorphism_group(self): sage: Z.automorphism_group().is_isomorphic(CyclicPermutationGroup(2)) True sage: group = Z.automorphism_group() - sage: group.domain() - {'1', '2', '3', 'a'} + sage: sorted(group.domain()) + ['1', '2', '3', 'a'] Check that :trac:`17032` is fixed:: @@ -4213,7 +4283,7 @@ def _is_numeric(self): EXAMPLES:: - sage: s = SimplicialComplex(sort_facets=str) + sage: s = SimplicialComplex() sage: s._is_numeric() True sage: s.add_face(['a', 'b', 123]) @@ -4221,7 +4291,7 @@ def _is_numeric(self): False """ return all(isinstance(v, integer_types + (Integer,)) - for v in self._vertex_set) + for v in self.vertices()) # @cached_method when we switch to immutable SimplicialComplex def _translation_to_numeric(self): @@ -4238,7 +4308,7 @@ def _translation_to_numeric(self): EXAMPLES:: - sage: s = SimplicialComplex(sort_facets=str) + sage: s = SimplicialComplex() sage: s._translation_to_numeric() {} sage: s.add_face(['a', 'b', 123]) @@ -4249,7 +4319,7 @@ def _translation_to_numeric(self): sage: sorted(s._translation_to_numeric().values()) [0, 1, 2] """ - return dict((vertex, i) for i, vertex in enumerate(self._vertex_set)) + return self._vertex_to_index # @cached_method when we switch to immutable SimplicialComplex def _translation_from_numeric(self): @@ -4266,7 +4336,7 @@ def _translation_from_numeric(self): EXAMPLES:: - sage: s = SimplicialComplex(sort_facets=str) + sage: s = SimplicialComplex() sage: s._translation_from_numeric() {} sage: s.add_face(['a', 'b', 123]) @@ -4277,7 +4347,8 @@ def _translation_from_numeric(self): sage: set(s._translation_from_numeric().values()) == set(['a', 'b', 123]) True """ - return dict(enumerate(self._vertex_set)) + d = self._vertex_to_index + return {idx: v for v, idx in d.items()} def _chomp_repr_(self): r""" @@ -4586,7 +4657,7 @@ def intersection(self,other): r""" Calculate the intersection of two simplicial complexes. - EXAMPLES: + EXAMPLES:: sage: X = SimplicialComplex([[1,2,3],[1,2,4]]) sage: Y = SimplicialComplex([[1,2,3],[1,4,5]]) diff --git a/src/sage/homology/simplicial_complex_morphism.py b/src/sage/homology/simplicial_complex_morphism.py index 4ab77a9b9ce..472dca2a5d7 100644 --- a/src/sage/homology/simplicial_complex_morphism.py +++ b/src/sage/homology/simplicial_complex_morphism.py @@ -68,8 +68,8 @@ sage: H = Hom(T,S) sage: T Simplicial complex with 8 vertices and 12 facets - sage: T.vertices() - ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) + sage: sorted(T.vertices()) + [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)] sage: f = {(0, 0): 0, (0, 1): 0, (1, 0): 1, (1, 1): 1, (2, 0): 2, (2, 1): 2, (3, 0): 3, (3, 1): 3} sage: x = H(f) sage: U = simplicial_complexes.Sphere(1) @@ -81,7 +81,7 @@ sage: z = y.fiber_product(x) sage: z # this is the mapping path space Simplicial complex morphism: - From: Simplicial complex with 6 vertices and 6 facets + From: Simplicial complex with 6 vertices and 4 facets To: Minimal triangulation of the 2-sphere Defn: ['L0R(0, 0)', 'L0R(0, 1)', 'L1R(1, 0)', 'L1R(1, 1)', 'L2R(2, 0)', 'L2R(2, 1)'] --> [0, 0, 1, 1, 2, 2] """ @@ -160,7 +160,7 @@ def __init__(self,f,X,Y): """ if not isinstance(X,SimplicialComplex) or not isinstance(Y,SimplicialComplex): raise ValueError("X and Y must be SimplicialComplexes") - if not set(f.keys()) == set(X._vertex_set): + if not set(f.keys()) == set(X.vertices()): raise ValueError("f must be a dictionary from the vertex set of X to single values in the vertex set of Y") dim = X.dimension() Y_faces = Y.faces() @@ -553,7 +553,7 @@ def is_identity(self): return False else: f = dict() - for i in self.domain()._vertex_set: + for i in self.domain().vertices(): f[i] = i if self._vertex_dictionary != f: return False @@ -581,7 +581,7 @@ def fiber_product(self, other, rename_vertices = True): sage: z = x.fiber_product(y) sage: z Simplicial complex morphism: - From: Simplicial complex with 4 vertices and facets {('L1R1',), ('L2R0',), ('L0R0', 'L1R2')} + From: Simplicial complex with 4 vertices and facets {...} To: Simplicial complex with vertex set (0, 1, 2) and facets {(2,), (0, 1)} Defn: L0R0 |--> 0 L1R1 |--> 1 @@ -593,8 +593,8 @@ def fiber_product(self, other, rename_vertices = True): X = self.domain().product(other.domain(),rename_vertices = rename_vertices) v = [] f = dict() - eff1 = self.domain()._vertex_set - eff2 = other.domain()._vertex_set + eff1 = self.domain().vertices() + eff2 = other.domain().vertices() for i in eff1: for j in eff2: if self(Simplex([i])) == other(Simplex([j])): diff --git a/src/sage/homology/simplicial_set.py b/src/sage/homology/simplicial_set.py index 96deed991e5..7b19eb069b4 100644 --- a/src/sage/homology/simplicial_set.py +++ b/src/sage/homology/simplicial_set.py @@ -1849,7 +1849,7 @@ def subsimplicial_set(self, simplices): d = f.dimension() found = False for x in self.n_cells(d): - if str(x) == str(f): + if str(x) == str(tuple(sorted(tuple(f), key=str))): new.append(x) found = True break @@ -2289,7 +2289,6 @@ def quotient(self, subcomplex, vertex_name='*'): if (not isinstance(subcomplex, SubSimplicialSet) and subcomplex.ambient_space() == self): raise ValueError('the "subcomplex" is not actually a subcomplex') - pass if self.is_finite(): return QuotientOfSimplicialSet_finite(subcomplex.inclusion_map(), vertex_name=vertex_name) @@ -3264,7 +3263,7 @@ def face(sigma, i): faces = {} for idx, sigma in enumerate(data.n_cells(d)): new_sigma = AbstractSimplex(d) - new_sigma.rename(str(sigma)) + new_sigma.rename(str(tuple(sorted(tuple(sigma), key=str)))) if d > 0: simplices[new_sigma] = [old_faces[_] for _ in sigma.faces()] else: @@ -4055,8 +4054,8 @@ def shrink_simplicial_complex(K): sage: Z.homology() {0: 0, 1: Z^6, 2: Z} sage: M = shrink_simplicial_complex(Z) - sage: M.f_vector() - [1, 30, 25] + sage: M.f_vector() # random + [1, 32, 27] sage: M.homology() {0: 0, 1: Z^6, 2: Z} """ diff --git a/src/sage/homology/simplicial_set_constructions.py b/src/sage/homology/simplicial_set_constructions.py index 46be7d06bea..69edf35459b 100644 --- a/src/sage/homology/simplicial_set_constructions.py +++ b/src/sage/homology/simplicial_set_constructions.py @@ -2783,7 +2783,7 @@ def __repr_or_latex__(self, output_type=None): We use `S` to denote unreduced suspension, `\Sigma` for reduced suspension. - EXAMPLES: + EXAMPLES:: sage: T = simplicial_sets.Torus() sage: K = T.suspension(10) @@ -2824,7 +2824,7 @@ def _repr_(self): We use `S` to denote unreduced suspension, `\Sigma` for reduced suspension. - EXAMPLES: + EXAMPLES:: sage: S2 = simplicial_sets.Sphere(2) sage: S2.suspension(3) @@ -2844,7 +2844,7 @@ def _latex_(self): We use `S` to denote unreduced suspension, `\Sigma` for reduced suspension. - EXAMPLES: + EXAMPLES:: sage: S2 = simplicial_sets.Sphere(2) sage: latex(S2.suspension(3)) diff --git a/src/sage/homology/simplicial_set_examples.py b/src/sage/homology/simplicial_set_examples.py index f7f1c6dbd02..e59d6682119 100644 --- a/src/sage/homology/simplicial_set_examples.py +++ b/src/sage/homology/simplicial_set_examples.py @@ -635,7 +635,7 @@ def simplicial_data_from_kenzo_output(filename): OUTPUT: data to construct a simplicial set from the Kenzo output Several files with Kenzo output are in the directory - :file:`SAGE_ROOT/src/ext/kenzo/`. + :file:`SAGE_EXTCODE/kenzo/`. EXAMPLES:: diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index 51394652aa3..67245e72446 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -12,7 +12,10 @@ HTML and Sage code which creates the mathlet:: sage: interacts.calculus.taylor_polynomial() - ... + Interactive function with 3 widgets + title: HTMLText(value=u'

    Taylor polynomial

    ') + f: EvalText(value=u'e^(-x)*sin(x)', description=u'$f(x)=$', layout=Layout(max_width=u'81em')) + order: SelectionSlider(description=u'order', options=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), value=1) AUTHORS: @@ -32,6 +35,8 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from __future__ import absolute_import, division + from sage.all import * x = SR.var('x') @@ -67,7 +72,8 @@ def library_interact(f): ....: def f(n=5): ....: print(n) sage: f() # an interact appears if using the notebook, else code - ... + Interactive function with 1 widget + n: IntSlider(value=5, description=u'n', max=15, min=-5) """ @sage_wraps(f) def library_wrapper(): @@ -108,7 +114,9 @@ def demo(n=slider(range(10)), m=slider(range(10))): creates the mathlet:: sage: interacts.demo() - ... + Interactive function with 2 widgets + n: SelectionSlider(description=u'n', options=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), value=0) + m: SelectionSlider(description=u'm', options=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), value=0) """ print(n + m) @@ -131,7 +139,10 @@ def taylor_polynomial( creates the mathlet:: sage: interacts.calculus.taylor_polynomial() - ... + Interactive function with 3 widgets + title: HTMLText(value=u'

    Taylor polynomial

    ') + f: EvalText(value=u'e^(-x)*sin(x)', description=u'$f(x)=$', layout=Layout(max_width=u'81em')) + order: SelectionSlider(description=u'order', options=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), value=1) """ x0 = 0 p = plot(f,(x,-1,5), thickness=2) @@ -171,7 +182,13 @@ def definite_integral( creates the mathlet:: sage: interacts.calculus.definite_integral() - ... + Interactive function with 6 widgets + title: HTMLText(value=u'

    Definite integral

    ') + f: EvalText(value=u'3*x', description=u'$f(x)=$', layout=Layout(max_width=u'81em')) + g: EvalText(value=u'x^2', description=u'$g(x)=$', layout=Layout(max_width=u'81em')) + interval: IntRangeSlider(value=(0, 3), description=u'Interval', max=10, min=-10) + x_range: IntRangeSlider(value=(0, 3), description=u'plot range (x)', max=10, min=-10) + selection: Dropdown(description=u'Select', index=2, options=('f', 'g', 'f and g', 'f - g'), value='f and g') """ x = SR.var('x') f = symbolic_expression(f).function(x) @@ -246,7 +263,11 @@ def function_derivative( creates the mathlet:: sage: interacts.calculus.function_derivative() - ... + Interactive function with 4 widgets + title: HTMLText(value=u'

    Derivative grapher

    ') + function: EvalText(value=u'x^5-3*x^3+1', description=u'Function:', layout=Layout(max_width=u'81em')) + x_range: FloatRangeSlider(value=(-2.0, 2.0), description=u'Range (x)', max=15.0, min=-15.0) + y_range: FloatRangeSlider(value=(-8.0, 6.0), description=u'Range (y)', max=15.0, min=-15.0) """ x = SR.var('x') f = symbolic_expression(function).function(x) @@ -289,7 +310,12 @@ def difference_quotient( creates the mathlet:: sage: interacts.calculus.difference_quotient() - ... + Interactive function with 5 widgets + title: HTMLText(value=u'

    Difference quotient

    ') + f: EvalText(value=u'sin(x)', description=u'f(x)', layout=Layout(max_width=u'81em')) + interval: FloatRangeSlider(value=(0.0, 10.0), description=u'Range', max=10.0) + a: IntSlider(value=5, description=u'$a$', max=10) + x0: IntSlider(value=2, description=u'$x_0$ (start point)', max=10) """ html('

    Difference Quotient

    ') html('
    \ @@ -344,7 +370,10 @@ def quadratic_equation(A = slider(-7, 7, 1, 1), B = slider(-7, 7, 1, 1), C = sli creates the mathlet:: sage: interacts.calculus.quadratic_equation() - ... + Interactive function with 3 widgets + A: IntSlider(value=1, description=u'A', max=7, min=-7) + B: IntSlider(value=1, description=u'B', max=7, min=-7) + C: IntSlider(value=-2, description=u'C', max=7, min=-7) """ x = SR.var('x') f = symbolic_expression(A*x**2 + B*x + C).function(x) @@ -402,7 +431,10 @@ def trigonometric_properties_triangle( creates the mathlet:: sage: interacts.geometry.trigonometric_properties_triangle() - ... + Interactive function with 3 widgets + a0: IntSlider(value=30, description=u'A', max=360) + a1: IntSlider(value=180, description=u'B', max=360) + a2: IntSlider(value=300, description=u'C', max=360) """ import math @@ -416,12 +448,12 @@ def distance(x1_y1, x2_y2): # are adjacent and the side c is opposite to the angle def angle(a, b, c): a,b,c = map(float,[a,b,c]) - return acos((b**2 + c**2 - a**2)/(2.0*b*c)) + return acos(0.5 * (b**2 + c**2 - a**2) / (b * c)) # Returns the area of a triangle when an angle alpha # and adjacent sides a and b are known def area(alpha, a, b): - return 1.0/2.0*a*b*sin(alpha) + return 0.5 * a * b * sin(alpha) xy = [0]*3 html('

    Trigonometric Properties of a Triangle

    ') @@ -452,14 +484,10 @@ def area(alpha, a, b): labels = a_label + b_label + c_label show(unit_circle + triangle + triangle_points + labels, figsize=[5, 5], xmin=-1, xmax=1, ymin=-1, ymax=1) - angl_txt = r"$\angle A = {%s}^{\circ},$ $\angle B = {%s}^{\circ},$ $\angle C = {%s}^{\circ}$" % ( - math.degrees(ak[0]), - math.degrees(ak[1]), - math.degrees(ak[2]) - ) - html(angl_txt) - html(r"$AB = %s,$ $BC = %s,$ $CA = %s$"%(al[2], al[0], al[1])) - html(r"Area of triangle $ABC = %s$"%A) + html(r"$\angle A = {%.3f}^{\circ},$ $\angle B = {%.3f}^{\circ},$ $\angle C = {%.3f}^{\circ}$" + % (math.degrees(ak[0]), math.degrees(ak[1]), math.degrees(ak[2]))) + html(r"$AB = %.6f$, $BC = %.6f$, $CA = %.6f$" % (al[2], al[0], al[1])) + html(r"Area of triangle $ABC = %.6f$" % A) @library_interact def unit_circle( @@ -482,7 +510,9 @@ def unit_circle( creates the mathlet:: sage: interacts.geometry.unit_circle() - ... + Interactive function with 2 widgets + function: Dropdown(description=u'function', options=(('sin(x)', 0), ('cos(x)', 1), ('tan(x)', 2)), value=0) + x: TransformFloatSlider(value=0.0, description=u'x', max=6.283185307179586, step=0.015707963267948967) """ xy = (cos(x), sin(x)) t = SR.var('t') @@ -569,15 +599,25 @@ def special_points( creates the mathlet:: sage: interacts.geometry.special_points() - ... + Interactive function with 10 widgets + title: HTMLText(value=u'

    Special points in triangle

    ') + a0: IntSlider(value=30, description=u'A', max=360) + a1: IntSlider(value=180, description=u'B', max=360) + a2: IntSlider(value=300, description=u'C', max=360) + show_median: Checkbox(value=False, description=u'Medians') + show_pb: Checkbox(value=False, description=u'Perpendicular Bisectors') + show_alt: Checkbox(value=False, description=u'Altitudes') + show_ab: Checkbox(value=False, description=u'Angle Bisectors') + show_incircle: Checkbox(value=False, description=u'Incircle') + show_euler: Checkbox(value=False, description=u"Euler's Line") """ import math # Return the intersection point of the bisector of the angle <(A[a],A[c],A[b]) and the unit circle. Angles given in radians. def half(A, a, b, c): if (A[a] < A[b] and (A[c] < A[a] or A[c] > A[b])) or (A[a] > A[b] and (A[c] > A[a] or A[c] < A[b])): - p = A[a] + (A[b] - A[a]) / 2.0 + p = A[a] + 0.5 * (A[b] - A[a]) else: - p = A[b] + (2*pi - (A[b]-A[a])) / 2.0 + p = A[b] + 0.5 * (2*pi - (A[b]-A[a])) return (math.cos(p), math.sin(p)) # Returns the distance between points (x1,y1) and (x2,y2) @@ -613,9 +653,9 @@ def line_to_points(x1_y1, x2_y2, **plot_kwargs): # Midpoints of edges (bc, ca, ab) a_middle = [ - ((xy[1][0] + xy[2][0])/2.0, (xy[1][1] + xy[2][1])/2.0), - ((xy[2][0] + xy[0][0])/2.0, (xy[2][1] + xy[0][1])/2.0), - ((xy[0][0] + xy[1][0])/2.0, (xy[0][1] + xy[1][1])/2.0) + (0.5 * (xy[1][0] + xy[2][0]), 0.5 * (xy[1][1] + xy[2][1])), + (0.5 * (xy[2][0] + xy[0][0]), 0.5 * (xy[2][1] + xy[0][1])), + (0.5 * (xy[0][0] + xy[1][0]), 0.5 * (xy[0][1] + xy[1][1])) ] # Incircle @@ -626,7 +666,7 @@ def line_to_points(x1_y1, x2_y2, **plot_kwargs): ) if show_incircle: - s = perimeter/2.0 + s = 0.5 * perimeter incircle_r = math.sqrt((s - ad[0]) * (s - ad[1]) * (s - ad[2]) / s) incircle_graph = circle(incircle_center, incircle_r) + point(incircle_center) else: @@ -728,7 +768,9 @@ def coin(n = slider(2,10000, 100, default=1000, label="Number of Tosses"), inter creates the mathlet:: sage: interacts.statistics.coin() - ... + Interactive function with 2 widgets + n: IntSlider(value=1000, description=u'Number of Tosses', max=10000, min=2, step=100) + interval: IntRangeSlider(value=(0, 0), description=u'Plotting range (y)', max=1) """ from random import random c = [] @@ -765,7 +807,12 @@ def bisection_method( creates the mathlet:: sage: interacts.calculus.secant_method() - ... + Interactive function with 5 widgets + title: HTMLText(value=u'

    Secant method for numerical root finding

    ') + f: EvalText(value=u'x^2-2', description=u'f(x)', layout=Layout(max_width=u'81em')) + interval: IntRangeSlider(value=(0, 4), description=u'range', max=5, min=-5) + d: IntSlider(value=3, description=u'10^-d precision', max=16, min=1) + maxn: IntSlider(value=10, description=u'max iterations', max=15) """ def _bisection_method(f, a, b, maxn, eps): intervals = [(a,b)] @@ -836,7 +883,12 @@ def secant_method( creates the mathlet:: sage: interacts.calculus.secant_method() - ... + Interactive function with 5 widgets + title: HTMLText(value=u'

    Secant method for numerical root finding

    ') + f: EvalText(value=u'x^2-2', description=u'f(x)', layout=Layout(max_width=u'81em')) + interval: IntRangeSlider(value=(0, 4), description=u'range', max=5, min=-5) + d: IntSlider(value=3, description=u'10^-d precision', max=16, min=1) + maxn: IntSlider(value=10, description=u'max iterations', max=15) """ def _secant_method(f, a, b, maxn, h): intervals = [(a,b)] @@ -902,7 +954,14 @@ def newton_method( creates the mathlet:: sage: interacts.calculus.newton_method() - ... + Interactive function with 7 widgets + title: HTMLText(value=u'

    Newton method

    ') + f: EvalText(value=u'x^2 - 2', description=u'f', layout=Layout(max_width=u'81em')) + c: IntSlider(value=6, description=u'Start ($x$)', max=10, min=-10) + d: IntSlider(value=3, description=u'$10^{-d}$ precision', max=16, min=1) + maxn: IntSlider(value=10, description=u'max iterations', max=15) + interval: IntRangeSlider(value=(0, 6), description=u'Interval', max=10, min=-10) + list_steps: Checkbox(value=False, description=u'List steps') """ def _newton_method(f, c, maxn, h): midpoints = [c] @@ -919,7 +978,7 @@ def _newton_method(f, c, maxn, h): f = symbolic_expression(f).function(x) a, b = interval h = 10**(-d) - c, midpoints = _newton_method(f, float(c), maxn, h/2.0) + c, midpoints = _newton_method(f, float(c), maxn, 0.5 * h) html(r"$\text{Precision } 2h = %s$"%latex(float(h))) html(r"${c = }%s$"%c) html(r"${f(c) = }%s"%latex(f(c))) @@ -968,7 +1027,14 @@ def trapezoid_integration( creates the mathlet:: sage: interacts.calculus.trapezoid_integration() - ... + Interactive function with 7 widgets + title: HTMLText(value=u'

    Trapezoid integration

    ') + f: EvalText(value=u'x^2-5*x + 10', description=u'$f(x)=$', layout=Layout(max_width=u'81em')) + n: IntSlider(value=5, description=u'# divisions', min=1) + interval_input: ToggleButtons(description=u'Integration interval', options=('from slider', 'from keyboard'), value='from slider') + interval_s: IntRangeSlider(value=(0, 8), description=u'slider: ', max=10, min=-10) + interval_g: Grid(value=[[0, 8]], children=(Label(value=u'keyboard: '), VBox(children=(EvalText(value=u'0', layout=Layout(max_width=u'5em')),)), VBox(children=(EvalText(value=u'8', layout=Layout(max_width=u'5em')),)))) + output_form: ToggleButtons(description=u'Computations form', options=('traditional', 'table', 'none'), value='traditional') """ xs = [] ys = [] @@ -1075,7 +1141,14 @@ def simpson_integration( creates the mathlet:: sage: interacts.calculus.simpson_integration() - ... + Interactive function with 7 widgets + title: HTMLText(value=u'

    Simpson integration

    ') + f: EvalText(value=u'x*sin(x)+x+1', description=u'$f(x)=$', layout=Layout(max_width=u'81em')) + n: IntSlider(value=6, description=u'# divisions', min=2, step=2) + interval_input: ToggleButtons(description=u'Integration interval', options=('from slider', 'from keyboard'), value='from slider') + interval_s: IntRangeSlider(value=(0, 10), description=u'slider: ', max=10, min=-10) + interval_g: Grid(value=[[0, 10]], children=(Label(value=u'keyboard: '), VBox(children=(EvalText(value=u'0', layout=Layout(max_width=u'5em')),)), VBox(children=(EvalText(value=u'10', layout=Layout(max_width=u'5em')),)))) + output_form: ToggleButtons(description=u'Computations form', options=('traditional', 'table', 'none'), value='traditional') """ x = SR.var('x') f = symbolic_expression(f).function(x) @@ -1198,7 +1271,16 @@ def riemann_sum( creates the mathlet:: sage: interacts.calculus.riemann_sum() - ... + Manual interactive function with 9 widgets + title: HTMLText(value=u'

    Riemann integral with random sampling

    ') + f: EvalText(value=u'x^2+1', description=u'$f(x)=$', layout=Layout(max_width=u'41em')) + n: IntSlider(value=5, description=u'# divisions', max=30, min=1) + hr1: HTMLText(value=u'
    ') + interval_input: ToggleButtons(description=u'Integration interval', options=('from slider', 'from keyboard'), value='from slider') + interval_s: IntRangeSlider(value=(0, 2), description=u'slider: ', max=10, min=-5) + interval_g: Grid(value=[[0, 2]], children=(Label(value=u'keyboard: '), VBox(children=(EvalText(value=u'0', layout=Layout(max_width=u'5em')),)), VBox(children=(EvalText(value=u'2', layout=Layout(max_width=u'5em')),)))) + hr2: HTMLText(value=u'
    ') + list_table: Checkbox(value=False, description=u'List table') AUTHORS: @@ -1276,7 +1358,14 @@ def function_tool(f=sin(x), g=cos(x), xrange=range_slider(-3,3,default=(0,1),lab creates the mathlet:: sage: interacts.calculus.function_tool() - ... + Interactive function with 7 widgets + f: EvalText(value=u'sin(x)', description=u'f') + g: EvalText(value=u'cos(x)', description=u'g') + xrange: IntRangeSlider(value=(0, 1), description=u'x-range', max=3, min=-3) + yrange: Text(value=u'auto', description=u'yrange') + a: IntSlider(value=1, description=u'a', max=3, min=-1) + action: ToggleButtons(description=u'h = ', options=('f', 'df/dx', 'int f', 'num f', 'den f', '1/f', 'finv', 'f+a', 'f-a', 'f*a', 'f/a', 'f^a', 'f(x+a)', 'f(x*a)', 'f+g', 'f-g', 'f*g', 'f/g', 'f(g)'), value='f') + do_plot: Checkbox(value=True, description=u'Draw Plots') """ x = SR.var('x') try: @@ -1393,7 +1482,15 @@ def julia(expo = slider(-10,10,0.1,2), creates the mathlet:: sage: interacts.fractals.julia() - ... + Interactive function with 8 widgets + expo: FloatSlider(value=2.0, description=u'expo', max=10.0, min=-10.0) + c_real: FloatSlider(value=0.5, description=u'real part const.', max=2.0, min=-2.0, step=0.01) + c_imag: FloatSlider(value=0.5, description=u'imag part const.', max=2.0, min=-2.0, step=0.01) + iterations: IntSlider(value=20, description=u'# iterations', min=1) + zoom_x: FloatRangeSlider(value=(-1.5, 1.5), description=u'Zoom X', max=2.0, min=-2.0, step=0.01) + zoom_y: FloatRangeSlider(value=(-1.5, 1.5), description=u'Zoom Y', max=2.0, min=-2.0, step=0.01) + plot_points: IntSlider(value=150, description=u'plot points', max=400, min=20, step=20) + dpi: IntSlider(value=80, description=u'dpi', max=200, min=20, step=10) """ z = SR.var('z') I = CDF.gen() @@ -1434,7 +1531,13 @@ def mandelbrot(expo = slider(-10,10,0.1,2), creates the mathlet:: sage: interacts.fractals.mandelbrot() - ... + Interactive function with 6 widgets + expo: FloatSlider(value=2.0, description=u'expo', max=10.0, min=-10.0) + iterations: IntSlider(value=20, description=u'# iterations', min=1) + zoom_x: FloatRangeSlider(value=(-2.0, 1.0), description=u'Zoom X', max=2.0, min=-2.0, step=0.01) + zoom_y: FloatRangeSlider(value=(-1.5, 1.5), description=u'Zoom Y', max=2.0, min=-2.0, step=0.01) + plot_points: IntSlider(value=150, description=u'plot points', max=400, min=20, step=20) + dpi: IntSlider(value=80, description=u'dpi', max=200, min=20, step=10) """ x, z, c = SR.var('x, z, c') f = symbolic_expression(z**expo + c).function(z, c) @@ -1472,7 +1575,10 @@ def cellular_automaton( creates the mathlet:: sage: interacts.fractals.cellular_automaton() - ... + Interactive function with 3 widgets + N: IntSlider(value=100, description=u'Number of iterations', max=500, min=1) + rule_number: IntSlider(value=110, description=u'Rule number', max=255) + size: IntSlider(value=6, description=u'size of graphic', max=11, min=1) """ from sage.all import Integer if not 0 <= rule_number <= 255: @@ -1527,10 +1633,14 @@ def polar_prime_spiral( creates the mathlet:: sage: sage.interacts.algebra.polar_prime_spiral() - ... - + Interactive function with 6 widgets + interval: IntRangeSlider(value=(1, 1000), description=u'range', max=4000, min=1, step=10) + show_factors: Checkbox(value=True, description=u'show_factors') + highlight_primes: Checkbox(value=True, description=u'highlight_primes') + show_curves: Checkbox(value=True, description=u'show_curves') + n: IntSlider(value=89, description=u'number $n$', max=200, min=1) + dpi: IntSlider(value=100, description=u'dpi', max=300, min=10, step=10) """ - html('

    Polar Prime Spiral

    \
    \ For more information about the factors in the spiral, visit \ @@ -1593,12 +1703,12 @@ def polar_prime_spiral( t = SR.var('t') a=1.0 b=0.0 - if n > (floor(sqrt(n)))**2 and n <= (floor(sqrt(n)))**2 + floor(sqrt(n)): - c = -((floor(sqrt(n)))**2 - n) - c2= -((floor(sqrt(n)))**2 + floor(sqrt(n)) - n) + S = int(sqrt(n)) + if n <= S * (S + 1): + c = n - S**2 else: - c = -((ceil(sqrt(n)))**2 - n) - c2= -((floor(sqrt(n)))**2 + floor(sqrt(n)) - n) + c = n - (S + 1)**2 + c2 = n - S * (S + 1) html('Pink Curve: $n^2 + %s$' % c) html('Green Curve: $n^2 + n + %s$' % c2) m = SR.var('m') diff --git a/src/sage/interacts/test_jupyter.rst b/src/sage/interacts/test_jupyter.rst index ca68c03d3ef..2ef7b2f48e0 100644 --- a/src/sage/interacts/test_jupyter.rst +++ b/src/sage/interacts/test_jupyter.rst @@ -47,8 +47,8 @@ Test all interacts from the Sage interact library:: dpi: IntSlider(value=100, description=u'dpi', max=300, min=10, step=10)

    Polar Prime Spiral

    For more information about the factors in the spiral, visit Number Spirals by John Williamson.
    - Pink Curve: - Green Curve: + Pink Curve: + Green Curve: sage: test(interacts.calculus.taylor_polynomial) Interactive function with 3 widgets @@ -103,16 +103,6 @@ Test all interacts from the Sage interact library:: - sage: test(interacts.calculus.trigonometric_properties_triangle) - Interactive function with 3 widgets - a0: IntSlider(value=30, description=u'A', max=360) - a1: IntSlider(value=180, description=u'B', max=360) - a2: IntSlider(value=300, description=u'C', max=360) -

    Trigonometric Properties of a Triangle

    - - - Area of triangle - sage: test(interacts.calculus.secant_method) Interactive function with 5 widgets title: HTMLText(value=u'

    Secant method for numerical root finding

    ') @@ -270,9 +260,9 @@ Test all interacts from the Sage interact library:: a1: IntSlider(value=180, description=u'B', max=360) a2: IntSlider(value=300, description=u'C', max=360)

    Trigonometric Properties of a Triangle

    - - - Area of triangle + + , , + Area of triangle sage: test(interacts.geometry.special_points) Interactive function with 10 widgets diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py index 47fc5721863..8b43b196ebb 100644 --- a/src/sage/interfaces/expect.py +++ b/src/sage/interfaces/expect.py @@ -1175,7 +1175,7 @@ def _expect_expr(self, expr=None, timeout=None): running, so a timeout of 1 second should be sufficient. :: sage: print(sage0.eval("dummy=gp.eval('0'); alarm(1); gp._expect_expr('1')")) # long time - Control-C pressed. Interrupting PARI/GP interpreter. Please wait a few seconds... + ...Interrupting PARI/GP interpreter. Please wait a few seconds... ... AlarmInterrupt: """ diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index f02ae94dedf..2e941c66cd5 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -2,6 +2,7 @@ Interface to FriCAS .. TODO:: + - some conversions in ``sage.functions`` are still missing and all should be checked and tested @@ -196,17 +197,23 @@ ########################################################################### from __future__ import print_function +import re +import os from sage.interfaces.tab_completion import ExtraTabCompletion from sage.interfaces.expect import Expect, ExpectElement, FunctionElement, ExpectFunction from sage.misc.misc import SAGE_TMP_INTERFACE from sage.env import DOT_SAGE, LOCAL_IDENTIFIER from sage.docs.instancedoc import instancedoc -import re +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.misc.lazy_import import lazy_import +lazy_import('sage.libs.pynac.pynac', ['symbol_table']) +lazy_import('sage.calculus.var', ['var', 'function']) -FRICAS_SINGLE_LINE_START = 3 # where the output starts when it fits next to the line number -FRICAS_MULTI_LINE_START = 2 # and when it doesn't -FRICAS_LINE_LENGTH = 80 # length of a line, should match the line length in sage +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 +FRICAS_LINE_LENGTH = 80 # length of a line, should match the line length in sage # the following messages have, unfortunately, no markup. FRICAS_WHAT_OPERATIONS_STRING = r"Operations whose names satisfy the above pattern\(s\):" FRICAS_ERROR_IN_LIBRARY_CODE = ">> Error detected within library code:" @@ -215,21 +222,39 @@ # work, the other are optimizations. Beware that lisp distinguishes # between ' and ". FRICAS_INIT_CODE = ( -")set functions compile on", -")set message autoload off", -")set message type off", -")set output length " + str(FRICAS_LINE_LENGTH), -")lisp (setf |$ioHook|" -" (lambda (x &optional args)" -" (when (member x '(|startAlgebraOutput| |endOfAlgebraOutput|" -" |startKeyedMsg| |endOfKeyedMsg|))" -" (prin1 x)" -" (princ #\\Newline))))") + ")set functions compile on", + ")set message autoload off", + ")set message type off", + ")set output length " + str(FRICAS_LINE_LENGTH), + ")lisp (setf |$ioHook|" + " (lambda (x &optional args)" + " (when (member x '(|startAlgebraOutput| |endOfAlgebraOutput|" + " |startKeyedMsg| |endOfKeyedMsg|))" + " (prin1 x)" + " (princ #\\Newline))))") +# code (one-liners!) executed after having set up the prompt +FRICAS_HELPER_CODE = ( + 'sageprint(x:InputForm):String == ' + + '(atom? x => (' + + 'float? x => return float(x)::String;' + + 'integer? x => return integer(x)::String;' + + 'string? x => return concat(["_"", string(x)::String, "_""])$String;' + + 'symbol? x => return string(symbol(x)));' + + 'S: List String := [sageprint y for y in destruct x];' + + 'R: String := new(1 + reduce(_+, [1 + #(s)$String for s in S], 0),' + + 'space()$Character);' + + 'copyInto!(R, "(", 1);' + + 'i := 2;' + + 'for s in S repeat' + '(copyInto!(R, s, i); i := i + 1 + #(s)$String);' + + 'copyInto!(R, ")", i-1);' + + 'return R)',) FRICAS_LINENUMBER_OFF_CODE = ")lisp (setf |$IOindex| NIL)" FRICAS_FIRST_PROMPT = r"\(1\) -> " FRICAS_LINENUMBER_OFF_PROMPT = r"\(NIL\) -> " + class FriCAS(ExtraTabCompletion, Expect): """ Interface to a FriCAS interpreter. @@ -259,22 +284,22 @@ def __init__(self, name='fricas', command='fricas -nosman', sage: fricas(I*x).sage() # optional - fricas I*x """ - eval_using_file_cutoff = 4096-5 # magic number from Expect._eval_line (there might be a bug) + eval_using_file_cutoff = 4096-5 # magic number from Expect._eval_line (there might be a bug) assert max(len(c) for c in FRICAS_INIT_CODE) < eval_using_file_cutoff self.__eval_using_file_cutoff = eval_using_file_cutoff - self._COMMANDS_CACHE = '%s/%s_commandlist_cache.sobj'%(DOT_SAGE, name) + self._COMMANDS_CACHE = '%s/%s_commandlist_cache.sobj' % (DOT_SAGE, name) # we run the init code in _start to avoid spurious output Expect.__init__(self, - name = name, - prompt = FRICAS_FIRST_PROMPT, - command = command, - script_subdirectory = script_subdirectory, + name=name, + prompt=FRICAS_FIRST_PROMPT, + command=command, + script_subdirectory=script_subdirectory, server=server, server_tmpdir=server_tmpdir, - restart_on_ctrlc = False, - verbose_start = False, - init_code = [], - logfile = logfile, + restart_on_ctrlc=False, + verbose_start=False, + init_code=[], + logfile=logfile, eval_using_file_cutoff=eval_using_file_cutoff) def _start(self): @@ -299,6 +324,8 @@ def _start(self): # switching off the line numbers also modified the prompt self._prompt = FRICAS_LINENUMBER_OFF_PROMPT self.eval(FRICAS_LINENUMBER_OFF_CODE, reformat=False) + for line in FRICAS_HELPER_CODE: + self.eval(line, reformat=False) def _quit_string(self): """ @@ -344,7 +371,8 @@ def _commands(self): True """ output = self.eval(")what operations", reformat=False) - m = re.search(FRICAS_WHAT_OPERATIONS_STRING + r"\n(.*)\n\|startKeyedMsg\|", output, flags = re.DOTALL) + m = re.search(FRICAS_WHAT_OPERATIONS_STRING + r"\n(.*)\n\|startKeyedMsg\|", + output, flags=re.DOTALL) l = m.groups()[0].split() return l @@ -385,13 +413,12 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): print("To force rebuild later, delete %s." % self._COMMANDS_CACHE) v = self._commands() - #Process we now need process the commands to strip out things which - #are not valid Python identifiers. + # process the commands to strip out things which are not + # valid Python identifiers valid = re.compile('[^a-zA-Z0-9_]+') names = [x for x in v if valid.search(x) is None] - #Change everything that ends with ? to _q and - #everything that ends with ! to _e + # replace trailing ? with _q and trailing ! with _e names += [x[:-1]+"_q" for x in v if x.endswith("?")] names += [x[:-1]+"_e" for x in v if x.endswith("!")] @@ -424,7 +451,7 @@ def _read_in_file_command(self, filename): if not filename.endswith('.input'): raise ValueError("the filename must end with .input") - return ')read %s )quiet'%filename + return ')read %s )quiet' % filename def _local_tmpfile(self): """ @@ -447,7 +474,7 @@ def _remote_tmpfile(self): try: return self.__remote_tmpfile except AttributeError: - self.__remote_tmpfile = self._remote_tmpdir()+"/interface_%s:%s.input"%(LOCAL_IDENTIFIER,self.pid()) + self.__remote_tmpfile = self._remote_tmpdir() + "/interface_%s:%s.input" % (LOCAL_IDENTIFIER, self.pid()) return self.__remote_tmpfile # what I expect from FriCAS: @@ -511,7 +538,8 @@ def _check_errors(self, line, output): """ # otherwise there might be a message - m = re.search(r"\|startKeyedMsg\|\n(.*)\n\|endOfKeyedMsg\|", output, flags = re.DOTALL) + m = re.search(r"\|startKeyedMsg\|\n(.*)\n\|endOfKeyedMsg\|", + output, flags=re.DOTALL) if m: replacements = [('|startKeyedMsg|\n', ''), ('|endOfKeyedMsg|', '')] @@ -541,7 +569,7 @@ def set(self, var, value): '2' """ - cmd = '%s%s%s;'%(var,self._assign_symbol(), value) + cmd = '%s%s%s;' % (var, self._assign_symbol(), value) output = self.eval(cmd, reformat=False) self._check_errors(value, output) @@ -568,7 +596,8 @@ def get(self, var): """ output = self.eval(str(var), reformat=False) # if there is AlgebraOutput we ask no more - m = re.search(r"\|startAlgebraOutput\|\n(.*)\n\|endOfAlgebraOutput\|", output, flags = re.DOTALL) + m = re.search(r"\|startAlgebraOutput\|\n(.*)\n\|endOfAlgebraOutput\|", + output, flags=re.DOTALL) if m: lines = m.groups()[0].split("\n") if max(len(line) for line in lines) < FRICAS_LINE_LENGTH: @@ -674,7 +703,19 @@ def get_unparsed_InputForm(self, var): '(1..3)$Segment(PositiveInteger())' """ - return self.get_string('unparse((%s)::InputForm)' %str(var)) + return self.get_string('unparse((%s)::InputForm)' % str(var)) + + def get_InputForm(self, var): + """ + Return the ``InputForm`` as a string. + + TESTS:: + + sage: fricas.get_InputForm('1..3') # optional - fricas + '(($elt (Segment (PositiveInteger)) SEGMENT) 1 3)' + + """ + return self.get_string('sageprint((%s)::InputForm)' % str(var)) def _assign_symbol(self): """ @@ -805,7 +846,6 @@ def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file= return output - def _function_class(self): """ Return the FriCASExpectFunction class. @@ -883,7 +923,7 @@ def __len__(self): 6 """ P = self._check_valid() - l = P('#(%s)' %self._name) + l = P('#(%s)' % self._name) return l.sage() def __getitem__(self, n): @@ -916,7 +956,7 @@ def __getitem__(self, n): P = self._check_valid() # use "elt" instead of "." here because then the error # message is clearer - return P.new("elt(%s,%s)" %(self._name, n+1)) + return P.new("elt(%s,%s)" % (self._name, n+1)) def __int__(self): """ @@ -980,7 +1020,6 @@ def _integer_(self, ZZ=None): sage: ZZ(fricas('1')) # optional - fricas 1 """ - from sage.rings.all import ZZ return ZZ(self.sage()) def _rational_(self): @@ -990,7 +1029,6 @@ def _rational_(self): sage: QQ(fricas('-1/2')) # optional - fricas -1/2 """ - from sage.rings.all import QQ return QQ(self.sage()) def gen(self, n): @@ -1007,7 +1045,7 @@ def _latex_(self): {{\log \left( {{e+1}} \right)} \ {\sin \left( {{y+x}} \right)}} \over {{e} ^{z}} sage: latex(fricas("matrix([[1,2],[3,4]])")) # optional - fricas - \left[ \begin{array}{cc} 1 & 2 \\ 3 & 4 \end{array} \right] + \left[ \begin{array}{cc} 1 & 2 \\ 3 & 4\end{array} \right] sage: latex(fricas("integrate(sin(x+1/x),x)")) # optional - fricas \int ^{\displaystyle x} {{\sin \left( {{{{{ \%O} ^{2}}+1} \over \%O}} \right)} \ {d \%O}} @@ -1017,7 +1055,7 @@ def _latex_(self): (r'\sb ', '_'), (r'\sb{', '_{')] P = self._check_valid() - s = P.get_string("first tex(%s)" % self._name) + s = P.get_string("latex(%s)" % self._name) for old, new in replacements: s = s.replace(old, new) return s @@ -1037,8 +1075,14 @@ def _get_sage_type(self, domain): sage: m = fricas("dom(1/2)::Any") # optional - fricas sage: fricas(0)._get_sage_type(m) # optional - fricas Rational Field + + TESTS:: + + sage: m = fricas("UP(y, UP(x, AN))::INFORM") # optional - fricas + sage: fricas(0)._get_sage_type(m) # optional - fricas + Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Algebraic Field """ - from sage.rings.all import ZZ, QQbar, RDF + from sage.rings.all import QQbar, RDF, PolynomialRing from sage.rings.fraction_field import FractionField from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.finite_rings.finite_field_constructor import FiniteField @@ -1053,7 +1097,7 @@ def _get_sage_type(self, domain): return str if head == "Float": P = self._check_valid() - prec = max(P.new("length mantissa(%s)" %self._name).sage(), 53) + prec = max(P.new("length mantissa(%s)" % self._name).sage(), 53) return RealField(prec) if head == "DoubleFloat": return RDF @@ -1081,19 +1125,217 @@ def _get_sage_type(self, domain): # this is a workaround, since in sage we always have to specify the variables return SR - raise NotImplementedError("The translation of FriCAS type %s to sage is not yet implemented." %domain) + if head == "UnivariatePolynomial": + var = str(domain[1]) + return PolynomialRing(self._get_sage_type(domain[2]), var) + + raise NotImplementedError("the translation of FriCAS type %s to sage is not yet implemented" % domain) + + _WHITESPACE = " " + _LEFTBRACKET = "(" + _RIGHTBRACKET = ")" + _STRINGMARKER = '"' + _ESCAPEMARKER = '_' # STRINGMARKER must be escaped in strings + + @staticmethod + def _parse_and_eval(s, start=0): + """ + Parse and evaluate the string. + + INPUT: + + - ``s`` -- string + - ``start`` -- integer; specifies where to start parsing + + OUTPUT: + + - a pair ``(L, end)``, where ``L`` is the parsed list and + ``end`` is the position of the last parsed letter. + + TESTS:: + + sage: from sage.interfaces.fricas import FriCASElement + sage: FriCASElement._parse_and_eval("abc") + (abc, 2) + + sage: FriCASElement._parse_and_eval("(asin c)") + (arcsin(c), 7) + + sage: N(FriCASElement._parse_and_eval("(pi)")[0]) # optional - fricas + 3.14159265358979 + + sage: FriCASElement._parse_and_eval('(a "(b c)")') + Traceback (most recent call last): + ... + TypeError: cannot coerce arguments: no canonical coercion from to Symbolic Ring + + """ + a = start + while s[a] in FriCASElement._WHITESPACE: + a += 1 + + if s[a] == FriCASElement._LEFTBRACKET: + return FriCASElement._parse_list(s, start=a) + elif s[a] == FriCASElement._STRINGMARKER: + return FriCASElement._parse_string(s, start=a) + else: + return FriCASElement._parse_other(s, start=a) + + @staticmethod + def _parse_list(s, start=0): + """ + Parse the initial part of a string, assuming that it is a + whitespace separated list, treating its first element as + function and the rest as arguments. + + INPUT: + + - ``s`` -- string + - ``start`` -- integer; specifies the position of the left + bracket + + TESTS:: + + sage: from sage.interfaces.fricas import FriCASElement + sage: FriCASElement._parse_list("()") + Traceback (most recent call last): + ... + TypeError: 'tuple' object is not callable + + sage: FriCASElement._parse_list("(a b c)") + (a(b, c), 6) + + sage: FriCASElement._parse_list('(bcd)') + (bcd(), 4) + + """ + a = start + assert s[a] == FriCASElement._LEFTBRACKET + a += 1 + # the first element of a list must be a function call + fun, a = FriCASElement._parse_other(s, start=a, make_fun=True) + a += 1 + args = [] + while s[a] != FriCASElement._RIGHTBRACKET: + e, a = FriCASElement._parse_and_eval(s, start=a) + args.append(e) + a += 1 + return fun(*args), a + + @staticmethod + def _parse_other(s, start=0, make_fun=False): + """ + Parse the initial part of a string, assuming that it is an + atom, but not a string. + + Symbols and numbers must not contain ``FriCASElement._WHITESPACE`` and + ``FriCASElement._RIGHTBRACKET``. + + INPUT: + + - ``s`` -- string + - ``start`` -- integer; specifies where the symbol begins + - ``make_fun`` -- (default: ``False``) a Boolean; specifying + whether the atom should be interpreted as a function call + + TESTS:: - def _sage_expression(self, unparsed_InputForm): + sage: from sage.interfaces.fricas import FriCASElement + sage: FriCASElement._parse_other("abc") + (abc, 2) + sage: FriCASElement._parse_other("123 xyz") + (123, 2) + sage: FriCASElement._parse_other("abc -1.23", 4) + (-1.23, 8) + + This function uses the symbol table to translate symbols + which are not function calls. At least ``%pi`` is an + example showing that this may be necessary:: + + sage: FriCASElement._parse_other("%pi") + (pi, 2) + + """ + a = start + b = len(s) + while a < b and s[a] not in FriCASElement._WHITESPACE and s[a] != FriCASElement._RIGHTBRACKET: + a += 1 + + e = s[start:a] + if make_fun: + try: + e = symbol_table["fricas"][e] + except KeyError: + e = function(e) + else: + try: + e = ZZ(e) + except TypeError: + try: + e = float(e) + except ValueError: + try: + e = symbol_table["fricas"][e] + except KeyError: + e = var(e.replace("%", "_")) + return e, a-1 + + @staticmethod + def _parse_string(s, start=0): r""" - Convert an expression to an element of the Symbolic Ring. + Parse the initial part of a string, assuming that it represents a + string. - This does not depend on `self`. Instead, for practical - reasons of the implementation of `self._sage_`, it takes the - unparsed InputForm as argument. + INPUT: - .. TODO:: + - ``s`` -- string + - ``start`` -- integer; specifies the position of the left + quote + + TESTS:: + + sage: from sage.interfaces.fricas import FriCASElement + sage: FriCASElement._parse_string('"abc" 123') + ('abc', 4) + + sage: FriCASElement._parse_string('"" 123') + ('', 1) + + sage: FriCASElement._parse_string('"____" 123') + ('__', 5) + + sage: FriCASElement._parse_string('"_a" 123') + ('a', 3) + + sage: FriCASElement._parse_string('"_" _"" 123') + ('" "', 6) + + sage: FriCASElement._parse_string('"(b c)"') + ('(b c)', 6) + + """ + a = start + assert s[a] == FriCASElement._STRINGMARKER + b = a + 1 + a = b + S = [] + while s[b] != FriCASElement._STRINGMARKER: + if s[b] == FriCASElement._ESCAPEMARKER: + S.append(s[a:b]) + b += 1 + a = b + b += 1 + S.append(s[a:b]) + return "".join(S), b + + @staticmethod + def _sage_expression(fricas_InputForm): + """ + Convert an expression to an element of the Symbolic Ring. + + INPUT: - We really should walk through the InputForm here. + - fricas_InputForm, a string, the InputForm of a FriCAS expression. TESTS:: @@ -1107,9 +1349,10 @@ def _sage_expression(self, unparsed_InputForm): | 2 |--- \|%pi - sage: s = fricas.get_unparsed_InputForm(f._name); s # optional - fricas - 'fresnelS(x*(2/pi())^(1/2))/((2/pi())^(1/2))' - sage: f._sage_expression(s) # optional - fricas + sage: s = fricas.get_InputForm(f._name); s # optional - fricas + '(/ (fresnelS (* x (^ (/ 2 (pi)) (/ 1 2)))) (^ (/ 2 (pi)) (/ 1 2)))' + sage: from sage.interfaces.fricas import FriCASElement + sage: FriCASElement._sage_expression(s) # optional - fricas 1/2*sqrt(2)*sqrt(pi)*fresnel_sin(sqrt(2)*x/sqrt(pi)) Check that :trac:`22525` is fixed:: @@ -1199,6 +1442,40 @@ def _sage_expression(self, unparsed_InputForm): sage: n(r.subs(a=1, x=5)-r.subs(a=1, x=3)) # optional - fricas tol 0.1 193.020947266268 - 8.73114913702011e-11*I + Check conversions of sums and products:: + + sage: var("k, m, n") # optional - fricas + (k, m, n) + sage: fricas("sum(1/factorial(k), k=1..n)").sage() # optional - fricas + sum(1/factorial(_...), _..., 1, n) + sage: fricas("eval(sum(x/k, k=1..n), x=k)").sage() # optional - fricas + k*harmonic_number(n) + sage: fricas("product(1/factorial(k), k=1..n)").sage() # optional - fricas + 1/product(factorial(_...), _..., 1, n) + + sage: f = fricas.guess([sum(1/k, k,1,n) for n in range(10)])[0]; f # optional - fricas + n - 1 + --+ 1 + > ------- + --+ s + 1 + s = 0 10 + 10 + + sage: f.sage() # optional - fricas + harmonic_number(n) + + sage: f = fricas.guess([0, 1, 3, 9, 33])[0]; f # optional - fricas + s - 1 + n - 1 5 + --+ ++-++ + > | | p + 2 + --+ | | 4 + s = 0 p = 0 + 5 4 + + sage: f.sage() # optional - fricas + sum(factorial(_... + 1), _..., 0, n - 1) + Check that :trac:`26746` is fixed:: sage: _ = var('x, y, z') @@ -1217,70 +1494,106 @@ def _sage_expression(self, unparsed_InputForm): 0.7798934003_7682282947_42 """ - from sage.calculus.calculus import symbolic_expression_from_string - from sage.calculus.functional import diff - from sage.libs.pynac.pynac import symbol_table, register_symbol + from sage.libs.pynac.pynac import register_symbol from sage.symbolic.all import I + from sage.symbolic.constants import e, pi + from sage.calculus.functional import diff from sage.functions.log import dilog, lambert_w - register_symbol(lambda f,x: diff(f, x), {'fricas':'D'}) - register_symbol(lambda x,y: x + y*I, {'fricas':'complex'}) - register_symbol(lambda x: dilog(1-x), {'fricas':'dilog'}) - register_symbol(lambda z: lambert_w(z), {'fricas':'lambertW'}) - + from sage.functions.trig import sin, cos, tan, cot, sec, csc + from sage.functions.hyperbolic import tanh, sinh, cosh, coth, sech, csch + from sage.misc.functional import symbolic_sum, symbolic_prod + from sage.rings.infinity import infinity + register_symbol(I, {'fricas': '%i'}) + register_symbol(e, {'fricas': '%e'}) + register_symbol(pi, {'fricas': 'pi'}) # fricas uses both pi and %pi + register_symbol(lambda: infinity, {'fricas': 'infinity'}) + register_symbol(lambda: infinity, {'fricas': 'plusInfinity'}) + register_symbol(lambda: -infinity, {'fricas': 'minusInfinity'}) + register_symbol(cos, {'fricas': 'cos'}) + register_symbol(sin, {'fricas': 'sin'}) + register_symbol(tan, {'fricas': 'tan'}) + register_symbol(cot, {'fricas': 'cot'}) + register_symbol(sec, {'fricas': 'sec'}) + register_symbol(csc, {'fricas': 'csc'}) + register_symbol(tanh, {'fricas': 'tanh'}) + register_symbol(sinh, {'fricas': 'sinh'}) + register_symbol(cosh, {'fricas': 'cosh'}) + register_symbol(coth, {'fricas': 'coth'}) + register_symbol(sech, {'fricas': 'sech'}) + register_symbol(csch, {'fricas': 'csch'}) + register_symbol(lambda x, y: x + y, {'fricas': '+'}) + register_symbol(lambda x, y: x - y, {'fricas': '-'}) + register_symbol(lambda x, y: x * y, {'fricas': '*'}) + register_symbol(lambda x, y: x / y, {'fricas': '/'}) + register_symbol(lambda x, y: x ** y, {'fricas': '^'}) + register_symbol(lambda f, x: diff(f, x), {'fricas': 'D'}) + register_symbol(lambda x, y: x + y*I, {'fricas': 'complex'}) + register_symbol(lambda x: dilog(1-x), {'fricas': 'dilog'}) + register_symbol(lambda z: lambert_w(z), {'fricas': 'lambertW'}) + # the following is a hack to deal with + # integrate(sin((x^2+1)/x),x)::INFORM giving + # (integral (sin (/ (+ (^ x 2) 1) x)) (:: x Symbol)) + register_symbol(lambda x, y: x, {'fricas': '::'}) + + def _convert_sum(x, y): + v, seg = y.operands() + a, b = seg.operands() + return symbolic_sum(x, v, a, b) + + def _convert_prod(x, y): + v, seg = y.operands() + a, b = seg.operands() + return symbolic_prod(x, v, a, b) + + register_symbol(_convert_sum, {'fricas': 'sum'}) + register_symbol(_convert_prod, {'fricas': 'product'}) def explicitely_not_implemented(*args): - raise NotImplementedError("The translation of the FriCAS Expression %s to sage is not yet implemented." %args) - register_symbol(explicitely_not_implemented, {'fricas':'rootOfADE'}) - register_symbol(explicitely_not_implemented, {'fricas':'rootOfRec'}) + raise NotImplementedError("the translation of the FriCAS Expression '%s' to sage is not yet implemented" % args) + + register_symbol(lambda *args: explicitely_not_implemented("rootOfADE"), {'fricas': 'rootOfADE'}) + register_symbol(lambda *args: explicitely_not_implemented("rootOfRec"), {'fricas': 'rootOfRec'}) + + rootOf = dict() # (variable, polynomial) + rootOf_ev = dict() # variable -> (complex) algebraic number - rootOf = dict() # (variable, polynomial) - rootOf_ev = dict() # variable -> (complex) algebraic number def convert_rootOf(x, y): if y in rootOf: assert rootOf[y] == x else: rootOf[y] = x return y - register_symbol(convert_rootOf, {'fricas':'rootOf'}) - s = unparsed_InputForm - replacements = [('pi()', 'pi '), - ('::Symbol', ' '), - ('%', '_')] # this last one is a workaround - python does not allow % in variable names - for old, new in replacements: - s = s.replace(old, new) - - try: - ex = symbolic_expression_from_string(s, symbol_table["fricas"]) - except (SyntaxError, TypeError): - raise NotImplementedError("The translation of the FriCAS Expression %s to sage is not yet implemented." %s) + register_symbol(convert_rootOf, {'fricas': 'rootOf'}) + ex, _ = FriCASElement._parse_and_eval(fricas_InputForm) + # postprocessing of rootOf from sage.rings.all import QQbar, PolynomialRing - i = 0 while rootOf: - (var, poly) = rootOf.items()[i] - pvars = poly.variables() - rvars = [v for v in pvars if v not in rootOf_ev] # remaining variables - uvars = [v for v in rvars if v in rootOf] # variables to evaluate - if len(uvars) == 1: - assert uvars[0] == var - # substitute known roots - poly = poly.subs(rootOf_ev) - evars = [v for v in rvars if v not in rootOf] # extraneous variables - assert set(evars) == set(poly.variables()).difference([var]) - if evars: - # we just need any root per FriCAS specification - rootOf_ev[var] = poly.roots(var, multiplicities=False)[0] - else: - R = PolynomialRing(QQbar, "x") - # PolynomialRing does not accept variable names with leading underscores - poly = R(poly.subs({var:R.gen()})) - # we just need any root per FriCAS specification - rootOf_ev[var] = poly.roots(multiplicities=False)[0].radical_expression() - del rootOf[var] - i = 0 + for var, poly in rootOf.items(): + pvars = poly.variables() + rvars = [v for v in pvars if v not in rootOf_ev] # remaining variables + uvars = [v for v in rvars if v in rootOf] # variables to evaluate + if len(uvars) == 1: + assert uvars[0] == var, "the only variable in uvars should be %s but is %s" % (var, uvars[0]) + break else: - i += 1 + assert False, "circular dependency in rootOf expression" + # substitute known roots + poly = poly.subs(rootOf_ev) + evars = [v for v in rvars if v not in rootOf] # extraneous variables + assert set(evars) == set(poly.variables()).difference([var]) + del rootOf[var] + if evars: + # we just need any root per FriCAS specification + rootOf_ev[var] = poly.roots(var, multiplicities=False)[0] + else: + R = PolynomialRing(QQbar, "x") + # PolynomialRing does not accept variable names with leading underscores + poly = R(poly.subs({var: R.gen()})) + # we just need any root per FriCAS specification + rootOf_ev[var] = poly.roots(multiplicities=False)[0].radical_expression() + return ex.subs(rootOf_ev) def _sage_(self): @@ -1346,6 +1659,23 @@ def _sage_(self): sage: fricas("x^2/2").sage() # optional - fricas 1/2*x^2 + sage: x = polygen(QQ, 'x') + sage: fricas(x+3).sage() # optional - fricas + x + 3 + sage: fricas(x+3).domainOf() # optional - fricas + Polynomial(Integer()) + + sage: fricas(matrix([[2,3],[4,x+5]])).diagonal().sage() # optional - fricas + (2, x + 5) + + sage: f = fricas("(y^2+3)::UP(y, INT)").sage(); f # optional - fricas + y^2 + 3 + sage: f.parent() # optional - fricas + Univariate Polynomial Ring in y over Integer Ring + + sage: fricas("(y^2+sqrt 3)::UP(y, AN)").sage() # optional - fricas + y^2 + 1.732050807568878? + Rational functions:: sage: fricas("x^2 + 1/z").sage() # optional - fricas @@ -1353,6 +1683,9 @@ def _sage_(self): Expressions:: + sage: fricas(pi).sage() # optional - fricas + pi + sage: fricas("sin(x+y)/exp(z)*log(1+%e)").sage() # optional - fricas e^(-z)*log(e + 1)*sin(x + y) @@ -1398,7 +1731,7 @@ def _sage_(self): sage: s.sage() # optional - fricas Traceback (most recent call last): ... - NotImplementedError: The translation of the FriCAS Expression rootOfADE(n,...()) to sage is not yet implemented. + NotImplementedError: the translation of the FriCAS Expression 'rootOfADE' to sage is not yet implemented sage: s = fricas("series(sqrt(1+x), x=0)"); s # optional - fricas 1 1 2 1 3 5 4 7 5 21 6 33 7 429 8 @@ -1412,7 +1745,7 @@ def _sage_(self): sage: s.sage() # optional - fricas Traceback (most recent call last): ... - NotImplementedError: The translation of the FriCAS object + NotImplementedError: the translation of the FriCAS object 1 1 2 1 3 5 4 7 5 21 6 33 7 429 8 1 + - x - - x + -- x - --- x + --- x - ---- x + ---- x - ----- x @@ -1427,7 +1760,7 @@ def _sage_(self): Cannot convert the value from type Any to InputForm . """ - from sage.rings.all import ZZ, PolynomialRing, RDF + from sage.rings.all import PolynomialRing, RDF from sage.rings.real_mpfr import RealField from sage.symbolic.ring import SR from sage.symbolic.all import I @@ -1443,10 +1776,10 @@ def _sage_(self): # the coercion to Any gets rid of the Union domain P = self._check_valid() - domain = P.new("dom((%s)::Any)" % self._name) # domain is now a fricas SExpression + domain = P.new("dom((%s)::Any)" % self._name) # domain is now a fricas SExpression - # first translate dummy domains such as "failed". we must not - # recurse here! + # first translate dummy domains such as "failed". We must + # not recurse here! if P.get_boolean("string?(%s)" % domain._name): return P.get_string("string(%s)" % domain._name) @@ -1454,38 +1787,44 @@ def _sage_(self): # or where we do not need it. head = str(domain.car()) if head == "Record": - fields = fricas("[string symbol(e.2) for e in rest destruct %s]"%domain._name).sage() + fields = fricas("[string symbol(e.2) for e in rest destruct %s]" % domain._name).sage() return {field: self.elt(field).sage() for field in fields} if head == "List": - n = P.get_integer('#(%s)' %self._name) - return [P.new('elt(%s,%s)' %(self._name, k)).sage() for k in range(1, n+1)] + n = P.get_integer('#(%s)' % self._name) + return [self.elt(k).sage() for k in range(1, n + 1)] - if head == "Vector": - n = P.get_integer('#(%s)' %self._name) - return vector([P.new('elt(%s,%s)' %(self._name, k)).sage() for k in range(1, n+1)]) + if head == "Vector" or head == "DirectProduct": + n = P.get_integer('#(%s)' % self._name) + return vector([self.elt(k).sage() for k in range(1, n + 1)]) if head == "Matrix": base_ring = self._get_sage_type(domain[1]) - rows = P.new('listOfLists(%s)' %self._name).sage() + rows = self.listOfLists().sage() return matrix(base_ring, rows) if head == "Fraction": - return P.new("numer(%s)" %self._name).sage()/P.new("denom(%s)" %self._name).sage() + return self.numer().sage() / self.denom().sage() if head == "Complex": - return (P.new("real(%s)" %self._name).sage() + - P.new("imag(%s)" %self._name).sage()*I) + return self.real().sage() + self.imag().sage()*I if head == "Factored": - l = P.new('[[f.factor, f.exponent] for f in factors(%s)]' %self._name).sage() - return Factorization([(p, e) for p,e in l]) + l = P.new('[[f.factor, f.exponent] for f in factors(%s)]' % self._name).sage() + return Factorization([(p, e) for p, e in l]) + + if head == "UnivariatePolynomial": + base_ring = self._get_sage_type(domain[2]) + vars = str(domain[1]) + R = PolynomialRing(base_ring, vars) + return R([self.coefficient(i).sage() + for i in range(ZZ(self.degree()) + 1)]) # finally translate domains with InputForm try: unparsed_InputForm = P.get_unparsed_InputForm(self._name) except RuntimeError as error: - raise NotImplementedError("The translation of the FriCAS object\n\n%s\n\nto sage is not yet implemented:\n%s" %(self, error)) + raise NotImplementedError("the translation of the FriCAS object\n\n%s\n\nto sage is not yet implemented:\n%s" % (self, error)) if head == "Boolean": return unparsed_InputForm == "true" @@ -1499,7 +1838,7 @@ def _sage_(self): # Warning: precision$Float gives the current precision, # whereas length(mantissa(self)) gives the precision of # self. - prec = max(P.new("length mantissa(%s)" %self._name).sage(), 53) + prec = max(P.new("length mantissa(%s)" % self._name).sage(), 53) R = RealField(prec) x, e, b = unparsed_InputForm.lstrip('float(').rstrip(')').split(',') return R(ZZ(x)*ZZ(b)**ZZ(e)) @@ -1522,25 +1861,25 @@ def _sage_(self): base_ring = self._get_sage_type(domain[1]) # Polynomial Complex is translated into SR if base_ring is SR: - return self._sage_expression(unparsed_InputForm) + return FriCASElement._sage_expression(P.get_InputForm(self._name)) # the following is a bad hack, we should be getting a list here - vars = P.get_unparsed_InputForm("variables(%s)" %self._name)[1:-1] + vars = P.get_unparsed_InputForm("variables(%s)" % self._name)[1:-1] if vars == "": return base_ring(unparsed_InputForm) else: R = PolynomialRing(base_ring, vars) return R(unparsed_InputForm) - if head == "OrderedCompletion": - # this is a workaround, I don't know how translate this - if str(domain[1].car()) == "Expression": - return self._sage_expression(unparsed_InputForm) + if head in ["OrderedCompletion", "OnePointCompletion"]: + # it would be more correct to get the type parameter + # (which might not be Expression Integer) and recurse + return FriCASElement._sage_expression(P.get_InputForm(self._name)) - if head == "Expression": + if head == "Expression" or head == "Pi": # we treat Expression Integer and Expression Complex # Integer just the same - return self._sage_expression(unparsed_InputForm) + return FriCASElement._sage_expression(P.get_InputForm(self._name)) if head == 'DistributedMultivariatePolynomial': base_ring = self._get_sage_type(domain[2]) @@ -1548,7 +1887,7 @@ def _sage_(self): R = PolynomialRing(base_ring, vars) return R(unparsed_InputForm) - raise NotImplementedError("The translation of the FriCAS object %s to sage is not yet implemented." %(unparsed_InputForm)) + raise NotImplementedError("the translation of the FriCAS object %s to sage is not yet implemented" % (unparsed_InputForm)) @instancedoc @@ -1611,8 +1950,10 @@ def is_FriCASElement(x): """ return isinstance(x, FriCASElement) + fricas = FriCAS() + def reduce_load_fricas(): """ Returns the FriCAS interface object defined in @@ -1626,7 +1967,6 @@ def reduce_load_fricas(): """ return fricas -import os def fricas_console(): """ @@ -1649,6 +1989,7 @@ def fricas_console(): raise RuntimeError('Can use the console only in the terminal. Try %%fricas magics instead.') os.system('fricas -nox') + def __doctest_cleanup(): """ EXAMPLES:: diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index aa7bc198a03..4e35d3a1aad 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -1,4 +1,4 @@ -# -*- coding: UTF-8 -*- +# -*- coding: utf-8 -*- r""" Interface to GAP @@ -226,8 +226,8 @@ def set_gap_memory_pool_size(size_in_bytes): """ Set the desired gap memory pool size. - Subsequently started GAP/libGAP instances will use this as - default. Currently running instances are unchanged. + Subsequently started GAP instances will use this as default. + Already running instances are unchanged. GAP will only reserve ``size_in_bytes`` address space. Unless you actually start a big GAP computation, the memory will not be @@ -295,7 +295,7 @@ def _get_gap_memory_pool_size_MB(): String. - EXAMPLES: + EXAMPLES:: sage: from sage.interfaces.gap import \ ....: _get_gap_memory_pool_size_MB @@ -944,7 +944,7 @@ def function_call(self, function, args=None, kwds=None): return self.new('last2;') else: if res.strip(): - from sage.interfaces.expect import AsciiArtString + from sage.interfaces.interface import AsciiArtString return AsciiArtString(res) def get_record_element(self, record, name): @@ -1584,7 +1584,6 @@ def gap_reset_workspace(max_workspace_size=None, verbose=False): except RuntimeError as msg: if verbose: print('*** %s' % msg) - pass # end for g.save_workspace() g.quit() @@ -1651,15 +1650,13 @@ def _tab_completion(self): sage: 'Centralizer' in s5._tab_completion() True """ - from sage.misc.misc import uniq P = self.parent() v = P.eval(r'\$SAGE.OperationsAdmittingFirstArgument(%s)'%self.name()) v = v.replace('Tester(','').replace('Setter(','').replace(')','').replace('\n', '') v = v.split(',') v = [ oper.split('"')[1] for oper in v ] v = [ oper for oper in v if all(ch in string.ascii_letters for ch in oper) ] - v = uniq(v) - return v + return sorted(set(v)) @instancedoc diff --git a/src/sage/interfaces/gap_workspace.py b/src/sage/interfaces/gap_workspace.py index 3416cdfe466..f0f077d7269 100644 --- a/src/sage/interfaces/gap_workspace.py +++ b/src/sage/interfaces/gap_workspace.py @@ -27,7 +27,7 @@ def gap_workspace_file(system="gap", name="workspace", dir=None): ``"libgap"`` - ``name`` -- the kind of workspace, usually ``"workspace"`` but - libGAP also uses other files + the library interface also uses other files - ``dir`` -- the directory where the workspaces should be stored. By default, this is ``DOT_SAGE/gap`` diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index cff97b8c901..ee7b1b860be 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -226,7 +226,6 @@ import os from sage.interfaces.expect import Expect, ExpectElement, ExpectFunction, FunctionElement, gc_disabled -from sage.interfaces.tab_completion import ExtraTabCompletion import pexpect @@ -294,15 +293,18 @@ class Giac(Expect): a^2+2*a*b+4*a+b^2+4*b+4 a^2 + 2*a*b + b^2 + 4*a + 4*b + 4 - Variable names in python and giac are independant. + Variable names in python and giac are independent:: - :: - - sage: a=sqrt(2);giac('Digits:=30;a:=5');a,giac('a'),giac(a),giac(a).evalf() - 30 - (sqrt(2), 5, sqrt(2), 1.41421356237309504880168872421) + sage: a=sqrt(2);giac('Digits:=30;a:=5');a,giac('a'),giac(a),giac(a).evalf() + 30 + (sqrt(2), 5, sqrt(2), 1.41421356237309504880168872421) + TESTS:: + sage: g = giac('euler_gamma').sage();g + euler_gamma + sage: g.n() + 0.577215664901533 """ def __init__(self, maxread=None, script_subdirectory=None, server=None, server_tmpdir=None, logfile=None): """ @@ -617,10 +619,7 @@ def eval(self, code, strip=True, **kwds): '4\n3' sage: s='g(x):={\nx+1;\nx+2;\n}' sage: giac(s) - (x)->{ - x+1; - x+2; - } + (x)->[x+1,x+2] sage: giac.g(5) 7 """ @@ -998,7 +997,6 @@ def _latex_(self): """ return self.parent().eval('latex(%s)'%self.name()) - def _matrix_(self, R): r""" Return matrix over the (Sage) ring R determined by self, where self @@ -1079,7 +1077,7 @@ def _sage_(self, locals={}): sage: L = giac('solve((2/3)^x-2, x)'); L list[ln(2)/(ln(2)-ln(3))] sage: L.sage() - [-ln(2)/(ln(3) - ln(2))] + [-log(2)/(log(3) - log(2))] """ from sage.libs.pynac.pynac import symbol_table from sage.calculus.calculus import symbolic_expression_from_string @@ -1134,14 +1132,14 @@ def integral(self, var='x', min=None, max=None): -2*sin(y) """ if min is None: - return giac('int(%s,%s)'%(self.name(),var)) + return giac('int(%s,%s)' % (self.name(), var)) else: if max is None: raise ValueError("neither or both of min/max must be specified.") - return giac('int(%s,%s,%s,%s)'%(self.name(),var,giac(min),giac(max))) - - integrate=integral + return giac('int(%s,%s,%s,%s)' % (self.name(), var, + giac(min), giac(max))) + integrate = integral def sum(self, var, min=None, max=None): r""" @@ -1164,11 +1162,12 @@ def sum(self, var, min=None, max=None): (pi*exp(pi)^2+pi)/(exp(pi)^2-1) """ if min is None: - return giac('sum(%s,%s)'%(self.name(),var)) + return giac('sum(%s,%s)' % (self.name(), var)) else: if max is None: raise ValueError("neither or both of min/max must be specified.") - return giac('sum(%s,%s,%s,%s)'%(self.name(),var,giac(min),giac(max))) + return giac('sum(%s,%s,%s,%s)' % (self.name(), var, + giac(min), giac(max))) # An instance diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index c59c7d67d78..9e3946cec78 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -1114,7 +1114,7 @@ def __repr__(self): """ try: - P = self._check_valid() + self._check_valid() except ValueError as msg: return '(invalid {} object -- {})'.format(self.parent() or type(self), msg) cr = getattr(self, '_cached_repr', None) diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py new file mode 100644 index 00000000000..cc24ed3f0cb --- /dev/null +++ b/src/sage/interfaces/kenzo.py @@ -0,0 +1,377 @@ +r""" +Library interface to Kenzo + +Kenzo is a set of lisp functions to compute homology and +homotopy groups of topological spaces. + +AUTHORS: + +- Miguel Marco, Ana Romero (2019-01): Initial version + + +For this interface, Kenzo is loaded into ECL which is itself loaded +as a C library in Sage. Kenzo objects in this interface are nothing +but wrappers around ECL objects. + + + +# **************************************************************************** +# Copyright (C) 2019 Miguel Marco +# and Ana Romero +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** +""" + + +from __future__ import print_function +from __future__ import absolute_import +from six import string_types + +from sage.structure.sage_object import SageObject +from sage.homology.homology_group import HomologyGroup +from sage.rings.integer_ring import ZZ +from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + +from sage.libs.ecl import EclObject, ecl_eval, EclListIterator + + +# Redirection of ECL and Maxima stdout to /dev/null +# This is also done in the Maxima library, but we +# also do it here for redundancy. +ecl_eval(r"""(defparameter *dev-null* (make-two-way-stream + (make-concatenated-stream) (make-broadcast-stream)))""") +ecl_eval("(setf original-standard-output *standard-output*)") +ecl_eval("(setf *standard-output* *dev-null*)") + +# Loading and initialization of Kenzo +# Note that it will load kenzo.fas file from $SAGE_LOCAL/lib/ecl/ +ecl_eval("(require :kenzo)") +ecl_eval("(in-package :cat)") +ecl_eval("(setf *HOMOLOGY-VERBOSE* nil)") + + +# defining the auxiliary functions as wrappers over the kenzo ones +chcm_mat = EclObject("chcm-mat") +homologie = EclObject("homologie") +sphere = EclObject("sphere") +crts_prdc = EclObject("crts-prdc") +moore = EclObject("moore") +k_z = EclObject("k-z") +k_z2 = EclObject("k-z2") +echcm = EclObject("echcm") +loop_space = EclObject("loop-space") +tnsr_prdc = EclObject("tnsr-prdc") +typep = EclObject("typep") +classifying_space = EclObject("classifying-space") +suspension = EclObject("suspension") + + +def Sphere(n): + r""" + Return the ``n`` dimensional sphere as a Kenzo simplicial set. + + INPUT: + + - ``n`` -- the dimension of the sphere + + OUTPUT: + + - A :class:`KenzoSimplicialSet` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s2 # optional - kenzo + [K1 Simplicial-Set] + sage: [s2.homology(i) for i in range(8)] # optional - kenzo + [Z, 0, Z, 0, 0, 0, 0, 0] + """ + kenzosphere = sphere(n) + return KenzoSimplicialSet(kenzosphere) + + +def MooreSpace(m, n): + r""" + Return the Moore space ``M(m, n)`` as a Kenzo simplicial set. + + The Moore space ``M(m, n)`` is the space whose n'th homology group + is isomorphic to the cyclic group of order ``m``, and the rest of the + homology groups are trivial. + + INPUT: + + - ``m`` - A positive integer. The order of the nontrivial homology group. + + - ``n`` - The dimension in which the homology is not trivial + + + OUTPUT: + + - A KenzoSimplicialSet + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import MooreSpace # optional - kenzo + sage: m24 = MooreSpace(2,4) # optional - kenzo + sage: m24 # optional - kenzo + [K10 Simplicial-Set] + sage: [m24.homology(i) for i in range(8)] # optional - kenzo + [Z, 0, 0, 0, C2, 0, 0, 0] + """ + + kenzomoore = moore(m, n) + return KenzoSimplicialSet(kenzomoore) + + +def EilenbergMacLaneSpace(G, n): + r""" + Return the Eilenberg-MacLane space ``K(G, n)`` as a Kenzo simplicial group. + + The Eilenberg-MacLane space ``K(G, n)`` is the space whose has n'th homotopy + group isomorphic to ``G``, and the rest of the homotopy groups are trivial. + + INPUT: + + - ``G`` -- group. Currently only ``ZZ`` and the additive group of two + elements are supported. + + - ``n`` -- the dimension in which the homotopy is not trivial + + + OUTPUT: + + - A :class:`KenzoSimplicialGroup` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import EilenbergMacLaneSpace # optional - kenzo + sage: e3 = EilenbergMacLaneSpace(ZZ, 3) # optional - kenzo + sage: [e3.homology(i) for i in range(8)] # optional - kenzo + [Z, 0, 0, Z, 0, C2, 0, C3] + sage: f3 = EilenbergMacLaneSpace(AdditiveAbelianGroup([2]), 3) # optional - kenzo + sage: [f3.homology(i) for i in range(8)] # optional - kenzo + [Z, 0, 0, C2, 0, C2, C2, C2] + """ + if G is ZZ: + kenzospace = k_z(n) + return KenzoSimplicialGroup(kenzospace) + elif G in CommutativeAdditiveGroups() and G.cardinality() == 2: + kenzospace = k_z2(n) + return KenzoSimplicialGroup(kenzospace) + else: + raise NotImplementedError("Eilenberg-MacLane spaces are only supported over ZZ and ZZ_2") + +class KenzoObject(SageObject): + r""" + Wrapper to kenzo objects + + INPUT: + + - ``kenzo_object`` -- a wrapper around a kenzo object + (which is an ecl object). + """ + + def __init__(self, kenzo_object): + r""" + Construct the chain complex. + + TESTS:: + + sage: from sage.interfaces.kenzo import KenzoObject # optional -kenzo + sage: from sage.interfaces.kenzo import sphere # optional -kenzo + sage: ks = sphere(2) # optional -kenzo + sage: ks # optional -kenzo + + sage: s2 = KenzoObject(ks) # optional -kenzo + sage: s2 # optional -kenzo + [K1 Simplicial-Set] + sage: TestSuite(s2).run(skip='_test_pickling') # optional -kenzo + + """ + self._kenzo = kenzo_object + + def _repr_(self): + r""" + Represent the object. It just uses the ecl representation, removing the + ecl decoration. + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import MooreSpace # optional - kenzo + sage: m2 = MooreSpace(2,4) # optional - kenzo + sage: m2._repr_() # optional - kenzo + '[K10 Simplicial-Set]' + """ + kenzo_string = repr(self._kenzo) + return kenzo_string[6:-1] + + +class KenzoChainComplex(KenzoObject): + r""" + Wrapper to kenzo chain complexes. + """ + def homology(self, n): + r""" + Return the ``n``'th homology group of the kenzo chain complex + + INPUT: + + - ``n`` -- the dimension in which compute the homology + + OUTOUT: + + - An homology group. + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s2 # optional - kenzo + [K1 Simplicial-Set] + sage: s2.homology(2) # optional - kenzo + Z + """ + echcm1 = echcm(self._kenzo) + m1 = chcm_mat(echcm1, n) + m2 = chcm_mat(echcm1, n+1) + homology = homologie(m1, m2) + lhomomology = [i for i in EclListIterator(homology)] + res = [] + for component in lhomomology: + pair = [i for i in EclListIterator(component)] + res.append(pair[0].python()) + return HomologyGroup(len(res), ZZ, res) + + def tensor_product(self, other): + r""" + Return the tensor product of ``self`` and ``other``. + + INPUT: + + - ``other`` -- The Kenzo object with which to compute the tensor product + + OUTPUT: + + - A :class:`KenzoChainComplex` + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: p = s2.tensor_product(s3) # optional - kenzo + sage: type(p) # optional - kenzo + + sage: [p.homology(i) for i in range(8)] # optional - kenzo + [Z, 0, Z, Z, 0, Z, 0, 0] + """ + return KenzoChainComplex(tnsr_prdc(self._kenzo, other._kenzo)) + + +class KenzoSimplicialSet(KenzoChainComplex): + r""" + Wrapper to Kenzo simplicial sets. + """ + + def loop_space(self, n=1): + r""" + Return the ``n`` th iterated loop space. + + INPUT: + + - ``n`` -- (default: 1) the number of times to iterate the loop space + construction + + OUTPUT: + + - A :class:`KenzoSimplicialGroup` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: l2 = s2.loop_space() # optional - kenzo + sage: type(l2) # optional - kenzo + + sage: l2 = s2.loop_space() # optional - kenzo + sage: [l2.homology(i) for i in range(8)] # optional - kenzo + [Z, Z, Z, Z, Z, Z, Z, Z] + """ + return KenzoSimplicialGroup(loop_space(self._kenzo, n)) + + def cartesian_product(self, other): + r""" + Return the cartesian product of ``self`` and ``other``. + + INPUT: + + - ``other`` -- the Kenzo simplicial set with which the product is made + + OUTPUT: + + - A :class:`KenzoSimplicialSet` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import Sphere # optional - kenzo + sage: s2 = Sphere(2) # optional - kenzo + sage: s3 = Sphere(3) # optional - kenzo + sage: p = s2.cartesian_product(s3) # optional - kenzo + sage: type(p) # optional - kenzo + + sage: [p.homology(i) for i in range(6)] # optional - kenzo + [Z, 0, Z, Z, 0, Z] + """ + prod_kenzo = crts_prdc(self._kenzo, other._kenzo) + return KenzoSimplicialSet(prod_kenzo) + + def suspension(self): + r""" + Return the suspension of the simplicial set. + + OUTPUT: + + - A :class:`KenzoSimplicialSet` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import EilenbergMacLaneSpace # optional - kenzo + sage: e3 = EilenbergMacLaneSpace(ZZ, 3) # optional - kenzo + sage: s = e3.suspension() # optional - kenzo + sage: type(s) # optional - kenzo + + sage: [s.homology(i) for i in range(6)] # optional - kenzo + [Z, 0, 0, 0, Z, 0] + """ + return KenzoSimplicialSet(suspension(self._kenzo)) + + +class KenzoSimplicialGroup(KenzoSimplicialSet): + r""" + Wrapper around Kenzo simplicial groups. + """ + + def classifying_space(self): + r""" + Return the classifying space. + + OUTPUT: + + - A :class:`KenzoSimplicialGroup` + + EXAMPLES:: + + sage: from sage.interfaces.kenzo import MooreSpace # optional - kenzo + sage: m2 = MooreSpace(2,4) # optional - kenzo + sage: l2 = m2.loop_space() # optional - kenzo + sage: c = l2.classifying_space() # optional - kenzo + sage: type(c) # optional - kenzo + + sage: [c.homology(i) for i in range(8)] # optional - kenzo + [Z, 0, 0, 0, C2, 0, 0, 0] + """ + return KenzoSimplicialGroup(classifying_space(self._kenzo)) diff --git a/src/sage/interfaces/latte.py b/src/sage/interfaces/latte.py index 2678885a8ef..b5503089f82 100644 --- a/src/sage/interfaces/latte.py +++ b/src/sage/interfaces/latte.py @@ -15,9 +15,10 @@ from subprocess import Popen, PIPE from sage.misc.misc import SAGE_TMP - +from sage.rings.integer import Integer from sage.features.latte import Latte + def count(arg, ehrhart_polynomial=False, multivariate_generating_function=False, raw_output=False, verbose=False, **kwds): r""" Call to the program count from LattE integrale @@ -187,9 +188,9 @@ def count(arg, ehrhart_polynomial=False, multivariate_generating_function=False, if raw_output: return ans else: - from sage.rings.integer import Integer return Integer(ans) + def integrate(arg, polynomial=None, algorithm='triangulate', raw_output=False, verbose=False, **kwds): r""" Call to the function integrate from LattE integrale. @@ -304,6 +305,8 @@ def integrate(arg, polynomial=None, algorithm='triangulate', raw_output=False, v # Check that LattE is present Latte().require() + from sage.rings.rational import Rational + args = ['integrate'] got_polynomial = True if polynomial is not None else False @@ -371,9 +374,9 @@ def integrate(arg, polynomial=None, algorithm='triangulate', raw_output=False, v if raw_output: return ans else: - from sage.rings.rational import Rational return Rational(ans) + def to_latte_polynomial(polynomial): r""" Helper function to transform a polynomial to its LattE description. diff --git a/src/sage/interfaces/lie.py b/src/sage/interfaces/lie.py index 2ddcf9bcf14..6db27637859 100644 --- a/src/sage/interfaces/lie.py +++ b/src/sage/interfaces/lie.py @@ -285,10 +285,10 @@ # http://www.gnu.org/licenses/ # ########################################################################## -from __future__ import print_function -from __future__ import absolute_import +from __future__ import print_function, absolute_import -from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement, AsciiArtString +from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement +from sage.interfaces.interface import AsciiArtString from sage.misc.all import prod from sage.env import DOT_SAGE, SAGE_LOCAL from sage.interfaces.tab_completion import ExtraTabCompletion @@ -296,8 +296,9 @@ import os -COMMANDS_CACHE = '%s/lie_commandlist_cache.sobj'%DOT_SAGE -HELP_CACHE = '%s/lie_helpdict_cache.sobj'%DOT_SAGE +COMMANDS_CACHE = '%s/lie_commandlist_cache.sobj' % DOT_SAGE +HELP_CACHE = '%s/lie_helpdict_cache.sobj' % DOT_SAGE + class LiE(ExtraTabCompletion, Expect): r""" diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index c80b2e78bd1..c6e44f45223 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -98,15 +98,14 @@ from __future__ import print_function import os +import re -from sage.interfaces.expect import (Expect, ExpectElement, ExpectFunction, - AsciiArtString) - +from sage.interfaces.expect import Expect, ExpectElement, ExpectFunction +from sage.interfaces.interface import AsciiArtString from sage.misc.multireplace import multiple_replace from sage.interfaces.tab_completion import ExtraTabCompletion from sage.docs.instancedoc import instancedoc -import re def remove_output_labels(s): r""" diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index 4ae6a9dd5c9..4e8a47d972d 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -1512,7 +1512,6 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): N.append(x[:i]) except RuntimeError as msg: # weird internal problems in Magma type system print('Error -- %s' % msg) - pass if verbose: print("Done! (%s seconds)" % sage.misc.misc.cputime(tm)) N = sorted(set(N)) @@ -1566,11 +1565,9 @@ def set_verbose(self, type, level): INPUT: + - ``type`` -- string (e.g. 'Groebner') - - ``type`` - string (e.g. 'Groebner') - - - ``level`` - integer = 0 - + - ``level`` -- integer >= 0 EXAMPLES:: diff --git a/src/sage/interfaces/maple.py b/src/sage/interfaces/maple.py index f6ddf3b59eb..42c9b547a7c 100644 --- a/src/sage/interfaces/maple.py +++ b/src/sage/interfaces/maple.py @@ -101,7 +101,7 @@ :: sage: maple('(x^28-1)').factor( ) # optional - maple - (x-1)*(x^6+x^5+x^4+x^3+x^2+x+1)*(x+1)*(1-x+x^2-x^3+x^4-x^5+x^6)*(x^2+1)*(x^12-x^10+x^8-x^6+x^4-x^2+1) + (x-1)*(x^6+x^5+x^4+x^3+x^2+x+1)*(x+1)*(x^6-x^5+x^4-x^3+x^2-x+1)*(x^2+1)*(x^12-x^10+x^8-x^6+x^4-x^2+1) Another important feature of maple is its online help. We can access this through sage as well. After reading the description of @@ -232,10 +232,9 @@ # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ############################################################################# -from __future__ import print_function -from __future__ import absolute_import +from __future__ import print_function, absolute_import import os @@ -248,7 +247,7 @@ from sage.interfaces.tab_completion import ExtraTabCompletion from sage.docs.instancedoc import instancedoc -COMMANDS_CACHE = '%s/maple_commandlist_cache.sobj'%DOT_SAGE +COMMANDS_CACHE = '%s/maple_commandlist_cache.sobj' % DOT_SAGE class Maple(ExtraTabCompletion, Expect): @@ -1118,11 +1117,42 @@ def _sage_(self): sage: m.sage() # optional - maple (cos(1/x) - 1)^2*sin(sqrt(-x^2 + 1)) + Some matrices can be converted back:: + + sage: m = matrix(2, 2, [1, 2, x, 3]) # optional - maple + sage: mm = maple(m) # optional - maple + sage: mm.sage() == m # optional - maple + True + + Some vectors can be converted back:: + + sage: m = vector([1, x, 2, 3]) # optional - maple + sage: mm = maple(m) # optional - maple + sage: mm.sage() == m # optional - maple + True """ + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + from sage.rings.integer_ring import ZZ + result = repr(self) # The next few lines are a very crude excuse for a maple "parser". result = result.replace("Pi", "pi") + if result[:6] == "Matrix": + content = result[7:-1] + m, n = content.split(',')[:2] + m = ZZ(m.strip()) + n = ZZ(n.strip()) + coeffs = [self[i + 1, j + 1].sage() + for i in range(m) for j in range(n)] + return matrix(m, n, coeffs) + elif result[:6] == "Vector": + start = result.index('(') + content = result[start + 1:-1] + m = ZZ(content.split(',')[0].strip()) + return vector([self[i + 1].sage() for i in range(m)]) + try: from sage.symbolic.all import SR return SR(result) diff --git a/src/sage/interfaces/mathematica.py b/src/sage/interfaces/mathematica.py index 611969d1eb9..547fd42534c 100644 --- a/src/sage/interfaces/mathematica.py +++ b/src/sage/interfaces/mathematica.py @@ -362,7 +362,8 @@ from sage.misc.cachefunc import cached_method from sage.interfaces.expect import (Expect, ExpectElement, ExpectFunction, - FunctionElement, AsciiArtString) + FunctionElement) +from sage.interfaces.interface import AsciiArtString from sage.interfaces.tab_completion import ExtraTabCompletion from sage.docs.instancedoc import instancedoc diff --git a/src/sage/interfaces/maxima.py b/src/sage/interfaces/maxima.py index b1f35f47e8a..eacbc4c3a22 100644 --- a/src/sage/interfaces/maxima.py +++ b/src/sage/interfaces/maxima.py @@ -741,7 +741,6 @@ def _expect_expr(self, expr=None, timeout=None): i += 1 if i > 10: break - pass else: break raise KeyboardInterrupt(msg) diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index 518644f7a5b..d8d6576f134 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -58,7 +58,7 @@ import subprocess from sage.env import DOT_SAGE -COMMANDS_CACHE = '%s/maxima_commandlist_cache.sobj'%DOT_SAGE +COMMANDS_CACHE = '%s/maxima_commandlist_cache.sobj' % DOT_SAGE from sage.cpython.string import bytes_to_str @@ -68,7 +68,7 @@ import sage.server.support from .interface import (Interface, InterfaceElement, InterfaceFunctionElement, - InterfaceFunction, AsciiArtString) + InterfaceFunction, AsciiArtString) from sage.interfaces.tab_completion import ExtraTabCompletion from sage.docs.instancedoc import instancedoc diff --git a/src/sage/interfaces/mupad.py b/src/sage/interfaces/mupad.py index 68449ebb8dd..21a47e49911 100644 --- a/src/sage/interfaces/mupad.py +++ b/src/sage/interfaces/mupad.py @@ -89,18 +89,18 @@ # # http://www.gnu.org/licenses/ ############################################################################# -from __future__ import print_function -from __future__ import absolute_import +from __future__ import print_function, absolute_import import os from .expect import (Expect, ExpectElement, ExpectFunction, - FunctionElement, AsciiArtString) + FunctionElement) +from sage.interfaces.interface import AsciiArtString from sage.interfaces.tab_completion import ExtraTabCompletion from sage.env import DOT_SAGE from sage.docs.instancedoc import instancedoc -COMMANDS_CACHE = '%s/mupad_commandlist_cache.sobj'%DOT_SAGE +COMMANDS_CACHE = '%s/mupad_commandlist_cache.sobj' % DOT_SAGE PROMPT = ">>" seq = 0 diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index 045fd8b3d52..2c9723be9e7 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -144,6 +144,7 @@ import os from .expect import Expect, ExpectElement +import pexpect from sage.misc.misc import verbose from sage.docs.instancedoc import instancedoc @@ -182,10 +183,8 @@ def __init__(self, maxread=None, script_subdirectory=None, logfile=None, True """ if command is None: - import os command = os.getenv('SAGE_OCTAVE_COMMAND') or 'octave-cli' if server is None: - import os server = os.getenv('SAGE_OCTAVE_SERVER') or None Expect.__init__(self, name = 'octave', @@ -239,7 +238,7 @@ def _read_in_file_command(self, filename): sage: octave._read_in_file_command(filename) 'source("...");' """ - return 'source("%s");'%filename + return 'source("%s");' % filename def _quit_string(self): """ @@ -723,7 +722,7 @@ def _vector_(self, R=None): sage: vector(A) # optional - octave (1.0, 1.0*I) """ - oc = self.parent() + from sage.modules.free_module import FreeModule if not self.isvector(): raise TypeError('not an octave vector') if R is None: @@ -736,7 +735,6 @@ def _vector_(self, R=None): if self.iscomplex(): w = [to_complex(x, R) for x in w] - from sage.modules.free_module import FreeModule return FreeModule(R, nrows)(w) def _scalar_(self): diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index 8215e97160a..390ac0ea748 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -10,7 +10,7 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Simon King # # Distributed under the terms of the GNU General Public License (GPL) @@ -22,20 +22,20 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** -from __future__ import print_function -from __future__ import absolute_import +# hsttp://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import print_function, absolute_import +import six +from six.moves import range +from six import reraise as raise_ import os import re import sys -import six +import time -from sage.structure.parent import Parent -from .expect import console, Expect, ExpectElement, ExpectFunction, FunctionElement +from .expect import Expect, ExpectElement, FunctionElement -from sage.env import SAGE_EXTCODE, DOT_SAGE from sage.misc.misc import get_verbose from sage.misc.cachefunc import cached_method from sage.interfaces.tab_completion import ExtraTabCompletion @@ -44,8 +44,6 @@ from random import randrange from time import sleep -from six.moves import range -from six import reraise as raise_ import warnings _name_pattern = re.compile('SAGE[0-9]+') @@ -62,6 +60,7 @@ 8: "fails to respond timely" } + class PolymakeError(RuntimeError): """ Raised if polymake yields an error message. @@ -76,6 +75,7 @@ class PolymakeError(RuntimeError): """ pass + def polymake_console(command=''): """ Spawn a new polymake command-line session. @@ -105,6 +105,7 @@ def polymake_console(command=''): raise RuntimeError('Can use the console only in the terminal. Try %%polymake magics instead.') os.system(command or os.getenv('SAGE_POLYMAKE_COMMAND') or 'polymake') + class Polymake(ExtraTabCompletion, Expect): r""" Interface to the polymake interpreter. @@ -1263,7 +1264,6 @@ def reduce_load_Polymake(): ######################################## ## Elements -from warnings import warn class PolymakeElement(ExtraTabCompletion, ExpectElement): """ @@ -1544,7 +1544,7 @@ def _member_list(self): cmd = 'print join(", ", sorted_uniq(sort { $a cmp $b } map { keys %{$_->properties} }$SAGETMP, @{$SAGETMP->super}));' try: out = P.eval(cmd).split(', ') - except PolymakeError as msg: + except PolymakeError: return [] return sorted(out) @@ -1564,7 +1564,7 @@ def typename(self): P = self._check_valid() try: return P.eval('print {}->type->name;'.format(self._name)) - except PolymakeError as msg: + except PolymakeError: return '' def full_typename(self): @@ -1583,7 +1583,7 @@ def full_typename(self): P = self._check_valid() try: return P.eval('print {}->type->full_name;'.format(self._name)) - except PolymakeError as msg: + except PolymakeError: return '' def qualified_typename(self): @@ -1602,7 +1602,7 @@ def qualified_typename(self): P = self._check_valid() try: return P.eval('print {}->type->qualified_name;'.format(self._name)) - except PolymakeError as msg: + except PolymakeError: return '' def _tab_completion(self): @@ -1810,9 +1810,9 @@ def __getitem__(self, key): _, T = self.typeof() if self._name.startswith('@'): return P('${}[{}]'.format(self._name[1:], key)) - if T=='ARRAY': + if T == 'ARRAY': return P('{}[{}]'.format(self._name, key)) - if T=='HASH': + if T == 'HASH': try: if key.parent() is self.parent(): key = key._name @@ -1820,7 +1820,7 @@ def __getitem__(self, key): key = str(key) except AttributeError: key = str(key) - return P(name+"{"+key+"}") + return P(self._name + "{" + key + "}") raise NotImplementedError("Cannot get items from Perl type {}".format(T)) def __iter__(self): @@ -1850,12 +1850,12 @@ def __len__(self): """ P = self._check_valid() - T1,T2 = self.typeof() + T1, T2 = self.typeof() name = self._name - if T2=='ARRAY': - return int(P.eval('print scalar @{+%s};'%name)) - if T2=='HASH': - return int(P.eval('print scalar keys %{+%s};'%name)) + if T2 == 'ARRAY': + return int(P.eval('print scalar @{+%s};' % name)) + if T2 == 'HASH': + return int(P.eval('print scalar keys %{+' + '%s};' % name)) if T1: raise TypeError("Don't know how to compute the length of {} object".format(T1)) return int(P.eval('print scalar {};'.format(name))) @@ -1937,7 +1937,7 @@ def _sage_(self): """ T1, T2 = self.typeof() - P = self._check_valid() + self._check_valid() if T1: Temp = self.typename() if Temp: diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index 43c19f7e0eb..632f2482a0c 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -604,8 +604,7 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import print_function -from __future__ import absolute_import +from __future__ import print_function, absolute_import from six import string_types from sage.env import SAGE_LOCAL @@ -618,7 +617,8 @@ from sage.repl.preparse import implicit_mul from sage.interfaces.tab_completion import ExtraTabCompletion from sage.docs.instancedoc import instancedoc -from .expect import Expect, ExpectFunction, AsciiArtString +from .expect import Expect, ExpectFunction +from sage.interfaces.interface import AsciiArtString def _qepcad_atoms(formula): diff --git a/src/sage/interfaces/qsieve.py b/src/sage/interfaces/qsieve.py index 72f03c87ad1..2006e6fbb8f 100644 --- a/src/sage/interfaces/qsieve.py +++ b/src/sage/interfaces/qsieve.py @@ -292,7 +292,6 @@ def _get(self, timeout=0.1): except pexpect.TIMEOUT: pass except pexpect.EOF: - pass self._done = True self._p.close() self._out += bytes_to_str(e.before) diff --git a/src/sage/interfaces/quit.py b/src/sage/interfaces/quit.py index bb8071a9d66..743fd9e2207 100644 --- a/src/sage/interfaces/quit.py +++ b/src/sage/interfaces/quit.py @@ -36,7 +36,6 @@ def expect_quitall(verbose=False): if not R is None: try: R.quit(verbose=verbose) - pass except RuntimeError: pass kill_spawned_jobs() @@ -78,6 +77,7 @@ def kill_spawned_jobs(verbose=False): except OSError: pass + def is_running(pid): """ Return True if and only if there is a process with id pid running. diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 972fb4b5a14..145e6de6696 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -308,19 +308,19 @@ '' """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 David Joyner and William Stein # # This 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/ -#***************************************************************************** -from __future__ import print_function -from __future__ import absolute_import +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import print_function, absolute_import from six.moves import range from six import integer_types, string_types +from six import reraise as raise_ import io import os @@ -338,10 +338,8 @@ import sage.rings.integer from sage.misc.misc import get_verbose -from sage.misc.superseded import deprecation from sage.docs.instancedoc import instancedoc -from six import reraise as raise_ class SingularError(RuntimeError): """ @@ -2263,7 +2261,6 @@ def generate_docstring_dictionary(): nodes.clear() node_names.clear() - import os singular_docdir = os.environ['SINGULARPATH']+"/../info/" new_node = re.compile(r"File: singular\.hlp, Node: ([^,]*),.*") @@ -2612,7 +2609,6 @@ def __enter__(self): 7*b+210*c^3-79*c^2+3*c, 7*a-420*c^3+158*c^2+8*c-7 """ - from sage.interfaces.singular import SingularError try: self.bck_degBound = int(self.singular.eval('degBound')) except SingularError: @@ -2650,17 +2646,17 @@ def __exit__(self, typ, value, tb): 7*b+210*c^3-79*c^2+3*c, 7*a-420*c^3+158*c^2+8*c-7 """ - from sage.interfaces.singular import SingularError - self.singular.option("set",self.o) + self.singular.option("set", self.o) try: - self.singular.eval('degBound=%d'%self.bck_degBound) + self.singular.eval('degBound=%d' % self.bck_degBound) except SingularError: pass try: - self.singular.eval('multBound=%d'%self.bck_multBound) + self.singular.eval('multBound=%d' % self.bck_multBound) except SingularError: pass + def singular_gb_standard_options(func): r""" Decorator to force a reduced Singular groebner basis. diff --git a/src/sage/interfaces/sympy.py b/src/sage/interfaces/sympy.py index a6f2823b81d..2ac9e40b791 100644 --- a/src/sage/interfaces/sympy.py +++ b/src/sage/interfaces/sympy.py @@ -815,7 +815,6 @@ def check_expression(expr, var_symbols, only_from_sympy=False): sage: from sage.interfaces.sympy import check_expression sage: check_expression("1.123*x", "x") """ - from sage import __dict__ as sagedict from sage.symbolic.ring import SR from sympy import (__dict__ as sympydict, Basic, S, var as svar) # evaluate the expression in the context of Sage: @@ -827,7 +826,6 @@ def check_expression(expr, var_symbols, only_from_sympy=False): assert not isinstance(e_sage, Basic) except (NameError, TypeError): is_different = True - pass # evaluate the expression in the context of SymPy: if var_symbols: @@ -968,10 +966,12 @@ def test_undefined_function(): #test_integral_failing() test_undefined_function() + def sympy_set_to_list(set, vars): """ Convert all set objects that can be returned by SymPy's solvers. """ + from sage.rings.infinity import UnsignedInfinity from sympy import (FiniteSet, And, Or, Union, Interval, oo, S) from sympy.core.relational import Relational if set == S.Reals: diff --git a/src/sage/interfaces/tachyon.py b/src/sage/interfaces/tachyon.py index 199bafa3f65..a492170cb0b 100644 --- a/src/sage/interfaces/tachyon.py +++ b/src/sage/interfaces/tachyon.py @@ -22,7 +22,6 @@ from sage.misc.pager import pager from sage.misc.temporary_file import tmp_filename from sage.structure.sage_object import SageObject -from sage.cpython.string import bytes_to_str class TachyonRT(SageObject): diff --git a/src/sage/interfaces/tides.py b/src/sage/interfaces/tides.py index 8248083f713..cf7c0f354d5 100644 --- a/src/sage/interfaces/tides.py +++ b/src/sage/interfaces/tides.py @@ -717,7 +717,7 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, sage: l[16] ' int nfun = 0;\n' sage: l[26] - '\tmpfr_set_str(v[2], "0.0000000000000000000000000000000000000000000000000000", 10, TIDES_RND);\n' + '\tmpfr_set_str(v[2], "0.000000000000000000000000000000000000000000000000000", 10, TIDES_RND);\n' sage: l[30] '\tmpfr_init2(tolabs, TIDES_PREC); \n' sage: l[34] diff --git a/src/sage/knots/all.py b/src/sage/knots/all.py index d4047819d7b..61485575367 100644 --- a/src/sage/knots/all.py +++ b/src/sage/knots/all.py @@ -1,3 +1,3 @@ -from sage.knots.knot import Knot +from sage.knots.knot import Knot, Knots from sage.knots.link import Link diff --git a/src/sage/knots/knot.py b/src/sage/knots/knot.py index 91f06545e69..06b0d9f4d52 100644 --- a/src/sage/knots/knot.py +++ b/src/sage/knots/knot.py @@ -7,21 +7,29 @@ - Amit Jamadagni """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 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 six import add_metaclass from sage.knots.link import Link -from sage.rings.finite_rings.integer_mod import Mod +from sage.structure.parent import Parent +from sage.structure.element import Element +from sage.misc.fast_methods import Singleton +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.categories.monoids import Monoids -class Knot(Link): +# We need Link to be first in the MRO in order to use its equality, hash, etc. +@add_metaclass(InheritComparisonClasscallMetaclass) +class Knot(Link, Element): r""" A knot. @@ -69,12 +77,22 @@ class Knot(Link): REFERENCES: - :wikipedia:`Knot_(mathematics)` + """ + @staticmethod + def __classcall_private__(self, data, check=True): + """ + Make sure this is an instance of the element class + of :class:`Knots`. - .. TODO:: + EXAMPLES:: + + sage: B = BraidGroup(8) + sage: K = Knot(B([-1, -1, -1, 2, 1, -2, 3, -2, 3])) + sage: type(K) + + """ + return Knots().element_class(data, check=check) - - Make a class Knots for the monoid of all knots and have this be an - element in that monoid. - """ def __init__(self, data, check=True): """ Initialize ``self``. @@ -82,8 +100,6 @@ def __init__(self, data, check=True): TESTS:: sage: B = BraidGroup(8) - sage: K = Knot(B([-1, -1, -1, 2, 1, -2, 3, -2, 3])) - sage: TestSuite(K).run() sage: K = Knot(B([1, -2, 1, -2])) sage: TestSuite(K).run() sage: K = Knot([[1, 1, 2, 2]]) @@ -99,12 +115,13 @@ def __init__(self, data, check=True): sage: Knot([[[1, 2], [-2, -1]], [1, -1]], check=False) Knot represented by 2 crossings """ + Element.__init__(self, Knots()) Link.__init__(self, data) if check: if self.number_of_components() != 1: raise ValueError("the input has more than 1 connected component") - def __repr__(self): + def _repr_(self): """ Return a string representation. @@ -177,7 +194,7 @@ def dt_code(self): assert label[2 * crossing + next_label % 2] != 1, "invalid knot" label[2 * crossing + next_label % 2] = next_label - next_label = next_label + 1 + next_label += 1 if type1 == 0: if b[crossing] < 0: type1 = 1 @@ -187,14 +204,14 @@ def dt_code(self): type1 = -1 * type1 if ((abs(b[crossing]) == string and b[crossing] * type1 > 0) or (abs(b[crossing]) != string and b[crossing] * type1 < 0)): - if next_label % 2 == 1: + if next_label % 2: label[2 * crossing] = label[2 * crossing] * -1 if abs(b[crossing]) == string: - string = string + 1 + string += 1 else: - string = string - 1 - crossing = crossing + 1 - code = [0 for i in range(N)] + string -= 1 + crossing += 1 + code = [0 for _ in range(N)] for i in range(N): for j in range(N): if label[2 * j + 1] == 2 * i + 1: @@ -220,10 +237,9 @@ def arf_invariant(self): sage: K.arf_invariant() 1 """ - a = self.alexander_polynomial() - if Mod(a(-1), 8) == 1 or Mod(a(-1), 8) == 7: + a = self.alexander_polynomial()(-1) + if (a % 8) == 1 or (a % 8) == 7: return 0 - return 1 def connected_sum(self, other): @@ -277,20 +293,88 @@ def connected_sum(self, other): K = t.connected_sum(tr) sphinx_plot(K.plot()) + TESTS:: + + sage: B = BraidGroup(2) + sage: trivial = Knots().one() + sage: trivial * trivial + Knot represented by 0 crossings + sage: trefoil = Knot(B([1,1,1])) + sage: trefoil * trivial + Knot represented by 3 crossings + sage: trefoil * trefoil + Knot represented by 6 crossings + REFERENCES: - :wikipedia:`Connected_sum` """ - from copy import deepcopy from sage.functions.generalized import sign - ogc1 = deepcopy(self.oriented_gauss_code()) - ogc2 = deepcopy(other.oriented_gauss_code()) + ogc1 = self.oriented_gauss_code() + ogc2 = other.oriented_gauss_code() + if not ogc1[0]: + return other + if not ogc2[0]: + return self # how much we have to "displace" the numbering of the crossings of other - m1 = max([abs(i) for i in ogc1[0][0]]) - m2 = min([abs(i) for i in ogc2[0][0]]) + m1 = max(abs(i) for i in ogc1[0][0]) + m2 = min(abs(i) for i in ogc2[0][0]) n = m1 - m2 + 1 # construct the oriented gauss code of the result - ogc2[0][0] = [a+int(sign(a))*n for a in ogc2[0][0]] - nogc = [[ogc1[0][0]+ogc2[0][0]],ogc1[1]+ogc2[1]] - return Knot(nogc) + ogc2_0_0 = [a + int(sign(a)) * n for a in ogc2[0][0]] + nogc = [[ogc1[0][0] + ogc2_0_0], ogc1[1] + ogc2[1]] + return type(self)(nogc) + + _mul_ = connected_sum + + +class Knots(Singleton, Parent): + """ + The set for all knots, as a monoid for the connected sum. + """ + def __init__(self): + """ + TESTS:: + + sage: S = Knots() + sage: S.cardinality() + +Infinity + sage: TestSuite(S).run() + """ + Parent.__init__(self, category=Monoids().Infinite()) + + def _repr_(self): + r""" + TESTS:: + + sage: Knots() + Knots + """ + return "Knots" + + def one(self): + """ + Return the unit of the monoid. + + This is the trivial knot. + + EXAMPLES:: + + sage: Knots().one() + Knot represented by 0 crossings + """ + return self.element_class([]) + + def an_element(self): + """ + Return the trefoil knot. + + EXAMPLES:: + + sage: Knots().an_element() + Knot represented by 3 crossings + """ + return self.element_class([[1, 5, 2, 4], [5, 3, 6, 2], [3, 1, 4, 6]]) + + Element = Knot diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index 848582eea72..3dc3e16137e 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -36,7 +36,7 @@ - Amit Jamadagni """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Miguel Angel Marco Buzunariz # Amit Jamadagni # @@ -44,8 +44,8 @@ # 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 __future__ import division import six @@ -65,9 +65,10 @@ from sage.misc.cachefunc import cached_method from copy import deepcopy, copy from itertools import combinations +from sage.structure.sage_object import SageObject -class Link(object): +class Link(SageObject): r""" A link. @@ -511,7 +512,7 @@ def fundamental_group(self, presentation='wirtinger'): rels.append(ela * elb / elc / elb) return F.quotient(rels) - def __repr__(self): + def _repr_(self): """ Return a string representation. @@ -1722,6 +1723,16 @@ def signature(self): """ Return the signature of ``self``. + This is defined as the signature of the symmetric matrix + + .. MATH:: + + V + V^{t}, + + where `V` is the :meth:`Seifert matrix `. + + .. SEEALSO:: :meth:`omega_signature`, :meth:`seifert_matrix` + EXAMPLES:: sage: B = BraidGroup(4) @@ -1736,8 +1747,56 @@ def signature(self): sage: L.signature() -2 """ - m = 2 * (self.seifert_matrix() + self.seifert_matrix().transpose()) - return sum([j.real().sign() for j in m.eigenvalues()], ZZ.zero()) + V = self.seifert_matrix() + m = V + V.transpose() + return ZZ.sum(j.real().sign() for j in m.eigenvalues()) + + def omega_signature(self, omega): + r""" + Compute the `\omega`-signature of ``self``. + + INPUT: + + - `\omega` -- a complex number of modulus 1. This is assumed to be + coercible to ``QQbar``. + + This is defined as the signature of the Hermitian matrix + + .. MATH:: + + (1 - \omega) V + (1 - \omega^{-1}) V^{t}, + + where `V` is the :meth:`Seifert matrix `, + as explained on page 122 of [Livi1993]_. + + According to [Conway2018]_, this is also known as the + Levine-Tristram signature, the equivariant signature or the + Tristram-Levine signature. + + .. SEEALSO:: :meth:`signature`, :meth:`seifert_matrix` + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: K = Knot(B([1,1,1,2,-1,2,-3,2,-3])) + sage: omega = QQbar.zeta(3) + sage: K.omega_signature(omega) + -2 + + REFERENCES: + + .. [Livi1993] Charles Livingston, *Knot Theory*, Carus Mathematical + Monographs, number 24. + + .. [Conway2018] Anthony Conway, *Notes On The Levine-Tristram + Signature Function*, July 2018 + http://www.unige.ch/math/folks/conway/Notes/LevineTristramSurvey.pdf + """ + from sage.rings.qqbar import QQbar + omega = QQbar(omega) + V = self.seifert_matrix() + m = (1 - omega) * V + (1 - omega.conjugate()) * V.transpose() + return ZZ.sum(j.real().sign() for j in m.eigenvalues()) def alexander_polynomial(self, var='t'): """ diff --git a/src/sage/libs/arb/acb.pxd b/src/sage/libs/arb/acb.pxd index 64232ab9dfa..80565792a0b 100644 --- a/src/sage/libs/arb/acb.pxd +++ b/src/sage/libs/arb/acb.pxd @@ -125,6 +125,8 @@ cdef extern from "acb.h": void acb_sin_cos(arb_t s, arb_t c, const acb_t z, long prec) void acb_tan(acb_t s, const acb_t z, long prec) void acb_cot(acb_t s, const acb_t z, long prec) + void acb_sec(acb_t s, const acb_t z, long prec) + void acb_csc(acb_t c, const acb_t z, long prec) void acb_sin_pi(acb_t s, const acb_t z, long prec) void acb_cos_pi(acb_t s, const acb_t z, long prec) void acb_sin_cos_pi(acb_t s, acb_t c, const acb_t z, long prec) @@ -143,6 +145,8 @@ cdef extern from "acb.h": void acb_sinh_cosh(acb_t s, acb_t c, const acb_t z, long prec) void acb_tanh(acb_t s, const acb_t z, long prec) void acb_coth(acb_t s, const acb_t z, long prec) + void acb_sech(acb_t s, const acb_t z, long prec) + void acb_csch(acb_t c, const acb_t z, long prec) void acb_rising_ui_bs(acb_t z, const acb_t x, unsigned long n, long prec) void acb_rising_ui_rs(acb_t z, const acb_t x, unsigned long n, unsigned long step, long prec) diff --git a/src/sage/libs/arb/arb.pxd b/src/sage/libs/arb/arb.pxd index d855de62a2a..1b922d43658 100644 --- a/src/sage/libs/arb/arb.pxd +++ b/src/sage/libs/arb/arb.pxd @@ -182,6 +182,8 @@ cdef extern from "arb.h": void arb_cos_pi_fmpq(arb_t c, const fmpq_t x, long prec) void arb_tan_pi(arb_t y, const arb_t x, long prec) void arb_cot_pi(arb_t y, const arb_t x, long prec) + void arb_sec(arb_t s, const arb_t x, long prec) + void arb_csc(arb_t c, const arb_t x, long prec) void arb_atan_arf(arb_t z, const arf_t x, long prec) void arb_atan(arb_t z, const arb_t x, long prec) @@ -194,6 +196,8 @@ cdef extern from "arb.h": void arb_sinh_cosh(arb_t s, arb_t c, const arb_t x, long prec) void arb_tanh(arb_t y, const arb_t x, long prec) void arb_coth(arb_t y, const arb_t x, long prec) + void arb_sech(arb_t s, const arb_t x, long prec) + void arb_csch(arb_t c, const arb_t x, long prec) void arb_asinh(arb_t z, const arb_t x, long prec) void arb_acosh(arb_t z, const arb_t x, long prec) diff --git a/src/sage/libs/coxeter3/coxeter.pyx b/src/sage/libs/coxeter3/coxeter.pyx index 694239fd555..98d6287f12f 100644 --- a/src/sage/libs/coxeter3/coxeter.pyx +++ b/src/sage/libs/coxeter3/coxeter.pyx @@ -797,7 +797,7 @@ cdef class CoxGroupElement: def __richcmp__(CoxGroupElement self, other, int op): """ - EXAMPLES: + EXAMPLES:: sage: from sage.libs.coxeter3.coxeter import * # optional - coxeter3 sage: W = CoxGroup(['A', 5]) # optional - coxeter3 diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index e4088660b27..ee5cc783550 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -1145,7 +1145,7 @@ cdef class EclObject: Strings are not characters - EXAMPLES: + EXAMPLES:: sage: from sage.libs.ecl import * sage: EclObject('"a"').characterp() diff --git a/src/sage/libs/eclib/__init__.pxd b/src/sage/libs/eclib/__init__.pxd index 0ce67a72c13..7ff4ac13fa9 100644 --- a/src/sage/libs/eclib/__init__.pxd +++ b/src/sage/libs/eclib/__init__.pxd @@ -1,5 +1,4 @@ # distutils: language = c++ -# distutils: extra_compile_args = -DNTL_ALL # distutils: libraries = ec ntl pari gmp m diff --git a/src/sage/libs/eclib/all.py b/src/sage/libs/eclib/all.py index e0cf7fe4bbf..717a66fae7b 100644 --- a/src/sage/libs/eclib/all.py +++ b/src/sage/libs/eclib/all.py @@ -1,7 +1,4 @@ -from __future__ import absolute_import from .constructor import CremonaModularSymbols - -from .interface import (mwrank_EllipticCurve, mwrank_MordellWeil, - get_precision, set_precision) - +from .interface import mwrank_EllipticCurve, mwrank_MordellWeil +from .mwrank import get_precision, set_precision from .mwrank import initprimes as mwrank_initprimes diff --git a/src/sage/libs/eclib/interface.py b/src/sage/libs/eclib/interface.py index dceed55a903..5e7af59eec1 100644 --- a/src/sage/libs/eclib/interface.py +++ b/src/sage/libs/eclib/interface.py @@ -13,62 +13,25 @@ This interface is a direct library-level interface to ``eclib``, including the 2-descent program ``mwrank``. -""" - -from sage.structure.sage_object import SageObject -from sage.rings.integer_ring import IntegerRing - -def get_precision(): - r""" - Return the global NTL real number precision. - - See also :meth:`set_precision`. - - .. warning:: - The internal precision is binary. This function multiplies the - binary precision by 0.3 (`=\log_2(10)` approximately) and - truncates. +TESTS: - OUTPUT: - - (int) The current decimal precision. - - EXAMPLES:: - - sage: mwrank_get_precision() - 50 - """ - # don't want to load mwrank every time Sage starts up, so we do - # the import here. - from sage.libs.eclib.mwrank import get_precision - return get_precision() - -def set_precision(n): - r""" - Set the global NTL real number precision. This has a massive - effect on the speed of mwrank calculations. The default (used if - this function is not called) is ``n=50``, but it might have to be - increased if a computation fails. See also :meth:`get_precision`. +Check that ``eclib`` is imported as needed:: - INPUT: - - - ``n`` (long) -- real precision used for floating point - computations in the library, in decimal digits. - - .. warning:: + sage: [k for k in sys.modules if k.startswith("sage.libs.eclib")] + [] + sage: EllipticCurve('11a1').mwrank_curve() + y^2+ y = x^3 - x^2 - 10*x - 20 + sage: [k for k in sys.modules if k.startswith("sage.libs.eclib")] + ['...'] +""" - This change is global and affects *all* future calls of eclib - functions by Sage. +from sage.structure.sage_object import SageObject +from sage.rings.all import Integer +from sage.rings.integer_ring import IntegerRing - EXAMPLES:: +from .mwrank import _Curvedata, _two_descent, _mw - sage: mwrank_set_precision(20) - """ - # don't want to load mwrank every time Sage starts up, so we do - # the import here. - from sage.libs.eclib.mwrank import set_precision - set_precision(n) class mwrank_EllipticCurve(SageObject): r""" @@ -140,17 +103,13 @@ def __init__(self, ainvs, verbose=False): sage: e.ainvs() [0, 1, 1, -2, 0] """ - # import here to save time during startup (mwrank takes a while to init) - - from sage.libs.eclib.mwrank import _Curvedata - # if not isinstance(ainvs, list) and len(ainvs) <= 5: - if not isinstance(ainvs, (list,tuple)) or not len(ainvs) <= 5: - raise TypeError("ainvs must be a list or tuple of length at most 5.") + ainvs = list(ainvs) + if len(ainvs) > 5: + raise TypeError("ainvs must have length at most 5") - # Pad ainvs on the beginning by 0's, so e.g. - # [a4,a5] works. - ainvs = [0]*(5-len(ainvs)) + ainvs + # Pad ainvs on the beginning by 0's, so e.g. [a4, a6] works + ainvs = [0] * (5 - len(ainvs)) + ainvs # Convert each entry to an int try: @@ -203,7 +162,7 @@ def set_verbose(self, verbose): sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0]) sage: E.set_verbose(1) - sage: E.saturate() # tol 1e-14 + sage: E.saturate() # tol 1e-10 Basic pair: I=48, J=-432 disc=255744 2-adic index bound = 2 @@ -411,7 +370,6 @@ def two_descent(self, sage: E.two_descent(verbose=False) True """ - from sage.libs.eclib.mwrank import _two_descent # import here to save time first_limit = int(first_limit) second_limit = int(second_limit) n_aux = int(n_aux) @@ -655,7 +613,6 @@ def gens(self): [[0, -1, 1]] """ self.saturate() - from sage.rings.all import Integer L = eval(self.__two_descent_data().getbasis().replace(":",",")) return [[Integer(x), Integer(y), Integer(z)] for (x,y,z) in L] @@ -910,7 +867,6 @@ def __init__(self, curve, verbose=True, pp=1, maxr=999): verb = 1 else: verb = 0 - from sage.libs.eclib.mwrank import _mw # import here to save time self.__mw = _mw(curve._curve_data(), verb, pp, maxr) def __reduce__(self): @@ -1007,7 +963,7 @@ def process(self, v, sat=0): sage: EQ.points() [[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]] sage: EQ.regulator() - 375.42919921875 + 375.42920288254555 sage: EQ.saturate(2) # points were not 2-saturated saturating basis...Saturation index bound = 93 WARNING: saturation at primes p > 2 will not be done; @@ -1018,7 +974,7 @@ def process(self, v, sat=0): sage: EQ.points() [[-2, 3, 1], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]] sage: EQ.regulator() - 93.8572998046875 + 93.85730072063639 sage: EQ.saturate(3) # points were not 3-saturated saturating basis...Saturation index bound = 46 WARNING: saturation at primes p > 3 will not be done; @@ -1029,7 +985,7 @@ def process(self, v, sat=0): sage: EQ.points() [[-2, 3, 1], [-14, 25, 8], [-13422227300, -49322830557, 12167000000]] sage: EQ.regulator() - 10.4285888671875 + 10.4285889689596 sage: EQ.saturate(5) # points were not 5-saturated saturating basis...Saturation index bound = 15 WARNING: saturation at primes p > 5 will not be done; @@ -1040,7 +996,7 @@ def process(self, v, sat=0): sage: EQ.points() [[-2, 3, 1], [-14, 25, 8], [1, -1, 1]] sage: EQ.regulator() - 0.4171435534954071 + 0.417143558758384 sage: EQ.saturate() # points are now saturated saturating basis...Saturation index bound = 3 Checking saturation at [ 2 3 ] @@ -1128,7 +1084,7 @@ def rank(self): sage: EQ.rank() 3 sage: EQ.regulator() - 0.4171435534954071 + 0.417143558758384 We do in fact now have a full Mordell-Weil basis. @@ -1169,7 +1125,7 @@ def saturate(self, max_prime=-1, odd_primes_only=False): - ``unsatlist`` (list of ints) -- list of primes at which saturation could not be proved or achieved. Increasing the - decimal precision should correct this, since it happens when + precision should correct this, since it happens when a linear combination of the points appears to be a multiple of `p` but cannot be divided by `p`. (Note that ``eclib`` uses floating point methods based on elliptic logarithms to @@ -1211,7 +1167,7 @@ def saturate(self, max_prime=-1, odd_primes_only=False): sage: EQ Subgroup of Mordell-Weil group: [[1547:-2967:343], [2707496766203306:864581029138191:2969715140223272], [-13422227300:-49322830557:12167000000]] sage: EQ.regulator() - 375.42919921875 + 375.42920288254555 Now we saturate at `p=2`, and gain index 2:: @@ -1225,7 +1181,7 @@ def saturate(self, max_prime=-1, odd_primes_only=False): sage: EQ Subgroup of Mordell-Weil group: [[-2:3:1], [2707496766203306:864581029138191:2969715140223272], [-13422227300:-49322830557:12167000000]] sage: EQ.regulator() - 93.8572998046875 + 93.85730072063639 Now we saturate at `p=3`, and gain index 3:: @@ -1239,7 +1195,7 @@ def saturate(self, max_prime=-1, odd_primes_only=False): sage: EQ Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [-13422227300:-49322830557:12167000000]] sage: EQ.regulator() - 10.4285888671875 + 10.4285889689596 Now we saturate at `p=5`, and gain index 5:: @@ -1253,7 +1209,7 @@ def saturate(self, max_prime=-1, odd_primes_only=False): sage: EQ Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [1:-1:1]] sage: EQ.regulator() - 0.4171435534954071 + 0.417143558758384 Finally we finish the saturation. The output here shows that the points are now provably saturated at all primes:: @@ -1280,7 +1236,7 @@ def saturate(self, max_prime=-1, odd_primes_only=False): sage: EQ Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [1:-1:1]] sage: EQ.regulator() - 0.4171435534954071 + 0.417143558758384 But we would still need to use the :meth:`saturate()` function to verify that full saturation has been done:: @@ -1369,17 +1325,6 @@ def search(self, height_limit=18, verbose=False): moduli_option = 0 # Use Stoll's sieving program... see strategies in ratpoints-1.4.c - ## moduli_option -- int (default: 0); if > 0; a flag used to determine - ## the moduli that are used in sieving - ## 1 -- first 10 odd primes; the first one you - ## would think of. - ## 2 -- three composites; $2^6\cdot 3^4$, ... TODO - ## (from German mathematician J. Gebel; - ## personal conversation about SIMATH) - ## 3 -- nine prime powers; $2^5, \ldots$; - ## like 1 but includes powers of small primes - ## TODO: Extract the meaning from mwprocs.cc; line 776 etc. - verbose = bool(verbose) self.__mw.search(height_limit, moduli_option, verbose) @@ -1408,5 +1353,4 @@ def points(self): """ L = eval(self.__mw.getbasis().replace(":",",")) - from sage.rings.all import Integer return [[Integer(x), Integer(y), Integer(z)] for (x,y,z) in L] diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx index 5625153658c..6f7dbbe9077 100644 --- a/src/sage/libs/eclib/mwrank.pyx +++ b/src/sage/libs/eclib/mwrank.pyx @@ -18,6 +18,7 @@ EXAMPLES:: sage: t [[1:2:1]] """ + from __future__ import print_function, absolute_import import os @@ -54,7 +55,7 @@ cdef extern from "wrap.cpp": bigint* x, bigint* y, bigint* z, int sat) char* mw_getbasis(mw* m) - char* mw_regulator(mw* m) + double mw_regulator(mw* m) int mw_rank(mw* m) int mw_saturate(mw* m, bigint* index, char** unsat, long sat_bd, int odd_primes_only) @@ -64,7 +65,7 @@ cdef extern from "wrap.cpp": int two_descent_ok(two_descent* t) long two_descent_get_certain(two_descent* t) char* two_descent_get_basis(two_descent* t) - char* two_descent_regulator(two_descent* t) + double two_descent_regulator(two_descent* t) long two_descent_get_rank(two_descent* t) long two_descent_get_rank_bound(two_descent* t) long two_descent_get_selmer_rank(two_descent* t) @@ -78,45 +79,70 @@ cdef object string_sigoff(char* s): sig_free(s) return t -# set the default -mwrank_set_precision(50) + +# set the default bit precision +mwrank_set_precision(150) def get_precision(): """ - Returns the working floating point precision of mwrank. + Returns the working floating point bit precision of mwrank, which is + equal to the global NTL real number precision. OUTPUT: - (int) The current precision in decimal digits. + (int) The current precision in bits. + + See also :meth:`set_precision`. EXAMPLES:: - sage: from sage.libs.eclib.mwrank import get_precision - sage: get_precision() - 50 + sage: mwrank_get_precision() + 150 """ return mwrank_get_precision() + def set_precision(n): """ - Sets the working floating point precision of mwrank. + Sets the working floating point bit precision of mwrank, which is + equal to the global NTL real number precision. + + NTL real number bit precision. This has a massive effect on the + speed of mwrank calculations. The default (used if this function is + not called) is ``n=150``, but it might have to be increased if a + computation fails. INPUT: - - ``n`` (int) -- a positive integer: the number of decimal digits. + - ``n`` -- a positive integer: the number of bits of precision. - OUTPUT: + .. warning:: + + This change is global and affects *all* future calls of eclib + functions by Sage. + + .. note:: + + The minimal value to which the precision may be set is 53. + Lower values will be increased to 53. - None. + See also :meth:`get_precision`. EXAMPLES:: - sage: from sage.libs.eclib.mwrank import set_precision + sage: from sage.libs.eclib.mwrank import set_precision, get_precision + sage: old_prec = get_precision(); old_prec + 150 sage: set_precision(50) - + sage: get_precision() + 53 + sage: set_precision(old_prec) + sage: get_precision() + 150 """ mwrank_set_precision(n) + def initprimes(filename, verb=False): """ Initialises mwrank/eclib's internal prime list. @@ -148,9 +174,6 @@ def initprimes(filename, verb=False): raise IOError('No such file or directory: %s' % filename) filename = str_to_bytes(filename, FS_ENCODING, 'surrogateescape') mwrank_initprimes(filename, verb) - if verb: - sys.stdout.flush() - sys.stderr.flush() ############# bigint ########################################### # @@ -322,10 +345,12 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class + B`, where `h(P)` is the naive height and `\hat{h}(P)` the canonical height. - .. TODO:: + .. note:: - Since eclib can compute this to arbitrary precision it would - make sense to return a Sage real. + Since eclib can compute this to arbitrary precision, we + could return a Sage real, but this is only a bound and in + the contexts in which it is used extra precision is + irrelevant. EXAMPLES:: @@ -349,26 +374,25 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class + B`, where `h(P)` is the naive height and `\hat{h}(P)` the canonical height. - .. TODO:: + .. note:: - Since eclib can compute this to arbitrary precision it would - make sense to return a Sage real. + Since eclib can compute this to arbitrary precision, we + could return a Sage real, but this is only a bound and in + the contexts in which it is used extra precision is + irrelevant. EXAMPLES:: sage: from sage.libs.eclib.mwrank import _Curvedata sage: E = _Curvedata(1,2,3,4,5) sage: E.cps_bound() - 0.11912451909250982 + 0.11912451909250982... Note that this is a better bound than Silverman's in this case:: sage: E.silverman_bound() 6.52226179519101... """ - cdef double x - # We declare x so there are *no* Python library - # calls within the sig_on()/sig_off(). sig_on() x = Curvedata_cps_bound(self.x) sig_off() @@ -386,17 +410,19 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class canonical height. This is the minimum of the Silverman and Cremona_Prickett-Siksek height bounds. - .. TODO:: + .. note:: - Since eclib can compute this to arbitrary precision it would - make sense to return a Sage real. + Since eclib can compute this to arbitrary precision, we + could return a Sage real, but this is only a bound and in + the contexts in which it is used extra precision is + irrelevant. EXAMPLES:: sage: from sage.libs.eclib.mwrank import _Curvedata sage: E = _Curvedata(1,2,3,4,5) sage: E.height_constant() - 0.11912451909250982 + 0.119124519092509... """ return Curvedata_height_constant(self.x) @@ -474,9 +500,6 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class """ sig_on() s = string_sigoff(Curvedata_isogeny_class(self.x, verbose)) - if verbose: - sys.stdout.flush() - sys.stderr.flush() return eval(s) @@ -761,7 +784,7 @@ cdef class _mw: OUTPUT: - (float) The current regulator. + (double) The current regulator. .. TODO:: @@ -780,11 +803,11 @@ cdef class _mw: sage: EQ.rank() 2 sage: EQ.regulator() - 0.15246017277240753 + 0.15246017794314376 """ - cdef float f sig_on() - f = float(string_sigoff(mw_regulator(self.x))) + f = mw_regulator(self.x) + sig_off() return f def rank(self): @@ -939,9 +962,6 @@ cdef class _mw: sig_on() mw_search(self.x, h_lim, moduli_option, verb) - if verb: - sys.stdout.flush() - sys.stderr.flush() sig_off() @@ -1043,9 +1063,6 @@ cdef class _two_descent: """ sig_on() self.x = new two_descent(curve.x, verb, sel, firstlim, secondlim, n_aux, second_descent) - if verb: - sys.stdout.flush() - sys.stderr.flush() sig_off() def getrank(self): @@ -1297,7 +1314,7 @@ cdef class _two_descent: OUTPUT: - (float) The regulator (of the subgroup found by 2-descent). + (double) The regulator (of the subgroup found by 2-descent). EXAMPLES:: @@ -1339,4 +1356,6 @@ cdef class _two_descent: 0.417143558758384 """ sig_on() - return float(string_sigoff(two_descent_regulator(self.x))) + reg = two_descent_regulator(self.x) + sig_off() + return reg diff --git a/src/sage/libs/eclib/wrap.cpp b/src/sage/libs/eclib/wrap.cpp index 84da3d7f9ae..58c18ab67b6 100644 --- a/src/sage/libs/eclib/wrap.cpp +++ b/src/sage/libs/eclib/wrap.cpp @@ -4,25 +4,17 @@ using namespace std; /**************** Miscellaneous functions ****************/ +/* NB In eclib versions before v20190226, precision was decimal + precision by default, while now it is bit precision. */ + long mwrank_get_precision() { - return decimal_precision(); + return bit_precision(); } void mwrank_set_precision(long n) { - set_precision(n); - /* - Conversion from base 10 to base 2 and back is done within eclib by - the functions n --> int(3.33*n) and n --> int(0.3*n) which - introduces rounding errors. Without the following loop, doing - set_precision(get_precision()) reduces the decimal precision by at - least 1 (exactly 1 for n<803), which has disastrous effects if done - repeatedly. - */ - long m=n; - while (decimal_precision()process(P, sat); + cout<getbasis()); } -char* mw_regulator(struct mw* m) +double mw_regulator(struct mw* m) { - bigfloat reg = m->regulator(); - ostringstream instore; - instore << reg; - return stringstream_to_char(instore); + return to_double(m->regulator()); } int mw_rank(struct mw* m) @@ -209,13 +199,11 @@ bigfloat str_to_bigfloat(char* s) { void mw_search(struct mw* m, char* h_lim, int moduli_option, int verb) { - m->search(str_to_bigfloat(h_lim), moduli_option, verb); + cout<saturate(sat_bd); } -char* two_descent_regulator(struct two_descent* t) +double two_descent_regulator(struct two_descent* t) { - bigfloat reg = t->regulator(); - ostringstream instore; - instore << reg; - return stringstream_to_char(instore); + return to_double(t->regulator()); } diff --git a/src/sage/libs/gap/element.pxd b/src/sage/libs/gap/element.pxd index 74e7d6c40ca..288d320b367 100644 --- a/src/sage/libs/gap/element.pxd +++ b/src/sage/libs/gap/element.pxd @@ -13,6 +13,7 @@ from sage.structure.sage_object cimport SageObject from sage.structure.element cimport Element, ModuleElement, RingElement cdef Obj make_gap_list(sage_list) except NULL +cdef Obj make_gap_matrix(sage_list, gap_ring) except NULL cdef Obj make_gap_record(sage_dict) except NULL cdef Obj make_gap_integer(sage_dict) except NULL cdef Obj make_gap_string(sage_string) except NULL @@ -46,7 +47,8 @@ cdef class GapElement(RingElement): cpdef is_bool(self) cpdef _add_(self, other) cpdef _mul_(self, other) - cpdef _mod_(self, right) + cpdef _mod_(self, other) + cpdef _pow_(self, other) cpdef GapElement deepcopy(self, bint mut) diff --git a/src/sage/libs/gap/element.pyx b/src/sage/libs/gap/element.pyx index e69e0de922b..03d0cbe6f9f 100644 --- a/src/sage/libs/gap/element.pyx +++ b/src/sage/libs/gap/element.pyx @@ -1,20 +1,20 @@ """ -libGAP element wrapper +GAP element wrapper This document describes the individual wrappers for various GAP -elements. For general information about libGAP, you should read the +elements. For general information about GAP, you should read the :mod:`~sage.libs.gap.libgap` module documentation. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Volker Braun # # This 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 __future__ import absolute_import, print_function @@ -23,6 +23,7 @@ from cysignals.signals cimport sig_on, sig_off from .gap_includes cimport * from .util cimport * +from .util import GAPError from sage.cpython.string cimport str_to_bytes, char_to_str from sage.misc.cachefunc import cached_method from sage.structure.sage_object cimport SageObject @@ -31,6 +32,7 @@ from sage.rings.all import ZZ, QQ, RDF from sage.groups.perm_gps.permgroup_element cimport PermutationGroupElement from sage.combinat.permutation import Permutation +from sage.structure.coerce cimport coercion_model as cm decode_type_number = { 0: 'T_INT (integer)', @@ -84,6 +86,43 @@ cdef Obj make_gap_list(sage_list) except NULL: return l.value +cdef Obj make_gap_matrix(sage_list, gap_ring) except NULL: + """ + Convert Sage lists into Gap matrices + + INPUT: + + - ``sage_list`` -- list of :class:`GapElement`. + + - ``gap_ring`` -- the base ring + + If ``gap_ring`` is ``None``, nothing is made to make sure + that all coefficients live in the same Gap ring. The resulting Gap list + may not be recognized as a matrix by Gap. + + OUTPUT: + + The list of the elements in ``sage_list`` as a Gap ``Obj``. + """ + from sage.libs.gap.libgap import libgap + cdef GapElement l = libgap.eval('[]') + cdef GapElement elem + cdef GapElement one + if gap_ring is not None: + one = gap_ring.One() + else: + one = libgap(1) + for x in sage_list: + if not isinstance(x, GapElement): + elem = libgap(x) + elem = elem * one + else: + elem = x + + AddList(l.value, elem.value) + return l.value + + cdef char *crepr(Obj obj): cdef Obj s, stream, output_text_string, view_obj cdef UInt res @@ -103,8 +142,8 @@ cdef char *crepr(Obj obj): stream = CALL_2ARGS(output_text_string, s, GAP_True) if not OpenOutputStream(stream): - raise RuntimeError("failed to open output capture stream for " - "representing GAP object") + raise GAPError("failed to open output capture stream for " + "representing GAP object") viewobj = GAP_ValueGlobalVariable("ViewObj") CALL_1ARGS(viewobj, obj) @@ -209,7 +248,7 @@ cdef Obj make_gap_string(sage_string) except NULL: cdef GapElement make_any_gap_element(parent, Obj obj): """ - Return the libGAP element wrapper of ``obj`` + Return the GAP element wrapper of ``obj`` The most suitable subclass of GapElement is determined automatically. Use this function to wrap GAP objects unless you @@ -344,19 +383,20 @@ cdef class GapElement(RingElement): sage: libgap(0) 0 - If Gap finds an error while evaluating, a corresponding assertion is raised:: + If Gap finds an error while evaluating, a :class:`GAPError` + exception is raised:: sage: libgap.eval('1/0') Traceback (most recent call last): ... - ValueError: libGAP: Error, Rational operations: must not be zero + GAPError: Error, Rational operations: must not be zero - Also, a ``ValueError`` is raised if the input is not a simple expression:: + Also, a ``GAPError`` is raised if the input is not a simple expression:: sage: libgap.eval('1; 2; 3') Traceback (most recent call last): ... - ValueError: can only evaluate a single statement + GAPError: can only evaluate a single statement """ def __cinit__(self): @@ -371,7 +411,6 @@ cdef class GapElement(RingElement): self.value = NULL self._compare_by_id = False - def __init__(self): """ The ``GapElement`` constructor @@ -419,7 +458,6 @@ cdef class GapElement(RingElement): return reference_obj(obj) - def __dealloc__(self): r""" The Cython destructor @@ -538,7 +576,7 @@ cdef class GapElement(RingElement): sage: libgap.eval('Integers') in libgap(1) Traceback (most recent call last): ... - ValueError: libGAP: Error, no method found! Error, no 1st choice method found for `in' on 2 arguments + GAPError: Error, no method found! Error, no 1st choice method found for `in' on 2 arguments """ from sage.libs.gap.libgap import libgap GAP_IN = libgap.eval(r'\in') @@ -609,24 +647,24 @@ cdef class GapElement(RingElement): sage: lst.Adddddd(1) Traceback (most recent call last): ... - AttributeError: name "Adddddd" is not defined in GAP. + AttributeError: 'Adddddd' is not defined in GAP sage: libgap.eval('some_name := 1') 1 sage: lst.some_name Traceback (most recent call last): ... - AttributeError: name "some_name" does not define a GAP function. + AttributeError: 'some_name' does not define a GAP function """ if name in ('__dict__', '_getAttributeNames', '__custom_name', 'keys'): raise AttributeError('Python special name, not a GAP function.') try: proxy = make_GapElement_MethodProxy\ (self.parent(), gap_eval(name), self) - except ValueError: - raise AttributeError('name "'+str(name)+'" is not defined in GAP.') + except GAPError: + raise AttributeError(f"'{name}' is not defined in GAP") if not proxy.is_function(): - raise AttributeError('name "'+str(name)+'" does not define a GAP function.') + raise AttributeError(f"'{name}' does not define a GAP function") return proxy def _repr_(self): @@ -653,15 +691,15 @@ cdef class GapElement(RingElement): """ Set comparison to compare by ``id`` - By default, GAP is used to compare libGAP objects. However, - this is not defined for all GAP objects. To have libGAP play + By default, GAP is used to compare GAP objects. However, + this is not defined for all GAP objects. To have GAP play nice with ``UniqueRepresentation``, comparison must always work. This method allows one to override the comparison to sort by the (unique) Python ``id``. Obviously it is a bad idea to change the comparison of objects after you have inserted them into a set/dict. You also must - not mix libGAP objects with different sort methods in the same + not mix GAP objects with different sort methods in the same container. EXAMPLES:: @@ -671,7 +709,7 @@ cdef class GapElement(RingElement): sage: F1 < F2 Traceback (most recent call last): ... - ValueError: libGAP: cannot compare less than: Error, no method found! + GAPError: Error, no method found! Error, no 1st choice method found for `<' on 2 arguments sage: F1._set_compare_by_id() @@ -705,13 +743,13 @@ cdef class GapElement(RingElement): sage: x._assert_compare_by_id() Traceback (most recent call last): ... - ValueError: requires a libGAP objects whose comparison is by "id" + ValueError: this requires a GAP object whose comparison is by "id" sage: x._set_compare_by_id() sage: x._assert_compare_by_id() """ if not self._compare_by_id: - raise ValueError('requires a libGAP objects whose comparison is by "id"') + raise ValueError('this requires a GAP object whose comparison is by "id"') def __hash__(self): """ @@ -760,7 +798,7 @@ cdef class GapElement(RingElement): sage: F1 < F2 Traceback (most recent call last): ... - ValueError: libGAP: cannot compare less than: Error, no method found! + GAPError: Error, no method found! Error, no 1st choice method found for `<' on 2 arguments sage: F1._set_compare_by_id() @@ -786,7 +824,7 @@ cdef class GapElement(RingElement): True """ if self._compare_by_id != (other)._compare_by_id: - raise ValueError('comparison style must be the same for both operands') + raise ValueError("comparison style must be the same for both operands") if op==Py_LT: return self._compare_less(other) elif op==Py_LE: @@ -820,8 +858,6 @@ cdef class GapElement(RingElement): try: GAP_Enter() return EQ(self.value, c_other.value) - except RuntimeError as msg: - raise ValueError('libGAP: cannot compare equality: '+str(msg)) finally: GAP_Leave() sig_off() @@ -844,8 +880,6 @@ cdef class GapElement(RingElement): try: GAP_Enter() return LT(self.value, c_other.value) - except RuntimeError as msg: - raise ValueError('libGAP: cannot compare less than: '+str(msg)) finally: GAP_Leave() sig_off() @@ -866,21 +900,18 @@ cdef class GapElement(RingElement): sage: libgap(1) + libgap.CyclicGroup(2) Traceback (most recent call last): ... - ValueError: libGAP: Error, no method found! + GAPError: Error, no method found! Error, no 1st choice method found for `+' on 2 arguments """ cdef Obj result - sig_on() try: - GAP_Enter() + sig_GAP_Enter() + sig_on() result = SUM(self.value, (right).value) - return make_any_gap_element(self.parent(), result) - except RuntimeError as msg: - raise ValueError('libGAP: '+str(msg)) + sig_off() finally: GAP_Leave() - sig_off() - + return make_any_gap_element(self.parent(), result) cpdef _sub_(self, right): r""" @@ -898,19 +929,17 @@ cdef class GapElement(RingElement): sage: libgap(1) - libgap.CyclicGroup(2) Traceback (most recent call last): ... - ValueError: libGAP: Error, no method found! ... + GAPError: Error, no method found! ... """ cdef Obj result - sig_on() try: - GAP_Enter() + sig_GAP_Enter() + sig_on() result = DIFF(self.value, (right).value) - return make_any_gap_element(self.parent(), result) - except RuntimeError as msg: - raise ValueError('libGAP: {}'.format(msg)) + sig_off() finally: GAP_Leave() - sig_off() + return make_any_gap_element(self.parent(), result) cpdef _mul_(self, right): @@ -929,21 +958,18 @@ cdef class GapElement(RingElement): sage: libgap(1) * libgap.CyclicGroup(2) Traceback (most recent call last): ... - ValueError: libGAP: Error, no method found! + GAPError: Error, no method found! Error, no 1st choice method found for `*' on 2 arguments """ cdef Obj result - sig_on() try: - GAP_Enter() + sig_GAP_Enter() + sig_on() result = PROD(self.value, (right).value) - return make_any_gap_element(self.parent(), result) - except RuntimeError as msg: - raise ValueError('libGAP: {}'.format(msg)) + sig_off() finally: GAP_Leave() - sig_off() - + return make_any_gap_element(self.parent(), result) cpdef _div_(self, right): r""" @@ -961,25 +987,23 @@ cdef class GapElement(RingElement): sage: libgap(1) / libgap.CyclicGroup(2) Traceback (most recent call last): ... - ValueError: libGAP: Error, no method found! + GAPError: Error, no method found! Error, no 1st choice method found for `/' on 2 arguments sage: libgap(1) / libgap(0) Traceback (most recent call last): ... - ValueError: libGAP: Error, Rational operations: must not be zero + GAPError: Error, Rational operations: must not be zero """ cdef Obj result - sig_on() try: - GAP_Enter() + sig_GAP_Enter() + sig_on() result = QUO(self.value, (right).value) - return make_any_gap_element(self.parent(), result) - except RuntimeError as msg: - raise ValueError('libGAP: '+str(msg)) + sig_off() finally: GAP_Leave() - sig_off() + return make_any_gap_element(self.parent(), result) cpdef _mod_(self, right): r""" @@ -995,60 +1019,76 @@ cdef class GapElement(RingElement): sage: libgap(1) % libgap.CyclicGroup(2) Traceback (most recent call last): ... - ValueError: libGAP: Error, no method found! + GAPError: Error, no method found! Error, no 1st choice method found for `mod' on 2 arguments """ cdef Obj result - sig_on() try: - GAP_Enter() + sig_GAP_Enter() + sig_on() result = MOD(self.value, (right).value) - return make_any_gap_element(self.parent(), result) - except RuntimeError as msg: - raise ValueError('libGAP: '+str(msg)) + sig_off() finally: GAP_Leave() - sig_off() - + return make_any_gap_element(self.parent(), result) - def __pow__(GapElement self, right, dummy): + cpdef _pow_(self, other): r""" Exponentiation of two GapElement objects. EXAMPLES:: - sage: g1 = libgap(5) - sage: g2 = libgap(2) - sage: g1 ^ g2 + sage: r = libgap(5) ^ 2; r + 25 + sage: parent(r) + C library interface to GAP + sage: r = 5 ^ libgap(2); r 25 + sage: parent(r) + C library interface to GAP + sage: g, = libgap.CyclicGroup(5).GeneratorsOfGroup() + sage: g ^ 5 + of ... + + TESTS: + + Check that this can be interrupted gracefully:: + + sage: a, b = libgap.GL(1000, 3).GeneratorsOfGroup(); g = a * b + sage: alarm(0.5); g ^ (2 ^ 10000) + Traceback (most recent call last): + ... + AlarmInterrupt sage: libgap.CyclicGroup(2) ^ 2 Traceback (most recent call last): ... - ValueError: libGAP: Error, no method found! + GAPError: Error, no method found! Error, no 1st choice method found for `^' on 2 arguments sage: libgap(3) ^ Infinity Traceback (most recent call last): ... - ValueError: libGAP: Error, no method found! Error, no 1st choice + GAPError: Error, no method found! Error, no 1st choice method found for `InverseMutable' on 1 arguments """ - if not isinstance(right, GapElement): - libgap = self.parent() - right = libgap(right) - cdef Obj result - sig_on() try: - GAP_Enter() - result = POW(self.value, (right).value) - return make_any_gap_element(self.parent(), result) - except RuntimeError as msg: - raise ValueError('libGAP: ' + str(msg)) + sig_GAP_Enter() + sig_on() + result = POW(self.value, (other).value) + sig_off() finally: GAP_Leave() - sig_off() + return make_any_gap_element(self._parent, result) + + cpdef _pow_int(self, other): + """ + TESTS:: + sage: libgap(5)._pow_int(int(2)) + 25 + """ + return self._pow_(self._parent(other)) def is_function(self): """ @@ -1069,7 +1109,6 @@ cdef class GapElement(RingElement): """ return IS_FUNC(self.value) - def is_list(self): r""" Return whether the wrapped GAP object is a GAP List. @@ -1087,7 +1126,6 @@ cdef class GapElement(RingElement): """ return IS_LIST(self.value) - def is_record(self): r""" Return whether the wrapped GAP object is a GAP record. @@ -1105,7 +1143,6 @@ cdef class GapElement(RingElement): """ return IS_REC(self.value) - cpdef is_bool(self): r""" Return whether the wrapped GAP object is a GAP boolean. @@ -1139,7 +1176,6 @@ cdef class GapElement(RingElement): """ return IS_STRING(self.value) - def is_permutation(self): r""" Return whether the wrapped GAP object is a GAP permutation. @@ -1160,7 +1196,6 @@ cdef class GapElement(RingElement): return (TNUM_OBJ(self.value) == T_PERM2 or TNUM_OBJ(self.value) == T_PERM4) - def sage(self): r""" Return the Sage equivalent of the :class:`GapElement` @@ -1196,6 +1231,26 @@ cdef class GapElement(RingElement): 'this is a string' sage: type(_) <... 'str'> + + sage: x = libgap.eval('Indeterminate(Integers, "x")') + + sage: p = x^2 - 2*x + 3 + sage: p.sage() + x^2 - 2*x + 3 + sage: p.sage().parent() + Univariate Polynomial Ring in x over Integer Ring + + sage: p = x^-2 + 3*x + sage: p.sage() + x^-2 + 3*x + sage: p.sage().parent() + Univariate Laurent Polynomial Ring in x over Integer Ring + + sage: p = (3 * x^2 + x) / (x^2 - 2) + sage: p.sage() + (3*x^2 + x)/(x^2 - 2) + sage: p.sage().parent() + Fraction Field of Univariate Polynomial Ring in x over Integer Ring """ if self.value is NULL: return None @@ -1204,14 +1259,38 @@ cdef class GapElement(RingElement): if self.IsInfinity(): from sage.rings.infinity import Infinity return Infinity + elif self.IsNegInfinity(): from sage.rings.infinity import Infinity return -Infinity - raise NotImplementedError('cannot construct equivalent Sage object') - - + elif self.IsUnivariateRationalFunction(): + var = self.IndeterminateOfUnivariateRationalFunction().String() + var = var.sage() + num, den, val = self.CoefficientsOfUnivariateRationalFunction() + num = num.sage() + den = den.sage() + val = val.sage() + base_ring = cm.common_parent(*(num + den)) + + if self.IsUnivariatePolynomial(): + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(base_ring, var) + return R(num) + + elif self.IsLaurentPolynomial(): + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + R = LaurentPolynomialRing(base_ring, var) + x = R.gen() + return x**val * R(num) + + else: + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(base_ring, var) + x = R.gen() + return x**val * R(num) / R(den) + raise NotImplementedError('cannot construct equivalent Sage object') ############################################################################ @@ -1346,12 +1425,14 @@ cdef class GapElement_Integer(GapElement): sage: int(libgap(3)) 3 sage: type(_) - <... 'int'> + sage: int(libgap(2)**128) 340282366920938463463374607431768211456L - sage: type(_) + sage: type(_) # py2 + sage: type(_) # py3 + """ return self.sage(ring=int) @@ -1892,7 +1973,6 @@ cdef class GapElement_Ring(GapElement): """ return ZZ - def ring_rational(self): """ Construct the Sage rationals. @@ -1904,7 +1984,6 @@ cdef class GapElement_Ring(GapElement): """ return ZZ.fraction_field() - def ring_integer_mod(self): """ Construct a Sage integer mod ring. @@ -1945,6 +2024,25 @@ cdef class GapElement_Ring(GapElement): from sage.rings.number_field.number_field import CyclotomicField return CyclotomicField(conductor.sage()) + def ring_polynomial(self): + """ + Construct a polynomial ring. + + EXAMPLES:: + + sage: B = libgap(QQ['x']) + sage: B.ring_polynomial() + Univariate Polynomial Ring in x over Rational Field + + sage: B = libgap(ZZ['x','y']) + sage: B.ring_polynomial() + Multivariate Polynomial Ring in x, y over Integer Ring + """ + base_ring = self.CoefficientsRing().sage() + vars = [x.String().sage() + for x in self.IndeterminatesOfPolynomialRing()] + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(base_ring, vars) def sage(self, **kwds): r""" @@ -1975,6 +2073,9 @@ cdef class GapElement_Ring(GapElement): sage: libgap.CyclotomicField(6).sage() Cyclotomic Field of order 3 and degree 2 + + sage: libgap(QQ['x','y']).sage() + Multivariate Polynomial Ring in x, y over Rational Field """ if self.IsField(): if self.IsRationals(): @@ -1988,6 +2089,8 @@ cdef class GapElement_Ring(GapElement): return self.ring_integer(**kwds) if self.IsFinite(): return self.ring_integer_mod(**kwds) + if self.IsPolynomialRing(): + return self.ring_polynomial(**kwds) raise NotImplementedError('cannot convert GAP ring to Sage') @@ -2278,7 +2381,7 @@ cdef class GapElement_Function(GapElement): sage: s(libgap(1), libgap(2)) Traceback (most recent call last): ... - ValueError: libGAP: Error, no method found! + GAPError: Error, no method found! Error, no 1st choice method found for `SumOp' on 2 arguments sage: for i in range(0,100): @@ -2304,9 +2407,9 @@ cdef class GapElement_Function(GapElement): libgap = self.parent() a = [x if isinstance(x, GapElement) else libgap(x) for x in args] - sig_on() try: - GAP_Enter() + sig_GAP_Enter() + sig_on() if n == 0: result = CALL_0ARGS(self.value) elif n == 1: @@ -2345,17 +2448,13 @@ cdef class GapElement_Function(GapElement): elif n >= 7: arg_list = make_gap_list(args) result = CALL_XARGS(self.value, arg_list) - - if result == NULL: - # We called a procedure that does not return anything - return None - - return make_any_gap_element(self.parent(), result) - except RuntimeError as msg: - raise ValueError('libGAP: ' + str(msg)) + sig_off() finally: GAP_Leave() - sig_off() + if result == NULL: + # We called a procedure that does not return anything + return None + return make_any_gap_element(self.parent(), result) @@ -2917,8 +3016,7 @@ cdef class GapElement_Record(GapElement): sage: rec['no_such_element'] Traceback (most recent call last): ... - IndexError: libGAP: Error, Record Element: '.no_such_element' must - have an assigned value + GAPError: Error, Record Element: '.no_such_element' must have an assigned value """ def __len__(self): @@ -2937,7 +3035,6 @@ cdef class GapElement_Record(GapElement): """ return LEN_PREC(self.value) - def __iter__(self): r""" Iterate over the elements of the record. @@ -2957,7 +3054,6 @@ cdef class GapElement_Record(GapElement): """ return GapElement_RecordIterator(self) - cpdef UInt record_name_to_index(self, name): r""" Convert string to GAP record index. @@ -3007,13 +3103,10 @@ cdef class GapElement_Record(GapElement): try: GAP_Enter() result = ELM_REC(self.value, i) - return make_any_gap_element(self.parent(), result) - except RuntimeError as msg: - raise IndexError('libGAP: ' + str(msg)) finally: GAP_Leave() sig_off() - + return make_any_gap_element(self.parent(), result) def sage(self): r""" diff --git a/src/sage/libs/gap/gap_includes.pxd b/src/sage/libs/gap/gap_includes.pxd index f62b24ea604..864a13b385d 100644 --- a/src/sage/libs/gap/gap_includes.pxd +++ b/src/sage/libs/gap/gap_includes.pxd @@ -85,9 +85,13 @@ cdef extern from "": cdef extern from "" nogil: + """ + #define sig_GAP_Enter() {int t = GAP_Enter(); if (!t) sig_error();} + """ cdef void GAP_EnterStack() cdef void GAP_LeaveStack() cdef int GAP_Enter() except 0 + cdef void sig_GAP_Enter() cdef void GAP_Leave() cdef int GAP_Error_Setjmp() except 0 diff --git a/src/sage/libs/gap/libgap.pyx b/src/sage/libs/gap/libgap.pyx index 8cda7f75ad7..e78b88a33bc 100644 --- a/src/sage/libs/gap/libgap.pyx +++ b/src/sage/libs/gap/libgap.pyx @@ -1,8 +1,8 @@ """ -libGAP shared library Interface to GAP +Library Interface to GAP -This module implements a fast C library interface to GAP. To use -libGAP you simply call ``libgap`` (the parent of all +This module implements a fast C library interface to GAP. +To use it, you simply call ``libgap`` (the parent of all :class:`~sage.libs.gap.element.GapElement` instances) and use it to convert Sage objects into GAP objects. @@ -157,12 +157,12 @@ using the recursive expansion of the [ 0 0 7 8] -Using the libGAP C library from Cython -====================================== +Using the GAP C library from Cython +=================================== -.. TODO:: Update the following text +.. TODO:: Expand the following text - We are using libgap API provided by the GAP project since + We are using the GAP API provided by the GAP project since GAP 4.10. AUTHORS: @@ -357,12 +357,26 @@ class Gap(Parent): EXAMPLES:: - sage: libgap._construct_matrix(identity_matrix(ZZ,2)) + sage: M = libgap._construct_matrix(identity_matrix(ZZ,2)); M [ [ 1, 0 ], [ 0, 1 ] ] - sage: libgap(identity_matrix(ZZ,2)) # syntactic sugar + sage: M.IsMatrix() + true + + sage: M = libgap(identity_matrix(ZZ,2)); M # syntactic sugar [ [ 1, 0 ], [ 0, 1 ] ] - sage: libgap(matrix(GF(3),2,2,[4,5,6,7])) + sage: M.IsMatrix() + true + + sage: M = libgap(matrix(GF(3),2,2,[4,5,6,7])); M [ [ Z(3)^0, Z(3) ], [ 0*Z(3), Z(3)^0 ] ] + sage: M.IsMatrix() + true + + sage: x = polygen(QQ, 'x') + sage: M = libgap(matrix(QQ['x'],2,2,[x,5,6,7])); M + [ [ x, 5 ], [ 6, 7 ] ] + sage: M.IsMatrix() + true TESTS: @@ -380,7 +394,7 @@ class Gap(Parent): except ValueError: raise TypeError('base ring is not supported by GAP') M_list = map(list, M.rows()) - return make_GapElement_List(self, make_gap_list(M_list)) + return make_GapElement_List(self, make_gap_matrix(M_list, gap_ring)) def eval(self, gap_command): """ @@ -461,7 +475,7 @@ class Gap(Parent): sage: libgap.get_global('FooBar') Traceback (most recent call last): ... - ValueError: libGAP: Error, VAL_GVAR: No value bound to FooBar + GAPError: Error, VAL_GVAR: No value bound to FooBar """ is_bound = self.function_factory('IsBoundGlobal') bind_global = self.function_factory('BindGlobal') @@ -486,7 +500,7 @@ class Gap(Parent): sage: libgap.get_global('FooBar') Traceback (most recent call last): ... - ValueError: libGAP: Error, VAL_GVAR: No value bound to FooBar + GAPError: Error, VAL_GVAR: No value bound to FooBar """ is_readonlyglobal = self.function_factory('IsReadOnlyGlobal') make_readwrite = self.function_factory('MakeReadWriteGlobal') @@ -518,7 +532,7 @@ class Gap(Parent): sage: libgap.get_global('FooBar') Traceback (most recent call last): ... - ValueError: libGAP: Error, VAL_GVAR: No value bound to FooBar + GAPError: Error, VAL_GVAR: No value bound to FooBar """ value_global = self.function_factory('ValueGlobal') return value_global(variable) @@ -745,7 +759,7 @@ class Gap(Parent): def count_GAP_objects(self): """ Return the number of GAP objects that are being tracked by - libGAP + GAP. OUTPUT: diff --git a/src/sage/libs/gap/operations.py b/src/sage/libs/gap/operations.py index f28b4ab48bb..28c38ee1fea 100644 --- a/src/sage/libs/gap/operations.py +++ b/src/sage/libs/gap/operations.py @@ -54,7 +54,7 @@ def _repr_(self): String - EXAMPLES: + EXAMPLES:: sage: from sage.libs.gap.operations import OperationInspector sage: opr = OperationInspector(libgap(123)) diff --git a/src/sage/libs/gap/test.py b/src/sage/libs/gap/test.py index a5eb4c4b026..5f75ff3b16a 100644 --- a/src/sage/libs/gap/test.py +++ b/src/sage/libs/gap/test.py @@ -1,5 +1,5 @@ """ -Short tests for libGAP +Short tests for GAP """ from sage.libs.all import libgap diff --git a/src/sage/libs/gap/test/Makefile b/src/sage/libs/gap/test/Makefile deleted file mode 100644 index a8b0f4365f4..00000000000 --- a/src/sage/libs/gap/test/Makefile +++ /dev/null @@ -1,24 +0,0 @@ - - -GAPDIR="$(SAGE_LOCAL)/gap/latest" - -# VALGRIND=valgrind --leak-check=full -# VALGRIND=valgrind --db-attach=yes -#VALGRIND=valgrind --suppressions=libgap.supp --gen-suppressions=yes -#VALGRIND=valgrind --suppressions=libgap.supp --db-attach=yes -VALGRIND= - -all: main - $(VALGRIND) ./main - -main: main.o Makefile - gcc -L$(SAGE_LOCAL)/lib -o main main.o -lgap -lcsage -lntl -lstdc++ -lpari -lpython2.7 -lm -lgmp - -main.o: main.c - echo $(GAPDIR) - gcc -std=gnu99 -DGAPDIR="\"$(GAPDIR)\"" -I$(SAGE_LOCAL)/include -I$(SAGE_LOCAL)/include/python2.6 -c -g $^ - -clean: - rm main.o main *~ - -.PHONY: all clean diff --git a/src/sage/libs/gap/test/README.txt b/src/sage/libs/gap/test/README.txt deleted file mode 100644 index 0c596955983..00000000000 --- a/src/sage/libs/gap/test/README.txt +++ /dev/null @@ -1,5 +0,0 @@ -In this folder is a small stub program that uses libGAP library for -some simple computations for debugging purposes. It uses libGAP -essentially in the same as the Sage libgap interface, but without the -overhead. - diff --git a/src/sage/libs/gap/test/main.c b/src/sage/libs/gap/test/main.c deleted file mode 100644 index aa37b3cec21..00000000000 --- a/src/sage/libs/gap/test/main.c +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -extern char **environ; - -void error_handler(char* msg) -{ - printf("Error: %s\n", msg); -} - -void eval(char* cmd) { - printf("Input:\n%s", cmd); - libgap_start_interaction(cmd); - - libgap_enter(); - libGAP_ReadEvalCommand(libGAP_BottomLVars); - libGAP_ViewObjHandler(libGAP_ReadEvalResult); - char* out = libgap_get_output(); - libgap_exit(); - - printf("Output:\n%s", out); - libgap_finish_interaction(); -} - -int main() -{ - char* argv[8]; - argv[0] = "gap"; - argv[1] = "-l"; - argv[2] = GAPDIR; - argv[3] = "-m"; - argv[4] = "32M"; - argv[5] = "-q"; - argv[6] = "-T"; - argv[7] = NULL; - int argc=7; - // gap_main_loop(argc, argv, environ); - libgap_set_error_handler(&error_handler); - libgap_initialize(argc, argv); - printf("Initialized\n"); - - libgap_enter() - libGAP_CollectBags(0,1); // full GC - libgap_exit() - - eval("1+2+3;\n"); - eval("g:=FreeGroup(2);\n"); - eval("a:=g.1;\n"); - eval("b:=g.2;\n"); - eval("lis:=[a^2, a^2, b*a];\n"); - eval("h:=g/lis;\n"); - eval("c:=h.1;\n"); - eval("Set([1..1000000], i->Order(c));\n"); - - libgap_finalize(); - return 0; -} - - -/* - -g:=FreeGroup(2); -a:=g.1; -b:=g.2; -lis:=[a^2, a^2, b*a]; -h:=g/lis; -c:=h.1; -Set([1..300000], i->Order(c)); - - - */ diff --git a/src/sage/libs/gap/test_long.py b/src/sage/libs/gap/test_long.py index e091b11e9fe..33eb7c7eaf0 100644 --- a/src/sage/libs/gap/test_long.py +++ b/src/sage/libs/gap/test_long.py @@ -1,5 +1,5 @@ """ -Long tests for libGAP +Long tests for GAP These stress test the garbage collection inside GAP """ diff --git a/src/sage/libs/gap/util.pxd b/src/sage/libs/gap/util.pxd index d2ce2d0cf1d..986a2db45c2 100644 --- a/src/sage/libs/gap/util.pxd +++ b/src/sage/libs/gap/util.pxd @@ -28,11 +28,11 @@ cdef void reference_obj(Obj obj) cdef void dereference_obj(Obj obj) # callback from the GAP memory manager so we can mark all_gap_elements.values() -cdef void gasman_callback() +cdef void gasman_callback() with gil ############################################################################ -### Initialization of libGAP ############################################### +### Initialization of GAP ################################################## ############################################################################ cdef initialize() diff --git a/src/sage/libs/gap/util.pyx b/src/sage/libs/gap/util.pyx index 2649755ad56..7f6a9243bb5 100644 --- a/src/sage/libs/gap/util.pyx +++ b/src/sage/libs/gap/util.pyx @@ -1,5 +1,5 @@ """ -Utility functions for libGAP +Utility functions for GAP """ #***************************************************************************** @@ -17,14 +17,14 @@ from __future__ import print_function, absolute_import import os import signal import warnings - +from posix.dlfcn cimport dlopen, dlclose, RTLD_NOW, RTLD_GLOBAL from libc.string cimport strcpy, strlen -from cpython.exc cimport PyErr_SetObject, PyErr_Occurred, PyErr_Fetch +from cpython.exc cimport PyErr_Fetch, PyErr_Restore from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE -from cpython.ref cimport PyObject +from cpython.ref cimport PyObject, Py_XINCREF, Py_XDECREF from cysignals.memory cimport sig_malloc -from cysignals.pysignals import changesignal +from cysignals.pysignals import containsignals from cysignals.signals cimport sig_on, sig_off, sig_error import sage.env @@ -156,7 +156,7 @@ cdef void dereference_obj(Obj obj): owned_objects_refcount[wrapped] = refcount - 1 -cdef void gasman_callback(): +cdef void gasman_callback() with gil: """ Callback before each GAP garbage collection """ @@ -165,11 +165,8 @@ cdef void gasman_callback(): MarkBag((obj).value) - - - ############################################################################ -### Initialization of libGAP ############################################### +### Initialization of GAP ################################################## ############################################################################ def gap_root(): @@ -258,6 +255,18 @@ cdef initialize(): """ global _gap_is_initialized, environ if _gap_is_initialized: return + # Hack to ensure that all symbols provided by libgap are loaded into the + # global symbol table + # Note: we could use RTLD_NOLOAD and avoid the subsequent dlclose() but + # this isn't portable + cdef void* handle + libgapname = str_to_bytes(sage.env.GAP_SO) + handle = dlopen(libgapname, RTLD_NOW | RTLD_GLOBAL) + if handle is NULL: + raise RuntimeError( + "Could not dlopen() libgap even though it should already " + "be loaded!") + dlclose(handle) # Define argv and environ variables, which we will pass in to # initialize GAP. Note that we must pass define the memory pool @@ -311,21 +320,19 @@ cdef initialize(): env = copy_environ(environ) - # Initialize GAP and capture any error messages - # The initialization just prints error and does not use the error handler - sig_on() - try: - with changesignal(signal.SIGCHLD, signal.SIG_DFL), \ - changesignal(signal.SIGINT, signal.SIG_DFL): - # Need to save/restore current SIGINT handling since GAP_Initialize - # currently clobbers it; it doesn't matter what we set SIGINT to - # temporarily. + # Need to save/restore current SIGINT handling since GAP_Initialize + # currently clobbers it; it doesn't matter what we set SIGINT to + # temporarily. + with containsignals(): + sig_on() + try: + # Initialize GAP and capture any error messages. The + # initialization just prints any errors and does not + # use the error handler. GAP_Initialize(argc, argv, env, &gasman_callback, &error_handler) - except RuntimeError as msg: - raise RuntimeError('libGAP initialization failed\n' + msg) - finally: - sig_off() + finally: + sig_off() # Set the ERROR_OUTPUT global in GAP to an output stream in which to # receive error output @@ -374,7 +381,7 @@ cdef Obj gap_eval(str gap_string) except? NULL: sage: libgap.eval('if 4>3 thenPrint("hi");\nfi') Traceback (most recent call last): ... - ValueError: libGAP: Syntax error: then expected in stream:1 + GAPError: Syntax error: then expected in stream:1 if 4>3 thenPrint("hi"); ^^^^^^^^^ sage: libgap.eval('1+1') # testing that we have successfully recovered @@ -389,7 +396,7 @@ cdef Obj gap_eval(str gap_string) except? NULL: sage: libgap.eval('Complex Field with 53 bits of precision;') Traceback (most recent call last): ... - ValueError: libGAP: Error, Variable: 'Complex' must have a value + GAPError: Error, Variable: 'Complex' must have a value Syntax error: ; expected in stream:1 Complex Field with 53 bits of precision;; ^^^^^^^^^^^^ @@ -403,14 +410,13 @@ cdef Obj gap_eval(str gap_string) except? NULL: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Error, Variable: 'precision' must have a value - Test that on a subsequent attemt we get the same message (no garbage was left in the error stream):: sage: libgap.eval('Complex Field with 53 bits of precision;') Traceback (most recent call last): ... - ValueError: libGAP: Error, Variable: 'Complex' must have a value + GAPError: Error, Variable: 'Complex' must have a value ... Error, Variable: 'precision' must have a value @@ -422,7 +428,7 @@ cdef Obj gap_eval(str gap_string) except? NULL: cdef int i, j, nresults # Careful: We need to keep a reference to the bytes object here - # so that Cython doesn't dereference it before libGAP is done with + # so that Cython doesn't deallocate it before GAP is done with # its contents. cmd = str_to_bytes(gap_string + ';\n') sig_on() @@ -439,7 +445,7 @@ cdef Obj gap_eval(str gap_string) except? NULL: nresults = LEN_LIST(result) if nresults > 1: # to mimick the old libGAP # TODO: Get rid of this restriction eventually? - raise ValueError('can only evaluate a single statement') + raise GAPError("can only evaluate a single statement") # Get the result of the first statement result = ELM0_LIST(result, 1) # 1-indexed! @@ -448,7 +454,7 @@ cdef Obj gap_eval(str gap_string) except? NULL: # An otherwise unhandled error occurred in GAP (such as a # syntax error). Try running the error handler manually # to capture the error output, if any. - # This should result in a RuntimeError being set. + # This should result in a GAPError being set. error_handler_check_exception() # The actual resultant object, if any, is in the second entry @@ -457,8 +463,6 @@ cdef Obj gap_eval(str gap_string) except? NULL: # this like returning None) return ELM0_LIST(result, 2) - except RuntimeError as msg: - raise ValueError(f'libGAP: {msg}') finally: GAP_Leave() sig_off() @@ -491,8 +495,13 @@ cdef void hold_reference(Obj obj): ### Error handler ########################################################## ############################################################################ +class GAPError(ValueError): # ValueError for historical reasons + """ + Exceptions raised by the GAP library + """ -cdef object extract_libgap_errout(): + +cdef str extract_libgap_errout(): """ Reads the global variable libgap_errout and returns a Python string containing the error message (with some boilerplate removed). @@ -516,41 +525,55 @@ cdef object extract_libgap_errout(): return msg_py -cdef void error_handler(): +cdef void error_handler() with gil: """ The libgap error handler. - If an error occurred we set a RuntimeError; when the original - GAP_EvalString returns this exception will be raised. + If an error occurred, we raise a ``GAPError``; when the original + ``GAP_EvalString`` returns, this exception will be seen. TODO: We should probably prevent re-entering this function if we are already handling an error; if there is an error in our stream handling code below it could result in a stack overflow. """ - cdef PyObject* exc_type - cdef PyObject* exc_val - cdef PyObject* exc_tb + cdef PyObject* exc_type = NULL + cdef PyObject* exc_val = NULL + cdef PyObject* exc_tb = NULL - # Close the error stream: This flushes any remaining output and closes - # the stream for further writing; reset ERROR_OUTPUT to something sane - # just in case (trying to print to a closed stream segfaults GAP) try: GAP_EnterStack() + + # Close the error stream: this flushes any remaining output and + # closes the stream for further writing; reset ERROR_OUTPUT to + # something sane just in case (trying to print to a closed + # stream segfaults GAP) GAP_EvalStringNoExcept(_close_error_output_cmd) - msg = extract_libgap_errout() - if PyErr_Occurred() != NULL and msg: - # Sometimes error_handler() can be called multiple times from a - # single GAP_EvalString call before it returns; in this case we - # just update the exception by appending to the existing exception - # message - PyErr_Fetch(&exc_type, &exc_val, &exc_tb) - if exc_val != NULL: - msg = str(exc_val) + '\n' + msg - elif not msg: - msg = "An unknown error occurred in libGAP" + # Fetch any existing exception before calling + # extract_libgap_errout() so that the exception indicator is + # cleared + PyErr_Fetch(&exc_type, &exc_val, &exc_tb) - PyErr_SetObject(RuntimeError, msg) + msg = extract_libgap_errout() + # Sometimes error_handler() can be called multiple times + # from a single GAP_EvalString call before it returns. + # In this case, we just update the exception by appending + # to the existing exception message + if exc_type is GAPError and exc_val is not NULL: + msg = str(exc_val) + '\n' + msg + elif not msg: + msg = "an unknown error occurred in GAP" + + # Raise an exception using PyErr_Restore(). + # This way, we can keep any existing traceback object. + # Note that we manually need to deal with refcounts here. + Py_XDECREF(exc_type) + Py_XDECREF(exc_val) + exc_type = GAPError + exc_val = msg + Py_XINCREF(exc_type) + Py_XINCREF(exc_val) + PyErr_Restore(exc_type, exc_val, exc_tb) finally: # Reset ERROR_OUTPUT with a new text string stream GAP_EvalStringNoExcept(_reset_error_output_cmd) diff --git a/src/sage/libs/giac.py b/src/sage/libs/giac.py index ffcdec029a1..85de646390a 100644 --- a/src/sage/libs/giac.py +++ b/src/sage/libs/giac.py @@ -129,11 +129,15 @@ def wrapper(*args, **kwds): @local_giacsettings -def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, *args, **kwds): +def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, + elim_variables=None, *args, **kwds): """ Computes a Groebner Basis of an ideal using giacpy_sage. The result is automatically converted to sage. + Supported term orders of the underlying polynomial ring are ``lex``, + ``deglex``, ``degrevlex`` and block orders with 2 ``degrevlex`` blocks. + INPUT: - ``gens`` - an ideal (or a list) of polynomials over a prime field @@ -156,6 +160,17 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, *args, ** - ``prot`` - (default: False) if True print detailled informations + - ``elim_variables`` - (default: None) a list of variables to eliminate + from the ideal. + + * if ``elim_variables`` is None, a Groebner basis with respect to the + term ordering of the parent polynomial ring of the polynomials + ``gens`` is computed. + + * if ``elim_variables`` is a list of variables, a Groebner basis of the + elimination ideal with respect to a ``degrevlex`` term order is + computed, regardless of the term order of the polynomial ring. + OUTPUT: Polynomial sequence of the reduced Groebner basis. @@ -172,6 +187,18 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, *args, ** sage: B.is_groebner() # optional - giacpy_sage True + Elimination ideals can be computed by passing ``elim_variables``:: + + sage: P = PolynomialRing(GF(previous_prime(2**31)), 5, 'x') # optional - giacpy_sage + sage: I = sage.rings.ideal.Cyclic(P) # optional - giacpy_sage + sage: B = gb_giac(I.gens(), elim_variables=[P.gen(0), P.gen(2)]) # optional - giacpy_sage + + // Groebner basis computation time ... + sage: B.is_groebner() # optional - giacpy_sage + True + sage: B.ideal() == I.elimination_ideal([P.gen(0), P.gen(2)]) # optional - giacpy_sage + True + Computations over QQ can benefit from * a probabilistic lifting:: @@ -243,6 +270,25 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, *args, ** sage: I.groebner_basis() == gb_giac(I) # optional - giacpy_sage True + Test the supported term orderings:: + + sage: from sage.rings.ideal import Cyclic + sage: P = PolynomialRing(QQ, 'x', 4, order='lex') + sage: B = gb_giac(Cyclic(P)) # optional - giacpy_sage + ... + sage: B.is_groebner(), B.ideal() == Cyclic(P) # optional - giacpy_sage + (True, True) + sage: P = P.change_ring(order='deglex') + sage: B = gb_giac(Cyclic(P)) # optional - giacpy_sage + ... + sage: B.is_groebner(), B.ideal() == Cyclic(P) # optional - giacpy_sage + (True, True) + sage: P = P.change_ring(order='degrevlex(2),degrevlex(2)') + sage: B = gb_giac(Cyclic(P)) # optional - giacpy_sage + ... + sage: B.is_groebner(), B.ideal() == Cyclic(P) # optional - giacpy_sage + (True, True) + """ try: from giacpy_sage import libgiac, giacsettings @@ -269,9 +315,9 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, *args, ** blacklist = blackgiacconstants + [str(j) for j in libgiac.VARS()] problematicnames = list(set(P.gens_dict().keys()).intersection(blacklist)) - if(len(problematicnames)>0): + if problematicnames: raise ValueError("Variables names %s conflict in giac. Change them or purge them from in giac with libgiac.purge(\'%s\')" - %(problematicnames, problematicnames[0])) + % (problematicnames, problematicnames[0])) if K.is_prime_field() and p == 0: F = libgiac(gens) @@ -280,9 +326,6 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, *args, ** else: raise NotImplementedError("Only prime fields of cardinal < 2^31 are implemented in Giac for Groebner bases.") - if P.term_order() != "degrevlex": - raise NotImplementedError("Only degrevlex term orderings are supported in Giac Groebner bases.") - # proof or probabilistic reconstruction if proba_epsilon is None: if proof_polynomial(): @@ -300,7 +343,30 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, *args, ** if threads is not None: giacsettings.threads = threads - # compute de groebner basis with giac - gb_giac = F.gbasis([P.gens()], "revlex") + if elim_variables is None: + var_names = P.variable_names() + order_name = P.term_order().name() + if order_name == "degrevlex": + giac_order = "revlex" + elif order_name == "lex": + giac_order = "plex" + elif order_name == "deglex": + giac_order = "tdeg" + else: + blocks = P.term_order().blocks() + if (len(blocks) == 2 and + all(order.name() == "degrevlex" for order in blocks)): + giac_order = "revlex" + var_names = var_names[:len(blocks[0])] + else: + raise NotImplementedError( + "%s is not a supported term order in " + "Giac Groebner bases." % P.term_order()) + + # compute de groebner basis with giac + gb_giac = F.gbasis(list(var_names), giac_order) + + else: + gb_giac = F.eliminate(list(elim_variables)) return PolynomialSequence(gb_giac, P, immutable=True) diff --git a/src/sage/libs/gsl/types.pxd b/src/sage/libs/gsl/types.pxd index ace441c9d1d..04b9e17a501 100644 --- a/src/sage/libs/gsl/types.pxd +++ b/src/sage/libs/gsl/types.pxd @@ -44,6 +44,8 @@ cdef extern from "gsl/gsl_complex.h": ctypedef struct gsl_complex: double dat[2] + double real "dat[0]" + double imag "dat[1]" cdef extern from "gsl/gsl_block_double.h": diff --git a/src/sage/libs/lrcalc/lrcalc.pyx b/src/sage/libs/lrcalc/lrcalc.pyx index b6992d2cd87..1cf67dc15ab 100644 --- a/src/sage/libs/lrcalc/lrcalc.pyx +++ b/src/sage/libs/lrcalc/lrcalc.pyx @@ -10,7 +10,7 @@ fusion products. All of the above are achieved by counting LR appropriate shape and content by iterating through them. Additionally, ``lrcalc`` handles products of Schubert polynomials. -The web page of ``lrcalc`` is ``_. +The web page of ``lrcalc`` is ``_. The following describes the Sage interface to this library. @@ -93,21 +93,23 @@ this example `\mu=[3,2,1]` and `\nu=[2,1]`. Specifying a third entry sage: list(lrcalc.lrskew([3,2,1],[2,1],maxrows=2)) [[[None, None, 1], [None, 1], [1]], [[None, None, 1], [None, 1], [2]], [[None, None, 1], [None, 2], [1]]] -.. todo:: use this library in the :class:`SymmetricFunctions` code, to +.. TODO:: + + use this library in the :class:`SymmetricFunctions` code, to make it easy to apply it to linear combinations of Schur functions. .. SEEALSO:: - :func:`lrcoef` - + - :func:`mult` - + - :func:`coprod` - + - :func:`skew` - + - :func:`lrskew` - + - :func:`mult_schubert` .. rubric:: Underlying algorithmic in lrcalc @@ -178,12 +180,12 @@ AUTHORS: product, iterating through LR tableaux, finalization, documentation """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Mike Hansen # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.rings.integer cimport Integer from sage.structure.parent cimport Parent @@ -191,6 +193,7 @@ from sage.combinat.partition import _Partitions from sage.combinat.permutation import Permutation from sage.combinat.skew_tableau import SkewTableau + cdef vector* iterable_to_vector(it): """ Return an lrcalc vector (which is a list of integers) from a Python iterable. @@ -206,10 +209,11 @@ cdef vector* iterable_to_vector(it): cdef int n = len(itr) cdef int i v = v_new(n) - for i from 0 <= i < n: + for i in range(n): v.array[i] = int(itr[i]) return v + cdef list vector_to_list(vector *v): """ Converts a lrcalc vector to Python list. @@ -223,10 +227,11 @@ cdef list vector_to_list(vector *v): cdef int i, n n = v_length(v) cdef list result = [None]*n - for i from 0 <= i < n: + for i in range(n): result[i] = Integer(v_elem(v, i)) return result + def test_iterable_to_vector(it): """ A wrapper function for the cdef function ``iterable_to_vector`` @@ -243,6 +248,7 @@ def test_iterable_to_vector(it): v_free(v) return result + cdef skewtab_to_SkewTableau(skewtab *st): """ A wrapper function which transforms the data set ``st`` used in @@ -261,6 +267,7 @@ cdef skewtab_to_SkewTableau(skewtab *st): for x in range(inner[y], outer[y])] for y in range(len(outer) - 1, -1, -1)]]) + def test_skewtab_to_SkewTableau(outer, inner): """ A wrapper function for the cdef function ``skewtab_to_SkewTableau`` @@ -286,6 +293,7 @@ def test_skewtab_to_SkewTableau(outer, inner): cdef skewtab* st = st_new(o, i, NULL, 0) return skewtab_to_SkewTableau(st) + cdef dict sf_hashtab_to_dict(hashtab *ht): """ Return a dictionary representing a Schur function. The keys are @@ -308,6 +316,7 @@ cdef dict sf_hashtab_to_dict(hashtab *ht): hash_next(itr) return result + cdef dict schubert_hashtab_to_dict(hashtab *ht): """ Return a dictionary corresponding to a Schubert polynomial whose keys @@ -352,6 +361,7 @@ cdef dict vp_hashtab_to_dict(hashtab *ht): hash_next(itr) return result + def lrcoef_unsafe(outer, inner1, inner2): r""" Compute a single Littlewood-Richardson coefficient. @@ -390,9 +400,12 @@ def lrcoef_unsafe(outer, inner1, inner2): i1 = iterable_to_vector(inner1) i2 = iterable_to_vector(inner2) result = lrcoef_c(o, i1, i2) - v_free(o); v_free(i1); v_free(i2) + v_free(o) + v_free(i1) + v_free(i2) return Integer(result) + def lrcoef(outer, inner1, inner2): """ Compute a single Littlewood-Richardson coefficient. @@ -427,6 +440,7 @@ def lrcoef(outer, inner1, inner2): """ return lrcoef_unsafe(_Partitions(outer), _Partitions(inner1), _Partitions(inner2)) + def mult(part1, part2, maxrows=None, level=None, quantum=None): r""" Compute a product of two Schur functions. @@ -532,6 +546,7 @@ def mult(part1, part2, maxrows=None, level=None, quantum=None): l_free(qlist) return result + def skew(outer, inner, maxrows=0): """ Compute the Schur expansion of a skew Schur function. @@ -561,9 +576,12 @@ def skew(outer, inner, maxrows=0): cdef vector* v2 = iterable_to_vector(inner) cdef hashtab* ht = skew_c(v1, v2, int(maxrows)) result = sf_hashtab_to_dict(ht) - v_free(v1); v_free(v2); hash_free(ht) + v_free(v1) + v_free(v2) + hash_free(ht) return result + def coprod(part, all=0): """ Compute the coproduct of a Schur function. @@ -594,7 +612,8 @@ def coprod(part, all=0): cdef vector* v1 = iterable_to_vector(part) cdef hashtab* ht = coprod_c(v1, int(all)) result = vp_hashtab_to_dict(ht) - v_free(v1); hash_free(ht) + v_free(v1) + hash_free(ht) return result @@ -631,28 +650,31 @@ def mult_schubert(w1, w2, rank=0): cdef vector* v2 = iterable_to_vector(w2) cdef hashtab* ht = mult_schubert_c(v1, v2, int(rank)) result = schubert_hashtab_to_dict(ht) - v_free(v1); v_free(v2); hash_free(ht) + v_free(v1) + v_free(v2) + hash_free(ht) return result + def lrskew(outer, inner, weight=None, maxrows=0): - """ - Return the skew LR tableaux of shape ``outer / inner``. + r""" + Iterate over the skew LR tableaux of shape ``outer / inner``. INPUT: - - ``outer`` -- a partition. + - ``outer`` -- a partition - - ``inner`` -- a partition. + - ``inner`` -- a partition + + - ``weight`` -- a partition (optional) - - ``weight`` -- a partition (optional). + - ``maxrows`` -- an integer (optional) - - ``maxrows`` -- an integer (optional). + OUTPUT: an iterator of :class:`SkewTableau` - OUTPUT: a list of :class:`SkewTableau`x. This will change to an - iterator over such skew tableaux once Cython will support the - ``yield`` statement. Specifying a third entry `maxrows` restricts - the alphabet to `\{1,2,\ldots,maxrows\}`. Specifying `weight` - returns only those tableaux of given content/weight. + Specifying ``maxrows`` restricts the alphabet to `\{1,2,\ldots,maxrows\}`. + + Specifying ``weight`` returns only those tableaux of given content/weight. EXAMPLES:: @@ -678,19 +700,24 @@ def lrskew(outer, inner, weight=None, maxrows=0): 1 2 2 - sage: lrskew([3,2,1],[2], weight=[3,1]) + sage: list(lrskew([3,2,1],[2], weight=[3,1])) [[[None, None, 1], [1, 1], [2]]] """ cdef vector* o = iterable_to_vector(outer) - cdef vector* i = iterable_to_vector(inner+[0]*(len(outer)-len(inner))) + cdef vector* i = iterable_to_vector(inner + [0]*(len(outer) - len(inner))) cdef skewtab* st = st_new(o, i, NULL, int(maxrows)) - result = [skewtab_to_SkewTableau(st)] # todo: replace by the following line - #yield skewtab_to_SkewTableau(st) - while st_next(st): - result.append(skewtab_to_SkewTableau(st)) # todo: replace by the following line - #yield skewtab_to_SkewTableau(st) - st_free(st) - if weight is not None: - result = [r for r in result if r.weight() == _Partitions(weight) ] - return result # todo: remove + if weight is None: + yield skewtab_to_SkewTableau(st) + while st_next(st): + yield skewtab_to_SkewTableau(st) + else: + wt = _Partitions(weight) + r = skewtab_to_SkewTableau(st) + if r.weight() == wt: + yield r + while st_next(st): + r = skewtab_to_SkewTableau(st) + if r.weight() == wt: + yield r + st_free(st) diff --git a/src/sage/libs/meataxe.pyx b/src/sage/libs/meataxe.pyx index ab711d046bd..1120600b566 100644 --- a/src/sage/libs/meataxe.pyx +++ b/src/sage/libs/meataxe.pyx @@ -66,21 +66,27 @@ cdef Matrix_t *rawMatrix(int Field, list entries) except NULL: ## this module. Hence, `import sage.libs.meataxe` is enough ## to make sure that MeatAxe is initialised. -from cpython.bytes cimport PyBytes_AsString +from sage.cpython.string cimport str_to_bytes, char_to_str +import os +from sage.env import DOT_SAGE cdef void sage_meataxe_error_handler(const MtxErrorRecord_t *err): sig_block() - cdef bytes ErrText = err.Text - PyErr_SetObject(ErrMsg.get(ErrText.split(': ')[-1], RuntimeError), "{} in file {} (line {})".format(ErrText, err.FileInfo.BaseName, err.LineNo)) + ErrText = char_to_str(err.Text) + BaseName = char_to_str(err.FileInfo.BaseName) + LineNo = err.LineNo + PyErr_SetObject(ErrMsg.get(ErrText.split(': ')[-1], RuntimeError), f"{ErrText} in file {BaseName} (line {LineNo})") sig_unblock() cdef inline meataxe_init(): ## Assign to a variable that enables MeatAxe to find ## its multiplication tables. - import os - from sage.env import DOT_SAGE global MtxLibDir - MtxLibDir = PyBytes_AsString(os.path.join(DOT_SAGE,'meataxe')) + mtxdir = str_to_bytes(os.path.join(DOT_SAGE, 'meataxe')) + if len(mtxdir) >= 1024: + raise RuntimeError(f"the path for the meataxe library {mtxdir!r} is too long, it needs to be of length < 1024") + MtxLibDir[:len(mtxdir)] = mtxdir + MtxLibDir[len(mtxdir)] = c'\0' ## Error handling for MeatAxe, to prevent immediate exit of the program MtxSetErrorHandler(sage_meataxe_error_handler) diff --git a/src/sage/libs/ntl/ntl_GF2.pyx b/src/sage/libs/ntl/ntl_GF2.pyx index a86990e5f77..c7083501620 100644 --- a/src/sage/libs/ntl/ntl_GF2.pyx +++ b/src/sage/libs/ntl/ntl_GF2.pyx @@ -40,7 +40,8 @@ cdef class ntl_GF2(object): r""" Initializes a NTL bit. - EXAMPLES: + EXAMPLES:: + sage: ntl.GF2(1) 1 sage: ntl.GF2(int(2)) @@ -59,7 +60,8 @@ cdef class ntl_GF2(object): """ Return the string representation of self. - EXAMPLES: + EXAMPLES:: + sage: str(ntl.GF2(1)) # indirect doctest '1' """ @@ -69,7 +71,8 @@ cdef class ntl_GF2(object): """ Serializes self. - EXAMPLES: + EXAMPLES:: + sage: a = ntl.GF2(1) sage: loads(dumps(a)) 1 @@ -224,7 +227,8 @@ cdef class ntl_GF2(object): """ Return self as an int. - EXAMPLES: + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: int(z) @@ -239,7 +243,8 @@ def unpickle_class_value(cls, x): """ Here for unpickling. - EXAMPLES: + EXAMPLES:: + sage: sage.libs.ntl.ntl_GF2.unpickle_class_value(ntl.GF2,1) 1 sage: type(sage.libs.ntl.ntl_GF2.unpickle_class_value(ntl.GF2,1)) @@ -251,7 +256,8 @@ def unpickle_class_args(cls, x): """ Here for unpickling. - EXAMPLES: + EXAMPLES:: + sage: sage.libs.ntl.ntl_GF2.unpickle_class_args(ntl.GF2,[1]) 1 sage: type(sage.libs.ntl.ntl_GF2.unpickle_class_args(ntl.GF2,[1])) diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index ab15f89c692..8c0f5583d18 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -92,7 +92,8 @@ cdef class ntl_GF2E(object): OUTPUT: a new ntl.GF2E element - EXAMPLES: + EXAMPLES:: + sage: k. = GF(2^8) sage: e = ntl.GF2E(a,k); e [0 1] @@ -169,7 +170,8 @@ cdef class ntl_GF2E(object): """ Returns the structure that holds the underlying NTL GF2E modulus. - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext( ntl.GF2X([1,1,0,1,1,0,0,0,1]) ) sage: a = ntl.GF2E(ntl.ZZ_pX([1,1,3],2), ctx) sage: cty = a.modulus_context(); cty @@ -183,7 +185,8 @@ cdef class ntl_GF2E(object): """ Return the string representation of self. - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: ntl.GF2E([1,1,0,1], ctx) # indirect doctest [1 1 0 1] @@ -195,7 +198,8 @@ cdef class ntl_GF2E(object): """ Return a copy of self. - EXAMPLES: + EXAMPLES:: + sage: x = ntl.GF2E([0,1,1],GF(2^4,'a')) sage: y = copy(x) sage: x == y @@ -209,7 +213,8 @@ cdef class ntl_GF2E(object): def __mul__(ntl_GF2E self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: x = ntl.GF2E([1,0,1,0,1], ctx) ; y = ntl.GF2E([1,1,0,1,1], ctx) sage: x*y ## indirect doctest @@ -226,7 +231,8 @@ cdef class ntl_GF2E(object): def __sub__(ntl_GF2E self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: x = ntl.GF2E([1,0,1,0,1], ctx) ; y = ntl.GF2E([1,1,0,1,1], ctx) sage: x - y ## indirect doctest @@ -243,7 +249,8 @@ cdef class ntl_GF2E(object): def __add__(ntl_GF2E self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: x = ntl.GF2E([1,0,1,0,1], ctx) ; y = ntl.GF2E([1,1,0,1,1], ctx) sage: x+y ## indirect doctest @@ -260,7 +267,8 @@ cdef class ntl_GF2E(object): def __truediv__(ntl_GF2E self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: x = ntl.GF2E([1,0,1,0,1], ctx) ; y = ntl.GF2E([1,1,0,1,1], ctx) sage: x/y ## indirect doctest @@ -280,7 +288,8 @@ cdef class ntl_GF2E(object): def __neg__(ntl_GF2E self): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: x = ntl.GF2E([1,0,1,0,1], ctx) sage: -x ## indirect doctest @@ -292,7 +301,8 @@ cdef class ntl_GF2E(object): def __pow__(ntl_GF2E self, long e, ignored): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: x = ntl.GF2E([1,0,1,0,1], ctx) sage: x**2 ## indirect doctest @@ -337,7 +347,8 @@ cdef class ntl_GF2E(object): """ Returns True if this element equals zero, False otherwise. - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: x = ntl.GF2E([1,0,1,0,1], ctx) ; y = ntl.GF2E([1,1,0,1,1,0,0,0,1], ctx) sage: x.IsZero() @@ -351,7 +362,8 @@ cdef class ntl_GF2E(object): """ Returns True if this element equals one, False otherwise. - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: x = ntl.GF2E([1,0,1,0,1], ctx) ; y = ntl.GF2E([0,1,0,1,1,0,0,0,1], ctx) sage: x.IsOne() @@ -365,7 +377,8 @@ cdef class ntl_GF2E(object): """ Returns the trace of this element. - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: x = ntl.GF2E([1,0,1,0,1], ctx) ; y = ntl.GF2E([0,1,1,0,1,1], ctx) sage: x.trace() @@ -381,7 +394,8 @@ cdef class ntl_GF2E(object): """ Returns a ntl.GF2X copy of this element. - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,0,0,1])) sage: a = ntl.GF2E('0x1c', ctx) sage: a.rep() @@ -397,7 +411,8 @@ cdef class ntl_GF2E(object): """ Represents this element as a list of binary digits. - EXAMPLES: + EXAMPLES:: + sage: e=ntl.GF2E([0,1,1],GF(2^4,'a')) sage: e.list() [0, 1, 1] @@ -434,7 +449,8 @@ cdef class ntl_GF2E(object): OUTPUT: FiniteFieldElement over k - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext([1,1,0,1,1,0,0,0,1]) sage: e = ntl.GF2E([0,1], ctx) sage: a = e._sage_(); a diff --git a/src/sage/libs/ntl/ntl_GF2EContext.pyx b/src/sage/libs/ntl/ntl_GF2EContext.pyx index 3728a2fe69e..68f911fa121 100644 --- a/src/sage/libs/ntl/ntl_GF2EContext.pyx +++ b/src/sage/libs/ntl/ntl_GF2EContext.pyx @@ -24,7 +24,8 @@ GF2EContextDict = {} cdef class ntl_GF2EContext_class(object): def __init__(self, ntl_GF2X v): """ - EXAMPLES: + EXAMPLES:: + # You can construct contexts manually. sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1])) sage: n1 = ntl.GF2E([1,1],ctx) @@ -51,7 +52,8 @@ cdef class ntl_GF2EContext_class(object): def __reduce__(self): """ - EXAMPLES: + EXAMPLES:: + sage: c = ntl.GF2EContext(GF(2^5,'b')) sage: loads(dumps(c)) is c True @@ -62,10 +64,11 @@ cdef class ntl_GF2EContext_class(object): """ Returns a print representation of self. - EXAMPLES: - sage: c = ntl.GF2EContext(GF(2^16,'a')) - sage: c - NTL modulus [1 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1] + EXAMPLES:: + + sage: c = ntl.GF2EContext(GF(2^16,'a')) + sage: c + NTL modulus [1 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1] """ return "NTL modulus %s"%(self.m) @@ -74,7 +77,8 @@ cdef class ntl_GF2EContext_class(object): Return the current modulus associated to this context. - EXAMPLES: + EXAMPLES:: + sage: c = ntl.GF2EContext(GF(2^7,'foo')) sage: c.modulus() [1 1 0 0 0 0 0 1] @@ -84,7 +88,8 @@ cdef class ntl_GF2EContext_class(object): def restore(self): """ - EXAMPLES: + EXAMPLES:: + sage: c1 = ntl.GF2E([0,1],GF(2^4,'a')) ; c2 = ntl.GF2E([1,0,1],GF(2^4,'a')) sage: c1+c2 [1 1 1] @@ -100,7 +105,9 @@ cdef class ntl_GF2EContext_class(object): def ntl_GF2EContext( v ): """ Create a new GF2EContext. - EXAMPLES: + + EXAMPLES:: + sage: c = ntl.GF2EContext(GF(2^2,'a')) sage: n1 = ntl.GF2E([0,1],c) sage: n1 diff --git a/src/sage/libs/ntl/ntl_GF2EX.pyx b/src/sage/libs/ntl/ntl_GF2EX.pyx index b902ca3f117..3b17d720388 100644 --- a/src/sage/libs/ntl/ntl_GF2EX.pyx +++ b/src/sage/libs/ntl/ntl_GF2EX.pyx @@ -43,7 +43,8 @@ cdef class ntl_GF2EX(object): """ Minimal wrapper of NTL's GF2EX class. - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,1])) sage: ntl.GF2EX(ctx, '[[1 0] [2 1]]') [[1] [0 1]] @@ -99,7 +100,8 @@ cdef class ntl_GF2EX(object): def __reduce__(self): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,1])) sage: f = ntl.GF2EX(ctx, '[[1 0 1] [1 0 0 1] [1]]') sage: f == loads(dumps(f)) @@ -140,7 +142,8 @@ cdef class ntl_GF2EX(object): """ Return the string representation of self. - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,1])) sage: ntl.GF2EX(ctx, '[[1 0] [2 1]]').__repr__() '[[1] [0 1]]' @@ -149,7 +152,8 @@ cdef class ntl_GF2EX(object): def __mul__(ntl_GF2EX self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,1])) sage: f = ntl.GF2EX(ctx, '[[1 0] [2 1]]') sage: g = ntl.GF2EX(ctx, '[[1 0 1 1] [0 1 1 0 1] [1 0 1]]') @@ -168,7 +172,8 @@ cdef class ntl_GF2EX(object): def __sub__(ntl_GF2EX self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,1])) sage: f = ntl.GF2EX(ctx, '[[1 0] [2 1]]') sage: g = ntl.GF2EX(ctx, '[[1 0 1 1] [0 1 1 0 1] [1 0 1]]') @@ -187,7 +192,8 @@ cdef class ntl_GF2EX(object): def __add__(ntl_GF2EX self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,1])) sage: f = ntl.GF2EX(ctx, '[[1 0] [2 1]]') sage: g = ntl.GF2EX(ctx, '[[1 0 1 1] [0 1 1 0 1] [1 0 1]]') @@ -206,7 +212,8 @@ cdef class ntl_GF2EX(object): def __neg__(ntl_GF2EX self): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,1])) sage: f = ntl.GF2EX(ctx, '[[1 0] [2 1]]') sage: -f ## indirect doctest @@ -220,7 +227,8 @@ cdef class ntl_GF2EX(object): def __pow__(ntl_GF2EX self, long e, ignored): """ - EXAMPLES: + EXAMPLES:: + sage: ctx = ntl.GF2EContext(ntl.GF2X([1,1,0,1,1,0,1])) sage: f = ntl.GF2EX(ctx, '[[1 0] [2 1]]') sage: f**2 ## indirect doctest diff --git a/src/sage/libs/ntl/ntl_GF2X.pyx b/src/sage/libs/ntl/ntl_GF2X.pyx index 3b4892a132f..9eec2c213eb 100644 --- a/src/sage/libs/ntl/ntl_GF2X.pyx +++ b/src/sage/libs/ntl/ntl_GF2X.pyx @@ -1,4 +1,4 @@ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # Copyright (C) 2007 Martin Albrecht # @@ -11,9 +11,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import, division from cysignals.signals cimport sig_on, sig_off @@ -51,7 +50,8 @@ def GF2XHexOutput(have_hex=None): returned. INPUT: - have_hex if True hex representation will be used + + - have_hex -- if True hex representation will be used EXAMPLES:: @@ -80,6 +80,7 @@ def GF2XHexOutput(have_hex=None): else: GF2XHexOutput_c[0] = 0 + cdef class ntl_GF2X(object): """ Univariate Polynomials over GF(2) via NTL. @@ -523,7 +524,7 @@ cdef class ntl_GF2X(object): TESTS:: - sage: hex(e) + sage: hex(e) # py2 doctest:warning...: DeprecationWarning: use the method .hex instead See http://trac.sagemath.org/24514 for details. @@ -544,17 +545,19 @@ cdef class ntl_GF2X(object): def _sage_(ntl_GF2X self, R=None): """ - Returns a Sage polynomial over GF(2) equivalent to - this element. If a ring R is provided it is used - to construct the polynomial in, otherwise - an appropriate ring is generated. + Return a Sage polynomial over GF(2) equivalent to this element. + + If a ring R is provided, it is used to construct the polynomial + in. Otherwise, an appropriate ring is generated. INPUT: - self -- GF2X element - R -- PolynomialRing over GF(2) + + - self -- GF2X element + - R -- PolynomialRing over GF(2) OUTPUT: - polynomial in R + + polynomial in R EXAMPLES:: @@ -569,14 +572,15 @@ cdef class ntl_GF2X(object): from sage.rings.finite_rings.finite_field_constructor import FiniteField R = PolynomialRing(FiniteField(2), 'x') - return R(map(int,self.list())) + return R([int(c) for c in self.list()]) def coeff(self, int i): """ - Return the coefficient of the monomial $X^i$ in self. + Return the coefficient of the monomial `X^i` in ``self``. INPUT: - i -- degree of X + + - i -- degree of X EXAMPLES:: @@ -592,6 +596,8 @@ cdef class ntl_GF2X(object): def __getitem__(self, int i): """ + EXAMPLES:: + sage: e = ntl.GF2X([0,1,0,1]) sage: e[0] # indirect doctest 0 @@ -604,8 +610,9 @@ cdef class ntl_GF2X(object): def LeadCoeff(self): """ - Return the leading coefficient of self. This is always 1 - except when self == 0. + Return the leading coefficient of self. + + This is always 1 except when self == 0. EXAMPLES:: @@ -639,7 +646,7 @@ cdef class ntl_GF2X(object): def SetCoeff(self, int i, a): """ - Return the constant term of self. + Set the value of a coefficient of self. EXAMPLES:: @@ -655,6 +662,8 @@ cdef class ntl_GF2X(object): def __setitem__(self, int i, a): """ + EXAMPLES:: + sage: e = ntl.GF2X([1,0,1]); e [1 0 1] sage: e[1] = 1 # indirect doctest @@ -667,6 +676,9 @@ cdef class ntl_GF2X(object): def diff(self): """ Differentiate self. + + EXAMPLES:: + sage: e = ntl.GF2X([1,0,1,1,0]) sage: e.diff() [0 0 1] @@ -681,7 +693,8 @@ cdef class ntl_GF2X(object): hi defaults to deg(a) INPUT: - hi -- bit position until which reverse is requested + + - hi -- bit position until which reverse is requested EXAMPLES:: @@ -709,6 +722,8 @@ cdef class ntl_GF2X(object): def __int__(self): """ + EXAMPLES:: + sage: e = ntl.GF2X([1,0,1,1,0]) sage: int(e) Traceback (most recent call last): @@ -725,7 +740,7 @@ cdef class ntl_GF2X(object): def NumBits(self): """ - returns number of bits of self, i.e., deg(self) + 1. + Return the number of bits of self, i.e., deg(self) + 1. EXAMPLES:: @@ -737,6 +752,8 @@ cdef class ntl_GF2X(object): def __len__(self): """ + EXAMPLES:: + sage: e = ntl.GF2X([1,0,1,1,0]) sage: len(e) 4 @@ -745,7 +762,7 @@ cdef class ntl_GF2X(object): def NumBytes(self): """ - Returns number of bytes of self, i.e., floor((NumBits(self)+7)/8) + Return the number of bytes of self, i.e., floor((NumBits(self)+7)/8) EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_GF2X_linkage.pxi b/src/sage/libs/ntl/ntl_GF2X_linkage.pxi index 77d66c16983..fd5a276eecc 100644 --- a/src/sage/libs/ntl/ntl_GF2X_linkage.pxi +++ b/src/sage/libs/ntl/ntl_GF2X_linkage.pxi @@ -26,14 +26,16 @@ from sage.libs.ntl.GF2X cimport * cdef GF2X_c *celement_new(long parent): """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] """ return new GF2X_c() cdef int celement_delete(GF2X_c *e, long parent): """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: del x """ @@ -41,14 +43,16 @@ cdef int celement_delete(GF2X_c *e, long parent): cdef int celement_construct(GF2X_c *e, long parent): """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] """ pass cdef int celement_destruct(GF2X_c *e, long parent): """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: del x """ @@ -56,7 +60,8 @@ cdef int celement_destruct(GF2X_c *e, long parent): cdef int celement_gen(GF2X_c *e, long i, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] """ cdef unsigned char g = 2 @@ -66,7 +71,8 @@ cdef object celement_repr(GF2X_c *e, long parent): """ We ignore NTL's printing. - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x x @@ -75,7 +81,8 @@ cdef object celement_repr(GF2X_c *e, long parent): cdef inline int celement_set(GF2X_c* res, GF2X_c* a, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: y = x; y x @@ -84,7 +91,8 @@ cdef inline int celement_set(GF2X_c* res, GF2X_c* a, long parent) except -2: cdef inline int celement_set_si(GF2X_c* res, long i, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: P(0) 0 @@ -100,7 +108,8 @@ cdef inline long celement_get_si(GF2X_c* res, long parent) except -2: cdef inline bint celement_is_zero(GF2X_c* a, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: bool(x), x.is_zero() (True, False) @@ -111,7 +120,8 @@ cdef inline bint celement_is_zero(GF2X_c* a, long parent) except -2: cdef inline bint celement_is_one(GF2X_c *a, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x.is_one() False @@ -122,7 +132,8 @@ cdef inline bint celement_is_one(GF2X_c *a, long parent) except -2: cdef inline bint celement_equal(GF2X_c *a, GF2X_c *b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x == x True @@ -135,7 +146,8 @@ cdef inline bint celement_equal(GF2X_c *a, GF2X_c *b, long parent) except -2: cdef inline int celement_cmp(GF2X_c *a, GF2X_c *b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x != 1 True @@ -179,7 +191,8 @@ cdef inline int celement_cmp(GF2X_c *a, GF2X_c *b, long parent) except -2: cdef long celement_len(GF2X_c *a, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x.degree() 1 @@ -190,7 +203,8 @@ cdef long celement_len(GF2X_c *a, long parent) except -2: cdef inline int celement_add(GF2X_c *res, GF2X_c *a, GF2X_c *b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x + 1 x + 1 @@ -199,7 +213,8 @@ cdef inline int celement_add(GF2X_c *res, GF2X_c *a, GF2X_c *b, long parent) exc cdef inline int celement_sub(GF2X_c* res, GF2X_c* a, GF2X_c* b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x - 1 x + 1 @@ -208,7 +223,8 @@ cdef inline int celement_sub(GF2X_c* res, GF2X_c* a, GF2X_c* b, long parent) exc cdef inline int celement_neg(GF2X_c* res, GF2X_c* a, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: -x x @@ -236,7 +252,8 @@ cdef inline int celement_mul_scalar(GF2X_c* res, GF2X_c* p, object c, cdef inline int celement_mul(GF2X_c* res, GF2X_c* a, GF2X_c* b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x*(x+1) x^2 + x @@ -245,14 +262,16 @@ cdef inline int celement_mul(GF2X_c* res, GF2X_c* a, GF2X_c* b, long parent) exc cdef inline int celement_div(GF2X_c* res, GF2X_c* a, GF2X_c* b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] """ return GF2X_divide(res[0], a[0], b[0]) cdef inline int celement_floordiv(GF2X_c* res, GF2X_c* a, GF2X_c* b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x//(x + 1) 1 @@ -263,7 +282,8 @@ cdef inline int celement_floordiv(GF2X_c* res, GF2X_c* a, GF2X_c* b, long parent cdef inline int celement_mod(GF2X_c* res, GF2X_c* a, GF2X_c* b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: (x^2 + 1) % x^2 1 @@ -272,7 +292,8 @@ cdef inline int celement_mod(GF2X_c* res, GF2X_c* a, GF2X_c* b, long parent) exc cdef inline int celement_quorem(GF2X_c* q, GF2X_c* r, GF2X_c* a, GF2X_c* b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: f = x^2 + x + 1 sage: f.quo_rem(x + 1) @@ -284,14 +305,16 @@ cdef inline int celement_inv(GF2X_c* res, GF2X_c* a, long parent) except -2: """ We ignore NTL here and use the fraction field constructor. - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] """ raise NotImplementedError cdef inline int celement_pow(GF2X_c* res, GF2X_c* x, long e, GF2X_c *modulus, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: x^1000 x^1000 @@ -326,7 +349,8 @@ cdef inline int celement_pow(GF2X_c* res, GF2X_c* x, long e, GF2X_c *modulus, lo cdef inline int celement_gcd(GF2X_c* res, GF2X_c* a, GF2X_c *b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: f = x*(x+1) sage: f.gcd(x+1) @@ -338,7 +362,8 @@ cdef inline int celement_gcd(GF2X_c* res, GF2X_c* a, GF2X_c *b, long parent) exc cdef inline int celement_xgcd(GF2X_c* res, GF2X_c* s, GF2X_c *t, GF2X_c* a, GF2X_c *b, long parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = GF(2)[] sage: f = x*(x+1) sage: f.xgcd(x+1) diff --git a/src/sage/libs/ntl/ntl_ZZ.pyx b/src/sage/libs/ntl/ntl_ZZ.pyx index a32b2cae80c..b504501ca8e 100644 --- a/src/sage/libs/ntl/ntl_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_ZZ.pyx @@ -102,7 +102,8 @@ cdef class ntl_ZZ(object): """ Return the string representation of self. - EXAMPLES: + EXAMPLES:: + sage: ntl.ZZ(5).__repr__() '5' """ @@ -244,7 +245,8 @@ cdef class ntl_ZZ(object): """ Return self as an int. - EXAMPLES: + EXAMPLES:: + sage: ntl.ZZ(22).__int__() 22 sage: type(ntl.ZZ(22).__int__()) @@ -310,7 +312,8 @@ cdef class ntl_ZZ(object): r""" Sets the value from a sage int. - EXAMPLES: + EXAMPLES:: + sage: n=ntl.ZZ(2983) sage: n 2983 @@ -394,7 +397,8 @@ def unpickle_class_value(cls, x): """ Here for unpickling. - EXAMPLES: + EXAMPLES:: + sage: sage.libs.ntl.ntl_ZZ.unpickle_class_value(ntl.ZZ, 3) 3 sage: type(sage.libs.ntl.ntl_ZZ.unpickle_class_value(ntl.ZZ, 3)) @@ -406,7 +410,8 @@ def unpickle_class_args(cls, x): """ Here for unpickling. - EXAMPLES: + EXAMPLES:: + sage: sage.libs.ntl.ntl_ZZ.unpickle_class_args(ntl.ZZ, [3]) 3 sage: type(sage.libs.ntl.ntl_ZZ.unpickle_class_args(ntl.ZZ, [3])) diff --git a/src/sage/libs/ntl/ntl_ZZX.pyx b/src/sage/libs/ntl/ntl_ZZX.pyx index caf87d10554..1ee992279b3 100644 --- a/src/sage/libs/ntl/ntl_ZZX.pyx +++ b/src/sage/libs/ntl/ntl_ZZX.pyx @@ -107,7 +107,8 @@ cdef class ntl_ZZX(object): # See ntl_ZZX.pxd for definition of data members def __init__(self, v=None): """ - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,5,-9]) sage: f [1 2 5 -9] @@ -148,7 +149,8 @@ cdef class ntl_ZZX(object): """ Return the string representation of self. - EXAMPLES: + EXAMPLES:: + sage: ntl.ZZX([1,3,0,5]).__repr__() '[1 3 0 5]' """ @@ -162,7 +164,8 @@ cdef class ntl_ZZX(object): """ Return a copy of self. - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZX([1,32]) sage: y = copy(x) sage: y == x @@ -263,7 +266,8 @@ cdef class ntl_ZZX(object): r""" Retrieves coefficients as a list of ntl.ZZ Integers. - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZX([129381729371289371237128318293718237, 2, -3, 0, 4]) sage: L = x.list(); L [129381729371289371237128318293718237, 2, -3, 0, 4] @@ -278,7 +282,8 @@ cdef class ntl_ZZX(object): def __add__(ntl_ZZX self, ntl_ZZX other): """ - EXAMPLES: + EXAMPLES:: + sage: ntl.ZZX(list(range(5))) + ntl.ZZX(list(range(6))) [0 2 4 6 8 5] """ @@ -292,7 +297,8 @@ cdef class ntl_ZZX(object): def __sub__(ntl_ZZX self, ntl_ZZX other): """ - EXAMPLES: + EXAMPLES:: + sage: ntl.ZZX(list(range(5))) - ntl.ZZX(list(range(6))) [0 0 0 0 0 -5] """ @@ -306,7 +312,8 @@ cdef class ntl_ZZX(object): def __mul__(ntl_ZZX self, ntl_ZZX other): """ - EXAMPLES: + EXAMPLES:: + sage: ntl.ZZX(list(range(5))) * ntl.ZZX(list(range(6))) [0 0 1 4 10 20 30 34 31 20] """ @@ -325,7 +332,8 @@ cdef class ntl_ZZX(object): Compute quotient self / other, if the quotient is a polynomial. Otherwise an Exception is raised. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3]) * ntl.ZZX([4,5])**2 sage: g = ntl.ZZX([4,5]) sage: f/g @@ -360,7 +368,8 @@ cdef class ntl_ZZX(object): function returns q if q lies in ZZ[X], and otherwise raises an Exception. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([2,4,6]); g = ntl.ZZX([2]) sage: f % g # 0 [] @@ -384,7 +393,8 @@ cdef class ntl_ZZX(object): Returns the unique integral q and r such that self = q*other + r, if they exist. Otherwise raises an Exception. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX(list(range(10))); g = ntl.ZZX([-1,0,1]) sage: q, r = f.quo_rem(g) sage: q, r @@ -405,7 +415,8 @@ cdef class ntl_ZZX(object): """ Return f*f. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([-1,0,1]) sage: f*f [1 0 -2 0 1] @@ -469,7 +480,8 @@ cdef class ntl_ZZX(object): """ Return True exactly if this polynomial is 0. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([0,0,0,0]) sage: f.is_zero() True @@ -485,7 +497,8 @@ cdef class ntl_ZZX(object): """ Return True exactly if this polynomial is 1. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,1]) sage: f.is_one() False @@ -499,7 +512,8 @@ cdef class ntl_ZZX(object): """ Return True exactly if this polynomial is monic. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([2,0,0,1]) sage: f.is_monic() True @@ -520,7 +534,9 @@ cdef class ntl_ZZX(object): def __neg__(self): """ Return the negative of self. - EXAMPLES: + + EXAMPLES:: + sage: f = ntl.ZZX([2,0,0,1]) sage: -f [-2 0 0 -1] @@ -532,7 +548,8 @@ cdef class ntl_ZZX(object): Return the polynomial obtained by shifting all coefficients of this polynomial to the left n positions. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([2,0,0,1]) sage: f [2 0 0 1] @@ -552,7 +569,8 @@ cdef class ntl_ZZX(object): Return the polynomial obtained by shifting all coefficients of this polynomial to the right n positions. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([2,0,0,1]) sage: f [2 0 0 1] @@ -571,7 +589,8 @@ cdef class ntl_ZZX(object): leading coefficient of f. Also, our convention is that the content of 0 is 0. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([2,0,0,2]) sage: f.content() 2 @@ -595,7 +614,8 @@ cdef class ntl_ZZX(object): coefficient of the primitive part is nonnegative, and the primitive part of 0 is 0. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([6,12,3,9]) sage: f.primitive_part() [2 4 1 3] @@ -618,7 +638,8 @@ cdef class ntl_ZZX(object): deg(b), and \code{LeadCoeff(b)\^(deg(a)-deg(b)+1) a = b q + r}. Only the classical algorithm is used. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([0,1]) sage: g = ntl.ZZX([1,2,3]) sage: g.pseudo_quo_rem(f) @@ -641,7 +662,8 @@ cdef class ntl_ZZX(object): Return the gcd d = gcd(a, b), where by convention the leading coefficient of d is >= 0. We use a multi-modular algorithm. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3]) * ntl.ZZX([4,5])**2 sage: g = ntl.ZZX([1,1,1])**3 * ntl.ZZX([1,2,3]) sage: f.gcd(g) @@ -656,7 +678,8 @@ cdef class ntl_ZZX(object): """ Return the least common multiple of self and other. - EXAMPLES: + EXAMPLES:: + sage: x1 = ntl.ZZX([-1,0,0,1]) sage: x2 = ntl.ZZX([-1,0,0,0,0,0,1]) sage: x1.lcm(x2) @@ -684,7 +707,8 @@ cdef class ntl_ZZX(object): $2^{-80}$. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3]) * ntl.ZZX([4,5])**2 sage: g = ntl.ZZX([1,1,1])**3 * ntl.ZZX([1,2,3]) sage: f.xgcd(g) # nothing since they are not coprime @@ -713,7 +737,8 @@ cdef class ntl_ZZX(object): Return the degree of this polynomial. The degree of the 0 polynomial is -1. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([5,0,1]) sage: f.degree() 2 @@ -733,7 +758,8 @@ cdef class ntl_ZZX(object): """ Return the leading coefficient of this polynomial. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([3,6,9]) sage: f.leading_coefficient() 9 @@ -749,7 +775,8 @@ cdef class ntl_ZZX(object): """ Return the constant coefficient of this polynomial. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([3,6,9]) sage: f.constant_term() 3 @@ -765,7 +792,8 @@ cdef class ntl_ZZX(object): """ Set this polynomial to the monomial "x". - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX() sage: f.set_x() sage: f @@ -784,7 +812,8 @@ cdef class ntl_ZZX(object): """ True if this is the polynomial "x". - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX() sage: f.set_x() sage: f.is_x() @@ -802,7 +831,8 @@ cdef class ntl_ZZX(object): """ Return the derivative of this polynomial. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,7,0,13]) sage: f.derivative() [7 0 39] @@ -815,7 +845,8 @@ cdef class ntl_ZZX(object): of this polynomial. If hi is set then this function behaves as if this polynomial has degree hi. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3,4,5]) sage: f.reverse() [5 4 3 2 1] @@ -836,7 +867,8 @@ cdef class ntl_ZZX(object): Return the truncation of this polynomial obtained by removing all terms of degree >= m. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3,4,5]) sage: f.truncate(3) [1 2 3] @@ -861,7 +893,8 @@ cdef class ntl_ZZX(object): """ Return self*other but with terms of degree >= m removed. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3,4,5]) sage: g = ntl.ZZX([10]) sage: f.multiply_and_truncate(g, 2) @@ -878,7 +911,8 @@ cdef class ntl_ZZX(object): """ Return self*self but with terms of degree >= m removed. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3,4,5]) sage: f.square_and_truncate(4) [1 4 10 20] @@ -895,7 +929,8 @@ cdef class ntl_ZZX(object): Compute and return the inverse of self modulo $x^m$. The constant term of self must be 1 or -1. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3,4,5,6,7]) sage: f.invert_and_truncate(20) [1 -2 1 0 0 0 0 8 -23 22 -7 0 0 0 64 -240 337 -210 49] @@ -916,7 +951,8 @@ cdef class ntl_ZZX(object): Return self*other % modulus. The modulus must be monic with deg(modulus) > 0, and self and other must have smaller degree. - EXAMPLES: + EXAMPLES:: + sage: modulus = ntl.ZZX([1,2,0,1]) # must be monic sage: g = ntl.ZZX([-1,0,1]) sage: h = ntl.ZZX([3,7,13]) @@ -932,7 +968,8 @@ cdef class ntl_ZZX(object): The modulus must be monic, and of positive degree degree bigger than the degree of self. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,0,3]) sage: mod = ntl.ZZX([5,3,-1,1,1]) sage: f.trace_mod(mod) @@ -947,12 +984,14 @@ cdef class ntl_ZZX(object): monomial x modulo this polynomial for i = 0, ..., deg(f)-1. This polynomial must be monic. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,0,3,0,1]) sage: f.trace_list() [5, 0, -6, 0, 10] - The input polynomial must be monic or a ValueError is raised: + The input polynomial must be monic or a ValueError is raised:: + sage: f = ntl.ZZX([1,2,0,3,0,2]) sage: f.trace_list() Traceback (most recent call last): @@ -976,7 +1015,8 @@ cdef class ntl_ZZX(object): randomized strategy that errors with probability no more than $2^{-80}$. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([17,0,1,1]) sage: g = ntl.ZZX([34,-17,18,2]) sage: f.resultant(g) @@ -1000,13 +1040,15 @@ cdef class ntl_ZZX(object): randomized strategy that errors with probability no more than $2^{-80}$. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,0,3]) sage: mod = ntl.ZZX([-5,2,0,0,1]) sage: f.norm_mod(mod) -8846 - The norm is the constant term of the characteristic polynomial. + The norm is the constant term of the characteristic polynomial:: + sage: f.charpoly_mod(mod) [-8846 -594 -60 14 1] """ @@ -1027,7 +1069,8 @@ cdef class ntl_ZZX(object): randomized strategy that errors with probability no more than $2^{-80}$. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,0,3]) sage: f.discriminant() -339 @@ -1052,7 +1095,8 @@ cdef class ntl_ZZX(object): randomized strategy that errors with probability no more than $2^{-80}$. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,0,3]) sage: mod = ntl.ZZX([-5,2,0,0,1]) sage: f.charpoly_mod(mod) @@ -1070,14 +1114,16 @@ cdef class ntl_ZZX(object): self. In all cases, this function may use a randomized strategy that errors with probability no more than $2^{-80}$. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([0,0,1]) sage: g = f*f sage: f.charpoly_mod(g) [0 0 0 0 1] However, since $f^2 = 0$ modulo $g$, its minimal polynomial - is of degree $2$. + is of degree $2$:: + sage: f.minpoly_mod_noproof(g) [0 0 1] """ @@ -1088,7 +1134,8 @@ cdef class ntl_ZZX(object): """ Reset this polynomial to 0. Changes this polynomial in place. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3]) sage: f [1 2 3] @@ -1106,7 +1153,8 @@ cdef class ntl_ZZX(object): the polynomial grows. (You might save a millisecond with this function.) - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([1,2,3]) sage: f.preallocate_space(20) sage: f @@ -1127,7 +1175,8 @@ cdef class ntl_ZZX(object): is a factor, and the second is its exponent. Assumes that self is primitive. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.ZZX([0, 1, 2, 1]) sage: f.squarefree_decomposition() [([0 1], 1), ([1 1], 2)] diff --git a/src/sage/libs/ntl/ntl_ZZ_p.pyx b/src/sage/libs/ntl/ntl_ZZ_p.pyx index 0ed38a1f736..50ea48dace6 100644 --- a/src/sage/libs/ntl/ntl_ZZ_p.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_p.pyx @@ -85,7 +85,8 @@ cdef class ntl_ZZ_p(object): r""" Initializes an NTL integer mod p. - EXAMPLES: + EXAMPLES:: + sage: c = ntl.ZZ_pContext(11) sage: ntl.ZZ_p(12r, c) 1 @@ -165,7 +166,8 @@ cdef class ntl_ZZ_p(object): """ Return the modulus for self. - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZ_p(5,17) sage: c = x.modulus_context() sage: y = ntl.ZZ_p(3,c) @@ -182,7 +184,8 @@ cdef class ntl_ZZ_p(object): """ Return the string representation of self. - EXAMPLES: + EXAMPLES:: + sage: ntl.ZZ_p(7,192).__repr__() '7' """ @@ -220,7 +223,8 @@ cdef class ntl_ZZ_p(object): def __invert__(ntl_ZZ_p self): r""" - EXAMPLES: + EXAMPLES:: + sage: c=ntl.ZZ_pContext(11) sage: ~ntl.ZZ_p(2r,modulus=c) 6 @@ -234,7 +238,8 @@ cdef class ntl_ZZ_p(object): def __mul__(ntl_ZZ_p self, other): """ - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZ_p(5,31) ; y = ntl.ZZ_p(8,31) sage: x*y ## indirect doctest 9 @@ -252,7 +257,8 @@ cdef class ntl_ZZ_p(object): def __sub__(ntl_ZZ_p self, other): """ - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZ_p(5,31) ; y = ntl.ZZ_p(8,31) sage: x-y ## indirect doctest 28 @@ -270,7 +276,8 @@ cdef class ntl_ZZ_p(object): def __add__(ntl_ZZ_p self, other): """ - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZ_p(5,31) ; y = ntl.ZZ_p(8,31) sage: x+y ## indirect doctest 13 @@ -290,7 +297,8 @@ cdef class ntl_ZZ_p(object): def __neg__(ntl_ZZ_p self): """ - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZ_p(5,31) sage: -x ## indirect doctest 26 @@ -304,7 +312,8 @@ cdef class ntl_ZZ_p(object): def __pow__(ntl_ZZ_p self, long e, ignored): """ - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZ_p(5,31) sage: x**3 ## indirect doctest 1 @@ -320,7 +329,8 @@ cdef class ntl_ZZ_p(object): """ Return self as an int. - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZ_p(3,8) sage: x.__int__() 3 @@ -343,7 +353,8 @@ cdef class ntl_ZZ_p(object): r""" This method exists solely for automated testing of get_as_int(). - EXAMPLES: + EXAMPLES:: + sage: c = ntl.ZZ_pContext(20) sage: x = ntl.ZZ_p(42,modulus=c) sage: i = x._get_as_int_doctest() @@ -368,7 +379,8 @@ cdef class ntl_ZZ_p(object): r""" This method exists solely for automated testing of set_from_int(). - EXAMPLES: + EXAMPLES:: + sage: c=ntl.ZZ_pContext(ntl.ZZ(20)) sage: x = ntl.ZZ_p(modulus=c) sage: x._set_from_int_doctest(42) @@ -386,7 +398,8 @@ cdef class ntl_ZZ_p(object): """ Return a lift of self as an ntl.ZZ object. - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZ_p(8,18) sage: x.lift() 8 @@ -402,7 +415,8 @@ cdef class ntl_ZZ_p(object): r""" Returns the modulus as an NTL ZZ. - EXAMPLES: + EXAMPLES:: + sage: c = ntl.ZZ_pContext(ntl.ZZ(20)) sage: n = ntl.ZZ_p(2983,c) sage: n.modulus() @@ -445,7 +459,8 @@ cdef class ntl_ZZ_p(object): """ Return a lift of self as a Sage integer. - EXAMPLES: + EXAMPLES:: + sage: x = ntl.ZZ_p(8,188) sage: x._integer_() 8 @@ -461,7 +476,8 @@ cdef class ntl_ZZ_p(object): r""" Returns the value as a sage IntegerModRing. - EXAMPLES: + EXAMPLES:: + sage: c = ntl.ZZ_pContext(20) sage: n = ntl.ZZ_p(2983, c) sage: type(n._sage_()) diff --git a/src/sage/libs/ntl/ntl_ZZ_pContext.pyx b/src/sage/libs/ntl/ntl_ZZ_pContext.pyx index 40d0c430ba2..09abc82949c 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pContext.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pContext.pyx @@ -25,7 +25,8 @@ from sage.rings.integer cimport Integer cdef class ntl_ZZ_pContext_class(object): def __init__(self, ntl_ZZ v): """ - EXAMPLES: + EXAMPLES:: + # You can construct contexts manually. sage: c = ntl.ZZ_pContext(11) sage: n1 = ntl.ZZ_p(12,c) @@ -52,7 +53,8 @@ cdef class ntl_ZZ_pContext_class(object): def __reduce__(self): """ - EXAMPLES: + EXAMPLES:: + sage: c = ntl.ZZ_pContext(13) sage: loads(dumps(c)) is c True @@ -63,10 +65,11 @@ cdef class ntl_ZZ_pContext_class(object): """ Returns a print representation of self. - EXAMPLES: - sage: c = ntl.ZZ_pContext(7) - sage: c - NTL modulus 7 + EXAMPLES:: + + sage: c = ntl.ZZ_pContext(7) + sage: c + NTL modulus 7 """ return "NTL modulus %s"%(self.p) @@ -78,7 +81,8 @@ cdef class ntl_ZZ_pContext_class(object): Return the current modulus associated to this context. - EXAMPLES: + EXAMPLES:: + sage: c = ntl.ZZ_pContext(7) sage: c.modulus() 7 @@ -94,7 +98,8 @@ cdef class ntl_ZZ_pContext_class(object): def restore(self): """ - EXAMPLES: + EXAMPLES:: + sage: c1 = ntl.ZZ_p(5,92) ; c2 = ntl.ZZ_p(7,92) sage: c1+c2 12 @@ -132,7 +137,8 @@ ZZ_pContext_factory = ntl_ZZ_pContext_factory() def ntl_ZZ_pContext( v ): """ Create a new ZZ_pContext. - EXAMPLES: + EXAMPLES:: + sage: c = ntl.ZZ_pContext(178) sage: n1 = ntl.ZZ_p(212,c) sage: n1 diff --git a/src/sage/libs/ntl/ntl_ZZ_pE.pyx b/src/sage/libs/ntl/ntl_ZZ_pE.pyx index d2ba7059ef6..bbb9ef8c8d3 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pE.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pE.pyx @@ -70,7 +70,8 @@ cdef class ntl_ZZ_pE(object): r""" Initializes an ntl ZZ_pE. - EXAMPLES: + EXAMPLES:: + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1],11)) sage: c.ZZ_pE([13,4,1]) [1 3] @@ -203,7 +204,8 @@ cdef class ntl_ZZ_pE(object): def __invert__(ntl_ZZ_pE self): r""" - EXAMPLES: + EXAMPLES:: + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([2,7,1],11)) sage: ~ntl.ZZ_pE([1,1],modulus=c) [7 3] @@ -337,11 +339,12 @@ def make_ZZ_pE(x, c): """ Here for unpickling. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5,0,1],25)) - sage: sage.libs.ntl.ntl_ZZ_pE.make_ZZ_pE([4,3], c) - [4 3] - sage: type(sage.libs.ntl.ntl_ZZ_pE.make_ZZ_pE([4,3], c)) - + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5,0,1],25)) + sage: sage.libs.ntl.ntl_ZZ_pE.make_ZZ_pE([4,3], c) + [4 3] + sage: type(sage.libs.ntl.ntl_ZZ_pE.make_ZZ_pE([4,3], c)) + """ return ntl_ZZ_pE(x, c) diff --git a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx index 5e025302fe0..bfa408be73f 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx @@ -26,6 +26,7 @@ cdef class ntl_ZZ_pEContext_class(object): def __init__(self, ntl_ZZ_pX f): """ EXAMPLES: + # You can construct contexts manually. sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([4,1,6],25)) sage: n1=c.ZZ_pE([10,17,12]) @@ -64,9 +65,10 @@ cdef class ntl_ZZ_pEContext_class(object): """ Returns a string representation of self. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)); c - NTL modulus [1 1 1] (mod 7) + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)); c + NTL modulus [1 1 1] (mod 7) """ return "NTL modulus %s (mod %s)"%(self.f, self.pc.p) @@ -74,11 +76,12 @@ cdef class ntl_ZZ_pEContext_class(object): """ Returns the ZZ_pContext contained within self. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)); c - NTL modulus [1 1 1] (mod 7) - sage: c.get_pc() - NTL modulus 7 + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)); c + NTL modulus [1 1 1] (mod 7) + sage: c.get_pc() + NTL modulus 7 """ return self.pc @@ -86,10 +89,11 @@ cdef class ntl_ZZ_pEContext_class(object): """ Returns the ZZ_pX polynomial defining self. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: c.polynomial() - [1 1 1] + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: c.polynomial() + [1 1 1] """ return self.f @@ -126,10 +130,11 @@ cdef class ntl_ZZ_pEContext_class(object): """ Returns a ZZ_pE object with modulus self out of the data v. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: c.ZZ_pE([4,3]) - [4 3] + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: c.ZZ_pE([4,3]) + [4 3] """ from .ntl_ZZ_pE import ntl_ZZ_pE return ntl_ZZ_pE(v,modulus=self) @@ -138,10 +143,11 @@ cdef class ntl_ZZ_pEContext_class(object): """ Returns a ZZ_pE object with modulus self out of the data v. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: c.ZZ_pEX([4,3]) - [[4] [3]] + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: c.ZZ_pEX([4,3]) + [[4] [3]] """ from .ntl_ZZ_pEX import ntl_ZZ_pEX return ntl_ZZ_pEX(v, modulus=self) @@ -153,9 +159,11 @@ def ntl_ZZ_pEContext( ntl_ZZ_pX f): Such an object must be created before any ZZ_pE or ZZ_pEX objects can be used. The context handling should be taken care of by the wrapper classes. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)); c - NTL modulus [1 1 1] (mod 7) + + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)); c + NTL modulus [1 1 1] (mod 7) """ try: return ZZ_pEContextDict[repr(f), repr(f.c.p)] diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx index 382a4514933..2d4c740fe48 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx @@ -56,7 +56,8 @@ cdef class ntl_ZZ_pEX(object): # See ntl_ZZ_pEX.pxd for definition of data members def __init__(self, v=None, modulus=None): """ - EXAMPLES: + EXAMPLES:: + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) sage: a = ntl.ZZ_pE([3,2], c) sage: b = ntl.ZZ_pE([1,2], c) @@ -191,13 +192,14 @@ cdef class ntl_ZZ_pEX(object): """ Returns the structure that holds the underlying NTL modulus. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.get_modulus_context() - NTL modulus [1 1 1] (mod 7) + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.get_modulus_context() + NTL modulus [1 1 1] (mod 7) """ return self.c @@ -205,13 +207,14 @@ cdef class ntl_ZZ_pEX(object): r""" Sets the ith coefficient of self to be a. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f[1] = 4; f - [[3 2] [4] [1 2]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f[1] = 4; f + [[3 2] [4] [1 2]] """ if i < 0: raise IndexError("index (i=%s) must be >= 0" % i) @@ -227,15 +230,16 @@ cdef class ntl_ZZ_pEX(object): r""" Returns the ith coefficient of self. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f[0] - [3 2] - sage: f[5] - [] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f[0] + [3 2] + sage: f[5] + [] """ if i < 0: raise IndexError("index (=%s) must be >= 0" % i) @@ -252,13 +256,14 @@ cdef class ntl_ZZ_pEX(object): """ Return list of entries as a list of ntl_ZZ_pEs. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.list() - [[3 2], [1 2], [1 2]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.list() + [[3 2], [1 2], [1 2]] """ # This function could be sped up by using the list API and not restoring the context each time. # Or by using self.x.rep directly. @@ -270,14 +275,15 @@ cdef class ntl_ZZ_pEX(object): """ Adds self and other. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: g = ntl.ZZ_pEX([-b, a]) - sage: f + g - [[2] [4 4] [1 2]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: g = ntl.ZZ_pEX([-b, a]) + sage: f + g + [[2] [4 4] [1 2]] """ if self.c is not other.c: raise ValueError("You can not perform arithmetic with elements of different moduli.") @@ -292,14 +298,15 @@ cdef class ntl_ZZ_pEX(object): """ Subtracts other from self. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: g = ntl.ZZ_pEX([-b, a]) - sage: f - g - [[4 4] [5] [1 2]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: g = ntl.ZZ_pEX([-b, a]) + sage: f - g + [[4 4] [5] [1 2]] """ if self.c is not other.c: raise ValueError("You can not perform arithmetic with elements of different moduli.") @@ -314,20 +321,21 @@ cdef class ntl_ZZ_pEX(object): """ Returns the product self * other. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: g = ntl.ZZ_pEX([-b, a]) - sage: f * g - [[1 3] [1 1] [2 4] [6 4]] - sage: c2 = ntl.ZZ_pEContext(ntl.ZZ_pX([4,1,1], 5)) # we can mix up the moduli - sage: x = c2.ZZ_pEX([2,4]) - sage: x^2 - [[4] [1] [1]] - sage: f * g # back to the first one and the ntl modulus gets reset correctly - [[1 3] [1 1] [2 4] [6 4]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: g = ntl.ZZ_pEX([-b, a]) + sage: f * g + [[1 3] [1 1] [2 4] [6 4]] + sage: c2 = ntl.ZZ_pEContext(ntl.ZZ_pX([4,1,1], 5)) # we can mix up the moduli + sage: x = c2.ZZ_pEX([2,4]) + sage: x^2 + [[4] [1] [1]] + sage: f * g # back to the first one and the ntl modulus gets reset correctly + [[1 3] [1 1] [2 4] [6 4]] """ if self.c is not other.c: raise ValueError("You can not perform arithmetic with elements of different moduli.") @@ -343,18 +351,19 @@ cdef class ntl_ZZ_pEX(object): Compute quotient self / other, if the quotient is a polynomial. Otherwise an Exception is raised. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a^2, -a*b-a*b, b^2]) - sage: g = ntl.ZZ_pEX([-a, b]) - sage: f / g - [[4 5] [1 2]] - sage: g / f - Traceback (most recent call last): - ... - ArithmeticError: self (=[[4 5] [1 2]]) is not divisible by other (=[[5 1] [2 6] [4]]) + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a^2, -a*b-a*b, b^2]) + sage: g = ntl.ZZ_pEX([-a, b]) + sage: f / g + [[4 5] [1 2]] + sage: g / f + Traceback (most recent call last): + ... + ArithmeticError: self (=[[4 5] [1 2]]) is not divisible by other (=[[5 1] [2 6] [4]]) """ if self.c is not other.c: raise ValueError("You can not perform arithmetic with elements of different moduli.") @@ -380,16 +389,17 @@ cdef class ntl_ZZ_pEX(object): If p is not prime or the modulus is not irreducible, this function may raise a RuntimeError due to division by a noninvertible element of ZZ_p. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5, 0, 1], 5^10)) - sage: a = c.ZZ_pE([5, 1]) - sage: b = c.ZZ_pE([4, 99]) - sage: f = c.ZZ_pEX([a, b]) - sage: g = c.ZZ_pEX([a^2, -b, a + b]) - sage: g % f - [[1864280 2123186]] - sage: f % g - [[5 1] [4 99]] + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5, 0, 1], 5^10)) + sage: a = c.ZZ_pE([5, 1]) + sage: b = c.ZZ_pE([4, 99]) + sage: f = c.ZZ_pEX([a, b]) + sage: g = c.ZZ_pEX([a^2, -b, a + b]) + sage: g % f + [[1864280 2123186]] + sage: f % g + [[5 1] [4 99]] """ if self.c is not other.c: raise ValueError("You can not perform arithmetic with elements of different moduli.") @@ -409,16 +419,17 @@ cdef class ntl_ZZ_pEX(object): If p is not prime or the modulus is not irreducible, this function may raise a RuntimeError due to division by a noninvertible element of ZZ_p. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5, 0, 1], 5^10)) - sage: a = c.ZZ_pE([5, 1]) - sage: b = c.ZZ_pE([4, 99]) - sage: f = c.ZZ_pEX([a, b]) - sage: g = c.ZZ_pEX([a^2, -b, a + b]) - sage: g.quo_rem(f) - ([[4947544 2492106] [4469276 6572944]], [[1864280 2123186]]) - sage: f.quo_rem(g) - ([], [[5 1] [4 99]]) + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5, 0, 1], 5^10)) + sage: a = c.ZZ_pE([5, 1]) + sage: b = c.ZZ_pE([4, 99]) + sage: f = c.ZZ_pEX([a, b]) + sage: g = c.ZZ_pEX([a^2, -b, a + b]) + sage: g.quo_rem(f) + ([[4947544 2492106] [4469276 6572944]], [[1864280 2123186]]) + sage: f.quo_rem(g) + ([], [[5 1] [4 99]]) """ if self.c is not other.c: raise ValueError("You can not perform arithmetic with elements of different moduli.") @@ -434,13 +445,14 @@ cdef class ntl_ZZ_pEX(object): """ Return $f^2$. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.square() - [[5 1] [5 1] [2 1] [1] [4]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.square() + [[5 1] [5 1] [2 1] [1] [4]] """ # self.c.restore_c() # _new() restores the context cdef ntl_ZZ_pEX r = self._new() @@ -513,16 +525,17 @@ cdef class ntl_ZZ_pEX(object): """ Return True exactly if this polynomial is 0. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.is_zero() - False - sage: f = ntl.ZZ_pEX([0,0,7], c) - sage: f.is_zero() - True + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.is_zero() + False + sage: f = ntl.ZZ_pEX([0,0,7], c) + sage: f.is_zero() + True """ self.c.restore_c() return bool(ZZ_pEX_IsZero(self.x)) @@ -531,16 +544,17 @@ cdef class ntl_ZZ_pEX(object): """ Return True exactly if this polynomial is 1. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.is_one() - False - sage: f = ntl.ZZ_pEX([1, 0, 0], c) - sage: f.is_one() - True + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.is_one() + False + sage: f = ntl.ZZ_pEX([1, 0, 0], c) + sage: f.is_one() + True """ self.c.restore_c() return bool(ZZ_pEX_IsOne(self.x)) @@ -549,16 +563,17 @@ cdef class ntl_ZZ_pEX(object): """ Return True exactly if this polynomial is monic. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.is_monic() - False - sage: f = ntl.ZZ_pEX([a, b, 1], c) - sage: f.is_monic() - True + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.is_monic() + False + sage: f = ntl.ZZ_pEX([a, b, 1], c) + sage: f.is_monic() + True """ self.c.restore_c() # The following line is what we should have. However, strangely this is *broken* @@ -575,13 +590,14 @@ cdef class ntl_ZZ_pEX(object): """ Return the negative of self. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: -f - [[4 5] [6 5] [6 5]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: -f + [[4 5] [6 5] [6 5]] """ cdef ntl_ZZ_pEX r = self._new() # self.c.restore_c() # _new() calls restore @@ -596,20 +612,21 @@ cdef class ntl_ZZ_pEX(object): (in which case self is reduced modulo c.p) or self.c.p should divide c.p (in which case self is lifted to something modulo c.p congruent to self modulo self.c.p) - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5, 0, 1], 5^20)) - sage: a = ntl.ZZ_pE([192870, 1928189], c) - sage: b = ntl.ZZ_pE([18275,293872987], c) - sage: f = ntl.ZZ_pEX([a, b]) - sage: g = f.convert_to_modulus(ntl.ZZ_pContext(ntl.ZZ(5^5))) - sage: g - [[2245 64] [2650 1112]] - sage: g.get_modulus_context() - NTL modulus [3120 0 1] (mod 3125) - sage: g^2 - [[1130 2985] [805 830] [2095 2975]] - sage: (f^2).convert_to_modulus(ntl.ZZ_pContext(ntl.ZZ(5^5))) - [[1130 2985] [805 830] [2095 2975]] + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5, 0, 1], 5^20)) + sage: a = ntl.ZZ_pE([192870, 1928189], c) + sage: b = ntl.ZZ_pE([18275,293872987], c) + sage: f = ntl.ZZ_pEX([a, b]) + sage: g = f.convert_to_modulus(ntl.ZZ_pContext(ntl.ZZ(5^5))) + sage: g + [[2245 64] [2650 1112]] + sage: g.get_modulus_context() + NTL modulus [3120 0 1] (mod 3125) + sage: g^2 + [[1130 2985] [805 830] [2095 2975]] + sage: (f^2).convert_to_modulus(ntl.ZZ_pContext(ntl.ZZ(5^5))) + [[1130 2985] [805 830] [2095 2975]] """ cdef ntl_ZZ_pEContext_class cE = ntl_ZZ_pEContext(self.c.f.convert_to_modulus(c)) cE.restore_c() @@ -625,20 +642,22 @@ cdef class ntl_ZZ_pEX(object): Return the polynomial obtained by shifting all coefficients of this polynomial to the left n positions. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]); f - [[3 2] [1 2] [1 2]] - sage: f.left_shift(2) - [[] [] [3 2] [1 2] [1 2]] - sage: f.left_shift(5) - [[] [] [] [] [] [3 2] [1 2] [1 2]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]); f + [[3 2] [1 2] [1 2]] + sage: f.left_shift(2) + [[] [] [3 2] [1 2] [1 2]] + sage: f.left_shift(5) + [[] [] [] [] [] [3 2] [1 2] [1 2]] - A negative left shift is a right shift. - sage: f.left_shift(-2) - [[1 2]] + A negative left shift is a right shift:: + + sage: f.left_shift(-2) + [[1 2]] """ # self.c.restore_c() # _new() calls restore cdef ntl_ZZ_pEX r = self._new() @@ -652,20 +671,22 @@ cdef class ntl_ZZ_pEX(object): Return the polynomial obtained by shifting all coefficients of this polynomial to the right n positions. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]); f - [[3 2] [1 2] [1 2]] - sage: f.right_shift(2) - [[1 2]] - sage: f.right_shift(5) - [] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 7)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]); f + [[3 2] [1 2] [1 2]] + sage: f.right_shift(2) + [[1 2]] + sage: f.right_shift(5) + [] - A negative right shift is a left shift. - sage: f.right_shift(-5) - [[] [] [] [] [] [3 2] [1 2] [1 2]] + A negative right shift is a left shift:: + + sage: f.right_shift(-5) + [[] [] [] [] [] [3 2] [1 2] [1 2]] """ # self.c.restore_c() # _new() calls restore cdef ntl_ZZ_pEX r = self._new() @@ -680,20 +701,21 @@ cdef class ntl_ZZ_pEX(object): NOTE: Does not work if p is not prime or if the modulus is not irreducible. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: g = f^2 - sage: h = f^3 - sage: g.gcd(h) - [[2 1] [8 1] [9 1] [2] [1]] - sage: f^2 - [[5 8] [9 8] [6 8] [5] [8]] - sage: eight = ntl.ZZ_pEX([[8]], c) - sage: f^2 / eight - [[2 1] [8 1] [9 1] [2] [1]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: g = f^2 + sage: h = f^3 + sage: g.gcd(h) + [[2 1] [8 1] [9 1] [2] [1]] + sage: f^2 + [[5 8] [9 8] [6 8] [5] [8]] + sage: eight = ntl.ZZ_pEX([[8]], c) + sage: f^2 / eight + [[2 1] [8 1] [9 1] [2] [1]] """ #If check = True, need to check that ZZ_pE is a field. self.c.restore_c() @@ -709,20 +731,21 @@ cdef class ntl_ZZ_pEX(object): Here r is the gcd of self and other. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: g = ntl.ZZ_pEX([a-b, b^2, a]) - sage: h = ntl.ZZ_pEX([a^2-b, b^4, b,a]) - sage: r,s,t = (g*f).xgcd(h*f) - sage: r - [[4 6] [1] [1]] - sage: f / ntl.ZZ_pEX([b]) - [[4 6] [1] [1]] - sage: s*f*g+t*f*h - [[4 6] [1] [1]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: g = ntl.ZZ_pEX([a-b, b^2, a]) + sage: h = ntl.ZZ_pEX([a^2-b, b^4, b,a]) + sage: r,s,t = (g*f).xgcd(h*f) + sage: r + [[4 6] [1] [1]] + sage: f / ntl.ZZ_pEX([b]) + [[4 6] [1] [1]] + sage: s*f*g+t*f*h + [[4 6] [1] [1]] """ self.c.restore_c() cdef ntl_ZZ_pEX s = self._new() @@ -738,15 +761,16 @@ cdef class ntl_ZZ_pEX(object): Return the degree of this polynomial. The degree of the 0 polynomial is -1. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.degree() - 2 - sage: ntl.ZZ_pEX([], c).degree() - -1 + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.degree() + 2 + sage: ntl.ZZ_pEX([], c).degree() + -1 """ self.c.restore_c() return ZZ_pEX_deg(self.x) @@ -755,13 +779,14 @@ cdef class ntl_ZZ_pEX(object): """ Return the leading coefficient of this polynomial. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.leading_coefficient() - [1 2] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.leading_coefficient() + [1 2] """ self.c.restore_c() cdef long i @@ -772,13 +797,14 @@ cdef class ntl_ZZ_pEX(object): """ Return the constant coefficient of this polynomial. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.constant_term() - [3 2] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.constant_term() + [3 2] """ self.c.restore_c() return self[0] @@ -787,15 +813,16 @@ cdef class ntl_ZZ_pEX(object): """ Set this polynomial to the monomial "x". - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f - [[3 2] [1 2] [1 2]] - sage: f.set_x(); f - [[] [1]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f + [[3 2] [1 2] [1 2]] + sage: f.set_x(); f + [[] [1]] """ self.c.restore_c() ZZ_pEX_SetX(self.x) @@ -804,15 +831,16 @@ cdef class ntl_ZZ_pEX(object): """ True if this is the polynomial "x". - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.is_x() - False - sage: f.set_x(); f.is_x() - True + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.is_x() + False + sage: f.set_x(); f.is_x() + True """ return bool(ZZ_pEX_IsX(self.x)) @@ -820,13 +848,14 @@ cdef class ntl_ZZ_pEX(object): """ Return the derivative of this polynomial. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.derivative() - [[1 2] [2 4]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.derivative() + [[1 2] [2 4]] """ cdef ntl_ZZ_pEX r = self._new() sig_on() @@ -870,19 +899,20 @@ cdef class ntl_ZZ_pEX(object): of this polynomial. If hi is set then this function behaves as if this polynomial has degree hi. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.reverse() - [[1 2] [1 2] [3 2]] - sage: f.reverse(hi=5) - [[] [] [] [1 2] [1 2] [3 2]] - sage: f.reverse(hi=1) - [[1 2] [3 2]] - sage: f.reverse(hi=-2) - [] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.reverse() + [[1 2] [1 2] [3 2]] + sage: f.reverse(hi=5) + [[] [] [] [1 2] [1 2] [3 2]] + sage: f.reverse(hi=1) + [[1 2] [3 2]] + sage: f.reverse(hi=-2) + [] """ cdef ntl_ZZ_pEX r = self._new() if not (hi is None): @@ -896,15 +926,16 @@ cdef class ntl_ZZ_pEX(object): Return the truncation of this polynomial obtained by removing all terms of degree >= m. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.truncate(3) - [[3 2] [1 2] [1 2]] - sage: f.truncate(1) - [[3 2]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.truncate(3) + [[3 2] [1 2] [1 2]] + sage: f.truncate(1) + [[3 2]] """ cdef ntl_ZZ_pEX r = self._new() if m > 0: @@ -917,16 +948,17 @@ cdef class ntl_ZZ_pEX(object): """ Return self*other but with terms of degree >= m removed. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: g = ntl.ZZ_pEX([a - b, b^2, a, a*b]) - sage: f*g - [[6 4] [4 9] [4 6] [7] [1 9] [2 5]] - sage: f.multiply_and_truncate(g, 3) - [[6 4] [4 9] [4 6]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: g = ntl.ZZ_pEX([a - b, b^2, a, a*b]) + sage: f*g + [[6 4] [4 9] [4 6] [7] [1 9] [2 5]] + sage: f.multiply_and_truncate(g, 3) + [[6 4] [4 9] [4 6]] """ cdef ntl_ZZ_pEX r = self._new() if m > 0: @@ -939,15 +971,16 @@ cdef class ntl_ZZ_pEX(object): """ Return self*self but with terms of degree >= m removed. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f^2 - [[5 8] [9 8] [6 8] [5] [8]] - sage: f.square_and_truncate(3) - [[5 8] [9 8] [6 8]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f^2 + [[5 8] [9 8] [6 8] [5] [8]] + sage: f.square_and_truncate(3) + [[5 8] [9 8] [6 8]] """ cdef ntl_ZZ_pEX r = self._new() if m > 0: @@ -961,16 +994,17 @@ cdef class ntl_ZZ_pEX(object): Compute and return the inverse of self modulo $x^m$. The constant term of self must be invertible. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: g = f.invert_and_truncate(5) - sage: g - [[8 6] [4 4] [5 9] [1 4] [0 1]] - sage: f * g - [[1] [] [] [] [] [2 8] [9 10]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: g = f.invert_and_truncate(5) + sage: g + [[8 6] [4 4] [5 9] [1 4] [0 1]] + sage: f * g + [[1] [] [] [] [] [2 8] [9 10]] """ if m < 0: raise ArithmeticError("m (=%s) must be positive" % m) @@ -987,15 +1021,16 @@ cdef class ntl_ZZ_pEX(object): Return self*other % modulus. The modulus must be monic with deg(modulus) > 0, and self and other must have smaller degree. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: g = ntl.ZZ_pEX([b^4, a*b^2, a - b]) - sage: m = ntl.ZZ_pEX([a - b, b^2, a, a*b]) - sage: f.multiply_mod(g, m) - [[10 10] [4 4] [10 3]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: g = ntl.ZZ_pEX([b^4, a*b^2, a - b]) + sage: m = ntl.ZZ_pEX([a - b, b^2, a, a*b]) + sage: f.multiply_mod(g, m) + [[10 10] [4 4] [10 3]] """ self.c.restore_c() cdef ntl_ZZ_pEX r = self._new() @@ -1010,14 +1045,15 @@ cdef class ntl_ZZ_pEX(object): The modulus must be monic, and of positive degree degree bigger than the degree of self. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: m = ntl.ZZ_pEX([a - b, b^2, a, a*b]) - sage: f.trace_mod(m) - [8 1] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: m = ntl.ZZ_pEX([a - b, b^2, a, a*b]) + sage: f.trace_mod(m) + [8 1] """ self.c.restore_c() cdef ntl_ZZ_pE r = ntl_ZZ_pE(modulus = self.c) @@ -1032,13 +1068,15 @@ cdef class ntl_ZZ_pEX(object): # monomial x modulo this polynomial for i = 0, ..., deg(f)-1. # This polynomial must be monic. # - # EXAMPLES: + # EXAMPLES:: + # # sage: c=ntl.ZZ_pContext(ntl.ZZ(20)) # sage: f = c.ZZ_pX([1,2,0,3,0,1]) # sage: f.trace_list() # [5, 0, 14, 0, 10] # - # The input polynomial must be monic or a ValueError is raised: + # The input polynomial must be monic or a ValueError is raised:: + # # sage: c=ntl.ZZ_pContext(ntl.ZZ(20)) # sage: f = c.ZZ_pX([1,2,0,3,0,2] # sage: f.trace_list() @@ -1060,16 +1098,17 @@ cdef class ntl_ZZ_pEX(object): """ Return the resultant of self and other. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: g = ntl.ZZ_pEX([a - b, b^2, a, a*b]) - sage: f.resultant(g) - [1] - sage: (f*g).resultant(f^2) - [] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: g = ntl.ZZ_pEX([a - b, b^2, a, a*b]) + sage: f.resultant(g) + [1] + sage: (f*g).resultant(f^2) + [] """ self.c.restore_c() cdef ntl_ZZ_pE r = ntl_ZZ_pE(modulus = self.c) @@ -1084,14 +1123,15 @@ cdef class ntl_ZZ_pEX(object): modulus must be monic, and of positive degree strictly greater than the degree of self. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: m = ntl.ZZ_pEX([a - b, b^2, a, a*b]) - sage: f.norm_mod(m) - [9 2] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: m = ntl.ZZ_pEX([a - b, b^2, a, a*b]) + sage: f.norm_mod(m) + [9 2] """ self.c.restore_c() cdef ntl_ZZ_pE r = ntl_ZZ_pE(modulus = self.c) @@ -1108,13 +1148,14 @@ cdef class ntl_ZZ_pEX(object): $$ where m = deg(a), and lc(a) is the leading coefficient of a. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f.discriminant() - [1 6] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f.discriminant() + [1 6] """ self.c.restore_c() cdef long m @@ -1131,14 +1172,15 @@ cdef class ntl_ZZ_pEX(object): modulus. The modulus must be monic of degree bigger than self. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: m = ntl.ZZ_pEX([a - b, b^2, a, a*b]) - sage: f.minpoly_mod(m) - [[2 9] [8 2] [3 10] [1]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: m = ntl.ZZ_pEX([a - b, b^2, a, a*b]) + sage: f.minpoly_mod(m) + [[2 9] [8 2] [3 10] [1]] """ self.c.restore_c() cdef ntl_ZZ_pEX r = self._new() @@ -1151,15 +1193,16 @@ cdef class ntl_ZZ_pEX(object): """ Reset this polynomial to 0. Changes this polynomial in place. - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f - [[3 2] [1 2] [1 2]] - sage: f.clear(); f - [] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f + [[3 2] [1 2] [1 2]] + sage: f.clear(); f + [] """ self.c.restore_c() sig_on() @@ -1174,14 +1217,15 @@ cdef class ntl_ZZ_pEX(object): the polynomial grows. (You might save a millisecond with this function.) - EXAMPLES: - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: f = ntl.ZZ_pEX([a, b, b]) - sage: f[10]=ntl.ZZ_pE([1,8],c) # no new memory is allocated - sage: f - [[3 2] [1 2] [1 2] [] [] [] [] [] [] [] [1 8]] + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1], 11)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: f = ntl.ZZ_pEX([a, b, b]) + sage: f[10]=ntl.ZZ_pE([1,8],c) # no new memory is allocated + sage: f + [[3 2] [1 2] [1 2] [] [] [] [] [] [] [] [1 8]] """ self.c.restore_c() sig_on() @@ -1193,13 +1237,14 @@ def make_ZZ_pEX(v, modulus): """ Here for unpickling. - EXAMPLES: - sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5,0,1],25)) - sage: a = ntl.ZZ_pE([3,2], c) - sage: b = ntl.ZZ_pE([1,2], c) - sage: sage.libs.ntl.ntl_ZZ_pEX.make_ZZ_pEX([a,b,b], c) - [[3 2] [1 2] [1 2]] - sage: type(sage.libs.ntl.ntl_ZZ_pEX.make_ZZ_pEX([a,b,b], c)) - + EXAMPLES:: + + sage: c = ntl.ZZ_pEContext(ntl.ZZ_pX([-5,0,1],25)) + sage: a = ntl.ZZ_pE([3,2], c) + sage: b = ntl.ZZ_pE([1,2], c) + sage: sage.libs.ntl.ntl_ZZ_pEX.make_ZZ_pEX([a,b,b], c) + [[3 2] [1 2] [1 2]] + sage: type(sage.libs.ntl.ntl_ZZ_pEX.make_ZZ_pEX([a,b,b], c)) + """ return ntl_ZZ_pEX(v, modulus) diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi b/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi index ae325adc330..a5de653c2e8 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi +++ b/src/sage/libs/ntl/ntl_ZZ_pEX_linkage.pxi @@ -27,7 +27,8 @@ from sage.libs.ntl.types cimport ZZ_pX_c, ZZ_pEX_c cdef ZZ_pEX_c *celement_new(cparent parent): """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') """ if parent != NULL: @@ -37,7 +38,8 @@ cdef ZZ_pEX_c *celement_new(cparent parent): cdef int celement_delete(ZZ_pEX_c *e, cparent parent): """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') sage: del x """ @@ -48,7 +50,8 @@ cdef int celement_delete(ZZ_pEX_c *e, cparent parent): cdef int celement_construct(ZZ_pEX_c *e, cparent parent): """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') """ if parent != NULL: @@ -57,7 +60,8 @@ cdef int celement_construct(ZZ_pEX_c *e, cparent parent): cdef int celement_destruct(ZZ_pEX_c *e, cparent parent): """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') sage: del x """ @@ -67,7 +71,8 @@ cdef int celement_destruct(ZZ_pEX_c *e, cparent parent): cdef int celement_gen(ZZ_pEX_c *e, long i, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') """ if parent != NULL: @@ -79,7 +84,8 @@ cdef object celement_repr(ZZ_pEX_c *e, cparent parent): """ We ignore NTL's printing. - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') sage: x x @@ -88,7 +94,8 @@ cdef object celement_repr(ZZ_pEX_c *e, cparent parent): cdef inline int celement_set(ZZ_pEX_c* res, ZZ_pEX_c* a, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') sage: y = x sage: y @@ -98,7 +105,8 @@ cdef inline int celement_set(ZZ_pEX_c* res, ZZ_pEX_c* a, cparent parent) except cdef inline int celement_set_si(ZZ_pEX_c* res, long i, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') sage: P(0) 0 @@ -117,7 +125,8 @@ cdef inline long celement_get_si(ZZ_pEX_c* res, cparent parent) except -2: cdef inline bint celement_is_zero(ZZ_pEX_c* a, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') sage: bool(x), x.is_zero() (True, False) @@ -131,7 +140,8 @@ cdef inline bint celement_is_zero(ZZ_pEX_c* a, cparent parent) except -2: cdef inline bint celement_is_one(ZZ_pEX_c *a, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') sage: x.is_one() False @@ -145,7 +155,8 @@ cdef inline bint celement_is_one(ZZ_pEX_c *a, cparent parent) except -2: cdef inline bint celement_equal(ZZ_pEX_c *a, ZZ_pEX_c *b, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') sage: x == x True @@ -170,7 +181,8 @@ cdef inline int celement_cmp(ZZ_pEX_c *a, ZZ_pEX_c *b, cparent parent) except -2 cdef long celement_len(ZZ_pEX_c *a, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(GF(next_prime(2**60)**3,'a'),implementation='NTL') sage: x.degree() 1 @@ -184,7 +196,8 @@ cdef long celement_len(ZZ_pEX_c *a, cparent parent) except -2: cdef inline int celement_add(ZZ_pEX_c *res, ZZ_pEX_c *a, ZZ_pEX_c *b, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: K. = GF(next_prime(2**60)**3) sage: P. = PolynomialRing(K,implementation='NTL') sage: (1+a+a^2)*x + (1+x+x^2) @@ -197,7 +210,8 @@ cdef inline int celement_add(ZZ_pEX_c *res, ZZ_pEX_c *a, ZZ_pEX_c *b, cparent pa cdef inline int celement_sub(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c* b, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: K. = GF(next_prime(2**60)**3) sage: P. = PolynomialRing(K,implementation='NTL') sage: (1+a+a^2)*x - (1+x+x^2) @@ -210,7 +224,8 @@ cdef inline int celement_sub(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c* b, cparent pa cdef inline int celement_neg(ZZ_pEX_c* res, ZZ_pEX_c* a, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: K. = GF(next_prime(2**60)**3) sage: P. = PolynomialRing(K,implementation='NTL') sage: -x @@ -226,7 +241,8 @@ cdef inline int celement_mul_scalar(ZZ_pEX_c* res, ZZ_pEX_c* p, object c, cparen cdef inline int celement_mul(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c* b, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: K. = GF(next_prime(2**60)**3) sage: P. = PolynomialRing(K,implementation='NTL') sage: (1+a+a^2)*x * (1+x+x^2) @@ -245,7 +261,8 @@ cdef inline int celement_div(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c* b, cparent pa cdef inline int celement_floordiv(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c* b, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: K. = GF(next_prime(2**60)**3) sage: P. = PolynomialRing(K,implementation='NTL') sage: (x^2+2*a*x+a^2)//(x+a) @@ -264,7 +281,8 @@ cdef inline int celement_floordiv(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c* b, cpare cdef inline int celement_mod(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c* b, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: K. = GF(next_prime(2**60)**3) sage: P. = PolynomialRing(K,implementation='NTL') sage: (x^2-2*a*x) % (x+a) @@ -277,7 +295,8 @@ cdef inline int celement_mod(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c* b, cparent pa cdef inline int celement_quorem(ZZ_pEX_c* q, ZZ_pEX_c* r, ZZ_pEX_c* a, ZZ_pEX_c* b, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: K. = GF(next_prime(2**60)**3) sage: P. = PolynomialRing(K,implementation='NTL') sage: (x^2+2*a*x).quo_rem(x-a) @@ -357,7 +376,8 @@ cdef inline int celement_pow(ZZ_pEX_c* res, ZZ_pEX_c* x, long e, ZZ_pEX_c *modul cdef inline int celement_gcd(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c *b, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: K. = GF(next_prime(2**60)**3) sage: P. = PolynomialRing(K,implementation='NTL') sage: f = (x+3)*(x^7+a*x^5+1) @@ -373,7 +393,8 @@ cdef inline int celement_gcd(ZZ_pEX_c* res, ZZ_pEX_c* a, ZZ_pEX_c *b, cparent pa cdef inline int celement_xgcd(ZZ_pEX_c* res, ZZ_pEX_c* s, ZZ_pEX_c *t, ZZ_pEX_c* a, ZZ_pEX_c *b, cparent parent) except -2: """ - EXAMPLES: + EXAMPLES:: + sage: K. = GF(next_prime(2**60)**3) sage: P. = PolynomialRing(K,implementation='NTL') sage: f = (x+3)*(x^7+a*x^5+1) diff --git a/src/sage/libs/ntl/ntl_ZZ_pX.pyx b/src/sage/libs/ntl/ntl_ZZ_pX.pyx index 39bb2bbca6c..103e5f4015f 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pX.pyx @@ -68,7 +68,7 @@ cdef class ntl_ZZ_pX(object): or Karatsuba algorithms. """ # See ntl_ZZ_pX.pxd for definition of data members - def __init__(self, v = None, modulus = None): + def __init__(self, v=None, modulus=None): """ EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_lzz_p.pyx b/src/sage/libs/ntl/ntl_lzz_p.pyx index 36850937558..b5cd62502c4 100644 --- a/src/sage/libs/ntl/ntl_lzz_p.pyx +++ b/src/sage/libs/ntl/ntl_lzz_p.pyx @@ -149,7 +149,8 @@ cdef class ntl_zz_p(object): """ Quick and dirty zz_p object creation. - EXAMPLES: + EXAMPLES:: + sage: x = ntl.zz_p(23,75) sage: y = x*x ## indirect doctest """ @@ -183,7 +184,8 @@ cdef class ntl_zz_p(object): def __add__(ntl_zz_p self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ntl.zz_p(5,23) + ntl.zz_p(6,23) 11 """ @@ -199,7 +201,8 @@ cdef class ntl_zz_p(object): def __sub__(ntl_zz_p self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ntl.zz_p(5,23) - ntl.zz_p(6,23) 22 """ @@ -215,7 +218,8 @@ cdef class ntl_zz_p(object): def __mul__(ntl_zz_p self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ntl.zz_p(5,23) * ntl.zz_p(6,23) 7 """ @@ -231,7 +235,8 @@ cdef class ntl_zz_p(object): def __truediv__(ntl_zz_p self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ntl.zz_p(5,23) / ntl.zz_p(2,23) 14 """ @@ -297,7 +302,8 @@ cdef class ntl_zz_p(object): """ Return the negative of self. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_p(5,234) sage: -f ## indirect doctest 229 @@ -343,7 +349,8 @@ cdef class ntl_zz_p(object): """ Return self as an int. - EXAMPLES: + EXAMPLES:: + sage: ntl.zz_p(3,next_prime(100)).__int__() 3 sage: int(ntl.zz_p(3,next_prime(100))) @@ -357,7 +364,8 @@ cdef class ntl_zz_p(object): """ Return f*f. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_p(15,23) sage: f*f 18 @@ -372,7 +380,8 @@ cdef class ntl_zz_p(object): """ Return True exactly if this element is 0. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_p(0,20) sage: f.is_zero() True @@ -387,7 +396,8 @@ cdef class ntl_zz_p(object): """ Return True exactly if this element is 1. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_p(1,11) sage: f.is_one() True @@ -402,7 +412,8 @@ cdef class ntl_zz_p(object): """ Reset this element to 0. - EXAMPLES: + EXAMPLES:: + sage: x = ntl.zz_p(5,102) ; x 5 sage: x.clear() ; x diff --git a/src/sage/libs/ntl/ntl_lzz_pContext.pyx b/src/sage/libs/ntl/ntl_lzz_pContext.pyx index 284f31304c1..c38d7e8ed67 100644 --- a/src/sage/libs/ntl/ntl_lzz_pContext.pyx +++ b/src/sage/libs/ntl/ntl_lzz_pContext.pyx @@ -19,7 +19,8 @@ zz_pContextDict = {} cdef class ntl_zz_pContext_class(object): def __init__(self, long v): """ - EXAMPLES: + EXAMPLES:: + # You can construct contexts manually. sage: c = ntl.zz_pContext(11) sage: n1 = ntl.zz_p(12,c) @@ -58,7 +59,8 @@ cdef class ntl_zz_pContext_class(object): """ Print the modulus for self. - EXAMPLES: + EXAMPLES:: + sage: c1 = ntl.zz_pContext(36) sage: c1.modulus() 36 @@ -69,7 +71,8 @@ cdef class ntl_zz_pContext_class(object): """ Restore a zz_pContext. - EXAMPLES: + EXAMPLES:: + sage: c = ntl.zz_pContext(5) sage: m = ntl.zz_p(4,7) sage: c.restore() @@ -80,7 +83,8 @@ cdef class ntl_zz_pContext_class(object): """ Actual code for the above. - EXAMPLES: + EXAMPLES:: + sage: n = ntl.zz_p(3,5) sage: m = ntl.zz_p(4,7) sage: n*n ## indirect doctest @@ -93,7 +97,8 @@ def ntl_zz_pContext( v ): """ Creation function for a zz_p context. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pContext(26) sage: f = ntl.zz_pContext(10^100) Traceback (most recent call last): diff --git a/src/sage/libs/ntl/ntl_lzz_pX.pyx b/src/sage/libs/ntl/ntl_lzz_pX.pyx index 4df255c26d9..8a36824282c 100644 --- a/src/sage/libs/ntl/ntl_lzz_pX.pyx +++ b/src/sage/libs/ntl/ntl_lzz_pX.pyx @@ -63,7 +63,8 @@ cdef class ntl_zz_pX(object): # See ntl_zz_pX.pxd for definition of data members def __init__(self, ls=[], modulus=None): """ - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,2,5,-9],20) sage: f [1, 2, 5, 11] @@ -174,7 +175,8 @@ cdef class ntl_zz_pX(object): """ Return the string representation of self. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([3,5], 17) sage: f.__repr__() '[3, 5]' @@ -185,7 +187,8 @@ cdef class ntl_zz_pX(object): """ Return the ith coefficient of f. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX(range(7), 71) sage: f[3] ## indirect doctest 3 @@ -210,7 +213,8 @@ cdef class ntl_zz_pX(object): Set the ith coefficient of self to val. If i is out of range, raise an exception. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([], 7) sage: f[3] = 2 ; f [0, 0, 0, 2] @@ -235,7 +239,8 @@ cdef class ntl_zz_pX(object): Quick and dirty method for creating a new object with the same zz_pContext as self. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1], 20) sage: f.square() ## indirect doctest [1] @@ -249,7 +254,8 @@ cdef class ntl_zz_pX(object): """ Return self + other. - EXAMPLES: + EXAMPLES:: + sage: ntl.zz_pX(range(5),20) + ntl.zz_pX(range(6),20) ## indirect doctest [0, 2, 4, 6, 8, 5] sage: ntl.zz_pX(range(5),20) + ntl.zz_pX(range(6),50) @@ -271,7 +277,8 @@ cdef class ntl_zz_pX(object): """ Return self - other. - EXAMPLES: + EXAMPLES:: + sage: ntl.zz_pX(range(5),32) - ntl.zz_pX(range(6),32) [0, 0, 0, 0, 0, 27] sage: ntl.zz_pX(range(5),20) - ntl.zz_pX(range(6),50) ## indirect doctest @@ -291,7 +298,8 @@ cdef class ntl_zz_pX(object): def __mul__(ntl_zz_pX self, other): """ - EXAMPLES: + EXAMPLES:: + sage: ntl.zz_pX(range(5),20) * ntl.zz_pX(range(6),20) ## indirect doctest [0, 0, 1, 4, 10, 0, 10, 14, 11] sage: ntl.zz_pX(range(5),20) * ntl.zz_pX(range(6),50) @@ -316,7 +324,8 @@ cdef class ntl_zz_pX(object): Compute quotient self / other, if the quotient is a polynomial. Otherwise an Exception is raised. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,2,3],17) * ntl.zz_pX([4,5],17)**2 sage: g = ntl.zz_pX([4,5],17) sage: f/g ## indirect doctest @@ -359,7 +368,8 @@ cdef class ntl_zz_pX(object): function returns q if q lies in ZZ[X], and otherwise raises an Exception. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([2,4,6],17); g = ntl.zz_pX([2],17) sage: f % g ## indirect doctest [] @@ -384,7 +394,8 @@ cdef class ntl_zz_pX(object): """ Return the n-th nonnegative power of self. - EXAMPLES: + EXAMPLES:: + sage: g = ntl.zz_pX([-1,0,1],20) sage: g**10 ## indirect doctest [1, 0, 10, 0, 5, 0, 0, 0, 10, 0, 8, 0, 10, 0, 0, 0, 5, 0, 10, 0, 1] @@ -404,7 +415,8 @@ cdef class ntl_zz_pX(object): Specifically, this return r, q such that $self = q * right + r$ - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX(range(7), 19) sage: g = ntl.zz_pX([2,4,6], 19) sage: f // g @@ -428,7 +440,8 @@ cdef class ntl_zz_pX(object): """ Returns the whole part of $self / right$. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX(range(10), 19); g = ntl.zz_pX([1]*5, 19) sage: f // g ## indirect doctest [8, 18, 18, 18, 18, 9] @@ -445,7 +458,8 @@ cdef class ntl_zz_pX(object): """ Shifts this polynomial to the left, which is multiplication by $x^n$. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([2,4,6], 17) sage: f << 2 ## indirect doctest [0, 0, 2, 4, 6] @@ -459,7 +473,8 @@ cdef class ntl_zz_pX(object): """ Shifts this polynomial to the right, which is division by $x^n$ (and truncation). - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,2,3], 17) sage: f >> 2 ## indirect doctest [3] @@ -473,7 +488,8 @@ cdef class ntl_zz_pX(object): """ The formal derivative of self. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX(range(10), 17) sage: f.diff() [1, 4, 9, 16, 8, 2, 15, 13, 13] @@ -487,7 +503,8 @@ cdef class ntl_zz_pX(object): """ Returns self with coefficients reversed, i.e. $x^n self(x^{-n})$. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([2,4,6], 17) sage: f.reverse() [6, 4, 2] @@ -500,7 +517,8 @@ cdef class ntl_zz_pX(object): def __neg__(self): """ Return the negative of self. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([2,0,0,1],20) sage: -f [18, 0, 0, 19] @@ -546,7 +564,8 @@ cdef class ntl_zz_pX(object): """ Return list of entries as a list of python ints. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([23, 5,0,1], 10) sage: f.list() [3, 5, 0, 1] @@ -562,7 +581,8 @@ cdef class ntl_zz_pX(object): Return the degree of this polynomial. The degree of the 0 polynomial is -1. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([5,0,1],50) sage: f.degree() 2 @@ -583,7 +603,8 @@ cdef class ntl_zz_pX(object): """ Return the leading coefficient of this polynomial. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([3,6,9],19) sage: f.leading_coefficient() 9 @@ -598,7 +619,8 @@ cdef class ntl_zz_pX(object): """ Return the constant coefficient of this polynomial. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([3,6,9],127) sage: f.constant_term() 3 @@ -613,7 +635,8 @@ cdef class ntl_zz_pX(object): """ Return f*f. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([-1,0,1],17) sage: f*f [1, 0, 15, 0, 1] @@ -630,7 +653,8 @@ cdef class ntl_zz_pX(object): Return the truncation of this polynomial obtained by removing all terms of degree >= m. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,2,3,4,5],70) sage: f.truncate(3) [1, 2, 3] @@ -659,7 +683,8 @@ cdef class ntl_zz_pX(object): """ Return self*other but with terms of degree >= m removed. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,2,3,4,5],20) sage: g = ntl.zz_pX([10],20) sage: f.multiply_and_truncate(g, 2) @@ -681,7 +706,8 @@ cdef class ntl_zz_pX(object): """ Return self*self but with terms of degree >= m removed. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,2,3,4,5],20) sage: f.square_and_truncate(4) [1, 4, 10] @@ -703,7 +729,8 @@ cdef class ntl_zz_pX(object): Compute and return the inverse of self modulo $x^m$. The constant term of self must be 1 or -1. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,2,3,4,5,6,7],20) sage: f.invert_and_truncate(20) [1, 18, 1, 0, 0, 0, 0, 8, 17, 2, 13, 0, 0, 0, 4, 0, 17, 10, 9] @@ -733,7 +760,8 @@ cdef class ntl_zz_pX(object): """ Return True exactly if this polynomial is 0. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([0,0,0,20],5) sage: f.is_zero() True @@ -750,7 +778,8 @@ cdef class ntl_zz_pX(object): """ Return True exactly if this polynomial is 1. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,1],101) sage: f.is_one() False @@ -765,7 +794,8 @@ cdef class ntl_zz_pX(object): """ Return True exactly if this polynomial is monic. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([2,0,0,1],17) sage: f.is_monic() True @@ -787,7 +817,8 @@ cdef class ntl_zz_pX(object): """ Set this polynomial to the monomial "x". - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([],177) sage: f.set_x() sage: f @@ -808,7 +839,8 @@ cdef class ntl_zz_pX(object): """ True if this is the polynomial "x". - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([],100) sage: f.set_x() sage: f.is_x() @@ -827,7 +859,8 @@ cdef class ntl_zz_pX(object): """ Reset this polynomial to 0. Changes this polynomial in place. - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,2,3],17) sage: f [1, 2, 3] @@ -846,7 +879,8 @@ cdef class ntl_zz_pX(object): the polynomial grows. (You might save a millisecond with this function.) - EXAMPLES: + EXAMPLES:: + sage: f = ntl.zz_pX([1,2,3],17) sage: f.preallocate_space(20) sage: f diff --git a/src/sage/libs/ntl/ntl_mat_ZZ.pyx b/src/sage/libs/ntl/ntl_mat_ZZ.pyx index 60d3b467c59..2fa8e3e7487 100644 --- a/src/sage/libs/ntl/ntl_mat_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_mat_ZZ.pyx @@ -69,7 +69,8 @@ cdef class ntl_mat_ZZ(object): """ The \class{mat_ZZ} class implements arithmetic with matrices over $\Z$. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(3,3) ; M [ [0 0 0] @@ -101,7 +102,8 @@ cdef class ntl_mat_ZZ(object): def __reduce__(self): """ - EXAMPLES: + EXAMPLES:: + sage: m = ntl.mat_ZZ(3, 2, range(6)); m [ [0 1] @@ -123,7 +125,8 @@ cdef class ntl_mat_ZZ(object): """ Return the string representation of self. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(2,3,[5..10]) ; M.__repr__() '[\n[5 6 7]\n[8 9 10]\n]' """ @@ -133,7 +136,8 @@ cdef class ntl_mat_ZZ(object): """ Multiply two matrices. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(2,2,[8..11]) ; N = ntl.mat_ZZ(2,2,[-1..2]) sage: M*N [ @@ -155,7 +159,8 @@ cdef class ntl_mat_ZZ(object): """ Return self - other. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(2,2,[8..11]) ; N = ntl.mat_ZZ(2,2,[-1..2]) sage: M-N [ @@ -177,7 +182,8 @@ cdef class ntl_mat_ZZ(object): """ Return self + other. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(2,2,[8..11]) ; N = ntl.mat_ZZ(2,2,[-1..2]) sage: M+N [ @@ -227,7 +233,8 @@ cdef class ntl_mat_ZZ(object): """ Return self to the e power. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(2,2,[8..11]) sage: M**4 [ @@ -258,7 +265,8 @@ cdef class ntl_mat_ZZ(object): """ Return the number of rows in self. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(5,5,range(25)) sage: M.nrows() 5 @@ -269,7 +277,8 @@ cdef class ntl_mat_ZZ(object): """ Return the number of columns in self. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(5,8,range(40)) sage: M.ncols() 8 @@ -280,7 +289,8 @@ cdef class ntl_mat_ZZ(object): """ Given a tuple (i, j), return self[i,j]. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(2,9,[3..20]) sage: M[1,7] ## indirect doctest 19 @@ -323,7 +333,8 @@ cdef class ntl_mat_ZZ(object): def list(self): """ - EXAMPLES: + EXAMPLES:: + sage: m = ntl.mat_ZZ(3, 4, range(12)); m [ [0 1 2 3] @@ -345,7 +356,8 @@ cdef class ntl_mat_ZZ(object): """ Return the determinant of self. - EXAMPLES: + EXAMPLES:: + sage: ntl.mat_ZZ(8,8,[3..66]).determinant() 0 sage: ntl.mat_ZZ(2,5,range(10)).determinant() @@ -428,7 +440,8 @@ cdef class ntl_mat_ZZ(object): Find the characteristic polynomial of self, and return it as an NTL ZZX. - EXAMPLES: + EXAMPLES:: + sage: M = ntl.mat_ZZ(2,2,[1,2,3,4]) sage: M.charpoly() [-2 -5 1] @@ -476,7 +489,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.BKZ_FP(); a @@ -545,7 +559,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.BKZ_QP(); a @@ -614,7 +629,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.BKZ_QP1(); a @@ -683,7 +699,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.BKZ_XD(); a @@ -752,7 +769,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.BKZ_RR(); a @@ -821,7 +839,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.G_BKZ_FP(); a @@ -890,7 +909,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.G_BKZ_QP(); a @@ -959,7 +979,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.G_BKZ_QP1(); a @@ -1028,7 +1049,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.G_BKZ_XD(); a @@ -1097,7 +1119,8 @@ cdef class ntl_mat_ZZ(object): prune -- see above (default: 0) verbose -- print verbose output (default: False) - EXAMPLES: + EXAMPLES:: + sage: A = Matrix(ZZ,5,5,range(25)) sage: a = A._ntl_() sage: a.G_BKZ_RR(); a @@ -1185,7 +1208,8 @@ cdef class ntl_mat_ZZ(object): above and U is an optional return value if return_U is True. - EXAMPLES: + EXAMPLES:: + sage: M=ntl.mat_ZZ(3,3,[1,2,3,4,5,6,7,8,9]) sage: M.LLL() (2, 54) @@ -1270,7 +1294,8 @@ cdef class ntl_mat_ZZ(object): (rank,[U]) where rank and U are as described above and U is an optional return value if return_U is True. - EXAMPLES: + EXAMPLES:: + sage: M=ntl.mat_ZZ(3,3,[1,2,3,4,5,6,7,8,9]) sage: M.LLL_FP() 2 @@ -1318,7 +1343,8 @@ cdef class ntl_mat_ZZ(object): Performs the same reduction as \code{self.LLL_FP} using the same calling conventions but with quad float precision. - EXAMPLES: + EXAMPLES:: + sage: M=ntl.mat_ZZ(3,3,[1,2,3,4,5,6,7,8,9]) sage: M.LLL_QP(delta=0.75) 2 @@ -1342,7 +1368,8 @@ cdef class ntl_mat_ZZ(object): same calling conventions but with extended exponent double precision. - EXAMPLES: + EXAMPLES:: + sage: M=ntl.mat_ZZ(3,3,[1,2,3,4,5,6,7,8,9]) sage: M.LLL_XD(delta=0.75) 2 @@ -1366,7 +1393,8 @@ cdef class ntl_mat_ZZ(object): same calling conventions but with arbitrary precision floating point numbers. - EXAMPLES: + EXAMPLES:: + sage: M=ntl.mat_ZZ(3,3,[1,2,3,4,5,6,7,8,9]) sage: M.LLL_RR(delta=0.75) 2 diff --git a/src/sage/libs/ppl.pyx b/src/sage/libs/ppl.pyx index aee9be89b65..16e89ea17e6 100644 --- a/src/sage/libs/ppl.pyx +++ b/src/sage/libs/ppl.pyx @@ -22,6 +22,11 @@ C++ excerpt: translates into:: sage: from sage.libs.ppl import Variable, Constraint_System, C_Polyhedron + doctest:warning + ... + DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + See http://trac.sagemath.org/23024 for details. sage: x = Variable(0) sage: y = Variable(1) sage: cs = Constraint_System() @@ -135,6 +140,9 @@ AUTHORS: - Volker Braun (2010-10-08): initial version. - Risan (2012-02-19): extension for MIP_Problem class +- Vincent Klein (2017-12-21) : Deprecate this module. + Future change should be done in the standalone package pplpy + (https://github.com/videlec/pplpy). """ #***************************************************************************** @@ -146,7 +154,7 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function - +from sage.misc.superseded import deprecation from cysignals.signals cimport sig_on, sig_off from sage.structure.sage_object cimport SageObject @@ -158,6 +166,10 @@ from sage.rings.rational cimport Rational from libcpp cimport bool as cppbool from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE +deprecation(23024, "The Sage wrappers around ppl are now superseded " + + "by the standalone pplpy. Please use import 'ppl' instead" + + " of 'sage.libs.ppl'.") + #################################################### # Potentially expensive operations: # - compute dual description @@ -175,7 +187,6 @@ cdef extern from "ppl.hh" namespace "Parma_Polyhedra_Library": # but with PPL's rounding the gsl will be very unhappy; must turn off! restore_pre_PPL_rounding() - #################################################### # Cython does not support ctypedef within cppclass; Hack around this restriction: cdef extern from "ppl.hh" namespace "Parma_Polyhedra_Library::Generator": @@ -2988,6 +2999,10 @@ cdef class Polyhedron(_mutable_or_immutable): sage: from sage.tests.cmdline import test_executable sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd], timeout=100) # long time, indirect doctest sage: print(err) # long time + /... DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + See http://trac.sagemath.org/23024 for details. + ... space_dim 2 -ZE -EM +CM +GM +CS +GS -CP -GP -SC +SG con_sys (up-to-date) @@ -3941,6 +3956,10 @@ cdef class Variables_Set(object): sage: from sage.tests.cmdline import test_executable sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd], timeout=100) # long time, indirect doctest sage: print(err) # long time + /... DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + See http://trac.sagemath.org/23024 for details. + ... variables( 1 ) 123 @@ -4225,6 +4244,10 @@ cdef class Linear_Expression(object): sage: from sage.tests.cmdline import test_executable sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd], timeout=100) # long time, indirect doctest sage: print(err) # long time + /... DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + See http://trac.sagemath.org/23024 for details. + ... size 3 1 3 2 """ self.thisptr.ascii_dump() @@ -5119,6 +5142,10 @@ cdef class Generator(object): sage: from sage.tests.cmdline import test_executable sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd], timeout=100) # long time, indirect doctest sage: print(err) # long time + /... DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + See http://trac.sagemath.org/23024 for details. + ... size 3 1 3 2 P (C) """ self.thisptr.ascii_dump() @@ -5420,6 +5447,10 @@ cdef class Generator_System(_mutable_or_immutable): sage: from sage.tests.cmdline import test_executable sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd], timeout=100) # long time, indirect doctest sage: print(err) # long time + /... DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + See http://trac.sagemath.org/23024 for details. + ... topology NECESSARILY_CLOSED 1 x 2 SPARSE (sorted) index_first_pending 1 @@ -6108,6 +6139,10 @@ cdef class Constraint(object): sage: from sage.tests.cmdline import test_executable sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd], timeout=100) # long time, indirect doctest sage: print(err) # long time + /... DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + See http://trac.sagemath.org/23024 for details. + ... size 4 1 3 2 -1 > (NNC) """ self.thisptr.ascii_dump() @@ -6454,6 +6489,9 @@ cdef class Constraint_System(object): sage: from sage.tests.cmdline import test_executable sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd], timeout=100) # long time, indirect doctest sage: print(err) # long time + /... DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + ... topology NOT_NECESSARILY_CLOSED 1 x 2 SPARSE (sorted) index_first_pending 1 @@ -6805,6 +6843,10 @@ cdef class Poly_Gen_Relation(object): sage: from sage.tests.cmdline import test_executable sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd], timeout=100) # long time, indirect doctest sage: print(err) # long time + /... DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + See http://trac.sagemath.org/23024 for details. + ... NOTHING """ self.thisptr.ascii_dump() @@ -7055,6 +7097,10 @@ cdef class Poly_Con_Relation(object): sage: from sage.tests.cmdline import test_executable sage: (out, err, ret) = test_executable(['sage', '-c', sage_cmd], timeout=100) # long time, indirect doctest sage: print(err) # long time + /... DeprecationWarning: The Sage wrappers around ppl are now superseded by the standalone pplpy. + Please use import 'ppl' instead of 'sage.libs.ppl'. + See http://trac.sagemath.org/23024 for details. + ... NOTHING """ self.thisptr.ascii_dump() diff --git a/src/sage/libs/pynac/constant.pyx b/src/sage/libs/pynac/constant.pyx index f05941e6f08..48ce02fc594 100644 --- a/src/sage/libs/pynac/constant.pyx +++ b/src/sage/libs/pynac/constant.pyx @@ -27,7 +27,7 @@ cdef class PynacConstant: """ Creates a constant in Pynac. - EXAMPLES: + EXAMPLES:: sage: from sage.libs.pynac.constant import PynacConstant sage: f = PynacConstant('foo', 'foo', 'real') diff --git a/src/sage/libs/pynac/pynac.pxd b/src/sage/libs/pynac/pynac.pxd index f6eb0cdb0ea..94d5e3fb1a8 100644 --- a/src/sage/libs/pynac/pynac.pxd +++ b/src/sage/libs/pynac/pynac.pxd @@ -28,7 +28,7 @@ Check that we can externally cimport this (:trac:`18825`):: # http://www.gnu.org/licenses/ #***************************************************************************** -from cpython cimport PyObject +from cpython.object cimport PyObject from libcpp.vector cimport vector from libcpp.pair cimport pair from libcpp.string cimport string as stdstring diff --git a/src/sage/libs/pynac/pynac.pyx b/src/sage/libs/pynac/pynac.pyx index 84e4d17b170..ad398637020 100644 --- a/src/sage/libs/pynac/pynac.pyx +++ b/src/sage/libs/pynac/pynac.pyx @@ -30,7 +30,8 @@ from sage.cpython.string cimport str_to_bytes, char_to_str from sage.arith.all import gcd, lcm, is_prime, factorial, bernoulli -from sage.structure.element cimport Element, parent, coercion_model +from sage.structure.coerce cimport coercion_model +from sage.structure.element cimport Element, parent from sage.misc.persist import loads, dumps from sage.rings.integer_ring import ZZ @@ -1726,7 +1727,7 @@ cdef py_log(x): return math.log(real) elif real < 0: res = gsl_complex_log(gsl_complex_rect(real, 0)) - return PyComplex_FromDoubles(res.dat[0], res.dat[1]) + return PyComplex_FromDoubles(res.real, res.imag) else: return float('-inf') elif type(x) is complex: @@ -1735,7 +1736,7 @@ cdef py_log(x): if real == 0 and imag == 0: return float('-inf') res = gsl_complex_log(gsl_complex_rect(real, imag)) - return PyComplex_FromDoubles(res.dat[0], res.dat[1]) + return PyComplex_FromDoubles(res.real, res.imag) elif isinstance(x, Integer): return x.log().n() elif hasattr(x, 'log'): diff --git a/src/sage/libs/readline.pyx b/src/sage/libs/readline.pyx index e3e7671d117..ba186067c24 100644 --- a/src/sage/libs/readline.pyx +++ b/src/sage/libs/readline.pyx @@ -10,9 +10,9 @@ EXAMPLES:: sage: from sage.libs.readline import * sage: replace_line('foobar', 0) sage: set_point(3) - sage: print('current line: ' + repr(copy_text(0, get_end()))) + sage: print('current line:', repr(copy_text(0, get_end()))) current line: 'foobar' - sage: print('cursor position: {}'.format(get_point())) + sage: print('cursor position:', get_point()) cursor position: 3 When printing with :class:`interleaved_output` the prompt and current @@ -20,8 +20,9 @@ line is removed:: sage: with interleaved_output(): ....: print('output') - ....: print('current line: ' + repr(copy_text(0, get_end()))) - ....: print('cursor position: {}'.format(get_point())) + ....: print('current line: ', + ....: repr(copy_text(0, get_end()))) + ....: print('cursor position:', get_point()) output current line: '' cursor position: 0 @@ -29,9 +30,9 @@ line is removed:: After the interleaved output, the line and cursor is restored to the old value:: - sage: print('current line: ' + repr(copy_text(0, get_end()))) + sage: print('current line:', repr(copy_text(0, get_end()))) current line: 'foobar' - sage: print('cursor position: {}'.format(get_point())) + sage: print('cursor position:', get_point()) cursor position: 3 Finally, clear the current line for the remaining doctests:: @@ -49,6 +50,7 @@ Finally, clear the current line for the remaining doctests:: # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function +from sage.cpython.string cimport str_to_bytes, bytes_to_str cdef extern from 'readline/readline.h': @@ -206,7 +208,7 @@ def copy_text(pos_start, pos_end): sage: copy_text(1, 5) 'ooba' """ - return rl_copy_text(pos_start, pos_end) + return bytes_to_str(rl_copy_text(pos_start, pos_end)) def replace_line(text, clear_undo): """ @@ -228,7 +230,7 @@ def replace_line(text, clear_undo): sage: copy_text(1, 5) 'ooba' """ - rl_replace_line(text, clear_undo) + rl_replace_line(str_to_bytes(text), clear_undo) def initialize(): """ diff --git a/src/sage/libs/singular/decl.pxd b/src/sage/libs/singular/decl.pxd index 7f09aafd9ec..0c2848eb166 100644 --- a/src/sage/libs/singular/decl.pxd +++ b/src/sage/libs/singular/decl.pxd @@ -637,6 +637,7 @@ cdef extern from "singular/Singular/libsingular.h": # divide monomial p by monomial q, p,q const poly *pMDivide(poly *p,poly *q) + poly *p_MDivide(poly *p, poly *q, ring *r) # return the i-th power of p; p destroyed, requires global ring diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index a7dcf952b30..d6829795d5d 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -72,12 +72,14 @@ cdef int singular_polynomial_add(poly **ret, poly *p, poly *q, ring *r): sage: x + P(0) x """ - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) p = p_Copy(p, r) q = p_Copy(q, r) ret[0] = p_Add_q(p, q, r) return 0; + cdef int singular_polynomial_sub(poly **ret, poly *p, poly *q, ring *r): """ ``ret[0] = p-q`` where ``p`` and ``p`` in ``r``. @@ -98,7 +100,8 @@ cdef int singular_polynomial_sub(poly **ret, poly *p, poly *q, ring *r): sage: x + P(0) x """ - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) p = p_Copy(p, r) q = p_Copy(q, r) ret[0] = p_Add_q(p, p_Neg(q, r), r) @@ -124,7 +127,8 @@ cdef int singular_polynomial_rmul(poly **ret, poly *p, RingElement n, ring *r): sage: P(0)*x 0 """ - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) cdef number *_n = sa2si(n, r) ret[0] = pp_Mult_nn(p, _n, r) n_Delete(&_n, r) @@ -248,7 +252,8 @@ cdef int singular_polynomial_cmp(poly *p, poly *q, ring *r): cdef number *h cdef int ret = 0 - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) # handle special cases first (slight slowdown, as special cases # are - well - special @@ -303,7 +308,8 @@ cdef int singular_polynomial_mul(poly** ret, poly *p, poly *q, ring *r) except - sage: x * P(0) 0 """ - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) cdef unsigned long le = p_GetMaxExp(p, r) cdef unsigned long lr = p_GetMaxExp(q, r) cdef unsigned long esum = le + lr @@ -377,7 +383,8 @@ cdef int singular_polynomial_pow(poly **ret, poly *p, unsigned long exp, ring *r v = v * exp overflow_check(v, r) - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) cdef int count = singular_polynomial_length_bounded(p,15) if count >= 15 or exp > 15: sig_on() @@ -407,10 +414,12 @@ cdef int singular_polynomial_neg(poly **ret, poly *p, ring *r): sage: -P(0) 0 """ - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) ret[0] = p_Neg(p_Copy(p,r),r) return 0 + cdef object singular_polynomial_str(poly *p, ring *r): """ Return the string representation of ``p``. @@ -428,7 +437,8 @@ cdef object singular_polynomial_str(poly *p, ring *r): sage: str(10*x) '10*x' """ - if(r!=currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) s = bytes_to_str(p_String(p, r, r)) s = plusminus_pattern.sub("\\1 \\2 ", s) @@ -460,6 +470,17 @@ cdef object singular_polynomial_latex(poly *p, ring *r, object base, object late sage: P. = K[] sage: latex((z+1)*v*w - z*w^2 + z*v + z^2*w + z + 1) \left(z + 1\right) v w - z w^{2} + z v + \left(-z - 1\right) w + z + 1 + + Demonstrate that there are no extra blanks in latex expression of multivariate + polynomial (:trac:`12908`):: + + sage: R. = ZZ[] + sage: latex(X-Y) + X - Y + sage: latex(X^2-X) + X^{2} - X + sage: latex(-Y^2-Y) + -Y^{2} - Y """ poly = "" cdef unsigned long e @@ -483,7 +504,7 @@ cdef object singular_polynomial_latex(poly *p, ring *r, object base, object late multi = latex(c) elif c != 1: if c == -1: - multi = "- %s"%(multi) + multi = "-%s"%(multi) else: sc = latex(c) # Add parenthesis if the coefficient consists of terms divided by +, - @@ -536,7 +557,8 @@ cdef long singular_polynomial_deg(poly *p, poly *x, ring *r): _deg = -1 if p == NULL: return -1 - if(r != currRing): rChangeCurrRing(r) + if r != currRing: + rChangeCurrRing(r) if x == NULL: while p: _deg = p_WDegree(p,r) @@ -609,7 +631,7 @@ cdef int singular_polynomial_subst(poly **p, int var_index, poly *value, ring *r cdef unsigned long exp = p_GetExp(p[0], var_index+1, r) * p_GetMaxExp(value, r) overflow_check(exp, r) - if(r != currRing): + if r != currRing: rChangeCurrRing(r) cdef int count = singular_polynomial_length_bounded(p[0], 15) diff --git a/src/sage/libs/symmetrica/sb.pxi b/src/sage/libs/symmetrica/sb.pxi index 46c0bc56d97..2a7b7ed6a5c 100644 --- a/src/sage/libs/symmetrica/sb.pxi +++ b/src/sage/libs/symmetrica/sb.pxi @@ -35,7 +35,8 @@ def mult_schubert_schubert_symmetrica(a, b): """ Multiplies the Schubert polynomials a and b. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.mult_schubert_schubert([3,2,1], [3,2,1]) X[5, 3, 1, 2, 4] """ @@ -68,7 +69,8 @@ def t_SCHUBERT_POLYNOM_symmetrica(a): Converts a Schubert polynomial to a 'regular' multivariate polynomial. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.t_SCHUBERT_POLYNOM([3,2,1]) x0^2*x1 """ @@ -97,7 +99,8 @@ def t_POLYNOM_SCHUBERT_symmetrica(a): """ Converts a multivariate polynomial a to a Schubert polynomial. - EXAMPLES: + EXAMPLES:: + sage: R. = QQ[] sage: w0 = x1^2*x2 sage: symmetrica.t_POLYNOM_SCHUBERT(w0) @@ -134,7 +137,8 @@ def mult_schubert_variable_symmetrica(a, i): Returns the product of a and x_i. Note that indexing with i starts at 1. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.mult_schubert_variable([3,2,1], 2) X[3, 2, 4, 1] sage: symmetrica.mult_schubert_variable([3,2,1], 4) @@ -169,7 +173,8 @@ def divdiff_perm_schubert_symmetrica(perm, a): $\delta_i$ to $a$ where $a$ is either a permutation or a Schubert polynomial over QQ. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.divdiff_perm_schubert([2,3,1], [3,2,1]) X[2, 1] sage: symmetrica.divdiff_perm_schubert([3,1,2], [3,2,1]) @@ -215,7 +220,8 @@ def divdiff_perm_schubert_symmetrica(perm, a): def scalarproduct_schubert_symmetrica(a, b): """ - EXAMPLES: + EXAMPLES:: + sage: symmetrica.scalarproduct_schubert([3,2,1], [3,2,1]) X[1, 3, 5, 2, 4] sage: symmetrica.scalarproduct_schubert([3,2,1], [2,1,3]) @@ -251,7 +257,8 @@ def divdiff_schubert_symmetrica(i, a): $\delta_i$ to $a$ where $a$ is either a permutation or a Schubert polynomial over QQ. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.divdiff_schubert(1, [3,2,1]) X[2, 3, 1] sage: symmetrica.divdiff_schubert(2, [3,2,1]) diff --git a/src/sage/libs/symmetrica/schur.pxi b/src/sage/libs/symmetrica/schur.pxi index 4f4f495547a..71edb10b02d 100644 --- a/src/sage/libs/symmetrica/schur.pxi +++ b/src/sage/libs/symmetrica/schur.pxi @@ -63,7 +63,8 @@ def outerproduct_schur_symmetrica(parta, partb): outer tensor product of two irreducibe representations of the symmetric group. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.outerproduct_schur([2],[2]) s[2, 2] + s[3, 1] + s[4] """ @@ -140,7 +141,8 @@ def compute_schur_with_alphabet_symmetrica(part, length, alphabet='x'): partition PART as a POLYNOM erg. The INTEGER length specifies the length of the alphabet. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.compute_schur_with_alphabet(2,2) x0^2 + x0*x1 + x1^2 sage: symmetrica.compute_schur_with_alphabet([2],2) @@ -185,7 +187,8 @@ def compute_homsym_with_alphabet_symmetrica(n, length, alphabet='x'): The INTEGER laenge specifies the length of the alphabet. Both routines are the same. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.compute_homsym_with_alphabet(3,1,'x') x^3 sage: symmetrica.compute_homsym_with_alphabet([2,1],1,'x') @@ -231,7 +234,8 @@ def compute_elmsym_with_alphabet_symmetrica(n, length, alphabet='x'): The INTEGER length specifies the length of the alphabet. Both routines are the same. - EXAMPLES: + EXAMPLES:: + sage: a = symmetrica.compute_elmsym_with_alphabet(2,2); a x0*x1 sage: a.parent() @@ -279,7 +283,8 @@ def compute_monomial_with_alphabet_symmetrica(n, length, alphabet='x'): function labeled by a PARTITION number as a POLYNOM erg. The INTEGER laenge specifies the length of the alphabet. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.compute_monomial_with_alphabet([2,1],2,'x') x0^2*x1 + x0*x1^2 sage: symmetrica.compute_monomial_with_alphabet([1,1,1],2,'x') @@ -325,7 +330,8 @@ def compute_powsym_with_alphabet_symmetrica(n, length, alphabet='x'): or a POW_SYM label as a POLYNOM erg. The INTEGER laenge specifies the length of the alphabet. - EXAMPLES: + EXAMPLES:: + sage: symmetrica.compute_powsym_with_alphabet(2,2,'x') x0^2 + x1^2 sage: symmetrica.compute_powsym_with_alphabet(2,2,'x').parent() @@ -365,7 +371,8 @@ def compute_powsym_with_alphabet_symmetrica(n, length, alphabet='x'): def compute_schur_with_alphabet_det_symmetrica(part, length, alphabet='x'): """ - EXAMPLES: + EXAMPLES:: + sage: symmetrica.compute_schur_with_alphabet_det(2,2) x0^2 + x0*x1 + x1^2 sage: symmetrica.compute_schur_with_alphabet_det([2],2) diff --git a/src/sage/logic/boolformula.py b/src/sage/logic/boolformula.py index c500841cf25..1dc12c486b6 100644 --- a/src/sage/logic/boolformula.py +++ b/src/sage/logic/boolformula.py @@ -1030,16 +1030,16 @@ def satformat(self): # wtd = boolopt.WFFtoDNF() # dnf = wtd(wff) # dnf = wtd.clean(dnf) -# if(dnf == [] or dnf == [[]]): +# if dnf == [] or dnf == [[]]: # exp = self.__vars_order[0] + '&~' + self.__vars_order[0] + ' ' # opt = boolopt.optimize(dnf) -# if(exp == '' and (opt == [] or opt == [[]])): +# if exp == '' and (opt == [] or opt == [[]]): # exp = self.__vars_order[0] + '|~' + self.__vars_order[0] + ' ' -# if(exp == ''): +# if exp == '': # for con in opt: # s = '(' # for prop in con: -# if(prop[0] == 'notprop'): +# if prop[0] == 'notprop': # s += '~' # s += prop[1] + '&' # exp += s[:-1] + ')|' diff --git a/src/sage/logic/logic.py b/src/sage/logic/logic.py index 41f739b273a..4b7fb4baa59 100644 --- a/src/sage/logic/logic.py +++ b/src/sage/logic/logic.py @@ -852,13 +852,13 @@ def tokenize(s, toks): tok = tok_list[6] skip = 3 - if len(tok) > 0: + if tok: toks.append(tok) i += skip continue else: # token is a variable name - if(s[i] == ' '): + if s[i] == ' ': i += 1 continue @@ -866,7 +866,7 @@ def tokenize(s, toks): tok += s[i] i += 1 - if len(tok) > 0: + if tok: if tok[0] not in string.ascii_letters: valid = 0 for c in tok: diff --git a/src/sage/manifolds/calculus_method.py b/src/sage/manifolds/calculus_method.py index 3d7b1550fb2..4621f1397f1 100644 --- a/src/sage/manifolds/calculus_method.py +++ b/src/sage/manifolds/calculus_method.py @@ -100,16 +100,17 @@ def _Sympy_to_SR(expression): """ try: return SR(expression) - except: + except Exception: # If SR cannot transform a sympy expression is because it is a # sympy abstract function. a = expression._sage_() # As all sage objects have a ._sage_ operator, they have to be # catched - if type(a) == type(expression): + if type(a) is type(expression): raise TypeError return a + class CalculusMethod(SageObject): r""" Control of calculus methods used on coordinate charts of manifolds. diff --git a/src/sage/manifolds/chart_func.py b/src/sage/manifolds/chart_func.py index 4fe5dc7bc85..02bee67d7ef 100644 --- a/src/sage/manifolds/chart_func.py +++ b/src/sage/manifolds/chart_func.py @@ -2807,8 +2807,8 @@ def __eq__(self, other): return False if other._nf != self._nf: return False - return all([other._functions[i] == self._functions[i] - for i in range(self._nf)]) + return all(other._functions[i] == self._functions[i] + for i in range(self._nf)) def __ne__(self, other): r""" diff --git a/src/sage/manifolds/differentiable/integrated_curve.py b/src/sage/manifolds/differentiable/integrated_curve.py index 861db99c421..23fa8332647 100644 --- a/src/sage/manifolds/differentiable/integrated_curve.py +++ b/src/sage/manifolds/differentiable/integrated_curve.py @@ -1715,7 +1715,7 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, # unfortunately building the tangent space is too # slow, so we have to cheat a little and apply the # change of frame manually (with a precompiled - # fonction) + # function) new_vel = self._fast_changes_of_frame[(new_chart.frame().restrict(inter), chart.frame().restrict(inter))](last_pts, last_vel) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 5a3a3489211..33a9d63926e 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -3727,7 +3727,7 @@ def laplacian(self, metric=None): In the present case (Euclidean metric and Cartesian coordinates), the components of the Laplacian are the Laplacians of the components:: - sage: all([Dv[[i]] == laplacian(v[[i]]) for i in M.irange()]) + sage: all(Dv[[i]] == laplacian(v[[i]]) for i in M.irange()) True The Laplacian can be taken with respect to a metric tensor that is diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index 72b80d33e2d..3b8637b5cee 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -1550,8 +1550,8 @@ def contract(self, *args): Check:: - sage: all([s[ind] == sum(a[k, ind[0]]*b[ind[1], k] for k in [0..1]) - ....: for ind in M.index_generator(2)]) + sage: all(s[ind] == sum(a[k, ind[0]]*b[ind[1], k] for k in [0..1]) + ....: for ind in M.index_generator(2)) True The same contraction with repeated index notation:: @@ -1569,8 +1569,8 @@ def contract(self, *args): Check:: - sage: all([s[ind] == sum(a[ind[0], k]*b[ind[1], k] for k in [0..1]) - ....: for ind in M.index_generator(2)]) + sage: all(s[ind] == sum(a[ind[0], k]*b[ind[1], k] for k in [0..1]) + ....: for ind in M.index_generator(2)) True The same contraction with repeated index notation:: @@ -1622,8 +1622,8 @@ def __mul__(self, other): a*v = -(x + 1)*y d/dx*dx*dx - 2*y d/dx*dx*dy - y^2 d/dx*dy*dx + x^2*y d/dx*dy*dy + (x^2 + x) d/dy*dx*dx + 2*x d/dy*dx*dy + x*y d/dy*dy*dx - x^3 d/dy*dy*dy - sage: all([s[ind] == v[ind[0]] * a[ind[1],ind[2]] - ....: for ind in M.index_generator(3)]) + sage: all(s[ind] == v[ind[0]] * a[ind[1],ind[2]] + ....: for ind in M.index_generator(3)) True Multiplication on the right by a scalar field:: diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 7d7a5af68bf..d0963d43f90 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -24,7 +24,7 @@ """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # Copyright (C) 2016 Travis Scrimshaw @@ -33,8 +33,8 @@ # 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 six import itervalues @@ -42,6 +42,7 @@ from sage.symbolic.expression import Expression from sage.manifolds.chart_func import ChartFunction + class ScalarField(CommutativeAlgebraElement): r""" Scalar field on a topological manifold. @@ -1575,28 +1576,6 @@ def coord_function(self, chart=None, from_chart=None): self._del_derived() return self._express[chart] - def function_chart(self, chart=None, from_chart=None): - r""" - Deprecated. - - Use :meth:`coord_function` instead. - - EXAMPLES:: - - sage: M = Manifold(2, 'M', structure='topological') - sage: c_xy. = M.chart() - sage: f = M.scalar_field(x*y^2) - sage: fc = f.function_chart() - doctest:...: DeprecationWarning: Use coord_function() instead. - See http://trac.sagemath.org/18640 for details. - sage: fc - x*y^2 - - """ - from sage.misc.superseded import deprecation - deprecation(18640, 'Use coord_function() instead.') - return self.coord_function(chart=chart, from_chart=from_chart) - def expr(self, chart=None, from_chart=None): r""" Return the coordinate expression of the scalar field in a given diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index b9cd15cb307..e43d7b58937 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -65,7 +65,7 @@ import operator from .matrix_space import MatrixSpace, is_MatrixSpace from sage.modules.free_module import FreeModule, is_FreeModule -from sage.structure.element cimport coercion_model +from sage.structure.coerce cimport coercion_model cdef class MatrixMulAction(Action): diff --git a/src/sage/matrix/all.py b/src/sage/matrix/all.py index 6383b0ca73b..ff184edde52 100644 --- a/src/sage/matrix/all.py +++ b/src/sage/matrix/all.py @@ -1,4 +1,15 @@ +""" +Test for deprecations of imports into global namespace:: + + sage: berlekamp_massey + doctest:warning...: + DeprecationWarning: + Importing berlekamp_massey from here is deprecated. If you need to use it, please import it directly from sage.matrix.berlekamp_massey + See https://trac.sagemath.org/27066 for details. + +""" from __future__ import absolute_import + from sage.misc.lazy_import import lazy_import from .matrix_space import MatrixSpace @@ -6,8 +17,12 @@ diagonal_matrix, identity_matrix, block_matrix, block_diagonal_matrix, jordan_block, zero_matrix, ones_matrix, elementary_matrix, companion_matrix) -from .berlekamp_massey import berlekamp_massey + +lazy_import("sage.matrix.berlekamp_massey", 'berlekamp_massey', + deprecation=27066) lazy_import('sage.matrix.joint_spectral_radius', 'joint_spectral_radius') Mat = MatrixSpace + +del absolute_import diff --git a/src/sage/matrix/args.pyx b/src/sage/matrix/args.pyx index e6a383ae608..514b5f2f879 100644 --- a/src/sage/matrix/args.pyx +++ b/src/sage/matrix/args.pyx @@ -24,9 +24,9 @@ from cypari2.types cimport typ, t_MAT, t_VEC, t_COL, t_VECSMALL, t_LIST, t_STR, from .matrix_space import MatrixSpace from sage.rings.all import ZZ, RDF, CDF -from sage.structure.coerce cimport is_numpy_type, py_scalar_parent -from sage.structure.element cimport (coercion_model, - Element, RingElement, coercion_model) +from sage.structure.coerce cimport (coercion_model, + is_numpy_type, py_scalar_parent) +from sage.structure.element cimport Element, RingElement from sage.arith.long cimport pyobject_to_long from sage.misc.misc_c import sized_iter from sage.categories import monoids @@ -1161,6 +1161,29 @@ cdef class MatrixArgs: change ``self.entries``. If the entries are invalid, return ``MA_ENTRIES_UNKNOWN``. + + TESTS: + + Check that :trac:`26655` is fixed:: + + sage: F. = GF(9) + sage: M = MatrixSpace(F, 2, 2) + sage: A = M([[1, a], [0, 1]]) + sage: M(pari(A)) + [1 a] + [0 1] + + Constructing a matrix from a PARI ``t_VEC`` or ``t_COL`` with + ``t_VEC`` or ``t_COL`` elements is currently not supported:: + + sage: M(pari([1, a, 0, 1])) + Traceback (most recent call last): + ... + NameError: name 'a' is not defined + sage: M(pari([[1, a], [0, 1]])) + Traceback (most recent call last): + ... + NameError: name 'a' is not defined """ # Check basic Python types. This is very fast, so it doesn't # hurt to do these first. @@ -1204,7 +1227,12 @@ cdef class MatrixArgs: if isinstance(self.entries, Gen): # PARI object t = typ((self.entries).g) if t == t_MAT: - self.entries = self.entries.Col().sage() + R = self.base + if R is None: + self.entries = self.entries.Col().sage() + else: + self.entries = [[R(x) for x in v] + for v in self.entries.mattranspose()] return MA_ENTRIES_SEQ_SEQ elif t in [t_VEC, t_COL, t_VECSMALL, t_LIST]: self.entries = self.entries.sage() diff --git a/src/sage/matrix/berlekamp_massey.py b/src/sage/matrix/berlekamp_massey.py index 9547534e2e1..3f37d48fed8 100644 --- a/src/sage/matrix/berlekamp_massey.py +++ b/src/sage/matrix/berlekamp_massey.py @@ -39,21 +39,18 @@ def berlekamp_massey(a): INPUT: - - - ``a`` - a list of even length of elements of a field + - ``a`` -- a list of even length of elements of a field (or domain) - OUTPUT: - - - ``Polynomial`` - the minimal polynomial of the + - ``Polynomial`` -- the minimal polynomial of the sequence (as a polynomial over the field in which the entries of a live) - EXAMPLES:: + sage: from sage.matrix.berlekamp_massey import berlekamp_massey sage: berlekamp_massey([1,2,1,2,1,2]) x^2 - 1 sage: berlekamp_massey([GF(7)(1),19,1,19]) diff --git a/src/sage/matrix/change_ring.pyx b/src/sage/matrix/change_ring.pyx index 7d8ad3fe133..76e7275d5ec 100644 --- a/src/sage/matrix/change_ring.pyx +++ b/src/sage/matrix/change_ring.pyx @@ -21,7 +21,8 @@ def integer_to_real_double_dense(Matrix_integer_dense A): OUTPUT: -- a dense real double matrix - EXAMPLES: + EXAMPLES:: + sage: a = matrix(ZZ,2,3,[-2,-5,3,4,8,1030339830489349908]) sage: a.change_ring(RDF) [ -2.0 -5.0 3.0] diff --git a/src/sage/matrix/compute_J_ideal.py b/src/sage/matrix/compute_J_ideal.py index 811b57c0299..d2dee2d1e9c 100644 --- a/src/sage/matrix/compute_J_ideal.py +++ b/src/sage/matrix/compute_J_ideal.py @@ -345,9 +345,9 @@ def __init__(self, B): self._B = B self._D = B.base_ring() X = polygen(self._D) - adjoint = (X - B).adjoint() + adjugate = (X - B).adjugate() d = B.nrows()**2 - b = matrix(d, 1, adjoint.list()) + b = matrix(d, 1, adjugate.list()) self.chi_B = B.charpoly(X) self.mu_B = B.minimal_polynomial() self._A = matrix.block([[b , -self.chi_B*matrix.identity(d)]]) @@ -549,7 +549,7 @@ def mccoy_column(self, p, t, nu): sage: x = polygen(ZZ, 'x') sage: nu_4 = x^2 + 3*x + 2 sage: g = C.mccoy_column(2, 2, nu_4) - sage: b = matrix(9, 1, (x-B).adjoint().list()) + sage: b = matrix(9, 1, (x-B).adjugate().list()) sage: M = matrix.block([[b , -B.charpoly(x)*matrix.identity(9)]]) sage: (M*g % 4).is_zero() True diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 6e9d1244b74..04d2ecfca48 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -23,7 +23,7 @@ from __future__ import absolute_import from cpython cimport * import sage.modules.free_module -from sage.structure.element cimport coercion_model +from sage.structure.coerce cimport coercion_model cdef class Matrix(Matrix0): @@ -291,9 +291,7 @@ cdef class Matrix(Matrix0): EXAMPLES: - We first coerce a square matrix. - - :: + We first coerce a square matrix. :: sage: A = MatrixSpace(QQ,3)([1,2,3,4/3,5/3,6/4,7,8,9]) sage: B = magma(A); B # (indirect doctest) optional - magma @@ -306,9 +304,7 @@ cdef class Matrix(Matrix0): Full Matrix Algebra of degree 3 over Rational Field We coerce a non-square matrix over - `\ZZ/8\ZZ`. - - :: + `\ZZ/8\ZZ`. :: sage: A = MatrixSpace(Integers(8),2,3)([-1,2,3,4,4,-2]) sage: B = magma(A); B # optional - magma @@ -319,16 +315,12 @@ cdef class Matrix(Matrix0): sage: B.Parent() # optional - magma Full RMatrixSpace of 2 by 3 matrices over IntegerRing(8) - :: - sage: R. = QQ[] sage: A = MatrixSpace(R,2,2)([x+y,x-1,y+5,x*y]) sage: B = magma(A); B # optional - magma [x + y x - 1] [y + 5 x*y] - :: - sage: R. = ZZ[] sage: A = MatrixSpace(R,2,2)([x+y,x-1,y+5,x*y]) sage: B = magma(A); B # optional - magma @@ -336,9 +328,7 @@ cdef class Matrix(Matrix0): [y + 5 x*y] We coerce a matrix over a cyclotomic field, where the generator - must be named during the coercion. - - :: + must be named during the coercion. :: sage: K = CyclotomicField(9) ; z = K.0 sage: M = matrix(K,3,3,[0,1,3,z,z**4,z-1,z**17,1,0]) @@ -352,10 +342,27 @@ cdef class Matrix(Matrix0): [-zeta9^5 - zeta9^2 1 0] sage: magma(M**2) == magma(M)**2 # optional - magma True + + One sparse matrix:: + + sage: M = matrix(QQ,2,2,[4,6,55,0],sparse=True) + sage: T = magma(M); T # optional - magma + Sparse matrix with 2 rows and 2 columns over Rational Field + sage: T.Determinant() # optional - magma + -330 """ - P = magma(self.parent()) - v = [x._magma_init_(magma) for x in self.list()] - return '%s![%s]'%(P.name(), ','.join(v)) + if self.is_sparse(): + R = magma(self.base_ring()) + s = "SparseMatrix({}, {}, {}, [" + s = s.format(R.name(), self.nrows(), self.ncols()) + entries = ("<{}, {}, {}>".format(ij[0] + 1, ij[1] + 1, + mij._magma_init_(magma)) + for ij, mij in self.dict().items()) + return s + ', '.join(entries) + "])" + else: + P = magma(self.parent()) + v = [x._magma_init_(magma) for x in self.list()] + return '%s![%s]' % (P.name(), ','.join(v)) def _maple_init_(self): """ @@ -442,7 +449,7 @@ cdef class Matrix(Matrix0): """ Returns a string defining a Scilab representation of self. - EXAMPLES: + EXAMPLES:: sage: a = matrix([[1,2,3],[4,5,6],[7,8,9]]); a [1 2 3] @@ -471,7 +478,7 @@ cdef class Matrix(Matrix0): """ Creates a ScilabElement object based on self and returns it. - EXAMPLES: + EXAMPLES:: sage: a = matrix([[1,2,3],[4,5,6],[7,8,9]]); a [1 2 3] diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index e0e12eb16ee..9c76d51b01e 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -7,28 +7,22 @@ AUTHORS: - William Stein: initial version -- Miguel Marco (2010-06-19): modified eigenvalues and eigenvectors functions to - allow the option extend=False +- Sebastian Pancratz (2009-06-12): implemented ``adjoint`` and ``charpoly`` methods -- Rob Beezer (2011-02-05): refactored all of the matrix kernel routines +- Sebastian Pancratz (2009-06-25): fixed ``adjoint`` reflecting the change that + ``_adjoint`` is now implemented in :class:`Matrix` -TESTS:: +- Sebastian Pancratz (2009-06-25): use the division-free algorithm for ``charpoly`` + +- Miguel Marco (2010-06-19): modified eigenvalues and eigenvectors functions to + allow the option ``extend=False`` - sage: m = matrix(ZZ['x'], 2, 3, [1..6]) - sage: TestSuite(m).run() +- Thierry Monteil (2010-10-05): Bugfix for :trac:`10063`, so that the + determinant is computed even for rings for which the ``is_field`` method is not + implemented. -Check that a pair consisting of a matrix and its echelon form is -pickled correctly (this used to give a wrong answer due to a Python -bug, see :trac:`17527`):: +- Rob Beezer (2011-02-05): refactored all of the matrix kernel routines - sage: K. = FractionField(QQ['x']) - sage: m = Matrix([[1], [x]]) - sage: t = (m, m.echelon_form()) - sage: loads(dumps(t)) - ( - [1] [1] - [x], [0] - ) """ #***************************************************************************** @@ -47,8 +41,9 @@ from cysignals.signals cimport sig_check from sage.misc.randstate cimport randstate, current_randstate from sage.structure.coerce cimport py_scalar_parent from sage.structure.sequence import Sequence +from sage.structure.coerce cimport coercion_model from sage.structure.element import is_Vector -from sage.structure.element cimport have_same_parent, coercion_model +from sage.structure.element cimport have_same_parent from sage.misc.misc import verbose, get_verbose from sage.rings.ring import is_Ring from sage.rings.number_field.number_field_base import is_NumberField @@ -69,8 +64,31 @@ from . import berlekamp_massey from sage.modules.free_module_element import is_FreeModuleElement from sage.matrix.matrix_misc import permanental_minor_polynomial +# used to deprecate only adjoint method +from sage.misc.superseded import deprecated_function_alias cdef class Matrix(Matrix1): + """ + Base class for matrices, part 2 + + TESTS:: + + sage: m = matrix(ZZ['x'], 2, 3, [1..6]) + sage: TestSuite(m).run() + + Check that a pair consisting of a matrix and its echelon form is + pickled correctly (this used to give a wrong answer due to a Python + bug, see :trac:`17527`):: + + sage: K. = FractionField(QQ['x']) + sage: m = Matrix([[1], [x]]) + sage: t = (m, m.echelon_form()) + sage: loads(dumps(t)) + ( + [1] [1] + [x], [0] + ) + """ def _backslash_(self, B): r""" Used to compute `A \backslash B`, i.e., the backslash solver @@ -1486,7 +1504,7 @@ cdef class Matrix(Matrix1): If the base ring has a method :meth:`_matrix_determinant`, we call it. - Otherwise, for small matrices (n less than 4), this is computed using the + Otherwise, for small matrices (n less than 4), this is computed using the naive formula. In the specific case of matrices over the integers modulo a non-prime, the determinant of a lift is computed over the integers. In general, the characteristic polynomial is computed either using @@ -1584,14 +1602,6 @@ cdef class Matrix(Matrix1): sage: A.determinant() == B.determinant() True - AUTHORS: - - - Unknown: No author specified in the file from 2009-06-25 - - Sebastian Pancratz (2009-06-25): Use the division-free - algorithm for charpoly - - Thierry Monteil (2010-10-05): Bugfix for :trac:`10063`, - so that the determinant is computed even for rings for which - the is_field method is not implemented. """ from sage.rings.finite_rings.integer_mod_ring import is_IntegerModRing @@ -2327,10 +2337,6 @@ cdef class Matrix(Matrix1): sage: A._cache['charpoly'] x^2 - 3.00000000000000*x - 2.00000000000000 - AUTHORS: - - - Unknown: No author specified in the file from 2009-06-25 - - Sebastian Pancratz (2009-06-25): Include the division-free algorithm """ f = self.fetch('charpoly') @@ -2425,14 +2431,11 @@ cdef class Matrix(Matrix1): The key feature of this implementation is that it is division-free. This means that it can be used as a generic implementation for any ring (commutative and with multiplicative identity). The algorithm - is described in full detail as Algorithm 3.1 in [Se02]_. + is described in full detail as Algorithm 3.1 in [Sei2002]_. Note that there is a missing minus sign in front of the last term in the penultimate line of Algorithm 3.1. - AUTHORS: - - - Sebastian Pancratz (2009-06-12) """ # Validate assertions @@ -5493,10 +5496,10 @@ cdef class Matrix(Matrix1): Next we compute the left eigenspaces over the finite field of order 11. :: sage: A = ModularSymbols(43, base_ring=GF(11), sign=1).T(2).matrix(); A - [ 3 9 0 0] - [ 0 9 0 1] - [ 0 10 9 2] - [ 0 9 0 2] + [ 3 0 9 0] + [ 0 9 0 10] + [ 0 0 10 1] + [ 0 0 1 1] sage: A.base_ring() Finite Field of size 11 sage: A.charpoly() @@ -5505,13 +5508,13 @@ cdef class Matrix(Matrix1): [ (9, Vector space of degree 4 and dimension 1 over Finite Field of size 11 User basis matrix: - [0 0 1 5]), + [0 1 5 6]), (3, Vector space of degree 4 and dimension 1 over Finite Field of size 11 User basis matrix: - [1 6 0 6]), + [1 0 1 6]), (beta2, Vector space of degree 4 and dimension 1 over Univariate Quotient Polynomial Ring in beta2 over Finite Field of size 11 with modulus x^2 + 9 User basis matrix: - [ 0 1 0 5*beta2 + 10]) + [ 0 0 1 beta2 + 1]) ] This method is only applicable to exact matrices. @@ -7342,23 +7345,31 @@ cdef class Matrix(Matrix1): sage: all(M.with_permuted_rows_and_columns(*i) == M for i in A) True + + Check that :trac:`25426` is fixed:: + + sage: j = matrix([(3, 2, 1, 0, 0), + ....: (2, 2, 0, 1, 0), + ....: (1, 0, 3, 0, 2), + ....: (0, 1, 0, 2, 1), + ....: (0, 0, 2, 1, 2)]) + sage: j.automorphisms_of_rows_and_columns() + [((), ()), ((1,3)(2,5), (1,3)(2,5))] """ from sage.groups.perm_gps.permgroup_element import \ PermutationGroupElement B = self.as_bipartite_graph() nrows = self.nrows() ncols = self.ncols() - parts = [list(range(1, nrows + 1)), - list(range(nrows + 1, nrows + ncols + 1))] - A = B.automorphism_group(partition=parts, edge_labels=True) + A = B.automorphism_group(edge_labels=True) + + # Convert to elements of Sym(self) from S_n permutations = [] for p in A: - p = p.domain() - # Convert to elements of Sym(self) from S_n - if p[0] <= nrows: + if p(1) <= nrows: # Check that rows are mapped to rows permutations.append( - (PermutationGroupElement(p[:nrows]), - PermutationGroupElement([elt - nrows for elt in p[nrows:]]) + (PermutationGroupElement([p(1 + i) for i in range(nrows)]), + PermutationGroupElement([p(1 + nrows + i) - nrows for i in range(ncols)]) )) return permutations @@ -8856,30 +8867,22 @@ cdef class Matrix(Matrix1): """ return ~self - def adjoint(self): - """ - Returns the adjoint matrix of self (matrix of cofactors). - - OUTPUT: - - - ``N`` - the adjoint matrix, such that - N \* M = M \* N = M.parent(M.det()) - - ALGORITHM: - - Use PARI whenever the method ``self._adjoint`` is included to do so - in an inheriting class. Otherwise, use a generic division-free - algorithm to compute the characteristic polynomial and hence the - adjoint. + def adjugate(self): + r""" + Return the adjugate matrix of ``self`` (that is, the transpose of the + matrix of cofactors). - The result is cached. + Let `M` be an `n \times n`-matrix. The adjugate matrix of `M` is the `n + \times n`-matrix `N` whose `(i, j)`-th entry is `(-1)^{i + j} + \det(M_{j, i})`, where `M_{j,i}` is the matrix `M` with its `j`-th row + and `i`-th column removed. It is known to satisfy `NM = MN = \det(M)I`. EXAMPLES:: sage: M = Matrix(ZZ,2,2,[5,2,3,4]) ; M [5 2] [3 4] - sage: N = M.adjoint() ; N + sage: N = M.adjugate() ; N [ 4 -2] [-3 5] sage: M * N @@ -8891,38 +8894,56 @@ cdef class Matrix(Matrix1): sage: M = Matrix(QQ,2,2,[5/3,2/56,33/13,41/10]) ; M [ 5/3 1/28] [33/13 41/10] - sage: N = M.adjoint() ; N + sage: N = M.adjugate() ; N [ 41/10 -1/28] [-33/13 5/3] sage: M * N [7363/1092 0] [ 0 7363/1092] - AUTHORS: + An alias is :meth:`adjoint_classical`, which replaces the deprecated + :meth:`adjoint` method:: + + sage: M.adjoint() + ...: DeprecationWarning: adjoint is deprecated. Please use adjugate instead. + See http://trac.sagemath.org/10501 for details. + [ 41/10 -1/28] + [-33/13 5/3] + sage: M.adjoint_classical() + [ 41/10 -1/28] + [-33/13 5/3] + + ALGORITHM: + + Use PARI whenever the method ``self._adjugate`` is included to do so in + an inheriting class. Otherwise, use a generic division-free algorithm + that computes the adjugate matrix from the characteristic polynomial. - - Unknown: No author specified in the file from 2009-06-25 - - Sebastian Pancratz (2009-06-25): Reflecting the change that - ``_adjoint`` is now implemented in this class + The result is cached. """ if self._nrows != self._ncols: - raise ValueError("self must be a square matrix") + raise ValueError("must be a square matrix") - X = self.fetch('adjoint') + X = self.fetch('adjugate') if not X is None: return X - X = self._adjoint() - self.cache('adjoint', X) + X = self._adjugate() + self.cache('adjugate', X) return X - def _adjoint(self): + adjoint = deprecated_function_alias(10501, adjugate) + + adjoint_classical = adjugate + + def _adjugate(self): r""" - Returns the adjoint of self. + Return the adjugate of this matrix. OUTPUT: - - matrix -- the adjoint of self + - matrix -- the adjugate of the matrix EXAMPLES: @@ -8932,7 +8953,7 @@ cdef class Matrix(Matrix1): sage: A [ 1 24] [ 3 5] - sage: A._adjoint() + sage: A._adjugate() [ 5 -24] [ -3 1] @@ -8949,14 +8970,13 @@ cdef class Matrix(Matrix1): [ -2*t^2 + t + 3/2 7*t^2 + 1/2*t - 1 -6*t^2 + t - 2/11] [-7/3*t^2 - 1/2*t - 1/15 -2*t^2 + 19/8*t -10*t^2 + 2*t + 1/2] [ 6*t^2 - 1/2 -1/7*t^2 + 9/4*t -t^2 - 4*t - 1/10] - sage: A._adjoint() + sage: A._adjugate() [ 4/7*t^4 + 1591/56*t^3 - 961/70*t^2 - 109/80*t 55/7*t^4 + 104/7*t^3 + 6123/1540*t^2 - 959/220*t - 1/10 -82*t^4 + 101/4*t^3 + 1035/88*t^2 - 29/22*t - 1/2] [ -187/3*t^4 + 13/6*t^3 + 57/10*t^2 - 79/60*t - 77/300 38*t^4 + t^3 - 793/110*t^2 - 28/5*t - 53/220 -6*t^4 + 44/3*t^3 + 4727/330*t^2 - 1147/330*t - 487/660] [ 37/3*t^4 - 136/7*t^3 - 1777/840*t^2 + 83/80*t 292/7*t^4 + 107/14*t^3 - 323/28*t^2 - 29/8*t + 1/2 61/3*t^4 - 25/12*t^3 - 269/120*t^2 + 743/240*t - 1/15] - Finally, an example over a general ring, that is to say, as of - version 4.0.2, SAGE does not even determine that ``S`` in the following - example is an integral domain:: + Finally, an example over a general ring ``S`` that is + not an integral domain:: sage: R. = QQ[] sage: S. = R.quo((b^3)) @@ -8968,10 +8988,10 @@ cdef class Matrix(Matrix1): -4*x sage: A.charpoly('T') T^2 + (-x^10*y - x*y^2)*T - 4*x - sage: A.adjoint() + sage: A.adjugate() [x^10*y -2*x] [ -2 x*y^2] - sage: A.adjoint() * A + sage: A.adjugate() * A [-4*x 0] [ 0 -4*x] @@ -8982,20 +9002,20 @@ cdef class Matrix(Matrix1): sage: A = matrix(ZZ, 0, 0) sage: A [] - sage: A._adjoint() + sage: A._adjugate() [] sage: A = matrix(ZZ, [[2]]) sage: A [2] - sage: A._adjoint() + sage: A._adjugate() [1] - Ensure proper computation of the adjoint matrix even in the + Ensure proper computation of the adjugate matrix even in the presence of non-integral powers of the variable `x` (:trac:`14403`):: sage: x = var('x') - sage: Matrix([[sqrt(x),x],[1,0]]).adjoint() + sage: Matrix([[sqrt(x),x],[1,0]]).adjugate() [ 0 -x] [ -1 sqrt(x)] @@ -9004,51 +9024,34 @@ cdef class Matrix(Matrix1): The key feature of this implementation is that it is division-free. This means that it can be used as a generic implementation for any ring (commutative and with multiplicative identity). The algorithm - is described in full detail as Algorithm 3.1 in [Se02]_. + is described in full detail as Algorithm 3.1 in [Sei2002]_. - Note that this method does not utilise a lookup if the adjoint has + Note that this method does not utilise a lookup if the adjugate has already been computed previously, and it does not cache the result. - This is all left to the method `adjoint`. - - REFERENCES: + This is all left to the method `adjugate`. - .. [Se02] \T. R. Seifullin, *Computation of determinants, adjoint - matrices, and characteristic polynomials without division* - :doi:`10.1023/A:1021878507303` - - AUTHORS: - - - Sebastian Pancratz (2009-06-12): Initial version """ - - # Validate assertions - # + # self must be square if self._nrows != self._ncols: raise ValueError("self must be a square matrix") - # Corner cases - # N.B. We already tested for the matrix to be square, hence we do not - # need to test for 0 x n or m x 0 matrices. - # + # as self is square, we do not need to test for 0 x n or m x 0 + # matrices if self._ncols == 0: return self.copy() - # Extract parameters - # + # extract parameters n = self._ncols R = self._base_ring MS = self._parent f = self.charpoly() - # Let A denote the adjoint of M, which we want to compute, and - # N denote a copy of M used to store powers of M. - # + # A will be the adjugate of M and N is used to store powers of M A = f[1] * MS.identity_matrix() N = R(1) * MS.identity_matrix() for i in range(1, n): - # Set N to be M^i - # + # set N to M^i N = N * self A = A + f[i+1] * N if not (n % 2): @@ -13947,7 +13950,7 @@ cdef class Matrix(Matrix1): [Sto1998]_, where the former is more representative of the code here. - EXAMPLES: + EXAMPLES:: sage: A = matrix(QQ, [[-68, 69, -27, -11, -65, 9, -181, -32], ....: [-52, 52, -27, -8, -52, -16, -133, -14], @@ -15731,7 +15734,6 @@ def decomp_seq(v): list.sort(v, key=lambda x: x[0].dimension()) return Sequence(v, universe=tuple, check=False, cr=True) - def _choose(Py_ssize_t n, Py_ssize_t t): """ Returns all possible sublists of length t from range(n) diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index 8d51651cf86..52507b7d4a3 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -36,14 +36,14 @@ TESTS:: sage: TestSuite(a).run() """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004,2005,2006 Joshua Kantor # # 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 __future__ import absolute_import import math @@ -608,7 +608,7 @@ cdef class Matrix_double_dense(Matrix_dense): sage: B.condition() doctest:warning ... - ComplexWarning: Casting complex values to real discards the imaginary part + ...ComplexWarning: Casting complex values to real discards the imaginary part 203.851798... sage: B.condition(p='frob') 203.851798... @@ -993,7 +993,7 @@ cdef class Matrix_double_dense(Matrix_dense): [35.13996365902..., 2.27661020871472..., 0.0, 0.0] sage: set_verbose(0) - sage: all([s in RDF for s in sv]) + sage: all(s in RDF for s in sv) True TESTS: @@ -3046,7 +3046,7 @@ cdef class Matrix_double_dense(Matrix_dense): [ 0.0 0.9999999999999996 0.0 0.0] [ 0.0 0.0 0.9999999999999992 0.0] [ 0.0 0.0 0.0 0.9999999999999999] - sage: all([T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i)]) + sage: all(T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i)) True sage: (Q*T*Q.conjugate().transpose()-A).zero_at(1.0e-11) [0.0 0.0 0.0 0.0] @@ -3073,7 +3073,7 @@ cdef class Matrix_double_dense(Matrix_dense): [ 0.0 0.0 0.0 1.0000000000000007] sage: T.parent() Full MatrixSpace of 4 by 4 dense matrices over Complex Double Field - sage: all([T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i)]) + sage: all(T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i)) True sage: (Q*T*Q.conjugate().transpose()-A).zero_at(1.0e-11) [0.0 0.0 0.0 0.0] @@ -3098,9 +3098,9 @@ cdef class Matrix_double_dense(Matrix_dense): [ 0.0 1.0000000000000013 0.0 0.0] [ 0.0 0.0 1.0000000000000004 0.0] [ 0.0 0.0 0.0 1.0000000000000016] - sage: all([T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i)]) + sage: all(T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i)) False - sage: all([T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i-1)]) + sage: all(T.zero_at(1.0e-12)[i,j] == 0 for i in range(4) for j in range(i-1)) True sage: (Q*T*Q.conjugate().transpose()-A).zero_at(1.0e-11) [0.0 0.0 0.0 0.0] @@ -3210,7 +3210,7 @@ cdef class Matrix_double_dense(Matrix_dense): sage: A = matrix(RDF, 2, 2, [[0, -1], [1, 0]]) sage: Qr, Tr = A.schur(base_ring=RDF) sage: Qc, Tc = A.schur(base_ring=CDF) - sage: all([M.is_immutable() for M in [Qr, Tr, Qc, Tc]]) + sage: all(M.is_immutable() for M in [Qr, Tr, Qc, Tc]) True sage: Tr.round(6) != Tc.round(6) True diff --git a/src/sage/matrix/matrix_gap.pyx b/src/sage/matrix/matrix_gap.pyx index 8ee45d9feea..a5a453992c0 100644 --- a/src/sage/matrix/matrix_gap.pyx +++ b/src/sage/matrix/matrix_gap.pyx @@ -1,15 +1,15 @@ r""" Wrappers on GAP matrices """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Vincent Delecroix <20100.delecroix@gmail.com> # # This 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 __future__ import print_function, absolute_import @@ -79,8 +79,8 @@ cdef class Matrix_gap(Matrix_dense): - ``copy`` -- ignored (for backwards compatibility) - - ``coerce`` -- if True (the default), convert elements to the - base ring before passing them to GAP. If False, pass the + - ``coerce`` -- if ``True`` (the default), convert elements to the + base ring before passing them to GAP. If ``False``, pass the elements to GAP as given. TESTS:: @@ -110,9 +110,9 @@ cdef class Matrix_gap(Matrix_dense): Traceback (most recent call last): ... TypeError: nonzero scalar matrix must be square - sage: MatrixSpace(QQ, 1, 2)(0) + sage: MatrixSpace(QQ, 1, 2, implementation='gap')(0) [0 0] - sage: MatrixSpace(QQ, 2, 1)(0) + sage: MatrixSpace(QQ, 2, 1, implementation='gap')(0) [0] [0] """ @@ -270,7 +270,7 @@ cdef class Matrix_gap(Matrix_dense): r""" TESTS:: - sage: M = MatrixSpace(QQ, 2) + sage: M = MatrixSpace(QQ, 2, implementation='gap') sage: ~M([4,2,2,2]) [ 1/2 -1/2] [-1/2 1] @@ -283,7 +283,6 @@ cdef class Matrix_gap(Matrix_dense): else: return Matrix_dense.__invert__(self) - cpdef _add_(left, right): r""" TESTS:: @@ -327,6 +326,28 @@ cdef class Matrix_gap(Matrix_dense): M._libgap = (( left)._libgap * ( right)._libgap) return M + def transpose(self): + r""" + Return the transpose of this matrix. + + EXAMPLES:: + + sage: M = MatrixSpace(QQ, 2, implementation='gap') + sage: M([4,2,23,52]).transpose() + [ 4 23] + [ 2 52] + + sage: M = MatrixSpace(QQ, 1, 3, implementation='gap') + sage: M([4,2,52]).transpose() + [ 4] + [ 2] + [52] + """ + cdef Matrix_gap M + M = self._new(self._ncols, self._nrows) + M._libgap = self._libgap.TransposedMat() + return M + def determinant(self): r""" Return the determinant of this matrix. @@ -353,7 +374,7 @@ cdef class Matrix_gap(Matrix_dense): sage: parent(M(1).determinant()) Universal Cyclotomic Field """ - return self._base_ring(self._libgap.Determinant()) + return self._base_ring(self._libgap.DeterminantMat()) def trace(self): r""" @@ -381,7 +402,7 @@ cdef class Matrix_gap(Matrix_dense): sage: parent(M(1).trace()) Universal Cyclotomic Field """ - return self._base_ring(self._libgap.Trace()) + return self._base_ring(self._libgap.TraceMat()) def rank(self): r""" @@ -395,4 +416,18 @@ cdef class Matrix_gap(Matrix_dense): sage: M([2, 1, 4, 2]).rank() 1 """ - return int(self._libgap.Rank()) + return int(self._libgap.RankMat()) + + def elementary_divisors(self): + """ + Return the list of elementary divisors of this matrix. + + EXAMPLES:: + + sage: M = MatrixSpace(ZZ, 5, implementation='gap') + sage: T = M([(i+1)**(j+1) for i in range(5) for j in range(5)]) + sage: T.elementary_divisors() + [1, 2, 6, 24, 120] + """ + return [self._base_ring(u) + for u in self._libgap.ElementaryDivisorsMat()] diff --git a/src/sage/matrix/matrix_generic_dense.pyx b/src/sage/matrix/matrix_generic_dense.pyx index a8cc42ca55e..41ff970ff51 100644 --- a/src/sage/matrix/matrix_generic_dense.pyx +++ b/src/sage/matrix/matrix_generic_dense.pyx @@ -117,7 +117,8 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): def _pickle(self): """ - EXAMPLES: + EXAMPLES:: + sage: R. = Integers(25)['x']; A = matrix(R, [1,x,x^3+1,2*x]) sage: A._pickle() ([1, x, x^3 + 1, 2*x], 0) @@ -126,7 +127,8 @@ cdef class Matrix_generic_dense(matrix_dense.Matrix_dense): def _unpickle(self, data, int version): """ - EXAMPLES: + EXAMPLES:: + sage: R. = Integers(25)['x']; A = matrix(R, [1,x,x^3+1,2*x]); B = A.parent()(0) sage: v = A._pickle() sage: B._unpickle(v[0], v[1]) diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index 3c7ae9c4925..85636aa1c5a 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -440,6 +440,7 @@ cdef class Matrix_gfpn_dense(Matrix_dense): for j in range(nc): c = self._converter.field_to_fel(self._coerce_element(next(it))) FfInsert(x, j, c) + sig_check() FfStepPtr(&x) self._is_immutable = not mutable @@ -467,8 +468,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): if type(filename) is not bytes: filename = str_to_bytes(filename, FS_ENCODING, 'surrogateescape') - - return new_mtx(MatLoad(filename), None) + sig_on() + try: + mat = MatLoad(filename) + finally: + sig_off() + return new_mtx(mat, None) def __copy__(self): """ @@ -495,7 +500,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): """ if self.Data is NULL: raise ValueError("cannot copy an uninitialized matrix") - retval = new_mtx(MatDup(self.Data), self) + sig_on() + try: + mat = MatDup(self.Data) + finally: + sig_off() + retval = new_mtx(mat, self) if self._cache: retval._cache = dict(self._cache) return retval @@ -593,8 +603,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): """ if not 0 <= i < j <= self.Data.Nor: raise IndexError("Indices i={}, j={} violate the condition 0 < i < j < {}".format(i,j,self.Data.Nor)) - mat = MatAlloc(self.Data.Field, j-i, self.Data.Noc) - memcpy(mat.Data, FfGetPtr(self.Data.Data, i), FfCurrentRowSize*(j-i)) + sig_on() + try: + mat = MatAlloc(self.Data.Field, j-i, self.Data.Noc) + memcpy(mat.Data, FfGetPtr(self.Data.Data, i), FfCurrentRowSize*(j-i)) + finally: + sig_off() return new_mtx(mat, self) cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, value): @@ -641,7 +655,11 @@ cdef class Matrix_gfpn_dense(Matrix_dense): # NOTE: # It is essential that you call FfSetField and FfSetNoc YOURSELF # and that the dimensions of self and S match! - memcpy(FfGetPtr(self.Data.Data, i), S.Data.Data, FfCurrentRowSize*S.Data.Nor) + sig_on() + try: + memcpy(FfGetPtr(self.Data.Data, i), S.Data.Data, FfCurrentRowSize*S.Data.Nor) + finally: + sig_off() def randomize(self, density=None, nonzero=False, *args, **kwds): """ @@ -807,8 +825,6 @@ cdef class Matrix_gfpn_dense(Matrix_dense): cdef Matrix_gfpn_dense N = right if self is None or N is None: return -1 - cdef char* d1 - cdef char* d2 if self.Data == NULL: if N.Data == NULL: return 0 @@ -828,10 +844,14 @@ cdef class Matrix_gfpn_dense(Matrix_dense): if self.Data.Nor > N.Data.Nor: return 1 return -1 - d1 = (self.Data.Data) - d2 = (N.Data.Data) - cdef bytes s1 = PyBytes_FromStringAndSize(d1,self.Data.RowSize * self.Data.Nor) - cdef bytes s2 = PyBytes_FromStringAndSize(d2,N.Data.RowSize * N.Data.Nor) + + cdef char* d1 = self.Data.Data + cdef char* d2 = N.Data.Data + cdef Py_ssize_t total_size = self.Data.RowSize + total_size *= self.Data.Nor + cdef bytes s1, s2 + s1 = PyBytes_FromStringAndSize(d1, total_size) + s2 = PyBytes_FromStringAndSize(d2, total_size) if s1 != s2: if s1 > s2: return 1 @@ -1148,9 +1168,13 @@ cdef class Matrix_gfpn_dense(Matrix_dense): return other.__copy__() if other._nrows == 0 or other.Data == NULL: return self.__copy__() - mat = MatAlloc(self.Data.Field, self.Data.Nor+other.Data.Nor, self.Data.Noc) - memcpy(mat.Data, self.Data.Data, FfCurrentRowSize*self.Data.Nor) - memcpy(MatGetPtr(mat, self.Data.Nor), other.Data.Data, FfCurrentRowSize*other.Data.Nor) + sig_on() + try: + mat = MatAlloc(self.Data.Field, self.Data.Nor+other.Data.Nor, self.Data.Noc) + memcpy(mat.Data, self.Data.Data, FfCurrentRowSize*self.Data.Nor) + memcpy(MatGetPtr(mat, self.Data.Nor), other.Data.Data, FfCurrentRowSize*other.Data.Nor) + finally: + sig_off() return new_mtx(mat, self) cpdef _add_(self, right): @@ -1172,8 +1196,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): assert Right is not None if Self.Data == NULL or Right.Data == NULL: raise NotImplementedError("The matrices must not be empty") - mat = MatDup(Self.Data) - MatAdd(mat, Right.Data) + sig_on() + try: + mat = MatDup(Self.Data) + MatAdd(mat, Right.Data) + finally: + sig_off() return new_mtx(mat, self) cpdef _sub_(self, right): @@ -1195,8 +1223,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): assert Right is not None if Self.Data == NULL or Right.Data == NULL: raise NotImplementedError("The matrices must not be empty") - mat = MatDup(Self.Data) - MatAddMul(mat, Right.Data, mtx_taddinv[1]) + sig_on() + try: + mat = MatDup(Self.Data) + MatAddMul(mat, Right.Data, mtx_taddinv[1]) + finally: + sig_off() return new_mtx(mat, self) def __neg__(self): @@ -1250,8 +1282,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): if self.Data == NULL: return self.__copy__() FfSetField(self.Data.Field) - mat = MatDup(self.Data) - MatMulScalar(mat, self._converter.field_to_fel(right)) + sig_on() + try: + mat = MatDup(self.Data) + MatMulScalar(mat, self._converter.field_to_fel(right)) + finally: + sig_off() return new_mtx(mat, self) cdef int _strassen_default_cutoff(self, sage.matrix.matrix0.Matrix right) except -2: @@ -1282,9 +1318,11 @@ cdef class Matrix_gfpn_dense(Matrix_dense): if self._ncols != right._nrows: raise ArithmeticError("left ncols must match right nrows") sig_on() - mat = MatDup(self.Data) - MatMul(mat, right.Data) - sig_off() + try: + mat = MatDup(self.Data) + MatMul(mat, right.Data) + finally: + sig_off() return new_mtx(mat, self) cpdef Matrix_gfpn_dense _multiply_strassen(Matrix_gfpn_dense self, Matrix_gfpn_dense right, cutoff=0): @@ -1315,10 +1353,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): if self._ncols != right._nrows: raise ArithmeticError("left ncols must match right nrows") StrassenSetCutoff(cutoff // sizeof(long)) - mat = MatAlloc(self.Data.Field, self._nrows, right._ncols) sig_on() - MatMulStrassen(mat, self.Data, right.Data) - sig_off() + try: + mat = MatAlloc(self.Data.Field, self._nrows, right._ncols) + MatMulStrassen(mat, self.Data, right.Data) + finally: + sig_off() return new_mtx(mat, self) cdef _mul_long(self, long n): @@ -1341,8 +1381,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): cdef FEL r with cython.cdivision(False): r = FfFromInt(n%FfChar) - mat = MatDup(self.Data) - MatMulScalar(mat, r) + sig_on() + try: + mat = MatDup(self.Data) + MatMulScalar(mat, r) + finally: + sig_off() return new_mtx(mat, self) def __div__(Matrix_gfpn_dense self, p): @@ -1375,9 +1419,13 @@ cdef class Matrix_gfpn_dense(Matrix_dense): raise ValueError("{} is not a scalar".format(p)) p = self._base_ring(p) FfSetField(self.Data.Field) - mat = MatDup(self.Data) cdef FEL r = mtx_tmultinv[self._converter.field_to_fel(p)] - MatMulScalar(mat, r) + sig_on() + try: + mat = MatDup(self.Data) + MatMulScalar(mat, r) + finally: + sig_off() return new_mtx(mat, self) def __invert__(Matrix_gfpn_dense self): @@ -1444,8 +1492,10 @@ cdef class Matrix_gfpn_dense(Matrix_dense): if self.Data == NULL: raise ValueError("The matrix must not be empty") sig_on() - mat = MatTransposed(self.Data) - sig_off() + try: + mat = MatTransposed(self.Data) + finally: + sig_off() return new_mtx(mat, self) def order(self): @@ -1471,8 +1521,10 @@ cdef class Matrix_gfpn_dense(Matrix_dense): if self.Data.Nor != self.Data.Noc: raise ValueError("only defined for square matrices") sig_on() - o = MatOrder(self.Data) - sig_off() + try: + o = MatOrder(self.Data) + finally: + sig_off() if o == -1: raise ArithmeticError("order too large") else: @@ -1521,8 +1573,10 @@ cdef class Matrix_gfpn_dense(Matrix_dense): if self.Data is NULL: raise ValueError("The matrix must not be empty") sig_on() - mat = MatNullSpace(self.Data) - sig_off() + try: + mat = MatNullSpace(self.Data) + finally: + sig_off() OUT = new_mtx(mat, self) self.cache("left_kernel_matrix", OUT) return OUT @@ -1678,8 +1732,10 @@ cdef class Matrix_gfpn_dense(Matrix_dense): return () self._cache = None sig_on() - MatEchelonize(self.Data) - sig_off() + try: + MatEchelonize(self.Data) + finally: + sig_off() # Now, self.Data is in semi-echelon form. r = self.Data.Nor cdef size_t i, j, pos @@ -1859,7 +1915,11 @@ def mtx_unpickle(f, int nr, int nc, bytes Data, bint m): f = MS.base_ring().order() OUT = Matrix_gfpn_dense.__new__(Matrix_gfpn_dense, MS) - OUT.Data = MatAlloc(f, nr, nc) + sig_on() + try: + OUT.Data = MatAlloc(f, nr, nc) + finally: + sig_off() OUT._is_immutable = not m OUT._converter = FieldConverter(OUT._base_ring) cdef char *x @@ -1880,6 +1940,7 @@ def mtx_unpickle(f, int nr, int nc, bytes Data, bint m): memcpy(pt,x,FfCurrentRowSizeIo) x += FfCurrentRowSizeIo FfStepPtr(&(pt)) + sig_check() elif pickled_rowsize >= FfCurrentRowSizeIo: deprecation(23411, "Reading this pickle may be machine dependent") if pickled_rowsize == FfCurrentRowSize: @@ -1890,6 +1951,7 @@ def mtx_unpickle(f, int nr, int nc, bytes Data, bint m): memcpy(pt,x,FfCurrentRowSizeIo) x += pickled_rowsize FfStepPtr(&(pt)) + sig_check() else: raise ValueError(f"Expected a pickle with {FfCurrentRowSizeIo}*{nr} bytes, got {pickled_rowsize}*{nr} instead") return OUT diff --git a/src/sage/matrix/matrix_integer_dense.pxd b/src/sage/matrix/matrix_integer_dense.pxd index bc3af7cb706..5dd2a8e2f3e 100644 --- a/src/sage/matrix/matrix_integer_dense.pxd +++ b/src/sage/matrix/matrix_integer_dense.pxd @@ -30,6 +30,5 @@ cdef class Matrix_integer_dense(Matrix_dense): cdef Matrix_integer_dense _new(self, Py_ssize_t nrows, Py_ssize_t ncols) - cdef extract_hnf_from_pari_matrix(self, GEN H, int flag, bint include_zero_rows) cpdef _lift_crt(Matrix_integer_dense M, residues, moduli=*) diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index 4f0b0e61d25..7732bf8d7e6 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -87,11 +87,11 @@ from .args cimport SparseEntry, MatrixArgs_init ######################################################### # PARI C library from cypari2.gen cimport Gen +from cypari2.stack cimport clear_stack, new_gen +from cypari2.paridecl cimport * from sage.libs.pari.convert_gmp cimport INT_to_mpz from sage.libs.pari.convert_flint cimport (_new_GEN_from_fmpz_mat_t, _new_GEN_from_fmpz_mat_t_rotate90, integer_matrix) -from cypari2.stack cimport clear_stack -from cypari2.paridecl cimport * ######################################################### from sage.arith.multi_modular cimport MultiModularBasis @@ -479,7 +479,9 @@ cdef class Matrix_integer_dense(Matrix_dense): Return space separated string of the entries in this matrix, in the given base. This is optimized for speed. - INPUT: base -an integer = 36; (default: 10) + INPUT: + + - base -- an integer <= 36; (default: 10) EXAMPLES:: @@ -2016,10 +2018,7 @@ cdef class Matrix_integer_dense(Matrix_dense): raise ValueError("transformation matrix only available with p-adic algorithm") elif algorithm in ["pari", "pari0", "pari1", "pari4"]: flag = int(algorithm[-1]) if algorithm != "pari" else 1 - if self.height().ndigits() > 10000 or n >= 50: - H_m = self._hnf_pari_big(flag, include_zero_rows=include_zero_rows) - else: - H_m = self._hnf_pari(flag, include_zero_rows=include_zero_rows) + H_m = self._hnf_pari(flag, include_zero_rows=include_zero_rows) elif algorithm == 'ntl': if nr != nc: raise ValueError("ntl only computes HNF for square matrices of full rank.") @@ -2653,16 +2652,16 @@ cdef class Matrix_integer_dense(Matrix_dense): return (format, K) # TODO: implement using flint function - def _adjoint(self): + def _adjugate(self): """ - Return the adjoint of this matrix. + Return the adjugate (classical adjoint) of this matrix. - Assumes self is a square matrix (checked in adjoint). + Assumes ``self`` is a square matrix (checked in adjugate). EXAMPLES:: sage: m = matrix(ZZ,3,[1..9]) - sage: m.adjoint() + sage: m.adjugate() [ -3 6 -3] [ 6 -12 6] [ -3 6 -3] @@ -4108,8 +4107,8 @@ cdef class Matrix_integer_dense(Matrix_dense): ... ZeroDivisionError: Matrix is singular """ - A,d = self._invert_flint() - return A/d + A, d = self._invert_flint() + return A / d def _invert_unit(self): r""" @@ -4148,7 +4147,7 @@ cdef class Matrix_integer_dense(Matrix_dense): ... ArithmeticError: non-invertible matrix """ - A,d = self._invert_flint() + A, d = self._invert_flint() if not d.is_one(): raise ArithmeticError("non-invertible matrix") return A @@ -4252,7 +4251,7 @@ cdef class Matrix_integer_dense(Matrix_dense): True """ - t = verbose('starting %s solve_right...'%algorithm) + t = verbose('starting %s solve_right...' % algorithm) # It would probably be much better to rewrite linbox so it # throws an error instead of ** going into an infinite loop ** @@ -4807,8 +4806,20 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: t = ModularSymbols(11,sign=1).hecke_matrix(2) sage: w = t.change_ring(ZZ) - sage: w.list() - [3, -1, 0, -2] + sage: w + [ 3 -2] + [ 0 -2] + sage: w.charpoly().factor() + (x - 3) * (x + 2) + sage: w.decomposition() + [ + (Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [ 5 -2], True), + (Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [0 1], True) + ] """ F = self.charpoly().factor() if len(F) == 1: @@ -5664,6 +5675,7 @@ cdef class Matrix_integer_dense(Matrix_dense): matrices. EXAMPLES:: + sage: matrix(ZZ,3,[1..9])._rank_pari() 2 """ @@ -5674,16 +5686,12 @@ cdef class Matrix_integer_dense(Matrix_dense): def _hnf_pari(self, int flag=0, bint include_zero_rows=True): """ - Hermite form of this matrix, computed using PARI. The - computation is done entirely on the PARI stack, then the PARI - stack is cleared. This function is only useful for small - matrices, and can crash on large matrices (e.g., if the PARI - stack overflows). + Hermite normal form of this matrix, computed using PARI. INPUT: - ``flag`` -- 0 (default), 1, 3 or 4 (see docstring for - gp.mathnf). + ``pari.mathnf``). - ``include_zero_rows`` -- boolean. if False, do not include any of the zero rows at the bottom of the matrix in the @@ -5733,98 +5741,13 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: pari('mathnf(Mat([0,1]), 4)') [Mat(1), [1, 0; 0, 1]] """ - cdef GEN A sig_on() A = _new_GEN_from_fmpz_mat_t_rotate90(self._matrix) - cdef GEN H = mathnf0(A, flag) - B = self.extract_hnf_from_pari_matrix(H, flag, include_zero_rows) - clear_stack() # This calls sig_off() - return B - - - def _hnf_pari_big(self, int flag=0, bint include_zero_rows=True): - """ - Hermite form of this matrix, computed using PARI. - - INPUT: - - - ``flag`` -- 0 (default), 1, 3 or 4 (see docstring for - gp.mathnf). - - - ``include_zero_rows`` -- boolean. if False, do not include - any of the zero rows at the bottom of the matrix in the - output. - - .. NOTE:: - - In no cases is the transformation matrix returned by this - function. - - EXAMPLES:: - - sage: a = matrix(ZZ,3,3,[1..9]) - sage: a._hnf_pari_big(flag=0, include_zero_rows=True) - [1 2 3] - [0 3 6] - [0 0 0] - sage: a._hnf_pari_big(flag=1, include_zero_rows=True) - [1 2 3] - [0 3 6] - [0 0 0] - sage: a._hnf_pari_big(flag=3, include_zero_rows=True) - [1 2 3] - [0 3 6] - [0 0 0] - sage: a._hnf_pari_big(flag=4, include_zero_rows=True) - [1 2 3] - [0 3 6] - [0 0 0] - - Check that ``include_zero_rows=False`` works correctly:: - - sage: matrix(ZZ,3,[1..9])._hnf_pari_big(0, include_zero_rows=False) - [1 2 3] - [0 3 6] - sage: matrix(ZZ,3,[1..9])._hnf_pari_big(1, include_zero_rows=False) - [1 2 3] - [0 3 6] - sage: matrix(ZZ,3,[1..9])._hnf_pari_big(3, include_zero_rows=False) - [1 2 3] - [0 3 6] - sage: matrix(ZZ,3,[1..9])._hnf_pari_big(4, include_zero_rows=False) - [1 2 3] - [0 3 6] - """ - cdef Gen H = integer_matrix(self._matrix, 1) - H = H.mathnf(flag) - sig_on() - B = self.extract_hnf_from_pari_matrix(H.g, flag, include_zero_rows) - clear_stack() # This calls sig_off() - return B - - cdef extract_hnf_from_pari_matrix(self, GEN H, int flag, bint include_zero_rows): - # Throw away the transformation matrix (yes, we should later - # code this to keep track of it). - cdef mpz_t tmp - mpz_init(tmp) - if flag > 0: - H = gel(H,1) - - # Figure out how many columns we got back. - cdef Py_ssize_t H_nc = glength(H) # number of columns - # Now get the resulting Hermite form matrix back to Sage, suitably re-arranged. - cdef Matrix_integer_dense B - if include_zero_rows: - B = self.new_matrix() - else: - B = self.new_matrix(nrows=H_nc) - for i in range(self._ncols): - for j in range(H_nc): - INT_to_mpz(tmp, gcoeff(H, i+1, H_nc-j)) - fmpz_set_mpz(fmpz_mat_entry(B._matrix,j,self._ncols-i-1),tmp) - mpz_clear(tmp) - return B - + H = mathnf0(A, flag) + if typ(H) == t_VEC: + H = gel(H, 1) + GenH = new_gen(H) + return extract_hnf_from_pari_matrix(self, GenH, include_zero_rows) def p_minimal_polynomials(self, p, s_max=None): r""" @@ -5966,7 +5889,27 @@ cdef inline GEN pari_GEN(Matrix_integer_dense B): return A - ##################################################################################### +cdef extract_hnf_from_pari_matrix(Matrix_integer_dense self, Gen H, bint include_zero_rows): + cdef mpz_t tmp + mpz_init(tmp) + + # Figure out how many columns we got back. + cdef long H_nc = glength(H.g) # number of columns + # Now get the resulting Hermite form matrix back to Sage, suitably re-arranged. + cdef Matrix_integer_dense B + if include_zero_rows: + B = self.new_matrix() + else: + B = self.new_matrix(nrows=H_nc) + cdef long i, j + for i in range(self._ncols): + for j in range(H_nc): + sig_check() + INT_to_mpz(tmp, gcoeff(H.g, i+1, H_nc-j)) + fmpz_set_mpz(fmpz_mat_entry(B._matrix,j,self._ncols-i-1),tmp) + mpz_clear(tmp) + return B + cdef _clear_columns(Matrix_integer_dense A, pivots, Py_ssize_t n): # Clear all columns @@ -5990,11 +5933,6 @@ cdef _clear_columns(Matrix_integer_dense A, pivots, Py_ssize_t n): fmpz_clear(t) sig_off() -############################################################### - - - - cpdef _lift_crt(Matrix_integer_dense M, residues, moduli=None): """ diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 20335a131bb..ccff33d9c7d 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -1975,17 +1975,17 @@ def unpickle_matrix_mod2_dense_v2(r, c, data, size, immutable=False): Check that old pickles before :trac:`24589` still work:: - sage: s = ("x\x9ck`J.NLO\xd5\xcbM,)\xca\xac\x80R\xf1\xb9\xf9)F\xf1)\xa9y" - ....: "\xc5\xa9\\\xa5y\x05\x99\xc9\xd99\xa9\xf1\x18R\xf1e\x86\\\x85" - ....: "\x8c\x1a\xdeL\xdeL\xb1\x85L\x1a^\x9d\xff\xff\xff\xf7\x0e\xf0" - ....: "\xf6\xf3v\xf7\xe6\xf5\xe6\xf2\x96\x02b\x060\xe4\xf5\xf6\xf4" - ....: "\xf6\xf0v\xf1\x0e\x82\xf2\x99\xe04\xa373\x94\xed\xe1]\xe15" - ....: "\x1fd@:T\x80\rh\x94\x8fw\x88\xb7+\x84\xef\x05\x94\xfb\x8fD," - ....: "\x05\x117A\x04H\x97\xd7]\x90V\x88FN\xef\x02\xa0i\x91\xde\xc5" - ....: "`\x1e\x9f\xd7\x11\x98\x14\x94\xc9\xe85\x15Di{\xf3yKC\xb5\xf0" - ....: "\x00\x1d\xe8\xe2\xed\x08\xb4\x8d\xc3k&H2\x19hF\x82w\x06X\x92" - ....: "\x11(\xc5\xe0u\x10$\x9c\x0ft\x9d\xa1\xd7\x03\x84]\x0c@\x8d\xae@" - ....: "\x1f\xbbx\xad\x03\t:y'x5\x01\x19\xa9\xde9%A\x85\xccz\x000I\x88D") + sage: s = (b"x\x9ck`J.NLO\xd5\xcbM,)\xca\xac\x80R\xf1\xb9\xf9)F\xf1)\xa9y" + ....: b"\xc5\xa9\\\xa5y\x05\x99\xc9\xd99\xa9\xf1\x18R\xf1e\x86\\\x85" + ....: b"\x8c\x1a\xdeL\xdeL\xb1\x85L\x1a^\x9d\xff\xff\xff\xf7\x0e\xf0" + ....: b"\xf6\xf3v\xf7\xe6\xf5\xe6\xf2\x96\x02b\x060\xe4\xf5\xf6\xf4" + ....: b"\xf6\xf0v\xf1\x0e\x82\xf2\x99\xe04\xa373\x94\xed\xe1]\xe15" + ....: b"\x1fd@:T\x80\rh\x94\x8fw\x88\xb7+\x84\xef\x05\x94\xfb\x8fD," + ....: b"\x05\x117A\x04H\x97\xd7]\x90V\x88FN\xef\x02\xa0i\x91\xde\xc5" + ....: b"`\x1e\x9f\xd7\x11\x98\x14\x94\xc9\xe85\x15Di{\xf3yKC\xb5\xf0" + ....: b"\x00\x1d\xe8\xe2\xed\x08\xb4\x8d\xc3k&H2\x19hF\x82w\x06X\x92" + ....: b"\x11(\xc5\xe0u\x10$\x9c\x0ft\x9d\xa1\xd7\x03\x84]\x0c@\x8d\xae@" + ....: b"\x1f\xbbx\xad\x03\t:y'x5\x01\x19\xa9\xde9%A\x85\xccz\x000I\x88D") sage: loads(s) [1 0] [0 1] diff --git a/src/sage/matrix/matrix_modn_sparse.pyx b/src/sage/matrix/matrix_modn_sparse.pyx index a848ad7581d..241167ace4f 100644 --- a/src/sage/matrix/matrix_modn_sparse.pyx +++ b/src/sage/matrix/matrix_modn_sparse.pyx @@ -253,7 +253,8 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): This code is implicitly called for multiplying self by another sparse matrix. - EXAMPLES: + EXAMPLES:: + sage: a = matrix(GF(43), 3, 3, range(9), sparse=True) sage: b = matrix(GF(43), 3, 3, range(10,19), sparse=True) sage: a*b @@ -326,7 +327,8 @@ cdef class Matrix_modn_sparse(matrix_sparse.Matrix_sparse): Multiply self by the sparse matrix _right, and return the result as a dense matrix. - EXAMPLES: + EXAMPLES:: + sage: a = matrix(GF(10007), 2, [1,2,3,4], sparse=True) sage: b = matrix(GF(10007), 2, 3, [1..6], sparse=True) sage: a * b diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index ad798311ea8..e13d4a8b18b 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -227,7 +227,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): elif algorithm == 'row_reduction': self._echelonize_row_reduction() else: - raise ValueError("Unknown algorithm '%s'"%algorithm) + raise ValueError("Unknown algorithm '%s'" % algorithm) def _echelonize_gauss_bareiss(self): """ diff --git a/src/sage/matrix/matrix_polynomial_dense.pyx b/src/sage/matrix/matrix_polynomial_dense.pyx index 05ddb500cdc..7dd49d2ff62 100644 --- a/src/sage/matrix/matrix_polynomial_dense.pyx +++ b/src/sage/matrix/matrix_polynomial_dense.pyx @@ -13,18 +13,22 @@ AUTHORS: - Vincent Neiger (2018-06-13): added basic functions (row/column degrees, leading positions, leading matrix, testing reduced and canonical forms) +- Vincent Neiger (2018-09-29): added functions for computing and for verifying + minimal approximant bases + """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Kwankyu Lee # # 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 sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix +from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.misc.superseded import deprecated_function_alias @@ -146,8 +150,8 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): """ if self.nrows() == 0 or self.ncols() == 0: raise ValueError('empty matrix does not have a degree') - return max([ self[i,j].degree() - for i in range(self.nrows()) for j in range(self.ncols()) ]) + return max(self[i, j].degree() + for i in range(self.nrows()) for j in range(self.ncols())) def degree_matrix(self, shifts=None, row_wise=True): r""" @@ -1462,3 +1466,532 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): U.set_immutable() return (A, U) if transformation else A + + def is_minimal_approximant_basis(self, + pmat, + order, + shifts=None, + row_wise=True, + normal_form=False): + r""" + Return ``True`` if and only if this matrix is an approximant basis in + ``shifts``-ordered weak Popov form for the polynomial matrix ``pmat`` + at order ``order``. + + If ``normal_form`` is ``True``, then the polynomial matrix must + furthermore be in ``shifts``-Popov form. An error is raised if the + input dimensions are not sound. If a single integer is provided for + ``order``, then it is interpreted as a list of repeated integers with + this value. (See :meth:`minimal_approximant_basis` for definitions and + more details.) + + INPUT: + + - ``pmat`` -- a polynomial matrix. + + - ``order`` -- a list of positive integers, or a positive integer. + + - ``shifts`` -- (optional, default: ``None``) list of integers; + ``None`` is interpreted as ``shifts=[0,...,0]``. + + - ``row_wise`` -- (optional, default: ``True``) boolean, if ``True`` + then the basis considered row-wise and operates on the left of + ``pmat``; otherwise it is column-wise and operates on the right of + ``pmat``. + + - ``normal_form`` -- (optional, default: ``False``) boolean, if + ``True`` then checks for a basis in ``shifts``-Popov form. + + OUTPUT: a boolean. + + ALGORITHM: + + Verification that the matrix is formed by approximants is done via a + truncated matrix product; verification that the matrix is square, + nonsingular and in shifted weak Popov form is done via + :meth:`is_weak_popov`; verification that the matrix generates the + module of approximants is done via the characterization in Theorem 2.1 + of [GN2018]_ . + + EXAMPLES:: + + sage: pR. = GF(97)[] + + We consider the following example from [Arne Storjohann, Notes on + computing minimal approximant bases, 2006]:: + + sage: order = 8; shifts = [1,1,0,0,0] + sage: pmat = Matrix(pR, 5, 1, [ \ + pR([35, 0, 41, 87, 3, 42, 22, 90]), \ + pR([80, 15, 62, 87, 14, 93, 24, 0]), \ + pR([42, 57, 90, 87, 22, 80, 71, 53]), \ + pR([37, 72, 74, 6, 5, 75, 23, 47]), \ + pR([36, 10, 74, 1, 29, 44, 87, 74]) ]) + sage: appbas = Matrix(pR, [ \ + [x+47, 57, 58*x+44, 9*x+23, 93*x+76], \ + [ 15, x+18, 52*x+23, 15*x+58, 93*x+88], \ + [ 17, 86, x^2+77*x+16, 76*x+29, 90*x+78], \ + [ 44, 36, 3*x+42, x^2+50*x+26, 85*x+44], \ + [ 2, 22, 54*x+94, 73*x+24, x^2+2*x+25] ]) + sage: appbas.is_minimal_approximant_basis(pmat,\ + order, shifts, row_wise=True, normal_form=True) + True + + The matrix `x^8 \mathrm{Id}_5` is square, nonsingular, in Popov form, + and its rows are approximants for ``pmat`` at order 8. However, it is + not an approximant basis since its rows generate a module strictly + contained in the set of approximants for ``pmat`` at order 8:: + + sage: (x^8*Matrix.identity(pR, 5)).is_minimal_approximant_basis(\ + pmat, 8) + False + + Since ``pmat`` is a single column, with nonzero constant coefficient, + its column-wise approximant bases at order 8 are all `1\times 1` + matrices `[c x^8]` for some nonzero field element `c`:: + + sage: Matrix(pR, [x^8]).is_minimal_approximant_basis(pmat, \ + 8, row_wise=False, normal_form=True) + True + + Exceptions are raised if input dimensions are not sound:: + + sage: appbas.is_minimal_approximant_basis(pmat, [8,8], shifts) + Traceback (most recent call last): + ... + ValueError: order length should be the column dimension + of the input matrix + + sage: appbas.is_minimal_approximant_basis(pmat, \ + order, shifts, row_wise=False) + Traceback (most recent call last): + ... + ValueError: shifts length should be the column dimension + of the input matrix + + sage: Matrix(pR, [x^8]).is_minimal_approximant_basis(pmat, 8) + Traceback (most recent call last): + ... + ValueError: column dimension should be the row dimension of the + input matrix + + .. SEEALSO:: + + :meth:`minimal_approximant_basis` . + """ + m = pmat.nrows() + n = pmat.ncols() + + # set default shifts / check shifts dimension + if shifts == None: + shifts = [0]*m if row_wise else [0]*n + elif row_wise and len(shifts) != m: + raise ValueError('shifts length should be the row dimension of' \ + + ' the input matrix') + elif (not row_wise) and len(shifts) != n: + raise ValueError('shifts length should be the column dimension' \ + + ' of the input matrix') + + # set default order / check order dimension + if not isinstance(order,list): + order = [order]*n if row_wise else [order]*m + + if row_wise and len(order) != n: + raise ValueError("order length should be the column dimension" \ + + " of the input matrix") + elif (not row_wise) and len(order) != m: + raise ValueError("order length should be the row dimension of" \ + + " the input matrix") + + # raise an error if self does not have the right dimension + if row_wise and self.ncols() != m: + raise ValueError("column dimension should be the row dimension" \ + + " of the input matrix") + elif (not row_wise) and self.nrows() != n: + raise ValueError("row dimension should be the column dimension" \ + + " of the input matrix") + + # check square + if not self.is_square(): + return False + # check nonsingular and shifts-(ordered weak) Popov form + if normal_form: + if not self.is_popov(shifts, row_wise, False, False): + return False + else: + if not self.is_weak_popov(shifts, row_wise, True, False): + return False + + # check that self is a basis of the set of approximants + if row_wise: + # check that self * pmat is 0 bmod x^order + # and compute certificate matrix ``cert_mat`` which is + # the constant term of (self * pmat) * x^(-order) + residual = self * pmat + for i in range(m): + for j in range(n): + if residual[i,j].truncate(order[j]) != 0: + return False + residual[i,j] = residual[i,j].shift(-order[j]) + cert_mat = residual(0) + + # check that self generates the set of approximants + # 1/ determinant of self should be a monomial c*x^d, + # with d the sum of pivot degrees + d = sum([self[i,i].degree() for i in range(m)]) + X = self.base_ring().gen() + if self.determinant() != (self(1).determinant() * X**d): + return False + # 2/ the m x (m+n) constant matrix [self(0) | cert_mat] should have + # full rank, that is, rank m + from sage.matrix.constructor import block_matrix + if block_matrix([[self(0), cert_mat]]).rank() < m: + return False + + else: + # check that pmat * self is 0 bmod x^order + # and compute certificate matrix ``cert_mat`` which is + # the constant term of x^(-order) * (pmat * self) + residual = pmat * self + for i in range(m): + for j in range(n): + if residual[i,j].truncate(order[i]) != 0: + return False + residual[i,j] = residual[i,j].shift(-order[i]) + cert_mat = residual(0) + + # check that self generates the set of approximants + # 1/ determinant of self should be a monomial c*x^d, + # with d the sum of pivot degrees + d = sum([self[i,i].degree() for i in range(n)]) + X = self.base_ring().gen() + if self.determinant() != (self(1).determinant() * X**d): + return False + # 2/ the (m+n) x n constant matrix [self(0).T | cert_mat.T].T + # should have full rank, that is, rank n + from sage.matrix.constructor import block_matrix + if block_matrix([[self(0)], [cert_mat]]).rank() < n: + return False + + return True + + + def minimal_approximant_basis(self, + order, + shifts=None, + row_wise=True, + normal_form=False): + r""" + Return an approximant basis in ``shifts``-ordered weak Popov form for + this polynomial matrix at order ``order``. + + Assuming we work row-wise, if `F` is an `m \times n` polynomial matrix + and `(d_0,\ldots,d_{n-1})` are positive integers, then an approximant + basis for `F` at order `(d_0,\ldots,d_{n-1})` is a polynomial matrix + whose rows form a basis of the module of approximants for `F` at order + `(d_0,\ldots,d_{n-1})`. The latter approximants are the polynomial + vectors `p` of size `m` such that the column `j` of `p F` has valuation + at least `d_j`, for all `0 \le j \le n-1`. + + If ``normal_form`` is ``True``, then the output basis `P` is + furthermore in ``shifts``-Popov form. By default, `P` is considered + row-wise, that is, its rows are left-approximants for ``self``; if + ``row_wise`` is ``False`` then its columns are right-approximants for + ``self``. It is guaranteed that the degree of the output basis is at + most the maximum of the entries of ``order``, independently of + ``shifts``. + + An error is raised if the input dimensions are not sound: if working + row-wise (resp. column-wise), the length of ``order`` must be the + number of columns (resp. rows) of ``self``, while the length of + ``shifts`` must be the number of rows (resp. columns) of ``self``. + + If a single integer is provided for ``order``, then it is converted + into a list of repeated integers with this value. + + INPUT: + + - ``order`` -- a list of positive integers, or a positive integer. + + - ``shifts`` -- (optional, default: ``None``) list of integers; + ``None`` is interpreted as ``shifts=[0,...,0]``. + + - ``row_wise`` -- (optional, default: ``True``) boolean, if ``True`` + then the output basis considered row-wise and operates on the left + of ``self``; otherwise it is column-wise and operates on the right + of ``self``. + + - ``normal_form`` -- (optional, default: ``False``) boolean, if + ``True`` then the output basis is in ``shifts``-Popov form. + + OUTPUT: a polynomial matrix. + + ALGORITHM: + + The implementation is inspired from the iterative algorithms described + in [VBB1992]_ and [BL1994]_ ; for obtaining the normal form, it relies + directly on Lemmas 3.3 and 4.1 in [JNSV2016]_ . + + EXAMPLES:: + + sage: pR. = GF(7)[] + + sage: order = [4, 3]; shifts = [-1, 2, 0] + sage: F = Matrix(pR, [[5*x^3 + 4*x^2 + 4*x + 6, 5*x^2 + 4*x + 1], \ + [ 2*x^2 + 2*x + 3, 6*x^2 + 6*x + 3], \ + [4*x^3 + x + 1, 4*x^2 + 2*x + 3] ]) + sage: P = F.minimal_approximant_basis(order, shifts) + sage: P.is_minimal_approximant_basis(F, order, shifts) + True + + By default, the computed basis is not required to be in normal form + (and will not be except in rare special cases):: + + sage: P.is_minimal_approximant_basis(F, order, shifts, \ + normal_form=True) + False + sage: P = F.minimal_approximant_basis(order, shifts, normal_form=True) + sage: P.is_minimal_approximant_basis(F, order, shifts, \ + normal_form=True) + True + + If shifts are not specified, they are chosen as uniform `[0,\ldots,0]` + by default. Besides, if the orders are all the same, one can rather + give a single integer:: + + sage: F.minimal_approximant_basis(3) == \ + F.minimal_approximant_basis([3,3], shifts=None) + True + + One can work column-wise by specifying ``row_wise=False``:: + + sage: P = F.minimal_approximant_basis([5,2,2], [0,1], row_wise=False) + sage: P.is_minimal_approximant_basis(F, [5,2,2], \ + shifts=[0,1], row_wise=False) + True + sage: F.minimal_approximant_basis(3, row_wise=True) == \ + F.transpose().minimal_approximant_basis(3, row_wise=False).transpose() + True + + Errors are raised if the input dimensions are not sound:: + + sage: P = F.minimal_approximant_basis([4], shifts) + Traceback (most recent call last): + ... + ValueError: order length should be the column dimension + + sage: P = F.minimal_approximant_basis(order, [0,0,0,0]) + Traceback (most recent call last): + ... + ValueError: shifts length should be the row dimension + + An error is raised if order does not contain only positive integers:: + + sage: P = F.minimal_approximant_basis([1,0], shifts) + Traceback (most recent call last): + ... + ValueError: order should consist of positive integers + """ + m = self.nrows() + n = self.ncols() + + # set default shifts / check shifts dimension + if shifts == None: + shifts = [0]*m if row_wise else [0]*n + elif row_wise and len(shifts) != m: + raise ValueError('shifts length should be the row dimension') + elif (not row_wise) and len(shifts) != n: + raise ValueError('shifts length should be the column dimension') + + # set default order / check order dimension + if not isinstance(order,list): + order = [order]*n if row_wise else [order]*m + + if row_wise and len(order) != n: + raise ValueError("order length should be the column dimension") + elif (not row_wise) and len(order) != m: + raise ValueError("order length should be the row dimension") + + for o in order: + if o < 1: + raise ValueError("order should consist of positive integers") + + # compute approximant basis + # if required, normalize it into shifted Popov form + if row_wise: + P,rdeg = self._approximant_basis_iterative(order, shifts) + if normal_form: + # compute the list "- pivot degree" + # (since weak Popov, pivot degree is rdeg-shifts entrywise) + # Note: -deg(P[i,i]) = shifts[i] - rdeg[i] + degree_shifts = [shifts[i] - rdeg[i] for i in range(m)] + # compute approximant basis with that list as shifts + P,rdeg = self._approximant_basis_iterative(order, + degree_shifts) + # left-multiply by inverse of leading matrix + lmat = P.leading_matrix(shifts=degree_shifts) + P = lmat.inverse() * P + else: + P,rdeg = self.transpose()._approximant_basis_iterative(order, + shifts) + if normal_form: + # compute the list "- pivot degree" + # (since weak Popov, pivot degree is rdeg-shifts entrywise) + degree_shifts = [shifts[i] - rdeg[i] for i in range(n)] + # compute approximant basis with that list as shifts + P,rdeg = self.transpose()._approximant_basis_iterative( \ + order, degree_shifts) + P = P.transpose() + # right-multiply by inverse of leading matrix + lmat = P.leading_matrix(shifts=degree_shifts,row_wise=False) + P = P * lmat.inverse() + else: + P = P.transpose() + + return P + + def _approximant_basis_iterative(self, order, shifts): + r""" + Return a ``shifts``-ordered weak Popov approximant basis for this + polynomial matrix at order ``order`` + (see :meth:`minimal_approximant_basis` for definitions). + + The output basis is considered row-wise, that is, its rows are + left-approximants for the columns of ``self``. It is guaranteed that + the degree of the output basis is at most the maximum of the entries of + ``order``, independently of ``shifts``. + + The input dimensions are supposed to be sound: the length of ``order`` + must be the number of columns of ``self``, while the length of + ``shifts`` must be the number of rows of ``self``. + + INPUT: + + - ``order`` -- a list of positive integers. + + - ``shifts`` -- a list of integers. + + OUTPUT: + + - a polynomial matrix (the approximant basis ``P``). + + - a list of integers (the shifts-row degrees of ``P``). + + ALGORITHM: + + This is inspired from the iterative algorithms described in [VBB1992]_ + and [BL1994]_ . + + EXAMPLES:: + + sage: pR. = GF(7)[] + + This method supports any number of columns or rows, as well as + arbitrary shifts and orders:: + + sage: order = [4, 1, 2]; shifts = [-3, 4] + sage: pmat = Matrix(pR, [[5*x^3 + 4*x^2 + 4*x + 6, 5, 4], \ + [2*x^3 + 2*x^2 + 2*x + 3, 6, 6*x + 3]]) + sage: appbas,rdeg = pmat._approximant_basis_iterative(order, \ + shifts) + sage: appbas.is_minimal_approximant_basis(pmat, order, shifts) + True + + The returned list is the shifted row degrees of ``appbas``:: + + sage: rdeg == appbas.row_degrees(shifts) + True + + Approximant bases for the zero matrix are all constant unimodular + matrices; in fact, this algorithm returns the identity:: + + sage: pmat = Matrix(pR, 3, 2) + sage: appbas,rdeg = pmat._approximant_basis_iterative([2,5], \ + [5,0,-4]) + sage: rdeg == [5,0,-4] and appbas == Matrix.identity(pR, 3) + True + """ + # Define parameters and perform some sanity checks + m = self.nrows() + n = self.ncols() + polynomial_ring = self.base_ring() + X = polynomial_ring.gen() + + # 'rest_order': the orders that remains to be dealt with + # 'rest_index': indices of orders that remains to be dealt with + rest_order = list(order) + rest_index = list(range(n)) + + # initialization of the residuals (= input self) + # and of the approximant basis (= identity matrix) + from sage.matrix.constructor import identity_matrix + appbas = identity_matrix(polynomial_ring, m) + residuals = self.__copy__() + + # throughout the algorithm, 'rdeg' will be the shifts-row degrees of + # 'appbas' + # --> initially, 'rdeg' is the shift-row degree of the identity matrix + rdeg = list(shifts) + + while rest_order: + # invariant: + # * appbas is a shifts-ordered weak Popov approximant basis for + # (self,doneorder) + # where doneorder = the already processed order, that is, the + # tuple order-rest_order (entrywise subtraction) + # * rdeg is the shifts-row degree of appbas + # * residuals is the submatrix of columns (appbas * self)[:,j] + # for all j such that rest_order[j] > 0 + + # choice for the next coefficient to be dealt with: first of the + # largest entries in order (--> process 'self' degree-wise, and + # left to right) + # Note: one may also consider the first one in order (--> process + # 'self' columnwise, from left column to right column, set j=0 + # instead of the below), but it seems to often be (barely) slower + max_rest_order = max(rest_order) + for ind, value in enumerate(rest_order): + if value == max_rest_order: + j = ind + break + d = order[rest_index[j]] - rest_order[j] + + # coefficient = the coefficient of degree d of the column j of the + # residual matrix + # --> this is very likely nonzero and we want to make it zero, so + # that this column becomes zero mod X^{d+1} + coefficient = [residuals[i, j][d] for i in range(m)] + + # Lambda: collect rows [i] with nonzero coefficient[i] + # pi: index of the first row with smallest shift, among those in + # Lambda + Lambda = [] + pi = -1 + for i in range(m): + if coefficient[i] != 0: + Lambda.append(i) + if pi < 0 or rdeg[i] < rdeg[pi]: + pi = i + if Lambda: # otherwise, nothing to do + # update all rows in Lambda--{pi} + Lambda.remove(pi) + for row in Lambda: + scalar = -coefficient[row]/coefficient[pi] + appbas.add_multiple_of_row(row, pi, scalar) + residuals.add_multiple_of_row(row, pi, scalar) + # update row pi + rdeg[pi] += 1 + appbas.rescale_row(pi, X) + residuals.rescale_row(pi, X) + + # Decrement rest_order[j], unless there is no more work to do in + # this column, i.e. if rest_order[j] was 1: + # in this case remove the column j of + # residual,rest_order,rest_index + if rest_order[j] == 1: + residuals = residuals.delete_columns([j]) + rest_order.pop(j) + rest_index.pop(j) + else: + rest_order[j] -= 1 + return appbas, rdeg diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index dd30e6323d4..680c0a8a389 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -1277,11 +1277,11 @@ cdef class Matrix_rational_dense(Matrix_dense): sig_off() return 0 - def _adjoint(self): + def _adjugate(self): """ - Return the adjoint of this matrix. + Return the adjugate of this matrix. - Assumes self is a square matrix (checked in adjoint). + Assumes self is a square matrix (checked in adjugate). EXAMPLES:: @@ -1289,7 +1289,7 @@ cdef class Matrix_rational_dense(Matrix_dense): [1/9 2/9 1/3] [4/9 5/9 2/3] [7/9 8/9 1] - sage: m.adjoint() + sage: m.adjugate() [-1/27 2/27 -1/27] [ 2/27 -4/27 2/27] [-1/27 2/27 -1/27] diff --git a/src/sage/matrix/misc.pyx b/src/sage/matrix/misc.pyx index 55d80be5941..180beae4f53 100644 --- a/src/sage/matrix/misc.pyx +++ b/src/sage/matrix/misc.pyx @@ -11,7 +11,7 @@ relevant classes and this file deleted. """ from __future__ import absolute_import -from cysignals.signals cimport sig_on, sig_off +from cysignals.signals cimport sig_check from sage.ext.mod_int cimport * from sage.libs.gmp.mpz cimport * @@ -59,7 +59,7 @@ def matrix_integer_dense_rational_reconstruction(Matrix_integer_dense A, Integer A -- matrix N -- an integer - EXAMPLES: + EXAMPLES:: sage: B = ((matrix(ZZ, 3,4, [1,2,3,-4,7,2,18,3,4,3,4,5])/3)%500).change_ring(ZZ) sage: sage.matrix.misc.matrix_integer_dense_rational_reconstruction(B, 500) @@ -83,70 +83,66 @@ def matrix_integer_dense_rational_reconstruction(Matrix_integer_dense A, Integer R = Matrix_rational_dense.__new__(Matrix_rational_dense, A.parent().change_ring(QQ), 0,0,0) - cdef mpz_t a, bnd, other_bnd, one, denom, tmp + cdef mpz_t a, bnd, other_bnd, denom, tmp cdef mpq_t qtmp cdef Integer _bnd cdef Py_ssize_t i, j cdef int do_it - import math - - sig_on() - try: - mpz_init_set_si(denom, 1) - mpz_init(a) - mpz_init(tmp) - mpz_init_set_si(one, 1) - mpz_init(other_bnd) - mpq_init(qtmp) - - _bnd = (N//2).isqrt() - mpz_init_set(bnd, _bnd.value) - mpz_sub(other_bnd, N.value, bnd) - - for i from 0 <= i < A._nrows: - for j from 0 <= j < A._ncols: - A.get_unsafe_mpz(i, j, a) - if mpz_cmp(denom, one) != 0: - mpz_mul(a, a, denom) - mpz_fdiv_r(a, a, N.value) - do_it = 0 - if mpz_cmp(a, bnd) <= 0: - do_it = 1 - elif mpz_cmp(a, other_bnd) >= 0: - mpz_sub(a, a, N.value) - do_it = 1 - if do_it: - fmpz_set_mpz(fmpq_mat_entry_num(R._matrix, i, j), a) - if mpz_cmp(denom, one) != 0: - fmpz_set_mpz(fmpq_mat_entry_den(R._matrix, i, j), denom) - fmpq_canonicalise(fmpq_mat_entry(R._matrix, i, j)) - else: - fmpz_one(fmpq_mat_entry_den(R._matrix, i, j)) + + mpz_init_set_si(denom, 1) + mpz_init(a) + mpz_init(tmp) + mpz_init(other_bnd) + mpq_init(qtmp) + + _bnd = (N//2).isqrt() + mpz_init_set(bnd, _bnd.value) + mpz_sub(other_bnd, N.value, bnd) + + for i in range(A._nrows): + for j in range(A._ncols): + sig_check() + A.get_unsafe_mpz(i, j, a) + if mpz_cmp_ui(denom, 1) != 0: + mpz_mul(a, a, denom) + mpz_fdiv_r(a, a, N.value) + do_it = 0 + if mpz_cmp(a, bnd) <= 0: + do_it = 1 + elif mpz_cmp(a, other_bnd) >= 0: + mpz_sub(a, a, N.value) + do_it = 1 + if do_it: + fmpz_set_mpz(fmpq_mat_entry_num(R._matrix, i, j), a) + if mpz_cmp_ui(denom, 1) != 0: + fmpz_set_mpz(fmpq_mat_entry_den(R._matrix, i, j), denom) + fmpq_canonicalise(fmpq_mat_entry(R._matrix, i, j)) else: - # Otherwise have to do it the hard way - A.get_unsafe_mpz(i, j, tmp) - mpq_rational_reconstruction(qtmp, tmp, N.value) - mpz_lcm(denom, denom, mpq_denref(qtmp)) - fmpq_set_mpq(fmpq_mat_entry(R._matrix, i, j), qtmp) - - mpz_clear(denom) - mpz_clear(a) - mpz_clear(tmp) - mpz_clear(one) - mpz_clear(other_bnd) - mpz_clear(bnd) - mpq_clear(qtmp) - finally: - sig_off() + fmpz_one(fmpq_mat_entry_den(R._matrix, i, j)) + else: + # Otherwise have to do it the hard way + A.get_unsafe_mpz(i, j, tmp) + mpq_rational_reconstruction(qtmp, tmp, N.value) + mpz_lcm(denom, denom, mpq_denref(qtmp)) + fmpq_set_mpq(fmpq_mat_entry(R._matrix, i, j), qtmp) + + mpz_clear(denom) + mpz_clear(a) + mpz_clear(tmp) + mpz_clear(other_bnd) + mpz_clear(bnd) + mpq_clear(qtmp) + return R + def matrix_integer_sparse_rational_reconstruction(Matrix_integer_sparse A, Integer N): """ Given a sparse matrix over the integers and an integer modulus, do rational reconstruction on all entries of the matrix, viewed as numbers mod N. - EXAMPLES: + EXAMPLES:: sage: A = matrix(ZZ, 3, 4, [(1/3)%500, 2, 3, (-4)%500, 7, 2, 2, 3, 4, 3, 4, (5/7)%500], sparse=True) sage: sage.matrix.misc.matrix_integer_sparse_rational_reconstruction(A, 500) @@ -171,68 +167,63 @@ def matrix_integer_sparse_rational_reconstruction(Matrix_integer_sparse A, Integ A.parent().change_ring(QQ), 0,0,0) cdef mpq_t t - cdef mpz_t a, bnd, other_bnd, one, denom + cdef mpz_t a, bnd, other_bnd, denom cdef Integer _bnd cdef Py_ssize_t i, j cdef int do_it cdef mpz_vector* A_row cdef mpq_vector* R_row - import math - - sig_on() - try: - mpq_init(t) - mpz_init_set_si(denom, 1) - mpz_init(a) - mpz_init_set_si(one, 1) - mpz_init(other_bnd) - - _bnd = (N//2).isqrt() - mpz_init_set(bnd, _bnd.value) - mpz_sub(other_bnd, N.value, bnd) - - for i from 0 <= i < A._nrows: - A_row = &A._matrix[i] - R_row = &R._matrix[i] - reallocate_mpq_vector(R_row, A_row.num_nonzero) - R_row.num_nonzero = A_row.num_nonzero - R_row.degree = A_row.degree - for j from 0 <= j < A_row.num_nonzero: - mpz_set(a, A_row.entries[j]) - if mpz_cmp(denom, one) != 0: - mpz_mul(a, a, denom) - mpz_fdiv_r(a, a, N.value) - do_it = 0 - if mpz_cmp(a, bnd) <= 0: - do_it = 1 - elif mpz_cmp(a, other_bnd) >= 0: - mpz_sub(a, a, N.value) - do_it = 1 - if do_it: - mpz_set(mpq_numref(t), a) - if mpz_cmp(denom, one) != 0: - mpz_set(mpq_denref(t), denom) - mpq_canonicalize(t) - else: - mpz_set_si(mpq_denref(t), 1) - mpq_set(R_row.entries[j], t) - R_row.positions[j] = A_row.positions[j] + + mpq_init(t) + mpz_init_set_si(denom, 1) + mpz_init(a) + mpz_init(other_bnd) + + _bnd = (N//2).isqrt() + mpz_init_set(bnd, _bnd.value) + mpz_sub(other_bnd, N.value, bnd) + + for i in range(A._nrows): + sig_check() + A_row = &A._matrix[i] + R_row = &R._matrix[i] + reallocate_mpq_vector(R_row, A_row.num_nonzero) + R_row.num_nonzero = A_row.num_nonzero + R_row.degree = A_row.degree + for j in range(A_row.num_nonzero): + sig_check() + mpz_set(a, A_row.entries[j]) + if mpz_cmp_ui(denom, 1) != 0: + mpz_mul(a, a, denom) + mpz_fdiv_r(a, a, N.value) + do_it = 0 + if mpz_cmp(a, bnd) <= 0: + do_it = 1 + elif mpz_cmp(a, other_bnd) >= 0: + mpz_sub(a, a, N.value) + do_it = 1 + if do_it: + mpz_set(mpq_numref(t), a) + if mpz_cmp_ui(denom, 1) != 0: + mpz_set(mpq_denref(t), denom) + mpq_canonicalize(t) else: - # Otherwise have to do it the hard way - mpq_rational_reconstruction(t, A_row.entries[j], N.value) - mpq_set(R_row.entries[j], t) - R_row.positions[j] = A_row.positions[j] - mpz_lcm(denom, denom, mpq_denref(t)) - - mpq_clear(t) - - mpz_clear(denom) - mpz_clear(a) - mpz_clear(one) - mpz_clear(other_bnd) - mpz_clear(bnd) - finally: - sig_off() + mpz_set_si(mpq_denref(t), 1) + mpq_set(R_row.entries[j], t) + R_row.positions[j] = A_row.positions[j] + else: + # Otherwise have to do it the hard way + mpq_rational_reconstruction(t, A_row.entries[j], N.value) + mpq_set(R_row.entries[j], t) + R_row.positions[j] = A_row.positions[j] + mpz_lcm(denom, denom, mpq_denref(t)) + + mpq_clear(t) + mpz_clear(denom) + mpz_clear(a) + mpz_clear(other_bnd) + mpz_clear(bnd) + return R @@ -290,7 +281,7 @@ def matrix_rational_echelon_form_multimodular(Matrix self, height_guess=None, pr where H denotes the height. If this fails, do step 4 with a few more primes. - EXAMPLES: + EXAMPLES:: sage: A = matrix(QQ, 3, 7, [1..21]) sage: from sage.matrix.misc import matrix_rational_echelon_form_multimodular @@ -440,8 +431,6 @@ def matrix_rational_echelon_form_multimodular(Matrix self, height_guess=None, pr return E, tuple(best_pivots) -########################### - def cmp_pivots(x, y): """ Compare two sequences of pivot columns. @@ -485,12 +474,6 @@ def cmp_pivots(x, y): return -1 - -####################################### - - - -####################################### def hadamard_row_bound_mpfr(Matrix A): """ Given a matrix A with entries that coerce to RR, compute the row @@ -540,9 +523,10 @@ def hadamard_row_bound_mpfr(Matrix A): mpfr_init(pr) mpfr_set_si(d, 0, MPFR_RNDU) - for i from 0 <= i < A._nrows: + for i in range(A._nrows): mpfr_set_si(s, 0, MPFR_RNDU) - for j from 0 <= j < A._ncols: + for j in range(A._ncols): + sig_check() a = A.get_unsafe(i, j) mpfr_mul(pr, a.value, a.value, MPFR_RNDU) mpfr_add(s, s, pr, MPFR_RNDU) @@ -555,4 +539,3 @@ def hadamard_row_bound_mpfr(Matrix A): mpfr_clear(d) mpfr_clear(pr) return b.ceil() - diff --git a/src/sage/matroids/circuit_closures_matroid.pyx b/src/sage/matroids/circuit_closures_matroid.pyx index fda80fdf1db..3042c3f3e1c 100644 --- a/src/sage/matroids/circuit_closures_matroid.pyx +++ b/src/sage/matroids/circuit_closures_matroid.pyx @@ -251,12 +251,12 @@ cdef class CircuitClosuresMatroid(Matroid): False """ - for r in sorted(self._circuit_closures.keys()): + for r in sorted(self._circuit_closures): if len(F) <= r: break for C in self._circuit_closures[r]: S = F & C - if(len(S) > r): + if len(S) > r: return False return True @@ -315,17 +315,16 @@ cdef class CircuitClosuresMatroid(Matroid): sage: sorted(M._circuit(set(['a', 'c', 'd']))) Traceback (most recent call last): ... - ValueError: no circuit in independent set. - + ValueError: no circuit in independent set """ - for r in sorted(self._circuit_closures.keys()): + for r in sorted(self._circuit_closures): for C in self._circuit_closures[r]: S = set(F & C) - if(len(S) > r): + if len(S) > r: while len(S) > r + 1: S.pop() return frozenset(S) - raise ValueError("no circuit in independent set.") + raise ValueError("no circuit in independent set") cpdef circuit_closures(self): """ diff --git a/src/sage/matroids/dual_matroid.py b/src/sage/matroids/dual_matroid.py index fe7a75f8906..d760891c877 100644 --- a/src/sage/matroids/dual_matroid.py +++ b/src/sage/matroids/dual_matroid.py @@ -311,8 +311,7 @@ def _cocircuit(self, X): sage: sorted(M._cocircuit(set(['a', 'c', 'd']))) Traceback (most recent call last): ... - ValueError: no circuit in independent set. - + ValueError: no circuit in independent set """ return self._matroid._circuit(X) diff --git a/src/sage/matroids/graphic_matroid.py b/src/sage/matroids/graphic_matroid.py index 15ab6b4dffe..deb95a2b3fe 100644 --- a/src/sage/matroids/graphic_matroid.py +++ b/src/sage/matroids/graphic_matroid.py @@ -202,7 +202,7 @@ def __init__(self, G, groundset=None): self._groundset = groundset_set # Map vertices on input graph to vertices in self._G - self._vertex_map = {v: v for v in G.vertices()} + self._vertex_map = {v: v for v in G.vertex_iterator()} comps = G.connected_components() while len(comps) > 1: comp = comps.pop() @@ -227,7 +227,7 @@ def __init__(self, G, groundset=None): # Map ground set elements to graph edges: # The the edge labels should already be the elements. self._groundset_edge_map = ({l: (u, v) for - (u, v, l) in self._G.edges()}) + (u, v, l) in self._G.edge_iterator()}) def groundset(self): """ @@ -329,19 +329,19 @@ def _vertex_stars(self): EXAMPLES:: sage: M = Matroid(range(5), graphs.DiamondGraph()) - sage: sorted(M._vertex_stars()) - [frozenset({0, 2, 3}), + sage: sorted(M._vertex_stars(), key=str) + [frozenset({0, 1}), + frozenset({0, 2, 3}), frozenset({1, 2, 4}), - frozenset({3, 4}), - frozenset({0, 1})] + frozenset({3, 4})] sage: N = Matroid(range(5), graphs.BullGraph()) - sage: sorted(N._vertex_stars()) - [frozenset({0, 2, 3}), - frozenset({4}), + sage: sorted(N._vertex_stars(), key=str) + [frozenset({0, 1}), + frozenset({0, 2, 3}), frozenset({1, 2, 4}), frozenset({3}), - frozenset({0, 1})] + frozenset({4})] """ star_list = [] for v in self._G.vertices(): @@ -1351,15 +1351,15 @@ def graphic_extension(self, u, v=None, element=None): sage: M = matroids.CompleteGraphic(4) sage: M1 = M.graphic_extension(0,1,'a'); M1 Graphic matroid of rank 3 on 7 elements - sage: M1.graph().edges() - [(0, 1, 0), (0, 1, 'a'), (0, 2, 1), (0, 3, 2), (1, 2, 3), (1, 3, 4), (2, 3, 5)] + sage: list(M1.graph().edge_iterator()) + [(0, 1, 'a'), (0, 1, 0), (0, 2, 1), (0, 3, 2), (1, 2, 3), (1, 3, 4), (2, 3, 5)] sage: M2 = M1.graphic_extension(3); M2 Graphic matroid of rank 3 on 8 elements :: sage: M = Matroid(range(10), graphs.PetersenGraph()) - sage: M.graphic_extension(0, 'b', 'c').graph().vertices() + sage: sorted(M.graphic_extension(0, 'b', 'c').graph().vertex_iterator(), key=str) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'b'] sage: M.graphic_extension('a', 'b', 'c').graph().vertices() Traceback (most recent call last): @@ -1427,14 +1427,14 @@ def graphic_extensions(self, element=None, vertices=None, simple=False): sage: M = Matroid(range(5), graphs.DiamondGraph()) sage: I = M.graphic_extensions('a') sage: for N in I: - ....: N.graph().edges() + ....: list(N.graph().edge_iterator()) [(0, 0, 'a'), (0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4)] - [(0, 1, 0), (0, 1, 'a'), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4)] - [(0, 1, 0), (0, 2, 1), (0, 2, 'a'), (1, 2, 2), (1, 3, 3), (2, 3, 4)] + [(0, 1, 'a'), (0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4)] + [(0, 1, 0), (0, 2, 'a'), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4)] [(0, 1, 0), (0, 2, 1), (0, 3, 'a'), (1, 2, 2), (1, 3, 3), (2, 3, 4)] - [(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 2, 'a'), (1, 3, 3), (2, 3, 4)] - [(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (1, 3, 'a'), (2, 3, 4)] - [(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4), (2, 3, 'a')] + [(0, 1, 0), (0, 2, 1), (1, 2, 'a'), (1, 2, 2), (1, 3, 3), (2, 3, 4)] + [(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 'a'), (1, 3, 3), (2, 3, 4)] + [(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 'a'), (2, 3, 4)] :: @@ -1550,8 +1550,8 @@ def graphic_coextension(self, u, v=None, X=None, element=None): sage: M = Matroid(graphs.DiamondGraph()) sage: N = M.graphic_coextension(0,'q') - sage: N.graph().vertices() - [0, 1, 2, 3, 'q'] + sage: list(N.graph().vertex_iterator()) + ['q', 0, 1, 2, 3] :: @@ -1630,16 +1630,15 @@ def graphic_coextensions(self, vertices=None, v=None, element=None, cosimple=Fal sage: G = Graph([(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 4), (2, 3), (3, 4)]) sage: M = Matroid(range(8), G) sage: I = M.graphic_coextensions(vertices=[0], element='a') - sage: for N in I: - ....: N.graph().edges_incident(0, sort=True) - [(0, 1, 0), (0, 2, 1), (0, 3, 2), (0, 4, 3), (0, 5, 'a')] - [(0, 2, 1), (0, 3, 2), (0, 4, 3), (0, 5, 'a')] - [(0, 1, 0), (0, 2, 1), (0, 3, 2), (0, 5, 'a')] - [(0, 1, 0), (0, 3, 2), (0, 4, 3), (0, 5, 'a')] - [(0, 1, 0), (0, 2, 1), (0, 4, 3), (0, 5, 'a')] - [(0, 2, 1), (0, 3, 2), (0, 5, 'a')] - [(0, 1, 0), (0, 3, 2), (0, 5, 'a')] - [(0, 1, 0), (0, 2, 1), (0, 5, 'a')] + sage: sorted([N.graph().edges_incident(0, sort=True) for N in I],key=str) + [[(0, 1, 0), (0, 2, 1), (0, 3, 2), (0, 4, 3), (0, 5, 'a')], + [(0, 1, 0), (0, 2, 1), (0, 3, 2), (0, 5, 'a')], + [(0, 1, 0), (0, 2, 1), (0, 4, 3), (0, 5, 'a')], + [(0, 1, 0), (0, 2, 1), (0, 5, 'a')], + [(0, 1, 0), (0, 3, 2), (0, 4, 3), (0, 5, 'a')], + [(0, 1, 0), (0, 3, 2), (0, 5, 'a')], + [(0, 2, 1), (0, 3, 2), (0, 4, 3), (0, 5, 'a')], + [(0, 2, 1), (0, 3, 2), (0, 5, 'a')]] :: diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 6e9c00ef137..730b2ebb9ac 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -2751,18 +2751,16 @@ cdef class LinearMatroid(BasisExchangeMatroid): n = len(X) m = len(Y) - sol=False + sol = False T = spanning_stars(M) - for (x1,y1) in T: + for (x1, y1) in T: # The whiting out B = copy(M) - for (x,y) in product(range(n),range(m)): - if (x1!=x and y1!=y): - if(M[x1,y]!=0 and - M[x,y1]!=0 and - M[x,y]!=0): - B[x,y]=0 + for (x, y) in product(range(n), range(m)): + if (x1 != x and y1 != y): + if (M[x1, y] != 0 and M[x, y1] != 0 and M[x, y] != 0): + B[x, y] = 0 # remove row x1 and y1 Xp = list(xrange(n)) @@ -2784,7 +2782,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): Q_rows = [] Q_cols = [] # make sure the matrix has rank 2 - if(M.matrix_from_rows_and_columns(P_rows,P_cols).rank()==2): + if M.matrix_from_rows_and_columns(P_rows,P_cols).rank() == 2: sol,cert_pair = M2.shifting_all(P_rows, P_cols, Q_rows, Q_cols, 3) if sol: break @@ -5869,7 +5867,7 @@ cdef class RegularMatroid(LinearMatroid): """ if self._r_projection is None: R = self._basic_representation()._matrix_() - self._r_projection = R.transpose() * (R * R.transpose()).adjoint() * R + self._r_projection = R.transpose() * (R * R.transpose()).adjugate() * R return self._r_projection cpdef _invariant(self): diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 26dbb1e94a7..8407ed1f6f1 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -1472,7 +1472,7 @@ cdef class Matroid(SageObject): sage: sorted(M.circuit(['a', 'c', 'd'])) Traceback (most recent call last): ... - ValueError: no circuit in independent set. + ValueError: no circuit in independent set sage: M.circuit(['x']) Traceback (most recent call last): ... @@ -5482,12 +5482,10 @@ cdef class Matroid(SageObject): for (x1,y1) in T: # The whiting out B = M - for (x,y) in product(range(n),range(m)): - if (x1!=x and y1!=y): - if(M[x1,y]==1 and - M[x,y1]==1 and - M[x,y]==1): - B[x,y]=0 + for (x, y) in product(range(n), range(m)): + if x1 != x and y1 != y: + if M[x1, y] == 1 and M[x, y1] == 1 and M[x, y] == 1: + B[x, y] = 0 # remove row x1 and y1 Xp = list(xrange(n)) @@ -5651,16 +5649,16 @@ cdef class Matroid(SageObject): #rowshifts rowshift = False for x in set(remainX): - if(self.rank(Y_1|(X-(X_2|set([x])))) - len(X-(X_2|set([x]))) - > self.rank(Y_1|(X-X_2)) - len(X-X_2)): + if (self.rank(Y_1|(X-(X_2|set([x])))) - len(X-(X_2|set([x]))) + > self.rank(Y_1|(X-X_2)) - len(X-X_2)): X_1.add(x) remainX.remove(x) rowshift = True #colshifts colshift = False for y in set(remainY): - if(self.rank(Y_2|set([y])|(X-X_1)) - len(X-X_1) - > self.rank(Y_2|(X-X_1)) - len(X-X_1)): + if (self.rank(Y_2|set([y])|(X-X_1)) - len(X-X_1) + > self.rank(Y_2|(X-X_1)) - len(X-X_1)): Y_1.add(y) remainY.remove(y) colshift = True diff --git a/src/sage/matroids/matroids_plot_helpers.py b/src/sage/matroids/matroids_plot_helpers.py index f5ab9ece748..373a45089de 100644 --- a/src/sage/matroids/matroids_plot_helpers.py +++ b/src/sage/matroids/matroids_plot_helpers.py @@ -67,7 +67,7 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # ***************************************************************************** from __future__ import print_function @@ -113,21 +113,21 @@ def it(M, B1, nB1, lps): EXAMPLES:: sage: from sage.matroids import matroids_plot_helpers as mph - sage: M=Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0], + sage: M = Matroid(ring=GF(2), matrix=[[1, 0, 0, 0, 1, 1, 1,0], ....: [0, 1, 0, 1, 0, 1, 1,0],[0, 0, 1, 1, 1, 0, 1,0]]) - sage: N=M.simplify() - sage: B1=list(N.basis()) - sage: nB1=list(set(M.simplify().groundset())-set(B1)) - sage: pts,trilines,nontripts,curvedlines=mph.it(M, + sage: N = M.simplify() + sage: B1 = list(N.basis()) + sage: nB1 = list(set(M.simplify().groundset())-set(B1)) + sage: pts,trilines,nontripts,curvedlines = mph.it(M, ....: B1,nB1,M.loops()) - sage: print(pts) - {1: (1.0, 0.0), 2: (1.5, 1.0), 3: (0.5, 1.0), 4: (0, 0), 5: (1, 2), - 6: (2, 0)} - sage: print(trilines) + sage: pts + {1: (1.0, 0.0), 2: (1.5, 1.0), 3: (0.5, 1.0), + 4: (0, 0), 5: (1, 2), 6: (2, 0)} + sage: trilines [[3, 4, 5], [2, 5, 6], [1, 4, 6]] - sage: print(nontripts) + sage: nontripts [0] - sage: print(curvedlines) + sage: curvedlines [[0, 1, 5], [0, 2, 4], [0, 3, 6], [1, 2, 3], [1, 4, 6], [2, 5, 6], [3, 4, 5]] @@ -198,8 +198,8 @@ def trigrid(tripts): EXAMPLES:: sage: from sage.matroids import matroids_plot_helpers - sage: points=matroids_plot_helpers.trigrid([[2,1],[4,5],[5,2]]) - sage: print(points) + sage: points = matroids_plot_helpers.trigrid([[2,1],[4,5],[5,2]]) + sage: points [[3.6666666666666665, 2.6666666666666665], [3.222222222222222, 2.888888888888889], [4.222222222222222, 3.222222222222222], @@ -210,7 +210,6 @@ def trigrid(tripts): This method does NOT do any checks. """ - n = 0 pairs = [[0, 1], [1, 2], [0, 2]] cpt = list((float(tripts[0][0]+tripts[1][0]+tripts[2][0])/3, float(tripts[0][1]+tripts[1][1]+tripts[2][1])/3)) @@ -427,10 +426,9 @@ def slp(M1, pos_dict=None, B=None): """ L = set(M1.loops()) - sg = sorted(M1.simplify().groundset()) nP = L | set(M1.simplify().groundset()) P = set(M1.groundset())-nP - if len(P) > 0: + if P: if pos_dict is not None: pcls = list(set([frozenset(set(M1.closure([p])) - L) for p in list(P)])) @@ -501,10 +499,10 @@ def addlp(M, M1, L, P, ptsdict, G=None, limits=None): if G is None: G = Graphics() # deal with loops - if len(L) > 0: + if L: loops = L - looptext = ", ".join([str(l) for l in loops]) - if(limits is None): + looptext = ", ".join(str(l) for l in loops) + if limits is None: rectx = -1 recty = -1 else: @@ -523,7 +521,7 @@ def addlp(M, M1, L, P, ptsdict, G=None, limits=None): fontsize=13, color='black') limits = tracklims(limits, [rectx, rectx+rectw], [recty, recty+recth]) # deal with parallel elements - if len(P) > 0: + if P: # create list of lists where inner lists are parallel classes pcls = [] gnd = sorted(list(M1.groundset())) @@ -684,7 +682,6 @@ def posdict_is_sane(M1, pos_dict): matroid and ``posdict`` is assumed to be a dictionary. """ L = set(M1.loops()) - sg = sorted(M1.simplify().groundset()) nP = L | set(M1.simplify().groundset()) P = set(M1.groundset())-nP pcls = list(set([frozenset(set(M1.closure([p])) - L) for p in list(P)])) diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index 67b7c67ba24..47263951ab1 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -416,8 +416,6 @@ the parent as its first argument:: # **************************************************************************** from __future__ import print_function, absolute_import -from cpython cimport PyObject - cdef extern from "methodobject.h": cdef int METH_NOARGS, METH_O cdef int PyCFunction_GetFlags(object op) except -1 diff --git a/src/sage/misc/citation.pyx b/src/sage/misc/citation.pyx index 86b850af467..3145a599f38 100644 --- a/src/sage/misc/citation.pyx +++ b/src/sage/misc/citation.pyx @@ -5,7 +5,7 @@ Dependency usage tracking for citations from __future__ import absolute_import from sage.misc.all import tmp_filename -from sage.env import SAGE_ROOT +from sage.env import SAGE_LOCAL systems = {} systems['PARI'] = ['cypari2', 'sage.interfaces.gp'] @@ -48,16 +48,18 @@ systems['M4RI'] = ['sage.matrix.matrix_mod2_dense'] systems['Givaro'] = ['sage.rings.finite_rings.element_givaro'] systems['PolyBoRi'] = ['sage.rings.polynomial.pbori'] + def get_systems(cmd): """ - Returns a list of the systems used in running the command ``cmd``. + Return a list of the systems used in running the command ``cmd``. + Note that the results can sometimes include systems that did not actually contribute to the computation. Due to caching, it could miss some dependencies as well. INPUT: - - ``cmd`` - a string to run + - ``cmd`` -- a string to run .. WARNING:: @@ -74,7 +76,7 @@ def get_systems(cmd): sage: integrate(x^2, x) # Priming coercion model 1/3*x^3 sage: get_systems('integrate(x^2, x)') - ['ginac', 'Maxima'] + ['Maxima', 'ginac'] sage: R. = QQ[] sage: I = R.ideal(x^2+y^2, z^2+y) sage: get_systems('I.primary_decomposition()') @@ -110,7 +112,8 @@ def get_systems(cmd): stats = pstats.Stats(filename) #Strings is a list of method names and modules which get run - strings = [a[0].replace(SAGE_ROOT, "") + " " + a[2] for a in stats.stats.keys()] + strings = [a[0].replace(SAGE_LOCAL, "") + " " + a[2] + for a in stats.stats] #Remove trivial functions bad_res = [re.compile(r'is_.*Element'), re.compile("is_[a-z_]*_type")] @@ -128,7 +131,7 @@ def get_systems(cmd): if any((r in s) or (r.replace('.', '/') in s) for r in systems[system] for s in strings): systems_used.append(system) - return systems_used + return sorted(systems_used) cdef extern from *: @@ -140,6 +143,7 @@ cdef extern from *: #endif """ + cpdef inline bint cython_profile_enabled(): """ Return whether Cython profiling is enabled. diff --git a/src/sage/misc/converting_dict.py b/src/sage/misc/converting_dict.py index 4b0dbb02f1b..f9bdb17bba3 100644 --- a/src/sage/misc/converting_dict.py +++ b/src/sage/misc/converting_dict.py @@ -27,25 +27,23 @@ sage: K. = QQ[] sage: I = ideal([x^2+2*y-5,x+y+3]) - sage: v = I.variety(AA)[0]; v - {x: 4.464101615137755?, y: -7.464101615137755?} + sage: V = sorted(I.variety(AA), key=str) + sage: v = V[0] + sage: v['x'], v['y'] + (-2.464101615137755?, -0.535898384862246?) sage: list(v)[0].parent() Multivariate Polynomial Ring in x, y over Algebraic Real Field - sage: v[x] - 4.464101615137755? - sage: v["y"] - -7.464101615137755? """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Martin von Gagern # # This 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 __future__ import absolute_import from six import iteritems diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index dcf21b64a43..057e4afe224 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -33,7 +33,6 @@ sage_include_directories) from sage.misc.misc import SPYX_TMP, sage_makedirs from .temporary_file import tmp_filename -from sage.misc.superseded import deprecated_function_alias from sage.repl.user_globals import get_globals from sage.misc.sage_ostools import restore_cwd, redirection @@ -50,292 +49,7 @@ ] + cblas_libs + [ 'ntl'] - -# Functions which used to be automatically declared. -# We list these here in order to give useful warnings. -old_pxi_names = { - "cysignals.signals": [ - "sig_on", "sig_str", "sig_check", "sig_off", - "sig_retry", "sig_error", "sig_block", "sig_unblock", - "sig_on_no_except", "sig_str_no_except", "sig_check_no_except", - "cython_check_exception", - ], - "sage.ext.stdsage": [ - "PY_NEW", "HAS_DICTIONARY", - ], - "cysignals.memory": [ - "sig_malloc", "sig_realloc", "sig_calloc", "sig_free", - "check_allocarray", "check_reallocarray", - "check_malloc", "check_realloc", "check_calloc", - ], - "libc.string": [ - "strlen", "strcpy", "memset", "memcpy", "memcmp", - ], - "libc.math": [ - "sqrt", "frexp", "ldexp", - ], - "libc.stdio": [ - "stdin", "stdout", "stderr", - "FOPEN_MAX", "FILENAME_MAX", - "fopen", "freopen", "fdopen", "fclose", - "remove", "rename", "tmpfile", - "setvbuf", "BUFSIZ", "setbuf", - "fread", "fwrite", "fflush", - "EOF", "clearerr", "feof", "ferror", - "SEEK_SET", "SEEK_CUR", "SEEK_END", - "fseek", "rewind", "ftell", "fgetpos", "fsetpos", - "scanf", "sscanf", "fscanf", - "printf", "sprintf", "snprintf", "fprintf", - "perror", "gets", "fgets", "getchar", "fgetc", "getc", "ungetc", - "puts", "fputs", "putchar", "fputc", "putc", "getline", - ] - } - - -def _parse_keywords(kwd, s): - r""" - Given a keyword ``kwd`` and a string ``s``, return a list of all arguments - on the same line as that keyword in ``s``, as well as a new copy of ``s`` - in which each occurrence of ``kwd`` is in a comment. If a comment already - occurs on the line containing ``kwd``, no words after the ``#`` are added - to the list. - - EXAMPLES:: - - sage: from sage.misc.cython import _parse_keywords - sage: _parse_keywords('clib', " clib foo bar baz\n #cinclude bar\n") - doctest:...: DeprecationWarning: the Sage-specific Cython pragma '#clib' is deprecated; - use '# distutils: libraries' instead - See http://trac.sagemath.org/24105 for details. - (['foo', 'bar', 'baz'], ' #clib foo bar baz\n #cinclude bar\n') - sage: _parse_keywords('clib', "# qux clib foo bar baz\n #cinclude bar\n") - (['foo', 'bar', 'baz'], '# qux clib foo bar baz\n #cinclude bar\n') - sage: _parse_keywords('clib', "# clib foo bar # baz\n #cinclude bar\n") - (['foo', 'bar'], '# clib foo bar # baz\n #cinclude bar\n') - - TESTS:: - - sage: from sage.misc.cython import parse_keywords - sage: parse_keywords('kwd', "#kwd foo") - doctest:...: DeprecationWarning: parse_keywords is deprecated. Please use sage.misc.cython._parse_keywords instead. - See http://trac.sagemath.org/24105 for details. - (['foo'], '#kwd foo') - """ - j = 0 - v = [] - while True: - # see if kwd occurs - i = s[j:].find(kwd) - if i == -1: break - j = i + j - - # add a hash, if necessary - last_hash = s[:j].rfind('#') - last_newline = s[:j].rfind('\n') - if last_hash > last_newline: - j += len(kwd) - else: - s = s[:j] + '#' + s[j:] - j += len(kwd) + 1 - - # find all other words on this line - k = s[j:].find('\n') - if k == -1: - k = len(s) - - # add them to our list, until we find a comment - for X in s[j:j+k].split(): - if X[0] == '#': # skip rest of line - break - v.append(X) - - if v: - replacements = { - "clang": "# distutils: language", - "clib": "# distutils: libraries", - "cfile": "# distutils: sources", - "cinclude": "# distutils: include_dirs", - "cargs": "# distutils: extra_compile_args", - } - if kwd in replacements: - from sage.misc.superseded import deprecation - deprecation(24105, "the Sage-specific Cython pragma {!r} is deprecated;\n" - "use {!r} instead".format("#" + kwd, replacements[kwd])) - return v, s - - -def _environ_parse(s): - r""" - Given a string s, find each substring of the form ``'\$ABC'``. If the - environment variable :envvar:`$ABC` is set, replace ``'\$ABC'`` with its - value and move on to the next such substring. If it is not set, stop - parsing there. - - EXAMPLES:: - - sage: from sage.misc.cython import _environ_parse - sage: _environ_parse('$SAGE_LOCAL') == SAGE_LOCAL - True - sage: _environ_parse('$THIS_IS_NOT_DEFINED_ANYWHERE') - '$THIS_IS_NOT_DEFINED_ANYWHERE' - sage: os.environ['DEFINE_THIS'] = 'hello' - sage: _environ_parse('$DEFINE_THIS/$THIS_IS_NOT_DEFINED_ANYWHERE/$DEFINE_THIS') - 'hello/$THIS_IS_NOT_DEFINED_ANYWHERE/$DEFINE_THIS' - - TESTS:: - - sage: from sage.misc.cython import environ_parse - sage: environ_parse('$SAGE_LOCAL') == SAGE_LOCAL - doctest:...: DeprecationWarning: environ_parse is deprecated. Please use sage.misc.cython._environ_parse instead. - See http://trac.sagemath.org/24105 for details. - True - """ - i = s.find('$') - if i == -1: - return s - j = s[i:].find('/') - if j == -1: - j = len(s) - else: - j = i + j - name = s[i+1:j] - if name in os.environ: - s = s[:i] + os.environ[name] + s[j:] - else: - return s - return _environ_parse(s) - - -def _pyx_preparse(s): - r""" - Preparse a pyx file: - - * parse ``clang`` pragma (c or c++) - * parse ``clib`` pragma (additional libraries to link in) - * parse ``cinclude`` (additional include directories) - * parse ``cfile`` (additional files to be included) - * parse ``cargs`` (additional parameters passed to the compiler) - - The pragmas: - - - ``clang`` - may be either ``'c'`` or ``'c++'`` indicating whether a C or - C++ compiler should be used - - - ``clib`` - additional libraries to be linked in, the space separated list - is split and passed to distutils. - - - ``cinclude`` - additional directories to search for header files. The - space separated list is split and passed to distutils. - - - ``cfile`` - additional C or C++ files to be compiled. Also, - :envvar:`$SAGE_SRC` and :envvar:`$SAGE_LOCAL` are expanded, but other - environment variables are not. - - - ``cargs`` - additional parameters passed to the compiler - - OUTPUT: preamble, libs, includes, language, files, args - - EXAMPLES:: - - sage: from sage.misc.cython import _pyx_preparse - sage: _pyx_preparse("") - ('', - ['mpfr', - 'gmp', - 'gmpxx', - 'stdc++', - 'pari', - 'm', - 'ec', - 'gsl', - ..., - 'ntl'], - ['.../include', - '.../include/python...', - '.../python.../numpy/core/include', - '...', - '.../sage/ext', - '.../cysignals'], - 'c', - [], ['-w', '-O2'],...) - sage: s, libs, inc, lang, f, args, libdirs = _pyx_preparse("# clang c++\n #clib foo\n # cinclude bar\n") - doctest:...: DeprecationWarning: the Sage-specific Cython pragma '#clang' is deprecated; - use '# distutils: language' instead - See http://trac.sagemath.org/24105 for details. - doctest:...: DeprecationWarning: the Sage-specific Cython pragma '#clib' is deprecated; - use '# distutils: libraries' instead - See http://trac.sagemath.org/24105 for details. - doctest:...: DeprecationWarning: the Sage-specific Cython pragma '#cinclude' is deprecated; - use '# distutils: include_dirs' instead - See http://trac.sagemath.org/24105 for details. - sage: lang - 'c++' - - sage: libs - ['foo', 'mpfr', - 'gmp', 'gmpxx', - 'stdc++', - 'pari', - 'm', - 'ec', - 'gsl', - ..., - 'ntl'] - sage: libs[1:] == sage.misc.cython.standard_libs - True - - sage: inc - ['bar', - '.../include', - '.../include/python...', - '.../python.../numpy/core/include', - '...', - '.../sage/ext', - '.../cysignals'] - - sage: s, libs, inc, lang, f, args, libdirs = _pyx_preparse("# cargs -O3 -ggdb\n") - doctest:...: DeprecationWarning: the Sage-specific Cython pragma '#cargs' is deprecated; - use '# distutils: extra_compile_args' instead - See http://trac.sagemath.org/24105 for details. - sage: args - ['-w', '-O2', '-O3', '-ggdb'] - - TESTS:: - - sage: from sage.misc.cython import pyx_preparse - sage: _ = pyx_preparse("") - doctest:...: DeprecationWarning: pyx_preparse is deprecated. Please use sage.misc.cython._pyx_preparse instead. - See http://trac.sagemath.org/24105 for details. - """ - lang, s = _parse_keywords('clang', s) - if lang: - lang = lang[0].lower() # this allows both C++ and c++ - else: - lang = "c" - - v, s = _parse_keywords('clib', s) - libs = v + standard_libs - - additional_source_files, s = _parse_keywords('cfile', s) - - v, s = _parse_keywords('cinclude', s) - inc = [_environ_parse(x.replace('"','').replace("'","")) for x in v] + sage_include_directories() - args, s = _parse_keywords('cargs', s) - args = ['-w','-O2'] + args - libdirs = cblas_library_dirs - - # Add cysignals directory to includes - for path in sys.path: - cysignals_path = os.path.join(path, "cysignals") - if os.path.isdir(cysignals_path): - inc.append(cysignals_path) - - return s, libs, inc, lang, additional_source_files, args, libdirs - - -parse_keywords = deprecated_function_alias(24105, _parse_keywords) -environ_parse = deprecated_function_alias(24105, _environ_parse) -pyx_preparse = deprecated_function_alias(24105, _pyx_preparse) +standard_libdirs = [os.path.join(SAGE_LOCAL, "lib")] + cblas_library_dirs ################################################################ @@ -429,7 +143,6 @@ def cython(filename, verbose=0, compile_message=False, first moving to a tempdir to avoid clutter. Before :trac:`22113`, the create_local_c_file argument was not tested for C++ code:: - sage: import sage.misc.cython sage: d = sage.misc.temporary_file.tmp_dir() sage: os.chdir(d) sage: with open("test.pyx", 'w') as f: @@ -440,7 +153,6 @@ def cython(filename, verbose=0, compile_message=False, Accessing a ``.pxd`` file from the current directory works:: - sage: import sage.misc.cython sage: d = sage.misc.temporary_file.tmp_dir() sage: os.chdir(d) sage: with open("helper.pxd", 'w') as f: @@ -479,26 +191,6 @@ def cython(filename, verbose=0, compile_message=False, Traceback (most recent call last): ... RuntimeError: ... - - Sage used to automatically include various ``.pxi`` files. Since - :trac:`22805`, we no longer do this. But we make sure to give a - useful message in case the ``.pxi`` files were needed:: - - sage: cython("sig_malloc(0)\n") - Traceback (most recent call last): - ... - RuntimeError: Error compiling Cython file: - ------------------------------------------------------------ - ... - sig_malloc(0) - ^ - ------------------------------------------------------------ - - ...:1:0: undeclared name not builtin: sig_malloc - - NOTE: Sage no longer automatically includes the deprecated files - "cdefs.pxi", "signals.pxi" and "stdsage.pxi" in Cython files. - You can fix your code by adding "from cysignals.memory cimport sig_malloc". """ if not filename.endswith('pyx'): print("Warning: file (={}) should have extension .pyx".format(filename), file=sys.stderr) @@ -560,29 +252,16 @@ def cython(filename, verbose=0, compile_message=False, sequence_number[base] += 1 if compile_message: - print("Compiling {}...".format(filename), file=sys.stderr) + sys.stderr.write("Compiling {}...\n".format(filename)) sys.stderr.flush() - with open(filename) as f: - (preparsed, libs, includes, language, additional_source_files, - extra_args, libdirs) = _pyx_preparse(f.read()) - - # New filename with preparsed code. - # NOTE: if we ever stop preparsing, we should still copy the - # original file to the target directory. + # Copy original file to the target directory. pyxfile = os.path.join(target_dir, name + ".pyx") - with open(pyxfile, 'w') as f: - f.write(preparsed) - - extra_sources = [] - for fname in additional_source_files: - fname = fname.replace("$SAGE_SRC", SAGE_SRC) - fname = fname.replace("$SAGE_LOCAL", SAGE_LOCAL) - extra_sources.append(fname) + shutil.copy(filename, pyxfile) # Add current working directory to includes. This is needed because # we cythonize from a different directory. See Trac #24764. - includes.insert(0, os.getcwd()) + includes = [os.getcwd()] + sage_include_directories() # Now do the actual build, directly calling Cython and distutils from Cython.Build import cythonize @@ -598,11 +277,10 @@ def cython(filename, verbose=0, compile_message=False, Cython.Compiler.Options.pre_import = "sage.all" if sage_namespace else None ext = Extension(name, - sources=[pyxfile] + extra_sources, - libraries=libs, - library_dirs=[os.path.join(SAGE_LOCAL, "lib")] + libdirs, - extra_compile_args=extra_args, - language=language) + sources=[pyxfile], + extra_compile_args=["-w"], # no warnings + libraries=standard_libs, + library_dirs=standard_libdirs) directives = dict(language_level=sys.version_info[0]) @@ -627,16 +305,6 @@ def cython(filename, verbose=0, compile_message=False, except IOError: cython_messages = "Error compiling Cython file" except CompileError: - # Check for names in old_pxi_names - for pxd, names in old_pxi_names.items(): - for name in names: - if re.search(r"\b{}\b".format(name), cython_messages): - cython_messages += dedent( - """ - NOTE: Sage no longer automatically includes the deprecated files - "cdefs.pxi", "signals.pxi" and "stdsage.pxi" in Cython files. - You can fix your code by adding "from {} cimport {}". - """.format(pxd, name)) raise RuntimeError(cython_messages.strip()) if verbose >= 0: diff --git a/src/sage/misc/cython_c.pyx b/src/sage/misc/cython_c.pyx deleted file mode 100644 index 77757fa6d81..00000000000 --- a/src/sage/misc/cython_c.pyx +++ /dev/null @@ -1,13 +0,0 @@ -""" -TESTS:: - - sage: from sage.misc.cython_c import cython_compile - doctest:...: DeprecationWarning: the module sage.misc.cython_c has been moved to sage.misc.cython - See http://trac.sagemath.org/24105 for details. - sage: cython_compile('''print("Hello World!")''') - Hello World! -""" -from sage.misc.superseded import deprecation -deprecation(24105, "the module sage.misc.cython_c has been moved to sage.misc.cython") - -from .cython import cython_compile diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index 21e6253ea0d..296cd206db8 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -7,12 +7,12 @@ - Vincent Delecroix (2012 and 2013): improve import_statements """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from __future__ import absolute_import import os @@ -180,7 +180,6 @@ def load_submodules(module=None, exclude_pattern=None): exclude_pattern = r"^sage\.libs|^sage\.tests|tests$|^sage\.all_|all$|sage\.interacts$|^sage\.misc\.benchmark$" if exclude_pattern: - import re exclude = re.compile(exclude_pattern) else: exclude = None diff --git a/src/sage/misc/edit_module.py b/src/sage/misc/edit_module.py index dc36756c815..850622062f3 100644 --- a/src/sage/misc/edit_module.py +++ b/src/sage/misc/edit_module.py @@ -23,8 +23,7 @@ In fact, if the environment variable :envvar:`EDITOR` is set to a known editor, then the system will use that if no template has been set explicitly. """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Nils Bruin and # William Stein # @@ -32,22 +31,20 @@ # 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 __future__ import absolute_import import sage.misc.sageinspect -import inspect import os import re from string import Template -#by default we do not have an edit template +# by default we do not have an edit template edit_template = None -#we can set some defaults, however. Add your own if you like. +# we can set some defaults, however. Add your own if you like. template_defaults = { 'vi' : Template('vi -c ${line} ${file}'), @@ -59,222 +56,226 @@ 'gedit' : Template('gedit +${line} ${file} &'), 'kate' : Template('kate -u --line +${line} ${file} &') } + def file_and_line(obj): - r""" - Look up source file and line number of obj. - - If the file lies in the Sage library, the path name of the - corresponding file in the current branch (i.e., the file that gets - copied into the Sage library upon running 'sage -br'). Note that - the first line of a file is considered to be 1 rather than 0 - because most editors think that this is the case. - - AUTHORS: - - - Nils Bruin (2007-10-03) - - Simon King (2011-05): Use :mod:`~sage.misc.sageinspect` to get the file - and the line. - - EXAMPLES:: - - sage: import sage.misc.edit_module as edit_module - sage: edit_module.file_and_line(sage) - ('...sage/__init__.py', 0) - - The following tests against a bug that was fixed in :trac:`11298`:: - - sage: edit_module.file_and_line(x) - ('...sage/symbolic/expression.pyx', ...) - - """ - #d = inspect.getdoc(obj) - #ret = sage.misc.sageinspect._extract_embedded_position(d); - #if ret is not None: - # (_, filename, lineno) = ret - #else: - # filename = inspect.getsourcefile(obj) - # _,lineno = inspect.findsource(obj) - - # - # for sage files, the registered source file is the result of the preparsing - # these files end in ".py" and have "*autogenerated*" on the second line - # for those files, we replace the extension by ".sage" and we subtract - # 3 from the line number to compensate for the 3 lines that were prefixed - # in the preparsing process - # - from sage.misc.sageinspect import sage_getfile, sage_getsourcelines - filename = sage_getfile(obj) - lineno = sage_getsourcelines(obj)[1] - 1 - if filename.endswith('.py'): - infile=open(filename,'r') - infile.readline() - if infile.readline().find("*autogenerated*") >= 0: - filename=filename[:-3]+'.sage' - lineno = lineno-3 - - runpathpattern = '^'+sage.env.SAGE_LIB - develbranch = sage.env.SAGE_SRC - filename=re.sub(runpathpattern,develbranch,filename) - - return filename, lineno+1 + r""" + Look up source file and line number of ``obj``. + + If the file lies in the Sage library, the path name of the + corresponding file in the current branch (i.e., the file that gets + copied into the Sage library upon running 'sage -br'). Note that + the first line of a file is considered to be 1 rather than 0 + because most editors think that this is the case. + + AUTHORS: + + - Nils Bruin (2007-10-03) + - Simon King (2011-05): Use :mod:`~sage.misc.sageinspect` to get the file + and the line. + + EXAMPLES:: + + sage: import sage.misc.edit_module as edit_module + sage: edit_module.file_and_line(sage) + ('...sage/__init__.py', 0) + + The following tests against a bug that was fixed in :trac:`11298`:: + + sage: edit_module.file_and_line(x) + ('...sage/symbolic/expression...pyx', ...) + """ + # d = inspect.getdoc(obj) + # ret = sage.misc.sageinspect._extract_embedded_position(d); + # if ret is not None: + # (_, filename, lineno) = ret + # else: + # filename = inspect.getsourcefile(obj) + # _,lineno = inspect.findsource(obj) + + # + # for sage files, the registered source file is the result of the + # preparsing these files end in ".py" and have "*autogenerated*" + # on the second line for those files, we replace the extension by + # ".sage" and we subtract 3 from the line number to compensate + # for the 3 lines that were prefixed in the preparsing process + # + from sage.misc.sageinspect import sage_getfile, sage_getsourcelines + filename = sage_getfile(obj) + lineno = sage_getsourcelines(obj)[1] - 1 + if filename.endswith('.py'): + infile = open(filename, 'r') + infile.readline() + if infile.readline().find("*autogenerated*") >= 0: + filename = filename[:-3] + '.sage' + lineno -= 3 + + runpathpattern = '^' + sage.env.SAGE_LIB + develbranch = sage.env.SAGE_SRC + filename = re.sub(runpathpattern, develbranch, filename) + + return filename, lineno + 1 + def template_fields(template): - r""" - Given a String.Template object, returns the fields. - - AUTHOR: - - - Nils Bruin (2007-10-22) - - EXAMPLES:: - - sage: from sage.misc.edit_module import template_fields - sage: from string import Template - sage: t=Template("Template ${one} with ${two} and ${three}") - sage: template_fields(t) - ['three', 'two', 'one'] - """ - dict={} - dummy=None - while not(dummy): - try: - dummy=template.substitute(dict) - except KeyError as inst: - dict[inst.args[0]]=None - return dict.keys() - -## The routine set_edit_template should only do some consistency checks on template_string -## It should not do any magic. This routine should give the user full control over what is -## going on. + r""" + Given a String.Template object, returns the fields. + + AUTHOR: + + Nils Bruin (2007-10-22) + + EXAMPLES:: + + sage: from sage.misc.edit_module import template_fields + sage: from string import Template + sage: t = Template("Template ${one} with ${two} and ${three}") + sage: sorted(template_fields(t)) + ['one', 'three', 'two'] + """ + dict = {} + dummy = None + while not(dummy): + try: + dummy = template.substitute(dict) + except KeyError as inst: + dict[inst.args[0]] = None + return list(dict) + +# The routine set_edit_template should only do some consistency +# checks on template_string It should not do any magic. This routine +# should give the user full control over what is going on. + def set_edit_template(template_string): - r""" - Sets default edit template string. + r""" + Set the default edit template string. - It should reference ``${file}`` and ``${line}``. This routine normally - needs to be called prior to using 'edit'. However, if the editor - set in the shell variable :envvar:`EDITOR` is known, then the system will - substitute an appropriate template for you. See - edit_module.template_defaults for the recognised templates. + It should reference ``${file}`` and ``${line}``. This routine normally + needs to be called prior to using 'edit'. However, if the editor + set in the shell variable :envvar:`EDITOR` is known, then the system will + substitute an appropriate template for you. See + edit_module.template_defaults for the recognised templates. - AUTHOR: + AUTHOR: - - Nils Bruin (2007-10-03) + Nils Bruin (2007-10-03) - EXAMPLES:: + EXAMPLES:: - sage: from sage.misc.edit_module import set_edit_template - sage: set_edit_template("echo EDIT ${file}:${line}") - sage: edit(sage) # not tested - EDIT /usr/local/sage/src/sage/__init__.py:1 - """ - global edit_template + sage: from sage.misc.edit_module import set_edit_template + sage: set_edit_template("echo EDIT ${file}:${line}") + sage: edit(sage) # not tested + EDIT /usr/local/sage/src/sage/__init__.py:1 + """ + global edit_template - if not(isinstance(template_string,Template)): - template_string = Template(template_string) - fields = set(template_fields(template_string)) - if not(fields <= set(['file','line']) and ('file' in fields)): - raise ValueError("Only ${file} and ${line} are allowed as template variables, and ${file} must occur.") - edit_template = template_string + if not(isinstance(template_string, Template)): + template_string = Template(template_string) + fields = set(template_fields(template_string)) + if not(fields <= set(['file', 'line']) and ('file' in fields)): + raise ValueError("Only ${file} and ${line} are allowed as template variables, and ${file} must occur.") + edit_template = template_string -## The routine set_editor is for convenience and hence is allowed to apply magic. Given an editor name -## and possibly some options, it should try to set an editor_template that is as appropriate as possible -## for the situation. If it's necessary to query the environment for 'DISPLAY' to figure out if -## certain editors should be run in the background, this is where the magic should go. +# The routine set_editor is for convenience and hence is allowed to +# apply magic. Given an editor name and possibly some options, it +# should try to set an editor_template that is as appropriate as +# possible for the situation. If it's necessary to query the +# environment for 'DISPLAY' to figure out if certain editors should +# be run in the background, this is where the magic should go. -def set_editor(editor_name,opts=''): - r""" - Sets the editor to be used by the edit command by basic editor name. - Currently, the system only knows appropriate call strings for a limited number - of editors. If you want to use another editor, you should set the - whole edit template via set_edit_template. +def set_editor(editor_name, opts=''): + r""" + Set the editor to be used by the edit command by basic editor name. - AUTHOR: + Currently, the system only knows appropriate call strings for a + limited number of editors. If you want to use another editor, you + should set the whole edit template via :func:`set_edit_template`. - - Nils Bruin (2007-10-05) + AUTHOR: - EXAMPLES:: + Nils Bruin (2007-10-05) - sage: from sage.misc.edit_module import set_editor - sage: set_editor('vi') - sage: sage.misc.edit_module.edit_template.template - 'vi -c ${line} ${file}' - """ + EXAMPLES:: + + sage: from sage.misc.edit_module import set_editor + sage: set_editor('vi') + sage: sage.misc.edit_module.edit_template.template + 'vi -c ${line} ${file}' + """ + if editor_name in sage.misc.edit_module.template_defaults: + set_edit_template(Template(template_defaults[editor_name].safe_substitute(opts=opts))) + else: + raise ValueError("editor_name not known. Try set_edit_template() instead.") - if editor_name in sage.misc.edit_module.template_defaults: - set_edit_template(Template(template_defaults[editor_name].safe_substitute(opts=opts))) - else: - raise ValueError("editor_name not known. Try set_edit_template() instead.") def edit(obj, editor=None, bg=None): - r"""nodetex - Open source code of obj in editor of your choice. + r"""nodetex + Open source code of ``obj`` in editor of your choice. - INPUT: + INPUT: - - editor -- str (default: None); If given, use specified editor. Choice is stored for next time. + - editor -- str (default: None); If given, use specified editor. + Choice is stored for next time. - AUTHOR: + AUTHOR: - - Nils Bruin (2007-10-03) + Nils Bruin (2007-10-03) - EXAMPLES: + EXAMPLES: - This is a typical example of how to use this routine. - :: + This is a typical example of how to use this routine:: - # make some object obj - sage: edit(obj) # not tested + # make some object obj + sage: edit(obj) # not tested - Now for more details and customization:: + Now for more details and customization:: - sage: import sage.misc.edit_module as m - sage: m.set_edit_template("vi -c ${line} ${file}") + sage: import sage.misc.edit_module as m + sage: m.set_edit_template("vi -c ${line} ${file}") - In fact, since vi is a well-known editor, you could also just use - :: + In fact, since ``vi`` is a well-known editor, you could also just use:: - sage: m.set_editor("vi") + sage: m.set_editor("vi") - To illustrate:: + To illustrate:: - sage: m.edit_template.template - 'vi -c ${line} ${file}' + sage: m.edit_template.template + 'vi -c ${line} ${file}' - And if your environment variable :envvar:`EDITOR` is set to a recognised - editor, you would not have to set anything. + And if your environment variable :envvar:`EDITOR` is set to a recognised + editor, you would not have to set anything. - To edit the source of an object, just type something like:: + To edit the source of an object, just type something like:: - sage: edit(edit) # not tested - """ - global edit_template + sage: edit(edit) # not tested + """ + global edit_template - if editor: - set_editor(editor) - elif not(edit_template): - try: - ED = os.environ['EDITOR'] - EDITOR = ED.split() - base = EDITOR[0] - opts = ' '.join(EDITOR[1:]) #for future use - set_editor(base,opts=opts) - except (ValueError, KeyError, IndexError): - raise ValueError("Use set_edit_template() to set a default") + if editor: + set_editor(editor) + elif not(edit_template): + try: + ED = os.environ['EDITOR'] + EDITOR = ED.split() + base = EDITOR[0] + opts = ' '.join(EDITOR[1:]) # for future use + set_editor(base, opts=opts) + except (ValueError, KeyError, IndexError): + raise ValueError("Use set_edit_template() to set a default") - if not(edit_template): - raise ValueError("Use set_edit_template() to set a default") + if not(edit_template): + raise ValueError("Use set_edit_template() to set a default") - filename, lineno = file_and_line(obj) - cmd = edit_template.substitute(line = lineno, file = filename) + filename, lineno = file_and_line(obj) + cmd = edit_template.substitute(line=lineno, file=filename) - if bg is True and cmd[-1] != '&': - cmd=cmd+'&' - if bg is False and cmd[-1] == '&': - cmd=cmd[:-1] + if bg is True and cmd[-1] != '&': + cmd = cmd + '&' + if bg is False and cmd[-1] == '&': + cmd = cmd[:-1] - os.system(cmd) + os.system(cmd) def edit_devel(self, filename, linenum): @@ -297,8 +298,7 @@ def edit_devel(self, filename, linenum): editor supports it, also at the line in which gcd is defined. """ import IPython.core.hooks - runpathpattern = '^'+sage.env.SAGE_LIB + runpathpattern = '^' + sage.env.SAGE_LIB develbranch = sage.env.SAGE_SRC - filename=re.sub(runpathpattern,develbranch,filename) + filename = re.sub(runpathpattern, develbranch, filename) IPython.core.hooks.editor(self, filename, linenum) - diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index c5519ea07f8..67c0bd64601 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -460,7 +460,7 @@ def run_pickle(self, p): sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True) - sage: sib(pe.run_pickle('T\5\0\0\0hello.')) + sage: sib(pe.run_pickle('T\5\0\0\0hello.')) # py2 {atomic:'hello'} """ for (op, arg, pos) in genops(p): @@ -646,7 +646,7 @@ def APPEND(self): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(['a']) + sage: test_pickle(['a']) # py2 0: \x80 PROTO 2 2: ] EMPTY_LIST 3: q BINPUT 1 @@ -663,7 +663,7 @@ def APPEND(self): sage: v = [] sage: v.append(v) - sage: test_pickle(v) + sage: test_pickle(v) # py2 0: \x80 PROTO 2 2: ] EMPTY_LIST 3: q BINPUT 1 @@ -687,7 +687,7 @@ def APPENDS(self): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(['a', 'b']) + sage: test_pickle(['a', 'b']) # py2 0: \x80 PROTO 2 2: ] EMPTY_LIST 3: q BINPUT 1 @@ -707,7 +707,7 @@ def APPENDS(self): sage: v = [] sage: v.append(v) sage: v.append(v) - sage: test_pickle(v) + sage: test_pickle(v) # py2 0: \x80 PROTO 2 2: ] EMPTY_LIST 3: q BINPUT 1 @@ -739,7 +739,7 @@ def _APPENDS_helper(self, lst, slice): an exception, so we can tell that cPickle doesn't call it either):: sage: from sage.misc.explain_pickle import * - sage: test_pickle(TestAppendList((True,))) # indirect doctest + sage: test_pickle(TestAppendList((True,))) # indirect doctest # py2 0: \x80 PROTO 2 2: c GLOBAL 'sage.misc.explain_pickle TestAppendList' 43: q BINPUT 1 @@ -771,7 +771,7 @@ def _APPENDS_helper(self, lst, slice): sage: v = TestAppendNonlist() sage: v.list = [False, None] - sage: test_pickle(v, verbose_eval=True) + sage: test_pickle(v, verbose_eval=True) # py2 0: \x80 PROTO 2 2: c GLOBAL 'sage.misc.explain_pickle TestAppendNonlist' 46: q BINPUT 1 @@ -809,7 +809,7 @@ def _APPENDS_helper(self, lst, slice): instead of once. If we set pedantic=True, then this is fixed. (We show only the changed parts of the output):: - sage: test_pickle(v, verbose_eval=True, pedantic=True) + sage: test_pickle(v, verbose_eval=True, pedantic=True) # py2 0: \x80 PROTO 2 ... explain_pickle in_current_sage=True: @@ -857,7 +857,7 @@ def BINFLOAT(self, f): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(float(pi)) + sage: test_pickle(float(pi)) # py2 0: \x80 PROTO 2 2: G BINFLOAT 3.141592653589793 11: . STOP @@ -874,7 +874,7 @@ def BINGET(self, n): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_LIST + BINPUT + 'x' + POP + BINGET + 'x' + '.') + sage: test_pickle(EMPTY_LIST + BINPUT + 'x' + POP + BINGET + 'x' + '.') # py2 0: ] EMPTY_LIST 1: q BINPUT 120 3: 0 POP @@ -892,7 +892,7 @@ def BININT(self, n): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(dumps(100000r, compress=False)) + sage: test_pickle(dumps(100000r, compress=False)) # py2 0: \x80 PROTO 2 2: J BININT 100000 7: . STOP @@ -908,7 +908,7 @@ def BININT1(self, n): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(dumps(100r, compress=False)) + sage: test_pickle(dumps(100r, compress=False)) # py2 0: \x80 PROTO 2 2: K BININT1 100 4: . STOP @@ -924,7 +924,7 @@ def BININT2(self, n): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(dumps(1000r, compress=False)) + sage: test_pickle(dumps(1000r, compress=False)) # py2 0: \x80 PROTO 2 2: M BININT2 1000 5: . STOP @@ -941,7 +941,7 @@ def BINPUT(self, n): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_LIST + BINPUT + 'x' + POP + BINGET + 'x') + sage: test_pickle(EMPTY_LIST + BINPUT + 'x' + POP + BINGET + 'x') # py2 0: ] EMPTY_LIST 1: q BINPUT 120 3: 0 POP @@ -961,7 +961,7 @@ def BINSTRING(self, s): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle('T\5\0\0\0hello.') + sage: test_pickle('T\5\0\0\0hello.') # py2 0: T BINSTRING 'hello' 10: . STOP highest protocol among opcodes = 1 @@ -976,7 +976,7 @@ def BINUNICODE(self, s): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(u'hi\u1234\U00012345') + sage: test_pickle(u'hi\u1234\U00012345') # py2 0: \x80 PROTO 2 2: X BINUNICODE u'hi\u1234\U00012345' 16: q BINPUT 1 @@ -993,7 +993,7 @@ def BUILD(self): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(TestBuild()) + sage: test_pickle(TestBuild()) # py2 0: \x80 PROTO 2 2: c GLOBAL 'sage.misc.explain_pickle TestBuild' 38: q BINPUT 1 @@ -1029,7 +1029,7 @@ def BUILD(self): :: - sage: test_pickle(TestBuildSetstate(), verbose_eval=True) + sage: test_pickle(TestBuildSetstate(), verbose_eval=True) # py2 0: \x80 PROTO 2 2: c GLOBAL 'sage.misc.explain_pickle TestBuildSetstate' 46: q BINPUT 1 @@ -1119,7 +1119,7 @@ def DICT(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(DICT, args=('mark', 'a', 1, 2, 'b')) + sage: test_pickle(DICT, args=('mark', 'a', 1, 2, 'b')) # py2 0: ( MARK 1: P PERSID '1' 4: P PERSID '2' @@ -1142,7 +1142,7 @@ def DUP(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_LIST + DUP + TUPLE2 + STOP) + sage: test_pickle(EMPTY_LIST + DUP + TUPLE2 + STOP) # py2 0: ] EMPTY_LIST 1: 2 DUP 2: \x86 TUPLE2 @@ -1163,7 +1163,7 @@ def EMPTY_DICT(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_DICT) + sage: test_pickle(EMPTY_DICT) # py2 0: } EMPTY_DICT 1: . STOP highest protocol among opcodes = 1 @@ -1179,7 +1179,7 @@ def EMPTY_LIST(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_LIST) + sage: test_pickle(EMPTY_LIST) # py2 0: ] EMPTY_LIST 1: . STOP highest protocol among opcodes = 1 @@ -1195,7 +1195,7 @@ def EMPTY_TUPLE(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_TUPLE) + sage: test_pickle(EMPTY_TUPLE) # py2 0: ) EMPTY_TUPLE 1: . STOP highest protocol among opcodes = 1 @@ -1212,7 +1212,7 @@ def EXT1(self, n): sage: from six.moves.copyreg import * sage: from sage.misc.explain_pickle import * sage: add_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 42) - sage: test_pickle(EmptyNewstyleClass()) + sage: test_pickle(EmptyNewstyleClass()) # py2 0: \x80 PROTO 2 2: \x82 EXT1 42 4: ) EMPTY_TUPLE @@ -1239,7 +1239,7 @@ def EXT2(self, n): sage: from six.moves.copyreg import * sage: from sage.misc.explain_pickle import * sage: add_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 31415) - sage: test_pickle(EmptyNewstyleClass()) + sage: test_pickle(EmptyNewstyleClass()) # py2 0: \x80 PROTO 2 2: \x83 EXT2 31415 5: ) EMPTY_TUPLE @@ -1266,7 +1266,7 @@ def EXT4(self, n): sage: from six.moves.copyreg import * sage: from sage.misc.explain_pickle import * sage: add_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 27182818) - sage: test_pickle(EmptyNewstyleClass()) + sage: test_pickle(EmptyNewstyleClass()) # py2 0: \x80 PROTO 2 2: \x84 EXT4 27182818 7: ) EMPTY_TUPLE @@ -1292,7 +1292,7 @@ def FLOAT(self, f): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(FLOAT + '2.71828\n') + sage: test_pickle(FLOAT + '2.71828\n') # py2 0: F FLOAT 2.71828 9: . STOP highest protocol among opcodes = 0 @@ -1308,7 +1308,7 @@ def GET(self, n): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_LIST + PUT + '1\n' + POP + GET + '1\n' + '.') + sage: test_pickle(EMPTY_LIST + PUT + '1\n' + POP + GET + '1\n' + '.') # py2 0: ] EMPTY_LIST 1: p PUT 1 4: 0 POP @@ -1332,7 +1332,7 @@ def GLOBAL(self, name): :: - sage: test_pickle(TestGlobalOldName()) + sage: test_pickle(TestGlobalOldName()) # py2 0: \x80 PROTO 2 2: c GLOBAL 'sage.misc.explain_pickle TestGlobalOldName' 46: q BINPUT 1 @@ -1365,7 +1365,7 @@ def GLOBAL(self, name): A class name need not be a valid identifier:: sage: sage.misc.explain_pickle.__dict__['funny$name'] = TestGlobalFunnyName # see comment at end of file - sage: test_pickle((TestGlobalFunnyName(), TestGlobalFunnyName())) + sage: test_pickle((TestGlobalFunnyName(), TestGlobalFunnyName())) # py2 0: \x80 PROTO 2 2: c GLOBAL 'sage.misc.explain_pickle funny$name' 39: q BINPUT 1 @@ -1446,7 +1446,7 @@ def INST(self, name): sage: import pickle sage: from sage.misc.explain_pickle import * - sage: test_pickle(pickle.dumps(EmptyOldstyleClass(), protocol=0)) + sage: test_pickle(pickle.dumps(EmptyOldstyleClass(), protocol=0)) # py2 0: ( MARK 1: i INST 'sage.misc.explain_pickle EmptyOldstyleClass' (MARK at 0) 46: p PUT 0 @@ -1479,7 +1479,7 @@ def INT(self, n): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(INT + "-12345\n") + sage: test_pickle(INT + "-12345\n") # py2 0: I INT -12345 8: . STOP highest protocol among opcodes = 0 @@ -1489,14 +1489,14 @@ def INT(self, n): INT can also be used to record True and False:: - sage: test_pickle(INT + "00\n") + sage: test_pickle(INT + "00\n") # py2 0: I INT False 4: . STOP highest protocol among opcodes = 0 explain_pickle in_current_sage=True/False: False result: False - sage: test_pickle(INT + "01\n") + sage: test_pickle(INT + "01\n") # py2 0: I INT True 4: . STOP highest protocol among opcodes = 0 @@ -1512,7 +1512,7 @@ def LIST(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(MARK + NONE + NEWFALSE + LIST) + sage: test_pickle(MARK + NONE + NEWFALSE + LIST) # py2 0: ( MARK 1: N NONE 2: \x89 NEWFALSE @@ -1532,7 +1532,7 @@ def LONG(self, n): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(LONG + "12345678909876543210123456789L\n") + sage: test_pickle(LONG + "12345678909876543210123456789L\n") # py2 0: L LONG 12345678909876543210123456789L 32: . STOP highest protocol among opcodes = 0 @@ -1547,7 +1547,7 @@ def LONG1(self, n): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(1L) + sage: test_pickle(1L) # py2 0: \x80 PROTO 2 2: \x8a LONG1 1L 5: . STOP @@ -1564,7 +1564,7 @@ def LONG4(self, n): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(LONG4 + '\014\0\0\0' + 'hello, world') + sage: test_pickle(LONG4 + '\014\0\0\0' + 'hello, world') # py2 0: \x8b LONG4 31079605376604435891501163880L 17: . STOP highest protocol among opcodes = 2 @@ -1580,7 +1580,7 @@ def LONG_BINGET(self, n): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_LIST + LONG_BINPUT + 'Sage' + POP + LONG_BINGET + 'Sage') + sage: test_pickle(EMPTY_LIST + LONG_BINPUT + 'Sage' + POP + LONG_BINGET + 'Sage') # py2 0: ] EMPTY_LIST 1: r LONG_BINPUT 1701273939 6: 0 POP @@ -1599,7 +1599,7 @@ def LONG_BINPUT(self, n): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_LIST + LONG_BINPUT + 'Sage' + POP + LONG_BINGET + 'Sage') + sage: test_pickle(EMPTY_LIST + LONG_BINPUT + 'Sage' + POP + LONG_BINGET + 'Sage') # py2 0: ] EMPTY_LIST 1: r LONG_BINPUT 1701273939 6: 0 POP @@ -1620,7 +1620,7 @@ def MARK(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(MARK + TUPLE) + sage: test_pickle(MARK + TUPLE) # py2 0: ( MARK 1: t TUPLE (MARK at 0) 2: . STOP @@ -1637,7 +1637,7 @@ def NEWFALSE(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(NEWFALSE) + sage: test_pickle(NEWFALSE) # py2 0: \x89 NEWFALSE 1: . STOP highest protocol among opcodes = 2 @@ -1653,7 +1653,7 @@ def NEWTRUE(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(NEWTRUE) + sage: test_pickle(NEWTRUE) # py2 0: \x88 NEWTRUE 1: . STOP highest protocol among opcodes = 2 @@ -1668,7 +1668,7 @@ def NEWOBJ(self): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(EmptyNewstyleClass()) + sage: test_pickle(EmptyNewstyleClass()) # py2 0: \x80 PROTO 2 2: c GLOBAL 'sage.misc.explain_pickle EmptyNewstyleClass' 47: q BINPUT 1 @@ -1704,7 +1704,7 @@ def NONE(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(NONE) + sage: test_pickle(NONE) # py2 0: N NONE 1: . STOP highest protocol among opcodes = 0 @@ -1719,7 +1719,7 @@ def OBJ(self): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(EmptyOldstyleClass()) + sage: test_pickle(EmptyOldstyleClass()) # py2 0: \x80 PROTO 2 2: ( MARK 3: c GLOBAL 'sage.misc.explain_pickle EmptyOldstyleClass' @@ -1755,7 +1755,7 @@ def PERSID(self, id): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(PERSID + "0\n" + '.', args=('Yo!',)) + sage: test_pickle(PERSID + "0\n" + '.', args=('Yo!',)) # py2 0: P PERSID '0' 3: . STOP highest protocol among opcodes = 0 @@ -1771,7 +1771,7 @@ def BINPERSID(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(INT + "0\n" + BINPERSID + '.', args=('Yo!',)) + sage: test_pickle(INT + "0\n" + BINPERSID + '.', args=('Yo!',)) # py2 0: I INT 0 3: Q BINPERSID 4: . STOP @@ -1789,7 +1789,7 @@ def POP(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(INT + "0\n" + POP + INT + "42\n") + sage: test_pickle(INT + "0\n" + POP + INT + "42\n") # py2 0: I INT 0 3: 0 POP 4: I INT 42 @@ -1809,7 +1809,7 @@ def POP_MARK(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(MARK + NONE + NEWFALSE + POP_MARK + NEWTRUE) + sage: test_pickle(MARK + NONE + NEWFALSE + POP_MARK + NEWTRUE) # py2 0: ( MARK 1: N NONE 2: \x89 NEWFALSE @@ -1828,7 +1828,7 @@ def PROTO(self, proto): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(0r) + sage: test_pickle(0r) # py2 0: \x80 PROTO 2 2: K BININT1 0 4: . STOP @@ -1846,7 +1846,7 @@ def PUT(self, n): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_LIST + PUT + '1\n' + POP + GET + '1\n' + '.') + sage: test_pickle(EMPTY_LIST + PUT + '1\n' + POP + GET + '1\n' + '.') # py2 0: ] EMPTY_LIST 1: p PUT 1 4: 0 POP @@ -1867,7 +1867,7 @@ def REDUCE(self): sage: import pickle sage: from sage.misc.explain_pickle import * - sage: test_pickle(pickle.dumps(EmptyNewstyleClass(), protocol=1)) + sage: test_pickle(pickle.dumps(EmptyNewstyleClass(), protocol=1)) # py2 0: c GLOBAL 'copy_reg _reconstructor' 25: q BINPUT 0 27: ( MARK @@ -1896,7 +1896,7 @@ def REDUCE(self): :: - sage: test_pickle(TestReduceGetinitargs(), verbose_eval=True) + sage: test_pickle(TestReduceGetinitargs(), verbose_eval=True) # py2 Running __init__ for TestReduceGetinitargs 0: \x80 PROTO 2 2: ( MARK @@ -1927,7 +1927,7 @@ def REDUCE(self): :: - sage: test_pickle(TestReduceNoGetinitargs(), verbose_eval=True) + sage: test_pickle(TestReduceNoGetinitargs(), verbose_eval=True) # py2 Running __init__ for TestReduceNoGetinitargs 0: \x80 PROTO 2 2: ( MARK @@ -1999,7 +1999,7 @@ def SETITEM(self): sage: import pickle sage: from sage.misc.explain_pickle import * - sage: test_pickle(pickle.dumps({'a': 'b'})) + sage: test_pickle(pickle.dumps({'a': 'b'})) # py2 0: ( MARK 1: d DICT (MARK at 0) 2: p PUT 0 @@ -2020,7 +2020,7 @@ def SETITEM(self): sage: value_rec = dict() sage: value_rec['circular'] = value_rec - sage: test_pickle(pickle.dumps(value_rec)) + sage: test_pickle(pickle.dumps(value_rec)) # py2 0: ( MARK 1: d DICT (MARK at 0) 2: p PUT 0 @@ -2042,7 +2042,7 @@ def SETITEM(self): sage: key = EmptyNewstyleClass() sage: key.circular = key_rec sage: key_rec[key] = 'circular' - sage: test_pickle(pickle.dumps(key_rec)) + sage: test_pickle(pickle.dumps(key_rec)) # py2 0: ( MARK 1: d DICT (MARK at 0) 2: p PUT 0 @@ -2100,7 +2100,7 @@ def SETITEMS(self): sage: import pickle sage: from sage.misc.explain_pickle import * - sage: test_pickle(pickle.dumps({'a': 'b', 1r : 2r}, protocol=2)) + sage: test_pickle(pickle.dumps({'a': 'b', 1r : 2r}, protocol=2)) # py2 0: \x80 PROTO 2 2: } EMPTY_DICT 3: q BINPUT 0 @@ -2125,7 +2125,7 @@ def SETITEMS(self): sage: key = EmptyOldstyleClass() sage: key.recdict = recdict sage: recdict[key] = 'circular_key' - sage: test_pickle(pickle.dumps(recdict, protocol=2)) + sage: test_pickle(pickle.dumps(recdict, protocol=2)) # py2 0: \x80 PROTO 2 2: } EMPTY_DICT 3: q BINPUT 0 @@ -2178,7 +2178,7 @@ def _SETITEMS_helper(self, slice): sage: import pickle sage: from sage.misc.explain_pickle import * - sage: test_pickle(pickle.dumps({'a': 'b'})) # indirect doctest + sage: test_pickle(pickle.dumps({'a': 'b'})) # indirect doctest # py2 0: ( MARK 1: d DICT (MARK at 0) 2: p PUT 0 @@ -2218,7 +2218,7 @@ def SHORT_BINSTRING(self, s): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(dumps('hello', compress=False)) + sage: test_pickle(dumps('hello', compress=False)) # py2 0: \x80 PROTO 2 2: U SHORT_BINSTRING 'hello' 9: q BINPUT 1 @@ -2236,7 +2236,7 @@ def STOP(self): sage: from pickle import * sage: from sage.misc.explain_pickle import * - sage: test_pickle(EMPTY_TUPLE) + sage: test_pickle(EMPTY_TUPLE) # py2 0: ) EMPTY_TUPLE 1: . STOP highest protocol among opcodes = 1 @@ -2251,7 +2251,7 @@ def STRING(self, s): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle("S'Testing...'\n.") + sage: test_pickle("S'Testing...'\n.") # py2 0: S STRING 'Testing...' 14: . STOP highest protocol among opcodes = 0 @@ -2267,7 +2267,7 @@ def TUPLE(self): sage: import pickle sage: from sage.misc.explain_pickle import * - sage: test_pickle(pickle.dumps(('a',))) + sage: test_pickle(pickle.dumps(('a',))) # py2 0: ( MARK 1: S STRING 'a' 6: p PUT 0 @@ -2287,7 +2287,7 @@ def TUPLE(self): sage: v = ([],) sage: v[0].append(v) - sage: test_pickle(pickle.dumps(v)) + sage: test_pickle(pickle.dumps(v)) # py2 0: ( MARK 1: ( MARK 2: l LIST (MARK at 1) @@ -2317,7 +2317,7 @@ def TUPLE1(self): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(('a',)) + sage: test_pickle(('a',)) # py2 0: \x80 PROTO 2 2: U SHORT_BINSTRING 'a' 5: \x85 TUPLE1 @@ -2336,7 +2336,7 @@ def TUPLE2(self): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(('a','b')) + sage: test_pickle(('a','b')) # py2 0: \x80 PROTO 2 2: U SHORT_BINSTRING 'a' 5: U SHORT_BINSTRING 'b' @@ -2357,7 +2357,7 @@ def TUPLE3(self): TESTS:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(('a','b','c')) + sage: test_pickle(('a','b','c')) # py2 0: \x80 PROTO 2 2: U SHORT_BINSTRING 'a' 5: U SHORT_BINSTRING 'b' @@ -2381,7 +2381,7 @@ def UNICODE(self, s): sage: import pickle sage: from sage.misc.explain_pickle import * - sage: test_pickle(pickle.dumps(u'hi\u1234\U00012345')) + sage: test_pickle(pickle.dumps(u'hi\u1234\U00012345')) # py2 0: V UNICODE u'hi\u1234\U00012345' 20: p PUT 0 23: . STOP @@ -2586,7 +2586,7 @@ def test_pickle(p, verbose_eval=False, pedantic=False, args=()): EXAMPLES:: sage: from sage.misc.explain_pickle import * - sage: test_pickle(['a']) + sage: test_pickle(['a']) # py2 0: \x80 PROTO 2 2: ] EMPTY_LIST 3: q BINPUT 1 @@ -2922,7 +2922,7 @@ def __reduce__(self): sage: v = TestAppendNonlist() sage: v.list = [1,2,3,4] sage: v.__reduce__() - (, (), None, ) + (, (), None, <...iterator object at 0x...>) sage: list(v.__reduce__()[3]) [1, 2, 3, 4] sage: loads(dumps(v)) diff --git a/src/sage/misc/fpickle.pyx b/src/sage/misc/fpickle.pyx index 44efb2385c3..2f4fed80caf 100644 --- a/src/sage/misc/fpickle.pyx +++ b/src/sage/misc/fpickle.pyx @@ -86,7 +86,7 @@ def unpickle_function(pickled): """ Unpickle a pickled function. - EXAMPLES: + EXAMPLES:: sage: def f(N,M): return N*M ... diff --git a/src/sage/misc/function_mangling.pyx b/src/sage/misc/function_mangling.pyx index 0aee96630e9..93d2b9fd34c 100644 --- a/src/sage/misc/function_mangling.pyx +++ b/src/sage/misc/function_mangling.pyx @@ -110,7 +110,7 @@ cdef class ArgumentFixer: sage: class one: ....: def __init__(self, x = 1): ....: self.x = x - sage: af = ArgumentFixer(one.__init__.__func__, classmethod=True) + sage: af = ArgumentFixer(one.__init__, classmethod=True) sage: af.fix_to_pos(1,2,3,a=31,b=2,n=3) ((1, 2, 3), (('a', 31), ('b', 2), ('n', 3))) diff --git a/src/sage/misc/gperftools.py b/src/sage/misc/gperftools.py index 551c20bbfdf..2d5398711ba 100644 --- a/src/sage/misc/gperftools.py +++ b/src/sage/misc/gperftools.py @@ -26,13 +26,13 @@ - Volker Braun (2014-03-31): initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sys import ctypes @@ -144,7 +144,7 @@ def _libprofiler(self): global libprofiler if libprofiler is not None: return libprofiler - import ctypes, ctypes.util + import ctypes.util name = ctypes.util.find_library('profiler') if name: libprofiler = ctypes.CDLL(name) diff --git a/src/sage/misc/inline_fortran.py b/src/sage/misc/inline_fortran.py index e44724bc018..6b8b5fdd72d 100644 --- a/src/sage/misc/inline_fortran.py +++ b/src/sage/misc/inline_fortran.py @@ -5,6 +5,7 @@ import os import shutil +import subprocess import sys import six @@ -22,7 +23,7 @@ def _import_module_from_path(name, path=None): Returns a fully executed module object without inserting that module into `sys.modules`. - EXAMPLES: + EXAMPLES:: sage: from sage.misc.inline_fortran import _import_module_from_path sage: modname = '___test__import_module_from_path' @@ -140,12 +141,12 @@ def eval(self, x, globals=None, locals=None): TESTS:: - sage: os.chdir(SAGE_ROOT) + sage: os.chdir(DOT_SAGE) sage: fortran.eval("SYNTAX ERROR !@#$") Traceback (most recent call last): ... RuntimeError: failed to compile Fortran code:... - sage: os.getcwd() == SAGE_ROOT + sage: os.getcwd() == os.path.normpath(DOT_SAGE) True """ if globals is None: @@ -154,8 +155,6 @@ def eval(self, x, globals=None, locals=None): from sage.repl.user_globals import get_globals globals = get_globals() - from numpy import f2py - # Create everything in a temporary directory mytmpdir = tmp_dir() @@ -171,36 +170,44 @@ def eval(self, x, globals=None, locals=None): else: fortran_file = name + '.f' - s_lib_path = "" - s_lib = "" - for s in self.library_paths: - s_lib_path = s_lib_path + "-L%s " + s_lib_path = ['-L' + p for p in self.library_paths] + s_lib = ['-l' + l for l in self.libraries] - for s in self.libraries: - s_lib = s_lib + "-l%s "%s + with open(fortran_file, 'w') as fobj: + fobj.write(x) - log = name + ".log" - extra_args = ('--quiet --f77exec=sage-inline-fortran ' - '--f90exec=sage-inline-fortran {lib_path} {lib} ' - '> {log} 2>&1'.format(lib_path=s_lib_path, - lib=s_lib, log=log)) + # This is basically the same as what f2py.compile() does, but we + # do it manually here in order to customize running the subprocess + # a bit more (in particular to capture stderr) + cmd = [sys.executable, '-c', 'import numpy.f2py; numpy.f2py.main()'] - f2py.compile(x, name, extra_args=extra_args, - source_fn=fortran_file) + # What follows are the arguments to f2py itself (appended later + # just for logical separation) + cmd += ['-c', '-m', name, fortran_file, '--quiet', + '--f77exec=sage-inline-fortran', + '--f90exec=sage-inline-fortran'] + s_lib_path + s_lib - with open(log) as fobj: - log_string = fobj.read() + try: + out = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as exc: + raise RuntimeError( + "failed to compile Fortran code:\n{}".format(exc.output)) # Note that f2py() doesn't raise an exception if it fails. # In that case, the import below will fail. try: mod = _import_module_from_path(name, [mytmpdir]) - except ImportError: - raise RuntimeError("failed to compile Fortran code:\n" + - log_string) + except ImportError as exc: + # Failed to import the module; include any output from building + # the module (even though it was ostensibly successful) in case + # it might help + msg = "failed to load compiled Fortran code: {}".format(exc) + if out: + msg += '\n' + out + raise RuntimeError(msg) if self.verbose: - print(log_string) + print(out) finally: os.chdir(old_cwd) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 7f09a049164..3a481216280 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -2383,7 +2383,7 @@ def repr_lincomb(symbols, coeffs): sage: x = EllipticCurve('64a1').modular_symbol_space(sign=1).basis()[0] sage: from sage.misc.latex import repr_lincomb sage: latex(x.modular_symbol_rep()) - \left\{\frac{-1}{3}, \frac{-1}{4}\right\} - \left\{\frac{1}{5}, \frac{1}{4}\right\} + \left\{\frac{-3}{11}, \frac{-1}{4}\right\} - \left\{\frac{3}{13}, \frac{1}{4}\right\} Verify that it works when the symbols are numbers:: @@ -2617,7 +2617,6 @@ def latex_variable_name(x, is_fname=False): sage: latex_variable_name('5') '5' """ - import re # if x is an integer (it might be the case for padics), we return x if re.match(r'\d+$', x): return x @@ -2821,7 +2820,7 @@ def _repr_(self): """ String representation - EXAMPLES: + EXAMPLES:: sage: from sage.misc.latex import latex_examples sage: len(latex_examples.knot()._repr_()) > 300 @@ -2873,7 +2872,7 @@ def _repr_(self): """ String representation - EXAMPLES: + EXAMPLES:: sage: from sage.misc.latex import latex_examples sage: len(latex_examples.diagram()._repr_()) > 300 diff --git a/src/sage/misc/lazy_import_cache.py b/src/sage/misc/lazy_import_cache.py index 7688a9565e5..0f9d7de8aca 100644 --- a/src/sage/misc/lazy_import_cache.py +++ b/src/sage/misc/lazy_import_cache.py @@ -6,11 +6,12 @@ import os -from ..env import SAGE_SRC, DOT_SAGE +from ..env import SAGE_LIB, DOT_SAGE def get_cache_file(): """ - Returns a per-branch file for caching names of lazily imported modules. + Return the canonical filename for caching names of lazily imported + modules. EXAMPLES:: @@ -30,6 +31,6 @@ def get_cache_file(): True sage: sage.misc.lazy_import_cache.DOT_SAGE = OLD """ - mangled = os.path.realpath(SAGE_SRC).replace(os.sep, '_') + mangled = os.path.realpath(SAGE_LIB).replace(os.sep, '_') return os.path.join(DOT_SAGE, 'cache', "%s-lazy_import_cache.pickle" % mangled) diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index ab4605f720b..54f72e7bf46 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -61,7 +61,7 @@ ################################################################# -def sage_makedirs(dir): +def sage_makedirs(dirname): """ Python version of ``mkdir -p``: try to create a directory, and also create all intermediate directories as necessary. Succeed silently @@ -74,18 +74,18 @@ def sage_makedirs(dir): sage: sage_makedirs(DOT_SAGE) # no output The following fails because we are trying to create a directory in - place of an ordinary file (the main Sage executable):: + place of an ordinary file:: - sage: sage_executable = os.path.join(SAGE_ROOT, 'sage') - sage: sage_makedirs(sage_executable) + sage: filename = tmp_filename() + sage: sage_makedirs(filename) Traceback (most recent call last): ... - OSError: ... + OSError: [Errno ...] File exists: ... """ try: - os.makedirs(dir) + os.makedirs(dirname) except OSError: - if not os.path.isdir(dir): + if not os.path.isdir(dirname): raise @@ -715,14 +715,44 @@ def uniq(x): EXAMPLES:: - sage: v = uniq([1,1,8,-5,3,-5,'a','x','a']) - sage: v # potentially random ordering of output - ['a', 'x', -5, 1, 3, 8] - sage: set(v) == set(['a', 'x', -5, 1, 3, 8]) - True + sage: uniq([1, 1, 8, -5, 3, -5, -13, 13, -13]) + doctest:...: DeprecationWarning: the output of uniq(X) being sorted is deprecated; use sorted(set(X)) instead if you want sorted output + See https://trac.sagemath.org/27014 for details. + [-13, -5, 1, 3, 8, 13] """ - v = sorted(set(x)) - return v + # After deprecation period, rename _stable_uniq -> uniq + from sage.misc.superseded import deprecation + deprecation(27014, "the output of uniq(X) being sorted is deprecated; use sorted(set(X)) instead if you want sorted output") + return sorted(set(x)) + + +def _stable_uniq(L): + """ + Iterate over the elements of ``L``, yielding every element at most + once: keep only the first occurance of any item. + + The items must be hashable. + + INPUT: + + - ``L`` -- iterable + + EXAMPLES:: + + sage: from sage.misc.misc import _stable_uniq + sage: L = [1, 1, 8, -5, 3, -5, 'a', 'x', 'a'] + sage: it = _stable_uniq(L) + sage: it + + sage: list(it) + [1, 8, -5, 3, 'a', 'x'] + """ + seen = set() + for x in L: + if x in seen: + continue + yield x + seen.add(x) def coeff_repr(c, is_latex=False): @@ -854,7 +884,7 @@ def repr_monomial(monomial): try: if c < 0: negative = True - except NotImplementedError: + except (NotImplementedError, TypeError): # comparisons may not be implemented for some coefficients pass if negative: @@ -1640,7 +1670,7 @@ def __hash__(self): unique representation of parents taking ``attrcall`` objects as input; see :trac:`8911`. """ - return hash((self.args, tuple(self.kwds.items()))) + return hash((self.args, tuple(sorted(self.kwds.items())))) def attrcall(name, *args, **kwds): diff --git a/src/sage/misc/nested_class_test.py b/src/sage/misc/nested_class_test.py index 21321cadcf9..71e6c754cc0 100644 --- a/src/sage/misc/nested_class_test.py +++ b/src/sage/misc/nested_class_test.py @@ -228,6 +228,6 @@ class TestNestedParent(UniqueRepresentation, Parent): See the test in ``sage.misc.sageinspect.sage_getsourcelines``. """ - class Element: + class Element(object): "This is a dummy element class" pass diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index 689e5a23b91..3bca15d53b1 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -34,20 +34,21 @@ --------- """ -#***************************************************************************** +# **************************************************************************** # This 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 __future__ import print_function -from sage.env import SAGE_ROOT, SAGE_PKGS +from sage.env import SAGE_PKGS import json import os import subprocess +import sys try: # Python 3.3+ from urllib.request import urlopen @@ -142,9 +143,15 @@ def pip_installed_packages(): sage: d['beautifulsoup'] # optional - beautifulsoup u'...' """ - proc = subprocess.Popen(["pip", "list", "--no-index", "--format", "json"], stdout=subprocess.PIPE) - stdout = proc.communicate()[0].decode() - return {package['name'].lower():package['version'] for package in json.loads(stdout)} + with open(os.devnull, 'w') as devnull: + proc = subprocess.Popen( + [sys.executable, "-m", "pip", "list", "--no-index", "--format", "json"], + stdout=subprocess.PIPE, + stderr=devnull, + ) + stdout = proc.communicate()[0].decode() + return {package['name'].lower():package['version'] + for package in json.loads(stdout)} def list_packages(*pkg_types, **opts): r""" @@ -330,6 +337,7 @@ def is_package_installed(package, exclude_pip=True): """ return any(p.split('-')[0] == package for p in installed_packages(exclude_pip)) + def package_versions(package_type, local=False): r""" Return version information for each Sage package. @@ -362,6 +370,7 @@ def package_versions(package_type, local=False): """ return {pkg['name']: (pkg['installed_version'], pkg['remote_version']) for pkg in list_packages(package_type, local=local).values()} + def standard_packages(): """ Return two lists. The first contains the installed and the second @@ -427,6 +436,7 @@ def optional_packages(): return (sorted(pkg['name'] for pkg in pkgs if pkg['installed']), sorted(pkg['name'] for pkg in pkgs if not pkg['installed'])) + def experimental_packages(): """ Return two lists. The first contains the installed and the second @@ -453,6 +463,42 @@ def experimental_packages(): return (sorted(pkg['name'] for pkg in pkgs if pkg['installed']), sorted(pkg['name'] for pkg in pkgs if not pkg['installed'])) +def package_manifest(package): + """ + Return the manifest for ``package``. + + INPUT: + + - ``package`` -- package name + + The manifest is written in the file + ``SAGE_SPKG_INST/package-VERSION``. It is a JSON file containing a + dictionary with the package name, version, installation date, list + of installed files, etc. + + EXAMPLES:: + + sage: from sage.misc.package import package_manifest + sage: sagetex_manifest = package_manifest('sagetex') + sage: sagetex_manifest['package_name'] == 'sagetex' + True + sage: 'files' in sagetex_manifest + True + + Test a nonexistent package:: + + sage: package_manifest('dummy-package') + Traceback (most recent call last): + ... + KeyError: 'dummy-package' + """ + version = installed_packages()[package] + stamp_file = os.path.join(os.environ['SAGE_SPKG_INST'], + '{}-{}'.format(package, version)) + with open(stamp_file) as f: + spkg_meta = json.load(f) + return spkg_meta + class PackageNotFoundError(RuntimeError): """ diff --git a/src/sage/misc/persist.pyx b/src/sage/misc/persist.pyx index c493b20a312..b413db13018 100644 --- a/src/sage/misc/persist.pyx +++ b/src/sage/misc/persist.pyx @@ -76,12 +76,13 @@ def load(*filename, compress=True, verbose=True): EXAMPLES:: - sage: u = 'http://sage.math.washington.edu/home/was/db/test.sobj' + sage: u = 'http://www.sagemath.org/files/test.sobj' sage: s = load(u) # optional - internet - Attempting to load remote file: http://sage.math.washington.edu/home/was/db/test.sobj - Loading: [.] + Attempting to load remote file: http://www.sagemath.org/files/test.sobj + Loading started + Loading ended sage: s # optional - internet - 'hello SAGE' + 'hello SageMath' We test loading a file or multiple files or even mixing loading files and objects:: @@ -980,7 +981,7 @@ def picklejar(obj, dir=None): environment variable ``SAGE_PICKLE_JAR``, which will make it so :func:`dumps` will by default call :func:`picklejar` with the default dir. Once you do that and doctest Sage, you'll find that - the ``SAGE_ROOT/tmp/pickle_jar`` directory contains a bunch of + the ``DOT_SAGE/pickle_jar`` directory contains a bunch of pickled objects along with corresponding txt descriptions of them. Use the :func:`unpickle_all` to see if they unpickle later. @@ -989,7 +990,7 @@ def picklejar(obj, dir=None): - ``obj`` -- a pickleable object - ``dir`` -- a string or None; if None then ``dir`` defaults to - ``SAGE_ROOT/tmp/pickle_jar`` + ``DOT_SAGE/pickle_jar`` EXAMPLES:: @@ -1021,7 +1022,8 @@ def picklejar(obj, dir=None): sage: os.chmod(dir, 0o755) """ if dir is None: - dir = os.path.join(os.environ['SAGE_ROOT'], '/tmp/pickle_jar/') + from sage.env import DOT_SAGE + dir = os.path.join(DOT_SAGE, 'pickle_jar') try: os.makedirs(dir) except OSError as err: diff --git a/src/sage/misc/remote_file.py b/src/sage/misc/remote_file.py index dbfa74185e8..4036224a52d 100644 --- a/src/sage/misc/remote_file.py +++ b/src/sage/misc/remote_file.py @@ -22,9 +22,13 @@ def get_remote_file(filename, verbose=True): EXAMPLES:: - sage: g = get_remote_file("http://sagemath.org/ack.html", verbose=False) # optional - internet - sage: len(open(g).read()) # optional - internet; random - 10198 + sage: url = 'http://www.sagemath.org/files/loadtest.py' + sage: g = get_remote_file(url, verbose=False) # optional - internet + sage: with open(g) as f: print(f.read()) # optional - internet + print("hi from the net") + + print(2+3) + """ if verbose: print("Attempting to load remote file: " + filename) @@ -35,24 +39,18 @@ def get_remote_file(filename, verbose=True): # so do not import it in the module scope. # import compatible with py2 and py3 - from six.moves.urllib.request import urlretrieve + from six.moves.urllib.request import Request, urlopen + req = Request(filename, headers={"User-Agent":"sage-doctest"}) - global cur - cur = 0 if verbose: - sys.stdout.write("Loading: [") - sys.stdout.flush() - urlretrieve(filename, temp_name, report_hook) - print("]") - else: - urlretrieve(filename, temp_name) + print("Loading started") + + content = urlopen(req, timeout=1) + with open(temp_name, 'w') as f: + f.write(content.read()) + + if verbose: + print("Loading ended") + return temp_name -cur = 0 -def report_hook(block, size, total): - global cur - n = block*size*50/total - if n > cur: - cur = n - sys.stdout.write('.') - sys.stdout.flush() diff --git a/src/sage/misc/rest_index_of_methods.py b/src/sage/misc/rest_index_of_methods.py index 6aee7768924..fbac3d0161d 100644 --- a/src/sage/misc/rest_index_of_methods.py +++ b/src/sage/misc/rest_index_of_methods.py @@ -15,6 +15,7 @@ from sage.misc.sageinspect import _extract_embedded_position + def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True): r""" Return a ReST table describing a list of functions. @@ -241,7 +242,6 @@ def list_of_subfunctions(root, only_local_functions=True): {: 'x'}) """ - import inspect if inspect.ismodule(root): ismodule = True elif inspect.isclass(root): diff --git a/src/sage/misc/sage_input.py b/src/sage/misc/sage_input.py index 9e4bc9ce9e0..b811e98652e 100644 --- a/src/sage/misc/sage_input.py +++ b/src/sage/misc/sage_input.py @@ -2280,8 +2280,8 @@ def __init__(self, sib, entries): sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() - sage: sib.dict({'us':'good', 'them':'bad'}) - {dict: {{atomic:'them'}:{atomic:'bad'}, {atomic:'us'}:{atomic:'good'}}} + sage: sib.dict({'me':'good', 'you':'bad'}) + {dict: {{atomic:'me'}:{atomic:'good'}, {atomic:'you'}:{atomic:'bad'}}} sage: sib.dict([(10, 'PS2'), (12, 'PS2'), (13, 'PS3')]) {dict: {{atomic:10}:{atomic:'PS2'}, {atomic:12}:{atomic:'PS2'}, {atomic:13}:{atomic:'PS3'}}} """ diff --git a/src/sage/misc/sage_ostools.pyx b/src/sage/misc/sage_ostools.pyx index f3512ac3846..a272097876f 100644 --- a/src/sage/misc/sage_ostools.pyx +++ b/src/sage/misc/sage_ostools.pyx @@ -58,7 +58,7 @@ def restore_cwd(chdir=None): - ``chdir`` -- optionally change directories to the given directory upon entering the context manager - EXAMPLES: + EXAMPLES:: sage: import os sage: from sage.misc.sage_ostools import restore_cwd diff --git a/src/sage/misc/sage_timeit.py b/src/sage/misc/sage_timeit.py index 38516329664..f6b33cacad9 100644 --- a/src/sage/misc/sage_timeit.py +++ b/src/sage/misc/sage_timeit.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ Accurate timing information for Sage commands @@ -43,7 +44,7 @@ class SageTimeitResult(object): :: - sage: units = ["s", "ms", "\xc2\xb5s", "ns"] + sage: units = [u"s", u"ms", u"μs", u"ns"] sage: scaling = [1, 1e3, 1e6, 1e9] sage: number = 7 sage: repeat = 13 @@ -90,7 +91,11 @@ def __repr__(self): sage: SageTimeitResult(stats) #indirect doctest 1 loops, best of 2: 3.14 ns per loop """ - return "%d loops, best of %d: %.*g %s per loop" % self.stats + s = u"%d loops, best of %d: %.*g %s per loop" % self.stats + if isinstance(s, str): + return s + return s.encode("utf-8") + def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, precision=3, seconds=False): """nodetex @@ -210,7 +215,7 @@ def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, prec if stmt == "": return '' - units = ["s", "ms", "\xc2\xb5s", "ns"] + units = [u"s", u"ms", u"μs", u"ns"] scaling = [1, 1e3, 1e6, 1e9] timer = timeit_.Timer() diff --git a/src/sage/misc/sage_timeit_class.pyx b/src/sage/misc/sage_timeit_class.pyx index 9dcc1e57665..273523d083b 100644 --- a/src/sage/misc/sage_timeit_class.pyx +++ b/src/sage/misc/sage_timeit_class.pyx @@ -81,7 +81,7 @@ class SageTimeit: globs = globals() return sage_timeit.sage_timeit(code, globs, **kwds) - def __call__(self, code, globals=None, preparse=None, **kwds): + def __call__(self, code, globals=None, **kwds): """ INPUT: @@ -104,18 +104,17 @@ class SageTimeit: OUTPUT: - This method prints the timing information and does not return - anything, except if the option ``seconds=True`` was passed, in - which case the wall time in seconds is returned. + Return the timing information, either as + :class:`~sage.misc.sage_timeit.SageTimeitResult` + or as a floating-point number containing the number of seconds + (if ``seconds=True`` was passed). EXAMPLES:: sage: timeit('2^10000', preparse=False, number=100) 100 loops, best of 3: ... per loop """ - if 'seconds' in kwds: - return self.eval(code, globals, preparse=preparse, **kwds) - print(self.eval(code, globals, preparse=preparse, **kwds)) + return self.eval(code, globals, **kwds) timeit = SageTimeit() diff --git a/src/sage/misc/sage_unittest.py b/src/sage/misc/sage_unittest.py index d114255a4a4..8fc8ba71131 100644 --- a/src/sage/misc/sage_unittest.py +++ b/src/sage/misc/sage_unittest.py @@ -2,15 +2,15 @@ Unit testing for Sage objects """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # # This 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/ +# **************************************************************************** import unittest import sys @@ -152,7 +152,7 @@ def __init__(self, instance): Test suite for Integer Ring """ from sage.structure.sage_object import SageObject - if not isinstance(instance, (SageObject,PythonObjectWithTests)): + if not isinstance(instance, (SageObject, PythonObjectWithTests)): instance = PythonObjectWithTests(instance) self._instance = instance @@ -163,10 +163,10 @@ def __repr__(self): sage: TestSuite(ZZ) Test suite for Integer Ring """ - return "Test suite for %s"%self._instance + return "Test suite for %s" % self._instance - - def run(self, category = None, skip = [], catch = True, raise_on_failure = False, **options): + def run(self, category=None, skip=[], catch=True, raise_on_failure=False, + **options): """ Run all the tests from this test suite: @@ -281,8 +281,8 @@ def _test_b(self, tester): tester.fail() skip = tuple(skip) # The class of exceptions that will be caught and reported; - # other exceptions will get through. None catches nothing. - catch_exception = Exception if catch else None + # other exceptions will get through. () catches nothing. + catch_exception = Exception if catch else () tester = instance_tester(self._instance, **options) failed = [] @@ -290,10 +290,10 @@ def _test_b(self, tester): tester.fail() if method_name[0:6] == "_test_" and method_name not in skip: # TODO: improve pretty printing # could use the doc string of the test method? - tester.info(tester._prefix+"running .%s() . . ."%method_name, newline = False) + tester.info(tester._prefix + "running .%s() . . ." % method_name, newline=False) test_method = getattr(self._instance, method_name) try: - test_method(tester = tester) + test_method(tester=tester) tester.info(" pass") except catch_exception as e: failed.append(method_name) @@ -302,26 +302,28 @@ def _test_b(self, tester): tester.fail() # which has already reported the details of # that failure if not tester._verbose: - print(tester._prefix+"Failure in {}".format(method_name)) + print(tester._prefix + "Failure in {}".format(method_name)) else: if tester._verbose: tester.info(" fail") else: - print(tester._prefix+"Failure in {}:".format(method_name)) + print(tester._prefix + "Failure in {}:".format(method_name)) s = traceback.format_exc() - print(tester._prefix + s.strip().replace("\n", "\n"+tester._prefix)) + print(tester._prefix + s.strip().replace("\n", "\n" + tester._prefix)) print(tester._prefix + "-" * 60) - if len(failed) > 0: - print(tester._prefix+"The following tests failed: {}".format(", ".join(failed))) + if failed: + print(tester._prefix + "The following tests failed: {}".format(", ".join(failed))) if raise_on_failure: raise TestSuiteFailure + class TestSuiteFailure(AssertionError): pass -def instance_tester(instance, tester = None, **options): + +def instance_tester(instance, tester=None, **options): """ - Returns a gadget attached to ``instance`` providing testing utilities. + Return a gadget attached to ``instance`` providing testing utilities. EXAMPLES:: @@ -356,10 +358,11 @@ def instance_tester(instance, tester = None, **options): if tester is None: return InstanceTester(instance, **options) else: - assert len(options) == 0 + assert not options assert tester._instance is instance return tester + class InstanceTester(unittest.TestCase): """ A gadget attached to an instance providing it with testing utilities. @@ -383,7 +386,8 @@ class InstanceTester(unittest.TestCase): # all that much anyways) longMessage = False - def __init__(self, instance, elements = None, verbose = False, prefix = "", max_runs = 4096, max_samples = None, **options): + def __init__(self, instance, elements=None, verbose=False, prefix="", + max_runs=4096, max_samples=None, **options): """ A gadget attached to an instance providing it with testing utilities. @@ -420,9 +424,9 @@ def runTest(self): """ pass - def info(self, message, newline = True): + def info(self, message, newline=True): """ - Displays user information + Display user information EXAMPLES:: @@ -442,7 +446,7 @@ def info(self, message, newline = True): """ if self._verbose: if newline: - sys.stdout.write(message+"\n") + sys.stdout.write(message + "\n") else: sys.stdout.write(message) sys.stdout.flush() @@ -456,14 +460,14 @@ def __repr__(self): Testing utilities for Integer Ring """ - return "Testing utilities for %s"%self._instance - + return "Testing utilities for %s" % self._instance def some_elements(self, S=None, repeat=None): """ - Returns a list (or iterable) of elements of the instance on which - the tests should be run. This is only meaningful for container - objects like parents. + Return a list (or iterable) of elements of the instance on which + the tests should be run. + + This is only meaningful for container objects like parents. INPUT: @@ -570,6 +574,7 @@ def some_elements(self, S=None, repeat=None): from sage.misc.misc import some_tuples return list(some_tuples(S, repeat, self._max_runs, self._max_samples)) + class PythonObjectWithTests(object): """ Utility class for running basis tests on a plain Python object diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index a19da807125..4641ca5812b 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -1018,11 +1018,16 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', The following produces an error because the string 'fetch(' is a malformed regular expression:: - sage: print(search_src(" fetch(", "def", interact=False)) + sage: print(search_src(" fetch(", "def", interact=False)) # py2 Traceback (most recent call last): ... error: unbalanced parenthesis + sage: print(search_src(" fetch(", "def", interact=False)) # py3 + Traceback (most recent call last): + ... + sre_constants.error: missing ), unterminated subpattern at position 6 + To fix this, *escape* the parenthesis with a backslash:: sage: print(search_src(r" fetch\(", "def", interact=False)) # random # long time @@ -1067,7 +1072,8 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) # random # long time misc/sagedoc.py:... len(search_src("matrix", module="sage.calculus", interact=False).splitlines()) # random misc/sagedoc.py:... len(search_src("matrix", path_re="calc", interact=False).splitlines()) > 15 - misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False)) + misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False)) # py2 + misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False)) # py3 misc/sagedoc.py:... print(search_src(r" fetch\(", "def", interact=False)) # random # long time misc/sagedoc.py:... print(search_src(r" fetch\(", "def", "pyx", interact=False)) # random # long time misc/sagedoc.py:... s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0 diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index a2315028edd..b4cb5f6560d 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -125,7 +125,7 @@ def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return import tokenize import re EMBEDDED_MODE = False -from sage.env import SAGE_SRC +from sage.env import SAGE_LIB def loadable_module_extension(): r""" @@ -249,7 +249,7 @@ def _extract_embedded_position(docstring): # 2) Module compiled by Sage's inline cython() compiler from sage.misc.misc import SPYX_TMP try_filenames = [ - os.path.join(SAGE_SRC, raw_filename), + os.path.join(SAGE_LIB, raw_filename), os.path.join(SPYX_TMP, '_'.join(raw_filename.split('_')[:-1]), raw_filename) ] @@ -1337,7 +1337,7 @@ def sage_getfile(obj): sage: P. = QQ[] sage: sage_getfile(P) - '...sage/rings/polynomial/multi_polynomial_libsingular.pyx' + '...sage/rings/polynomial/multi_polynomial_libsingular...' A problem fixed in :trac:`16309`:: @@ -1507,9 +1507,11 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return sage: sage.misc.sageinspect.sage_getargspec(foo) ArgSpec(args=['x', 'a', 'b'], varargs=None, keywords=None, defaults=('\')"', {False: 'bar'})) - The following produced a syntax error before the patch at :trac:`11913`:: + The following produced a syntax error before the patch at :trac:`11913`, + see also :trac:`26906`:: sage: sage.misc.sageinspect.sage_getargspec(r.lm) + ArgSpec(args=['self'], varargs='args', keywords='kwds', defaults=None) The following was fixed in :trac:`16309`:: @@ -1598,8 +1600,9 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return return _sage_getargspec_from_ast(proxy) except SyntaxError: # To fix trac #10860. See #11913 for more information. - return None - elif isinstance(obj,functools.partial): + # See also #26906. + pass + if isinstance(obj, functools.partial): base_spec = sage_getargspec(obj.func) return base_spec return sage_getargspec(obj.__class__.__call__) @@ -2174,20 +2177,17 @@ def sage_getsourcelines(obj): sage: from sage.misc.sageinspect import sage_getsource sage: P = TestNestedParent() sage: E = P.element_class - sage: E.__bases__ # py2 - (, - ) - sage: E.__bases__ # py3 + sage: E.__bases__ (, ) sage: print(sage_getsource(E)) - class Element: + class Element(object): "This is a dummy element class" pass sage: print(sage_getsource(P)) class TestNestedParent(UniqueRepresentation, Parent): ... - class Element: + class Element(object): "This is a dummy element class" pass @@ -2452,7 +2452,7 @@ def test3(b, # 12 Test _extract_embedded_position: - We cannot test the filename since it depends on SAGE_SRC. + We cannot test the filename since it depends on ``SAGE_LIB``. Make sure things work with no trailing newline:: diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 59eec322793..8392b471034 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -20,7 +20,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################## from __future__ import print_function, absolute_import from six import iteritems @@ -274,7 +274,6 @@ def __call__(self, func): from sage.misc.decorators import sage_wraps @sage_wraps(func) def wrapper(*args, **kwds): - from sage.misc.superseded import experimental_warning if not wrapper._already_issued: experimental_warning(self.trac_number, 'This class/method/function is marked as ' @@ -288,8 +287,8 @@ def wrapper(*args, **kwds): return wrapper -from sage.structure.sage_object import SageObject -class __experimental_self_test(SageObject): + +class __experimental_self_test(object): r""" This is a class only to demonstrate with a doc-test that the @experimental decorator only issues a warning message once (see :trac:`20601`). diff --git a/src/sage/misc/test_class_pickling.py b/src/sage/misc/test_class_pickling.py index 3ff5b9cff50..ba9c1e625cc 100644 --- a/src/sage/misc/test_class_pickling.py +++ b/src/sage/misc/test_class_pickling.py @@ -1,4 +1,5 @@ from __future__ import absolute_import +from six.moves import copyreg class bar: @@ -17,14 +18,14 @@ def metaclass(name, bases): EXAMPLES:: sage: from sage.misc.test_class_pickling import metaclass, bar - sage: c = metaclass("foo2", (object, bar,)) + sage: c = metaclass("foo2", (bar, object)) constructing class sage: c sage: type(c) sage: c.__bases__ - (<... 'object'>, ) + (<...sage.misc.test_class_pickling.bar...>, <... 'object'>) """ print("constructing class") @@ -46,7 +47,7 @@ class Metaclass(type): EXAMPLES:: sage: from sage.misc.test_class_pickling import metaclass, bar - sage: c = metaclass("foo", (object, bar,)) + sage: c = metaclass("foo", (bar, object)) constructing class sage: from six.moves import cPickle sage: s = cPickle.dumps(c) @@ -69,15 +70,15 @@ def __reduce__(self): EXAMPLES:: sage: from sage.misc.test_class_pickling import metaclass, bar - sage: c = metaclass("foo3", (object, bar,)) + sage: c = metaclass("foo3", (bar, object)) constructing class sage: c.__class__.__reduce__(c) reducing a class - (, ('foo3', (<... 'object'>, ))) + (, + ('foo3', (<...sage.misc.test_class_pickling.bar...>, <...'object'>))) """ print("reducing a class") return (metaclass, self.reduce_args) -from six.moves import copyreg copyreg.pickle(Metaclass, Metaclass.__reduce__) diff --git a/src/sage/misc/trace.py b/src/sage/misc/trace.py index 74fabffbb75..ae21eb8e531 100644 --- a/src/sage/misc/trace.py +++ b/src/sage/misc/trace.py @@ -64,7 +64,7 @@ def trace(code, preparse=True): Seeing the ipdb prompt and the 2 \* 5 in the output below is a strong indication that the trace command worked correctly:: - sage: print(s.before[s.before.find('--'):]) + sage: print(s.before[s.before.find(b'--'):].decode()) --... ipdb> c 2 * 5 diff --git a/src/sage/misc/weak_dict.pyx b/src/sage/misc/weak_dict.pyx index 26ce543667a..48122f291c4 100644 --- a/src/sage/misc/weak_dict.pyx +++ b/src/sage/misc/weak_dict.pyx @@ -124,7 +124,7 @@ import six from weakref import KeyedRef from copy import deepcopy -from cpython.dict cimport * +from cpython.dict cimport PyDict_SetItem, PyDict_Next from cpython.tuple cimport PyTuple_GET_SIZE, PyTuple_New from cpython.weakref cimport PyWeakref_NewRef from cpython.object cimport PyObject_Hash diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 52a8bcd73f7..4f9d6b82260 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -22,15 +22,15 @@ """ from __future__ import absolute_import -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein # # This 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.categories.all import ModularAbelianVarieties from sage.structure.sequence import Sequence, Sequence_generic @@ -2214,10 +2214,10 @@ def _ambient_hecke_matrix_on_modular_symbols(self, n): sage: (J0(11) * J1(13))._ambient_hecke_matrix_on_modular_symbols(2) [-2 0 0 0 0 0] [ 0 -2 0 0 0 0] - [ 0 0 -2 0 -1 1] - [ 0 0 1 -1 0 -1] - [ 0 0 1 1 -2 0] - [ 0 0 0 1 -1 -1] + [ 0 0 -1 -1 -1 1] + [ 0 0 1 -2 -1 0] + [ 0 0 0 0 -2 1] + [ 0 0 0 0 -1 -1] """ if not self.is_ambient(): return self.ambient_variety()._ambient_hecke_matrix_on_modular_symbols(n) @@ -2501,10 +2501,10 @@ def integral_homology(self): sage: H.hecke_operator(2).matrix() [-2 0 0 0 0 0] [ 0 -2 0 0 0 0] - [ 0 0 -2 0 -1 1] - [ 0 0 1 -1 0 -1] - [ 0 0 1 1 -2 0] - [ 0 0 0 1 -1 -1] + [ 0 0 -1 -1 -1 1] + [ 0 0 1 -2 -1 0] + [ 0 0 0 0 -2 1] + [ 0 0 0 0 -1 -1] """ return self.homology(ZZ) @@ -3094,8 +3094,6 @@ def finite_subgroup(self, X, field_of_definition=None, check=True): if field_of_definition is None: field_of_definition = QQbar - else: - field_of_definition = field_of_definition return FiniteSubgroup_lattice( self, X, field_of_definition=field_of_definition, check=check) diff --git a/src/sage/modular/abvar/constructor.py b/src/sage/modular/abvar/constructor.py index 5017bb5ae10..4255061b6c0 100644 --- a/src/sage/modular/abvar/constructor.py +++ b/src/sage/modular/abvar/constructor.py @@ -186,7 +186,7 @@ def AbelianVariety(X): if is_ModularSymbolsSpace(X): return abvar.ModularAbelianVariety_modsym(X) - if isinstance(X, (tuple,list)) and all([is_CongruenceSubgroup(G) for G in X]): + if isinstance(X, (tuple,list)) and all(is_CongruenceSubgroup(G) for G in X): return abvar.ModularAbelianVariety(X) raise TypeError("X must be an integer, string, newform, modsym space, congruence subgroup or tuple of congruence subgroups") diff --git a/src/sage/modular/abvar/cuspidal_subgroup.py b/src/sage/modular/abvar/cuspidal_subgroup.py index 7904792449d..e929e66b70c 100644 --- a/src/sage/modular/abvar/cuspidal_subgroup.py +++ b/src/sage/modular/abvar/cuspidal_subgroup.py @@ -11,7 +11,7 @@ sage: C = A.cuspidal_subgroup(); C Finite subgroup with invariants [19, 19] over QQ of Abelian variety J1(13) of dimension 2 sage: C.gens() - [[(1/19, 0, 0, 9/19)], [(0, 1/19, 1/19, 18/19)]] + [[(1/19, 0, 9/19, 9/19)], [(0, 1/19, 0, 9/19)]] sage: C.order() 361 sage: C.invariants() @@ -132,10 +132,10 @@ def _compute_lattice(self, rational_only=False, rational_subgroup=False): sage: C._compute_lattice() Free module of degree 4 and rank 4 over Integer Ring Echelon basis matrix: - [ 1/19 0 0 9/19] - [ 0 1/19 1/19 18/19] - [ 0 0 1 0] - [ 0 0 0 1] + [1/19 0 9/19 9/19] + [ 0 1/19 0 9/19] + [ 0 0 1 0] + [ 0 0 0 1] We compute with and without the optional ``rational_only`` option. diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 902d27a24c7..f986041230a 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -577,7 +577,7 @@ def gens(self): sage: J0(43).cuspidal_subgroup().gens() [[(0, 1/7, 0, 6/7, 0, 5/7)]] sage: J1(13).cuspidal_subgroup().gens() - [[(1/19, 0, 0, 9/19)], [(0, 1/19, 1/19, 18/19)]] + [[(1/19, 0, 9/19, 9/19)], [(0, 1/19, 0, 9/19)]] sage: J0(22).torsion_subgroup(6).gens() [[(1/6, 0, 0, 0)], [(0, 1/6, 0, 0)], [(0, 0, 1/6, 0)], [(0, 0, 0, 1/6)]] """ diff --git a/src/sage/modular/abvar/homology.py b/src/sage/modular/abvar/homology.py index 9e40ed42a8c..33c9357fe73 100644 --- a/src/sage/modular/abvar/homology.py +++ b/src/sage/modular/abvar/homology.py @@ -31,7 +31,7 @@ doctest:warning ... DeprecationWarning: The default order on free modules has changed. The old ordering is in sage.modules.free_module.EchelonMatrixKey - See http://trac.sagemath.org/23878 for details. + See http://trac.sagemath.org/23978 for details. [ Submodule of rank 2 of Integral Homology of Abelian variety J0(43) of dimension 3, Submodule of rank 4 of Integral Homology of Abelian variety J0(43) of dimension 3 @@ -388,10 +388,10 @@ def hecke_matrix(self, n): sage: J0(48).integral_homology().hecke_bound() 16 sage: t = J1(13).integral_homology().hecke_matrix(3); t + [-2 2 2 -2] + [-2 0 2 0] + [ 0 0 0 -2] [ 0 0 2 -2] - [-2 -2 0 2] - [-2 -2 0 0] - [ 0 -2 2 -2] sage: t.base_ring() Integer Ring """ @@ -461,17 +461,17 @@ def hecke_matrix(self, n): EXAMPLES:: sage: t = J1(13).homology(QQ).hecke_matrix(3); t + [-2 2 2 -2] + [-2 0 2 0] + [ 0 0 0 -2] [ 0 0 2 -2] - [-2 -2 0 2] - [-2 -2 0 0] - [ 0 -2 2 -2] sage: t.base_ring() Rational Field sage: t = J1(13).homology(GF(3)).hecke_matrix(3); t + [1 2 2 1] + [1 0 2 0] + [0 0 0 1] [0 0 2 1] - [1 1 0 2] - [1 1 0 0] - [0 1 2 1] sage: t.base_ring() Finite Field of size 3 """ @@ -552,10 +552,10 @@ def hecke_matrix(self, n): EXAMPLES:: sage: t = J1(13).homology(GF(3)).hecke_matrix(3); t + [1 2 2 1] + [1 0 2 0] + [0 0 0 1] [0 0 2 1] - [1 1 0 2] - [1 1 0 0] - [0 1 2 1] sage: t.base_ring() Finite Field of size 3 """ diff --git a/src/sage/modular/all.py b/src/sage/modular/all.py index 32d53d6a667..dd2ead1d705 100644 --- a/src/sage/modular/all.py +++ b/src/sage/modular/all.py @@ -1,3 +1,13 @@ +""" +Test for deprecations of imports into global namespace:: + + sage: buzzard_tpslopes + doctest:warning...: + DeprecationWarning: + Importing buzzard_tpslopes from here is deprecated. If you need to use it, please import it directly from sage.modular.buzzard + See https://trac.sagemath.org/27066 for details. + +""" from __future__ import absolute_import from sage.misc.lazy_import import lazy_import @@ -12,22 +22,22 @@ from .abvar.all import * from .dirichlet import (DirichletGroup, - kronecker_character, kronecker_character_upside_down, - trivial_character) + kronecker_character, kronecker_character_upside_down, + trivial_character) from .arithgroup.all import (Gamma0, Gamma1, GammaH, Gamma, SL2Z, - ArithmeticSubgroup_Permutation, - CongruenceSubgroup, FareySymbol) + ArithmeticSubgroup_Permutation, + CongruenceSubgroup, FareySymbol) from .cusps import Cusp, Cusps from .dims import (dimension_cusp_forms, - dimension_new_cusp_forms, - dimension_eis, - dimension_modular_forms, - sturm_bound) + dimension_new_cusp_forms, + dimension_eis, + dimension_modular_forms, + sturm_bound) -from .buzzard import buzzard_tpslopes +lazy_import("sage.modular.buzzard", 'buzzard_tpslopes', deprecation=27066) from .etaproducts import (EtaGroup, EtaProduct, EtaGroupElement, AllCusps, CuspFamily) diff --git a/src/sage/modular/arithgroup/congroup_gamma.py b/src/sage/modular/arithgroup/congroup_gamma.py index d8e7afa33ff..232005ebf2a 100644 --- a/src/sage/modular/arithgroup/congroup_gamma.py +++ b/src/sage/modular/arithgroup/congroup_gamma.py @@ -235,7 +235,8 @@ def reduce_cusp(self, c): TESTS:: - sage: G = Gamma(50); all([c == G.reduce_cusp(c) for c in G.cusps()]) + sage: G = Gamma(50) + sage: all(c == G.reduce_cusp(c) for c in G.cusps()) True """ N = self.level() diff --git a/src/sage/modular/arithgroup/congroup_generic.py b/src/sage/modular/arithgroup/congroup_generic.py index e3c48efe918..89926b129dc 100644 --- a/src/sage/modular/arithgroup/congroup_generic.py +++ b/src/sage/modular/arithgroup/congroup_generic.py @@ -101,7 +101,7 @@ def CongruenceSubgroup_constructor(*args): if not hasattr(R, "cover_ring") or R.cover_ring() != ZZ: raise TypeError("Ring of definition must be Z / NZ for some N") - if not all([x.matrix().det() == 1 for x in G.gens()]): + if not all(x.matrix().det() == 1 for x in G.gens()): raise ValueError("Group must be contained in SL(2, Z / N)") GG = _minimize_level(G) if GG in ZZ: diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 07cd03c0b9d..e03c7b3e39f 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -610,7 +610,6 @@ def vertex(self, M): True """ p = self._p - # M_orig = M def lift(a): try: @@ -621,9 +620,9 @@ def lift(a): if M.base_ring() is not ZZ: M = M.apply_map(lift, R=ZZ) - v = min([M[i, j].valuation(p) for i in range(2) for j in range(2)]) + v = min(M[i, j].valuation(p) for i in range(2) for j in range(2)) - if v != 0: + if v: M = p ** (-v) * M m00 = M[0, 0].valuation(p) m01 = M[0, 1].valuation(p) @@ -631,11 +630,10 @@ def lift(a): M = copy(M) M.swap_columns(0, 1) m00 = m01 - m10 = M[1, 0].valuation(p) tmp = M.determinant().valuation(p) - m00 bigpower = p ** tmp r = M[0, 0] - if r != 0: + if r: r /= p ** m00 # r = ZZ(r) % bigpower g, s, _ = xgcd(r, bigpower) @@ -1036,7 +1034,7 @@ def find_geodesic(self, v1, v2, normalized=True): if not normalized: v1, v2 = self.vertex(v1), self.vertex(v2) gamma = v2 - vv = self.vertex(gamma.adjoint() * v1) + vv = self.vertex(gamma.adjugate() * v1) chain, v0 = self.find_path(vv) return [self.vertex(gamma * x) for x in chain + [v0]] @@ -1428,7 +1426,7 @@ def __classcall__(cls, p, Nminus, Nplus=1, character=None, """ Ensure that a canonical BruhatTitsQuotient is created. - EXAMPLES: + EXAMPLES:: sage: BruhatTitsQuotient(3,17) is BruhatTitsQuotient(3,17,1) True @@ -2390,7 +2388,7 @@ def get_extra_embedding_matrices(self): verbose('Calling magma: pMatrixRing, args = %s' % [OrdMax, l]) M, f, rho = self._magma.function_call('pMatrixRing', args=[OrdMax, l], params={'Precision': 20}, nvals=3) v = [f.Image(OBasis[i]) for i in [1, 2, 3, 4]] - if all([Qp(l, 5)(v[kk][2, 1].sage()).valuation() >= 1 for kk in range(4)]) and not all([Qp(l, 5)(v[kk][2, 1].sage()).valuation() >= 2 for kk in range(4)]): + if all(Qp(l, 5)(v[kk][2, 1].sage()).valuation() >= 1 for kk in range(4)) and not all(Qp(l, 5)(v[kk][2, 1].sage()).valuation() >= 2 for kk in range(4)): found = True success = True else: @@ -2427,7 +2425,7 @@ def _increase_precision(self, amount=1): - ``amount`` Integer (default: 1). The amount by which to increase the precision. - EXAMPLES: + EXAMPLES:: sage: X = BruhatTitsQuotient(3,101) sage: X.get_embedding_matrix() @@ -2954,7 +2952,7 @@ def _get_atkin_lehner_data(self, q): x = self.embed_quaternion(beta1) nn = x.determinant().valuation() T = [beta1, - [DoubleCosetReduction(self, x.adjoint() * e.rep, + [DoubleCosetReduction(self, x.adjugate() * e.rep, extrapow=nn) for e in E]] success = True except (PrecisionError, NotImplementedError): @@ -3035,7 +3033,7 @@ def enumerate_words(v, n=None): for tt in T0: r = vinv * tt r_in_order = BB * Matrix(QQ, 4, 1, r.coefficient_tuple()) - if all([a.is_S_integral(Sset) for a in r_in_order.list()]): + if all(a.is_S_integral(Sset) for a in r_in_order.list()): new = False break if new: @@ -3046,7 +3044,7 @@ def enumerate_words(v, n=None): x = self.embed_quaternion(v1, prec=max(self._prec, 40), exact=False) * alphamat nn = x.determinant().valuation() - dcr = [DoubleCosetReduction(self, x.adjoint() * e.rep, + dcr = [DoubleCosetReduction(self, x.adjugate() * e.rep, extrapow=nn) for e in E] T.append([v1, dcr]) success = True @@ -3220,13 +3218,13 @@ def _find_lattice(self, v1, v2, as_edges, m): [0 0 0 1], [102 153 -34 102] ) """ - if(as_edges): + if as_edges: X = self._Xe else: X = self._Xv if m + 1 > self._prec: self.get_embedding_matrix(prec=m + 1) - v1adj = v1.adjoint() + v1adj = v1.adjugate() R = self._Mat_44 vecM = [v2 * X[ii] * v1adj for ii in range(4)] M = self._Iotainv * R([[vecM[ii][jj, kk] for ii in range(4)] diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index 344a93720b2..2551ca391ce 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -954,7 +954,7 @@ def _an_element_(self): A harmonic cocycle in self. - EXAMPLES: + EXAMPLES:: sage: X = BruhatTitsQuotient(5,23) sage: H = X.harmonic_cocycles(2,prec=10) @@ -1727,7 +1727,7 @@ def evaluate(self, e1): X = self.parent()._source p = self.parent().prime() u = DoubleCosetReduction(X, e1) - tmp = ((u.t(self.parent()._U.base_ring().precision_cap())) * p ** (u.power)).adjoint() + tmp = ((u.t(self.parent()._U.base_ring().precision_cap())) * p ** (u.power)).adjugate() S0 = self.parent()._Sigma0 return S0(tmp, check=False) * self._value[u.label] # Warning! Should remove check=False... @@ -2626,7 +2626,7 @@ def _make_invariant(self, F): m = M[ii] for v in Si: s += 1 - g = self._Sigma0(m.adjoint() * self._source.embed_quaternion(v[0], prec=self._prec).adjoint() * m,check = False) + g = self._Sigma0(m.adjugate() * self._source.embed_quaternion(v[0], prec=self._prec).adjugate() * m,check = False) newFi += g * x newF.append((QQ(1) / s) * newFi) else: @@ -2671,7 +2671,7 @@ def _apply_Up_operator(self, f, scale=False, original_moments=None): for gg, edge_list in HeckeData: u = edge_list[jj] tprec = 2 * (prec_cap + u.power) + 1 - r = S0(self._p ** -u.power * (u.t(tprec) * gg).adjoint(),check=False) + r = S0(self._p ** -u.power * (u.t(tprec) * gg).adjugate(),check=False) tmp += r * f._value[u.label] tmp *= factor for ii in range(self._n + 1): diff --git a/src/sage/modular/buzzard.py b/src/sage/modular/buzzard.py index 2faf6d8334c..fc980bf6c5c 100644 --- a/src/sage/modular/buzzard.py +++ b/src/sage/modular/buzzard.py @@ -10,13 +10,12 @@ - Kevin Buzzard: PARI program that implements underlying functionality """ - ############################################################################# # Copyright (C) 2006 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ############################################################################# from sage.interfaces.gp import Gp @@ -30,10 +29,10 @@ def gp(): EXAMPLES:: + sage: import sage.modular.buzzard sage: sage.modular.buzzard.gp() PARI/GP interpreter """ - global _gp if _gp is None: _gp = Gp(script_subdirectory='buzzard') @@ -66,7 +65,7 @@ def gp(): ## which is why this is commented out! ## """ ## s = gp().eval('DimensionCuspForms(%s, %s)'%(eps,k)) -## print s +## print(s) ## return Integer(s) @@ -83,6 +82,7 @@ def buzzard_tpslopes(p, N, kmax): EXAMPLES:: + sage: from sage.modular.buzzard import buzzard_tpslopes sage: c = buzzard_tpslopes(2,1,50) sage: c[50] [4, 8, 13] @@ -103,10 +103,9 @@ def buzzard_tpslopes(p, N, kmax): - Kevin Buzzard: several PARI/GP scripts - - William Stein (2006-03-17): small Sage wrapper of Buzzard's - scripts + - William Stein (2006-03-17): small Sage wrapper of Buzzard's scripts """ - v = gp().eval('tpslopes(%s, %s, %s)'%(p,N,kmax)) + v = gp().eval('tpslopes(%s, %s, %s)' % (p, N, kmax)) v = sage_eval(v) v.insert(0, []) # so v[k] = info about weight k (since python is 0-based) return v diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index 56ef823c9dc..47c3f8286d8 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -751,7 +751,7 @@ def is_gamma_h_equiv(self, other, G): sage: G = GammaH(25,[6]) ; M = G.modular_symbols() ; M Modular Symbols space of dimension 11 for Congruence Subgroup Gamma_H(25) with H generated by [6] of weight 2 with sign 0 and over Rational Field sage: M.cusps() - [37/75, 1/2, 31/125, 1/4, -2/5, 2/5, -1/5, 1/10, -3/10, 1/15, 7/15, 9/20] + [33/100, 1/3, 31/125, 1/4, 1/15, -7/15, 7/15, 4/15, 1/20, 3/20, 7/20, 9/20] sage: len(M.cusps()) 12 diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index a4b1ae66691..0dcf2ce64f3 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -1011,33 +1011,25 @@ def Gamma0_NFCusps(N): A list of inequivalent number field cusps. - EXAMPLES: - - :: + EXAMPLES:: sage: k. = NumberField(x^2 + 5) sage: N = k.ideal(3) sage: L = Gamma0_NFCusps(N) - The cusps in the list are inequivalent: + The cusps in the list are inequivalent:: - :: - - sage: all([not L[i].is_Gamma0_equivalent(L[j], N) for i, j in \ - mrange([len(L), len(L)]) if i = NumberField(x^4 - x^3 -21*x^2 + 17*x + 133) sage: N = k.ideal(5) @@ -1163,7 +1155,7 @@ def NFCusps_ideal_reps_for_levelN(N, nlists=1): sage: NFCusps_ideal_reps_for_levelN(N) [(Fractional ideal (1), Fractional ideal (2, a + 1))] sage: L = NFCusps_ideal_reps_for_levelN(N, 3) - sage: all([len(L[i])==k.class_number() for i in range(len(L))]) + sage: all(len(L[i]) == k.class_number() for i in range(len(L))) True :: @@ -1244,7 +1236,7 @@ def units_mod_ideal(I): Unit group with structure C6 x Z of Number Field in a with defining polynomial x^4 - x^3 - 21*x^2 + 17*x + 133 sage: I = k.ideal(3) sage: U = units_mod_ideal(I) - sage: all([U[j].is_unit() and not (U[j] in I) for j in range(len(U))]) + sage: all(U[j].is_unit() and (U[j] not in I) for j in range(len(U))) True """ k = I.number_field() diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index c4d6d8b9a30..7d2fde31412 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -46,7 +46,7 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004-2006 William Stein # Copyright (C) 2014 Julian Rueth # @@ -54,8 +54,8 @@ # 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 __future__ import print_function from six.moves import range, zip @@ -73,6 +73,7 @@ from sage.rings.qqbar import is_AlgebraicField from sage.rings.ring import is_Ring +from sage.misc.functional import round from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import WithEqualityById from sage.structure.element import MultiplicativeGroupElement @@ -1748,11 +1749,12 @@ def element(self): if is_ComplexField(P.base_ring()): zeta = P.zeta() zeta_argument = zeta.argument() - v = M([int(round(x.argument()/zeta_argument)) + v = M([int(round(x.argument() / zeta_argument)) for x in self.values_on_gens()]) else: dlog = P._zeta_dlog v = M([dlog[x] for x in self.values_on_gens()]) + v.set_immutable() return v def __setstate__(self, state): diff --git a/src/sage/modular/hecke/algebra.py b/src/sage/modular/hecke/algebra.py index 2957b1e2f99..13a4b4750eb 100644 --- a/src/sage/modular/hecke/algebra.py +++ b/src/sage/modular/hecke/algebra.py @@ -75,7 +75,7 @@ def _heckebasis(M): [1 0] [0 1], Hecke operator on Modular Symbols space of dimension 2 for Gamma_0(11) of weight 2 with sign 1 over Rational Field defined by: - [0 1] + [0 2] [0 5]] """ d = M.rank() @@ -410,7 +410,7 @@ def basis(self): sage: M = ModularSymbols(Gamma0(22), sign=1) sage: [B[0,0] for B in M.hecke_algebra().basis()] - [701, 512, 413, 160, 850] + [-955, -994, -706, -490, -1070] sage: [B[0, 0] for B in M.anemic_hecke_algebra().basis()] Traceback (most recent call last): ... @@ -534,20 +534,10 @@ def diamond_bracket_matrix(self, d): EXAMPLES:: sage: T = ModularSymbols(Gamma1(7), 4).hecke_algebra() - sage: T.diamond_bracket_matrix(3) - [ 0 0 1 0 0 0 0 0 0 0 0 0] - [ 1 0 0 0 0 0 0 0 0 0 0 0] - [ 0 1 0 0 0 0 0 0 0 0 0 0] - [ 0 0 0 -11/9 -4/9 1 2/3 7/9 2/9 7/9 -5/9 -2/9] - [ 0 0 0 58/9 17/9 -5 -10/3 4/9 5/9 -50/9 37/9 13/9] - [ 0 0 0 -22/9 -8/9 2 4/3 5/9 4/9 14/9 -10/9 -4/9] - [ 0 0 0 44/9 16/9 -4 -8/3 8/9 1/9 -28/9 20/9 8/9] - [ 0 0 0 0 0 0 0 0 0 0 1 0] - [ 0 0 0 0 0 0 0 0 0 0 0 1] - [ 0 0 0 1 0 0 0 0 0 0 0 0] - [ 0 0 0 2 0 -1 0 0 0 0 0 0] - [ 0 0 0 -4 0 4 1 0 0 0 0 0] - + sage: d3 = T.diamond_bracket_matrix(3) + sage: x = d3.charpoly().variables()[0] + sage: d3.charpoly() == (x^3-1)^4 + True """ return self.__M.diamond_bracket_matrix(d) diff --git a/src/sage/modular/hecke/ambient_module.py b/src/sage/modular/hecke/ambient_module.py index f62accea9c9..4bdfb271a1d 100644 --- a/src/sage/modular/hecke/ambient_module.py +++ b/src/sage/modular/hecke/ambient_module.py @@ -292,20 +292,20 @@ def degeneracy_map(self, codomain, t=1): sage: d1 = M.degeneracy_map(33); d1 Hecke module morphism degeneracy map corresponding to f(q) |--> f(q) defined by the matrix [ 1 0 0 0 -2 -1] - [ 0 0 -2 2 0 0] + [ 0 -1 1 0 0 0] Domain: Modular Symbols space of dimension 2 for Gamma_0(11) of weight ... Codomain: Modular Symbols space of dimension 6 for Gamma_0(33) of weight ... sage: M.degeneracy_map(33,3).matrix() - [ 3 2 2 0 -2 1] - [ 0 2 0 -2 0 0] + [ 3 2 0 2 -2 1] + [ 0 0 -1 1 0 0] sage: M = ModularSymbols(33,sign=1) sage: d2 = M.degeneracy_map(11); d2.matrix() - [ 1 0] - [ 0 1/2] - [ 0 -1] - [ 0 1] - [ -1 0] - [ -1 0] + [ 1 0] + [ 0 -2] + [ 0 2] + [ 0 1] + [-1 0] + [-1 0] sage: (d2*d1).matrix() [4 0] [0 4] diff --git a/src/sage/modular/hecke/hecke_operator.py b/src/sage/modular/hecke/hecke_operator.py index 45e5af7a4a1..d32b5b96cb1 100644 --- a/src/sage/modular/hecke/hecke_operator.py +++ b/src/sage/modular/hecke/hecke_operator.py @@ -118,21 +118,21 @@ def hecke_module_morphism(self): Hecke operator T_2 on Modular Symbols space of dimension 15 for Gamma_1(13) of weight 2 with sign 0 and over Rational Field sage: t.hecke_module_morphism() Hecke module morphism T_2 defined by the matrix - [ 2 1 0 0 0 0 0 0 0 0 0 0 0 0 -1] - [ 0 2 0 1 0 0 0 -1 0 0 0 0 0 0 0] - [ 0 0 2 0 0 1 -1 1 0 -1 0 1 -1 0 0] - [ 0 0 0 2 1 0 1 0 0 0 1 -1 0 0 0] - [ 0 0 1 0 2 0 0 0 0 1 -1 0 0 0 1] - [ 1 0 0 0 0 2 0 0 0 0 0 0 1 0 0] - [ 0 0 0 0 0 0 0 1 -1 1 -1 0 -1 1 1] - [ 0 0 0 0 0 0 0 -1 1 1 0 0 -1 1 0] - [ 0 0 0 0 0 0 -1 -1 0 1 -1 -1 1 0 -1] - [ 0 0 0 0 0 0 -2 0 2 -2 0 2 -2 1 -1] - [ 0 0 0 0 0 0 0 0 2 -1 1 0 0 1 -1] - [ 0 0 0 0 0 0 -1 1 2 -1 1 0 -2 2 0] - [ 0 0 0 0 0 0 0 0 1 1 0 -1 0 0 0] - [ 0 0 0 0 0 0 -1 1 1 0 1 1 -1 0 0] - [ 0 0 0 0 0 0 2 0 0 0 2 -1 0 1 -1] + [ 2 0 0 0 0 0 0 1 0 0 1 0 0 0 0] + [ 0 2 0 1 0 1 0 0 -1 0 0 0 0 0 1] + [ 0 1 2 0 0 0 0 0 0 0 0 -1 1 0 0] + [ 1 0 0 2 0 -1 1 0 1 0 -1 1 -1 0 0] + [ 0 0 1 0 2 0 -1 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 0 0 0 0 1 -2 2 -1] + [ 0 0 0 0 0 2 -1 0 -1 0 0 0 0 1 0] + [ 0 0 0 0 1 0 0 2 0 0 0 0 0 0 -1] + [ 0 0 0 0 0 1 0 0 -1 0 2 -1 0 2 -1] + [ 0 0 0 0 0 1 1 0 0 -1 0 1 -1 2 0] + [ 0 0 0 0 0 2 0 0 -1 -1 1 -1 0 1 0] + [ 0 0 0 0 0 1 1 0 1 0 0 0 -1 1 0] + [ 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0] + [ 0 0 0 0 0 1 0 0 1 -1 2 0 0 0 -1] + [ 0 0 0 0 0 0 0 0 0 1 0 -1 2 0 -1] Domain: Modular Symbols space of dimension 15 for Gamma_1(13) of weight ... Codomain: Modular Symbols space of dimension 15 for Gamma_1(13) of weight ... """ @@ -171,12 +171,12 @@ def _add_(self, other): sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3) sage: t2 + t3 Hecke operator on Modular Symbols space of dimension 6 for Gamma_1(6) of weight 4 with sign 0 and over Rational Field defined by: - [ 35 0 0 -8/7 24/7 -16/7] - [ 4 28 0 19/7 -57/7 38/7] - [ 18 0 9 -40/7 22/7 18/7] - [ 0 18 4 -22/7 -18/7 54/7] - [ 0 18 4 13/7 -53/7 54/7] - [ 0 18 4 13/7 -18/7 19/7] + [ 35 0 0 8/5 8/5 -16/5] + [ 4 28 0 -19/5 -19/5 38/5] + [ 18 0 9 -6 8 -2] + [ 0 18 4 -23/5 -13/5 46/5] + [ 0 18 4 2/5 -38/5 46/5] + [ 0 18 4 2/5 -13/5 21/5] sage: (t2 - t3).charpoly('x') x^6 + 36*x^5 + 104*x^4 - 3778*x^3 + 7095*x^2 - 3458*x """ @@ -227,12 +227,12 @@ def _sub_(self, other): sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3) sage: t2 - t3 # indirect doctest Hecke operator on Modular Symbols space of dimension 6 for Gamma_1(6) of weight 4 with sign 0 and over Rational Field defined by: - [ -19 0 0 4/7 -12/7 8/7] - [ 4 -26 0 -17/7 51/7 -34/7] - [ -18 0 7 -12/7 -6/7 18/7] - [ 0 -18 4 -16/7 34/7 -18/7] - [ 0 -18 4 -23/7 41/7 -18/7] - [ 0 -18 4 -23/7 34/7 -11/7] + [ -19 0 0 -4/5 -4/5 8/5] + [ 4 -26 0 17/5 17/5 -34/5] + [ -18 0 7 -18/5 12/5 6/5] + [ 0 -18 4 3/5 23/5 -26/5] + [ 0 -18 4 -2/5 28/5 -26/5] + [ 0 -18 4 -2/5 23/5 -21/5] """ return self.parent()(self.matrix() - other.matrix(), check=False) @@ -549,16 +549,16 @@ def __init__(self, parent, d): sage: type(d) sage: d.matrix() - [ 0 1 0 0 0 0 0 0 0 0] - [ 1 0 0 0 0 0 0 0 0 0] - [ 0 0 0 0 0 0 0 1 0 0] - [ 0 0 -8/17 -1 14/17 11/17 0 -8/17 14/17 11/17] - [ 0 0 0 0 0 0 0 0 1 0] - [ 0 0 0 0 0 0 0 0 0 1] - [ 0 0 16/17 0 -11/17 12/17 -1 16/17 -11/17 12/17] - [ 0 0 1 0 0 0 0 0 0 0] - [ 0 0 0 0 1 0 0 0 0 0] - [ 0 0 0 0 0 1 0 0 0 0] + [ 0 1 0 0 0 0 0 0 0 0] + [ 1 0 0 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 1 0 0 0] + [ 0 0 0 0 0 0 0 0 0 1] + [ 0 0 0 0 0 0 0 1 0 0] + [ 0 0 17/16 11/16 -3/4 -1 17/16 -3/4 0 11/16] + [ 0 0 1 0 0 0 0 0 0 0] + [ 0 0 0 0 1 0 0 0 0 0] + [ 0 0 -1/2 1/2 1 0 -1/2 1 -1 1/2] + [ 0 0 0 1 0 0 0 0 0 0] sage: d**4 == 1 True """ diff --git a/src/sage/modular/hecke/module.py b/src/sage/modular/hecke/module.py index 26380cb278f..007b8bb323f 100644 --- a/src/sage/modular/hecke/module.py +++ b/src/sage/modular/hecke/module.py @@ -1448,8 +1448,8 @@ def diamond_bracket_matrix(self, d): [-zeta4 0] [ 0 -zeta4] sage: ModularSymbols(Gamma1(5), 3).diamond_bracket_matrix(3) - [ 0 -1 0 0] - [ 1 0 0 0] + [ 0 1 0 0] + [-1 0 0 0] [ 0 0 0 1] [ 0 0 -1 0] """ @@ -1631,9 +1631,11 @@ def projection(self): Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 5 for Gamma_0(53) of weight 2 with sign 1 over Rational Field sage: p = S.projection() sage: S.basis() - ((1,33) - (1,37), (1,35), (1,49)) + ((1,43) - (1,45), (1,47), (1,50)) sage: [ p(x) for x in S.basis() ] - [(1,33) - (1,37), (1,35), (1,49)] + [(1,43) - (1,45), (1,47), (1,50)] + sage: all([p(x)==x for x in S.basis()]) + True """ # Compute the Hecke-stable projection map pi from the ambient diff --git a/src/sage/modular/hecke/submodule.py b/src/sage/modular/hecke/submodule.py index 99e4b7b1a7a..26f814d4d5c 100644 --- a/src/sage/modular/hecke/submodule.py +++ b/src/sage/modular/hecke/submodule.py @@ -1,7 +1,7 @@ """ Submodules of Hecke modules """ -#***************************************************************************** +# **************************************************************************** # Sage: System for Algebra and Geometry Experimentation # # Copyright (C) 2005 William Stein @@ -15,8 +15,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import import sage.arith.all as arith @@ -242,7 +242,7 @@ def _compute_hecke_matrix(self, n): def _compute_diamond_matrix(self, d): r""" - EXAMPLES: + EXAMPLES:: sage: f = ModularSymbols(Gamma1(13),2,sign=1).cuspidal_subspace().decomposition()[0] sage: a = f.diamond_bracket_operator(2).matrix() # indirect doctest @@ -969,9 +969,11 @@ def submodule_from_nonembedded_module(self, V, Vdual=None, check=True): return self.ambient_hecke_module().submodule(V, Vdual, check=check) def hecke_bound(self): - """ - Compute the Hecke bound for self; that is, a number n such that the - T_m for m = n generate the Hecke algebra. + r""" + Compute the Hecke bound for ``self``. + + This is a number `n` such that the `T_m` for `m \leq n` + generate the Hecke algebra. EXAMPLES:: diff --git a/src/sage/modular/local_comp/smoothchar.py b/src/sage/modular/local_comp/smoothchar.py index 68b7ee19ba2..0471d9f7a1e 100644 --- a/src/sage/modular/local_comp/smoothchar.py +++ b/src/sage/modular/local_comp/smoothchar.py @@ -97,7 +97,7 @@ def _check_level(self): """ if self.level() == 0: return v = self.parent().subgroup_gens(self.level()) - if all([self(x) == 1 for x in v]): + if all(self(x) == 1 for x in v): new_gens = self.parent().unit_gens(self.level() - 1) new_values = [self(x) for x in new_gens] self._values_on_gens = Sequence(new_values, universe=self.base_ring(), immutable=True) @@ -754,8 +754,8 @@ def _test_unitgens(self, **options): gens = self.unit_gens(c) exps = self.exponents(c) T.assertTrue(exps[-1] == 0) - T.assertTrue(all([u != 0 for u in exps[:-1]])) - T.assertTrue(all([u.parent() is self.number_field() for u in gens])) + T.assertTrue(all(u != 0 for u in exps[:-1])) + T.assertTrue(all(u.parent() is self.number_field() for u in gens)) I = self.ideal(c) for i in range(len(exps[:-1])): @@ -790,7 +790,7 @@ def _test_subgroupgens(self, **options): for c in range(1, 6): sgs = self.subgroup_gens(c) I2 = self.ideal(c-1) - T.assertTrue(all([x-1 in I2 for x in sgs]), "Kernel gens at level %s not in kernel!" % c) + T.assertTrue(all(x - 1 in I2 for x in sgs), "Kernel gens at level %s not in kernel!" % c) # now find the exponent of the kernel diff --git a/src/sage/modular/local_comp/type_space.py b/src/sage/modular/local_comp/type_space.py index 0f1a8426e4a..5497d529c38 100644 --- a/src/sage/modular/local_comp/type_space.py +++ b/src/sage/modular/local_comp/type_space.py @@ -412,19 +412,23 @@ def _rho_s(self, g): sage: from sage.modular.local_comp.type_space import example_type_space sage: T = example_type_space(2) - sage: T._rho_s([1,1,0,1]) - [ 0 0 0 -1] - [ 0 0 -1 0] - [ 0 1 -2 1] + sage: TT = T._rho_s([1,1,0,1]); TT + [ 0 0 1 0] [ 1 0 -1 1] - sage: T._rho_s([0,-1,1,0]) - [ 0 1 -2 1] - [ 0 0 -1 0] - [ 0 -1 0 0] - [ 1 -2 1 0] + [ 0 0 -2 1] + [ 0 -1 -2 1] + sage: TT**5 == 1 + True + sage: TS = T._rho_s([0,-1,1,0]); TS + [ 0 0 1 0] + [ 0 0 1 -1] + [ 1 0 0 0] + [ 1 -1 0 0] + sage: TS**2 == 1 + True sage: example_type_space(3)._rho_s([1,1,0,1]) - [ 0 1] [-1 -1] + [ 1 0] """ if self.conductor() % 2 == 1: return self._rho_ramified(g) @@ -442,12 +446,12 @@ def _second_gen_unramified(self): sage: from sage.modular.local_comp.type_space import example_type_space sage: T = example_type_space(2) - sage: T._second_gen_unramified() - [ 0 1 -2 1] - [ 0 0 -1 0] - [ 0 -1 0 0] - [ 1 -2 1 0] - sage: T._second_gen_unramified()**4 == 1 + sage: TS = T._second_gen_unramified(); TS + [ 0 0 1 0] + [ 0 0 1 -1] + [ 1 0 0 0] + [ 1 -1 0 0] + sage: TS**2 == 1 True """ f = self.prime() ** self.u() @@ -476,10 +480,10 @@ def _rho_unramified(self, g): sage: from sage.modular.local_comp.type_space import example_type_space sage: T = example_type_space(2) sage: T._rho_unramified([2,1,1,1]) - [-1 1 -1 1] - [ 0 0 0 1] + [-1 0 0 -1] + [ 0 -1 1 0] [ 1 -1 0 1] - [ 1 -2 1 0] + [ 2 -1 1 1] sage: T._rho_unramified([1,-2,1,-1]) == T._rho_unramified([2,1,1,1]) * T._rho_unramified([0,-1,1,0]) True """ @@ -513,8 +517,8 @@ def _rho_ramified(self, g): sage: from sage.modular.local_comp.type_space import example_type_space sage: T = example_type_space(3) sage: T._rho_ramified([1,0,3,1]) + [ 0 1] [-1 -1] - [ 1 0] sage: T._rho_ramified([1,3,0,1]) == 1 True """ @@ -565,10 +569,10 @@ def _intertwining_basis(self, a): sage: from sage.modular.local_comp.type_space import example_type_space sage: example_type_space(2)._intertwining_basis(2) [ - [ 1 -2 1 0] [ 1 -1 0 1] - [ 1 0 -1 1] - [ 0 1 -2 1] + [ 0 0 1 -1] + [ 0 1 1 -1] + [-1 1 2 -2] ] sage: example_type_space(3)._intertwining_basis(2) [ @@ -607,10 +611,10 @@ def _discover_torus_action(self): sage: from sage.modular.local_comp.type_space import example_type_space sage: example_type_space(2).rho([2,0,0,1]) # indirect doctest - [ 1 -2 1 0] - [ 1 -1 0 1] - [ 1 0 -1 1] - [ 0 1 -2 1] + [-1 1 0 -1] + [ 0 0 -1 1] + [ 0 -1 -1 1] + [ 1 -1 -2 2] """ f = self.prime() ** self.u() if len(Zmod(f).unit_gens()) != 1: @@ -633,10 +637,10 @@ def rho(self, g): sage: from sage.modular.local_comp.type_space import example_type_space sage: T = example_type_space(2) sage: m = T.rho([2,0,0,1]); m - [ 1 -2 1 0] - [ 1 -1 0 1] - [ 1 0 -1 1] - [ 0 1 -2 1] + [-1 1 0 -1] + [ 0 0 -1 1] + [ 0 -1 -1 1] + [ 1 -1 -2 2] sage: v = T.eigensymbol_subspace().basis()[0] sage: m * v == v True @@ -690,7 +694,7 @@ def rho(self, g): # funny business if (self.conductor() % 2 == 0): - if all([x.valuation(p) > 0 for x in g]): + if all(x.valuation(p) > 0 for x in g): eps = self.form().character()(crt(1, p, f, self.tame_level())) return ~eps * self.rho([x // p for x in g]) else: diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index 0bfee0905e1..8d3ab086a29 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -298,7 +298,7 @@ def __find_eisen_chars_gammaH(N, H, k): """ params = [] for chi in dirichlet.DirichletGroup(N): - if all([chi(h) == 1 for h in H]): + if all(chi(h) == 1 for h in H): params += __find_eisen_chars(chi, k) return params diff --git a/src/sage/modular/modform/eis_series_cython.pyx b/src/sage/modular/modform/eis_series_cython.pyx index f7e944cb055..3557c6b8dc1 100644 --- a/src/sage/modular/modform/eis_series_cython.pyx +++ b/src/sage/modular/modform/eis_series_cython.pyx @@ -3,7 +3,7 @@ Eisenstein Series (optimized compiled functions) """ from cysignals.memory cimport check_allocarray, sig_free -from cysignals.signals cimport sig_on, sig_off +from cysignals.signals cimport sig_check from sage.rings.rational_field import QQ from sage.rings.power_series_ring import PowerSeriesRing @@ -161,8 +161,7 @@ cpdef eisenstein_series_poly(int k, int prec = 10) : """ cdef mpz_t *val = check_allocarray(prec, sizeof(mpz_t)) cdef mpz_t one, mult, term, last, term_m1, last_m1 - cdef unsigned long int expt - cdef long ind, ppow, int_p + cdef long ind cdef int i cdef Fmpz_poly res = Fmpz_poly.__new__(Fmpz_poly) @@ -173,8 +172,6 @@ cpdef eisenstein_series_poly(int k, int prec = 10) : if (prec == 0): return Fmpz_poly.__new__(Fmpz_poly) - sig_on() - mpz_init(one) mpz_init(term) mpz_init(last) @@ -182,33 +179,33 @@ cpdef eisenstein_series_poly(int k, int prec = 10) : mpz_init(term_m1) mpz_init(last_m1) - for i from 0 <= i < prec : - mpz_init(val[i]) - mpz_set_si(val[i], 1) + for i in range(prec): + mpz_init_set_si(val[i], 1) mpz_set_si(one, 1) - expt = (k - 1) - a0 = - bernoulli(k) / (2*k) + cdef unsigned long expt = k - 1 + a0 = -bernoulli(k) / (2*k) - for p in primes(1,prec) : - int_p = int(p) - ppow = int_p + cdef long p, ppow + for p in primes(1, prec) : + ppow = p - mpz_set_si(mult, int_p) + mpz_set_si(mult, p) mpz_pow_ui(mult, mult, expt) mpz_mul(term, mult, mult) mpz_set(last, mult) - while (ppow < prec): + while ppow < prec: + sig_check() ind = ppow mpz_sub(term_m1, term, one) mpz_sub(last_m1, last, one) - while (ind < prec): + while ind < prec: mpz_mul(val[ind], val[ind], term_m1) mpz_fdiv_q(val[ind], val[ind], last_m1) ind += ppow - ppow *= int_p + ppow *= p mpz_set(last, term) mpz_mul(term, term, mult) @@ -228,6 +225,4 @@ cpdef eisenstein_series_poly(int k, int prec = 10) : sig_free(val) - sig_off() - return res diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 31b2ca6b97f..c994d924004 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -15,15 +15,15 @@ - :class:`EisensteinSeries` """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004-2008 William Stein # # This 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 __future__ import absolute_import, division from six.moves import range @@ -50,7 +50,7 @@ def is_ModularFormElement(x): """ - Return True if x is a modular form. + Return ``True`` if x is a modular form. EXAMPLES:: @@ -62,6 +62,7 @@ def is_ModularFormElement(x): """ return isinstance(x, ModularFormElement) + def delta_lseries(prec=53, max_imaginary_part=0, max_asymp_coeffs=40): @@ -104,6 +105,7 @@ def delta_lseries(prec=53, L.rename('L-series associated to the modular form Delta') return L + class ModularForm_abstract(ModuleElement): """ Constructor for generic class of a modular form. This @@ -113,7 +115,7 @@ class ModularForm_abstract(ModuleElement): """ def group(self): """ - Return the group for which self is a modular form. + Return the group for which ``self`` is a modular form. EXAMPLES:: @@ -124,7 +126,7 @@ def group(self): def weight(self): """ - Return the weight of self. + Return the weight of ``self``. EXAMPLES:: @@ -1032,7 +1034,7 @@ def dirichlet_convolution(A, B): # If the base ring is QQ we pass the coefficients to GP/PARI as exact # rationals. Otherwise, need to use the embedding. if self.base_ring() != QQ: - dirichlet_series = map(emb, dirichlet_series) + dirichlet_series = [emb(cf) for cf in dirichlet_series] if chi is not None: pari_precode_chi = str(chi.values()) + "[n%" + str(chi.conductor()) + "+1]; " @@ -1257,7 +1259,8 @@ def cm_discriminant(self): ... ValueError: Not a CM form """ - if not self.has_cm(): raise ValueError("Not a CM form") + if not self.has_cm(): + raise ValueError("Not a CM form") return -self.__cm_char.conductor() class Newform(ModularForm_abstract): @@ -1689,9 +1692,9 @@ def _atkin_lehner_eigenvalue_from_qexp(self, Q): q + a2*q^2 + (-a2 - 2)*q^3 - q^4 - a2*q^5 + O(q^6) sage: f._atkin_lehner_eigenvalue_from_qexp(5) a2 - """ - if Q == 1: return ZZ(1) + if Q == 1: + return ZZ(1) a_Q = self[Q] if not a_Q: raise ValueError("a_Q must be nonzero") @@ -1730,7 +1733,8 @@ def _atkin_lehner_eigenvalue_from_modsym(self, Q): sage: _ == F._atkin_lehner_eigenvalue_from_qexp(5) True """ - if Q == 1: return ZZ(1) + if Q == 1: + return ZZ(1) S = self._defining_modular_symbols() A = S.ambient() @@ -1744,7 +1748,8 @@ def _atkin_lehner_eigenvalue_from_modsym(self, Q): else: L = [] for a in xsrange(Q0): - if a.gcd(Q0) > 1: continue + if a.gcd(Q0) > 1: + continue aa = crt(a, 1, Q, N.prime_to_m_part(Q)) diam = matrix(ZZ, 2, lift_to_sl2z(0,aa,N) ) L.append( (W * diam * matrix(QQ, 2, [1,a/Q0,0,1]) ).change_ring(ZZ) ) @@ -1753,7 +1758,8 @@ def _atkin_lehner_eigenvalue_from_modsym(self, Q): e = S.dual_eigenvector(names=self._name()) i = e.nonzero_positions()[0] w = (W*e)[i]/e[i] - if W*e != w*e: raise ArithmeticError("Bug in Atkin--Lehner computation: eigenspace not invariant") + if W * e != w * e: + raise ArithmeticError("Bug in Atkin--Lehner computation: eigenspace not invariant") sign = prod([eps(-1) for eps in self.character().decomposition() if eps.conductor().divides(Q)]) return w / Q0 / sign * self.character()(crt(1, Q//Q0, Q, N//Q)) @@ -1999,14 +2005,18 @@ def atkin_lehner_eigenvalue(self, d=None, normalization='analytic', embedding=No if d is None: d = N d = ZZ(d) - if (N % d): raise ValueError("d should divide N") + if N % d: + raise ValueError("d should divide N") d = N // N.prime_to_m_part(d) d1 = d2 = d3 = 1 for (p, e) in d.factor(): - if self[p] == 0: d1 *= p**e - elif self.character().conductor().valuation(p) == e: d2 *= p**e - else: d3 *= p**e + if self[p] == 0: + d1 *= p**e + elif self.character().conductor().valuation(p) == e: + d2 *= p**e + else: + d3 *= p**e verbose("computing W_%s using modsym, W_%s using qexp, W_%s using both" % (d1, d2, d3), level=2) w1 = self._atkin_lehner_eigenvalue_from_modsym(d1) @@ -2022,7 +2032,7 @@ def atkin_lehner_eigenvalue(self, d=None, normalization='analytic', embedding=No else: R = embedding.codomain() - if normalization=='arithmetic': + if normalization == 'arithmetic': return embedding(w) else: # get rid of the normalisation factors @@ -2170,7 +2180,8 @@ def twist(self, chi, level=None, check=True): if p.divides(N) or p.divides(chi.level()): continue D = (D.hecke_operator(p) - self[p]*chi(p)).kernel() - if D.rank() == 1: break + if D.rank() == 1: + break if D.is_zero(): raise ValueError('twist of %s by %s is not a newform of level %s' % (self, chi, level)) else: @@ -2319,10 +2330,13 @@ def __mul__(self, other): from .constructor import ModularForms if newchar is not None: verbose("creating a parent with char") - newparent = ModularForms(newchar, self.weight() + other.weight(), base_ring = newchar.base_ring()) + newparent = ModularForms(newchar, self.weight() + other.weight(), + base_ring=newchar.base_ring()) verbose("parent is %s" % newparent) else: - newparent = ModularForms(self.group(), self.weight() + other.weight(), base_ring = ZZ) + newparent = ModularForms(self.group(), + self.weight() + other.weight(), + base_ring=ZZ) m = newparent.sturm_bound() newqexp = self.qexp(m) * other.qexp(m) @@ -2364,7 +2378,8 @@ def atkin_lehner_eigenvalue(self, d=None, embedding=None): ... NotImplementedError: Don't know how to compute Atkin-Lehner matrix acting on this space (try using a newform constructor instead) """ - if d is None: d = self.level() + if d is None: + d = self.level() try: f = self.parent().atkin_lehner_operator(d)(self) except NotImplementedError: @@ -2537,7 +2552,7 @@ def elliptic_curve(self): def _compute_element(self): """ - Compute self as a linear combination of the basis elements + Compute ``self`` as a linear combination of the basis elements of parent. EXAMPLES:: @@ -2550,12 +2565,13 @@ def _compute_element(self): M = self.parent() S = M.cuspidal_subspace() ## return S.find_in_space( self.__E.q_expansion( S.q_expansion_basis()[0].prec() ) ) + [0] * ( M.dimension() - S.dimension() ) - return vector(S.find_in_space( self.__E.q_expansion( S.sturm_bound() ) ) + [0] * ( M.dimension() - S.dimension() )) + return vector(S.find_in_space(self.__E.q_expansion(S.sturm_bound())) + [0] * (M.dimension() - S.dimension())) def _compute_q_expansion(self, prec): r""" The `q`-expansion of the modular form to precision `O(q^\text{prec})`. - This function takes one argument, which is the integer prec. + + This function takes one argument, which is the integer ``prec``. EXAMPLES:: @@ -2733,11 +2749,11 @@ def __compute_weight2_trivial_character(self, X): if n < 0: pass elif n == 0: - v.append(F(t-1)/F(24)) + v.append(F(t - 1) / F(24)) else: - an = sigma(n,1) + an = sigma(n, 1) if n % t == 0: - an -= t * sigma(n//t,1) + an -= t * sigma(n // t, 1) v.append(an) return v @@ -2806,9 +2822,9 @@ def __defining_parameters(self): K = chi.base_ring() n = K.zeta_order() if L == 1: - c0 = K(-psi.bernoulli(k))/K(2*k) + c0 = K(-psi.bernoulli(k)) / K(2 * k) else: - c0 = K(0) + c0 = K.zero() return (c0, chi, psi, K, n, t, L, M) def chi(self): @@ -2923,4 +2939,4 @@ def new_level(self): """ if self.__chi.is_trivial() and self.__psi.is_trivial() and self.weight() == 2: return factor(self.__t)[0][0] - return self.L()*self.M() + return self.L() * self.M() diff --git a/src/sage/modular/modform/half_integral.py b/src/sage/modular/modform/half_integral.py index efd8e04e8e0..0bae6bf53b3 100644 --- a/src/sage/modular/modform/half_integral.py +++ b/src/sage/modular/modform/half_integral.py @@ -25,14 +25,11 @@ def half_integral_weight_modform_basis(chi, k, prec): INPUT: + - ``chi`` -- a Dirichlet character with modulus divisible by 16 - - ``chi`` - a Dirichlet character with modulus - divisible by 16 - - - ``k`` - an odd integer = 1 - - - ``prec`` - a positive integer + - ``k`` -- an odd integer > 1 + - ``prec`` -- a positive integer OUTPUT: a list of power series @@ -114,15 +111,14 @@ def half_integral_weight_modform_basis(chi, k, prec): isomorphic to `S_{k/2}(\chi)` via the map `(a,b) \mapsto a/\Theta_3`. """ - if chi.modulus() % 16: raise ValueError("the character must have modulus divisible by 16") - if not k%2: - raise ValueError("k (=%s) must be odd"%k) + if not k % 2: + raise ValueError("k (=%s) must be odd" % k) if k < 3: - raise ValueError("k (=%s) must be at least 3"%k) + raise ValueError("k (=%s) must be at least 3" % k) chi = chi.minimize_base_ring() psi = chi.parent()(DirichletGroup(4, chi.base_ring()).gen()) diff --git a/src/sage/modular/modform/numerical.py b/src/sage/modular/modform/numerical.py index 702d92b8cd2..fac22c1b80b 100644 --- a/src/sage/modular/modform/numerical.py +++ b/src/sage/modular/modform/numerical.py @@ -72,12 +72,12 @@ class NumericalEigenforms(SageObject): sage: n = numerical_eigenforms(23) sage: n == loads(dumps(n)) True - sage: n.ap(2) # rel tol 2e-15 - [3.0, 0.6180339887498941, -1.618033988749895] - sage: n.systems_of_eigenvalues(7) # rel tol 2e-15 + sage: n.ap(2) # rel tol 2e-14 + [3.0, -1.6180339887498947, 0.6180339887498968] + sage: n.systems_of_eigenvalues(7) # rel tol 2e-14 [ - [-1.618033988749895, 2.23606797749979, -3.23606797749979], - [0.6180339887498941, -2.2360679774997902, 1.2360679774997883], + [-1.6180339887498947, 2.2360679774997894, -3.2360679774997894], + [0.6180339887498968, -2.236067977499788, 1.2360679774997936], [3.0, 4.0, 6.0] ] sage: n.systems_of_abs(7) @@ -86,10 +86,10 @@ class NumericalEigenforms(SageObject): [1.6180339887..., 2.236067977..., 3.236067977...], [3.0, 4.0, 6.0] ] - sage: n.eigenvalues([2,3,5]) # rel tol 2e-15 - [[3.0, 0.6180339887498941, -1.618033988749895], - [4.0, -2.2360679774997902, 2.23606797749979], - [6.0, 1.2360679774997883, -3.23606797749979]] + sage: n.eigenvalues([2,3,5]) # rel tol 2e-14 + [[3.0, -1.6180339887498947, 0.6180339887498968], + [4.0, 2.2360679774997894, -2.236067977499788], + [6.0, -3.2360679774997894, 1.2360679774997936]] """ def __init__(self, group, weight=2, eps=1e-20, delta=1e-2, tp=[2,3,5]): @@ -212,7 +212,7 @@ def _eigenvectors(self): sage: n = numerical_eigenforms(61, eps=2.0) sage: evectors = n._eigenvectors() - sage: evalues = diagonal_matrix(CDF, [-283.0, 108.522012456, 142.0]) + sage: evalues = diagonal_matrix(CDF, [-283.0, 142.0, 108.522012456]) sage: diff = n._hecke_matrix*evectors - evectors*evalues sage: sum([abs(diff[i,j]) for i in range(5) for j in range(3)]) < 1.0e-9 True @@ -295,7 +295,7 @@ def best_row(M): EXAMPLES:: sage: numerical_eigenforms(61)._easy_vector() # indirect doctest - (1.0, 1.0, 0.0, 0.0, 0.0) + (1.0, 0.0, 0.0, 0.0, 1.0) """ R = M.rows() v = [len(support(r, delta)) for r in R] @@ -309,14 +309,14 @@ def best_row(M): while True: s = set(support(e, delta)) - zp = [i for i in range(e.degree()) if not i in s] - if len(zp) == 0: + zp = [j for j in range(e.degree()) if j not in s] + if not zp: break C = E.matrix_from_columns(zp) # best row i, f = best_row(C) x[i] += 1 # simplistic - e = x*E + e = x * E self.__easy_vector = x return x @@ -502,7 +502,7 @@ def support(v, eps): [] sage: sage.modular.modform.numerical.support( numerical_eigenforms(61)._easy_vector(), 0.5 ) - [0, 1] + [0, 4] """ return [i for i in range(v.degree()) if abs(v[i]) > eps] diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index b60209740e1..98f96ee2e42 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -779,22 +779,23 @@ def diff_alg(self): sage: from sage.modular.modform_hecketriangle.graded_ring import ModularFormsRing sage: ModularFormsRing().diff_alg() - Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dZ*Z: Z*dZ + 1, dY*Y: Y*dY + 1, dX*X: X*dX + 1} + Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dX*X: X*dX + 1, dY*Y: Y*dY + 1, dZ*Z: Z*dZ + 1} sage: from sage.modular.modform_hecketriangle.space import CuspForms sage: CuspForms(k=12, base_ring=AA).diff_alg() - Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dZ*Z: Z*dZ + 1, dY*Y: Y*dY + 1, dX*X: X*dX + 1} + Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dX*X: X*dX + 1, dY*Y: Y*dY + 1, dZ*Z: Z*dZ + 1} """ - - # We only use two operators for now which do not involve 'd', so for performance - # reason and due to restrictions for possible rings that can be used with algebra - # relations we choose FractionField(base_ring) instead of self.coeff_ring(). - # For our purposes it is currently enough to define the operators over ZZ resp. QQ. - free_alg = FreeAlgebra(FractionField(ZZ),6,'X,Y,Z,dX,dY,dZ') - (X,Y,Z,dX,dY,dZ) = free_alg.gens() - diff_alg = free_alg.g_algebra({dX*X:1+X*dX,dY*Y:1+Y*dY,dZ*Z:1+Z*dZ}) - - return diff_alg + # We only use two operators for now which do not involve 'd', + # so for performance reason and due to restrictions for + # possible rings that can be used with algebra relations we + # choose FractionField(base_ring) instead of + # self.coeff_ring(). For our purposes it is currently enough + # to define the operators over ZZ resp. QQ. + free_alg = FreeAlgebra(QQ, 6, 'X,Y,Z,dX,dY,dZ') + X, Y, Z, dX, dY, dZ = free_alg.gens() + return free_alg.g_algebra({dX * X: 1 + X * dX, + dY * Y: 1 + Y * dY, + dZ * Z: 1 + Z * dZ}) @cached_method def _derivative_op(self): diff --git a/src/sage/modular/modform_hecketriangle/element.py b/src/sage/modular/modform_hecketriangle/element.py index 87ace8d20d6..09252f20d24 100644 --- a/src/sage/modular/modform_hecketriangle/element.py +++ b/src/sage/modular/modform_hecketriangle/element.py @@ -109,7 +109,7 @@ def _latex_(self): sage: latex(QuasiModularForms(n=5, k=10, ep=-1)(x^3*z^3-y^3)) f_{\rho}^{3} E_{2}^{3} - f_{i}^{3} sage: latex(QuasiModularForms(n=infinity, k=8, ep=1)(x*(x-y^2))) - - E_{4} f_{i}^{2} + E_{4}^{2} + -E_{4} f_{i}^{2} + E_{4}^{2} """ return super(FormsElement, self)._latex_() diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index c8e6f7c7c03..4b2065da610 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -250,7 +250,7 @@ def _latex_(self): f_{\rho}^{3} - f_{i}^{2} sage: latex(QuasiModularFormsRing(n=infinity)(x*(x-y^2)*z)) - - E_{4} f_{i}^{2} E_{2} + E_{4}^{2} E_{2} + -E_{4} f_{i}^{2} E_{2} + E_{4}^{2} E_{2} """ from sage.misc.latex import latex diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index 74091a5c21a..f7dfb0efe6e 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -7,14 +7,14 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann # # 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 __future__ import print_function from sage.misc.latex import latex @@ -31,6 +31,7 @@ def coerce_AA(p): r""" Return the argument first coerced into ``AA`` and then simplified. + This leads to a major performance gain with some operations. EXAMPLES:: @@ -75,12 +76,11 @@ def cyclic_representative(L): sage: cyclic_representative((1,2,3,2,3,1)) (3, 2, 3, 1, 1, 2) """ - if not isinstance(L,list): - L = list(L) + L = list(L) n = len(L) Lmax = L[:] - for _ in range(n-1): - L.insert(n-1,L.pop(0)) + for _ in range(n - 1): + L.append(L.pop(0)) if L > Lmax: Lmax = L[:] @@ -428,7 +428,7 @@ def string_repr(self, method="default"): sage: print(el.string_repr(method="basic")) S*T^3*S*T^(-2) """ - if method == "default": + if method == "default": return MatrixGroupElement_generic._repr_(self) elif method == "basic": (L, sgn) = self._word_S_T_data() @@ -486,7 +486,7 @@ def string_repr(self, method="default"): repr_str = "" begin = True for v in L: - if self.is_identity(): + if self.is_identity(): pass elif self.is_elliptic(): if v[0] == 0: @@ -2032,17 +2032,16 @@ def simple_fixed_point_set(self, extended=True): if self.is_identity() or self.is_elliptic(): raise NotImplementedError - from sage.sets.set import Set R = self.simple_elements() - FPS = Set([v.fixed_points()[0] for v in R]) + FPS = Set(v.fixed_points()[0] for v in R) if not extended: return FPS S = self.parent().S() - FPS2 = Set([S.acton(v) for v in FPS]) + FPS2 = Set(S.acton(v) for v in FPS) return FPS.union(FPS2) @@ -2057,7 +2056,7 @@ def _latex_(self): sage: latex(V) \begin{pmatrix} \mathit{\lambda}^{3} - 2 \mathit{\lambda} & \mathit{\lambda}^{2} - 1 \\ \mathit{\lambda}^{4} - 3 \mathit{\lambda}^{2} + 1 & \mathit{\lambda}^{3} - 2 \mathit{\lambda} \end{pmatrix} """ - latex_out = r"\begin{pmatrix} %s & %s \\ %s & %s \end{pmatrix}"%(latex(self.a()), latex(self.b()), latex(self.c()), latex(self.d())) + latex_out = r"\begin{pmatrix} %s & %s \\ %s & %s \end{pmatrix}" % (latex(self.a()), latex(self.b()), latex(self.c()), latex(self.d())) return latex_out.replace("lam", r"\lambda") def __neg__(self): @@ -2496,8 +2495,9 @@ def is_hecke_symmetric(self): The method assumes that ``self`` is hyperbolic. - Warning: The case ``n=infinity`` is not verified at all - and probably wrong! + .. WARNING:: + + The case ``n=infinity`` is not verified at all and probably wrong! EXAMPLES:: @@ -2519,8 +2519,11 @@ def is_hecke_symmetric(self): sage: el = G.V(2)*G.V(3) sage: el.is_hecke_symmetric() True - sage: el.simple_fixed_point_set() - {(lam - 3/2)*e + 1/2*lam - 1, (-lam + 3/2)*e - 1/2*lam + 1, (lam - 3/2)*e - 1/2*lam + 1, (-lam + 3/2)*e + 1/2*lam - 1} + sage: sorted(el.simple_fixed_point_set(), key=str) + [(-lam + 3/2)*e + 1/2*lam - 1, + (-lam + 3/2)*e - 1/2*lam + 1, + (lam - 3/2)*e + 1/2*lam - 1, + (lam - 3/2)*e - 1/2*lam + 1] sage: el.simple_fixed_point_set() == el.inverse().simple_fixed_point_set() True """ @@ -2574,8 +2577,8 @@ def rational_period_function(self, k): ....: return True sage: z = PolynomialRing(G.base_ring(), 'z').gen() - sage: uniq([ is_rpf(1 - z^(-k), k=k) for k in range(-6, 6, 2)]) # long time - [True] + sage: [is_rpf(1 - z^(-k), k=k) for k in range(-6, 6, 2)] # long time + [True, True, True, True, True, True] sage: [is_rpf(1/z, k=k) for k in range(-6, 6, 2)] [False, False, False, False, True, False] @@ -2658,7 +2661,7 @@ def rational_period_function(self, k): try: k = ZZ(k) - if k%2 != 0: + if k % 2: raise TypeError except TypeError: raise ValueError("k={} must be an even integer!".format(k)) @@ -2867,7 +2870,7 @@ def root_extension_embedding(self, K=None): INPUT: - - ``K`` -- A field to which we want the (correct) embeddding. + - ``K`` -- A field to which we want the (correct) embedding. If ``K=None`` (default) then ``AlgebraicField()`` is used for elliptic elements and ``AlgebraicRealField()`` otherwise. @@ -3280,7 +3283,7 @@ def slash(self, f, tau=None, k=None): try: k = ZZ(k) - if k%2 != 0: + if k % 2: raise TypeError except TypeError: raise ValueError("k={} must be an even integer!".format(k)) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index 0a470f03265..98799ec8c46 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -732,7 +732,7 @@ def root_extension_embedding(self, D, K=None): - ``D`` -- An element of the base ring of ``self`` corresponding to a discriminant. - - ``K`` -- A field to which we want the (correct) embeddding. + - ``K`` -- A field to which we want the (correct) embedding. If ``K=None`` (default) then ``AlgebraicField()`` is used for positive ``D`` and ``AlgebraicRealField()`` otherwise. diff --git a/src/sage/modular/modform_hecketriangle/readme.py b/src/sage/modular/modform_hecketriangle/readme.py index e182b07d884..cd13f2641c8 100644 --- a/src/sage/modular/modform_hecketriangle/readme.py +++ b/src/sage/modular/modform_hecketriangle/readme.py @@ -410,8 +410,8 @@ ....: return True sage: z = PolynomialRing(G.base_ring(), 'z').gen() - sage: uniq([ is_rpf(1 - z^(-k), k=k) for k in range(-6, 6, 2)]) # long time - [True] + sage: [is_rpf(1 - z^(-k), k=k) for k in range(-6, 6, 2)] # long time + [True, True, True, True, True, True] sage: [is_rpf(1/z, k=k) for k in range(-6, 6, 2)] [False, False, False, False, True, False] @@ -531,11 +531,11 @@ sage: G.class_representatives(68) [S*T^(-2)*S*T^(-1)*S*T, -S*T^(-1)*S*T^2*S*T, S*T^(-5)*S*T^(-1)*S, T*S*T^5] sage: R = G.reduced_elements(68) - sage: uniq([v.is_reduced() for v in R]) # long time - [True] + sage: all(v.is_reduced() for v in R) # long time + True sage: R = G.simple_elements(68) - sage: uniq([v.is_simple() for v in R]) # long time - [True] + sage: all(v.is_simple() for v in R) # long time + True sage: G.element_repr_method("default") sage: G = HeckeTriangleGroup(n=5) @@ -549,8 +549,8 @@ sage: G.class_representatives(9*G.lam() + 5) [S*T^(-2)*S*T^(-1)*S, T*S*T^2] sage: R = G.reduced_elements(9*G.lam() + 5) - sage: uniq([v.is_reduced() for v in R]) # long time - [True] + sage: all(v.is_reduced() for v in R) # long time + True sage: R = G.simple_elements(7*G.lam() + 6) sage: for v in R: print(v.string_repr("default")) [lam + 2 lam] diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 5d15d37c327..38ef23df84e 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -533,10 +533,10 @@ def _action_on_modular_symbols(self, g): sage: M = ModularSymbols(11,4,1) sage: M._action_on_modular_symbols([1,2,3,7]) - [ 0 0 5/2 -3/2] - [ 0 0 5/2 -3/2] - [ 0 1 0 0] - [ 0 1 -1/2 1/2] + [0 0 1 0] + [0 0 0 1] + [0 1 0 0] + [0 1 0 0] """ if not isinstance(g, list): @@ -558,15 +558,15 @@ def manin_symbol(self, x, check=True): OUTPUT: - (ManinSymbol) the monomial Manin Symbol associated to - `[i;(u,v)]`, with `i=0` if not supplied, corresponding to the - symbol `[X^i*Y^{k-2-i}, (u,v)]`. + (ManinSymbol) the Manin Symbol associated to `[i;(u,v)]`, with + `i=0` if not supplied, corresponding to the monomial symbol + `[X^i*Y^{k-2-i}, (u,v)]`. EXAMPLES:: sage: M = ModularSymbols(11,4,1) sage: M.manin_symbol([2,5,6]) - [X^2,(1,10)] + -2/3*[X^2,(1,6)] + 5/3*[X^2,(1,9)] """ if check: if len(x) == 2: @@ -612,11 +612,11 @@ def _modular_symbol_0_to_alpha(self, alpha, i=0): sage: M = ModularSymbols(11,4,1) sage: M._modular_symbol_0_to_alpha(Cusp(3/5)) - 11*[X^2,(1,7)] + 33*[X^2,(1,9)] - 20*[X^2,(1,10)] + 11*[X^2,(1,4)] + 40/3*[X^2,(1,6)] - 1/3*[X^2,(1,9)] sage: M._modular_symbol_0_to_alpha(Cusp(3/5),1) - 15/2*[X^2,(1,7)] + 35/2*[X^2,(1,9)] - 10*[X^2,(1,10)] + 15/2*[X^2,(1,4)] + 20/3*[X^2,(1,6)] + 5/6*[X^2,(1,9)] sage: M._modular_symbol_0_to_alpha(Cusp(Infinity)) - -[X^2,(1,10)] + 2/3*[X^2,(1,6)] - 5/3*[X^2,(1,9)] sage: M._modular_symbol_0_to_alpha(Cusp(Infinity),1) 0 """ @@ -850,10 +850,10 @@ def _compute_dual_hecke_matrix(self, n): sage: M = ModularSymbols(11,4,1) sage: M._compute_dual_hecke_matrix(5) - [126 0 0 0] - [ 2 63 38 22] - [ 11 33 82 121] - [-13 30 6 -17] + [ 126 0 0 0] + [ 2 63 62 38] + [ 26/3 -20 -27 -4] + [-32/3 83 91 92] """ return self.hecke_matrix(n).transpose() @@ -1255,14 +1255,6 @@ def _compute_atkin_lehner_matrix(self, d): sage: M = ModularSymbols(Gamma1(10), 2) sage: w = M.atkin_lehner_operator(2).matrix() - sage: w^2 - [ 0 1 0 0 0 0 0] - [ 1 0 0 0 0 0 0] - [ 0 0 0 0 1 0 0] - [ 0 0 0 0 0 1 -1] - [ 0 0 1 0 0 0 0] - [ 0 0 0 1 0 0 -1] - [ 0 0 0 0 0 0 -1] sage: w^2 == M.diamond_bracket_matrix(7) True @@ -1604,9 +1596,9 @@ def element(self, x): sage: M.T(3) Hecke operator T_3 on Modular Symbols space of dimension 4 for Gamma_0(11) of weight 4 with sign 1 over Rational Field sage: M.T(3)(M.0) - 28*[X^2,(0,1)] + 2*[X^2,(1,7)] - [X^2,(1,9)] - [X^2,(1,10)] + 28*[X^2,(0,1)] + 2*[X^2,(1,4)] + 2/3*[X^2,(1,6)] - 8/3*[X^2,(1,9)] sage: M.T(3)(M.0).element() - (28, 2, -1, -1) + (28, 2, 2/3, -8/3) """ if isinstance(x, ManinSymbol): if not x.parent().weight() == self.weight(): @@ -2095,10 +2087,10 @@ def _compute_diamond_matrix(self, d): sage: M = Newforms(Gamma1(13),names = 'a')[0].modular_symbols(sign=0) sage: M.diamond_bracket_operator(4).matrix() + [-1 1 1 -1] + [-1 0 1 0] + [ 0 0 0 -1] [ 0 0 1 -1] - [-1 -1 0 1] - [-1 -1 0 0] - [ 0 -1 1 -1] We check that the result is correctly normalised for weight > 2:: @@ -2264,16 +2256,16 @@ def integral_structure(self, algorithm='default'): sage: M.integral_structure() Free module of degree 10 and rank 10 over Integer Ring Echelon basis matrix: - [ 1 0 0 0 0 0 0 0 0 0] - [ 0 1 0 0 0 0 0 0 0 0] - [ 0 0 1/102 0 5/204 1/136 23/24 3/17 43/136 69/136] - [ 0 0 0 1/48 0 1/48 23/24 1/6 1/8 17/24] - [ 0 0 0 0 1/24 0 23/24 1/3 1/6 1/2] - [ 0 0 0 0 0 1/24 23/24 1/3 11/24 5/24] - [ 0 0 0 0 0 0 1 0 0 0] - [ 0 0 0 0 0 0 0 1/2 0 1/2] - [ 0 0 0 0 0 0 0 0 1/2 1/2] - [ 0 0 0 0 0 0 0 0 0 1] + [ 1 0 0 0 0 0 0 0 0 0] + [ 0 1 0 0 0 0 0 0 0 0] + [ 0 0 1/96 1/32 23/24 0 1/96 0 7/24 67/96] + [ 0 0 0 1/24 23/24 0 0 1/24 1/4 17/24] + [ 0 0 0 0 1 0 0 0 0 0] + [ 0 0 0 0 0 1/6 0 1/48 23/48 1/3] + [ 0 0 0 0 0 0 1/24 1/24 11/24 11/24] + [ 0 0 0 0 0 0 0 1/16 7/16 1/2] + [ 0 0 0 0 0 0 0 0 1/2 1/2] + [ 0 0 0 0 0 0 0 0 0 1] """ if not self.base_ring() == QQ: raise NotImplementedError @@ -2950,9 +2942,9 @@ def _hecke_image_of_ith_basis_vector(self, n, i): sage: M.hecke_operator(2)(M.0) 3*(1,0) - 2*(1,33) sage: M._hecke_image_of_ith_basis_vector(6, 1) - -2*(1,33) + 4*(1,31) - 3*(1,33) + 3*(1,39) sage: M.hecke_operator(6)(M.1) - -2*(1,33) + 4*(1,31) - 3*(1,33) + 3*(1,39) """ c = self.manin_generators()[self.manin_basis()[i]] N = self.level() @@ -3331,14 +3323,14 @@ def _compute_hecke_matrix_prime_power(self, p, r): sage: M = ModularSymbols(GammaH(15,[4]),2) sage: M._compute_hecke_matrix_prime_power(2, 3) - [10 0 5 0 1 0 0 4 0] - [ 0 10 0 0 -4 -5 0 -1 6] - [ 5 0 10 0 -4 0 0 -1 0] - [ 0 0 0 5 -7 0 10 -3 4] - [ 0 0 0 0 -1 0 0 -4 0] - [ 0 -5 0 0 -1 10 0 -4 -6] - [ 0 0 0 10 -3 0 5 -7 -4] - [ 0 0 0 0 -4 0 0 -1 0] + [10 0 5 1 0 0 0 4 0] + [ 0 10 0 4 10 -5 -5 -4 5] + [ 5 0 10 -4 0 0 0 -1 0] + [ 0 0 0 -1 0 0 0 -4 0] + [ 0 0 0 -7 5 0 10 -3 6] + [ 0 -5 0 -6 0 10 5 -4 -1] + [ 0 0 0 -3 10 0 5 -7 6] + [ 0 0 0 -4 0 0 0 -1 0] [ 0 0 0 0 0 0 0 0 3] sage: M.hecke_matrix(7)^2 == M.hecke_matrix(49) + 7 * M.diamond_bracket_operator(7).matrix() # indirect doctest True diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index 960ae878d57..55f3b46a823 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -508,9 +508,9 @@ def _coerce_in_manin_symbol(self, x): sage: M = ModularSymbols(Gamma1(5), 4) ; B = M.boundary_space() sage: [ B(x) for x in M.basis() ] - [-[2/5], -[-1/5], -[1/2], -[1/2], -[1/4], -[1/4]] + [-[2/5], -[-1/5], -[1/3], -[-1/4], -[-1/4], -[-1/4]] sage: [ B._coerce_in_manin_symbol(x) for x in M.manin_symbols_basis() ] - [-[2/5], -[-1/5], -[1/2], -[1/2], -[1/4], -[1/4]] + [-[2/5], -[-1/5], -[1/3], -[-1/4], -[-1/4], -[-1/4]] """ i = x.i alpha, beta = x.endpoints(self.level()) diff --git a/src/sage/modular/modsym/hecke_operator.py b/src/sage/modular/modsym/hecke_operator.py index 7709d95d2df..9316ca2f904 100644 --- a/src/sage/modular/modsym/hecke_operator.py +++ b/src/sage/modular/modsym/hecke_operator.py @@ -30,7 +30,7 @@ def apply_sparse(self, x): sage: M = ModularSymbols(17,4,-1) sage: T = M.hecke_operator(4) sage: T.apply_sparse(M.0) - 64*[X^2,(1,8)] + 24*[X^2,(1,10)] - 9*[X^2,(1,13)] + 37*[X^2,(1,16)] + -27*[X^2,(1,7)] - 167/2*[X^2,(1,9)] - 21/2*[X^2,(1,13)] + 53/2*[X^2,(1,15)] sage: [T.apply_sparse(x) == T.hecke_module_morphism()(x) for x in M.basis()] [True, True, True, True] sage: N = ModularSymbols(17,4,1) diff --git a/src/sage/modular/modsym/heilbronn.pyx b/src/sage/modular/modsym/heilbronn.pyx index 9519d1e457d..9d3bc0f3e89 100644 --- a/src/sage/modular/modsym/heilbronn.pyx +++ b/src/sage/modular/modsym/heilbronn.pyx @@ -1,8 +1,7 @@ """ Heilbronn matrix computation """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -14,16 +13,15 @@ Heilbronn matrix computation # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import from cysignals.memory cimport check_allocarray, sig_malloc, sig_free -from cysignals.signals cimport sig_on, sig_off - -import sage.arith.all +from cysignals.signals cimport sig_on, sig_off, sig_check -import sage.misc.misc +from sage.misc.misc import verbose +from sage.arith.misc import is_prime from sage.libs.gmp.mpz cimport * from sage.libs.gmp.mpq cimport * @@ -103,8 +101,9 @@ cdef class Heilbronn: def _initialize_list(self): """ - Initialize the list of matrices corresponding to self. (This - function is automatically called during initialization.) + Initialize the list of matrices corresponding to ``self``. + + (This function is automatically called during initialization.) .. note:: @@ -122,7 +121,7 @@ cdef class Heilbronn: def __getitem__(self, int n): """ - Return the nth matrix in self. + Return the n-th matrix in ``self``. EXAMPLES:: @@ -136,12 +135,12 @@ cdef class Heilbronn: """ if n < 0 or n >= self.length: raise IndexError - return [self.list.v[4*n], self.list.v[4*n+1], \ + return [self.list.v[4*n], self.list.v[4*n+1], self.list.v[4*n+2], self.list.v[4*n+3]] def __len__(self): """ - Return the number of matrices in self. + Return the number of matrices in ``self``. EXAMPLES:: @@ -152,8 +151,9 @@ cdef class Heilbronn: def to_list(self): """ - Return the list of Heilbronn matrices corresponding to self. Each - matrix is given as a list of four ints. + Return the list of Heilbronn matrices corresponding to ``self``. + + Each matrix is given as a list of four ints. EXAMPLES:: @@ -165,7 +165,7 @@ cdef class Heilbronn: cdef int i L = [] for i in range(self.length): - L.append([self.list.v[4*i], self.list.v[4*i+1], \ + L.append([self.list.v[4*i], self.list.v[4*i+1], self.list.v[4*i+2], self.list.v[4*i+3]]) return L @@ -228,17 +228,23 @@ cdef class Heilbronn: def apply(self, int u, int v, int N): """ - Return a list of pairs ((c,d),m), which is obtained as follows: 1) - Compute the images (a,b) of the vector (u,v) (mod N) acted on by - each of the HeilbronnCremona matrices in self. 2) Reduce each (a,b) - to canonical form (c,d) using p1normalize 3) Sort. 4) Create the - list ((c,d),m), where m is the number of times that (c,d) appears - in the list created in steps 1-3 above. Note that the pairs - ((c,d),m) are sorted lexicographically by (c,d). + Return a list of pairs ((c,d),m), which is obtained as follows: + + 1) Compute the images (a,b) of the vector (u,v) (mod N) acted on by + each of the HeilbronnCremona matrices in self. + + 2) Reduce each (a,b) to canonical form (c,d) using p1normalize. + + 3) Sort. + + 4) Create the list ((c,d),m), where m is the number of times + that (c,d) appears in the list created in steps 1-3 + above. Note that the pairs ((c,d),m) are sorted + lexicographically by (c,d). INPUT: - - ``u, v, N`` - integers + - ``u, v, N`` -- integers OUTPUT: list @@ -247,51 +253,51 @@ cdef class Heilbronn: sage: H = sage.modular.modsym.heilbronn.HeilbronnCremona(2); H The Cremona-Heilbronn matrices of determinant 2 sage: H.apply(1,2,7) - [((1, 5), 1), ((1, 6), 1), ((1, 1), 1), ((1, 4), 1)] + [((1, 1), 1), ((1, 4), 1), ((1, 5), 1), ((1, 6), 1)] """ cdef int i, a, b, c, d, s cdef object X - M = {} - t = sage.misc.misc.verbose("start making list M.",level=5) - sig_on() + cdef dict M = {} + t = verbose("start making list M.", level=5) if N < 32768: # use ints with no reduction modulo N for i in range(self.length): + sig_check() a = u*self.list.v[4*i] + v*self.list.v[4*i+2] b = u*self.list.v[4*i+1] + v*self.list.v[4*i+3] export.c_p1_normalize_int(N, a, b, &c, &d, &s, 0) - X = (c,d) + X = (c, d) if X in M: - M[X] = M[X] + 1 + M[X] += 1 else: M[X] = 1 elif N < 46340: # use ints but reduce mod N so can add two for i in range(self.length): - a = (u * self.list.v[4*i])%N + (v * self.list.v[4*i+2])%N - b = (u * self.list.v[4*i+1])%N + (v * self.list.v[4*i+3])%N + sig_check() + a = (u * self.list.v[4*i]) % N + (v * self.list.v[4*i+2]) % N + b = (u * self.list.v[4*i+1]) % N + (v * self.list.v[4*i+3]) % N export.c_p1_normalize_int(N, a, b, &c, &d, &s, 0) - X = (c,d) + X = (c, d) if X in M: - M[X] = M[X] + 1 + M[X] += 1 else: M[X] = 1 else: for i in range(self.length): + sig_check() a = llong_prod_mod(u,self.list.v[4*i],N) + llong_prod_mod(v,self.list.v[4*i+2], N) b = llong_prod_mod(u,self.list.v[4*i+1],N) + llong_prod_mod(v,self.list.v[4*i+3], N) export.c_p1_normalize_llong(N, a, b, &c, &d, &s, 0) - X = (c,d) + X = (c, d) if X in M: - M[X] = M[X] + 1 + M[X] += 1 else: M[X] = 1 - t = sage.misc.misc.verbose("finished making list M.",t, level=5) - mul = [] - for x,y in M.items(): - mul.append((x,y)) - t = sage.misc.misc.verbose("finished making mul list.",t, level=5) - sig_off() + t = verbose("finished making list M.", t, level=5) + mul = sorted(M.items()) + t = verbose("finished making mul list.", t, level=5) return mul + cdef class HeilbronnCremona(Heilbronn): cdef public int p @@ -311,14 +317,14 @@ cdef class HeilbronnCremona(Heilbronn): [3, -1, 0, 1], [-1, 0, 1, -3]] """ - if p <= 1 or not sage.arith.all.is_prime(p): + if p <= 1 or not is_prime(p): raise ValueError("p must be >= 2 and prime") self.p = p self._initialize_list() def __repr__(self): """ - Return the string representation of self. + Return the string representation of ``self``. EXAMPLES:: @@ -329,8 +335,9 @@ cdef class HeilbronnCremona(Heilbronn): def _initialize_list(self): """ - Initialize the list of matrices corresponding to self. (This - function is automatically called during initialization.) + Initialize the list of matrices corresponding to ``self``. + + (This function is automatically called during initialization.) EXAMPLES:: @@ -377,7 +384,16 @@ cdef class HeilbronnCremona(Heilbronn): # means "round down." sig_on() for r in range(-p/2, p/2+1): - x1=p; x2=-r; y1=0; y2=1; a=-p; b=r; c=0; x3=0; y3=0; q=0 + x1 = p + x2 = -r + y1 = 0 + y2 = 1 + a = -p + b = r + c = 0 + x3 = 0 + y3 = 0 + q = 0 list_append4(L, x1,x2,y1,y2) while b: q = roundf(a / b) @@ -396,8 +412,7 @@ cdef class HeilbronnMerel(Heilbronn): def __init__(self, int n): r""" - Initialize the list of Merel-Heilbronn matrices of determinant - `n`. + Initialize the list of Merel-Heilbronn matrices of determinant `n`. EXAMPLES:: @@ -419,19 +434,20 @@ cdef class HeilbronnMerel(Heilbronn): def __repr__(self): """ - Return the string representation of self. + Return the string representation of ``self``. EXAMPLES:: sage: HeilbronnMerel(8).__repr__() 'The Merel-Heilbronn matrices of determinant 8' """ - return "The Merel-Heilbronn matrices of determinant %s"%self.n + return "The Merel-Heilbronn matrices of determinant %s" % self.n def _initialize_list(self): """ - Initialize the list of matrices corresponding to self. (This - function is automatically called during initialization.) + Initialize the list of matrices corresponding to ``self``. + + (This function is automatically called during initialization.) EXAMPLES:: @@ -548,11 +564,11 @@ def hecke_images_gamma0_weight2(int u, int v, int N, indices, R): cdef Heilbronn H - t = sage.misc.misc.verbose("computing non-reduced images of symbol under Hecke operators", + t = verbose("computing non-reduced images of symbol under Hecke operators", level=1, caller_name='hecke_images_gamma0_weight2') for i, n in enumerate(indices): # List the Heilbronn matrices of determinant n defined by Cremona or Merel - H = HeilbronnCremona(n) if sage.arith.all.is_prime(n) else HeilbronnMerel(n) + H = HeilbronnCremona(n) if is_prime(n) else HeilbronnMerel(n) # Allocate memory to hold images of (u,v) under all Heilbronn matrices a = sig_malloc(sizeof(int)*H.length) @@ -578,25 +594,25 @@ def hecke_images_gamma0_weight2(int u, int v, int N, indices, R): sig_free(a) sig_free(b) - t = sage.misc.misc.verbose("finished computing non-reduced images", + t = verbose("finished computing non-reduced images", t, level=1, caller_name='hecke_images_gamma0_weight2') - t = sage.misc.misc.verbose("Now reducing images of symbol", + t = verbose("Now reducing images of symbol", level=1, caller_name='hecke_images_gamma0_weight2') # Return the product T * R, whose rows are the image of (u,v) under # the Hecke operators T_n for n in indices. if max(indices) <= 30: # In this case T tends to be very sparse ans = T.sparse_matrix()._matrix_times_matrix_dense(R) - sage.misc.misc.verbose("did reduction using sparse multiplication", + verbose("did reduction using sparse multiplication", t, level=1, caller_name='hecke_images_gamma0_weight2') elif R.is_sparse(): ans = T * R.dense_matrix() - sage.misc.misc.verbose("did reduction using dense multiplication", + verbose("did reduction using dense multiplication", t, level=1, caller_name='hecke_images_gamma0_weight2') else: ans = T * R - sage.misc.misc.verbose("did reduction using dense multiplication", + verbose("did reduction using dense multiplication", t, level=1, caller_name='hecke_images_gamma0_weight2') if original_base_ring != QQ: @@ -677,7 +693,7 @@ def hecke_images_nonquad_character_weight2(int u, int v, int N, indices, chi, R) cdef Heilbronn H - t = sage.misc.misc.verbose("computing non-reduced images of symbol under Hecke operators", + t = verbose("computing non-reduced images of symbol under Hecke operators", level=1, caller_name='hecke_images_character_weight2') # Make a matrix over the rational numbers each of whose columns @@ -687,7 +703,7 @@ def hecke_images_nonquad_character_weight2(int u, int v, int N, indices, chi, R) chi_vals = matrix(QQ, z).transpose() for i, n in enumerate(indices): - H = HeilbronnCremona(n) if sage.arith.all.is_prime(n) else HeilbronnMerel(n) + H = HeilbronnCremona(n) if is_prime(n) else HeilbronnMerel(n) # Allocate memory to hold images of (u,v) under all Heilbronn matrices a = sig_malloc(sizeof(int)*H.length) @@ -720,6 +736,7 @@ def hecke_images_nonquad_character_weight2(int u, int v, int N, indices, chi, R) return T * R + def hecke_images_quad_character_weight2(int u, int v, int N, indices, chi, R): """ INPUT: @@ -772,7 +789,7 @@ def hecke_images_quad_character_weight2(int u, int v, int N, indices, chi, R): cdef int k, scalar cdef Heilbronn H - t = sage.misc.misc.verbose("computing non-reduced images of symbol under Hecke operators", + t = verbose("computing non-reduced images of symbol under Hecke operators", level=1, caller_name='hecke_images_quad_character_weight2') # Make a matrix over the rational numbers each of whose columns @@ -784,7 +801,7 @@ def hecke_images_quad_character_weight2(int u, int v, int N, indices, chi, R): chi_vals[i] = _chivals[i] for i, n in enumerate(indices): - H = HeilbronnCremona(n) if sage.arith.all.is_prime(n) else HeilbronnMerel(n) + H = HeilbronnCremona(n) if is_prime(n) else HeilbronnMerel(n) a = sig_malloc(sizeof(int)*H.length) if not a: raise MemoryError b = sig_malloc(sizeof(int)*H.length) @@ -868,7 +885,7 @@ def hecke_images_gamma0_weight_k(int u, int v, int i, int N, int k, indices, R): cdef Integer coeff = Integer() for z, m in enumerate(indices): - H = HeilbronnCremona(m) if sage.arith.all.is_prime(m) else HeilbronnMerel(m) + H = HeilbronnCremona(m) if is_prime(m) else HeilbronnMerel(m) # Allocate memory to hold images of (u,v) under all Heilbronn matrices a = sig_malloc(sizeof(int)*H.length) diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index f5622bbc9c5..a94fa462322 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -182,6 +182,7 @@ def ModularSymbols_clear_cache(): global _cache _cache = {} + def ModularSymbols(group = 1, weight = 2, sign = 0, @@ -194,7 +195,7 @@ def ModularSymbols(group = 1, INPUT: - ``group`` - A congruence subgroup or a Dirichlet character eps. - - ``weight`` - int, the weight, which must be = 2. + - ``weight`` - int, the weight, which must be >= 2. - ``sign`` - int, The sign of the involution on modular symbols induced by complex conjugation. The default is 0, which means "no sign", i.e., take the whole space. diff --git a/src/sage/modular/modsym/p1list.pyx b/src/sage/modular/modsym/p1list.pyx index 5aa5823582a..ba81d44346b 100644 --- a/src/sage/modular/modsym/p1list.pyx +++ b/src/sage/modular/modsym/p1list.pyx @@ -773,7 +773,7 @@ cdef class P1List(object): sage: L = P1List(8) sage: L.__reduce__() - (, (8,)) + (<... 'sage.modular.modsym.p1list.P1List'>, (8,)) """ return type(self), (self.__N, ) @@ -801,7 +801,7 @@ cdef class P1List(object): def __len__(self): """ - Returns the length of this P1List. + Return the length of this P1List. EXAMPLES:: @@ -813,7 +813,7 @@ cdef class P1List(object): def __repr__(self): """ - Returns the string representation of this P1List. + Return the string representation of this P1List. EXAMPLES:: @@ -1083,16 +1083,15 @@ cdef class P1List(object): if t: return i return -1 - def list(self): r""" - Returns the underlying list of this P1List object. + Return the underlying list of this :class:`P1List` object. EXAMPLES:: sage: L = P1List(8) sage: type(L) - + <... 'sage.modular.modsym.p1list.P1List'> sage: type(L.list()) <... 'list'> """ diff --git a/src/sage/modular/modsym/relation_matrix.py b/src/sage/modular/modsym/relation_matrix.py index 5e968c37485..39faf77d92d 100644 --- a/src/sage/modular/modsym/relation_matrix.py +++ b/src/sage/modular/modsym/relation_matrix.py @@ -496,8 +496,8 @@ def relation_matrix_wtk_g0(syms, sign, field, sparse): # Let rels = rels union I relations. rels.update(modI_relations(syms, sign)) - rels = list(rels) - # should be sorted(rels), but this breaks many doctests + rels = sorted(rels) + # required for stability of doctests with python3 if syms._apply_S_only_0pm1() and is_RationalField(field): from . import relation_matrix_pyx diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index 75ff364fb38..7b507e5b56f 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -201,12 +201,12 @@ def compact_system_of_eigenvalues(self, v, names='alpha', nz=None): Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 for Gamma_0(43) of weight 2 with sign 1 over Rational Field sage: E, v = M.compact_system_of_eigenvalues(prime_range(10)) sage: E - [ 3 -2] - [-3 2] - [-1 2] - [ 1 -2] + [ 2/3 -4/3] + [-2/3 4/3] + [ 4/3 4/3] + [-4/3 -4/3] sage: v - (1, -1/2*alpha + 3/2) + (1, -3/4*alpha + 1/2) sage: E*v (alpha, -alpha, -alpha + 2, alpha - 2) @@ -987,7 +987,7 @@ def _q_expansion_module(self, prec, algorithm='hecke'): if algorithm != 'eigen': raise ValueError("unknown algorithm '%s'"%algorithm) - def q_eigen_gens(A, f): + def q_eigen_gens(d, f): r""" Temporary function for internal use. EXAMPLES:: @@ -999,7 +999,6 @@ def q_eigen_gens(A, f): [ 0 0 1 -4 2] """ X = f.padded_list(prec) - d = A.dimension() if d == 1: # X is just a list of elements of R return [X] @@ -1012,7 +1011,9 @@ def q_eigen_gens(A, f): else: X = self - B = [sum([q_eigen_gens(A, f) for f in self._q_eigenform_images(A, prec, 'zeta')], []) for A, _ in X.factorization()] + B = [sum([q_eigen_gens(A.dimension(), f) + for f in self._q_eigenform_images(A, prec, 'zeta')], []) + for A, _ in X.factorization()] return V.span(sum(B, [])) @@ -1050,7 +1051,7 @@ def _q_expansion_module_rational(self, prec): # Construct the vector space over QQ of dimension equal to # the degree of the base field times the dimension over C # of the space of cusp forms corresponding to self. - def q_eigen_gens(f): + def q_eigen_gens(d, f): r""" Temporary function for internal use. @@ -1066,7 +1067,6 @@ def q_eigen_gens(f): # Return restricted down to QQ gens for cusp space corresponding # to the simple factor A. X = f.padded_list(prec) - d = A.dimension() if d == 1: return [[X[i][j] for i in range(prec)] for j in range(n)] else: @@ -1079,11 +1079,11 @@ def q_eigen_gens(f): else: X = self - B = [sum([q_eigen_gens(f) for f in self._q_eigenform_images(A, prec, 'alpha')], []) for A, _ in X.factorization()] + B = [sum([q_eigen_gens(A.dimension(), f) + for f in self._q_eigenform_images(A, prec, 'alpha')], []) + for A, _ in X.factorization()] A = QQ**prec - W = A.span(sum(B, [])) - return W - + return A.span(sum(B, [])) def _q_expansion_module_integral(self, prec): r""" @@ -1126,7 +1126,7 @@ def congruence_number(self, other, prec=None): If prec is not given it is set equal to the max of the ``hecke_bound`` function called on each space. - EXAMPLES: + EXAMPLES:: sage: A, B = ModularSymbols(48, 2).cuspidal_submodule().decomposition() sage: A.congruence_number(B) @@ -1335,7 +1335,7 @@ def q_expansion_cuspforms(self, prec=None): sage: f(0,0) q - 2*q^2 + q^4 - q^5 + 2*q^6 + O(q^8) sage: f(0,1) - q^2 - 2*q^3 - q^4 + 2*q^5 + 2*q^6 + O(q^8) + -q^2 + 2*q^3 + q^4 - 2*q^5 - 2*q^6 + O(q^8) :: diff --git a/src/sage/modular/modsym/tests.py b/src/sage/modular/modsym/tests.py index 4c73693476f..1aa67bcb46d 100644 --- a/src/sage/modular/modsym/tests.py +++ b/src/sage/modular/modsym/tests.py @@ -53,12 +53,13 @@ def __init__(self, levels=20, weights=4, onlyg0=False, onlyg1=False, EXAMPLES:: - sage: sage.modular.modsym.tests.Test() + sage: from sage.modular.modsym.tests import Test + sage: Test() Modular symbols testing class - sage: T = sage.modular.modsym.tests.Test(weights=[3,5,7]) + sage: T = Test(weights=[3,5,7]) sage: T.weights [3, 5, 7] - sage: T = sage.modular.modsym.tests.Test(levels=5) ; T.levels + sage: T = Test(levels=5) ; T.levels [1, 2, 3, 4, 5] """ if not isinstance(levels, list): @@ -82,7 +83,8 @@ def __repr__(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test().__repr__() + sage: from sage.modular.modsym.tests import Test + sage: Test().__repr__() 'Modular symbols testing class' """ return "Modular symbols testing class" @@ -94,7 +96,8 @@ def _modular_symbols_space(self): EXAMPLES:: - sage: T = sage.modular.modsym.tests.Test(levels=[5],weights=[2], onlychar=True) + sage: from sage.modular.modsym.tests import Test + sage: T = Test(levels=[5],weights=[2], onlychar=True) Note that the sign of the generated space is always arbitrary. sage: T._modular_symbols_space() @@ -130,7 +133,8 @@ def _level_weight_sign(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test()._level_weight_sign() # random + sage: from sage.modular.modsym.tests import Test + sage: Test()._level_weight_sign() # random level = 4, weight = 3, sign = 1 (4, 3, 1) """ @@ -148,7 +152,8 @@ def _modular_symbols_space_gamma0(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test()._modular_symbols_space_gamma0() # random + sage: from sage.modular.modsym.tests import Test + sage: Test()._modular_symbols_space_gamma0() # random level = 1, weight = 3, sign = 0 Modular Symbols space of dimension 0 for Gamma_0(1) of weight 3 with sign 0 over Rational Field """ @@ -165,7 +170,8 @@ def _modular_symbols_space_gamma1(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test()._modular_symbols_space_gamma1() # random + sage: from sage.modular.modsym.tests import Test + sage: Test()._modular_symbols_space_gamma1() # random level = 3, weight = 4, sign = 0 Modular Symbols space of dimension 2 for Gamma_1(3) of weight 4 with sign 0 and over Rational Field """ @@ -182,7 +188,8 @@ def _modular_symbols_space_character(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test()._modular_symbols_space_character() # random + sage: from sage.modular.modsym.tests import Test + sage: Test()._modular_symbols_space_character() # random level = 18, weight = 3, sign = 0 Modular Symbols space of dimension 0 and level 18, weight 3, character [1, zeta6 - 1], sign 0, over Cyclotomic Field of order 6 and degree 2 """ @@ -200,7 +207,8 @@ def _do(self, name): EXAMPLES:: - sage: sage.modular.modsym.tests.Test()._do("random") + sage: from sage.modular.modsym.tests import Test + sage: Test()._do("random") test_random ... """ @@ -217,7 +225,8 @@ def random(self, seconds=0): EXAMPLES:: - sage: sage.modular.modsym.tests.Test().random(1) + sage: from sage.modular.modsym.tests import Test + sage: Test().random(1) test_random ... """ @@ -231,10 +240,11 @@ def test(self, name, seconds=0): EXAMPLES:: - sage: sage.modular.modsym.tests.Test().test('cs_dimension',seconds=1) + sage: from sage.modular.modsym.tests import Test + sage: Test().test('cs_dimension',seconds=1) test_cs_dimension ... - sage: sage.modular.modsym.tests.Test().test('csnew_dimension',seconds=1) + sage: Test().test('csnew_dimension',seconds=1) test_csnew_dimension ... """ @@ -257,7 +267,8 @@ def test_cs_dimension(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test().test_cs_dimension() # random + sage: from sage.modular.modsym.tests import Test + sage: Test().test_cs_dimension() # random gamma0 level = 16, weight = 3, sign = -1 Modular Symbols space of dimension 0 for Gamma_0(16) of weight 3 with sign -1 over Rational Field @@ -271,7 +282,8 @@ def test_csnew_dimension(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test().test_csnew_dimension() # random + sage: from sage.modular.modsym.tests import Test + sage: Test().test_csnew_dimension() # random gamma0 level = 3, weight = 3, sign = 1 Modular Symbols space of dimension 0 for Gamma_0(3) of weight 3 with sign 1 over Rational Field @@ -290,7 +302,8 @@ def test_csns_nscs(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test().test_csns_nscs() # random + sage: from sage.modular.modsym.tests import Test + sage: Test().test_csns_nscs() # random gamma0 level = 5, weight = 4, sign = 1 Modular Symbols space of dimension 3 for Gamma_0(5) of weight 4 with sign 1 over Rational Field @@ -313,7 +326,8 @@ def test_decomposition(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test().test_decomposition() # random + sage: from sage.modular.modsym.tests import Test + sage: Test().test_decomposition() # random gamma1 level = 10, weight = 4, sign = 0 Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 and over Rational Field @@ -328,7 +342,8 @@ def test_dimension(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test().test_dimension() # random + sage: from sage.modular.modsym.tests import Test + sage: Test().test_dimension() # random gamma1 level = 14, weight = 2, sign = -1 Modular Symbols space of dimension 1 for Gamma_1(14) of weight 2 with sign -1 and over Rational Field @@ -341,7 +356,8 @@ def test_random(self): EXAMPLES:: - sage: sage.modular.modsym.tests.Test().test_random() # random + sage: from sage.modular.modsym.tests import Test + sage: Test().test_random() # random Doing random test test_csnew_dimension character level = 18, weight = 4, sign = -1 diff --git a/src/sage/modular/overconvergent/__init__.py b/src/sage/modular/overconvergent/__init__.py index aff91631885..3ca0b649873 100644 --- a/src/sage/modular/overconvergent/__init__.py +++ b/src/sage/modular/overconvergent/__init__.py @@ -1,4 +1,5 @@ from __future__ import absolute_import -pass from . import all + +del absolute_import diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index 645090843e6..67ad77bca76 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -169,7 +169,7 @@ # 2008-9 David Loeffler # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function, absolute_import from six.moves import range @@ -178,7 +178,6 @@ from sage.matrix.all import matrix, MatrixSpace, diagonal_matrix from sage.misc.misc import verbose from sage.misc.cachefunc import cached_method -from sage.misc.superseded import deprecated_function_alias from sage.modular.all import (trivial_character, EtaProduct, j_invariant_qexp, hecke_operator_on_qexp) from sage.modular.arithgroup.all import is_Gamma0, is_Gamma1 @@ -1018,12 +1017,12 @@ def hecke_matrix(self, m, n, use_recurrence = False, exact_arith = False): mat[i,j] = mat[i,j] + mat[i-u-1, j-v-1]*self.recurrence_matrix()[u,v] else: - if( n*self.prime() > self.prec()): + if n * self.prime() > self.prec(): raise ValueError("n is too large") for j in range(self.prime(), n): l = self._convert_to_basis(self.hecke_operator(self._basis_cache[j], m)) for i in range(n): - mat[i,j] = l[i] + mat[i, j] = l[i] return mat def slopes(self, n, use_recurrence=False): diff --git a/src/sage/modular/pollack_stevens/fund_domain.py b/src/sage/modular/pollack_stevens/fund_domain.py index b31ce89d830..eb75ded7468 100644 --- a/src/sage/modular/pollack_stevens/fund_domain.py +++ b/src/sage/modular/pollack_stevens/fund_domain.py @@ -682,8 +682,8 @@ def __init__(self, N): ## generators which satisfy a 2-torsion relation twotor_index.append(r) - # we use the adjoint instead of the inverse for speed - gam = SN(coset_reps[r] * sig * coset_reps[r].adjoint()) + # we use the adjugate instead of the inverse for speed + gam = SN(coset_reps[r] * sig * coset_reps[r].adjugate()) ## gam is 2-torsion matrix and in Gamma_0(N). ## if D is the divisor associated to coset_reps[r] ## then gam * D = - D and so (1+gam)D=0. @@ -719,8 +719,8 @@ def __init__(self, N): ## generators which satisfy a 3-torsion relation threetor_index.append(r) - # Use the adjoint instead of the inverse for speed. - gam = SN(coset_reps[r] * tau * coset_reps[r].adjoint()) + # Use the adjugate instead of the inverse for speed. + gam = SN(coset_reps[r] * tau * coset_reps[r].adjugate()) ## gam is 3-torsion matrix and in Gamma_0(N). ## if D is the divisor associated to coset_reps[r] ## then (1+gam+gam^2)D=0. @@ -779,8 +779,8 @@ def __init__(self, N): A = coset_reps[s] * sig ## A corresponds to reversing the orientation ## of the edge corr. to coset_reps[r] - # Use adjoint instead of inverse for speed - gam = SN(coset_reps[r] * A.adjoint()) + # Use adjugate instead of inverse for speed + gam = SN(coset_reps[r] * A.adjugate()) ## gam is in Gamma_0(N) (by assumption of ## ending up here in this if statement) @@ -1501,7 +1501,7 @@ def prep_hecke_on_gen(self, l, gen, modulus=None): # B is the coset rep equivalent to A B = self.equivalent_rep(A) # gaminv = B*A^(-1), but A is in SL2. - gaminv = B * A.adjoint() + gaminv = B * A.adjugate() # The matrix gaminv * gamma is added to our list in the j-th slot # (as described above) tmp = SN(gaminv * gamma) diff --git a/src/sage/modular/pollack_stevens/manin_map.py b/src/sage/modular/pollack_stevens/manin_map.py index 3a9093a8e2e..36ea54103c2 100644 --- a/src/sage/modular/pollack_stevens/manin_map.py +++ b/src/sage/modular/pollack_stevens/manin_map.py @@ -529,7 +529,7 @@ def _eval_sl2(self, A): SN = Sigma0(self._manin._N) A = M2Z(A) B = self._manin.equivalent_rep(A) - gaminv = SN(B * M2Z(A).adjoint()) + gaminv = SN(B * M2Z(A).adjugate()) return (self[B] * gaminv).normalize() def __call__(self, A): diff --git a/src/sage/modular/pollack_stevens/modsym.py b/src/sage/modular/pollack_stevens/modsym.py index 504dfbe33ac..071be5c0d57 100644 --- a/src/sage/modular/pollack_stevens/modsym.py +++ b/src/sage/modular/pollack_stevens/modsym.py @@ -486,7 +486,7 @@ def hecke(self, ell, algorithm="prep"): sage: phi.hecke(101) == phi * E.ap(101) True - sage: all([phi.hecke(p, algorithm='naive') == phi * E.ap(p) for p in [2,3,5,101]]) # long time + sage: all(phi.hecke(p, algorithm='naive') == phi * E.ap(p) for p in [2,3,5,101]) # long time True """ return self.__class__(self._map.hecke(ell, algorithm), diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index 344f5489c0a..8785a1a941b 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -469,8 +469,6 @@ def quaternion_order_with_given_level(A, level): if A.base_ring() is not QQ: raise NotImplementedError("base field must be rational numbers") - from sage.modular.quatalg.brandt import maximal_order - if len(A.ramified_primes()) > 1: raise NotImplementedError("Currently this algorithm only works when the quaternion algebra is only ramified at one finite prime.") @@ -479,7 +477,7 @@ def quaternion_order_with_given_level(A, level): level = abs(level) N = A.discriminant() N1 = gcd(level, N) - M1 = level/N1 + M1 = level / N1 O = maximal_order(A) if 0 and N1 != 1: # we don't know why magma does the following, so we don't do it. diff --git a/src/sage/modules/filtered_vector_space.py b/src/sage/modules/filtered_vector_space.py index 78e8d3e9dbc..b9ca38ddb6f 100644 --- a/src/sage/modules/filtered_vector_space.py +++ b/src/sage/modules/filtered_vector_space.py @@ -115,7 +115,7 @@ from sage.categories.fields import Fields from sage.modules.free_module import FreeModule_ambient_field, VectorSpace from sage.matrix.constructor import matrix -from sage.misc.all import uniq, cached_method +from sage.misc.all import cached_method def is_FilteredVectorSpace(X): @@ -310,10 +310,10 @@ def normalize_gen(v): # convert generator notation to generator+indices if len(filtration) == 0: raise ValueError('you need to specify at least one ray to deduce the dimension') - generators = [] + generators = set() for gens in filtration.values(): - generators += map(normalize_gen, gens) - generators = tuple(uniq(generators)) + generators.update(normalize_gen(g) for g in gens) + generators = tuple(sorted(generators)) # normalize filtration data normalized = dict() @@ -1013,7 +1013,8 @@ def join_indices(self_indices, other_indices): filtration = dict() self_indices = set() other_indices = set() - for deg in reversed(uniq(list(self_filt) + list(other_filt))): + degrees = list(self_filt) + list(other_filt) + for deg in sorted(set(degrees), reverse=True): self_indices.update(self_filt.get(deg, [])) other_indices.update(other_filt.get(deg, [])) gens = join_indices(self_indices, other_indices) diff --git a/src/sage/modules/finite_submodule_iter.pxd b/src/sage/modules/finite_submodule_iter.pxd index a5962333494..8173f265673 100644 --- a/src/sage/modules/finite_submodule_iter.pxd +++ b/src/sage/modules/finite_submodule_iter.pxd @@ -1,5 +1,4 @@ from sage.structure.element cimport ModuleElement -from cpython cimport bool cdef class FiniteZZsubmodule_iterator: #### Global Data @@ -13,7 +12,7 @@ cdef class FiniteZZsubmodule_iterator: cdef int _basis_length cdef int _count cdef int _order - cdef bool _immutable + cdef bint _immutable cdef ModuleElement _iteration(FiniteZZsubmodule_iterator self) cdef class FiniteFieldsubspace_iterator(FiniteZZsubmodule_iterator): @@ -23,5 +22,5 @@ cdef class FiniteFieldsubspace_projPoint_iterator: cdef int _basis_length, _normalized_pos cdef int _one_dimensional_case # takes the values 0, 1, 2 cdef list _basis - cdef bool _immutable + cdef bint _immutable cdef FiniteFieldsubspace_iterator _it diff --git a/src/sage/modules/finite_submodule_iter.pyx b/src/sage/modules/finite_submodule_iter.pyx index a0db0eaeab2..83764ba97ec 100644 --- a/src/sage/modules/finite_submodule_iter.pyx +++ b/src/sage/modules/finite_submodule_iter.pyx @@ -281,7 +281,7 @@ cdef class FiniteFieldsubspace_iterator(FiniteZZsubmodule_iterator): sage: Y = list(iter) sage: len(Y) 1024 - sage: all([Y[i]-X[i]==v for i in range(len(X))]) + sage: all(Y[i]-X[i] == v for i in range(len(X))) True """ cdef Py_ssize_t d, i, p @@ -336,7 +336,7 @@ cdef class FiniteFieldsubspace_projPoint_iterator: Prove that the option ``normalize == True`` will only return normalized vectors. - sage: all([ x.monic() == x for x in FiniteFieldsubspace_projPoint_iterator(A, True) ]) + sage: all(x.monic() == x for x in FiniteFieldsubspace_projPoint_iterator(A, True)) True TESTS:: diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index d878073d44a..d6d56d8e200 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -1055,7 +1055,7 @@ def __richcmp__(self, other, op): doctest:warning ... DeprecationWarning: The default order on free modules has changed. The old ordering is in sage.modules.free_module.EchelonMatrixKey - See http://trac.sagemath.org/23878 for details. + See http://trac.sagemath.org/23978 for details. False sage: CC^3 <= QQ^3 False @@ -1269,7 +1269,7 @@ def __richcmp__(self, other, op): return self._eq(other) if op == op_NE: return not self._eq(other) - deprecation(23878,"The default order on free modules has changed. " + deprecation(23978,"The default order on free modules has changed. " "The old ordering is in sage.modules.free_module.EchelonMatrixKey") if op == op_LE: return self.is_submodule(other) diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 02fce7a6eef..03d4d57a281 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -2563,8 +2563,8 @@ cdef class FreeModuleElement(Vector): # abstract base class sage: u.dot_product(w) 0 - The cross product is defined for degree seven vectors as well. - [Crossproduct]_ + The cross product is defined for degree seven vectors as well: + see :wikipedia:`Cross_product`. The 3-D cross product is achieved using the quaternions, whereas the 7-D cross product is achieved using the octonions. :: @@ -4882,7 +4882,7 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): sage: w[39893] = sqrt(2) Traceback (most recent call last): ... - TypeError: unable to convert sqrt(2) to an integer + TypeError: self must be a numeric expression :: diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index 5d0da94b98e..0f4e4811cee 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -267,7 +267,7 @@ class FreeQuadraticModule_generic(free_module.FreeModule_generic): doctest:warning ... DeprecationWarning: The default order on free modules has changed. The old ordering is in sage.modules.free_module.EchelonMatrixKey - See http://trac.sagemath.org/23878 for details. + See http://trac.sagemath.org/23978 for details. False sage: C3 < Q3 False @@ -1213,7 +1213,7 @@ class FreeQuadraticModule_submodule_with_basis_pid( doctest:warning ... DeprecationWarning: The default order on free modules has changed. The old ordering is in sage.modules.free_module.EchelonMatrixKey - See http://trac.sagemath.org/23878 for details. + See http://trac.sagemath.org/23978 for details. True sage: V < M False diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 81b72ff5072..5c45bb9d0fe 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -46,15 +46,15 @@ - Paolo Menegatti (2018-03): Added IntegralLatticeDirectSum, IntegralLatticeGluing """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Simon Brandhorst # # This 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 copy import copy from sage.rings.integer_ring import ZZ @@ -631,11 +631,9 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): for i in range(N): ALi = Lattices[i].discriminant_group() for g in glue: - try: - ALi(g[i]) - except: - raise ValueError("the gluing vectors must be in the" - "corresponding discriminant groups") + # Check that the gluing vectors are in the + # corresponding discriminant groups + ALi(g[i]) generators = [sum(phi[i](g[i].lift()*g[i].order())/g[i].order() for i in range(N)) for g in glue] @@ -1346,9 +1344,9 @@ def twist(self, s, discard_basis=False): """ try: s = self.base_ring()(s) - except: - ValueError("the scaling factor must be an element of the base ring.") - if (s==0): + except TypeError: + raise ValueError("the scaling factor must be an element of the base ring.") + if s==0: raise ValueError("the scaling factor must be non zero") if discard_basis: return IntegralLattice(s * self.gram_matrix()) @@ -1357,4 +1355,3 @@ def twist(self, s, discard_basis=False): inner_product_matrix = s * self.inner_product_matrix() ambient = FreeQuadraticModule(self.base_ring(), n, inner_product_matrix) return FreeQuadraticModule_integer_symmetric(ambient=ambient, basis=self.basis(), inner_product_matrix=inner_product_matrix) - diff --git a/src/sage/modules/multi_filtered_vector_space.py b/src/sage/modules/multi_filtered_vector_space.py index 2a203d5ca4d..fd69bad8860 100644 --- a/src/sage/modules/multi_filtered_vector_space.py +++ b/src/sage/modules/multi_filtered_vector_space.py @@ -30,14 +30,14 @@ [ 1 3/2] """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 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 six import iteritems, itervalues from sage.rings.all import QQ, ZZ, Integer @@ -611,14 +611,13 @@ def exterior_power(self, n): sage: F1 = FilteredVectorSpace(2, 1) sage: F2 = FilteredVectorSpace(1, 3) + FilteredVectorSpace(1,0) sage: V = MultiFilteredVectorSpace({'a':F1, 'b':F2}) - sage: V.exterior_power(2) + sage: V.exterior_power(2) # long time Filtrations a: QQ^1 >= 0 >= 0 b: QQ^1 >= QQ^1 >= 0 """ - filtrations = {} - for key in self.index_set(): - filtrations[key] = self._filt[key].exterior_power(n) + filtrations = {key: value.exterior_power(n) + for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) wedge = exterior_power @@ -647,9 +646,8 @@ def symmetric_power(self, n): a: QQ^3 >= QQ^3 >= QQ^3 >= 0 >= 0 >= 0 >= 0 >= 0 b: QQ^3 >= QQ^2 >= QQ^2 >= QQ^2 >= QQ^1 >= QQ^1 >= QQ^1 >= 0 """ - filtrations = {} - for key in self.index_set(): - filtrations[key] = self._filt[key].symmetric_power(n) + filtrations = {key: value.symmetric_power(n) + for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) def dual(self): @@ -671,9 +669,8 @@ def dual(self): a: QQ^2 >= QQ^2 >= QQ^2 >= 0 >= 0 b: QQ^2 >= QQ^1 >= QQ^1 >= QQ^1 >= 0 """ - filtrations = {} - for key in self.index_set(): - filtrations[key] = self._filt[key].dual() + filtrations = {key: value.dual() + for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) def shift(self, deg): @@ -695,9 +692,8 @@ def shift(self, deg): sage: V.shift(-5).support() (-5, -4, -2) """ - filtrations = {} - for key in self.index_set(): - filtrations[key] = self._filt[key].shift(deg) + filtrations = {key: value.shift(deg) + for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) def random_deformation(self, epsilon=None): @@ -727,7 +723,6 @@ def random_deformation(self, epsilon=None): Basis matrix: [ 1 8/1197] """ - filtrations = {} - for key in self.index_set(): - filtrations[key] = self._filt[key].random_deformation(epsilon) + filtrations = {key: value.random_deformation(epsilon) + for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) diff --git a/src/sage/modules/vector_complex_double_dense.pyx b/src/sage/modules/vector_complex_double_dense.pyx index fbdbcda2040..95da06bd693 100644 --- a/src/sage/modules/vector_complex_double_dense.pyx +++ b/src/sage/modules/vector_complex_double_dense.pyx @@ -53,7 +53,8 @@ cdef class Vector_complex_double_dense(Vector_double_dense): implemented using numpy which will call the underlying BLAS, if needed, on the system. - EXAMPLES: + EXAMPLES:: + sage: v = vector(CDF,[(1,-1), (2,pi), (3,5)]) sage: v (1.0 - 1.0*I, 2.0 + 3.141592653589793*I, 3.0 + 5.0*I) @@ -73,7 +74,8 @@ cdef class Vector_complex_double_dense(Vector_double_dense): """ Pickling - EXAMPLES: + EXAMPLES:: + sage: a = vector(CDF, range(9)) sage: loads(dumps(a)) == a True @@ -86,7 +88,8 @@ def unpickle_v0(parent, entries, degree): """ Create a complex double vector containing the entries. - EXAMPLES: + EXAMPLES:: + sage: v = vector(CDF, [1,2,3]) sage: w = sage.modules.vector_complex_double_dense.unpickle_v0(v.parent(), list(v), v.degree()) sage: v == w @@ -99,7 +102,8 @@ def unpickle_v1(parent, entries, degree, is_mutable=None): Create a complex double vector with the given parent, entries, degree, and mutability. - EXAMPLES: + EXAMPLES:: + sage: v = vector(CDF, [1,2,3]) sage: w = sage.modules.vector_complex_double_dense.unpickle_v1(v.parent(), list(v), v.degree(), v.is_mutable()) sage: v == w diff --git a/src/sage/modules/vector_modn_dense.pyx b/src/sage/modules/vector_modn_dense.pyx index d0184ad2939..afa49902dcb 100644 --- a/src/sage/modules/vector_modn_dense.pyx +++ b/src/sage/modules/vector_modn_dense.pyx @@ -293,7 +293,8 @@ cdef class Vector_modn_dense(free_module_element.FreeModuleElement): cpdef _pairwise_product_(self, Vector right): """ - EXAMPLES: + EXAMPLES:: + sage: v = vector(Integers(8), [2,3]); w = vector(Integers(8), [2,5]) sage: v * w 3 diff --git a/src/sage/modules/vector_real_double_dense.pyx b/src/sage/modules/vector_real_double_dense.pyx index bc01c96d6f6..9f96f23af38 100644 --- a/src/sage/modules/vector_real_double_dense.pyx +++ b/src/sage/modules/vector_real_double_dense.pyx @@ -1,7 +1,8 @@ r""" Dense real double vectors using a NumPy backend. -EXAMPLES: +EXAMPLES:: + sage: v = vector(RDF,[1, pi, sqrt(2)]) sage: v (1.0, 3.141592653589793, 1.414213562373095) @@ -43,7 +44,8 @@ cdef class Vector_real_double_dense(Vector_double_dense): using numpy which will call the underlying BLAS, if needed, on the system. - EXAMPLES: + EXAMPLES:: + sage: v = vector(RDF, [1,2,3,4]); v (1.0, 2.0, 3.0, 4.0) sage: v*v @@ -67,7 +69,8 @@ cdef class Vector_real_double_dense(Vector_double_dense): left tail of the distribution. (Paragraph from the scipy.stats docstring.) - EXAMPLES: + EXAMPLES:: + sage: v = vector(RDF, range(9)) sage: v.stats_skew() 0.0 @@ -80,7 +83,8 @@ cdef class Vector_real_double_dense(Vector_double_dense): """ Pickling - EXAMPLES: + EXAMPLES:: + sage: a = vector(RDF, range(9)) sage: loads(dumps(a)) == a True @@ -93,7 +97,8 @@ def unpickle_v0(parent, entries, degree): """ Create a real double vector containing the entries. - EXAMPLES: + EXAMPLES:: + sage: v = vector(RDF, [1,2,3]) sage: w = sage.modules.vector_real_double_dense.unpickle_v0(v.parent(), list(v), v.degree()) sage: v == w @@ -106,7 +111,8 @@ def unpickle_v1(parent, entries, degree, is_mutable=None): Create a real double vector with the given parent, entries, degree, and mutability. - EXAMPLES: + EXAMPLES:: + sage: v = vector(RDF, [1,2,3]) sage: w = sage.modules.vector_real_double_dense.unpickle_v1(v.parent(), list(v), v.degree(), v.is_mutable()) sage: v == w diff --git a/src/sage/modules/with_basis/indexed_element.pxd b/src/sage/modules/with_basis/indexed_element.pxd index b2f4988fcc3..ebc785d7ccf 100644 --- a/src/sage/modules/with_basis/indexed_element.pxd +++ b/src/sage/modules/with_basis/indexed_element.pxd @@ -10,4 +10,3 @@ cdef class IndexedFreeModuleElement(ModuleElement): cpdef _neg_(self) cpdef dict monomial_coefficients(self, bint copy=*) - cpdef _coefficient_fast(self, m) diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index f90c08f80e3..6e57c1b96cc 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -634,10 +634,9 @@ cdef class IndexedFreeModuleElement(ModuleElement): (other)._monomial_coefficients, self._monomial_coefficients)) - cpdef _coefficient_fast(self, m): + def __getitem__(self, m): """ - Return the coefficient of ``m`` in ``self``, where ``m`` is key in - ``self._monomial_coefficients``. + Return the coefficient of ``m`` in ``self``. EXAMPLES:: @@ -645,34 +644,19 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: q = Partition([1,1,1]) sage: s = SymmetricFunctions(QQ).schur() sage: a = s(p) - sage: a._coefficient_fast([2,1]) - Traceback (most recent call last): - ... - TypeError: unhashable type: 'list' - - :: - - sage: a._coefficient_fast(p) - 1 - sage: a._coefficient_fast(q) - 0 - """ - return self._monomial_coefficients.get(m, self.base_ring().zero()) - - def __getitem__(self, m): - """ - EXAMPLES:: - - sage: s = SymmetricFunctions(QQ).schur() - sage: p = Partition([2,1]) - sage: q = Partition([1,1,1]) - sage: a = s(p) sage: a[p] 1 sage: a[q] 0 + sage: a[[2,1]] + Traceback (most recent call last): + ... + TypeError: unhashable type: 'list' """ - return self._coefficient_fast(m) + res = self._monomial_coefficients.get(m) + if res is None: + return self.base_ring().zero() + return res def _vector_(self, new_base_ring=None): """ diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 8d01dee34c1..27f6e732a23 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -111,7 +111,6 @@ from sage.misc.misc import attrcall # The identity function would deserve a more canonical location from sage.misc.c3_controlled import identity -from sage.misc.superseded import deprecated_function_alias from sage.categories.commutative_additive_semigroups import CommutativeAdditiveSemigroups from sage.categories.homset import Hom from sage.categories.modules_with_basis import ModulesWithBasis @@ -643,20 +642,23 @@ def __init__(self, triangular="upper", unitriangular=False, Pickling fails (:trac:`17957`) because the attribute ``phi._inverse_on_support`` is a ``dict.get`` method which is - not yet picklable:: + not picklable in Python 2:: sage: phi = X.module_morphism(lt, triangular="lower", codomain=X, ....: inverse_on_support="compute") - sage: dumps(phi) + sage: dumps(phi) # py2 Traceback (most recent call last): ... TypeError: expected string or Unicode object, NoneType found sage: phi._inverse_on_support - sage: dumps(phi._inverse_on_support) + sage: dumps(phi._inverse_on_support) # py2 Traceback (most recent call last): ... TypeError: expected string or Unicode object, NoneType found + sage: ldp = loads(dumps(phi._inverse_on_support)) # py3 + sage: [ldp(i) == phi._inverse_on_support(i) for i in range(1, 4)] # py3 + [True, True, True] """ if key is not None: self._key_kwds = dict(key=key) @@ -1066,7 +1068,6 @@ def coreduced(self, y): c = c / s[j] # the base ring is a field remainder -= s._lmul_(c) return result - co_reduced = deprecated_function_alias(8678, coreduced) def cokernel_basis_indices(self): r""" @@ -1154,8 +1155,6 @@ def cokernel_projection(self, category = None): return codomain.module_morphism(function=self.coreduced, codomain=codomain, category=category) - co_kernel_projection = deprecated_function_alias(8678, cokernel_projection) - class TriangularModuleMorphismByLinearity(ModuleMorphismByLinearity, TriangularModuleMorphism): r""" A concrete class for triangular module morphisms obtained by extending a function by linearity. @@ -1312,14 +1311,16 @@ def __init__(self, domain, matrix, codomain=None, category=None, side="left"): sage: TestSuite(phi).run(skip=["_test_pickling"]) Pickling fails (:trac:`17957`) because ``phi._on_basis`` is - currently a ``dict.__getitem__`` which is not yet picklable:: + currently a ``dict.__getitem__`` which is not picklable in Python 2:: sage: phi._on_basis - sage: dumps(phi._on_basis) + sage: dumps(phi._on_basis) # py2 Traceback (most recent call last): ... TypeError: expected string or Unicode object, NoneType found + sage: loads(dumps(phi)) == phi # py3 + True The matrix is stored in the morphism, as if it was for an action on the right:: diff --git a/src/sage/monoids/automatic_semigroup.py b/src/sage/monoids/automatic_semigroup.py index f3b154bfabc..a85b0a8cc43 100644 --- a/src/sage/monoids/automatic_semigroup.py +++ b/src/sage/monoids/automatic_semigroup.py @@ -204,7 +204,7 @@ class AutomaticSemigroup(UniqueRepresentation, Parent): sage: len(M.idempotents()) 16 - sage: all([len(j) == 1 for j in M.j_classes()]) + sage: all(len(j) == 1 for j in M.j_classes()) True TESTS:: diff --git a/src/sage/numerical/backends/coin_backend.pyx b/src/sage/numerical/backends/coin_backend.pyx index 32f80cb0bde..f57dfb3d340 100644 --- a/src/sage/numerical/backends/coin_backend.pyx +++ b/src/sage/numerical/backends/coin_backend.pyx @@ -666,7 +666,7 @@ cdef class CoinBackend(GenericBackend): return (lb[i] if lb[i] != - self.si.getInfinity() else None, ub[i] if ub[i] != + self.si.getInfinity() else None) - cpdef add_col(self, list indices, list coeffs): + cpdef add_col(self, indices, coeffs): r""" Adds a column. @@ -701,14 +701,27 @@ cdef class CoinBackend(GenericBackend): 5 """ - cdef int n = len(indices) + cdef list list_indices + cdef list list_coeffs + + if type(indices) is not list: + list_indices = list(indices) + else: + list_indices = indices + + if type(coeffs) is not list: + list_coeffs = list(coeffs) + else: + list_coeffs = coeffs + + cdef int n = len(list_indices) cdef int * c_indices = check_malloc(n*sizeof(int)) cdef double * c_values = check_malloc(n*sizeof(double)) cdef int i for 0<= i< n: - c_indices[i] = indices[i] - c_values[i] = coeffs[i] + c_indices[i] = list_indices[i] + c_values[i] = list_coeffs[i] self.si.addCol (n, c_indices, c_values, 0, self.si.getInfinity(), 0) diff --git a/src/sage/numerical/backends/cplex_backend.pyx b/src/sage/numerical/backends/cplex_backend.pyx index 0cdb5678cc9..331296e9f89 100644 --- a/src/sage/numerical/backends/cplex_backend.pyx +++ b/src/sage/numerical/backends/cplex_backend.pyx @@ -800,7 +800,7 @@ cdef class CPLEXBackend(GenericBackend): return (None if lb <= -int(CPX_INFBOUND) else lb, None if ub >= +int(CPX_INFBOUND) else ub) - cpdef add_col(self, list indices, list coeffs): + cpdef add_col(self, indices, coeffs): r""" Adds a column. @@ -835,9 +835,22 @@ cdef class CPLEXBackend(GenericBackend): 5 """ + cdef list list_indices + cdef list list_coeffs + + if type(indices) is not list: + list_indices = list(indices) + else: + list_indices = indices + + if type(coeffs) is not list: + list_coeffs = list(coeffs) + else: + list_coeffs = coeffs + cdef int status cdef int i - cdef int n = len(indices) + cdef int n = len(list_indices) cdef int ncols = self.ncols() status = CPXnewcols(self.env, self.lp, 1, NULL, NULL, NULL, NULL, NULL) @@ -850,8 +863,8 @@ cdef class CPLEXBackend(GenericBackend): cdef int * c_col = sig_malloc(n * sizeof(int)) for 0<= i < n: - c_coeff[i] = coeffs[i] - c_indices[i] = indices[i] + c_coeff[i] = list_coeffs[i] + c_indices[i] = list_indices[i] c_col[i] = ncols diff --git a/src/sage/numerical/backends/cvxopt_backend.pyx b/src/sage/numerical/backends/cvxopt_backend.pyx index 7fd288f3c68..0eb2f32064b 100644 --- a/src/sage/numerical/backends/cvxopt_backend.pyx +++ b/src/sage/numerical/backends/cvxopt_backend.pyx @@ -316,7 +316,7 @@ cdef class CVXOPTBackend(GenericBackend): - cpdef add_col(self, list indices, list coeffs): + cpdef add_col(self, indices, coeffs): """ Add a column. @@ -351,11 +351,11 @@ cdef class CVXOPTBackend(GenericBackend): 5 """ column = [] - for i in range(len(indices)): + for _ in indices: column.append(0.0) - for i in range(len(indices)): - column[indices[i]] = coeffs[i] + for idx, ind in enumerate(indices): + column[ind] = coeffs[idx] self.G_matrix.append(column) diff --git a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx index 964c989ec1e..791d188e4ec 100644 --- a/src/sage/numerical/backends/cvxopt_sdp_backend.pyx +++ b/src/sage/numerical/backends/cvxopt_sdp_backend.pyx @@ -728,7 +728,7 @@ cdef class CVXOPTSDPBackend(GenericSDPBackend): [0.0 0.0] sage: B1.is_positive_definite() True - sage: x = p.get_values(x).values() + sage: x = sorted(p.get_values(x).values()) sage: x[0]*b1 + x[1]*b2 - b3 + B1 # tol 1e-09 [0.0 0.0] [0.0 0.0] diff --git a/src/sage/numerical/backends/generic_backend.pxd b/src/sage/numerical/backends/generic_backend.pxd index 472d01fe436..2d031424d1e 100644 --- a/src/sage/numerical/backends/generic_backend.pxd +++ b/src/sage/numerical/backends/generic_backend.pxd @@ -22,7 +22,7 @@ cdef class GenericBackend (SageObject): cpdef add_linear_constraint_vector(self, degree, coefficients, lower_bound, upper_bound, name=*) cpdef remove_constraint(self, int) cpdef remove_constraints(self, constraints) - cpdef add_col(self, list indices, list coeffs) + cpdef add_col(self, indices, coeffs) cpdef add_linear_constraints(self, int number, lower_bound, upper_bound, names=*) cpdef int solve(self) except -1 cpdef get_objective_value(self) diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index abc5b28fc69..bc1bd249853 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -156,13 +156,13 @@ cdef class GenericBackend: if obj is None: obj = self.zero() for i in range(n): - value = self.add_variable(lower_bound = lower_bound, - upper_bound = upper_bound, - binary = binary, - continuous = continuous, - integer = integer, - obj = obj, - name = None if names is None else names[i]) + value = self.add_variable(lower_bound=lower_bound, + upper_bound=upper_bound, + binary=binary, + continuous=continuous, + integer=integer, + obj=obj, + name=None if names is None else names[i]) return value @classmethod @@ -540,7 +540,7 @@ cdef class GenericBackend: p.add_linear_constraint_vector(2, coeffs, lower, upper, 'foo') # FIXME: Tests here. Careful what we expect regarding ranged constraints with some solvers. - cpdef add_col(self, list indices, list coeffs): + cpdef add_col(self, indices, coeffs): """ Add a column. diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index a15a7ddb9b7..ee95b475bb0 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -785,7 +785,7 @@ cdef class GLPKBackend(GenericBackend): (ub if ub != +DBL_MAX else None) ) - cpdef add_col(self, list indices, list coeffs): + cpdef add_col(self, indices, coeffs): """ Add a column. @@ -1466,10 +1466,14 @@ cdef class GLPKBackend(GenericBackend): sage: p.add_variable() 0 - sage: p.variable_upper_bound(0, 'hey!') + sage: p.variable_upper_bound(0, 'hey!') # py2 Traceback (most recent call last): ... TypeError: a float is required + sage: p.variable_upper_bound(0, 'hey!') # py3 + Traceback (most recent call last): + ... + TypeError: must be real number, not str """ cdef double x cdef double min @@ -1557,10 +1561,14 @@ cdef class GLPKBackend(GenericBackend): sage: p.add_variable() 0 - sage: p.variable_lower_bound(0, 'hey!') + sage: p.variable_lower_bound(0, 'hey!') # py2 Traceback (most recent call last): ... TypeError: a float is required + sage: p.variable_lower_bound(0, 'hey!') # py3 + Traceback (most recent call last): + ... + TypeError: must be real number, not str """ cdef double x cdef double max diff --git a/src/sage/numerical/backends/gurobi_backend.pyx b/src/sage/numerical/backends/gurobi_backend.pyx index 3cc6c7234b1..647edee259c 100644 --- a/src/sage/numerical/backends/gurobi_backend.pyx +++ b/src/sage/numerical/backends/gurobi_backend.pyx @@ -198,7 +198,7 @@ cdef class GurobiBackend(GenericBackend): return self.ncols()-1 - cpdef add_col(self, list indices, list coeffs): + cpdef add_col(self, indices, coeffs): """ Add a column. @@ -364,7 +364,7 @@ cdef class GurobiBackend(GenericBackend): cdef int error cdef char * pp_name[1] - if name: + if name is not None: error = GRBsetstrattr(self.model, "ModelName", str_to_bytes(name)) check(self.env, error) check(self.env,GRBupdatemodel(self.model)) diff --git a/src/sage/numerical/backends/interactivelp_backend.pyx b/src/sage/numerical/backends/interactivelp_backend.pyx index 4699adabc10..dafc8472489 100644 --- a/src/sage/numerical/backends/interactivelp_backend.pyx +++ b/src/sage/numerical/backends/interactivelp_backend.pyx @@ -8,7 +8,7 @@ AUTHORS: """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Nathann Cohen # Copyright (C) 2016 Matthias Koeppe # @@ -16,8 +16,8 @@ AUTHORS: # 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 __future__ import print_function from sage.numerical.mip import MIPSolverException @@ -25,6 +25,7 @@ from sage.numerical.interactive_simplex_method import InteractiveLPProblem, defa from sage.modules.all import vector from copy import copy + cdef class InteractiveLPBackend: """ MIP Backend that works with :class:`InteractiveLPProblem`. @@ -563,7 +564,7 @@ cdef class InteractiveLPBackend: problem_type, ring, objective_constant_term=d) - cpdef add_col(self, list indices, list coeffs): + cpdef add_col(self, indices, coeffs): """ Add a column. @@ -593,11 +594,11 @@ cdef class InteractiveLPBackend: sage: p.nrows() 0 sage: p.add_linear_constraints(5, 0, None) - sage: p.add_col(range(5), range(5)) + sage: p.add_col(list(range(5)), list(range(5))) sage: p.nrows() 5 """ - self.add_variable(coefficients = zip(indices, coeffs)) + self.add_variable(coefficients=zip(indices, coeffs)) cpdef int solve(self) except -1: """ @@ -614,7 +615,7 @@ cdef class InteractiveLPBackend: sage: from sage.numerical.backends.generic_backend import get_solver sage: p = get_solver(solver = "InteractiveLP") sage: p.add_linear_constraints(5, 0, None) - sage: p.add_col(range(5), range(5)) + sage: p.add_col(list(range(5)), list(range(5))) sage: p.solve() 0 sage: p.objective_coefficient(0,1) diff --git a/src/sage/numerical/backends/logging_backend.py b/src/sage/numerical/backends/logging_backend.py index 774e210c11e..44eee16b3f5 100644 --- a/src/sage/numerical/backends/logging_backend.py +++ b/src/sage/numerical/backends/logging_backend.py @@ -91,7 +91,7 @@ def m(self, *args, **kwdargs): update_wrapper(m, getattr(backend, attr)) return m -class LoggingBackend (GenericBackend): +class LoggingBackend(GenericBackend): """ See :class:`LoggingBackendFactory` for documentation. diff --git a/src/sage/numerical/backends/ppl_backend.pyx b/src/sage/numerical/backends/ppl_backend.pyx index ba312d56138..c01ade1ba9c 100644 --- a/src/sage/numerical/backends/ppl_backend.pyx +++ b/src/sage/numerical/backends/ppl_backend.pyx @@ -21,7 +21,7 @@ AUTHORS: from __future__ import print_function from sage.numerical.mip import MIPSolverException -from sage.libs.ppl import MIP_Problem, Variable, Variables_Set, Linear_Expression, Constraint, Generator +from ppl import MIP_Problem, Variable, Variables_Set, Linear_Expression, Constraint, Generator from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational from .generic_backend cimport GenericBackend @@ -179,7 +179,7 @@ cdef class PPLBackend(GenericBackend): mip_obj = mip_obj + Linear_Expression(coeff * Variable(i)) self.mip.set_objective_function(mip_obj) self.obj_denominator = denom - + # Constraints for i in range(len(self.Matrix)): l = Linear_Expression(0) @@ -193,17 +193,60 @@ cdef class PPLBackend(GenericBackend): l *= newdenom coeff *= newdenom l = l + Linear_Expression(coeff * Variable(j)) - self.mip._add_rational_constraint(l, denom, self.row_lower_bound[i], self.row_upper_bound[i]) + self._add_rational_constraint(l, denom, self.row_lower_bound[i], self.row_upper_bound[i]) assert len(self.col_lower_bound) == len(self.col_upper_bound) for i in range(len(self.col_lower_bound)): - self.mip._add_rational_constraint(Variable(i), 1, self.col_lower_bound[i], self.col_upper_bound[i]) + self._add_rational_constraint(Variable(i), 1, self.col_lower_bound[i], self.col_upper_bound[i]) if self.is_maximize == 1: self.mip.set_optimization_mode('maximization') else: self.mip.set_optimization_mode('minimization') + def _add_rational_constraint(self, e, denom, lower, upper): + """ + Helper function for adding constraints: add the constraint + ``lower <= e/denom <= upper``. + + INPUT: + + - ``e`` -- a linear expression (type ``Linear_Expression``) + + - ``denom`` -- a positive integer + + - ``lower``, ``upper`` -- a rational number or ``None``, where + ``None`` means that there is no constraint + + TESTS: + + Create a linear system with only equalities as constraints:: + + sage: p = MixedIntegerLinearProgram(solver="PPL") + sage: x = p.new_variable(nonnegative=False) + sage: n = 40 + sage: v = random_vector(QQ, n) + sage: M = random_matrix(QQ, 2*n, n) + sage: for j in range(2*n): # indirect doctest + ....: lhs = p.sum(M[j,i]*x[i] for i in range(n)) + ....: rhs = M.row(j).inner_product(v) + ....: p.add_constraint(lhs == rhs) + sage: p.solve() # long time + 0 + + """ + if lower == upper: + if lower is not None: + rhs = Rational(lower * denom) + self.mip.add_constraint(e * rhs.denominator() == rhs.numerator()) + else: + if lower is not None: + rhs = Rational(lower * denom) + self.mip.add_constraint(e * rhs.denominator() >= rhs.numerator()) + if upper is not None: + rhs = Rational(upper * denom) + self.mip.add_constraint(e * rhs.denominator() <= rhs.numerator()) + cpdef int add_variable(self, lower_bound=0, upper_bound=None, binary=False, continuous=False, integer=False, obj=0, name=None) except -1: """ Add a variable. @@ -556,7 +599,7 @@ cdef class PPLBackend(GenericBackend): self.row_upper_bound.append(upper_bound) self.row_name_var.append(name) - cpdef add_col(self, list indices, list coeffs): + cpdef add_col(self, indices, coeffs): """ Add a column. @@ -722,7 +765,7 @@ cdef class PPLBackend(GenericBackend): sage: p.get_variable_value(1) 3/2 """ - ans = self.mip.optimal_value() + ans = Rational(self.mip.optimal_value()) return ans / self.obj_denominator + self.obj_constant_term cpdef get_variable_value(self, int variable): @@ -751,7 +794,7 @@ cdef class PPLBackend(GenericBackend): 3/2 """ g = self.mip.optimizing_point() - return g.coefficient(Variable(variable)) / g.divisor() + return Integer(g.coefficient(Variable(variable))) / Integer(g.divisor()) cpdef int ncols(self): """ diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index 7a13b2af297..1481066669e 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -2001,13 +2001,13 @@ def __init__(self, A, b, c, x="x", problem_type="max", slack_variables = ["{}{:d}".format(slack_variables, i) for i in indices] else: - slack_variables = list(map(str, slack_variables)) + slack_variables = [str(s) for s in slack_variables] if len(slack_variables) != m: raise ValueError("wrong number of slack variables") if auxiliary_variable is None: auxiliary_variable = x + "0" if isinstance(x, str) else "x0" names = [str(auxiliary_variable)] - names.extend(map(str, self.x())) + names.extend([str(s) for s in self.x()]) names.extend(slack_variables) if names[0] == names[1]: names.pop(0) diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index 809631cfe6c..cd0e11457a4 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -809,7 +809,7 @@ cdef class LinearFunction(LinearFunctionOrConstraint): cpdef iteritems(self): """ - Iterate over the index, coefficient pairs + Iterate over the index, coefficient pairs. OUTPUT: @@ -822,11 +822,11 @@ cdef class LinearFunction(LinearFunctionOrConstraint): sage: p = MixedIntegerLinearProgram(solver = 'ppl') sage: x = p.new_variable() sage: f = 0.5 + 3/2*x[1] + 0.6*x[3] - sage: for id, coeff in f.iteritems(): + sage: for id, coeff in sorted(f.iteritems()): ....: print('id = {} coeff = {}'.format(id, coeff)) + id = -1 coeff = 1/2 id = 0 coeff = 3/2 id = 1 coeff = 3/5 - id = -1 coeff = 1/2 """ return self._f.iteritems() diff --git a/src/sage/numerical/mip.pyx b/src/sage/numerical/mip.pyx index 436387d7eaf..8e617599385 100644 --- a/src/sage/numerical/mip.pyx +++ b/src/sage/numerical/mip.pyx @@ -88,7 +88,7 @@ The following example shows all these steps:: x_3 is an integer variable (min=0.0, max=+oo) sage: print('Objective Value: {}'.format(p.solve())) Objective Value: 2.0 - sage: for i, v in p.get_values(w).iteritems(): + sage: for i, v in sorted(p.get_values(w).items()): ....: print('w_%s = %s' % (i, int(round(v)))) w_0 = 15 w_1 = 10 @@ -224,14 +224,14 @@ AUTHORS: - Risan (2012/02): added extension for exact computation """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Nathann Cohen # # 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 __future__ import print_function from copy import copy @@ -241,6 +241,7 @@ from sage.structure.element import is_Matrix from sage.misc.cachefunc import cached_method from sage.misc.superseded import deprecation + cdef class MixedIntegerLinearProgram(SageObject): r""" The ``MixedIntegerLinearProgram`` class is the link between Sage, linear @@ -777,7 +778,7 @@ cdef class MixedIntegerLinearProgram(SageObject): An exception is raised when two types are supplied :: - sage: z = p.new_variable(real = True, integer = True) + sage: z = p.new_variable(real=True, integer=True) Traceback (most recent call last): ... ValueError: Exactly one of the available types has to be True @@ -1420,7 +1421,7 @@ cdef class MixedIntegerLinearProgram(SageObject): values for the corresponding variables :: sage: x_sol = p.get_values(x) - sage: x_sol.keys() + sage: sorted(x_sol) [3, 5] Obviously, it also works with variables of higher dimension:: @@ -3155,7 +3156,7 @@ cdef class MIPVariable(SageObject): sage: p = MixedIntegerLinearProgram(solver='GLPK') sage: v = p.new_variable(nonnegative=True) sage: p.set_objective(v[0] + v[1]) - sage: list(v.keys()) + sage: sorted(v.keys()) [0, 1] """ return self._dict.keys() @@ -3169,7 +3170,7 @@ cdef class MIPVariable(SageObject): sage: p = MixedIntegerLinearProgram(solver='GLPK') sage: v = p.new_variable(nonnegative=True) sage: p.set_objective(v[0] + v[1]) - sage: list(v.items()) + sage: sorted(v.items()) [(0, x_0), (1, x_1)] """ return self._dict.items() @@ -3183,7 +3184,7 @@ cdef class MIPVariable(SageObject): sage: p = MixedIntegerLinearProgram(solver='GLPK') sage: v = p.new_variable(nonnegative=True) sage: p.set_objective(v[0] + v[1]) - sage: list(v.values()) + sage: sorted(v.values(), key=str) [x_0, x_1] """ return self._dict.values() diff --git a/src/sage/numerical/sdp.pyx b/src/sage/numerical/sdp.pyx index 1fd8c106b64..30d2f18f52d 100644 --- a/src/sage/numerical/sdp.pyx +++ b/src/sage/numerical/sdp.pyx @@ -80,7 +80,7 @@ The following example shows all these steps:: Optimal solution found. sage: print('Objective Value: {}'.format(round(opt,3))) Objective Value: 1.0 - sage: [round(x,3) for x in p.get_values(x).values()] + sage: [round(x, 3) for x in sorted(p.get_values(x).values())] [0.0, 1.0] sage: p.show() Maximization: @@ -728,7 +728,7 @@ cdef class SemidefiniteProgram(SageObject): values for the corresponding variables :: sage: x_sol = p.get_values(x) - sage: list(x_sol.keys()) + sage: sorted(x_sol) [3, 5] Obviously, it also works with variables of higher dimension:: @@ -1038,7 +1038,7 @@ cdef class SemidefiniteProgram(SageObject): [0.0 0.0] sage: B1.is_positive_definite() True - sage: x = p.get_values(x).values() + sage: x = sorted(p.get_values(x).values()) sage: x[0]*b1 + x[1]*b2 - b3 + B1 # tol 1e-09 [0.0 0.0] [0.0 0.0] @@ -1287,7 +1287,7 @@ cdef class SDPVariable(Element): sage: p = SemidefiniteProgram() sage: v = p.new_variable() sage: p.set_objective(v[0] + v[1]) - sage: list(v.keys()) + sage: sorted(v.keys()) [0, 1] """ return self._dict.keys() @@ -1301,7 +1301,7 @@ cdef class SDPVariable(Element): sage: p = SemidefiniteProgram() sage: v = p.new_variable() sage: p.set_objective(v[0] + v[1]) - sage: list(v.items()) + sage: sorted(v.items()) [(0, x_0), (1, x_1)] """ return self._dict.items() @@ -1315,7 +1315,7 @@ cdef class SDPVariable(Element): sage: p = SemidefiniteProgram() sage: v = p.new_variable() sage: p.set_objective(v[0] + v[1]) - sage: list(v.values()) + sage: sorted(v.values(), key=str) [x_0, x_1] """ return self._dict.values() diff --git a/src/sage/parallel/decorate.py b/src/sage/parallel/decorate.py index 2af0df6a466..c0713fa14f2 100644 --- a/src/sage/parallel/decorate.py +++ b/src/sage/parallel/decorate.py @@ -410,7 +410,6 @@ def parallel(p_iter='fork', ncpus=None, **kwds): Currently, parallel methods do not work with the multiprocessing implementation. """ - import types if isinstance(p_iter, types.FunctionType): return Parallel()(p_iter) return Parallel(p_iter, ncpus, **kwds) diff --git a/src/sage/plot/complex_plot.pyx b/src/sage/plot/complex_plot.pyx index 758fb709b75..7814c8c5d76 100644 --- a/src/sage/plot/complex_plot.pyx +++ b/src/sage/plot/complex_plot.pyx @@ -19,7 +19,7 @@ Complex Plots from __future__ import absolute_import # TODO: use NumPy buffers and complex fast_callable (when supported) -from cysignals.signals cimport sig_on, sig_off +from cysignals.signals cimport sig_on, sig_off, sig_check cimport numpy as cnumpy @@ -29,16 +29,16 @@ from sage.rings.complex_double cimport ComplexDoubleElement from sage.arith.srange import srange from libc.math cimport hypot, atan2, atan, log, sqrt - -cdef double PI = 4 * atan(1) +from sage.arith.constants cimport M_PI as PI cdef inline ComplexDoubleElement new_CDF_element(double x, double y): - cdef ComplexDoubleElement z = ComplexDoubleElement.__new__(ComplexDoubleElement) - z._complex.dat[0] = x - z._complex.dat[1] = y + z = ComplexDoubleElement.__new__(ComplexDoubleElement) + z._complex.real = x + z._complex.imag = y return z + cdef inline double mag_to_lightness(double r): """ Tweak this to adjust how the magnitude affects the color. @@ -114,7 +114,7 @@ def complex_to_rgb(z_values): z = zz else: z = CDF(zz) - x, y = z._complex.dat[0], z._complex.dat[1] + x, y = z._complex.dat mag = hypot(x, y) arg = atan2(y, x) # math module arctan has range from -pi to pi, so cut along negative x-axis @@ -381,12 +381,18 @@ def complex_plot(f, xrange, yrange, **options): pass cdef double x, y - ignore, ranges = setup_for_eval_on_grid([], [xrange, yrange], options['plot_points']) - xrange,yrange=[r[:2] for r in ranges] - sig_on() - z_values = [[ f(new_CDF_element(x, y)) for x in srange(*ranges[0], include_endpoint=True)] - for y in srange(*ranges[1], include_endpoint=True)] - sig_off() + _, ranges = setup_for_eval_on_grid([], [xrange, yrange], options['plot_points']) + xrange = ranges[0] + yrange = ranges[1] + cdef list z_values = [] + cdef list row + for y in srange(*yrange, include_endpoint=True): + row = [] + for x in srange(*xrange, include_endpoint=True): + sig_check() + row.append(f(new_CDF_element(x, y))) + z_values.append(row) + g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) g.add_primitive(ComplexPlot(complex_to_rgb(z_values), xrange, yrange, options)) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 603e54a430e..9b2a73add34 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -2383,10 +2383,10 @@ def _get_vmin_vmax(self, vmin, vmax, basev, axes_pad): at least 10 units apart:: sage: p = Graphics() - sage: p._get_vmin_vmax(1, 2, 10, None) - (9/10, 10.0) - sage: p._get_vmin_vmax(1, 5, 10, None) - (9/10, 10.0) + sage: p._get_vmin_vmax(1, 2, 10, None) == (9/10, 10) + True + sage: p._get_vmin_vmax(1, 5, 10, None) == (9/10, 10) + True sage: p._get_vmin_vmax(1, 10, 10, None) (9/10, 11) sage: p._get_vmin_vmax(1, 11, 10, None) @@ -2903,7 +2903,7 @@ def matplotlib(self, filename=None, if vgridlines=='minor': vgridstyle['which']='both' - if hasattr(hgridlines, '__iter__'): + if not isinstance(hgridlines, str) and hasattr(hgridlines, '__iter__'): hlines=iter(hgridlines) hgridstyle.pop("minor",None) for hline in hlines: @@ -2919,7 +2919,7 @@ def matplotlib(self, filename=None, if hgridlines not in (None, False): subplot.yaxis.grid(True, **hgridstyle) - if hasattr(vgridlines, '__iter__'): + if not isinstance(vgridlines, str) and hasattr(vgridlines, '__iter__'): vlines=iter(vgridlines) vgridstyle.pop("minor",None) for vline in vlines: diff --git a/src/sage/plot/histogram.py b/src/sage/plot/histogram.py index fc4b2046c07..8dd68e2fee8 100644 --- a/src/sage/plot/histogram.py +++ b/src/sage/plot/histogram.py @@ -92,8 +92,8 @@ def get_minmax_data(self): DeprecationWarning: the 'normed' option is deprecated. Use 'density' instead. See https://trac.sagemath.org/25260 for details. sage: h.get_minmax_data() - doctest:warning ...: - VisibleDeprecationWarning: Passing `normed=True` on non-uniform bins has always been broken, and computes neither the probability density function nor the probability mass function. The result is only correct if the bins are uniform, when density=True will produce the same result anyway. The argument will be removed in a future version of numpy. + doctest:warning ... + ...VisibleDeprecationWarning: Passing `normed=True` on non-uniform bins has always been broken, and computes neither the probability density function nor the probability mass function. The result is only correct if the bins are uniform, when density=True will produce the same result anyway. The argument will be removed in a future version of numpy. {'xmax': 10.0, 'xmin': 3.0, 'ymax': 0.476190476190..., 'ymin': 0} """ import numpy diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index f4b45135a89..7c6420f48bf 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -1975,7 +1975,6 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) xmin = kwds.pop('xmin', -1) xmax = kwds.pop('xmax', 1) G = _plot(funcs, (xmin, xmax), *args, **kwds) - pass else: sage.misc.misc.verbose("there were %s extra arguments (besides %s)" % (n, funcs), level=0) diff --git a/src/sage/plot/plot3d/implicit_plot3d.py b/src/sage/plot/plot3d/implicit_plot3d.py index 78679288baf..b413e83ac6c 100644 --- a/src/sage/plot/plot3d/implicit_plot3d.py +++ b/src/sage/plot/plot3d/implicit_plot3d.py @@ -7,27 +7,27 @@ def implicit_plot3d(f, xrange, yrange, zrange, **kwds): r""" - Plots an isosurface of a function. + Plot an isosurface of a function. INPUT: - - ``f`` - function + - ``f`` -- function - - ``xrange`` - a 2-tuple (x_min, x_max) or a 3-tuple (x, x_min, x_max) + - ``xrange`` -- a 2-tuple (x_min, x_max) or a 3-tuple (x, x_min, x_max) - - ``yrange`` - a 2-tuple (y_min, y_may) or a 3-tuple (y, y_min, y_may) + - ``yrange`` -- a 2-tuple (y_min, y_max) or a 3-tuple (y, y_min, y_max) - - ``zrange`` - a 2-tuple (z_min, z_maz) or a 3-tuple (z, z_min, z_maz) + - ``zrange`` -- a 2-tuple (z_min, z_max) or a 3-tuple (z, z_min, z_max) - - ``plot_points`` - (default: "automatic", which is 40) the number of + - ``plot_points`` -- (default: "automatic", which is 40) the number of function evaluations in each direction. (The number of cubes in the marching cubes algorithm will be one less than this). Can be a triple of integers, to specify a different resolution in each of x,y,z. - - ``contour`` - (default: 0) plot the isosurface f(x,y,z)==contour. Can be a + - ``contour`` -- (default: 0) plot the isosurface f(x,y,z)==contour. Can be a list, in which case multiple contours are plotted. - - ``region`` - (default: None) If region is given, it must be a Python + - ``region`` -- (default: None) If region is given, it must be a Python callable. Only segments of the surface where region(x,y,z) returns a number >0 will be included in the plot. (Note that returning a Python boolean is acceptable, since True == 1 and False == 0). @@ -588,17 +588,28 @@ def metaball(x0, y0, z0): return 1 / ((x-x0)**2+(y-y0)**2+(z-z0)**2) sage: implicit_plot3d(x^2 + y^2 + z^2, (x,-2,2), (y,-2,2), (z,-2,2), contour=4, viewer='tachyon') Graphics3d Object - An implicit plot that doesn't include any surface in the view volume + An implicit plot that does not include any surface in the view volume produces an empty plot:: sage: implicit_plot3d(x^2 + y^2 + z^2 - 5000, (x,-2,2), (y,-2,2), (z,-2,2), plot_points=6) Graphics3d Object - Make sure that implicit_plot3d doesn't error if the function cannot + Make sure that implicit_plot3d does not error if the function cannot be symbolically differentiated:: sage: implicit_plot3d(max_symbolic(x, y^2) - z, (x,-2,2), (y,-2,2), (z,-2,2), plot_points=6) Graphics3d Object + + TESTS: + + Check for :trac:`10599`:: + + sage: var('x,y,z') + (x, y, z) + sage: M = matrix(3,[1,-1,-1,-1,3,1,-1,1,3]) + sage: v = 1/M.eigenvalues()[1] + sage: implicit_plot3d(x^2+y^2+z^2==v, [x,-3,3], [y,-3,3],[z,-3,3]) + Graphics3d Object """ # These options, related to rendering with smooth shading, are irrelevant # since IndexFaceSet does not support surface normals: diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index 1ad8188c1d4..b823460d94f 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -7,16 +7,17 @@ from sage.structure.element import is_Matrix from sage.matrix.all import matrix from sage.rings.all import RDF +from sage.misc.superseded import deprecation -def list_plot3d(v, interpolation_type='default', texture="automatic", point_list=None, **kwds): + +def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): r""" A 3-dimensional plot of a surface defined by the list `v` of points in 3-dimensional space. INPUT: - - ``v`` - something that defines a set of points in 3 - space, for example: + - ``v`` - something that defines a set of points in 3 space: - a matrix @@ -25,19 +26,18 @@ def list_plot3d(v, interpolation_type='default', texture="automatic", point_list - a list of lists (all of the same length) - this is treated the same as a matrix. - - ``texture`` - (default: "automatic", a solid light blue) - OPTIONAL KEYWORDS: - ``interpolation_type`` - 'linear', 'clough' (CloughTocher2D), 'spline' 'linear' will perform linear interpolation - The option 'clough' will interpolate by using a piecewise cubic interpolating - Bezier polynomial on each triangle, using a Clough-Tocher scheme. - The interpolant is guaranteed to be continuously differentiable. - The gradients of the interpolant are chosen so that the curvature of the - interpolating surface is approximatively minimized. + The option 'clough' will interpolate by using a piecewise cubic + interpolating Bezier polynomial on each triangle, using a + Clough-Tocher scheme. The interpolant is guaranteed to be + continuously differentiable. The gradients of the interpolant + are chosen so that the curvature of the interpolating surface is + approximatively minimized. The option 'spline' interpolates using a bivariate B-spline. @@ -62,59 +62,46 @@ def list_plot3d(v, interpolation_type='default', texture="automatic", point_list EXAMPLES: - We plot a matrix that illustrates summation modulo `n`. - - :: + We plot a matrix that illustrates summation modulo `n`:: - sage: n = 5; list_plot3d(matrix(RDF, n, [(i+j)%n for i in [1..n] for j in [1..n]])) + sage: n = 5 + sage: list_plot3d(matrix(RDF, n, [(i+j)%n for i in [1..n] for j in [1..n]])) Graphics3d Object - We plot a matrix of values of sin. - - :: + We plot a matrix of values of ``sin``:: sage: pi = float(pi) sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) - sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object - Though it doesn't change the shape of the graph, increasing - num_points can increase the clarity of the graph. - - :: + Though it does not change the shape of the graph, increasing + num_points can increase the clarity of the graph:: - sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1, 1, 1/3], num_points=40) + sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3], num_points=40) Graphics3d Object - We can change the interpolation type. - - :: + We can change the interpolation type:: sage: import warnings sage: warnings.simplefilter('ignore', UserWarning) - sage: list_plot3d(m, texture='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object - We can make this look better by increasing the number of samples. - - :: + We can make this look better by increasing the number of samples:: - sage: list_plot3d(m, texture='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3], num_points=40) + sage: list_plot3d(m, color='yellow', interpolation_type='clough', frame_aspect_ratio=[1, 1, 1/3], num_points=40) Graphics3d Object - Let's try a spline. + Let us try a spline:: - :: - - sage: list_plot3d(m, texture='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object - That spline doesn't capture the oscillation very well; let's try a - higher degree spline. + That spline does not capture the oscillation very well; let's try a + higher degree spline:: - :: - - sage: list_plot3d(m, texture='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='spline', degree=5, frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object We plot a list of lists:: @@ -123,15 +110,13 @@ def list_plot3d(v, interpolation_type='default', texture="automatic", point_list We plot a list of points. As a first example we can extract the (x,y,z) coordinates from the above example and make a list plot - out of it. By default we do linear interpolation. - - :: + out of it. By default we do linear interpolation:: sage: l = [] sage: for i in range(6): ....: for j in range(6): ....: l.append((float(i*pi/5), float(j*pi/5), m[i, j])) - sage: list_plot3d(l, texture='yellow') + sage: list_plot3d(l, color='red') Graphics3d Object Note that the points do not have to be regularly sampled. For example:: @@ -140,7 +125,7 @@ def list_plot3d(v, interpolation_type='default', texture="automatic", point_list sage: for i in range(-5, 5): ....: for j in range(-5, 5): ....: l.append((normalvariate(0, 1), normalvariate(0, 1), normalvariate(0, 1))) - sage: L = list_plot3d(l, interpolation_type='clough', texture='yellow', num_points=100) + sage: L = list_plot3d(l, interpolation_type='clough', color='orange', num_points=100) sage: L Graphics3d Object @@ -156,24 +141,21 @@ def list_plot3d(v, interpolation_type='default', texture="automatic", point_list sage: list_plot3d([]) Graphics3d Object - :: - sage: list_plot3d([(2, 3, 4)]) Graphics3d Object - :: - sage: list_plot3d([(0, 0, 1), (2, 3, 4)]) Graphics3d Object However, if two points are given with the same x,y coordinates but different z coordinates, an exception will be raised:: - sage: pts =[(-4/5, -2/5, -2/5), (-4/5, -2/5, 2/5), (-4/5, 2/5, -2/5), (-4/5, 2/5, 2/5), (-2/5, -4/5, -2/5), (-2/5, -4/5, 2/5), (-2/5, -2/5, -4/5), (-2/5, -2/5, 4/5), (-2/5, 2/5, -4/5), (-2/5, 2/5, 4/5), (-2/5, 4/5, -2/5), (-2/5, 4/5, 2/5), (2/5, -4/5, -2/5), (2/5, -4/5, 2/5), (2/5, -2/5, -4/5), (2/5, -2/5, 4/5), (2/5, 2/5, -4/5), (2/5, 2/5, 4/5), (2/5, 4/5, -2/5), (2/5, 4/5, 2/5), (4/5, -2/5, -2/5), (4/5, -2/5, 2/5), (4/5, 2/5, -2/5), (4/5, 2/5, 2/5)] + sage: pts = [(-4/5, -2/5, -2/5), (-4/5, -2/5, 2/5), (-4/5, 2/5, -2/5), (-4/5, 2/5, 2/5), (-2/5, -4/5, -2/5), (-2/5, -4/5, 2/5), (-2/5, -2/5, -4/5), (-2/5, -2/5, 4/5), (-2/5, 2/5, -4/5), (-2/5, 2/5, 4/5), (-2/5, 4/5, -2/5), (-2/5, 4/5, 2/5), (2/5, -4/5, -2/5), (2/5, -4/5, 2/5), (2/5, -2/5, -4/5), (2/5, -2/5, 4/5), (2/5, 2/5, -4/5), (2/5, 2/5, 4/5), (2/5, 4/5, -2/5), (2/5, 4/5, 2/5), (4/5, -2/5, -2/5), (4/5, -2/5, 2/5), (4/5, 2/5, -2/5), (4/5, 2/5, 2/5)] sage: show(list_plot3d(pts, interpolation_type='clough')) Traceback (most recent call last): ... - ValueError: Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this. + ValueError: points with same x,y coordinates and different + z coordinates were given. Interpolation cannot handle this. Additionally we need at least 3 points to do the interpolation:: @@ -181,26 +163,37 @@ def list_plot3d(v, interpolation_type='default', texture="automatic", point_list sage: show(list_plot3d(mat, interpolation_type='clough')) Traceback (most recent call last): ... - ValueError: We need at least 3 points to perform the interpolation + ValueError: we need at least 3 points to perform the interpolation + + TESTS:: + + sage: P = list_plot3d([(0, 0, 1), (2, 3, 4)], texture='tomato') + doctest:warning...: + DeprecationWarning: please use 'color' instead of 'texture' + See https://trac.sagemath.org/27084 for details. """ import numpy - if texture == "automatic": - texture = "lightblue" + if 'texture' in kwds: + deprecation(27084, "please use 'color' instead of 'texture'") + txtr = kwds.pop('texture') + if txtr == "automatic": + txtr = "lightblue" + kwds['color'] = txtr if is_Matrix(v): - if interpolation_type == 'default' or interpolation_type == 'linear' and 'num_points' not in kwds: - return list_plot3d_matrix(v, texture=texture, **kwds) + if (interpolation_type == 'default' or + interpolation_type == 'linear' and 'num_points' not in kwds): + return list_plot3d_matrix(v, **kwds) else: - l = [] - for i in range(v.nrows()): - for j in range(v.ncols()): - l.append((i, j, v[i, j])) - return list_plot3d_tuples(l, interpolation_type, texture, **kwds) + data = [(i, j, v[i, j]) + for i in range(v.nrows()) + for j in range(v.ncols())] + return list_plot3d_tuples(data, interpolation_type, **kwds) if isinstance(v, numpy.ndarray): - return list_plot3d(matrix(v), interpolation_type, texture, **kwds) + return list_plot3d(matrix(v), interpolation_type, **kwds) if isinstance(v, list): - if len(v) == 0: + if not v: # return empty 3d graphic from .base import Graphics3d return Graphics3d() @@ -213,27 +206,26 @@ def list_plot3d(v, interpolation_type='default', texture="automatic", point_list from .shapes2 import line3d return line3d(v, **kwds) elif isinstance(v[0], tuple) or point_list and len(v[0]) == 3: - return list_plot3d_tuples(v, interpolation_type, texture=texture, **kwds) + return list_plot3d_tuples(v, interpolation_type, **kwds) else: - return list_plot3d_array_of_arrays(v, interpolation_type, texture, **kwds) + return list_plot3d_array_of_arrays(v, interpolation_type, **kwds) raise TypeError("v must be a matrix or list") -def list_plot3d_matrix(m, texture, **kwds): +def list_plot3d_matrix(m, **kwds): """ A 3-dimensional plot of a surface defined by a matrix ``M`` - defining points in 3-dimensional space. See :func:`list_plot3d` - for full details. + defining points in 3-dimensional space. + + See :func:`list_plot3d` for full details. INPUT: - - ``M`` - a matrix - - ``texture`` - (default: "automatic", a solid light blue) + - ``M`` -- a matrix OPTIONAL KEYWORDS: - - ``**kwds`` - all other arguments are passed to the - surface function + - ``**kwds`` - all other arguments are passed to the surface function OUTPUT: a 3d plot @@ -241,7 +233,8 @@ def list_plot3d_matrix(m, texture, **kwds): We plot a matrix that illustrates summation modulo `n`:: - sage: n = 5; list_plot3d(matrix(RDF, n, [(i+j)%n for i in [1..n] for j in [1..n]])) # indirect doctest + sage: n = 5 + sage: list_plot3d(matrix(RDF, n, [(i+j)%n for i in [1..n] for j in [1..n]])) # indirect doctest Graphics3d Object The interpolation type for matrices is 'linear'; for other types @@ -251,9 +244,9 @@ def list_plot3d_matrix(m, texture, **kwds): sage: pi = float(pi) sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) - sage: list_plot3d(m, texture='yellow', frame_aspect_ratio=[1, 1, 1/3]) # indirect doctest + sage: list_plot3d(m, color='yellow', frame_aspect_ratio=[1, 1, 1/3]) # indirect doctest Graphics3d Object - sage: list_plot3d(m, texture='yellow', interpolation_type='linear') # indirect doctest + sage: list_plot3d(m, color='yellow', interpolation_type='linear') # indirect doctest Graphics3d Object Here is a colored example, using a colormap and a coloring function @@ -271,28 +264,31 @@ def list_plot3d_matrix(m, texture, **kwds): cm = colormaps.rainbow cf = lambda x, y: ((2*(x-y)/20)**2) % 1 expl = list_plot3d(matrix(RDF,20,20,[cos(pi*(i+j)/20) for i in range(1,21) for j in range(1,21)]),color=(cf,cm)) - sphinx_plot(expl) + sphinx_plot(expl) """ from .parametric_surface import ParametricSurface - f = lambda i,j: (i, j, float(m[int(i), int(j)])) + + def f(i, j): + return (i, j, float(m[int(i), int(j)])) G = ParametricSurface(f, (list(range(m.nrows())), list(range(m.ncols()))), - texture=texture, **kwds) + **kwds) G._set_extra_kwds(kwds) return G -def list_plot3d_array_of_arrays(v, interpolation_type, texture, **kwds): +def list_plot3d_array_of_arrays(v, interpolation_type, **kwds): """ A 3-dimensional plot of a surface defined by a list of lists ``v`` - defining points in 3-dimensional space. This is done by making the - list of lists into a matrix and passing back to :func:`list_plot3d`. - See :func:`list_plot3d` for full details. + defining points in 3-dimensional space. + + This is done by making the list of lists into a matrix and passing + back to :func:`list_plot3d`. See :func:`list_plot3d` for full + details. INPUT: - ``v`` - a list of lists, all the same length - ``interpolation_type`` - (default: 'linear') - - ``texture`` - (default: "automatic", a solid light blue) OPTIONAL KEYWORDS: @@ -317,11 +313,12 @@ def list_plot3d_array_of_arrays(v, interpolation_type, texture, **kwds): sage: show(list_plot3d([[1, 1, 1, 1], [1, 2, 1, 2], [1, 1, 3, 1], [1, 2, 1, 4]], interpolation_type='spline')) """ m = matrix(RDF, len(v), len(v[0]), v) - G = list_plot3d(m, interpolation_type, texture, **kwds) + G = list_plot3d(m, interpolation_type, **kwds) G._set_extra_kwds(kwds) return G -def list_plot3d_tuples(v, interpolation_type, texture, **kwds): + +def list_plot3d_tuples(v, interpolation_type, **kwds): r""" A 3-dimensional plot of a surface defined by the list `v` of points in 3-dimensional space. @@ -333,14 +330,14 @@ def list_plot3d_tuples(v, interpolation_type, texture, **kwds): - a matrix - This will be if using an interpolation type other than 'linear', or if using - ``num_points`` with 'linear'; otherwise see :func:`list_plot3d_matrix`. + This will be if using an interpolation type other than + 'linear', or if using ``num_points`` with 'linear'; otherwise + see :func:`list_plot3d_matrix`. - a list of 3-tuples - - a list of lists (all of the same length, under same conditions as a matrix) - - - ``texture`` - (default: "automatic", a solid light blue) + - a list of lists (all of the same length, under same conditions + as a matrix) OPTIONAL KEYWORDS: @@ -348,9 +345,10 @@ def list_plot3d_tuples(v, interpolation_type, texture, **kwds): 'linear' will perform linear interpolation - The option 'clough' will interpolate by using a piecewise cubic interpolating - Bezier polynomial on each triangle, using a Clough-Tocher scheme. - The interpolant is guaranteed to be continuously differentiable. + The option 'clough' will interpolate by using a piecewise cubic + interpolating Bezier polynomial on each triangle, using a + Clough-Tocher scheme. The interpolant is guaranteed to be + continuously differentiable. The option 'spline' interpolates using a bivariate B-spline. @@ -376,16 +374,17 @@ def list_plot3d_tuples(v, interpolation_type, texture, **kwds): EXAMPLES: - All of these use this function; see :func:`list_plot3d` for other list plots:: + All of these use this function; see :func:`list_plot3d` for other + list plots:: sage: pi = float(pi) sage: m = matrix(RDF, 6, [sin(i^2 + j^2) for i in [0,pi/5,..,pi] for j in [0,pi/5,..,pi]]) - sage: list_plot3d(m, texture='yellow', interpolation_type='linear', num_points=5) # indirect doctest + sage: list_plot3d(m, color='yellow', interpolation_type='linear', num_points=5) # indirect doctest Graphics3d Object :: - sage: list_plot3d(m, texture='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) + sage: list_plot3d(m, color='yellow', interpolation_type='spline', frame_aspect_ratio=[1, 1, 1/3]) Graphics3d Object :: @@ -394,7 +393,7 @@ def list_plot3d_tuples(v, interpolation_type, texture, **kwds): :: - sage: list_plot3d([(1, 2, 3), (0, 1, 3), (2, 1, 4), (1, 0, -2)], texture='yellow', num_points=50) # long time + sage: list_plot3d([(1, 2, 3), (0, 1, 3), (2, 1, 4), (1, 0, -2)], color='yellow', num_points=50) # long time Graphics3d Object """ from matplotlib import tri @@ -403,8 +402,9 @@ def list_plot3d_tuples(v, interpolation_type, texture, **kwds): from scipy import interpolate from .plot3d import plot3d - if len(v)<3: - raise ValueError("We need at least 3 points to perform the interpolation") + if len(v) < 3: + raise ValueError("we need at least 3 points to perform the " + "interpolation") x = [float(p[0]) for p in v] y = [float(p[1]) for p in v] @@ -415,11 +415,10 @@ def list_plot3d_tuples(v, interpolation_type, texture, **kwds): # correlation of the x- and y-coordinates and add small random # noise to avoid the problem if needed. corr_matrix = numpy.corrcoef(x, y) - if corr_matrix[0, 1] > 0.9 or corr_matrix[0, 1] < -0.9: + if not (-0.9 <= corr_matrix[0, 1] <= 0.9): ep = float(.000001) - x = [float(p[0]) + random()*ep for p in v] - y = [float(p[1]) + random()*ep for p in v] - + x = [float(p[0]) + random() * ep for p in v] + y = [float(p[1]) + random() * ep for p in v] # If the list of data points has two points with the exact same # (x,y)-coordinate but different z-coordinates, then we sometimes @@ -431,10 +430,12 @@ def list_plot3d_tuples(v, interpolation_type, texture, **kwds): drop_list = [] nb_points = len(x) for i in range(nb_points): - for j in range(i+1, nb_points): + for j in range(i + 1, nb_points): if x[i] == x[j] and y[i] == y[j]: if z[i] != z[j]: - raise ValueError("Two points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this.") + raise ValueError("points with same x,y coordinates" + " and different z coordinates were" + " given. Interpolation cannot handle this.") elif z[i] == z[j]: drop_list.append(j) x = [x[i] for i in range(nb_points) if i not in drop_list] @@ -446,32 +447,38 @@ def list_plot3d_tuples(v, interpolation_type, texture, **kwds): ymin = float(min(y)) ymax = float(max(y)) - num_points = kwds['num_points'] if 'num_points' in kwds else int(4*numpy.sqrt(len(x))) - #arbitrary choice - assuming more or less a nxn grid of points - # x should have n^2 entries. We sample 4 times that many points. + num_points = kwds.get('num_points', int(4 * numpy.sqrt(len(x)))) + # arbitrary choice - assuming more or less a n x n grid of points + # x should have n^2 entries. We sample 4 times that many points. if interpolation_type == 'linear': T = tri.Triangulation(x, y) f = tri.LinearTriInterpolator(T, z) j = numpy.complex(0, 1) from .parametric_surface import ParametricSurface + def g(x, y): z = f(x, y) return (x, y, z) - G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points*j]), list(numpy.r_[ymin:ymax:num_points*j])), texture=texture, **kwds) + G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points * j]), + list(numpy.r_[ymin:ymax:num_points * j])), + **kwds) G._set_extra_kwds(kwds) return G - if interpolation_type == 'clough' or interpolation_type =='default': + if interpolation_type == 'clough' or interpolation_type == 'default': - points=[[x[i],y[i]] for i in range(len(x))] + points = [[x[i], y[i]] for i in range(len(x))] j = numpy.complex(0, 1) - f = interpolate.CloughTocher2DInterpolator(points,z) + f = interpolate.CloughTocher2DInterpolator(points, z) from .parametric_surface import ParametricSurface + def g(x, y): z = f([x, y]) return (x, y, z) - G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points*j]), list(numpy.r_[ymin:ymax:num_points*j])), texture=texture, **kwds) + G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points * j]), + list(numpy.r_[ymin:ymax:num_points * j])), + **kwds) G._set_extra_kwds(kwds) return G @@ -481,7 +488,11 @@ def g(x, y): if 'degree' in kwds: kx = kwds['degree'] ky = kwds['degree'] - s = kwds['smoothing'] if 'smoothing' in kwds else len(x)-numpy.sqrt(2*len(x)) - s = interpolate.bisplrep(x, y, z, [int(1)]*len(x), xmin, xmax, ymin, ymax, kx=kx, ky=ky, s=s) - f = lambda x,y: interpolate.bisplev(x, y, s) - return plot3d(f, (xmin, xmax), (ymin, ymax), texture=texture, plot_points=[num_points, num_points], **kwds) + s = kwds.get('smoothing', len(x) - numpy.sqrt(2 * len(x))) + s = interpolate.bisplrep(x, y, z, [int(1)] * len(x), xmin, xmax, + ymin, ymax, kx=kx, ky=ky, s=s) + + def f(x, y): + return interpolate.bisplev(x, y, s) + return plot3d(f, (xmin, xmax), (ymin, ymax), + plot_points=[num_points, num_points], **kwds) diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index b6e4e024fa4..8adbca5e3ce 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -1004,7 +1004,8 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: @interact ....: def _(which_plot=[A,B,C,D,E]): ....: show(which_plot) - ... + Interactive function with 1 widget + which_plot: Dropdown(description=u'which_plot', options=(Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object), value=Graphics3d Object) Now plot a function:: @@ -1017,7 +1018,8 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: @interact ....: def _(which_plot=[F, G, H, I, J]): ....: show(which_plot) - ... + Interactive function with 1 widget + which_plot: Dropdown(description=u'which_plot', options=(Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object), value=Graphics3d Object) TESTS: diff --git a/src/sage/plot/plot3d/revolution_plot3d.py b/src/sage/plot/plot3d/revolution_plot3d.py index 15ea91719cb..39f24cc4fd7 100644 --- a/src/sage/plot/plot3d/revolution_plot3d.py +++ b/src/sage/plot/plot3d/revolution_plot3d.py @@ -231,7 +231,6 @@ def cf(u, phi): return float(2 * u / pi) % 1 phirange = (phi, 0, 2 * pi) elif len(phirange) == 3: phi = phirange[0] - pass else: phirange = (phi, phirange[0], phirange[1]) diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index ae7f22b2890..2e836feb5d7 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -6,6 +6,7 @@ - David Kohel & Gabriele Nebe (2007): First created - Simon Brandhorst (2018): various bugfixes and printing +- Simon Brandhorst (2018): enumeration of genera """ #***************************************************************************** # Copyright (C) 2007 David Kohel @@ -22,12 +23,289 @@ from sage.arith.all import LCM from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix -from sage.rings.integer_ring import IntegerRing +from sage.rings.integer_ring import IntegerRing, ZZ from sage.rings.rational_field import RationalField, QQ from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_constructor import FiniteField +from copy import copy, deepcopy from sage.misc.misc import verbose -import copy + +def genera(sig_pair, determinant, max_scale=None, even=False): + r""" + Return a list of all global genera with the given conditions. + + Here a genus is called global if it is non-empty. + + INPUT: + + - ``sig_pair`` -- a pair of non-negative integers giving the signature + + - ``determinant`` -- an integer; the sign is ignored + + - ``max_scale`` -- (default: ``None``) an integer; the maximum scale of a + jordan block + + - ``even`` -- boolean (default: ``False``) + + OUTPUT: + + A list of all (non-empty) global genera with the given conditions. + + EXAMPLES:: + + sage: QuadraticForm.genera((4,0), 125, even=True) + [Genus of + None + Signature: (4, 0) + Genus symbol at 2: 1^-4 + Genus symbol at 5: 1^1 5^3, Genus of + None + Signature: (4, 0) + Genus symbol at 2: 1^-4 + Genus symbol at 5: 1^-2 5^1 25^-1, Genus of + None + Signature: (4, 0) + Genus symbol at 2: 1^-4 + Genus symbol at 5: 1^2 5^1 25^1, Genus of + None + Signature: (4, 0) + Genus symbol at 2: 1^-4 + Genus symbol at 5: 1^3 125^1] + """ + from sage.misc.mrange import mrange_iter + # input checks + ZZ = IntegerRing() + determinant = ZZ(determinant) + sig_pair = (ZZ(sig_pair[0]), ZZ(sig_pair[1])) + even = bool(even) + if not all(s >= 0 for s in sig_pair): + raise ValueError("the signature vector must be a pair of non negative integers.") + if max_scale is None: + max_scale = determinant + else: + max_scale = ZZ(max_scale) + rank = sig_pair[0] + sig_pair[1] + genera = [] + local_symbols = [] + # every global genus has a 2-adic symbol + if determinant % 2 != 0: + local_symbols.append(_local_genera(2, rank, 0, 0, even=even)) + # collect the p-adic symbols + for pn in determinant.factor(): + p = pn[0] + det_val = pn[1] + mscale_p = max_scale.valuation(p) + local_symbol_p = _local_genera(p, rank, det_val, mscale_p, even) + local_symbols.append(local_symbol_p) + # take the cartesian product of the collection of all possible + # local genus symbols one for each prime + # and check which combinations produce a global genus + # TODO: + # we are overcounting. Find a more + # clever way to directly match the symbols for different primes. + for g in mrange_iter(local_symbols): + # create a Genus from a list of local symbols + G = GenusSymbol_global_ring(sig_pair, g, representative=None, check=True) + # discard the empty genera + if is_GlobalGenus(G): + genera.append(G) + # render the output deterministic for testing + genera.sort(key=lambda x: [s.symbol_tuple_list() for s in x.local_symbols()]) + return(genera) + +def _local_genera(p, rank, det_val, max_scale, even): + r""" + Return all `p`-adic genera with the given conditions. + + This is a helper function for :meth:`genera`. + No input checks are done. + + INPUT: + + - ``p`` -- a prime number + + - ``rank`` -- the rank of this genus + + - ``det_val`` -- valuation of the determinant at p + + - ``max_scale`` -- an integer the maximal scale of a jordan block + + - ``even`` -- ``bool``; is igored if `p` is not `2` + + EXAMPLES:: + + sage: from sage.quadratic_forms.genera.genus import _local_genera + sage: _local_genera(2,3,1,2,False) + [Genus symbol at 2: 1^-2 [2^1]_1, + Genus symbol at 2: 1^2 [2^1]_1, + Genus symbol at 2: 1^2 [2^1]_7, + Genus symbol at 2: [1^2 2^1]_3, + Genus symbol at 2: 1^-2 [2^1]_7, + Genus symbol at 2: [1^-2 2^1]_7, + Genus symbol at 2: [1^-2 2^1]_1, + Genus symbol at 2: [1^2 2^1]_7, + Genus symbol at 2: [1^2 2^1]_5, + Genus symbol at 2: [1^-2 2^1]_3, + Genus symbol at 2: [1^-2 2^1]_5, + Genus symbol at 2: [1^2 2^1]_1] + + Setting a maximum scale:: + + sage: _local_genera(5, 2, 2, 1, True) + [Genus symbol at 5: 5^-2, Genus symbol at 5: 5^2] + sage: _local_genera(5, 2, 2, 2, True) + [Genus symbol at 5: 1^-1 25^-1, + Genus symbol at 5: 1^1 25^-1, + Genus symbol at 5: 1^-1 25^1, + Genus symbol at 5: 1^1 25^1, + Genus symbol at 5: 5^-2, + Genus symbol at 5: 5^2] + """ + from sage.misc.mrange import cantor_product + from sage.combinat.integer_lists.invlex import IntegerListsLex + scales_rks = [] # contains possibilities for scales and ranks + for rkseq in IntegerListsLex(rank, length=max_scale+1): # rank sequences + # sum(rkseq) = rank + # len(rkseq) = max_scale + 1 + # now assure that we get the right determinant + d = 0 + pgensymbol = [] + for i in range(max_scale + 1): + d += i * rkseq[i] + # blocks of rank 0 are omitted + if rkseq[i] != 0: + pgensymbol.append([i, rkseq[i], 0]) + if d == det_val: + scales_rks.append(pgensymbol) + # add possible determinant square classes + symbols = [] + if p != 2: + for g in scales_rks: + n = len(g) + for v in cantor_product([-1, 1], repeat=n): + g1 = deepcopy(g) + for k in range(n): + g1[k][2] = v[k] + g1 = Genus_Symbol_p_adic_ring(p, g1) + symbols.append(g1) + # for p == 2 we have to include determinant, even/odd, oddity + # further restrictions apply and are defered to _blocks + # (brute force sieving is too slow) + # TODO: If this is too slow, enumerate only the canonical symbols. + # as a drawback one has to reconstruct the symbol from the canonical symbol + # this is more work for the programmer + if p == 2: + for g in scales_rks: + n = len(g) + poss_blocks = [] + for b in g: + b += [0, 0] + poss_blocks.append(_blocks(b, even_only=(even and b[0]==0))) + for g1 in cantor_product(*poss_blocks): + g1 = list(g1) + if is_2_adic_genus(g1): + g1 = Genus_Symbol_p_adic_ring(p, g1) + # some of our symbols have the same canonical symbol + # thus they are equivalent - we want only one in + # each equivalence class + if not g1 in symbols: + symbols.append(g1) + return(symbols) + + +def _blocks(b, even_only=False): + r""" + Return all viable `2`-adic jordan blocks with rank and scale given by ``b`` + + This is a helper function for :meth:`_local_genera`. + It is based on the existence conditions for a modular `2`-adic genus symbol. + + INPUT: + + - ``b`` -- a list of `5` non-negative integers the first two are kept + and all possibilities for the remaining `3` are enumerated + + - ``even_only`` -- bool (default: ``True``) if set, the blocks are even + + EXAMPLES:: + + sage: from sage.quadratic_forms.genera.genus import _blocks + sage: _blocks([15, 2, 0, 0, 0]) + [[15, 2, 3, 0, 0], + [15, 2, 7, 0, 0], + [15, 2, 1, 1, 2], + [15, 2, 5, 1, 6], + [15, 2, 1, 1, 6], + [15, 2, 5, 1, 2], + [15, 2, 7, 1, 0], + [15, 2, 3, 1, 4]] + """ + blocks = [] + rk = b[1] + # recall: 2-genus_symbol is [scale, rank, det, even/odd, oddity] + if rk == 1 and not even_only: + for det in [1, 3, 5, 7]: + b1 = copy(b) + b1[2] = det + b1[3] = 1 + b1[4] = det + blocks.append(b1) + elif rk == 2: + b1 = copy(b) + # even case + b1[3] = 0 + b1[4] = 0 + b1[2] = 3 + blocks.append(b1) + b1 = copy(b1) + b1[2] = 7 + blocks.append(b1) + # odd case + if not even_only: + # format (det, oddity) + for s in [(1,2), (5,6), (1,6), (5,2), (7,0), (3,4)]: + b1 = copy(b) + b1[2] = s[0] + b1[3] = 1 + b1[4] = s[1] + blocks.append(b1) + elif rk % 2 == 0: + # the even case has even rank + b1 = copy(b) + b1[3] = 0 + b1[4] = 0 + d = (-1)**(rk//2) % 8 + for det in [d, d * (-3) % 8]: + b1 = copy(b1) + b1[2] = det + blocks.append(b1) + # odd case + if not even_only: + for s in [(1,2), (5,6), (1,6), (5,2), (7,0), (3,4)]: + b1 = copy(b) + b1[2] = s[0]*(-1)**(rk//2 -1) % 8 + b1[3] = 1 + b1[4] = s[1] + blocks.append(b1) + for s in [(1,4), (5,0)]: + b1 = copy(b) + b1[2] = s[0]*(-1)**(rk//2 - 2) % 8 + b1[3] = 1 + b1[4] = s[1] + blocks.append(b1) + elif rk % 2 == 1 and not even_only: + # odd case + for t in [1, 3, 5, 7]: + d = (-1)**(rk//2)*t % 8 + for det in [d, -3*d % 8]: + b1 = copy(b) + b1[2] = det + b1[3] = 1 + b1[4] = t + blocks.append(b1) + # convert ints to integers + blocks = [[ZZ(i) for i in b] for b in blocks] + return blocks def Genus(A, factored_determinant=None): r""" @@ -462,7 +740,7 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): Add an example where sign walking occurs! """ # Protect the input from unwanted modification - genus_symbol_quintuple_list = copy.deepcopy(genus_symbol_quintuple_list) + genus_symbol_quintuple_list = deepcopy(genus_symbol_quintuple_list) canonical_symbol = genus_symbol_quintuple_list # Canonical determinants: for i in range(len(genus_symbol_quintuple_list)): @@ -1401,7 +1679,7 @@ def symbol_tuple_list(self): sage: type(G2.symbol_tuple_list()) <... 'list'> """ - return copy.deepcopy(self._symbol) + return deepcopy(self._symbol) def number_of_blocks(self): r""" @@ -2006,7 +2284,7 @@ def local_symbols(self): [Genus symbol at 2: [2^-2 4^1 8^1]_4, Genus symbol at 3: 1^-3 3^-1] """ - return copy.deepcopy(self._local_symbols) + return deepcopy(self._local_symbols) def _gram_from_jordan_block(p, block, discr_form=False): diff --git a/src/sage/quadratic_forms/genera/normal_form.py b/src/sage/quadratic_forms/genera/normal_form.py index da3bc678e4c..bd17cc8aaf5 100644 --- a/src/sage/quadratic_forms/genera/normal_form.py +++ b/src/sage/quadratic_forms/genera/normal_form.py @@ -266,7 +266,7 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): return G.parent().zero(), G.parent().zero() # the transformation matrix is called B B = Matrix.identity(R, n) - if(p == 2): + if p == 2: D, B = _jordan_2_adic(G) else: D, B = _jordan_odd_adic(G) @@ -274,7 +274,7 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): B = B1 * B # we have reached a normal form for p != 2 # for p == 2 extra work is necessary - if p==2: + if p == 2: D, B1 = _two_adic_normal_forms(D, partial=partial) B = B1 * B nondeg = B * nondeg @@ -282,12 +282,13 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): D = Matrix.block_diagonal([D, Matrix.zero(kernel.nrows())]) if debug: assert B.determinant().valuation() == 0 # B is invertible! - if p==2: + if p == 2: assert B*G*B.T == Matrix.block_diagonal(collect_small_blocks(D)) else: assert B*G*B.T == Matrix.diagonal(D.diagonal()) return D/p**d, B + def _find_min_p(G, cnt, lower_bound=0): r""" Find smallest valuation below and right from ``cnt`` prefering the diagonal. @@ -716,7 +717,7 @@ def _jordan_2_adic(G): eqn_mat = D[cnt:cnt+2, cnt:cnt+2].list() eqn_mat = Matrix(R, 2, 2, [e // content for e in eqn_mat]) # calculate the inverse without using division - inv = eqn_mat.adjoint() * eqn_mat.det().inverse_of_unit() + inv = eqn_mat.adjugate() * eqn_mat.det().inverse_of_unit() B1 = B[cnt:cnt+2, :] B2 = D[cnt+2:, cnt:cnt+2] * inv for i in range(B2.nrows()): diff --git a/src/sage/quadratic_forms/quadratic_form.py b/src/sage/quadratic_forms/quadratic_form.py index 8a3e57fb3ee..3b60a467c33 100644 --- a/src/sage/quadratic_forms/quadratic_form.py +++ b/src/sage/quadratic_forms/quadratic_form.py @@ -34,7 +34,7 @@ from sage.structure.element import is_Vector from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.modules.free_module_element import vector - +from sage.quadratic_forms.genera.genus import genera from sage.quadratic_forms.quadratic_form__evaluate import QFEvaluateVector, QFEvaluateMatrix @@ -373,7 +373,7 @@ class QuadraticForm(SageObject): ## Routines for solving equations of the form Q(x) = c. from sage.quadratic_forms.qfsolve import solve - + def __init__(self, R, n=None, entries=None, unsafe_initialization=False, number_of_automorphisms=None, determinant=None): """ @@ -891,7 +891,7 @@ def __call__(self, v): if is_Matrix(v): ## Check that v has the correct number of rows if v.nrows() != n: - raise TypeError("Oops! The matrix must have " + str(n) + " rows. =(") + raise TypeError("the matrix must have {} rows".format(n)) ## Create the new quadratic form m = v.ncols() @@ -901,14 +901,14 @@ def __call__(self, v): elif (is_Vector(v) or isinstance(v, (list, tuple))): ## Check the vector/tuple/list has the correct length if not (len(v) == n): - raise TypeError("Oops! Your vector needs to have length " + str(n) + " .") + raise TypeError("your vector needs to have length {}".format(n)) ## TO DO: Check that the elements can be coerced into the base ring of Q -- on first elt. if len(v) > 0: try: - x = self.base_ring()(v[0]) + self.base_ring()(v[0]) except Exception: - raise TypeError("Oops! Your vector is not coercible to the base ring of the quadratic form... =(") + raise TypeError("your vector is not coercible to the base ring of the quadratic form") ## Attempt to evaluate Q[v] return QFEvaluateVector(self, v) @@ -970,7 +970,7 @@ def _is_even_symmetric_matrix_(self, A, R=None): try: for i in range(n): for j in range(i, n): - x = R(A[i,j]) + R(A[i,j]) except Exception: return False @@ -1267,7 +1267,7 @@ def adjoint_primitive(self): [ * 1 ] """ - return QuadraticForm(self.Hessian_matrix().adjoint()).primitive() + return QuadraticForm(self.Hessian_matrix().adjoint_classical()).primitive() def dim(self): """ @@ -1582,6 +1582,7 @@ def bilinear_map(self,v,w): raise TypeError("not defined for rings of characteristic 2") return (self(v+w) - self(v) - self(w))/2 + genera = staticmethod(genera) ## ===================================================================================================== diff --git a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py index b52b9e915d6..977126e99de 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py +++ b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py @@ -360,7 +360,7 @@ def signature(self): an integer - EXAMPLES: + EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,0,0,-4,3,11,3]) sage: Q.signature() @@ -873,7 +873,7 @@ def compute_definiteness_string_by_determinants(self): string describing the definiteness - EXAMPLES: + EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1]) sage: Q.compute_definiteness_string_by_determinants() diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index dc87669dcd6..6d4dff71aa7 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -137,9 +137,9 @@ def adjoint(self): """ if is_odd(self.dim()): - return QuadraticForm(self.matrix().adjoint()*2) + return QuadraticForm(self.matrix().adjoint_classical()*2) else: - return QuadraticForm(self.matrix().adjoint()) + return QuadraticForm(self.matrix().adjoint_classical()) def antiadjoint(self): diff --git a/src/sage/quadratic_forms/ternary.pyx b/src/sage/quadratic_forms/ternary.pyx index 9d756315739..f5095198f0f 100644 --- a/src/sage/quadratic_forms/ternary.pyx +++ b/src/sage/quadratic_forms/ternary.pyx @@ -967,7 +967,7 @@ def _find_p_neighbor_from_vec(a, b, c, r, s, t, p, v, mat = False): Reference: Gonzalo Tornaria's Thesis, Thrm 3.5, p34. - EXAMPLES: + EXAMPLES:: sage: from sage.quadratic_forms.ternary import _find_p_neighbor_from_vec sage: Q = TernaryQF([1, 3, 3, -2, 0, -1]) diff --git a/src/sage/quadratic_forms/ternary_qf.py b/src/sage/quadratic_forms/ternary_qf.py index 09b9cccb218..d1e8ced96ff 100644 --- a/src/sage/quadratic_forms/ternary_qf.py +++ b/src/sage/quadratic_forms/ternary_qf.py @@ -623,8 +623,9 @@ def __eq__(self,right): def adjoint(self): """ - Returns the adjoint form associated to the given ternary quadratic form. - That is, the Hessian matrix of the adjoint form is twice the adjoint matrix of the Hessian matrix of the given form. + Returns the adjoint form associated to the given ternary quadratic + form. That is, the Hessian matrix of the adjoint form is twice the + classical adjoint matrix of the Hessian matrix of the given form. EXAMPLES:: @@ -633,7 +634,7 @@ def adjoint(self): Ternary quadratic form with integer coefficients: [68 68 3] [0 0 -68] - sage: Q.adjoint().matrix() == 2*Q.matrix().adjoint() + sage: Q.adjoint().matrix() == 2*Q.matrix().adjoint_classical() True """ diff --git a/src/sage/quivers/algebra.py b/src/sage/quivers/algebra.py index 6cf7075345d..5fe6affaaea 100644 --- a/src/sage/quivers/algebra.py +++ b/src/sage/quivers/algebra.py @@ -500,7 +500,7 @@ def quiver(self): - :class:`DiGraph`, the quiver of the algebra - EXAMPLES: + EXAMPLES:: sage: P = DiGraph({1:{2:['a', 'b']}}).path_semigroup() sage: A = P.algebra(GF(3)) @@ -526,7 +526,7 @@ def semigroup(self): - the path semigroup from which ``self`` was formed (a partial semigroup) - EXAMPLES: + EXAMPLES:: sage: P = DiGraph({1:{2:['a', 'b']}}).path_semigroup() sage: A = P.algebra(GF(3)) diff --git a/src/sage/quivers/algebra_elements.pxd b/src/sage/quivers/algebra_elements.pxd index 61aa11c79a8..1d74a9780e6 100644 --- a/src/sage/quivers/algebra_elements.pxd +++ b/src/sage/quivers/algebra_elements.pxd @@ -14,7 +14,7 @@ Cython types for elements of path algebras # is in algebra_elements.pxi, the implementation of the Python class is in # algebra_elements.pyx. The latter file also contains all doctests. -from cpython cimport PyObject +from cpython.object cimport PyObject from sage.data_structures.bounded_integer_sequences cimport * from sage.structure.element cimport RingElement, ModuleElement, Element from sage.quivers.paths cimport QuiverPath diff --git a/src/sage/quivers/morphism.py b/src/sage/quivers/morphism.py index 1a1cc2cfded..b0c5cda1539 100644 --- a/src/sage/quivers/morphism.py +++ b/src/sage/quivers/morphism.py @@ -2,7 +2,7 @@ Quiver Morphisms """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Jim Stark # 2013 Simon King # @@ -15,12 +15,13 @@ # See the GNU General Public License for more details; the full text # is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.categories.morphism import CallMorphism from sage.matrix.constructor import Matrix + class QuiverRepHom(CallMorphism): r""" A homomorphism of quiver representations (of one and the same quiver) @@ -506,7 +507,6 @@ def __eq__(self, other): sage: g == h True """ - from sage.quivers.morphism import QuiverRepHom # A homomorphism can only be equal to another homomorphism between the # same domain and codomain if not isinstance(other, QuiverRepHom) or self._domain != other._domain or self._codomain != other._codomain: @@ -554,7 +554,6 @@ def __ne__(self, other): sage: g != h True """ - from sage.quivers.morphism import QuiverRepHom # A homomorphism can only be equal to another homomorphism between the # same domain and codomain if not isinstance(other, QuiverRepHom) or self._domain != other._domain or self._codomain != other._codomain: @@ -1201,7 +1200,6 @@ def direct_sum(self, maps, return_maps=False, pinch=None): sage: g.is_surjective() False """ - from sage.quivers.morphism import QuiverRepHom # Get the list of maps to be summed if isinstance(maps, QuiverRepHom): maplist = [self, maps] diff --git a/src/sage/quivers/representation.py b/src/sage/quivers/representation.py index 7c0ed7837b8..60a6b680ee3 100644 --- a/src/sage/quivers/representation.py +++ b/src/sage/quivers/representation.py @@ -2196,7 +2196,7 @@ def quotient(self, sub, check=True): projection map from ``self`` to ``quot`` can be obtained by calling ``quot.coerce_map_from(self)``. - EXAMPLES: + EXAMPLES:: sage: Q = DiGraph({1:{2:['a','b']}, 2:{3:['c']}}).path_semigroup() sage: M = Q.I(GF(3), 3) diff --git a/src/sage/repl/attach.py b/src/sage/repl/attach.py index f8935a42189..dc53a1cec42 100644 --- a/src/sage/repl/attach.py +++ b/src/sage/repl/attach.py @@ -168,6 +168,12 @@ def load_attach_path(path=None, replace=False): sage: t_dir = tmp_dir() sage: fullpath = os.path.join(t_dir, 'test.py') sage: _ = open(fullpath, 'w').write("print(37 * 3)") + + We put SAGE_TMP on the attach path for testing (otherwise this will + load ``test.py`` from the current working directory if that happens + to exist):: + + sage: load_attach_path(SAGE_TMP, replace=True) sage: attach('test.py') Traceback (most recent call last): ... @@ -180,6 +186,7 @@ def load_attach_path(path=None, replace=False): sage: sage.repl.attach.reset(); reset_load_attach_path() sage: load_attach_path() == ['.'] True + sage: load_attach_path(SAGE_TMP, replace=True) sage: load('test.py') Traceback (most recent call last): ... @@ -205,7 +212,7 @@ def load_attach_path(path=None, replace=False): if path is None: return search_paths else: - if isinstance(path, six.string_types): + if not isinstance(path, list): path = [path] if replace: search_paths = path @@ -432,7 +439,7 @@ def detach(filename): sage: t_dir = tmp_dir() sage: fullpath = os.path.join(t_dir, 'test.py') sage: _ = open(fullpath, 'w').write("print(37 * 3)") - sage: load_attach_path(t_dir) + sage: load_attach_path(t_dir, replace=True) sage: attach('test.py') 111 sage: attached_files() == [os.path.normpath(fullpath)] diff --git a/src/sage/repl/configuration.py b/src/sage/repl/configuration.py index edc0a2abe1f..67d7d2accf8 100644 --- a/src/sage/repl/configuration.py +++ b/src/sage/repl/configuration.py @@ -119,8 +119,11 @@ def default(self): EXAMPLES:: sage: from sage.repl.configuration import sage_ipython_config - sage: sage_ipython_config.default() - {'InteractiveShell': {'colors': ... + sage: conf = sage_ipython_config.default() + sage: type(conf) + + sage: 'InteractiveShell' in conf + True """ from sage.repl.interpreter import SageTerminalInteractiveShell cfg = Config( @@ -153,8 +156,11 @@ def copy(self): EXAMPLES:: sage: from sage.repl.configuration import sage_ipython_config - sage: sage_ipython_config.copy() - {'InteractiveShell': {'colors': ... + sage: conf = sage_ipython_config.copy() + sage: type(conf) + + sage: 'InteractiveShell' in conf + True """ try: return copy.deepcopy(get_ipython().config) diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 00759fbba0c..5c56e6bf89a 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -80,13 +80,11 @@ ZeroDivisionError...Traceback (most recent call last) in () ----> 1 Integer(1)/Integer(0) - - .../sage/rings/integer.pyx in sage.rings.integer.Integer.__div__ (.../cythonized/sage/rings/integer.c:...)() - ....: if type(left) is type(right): - ....: if mpz_sgn((right).value) == 0: + .../sage/rings/integer.pyx in sage.rings.integer.Integer...div... (.../cythonized/sage/rings/integer.c:...)() + ... -> ... raise ZeroDivisionError("rational division by zero") ....: x = Rational.__new__(Rational) - ....: mpq_div_zz(x.value, (left).value, (right).value) + ....: mpq_div_zz(x.value, ....value, (right).value) ZeroDivisionError: rational division by zero sage: shell.quit() diff --git a/src/sage/repl/ipython_kernel/interact.py b/src/sage/repl/ipython_kernel/interact.py index bd7373f3c60..441a6c6e858 100644 --- a/src/sage/repl/ipython_kernel/interact.py +++ b/src/sage/repl/ipython_kernel/interact.py @@ -194,8 +194,10 @@ def widget_from_tuple(cls, abbrev, *args, **kwds): IntSlider(value=5, description=u'number', max=10) sage: sage_interactive.widget_from_tuple( (3, (0, 10)) ) IntSlider(value=3, max=10) - sage: sage_interactive.widget_from_tuple( (2, dict(one=1, two=2, three=3)) ) + sage: sage_interactive.widget_from_tuple((2, dict(one=1, two=2, three=3))) # py2 Dropdown(index=1, options={'three': 3, 'two': 2, 'one': 1}, value=2) + sage: sage_interactive.widget_from_tuple((2, dict(one=1, two=2, three=3))) # py3 + Dropdown(index=1, options={'one': 1, 'two': 2, 'three': 3}, value=2) sage: sage_interactive.widget_from_tuple( (sqrt(2), pi) ) FloatSlider(value=2.277903107981444, max=3.141592653589793, min=1.4142135623730951) """ diff --git a/src/sage/repl/ipython_kernel/widgets.py b/src/sage/repl/ipython_kernel/widgets.py index 7ec23805beb..2fbd1d75ad3 100644 --- a/src/sage/repl/ipython_kernel/widgets.py +++ b/src/sage/repl/ipython_kernel/widgets.py @@ -26,7 +26,7 @@ from ipywidgets.widgets import (IntSlider, IntRangeSlider, FloatSlider, FloatRangeSlider, Text, - Textarea, ColorPicker, HTML, Label, + Textarea, ColorPicker, HTMLMath, Label, HBox, VBox, ValueWidget) from traitlets import List, Unicode, link @@ -35,9 +35,9 @@ from sage.plot.colors import Color -class HTMLText(HTML): +class HTMLText(HTMLMath): """ - A HTML widget whose ``description`` is always empty. + An HTML widget whose ``description`` is always empty. This is used to display arbitrary HTML text in interacts without a label. The :func:`text_control` function from SageNB is an alias diff --git a/src/sage/repl/ipython_kernel/widgets_sagenb.py b/src/sage/repl/ipython_kernel/widgets_sagenb.py index e5e3623857d..a206f78aff7 100644 --- a/src/sage/repl/ipython_kernel/widgets_sagenb.py +++ b/src/sage/repl/ipython_kernel/widgets_sagenb.py @@ -458,10 +458,14 @@ def selector(values, label=None, default=None, nrows=None, ncols=None, width=Non is not ordered, it is better to use an :class:`OrderedDict`:: sage: from collections import OrderedDict - sage: selector(OrderedDict(one=1, two=2, three=3)) + sage: selector(OrderedDict(one=1, two=2, three=3)) # py2 Dropdown(options=OrderedDict([('one', 1), ('three', 3), ('two', 2)]), value=1) - sage: selector(OrderedDict(one=1, two=2, three=3), buttons=True) + sage: selector(OrderedDict(one=1, two=2, three=3)) # py3 + Dropdown(options=OrderedDict([('one', 1), ('two', 2), ('three', 3)]), value=1) + sage: selector(OrderedDict(one=1, two=2, three=3), buttons=True) # py2 ToggleButtons(options=OrderedDict([('one', 1), ('three', 3), ('two', 2)]), value=1) + sage: selector(OrderedDict(one=1, two=2, three=3), buttons=True) # py3 + ToggleButtons(options=OrderedDict([('one', 1), ('two', 2), ('three', 3)]), value=1) The values can be any kind of object: diff --git a/src/sage/repl/ipython_tests.py b/src/sage/repl/ipython_tests.py index 2bb34cd43f7..d342ba7facf 100644 --- a/src/sage/repl/ipython_tests.py +++ b/src/sage/repl/ipython_tests.py @@ -23,7 +23,7 @@ EXAMPLES: ... - Init docstring: x.__init__(...) initializes x; see help(type(x)) for signature + Init docstring: ...ee help(type(...)) for...signature... File: .../sage/repl/ipython_tests.py Type: function @@ -33,16 +33,32 @@ sage: shell = get_test_shell() sage: shell.run_cell(u'from sage.tests.stl_vector import stl_int_vector') sage: shell.run_cell(u'%pinfo stl_int_vector') - Docstring: + ... Example class wrapping an STL vector EXAMPLES: ... - Init docstring: x.__init__(...) initializes x; see help(type(x)) for signature + Init docstring: ...ee help(type(...)) for...signature... File: .../sage/tests/stl_vector.pyx Type: type +Next, test the ``pinfo`` magic for ``R`` interface code, see :trac:`26906`:: + + sage: from sage.repl.interpreter import get_test_shell + sage: shell = get_test_shell() + sage: shell.run_cell(u'%pinfo r.lm') + Signature: r.lm(...*args, **kwds) + ... + String form: lm + File: .../sage/interfaces/r.py + Docstring: + title + ***** + + Fitting Linear Models + ... + Next, test the pinfo2 magic for Python code. This is what IPython calls when you ask for the double-questionmark help, like `foo??` :: @@ -78,7 +94,7 @@ def dummy(argument, optional=None): sage: shell = get_test_shell() sage: shell.run_cell(u'from sage.tests.stl_vector import stl_int_vector') sage: shell.run_cell(u'%pinfo2 stl_int_vector') - Source: + ... cdef class stl_int_vector(SageObject): """ Example class wrapping an STL vector @@ -101,6 +117,19 @@ def __cinit__(self): File: .../sage/tests/stl_vector.pyx Type: type +Next, test the ``pinfo2`` magic for ``R`` interface code, see :trac:`26906`:: + + sage: from sage.repl.interpreter import get_test_shell + sage: shell = get_test_shell() + sage: shell.run_cell(u'%pinfo2 r.lm') + Signature: r.lm(...*args, **kwds) + ... + String form: lm + File: .../sage/interfaces/r.py + Source: + function (formula, data, subset, weights, na.action, method = "qr", + ... + Test that there are no warnings being ignored internally:: sage: import warnings diff --git a/src/sage/repl/load.py b/src/sage/repl/load.py index d4f08a84098..58e54a0b8a9 100644 --- a/src/sage/repl/load.py +++ b/src/sage/repl/load.py @@ -93,6 +93,15 @@ def load(filename, globals, attach=False): - ``attach`` -- a boolean (default: False); whether to add the file to the list of attached files. + Loading an executable Sage script from the command prompt will run whatever + code is inside an + + if __name__ == "__main__": + + section, as the condition on ``__name__`` will hold true (code run from the + command prompt is considered to be running in the ``__main__`` module.) + + EXAMPLES: Note that ``.py`` files are *not* preparsed:: @@ -137,9 +146,9 @@ def load(filename, globals, attach=False): ... ValueError: unknown file extension '.foo' for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m) - We load a file given at a remote URL:: + We load a file given at a remote URL (not tested for security reasons):: - sage: sage.repl.load.load('http://wstein.org/loadtest.py', globals()) # optional - internet + sage: sage.repl.load.load('http://www.sagemath.org/files/loadtest.py', globals()) # not tested hi from the net 5 @@ -159,7 +168,7 @@ def load(filename, globals, attach=False): You can't attach remote URLs (yet):: - sage: sage.repl.load.load('http://wstein.org/loadtest.py', globals(), attach=True) # optional - internet + sage: sage.repl.load.load('http://www.sagemath.org/files/loadtest.py', globals(), attach=True) # optional - internet Traceback (most recent call last): ... NotImplementedError: you can't attach a URL @@ -176,7 +185,7 @@ def load(filename, globals, attach=False): sage: fullpath = os.path.join(t_dir, fname) sage: with open(fullpath, 'w') as f: ....: _ = f.write("print(37 * 3)") - sage: load_attach_path(t_dir) + sage: load_attach_path(t_dir, replace=True) sage: attach(fname) 111 sage: sage.repl.attach.reset(); reset_load_attach_path() # clean up diff --git a/src/sage/repl/rich_output/buffer.py b/src/sage/repl/rich_output/buffer.py index 3af7ae00ebb..0eb216023a2 100644 --- a/src/sage/repl/rich_output/buffer.py +++ b/src/sage/repl/rich_output/buffer.py @@ -21,14 +21,14 @@ sage: type(buf.get()) is bytes True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 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/ +# **************************************************************************** import os @@ -135,7 +135,6 @@ def _chmod_readonly(cls, filename): sage: stat.S_IMODE(os.stat(tmp).st_mode) & (stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH) 0 """ - import os from sage.env import SAGE_EXTCODE filename = os.path.abspath(filename) if filename.startswith(os.path.abspath(SAGE_EXTCODE)): diff --git a/src/sage/rings/algebraic_closure_finite_field.py b/src/sage/rings/algebraic_closure_finite_field.py index 59f9179eb25..3b6a5860dd7 100644 --- a/src/sage/rings/algebraic_closure_finite_field.py +++ b/src/sage/rings/algebraic_closure_finite_field.py @@ -548,6 +548,13 @@ class AlgebraicClosureFiniteField_generic(Field): """ Algebraic closure of a finite field. + TESTS:: + + sage: GF(3).algebraic_closure().cardinality() + +Infinity + + sage: GF(3).algebraic_closure().is_finite() + False """ def __init__(self, base_ring, name, category=None): """ @@ -557,7 +564,6 @@ def __init__(self, base_ring, name, category=None): sage: F = AlgebraicClosureFiniteField_generic(GF(5), 'z') sage: F Algebraic closure of Finite Field of size 5 - """ Field.__init__(self, base_ring=base_ring, names=name, normalize=False, category=category) @@ -597,44 +603,6 @@ def __ne__(self, other): """ return not (self == other) - def cardinality(self): - """ - Return the cardinality of ``self``. - - This always returns ``+Infinity``. - - .. TODO:: - - When :trac:`10963` is merged we should remove that method and set the - category to infinite fields (i.e. ``Fields().Infinite()``). - - EXAMPLES:: - - sage: F = GF(3).algebraic_closure() - sage: F.cardinality() - +Infinity - - """ - from sage.rings.infinity import Infinity - return Infinity - - def is_finite(self): - """ - Returns ``False`` as an algebraically closed field is always infinite. - - .. TODO:: - - When :trac:`10963` is merged we should remove that method and set the - category to infinite fields (i.e. ``Fields().Infinite()``). - - EXAMPLES:: - - sage: GF(3).algebraic_closure().is_finite() - False - - """ - return False - def characteristic(self): """ Return the characteristic of ``self``. @@ -1208,7 +1176,8 @@ def AlgebraicClosureFiniteField(base_ring, name, category=None, implementation=N """ if category is None: from sage.categories.fields import Fields - category = Fields() + category = Fields().Infinite() + if implementation is None: implementation = 'pseudo_conway' diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 30c5cadbc2c..613cf2abdb5 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -1,17 +1,26 @@ """ Rings -""" -#***************************************************************************** +Test for deprecations of imports into global namespace:: + + sage: convergents + doctest:warning...: + DeprecationWarning: + Importing convergents from here is deprecated. If you need to use it, please import it directly from sage.rings.continued_fraction + See https://trac.sagemath.org/27066 for details. + +""" +# **************************************************************************** # Copyright (C) 2005 William Stein # # This 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 __future__ import absolute_import +from sage.misc.lazy_import import lazy_import # Ring base classes from .ring import (Ring, Field, CommutativeRing, IntegralDomain, @@ -147,11 +156,14 @@ from .fast_arith import prime_range # continued fractions -from sage.rings.continued_fraction import (convergents, - continued_fraction, continued_fraction_list) +from sage.rings.continued_fraction import (continued_fraction, + continued_fraction_list) +lazy_import("sage.rings.continued_fraction", 'convergents', deprecation=27066) # asymptotic ring from .asymptotic.all import * # Register classes in numbers abc from . import numbers_abc + +del absolute_import diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 84fa0e41fe3..18f8e906d68 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -1095,7 +1095,7 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 2*u + u^2, tau=2, precision=5) Traceback (most recent call last): ... - ZeroDivisionError: Symbolic division by zero + ZeroDivisionError: symbolic division by zero sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 2*u + u^2, tau=3, precision=5) 3 - 4*I*sqrt(3)*Z^(-1/2) + 6*I*sqrt(3)*Z^(-3/2) + O(Z^(-2)) diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index ac3d94e4079..b458fed4cab 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -325,6 +325,9 @@ class ComplexBallField(UniqueRepresentation, Field): Traceback (most recent call last): ... ValueError: precision must be at least 2 + + sage: ComplexBallField().is_finite() + False """ Element = ComplexBall @@ -673,21 +676,6 @@ class ComplexBallField(UniqueRepresentation, Field): """ return False - def is_finite(self): - """ - Complex ball fields are infinite. - - They already specify it via their category, but we currently need to - re-implement this method due to the legacy implementation in - :class:`sage.rings.ring.Ring`. - - EXAMPLES:: - - sage: ComplexBallField().is_finite() - False - """ - return False - def characteristic(self): """ Complex ball fields have characteristic zero. @@ -3133,6 +3121,132 @@ cdef class ComplexBall(RingElement): if _do_sig(prec(self)): sig_off() return res + def sec(self): + """ + Return the secant of this ball. + + EXAMPLES:: + + sage: CBF(1, 1).sec() + [0.498337030555187 +/- ...e-16] + [0.591083841721045 +/- ...e-16]*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_sec(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def csc(self): + """ + Return the cosecant of this ball. + + EXAMPLES:: + + sage: CBF(1, 1).csc() + [0.621518017170428 +/- ...e-16] + [-0.303931001628426 +/- ...e-16]*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_csc(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def sinh(self): + """ + Return the hyperbolic sine of this ball. + + EXAMPLES:: + + sage: CBF(1, 1).sinh() + [0.634963914784736 +/- ...e-16] + [1.298457581415977 +/- ...e-16]*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_sinh(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def cosh(self): + """ + Return the hyperbolic cosine of this ball. + + EXAMPLES:: + + sage: CBF(1, 1).cosh() + [0.833730025131149 +/- ...e-16] + [0.988897705762865 +/- ...e-16]*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_cosh(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def tanh(self): + """ + Return the hyperbolic tangent of this ball. + + EXAMPLES:: + + sage: CBF(1, 1).tanh() + [1.083923327338694 +/- ...e-16] + [0.2717525853195117 +/- ...e-17]*I + sage: CBF(0, pi/2).tanh() + nan*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_tanh(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def coth(self): + """ + Return the hyperbolic cotangent of this ball. + + EXAMPLES:: + + sage: CBF(1, 1).coth() + [0.868014142895925 +/- ...e-16] + [-0.2176215618544027 +/- ...e-17]*I + sage: CBF(0, pi).coth() + nan*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_coth(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def sech(self): + """ + Return the hyperbolic secant of this ball. + + EXAMPLES:: + + sage: CBF(pi/2, 1/10).sech() + [0.397174529918189 +/- ...e-16] + [-0.0365488656274242 +/- ...e-17]*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_sech(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def csch(self): + """ + Return the hyperbolic cosecant of this ball. + + EXAMPLES:: + + sage: CBF(1, 1).csch() + [0.303931001628426 +/- ...e-16] + [-0.621518017170428 +/- ...e-16]*I + sage: CBF(i*pi).csch() + nan*I + """ + cdef ComplexBall res = self._new() + if _do_sig(prec(self)): sig_on() + acb_csch(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + def arcsin(self, analytic=False): """ Return the arcsine of this ball. diff --git a/src/sage/rings/complex_double.pxd b/src/sage/rings/complex_double.pxd index 929a509c5c8..75f27bc5b77 100644 --- a/src/sage/rings/complex_double.pxd +++ b/src/sage/rings/complex_double.pxd @@ -2,18 +2,18 @@ from sage.libs.gsl.types cimport gsl_complex cimport sage.structure.element cimport sage.rings.ring -cimport sage.structure.element -from sage.structure.element cimport RingElement, ModuleElement -from cypari2.types cimport GEN cdef class ComplexDoubleField_class(sage.rings.ring.Field): pass + cdef class ComplexDoubleElement(sage.structure.element.FieldElement): cdef gsl_complex _complex cdef ComplexDoubleElement _new_c(self, gsl_complex x) cpdef _add_(self, other) cpdef _mul_(self, other) + cpdef _pow_(self, other) + cdef ComplexDoubleElement new_ComplexDoubleElement() diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 6ce86661769..ec43d0e1992 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -107,9 +107,8 @@ from .real_double cimport RealDoubleElement, double_repr from .real_double import RDF from sage.rings.integer_ring import ZZ -IF HAVE_GMPY2: - cimport gmpy2 - gmpy2.import_gmpy2() +cimport gmpy2 +gmpy2.import_gmpy2() def is_ComplexDoubleField(x): """ @@ -125,6 +124,7 @@ def is_ComplexDoubleField(x): """ return isinstance(x, ComplexDoubleField_class) + cdef class ComplexDoubleField_class(sage.rings.ring.Field): """ An approximation to the field of complex numbers using double @@ -202,13 +202,16 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): """ Return the hash for ``self``. + This class is intended for use as a singleton so any instance + of it should be equivalent from a hashing perspective. + TESTS:: - sage: hash(CDF) % 2^32 == hash(str(CDF)) % 2^32 + sage: from sage.rings.complex_double import ComplexDoubleField_class + sage: hash(CDF) == hash(ComplexDoubleField_class()) True """ return 561162115 - #return hash(self.str()) def characteristic(self): """ @@ -300,8 +303,8 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): 1.0*I sage: CDF(pari("x^2 + x + 1").polroots()[0]) -0.5 - 0.8660254037844386*I - sage: from gmpy2 import mpc # optional - gmpy2 - sage: CDF(mpc('2.0+1.0j')) # optional - gmpy2 + sage: from gmpy2 import mpc + sage: CDF(mpc('2.0+1.0j')) 2.0 + 1.0*I A ``TypeError`` is raised if the coercion doesn't make sense:: @@ -352,7 +355,7 @@ cdef class ComplexDoubleField_class(sage.rings.ring.Field): return ComplexDoubleElement(x.real(), x.imag()) elif isinstance(x, pari_gen): return pari_to_cdf(x) - elif HAVE_GMPY2 and type(x) is gmpy2.mpc: + elif type(x) is gmpy2.mpc: return ComplexDoubleElement((x).real, (x).imag) elif isinstance(x, str): t = cdf_parser.parse_expression(x) @@ -776,7 +779,7 @@ cdef class ComplexDoubleElement(FieldElement): True """ return (ComplexDoubleElement, - (self._complex.dat[0], self._complex.dat[1])) + (self._complex.real, self._complex.imag)) cdef ComplexDoubleElement _new_c(self, gsl_complex x): """ @@ -841,13 +844,13 @@ cdef class ComplexDoubleElement(FieldElement): sage: 4.3 > CDF(5,1) False """ - if left._complex.dat[0] < (right)._complex.dat[0]: + if left._complex.real < (right)._complex.real: return -1 - if left._complex.dat[0] > (right)._complex.dat[0]: + if left._complex.real > (right)._complex.real: return 1 - if left._complex.dat[1] < (right)._complex.dat[1]: + if left._complex.imag < (right)._complex.imag: return -1 - if left._complex.dat[1] > (right)._complex.dat[1]: + if left._complex.imag > (right)._complex.imag: return 1 return 0 @@ -963,9 +966,9 @@ cdef class ComplexDoubleElement(FieldElement): sage: float(abs(CDF(1,1))) 1.4142135623730951 """ - if self._complex.dat[1]==0: - return float(self._complex.dat[0]) - raise TypeError("unable to convert {!r} to float; use abs() or real_part() as desired".format(self)) + if self._complex.imag: + raise TypeError(f"unable to convert {self} to float; use abs() or real_part() as desired") + return self._complex.real def __complex__(self): """ @@ -979,7 +982,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: complex(CDF(a)) (2303-3939j) """ - return complex(self._complex.dat[0], self._complex.dat[1]) + return complex(self._complex.real, self._complex.imag) def _interface_init_(self, I=None): """ @@ -1042,8 +1045,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: CDF(0) 0.0 """ - cdef double x = self._complex.dat[0] - cdef double y = self._complex.dat[1] + x, y = self._complex.dat if x == 0: if y == 0: # Not sure what to do with the signs of the real and @@ -1093,10 +1095,10 @@ cdef class ComplexDoubleElement(FieldElement): sage: pari(CDF(I)) 1.00000000000000*I """ - if self._complex.dat[1] == 0: - return new_gen_from_double(self._complex.dat[0]) + if not self._complex.imag: + return new_gen_from_double(self._complex.real) else: - return new_t_COMPLEX_from_double(self._complex.dat[0], self._complex.dat[1]) + return new_t_COMPLEX_from_double(self._complex.real, self._complex.imag) def __mpc__(self): """ @@ -1105,23 +1107,13 @@ cdef class ComplexDoubleElement(FieldElement): EXAMPLES:: sage: c = CDF(2,1) - sage: c.__mpc__() # optional - gmpy2 + sage: c.__mpc__() mpc('2.0+1.0j') - sage: from gmpy2 import mpc # optional - gmpy2 - sage: mpc(c) # optional - gmpy2 + sage: from gmpy2 import mpc + sage: mpc(c) mpc('2.0+1.0j') - - TESTS:: - - sage: c.__mpc__(); raise NotImplementedError("gmpy2 is not installed") - Traceback (most recent call last): - ... - NotImplementedError: gmpy2 is not installed """ - IF HAVE_GMPY2: - return gmpy2.mpc(self._complex.dat[0], self._complex.dat[1]) - ELSE: - raise NotImplementedError("gmpy2 is not installed") + return gmpy2.mpc(self._complex.dat[0], self._complex.dat[1]) ####################################################################### # Arithmetic @@ -1403,7 +1395,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: a.real_part() 3.0 """ - return RealDoubleElement(self._complex.dat[0]) + return RealDoubleElement(self._complex.real) real_part = real @@ -1419,7 +1411,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: a.imag_part() -2.0 """ - return RealDoubleElement(self._complex.dat[1]) + return RealDoubleElement(self._complex.imag) imag_part = imag @@ -1587,39 +1579,22 @@ cdef class ComplexDoubleElement(FieldElement): """ return self.real().is_NaN() or self.imag().is_NaN() - def _pow_(self, ComplexDoubleElement a): + cpdef _pow_(self, other): """ - The function returns the complex number `z` raised to the - complex power `a`, `z^a`. - - INPUT: - - - ``a`` - a :class:`ComplexDoubleElement` - - OUTPUT: :class:`ComplexDoubleElement` - - EXAMPLES:: - - sage: a = CDF(1,1); b = CDF(2,3) - sage: a._pow_(b) # rel tol 5e-16 - -0.163450932107355 + 0.09600498360894891*I - """ - return self._new_c(gsl_complex_pow(self._complex, a._complex)) - - def __pow__(z, a, dummy): - r""" - The function returns the complex number `z` raised to the - complex power `a`, `z^a`. + The complex number ``self`` raised to the power ``other``. - This is computed as `\exp(\log(z)*a)` using complex - logarithms and complex exponentials. + This is computed using complex logarithms and exponentials + as `z ^ a = \exp(a \log(z))`, unless ``self`` is real and + ``other`` is an exact integer: in that case, only real + arithmetic is used. EXAMPLES:: - sage: a = CDF(1,1); b = CDF(2,3) - sage: c = a^b; c # rel tol 5e-16, indirect doctest + sage: a = CDF(1,1) + sage: b = CDF(2,3) + sage: c = a ^ b; c # rel tol 5e-16 -0.163450932107355 + 0.09600498360894891*I - sage: c^(1/b) # rel tol 2e-16 + sage: c ^ (1/b) # rel tol 2e-16 1.0 + 1.0*I We compute the cube root of `-1` then cube it and observe a @@ -1632,27 +1607,69 @@ cdef class ComplexDoubleElement(FieldElement): We raise to symbolic powers:: - sage: x, n = var('x, n') + sage: var('x, n') + (x, n) sage: CDF(1.2)^x 1.2^x sage: CDF(1.2)^(x^n + n^x) 1.2^(n^x + x^n) + + A real number powered to an exact integer always yields a real + number:: + + sage: CDF(-0.26319743704743886) ^ 1 + -0.26319743704743886 + sage: CDF(-0.26319743704743886) ^ 0 + 1.0 + sage: CDF(-0.26319743704743886) ^ -1 + -3.7994290948196405 + sage: CDF(-0.26319743704743886) ^ 2 + 0.06927289086834054 + sage: CDF(-0.26319743704743886) ^ -2 + 14.435661446561994 + sage: CDF(-1) ^ (2^100) + 1.0 + + Note the difference with :: + + sage: CDF(-0.26319743704743886) ^ QQ(2) + 0.06927289086834053 - 1.6966964813919428e-17*I + sage: CDF(-0.26319743704743886) ^ RDF(2) + 0.06927289086834053 - 1.6966964813919428e-17*I + + TESTS:: + + sage: (-2) ^ CDF(-0.5) # abs tol 1e-16 + 4.329780281177467e-17 - 0.7071067811865476*I """ - try: - return z._pow_(a) - except AttributeError: - # z is not a complex number - return CDF(z)._pow_(a) - except TypeError: - # a is not a complex number - try: - return z._pow_(CDF(a)) - except TypeError: - try: - return a.parent()(z)**a - except AttributeError: - raise TypeError + z = other + return self._new_c(gsl_complex_pow(self._complex, z._complex)) + cdef _pow_long(self, long other): + if other == 1: + return self + elif other == 0: + res = gsl_complex_rect(1, 0) + elif other == -1: + res = gsl_complex_inverse(self._complex) + elif not self._complex.imag: + # If self is real, the result should be real too + real = self._complex.real ** other + res = gsl_complex_rect(real, 0) + else: + # General case + res = gsl_complex_pow_real(self._complex, other) + return self._new_c(res) + + cpdef _pow_int(self, other): + if not self._complex.imag: + # If self is real, the result should be real too + real = self._complex.real ** other + res = gsl_complex_rect(real, 0) + else: + # General case + res = gsl_complex_pow_real(self._complex, other) + return self._new_c(res) def exp(self): r""" @@ -2174,10 +2191,10 @@ cdef class ComplexDoubleElement(FieldElement): """ cdef GEN a, b, c, y, t - if self._complex.dat[1] <= 0: + if self._complex.imag <= 0: raise ValueError("value must be in the upper half plane") - if self._complex.dat[1] > 100000 and not omit_frac: + if self._complex.imag > 100000 and not omit_frac: # To the precision of doubles for such large imaginary # part, the answer is automatically 0. If we don't do # this, PARI can easily underflow. @@ -2317,13 +2334,13 @@ cdef class ComplexDoubleElement(FieldElement): sage: CDF(-1,0).gamma() Infinity """ - if self._complex.dat[1] == 0: - if self._complex.dat[0] == 0: + if not self._complex.imag: + if self._complex.real == 0: from .infinity import unsigned_infinity return unsigned_infinity try: from sage.rings.all import Integer, CC - if Integer(self._complex.dat[0]) < 0: + if Integer(self._complex.real) < 0: return CC(self).gamma() except TypeError: pass @@ -2358,7 +2375,7 @@ cdef class ComplexDoubleElement(FieldElement): sage: zeta(CDF(1)) Infinity """ - if self._complex.dat[0] == 1 and self._complex.dat[1] == 0: + if self._complex.real == 1 and self._complex.imag == 0: from .infinity import unsigned_infinity return unsigned_infinity return pari_to_cdf(self.__pari__().zeta()) @@ -2550,18 +2567,17 @@ cdef inline double complex extract_double_complex(ComplexDoubleElement x): Return the value of ``x`` as a c99 complex double. """ cdef double complex z - z.real = x._complex.dat[0] - z.imag = x._complex.dat[1] + z.real = x._complex.real + z.imag = x._complex.imag return z -cdef ComplexDoubleElement ComplexDoubleElement_from_doubles(double re, double im): + +cdef inline ComplexDoubleElement ComplexDoubleElement_from_doubles(double re, double im): """ Create a new :class:`ComplexDoubleElement` with the specified real and imaginary parts. """ - cdef ComplexDoubleElement z = ComplexDoubleElement.__new__(ComplexDoubleElement) - z._complex.dat[0] = re - z._complex.dat[1] = im + z = ComplexDoubleElement.__new__(ComplexDoubleElement) + z._complex.real = re + z._complex.imag = im return z - -##### diff --git a/src/sage/rings/complex_field.py b/src/sage/rings/complex_field.py index 665deeb9bd2..4d4c12b459c 100644 --- a/src/sage/rings/complex_field.py +++ b/src/sage/rings/complex_field.py @@ -198,12 +198,18 @@ def __init__(self, prec=53): sage: C = ComplexField(200) sage: C.category() - Join of Category of fields and Category of complete metric spaces + Join of Category of fields and Category of infinite sets and Category of complete metric spaces sage: TestSuite(C).run() + + sage: CC.is_field() + True + + sage: CC.is_finite() + False """ self._prec = int(prec) from sage.categories.fields import Fields - ParentWithGens.__init__(self, self._real_field(), ('I',), False, category=Fields().Metric().Complete()) + ParentWithGens.__init__(self, self._real_field(), ('I',), False, category=Fields().Infinite().Metric().Complete()) # self._populate_coercion_lists_() self._populate_coercion_lists_(coerce_list=[RRtoCC(self._real_field(), self)]) @@ -555,28 +561,6 @@ def gen(self, n=0): raise IndexError("n must be 0") return ComplexNumber(self, 0, 1) - def is_field(self, proof = True): - """ - Return ``True`` since the complex numbers are a field. - - EXAMPLES:: - - sage: CC.is_field() - True - """ - return True - - def is_finite(self): - """ - Return ``False`` since there are infinite number of complex numbers. - - EXAMPLES:: - - sage: CC.is_finite() - False - """ - return False - def construction(self): """ Returns the functorial construction of ``self``, namely the algebraic diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 2bfa7559fb3..437c8b9708e 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -561,7 +561,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): EXAMPLES:: sage: CIF(0).union(CIF(5, 5)).str(style='brackets') - '[0.00000000000000000 .. 5.0000000000000000] + [0.00000000000000000 .. 5.0000000000000000]*I' + '[0.0000000000000000 .. 5.0000000000000000] + [0.0000000000000000 .. 5.0000000000000000]*I' """ x = self._new() cdef ComplexIntervalFieldElement other_intv @@ -831,12 +831,12 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): sage: a = CIF(RIF(-1,1)) sage: print((a^2).str(style="brackets")) - [0.00000000000000000 .. 1.0000000000000000] + [0.0000000000000000 .. 1.0000000000000000] sage: print((a*a).str(style="brackets")) [-1.0000000000000000 .. 1.0000000000000000] sage: a = CIF(0, RIF(-1,1)) sage: print((a^2).str(style="brackets")) - [-1.0000000000000000 .. -0.00000000000000000] + [-1.0000000000000000 .. -0.0000000000000000] sage: print((a*a).str(style="brackets")) [-1.0000000000000000 .. 1.0000000000000000] sage: a = CIF(RIF(-1,1), RIF(-1,1)) diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index b4b2f66d7fa..10078564d05 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -183,6 +183,11 @@ class ComplexIntervalField_class(Field): 0.?e1 + 0.?e1*I sage: x + CIF(RIF(3.14,3.15), 0) x + 3.15? + + Methods inherited from categories:: + + sage: CIF.is_finite() + False """ Element = complex_interval.ComplexIntervalFieldElement @@ -613,17 +618,6 @@ def is_field(self, proof = True): """ return True - def is_finite(self): - """ - Return ``False``, since the complex numbers are infinite. - - EXAMPLES:: - - sage: CIF.is_finite() - False - """ - return False - def pi(self): r""" Returns `\pi` as an element in the complex (interval) field. diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index a7105e6aac5..0baee83bd0c 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -85,9 +85,8 @@ from .real_mpfr import mpfr_prec_min, mpfr_prec_max from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.categories.fields import Fields -IF HAVE_GMPY2: - cimport gmpy2 - gmpy2.import_gmpy2() +cimport gmpy2 +gmpy2.import_gmpy2() NumberFieldElement_quadratic = None AlgebraicNumber_base = None @@ -313,6 +312,9 @@ cdef class MPComplexField_class(sage.rings.ring.Field): TESTS:: sage: TestSuite(MPComplexField(17)).run() + + sage: MPComplexField(17).is_finite() + False """ if prec < mpfr_prec_min() or prec > mpfr_prec_max(): raise ValueError("prec (=%s) must be >= %s and <= %s." % ( @@ -594,17 +596,6 @@ cdef class MPComplexField_class(sage.rings.ring.Field): """ return False - def is_finite(self): - """ - Return ``False``, since the field of complex numbers is not finite. - - EXAMPLES:: - - sage: MPComplexField(17).is_finite() - False - """ - return False - def characteristic(self): """ Return 0, since the field of complex numbers has characteristic 0. @@ -821,18 +812,18 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): Conversion from gmpy2 numbers:: - sage: from gmpy2 import * # optional - gmpy2 - sage: MPC(mpc(int(2),int(1))) # optional - gmpy2 + sage: from gmpy2 import * + sage: MPC(mpc(int(2),int(1))) 2.0000000000000000000000000000 + 1.0000000000000000000000000000*I - sage: MPC(mpfr(2.5)) # optional - gmpy2 + sage: MPC(mpfr(2.5)) 2.5000000000000000000000000000 - sage: MPC(mpq('3/2')) # optional - gmpy2 + sage: MPC(mpq('3/2')) 1.5000000000000000000000000000 - sage: MPC(mpz(int(5))) # optional - gmpy2 + sage: MPC(mpz(int(5))) 5.0000000000000000000000000000 - sage: re = mpfr('2.5') # optional - gmpy2 - sage: im = mpz(int(2)) # optional - gmpy2 - sage: MPC(re, im) # optional - gmpy2 + sage: re = mpfr('2.5') + sage: im = mpz(int(2)) + sage: MPC(re, im) 2.5000000000000000000000000000 + 2.0000000000000000000000000000*I """ # This should not be called except when the number is being created. @@ -874,17 +865,17 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): zz = sage.rings.complex_field.ComplexField(self._parent.prec())(z) self._set(zz) return - elif HAVE_GMPY2 and type(z) is gmpy2.mpc: + elif type(z) is gmpy2.mpc: mpc_set(self.value, (z).c, rnd) return # then, no imaginary part - elif HAVE_GMPY2 and type(z) is gmpy2.mpfr: + elif type(z) is gmpy2.mpfr: mpc_set_fr(self.value, (z).f, rnd) return - elif HAVE_GMPY2 and type(z) is gmpy2.mpq: + elif type(z) is gmpy2.mpq: mpc_set_q(self.value, (z).q, rnd) return - elif HAVE_GMPY2 and type(z) is gmpy2.mpz: + elif type(z) is gmpy2.mpz: mpc_set_z(self.value, (z).z, rnd) return elif isinstance(z, RealNumber): @@ -1268,40 +1259,30 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): sage: MPC = MPComplexField() sage: c = MPC(2,1) - sage: c.__mpc__() # optional - gmpy2 + sage: c.__mpc__() mpc('2.0+1.0j') - sage: from gmpy2 import mpc # optional - gmpy2 - sage: mpc(c) # optional - gmpy2 + sage: from gmpy2 import mpc + sage: mpc(c) mpc('2.0+1.0j') sage: MPCF = MPComplexField(42) - sage: mpc(MPCF(12, 12)).precision # optional - gmpy2 + sage: mpc(MPCF(12, 12)).precision (42, 42) sage: MPCF = MPComplexField(236) - sage: mpc(MPCF(12, 12)).precision # optional - gmpy2 + sage: mpc(MPCF(12, 12)).precision (236, 236) sage: MPCF = MPComplexField(63) sage: x = MPCF('15.64E+128', '15.64E+128') - sage: y = mpc(x) # optional - gmpy2 - sage: y.precision # optional - gmpy2 + sage: y = mpc(x) + sage: y.precision (63, 63) - sage: MPCF(y) == x # optional - gmpy2 + sage: MPCF(y) == x True - sage: x = mpc('1.324+4e50j', precision=(70,70)) # optional - gmpy2 - sage: y = MPComplexField(70)(x) # optional - gmpy2 - sage: mpc(y) == x # optional - gmpy2 + sage: x = mpc('1.324+4e50j', precision=(70,70)) + sage: y = MPComplexField(70)(x) + sage: mpc(y) == x True - - TESTS:: - - sage: c.__mpc__(); raise NotImplementedError("gmpy2 is not installed") - Traceback (most recent call last): - ... - NotImplementedError: gmpy2 is not installed """ - IF HAVE_GMPY2: - return gmpy2.GMPy_MPC_From_mpfr(self.value.re, self.value.im) - ELSE: - raise NotImplementedError("gmpy2 is not installed") + return gmpy2.GMPy_MPC_From_mpfr(self.value.re, self.value.im) cpdef int _cmp_(self, other) except -2: r""" diff --git a/src/sage/rings/complex_number.pyx b/src/sage/rings/complex_number.pyx index 46221714f5e..a38652e3d94 100644 --- a/src/sage/rings/complex_number.pyx +++ b/src/sage/rings/complex_number.pyx @@ -46,9 +46,8 @@ import sage.rings.infinity as infinity from sage.libs.mpmath.utils cimport mpfr_to_mpfval from sage.rings.integer_ring import ZZ -IF HAVE_GMPY2: - cimport gmpy2 - gmpy2.import_gmpy2() +cimport gmpy2 +gmpy2.import_gmpy2() cdef object numpy_complex_interface = {'typestr': '=c16'} cdef object numpy_object_interface = {'typestr': '|O'} @@ -166,9 +165,9 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): Conversion from gmpy2 numbers:: - sage: from gmpy2 import * # optional - gmpy2 - sage: c = mpc('2.0+1.0j') # optional - gmpy2 - sage: CC(c) # optional - gmpy2 + sage: from gmpy2 import * + sage: c = mpc('2.0+1.0j') + sage: CC(c) 2.00000000000000 + 1.00000000000000*I """ cdef RealNumber rr, ii @@ -191,7 +190,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): real = re elif isinstance(real, complex): real, imag = real.real, real.imag - elif HAVE_GMPY2 and type(real) is gmpy2.mpc: + elif type(real) is gmpy2.mpc: real, imag = (real).real, (real).imag else: imag = 0 @@ -601,41 +600,31 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): EXAMPLES:: sage: c = ComplexNumber(2,1) - sage: c.__mpc__() # optional - gmpy2 + sage: c.__mpc__() mpc('2.0+1.0j') - sage: from gmpy2 import mpc # optional - gmpy2 - sage: mpc(c) # optional - gmpy2 + sage: from gmpy2 import mpc + sage: mpc(c) mpc('2.0+1.0j') - sage: CF = ComplexField(134) - sage: mpc(CF.pi()).precision # optional - gmpy2 + sage: CF = ComplexField(134) + sage: mpc(CF.pi()).precision (134, 134) - sage: CF = ComplexField(45) - sage: mpc(CF.zeta(5)).precision # optional - gmpy2 + sage: CF = ComplexField(45) + sage: mpc(CF.zeta(5)).precision (45, 45) sage: CF = ComplexField(255) sage: x = CF(5, 8) - sage: y = mpc(x) # optional - gmpy2 - sage: y.precision # optional - gmpy2 + sage: y = mpc(x) + sage: y.precision (255, 255) - sage: CF(y) == x # optional - gmpy2 + sage: CF(y) == x True - sage: x = mpc('1.324+4e50j', precision=(70,70)) # optional - gmpy2 + sage: x = mpc('1.324+4e50j', precision=(70,70)) sage: CF = ComplexField(70) - sage: y = CF(x) # optional - gmpy2 - sage: x == mpc(y) # optional - gmpy2 + sage: y = CF(x) + sage: x == mpc(y) True - - TESTS:: - - sage: c.__mpc__(); raise NotImplementedError("gmpy2 is not installed") - Traceback (most recent call last): - ... - NotImplementedError: gmpy2 is not installed """ - IF HAVE_GMPY2: - return gmpy2.GMPy_MPC_From_mpfr(self.__re, self.__im) - ELSE: - raise NotImplementedError("gmpy2 is not installed") + return gmpy2.GMPy_MPC_From_mpfr(self.__re, self.__im) def _mpmath_(self, prec=None, rounding=None): @@ -2654,9 +2643,9 @@ cdef class CCtoCDF(Map): sage: f(exp(pi*CC.0/4)) 0.7071067811865476 + 0.7071067811865475*I """ - cdef ComplexDoubleElement z = ComplexDoubleElement.__new__(ComplexDoubleElement) - z._complex.dat[0] = mpfr_get_d((x).__re, MPFR_RNDN) - z._complex.dat[1] = mpfr_get_d((x).__im, MPFR_RNDN) + z = ComplexDoubleElement.__new__(ComplexDoubleElement) + z._complex.real = mpfr_get_d((x).__re, MPFR_RNDN) + z._complex.imag = mpfr_get_d((x).__im, MPFR_RNDN) return z diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index 33d2d59efa2..e5464474cf4 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -2503,6 +2503,7 @@ def convergents(x): EXAMPLES:: + sage: from sage.rings.continued_fraction import convergents sage: convergents(143/255) [0, 1, 1/2, 4/7, 5/9, 9/16, 14/25, 23/41, 60/107, 143/255] """ diff --git a/src/sage/rings/convert/mpfi.pyx b/src/sage/rings/convert/mpfi.pyx index 65bbaa86331..bdf6d140712 100644 --- a/src/sage/rings/convert/mpfi.pyx +++ b/src/sage/rings/convert/mpfi.pyx @@ -135,11 +135,11 @@ cdef int mpfi_set_sage(mpfi_ptr re, mpfi_ptr im, x, field, int base) except -1: if isinstance(x, ComplexDoubleElement): zd = x if im is NULL: - if zd._complex.dat[1] != 0: + if zd._complex.imag: raise TypeError(f"unable to convert complex number {x!r} to real interval") else: - mpfi_set_d(im, zd._complex.dat[1]) - mpfi_set_d(re, zd._complex.dat[0]) + mpfi_set_d(im, zd._complex.imag) + mpfi_set_d(re, zd._complex.real) return 0 else: # not a Sage Element # Real diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index d56fd08ab43..37390206b99 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -40,15 +40,15 @@ AUTHORS: """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # # This 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 __future__ import absolute_import, print_function @@ -75,8 +75,6 @@ from cypari2.stack cimport clear_stack from sage.structure.parent cimport Parent -from sage.misc.superseded import deprecated_function_alias - cdef object is_IntegerMod cdef object Integer cdef object Rational @@ -1426,8 +1424,6 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): """ return Integer(self._cache.log_to_int(self.element)) - log_to_int = deprecated_function_alias(11295, _log_to_int) - def log(FiniteField_givaroElement self, base): """ Return the log to the base `b` of ``self``, i.e., an integer `n` @@ -1464,8 +1460,6 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): """ return self._cache._element_int_repr(self) - int_repr = deprecated_function_alias(11295, _int_repr) - def _log_repr(FiniteField_givaroElement self): r""" Return the log representation of ``self`` as a string. See the @@ -1481,8 +1475,6 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): """ return self._cache._element_log_repr(self) - log_repr = deprecated_function_alias(11295, _log_repr) - def _poly_repr(FiniteField_givaroElement self): r""" Return representation of this finite field element as a polynomial @@ -1497,8 +1489,6 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement): """ return self._cache._element_poly_repr(self) - poly_repr = deprecated_function_alias(11295, _poly_repr) - def polynomial(FiniteField_givaroElement self, name=None): """ Return self viewed as a polynomial over diff --git a/src/sage/rings/finite_rings/element_pari_ffelt.pyx b/src/sage/rings/finite_rings/element_pari_ffelt.pyx index ff73a1f63a0..2fcd3a11eca 100644 --- a/src/sage/rings/finite_rings/element_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/element_pari_ffelt.pyx @@ -869,7 +869,8 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): Univariate Polynomial Ring in beta over Finite Field of size 3 """ sig_on() - return self._parent.polynomial_ring(name)(new_gen(FF_to_FpXQ_i(self.val))) + pol = new_gen(FF_to_FpXQ(self.val)) + return self._parent.polynomial_ring(name)(pol) def minpoly(self, var='x'): """ @@ -887,7 +888,8 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): y^2 + 1 """ sig_on() - return self._parent.polynomial_ring(var)(new_gen(FF_minpoly(self.val))) + pol = new_gen(FF_minpoly(self.val)) + return self._parent.polynomial_ring(var)(pol) def charpoly(self, var='x'): """ @@ -905,7 +907,8 @@ cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): y^2 + 1 """ sig_on() - return self._parent.polynomial_ring(var)(new_gen(FF_charpoly(self.val))) + pol = new_gen(FF_charpoly(self.val)) + return self._parent.polynomial_ring(var)(pol) def is_square(self): """ diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index af90c0b323c..e0a5be16579 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -47,10 +47,14 @@ from sage.rings.integer cimport Integer # Copied from sage.misc.fast_methods, used in __hash__() below. cdef int SIZEOF_VOID_P_SHIFT = 8*sizeof(void *) - 4 - cdef class FiniteField(Field): """ Abstract base class for finite fields. + + TESTS:: + + sage: GF(997).is_finite() + True """ def __init__(self, base, names, normalize, category=None): """ @@ -763,17 +767,6 @@ cdef class FiniteField(Field): """ return True - def is_finite(self): - """ - Return ``True`` since a finite field is finite. - - EXAMPLES:: - - sage: GF(997).is_finite() - True - """ - return True - def order(self): """ Return the order of this finite field. @@ -1606,7 +1599,7 @@ cdef class FiniteField(Field): """ Return ``True`` if self is defined by a Conway polynomial. - EXAMPLES: + EXAMPLES:: sage: GF(5^3, 'a').is_conway() True diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 4f974c73dcd..cdf5acee03e 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -327,7 +327,7 @@ class FiniteFieldFactory(UniqueFactory): sage: K. = GF(13^2, modulus=sin(x)) Traceback (most recent call last): ... - TypeError: unable to convert sin(x) to an integer + TypeError: self must be a numeric expression If you wish to live dangerously, you can tell the constructor not to test irreducibility using ``check_irreducible=False``, but this diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 56041a26766..74fcd9e3cb6 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -70,7 +70,7 @@ TESTS:: #***************************************************************************** from __future__ import print_function, division, absolute_import -from cysignals.signals cimport sig_on, sig_off +from cysignals.signals cimport sig_on, sig_off, sig_check from cpython.int cimport * from cpython.list cimport * @@ -90,14 +90,15 @@ from sage.arith.long cimport integer_check_long, integer_check_long_py, ERR_OVER import sage.rings.rational as rational from sage.libs.pari.all import pari, PariError import sage.rings.integer_ring as integer_ring +import sage.rings.rational_field import sage.interfaces.all import sage.rings.integer -import sage.rings.integer_ring cimport sage.rings.integer from sage.rings.integer cimport Integer +from sage.structure.coerce cimport py_scalar_to_element import sage.structure.element cimport sage.structure.element coerce_binop = sage.structure.element.coerce_binop @@ -344,6 +345,15 @@ cdef class IntegerMod_abstract(FiniteRingElement): sage: TestSuite(Zmod(6)).run() sage: TestSuite(Zmod(2^10 * 3^5)).run() sage: TestSuite(Zmod(2^30 * 3^50 * 5^20)).run() + + sage: GF(29)(SR(1/3)) + 10 + sage: Integers(30)(QQ['x'](1/7)) + 13 + sage: Integers(30)(SR(1/4)) + Traceback (most recent call last): + ... + ZeroDivisionError: inverse of Mod(4, 30) does not exist """ self._parent = parent self.__modulus = parent._pyx_order @@ -363,7 +373,19 @@ cdef class IntegerMod_abstract(FiniteRingElement): self.set_from_long(longval) return else: - z = sage.rings.integer_ring.Z(value) + try: + z = integer_ring.Z(value) + except (TypeError, ValueError): + from sage.symbolic.expression import Expression + if isinstance(value, Expression): + value = value.pyobject() + else: + value = py_scalar_to_element(value) + if isinstance(value, Element) and value.parent().is_exact(): + value = sage.rings.rational_field.QQ(value) + z = value % self.__modulus.sageInteger + else: + raise self.set_from_mpz(z.value) cdef IntegerMod_abstract _new_c_fast(self, unsigned long value): @@ -813,7 +835,8 @@ cdef class IntegerMod_abstract(FiniteRingElement): """ Returns the minimal polynomial of this element. - EXAMPLES: + EXAMPLES:: + sage: GF(241, 'a')(1).minpoly() x + 240 """ @@ -823,7 +846,8 @@ cdef class IntegerMod_abstract(FiniteRingElement): """ Returns the minimal polynomial of this element. - EXAMPLES: + EXAMPLES:: + sage: GF(241, 'a')(1).minimal_polynomial(var = 'z') z + 240 """ @@ -2161,7 +2185,8 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): def __pow__(IntegerMod_gmp self, exp, m): # NOTE: m ignored, always use modulus of parent ring """ - EXAMPLES: + EXAMPLES:: + sage: R = Integers(10^10) sage: R(2)^1000 5668069376 @@ -2207,9 +2232,9 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): sig_on() try: mpz_pow_helper(x.value, self.value, exp, self.__modulus.sageInteger.value) - return x finally: sig_off() + return x def __invert__(IntegerMod_gmp self): """ @@ -2630,7 +2655,8 @@ cdef class IntegerMod_int(IntegerMod_abstract): def __pow__(IntegerMod_int self, exp, m): # NOTE: m ignored, always use modulus of parent ring """ - EXAMPLES: + EXAMPLES:: + sage: R = Integers(10) sage: R(2)^10 4 @@ -2682,15 +2708,16 @@ cdef class IntegerMod_int(IntegerMod_abstract): elif type(exp) is Integer and mpz_cmpabs_ui((exp).value, 100000) == -1: long_exp = mpz_get_si((exp).value) else: + base = self.lift() sig_on() try: mpz_init(res_mpz) - base = self.lift() mpz_pow_helper(res_mpz, (base).value, exp, self.__modulus.sageInteger.value) - return self._new_c(mpz_get_ui(res_mpz)) - finally: + res = mpz_get_ui(res_mpz) mpz_clear(res_mpz) + finally: sig_off() + return self._new_c(res) if long_exp == 0 and self.ivalue == 0: # Return 0 if the modulus is 1, otherwise return 1. @@ -3421,7 +3448,8 @@ cdef class IntegerMod_int64(IntegerMod_abstract): def __pow__(IntegerMod_int64 self, exp, m): # NOTE: m ignored, always use modulus of parent ring """ - EXAMPLES: + EXAMPLES:: + sage: R = Integers(10) sage: R(2)^10 4 @@ -3484,19 +3512,16 @@ cdef class IntegerMod_int64(IntegerMod_abstract): elif type(exp) is Integer and mpz_cmpabs_ui((exp).value, 100000) == -1: long_exp = mpz_get_si((exp).value) else: + base = self.lift() sig_on() try: mpz_init(res_mpz) - base = self.lift() mpz_pow_helper(res_mpz, (base).value, exp, self.__modulus.sageInteger.value) - if mpz_fits_ulong_p(res_mpz): - res = mpz_get_ui(res_mpz) - else: - res = mpz_get_pyintlong(res_mpz) - return self._new_c(res) - finally: + res = mpz_get_ui(res_mpz) mpz_clear(res_mpz) + finally: sig_off() + return self._new_c(res) if long_exp == 0 and self.ivalue == 0: # Return 0 if the modulus is 1, otherwise return 1. @@ -3604,9 +3629,10 @@ cdef class IntegerMod_int64(IntegerMod_abstract): g = 0 return self._new_c(g) + ### Helper functions -cdef mpz_pow_helper(mpz_t res, mpz_t base, object exp, mpz_t modulus): +cdef int mpz_pow_helper(mpz_t res, mpz_t base, object exp, mpz_t modulus) except -1: cdef bint invert = False cdef long long_exp @@ -3944,6 +3970,7 @@ cpdef square_root_mod_prime(IntegerMod_abstract a, p=None): b *= g*g return res + def lucas_q1(mm, IntegerMod_abstract P): """ Return `V_k(P, 1)` where `V_k` is the Lucas @@ -3981,16 +4008,15 @@ def lucas_q1(mm, IntegerMod_abstract P): d1 = P d2 = P*P - two - sig_on() cdef int j for j from mpz_sizeinbase(m.value, 2)-1 > j > 0: + sig_check() if mpz_tstbit(m.value, j): d1 = d1*d2 - P d2 = d2*d2 - two else: d2 = d1*d2 - P d1 = d1*d1 - two - sig_off() if mpz_odd_p(m.value): return d1*d2 - P else: @@ -4087,9 +4113,9 @@ def lucas(k, P, Q=1, n=None): q0 = p._new_c_from_long(1) q1 = p._new_c_from_long(1) - sig_on() cdef int j for j from mpz_sizeinbase(m.value, 2)-1 >= j >= 0: + sig_check() q0 = q0*q1 if mpz_tstbit(m.value, j): q1 = q0*Q @@ -4099,9 +4125,9 @@ def lucas(k, P, Q=1, n=None): q1 = q0 v1 = v0*v1 - p*q0 v0 = v0*v0 - two*q0 - sig_off() return [v0,q0] + ############# Homomorphisms ############### cdef class IntegerMod_hom(Morphism): diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index cd48b1ded2d..c54ad1fe49c 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -446,6 +446,10 @@ def __init__(self, order, cache=None, category=None): sage: TestSuite(Z16).run() sage: R = Integers(100000) sage: TestSuite(R).run() # long time (17s on sage.math, 2011) + + sage: R = IntegerModRing(18) + sage: R.is_finite() + True """ order = ZZ(order) if order <= 0: @@ -635,18 +639,6 @@ def multiplicative_subgroups(self): return tuple(tuple(g.value() for g in H.gens()) for H in self.unit_group().subgroups()) - def is_finite(self): - r""" - Return ``True`` since `\ZZ/N\ZZ` is finite for all positive `N`. - - EXAMPLES:: - - sage: R = IntegerModRing(18) - sage: R.is_finite() - True - """ - return True - def is_integral_domain(self, proof=None): """ Return ``True`` if and only if the order of ``self`` is prime. diff --git a/src/sage/rings/fraction_field_FpT.pxd b/src/sage/rings/fraction_field_FpT.pxd index 4c3a0812496..5029a49727c 100644 --- a/src/sage/rings/fraction_field_FpT.pxd +++ b/src/sage/rings/fraction_field_FpT.pxd @@ -2,10 +2,10 @@ from sage.libs.flint.types cimport nmod_poly_t from sage.rings.morphism cimport RingHomomorphism from sage.categories.morphism cimport Morphism -from sage.structure.element cimport Element, ModuleElement, RingElement +from sage.structure.element cimport Element, ModuleElement, FieldElement from sage.categories.map cimport Section -cdef class FpTElement(RingElement): +cdef class FpTElement(FieldElement): cdef nmod_poly_t _numer, _denom cdef bint initialized cdef long p diff --git a/src/sage/rings/fraction_field_FpT.pyx b/src/sage/rings/fraction_field_FpT.pyx index 4549fb9859c..1bfdc752861 100644 --- a/src/sage/rings/fraction_field_FpT.pyx +++ b/src/sage/rings/fraction_field_FpT.pyx @@ -11,7 +11,7 @@ from sage.libs.gmp.mpz cimport * from sage.rings.all import GF from sage.libs.flint.nmod_poly cimport * from sage.libs.flint.ulong_extras cimport n_jacobi -from sage.structure.element cimport Element, ModuleElement, RingElement +from sage.structure.element cimport Element, ModuleElement, FieldElement from sage.rings.integer_ring import ZZ from sage.rings.fraction_field import FractionField_generic, FractionField_1poly_field from sage.rings.finite_rings.integer_mod cimport IntegerMod_int @@ -83,9 +83,17 @@ class FpT(FractionField_1poly_field): """ return FpT_iter(self, bound, start) -cdef class FpTElement(RingElement): +cdef class FpTElement(FieldElement): """ An element of an FpT fraction field. + + TESTS:: + + sage: R. = GF(5)[] + sage: K = R.fraction_field() + sage: A. = K[] + sage: x.divides(x) # Testing ticket #27064 + True """ def __init__(self, parent, numer, denom=1, coerce=True, reduce=True): @@ -103,7 +111,7 @@ cdef class FpTElement(RingElement): sage: R(7) 2 """ - RingElement.__init__(self, parent) + super().__init__(parent) if coerce: numer = parent.poly_ring(numer) denom = parent.poly_ring(denom) diff --git a/src/sage/rings/function_field/differential.py b/src/sage/rings/function_field/differential.py new file mode 100644 index 00000000000..36ab1d03b46 --- /dev/null +++ b/src/sage/rings/function_field/differential.py @@ -0,0 +1,528 @@ +""" +Differentials of function fields + +Sage provides basic arithmetic and advanced computations with differentials on +global function fields. + +EXAMPLES: + +The module of differentials on a function field forms an one-dimensional vector space over +the function field:: + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: f = x + y + sage: g = 1 / y + sage: df = f.differential() + sage: dg = g.differential() + sage: dfdg = f.derivative() / g.derivative() + sage: df == dfdg * dg + True + sage: df + (x*y^2 + 1/x*y + 1) d(x) + sage: df.parent() + Space of differentials of Function field in y defined by y^3 + x^3*y + x + +We can compute a canonical divisor:: + + sage: k = df.divisor() + sage: k.degree() + 4 + sage: k.degree() == 2 * L.genus() - 2 + True + +Exact differentials vanish and logarithmic differentials are stable under the +Cartier operation:: + + sage: df.cartier() + 0 + sage: w = 1/f * df + sage: w.cartier() == w + True + +AUTHORS: + +- Kwankyu Lee (2017-04-30): initial version + +""" +#***************************************************************************** +# Copyright (C) 2016 Kwankyu Lee +# +# 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/ +#***************************************************************************** +from __future__ import absolute_import + +from sage.misc.latex import latex + +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.structure.element import ModuleElement +from sage.structure.richcmp import richcmp +from sage.sets.family import Family + +from sage.categories.modules import Modules + +class FunctionFieldDifferential(ModuleElement): + """ + Base class for differentials on function fields. + """ + pass + +class FunctionFieldDifferential_global(FunctionFieldDifferential): + """ + Differentials on global function fields. + + INPUT: + + - ``f`` -- element of the function field + + - ``t`` -- element of the function field; if `t` is not specified, `t` + is the generator of the base rational function field + + EXAMPLES:: + + sage: F.=FunctionField(GF(7)) + sage: f = x/(x^2 + x + 1) + sage: f.differential() + ((6*x^2 + 1)/(x^4 + 2*x^3 + 3*x^2 + 2*x + 1)) d(x) + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: y.differential() + (x*y^2 + 1/x*y) d(x) + """ + def __init__(self, parent, f, t=None): + """ + Initialize the differential `fdt`. + + TESTS:: + + sage: F.=FunctionField(GF(7)) + sage: f = x/(x^2 + x + 1) + sage: w = f.differential() + sage: TestSuite(w).run() + """ + ModuleElement.__init__(self, parent) + + if t is not None: + der = parent.function_field().derivation() + f *= der(t) + + self._f = f + + def _repr_(self): + """ + Return the string representation of the differential. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: y.differential() + (x*y^2 + 1/x*y) d(x) + + sage: F.=FunctionField(QQ) + sage: f = 1/x + sage: f.differential() + (-1/x^2) d(x) + """ + F = self.parent().function_field() + + if self._f.is_zero(): # zero differential + return '0' + + r = 'd({})'.format(F.base_field().gen()) + + if self._f.is_one(): + return r + + return '({})'.format(self._f) + ' ' + r + + def _latex_(self): + r""" + Return a latex representation of the differential. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: w = y.differential() + sage: latex(w) + \left( x y^{2} + \frac{1}{x} y \right)\, dx + """ + F = self.parent().function_field() + + if self._f.is_zero(): # zero differential + return '0' + + r = 'd{}'.format(F.base_field().gen()) + + if self._f.is_one(): + return r + + return '\\left(' + latex(self._f) + '\\right)\\,' + r + + def _richcmp_(self, other, op): + """ + Compare the differential and the other differential with respect to the + comparison operator. + + INPUT: + + - ``other`` -- differential + + - ``op`` -- comparison operator + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: w1 = y.differential() + sage: w2 = L(x).differential() + sage: w3 = (x*y).differential() + sage: w1 < w2 + False + sage: w2 < w1 + True + sage: w3 == x * w1 + y * w2 + True + + sage: F.=FunctionField(QQ) + sage: w1 = ((x^2+x+1)^10).differential() + sage: w2 = (x^2+x+1).differential() + sage: w1 < w2 + False + sage: w1 > w2 + True + sage: w1 == 10*(x^2+x+1)^9 * w2 + True + """ + return richcmp(self._f, other._f, op) + + def _add_(self, other): + """ + Return the sum of the differential and the other differential. + + INPUT: + + - ``other`` -- differential + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: w1 = y.differential() + sage: w2 = (1/y).differential() + sage: w1 + w2 + (((x^3 + 1)/x^2)*y^2 + 1/x*y) d(x) + + sage: F. = FunctionField(QQ) + sage: w1 = (1/x).differential() + sage: w2 = (x^2+1).differential() + sage: w1 + w2 + ((2*x^3 - 1)/x^2) d(x) + """ + W = self.parent() + return W.element_class(W, self._f + other._f) + + def _neg_(self): + """ + Return the negation of the differential. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: w1 = y.differential() + sage: w2 = (-y).differential() + sage: -w1 == w2 + True + + sage: F. = FunctionField(QQ) + sage: w1 = (1/x).differential() + sage: w2 = (-1/x).differential() + sage: -w1 == w2 + True + """ + W = self.parent() + return W.element_class(W, -self._f) + + def _rmul_(self, f): + """ + Return the differential multiplied by the element of the function + field. + + INPUT: + + - ``f`` -- element of the function field + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: w1 = (1/y).differential() + sage: w2 = (-1/y^2) * y.differential() + sage: w1 == w2 + True + + sage: F.=FunctionField(QQ) + sage: w1 = (x^2*(x^2+x+1)).differential() + sage: w2 = (x^2).differential() + sage: w3 = (x^2+x+1).differential() + sage: w1 == (x^2) * w3 + (x^2+x+1) * w2 + True + """ + W = self.parent() + return W.element_class(W, f * self._f) + + def divisor(self): + """ + Return the divisor of the differential. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: w = (1/y) * y.differential() + sage: w.divisor() + - Place (1/x, 1/x^3*y^2 + 1/x) + - Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1) + - Place (x, y) + + Place (x + 2, y + 3) + + Place (x^6 + 3*x^5 + 4*x^4 + 2*x^3 + x^2 + 3*x + 4, y + x^5) + + sage: F. = FunctionField(QQ) + sage: w = (1/x).differential() + sage: w.divisor() + -2*Place (x) + """ + F = self.parent().function_field() + x = F.base_field().gen() + return self._f.divisor() + (-2) * F(x).divisor_of_poles() + F.different() + + def residue(self, place): + """ + Return the residue of the differential at the place. + + INPUT: + + - ``place`` -- place of the function field + + OUTPUT: + + - an element of the residue field of the place + + EXAMPLES: + + We verify the residue theorem in a rational function field:: + + sage: F. = FunctionField(GF(4)) + sage: f = 0 + sage: while f == 0: + ....: f = F.random_element() + sage: w = 1/f * f.differential() + sage: d = f.divisor() + sage: s = d.support() + sage: sum([w.residue(p).trace() for p in s]) + 0 + + and also in an extension field:: + + sage: K. = FunctionField(GF(7)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: f = 0 + sage: while f == 0: + ....: f = L.random_element() + sage: w = 1/f * f.differential() + sage: d = f.divisor() + sage: s = d.support() + sage: sum([w.residue(p).trace() for p in s]) + 0 + """ + R,fr_R,to_R = place._residue_field() + + # Step 1: compute f such that fds equals this differential. + s = place.local_uniformizer() + dxds = ~(s.derivative()) + g = self._f * dxds + + # Step 2: compute c that is the coefficient of s^-1 in + # the power series expansion of f + r = g.valuation(place) + if r >= 0: + return R.zero() + else: + g_shifted = g * s**(-r) + c = g_shifted.higher_derivative(-r-1, s) + return to_R(c) + + def cartier(self): + """ + Return the image of the differential by the Cartier operator. + + The Cartier operator operates on differentials. Let `x` be a separating + element of the function field. If a differential `\omega` is written + `\omega=(f_0^p+f_1^px+\dots+f_{p-1}^px^{p-1})dx` (prime-power + representation), then the Cartier operator maps `\omega` to + `f_{p-1}dx`. It is known that this definition does not depend on the + choice of `x`. + + The Cartier operator has interesting properties. Notably, the set of + exact differentials is precisely the kernel of the Cartier operator and + logarithmic differentials are stable under the Cartier operation. + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: f = x/y + sage: w = 1/f * f.differential() + sage: w.cartier() == w + True + + sage: F. = FunctionField(GF(4)) + sage: f = x/(x^2+x+1) + sage: w = 1/f * f.differential() + sage: w.cartier() == w + True + """ + W = self.parent() + F = W.function_field() + der = F.higher_derivation() + power_repr = der._prime_power_representation(self._f) + return W.element_class(W, power_repr[-1]) + + def monomial_coefficients(self, copy=True): + """ + Return a dictionary whose keys are indices of basis + elements in the support of ``self`` and whose values + are the corresponding coefficients. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: d = y.differential() + sage: d + ((4*x/(x^7 + 3))*y^2 + ((4*x^7 + 1)/(x^8 + 3*x))*y + x^4/(x^7 + 3)) d(x) + sage: d.monomial_coefficients() + {0: (4*x/(x^7 + 3))*y^2 + ((4*x^7 + 1)/(x^8 + 3*x))*y + x^4/(x^7 + 3)} + """ + return {0: self._f} + +class DifferentialsSpace(UniqueRepresentation, Parent): + """ + Space of differentials of a function field. + + INPUT: + + - ``field`` -- function field + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: L.space_of_differentials() + Space of differentials of Function field in y defined by y^3 + x^3*y + x + """ + Element = FunctionFieldDifferential_global + + def __init__(self, field, category=None): + """ + Initialize the space of differentials of the function field. + + TESTS:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: W = L.space_of_differentials() + sage: TestSuite(W).run() + """ + Parent.__init__(self, base=field, category=Modules(field).FiniteDimensional().WithBasis().or_subcategory(category)) + + def _repr_(self): + """ + Return the string representation of the space of differentials. + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: w = y.differential() + sage: w.parent() + Space of differentials of Function field in y defined by y^3 + x^3*y + x + """ + return "Space of differentials of {}".format(self.base()) + + def _element_constructor_(self, f): + """ + Construct differential `df` in the space from `f`. + + INPUT: + + - ``f`` -- element of the function field + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: S = L.space_of_differentials() + sage: S(y) + (x*y^2 + 1/x*y) d(x) + sage: S(y) in S + True + sage: S(1) + 0 + """ + if f in self.base(): + return self.element_class(self, self.base().one(), f) + + raise ValueError + + def function_field(self): + """ + Return the function field to which the space of differentials + is attached. + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: S = L.space_of_differentials() + sage: S.function_field() + Function field in y defined by y^3 + x^3*y + x + """ + return self.base() + + def _an_element_(self): + """ + Return a differential. + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: S = L.space_of_differentials() + sage: S.an_element() # random + (x*y^2 + 1/x*y) d(x) + """ + F = self.base() + return self.element_class(self, F.one(), F.an_element()) + + def basis(self): + """ + Return a basis. + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: S = L.space_of_differentials() + sage: S.basis() + Family (d(x),) + """ + return Family([self.element_class(self, self.base().one())]) + diff --git a/src/sage/rings/function_field/divisor.py b/src/sage/rings/function_field/divisor.py new file mode 100644 index 00000000000..3835689b4df --- /dev/null +++ b/src/sage/rings/function_field/divisor.py @@ -0,0 +1,973 @@ +""" +Divisors of function fields + +Sage allows extensive computations with divisors on global function fields. + +EXAMPLES: + +The divisor of an element of the function field is the formal sum of poles and zeros +of the element with multiplicities:: + + sage: K. = FunctionField(GF(2)); R. = K[] + sage: L. = K.extension(t^3 + x^3*t + x) + sage: f = x/(y+1) + sage: f.divisor() + - Place (1/x, 1/x^3*y^2 + 1/x) + + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1) + + 3*Place (x, y) + - Place (x^3 + x + 1, y + 1) + +The Riemann-Roch space of a divisor can be computed. We can get a basis of +the space as a vector space over the constant field:: + + sage: p = L.places_finite()[0] + sage: q = L.places_infinite()[0] + sage: (3*p + 2*q).basis_function_space() + [1/x*y^2 + x^2, 1, 1/x] + +We verify the Riemann-Roch theorem:: + + sage: D = 3*p - q + sage: index_of_speciality = len(D.basis_differential_space()) + sage: D.dimension() == D.degree() - L.genus() + 1 + index_of_speciality + True + +AUTHORS: + +- Kwankyu Lee (2017-04-30): initial version + +""" +#***************************************************************************** +# Copyright (C) 2016 Kwankyu Lee +# +# 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/ +#***************************************************************************** +from __future__ import absolute_import + +import random + +from sage.misc.cachefunc import cached_method + +from sage.arith.all import lcm + +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.structure.element import ModuleElement +from sage.structure.richcmp import richcmp + +from sage.categories.homset import Hom +from sage.categories.morphism import SetMorphism +from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups + +from sage.matrix.constructor import matrix + +from sage.modules.free_module_element import vector + +from sage.rings.integer_ring import IntegerRing +from sage.rings.integer import Integer + +from .place import PlaceSet + +def divisor(field, data): + """ + Construct a divisor from the data. + + INPUT: + + - ``field`` -- function field + + - ``data`` -- dictionary of place and multiplicity pairs + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); R. = K[] + sage: F. = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: from sage.rings.function_field.divisor import divisor + sage: p, q, r = F.places() + sage: divisor(F, {p: 1, q: 2, r: 3}) + Place (1/x, 1/x^2*y + 1) + + 2*Place (x, (1/(x^3 + x^2 + x))*y^2) + + 3*Place (x + 1, y + 1) + """ + divisor_group = field.divisor_group() + return divisor_group.element_class(divisor_group, data) + +def prime_divisor(field, place, m=1): + """ + Construct a prime divisor from the place. + + INPUT: + + - ``field`` -- function field + + - ``place`` -- place of the function field + + - ``m`` -- (default: 1) a positive integer; multiplicity at the place + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); R. = K[] + sage: F. = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: p = F.places()[0] + sage: from sage.rings.function_field.divisor import prime_divisor + sage: d = prime_divisor(F, p) + sage: 3 * d == prime_divisor(F, p, 3) + True + """ + divisor_group = field.divisor_group() + return divisor_group.element_class(divisor_group, {place: Integer(m)}) + +class FunctionFieldDivisor(ModuleElement): + """ + Divisors of function fields. + + INPUT: + + - ``parent`` -- divisor group + + - ``data`` -- dict of place and multiplicity pairs + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); R. = K[] + sage: F. = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: f = x/(y+1) + sage: f.divisor() + Place (1/x, 1/x^4*y^2 + 1/x^2*y + 1) + + Place (1/x, 1/x^2*y + 1) + + 3*Place (x, (1/(x^3 + x^2 + x))*y^2) + - 6*Place (x + 1, y + 1) + """ + def __init__(self, parent, data): + """ + Initialize. + + TESTS:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: G = L.divisor_group() + sage: TestSuite(G).run() + """ + ModuleElement.__init__(self, parent) + self._data = data + + def _repr_(self, split=True): + """ + Return a string representation of the divisor. + + INPUT: + + - ``split`` -- boolean; if ``True``, split at the end of each place + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); R. = PolynomialRing(K) + sage: F. = K.extension(t^3-x^2*(x^2+x+1)^2) + sage: f = x/(y+1) + sage: d = f.divisor() + sage: d._repr_(split=False) + 'Place (1/x, 1/x^4*y^2 + 1/x^2*y + 1) + Place (1/x, 1/x^2*y + 1) + + 3*Place (x, (1/(x^3 + x^2 + x))*y^2) - 6*Place (x + 1, y + 1)' + """ + mul = '*' + plus = ' + ' + minus = ' - ' + + if split: + cr = '\n' + else: + cr = '' + + places = sorted(self._data) + + if len(places) == 0: + return '0' + + p = places.pop(0) + m = self._data[p] + if m == 1: + r = repr(p) + elif m == -1: + r = '- ' + repr(p) # seems more readable than `-` + else: # nonzero + r = repr(m) + mul + repr(p) + for p in places: + m = self._data[p] + if m == 1: + r += cr + plus + repr(p) + elif m == -1: + r += cr + minus + repr(p) + elif m > 0: + r += cr + plus + repr(m) + mul + repr(p) + elif m < 0: + r += cr + minus + repr(-m) + mul + repr(p) + return r + + def _richcmp_(self, other, op): + """ + Compare the divisor and the other divisor with respect to the operator. + + Divisors are compared lexicographically, viewed as lists of pairs of + place and multiplicity. + + INPUT: + + - ``other`` -- divisor + + - ``op`` -- comparison operator + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: pls1 = L.places() + sage: D1 = pls1[0] + pls1[1] + sage: D2 = pls1[1] + 2*pls1[2] + sage: (D1 < D2) == (not D2 < D1) + True + sage: D1 + D2 == D2 + D1 + True + """ + s = sorted(self._data) + o = sorted(other._data) + while s and o: + skey = s[-1] + okey = o[-1] + if skey == okey: + svalue = self._data[skey] + ovalue = other._data[okey] + if svalue == ovalue: + s.pop() + o.pop() + continue + return richcmp(svalue, ovalue, op) + return richcmp(skey, okey, op) + return richcmp(len(s), len(o), op) + + def _neg_(self): + """ + Return the additive inverse of the divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: f = x/(y+1) + sage: D = f.divisor() + sage: D + - Place (1/x, 1/x^3*y^2 + 1/x) + + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1) + + 3*Place (x, y) + - Place (x^3 + x + 1, y + 1) + sage: -D + Place (1/x, 1/x^3*y^2 + 1/x) + - Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1) + - 3*Place (x, y) + + Place (x^3 + x + 1, y + 1) + """ + divisor_group = self.parent() + data = {} + for place in self._data: + data[place] = -self._data[place] + return divisor_group.element_class(divisor_group, data) + + def _add_(self, other): + """ + Add the divisor to the other divisor. + + INPUT: + + - ``other`` -- divisor + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: f = x/(y+1) + sage: D = f.divisor() + sage: D + 2*D == 3*D + True + sage: 3*D - D == 2*D + True + """ + divisor_group = self.parent() + places = set(self.support()).union( set(other.support())) + data = {} + for place in places: + m = self.multiplicity(place) + other.multiplicity(place) + if m != 0: + data[place] = m + return divisor_group.element_class(divisor_group, data) + + def _rmul_(self, i): + """ + Multiply integer `i` to the divisor. + + INPUT: + + - ``i`` -- integer + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: f = x/(y+1) + sage: D = f.divisor() + sage: (-3)*(2*D) == -6*D + True + """ + divisor_group = self.parent() + data = {} + for place in self._data: + m = i * self._data[place] + if m != 0: + data[place] = m + return divisor_group.element_class(divisor_group, data) + + def dict(self): + """ + Return the dictionary representing the divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: f = x/(y+1) + sage: D = f.divisor() + sage: D.dict() + {Place (1/x, 1/x^3*y^2 + 1/x): -1, + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1): 1, + Place (x, y): 3, + Place (x^3 + x + 1, y + 1): -1} + """ + return self._data + + def list(self): + """ + Return the list of place and multiplicity pairs of the divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: f = x/(y+1) + sage: D = f.divisor() + sage: D.list() + [(Place (1/x, 1/x^3*y^2 + 1/x), -1), + (Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1), 1), + (Place (x, y), 3), + (Place (x^3 + x + 1, y + 1), -1)] + """ + return sorted(self._data.items()) + + def support(self): + """ + Return the support of the divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: f = x/(y+1) + sage: D = f.divisor() + sage: D.support() + [Place (1/x, 1/x^3*y^2 + 1/x), + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1), + Place (x, y), + Place (x^3 + x + 1, y + 1)] + """ + return sorted(self._data) + + def multiplicity(self, place): + """ + Return the multiplicity of the divisor at the place. + + INPUT: + + - ``place`` -- place of a function field + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: p1,p2 = L.places()[:2] + sage: D = 2*p1 - 3*p2 + sage: D.multiplicity(p1) + 2 + sage: D.multiplicity(p2) + -3 + """ + if not place in self._data: + return 0 + return self._data[place] + + def degree(self): + """ + Return the degree of the divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: p1,p2 = L.places()[:2] + sage: D = 2*p1 - 3*p2 + sage: D.degree() + -1 + """ + return sum([p.degree() * m for p, m in self.list()]) + + def dimension(self): + """ + Return the dimension of the Riemann-Roch space of the divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2-x^3-1) + sage: O = F.maximal_order() + sage: I = O.ideal(x-2) + sage: P1 = I.divisor().support()[0] + sage: Pinf = F.places_infinite()[0] + sage: D = 3*Pinf+2*P1 + sage: D.dimension() + 5 + """ + return len(self.basis_function_space()) + + def basis_function_space(self): + """ + Return a basis of the Riemann-Roch space of the divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = K[] + sage: F. = K.extension(t^2 - x^3 - 1) + sage: O = F.maximal_order() + sage: I = O.ideal(x-2) + sage: D = I.divisor() + sage: D.basis_function_space() + [x/(x + 3), 1/(x + 3)] + """ + basis,_ = self._function_space() + return basis + + @cached_method + def function_space(self): + """ + Return the vector space of the Riemann-Roch space of the divisor. + + OUTPUT: + + - a vector space, an isomorphism from the vector space + to the Riemann-Roch space, and its inverse. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2-x^3-1) + sage: O = F.maximal_order() + sage: I = O.ideal(x-2) + sage: D = I.divisor() + sage: V, from_V, to_V = D.function_space() + sage: all(to_V(from_V(e)) == e for e in V) + True + """ + F = self.parent()._field + k = F.constant_base_field() + + basis, coordinates = self._function_space() + + n = len(basis) + V = k ** n + + def from_V(v): + return sum(v[i] * basis[i] for i in range(n)) + + def to_V(f): + return vector(coordinates(f)) + + from sage.rings.function_field.maps import ( + FunctionFieldLinearMap, FunctionFieldLinearMapSection) + + mor_from_V = FunctionFieldLinearMap(Hom(V,F), from_V) + mor_to_V = FunctionFieldLinearMapSection(Hom(F,V), to_V) + + return V, mor_from_V, mor_to_V + + @cached_method + def _function_space(self): + """ + Return an (echelon) basis and coordinates function for the Riemann-Roch + space of the divisor. + + The return values are cached so that :meth:`basis_function_space` and + :meth:`function_space` methods give consistent outputs. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2-x^3-1) + sage: O = F.maximal_order() + sage: I = O.ideal(x-2) + sage: D = I.divisor() + sage: basis, coordinates = D._function_space() + sage: basis + [x/(x + 3), 1/(x + 3)] + sage: coordinates(basis[0]) + [1, 0] + sage: coordinates(basis[1]) + [0, 1] + sage: coordinates(basis[0] + basis[1]) + [1, 1] + sage: coordinates((x + 4)/(x + 3)) + [1, 4] + """ + basis, coordinates_func = self._echelon_basis(self._basis()) + + return basis, coordinates_func + + def basis_differential_space(self): + """ + Return a basis of the space of differentials `\Omega(D)` + for the divisor `D`. + + EXAMPLES: + + We check the Riemann-Roch theorem:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: d = 3*L.places()[0] + sage: l = len(d.basis_function_space()) + sage: i = len(d.basis_differential_space()) + sage: l == d.degree() + 1 - L.genus() + i + True + """ + F = self.parent()._field + W = F.space_of_differentials() + + fbasis, _ = self._differential_space() + return [W.element_class(W, f) for f in fbasis] + + def differential_space(self): + """ + Return the vector space of the differential space `\Omega(D)` of the divisor `D`. + + OUTPUT: + + - a vector space isomorphic to `\Omega(D)` + + - an isomorphism from the vector space to the differential space + + - the inverse of the isomorphism + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = K[] + sage: F. = K.extension(t^2 - x^3 - 1) + sage: O = F.maximal_order() + sage: I = O.ideal(x - 2) + sage: P1 = I.divisor().support()[0] + sage: Pinf = F.places_infinite()[0] + sage: D = -3*Pinf + P1 + sage: V, from_V, to_V = D.differential_space() + sage: all(to_V(from_V(e)) == e for e in V) + True + """ + F = self.parent()._field + W = F.space_of_differentials() + k = F.constant_base_field() + + fbasis, coordinates = self._differential_space() + + n = len(fbasis) + V = k ** n + + def from_V(v): + f = sum(v[i] * fbasis[i] for i in range(n)) + return W.element_class(W, f) + + def to_V(w): + return vector(coordinates(w._f)) + + from sage.rings.function_field.maps import ( + FunctionFieldLinearMap, FunctionFieldLinearMapSection) + + mor_from_V = FunctionFieldLinearMap(Hom(V,W), from_V) + mor_to_V = FunctionFieldLinearMapSection(Hom(W,V), to_V) + + return V, mor_from_V, mor_to_V + + @cached_method + def _differential_space(self): + """ + Return an (echelon) basis and coordinates function for the differential + space of the divisor. + + The return values are cached so that :meth:`basis_differential_space` and + :meth:`differential_space` methods give consistent outputs. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2-x^3-1) + sage: O = F.maximal_order() + sage: I = O.ideal(x-2) + sage: D = -I.divisor() + sage: basis, coordinates = D._differential_space() + sage: basis + [(x/(x^4 + 3*x^3 + x + 3))*y, (1/(x^4 + 3*x^3 + x + 3))*y] + sage: D.basis_differential_space() + [((x/(x^4 + 3*x^3 + x + 3))*y) d(x), ((1/(x^4 + 3*x^3 + x + 3))*y) d(x)] + sage: coordinates(basis[0]) + [1, 0] + sage: coordinates(basis[1]) + [0, 1] + sage: coordinates(basis[0]+basis[1]) + [1, 1] + """ + F = self.parent()._field + x = F.base_field().gen() + d = (-2) * F(x).divisor_of_poles() + F.different() - self + + fbasis, coordinates = self._echelon_basis(d._basis()) + return fbasis, coordinates + + def _basis(self): + """ + Return a basis of the Riemann-Roch space of the divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2-x^3-1) + sage: O = F.maximal_order() + sage: I = O.ideal(x-2) + sage: D = I.divisor() + sage: D._basis() + [1/(x + 3), x/(x + 3)] + + This implements Hess' algorithm 6.1 in [Hes2002]_ + """ + F = self.parent()._field + n = F.degree() + O = F.maximal_order() + Oinf = F.maximal_order_infinite() + + # Step 1: The ideal I is the inverse of the product of prime ideals attached + # to the finite places in the divisor while the ideal J corresponds + # to the infinite places in the divisor. The later steps are basically + # to compute the intersection of the ideals I and J. + I = O.ideal(1) + J = Oinf.ideal(1) + for p in self._data: + m = self._data[p] + if p.is_infinite_place(): + J *= p.prime_ideal() ** (-m) + else: + I *= p.prime_ideal() ** (-m) + + # Step 2: construct matrix M of rational functions in x such that + # M * B == C where B = [b1,b1,...,bn], C =[v1,v2,...,vn] + V,fr,to = F.vector_space() + B = matrix([to(b) for b in J.gens_over_base()]) + C = matrix([to(v) for v in I.gens_over_base()]) + M = C * B.inverse() + + # Step 2.5: get the denonimator d of M and set mat = d * M + den = lcm([e.denominator() for e in M.list()]) + R = den.parent() # polynomial ring + one = R.one() + mat = matrix(R, n, [e.numerator() for e in (den*M).list()]) + gens = list(I.gens_over_base()) + + # Step 3: transform mat to a weak Popov form, together with gens + + # initialise pivot_row and conflicts list + pivot_row = [[] for i in range(n)] + conflicts = [] + for i in range(n): + bestp = -1 + best = -1 + for c in range(n): + d = mat[i,c].degree() + if d >= best: + bestp = c + best = d + + if best >= 0: + pivot_row[bestp].append((i,best)) + if len(pivot_row[bestp]) > 1: + conflicts.append(bestp) + + # while there is a conflict, do a simple transformation + while conflicts: + c = conflicts.pop() + row = pivot_row[c] + i,ideg = row.pop() + j,jdeg = row.pop() + + if jdeg > ideg: + i,j = j,i + ideg,jdeg = jdeg,ideg + + coeff = - mat[i,c].lc() / mat[j,c].lc() + s = coeff * one.shift(ideg - jdeg) + + mat.add_multiple_of_row(i, j, s) + gens[i] += s * gens[j] + + row.append((j,jdeg)) + + bestp = -1 + best = -1 + for c in range(n): + d = mat[i,c].degree() + if d >= best: + bestp = c + best = d + + if best >= 0: + pivot_row[bestp].append((i,best)) + if len(pivot_row[bestp]) > 1: + conflicts.append(bestp) + + # Step 4: build a Riemann-Roch basis from the data in mat and gens. + # Note that the values mat[i,j].degree() - den.degree() are known as + # invariants of M. + basis = [] + for j in range(n): + i,ideg = pivot_row[j][0] + for k in range( den.degree() - ideg + 1 ): + basis.append(one.shift(k) * gens[i]) + # Done! + return basis + + def _echelon_basis(self, basis): + """ + This is a helper method to compute an echelonized basis of the subspace + generated by ``basis`` over `k`. + + The entries of ``basis`` vectors are function field elements, viewed + as vectors of rational functions over `k`. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); _. = PolynomialRing(K) + sage: F. = K.extension(t^2 - x^3 - 1) + sage: D = F.divisor_group().zero() + sage: echelon_basis, coordinates = D._echelon_basis([x/y, (x + 1)/y]) + sage: echelon_basis + [(x/(x^3 + 1))*y, (1/(x^3 + 1))*y] + sage: f1, f2 = echelon_basis + sage: coordinates(f1) + [1, 0] + sage: coordinates(f2) + [0, 1] + sage: coordinates(x/y) + [1, 0] + sage: coordinates((x + 1)/y) + [1, 1] + sage: 1 * f1 + 1 * f2 == (x + 1)/y + True + """ + F = self.parent()._field + k = F.constant_base_field() + V, fr_V, to_V = F.vector_space() + n = V.degree() + m = len(basis) + + vbasis = [to_V(f) for f in basis] + + # compute the pivot position for nonzero vector v over rational functions + def pivot(v): + for i in range(n): + e = v[i] + if e != 0: + return (i,e.numerator().degree() - e.denominator().degree()) + + def greater(v,w): # v and w are not equal + return v[0] < w[0] or v[0] == w[0] and v[1] > w[1] + + # collate rows by their pivot position + pivot_rows = {} + for i in range(m): + p = pivot(vbasis[i]) + if p in pivot_rows: + pivot_rows[p].append(i) + else: + pivot_rows[p] = [i] + + # compute "echelon" basis in which pivot positions decrease strictly + nbasis = [] + npivots = [] + while pivot_rows: + pivots = list(pivot_rows) + + head = pivots[0] + for p in pivots[1:]: + if not greater(head,p): + head = p + + rows = pivot_rows[head] + if len(rows) > 1: + r = rows[0] + vr = vbasis[r][head[0]] + cr = vr.numerator().lc() / vr.denominator().lc() + for i in rows[1:]: + vi = vbasis[i][head[0]] + ci = vi.numerator().lc() / vi.denominator().lc() + vbasis[i] -= ci/cr * vbasis[r] + p = pivot(vbasis[i]) + if p in pivot_rows: + pivot_rows[p].append(i) + else: + pivot_rows[p] = [i] + nbasis.append(vbasis[rows[0]]) + npivots.append(head) + del pivot_rows[head] + + def coordinates(f): + v = to_V(f) + coords = [k(0) for i in range(m)] + while v != 0: + p = pivot(v) + ind = npivots.index(p) # an exception implies x is not in the domain + w = nbasis[ind] + cv = v[p[0]].numerator().lc() / v[p[0]].denominator().lc() + cw = w[p[0]].numerator().lc() / w[p[0]].denominator().lc() + c = cv/cw + v -= c * w + coords[ind] = c + return coords + + newbasis = [fr_V(f) for f in nbasis] + + return newbasis, coordinates + +class DivisorGroup(UniqueRepresentation, Parent): + """ + Groups of divisors of function fields. + + INPUT: + + - ``field`` -- function field + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); _. = PolynomialRing(K) + sage: F. = K.extension(t^2 - x^3 - 1) + sage: F.divisor_group() + Divisor group of Function field in y defined by y^2 + 4*x^3 + 4 + """ + Element = FunctionFieldDivisor + + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: K. = FunctionField(GF(5)); _. = PolynomialRing(K) + sage: F. = K.extension(t^2 - x^3 - 1) + sage: G = F.divisor_group() + sage: TestSuite(G).run() + """ + Parent.__init__(self, base=IntegerRing(), category=CommutativeAdditiveGroups()) + + self._field = field # function field + + def _repr_(self): + """ + Return the string representation of the group of divisors. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); _. = PolynomialRing(K) + sage: F. = K.extension(t^2 - x^3 - 1) + sage: F.divisor_group() + Divisor group of Function field in y defined by y^2 + 4*x^3 + 4 + """ + return "Divisor group of %s"%(self._field,) + + def _element_constructor_(self, x): + """ + Construct a divisor from ``x``. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); _. = PolynomialRing(K) + sage: F. = K.extension(t^2 - x^3 - 1) + sage: G = F.divisor_group() + sage: G(0) + 0 + """ + if x == 0: + return self.element_class(self, {}) + raise ValueError + + def _coerce_map_from_(self, S): + """ + Define coercions. + + EXAMPLES: + + A place is converted to a prime divisor:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2 - x^3 - 1) + sage: O = F.maximal_order() + sage: I = O.ideal(x + 1,y) + sage: P = I.place() + sage: y.divisor() + P + -3*Place (1/x, 1/x^2*y) + + 2*Place (x + 1, y) + + Place (x^2 + 4*x + 1, y) + """ + if isinstance(S, PlaceSet): + func = lambda place: prime_divisor(self._field, place) + return SetMorphism(Hom(S,self), func) + + def function_field(self): + """ + Return the function field to which the divisor group is attached. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); _. = PolynomialRing(K) + sage: F. = K.extension(t^2 - x^3 - 1) + sage: G = F.divisor_group() + sage: G.function_field() + Function field in y defined by y^2 + 4*x^3 + 4 + """ + return self._field + + def _an_element_(self): + """ + Return a divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: G = L.divisor_group() + sage: G.an_element() # random + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1) + + 2*Place (x^2 + x + 1, y + x + 1) + + 2*Place (x^3 + x + 1, y + x^2) + + Place (x^3 + x^2 + 1, y + x^2 + 1) + """ + N = 10 + d = 1 + places = [] + while len(places) <= N: # collect at least N places + places += self._field.places(d) + d += 1 + e = self.element_class(self, {}) + for i in range(random.randint(0,N)): + e += random.choice(places) + return e diff --git a/src/sage/rings/function_field/element.pyx b/src/sage/rings/function_field/element.pyx index 6af8017a680..39ff0c78951 100644 --- a/src/sage/rings/function_field/element.pyx +++ b/src/sage/rings/function_field/element.pyx @@ -11,6 +11,28 @@ Arithmetic with rational functions:: sage: f = t - 1 sage: g = t^2 - 3 sage: h = f^2/g^3 + sage: h.valuation(t-1) + 2 + sage: h.valuation(t) + 0 + sage: h.valuation(t^2 - 3) + -3 + +Derivatives of elements in separable extensions:: + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: (y^3 + x).derivative() + ((x^2 + 1)/x^2)*y + (x^4 + x^3 + 1)/x^3 + +The divisor of an element of a global function field:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: y.divisor() + - Place (1/x, 1/x*y) + - Place (x, x*y) + + 2*Place (x + 1, x*y) AUTHORS: @@ -67,7 +89,7 @@ def make_FunctionFieldElement(parent, element_class, representing_element): sage: from sage.rings.function_field.element import make_FunctionFieldElement sage: K. = FunctionField(QQ) - sage: make_FunctionFieldElement(K, K._element_class, (x+1)/x) + sage: make_FunctionFieldElement(K, K.element_class, (x+1)/x) (x + 1)/x """ return element_class(parent, representing_element, reduce=False) @@ -318,6 +340,47 @@ cdef class FunctionFieldElement(FieldElement): R = self.parent().base_field().maximal_order() return all(a in R for a in self.minimal_polynomial()) + def differential(self): + """ + Return the differential `dx` where `x` is the element. + + EXAMPLES:: + + sage: K. = FunctionField(QQ) + sage: f = 1 / t + sage: f.differential() + (-1/t^2) d(t) + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x +1/x) + sage: (y^3 + x).differential() + (((x^2 + 1)/x^2)*y + (x^4 + x^3 + 1)/x^3) d(x) + """ + F = self.parent() + W = F.space_of_differentials() + return W.element_class(W, F.one(), self) + + def derivative(self): + """ + Return the derivative of the element. + + The derivative is with respect to the generator of the base rational + function field, over which the function field is a separable extension. + + EXAMPLES:: + + sage: K. = FunctionField(QQ) + sage: f = (t + 1) / (t^2 - 1/3) + sage: f.derivative() + (-t^2 - 2*t - 1/3)/(t^4 - 2/3*t^2 + 1/9) + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: (y^3 + x).derivative() + ((x^2 + 1)/x^2)*y + (x^4 + x^3 + 1)/x^3 + """ + D = self.parent().derivation() + return D(self) cdef class FunctionFieldElement_polymod(FunctionFieldElement): """ @@ -792,27 +855,43 @@ cdef class FunctionFieldElement_rational(FunctionFieldElement): """ return self._x.denominator() - def valuation(self, v): + def valuation(self, place): """ - Return the valuation of the element with respect to a prime element. + Return the valuation of the rational function at the place. + + Rational function field places are associated with irreducible + polynomials. INPUT: - - ``v`` -- a prime element of the function field + - ``place`` -- a place or an irreducible polynomial EXAMPLES:: sage: K. = FunctionField(QQ) - sage: f = (t-1)^2 * (t+1) / (t^2 - 1/3)^3 - sage: f.valuation(t-1) + sage: f = (t - 1)^2*(t + 1)/(t^2 - 1/3)^3 + sage: f.valuation(t - 1) 2 sage: f.valuation(t) 0 sage: f.valuation(t^2 - 1/3) -3 + + sage: K. = FunctionField(GF(2)) + sage: p = K.places_finite()[0] + sage: (1/x^2).valuation(p) + -2 """ - R = self._parent._ring - return self._x.valuation(R(self._parent(v)._x)) + from .place import FunctionFieldPlace + + if not isinstance(place, FunctionFieldPlace): + # place is an irreducible polynomial + R = self._parent._ring + return self._x.valuation(R(self._parent(place)._x)) + + prime = place.prime_ideal() + ideal = prime.ring().ideal(self) + return prime.valuation(ideal) def is_square(self): """ @@ -903,8 +982,191 @@ cdef class FunctionFieldElement_rational(FunctionFieldElement): assert self._x.denominator() == 1 return self.parent()(self._x.numerator().inverse_mod(f.numerator())) + @cached_method + def divisor(self): + """ + Return the divisor of the element. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)) + sage: f = 1/(x^3 + x^2 + x) + sage: f.divisor() + 3*Place (1/x) + - Place (x) + - Place (x^2 + x + 1) + """ + if self.is_zero(): + raise ValueError("divisor not defined for zero") + + F = self.parent() + I = F.maximal_order().ideal(self) + J = F.maximal_order_infinite().ideal(self) + return I.divisor() + J.divisor() + + def divisor_of_zeros(self): + """ + Return the divisor of zeros for the element. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)) + sage: f = 1/(x^3 + x^2 + x) + sage: f.divisor_of_zeros() + 3*Place (1/x) + """ + if self.is_zero(): + raise ValueError("divisor of zeros not defined for zero") + + F = self.parent() + I = F.maximal_order().ideal(self) + J = F.maximal_order_infinite().ideal(self) + return I.divisor_of_zeros() + J.divisor_of_zeros() + + def divisor_of_poles(self): + """ + Return the divisor of poles for the element. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)) + sage: f = 1/(x^3 + x^2 + x) + sage: f.divisor_of_poles() + Place (x) + + Place (x^2 + x + 1) + """ + if self.is_zero(): + raise ValueError("divisor of poles not defined for zero") + + F = self.parent() + I = F.maximal_order().ideal(self) + J = F.maximal_order_infinite().ideal(self) + return I.divisor_of_poles() + J.divisor_of_poles() + + def higher_derivative(self, i, separating_element=None): + """ + Return the `i`-th derivative of the element with respect to the + separating element. + + INPUT: + + - ``i`` -- nonnegative integer + + - ``separating_element`` -- separating element of the function field; + the default is the generator of the rational function field + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)) + sage: f = t^2 + sage: f.higher_derivative(2) + 1 + """ + D = self.parent().higher_derivation() + return D(self, i, separating_element) + cdef class FunctionFieldElement_global(FunctionFieldElement_polymod): """ Elements of global function fields """ - pass + def valuation(self, place): + """ + Return the valuation of the element at the place. + + INPUT: + + - ``place`` -- a place of the function field + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_infinite()[0] + sage: y.valuation(p) + -1 + """ + prime = place.prime_ideal() + ideal = prime.ring().ideal(self) + return prime.valuation(ideal) + + @cached_method + def divisor(self): + """ + Return the divisor for the element. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: y.divisor() + - Place (1/x, 1/x*y) + - Place (x, x*y) + + 2*Place (x + 1, x*y) + """ + if self.is_zero(): + raise ValueError("not defined for zero") + + F = self.parent() + I = F.maximal_order().ideal(self) + J = F.maximal_order_infinite().ideal(self) + return I.divisor() + J.divisor() + + def divisor_of_zeros(self): + """ + Return divisor of zeros for the element. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: (x/y).divisor_of_zeros() + 3*Place (x, x*y) + """ + if self.is_zero(): + raise ValueError("divisor of zeros not defined for zero") + + F = self.parent() + I = F.maximal_order().ideal(self) + J = F.maximal_order_infinite().ideal(self) + return I.divisor_of_zeros() + J.divisor_of_zeros() + + def divisor_of_poles(self): + """ + Return the divisor of poles for the element. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: (x/y).divisor_of_poles() + Place (1/x, 1/x*y) + 2*Place (x + 1, x*y) + """ + if self.is_zero(): + raise ValueError("divisor of poles not defined for zero") + + F = self.parent() + I = F.maximal_order().ideal(self) + J = F.maximal_order_infinite().ideal(self) + return I.divisor_of_poles() + J.divisor_of_poles() + + def higher_derivative(self, i, separating_element=None): + """ + Return the ``i``-th order higher derivative of the element with respect + to the separating element. + + INPUT: + + - ``i`` -- nonnegative integer + + - ``separating_element`` -- separating element of the function field; + the default is the generator of the base rational function field + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: (y^3 + x).higher_derivative(2) + 1/x^3*y + (x^6 + x^4 + x^3 + x^2 + x + 1)/x^5 + """ + D = self.parent().higher_derivation() + return D(self, i, separating_element) diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index 1905f4bbee0..3ca07dad4f5 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -105,6 +105,38 @@ sage: L.maximal_order_infinite().basis() (1, 1/x^2*y, 1/x^3*y^2, 1/x^4*y^3) +As an example of the most sophisticated computations that Sage can do with a +global function field, we compute all the Weierstrass places of the Klein +quartic over `\GF{2}` and gap numbers for ordinary places:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x^3*Y + x) + sage: L.genus() + 3 + sage: L.weierstrass_places() + [Place (1/x, 1/x^3*y^2 + 1/x), + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1), + Place (x, y), + Place (x + 1, (x^3 + 1)*y + x + 1), + Place (x^3 + x + 1, y + 1), + Place (x^3 + x + 1, y + x^2), + Place (x^3 + x + 1, y + x^2 + 1), + Place (x^3 + x^2 + 1, y + x), + Place (x^3 + x^2 + 1, y + x^2 + 1), + Place (x^3 + x^2 + 1, y + x^2 + x + 1)] + sage: L.gaps() + [1, 2, 3] + +The gap numbers for Weierstrass places are of course not ordinary:: + + sage: p1,p2,p3 = L.weierstrass_places()[:3] + sage: p1.gaps() + [1, 2, 4] + sage: p2.gaps() + [1, 2, 4] + sage: p3.gaps() + [1, 2, 4] + AUTHORS: - William Stein (2010): initial version @@ -146,6 +178,8 @@ from sage.rings.ring import Field from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.modules.free_module_element import vector + from sage.categories.homset import Hom from sage.categories.function_fields import FunctionFields @@ -644,6 +678,12 @@ def _test_derivation(self, **options): K = self.constant_base_field().some_elements() d = self.derivation() from itertools import product + # Non-zero + tester.assertFalse(d.is_zero()) + # Well-defined + if hasattr(self, "polynomial"): + f = self.polynomial() + tester.assertEqual(0, d(f)) # Leibniz's law for x,y in tester.some_elements(product(S, S)): tester.assertTrue(d(x*y) == x*d(y) + d(x)*y) @@ -871,6 +911,41 @@ def valuation(self, prime): from sage.rings.function_field.function_field_valuation import FunctionFieldValuation return FunctionFieldValuation(self, prime) + def space_of_differentials(self): + """ + Return the space of differentials attached to the function field. + + EXAMPLES:: + + sage: K. = FunctionField(QQ) + sage: K.space_of_differentials() + Space of differentials of Rational function field in t over Rational Field + + sage: K. = FunctionField(GF(5)); _. = K[] + sage: L. = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) + sage: L.space_of_differentials() + Space of differentials of Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + """ + from .differential import DifferentialsSpace + return DifferentialsSpace(self) + + def divisor_group(self): + """ + Return the group of divisors attached to the function field. + + EXAMPLES:: + + sage: K. = FunctionField(QQ) + sage: K.divisor_group() + Divisor group of Rational function field in t over Rational Field + + sage: K. = FunctionField(GF(5)); _. = K[] + sage: L. = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) + sage: L.divisor_group() + Divisor group of Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + """ + from .divisor import DivisorGroup + return DivisorGroup(self) class FunctionField_polymod(FunctionField): """ @@ -936,7 +1011,9 @@ class FunctionField_polymod(FunctionField): False False """ - def __init__(self, polynomial, names, element_class=FunctionFieldElement_polymod, category=FunctionFields()): + Element = FunctionFieldElement_polymod + + def __init__(self, polynomial, names, category=None): """ Create a function field defined as an extension of another function field by adjoining a root of a univariate polynomial. @@ -984,14 +1061,16 @@ def __init__(self, polynomial, names, element_class=FunctionFieldElement_polymod base_field = polynomial.base_ring() if not isinstance(base_field, FunctionField): raise TypeError("polynomial must be over a FunctionField") - self._element_class = element_class + self._base_field = base_field self._polynomial = polynomial - FunctionField.__init__(self, base_field, names=names, category = category) + FunctionField.__init__(self, base_field, names=names, + category=FunctionFields().or_subcategory(category)) self._hash = hash(polynomial) self._ring = self._polynomial.parent() + self._populate_coercion_lists_(coerce_list=[base_field, self._ring]) self._gen = self(self._ring.gen()) @@ -1026,8 +1105,8 @@ def _element_constructor_(self, x): y """ if isinstance(x, FunctionFieldElement): - return self._element_class(self, self._ring(x.element())) - return self._element_class(self, self._ring(x)) + return self.element_class(self, self._ring(x.element())) + return self.element_class(self, self._ring(x)) def gen(self, n=0): """ @@ -1440,28 +1519,51 @@ def polynomial(self): """ return self._polynomial - def is_separable(self): + def is_separable(self, base=None): r""" - Return whether the defining polynomial of the function field is - separable, i.e., whether the gcd of the defining polynomial and its - derivative is constant. + Return whether this is a separable extension of ``base``. + + INPUT: + + - ``base`` -- a function field from which this field has been created + as an extension or ``None`` (default: ``None``); if ``None``, then + return whether this is a separable extension over its base field. EXAMPLES:: - sage: K. = FunctionField(GF(5)); R. = K[] + sage: K. = FunctionField(GF(2)) + sage: R. = K[] + sage: L. = K.extension(y^2 - x) + sage: L.is_separable() + False + sage: R. = L[] + sage: M. = L.extension(z^3 - y) + sage: M.is_separable() + True + sage: M.is_separable(K) + False + + sage: K. = FunctionField(GF(5)) + sage: R. = K[] sage: L. = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) sage: L.is_separable() True - sage: K. = FunctionField(GF(5)); R. = K[] + sage: K. = FunctionField(GF(5)) + sage: R. = K[] sage: L. = K.extension(y^5 - 1) sage: L.is_separable() False """ - f = self.polynomial() - g = self.polynomial().derivative() - return f.gcd(g).degree() == 0 + if base is None: + base = self.base_field() + for k in self._intermediate_fields(base)[:-1]: + f = k.polynomial() + g = f.derivative() + if f.gcd(g).degree() != 0: + return False + return True def polynomial_ring(self): """ @@ -1793,14 +1895,32 @@ def genus(self): @cached_method def derivation(self): r""" - Return a derivation of the function field over the constant base field. + Return a generator of the space of derivations over the constant base + ring of this function field `K`. - A derivation on `R` is a map `R\to R` satisfying + A derivation on `K` is map `K\to K` with `D(\alpha+\beta)=D(\alpha)+D(\beta)` and `D(\alpha\beta)=\beta - D(\alpha)+\alpha D(\beta)` for all `\alpha, \beta \in R`. For a - function field which is a finite extension of `K(x)` with `K` perfect, - the derivations form a one-dimensional `K`-vector space generated by - the derivation returned by this method. + D(\alpha)+\alpha D(\beta)` for all `\alpha,\beta\in K`. + + If the base field `k` of `K` is perfect, then the derivations on `K` + form a one-dimensional `K`-vector space. (More generally, this is true + if `K` is separable over `k`, or in other words if the corresponding + curve is geometrically reduced over `k`; this is automatically the case + if `k` is perfect.) We apply the techniques from [GT1996]_ to find a + generator of this one-dimensional vector space, which is then returned + by the algorithm. + + ALGORITHM: + + If `K` is a separable extension of another function field `F` between + `K` and `k`, then Proposition 11 of [GT1996]_ describes how to compute + the unique extension of a derivation on `F` to `K`; we then apply this + algorithm to the generator of the space of derivations on `F`, which we + may calculate inductively. + If `K` is not given as a separable extension of another function field, + then we find a field isomorphic to `K` that is a separable extension of + a rational function field over `k` by using :meth:`separable_model`. + This part of the algorithm uses the assumption that `k` is perfect. EXAMPLES:: @@ -1812,6 +1932,7 @@ def derivation(self): From: Function field in y defined by y^2 + 2*x To: Function field in y defined by y^2 + 2*x Defn: y |--> 2/x*y + x |--> 1 sage: d(x) 1 sage: d(x^3) @@ -1821,27 +1942,29 @@ def derivation(self): sage: d(y) 2/x*y - Derivations are linear and satisfy Leibniz's law:: - - sage: d(x+y) == d(x) + d(y) - True - sage: d(x*y) == x*d(y) + y*d(x) - True + This also works for inseparable extensions:: - If the field is a separable extension of the base field, the derivation - extending a derivation of the base function field is uniquely - determined. Proposition 11 of [GT1996]_ describes how to compute the - extension. We apply the formula described there to the generator - of the space of derivations on the base field. + sage: R. = K[] + sage: L. = K.extension(y^3 - x) + sage: d = L.derivation(); d + Derivation map: + From: Function field in y defined by y^3 + 2*x + To: Function field in y defined by y^3 + 2*x + Defn: y |--> 1 + x |--> 0 + sage: d(x^2) + 0 + sage: d(y^2) + 2*y + sage: d(x*y) + x - The general inseparable case is not implemented yet (see :trac:`16562`, - :trac:`16564`.)` """ - from .maps import FunctionFieldDerivation_separable - if self.polynomial().gcd(self.polynomial().derivative()).is_one(): + from .maps import FunctionFieldDerivation_separable, FunctionFieldDerivation_inseparable + if self.is_separable(): return FunctionFieldDerivation_separable(self, self.base_ring().derivation()) else: - raise NotImplementedError("construction of separable models not implemented") + return FunctionFieldDerivation_inseparable(self) def _simple_model(self, name='v'): r""" @@ -2459,11 +2582,20 @@ class FunctionField_global(FunctionField_polymod): EXAMPLES:: - sage: K.=FunctionField(GF(5)); _.=K[] - sage: L.=K.extension(Y^3-(x^3-1)/(x^3-2)) + sage: K. = FunctionField(GF(5)); _. = K[] + sage: L. = K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) sage: L Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + + The defining equation needs not be monic:: + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension((1 - x)*Y^7 - x^3) + sage: L.gaps() + [1, 2, 3] """ + Element = FunctionFieldElement_global + def __init__(self, polynomial, names): """ Initialize. @@ -2474,8 +2606,11 @@ def __init__(self, polynomial, names): sage: L.=K.extension(Y^3-(x^3-1)/(x^3-2)) sage: TestSuite(L).run() """ - FunctionField_polymod.__init__(self, polynomial, names, - element_class=FunctionFieldElement_global) + from .place import FunctionFieldPlace_global + + FunctionField_polymod.__init__(self, polynomial, names) + + self._place_class = FunctionFieldPlace_global def maximal_order(self): """ @@ -2576,6 +2711,413 @@ def _inversion_isomorphism(self): return M, F2self*M2F, F2M*self2F + def place_set(self): + """ + Return the set of all places of the function field. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: L.place_set() + Set of places of Function field in y defined by y^2 + y + (x^2 + 1)/x + """ + from .place import PlaceSet + return PlaceSet(self) + + def residue_field(self, place, name=None): + """ + Return the residue field associated with the place along with the maps + from and to the residue field. + + INPUT: + + - ``place`` -- place of the function field + + - ``name`` -- string; name of the generator of the residue field + + The domain of the map to the residue field is the discrete valuation + ring associated with the place. + + The discrete valuation ring is defined as the ring of all elements of + the function field with nonnegative valuation at the place. The maximal + ideal is the set of elements of positive valuation. The residue field + is then the quotient of the discrete valuation ring by its maximal + ideal. + + If an element not in the valuation ring is applied to the map, an + exception ``TypeError`` is raised. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: R, fr_R, to_R = L.residue_field(p) + sage: R + Finite Field of size 2 + sage: f = 1 + y + sage: f.valuation(p) + -1 + sage: to_R(f) + Traceback (most recent call last): + ... + TypeError: ... + sage: (1+1/f).valuation(p) + 0 + sage: to_R(1 + 1/f) + 1 + sage: [fr_R(e) for e in R] + [0, 1] + """ + return place.residue_field(name=name) + + @cached_method + def higher_derivation(self): + """ + Return the higher derivation (also called the Hasse-Schmidt derivation) + for the function field. + + The higher derivation of the function field is uniquely determined with + respect to the separating element `x` of the base rational function + field `k(x)`. + + EXAMPLES:: + + sage: K.=FunctionField(GF(5)); _.=K[] + sage: L.=K.extension(Y^3 - (x^3 - 1)/(x^3 - 2)) + sage: L.higher_derivation() + Higher derivation map: + From: Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + To: Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) + """ + from .maps import FunctionFieldHigherDerivation_global + return FunctionFieldHigherDerivation_global(self) + + def places(self, degree=1): + """ + Return a list of the places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer (default: `1`) + + EXAMPLES:: + + sage: F. = GF(2) + sage: K. = FunctionField(F) + sage: R. = PolynomialRing(K) + sage: L. = K.extension(t^4 + t - x^5) + sage: L.places(1) + [Place (1/x, 1/x^4*y^3), Place (x, y), Place (x, y + 1)] + """ + return self.places_infinite(degree) + self.places_finite(degree) + + def places_finite(self, degree=1): + """ + Return a list of the finite places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer (default: `1`) + + EXAMPLES:: + + sage: F. = GF(2) + sage: K. = FunctionField(F) + sage: R. = PolynomialRing(K) + sage: L. = K.extension(t^4+t-x^5) + sage: L.places_finite(1) + [Place (x, y), Place (x, y + 1)] + """ + return list(self._places_finite(degree)) + + def _places_finite(self, degree): + """ + Return a generator of finite places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer + + EXAMPLES:: + + sage: F. = GF(2) + sage: K. = FunctionField(F) + sage: R. = PolynomialRing(K) + sage: L. = K.extension(t^4+t-x^5) + sage: L._places_finite(1) + + """ + O = self.maximal_order() + K = self.base_field() + + from sage.rings.integer import Integer + degree = Integer(degree) + + for d in degree.divisors(): + for p in K.places_finite(degree=d): + for prime,_,_ in O.decomposition(p.prime_ideal()): + place = prime.place() + if place.degree() == degree: + yield place + + def places_infinite(self, degree=1): + """ + Return a list of the infinite places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer (default: `1`) + + EXAMPLES:: + + sage: F. = GF(2) + sage: K. = FunctionField(F) + sage: R. = PolynomialRing(K) + sage: L. = K.extension(t^4+t-x^5) + sage: L.places_infinite(1) + [Place (1/x, 1/x^4*y^3)] + """ + return list(self._places_infinite(degree)) + + def _places_infinite(self, degree): + """ + Return a generator of *infinite* places with ``degree``. + + INPUT: + + - ``degree`` -- positive integer + + EXAMPLES:: + + sage: F. = GF(2) + sage: K. = FunctionField(F) + sage: R. = PolynomialRing(K) + sage: L. = K.extension(t^4+t-x^5) + sage: L._places_infinite(1) + + """ + Oinf = self.maximal_order_infinite() + for prime,_,_ in Oinf.decomposition(): + place = prime.place() + if place.degree() == degree: + yield place + + def different(self): + """ + Return the different of the function field. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); R. = PolynomialRing(K) + sage: F. = K.extension(t^3 - x^2*(x^2 + x + 1)^2) + sage: F.different() + 2*Place (x, (1/(x^3 + x^2 + x))*y^2) + + 2*Place (x^2 + x + 1, (1/(x^3 + x^2 + x))*y^2) + """ + O = self.maximal_order() + Oinf = self.maximal_order_infinite() + return O.different().divisor() + Oinf.different().divisor() + + def constant_field(self): + """ + Return the algebraic closure of the base constant field in the function + field. + + EXAMPLES:: + + sage: K. = FunctionField(GF(3)); _. = K[] + sage: L. = K.extension(y^5 - (x^3 + 2*x*y + 1/x)) + sage: L.constant_field() + Finite Field of size 3 + """ + return self.exact_constant_field()[0] + + def exact_constant_field(self, name='t'): + """ + Return the exact constant field and its embedding into the function field. + + INPUT: + + - ``name`` -- name (default: `t`) of the generator of the exact constant field + + EXAMPLES:: + + sage: K. = FunctionField(GF(3)); _. = K[] + sage: f = Y^2 - x*Y + x^2 + 1 # irreducible but not absolutely irreducible + sage: L. = K.extension(f) + sage: L.genus() + 0 + sage: L.exact_constant_field() + (Finite Field in t of size 3^2, Ring morphism: + From: Finite Field in t of size 3^2 + To: Function field in y defined by y^2 + 2*x*y + x^2 + 1 + Defn: t |--> y + x) + sage: (y+x).divisor() + 0 + """ + # A basis of the full constant field is obtained from + # computing a Riemann-Roch basis of zero divisor. + basis = self.divisor_group().zero().basis_function_space() + + dim = len(basis) + + for e in basis: + _min_poly = e.minimal_polynomial(name) + if _min_poly.degree() == dim: + break + k = self.constant_base_field() + R = k[name] + min_poly = R([k(c) for c in _min_poly.list()]) + + k_ext = k.extension(min_poly, name) + + if k_ext.is_prime_field(): + # The cover of the quotient ring k_ext is the integer ring + # whose generator is 1. This is different from the generator + # of k_ext. + embedding = k_ext.hom([self(1)], self) + else: + embedding = k_ext.hom([e], self) + + return k_ext, embedding + + def genus(self): + """ + Return the genus of the function field. + + EXAMPLES:: + + sage: F. = GF(16) + sage: K. = FunctionField(F); K + Rational function field in x over Finite Field in a of size 2^4 + sage: R. = PolynomialRing(K) + sage: L. = K.extension(t^4+t-x^5) + sage: L.genus() + 6 + + The genus is computed by the Hurwitz genus formula. + """ + k, _ = self.exact_constant_field() + different_degree = self.different().degree() # must be even + return different_degree // 2 - self.degree() / k.degree() + 1 + + def gaps(self): + """ + Return the gaps of the function field. + + These are the gaps at the ordinary places, that is, places which are + not Weierstrass places. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x^3 * Y + x) + sage: L.gaps() + [1, 2, 3] + """ + return self._weierstrass_places()[1] + + def weierstrass_places(self): + """ + Return all Weierstrass places of the function field. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x^3 * Y + x) + sage: L.weierstrass_places() + [Place (1/x, 1/x^3*y^2 + 1/x), + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1), + Place (x, y), + Place (x + 1, (x^3 + 1)*y + x + 1), + Place (x^3 + x + 1, y + 1), + Place (x^3 + x + 1, y + x^2), + Place (x^3 + x + 1, y + x^2 + 1), + Place (x^3 + x^2 + 1, y + x), + Place (x^3 + x^2 + 1, y + x^2 + 1), + Place (x^3 + x^2 + 1, y + x^2 + x + 1)] + """ + return self._weierstrass_places()[0].support() + + @cached_method + def _weierstrass_places(self): + """ + Return the Weierstrass places together with the gap sequence for + ordinary places. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x^3 * Y + x) + sage: len(L.weierstrass_places()) # indirect doctest + 10 + + This method implements Algorithm 30 in [Hes2002b]_. + """ + from sage.matrix.constructor import matrix + + W = self(self.base_field().gen()).differential().divisor() + basis = W._basis() + + if not basis: + return [], [] + d = len(basis) + + der = self.higher_derivation() + M = matrix([basis]) + e = 1 + gaps = [1] + while M.nrows() < d: + row = vector([der._derive(basis[i], e) for i in range(d)]) + if not row in M.row_space(): + M = matrix(M.rows() + [row]) + gaps.append(e+1) + e += 1 + + # This is faster than M.determinant(). Note that Mx + # is a matrix over univariate polynomial ring. + Mx = matrix(M.nrows(), [c._x for c in M.list()]) + detM = self(Mx.determinant() % self._polynomial) + + R = detM.divisor() + sum(gaps)*W # ramification divisor + + return R, gaps + + @cached_method + def completion(self, place, name=None, prec=None, gen_name=None): + """ + Return the completion of the function field at the place. + + INPUT: + + - ``place`` -- place + + - ``name`` -- string; name of the series variable + + - ``prec`` -- positive integer; default precision + + - ``gen_name`` -- string; name of the generator of the residue field; + used only when the place is non-rational + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: m = L.completion(p); m + Completion map: + From: Function field in y defined by y^2 + y + (x^2 + 1)/x + To: Laurent Series Ring in s over Finite Field of size 2 + sage: m(x,10) + s^2 + s^3 + s^4 + s^5 + s^7 + s^8 + s^9 + s^10 + O(s^12) + sage: m(y,10) + s^-1 + 1 + s^3 + s^5 + s^7 + O(s^9) + """ + from .maps import FunctionFieldCompletion_global + return FunctionFieldCompletion_global(self, place, name=name, prec=prec, gen_name=gen_name) + class FunctionField_global_integral(FunctionField_global): """ Global function fields defined by an irreducible and separable polynomial, @@ -2786,9 +3328,9 @@ class RationalFunctionField(FunctionField): To: Rational function field in tbar over Rational Field Defn: t |--> tbar """ - def __init__(self, constant_field, names, - element_class = FunctionFieldElement_rational, - category=FunctionFields()): + Element = FunctionFieldElement_rational + + def __init__(self, constant_field, names, category=None): """ Initialize. @@ -2814,14 +3356,19 @@ def __init__(self, constant_field, names, names = (names, ) if not constant_field.is_field(): raise TypeError("constant_field must be a field") - self._element_class = element_class + self._constant_field = constant_field - FunctionField.__init__(self, self, names=names, category = category) + + FunctionField.__init__(self, self, names=names, category=FunctionFields().or_subcategory(category)) + + from .place import FunctionFieldPlace_rational + self._place_class = FunctionFieldPlace_rational + R = constant_field[names[0]] self._hash = hash((constant_field, names)) self._ring = R - self._field = R.fraction_field() + hom = Hom(self._field, self) from .maps import FractionFieldToFunctionField self.register_coercion(hom.__make_element_class__(FractionFieldToFunctionField)(hom.domain(), hom.codomain())) @@ -2911,7 +3458,7 @@ def _element_constructor_(self, x): """ if isinstance(x, FunctionFieldElement): - return FunctionFieldElement_rational(self, self._field(x._x)) + return self.element_class(self, self._field(x._x)) try: x = self._field(x) except TypeError as Err: @@ -2921,7 +3468,7 @@ def _element_constructor_(self, x): except AttributeError: pass raise Err - return FunctionFieldElement_rational(self, x) + return self.element_class(self, x) def _to_constant_base_field(self, f): r""" @@ -3350,6 +3897,19 @@ def field(self): """ return self._field + def place_set(self): + """ + Return the set of all places of the function field. + + EXAMPLES:: + + sage: K. = FunctionField(GF(7)) + sage: K.place_set() + Set of places of Rational function field in t over Finite Field of size 7 + """ + from .place import PlaceSet + return PlaceSet(self) + @cached_method def maximal_order(self): """ @@ -3407,6 +3967,21 @@ def constant_base_field(self): constant_field = constant_base_field + def different(self): + """ + Return the different of the rational function field. + + For a rational function field, the different is simply the zero + divisor. + + EXAMPLES:: + + sage: K. = FunctionField(QQ) + sage: K.different() + 0 + """ + return self.divisor_group().zero() + def genus(self): """ Return the genus of the function field, namely 0. @@ -3479,6 +4054,7 @@ def derivation(self): Derivation map: From: Rational function field in x over Finite Field of size 3 To: Rational function field in x over Finite Field of size 3 + Defn: x |--> 1 sage: m(x) 1 @@ -3499,4 +4075,161 @@ class RationalFunctionField_global(RationalFunctionField): """ Rational function field over finite fields. """ - pass + def places(self, degree=1): + """ + Return all places of the degree. + + INPUT: + + - ``degree`` -- (default: 1) a positive integer + + EXAMPLES:: + + sage: F. = FunctionField(GF(5)) + sage: F.places() + [Place (1/x), + Place (x), + Place (x + 1), + Place (x + 2), + Place (x + 3), + Place (x + 4)] + """ + if degree == 1: + return [self.place_infinite()] + self.places_finite(degree) + else: + return self.places_finite(degree) + + def places_finite(self, degree=1): + """ + Return the finite places of the degree. + + INPUT: + + - ``degree`` -- (default: 1) a positive integer + + EXAMPLES:: + + sage: F. = FunctionField(GF(5)) + sage: F.places_finite() + [Place (x), Place (x + 1), Place (x + 2), Place (x + 3), Place (x + 4)] + """ + return list(self._places_finite(degree)) + + def _places_finite(self, degree=1): + """ + Return a generator for all monic irreducible polynomials of the degree. + + INPUT: + + - ``degree`` -- (default: 1) a positive integer + + EXAMPLES:: + + sage: F. = FunctionField(GF(5)) + sage: F._places_finite() + + """ + O = self.maximal_order() + R = O._ring + G = R.polynomials(of_degree=degree) + for g in G: + if not (g.is_monic() and g.is_irreducible()): + continue + yield O.ideal(g).place() + + def place_infinite(self): + """ + Return the unique place at infinity. + + EXAMPLES:: + + sage: F. = FunctionField(GF(5)) + sage: F.place_infinite() + Place (1/x) + """ + return self.maximal_order_infinite().prime_ideal().place() + + def residue_field(self, place, name=None): + """ + Return the residue field of the place along with the maps from + and to it. + + INPUT: + + - ``place`` -- place of the function field + + - ``name`` -- string; name of the generator of the residue field + + EXAMPLES:: + + sage: F. = FunctionField(GF(5)) + sage: p = F.places_finite(2)[0] + sage: R, fr_R, to_R = F.residue_field(p) + sage: R + Finite Field in z2 of size 5^2 + sage: to_R(x) in R + True + """ + return place.residue_field(name=name) + + @cached_method + def higher_derivation(self): + """ + Return the higher derivation for the function field. + + This is also called the Hasse-Schmidt derivation. + + EXAMPLES:: + + sage: F. = FunctionField(GF(5)) + sage: d = F.higher_derivation() + sage: [d(x^5,i) for i in range(10)] + [x^5, 0, 0, 0, 0, 1, 0, 0, 0, 0] + sage: [d(x^7,i) for i in range(10)] + [x^7, 2*x^6, x^5, 0, 0, x^2, 2*x, 1, 0, 0] + """ + from .maps import FunctionFieldHigherDerivation_rational + return FunctionFieldHigherDerivation_rational(self) + + @cached_method + def completion(self, place, name=None, prec=None, gen_name=None): + """ + Return the completion of the function field at the place + + INPUT: + + - ``place`` -- place + + - ``name`` -- string; name of the series variable + + - ``prec`` -- positive integer; default precision + + - ``gen_name`` -- string; name of the generator of the residue field; + used only when the place is non-rational + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)) + sage: p = K.places_finite()[0]; p + Place (x) + sage: m = K.completion(p); m + Completion map: + From: Rational function field in x over Finite Field of size 2 + To: Laurent Series Ring in s over Finite Field of size 2 + sage: m(1/(x+1)) + 1 + s + s^2 + s^3 + s^4 + s^5 + s^6 + s^7 + s^8 + s^9 + s^10 + s^11 + s^12 + + s^13 + s^14 + s^15 + s^16 + s^17 + s^18 + s^19 + O(s^20) + + sage: p = K.place_infinite(); p + Place (1/x) + sage: m = K.completion(p); m + Completion map: + From: Rational function field in x over Finite Field of size 2 + To: Laurent Series Ring in s over Finite Field of size 2 + sage: m(x) + s^-1 + O(s^19) + """ + from .maps import FunctionFieldCompletion_global + return FunctionFieldCompletion_global(self, place, name=name, prec=prec, gen_name=gen_name) + + diff --git a/src/sage/rings/function_field/function_field_valuation.py b/src/sage/rings/function_field/function_field_valuation.py index 7d78b17e07d..723e45e42f7 100644 --- a/src/sage/rings/function_field/function_field_valuation.py +++ b/src/sage/rings/function_field/function_field_valuation.py @@ -170,7 +170,7 @@ class FunctionFieldValuationFactory(UniqueFactory): isomorphisms to and from that function field EXAMPLES:: - + sage: K. = FunctionField(QQ) sage: v = K.valuation(1); v # indirect doctest (x - 1)-adic valuation @@ -202,7 +202,7 @@ def create_key_and_extra_args(self, domain, prime): The normalization is, however, not smart enough, to unwrap substitutions that turn out to be trivial:: - + sage: w = GaussValuation(R, QQ.valuation(2)) sage: w = K.valuation(w) sage: w is K.valuation((w, K.hom([~K.gen()]), K.hom([~K.gen()]))) @@ -227,7 +227,7 @@ def create_key_and_extra_args(self, domain, prime): # Instead, we return the key that was used to create prime # so the caller gets back a correctly cached version of prime if not hasattr(prime, "_factory_data"): - raise NotImplementedError("Valuations on function fields must be unique and come out of the FunctionFieldValuation factory but %r has been created by other means"%(prime,)) + raise NotImplementedError("Valuations on function fields must be unique and come out of the FunctionFieldValuation factory but %r has been created by other means" % (prime,)) return prime._factory_data[2], {} if prime in domain: @@ -246,7 +246,7 @@ def create_key_and_extra_args(self, domain, prime): if is_Ideal(prime): raise NotImplementedError("a place can not be given by an ideal yet") - raise NotImplementedError("argument must be a place or a pseudo-valuation on a supported subring but %r does not satisfy this for the domain %r"%(prime, domain)) + raise NotImplementedError("argument must be a place or a pseudo-valuation on a supported subring but %r does not satisfy this for the domain %r" % (prime, domain)) def create_key_and_extra_args_from_place(self, domain, generator): r""" @@ -276,9 +276,9 @@ def create_key_and_extra_args_from_place(self, domain, generator): # generator is a polynomial generator = domain._ring(generator) if not generator.is_monic(): - raise ValueError("place must be defined by a monic polynomiala but %r is not monic"%(generator,)) + raise ValueError("place must be defined by a monic polynomiala but %r is not monic" % (generator,)) if not generator.is_irreducible(): - raise ValueError("place must be defined by an irreducible polynomial but %r factors over %r"%(generator, domain._ring)) + raise ValueError("place must be defined by an irreducible polynomial but %r factors over %r" % (generator, domain._ring)) # we construct the corresponding valuation on the polynomial ring # with v(generator) = 1 from sage.rings.valuation.gauss_valuation import GaussValuation @@ -288,7 +288,7 @@ def create_key_and_extra_args_from_place(self, domain, generator): # generator is 1/x, the infinite place return (domain, (domain.valuation(domain.gen()), domain.hom(~domain.gen()), domain.hom(~domain.gen()))), {} else: - raise ValueError("a place must be given by an irreducible polynomial or the inverse of the generator; %r does not define a place over %r"%(generator, domain)) + raise ValueError("a place must be given by an irreducible polynomial or the inverse of the generator; %r does not define a place over %r" % (generator, domain)) def create_key_and_extra_args_from_valuation(self, domain, valuation): r""" @@ -320,7 +320,7 @@ def create_key_and_extra_args_from_valuation(self, domain, valuation): if domain.base_field() is not domain: vK = valuation.restriction(valuation.domain().base_ring()) if vK.domain() is not domain.base_field(): - raise ValueError("valuation must extend a valuation on the base field but %r extends %r whose domain is not %r"%(valuation, vK, domain.base_field())) + raise ValueError("valuation must extend a valuation on the base field but %r extends %r whose domain is not %r" % (valuation, vK, domain.base_field())) # Valuation is an approximant that describes a single valuation # on domain. # For uniqueness of valuations (which provides better caching @@ -335,14 +335,14 @@ def create_key_and_extra_args_from_valuation(self, domain, valuation): # does not have an element with valuation -infty extends to a # pseudo-valuation on K(x) if valuation.is_negative_pseudo_valuation(): - raise ValueError("there must not be an element of valuation -Infinity in the domain of valuation"%(valuation,)) + raise ValueError("there must not be an element of valuation -Infinity in the domain of valuation %r" % (valuation,)) return (domain, valuation), {} if valuation.domain().is_subring(domain.base_field()): # valuation is defined on a subring of this function field, try to lift it return self.create_key_and_extra_args(domain, valuation.extension(domain)) - raise NotImplementedError("extension of valuation from %r to %r not implemented yet"%(valuation.domain(), domain)) + raise NotImplementedError("extension of valuation from %r to %r not implemented yet" % (valuation.domain(), domain)) def create_key_and_extra_args_from_valuation_on_isomorphic_field(self, domain, valuation, to_valuation_domain, from_valuation_domain): r""" @@ -360,28 +360,28 @@ def create_key_and_extra_args_from_valuation_on_isomorphic_field(self, domain, v """ from sage.categories.function_fields import FunctionFields if valuation.domain() not in FunctionFields(): - raise ValueError("valuation must be defined over an isomorphic function field but %r is not a function field"%(valuation.domain(),)) + raise ValueError("valuation must be defined over an isomorphic function field but %r is not a function field" % (valuation.domain(),)) from sage.categories.homset import Hom if to_valuation_domain not in Hom(domain, valuation.domain()): - raise ValueError("to_valuation_domain must map from %r to %r but %r maps from %r to %r"%(domain, valuation.domain(), to_valuation_domain, to_valuation_domain.domain(), to_valuation_domain.codomain())) + raise ValueError("to_valuation_domain must map from %r to %r but %r maps from %r to %r" % (domain, valuation.domain(), to_valuation_domain, to_valuation_domain.domain(), to_valuation_domain.codomain())) if from_valuation_domain not in Hom(valuation.domain(), domain): - raise ValueError("from_valuation_domain must map from %r to %r but %r maps from %r to %r"%(valuation.domain(), domain, from_valuation_domain, from_valuation_domain.domain(), from_valuation_domain.codomain())) + raise ValueError("from_valuation_domain must map from %r to %r but %r maps from %r to %r" % (valuation.domain(), domain, from_valuation_domain, from_valuation_domain.domain(), from_valuation_domain.codomain())) if domain is domain.base(): if valuation.domain() is not valuation.domain().base() or valuation.domain().constant_base_field() != domain.constant_base_field(): - raise NotImplementedError("maps must be isomorphisms with a rational function field over the same base field, not with %r"%(valuation.domain(),)) + raise NotImplementedError("maps must be isomorphisms with a rational function field over the same base field, not with %r" % (valuation.domain(),)) if domain != valuation.domain(): # make it harder to create different representations of the same valuation # (nothing bad happens if we did, but >= and <= are only implemented when this is the case.) - raise NotImplementedError("domain and valuation.domain() must be the same rational function field but %r is not %r"%(domain, valuation.domain())) + raise NotImplementedError("domain and valuation.domain() must be the same rational function field but %r is not %r" % (domain, valuation.domain())) else: if domain.base() is not valuation.domain().base(): - raise NotImplementedError("domain and valuation.domain() must have the same base field but %r is not %r"%(domain.base(), valuation.domain().base())) + raise NotImplementedError("domain and valuation.domain() must have the same base field but %r is not %r" % (domain.base(), valuation.domain().base())) if to_valuation_domain != domain.hom([to_valuation_domain(domain.gen())]): - raise NotImplementedError("to_valuation_domain must be trivial on the base fields but %r is not %r"%(to_valuation_domain, domain.hom([to_valuation_domain(domain.gen())]))) + raise NotImplementedError("to_valuation_domain must be trivial on the base fields but %r is not %r" % (to_valuation_domain, domain.hom([to_valuation_domain(domain.gen())]))) if from_valuation_domain != valuation.domain().hom([from_valuation_domain(valuation.domain().gen())]): - raise NotImplementedError("from_valuation_domain must be trivial on the base fields but %r is not %r"%(from_valuation_domain, valuation.domain().hom([from_valuation_domain(valuation.domain().gen())]))) + raise NotImplementedError("from_valuation_domain must be trivial on the base fields but %r is not %r" % (from_valuation_domain, valuation.domain().hom([from_valuation_domain(valuation.domain().gen())]))) if to_valuation_domain(domain.gen()) == valuation.domain().gen(): raise NotImplementedError("to_valuation_domain seems to be trivial but trivial maps would currently break partial orders of valuations") @@ -430,7 +430,7 @@ def create_object(self, version, key, **extra_args): if domain is valuation.domain(): # we can not just return valuation in this case # as this would break uniqueness and pickling - raise ValueError("valuation must not be a valuation on domain yet but %r is a valuation on %r"%(valuation, domain)) + raise ValueError("valuation must not be a valuation on domain yet but %r is a valuation on %r" % (valuation, domain)) if domain.base_field() is domain: # valuation is a base valuation on K[x] that induces a valuation on K(x) @@ -449,7 +449,7 @@ def create_object(self, version, key, **extra_args): # valuation is a limit valuation that singles out an extension return parent.__make_element_class__(FunctionFieldFromLimitValuation)(parent, valuation, domain.polynomial(), extra_args['approximants']) - raise NotImplementedError("valuation on %r from %r on %r"%(domain, valuation, valuation.domain())) + raise NotImplementedError("valuation on %r from %r on %r" % (domain, valuation, valuation.domain())) FunctionFieldValuation = FunctionFieldValuationFactory("sage.rings.function_field.function_field_valuation.FunctionFieldValuation") @@ -577,8 +577,8 @@ def extensions(self, L): return reduce(add, A, []) elif L.constant_base_field() is not K.constant_base_field() and K.constant_base_field().is_subring(L): # subclasses should override this method and handle this case, so we never get here - raise NotImplementedError("Can not compute the extensions of %r from %r to %r since the base ring changes."%(self, self.domain(), L)) - raise NotImplementedError("extension of %r from %r to %r not implemented"%(self, K, L)) + raise NotImplementedError("Can not compute the extensions of %r from %r to %r since the base ring changes." % (self, self.domain(), L)) + raise NotImplementedError("extension of %r from %r to %r not implemented" % (self, K, L)) class RationalFunctionFieldValuation_base(FunctionFieldValuation_base): @@ -695,13 +695,13 @@ def __init__(self, parent, base_valuation): sage: from sage.rings.function_field.function_field_valuation import InducedRationalFunctionFieldValuation_base sage: isinstance(v, InducedRationalFunctionFieldValuation_base) True - + """ FunctionFieldValuation_base.__init__(self, parent) domain = parent.domain() if base_valuation.domain() is not domain._ring: - raise ValueError("base valuation must be defined on %r but %r is defined on %r"%(domain._ring, base_valuation, base_valuation.domain())) + raise ValueError("base valuation must be defined on %r but %r is defined on %r" % (domain._ring, base_valuation, base_valuation.domain())) self._base_valuation = base_valuation @@ -714,7 +714,7 @@ def uniformizer(self): sage: K. = FunctionField(QQ) sage: K.valuation(x).uniformizer() x - + """ return self.domain()(self._base_valuation.uniformizer()) @@ -806,11 +806,11 @@ def _repr_(self): if isinstance(self._base_valuation, AugmentedValuation_base): if self._base_valuation._base_valuation == GaussValuation(self.domain()._ring, TrivialValuation(self.domain().constant_base_field())): if self._base_valuation._mu == 1: - return "(%r)-adic valuation"%(self._base_valuation.phi()) + return "(%r)-adic valuation" % (self._base_valuation.phi()) vK = self._base_valuation.restriction(self._base_valuation.domain().base_ring()) if self._base_valuation == GaussValuation(self.domain()._ring, vK): return repr(vK) - return "Valuation on rational function field induced by %s"%self._base_valuation + return "Valuation on rational function field induced by %s" % self._base_valuation def extensions(self, L): r""" @@ -840,7 +840,7 @@ def extensions(self, L): # comes from an extension of the field of constants # Condition "L.base() is L" is important so we do not call this # code for extensions from K(x) to K(x)(y) - + # We extend the underlying valuation on the polynomial ring W = self._base_valuation.extensions(L._ring) return [L.valuation(w) for w in W] @@ -857,7 +857,7 @@ def _call_(self, f): sage: v = K.valuation(x) # indirect doctest sage: v((x+1)/x^2) -2 - + """ return self._base_valuation(f.numerator()) - self._base_valuation(f.denominator()) @@ -896,7 +896,7 @@ def simplify(self, f, error=None, force=False): Produce an element which differs from ``f`` by an element of valuation strictly greater than the valuation of ``f`` (or strictly greater than ``error`` if set.) - + If ``force`` is not set, then expensive simplifications may be avoided. EXAMPLES:: @@ -959,7 +959,7 @@ def _relative_size(self, f): of coefficients is going to lead to a significant shrinking of the coefficients of ``f``. - EXAMPLES:: + EXAMPLES:: sage: K. = FunctionField(QQ) sage: v = K.valuation(0) @@ -1012,13 +1012,13 @@ class FiniteRationalFunctionFieldValuation(InducedRationalFunctionFieldValuation def __init__(self, parent, base_valuation): r""" TESTS:: - + sage: K. = FunctionField(QQ) sage: v = K.valuation(x + 1) sage: from sage.rings.function_field.function_field_valuation import FiniteRationalFunctionFieldValuation sage: isinstance(v, FiniteRationalFunctionFieldValuation) True - + """ InducedRationalFunctionFieldValuation_base.__init__(self, parent, base_valuation) ClassicalFunctionFieldValuation_base.__init__(self, parent) @@ -1175,7 +1175,7 @@ class FunctionFieldMappedValuation_base(FunctionFieldValuation_base, MappedValua isomorphic function field. EXAMPLES:: - + sage: K. = FunctionField(GF(2)) sage: v = K.valuation(1/x); v Valuation at the infinite place @@ -1184,13 +1184,13 @@ class FunctionFieldMappedValuation_base(FunctionFieldValuation_base, MappedValua def __init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain): r""" TESTS:: - + sage: K. = FunctionField(GF(2)) sage: v = K.valuation(1/x) sage: from sage.rings.function_field.function_field_valuation import FunctionFieldMappedValuation_base sage: isinstance(v, FunctionFieldMappedValuation_base) True - + """ FunctionFieldValuation_base.__init__(self, parent) MappedValuation_base.__init__(self, parent, base_valuation) @@ -1269,7 +1269,7 @@ def _repr_(self): to_base = repr(self._to_base) if hasattr(self._to_base, '_repr_defn'): to_base = self._to_base._repr_defn().replace('\n', ', ') - return "%r (in %r after %s)"%(self._base_valuation, self._base_valuation.domain(), to_base) + return "%r (in %r after %s)" % (self._base_valuation, self._base_valuation.domain(), to_base) def is_discrete_valuation(self): r""" @@ -1296,7 +1296,7 @@ class FunctionFieldMappedValuationRelative_base(FunctionFieldMappedValuation_bas other function field is the identity on the constant field. EXAMPLES:: - + sage: K. = FunctionField(GF(2)) sage: v = K.valuation(1/x); v Valuation at the infinite place @@ -1305,17 +1305,17 @@ class FunctionFieldMappedValuationRelative_base(FunctionFieldMappedValuation_bas def __init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain): r""" TESTS:: - + sage: K. = FunctionField(GF(2)) sage: v = K.valuation(1/x) sage: from sage.rings.function_field.function_field_valuation import FunctionFieldMappedValuationRelative_base sage: isinstance(v, FunctionFieldMappedValuationRelative_base) True - + """ FunctionFieldMappedValuation_base.__init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain) if self.domain().constant_base_field() is not base_valuation.domain().constant_base_field(): - raise ValueError("constant fields must be identical but they differ for %r and %r"%(self.domain(), base_valuation.domain())) + raise ValueError("constant fields must be identical but they differ for %r and %r" % (self.domain(), base_valuation.domain())) def restriction(self, ring): r""" diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index a78afaf5da6..11b51706b4c 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -88,12 +88,10 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -import operator import itertools -from functools import reduce from sage.misc.cachefunc import cached_method -from sage.misc.lazy_import import lazy_import +from sage.misc.lazy_attribute import lazy_attribute from sage.structure.parent import Parent from sage.structure.element import Element @@ -108,12 +106,13 @@ from sage.rings.infinity import infinity from sage.rings.ideal import Ideal_generic -lazy_import('sage.matrix.constructor', 'matrix') +from sage.matrix.constructor import matrix +from .divisor import divisor class FunctionFieldIdeal(Element): """ - Fractional ideals of function fields. + Base class of fractional ideals of function fields. INPUT: @@ -208,6 +207,233 @@ def base_ring(self): """ return self.ring() + def place(self): + """ + Return the place associated with this prime ideal. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)) + sage: O = K.maximal_order() + sage: I = O.ideal(x^2 + x + 1) + sage: I.place() + Traceback (most recent call last): + ... + TypeError: not a prime ideal + sage: I = O.ideal(x^3+x+1) + sage: I.place() + Place (x^3 + x + 1) + + sage: K. = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x + 1)/(x^3 + 1)) + sage: p = I.factor()[0][0] + sage: p.place() + Place (1/x) + + sage: K. = FunctionField(GF(2)); _. = PolynomialRing(K) + sage: F. = K.extension(t^3-x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: [f.place() for f,_ in I.factor()] + [Place (x, (1/(x^3 + x^2 + x))*y^2), + Place (x^2 + x + 1, (1/(x^3 + x^2 + x))*y^2)] + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: [f.place() for f,_ in I.factor()] + [Place (x, x*y), Place (x + 1, x*y)] + + sage: K. = FunctionField(GF(3^2)); R. = PolynomialRing(K) + sage: F. = K.extension(t^3 + t^2 - x^4) + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(1/x) + sage: I.factor() + (Ideal (1/x,1/x^3*y^2) of Maximal infinite order of Function field + in y defined by y^3 + y^2 + 2*x^4)^3 + sage: J = I.factor()[0][0] + sage: J.is_prime() + True + sage: J.place() + Place (1/x, 1/x^3*y^2) + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(1/x) + sage: I.factor() + (Ideal (1/x,1/x*y) of Maximal infinite order of Function field in y + defined by y^2 + y + (x^2 + 1)/x)^2 + sage: J = I.factor()[0][0] + sage: J.is_prime() + True + sage: J.place() + Place (1/x, 1/x*y) + """ + if not self.is_prime(): + raise TypeError("not a prime ideal") + + place_set = self.ring().fraction_field().place_set() + return place_set.element_class(place_set, self) + + def factor(self): + """ + Return the factorization of this ideal. + + Subclass of this class should define :meth:`_factor` method that + returns a list of prime ideal and multiplicity pairs. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)) + sage: O = K.maximal_order() + sage: I = O.ideal(x^3*(x + 1)^2) + sage: I.factor() + (Ideal (x) of Maximal order of Rational function field in x + over Finite Field in z2 of size 2^2)^3 * + (Ideal (x + 1) of Maximal order of Rational function field in x + over Finite Field in z2 of size 2^2)^2 + + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x + 1)/(x^3 + 1)) + sage: I.factor() + (Ideal (1/x) of Maximal infinite order of Rational function field in x + over Finite Field in z2 of size 2^2)^2 + + sage: K. = FunctionField(GF(2)); _. = PolynomialRing(K) + sage: F. = K.extension(T^3 - x^2*(x^2 + x + 1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: I == I.factor().prod() + True + + sage: Oinf = F.maximal_order_infinite() + sage: f= 1/x + sage: I = Oinf.ideal(f) + sage: I.factor() + (Ideal (1/x,1/x^4*y^2 + 1/x^2*y + 1) of Maximal infinite order + of Function field in y defined by y^3 + x^6 + x^4 + x^2) * + (Ideal (1/x,1/x^2*y + 1) of Maximal infinite order + of Function field in y defined by y^3 + x^6 + x^4 + x^2) + """ + return Factorization(self._factor(), cr=True) + + def divisor(self): + """ + Return the divisor corresponding to the ideal. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)) + sage: O = K.maximal_order() + sage: I = O.ideal(x*(x + 1)^2/(x^2 + x + 1)) + sage: I.divisor() + Place (x) + 2*Place (x + 1) - Place (x + z2) - Place (x + z2 + 1) + + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x + 1)/(x^3 + 1)) + sage: I.divisor() + 2*Place (1/x) + + sage: K. = FunctionField(GF(2)); _. = PolynomialRing(K) + sage: F. = K.extension(T^3 - x^2*(x^2 + x + 1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: I.divisor() + 2*Place (x, (1/(x^3 + x^2 + x))*y^2) + + 2*Place (x^2 + x + 1, (1/(x^3 + x^2 + x))*y^2) + + sage: Oinf = F.maximal_order_infinite() + sage: I = Oinf.ideal(y) + sage: I.divisor() + -2*Place (1/x, 1/x^4*y^2 + 1/x^2*y + 1) + - 2*Place (1/x, 1/x^2*y + 1) + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: I.divisor() + - Place (x, x*y) + + 2*Place (x + 1, x*y) + + sage: Oinf = L.maximal_order_infinite() + sage: I = Oinf.ideal(y) + sage: I.divisor() + - Place (1/x, 1/x*y) + """ + if self.is_zero(): + raise ValueError("not defined for zero ideal") + + F = self.ring().fraction_field() + data = {prime.place(): multiplicity for prime, multiplicity in self._factor()} + return divisor(F, data) + + def divisor_of_zeros(self): + """ + Return the divisor of zeros corresponding to the ideal. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)) + sage: O = K.maximal_order() + sage: I = O.ideal(x*(x + 1)^2/(x^2 + x + 1)) + sage: I.divisor_of_zeros() + Place (x) + 2*Place (x + 1) + + sage: K. = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x + 1)/(x^3 + 1)) + sage: I.divisor_of_zeros() + 2*Place (1/x) + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: I.divisor_of_zeros() + 2*Place (x + 1, x*y) + """ + if self.is_zero(): + raise ValueError("not defined for zero ideal") + + F = self.ring().fraction_field() + data = {prime.place(): multiplicity for prime, multiplicity in self._factor() if multiplicity > 0} + return divisor(F, data) + + def divisor_of_poles(self): + """ + Return the divisor of poles corresponding to the ideal. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)) + sage: O = K.maximal_order() + sage: I = O.ideal(x*(x + 1)^2/(x^2 + x + 1)) + sage: I.divisor_of_poles() + Place (x + z2) + Place (x + z2 + 1) + + sage: K. = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x + 1)/(x^3 + 1)) + sage: I.divisor_of_poles() + 0 + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: O = L.maximal_order() + sage: I = O.ideal(y) + sage: I.divisor_of_poles() + Place (x, x*y) + """ + if self.is_zero(): + raise ValueError("not defined for zero ideal") + + F = self.ring().fraction_field() + data = {prime.place(): - multiplicity for prime, multiplicity in self._factor() if multiplicity < 0} + return divisor(F, data) class FunctionFieldIdeal_rational(FunctionFieldIdeal): """ @@ -479,23 +705,52 @@ def gens_over_base(self): """ return (self._gen,) - def factor(self): + def valuation(self, ideal): """ - Return the factorization of this ideal. + Return the valuation of the ideal at this prime ideal. + + INPUT: + + - ``ideal`` -- fractional ideal EXAMPLES:: - sage: K. = FunctionField(GF(4)) - sage: O = K.maximal_order() - sage: I = O.ideal(x^3*(x+1)^2) - sage: I.factor() - (Ideal (x) of Maximal order of Rational function field in x - over Finite Field in z2 of size 2^2)^3 * - (Ideal (x + 1) of Maximal order of Rational function field in x - over Finite Field in z2 of size 2^2)^2 + sage: F. = FunctionField(QQ) + sage: O = F.maximal_order() + sage: I = O.ideal(x^2*(x^2+x+1)^3) + sage: [f.valuation(I) for f,_ in I.factor()] + [2, 3] + """ + if not self.is_prime(): + raise TypeError("not a prime ideal") + + O = self.ring() + d = ideal.denominator() + return self._valuation(d*ideal) - self._valuation(O.ideal(d)) + + def _valuation(self, ideal): """ - factors = self._factor() - return Factorization(factors, cr=True) + Return the valuation of the integral ideal at this prime ideal. + + INPUT: + + - ``ideal`` -- ideal + + EXAMPLES:: + + sage: F. = FunctionField(QQ) + sage: O = F.maximal_order() + sage: p = O.ideal(x) + sage: p.valuation(O.ideal(x+1)) # indirect doctest + 0 + sage: p.valuation(O.ideal(x^2)) # indirect doctest + 2 + sage: p.valuation(O.ideal(1/x^3)) # indirect doctest + -3 + sage: p.valuation(O.ideal(0)) # indirect doctest + +Infinity + """ + return ideal.gen().valuation(self.gen()) def _factor(self): """ @@ -518,7 +773,6 @@ def _factor(self): factors.append( (self.ring().ideal(f), m) ) return factors - class FunctionFieldIdeal_module(FunctionFieldIdeal, Ideal_generic): """ A fractional ideal specified by a finitely generated module over @@ -1281,8 +1535,8 @@ def module(self): @cached_method def gens_over_base(self): """ - Return the generators of this ideal as a module over the - maximal order of the base rational function field. + Return the generators of this ideal as a module over the maximal order + of the base rational function field. EXAMPLES:: @@ -1299,11 +1553,28 @@ def gens_over_base(self): sage: I.gens_over_base() (x^3 + 1, y + x) """ + gens, d = self._gens_over_base + return tuple([~d * b for b in gens]) + + @lazy_attribute + def _gens_over_base(self): + """ + Return the generators of the integral ideal, which is the denominator + times the fractional ideal, together with the denominator. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); R. = K[] + sage: L. = K.extension(y^2 - x^3*y - x) + sage: O = L.maximal_order() + sage: I = O.ideal(1/y) + sage: I._gens_over_base + ([x, y], x) + """ gens = [] for row in self._hnf: gens.append(sum([c1*c2 for c1,c2 in zip(row, self._ring.basis())])) - denom_inv = ~self._denominator - return tuple([denom_inv * b for b in gens]) + return gens, self._denominator def gens(self): """ @@ -1393,7 +1664,9 @@ def _gens_two(self): hnf = self._hnf - norm = reduce(operator.mul, hnf.diagonal()) + norm = 1 + for e in hnf.diagonal(): + norm *= e if norm.is_constant(): # unit ideal return (F(1),) @@ -1557,59 +1830,6 @@ def ideal_below(self): return K.ideal(l) - def factor(self): - """ - Return the factorization of this ideal. - - EXAMPLES:: - - sage: K. = FunctionField(GF(2)); _. = PolynomialRing(K) - sage: F. = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(y) - sage: I == I.factor().prod() - True - - sage: K. = FunctionField(GF(2)); _. = K[] - sage: L. = K.extension(Y^2 + Y + x + 1/x) - sage: O = L.maximal_order() - sage: I = O.ideal(y) - sage: I == I.factor().prod() - True - """ - return Factorization(self._factor(), cr=True) - - def _factor(self): - """ - Return the factorization of this ideal. - - EXAMPLES:: - - sage: K. = FunctionField(GF(2)); _. = K[] - sage: F. = K.extension(t^3-x^2*(x^2+x+1)^2) - sage: O = F.maximal_order() - sage: I = O.ideal(y) - sage: I == I.factor().prod() # indirect doctest - True - """ - O = self.ring() - F = O.fraction_field() - o = F.base_field().maximal_order() - - # First we collect primes below self - d = self._denominator - i = d * self - - factors = [] - primes = set([o.ideal(p) for p,_ in d.factor()] + [p for p,_ in i.ideal_below().factor()]) - for prime in primes: - qs = [q[0] for q in O.decomposition(prime)] - for q in qs: - exp = q.valuation(self) - if exp != 0: - factors.append((q,exp)) - return factors - def norm(self): """ Return the norm of this fractional ideal. @@ -1650,7 +1870,10 @@ def norm(self): sage: i2.norm() == y.norm() True """ - return reduce(operator.mul, self.basis_matrix().diagonal()) + n = 1 + for e in self.basis_matrix().diagonal(): + n *= e + return n @cached_method def is_prime(self): @@ -1785,6 +2008,36 @@ def prime_below(self): """ return self._prime_below + def _factor(self): + """ + Return the factorization of this ideal. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: F. = K.extension(t^3-x^2*(x^2+x+1)^2) + sage: O = F.maximal_order() + sage: I = O.ideal(y) + sage: I == I.factor().prod() # indirect doctest + True + """ + O = self.ring() + F = O.fraction_field() + o = F.base_field().maximal_order() + + # First we collect primes below self + d = self._denominator + i = d * self + + factors = [] + primes = set([o.ideal(p) for p,_ in d.factor()] + [p for p,_ in i.ideal_below().factor()]) + for prime in primes: + qs = [q[0] for q in O.decomposition(prime)] + for q in qs: + exp = q.valuation(self) + if exp != 0: + factors.append((q,exp)) + return factors class FunctionFieldIdealInfinite(FunctionFieldIdeal): """ @@ -2002,27 +2255,6 @@ def gens_over_base(self): """ return (self._gen,) - def factor(self): - """ - Return the factorization of this ideal into prime ideals. - - EXAMPLES:: - - sage: K. = FunctionField(GF(2)) - sage: Oinf = K.maximal_order_infinite() - sage: I = Oinf.ideal((x+1)/(x^3+1)) - sage: I.factor() - (Ideal (1/x) of Maximal infinite order of Rational function field - in x over Finite Field of size 2)^2 - """ - g = ~(self.ring().fraction_field().gen()) - m = self._gen.denominator().degree() - self._gen.numerator().degree() - if m == 0: - factors = [] - else: - factors = [(self.ring().ideal(g), m)] - return Factorization(factors, cr=True) - def valuation(self, ideal): """ Return the valuation of ``ideal`` at this prime ideal. @@ -2050,6 +2282,25 @@ def valuation(self, ideal): else: return f.denominator().degree() - f.numerator().degree() + def _factor(self): + """ + Return the factorization of this ideal into prime ideals. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)) + sage: Oinf = K.maximal_order_infinite() + sage: I = Oinf.ideal((x+1)/(x^3+1)) + sage: I._factor() + [(Ideal (1/x) of Maximal infinite order of Rational function field in x + over Finite Field of size 2, 2)] + """ + g = ~(self.ring().fraction_field().gen()) + m = self._gen.denominator().degree() - self._gen.numerator().degree() + if m == 0: + return [] + else: + return [(self.ring().ideal(g), m)] class FunctionFieldIdealInfinite_module(FunctionFieldIdealInfinite, Ideal_generic): """ @@ -2654,33 +2905,27 @@ def prime_below(self): K = F.base_field() return K.maximal_order_infinite().prime_ideal() - def factor(self): + def valuation(self, ideal): """ - Return factorization of this ideal. + Return the valuation of ``ideal`` with respect to this prime ideal. - EXAMPLES:: + INPUT: - sage: K. = FunctionField(GF(2)); _. = PolynomialRing(K) - sage: F. = K.extension(t^3 - x^2*(x^2+x+1)^2) - sage: Oinf = F.maximal_order_infinite() - sage: f= 1/x - sage: I = Oinf.ideal(f) - sage: I.factor() - (Ideal (1/x,1/x^4*y^2 + 1/x^2*y + 1) of Maximal infinite order - of Function field in y defined by y^3 + x^6 + x^4 + x^2) * - (Ideal (1/x,1/x^2*y + 1) of Maximal infinite order - of Function field in y defined by y^3 + x^6 + x^4 + x^2) + - ``ideal`` -- fractional ideal - sage: K. = FunctionField(GF(2)); _. = K[] - sage: L. = K.extension(Y^2+Y+x+1/x) + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _. = K[] + sage: L.=K.extension(Y^2 + Y + x + 1/x) sage: Oinf = L.maximal_order_infinite() - sage: f= 1/x - sage: I = Oinf.ideal(f) - sage: I.factor() - (Ideal (1/x,1/x*y) of Maximal infinite order of Function field in y - defined by y^2 + y + (x^2 + 1)/x)^2 + sage: I = Oinf.ideal(y) + sage: [f.valuation(I) for f,_ in I.factor()] + [-1] """ - return Factorization(self._factor(), cr=True) + if not self.is_prime(): + raise TypeError("not a prime ideal") + + return self._ideal.valuation(self.ring()._to_iF(ideal)) def _factor(self): """ @@ -2693,44 +2938,22 @@ def _factor(self): sage: Oinf = F.maximal_order_infinite() sage: f= 1/x sage: I = Oinf.ideal(f) - sage: I.factor() # indirect doctest - (Ideal (1/x,1/x^4*y^2 + 1/x^2*y + 1) of Maximal infinite order - of Function field in y defined by y^3 + x^6 + x^4 + x^2) * - (Ideal (1/x,1/x^2*y + 1) of Maximal infinite order - of Function field in y defined by y^3 + x^6 + x^4 + x^2) + sage: I._factor() + [(Ideal (1/x,1/x^4*y^2 + 1/x^2*y + 1) of Maximal infinite order of Function field in y + defined by y^3 + x^6 + x^4 + x^2, 1), + (Ideal (1/x,1/x^2*y + 1) of Maximal infinite order of Function field in y + defined by y^3 + x^6 + x^4 + x^2, 1)] """ - O = self.ring() + if self._ideal.is_prime.is_in_cache() and self._ideal.is_prime(): + return [(self, 1)] + O = self.ring() factors = [] for iprime, exp in O._to_iF(self).factor(): prime = FunctionFieldIdealInfinite_global(O, iprime) factors.append((prime, exp)) - return factors - def valuation(self, ideal): - """ - Return the valuation of ``ideal`` with respect to this prime ideal. - - INPUT: - - - ``ideal`` -- fractional ideal - - EXAMPLES:: - - sage: K.=FunctionField(GF(2)); _. = K[] - sage: L.=K.extension(Y^2 + Y + x + 1/x) - sage: Oinf = L.maximal_order_infinite() - sage: I = Oinf.ideal(y) - sage: [f.valuation(I) for f,_ in I.factor()] - [-1] - """ - if not self.is_prime(): - raise TypeError("not a prime ideal") - - return self._ideal.valuation(self.ring()._to_iF(ideal)) - - class IdealMonoid(UniqueRepresentation, Parent): r""" The monoid of ideals in orders of function fields. diff --git a/src/sage/rings/function_field/maps.py b/src/sage/rings/function_field/maps.py index 80bd01208a4..d66d2d48963 100644 --- a/src/sage/rings/function_field/maps.py +++ b/src/sage/rings/function_field/maps.py @@ -25,6 +25,15 @@ ... ValueError: invalid morphism +For global function fields, which have positive characteristics, the higher +derivation is available:: + + sage: K. = FunctionField(GF(2)); _.=K[] + sage: L. = K.extension(Y^3+x+x^3*Y) + sage: h = L.higher_derivation() + sage: h(y^2, 2) + ((x^7 + 1)/x^2)*y^2 + x^3*y + AUTHORS: - William Stein (2010): initial version @@ -32,6 +41,8 @@ - Julian Rüth (2011-09-14, 2014-06-23, 2017-08-21): refactored class hierarchy; added derivation classes; morphisms to/from fraction fields +- Kwankyu Lee (2017-04-30): added higher derivations and completions + """ from __future__ import absolute_import #***************************************************************************** @@ -43,11 +54,21 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** - -from sage.categories.morphism import Morphism +from sage.categories.morphism import Morphism, SetMorphism from sage.categories.map import Map +from sage.categories.homset import Hom +from sage.categories.sets_cat import Sets + +from sage.rings.infinity import infinity from sage.rings.morphism import RingHomomorphism +from sage.modules.free_module_element import vector + +from sage.functions.other import binomial + +from sage.matrix.constructor import matrix + + class FunctionFieldDerivation(Map): r""" Base class for derivations on function fields. @@ -64,6 +85,7 @@ class FunctionFieldDerivation(Map): Derivation map: From: Rational function field in x over Rational Field To: Rational function field in x over Rational Field + Defn: x |--> 1 """ def __init__(self, K): r""" @@ -89,8 +111,6 @@ def __init__(self, K): if not is_FunctionField(K): raise ValueError("K must be a function field") self.__field = K - from sage.categories.homset import Hom - from sage.categories.sets_cat import Sets Map.__init__(self, Hom(K,K,Sets())) def _repr_type(self): @@ -131,6 +151,7 @@ class FunctionFieldDerivation_rational(FunctionFieldDerivation): Derivation map: From: Rational function field in x over Rational Field To: Rational function field in x over Rational Field + Defn: x |--> 1 """ def __init__(self, K, u): """ @@ -168,7 +189,7 @@ def _call_(self, x): sage: K. = FunctionField(QQ) sage: d = K.derivation() - sage: d(x) # indirect doctest + sage: d(x) # indirect doctest 1 sage: d(x^3) 3*x^2 @@ -184,6 +205,22 @@ def _call_(self, x): else: return self._u * self.codomain()(numerator / g**2) + def _repr_defn(self): + r""" + Helper method to print this map. + + TESTS:: + + sage: K. = FunctionField(QQ) + sage: K.derivation() # indirect doctest + Derivation map: + From: Rational function field in x over Rational Field + To: Rational function field in x over Rational Field + Defn: x |--> 1 + + """ + return "%s |--> %s"%(self.domain().variable_name(), self(self.domain().gen())) + class FunctionFieldDerivation_separable(FunctionFieldDerivation): """ Derivations of separable extensions. @@ -198,6 +235,7 @@ class FunctionFieldDerivation_separable(FunctionFieldDerivation): From: Function field in y defined by y^2 - x To: Function field in y defined by y^2 - x Defn: y |--> 1/2/x*y + x |--> 1 """ def __init__(self, L, d): """ @@ -222,12 +260,12 @@ def __init__(self, L, d): """ FunctionFieldDerivation.__init__(self, L) - f = self.domain().polynomial() - if not f.gcd(f.derivative()).is_one(): - raise ValueError("L must be a separable extension of its base field") + self._d = d + if not L.is_separable(): + raise ValueError("L must be a separable extension of its base field.") x = self.domain().gen() - + f = L.polynomial() self._d = d self._gen_image = - f.map_coefficients(lambda c: d(c))(x) / f.derivative()(x) @@ -274,6 +312,7 @@ def _repr_defn(self): From: Function field in y defined by y^2 - x To: Function field in y defined by y^2 - x Defn: y |--> 1/2/x*y + x |--> 1 sage: R. = L[] sage: M. = L.extension(z^2 - y) @@ -281,19 +320,633 @@ def _repr_defn(self): Derivation map: From: Function field in z defined by z^2 - y To: Function field in z defined by z^2 - y - Defn: y |--> 1/2/x*y - z |--> 1/4/x*z + Defn: z |--> 1/4/x*z + y |--> 1/2/x*y + x |--> 1 + """ base = self._d._repr_defn() - ret = '{} |--> {}'.format(self.domain().gen(), self._gen_image) + ret = "%s |--> %s"%(self.domain().variable_name(),self._gen_image) if base: - return base + '\n' + ret + return ret + "\n" + base else: return ret -class FunctionFieldVectorSpaceIsomorphism(Morphism): +class FunctionFieldDerivation_inseparable(FunctionFieldDerivation): + r""" + A generator of the space of derivations on ``L``. + + INPUT: + + - ``L`` -- a function field which is an inseparable extension of its base + field. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)) + sage: R. = K[] + sage: L. = K.extension(y^2 - x) + sage: d = L.derivation() + + This also works for iterated non-monic extensions:: + + sage: K. = FunctionField(GF(2)) + sage: R. = K[] + sage: L. = K.extension(y^2 - 1/x) + sage: R. = L[] + sage: M. = L.extension(z^2*y - x^3) + sage: M.derivation() + Derivation map: + From: Function field in z defined by y*z^2 + x^3 + To: Function field in z defined by y*z^2 + x^3 + Defn: z |--> 1 + y |--> 0 + x |--> 0 + + """ + def __init__(self, L): + r""" + Initialization. + + EXAMPLES:: + + sage: K. = FunctionField(GF(3)) + sage: R. = K[] + sage: L. = K.extension(y^3 - x) + sage: d = L.derivation() # indirect doctest + sage: type(d) + + + """ + from .function_field import is_FunctionField + if not is_FunctionField(L): + raise TypeError("L must be a function field") + FunctionFieldDerivation.__init__(self, L) + + if L.is_separable(): + raise ValueError("L must be an inseparable extension of its base field.") + M, self._f, self._t = L.separable_model() + self._d = M.derivation() + + def _call_(self, x): + r""" + Evaluate the derivation on ``x``. + + INPUT: + + - ``x`` -- an element of the function field + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)) + sage: R. = K[] + sage: L. = K.extension(y^2 - x) + sage: d = L.derivation() + sage: d(x) # indirect doctest + 0 + sage: d(y) + 1 + sage: d(y^2) + 0 + + """ + if x.is_zero(): + return self.codomain().zero() + return self._f(self._d(self._t(x))) + + def _repr_defn(self): + r""" + Helper method to print this map. + + TESTS:: + + sage: K. = FunctionField(GF(2)) + sage: R. = K[] + sage: L. = K.extension(y^2 - x) + sage: L.derivation() # indirect doctest + Derivation map: + From: Function field in y defined by y^2 + x + To: Function field in y defined by y^2 + x + Defn: y |--> 1 + x |--> 0 + sage: R. = L[] + sage: M. = L.extension(z^2 - y) + sage: M.derivation() + Derivation map: + From: Function field in z defined by z^2 + y + To: Function field in z defined by z^2 + y + Defn: z |--> 1 + y |--> 0 + x |--> 0 + + """ + ret = ["%s |--> %s"%(k.variable_name(), self(k.gen())) for k in self.domain()._intermediate_fields(self.domain().rational_function_field())] + return "\n".join(ret) + +class FunctionFieldHigherDerivation(Map): + """ + Base class of higher derivations on function fields. + + INPUT: + + - ``field`` -- function field on which the derivation operates + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: F.higher_derivation() + Higher derivation map: + From: Rational function field in x over Finite Field of size 2 + To: Rational function field in x over Finite Field of size 2 + """ + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: F. = FunctionField(GF(4)) + sage: h = F.higher_derivation() + sage: TestSuite(h).run(skip='_test_category') + """ + Map.__init__(self, Hom(field, field, Sets())) + + self._field = field + + # elements of a prime finite field do not have pth_root method + if field.constant_base_field().is_prime_field(): + self._pth_root_func = _pth_root_in_prime_field + else: + self._pth_root_func = _pth_root_in_finite_field + + def _repr_type(self): + """ + Return a string containing the type of the map. + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h # indirect doctest + Higher derivation map: + From: Rational function field in x over Finite Field of size 2 + To: Rational function field in x over Finite Field of size 2 + """ + return 'Higher derivation' + + def __eq__(self, other): + """ + Test if ``self`` equals ``other``. + + TESTS:: + + sage: F. = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: loads(dumps(h)) == h + True + """ + if isinstance(other, FunctionFieldHigherDerivation): + return self._field == other._field + return False + + +def _pth_root_in_prime_field(e): + """ + Return the `p`-th root of element ``e`` in a prime finite field. + + TESTS:: + + sage: from sage.rings.function_field.maps import _pth_root_in_prime_field + sage: p = 5 + sage: F. = GF(p) + sage: e = F.random_element() + sage: _pth_root_in_prime_field(e)^p == e + True + """ + return e + +def _pth_root_in_finite_field(e): + """ + Return the `p`-th root of element ``e`` in a finite field. + + TESTS:: + + sage: from sage.rings.function_field.maps import _pth_root_in_finite_field + sage: p = 3 + sage: F. = GF(p^2) + sage: e = F.random_element() + sage: _pth_root_in_finite_field(e)^p == e + True + """ + return e.pth_root() + +class FunctionFieldHigherDerivation_rational(FunctionFieldHigherDerivation): + """ + Higher derivations of rational function fields. + + INPUT: + + - ``field`` -- function field on which the derivation operates + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h + Higher derivation map: + From: Rational function field in x over Finite Field of size 2 + To: Rational function field in x over Finite Field of size 2 + sage: h(x^2,2) + 1 + """ + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: F. = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: TestSuite(h).run(skip='_test_category') + """ + FunctionFieldHigherDerivation.__init__(self, field) + + self._p = field.characteristic() + self._separating_element = field.gen() + + def _call_with_args(self, f, args=(), kwds={}): + """ + Call the derivation with args and kwds. + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h(x^2,2) # indirect doctest + 1 + """ + return self._derive(f, *args, **kwds) + + def _derive(self, f, i, separating_element=None): + """ + Return the `i`-th derivative of ``f`` with respect to the + separating element. + + This implements Hess' Algorithm 26 in [Hes2002b]_. + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h._derive(x^3,0) + x^3 + sage: h._derive(x^3,1) + x^2 + sage: h._derive(x^3,2) + x + sage: h._derive(x^3,3) + 1 + sage: h._derive(x^3,4) + 0 + """ + F = self._field + p = self._p + + if separating_element is None: + x = self._separating_element + derivative = lambda f: f.derivative() + else: + x = separating_element + xderinv = ~(x.derivative()) + derivative = lambda f: xderinv * f.derivative() + + prime_power_representation = self._prime_power_representation + + def derive(f, i): + # Step 1: zero-th derivative + if i == 0: + return f + # Step 2: + s = i % p + r = i // p + # Step 3: + e = f + while s > 0: + e = derivative(e) / F(s) + s -= 1 + # Step 4: + if r == 0: + return e + else: + # Step 5: + lambdas = prime_power_representation(e, x) + # Step 6 and 7: + der = 0 + for i in range(p): + mu = derive(lambdas[i], r) + der += mu**p * x**i + return der + + return derive(f, i) + + def _prime_power_representation(self, f, separating_element=None): + """ + Return `p`-th power representation of the element ``f``. + + Here `p` is the characteristic of the function field. + + This implements Hess' Algorithm 25. + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h._prime_power_representation(x^2 + x + 1) + [x + 1, 1] + sage: x^2 + x + 1 == _[0]^2 + _[1]^2 * x + True + """ + F = self._field + p = self._p + + if separating_element is None: + x = self._separating_element + derivative = lambda f: f.derivative() + else: + x = separating_element + xderinv = ~(x.derivative()) + derivative = lambda f: xderinv * f.derivative() + + # Step 1: + a = [f] + aprev = f + j = 1 + while j < p: + aprev = derivative(aprev) / F(j) + a.append(aprev) + j += 1 + # Step 2: + b = a + j = p - 2 + while j >= 0: + b[j] -= sum(binomial(i,j) * b[i] * x**(i-j) for i in range(j+1, p)) + j -= 1 + # Step 3 + return [self._pth_root(c) for c in b] + + def _pth_root(self, c): + """ + Return the `p`-th root of the rational function ``c``. + + INPUT: + + - ``c`` -- rational function + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: h = F.higher_derivation() + sage: h._pth_root((x^2+1)^2) + x^2 + 1 + """ + K = self._field + p = self._p + + R = K._field.ring() + + poly = c.numerator() + num = R([self._pth_root_func(poly[i]) for i in range(0, poly.degree()+1, p)]) + poly = c.denominator() + den = R([self._pth_root_func(poly[i]) for i in range(0, poly.degree()+1, p)]) + return K.element_class(K, num/den) + + +class FunctionFieldHigherDerivation_global(FunctionFieldHigherDerivation): """ - Base class for isomorphisms between function fields and vector spaces. + Higher derivations of global function fields. + + INPUT: + + - ``field`` -- function field on which the derivation operates + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: h + Higher derivation map: + From: Function field in y defined by y^3 + x^3*y + x + To: Function field in y defined by y^3 + x^3*y + x + sage: h(y^2, 2) + ((x^7 + 1)/x^2)*y^2 + x^3*y + """ + + def __init__(self, field): + """ + Initialize. + + TESTS:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: TestSuite(h).run(skip=['_test_category']) + """ + FunctionFieldHigherDerivation.__init__(self, field) + + self._p = field.characteristic() + self._separating_element = field(field.base_field().gen()) + + p = field.characteristic() + y = field.gen() + + # matrix for pth power map; used in _prime_power_representation method + self.__pth_root_matrix = matrix([(y**(i*p)).list() + for i in range(field.degree())]).transpose() + + # cache computed higher derivatives to speed up later computations + self._cache = {} + + def _call_with_args(self, f, args, kwds): + """ + Call the derivation with ``args`` and ``kwds``. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: h(y^2,2) # indirect doctest + ((x^7 + 1)/x^2)*y^2 + x^3*y + """ + return self._derive(f, *args, **kwds) + + def _derive(self, f, i, separating_element=None): + """ + Return ``i``-th derivative of ``f` with respect to the separating + element. + + This implements Hess' Algorithm 26 in [Hes2002b]_. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: y^3 + x^3*y + x + sage: h._derive(y^3,0) + x^3*y + x + sage: h._derive(y^3,1) + x^4*y^2 + 1 + sage: h._derive(y^3,2) + x^10*y^2 + (x^8 + x)*y + sage: h._derive(y^3,3) + (x^9 + x^2)*y^2 + x^7*y + sage: h._derive(y^3,4) + (x^22 + x)*y^2 + ((x^21 + x^14 + x^7 + 1)/x)*y + """ + F = self._field + p = self._p + frob = F.frobenius_endomorphism() # p-th power map + + if separating_element is None: + x = self._separating_element + derivative = lambda f: f.derivative() + else: + x = separating_element + xderinv = ~(x.derivative()) + derivative = lambda f: xderinv * f.derivative() + + try: + cache = self._cache[separating_element] + except KeyError: + cache = self._cache[separating_element] = {} + + def derive(f, i): + # Step 1: zero-th derivative + if i == 0: + return f + + # Step 1.5: use cached result if available + try: + return cache[f,i] + except KeyError: + pass + + # Step 2: + s = i % p + r = i // p + # Step 3: + e = f + while s > 0: + e = derivative(e) / F(s) + s -= 1 + # Step 4: + if r == 0: + der = e + else: + # Step 5: inlined self._prime_power_representation + a = [e] + aprev = e + j = 1 + while j < p: + aprev = derivative(aprev) / F(j) + a.append(aprev) + j += 1 + b = a + j = p - 2 + while j >= 0: + b[j] -= sum(binomial(k,j) * b[k] * x**(k-j) for k in range(j+1, p)) + j -= 1 + lambdas = [self._pth_root(c) for c in b] + + # Step 6 and 7: + der = 0 + xpow = 1 + for k in range(p): + mu = derive(lambdas[k], r) + der += frob(mu) * xpow + xpow *= x + + cache[f,i] = der + return der + + return derive(f, i) + + def _prime_power_representation(self, f, separating_element=None): + """ + Return `p`-th power representation of the element ``f``. + + Here `p` is the characteristic of the function field. + + This implements Hess' Algorithm 25 in [Hes2002b]_. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: b = h._prime_power_representation(y) + sage: y == b[0]^2 + b[1]^2 * x + True + """ + F = self._field + p = self._p + + if separating_element is None: + x = self._separating_element + derivative = lambda f: f.derivative() + else: + x = separating_element + xderinv = ~(x.derivative()) + derivative = lambda f: xderinv * f.derivative() + + # Step 1: + a = [f] + aprev = f + j = 1 + while j < p: + aprev = derivative(aprev) / F(j) + a.append(aprev) + j += 1 + # Step 2: + b = a + j = p - 2 + while j >= 0: + b[j] -= sum(binomial(i,j) * b[i] * x**(i-j) for i in range(j+1,p)) + j -= 1 + # Step 3 + return [self._pth_root(c) for c in b] + + def _pth_root(self, c): + """ + Return the `p`-th root of function field element ``c``. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: h = L.higher_derivation() + sage: h._pth_root((x^2 + y^2)^2) + y^2 + x^2 + """ + K = self._field.base_field() # rational function field + p = self._p + + coeffs = [] + for d in self.__pth_root_matrix.solve_right(vector(c.list())): + poly = d.numerator() + num = K([self._pth_root_func(poly[i]) for i in range(0, poly.degree()+1, p)]) + poly = d.denominator() + den = K([self._pth_root_func(poly[i]) for i in range(0, poly.degree()+1, p)]) + coeffs.append(num / den) + return self._field(coeffs) + +class FunctionFieldVectorSpaceIsomorphism(Morphism): + r""" + A base class for isomorphisms between function fields and vector spaces. EXAMPLES:: @@ -430,7 +1083,6 @@ def __init__(self, V, K): self._V = V self._K = K self._R = K.polynomial_ring() - from sage.categories.homset import Hom FunctionFieldVectorSpaceIsomorphism.__init__(self, Hom(V, K)) def _call_(self, v): @@ -543,7 +1195,6 @@ def __init__(self, K, V): self._K = K self._zero = K.base_ring()(0) self._n = K.degree() - from sage.categories.homset import Hom FunctionFieldVectorSpaceIsomorphism.__init__(self, Hom(K, V)) def _call_(self, x): @@ -861,7 +1512,6 @@ def section(self): """ - from sage.categories.all import Hom parent = Hom(self.codomain(), self.domain()) return parent.__make_element_class__(FractionFieldToFunctionField)(parent.domain(), parent.codomain()) @@ -920,7 +1570,274 @@ def section(self): To: Fraction Field of Univariate Polynomial Ring in x over Rational Field """ - from sage.categories.all import Hom parent = Hom(self.codomain(), self.domain()) return parent.__make_element_class__(FunctionFieldToFractionField)(parent) +class FunctionFieldCompletion(Map): + """ + Base class of completions on function fields. + """ + def _repr_type(self): + """ + Return a string containing the type of the map. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: m = L.completion(p) + sage: m # indirect doctest + Completion map: + From: Function field in y defined by y^2 + y + (x^2 + 1)/x + To: Laurent Series Ring in s over Finite Field of size 2 + """ + return 'Completion' + +class FunctionFieldCompletion_global(FunctionFieldCompletion): + """ + Completions on global functionf fields. + + INPUT: + + - ``field`` -- function field + + - ``place`` -- place of the function field + + - ``name`` -- string for the name of the series variable + + - ``prec`` -- positive integer; default precision + + - ``gen_name`` -- string; name of the generator of the residue + field; used only when place is non-rational + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: m = L.completion(p) + sage: m + Completion map: + From: Function field in y defined by y^2 + y + (x^2 + 1)/x + To: Laurent Series Ring in s over Finite Field of size 2 + sage: m(x) + s^2 + s^3 + s^4 + s^5 + s^7 + s^8 + s^9 + s^10 + s^12 + s^13 + + s^15 + s^16 + s^17 + s^19 + O(s^22) + sage: m(y) + s^-1 + 1 + s^3 + s^5 + s^7 + s^9 + s^13 + s^15 + s^17 + O(s^19) + sage: m(x*y) == m(x) * m(y) + True + sage: m(x+y) == m(x) + m(y) + True + + The variable name of the series can be supplied. If the place is not + rational such that the residue field is a proper extension of the constant + field, you can also specify the generator name of the extension:: + + sage: p2 = L.places_finite(2)[0] + sage: p2 + Place (x^2 + x + 1, x*y + 1) + sage: m2 = L.completion(p2, 't', gen_name='b') + sage: m2(x) + (b + 1) + t + t^2 + t^4 + t^8 + t^16 + O(t^20) + sage: m2(y) + b + b*t + b*t^3 + b*t^4 + (b + 1)*t^5 + (b + 1)*t^7 + b*t^9 + b*t^11 + + b*t^12 + b*t^13 + b*t^15 + b*t^16 + (b + 1)*t^17 + (b + 1)*t^19 + O(t^20) + """ + def __init__(self, field, place, name=None, prec=None, gen_name=None): + """ + Initialize. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: m = L.completion(p) + sage: m + Completion map: + From: Function field in y defined by y^2 + y + (x^2 + 1)/x + To: Laurent Series Ring in s over Finite Field of size 2 + """ + if name is None: + name = 's' # default + + if gen_name is None: + gen_name = 'a' # default + + k, from_k, to_k = place.residue_field(name=gen_name) + + self._place = place + self._gen_name = gen_name + + if prec == infinity: + raise NotImplementedError('infinite precision not yet supported') + else: # prec < infinity: + # if prec is None, the Laurent series ring provides default precision + from sage.rings.laurent_series_ring import LaurentSeriesRing + codomain = LaurentSeriesRing(k, name=name, default_prec=prec) + self._precision = codomain.default_prec() + + FunctionFieldCompletion.__init__(self, field, codomain) + + def _call_(self, f): + """ + Call the completion for f + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: m = L.completion(p) + sage: m(y) + s^-1 + 1 + s^3 + s^5 + s^7 + s^9 + s^13 + s^15 + s^17 + O(s^19) + """ + return self._expand(f, prec=None) + + def _call_with_args(self, f, args, kwds): + """ + Call the completion with ``args`` and ``kwds``. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: m = L.completion(p) + sage: m(x+y, 10) # indirect doctest + s^-1 + 1 + s^2 + s^4 + s^8 + O(s^9) + """ + return self._expand(f, *args, **kwds) + + def _expand(self, f, prec=None): + """ + Return the laurent series expansion of f with precision ``prec``. + + INPUT: + + - ``f`` -- element of the function field + + - ``prec`` -- positive integer; relative precision of the series + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: m = L.completion(p) + sage: m(x, prec=20) # indirect doctest + s^2 + s^3 + s^4 + s^5 + s^7 + s^8 + s^9 + s^10 + s^12 + s^13 + s^15 + + s^16 + s^17 + s^19 + O(s^22) + """ + if prec is None: + prec = self._precision + + place = self._place + F = place.function_field() + der = F.higher_derivation() + + k,from_k,to_k = place.residue_field(name=self._gen_name) + sep = place.local_uniformizer() + + val = f.valuation(place) + e = f * sep **(-val) + + coeffs = [to_k(der._derive(e, i, sep)) for i in range(prec)] + return self.codomain()(coeffs, val).add_bigoh(prec + val) + + def default_precision(self): + """ + Return the default precision. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: m = L.completion(p) + sage: m.default_precision() + 20 + """ + return self._precision + +class FunctionFieldRingMorphism(SetMorphism): + """ + Ring homomorphism. + """ + def _repr_(self): + """ + Return the string representaton of the map. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: R = p.valuation_ring() + sage: k, fr_k, to_k = R.residue_field() + sage: k + Finite Field of size 2 + sage: fr_k + Ring morphism: + From: Finite Field of size 2 + To: Valuation ring at Place (x, x*y) + """ + s = "Ring morphism:" + s += "\n From: {}".format(self.domain()) + s += "\n To: {}".format(self.codomain()) + return s + +class FunctionFieldLinearMap(SetMorphism): + """ + Linear map to function fields. + """ + def _repr_(self): + """ + Return the string representaton of the map. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2-x^3-1) + sage: O = F.maximal_order() + sage: I = O.ideal(x-2) + sage: D = I.divisor() + sage: V, from_V, to_V = D.function_space() + sage: from_V + Linear map: + From: Vector space of dimension 2 over Finite Field of size 5 + To: Function field in y defined by y^2 + 4*x^3 + 4 + """ + s = "Linear map:" + s += "\n From: {}".format(self.domain()) + s += "\n To: {}".format(self.codomain()) + return s + +class FunctionFieldLinearMapSection(SetMorphism): + """ + Section of linear map from function fields. + """ + def _repr_(self): + """ + Return the string representaton of the map. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2-x^3-1) + sage: O = F.maximal_order() + sage: I = O.ideal(x-2) + sage: D = I.divisor() + sage: V, from_V, to_V = D.function_space() + sage: to_V + Section of linear map: + From: Function field in y defined by y^2 + 4*x^3 + 4 + To: Vector space of dimension 2 over Finite Field of size 5 + """ + s = "Section of linear map:" + s += "\n From: {}".format(self.domain()) + s += "\n To: {}".format(self.codomain()) + return s + diff --git a/src/sage/rings/function_field/order.py b/src/sage/rings/function_field/order.py index d03903fe61e..9f6c1f1bc62 100644 --- a/src/sage/rings/function_field/order.py +++ b/src/sage/rings/function_field/order.py @@ -89,7 +89,6 @@ #***************************************************************************** from sage.misc.cachefunc import cached_method -from sage.misc.lazy_import import lazy_import from sage.modules.free_module_element import vector from sage.arith.all import lcm, gcd @@ -101,6 +100,9 @@ from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.categories.euclidean_domains import EuclideanDomains +from sage.matrix.special import block_matrix +from sage.matrix.constructor import matrix + from .ideal import ( IdealMonoid, FunctionFieldIdeal, @@ -111,9 +113,6 @@ FunctionFieldIdealInfinite_rational, FunctionFieldIdealInfinite_global) -lazy_import('sage.matrix.special', 'block_matrix') -lazy_import('sage.matrix.constructor', 'matrix') - class FunctionFieldOrder_base(CachedRepresentation, Parent): """ Base class for orders in function fields. diff --git a/src/sage/rings/function_field/place.py b/src/sage/rings/function_field/place.py new file mode 100644 index 00000000000..1c2222f5dd0 --- /dev/null +++ b/src/sage/rings/function_field/place.py @@ -0,0 +1,1073 @@ +""" +Places of function fields + +Places are defined for arbitrary function fields, but presently Sage can find +and compute with places only of rational function fields and global function +fields. + +The places of a function field correspond, one-to-one, to valuation rings +of the function field, each of which defines discrete valuation of the +elements of the function field. "Finite" places are in one-to-one +correspondence with the prime ideals of the finite maximal order while +places "at infinity" are in one-to-one correspondence with the prime ideals +of the infinite maximal order. + +EXAMPLES: + +All rational places of the function field can be computed:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: L.places() + [Place (1/x, 1/x^3*y^2 + 1/x), + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1), + Place (x, y)] + +The residue field associated with a place is given as an extension of the +constant field:: + + sage: F. = FunctionField(GF(2)) + sage: O = F.maximal_order() + sage: p = O.ideal(x^2 + x + 1).place() + sage: k, fr_k, to_k = p.residue_field() + sage: k + Finite Field in z2 of size 2^2 + +The isomorphisms are between the valuation ring and the residue field:: + + sage: fr_k + Ring morphism: + From: Finite Field in z2 of size 2^2 + To: Valuation ring at Place (x^2 + x + 1) + sage: to_k + Ring morphism: + From: Valuation ring at Place (x^2 + x + 1) + To: Finite Field in z2 of size 2^2 + +AUTHORS: + +- Kwankyu Lee (2017-04-30): initial version + +""" +#***************************************************************************** +# Copyright (C) 2016 Kwankyu Lee +# +# 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/ +#***************************************************************************** +from __future__ import absolute_import + +from sage.misc.cachefunc import cached_method + +from sage.arith.all import lcm + +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.structure.element import Element +from sage.structure.richcmp import richcmp + +from sage.categories.sets_cat import Sets + +from sage.modules.free_module_element import vector + +from sage.matrix.constructor import matrix + +class FunctionFieldPlace(Element): + """ + Places of function fields. + + INPUT: + + - ``field`` -- function field + + - ``prime`` -- prime ideal associated with the place + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _. = K[] + sage: L.=K.extension(Y^3 + x + x^3*Y) + sage: L.places_finite()[0] + Place (x, y) + """ + def __init__(self, parent, prime): + """ + Initialize the place. + + TESTS:: + + sage: K.=FunctionField(GF(2)); _. = K[] + sage: L.=K.extension(Y^3 + x + x^3*Y) + sage: p = L.places_finite()[0] + sage: TestSuite(p).run() + """ + Element.__init__(self, parent) + + self._prime = prime + + def __hash__(self): + """ + Return the hash of the place. + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _. = K[] + sage: L.=K.extension(Y^3 + x + x^3*Y) + sage: p = L.places_finite()[0] + sage: {p: 1} + {Place (x, y): 1} + """ + return hash((self.function_field(), self._prime)) + + def _repr_(self): + """ + Return the string representation of the place. + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: p = L.places_finite()[0] + sage: p + Place (x, y) + """ + try: + gens = self._prime.gens_two() + except AttributeError: + gens = self._prime.gens() + gens_str = ', '.join(repr(g) for g in gens) + return "Place ({})".format(gens_str) + + def _richcmp_(self, other, op): + """ + Compare the place with ``other`` place. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: p1, p2, p3 = L.places()[:3] + sage: p1 < p2 + True + sage: p2 < p1 + False + sage: p1 == p3 + False + """ + from sage.rings.function_field.order import FunctionFieldOrderInfinite + + # effect that places at infinity are ordered first + s = not isinstance(self._prime.ring(), FunctionFieldOrderInfinite) + o = not isinstance(other._prime.ring(), FunctionFieldOrderInfinite) + return richcmp((s, self._prime), (o, other._prime), op) + + def _acted_upon_(self, other, self_on_left): + """ + Define integer multiplication upon the prime divisor + of the place on the left. + + The output is a divisor. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2-x^3-1) + sage: O = F.maximal_order() + sage: I = O.ideal(x+1,y) + sage: P = I.place() + sage: -3*P + 5*P + 2*Place (x + 1, y) + """ + if self_on_left: + raise TypeError("only left multiplication by integers is allowed") + return other * self.divisor() + + def _add_(self, other): + """ + Return the divisor that is the sum of the place and ``other``. + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: p1, p2, p3 = L.places()[:3] + sage: p1 + p2 + p3 + Place (1/x, 1/x^3*y^2 + 1/x) + + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1) + + Place (x, y) + """ + from .divisor import prime_divisor + return prime_divisor(self.function_field(), self) + other + + def __radd__(self, other): + """ + Return the prime divisor of the place if ``other`` is zero. + + This is only to support the ``sum`` function, that adds + the argument to initial (int) zero. + + EXAMPLES:: + + sage: k.=GF(2) + sage: K.=FunctionField(k) + sage: sum(K.places_finite()) + Place (x) + Place (x + 1) + + Note that this does not work, as wanted:: + + sage: 0 + K.place_infinite() + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for +: ... + + The reason is that the ``0`` is a Sage integer, for which + the coercion system applies. + """ + if other == 0: + from .divisor import prime_divisor + return prime_divisor(self.function_field(), self) + raise NotImplementedError + + def function_field(self): + """ + Return the function field to which the place belongs. + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: p = L.places()[0] + sage: p.function_field() == L + True + """ + return self.parent()._field + + def prime_ideal(self): + """ + Return the prime ideal associated with the place. + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: p = L.places()[0] + sage: p.prime_ideal() + Ideal (1/x,1/x^3*y^2 + 1/x) of Maximal infinite order of Function field + in y defined by y^3 + x^3*y + x + """ + return self._prime + + def divisor(self, multiplicity=1): + """ + Return the prime divisor corresponding to the place. + + EXAMPLES:: + + sage: K. = FunctionField(GF(5)); R. = PolynomialRing(K) + sage: F. = K.extension(t^2-x^3-1) + sage: O = F.maximal_order() + sage: I = O.ideal(x+1,y) + sage: P = I.place() + sage: P.divisor() + Place (x + 1, y) + """ + from .divisor import prime_divisor + return prime_divisor(self.function_field(), self, multiplicity) + +class FunctionFieldPlace_rational(FunctionFieldPlace): + """ + Places of rational function field. + """ + def degree(self): + """ + Return the degree of the place. + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: O = F.maximal_order() + sage: i = O.ideal(x^2+x+1) + sage: p = i.place() + sage: p.degree() + 2 + """ + if self.is_infinite_place(): + return 1 + else: + return self._prime.gen().numerator().degree() + + def is_infinite_place(self): + """ + Return ``True`` if the place is at infinite. + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: F.places() + [Place (1/x), Place (x), Place (x + 1)] + sage: [p.is_infinite_place() for p in F.places()] + [True, False, False] + """ + F = self.function_field() + return self.prime_ideal().ring() == F.maximal_order_infinite() + + def local_uniformizer(self): + """ + Return a local uniformizer of the place. + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: F.places() + [Place (1/x), Place (x), Place (x + 1)] + sage: [p.local_uniformizer() for p in F.places()] + [1/x, x, x + 1] + """ + return self.prime_ideal().gen() + + def residue_field(self, name=None): + """ + Return the residue field of the place. + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: O = F.maximal_order() + sage: p = O.ideal(x^2 + x + 1).place() + sage: k, fr_k, to_k = p.residue_field() + sage: k + Finite Field in z2 of size 2^2 + sage: fr_k + Ring morphism: + From: Finite Field in z2 of size 2^2 + To: Valuation ring at Place (x^2 + x + 1) + sage: to_k + Ring morphism: + From: Valuation ring at Place (x^2 + x + 1) + To: Finite Field in z2 of size 2^2 + """ + return self.valuation_ring().residue_field(name=name) + + def _residue_field(self, name=None): + """ + Return the residue field of the place along with the maps from + and to it. + + INPUT: + + - ``name`` -- string; name of the generator of the residue field + + EXAMPLES:: + + sage: F. = FunctionField(GF(2)) + sage: O = F.maximal_order() + sage: i = O.ideal(x^2+x+1) + sage: p = i.place() + sage: R, fr, to = p._residue_field() + sage: R + Finite Field in z2 of size 2^2 + sage: [fr(e) for e in R.list()] + [0, x, x + 1, 1] + sage: to(x*(x+1)) == to(x) * to(x+1) + True + """ + F = self.function_field() + prime = self.prime_ideal() + + if self.is_infinite_place(): + K = F.constant_base_field() + + def from_K(e): + return F(e) + + def to_K(f): + n = f.numerator() + d = f.denominator() + + n_deg = n.degree() + d_deg =d.degree() + + if n_deg < d_deg: + return K(0) + elif n_deg == d_deg: + return n.lc() / d.lc() + else: + raise TypeError("not in the valuation ring") + else: + O = F.maximal_order() + K, from_K, _to_K = O._residue_field(prime, name=name) + + def to_K(f): + if f in O: # f.denominator() is 1 + return _to_K(f.numerator()) + else: + d = F(f.denominator()) + n = d * f + + nv = prime.valuation(O.ideal(n)) + dv = prime.valuation(O.ideal(d)) + + if nv > dv: + return K(0) + elif dv > nv: + raise TypeError("not in the valuation ring") + + s = ~prime.gen() + rd = d * s**dv # in O but not in prime + rn = n * s**nv # in O but not in prime + return to_K(rn) / to_K(rd) + + return K, from_K, to_K + + def valuation_ring(self): + """ + Return the valuation ring at the place. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: p.valuation_ring() + Valuation ring at Place (x, x*y) + """ + from .valuation_ring import FunctionFieldValuationRing_global + + return FunctionFieldValuationRing_global(self.function_field(), self) + +class FunctionFieldPlace_global(FunctionFieldPlace): + """ + Places of function fields + """ + def place_below(self): + """ + Return the place lying below the place. + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: OK = K.maximal_order() + sage: OL = L.maximal_order() + sage: p = OK.ideal(x^2 + x + 1) + sage: dec = OL.decomposition(p) + sage: q = dec[0][0].place() + sage: q.place_below() + Place (x^2 + x + 1) + """ + return self.prime_ideal().prime_below().place() + + def relative_degree(self): + """ + Return the relative degree of the place. + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: OK = K.maximal_order() + sage: OL = L.maximal_order() + sage: p = OK.ideal(x^2 + x + 1) + sage: dec = OL.decomposition(p) + sage: q = dec[0][0].place() + sage: q.relative_degree() + 1 + """ + return self._prime._relative_degree + + def degree(self): + """ + Return the degree of the place. + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: OK = K.maximal_order() + sage: OL = L.maximal_order() + sage: p = OK.ideal(x^2 + x + 1) + sage: dec = OL.decomposition(p) + sage: q = dec[0][0].place() + sage: q.degree() + 2 + """ + return self.relative_degree() * self.place_below().degree() + + def is_infinite_place(self): + """ + Return ``True`` if the place is above the unique infinite place + of the underlying rational function field. + + EXAMPLES:: + + sage: K.=FunctionField(GF(2)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: pls = L.places() + sage: [p.is_infinite_place() for p in pls] + [True, True, False] + sage: [p.place_below() for p in pls] + [Place (1/x), Place (1/x), Place (x)] + """ + return self.place_below().is_infinite_place() + + def local_uniformizer(self): + """ + Return an element of the function field that has a simple zero + at the place. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^3 + x^3*Y + x) + sage: pls = L.places() + sage: [p.local_uniformizer().valuation(p) for p in pls] + [1, 1, 1, 1, 1] + """ + gens = self._prime.gens() + for g in gens: + if g.valuation(self) == 1: + return g + assert False, "Internal error" + + def gaps(self): + """ + Return the gap sequence for the place. + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: O = L.maximal_order() + sage: p = O.ideal(x,y).place() + sage: p.gaps() # a Weierstrass place + [1, 2, 4] + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x^3 * Y + x) + sage: [p.gaps() for p in L.places()] + [[1, 2, 4], [1, 2, 4], [1, 2, 4]] + """ + if self.degree() == 1: + return self._gaps_rational() # faster for rational places + else: + return self._gaps_wronskian() + + def _gaps_rational(self): + """ + Return the gap sequence for the rational place. + + This method computes the gap numbers using the definition of gap + numbers. The dimension of the multiple of the prime divisor + supported at the place is computed by Hess' algorithm. + + EXAMPLES:: + + sage: K. = FunctionField(GF(4)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: O = L.maximal_order() + sage: p = O.ideal(x,y).place() + sage: p.gaps() # indirect doctest + [1, 2, 4] + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x^3 * Y + x) + sage: [p.gaps() for p in L.places()] # indirect doctest + [[1, 2, 4], [1, 2, 4], [1, 2, 4]] + """ + F = self.function_field() + n = F.degree() + O = F.maximal_order() + Oinf = F.maximal_order_infinite() + + R = O._module_base_ring._ring + one = R.one() + + # Hess' Riemann-Roch basis algorithm stripped down for gaps computation + def dim_RR(M): + den = lcm([e.denominator() for e in M.list()]) + mat = matrix(R, M.nrows(), [(den*e).numerator() for e in M.list()]) + + # initialise pivot_row and conflicts list + pivot_row = [[] for i in range(n)] + conflicts = [] + for i in range(n): + bestp = -1 + best = -1 + for c in range(n): + d = mat[i,c].degree() + if d >= best: + bestp = c + best = d + + if best >= 0: + pivot_row[bestp].append((i,best)) + if len(pivot_row[bestp]) > 1: + conflicts.append(bestp) + + # while there is a conflict, do a simple transformation + while conflicts: + c = conflicts.pop() + row = pivot_row[c] + i,ideg = row.pop() + j,jdeg = row.pop() + + if jdeg > ideg: + i,j = j,i + ideg,jdeg = jdeg,ideg + + coeff = - mat[i,c].lc() / mat[j,c].lc() + s = coeff * one.shift(ideg - jdeg) + + mat.add_multiple_of_row(i, j, s) + + row.append((j,jdeg)) + + bestp = -1 + best = -1 + for c in range(n): + d = mat[i,c].degree() + if d >= best: + bestp = c + best = d + + if best >= 0: + pivot_row[bestp].append((i,best)) + if len(pivot_row[bestp]) > 1: + conflicts.append(bestp) + + dim = 0 + for j in range(n): + i,ideg = pivot_row[j][0] + k = den.degree() - ideg + 1 + if k > 0: + dim += k + return dim + + V,fr,to = F.vector_space() + + prime_inv = ~ self.prime_ideal() + I = O.ideal(1) + J = Oinf.ideal(1) + + B = matrix([to(b) for b in J.gens_over_base()]) + C = matrix([to(v) for v in I.gens_over_base()]) + + prev = dim_RR(C * B.inverse()) + gaps = [] + g = F.genus() + i = 1 + if self.is_infinite_place(): + while g: + J = J * prime_inv + B = matrix([to(b) for b in J.gens_over_base()]) + dim = dim_RR(C * B.inverse()) + if dim == prev: + gaps.append(i) + g -= 1 + else: + prev = dim + i += 1 + else: # self is a finite place + Binv = B.inverse() + while g: + I = I * prime_inv + C = matrix([to(v) for v in I.gens_over_base()]) + dim = dim_RR(C * Binv) + if dim == prev: + gaps.append(i) + g -= 1 + else: + prev = dim + i += 1 + + return gaps + + def _gaps_wronskian(self): + """ + Return the gap sequence for the place. + + This method implements the local version of Hess' Algorithm 30 of [Hes2002b]_ + based on the Wronskian determinant. + + EXAMPLES:: + + sage: K.=FunctionField(GF(4)); _.=K[] + sage: L.=K.extension(Y^3+x+x^3*Y) + sage: O = L.maximal_order() + sage: p = O.ideal(x,y).place() + sage: p._gaps_wronskian() # a Weierstrass place + [1, 2, 4] + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x^3 * Y + x) + sage: [p._gaps_wronskian() for p in L.places()] + [[1, 2, 4], [1, 2, 4], [1, 2, 4]] + """ + F = self.function_field() + R,fr_R,to_R = self._residue_field() + der = F.higher_derivation() + + sep = self.local_uniformizer() + + # a differential divisor satisfying + # v_p(W) = 0 for the place p + W = sep.differential().divisor() + + # Step 3: + basis = W._basis() + d = len(basis) + M = matrix([to_R(b) for b in basis]) + if M.rank() == 0: + return [] + + # Steps 4, 5, 6, 7: + e = 1 + gaps = [1] + while M.nrows() < d: + row = vector([to_R(der._derive(basis[i], e, sep)) for i in range(d)]) + if not row in M.row_space(): + M = matrix(M.rows() + [row]) + M.echelonize() + gaps.append(e + 1) + e += 1 + + return gaps + + def residue_field(self, name=None): + """ + Return the residue field of the place. + + INPUT: + + - ``name`` -- string; name of the generator of the residue field + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: k, fr_k, to_k = p.residue_field() + sage: k + Finite Field of size 2 + sage: fr_k + Ring morphism: + From: Finite Field of size 2 + To: Valuation ring at Place (x, x*y) + sage: to_k + Ring morphism: + From: Valuation ring at Place (x, x*y) + To: Finite Field of size 2 + sage: to_k(y) + Traceback (most recent call last): + ... + TypeError: y fails to convert into the map's domain + Valuation ring at Place (x, x*y)... + sage: to_k(1/y) + 0 + sage: to_k(y/(1+y)) + 1 + """ + return self.valuation_ring().residue_field(name=name) + + @cached_method + def _residue_field(self, name=None): + """ + Return the residue field of the place along with the functions + mapping from and to it. + + INPUT: + + - ``name`` -- string (default: `None`); name of the generator + of the residue field + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: k,fr_k,to_k = p._residue_field() + sage: k + Finite Field of size 2 + sage: [fr_k(e) for e in k] + [0, 1] + + sage: K. = FunctionField(GF(9)); _. = K[] + sage: L. = K.extension(Y^3 + Y - x^4) + sage: p = L.places()[-1] + sage: p.residue_field() + (Finite Field in z2 of size 3^2, Ring morphism: + From: Finite Field in z2 of size 3^2 + To: Valuation ring at Place (x + 1, y + 2*z2), Ring morphism: + From: Valuation ring at Place (x + 1, y + 2*z2) + To: Finite Field in z2 of size 3^2) + """ + F = self.function_field() + prime = self.prime_ideal() + + if self.is_infinite_place(): + _F, from_F, to_F = F._inversion_isomorphism() + _prime = prime._ideal + _place = _prime.place() + + K, _from_K, _to_K = _place._residue_field(name=name) + + from_K = lambda e: from_F(_from_K(e)) + to_K = lambda f: _to_K(to_F(f)) + return K, from_K, to_K + + O = F.maximal_order() + Obasis = O.basis() + + M = prime.hnf() + R = M.base_ring() # univariate polynomial ring + n = M.nrows() # extension degree of the function field + + degs = [M[i,i].degree() for i in range(n)] + deg = sum(degs) # degree of the place + + # Step 1: construct a vector space representing the residue field + k = F.constant_base_field() + #V = k**deg + + def to_V(e): + """ + An example to show the idea: Suppose that + + [x 0 0] + M = [0 1 0] and v = (x^10, x^7 + x^3, x^7 + x^4 + x^3 + 1) + [1 0 1] + + Then to_V(e) = [1] + """ + v = O._coordinate_vector(e) + vec = [] + for i in reversed(range(n)): + q,r = v[i].quo_rem(M[i,i]) + v -= q * M[i] + for j in range(degs[i]): + vec.append(r[j]) + return vector(vec) + + def fr_V(vec): # to_O + vec = vec.list() + pos = 0 + e = F(0) + for i in reversed(range(n)): + if degs[i] == 0: continue + else: + end = pos + degs[i] + e += R(vec[pos:end]) * Obasis[i] + pos = end + return e + + # Step 2: find a generator of the residue field + def candidates(): + # Trial 1: this suffices for places obtained from Kummers' theorem + + # Note that a = O._kummer_gen is a simple generator of O/prime over + # o/p. If b is a simple generator of o/p over the constant base field + # k, then the set a + k * b contains a simple generator of O/prime + # over k (as there are finite number of intermediate fields). + a = O._kummer_gen + if a is not None: + K,fr_K,_ = self.place_below().residue_field() + b = fr_K(K.gen()) + for c in reversed(k.list()): + yield a + c * b + + # Trial 2: basis elements of the maximal order + for gen in reversed(Obasis): + yield gen + + import itertools + + # Trial 3: exhaustive search in O using only polynomials + # with coefficients 0 or 1 + for d in range(deg): + G = itertools.product(itertools.product([0,1],repeat=d+1), repeat=n) + for g in G: + gen = sum([R(c1)*c2 for c1,c2 in zip(g, Obasis)]) + yield gen + + # Trial 4: exhaustive search in O using all polynomials + for d in range(deg): + G = itertools.product(R.polynomials(max_degree=d), repeat=n) + for g in G: + # discard duplicate cases + if max(c.degree() for c in g) != d: continue + for j in range(n): + if g[j] != 0: break + if g[j].leading_coefficient() != 1: continue + + gen = sum([c1*c2 for c1,c2 in zip(g, Obasis)]) + yield gen + + for gen in candidates(): + g = F.one() + m = [] + for i in range(deg): + m.append(to_V(g)) + g *= gen + mat = matrix(m) + if mat.rank() == deg: + break + + # Step 3: compute the minimal polynomial of g + min_poly = R((-mat.solve_left(to_V(g))).list() + [1]) + + if deg > 1: + # Step 4: construct the finite field + K = k.extension(deg, name=name) + alpha = min_poly.roots(K)[0][0] + W, from_W, to_W = K.vector_space(k, basis=[alpha**i for i in range(deg)], map=True) + + # Step 5: compute the matrix of change of basis + C = mat.inverse() + + # Step 6: construct an isomorphism + def from_K(e): + return fr_V(to_W(e) * mat) + else: # deg == 1 + # Step 4: construct the finite field + K = k + + # Step 5: compute the matrix of change of basis + C = mat.inverse() + + # Step 6: construct an isomorphism + def from_K(e): + return fr_V(vector([e]) * mat) + + p = prime.prime_below().gen().numerator() + beta = prime._beta + alpha = ~p * sum(c1*c2 for c1,c2 in zip(beta, O.basis())) + alpha_powered_by_ramification_index = alpha ** prime._ramification_index + + def to_K(f): + if not f in O: + den = O.coordinate_vector(f).denominator() + num = den * f + + # s powered by the valuation of den at the prime + alpha_power = alpha_powered_by_ramification_index ** den.valuation(p) + rn = num * alpha_power # in O + rd = den * alpha_power # in O but not in prime + + # Note that rn is not in O if and only if f is + # not in the valuation ring. Hence f is in the + # valuation ring if and only if this procedure + # does not fall into an infinite loop. + return to_K(rn) / to_K(rd) + + e = (to_V(f)*C) + if deg > 1: + return from_W(e) + else: # len(e) == 1 + return K(e[0]) + + return K, from_K, to_K + + def valuation_ring(self): + """ + Return the valuation ring at the place. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: p.valuation_ring() + Valuation ring at Place (x, x*y) + """ + from .valuation_ring import FunctionFieldValuationRing_global + + return FunctionFieldValuationRing_global(self.function_field(), self) + +class PlaceSet(UniqueRepresentation, Parent): + """ + Sets of Places of function fields. + + INPUT: + + - ``field`` -- function field + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: L.place_set() + Set of places of Function field in y defined by y^3 + x^3*y + x + """ + Element = FunctionFieldPlace + + def __init__(self, field): + """ + Initialize the set of places of the function ``field``. + + TESTS:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: places = L.place_set() + sage: TestSuite(places).run() + """ + self.Element = field._place_class + Parent.__init__(self, category = Sets().Infinite()) + + self._field = field + + def _repr_(self): + """ + Return the string representation of the place. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: L.place_set() + Set of places of Function field in y defined by y^3 + x^3*y + x + """ + return "Set of places of {}".format(self._field) + + def _element_constructor_(self, ideal): + """ + Create a place from the prime ``ideal``. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: places = L.place_set() + sage: O = L.maximal_order() + sage: places(O.ideal(x,y)) + Place (x, y) + """ + if not ideal.is_prime(): + raise TypeError("not a prime ideal") + + return self.element_class(self, ideal) + + def _an_element_(self): + """ + Return a place. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^3 + x + x^3*Y) + sage: places = L.place_set() + sage: places.an_element() # random + Ideal (x) of Maximal order of Rational function field in x + over Finite Field of size 2 + """ + d = 1 + while True: + try: + p = self._field.places(d).pop() + except IndexError: + d = d + 1 + else: + break + return p + diff --git a/src/sage/rings/function_field/valuation_ring.py b/src/sage/rings/function_field/valuation_ring.py new file mode 100644 index 00000000000..1e46848b3af --- /dev/null +++ b/src/sage/rings/function_field/valuation_ring.py @@ -0,0 +1,216 @@ +r""" +Valuation rings of function fields + +A valuation ring of a function field is associated with a place of the +function field. The valuation ring consists of all elements of the function +field that have nonnegative valuation at the place. + +EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: p + Place (x, x*y) + sage: R = p.valuation_ring() + sage: R + Valuation ring at Place (x, x*y) + sage: R.place() == p + True + +Thus any nonzero element or its inverse of the function field lies in the +valuation ring, as shown in the following example:: + + sage: f = y/(1+y) + sage: f in R + True + sage: f not in R + False + sage: f.valuation(p) + 0 + +The residue field at the place is defined as the quotient ring of the valuaion +ring modulo its unique maximal ideal. In a global function field, the +:meth:`residue_field()` method returns a finite field isomorphic to the residue +field:: + + sage: k,phi,psi = R.residue_field() + sage: k + Finite Field of size 2 + sage: phi + Ring morphism: + From: Finite Field of size 2 + To: Valuation ring at Place (x, x*y) + sage: psi + Ring morphism: + From: Valuation ring at Place (x, x*y) + To: Finite Field of size 2 + sage: psi(f) in k + True + +AUTHORS: + +- Kwankyu Lee (2017-04-30): initial version + +""" +#***************************************************************************** +# Copyright (C) 2016 Kwankyu Lee +# +# 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/ +#***************************************************************************** +from __future__ import absolute_import + +from sage.misc.cachefunc import cached_method + +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent + +from sage.categories.homset import Hom +from sage.categories.rings import Rings + +class FunctionFieldValuationRing(UniqueRepresentation, Parent): + """ + Base class for valuation rings of function fields. + + INPUT: + + - ``field`` -- function field + + - ``place`` -- place of the function field + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: p.valuation_ring() + Valuation ring at Place (x, x*y) + """ + def __init__(self, field, place, category=None): + """ + Initialize. + + TESTS:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: R = p.valuation_ring() + sage: TestSuite(R).run() + """ + Parent.__init__(self, category=Rings().or_subcategory(category).Infinite(), facade=field) + + self._field = field + self._place = place + + def _element_constructor_(self, x): + """ + Construct an element of the function field belonging to the + valuation ring. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: R = p.valuation_ring() + sage: y in R + False + sage: 1/y in R + True + sage: x + y in R + False + sage: 1/(x + y) in R + True + """ + x = self._field(x) + if x.valuation(self._place) >= 0: + return x + else: + raise TypeError + + def _repr_(self): + """ + Return the string representation of the valuation ring. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: p.valuation_ring() + Valuation ring at Place (x, x*y) + """ + return 'Valuation ring at {}'.format(self._place) + + def place(self): + """ + Return the place associated with the valuation ring. + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: R = p.valuation_ring() + sage: p == R.place() + True + """ + return self._place + +class FunctionFieldValuationRing_global(FunctionFieldValuationRing): + """ + Valuation rings of global function fields. + """ + @cached_method + def residue_field(self, name=None): + """ + Return the residue field of the valuation ring together with + the maps from and to it. + + INPUT: + + - ``name`` -- string; name of the generator of the residue field + + OUTPUT: + + - a finite field isomorphic to the residue field + + - a ring homomorphism from the valuation ring to the finite field + + - a ring homomorphism from the finite field to the valuation ring + + EXAMPLES:: + + sage: K. = FunctionField(GF(2)); _. = K[] + sage: L. = K.extension(Y^2 + Y + x + 1/x) + sage: p = L.places_finite()[0] + sage: R = p.valuation_ring() + sage: k, fr_k, to_k = R.residue_field() + sage: k + Finite Field of size 2 + sage: fr_k + Ring morphism: + From: Finite Field of size 2 + To: Valuation ring at Place (x, x*y) + sage: to_k + Ring morphism: + From: Valuation ring at Place (x, x*y) + To: Finite Field of size 2 + sage: to_k(1/y) + 0 + sage: to_k(y/(1+y)) + 1 + """ + from .maps import FunctionFieldRingMorphism as morphism + + k, from_k, to_k = self._place._residue_field(name=name) + mor_from_k = morphism(Hom(k,self), from_k) + mor_to_k = morphism(Hom(self,k), to_k) + return k, mor_from_k, mor_to_k + + + diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 17e62f3932b..d03bf9426d5 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -1,11 +1,9 @@ r""" Elements of the ring `\ZZ` of integers -Sage has highly optimized and extensive functionality about arithmetic with integers +Sage has highly optimized and extensive functionality for arithmetic with integers and the ring of integers. -- Vincent Delecroix (2017-05-03): faster integer-rational comparisons - EXAMPLES: Add 2 integers:: @@ -62,7 +60,7 @@ Multiplication:: COERCIONS: -Returns version of this integer in the multi-precision floating +Return version of this integer in the multi-precision floating real field R:: sage: n = 9390823 @@ -116,19 +114,24 @@ AUTHORS: in favour of :meth:`~sage.rings.integer.Integer.is_perfect_power` (see :trac:`12116`) +- Vincent Delecroix (2017-05-03): faster integer-rational comparisons + - Vincent Klein (2017-05-11): add __mpz__() to class Integer - Vincent Klein (2017-05-22): Integer constructor support gmpy2.mpz parameter + +- Samuel Lelièvre (2018-08-02): document that divisors are sorted (:trac:`25983`) """ # **************************************************************************** -# Copyright (C) 2004,2006 William Stein +# Copyright (C) 2004, 2006 William Stein # Copyright (C) 2006 Gonzalo Tornaria # Copyright (C) 2006 Didier Deshommes # Copyright (C) 2007 David Harvey # Copyright (C) 2007 Martin Albrecht -# Copyright (C) 2007,2008 Robert Bradshaw +# Copyright (C) 2007, 2008 Robert Bradshaw # Copyright (C) 2007 David Roe # Copyright (C) 2017 Vincent Delecroix <20100.delecroix@gmail.com> +# Copyright (C) 2018 Samuel Lelièvre # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -144,11 +147,10 @@ cimport cython from libc.math cimport (ldexp, sqrt as sqrt_double, log as log_c, ceil as ceil_c, isnan) from libc.string cimport memcpy -cdef extern from "": - const long LONG_MAX # Work around https://github.com/cython/cython/pull/2016 +from libc.limits cimport LONG_MAX from cysignals.memory cimport check_allocarray, check_malloc, sig_free -from cysignals.signals cimport sig_on, sig_off, sig_check +from cysignals.signals cimport sig_on, sig_off, sig_check, sig_occurred import operator import sys @@ -169,8 +171,9 @@ from cpython.int cimport * from cpython.object cimport * from libc.stdint cimport uint64_t cimport sage.structure.element +from sage.structure.coerce cimport coercion_model from sage.structure.element cimport (Element, EuclideanDomainElement, - parent, coercion_model) + parent) from sage.structure.parent cimport Parent from cypari2.paridecl cimport * from sage.rings.rational cimport Rational @@ -178,6 +181,7 @@ from sage.arith.rational_reconstruction cimport mpq_rational_reconstruction from sage.libs.gmp.pylong cimport * from sage.libs.ntl.convert cimport mpz_to_ZZ from sage.libs.gmp.mpq cimport mpq_neg +from sage.libs.gmp.binop cimport mpq_add_z, mpq_mul_z, mpq_div_zz from cypari2.gen cimport objtogen, Gen as pari_gen from sage.libs.pari.convert_gmp cimport INT_to_mpz, new_gen_from_mpz_t @@ -188,13 +192,13 @@ import sage.rings.infinity from sage.structure.coerce cimport is_numpy_type from sage.structure.element import coerce_binop -from sage.misc.superseded import deprecation -from sage.libs.gmp.binop cimport mpq_add_z, mpq_mul_z, mpq_div_zz +from sage.structure.richcmp cimport rich_to_bool_sgn -IF HAVE_GMPY2: - cimport gmpy2 - gmpy2.import_gmpy2() +from . import integer_ring + +cimport gmpy2 +gmpy2.import_gmpy2() cdef extern from *: @@ -349,14 +353,7 @@ cdef _digits_internal(mpz_t v,l,int offset,int power_index,power_list,digits): mpz_clear(mpz_quot) mpz_clear(mpz_res) -from sage.structure.sage_object cimport SageObject -from sage.structure.richcmp cimport rich_to_bool_sgn -from sage.structure.element cimport EuclideanDomainElement, ModuleElement, Element -from sage.structure.element import bin_op -from sage.structure.coerce_exceptions import CoercionException - -from . import integer_ring cdef Parent the_integer_ring = integer_ring.ZZ # The documentation for the ispseudoprime() function in the PARI @@ -478,8 +475,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Conversion from gmpy2:: - sage: from gmpy2 import mpz # optional - gmpy2 - sage: Integer(mpz(3)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: Integer(mpz(3)) 3 .. automethod:: __pow__ @@ -538,8 +535,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): 0 sage: ZZ('+10') 10 - sage: from gmpy2 import mpz # optional - gmpy2 - sage: ZZ(mpz(42)) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: ZZ(mpz(42)) 42 :: @@ -740,7 +737,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): mpz_set_pylong(self.value, long(x)) return - elif HAVE_GMPY2 and type(x) is gmpy2.mpz: + elif type(x) is gmpy2.mpz: mpz_set(self.value, (x).z) return @@ -826,7 +823,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): """ if isinstance(x, Integer) and isinstance(y, Integer): return (x)._xor(y) - return bin_op(x, y, operator.xor) + return coercion_model.bin_op(x, y, operator.xor) def __richcmp__(left, right, int op): """ @@ -1074,10 +1071,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): EXAMPLES:: sage: a = 5 - sage: a.__mpz__() # optional - gmpy2 + sage: a.__mpz__() mpz(5) - sage: from gmpy2 import mpz # optional - gmpy2 - sage: mpz(a) # optional - gmpy2 + sage: from gmpy2 import mpz + sage: mpz(a) mpz(5) TESTS:: @@ -1087,10 +1084,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ... NotImplementedError: gmpy2 is not installed """ - IF HAVE_GMPY2: - return gmpy2.GMPy_MPZ_From_mpz(self.value) - ELSE: - raise NotImplementedError("gmpy2 is not installed") + return gmpy2.GMPy_MPZ_From_mpz(self.value) def str(self, int base=10): r""" @@ -1238,6 +1232,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return self.str(16) def __hex__(self): + from sage.misc.superseded import deprecation deprecation(26756, 'use the method .hex instead') return self.hex() @@ -1291,6 +1286,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return self.str(8) def __oct__(self): + from sage.misc.superseded import deprecation deprecation(26756, 'use the method .oct instead') return self.oct() @@ -2752,17 +2748,26 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: ZZ(8).log(int(2)) 3 + + TESTS:: + + sage: (-2).log(3) + (I*pi + log(2))/log(3) """ - if mpz_sgn(self.value) <= 0: - from sage.symbolic.all import SR - return SR(self).log() + cdef int self_sgn if m is not None and m <= 0: - raise ValueError("m must be positive") + 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 + return SR(self).log(m) if prec: - from sage.rings.real_mpfr import RealField - if m is None: - return RealField(prec)(self).log() - return RealField(prec)(self).log(m) + if self_sgn >= 0: + from sage.rings.real_mpfr import RealField + return RealField(prec)(self).log(m) + else: + from sage.rings.complex_field import ComplexField + return ComplexField(prec)(self).log(m) if m is None: from sage.functions.log import function_log @@ -2870,9 +2875,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def prime_divisors(self): """ - The prime divisors of self, sorted in increasing order. If n is - negative, we do *not* include -1 among the prime divisors, since - -1 is not a prime number. + Return the prime divisors of this integer, sorted in increasing order. + + If this integer is negative, we do *not* include -1 among + its prime divisors, since -1 is not a prime number. EXAMPLES:: @@ -2889,7 +2895,6 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): prime_factors = prime_divisors - cpdef list _pari_divisors_small(self): r""" Return the list of divisors of this number using PARI ``divisorsu``. @@ -2938,10 +2943,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): @cython.wraparound(False) def divisors(self, method=None): """ - Returns a list of all positive integer divisors of the integer - self. + Return the list of all positive integer divisors of this integer, + sorted in increasing order. - EXAMPLES:: + EXAMPLES: + + :: sage: (-3).divisors() [1, 3] @@ -2960,11 +2967,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ... ValueError: n must be nonzero sage: (2^3 * 3^2 * 17).divisors() - [1, 2, 3, 4, 6, 8, 9, 12, 17, 18, 24, 34, 36, 51, 68, 72, 102, 136, 153, 204, 306, 408, 612, 1224] + [1, 2, 3, 4, 6, 8, 9, 12, 17, 18, 24, 34, 36, 51, 68, 72, + 102, 136, 153, 204, 306, 408, 612, 1224] sage: a = odd_part(factorial(31)) - sage: v = a.divisors(); len(v) + sage: v = a.divisors() + sage: len(v) 172800 - sage: prod(e+1 for p,e in factor(a)) + sage: prod(e + 1 for p, e in factor(a)) 172800 sage: all([t.divides(a) for t in v]) True @@ -2978,7 +2987,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: L[-1] == n True - TESTS:: + TESTS: + + Overflow:: sage: prod(primes_first_n(64)).divisors() Traceback (most recent call last): @@ -3167,7 +3178,6 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return sorted - def __pos__(self): """ EXAMPLES:: @@ -5934,7 +5944,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): for a large list of small integers the overhead of calling StringToInteger can be a killer. - EXAMPLES: + EXAMPLES:: + sage: (117)._magma_init_(magma) # optional - magma '117' @@ -6374,7 +6385,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): except TypeError: raise TypeError("unsupported operands for %s: %s, %s"%(("<<" if sign == 1 else ">>"), self, y)) except ValueError: - return bin_op(self, y, operator.lshift if sign == 1 else operator.rshift) + return coercion_model.bin_op(self, y, operator.lshift if sign == 1 else operator.rshift) # If y wasn't a Python int, it's now an Integer, so set n # accordingly. @@ -6484,7 +6495,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): """ if isinstance(x, Integer) and isinstance(y, Integer): return (x)._and(y) - return bin_op(x, y, operator.and_) + return coercion_model.bin_op(x, y, operator.and_) cdef _or(Integer self, Integer other): cdef Integer x = PY_NEW(Integer) @@ -6503,7 +6514,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): """ if isinstance(x, Integer) and isinstance(y, Integer): return (x)._or(y) - return bin_op(x, y, operator.or_) + return coercion_model.bin_op(x, y, operator.or_) def __invert__(self): """ @@ -6731,7 +6742,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): Return the complex conjugate of this integer, which is the integer itself. - EXAMPLES: + EXAMPLES:: + sage: n = 205 sage: n.conjugate() 205 @@ -6806,6 +6818,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ....: (2^100).binomial(2^22, algorithm='pari') ....: except AlarmInterrupt: ....: pass + doctest:...: RuntimeWarning: cypari2 leaked ... bytes on the PARI stack... """ cdef Integer x cdef Integer mm @@ -7296,39 +7309,41 @@ cdef PyObject* fast_tp_new(type t, args, kwds) except NULL: return new -cdef void fast_tp_dealloc(PyObject* o): +cdef void fast_tp_dealloc(PyObject* o): # If there is room in the pool for a used integer object, # then put it in rather than deallocating it. - global integer_pool, integer_pool_count cdef mpz_ptr o_mpz = ((o).value) - if integer_pool_count < integer_pool_size: + # If we are recovering from an interrupt, throw the mpz_t away + # without recycling or freeing it because it might be in an + # inconsistent state (see Trac #24986). + if sig_occurred() is NULL: + if integer_pool_count < integer_pool_size: + # Here we free any extra memory used by the mpz_t by + # setting it to a single limb. + if o_mpz._mp_alloc > 10: + _mpz_realloc(o_mpz, 1) - # Here we free any extra memory used by the mpz_t by - # setting it to a single limb. - if o_mpz._mp_alloc > 10: - _mpz_realloc(o_mpz, 1) + # It's cheap to zero out an integer, so do it here. + o_mpz._mp_size = 0 - # It's cheap to zero out an integer, so do it here. - o_mpz._mp_size = 0 + # And add it to the pool. + integer_pool[integer_pool_count] = o + integer_pool_count += 1 + return - # And add it to the pool. - integer_pool[integer_pool_count] = o - integer_pool_count += 1 - return - - # Again, we move to the mpz_t and clear it. As in fast_tp_new, - # we free the memory directly. - sig_free(o_mpz._mp_d) + # No space in the pool, so just free the mpz_t. + sig_free(o_mpz._mp_d) # Free the object. This assumes that Py_TPFLAGS_HAVE_GC is not # set. If it was set another free function would need to be # called. PyObject_Free(o) + from sage.misc.allocator cimport hook_tp_functions cdef hook_fast_tp_functions(): """ diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index d9ed06bf0e3..1af4a41d208 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -294,6 +294,11 @@ cdef class IntegerRing_class(PrincipalIdealDomain): Traceback (most recent call last): ... NotImplementedError: len() of an infinite set + + sage: ZZ.is_finite() + False + sage: ZZ.cardinality() + +Infinity """ def __init__(self): @@ -836,17 +841,6 @@ cdef class IntegerRing_class(PrincipalIdealDomain): """ return False - def is_finite(self): - """ - Return ``False`` since the integers are an infinite ring. - - EXAMPLES:: - - sage: ZZ.is_finite() - False - """ - return False - def fraction_field(self): """ Return the field of rational numbers - the fraction field of the diff --git a/src/sage/rings/invariants/invariant_theory.py b/src/sage/rings/invariants/invariant_theory.py index dce5ff4ede8..c714ffbf0c0 100644 --- a/src/sage/rings/invariants/invariant_theory.py +++ b/src/sage/rings/invariants/invariant_theory.py @@ -100,14 +100,14 @@ - Jesper Noordsij (2018-05-18): support for binary quintics added """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 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 sage.matrix.constructor import matrix @@ -116,7 +116,6 @@ from sage.misc.cachefunc import cached_method - ###################################################################### def _guess_variables(polynomial, *args): """ @@ -155,14 +154,14 @@ def _guess_variables(polynomial, *args): R = polynomial[0].parent() if not all(p.parent() is R for p in polynomial): raise ValueError('All input polynomials must be in the same ring.') - if len(args)==0 or (len(args)==1 and args[0] is None): + if not args or (len(args) == 1 and args[0] is None): if isinstance(polynomial, (list, tuple)): - variables = set() + variables = tuple() for p in polynomial: - variables.update(p.variables()) - variables = list(variables) - variables.reverse() # to match polynomial.variables() behavior - return tuple(variables) + for var in p.variables(): + if var not in variables: + variables += (var,) + return variables else: return polynomial.variables() elif len(args) == 1 and isinstance(args[0], (tuple, list)): @@ -170,6 +169,7 @@ def _guess_variables(polynomial, *args): else: return tuple(args) + def transvectant(f, g, h=1, scale='default'): r""" Return the h-th transvectant of f and g. @@ -262,7 +262,7 @@ def transvectant(f, g, h=1, scale='default'): f = f.homogenized() g = g.homogenized() R = f._ring - if not g._ring is R: + if g._ring is not R: raise ValueError('All input forms must be in the same polynomial ring.') x = f._variables[0] y = f._variables[1] @@ -278,6 +278,7 @@ def transvectant(f, g, h=1, scale='default'): scalar = 1 else: raise ValueError('Unknown scale type: %s' %scale) + def diff(j): df = f.form().derivative(x,j).derivative(y,h-j) dg = g.form().derivative(x,h-j).derivative(y,j) @@ -291,6 +292,7 @@ def diff(j): ###################################################################### + @richcmp_method class FormsBase(SageObject): """ @@ -541,7 +543,6 @@ def __init__(self, n, d, polynomial, *args, **kwds): super(AlgebraicForm, self).__init__(n, homogeneous, ring, variables) self._check() - def _check(self): """ Check that the input is of the correct degree and number of @@ -573,7 +574,6 @@ def _check(self): else: raise ValueError('Polynomial is of the wrong degree.') - def _check_covariant(self, method_name, g=None, invariant=False): r""" Test whether ``method_name`` actually returns a covariant. @@ -620,7 +620,7 @@ def _check_covariant(self, method_name, g=None, invariant=False): # The transform of the covariant g_cov = getattr(self, method_name)().subs(transform) # they must be the same - assert (g_cov - cov_g).is_zero(), 'Not covariant.' + assert (g_cov - cov_g).is_zero(), 'Not covariant.' if invariant: cov = getattr(self, method_name)() assert (cov - cov_g).is_zero(), 'Not invariant.' @@ -818,6 +818,7 @@ def _extract_coefficients(self, monomials): assert indices == [0] coefficient_monomial_iter = [(c, R.gen(0)**i) for i,c in enumerate(self._polynomial.padded_list())] + def index(monomial): if monomial in R.base_ring(): return (0,) @@ -825,6 +826,7 @@ def index(monomial): else: # Multivariate polynomials coefficient_monomial_iter = self._polynomial + def index(monomial): if monomial in R.base_ring(): return tuple(0 for i in indices) @@ -980,7 +982,8 @@ def monomials(self): (x^2, y^2, 1, x*y, x, y) """ var = self._variables - def prod(a,b): + + def prod(a, b): if a is None and b is None: return self._ring.one() elif a is None: @@ -988,7 +991,7 @@ def prod(a,b): elif b is None: return a else: - return a*b + return a * b squares = tuple( prod(x,x) for x in var ) mixed = [] for i in range(self._n): @@ -1186,7 +1189,7 @@ def dual(self): (42849/256) * (2*x^2 + x*y + 3*y^2 + 4*z^2 + 5*z + 1) """ A = self.matrix() - Aadj = A.adjoint() + Aadj = A.adjugate() if self._homogeneous: var = self._variables else: @@ -1681,8 +1684,8 @@ def scaled_coeffs(self): (a0, a1, a2, a3, a4, a5) """ coeff = self.coeffs() - return (coeff[0], coeff[1]/5, coeff[2]/10, coeff[3]/10, coeff[4]/5, \ - coeff[5]) + return (coeff[0], coeff[1] / 5, coeff[2] / 10, coeff[3] / 10, + coeff[4] / 5, coeff[5]) @cached_method def H_covariant(self, as_form=False): @@ -2231,17 +2234,18 @@ def clebsch_invariants(self, as_tuple=False): """ if self._ring.characteristic() in [2, 3, 5]: - raise NotImplementedError('No invariants implemented for fields \ - of characteristic 2, 3 or 5.') # todo: add support + raise NotImplementedError('No invariants implemented for fields ' + 'of characteristic 2, 3 or 5.') + # todo: add support else: invariants = {} invariants['A'] = self.A_invariant() invariants['B'] = self.B_invariant() invariants['C'] = self.C_invariant() invariants['R'] = self.R_invariant() - if as_tuple == True: - return (invariants['A'], invariants['B'], invariants['C'], \ - invariants['R']) + if as_tuple: + return (invariants['A'], invariants['B'], invariants['C'], + invariants['R']) else: return invariants @@ -2306,6 +2310,8 @@ def arithmetic_invariants(self): return invariants ###################################################################### + + def _covariant_conic(A_scaled_coeffs, B_scaled_coeffs, monomials): """ Helper function for :meth:`TernaryQuadratic.covariant_conic` @@ -2841,10 +2847,10 @@ def Theta_covariant(self): sage: len(list(cubic.Theta_covariant())) 6952 """ - U_conic = self.polar_conic().adjoint() + U_conic = self.polar_conic().adjugate() U_coeffs = ( U_conic[0,0], U_conic[1,1], U_conic[2,2], U_conic[0,1], U_conic[0,2], U_conic[1,2] ) - H_conic = TernaryCubic(3, 3, self.Hessian(), self.variables()).polar_conic().adjoint() + H_conic = TernaryCubic(3, 3, self.Hessian(), self.variables()).polar_conic().adjugate() H_coeffs = ( H_conic[0,0], H_conic[1,1], H_conic[2,2], H_conic[0,1], H_conic[0,2], H_conic[1,2] ) quadratic = TernaryQuadratic(3, 2, self._ring.zero(), self.variables()) @@ -2908,7 +2914,7 @@ def syzygy(self, U, S, T, H, Theta, J): """ return ( -J**2 + 4*Theta**3 + T*U**2*Theta**2 + Theta*(-4*S**3*U**4 + 2*S*T*U**3*H - 72*S**2*U**2*H**2 - - 18*T*U*H**3 + 108*S*H**4) + - 18*T*U*H**3 + 108*S*H**4) -16*S**4*U**5*H - 11*S**2*T*U**4*H**2 -4*T**2*U**3*H**3 +54*S*T*U**2*H**4 -432*S**2*U*H**5 -27*T*H**6 ) @@ -3140,7 +3146,7 @@ def _check_covariant(self, method_name, g=None, invariant=False): # The transform of the covariant g_cov = getattr(self, method_name)().subs(transform) # they must be the same - assert (g_cov - cov_g).is_zero(), 'Not covariant.' + assert (g_cov - cov_g).is_zero(), 'Not covariant.' if invariant: cov = getattr(self, method_name)() assert (cov - cov_g).is_zero(), 'Not invariant.' @@ -3509,7 +3515,7 @@ def _Theta_helper(self, scaled_coeffs_1, scaled_coeffs_2): """ a0, a1, a2, a3, b0, b1, b2, b3, b4, b5 = scaled_coeffs_1 A0, A1, A2, A3, B0, B1, B2, B3, B4, B5 = scaled_coeffs_2 - return a1*a2*a3*A0 - a3*b3**2*A0 - a2*b4**2*A0 + 2*b3*b4*b5*A0 - a1*b5**2*A0 \ + return a1*a2*a3*A0 - a3*b3**2*A0 - a2*b4**2*A0 + 2*b3*b4*b5*A0 - a1*b5**2*A0 \ + a0*a2*a3*A1 - a3*b1**2*A1 - a2*b2**2*A1 + 2*b1*b2*b5*A1 - a0*b5**2*A1 \ + a0*a1*a3*A2 - a3*b0**2*A2 - a1*b2**2*A2 + 2*b0*b2*b4*A2 - a0*b4**2*A2 \ + a0*a1*a2*A3 - a2*b0**2*A3 - a1*b1**2*A3 + 2*b0*b1*b3*A3 - a0*b3**2*A3 \ @@ -3523,7 +3529,6 @@ def _Theta_helper(self, scaled_coeffs_1, scaled_coeffs_2): - 2*b0*b1*b5*B4 + 2*a0*b3*b5*B4 + 2*a1*b1*b2*B5 - 2*b0*b2*b3*B5 \ - 2*b0*b1*b4*B5 + 2*a0*b3*b4*B5 - 2*a0*a1*b5*B5 + 2*b0**2*b5*B5 - def Theta_invariant(self): r""" Return the `\Theta` invariant. @@ -3617,6 +3622,7 @@ def _T_helper(self, scaled_coeffs_1, scaled_coeffs_2): # Construct the entries of the 4x4 matrix T using symmetries: # cyclic: a0 -> a1 -> a2 -> a3 -> a0, b0->b3->b5->b2->b0, b1->b4->b1 # flip: a0<->a1, b1<->b3, b2<->b4 + def T00(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, B4, B5): return a0*a3*A0*A1*A2 - b2**2*A0*A1*A2 + a0*a2*A0*A1*A3 - b1**2*A0*A1*A3 \ + a0*a1*A0*A2*A3 - b0**2*A0*A2*A3 - a0*a3*A2*B0**2 + b2**2*A2*B0**2 \ @@ -3635,6 +3641,7 @@ def T00(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, + 2*b0*b1*B0*B2*B5 - 2*a0*b3*B0*B2*B5 + 2*a0*a1*B1*B2*B5 - 2*b0**2*B1*B2*B5 \ - 2*b0*b2*A0*B3*B5 + 2*a0*b4*A0*B3*B5 - 2*b0*b1*A0*B4*B5 + 2*a0*b3*A0*B4*B5 \ - a0*a1*A0*B5**2 + b0**2*A0*B5**2 + def T01(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, B4, B5): return a3*b0*A0*A1*A2 - b2*b4*A0*A1*A2 + a2*b0*A0*A1*A3 - b1*b3*A0*A1*A3 \ + a0*a1*A2*A3*B0 - b0**2*A2*A3*B0 - a3*b0*A2*B0**2 + b2*b4*A2*B0**2 \ @@ -3694,8 +3701,8 @@ def T_covariant(self): sage: p2 += B0*x*y + B1*x*z + B2*x + B3*y*z + B4*y + B5*z sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [x, y, z]) sage: T = invariant_theory.quaternary_quadratic(q.T_covariant(), [x,y,z]).matrix() - sage: M = q[0].matrix().adjoint() + t*q[1].matrix().adjoint() - sage: M = M.adjoint().apply_map( # long time (4s on my thinkpad W530) + sage: M = q[0].matrix().adjugate() + t*q[1].matrix().adjugate() + sage: M = M.adjugate().apply_map( # long time (4s on my thinkpad W530) ....: lambda m: m.coefficient(t)) sage: M == q.Delta_invariant()*T # long time True @@ -3717,8 +3724,8 @@ def T_prime_covariant(self): sage: q = invariant_theory.quaternary_biquadratic(p1, p2, [x, y, z]) sage: Tprime = invariant_theory.quaternary_quadratic( ....: q.T_prime_covariant(), [x,y,z]).matrix() - sage: M = q[0].matrix().adjoint() + t*q[1].matrix().adjoint() - sage: M = M.adjoint().apply_map( # long time (4s on my thinkpad W530) + sage: M = q[0].matrix().adjugate() + t*q[1].matrix().adjugate() + sage: M = M.adjugate().apply_map( # long time (4s on my thinkpad W530) ....: lambda m: m.coefficient(t^2)) sage: M == q.Delta_prime_invariant() * Tprime # long time True @@ -4329,6 +4336,4 @@ def quaternary_biquadratic(self, quadratic1, quadratic2, *args, **kwds): return TwoQuaternaryQuadratics([q1, q2]) - invariant_theory = InvariantTheoryFactory() - diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index 964a50bed86..5c9842a8435 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -577,7 +577,7 @@ def _latex_(self): -t0^4*t1^3*t2^4 - 2*t0*t1^4*t2^7 + 2*t1*t2^12 + 2*t0^7*t1^5*t2^2 + O(t0, t1, t2)^15 sage: f._latex_() - '- t_{0}^{4} t_{1}^{3} t_{2}^{4} + 3 t_{0} t_{1}^{4} t_{2}^{7} + + '-t_{0}^{4} t_{1}^{3} t_{2}^{4} + 3 t_{0} t_{1}^{4} t_{2}^{7} + 2 t_{1} t_{2}^{12} + 2 t_{0}^{7} t_{1}^{5} t_{2}^{2} + O(t_{0}, t_{1}, t_{2})^{15}' diff --git a/src/sage/rings/number_field/maps.py b/src/sage/rings/number_field/maps.py index 1727c13d812..57172271d3d 100644 --- a/src/sage/rings/number_field/maps.py +++ b/src/sage/rings/number_field/maps.py @@ -358,7 +358,7 @@ def _call_(self, alpha): g = g(beta).lift() # Convert the coefficients to elements of the base field. B, from_B, _ = K.absolute_base_field() - return self.codomain()([from_B(B(z.lift(), check=False)) for z in g.Vecrev(-K.relative_degree())]) + return self.codomain()([from_B(B(z.lift(), check=False)) for z in g.Vecrev(K.relative_degree())]) class NameChangeMap(NumberFieldIsomorphism): diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 864f1b738f9..7a1d77d6e10 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -85,15 +85,15 @@ explicitly coerce all elements into a common field, then do arithmetic with them there (which is quite fast). """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004, 2005, 2006, 2007 William Stein # 2014 Julian Rueth # # 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 __future__ import absolute_import, print_function from six.moves import range @@ -148,6 +148,7 @@ _NumberFields = NumberFields() + def is_NumberFieldHomsetCodomain(codomain): """ Returns whether ``codomain`` is a valid codomain for a number @@ -215,7 +216,6 @@ def proof_flag(t): from sage.rings.rational import Rational from sage.rings.integer import Integer import sage.rings.polynomial.polynomial_element as polynomial_element -import sage.rings.complex_field import sage.groups.abelian_gps.abelian_group import sage.rings.complex_interval_field @@ -4370,8 +4370,7 @@ def _S_class_group_and_units(self, S, proof=True): ([-6*a + 2, 6*a + 3, -1, 12*a + 5], []) """ K_pari = self.pari_bnf(proof=proof) - from sage.misc.all import uniq - S_pari = [p.pari_prime() for p in uniq(S)] + S_pari = [p.pari_prime() for p in sorted(set(S))] result = K_pari.bnfsunit(S_pari) units = [self(x, check=False) for x in result[0]] + self.unit_group().gens_values() orders = result[4][1].sage() @@ -5666,7 +5665,7 @@ def _pari_integral_basis(self, v=None, important=True): return self._integral_basis_dict[v] except (AttributeError, KeyError): f = self.pari_polynomial("y") - if len(v) > 0: + if v: B = f.nfbasis(fa=v) elif self._assume_disc_small: B = f.nfbasis(1) @@ -5678,7 +5677,7 @@ def _pari_integral_basis(self, v=None, important=True): # instead of D^(1/2). trialdivlimit2 = pari(10**12) trialdivlimit3 = pari(10**18) - if all([ p < trialdivlimit2 or (e == 1 and p < trialdivlimit3) or p.isprime() for p,e in zip(m[0],m[1]) ]): + if all(p < trialdivlimit2 or (e == 1 and p < trialdivlimit3) or p.isprime() for p, e in zip(m[0], m[1])): B = f.nfbasis(fa = m) else: raise RuntimeError("Unable to factor discriminant with trial division") @@ -6596,7 +6595,7 @@ def S_unit_group(self, proof=None, S=None): S = tuple(self.ideal(P) for P in S) except (NameError, TypeError, ValueError): raise ValueError("Cannot make a set of primes from %s"%(S,)) - if not all([P.is_prime() for P in S]): + if not all(P.is_prime() for P in S): raise ValueError("Not all elements of %s are prime ideals"%(S,)) try: @@ -6622,7 +6621,7 @@ def S_unit_group(self, proof=None, S=None): return U def S_unit_solutions(self, S=[], prec=106, include_exponents=False, include_bound=False, proof=None): - """ + r""" Return all solutions to the S-unit equation ``x + y = 1`` over K. INPUT: @@ -6631,38 +6630,38 @@ def S_unit_solutions(self, S=[], prec=106, include_exponents=False, include_boun - ``prec`` -- precision used for computations in real, complex, and p-adic fields (default: 106) - ``include_exponents`` -- whether to include the exponent vectors in the returned value (default: True). - ``include_bound`` -- whether to return the final computed bound (default: False) - - ``verbose`` -- whether to print information during the sieving step (default: False) + - ``proof`` -- if False, assume the GRH in computing the class group. Default is True. OUTPUT: A list of tuples ``[( A_1, B_1, x_1, y_1), (A_2, B_2, x_2, y_2), ... ( A_n, B_n, x_n, y_n)]`` such that: - 1. The first two entries are tuples ``A_i = (a_0, a_1, ... , a_t)`` and ``B_i = (b_0, b_1, ... , b_t)`` of exponents. These will be ommitted if ``include_exponents`` is ``False``. - 2. The last two entries are ``S``-units ``x_i`` and ``y_i`` in ``K`` with ``x_i + y_i = 1``. - 3. If the default generators for the ``S``-units of ``K`` are ``(rho_0, rho_1, ... , rho_t)``, then these satisfy ``x_i = \prod(rho_i)^(a_i)`` and ``y_i = \prod(rho_i)^(b_i)``. + 1. The first two entries are tuples ``A_i = (a_0, a_1, ... , a_t)`` and ``B_i = (b_0, b_1, ... , b_t)`` of exponents. These will be ommitted if ``include_exponents`` is ``False``. + 2. The last two entries are ``S``-units ``x_i`` and ``y_i`` in ``K`` with ``x_i + y_i = 1``. + 3. If the default generators for the ``S``-units of ``K`` are ``(rho_0, rho_1, ... , rho_t)``, then these satisfy ``x_i = \prod(rho_i)^(a_i)`` and ``y_i = \prod(rho_i)^(b_i)``. - If ``include_bound``, will return a pair ``(sols, bound)`` where ``sols`` is as above and ``bound`` is the bound used for the entries in the exponent vectors. + If ``include_bound``, will return a pair ``(sols, bound)`` where ``sols`` is as above and ``bound`` is the bound used for the entries in the exponent vectors. - EXAMPLES:: + EXAMPLES:: - sage: K. = NumberField(x^2+x+1) - sage: S = K.primes_above(3) - sage: K.S_unit_solutions(S) # random, due to ordering - [(xi + 2, -xi - 1), (1/3*xi + 2/3, -1/3*xi + 1/3), (-xi, xi + 1), (-xi + 1, xi)] + sage: K. = NumberField(x^2+x+1) + sage: S = K.primes_above(3) + sage: K.S_unit_solutions(S) # random, due to ordering + [(xi + 2, -xi - 1), (1/3*xi + 2/3, -1/3*xi + 1/3), (-xi, xi + 1), (-xi + 1, xi)] - You can get the exponent vectors:: + You can get the exponent vectors:: - sage: K.S_unit_solutions(S, include_exponents=True) # random, due to ordering - [((2, 1), (4, 0), xi + 2, -xi - 1), - ((5, -1), (4, -1), 1/3*xi + 2/3, -1/3*xi + 1/3), - ((5, 0), (1, 0), -xi, xi + 1), - ((1, 1), (2, 0), -xi + 1, xi)] + sage: K.S_unit_solutions(S, include_exponents=True) # random, due to ordering + [((2, 1), (4, 0), xi + 2, -xi - 1), + ((5, -1), (4, -1), 1/3*xi + 2/3, -1/3*xi + 1/3), + ((5, 0), (1, 0), -xi, xi + 1), + ((1, 1), (2, 0), -xi + 1, xi)] - And the computed bound:: + And the computed bound:: - sage: solutions, bound = K.S_unit_solutions(S, prec=100, include_bound=True) - sage: bound - 2 + sage: solutions, bound = K.S_unit_solutions(S, prec=100, include_bound=True) + sage: bound + 2 """ from .S_unit_solver import solve_S_unit_equation return solve_S_unit_equation(self, S, prec, include_exponents, include_bound, proof) @@ -6944,7 +6943,7 @@ def solve_CRT(self, reslist, Ilist, check=True): sage: K. = NumberField(x^2-10) sage: Ilist = [K.primes_above(p)[0] for p in prime_range(10)] sage: b = K.solve_CRT([1,2,3,4],Ilist,True) - sage: all([b-i-1 in Ilist[i] for i in range(4)]) + sage: all(b-i-1 in Ilist[i] for i in range(4)) True sage: Ilist = [K.ideal(a), K.ideal(2)] sage: K.solve_CRT([0,1],Ilist,True) @@ -6972,7 +6971,7 @@ def solve_CRT(self, reslist, Ilist, check=True): else: # n>2;, use induction / recursion x = self.solve_CRT([reslist[0],self.solve_CRT(reslist[1:],Ilist[1:])], [Ilist[0],prod(Ilist[1:])], check=check) - if check and not all([x-xi in Ii for xi,Ii in zip(reslist, Ilist)]): + if check and not all(x - xi in Ii for xi, Ii in zip(reslist, Ilist)): raise RuntimeError("Error in number field solve_CRT()") return self(x) @@ -9694,7 +9693,7 @@ def _gap_init_(self): sage: z = CyclotomicField(3).an_element(); z zeta3 sage: c = K.character([1,z,z**2]); c - Character of Subgroup of (Alternating group of order 4!/2 as a permutation group) generated by [(1,4,3)] + Character of Subgroup generated by [(1,4,3)] of (Alternating group of order 4!/2 as a permutation group) sage: c(g^2); z^2 zeta3 -zeta3 - 1 @@ -10251,6 +10250,13 @@ def _coerce_from_gap(self, x): Matrices over cyclotomic fields are correctly dealt with it as well:: + sage: b = libgap.eval('[[E(4), 1], [0, 1+E(8)-E(8)^3]]') + sage: matrix(F, b) + [ zeta8^2 1] + [ 0 -zeta8^3 + zeta8 + 1] + + It also works with the old pexpect interface to GAP:: + sage: b = gap(Matrix(F,[[z^2,1],[0,a+1]])); b [ [ E(4), 1 ], [ 0, 1+E(8)-E(8)^3 ] ] sage: b[1,2] @@ -10260,13 +10266,6 @@ def _coerce_from_gap(self, x): sage: matrix(F, b) [ zeta8^2 1] [ 0 -zeta8^3 + zeta8 + 1] - - It also word with libGAP instead of GAP:: - - sage: b = libgap.eval('[[E(4), 1], [0, 1+E(8)-E(8)^3]]') - sage: matrix(F, b) - [ zeta8^2 1] - [ 0 -zeta8^3 + zeta8 + 1] """ if x.IsRat(): return self(QQ(x)) diff --git a/src/sage/rings/number_field/number_field_base.pyx b/src/sage/rings/number_field/number_field_base.pyx index 4fdc55375b5..740af807f94 100644 --- a/src/sage/rings/number_field/number_field_base.pyx +++ b/src/sage/rings/number_field/number_field_base.pyx @@ -36,6 +36,15 @@ from sage.rings.ring cimport Field cdef class NumberField(Field): r""" Base class for all number fields. + + TESTS:: + + sage: z = polygen(QQ) + sage: K. = NumberField([z^3 - 3, z^2 + 1]) + sage: K.is_finite() + False + sage: K.order() + +Infinity """ # This token docstring is mostly there to prevent Sphinx from pasting in # the docstring of the __init__ method inherited from IntegralDomain, which @@ -120,21 +129,6 @@ cdef class NumberField(Field): """ raise NotImplementedError - def is_finite(self): - """ - Return False since number fields are not finite. - - EXAMPLES:: - - sage: z = polygen(QQ) - sage: K. = NumberField([z^3 - 3, z^2 + 1]) - sage: K.is_finite() - False - sage: K.order() - +Infinity - """ - return False - def is_absolute(self): """ Return True if self is viewed as a single extension over Q. diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index a90c12665a3..3edd42b2b36 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -1099,7 +1099,7 @@ def is_principal(self, proof=None): ``proof=True`` (this is the default setting) to prove the correctness of the output. - EXAMPLES: + EXAMPLES:: sage: K = QuadraticField(-119,'a') sage: P = K.factor(2)[1][0] diff --git a/src/sage/rings/padics/generic_nodes.py b/src/sage/rings/padics/generic_nodes.py index c726e7aa720..d862ccced0f 100644 --- a/src/sage/rings/padics/generic_nodes.py +++ b/src/sage/rings/padics/generic_nodes.py @@ -508,7 +508,7 @@ def label(self): Elements of a parent with some label do not coerce to a parent with a different label. However conversions are allowed. - EXAMPLES: + EXAMPLES:: sage: R = ZpLC(5) sage: R.label() # no label by default diff --git a/src/sage/rings/padics/lattice_precision.py b/src/sage/rings/padics/lattice_precision.py index 22c09f80710..e69ef472e78 100644 --- a/src/sage/rings/padics/lattice_precision.py +++ b/src/sage/rings/padics/lattice_precision.py @@ -780,7 +780,7 @@ def ambient_dimension(self): Return the dimension of the vector space in which the precision module/lattice lives. - EXAMPLES: + EXAMPLES:: sage: R = ZpLC(2, label='ambient_dim') sage: prec = R.precision() diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index c92d7949595..f2fcd5bcece 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -51,6 +51,17 @@ def __init__(self, base, prec, names, element_class, category=None): sage: R = Zp(5, 5, 'fixed-mod') sage: R._repr_option('element_is_atomic') False + + sage: R = Zp(3, 10,'fixed-mod') + sage: R.is_finite() + False + sage: R.cardinality() + +Infinity + + sage: Qp(11).is_finite() + False + sage: Qp(11).cardinality() + +Infinity """ self._prec = prec self.Element = element_class @@ -59,7 +70,7 @@ def __init__(self, base, prec, names, element_class, category=None): category = CompleteDiscreteValuationFields() else: category = CompleteDiscreteValuationRings() - category = category.Metric().Complete() + category = category.Metric().Complete().Infinite() if default_category is not None: category = check_default_category(default_category, category) Parent.__init__(self, base, names=(names,), normalize=False, category=category) @@ -1026,25 +1037,6 @@ def uniformiser_pow(self, n): """ return self.uniformizer_pow(n) - def is_finite(self): - r""" - Returns whether this ring is finite, i.e. ``False``. - - INPUT: - - - ``self`` -- a `p`-adic ring - - OUTPUT: - - - boolean -- whether self is finite, i.e., ``False`` - - EXAMPLES:: - - sage: R = Zp(3, 10,'fixed-mod'); R.is_finite() - False - """ - return False - def ext(self, *args, **kwds): """ Constructs an extension of self. See ``extension`` for more details. diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 7f482f9194e..8518daab69d 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -1128,7 +1128,7 @@ def _test_elements_eq_transitive(self, **options): The operator ``==`` is not transitive for `p`-adic numbers. We disable the check of the category framework by overriding this method. - EXAMPLES: + EXAMPLES:: sage: R = Zp(3) sage: R(3) == R(0,1) diff --git a/src/sage/rings/padics/padic_generic_element.pxd b/src/sage/rings/padics/padic_generic_element.pxd index 5b4641ddf44..9166e3fcf2c 100644 --- a/src/sage/rings/padics/padic_generic_element.pxd +++ b/src/sage/rings/padics/padic_generic_element.pxd @@ -38,4 +38,6 @@ cdef class pAdicGenericElement(LocalGenericElement): cdef bint _set_prec_both(self, long absprec, long relprec) except -1 cpdef abs(self, prec=*) + cpdef _mod_(self, right) + cpdef _floordiv_(self, right) cpdef bint _is_base_elt(self, p) except -1 diff --git a/src/sage/rings/padics/padic_lattice_element.py b/src/sage/rings/padics/padic_lattice_element.py index 51f672f1c5c..3c245d55d85 100644 --- a/src/sage/rings/padics/padic_lattice_element.py +++ b/src/sage/rings/padics/padic_lattice_element.py @@ -791,8 +791,8 @@ def lift_to_precision(self, prec=None, infer_precision=False): with the same parent. When ``infer_precision`` is set to ``False``, the precision on the - newly created variable is independant as if the variable were created - by hand by setting independantly the value of the absolute precision. + newly created variable is independent as if the variable were created + by hand by setting independently the value of the absolute precision. In particular, if ``self`` used to share diffused digits of precision with other variables, they are not preserved. @@ -909,7 +909,7 @@ def lift(self): its absolute precision. If a rational is returned, its denominator will be a power of `p`. - EXAMPLES: + EXAMPLES:: sage: R = ZpLC(7) sage: a = R(8); a.lift() diff --git a/src/sage/rings/polynomial/binary_form_reduce.py b/src/sage/rings/polynomial/binary_form_reduce.py index 944341096ab..bb0e275ade2 100644 --- a/src/sage/rings/polynomial/binary_form_reduce.py +++ b/src/sage/rings/polynomial/binary_form_reduce.py @@ -132,7 +132,7 @@ def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001): """ R = F.parent() d = ZZ(F.degree()) - if R.ngens() != 2 or any([sum(t) != d for t in F.exponents()]): + if R.ngens() != 2 or any(sum(t) != d for t in F.exponents()): raise TypeError('must be a binary form') if d < 3: raise ValueError('must be at least degree 3') @@ -328,7 +328,7 @@ def epsF(delta): if z is None: z, th = covariant_z0(F, prec=prec, emb=emb) else: #need to do our own input checking - if R.ngens() != 2 or any([sum(t) != d for t in F.exponents()]): + if R.ngens() != 2 or any(sum(t) != d for t in F.exponents()): raise TypeError('must be a binary form') if d < 3: raise ValueError('must be at least degree 3') diff --git a/src/sage/rings/polynomial/infinite_polynomial_element.py b/src/sage/rings/polynomial/infinite_polynomial_element.py index 4d7c4592a34..36c2e2a1240 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_element.py +++ b/src/sage/rings/polynomial/infinite_polynomial_element.py @@ -73,7 +73,7 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Simon King # and Mike Hansen , # @@ -86,8 +86,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from six.moves import range from sage.rings.integer_ring import ZZ @@ -254,7 +254,6 @@ def _repr_(self): sage: X. = InfinitePolynomialRing(QQ) sage: str(x[1] + x[2]) # indirect doctest 'x_2 + x_1' - """ return repr(self._p) @@ -264,9 +263,9 @@ def __hash__(self): sage: X. = InfinitePolynomialRing(QQ) sage: a = x[0] + x[1] - sage: hash(a) # indirect doctest - 971115012877883067 # 64-bit - -2103273797 # 32-bit + sage: b = 1 + 4*x[1] + sage: hash(a) != hash(b) + True """ return hash(self._p) @@ -277,7 +276,7 @@ def polynomial(self): EXAMPLES:: sage: X. = InfinitePolynomialRing(GF(7)) - sage: p=x[2]*y[1]+3*y[0] + sage: p = x[2]*y[1]+3*y[0] sage: p x_2*y_1 + 3*y_0 sage: p.polynomial() diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index 1ae30cae6f5..df95b964297 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -713,16 +713,16 @@ def __init__(self, R, names, order): self._find_maxshift = re.compile('_([0-9]+)') # findall yields stringrep of the shifts self._find_variables = re.compile('[a-zA-Z0-9]+_[0-9]+') self._find_varpowers = re.compile(r'([a-zA-Z0-9]+)_([0-9]+)\^?([0-9]*)') # findall yields triple "generator_name", "index", "exponent" - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + # Create some small underlying polynomial ring. # It is used to ensure that the parent of the underlying # polynomial of an element of self is actually a *multi*variate # polynomial ring. from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - if len(names)==1: - VarList = [names[0]+'_0',names[0]+'_1'] + if len(names) == 1: + VarList = [names[0] + '_0', names[0] + '_1'] else: - VarList = [X+'_0' for X in names] + VarList = [X + '_0' for X in names] VarList.sort(key=self.varname_key, reverse=True) self._minP = PolynomialRing(R, len(VarList), VarList) self._populate_coercion_lists_() @@ -828,18 +828,17 @@ def _coerce_map_from_(self, S): sage: X. = InfinitePolynomialRing(R) sage: a[2]*x[3]+x[1]*a[4]^2 a_4^2*x_1 + a_2*x_3 - """ # Use Construction Functors! - from sage.categories.pushout import pushout, construction_tower + from sage.categories.pushout import pushout try: # the following line should not test "pushout is self", but # only "pushout == self", since we also allow coercion from # dense to sparse implementation! - P = pushout(self,S) - # We don't care about the orders. But base ring and generators + P = pushout(self, S) + # We do not care about the orders. But base ring and generators # of the pushout should remain the same as in self. - return (P._names == self._names and P._base == self._base) + return P._names == self._names and P._base == self._base except Exception: return False @@ -1064,16 +1063,19 @@ def tensor_with_ring(self, R): # -- some stuff that is useful for quotient rings etc. def is_noetherian(self): """ + Return ``False``, since polynomial rings in infinitely many + variables are never Noetherian rings. + Since Infinite Polynomial Rings must have at least one generator, they have infinitely many variables and are thus not noetherian, as a ring. - NOTE: + .. NOTE:: - Infinite Polynomial Rings over a field `F` are noetherian as - `F(G)` modules, where `G` is the symmetric group of the - natural numbers. But this is not what the method - ``is_noetherian()`` is answering. + Infinite Polynomial Rings over a field `F` are noetherian as + `F(G)` modules, where `G` is the symmetric group of the + natural numbers. But this is not what the method + ``is_noetherian()`` is answering. TESTS:: @@ -1083,14 +1085,18 @@ def is_noetherian(self): sage: R.is_noetherian() False + sage: R. = InfinitePolynomialRing(QQ) + sage: R.is_noetherian() + False """ return False def is_field(self, *args, **kwds): """ - Return ``False``: Since Infinite Polynomial Rings must have at - least one generator, they have infinitely many variables and thus - never are fields. + Return ``False`` since Infinite Polynomial Rings are never fields. + + Since Infinite Polynomial Rings must have at least one generator, + they have infinitely many variables and thus never are fields. EXAMPLES:: @@ -1098,7 +1104,6 @@ def is_field(self, *args, **kwds): sage: R.is_field() False - TESTS:: sage: R = InfinitePolynomialRing(GF(2)) @@ -1112,8 +1117,6 @@ def is_field(self, *args, **kwds): sage: W = PowerSeriesRing(InfinitePolynomialRing(QQ,'a'),'x') sage: W.is_field() False - - """ return False @@ -1296,23 +1299,6 @@ def is_integral_domain(self, *args, **kwds): """ return self._base.is_integral_domain(*args, **kwds) - def is_noetherian(self, *args, **kwds): - """ - Return ``False``, since polynomial rings in infinitely many - variables are never Noetherian rings. - - Note, however, that they are noetherian modules over the group - ring of the symmetric group of the natural numbers - - EXAMPLES:: - - sage: R. = InfinitePolynomialRing(QQ) - sage: R.is_noetherian() - False - - """ - return False - def krull_dimension(self, *args, **kwds): """ Return ``Infinity``, since polynomial rings in infinitely many diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index f4161e4094f..c05d06d05fe 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -14,7 +14,7 @@ from __future__ import print_function, absolute_import from sage.rings.integer cimport Integer from sage.rings.integer_ring import ZZ -from sage.structure.element cimport coercion_model +from sage.structure.coerce cimport coercion_model from sage.misc.derivative import multi_derivative from sage.rings.infinity import infinity from sage.structure.element cimport Element diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 2a296087003..194aa52d3fe 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -1243,11 +1243,11 @@ def univariate_polynomial(self, R=None): monomial_coefficients = self._MPolynomial_element__element.dict() - if( not self.is_constant() ): + if not self.is_constant(): var_idx = self.degrees().nonzero_positions()[0] #variable else: - var_idx = 0; #constant - if( len(monomial_coefficients.keys())==0 ): + var_idx = 0 #constant + if len(monomial_coefficients) == 0: return R(0) #construct list diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 5bc617b22fc..6aaae477ef0 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -521,7 +521,6 @@ def _groebner_basis_libsingular(self, algorithm="groebner", *args, **kwds): from sage.rings.polynomial.multi_polynomial_ideal_libsingular import std_libsingular, slimgb_libsingular from sage.libs.singular.function import singular_function from sage.libs.singular.option import opt - from sage.misc.stopgap import stopgap import sage.libs.singular.function_factory groebner = sage.libs.singular.function_factory.ff.groebner @@ -532,8 +531,6 @@ def _groebner_basis_libsingular(self, algorithm="groebner", *args, **kwds): if value is not None: opt[name] = value - T = self.ring().term_order() - if algorithm == "std": S = std_libsingular(self) elif algorithm == "slimgb": @@ -1970,8 +1967,7 @@ def transformed_basis(self, algorithm="gwalk", other_ring=None, singular=singula else: raise TypeError("Cannot convert basis with given algorithm") - @libsingular_gb_standard_options - def elimination_ideal(self, variables): + def elimination_ideal(self, variables, algorithm=None, *args, **kwds): r""" Return the elimination ideal of this ideal with respect to the variables given in ``variables``. @@ -1980,29 +1976,77 @@ def elimination_ideal(self, variables): - ``variables`` -- a list or tuple of variables in ``self.ring()`` + - ``algorithm`` - determines the algorithm to use, see below + for available algorithms. + + ALGORITHMS: + + - ``'libsingular:eliminate'`` -- libSingular's ``eliminate`` command + (default) + + - ``'giac:eliminate'`` -- Giac's ``eliminate`` command (if available) + + If only a system is given - e.g. 'giac' - the default algorithm is + chosen for that system. + EXAMPLES:: sage: R. = PolynomialRing(QQ,5) sage: I = R * [x-t,y-t^2,z-t^3,s-x+y^3] - sage: I.elimination_ideal([t,s]) + sage: J = I.elimination_ideal([t,s]); J Ideal (y^2 - x*z, x*y - z, x^2 - y) of Multivariate Polynomial Ring in x, y, t, s, z over Rational Field + You can use Giac to compute the elimination ideal:: + + sage: I.elimination_ideal([t, s], algorithm="giac") == J # optional - giacpy_sage + ... + Running a probabilistic check for the reconstructed Groebner basis... + True + + The list of available Giac options is provided at + :func:`sage.libs.giac.groebner_basis`. + ALGORITHM: - Uses Singular. + Uses Singular, or Giac (if available). .. NOTE:: Requires computation of a Groebner basis, which can be a very expensive operation. """ + if not isinstance(variables, (list, tuple)): + variables = (variables,) + + if (algorithm is None or algorithm.lower() == 'libsingular' + or algorithm == 'libsingular:eliminate'): + return self._elimination_ideal_libsingular(variables) + + elif algorithm.lower() == 'giac' or algorithm == 'giac:eliminate': + from sage.libs.giac import groebner_basis as groebner_basis_libgiac + return groebner_basis_libgiac( + self, elim_variables=variables, *args, **kwds).ideal() + + else: + raise NameError("Algorithm '%s' unknown." % algorithm) + + @libsingular_gb_standard_options + def _elimination_ideal_libsingular(self, variables): + r""" + Compute the elimination ideal using libsingular. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ,5) + sage: I = R * [x-t,y-t^2,z-t^3,s-x+y^3] + sage: I.elimination_ideal([t,s], "libsingular") # indirect doctest + Ideal (y^2 - x*z, x*y - z, x^2 - y) of Multivariate + Polynomial Ring in x, y, t, s, z over Rational Field + """ import sage.libs.singular.function_factory eliminate = sage.libs.singular.function_factory.ff.eliminate - if not isinstance(variables, (list,tuple)): - variables = (variables,) - R = self.ring() Is = MPolynomialIdeal(R,self.groebner_basis()) return MPolynomialIdeal(R, eliminate(Is, prod(variables)) ) @@ -2137,9 +2181,9 @@ def variety(self, ring=None): + 1) of Multivariate Polynomial Ring in x, y over Finite Field in w of size 3^3 - sage: V = I.variety(); V - [{y: w^2 + 2, x: 2*w}, {y: w^2 + w, x: 2*w + 1}, {y: w^2 + 2*w, x: 2*w + 2}] - + sage: V = I.variety(); + sage: sorted(V, key=str) + [{y: w^2 + 2*w, x: 2*w + 2}, {y: w^2 + 2, x: 2*w}, {y: w^2 + w, x: 2*w + 1}] sage: [f.subs(v) for f in I.gens() for v in V] # check that all polynomials vanish [0, 0, 0, 0, 0, 0] sage: [I.subs(v).is_zero() for v in V] # same test, but nicer syntax @@ -2167,27 +2211,31 @@ def variety(self, ring=None): There are two real intersections:: - sage: I.variety(ring=RR) + sage: sorted(I.variety(ring=RR), key=str) [{y: 0.361103080528647, x: 2.76929235423863}, {y: 1.00000000000000, x: 1.00000000000000}] - sage: I.variety(ring=AA) - [{x: 2.769292354238632?, y: 0.3611030805286474?}, - {x: 1, y: 1}] + sage: I.variety(ring=AA) # py2 + [{x: 1, y: 1}, + {x: 2.769292354238632?, y: 0.3611030805286474?}] + sage: I.variety(ring=AA) # py3 + [{y: 1, x: 1}, + {y: 0.3611030805286474?, x: 2.769292354238632?}] + and a total of four intersections:: - sage: I.variety(ring=CC) - [{y: 0.31944845973567... - 1.6331702409152...*I, - x: 0.11535382288068... + 0.58974280502220...*I}, - {y: 0.31944845973567... + 1.6331702409152...*I, + sage: sorted(I.variety(ring=CC), key=str) + [{y: 0.31944845973567... + 1.6331702409152...*I, x: 0.11535382288068... - 0.58974280502220...*I}, + {y: 0.31944845973567... - 1.6331702409152...*I, + x: 0.11535382288068... + 0.58974280502220...*I}, {y: 0.36110308052864..., x: 2.7692923542386...}, {y: 1.00000000000000, x: 1.00000000000000}] - sage: I.variety(ring=QQbar) - [{y: 0.3194484597356763? - 1.633170240915238?*I, - x: 0.11535382288068429? + 0.5897428050222055?*I}, - {y: 0.3194484597356763? + 1.633170240915238?*I, + sage: sorted(I.variety(ring=QQbar), key=str) + [{y: 0.3194484597356763? + 1.633170240915238?*I, x: 0.11535382288068429? - 0.5897428050222055?*I}, + {y: 0.3194484597356763? - 1.633170240915238?*I, + x: 0.11535382288068429? + 0.5897428050222055?*I}, {y: 0.3611030805286474?, x: 2.769292354238632?}, {y: 1, x: 1}] @@ -2196,13 +2244,13 @@ def variety(self, ring=None): sage: R. = CC[] sage: I = ideal([x^2+y^2-1,x*y-1]) - sage: I.variety() + sage: sorted(I.variety(), key=str) verbose 0 (...: multi_polynomial_ideal.py, variety) Warning: computations in the complex field are inexact; variety may be computed partially or incorrectly. verbose 0 (...: multi_polynomial_ideal.py, variety) Warning: falling back to very slow toy implementation. - [{y: -0.86602540378443... - 0.500000000000000*I}, - {y: -0.86602540378443... + 0.500000000000000*I}, - {y: 0.86602540378443... - 0.500000000000000*I}, - {y: 0.86602540378443... + 0.500000000000000*I}] + [{y: -0.86602540378443... + 0.500000000000000*I}, + {y: -0.86602540378443... - 0.500000000000000*I}, + {y: 0.86602540378443... + 0.500000000000000*I}, + {y: 0.86602540378443... - 0.500000000000000*I}] This is due to precision error, which causes the computation of an intermediate Groebner basis to fail. @@ -2225,8 +2273,8 @@ def variety(self, ring=None): sage: K. = QQ[] sage: I = ideal([x^2+2*y-5,x+y+3]) - sage: v = I.variety(AA)[0]; v - {x: 4.464101615137755?, y: -7.464101615137755?} + sage: v = I.variety(AA)[0]; v[x], v[y] + (4.464101615137755?, -7.464101615137755?) sage: list(v)[0].parent() Multivariate Polynomial Ring in x, y over Algebraic Real Field sage: v[x] @@ -2243,8 +2291,8 @@ def variety(self, ring=None): Testing the robustness of the Singular interface:: sage: T = I.triangular_decomposition('singular:triangLfak') - sage: I.variety() - [{y: w^2 + 2, x: 2*w}, {y: w^2 + w, x: 2*w + 1}, {y: w^2 + 2*w, x: 2*w + 2}] + sage: sorted(I.variety(), key=str) + [{y: w^2 + 2*w, x: 2*w + 2}, {y: w^2 + 2, x: 2*w}, {y: w^2 + w, x: 2*w + 1}] Testing that a bug is indeed fixed :: @@ -2363,7 +2411,7 @@ def _variety(T, V, v=None): try: TI = self.triangular_decomposition('singular:triangLfak') T = [list(each.gens()) for each in TI] - except TypeError as msg: # conversion to Singular not supported + except TypeError: # conversion to Singular not supported if self.ring().term_order().is_global(): verbose("Warning: falling back to very slow toy implementation.", level=0) T = toy_variety.triangular_factorization(self.groebner_basis()) @@ -2374,11 +2422,9 @@ def _variety(T, V, v=None): V = [] for t in T: Vbar = _variety([P(f) for f in t], []) - #Vbar = _variety(list(t.gens()),[]) for v in Vbar: V.append(KeyConvertingDict(P, v)) - V.sort() return V @require_field @@ -2641,7 +2687,6 @@ def hilbert_numerator(self, grading = None, algorithm = 'sage'): gb = self.groebner_basis() t = ZZ['t'].gen() - n = self.ring().ngens() gb = MPolynomialIdeal(self.ring(), gb) if grading is not None: if not isinstance(grading, (list, tuple)) or any(a not in ZZ for a in grading): @@ -3604,7 +3649,9 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: I.groebner_basis('libsingular:slimgb') [a - 60*c^3 + 158/7*c^2 + 8/7*c - 1, b + 30*c^3 - 79/7*c^2 + 3/7*c, c^4 - 10/21*c^3 + 1/84*c^2 + 1/84*c] - Giac only supports the degree reverse lexicographical ordering:: + Although Giac does support lexicographical ordering, we use degree + reverse lexicographical ordering here, in order to test against + :trac:`21884`:: sage: I = sage.rings.ideal.Katsura(P,3) # regenerate to prevent caching sage: J = I.change_ring(P.change_ring(order='degrevlex')) @@ -3810,10 +3857,10 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal if not algorithm: try: gb = self._groebner_basis_libsingular("groebner", deg_bound=deg_bound, mult_bound=mult_bound, *args, **kwds) - except (TypeError, NameError) as msg: # conversion to Singular not supported + except (TypeError, NameError): # conversion to Singular not supported try: gb = self._groebner_basis_singular("groebner", deg_bound=deg_bound, mult_bound=mult_bound, *args, **kwds) - except (TypeError, NameError, NotImplementedError) as msg: # conversion to Singular not supported + except (TypeError, NameError, NotImplementedError): # conversion to Singular not supported if self.ring().term_order().is_global() and is_IntegerModRing(self.ring().base_ring()) and not self.ring().base_ring().is_field(): verbose("Warning: falling back to very slow toy implementation.", level=0) @@ -4307,7 +4354,6 @@ def plot(self, *args, **kwds): - Martin Albrecht (2008-09) """ - from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RR from sage.plot.all import implicit_plot @@ -4500,8 +4546,10 @@ def weil_restriction(self): Multivariate Polynomial Ring in x0, x1, y0, y1 over Finite Field of size 2 sage: J += sage.rings.ideal.FieldIdeal(J.ring()) # ensure radical ideal - sage: J.variety() + sage: J.variety() # py2 [{y1: 1, x1: 1, x0: 1, y0: 0}] + sage: J.variety() # py3 + [{y1: 1, y0: 0, x1: 1, x0: 1}] sage: J.weil_restriction() # returns J Ideal (x0*y0 + x1*y1 + 1, x1*y0 + x0*y1 + x1*y1, x1 + 1, x0 + x1, x0^2 + @@ -4513,8 +4561,10 @@ def weil_restriction(self): sage: I = sage.rings.ideal.Katsura(P) sage: I.dimension() 0 - sage: I.variety() + sage: I.variety() # py2 [{y: 0, z: 0, x: 1}] + sage: I.variety() # py3 + [{z: 0, y: 0, x: 1}] sage: J = I.weil_restriction(); J Ideal (x0 - y0 - z0 - 1, x1 - y1 - z1, x2 - y2 - z2, x3 - y3 - z3, x4 - @@ -4656,6 +4706,6 @@ def weil_restriction(self): result_ring = PolynomialRing(k, nvars*r, new_var_names) map_ideal = (0,) + result_ring.gens() - result = [f(*map_ideal) for f in result] + result = [h(*map_ideal) for h in result] return result_ring.ideal(result) diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 148eb91f7db..e8ea6bcd6db 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -191,7 +191,7 @@ from sage.libs.singular.decl cimport ( p_ISet, rChangeCurrRing, p_Copy, p_Init, p_SetCoeff, p_Setm, p_SetExp, p_Add_q, p_NSet, p_GetCoeff, p_Delete, p_GetExp, pNext, rRingVar, omAlloc0, omStrDup, omFree, p_Divide, p_SetCoeff0, n_Init, p_DivisibleBy, pLcm, p_LmDivisibleBy, - pMDivide, p_IsConstant, p_ExpVectorEqual, p_String, p_LmInit, n_Copy, + pMDivide, p_MDivide, p_IsConstant, p_ExpVectorEqual, p_String, p_LmInit, n_Copy, p_IsUnit, p_Series, p_Head, idInit, fast_map_common_subexp, id_Delete, p_IsHomogeneous, p_Homogen, p_Totaldegree,pLDeg1_Totaldegree, singclap_pdivide, singclap_factorize, idLift, IDELEMS, On, Off, SW_USE_CHINREM_GCD, SW_USE_EZGCD, @@ -219,7 +219,7 @@ from sage.libs.singular.ring cimport singular_ring_new, singular_ring_reference, from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict, MPolynomialRing_polydict_domain from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal -from sage.rings.polynomial.polydict import ETuple +from sage.rings.polynomial.polydict cimport ETuple from sage.rings.polynomial.polynomial_ring import is_PolynomialRing # base ring imports @@ -241,12 +241,8 @@ from sage.structure.parent_base cimport ParentWithBase from sage.structure.parent_gens cimport ParentWithGens from sage.structure.category_object cimport CategoryObject -from sage.structure.element cimport EuclideanDomainElement -from sage.structure.element cimport RingElement -from sage.structure.element cimport ModuleElement -from sage.structure.element cimport Element -from sage.structure.element cimport CommutativeRingElement -from sage.structure.element cimport coercion_model +from sage.structure.coerce cimport coercion_model +from sage.structure.element cimport Element, CommutativeRingElement from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.structure.factorization import Factorization @@ -960,7 +956,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): variable_names_t = self.variable_names() if variable_names_s.issubset(variable_names_t): - return eval(str(element),self.gens_dict()) + return eval(str(element),self.gens_dict(copy=False)) elif element.parent().ngens() <= self.ngens(): Q = element.parent() @@ -1544,7 +1540,8 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): """ Serializes self. - EXAMPLES: + EXAMPLES:: + sage: P. = PolynomialRing(QQ, order='degrevlex') sage: P == loads(dumps(P)) True @@ -2565,7 +2562,7 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: P. = QQ[] sage: f = - 1*x^2*y - 25/27 * y^3 - z^2 sage: latex(f) # indirect doctest - - x^{2} y - \frac{25}{27} y^{3} - z^{2} + -x^{2} y - \frac{25}{27} y^{3} - z^{2} """ cdef ring *_ring = self._parent_ring gens = self.parent().latex_variable_names() @@ -2833,6 +2830,14 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: f.coefficient(x) y^2 + y + 1 + Note that exponents have all variables specified:: + + sage: x.coefficient(x.exponents()[0]) + 1 + sage: f.coefficient([1,0]) + 1 + sage: f.coefficient({x:1,y:0}) + 1 Be aware that this may not be what you think! The physical appearance of the variable x is deceiving -- particularly if @@ -2877,6 +2882,9 @@ cdef class MPolynomial_libsingular(MPolynomial): exps[i] = -1 else: exps[i] = int(degrees[i]) + elif isinstance(degrees, ETuple): + for i in range(gens): + exps[i] = int((degrees).get_exp(i)) elif isinstance(degrees, dict): # Extract the ordered list of degree specifications from the dictionary poly_vars = self.parent().gens() @@ -3427,7 +3435,7 @@ cdef class MPolynomial_libsingular(MPolynomial): try_symbolic = 1 if not try_symbolic and fixed is not None: - for m,v in fixed.iteritems(): + for m,v in fixed.items(): if isinstance(m, (int, Integer)): mi = m+1 elif isinstance(m,MPolynomial_libsingular) and m.parent() is parent: @@ -3468,7 +3476,7 @@ cdef class MPolynomial_libsingular(MPolynomial): cdef dict gd if not try_symbolic: - gd = parent.gens_dict() + gd = parent.gens_dict(copy=False) for m,v in kw.iteritems(): m = gd[m] for i from 0 < i <= _ring.N: @@ -3533,7 +3541,7 @@ cdef class MPolynomial_libsingular(MPolynomial): cdef list g = list(parent.gens()) if fixed is not None: - for m,v in fixed.iteritems(): + for m,v in fixed.items(): if isinstance(m, (int, Integer)): mi = m+1 elif isinstance(m, MPolynomial_libsingular) and m.parent() is parent: @@ -3548,7 +3556,7 @@ cdef class MPolynomial_libsingular(MPolynomial): g[mi-1] = v - gd = parent.gens_dict() + gd = parent.gens_dict(copy=False) for m,v in kw.iteritems(): m = gd[m] for i from 0 < i <= _ring.N: @@ -4040,26 +4048,21 @@ cdef class MPolynomial_libsingular(MPolynomial): if right.is_zero(): raise ZeroDivisionError + elif right.is_one(): + return self if self._parent._base.is_finite() and self._parent._base.characteristic() > 1<<29: raise NotImplementedError("Division of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") _right = right - if r is not currRing: - rChangeCurrRing(r) - if r.cf.type != n_unknown: - if r.cf.type == n_Z: - P = parent.change_ring(QQ) - f = (P(self))._floordiv_(P(right)) - return parent(sum([c.floor() * m for c, m in f])) if _right.is_monomial(): p = self._poly quo = p_ISet(0,r) while p: if p_DivisibleBy(_right._poly, p, r): - temp = pMDivide(p, _right._poly) + temp = p_MDivide(p, _right._poly, r) p_SetCoeff0(temp, n_Copy(p_GetCoeff(p, r), r), r) quo = p_Add_q(quo, temp, r) p = pNext(p) @@ -4068,11 +4071,24 @@ cdef class MPolynomial_libsingular(MPolynomial): raise NotImplementedError("Division of multivariate polynomials over non fields by non-monomials not implemented.") count = singular_polynomial_length_bounded(self._poly, 15) + + # fast in the most common case where the division is exact; returns zero otherwise if count >= 15: # note that _right._poly must be of shorter length than self._poly for us to care about this call sig_on() - quo = singclap_pdivide(self._poly, _right._poly, r) + quo = p_Divide(p_Copy(self._poly, r), p_Copy(_right._poly, r), r) if count >= 15: sig_off() + + if quo == NULL: + if r.cf.type == n_Z: + P = parent.change_ring(QQ) + f = (P(self))._floordiv_(P(right)) + return parent(sum([c.floor() * m for c, m in f])) + else: + sig_on() + quo = singclap_pdivide(self._poly, _right._poly, r) + sig_off() + return new_MP(parent, quo) def factor(self, proof=None): diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd b/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd index 7e713c01dac..754098dd67b 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pxd @@ -2,6 +2,7 @@ cimport sage.rings.ring from sage.structure.parent cimport Parent cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): + cdef readonly _no_generic_basering_coercion cdef object __ngens cdef object __term_order cdef public object _has_singular diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index ee76f34c922..7eea1607e53 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -63,6 +63,14 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): True sage: A1(a) in A2 True + + Check that :trac:`26958` is fixed:: + + sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + sage: class Foo(MPolynomialRing_libsingular): + ....: pass + sage: Foo(QQ, 2, ['x','y'], 'degrevlex') + Multivariate Polynomial Ring in x, y over Rational Field """ if base_ring not in _CommutativeRings: raise TypeError("The base ring %s is not a commutative ring" % base_ring) @@ -85,6 +93,9 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): else: category = polynomial_default_category(base_ring.category(), n) + # Avoid calling __init_extra__ of Algebras(...).parent_class + self._no_generic_basering_coercion = True + sage.rings.ring.Ring.__init__(self, base_ring, names, category=category) def is_integral_domain(self, proof = True): @@ -548,30 +559,6 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): return 'PolynomialRing(%s,[%s])'%(gap(self.base_ring()).name(),','.join(L)) return 'PolynomialRing(%s,[%s])'%(self.base_ring()._gap_init_(),','.join(L)) - def is_finite(self): - r""" - Test whether this multivariate polynomial ring is finite. - - .. TODO:: - - This should be handled by categories but ``sage.rings.Ring`` does - implement a ``is_finite`` method that overrides that category - implementation. - - EXAMPLES:: - - sage: PolynomialRing(QQ, names=[]).is_finite() - False - sage: PolynomialRing(GF(5), names=[]).is_finite() - True - sage: PolynomialRing(GF(5),names=['x']).is_finite() - False - sage: PolynomialRing(Zmod(1), names=['x','y']).is_finite() - True - """ - category = self.category() - return category is category.Finite() - def is_field(self, proof = True): """ Test whether this multivariate polynomial ring is a field. @@ -587,6 +574,8 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): True sage: PolynomialRing(ZZ, 'x', 0).is_field() False + sage: PolynomialRing(Zmod(1), names=['x','y']).is_finite() + True """ if not self.ngens(): return self.base_ring().is_field(proof) diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index e62cf0eaa44..0ac6611dc62 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -208,8 +208,8 @@ from sage.rings.polynomial.polynomial_ring import PolynomialRing_general from sage.rings.ideal import FieldIdeal -from sage.structure.element cimport (Element, RingElement, - have_same_parent, coercion_model) +from sage.structure.coerce cimport coercion_model +from sage.structure.element cimport Element from sage.structure.parent cimport Parent from sage.structure.sequence import Sequence @@ -225,21 +225,20 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.interfaces.all import singular as singular_default from sage.interfaces.singular import SingularElement -order_dict= {"lp": pblp, - "dlex": pbdlex, - "dp_asc": pbdp_asc, - "dp": pbdp, - "block_dlex": pbblock_dlex, - "block_dp_asc": pbblock_dp_asc, - "block_dp": pbblock_dp, - } +order_dict = {"lp": pblp, + "dlex": pbdlex, + "dp_asc": pbdp_asc, + "dp": pbdp, + "block_dlex": pbblock_dlex, + "block_dp_asc": pbblock_dp_asc, + "block_dp": pbblock_dp} -inv_order_dict= {pblp: "lex", - pbdlex: "deglex", - pbdp_asc: "degneglex", - pbdp: "degrevlex", - } +inv_order_dict = {pblp: "lex", + pbdlex: "deglex", + pbdp_asc: "degneglex", + pbdp: "degrevlex"} + order_mapping = {'lp': pblp, 'lex': pblp, @@ -249,8 +248,7 @@ order_mapping = {'lp': pblp, 'dp_asc': pbdp_asc, 'degneglex': pbdp_asc, 'dp': pbdp, - 'degrevlex': pbdp, - } + 'degrevlex': pbdp} lp = int(pblp) @@ -262,6 +260,7 @@ block_dp_asc = int(pbblock_dp_asc) rings = sage.misc.weak_dict.WeakValueDictionary() + cdef class BooleanPolynomialRing(MPolynomialRing_base): """ Construct a boolean polynomial ring with the following parameters: @@ -349,7 +348,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): .. NOTE:: - See class documentation for parameters. + See class documentation for parameters. """ cdef Py_ssize_t i, j, bstart, bsize @@ -357,7 +356,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): raise TypeError("You must specify the names of the variables.") if n is None: - if isinstance(names, tuple) or isinstance(names, list): + if isinstance(names, (tuple, list)): n = len(names) try: @@ -379,10 +378,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): ', '.join(order_mapping.keys()) + " are supported.") - if pb_order_code in (pbdp, pbblock_dp): - from sage.misc.superseded import deprecation - deprecation(13849, "using 'degrevlex' in Boolean polynomial rings is deprecated. If needed, reverse the order of variables manually and use 'degneglex'") - if order.is_block_order(): if pb_order_code is pblp: raise ValueError("Only deglex and degneglex are supported for block orders.") @@ -489,7 +484,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): - ``i`` - an integer or a boolean monomial in one variable - EXAMPLES:: sage: P. = BooleanPolynomialRing(3) @@ -595,7 +589,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): # it to be fast. if self._repr is None: gens = ", ".join(self._names) - self._repr = "Boolean PolynomialRing in %s"%(gens) + self._repr = "Boolean PolynomialRing in %s" % (gens) return self._repr # Coercion @@ -668,9 +662,10 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): """ if self._base.has_coerce_map_from(S): return True - if isinstance(S,(MPolynomialRing_base,PolynomialRing_general,BooleanMonomialMonoid)): + if isinstance(S, (MPolynomialRing_base, PolynomialRing_general, + BooleanMonomialMonoid)): try: - get_var_mapping(self,S) + get_var_mapping(self, S) except NameError: return False return self._base.has_coerce_map_from(S.base()) @@ -805,8 +800,8 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): if isinstance(other, BooleSet): other = new_BP_from_PBSet(other.ring(), (other)._pbset) - if isinstance(other, int) or isinstance(other, Integer): - if (other %2) == 1: + if isinstance(other, (int, Integer)): + if other % 2: return self._one_element else: return self._zero_element @@ -846,8 +841,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): new_monom *= var_mapping[i] p += new_monom return p - elif (isinstance(other, MPolynomial) or \ - isinstance(other, Polynomial)) and \ + elif isinstance(other, (MPolynomial, Polynomial)) and \ self.base_ring().has_coerce_map_from(other.base_ring()) and \ (other.parent().ngens() <= self._pbring.nVariables()): try: @@ -961,13 +955,12 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): new_monom *= var_mapping[i] p += new_monom return p - elif (isinstance(other, MPolynomial) or \ - isinstance(other, Polynomial)) and \ + elif (isinstance(other, (MPolynomial, Polynomial))) and \ self.base_ring().has_coerce_map_from(other.base_ring()): try: var_mapping = get_var_mapping(self, other) except NameError as msg: - raise TypeError("cannot convert polynomial %s to %s: %s"%(other, self, msg)) + raise TypeError("cannot convert polynomial %s to %s: %s" % (other, self, msg)) p = self._zero_element exponents = other.exponents() coefs = other.coefficients() @@ -1007,8 +1000,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): except Exception: raise TypeError("cannot convert %s to BooleanPolynomial" % (type(other))) - i = i % 2 - if i == 1: + if i % 2: return self._one_element else: return self._zero_element @@ -1442,8 +1434,8 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): #R = magma(self.cover_ring()) #v = [z.name() for z in R.gens()] # important to use this because it caches the generators #w = [f._repr_with_changed_varnames(v) for f in self.defining_ideal().gens()] - #return "quo<%s | %s>"%(R.name(), ",".join(w)) - s = 'BooleanPolynomialRing(%s,%s)'%(self.ngens(), self.term_order().magma_str()) + #return "quo<%s | %s>" % (R.name(), ",".join(w)) + s = 'BooleanPolynomialRing(%s,%s)' % (self.ngens(), self.term_order().magma_str()) return magma._with_names(s, self.variable_names()) def interpolation_polynomial(self, zeros, ones): @@ -1885,7 +1877,7 @@ class BooleanMonomialMonoid(UniqueRepresentation, Monoid_class): .. NOTE:: - See class documentation for parameters. + See class documentation for parameters. """ cdef BooleanMonomial m self._ring = polring @@ -1938,7 +1930,7 @@ class BooleanMonomialMonoid(UniqueRepresentation, Monoid_class): def gen(self, Py_ssize_t i=0): """ - Return the i-th generator of self. + Return the i-th generator of ``self``. INPUT: @@ -4090,7 +4082,7 @@ cdef class BooleanPolynomial(MPolynomial): fixed = {} if in_dict is not None: - for var,val in in_dict.iteritems(): + for var,val in in_dict.items(): if isinstance(var, basestring): var = P(var) elif var.parent() is not P: @@ -4599,7 +4591,7 @@ cdef class BooleanPolynomial(MPolynomial): """ if isinstance(s, BooleSet): return new_BS_from_PBSet(pb_zeros(self._pbpoly, (s)._pbset), self._parent) - elif isinstance(s, list) or isinstance(s, tuple) or isinstance(s, set): + elif isinstance(s, (list, tuple, set)): from sage.misc.misc_c import prod B = self.parent() n = B.ngens() @@ -5125,53 +5117,53 @@ class BooleanPolynomialIdeal(MPolynomialIdeal): EXAMPLES: - A Simple example:: + A simple example:: - sage: from sage.doctest.fixtures import reproducible_repr - sage: R. = BooleanPolynomialRing() - sage: I = ideal( [ x*y*z + x*z + y + 1, x+y+z+1 ] ) - sage: print(reproducible_repr(I.variety())) - [{x: 0, y: 1, z: 0}, {x: 1, y: 1, z: 1}] + sage: from sage.doctest.fixtures import reproducible_repr + sage: R. = BooleanPolynomialRing() + sage: I = ideal( [ x*y*z + x*z + y + 1, x+y+z+1 ] ) + sage: print(reproducible_repr(I.variety())) + [{x: 0, y: 1, z: 0}, {x: 1, y: 1, z: 1}] TESTS: - BooleanIdeal and regular (quotient) Ideal should coincide:: - - sage: R = BooleanPolynomialRing(6, ['x%d'%(i+1) for i in range(6)], order='lex') - sage: R.inject_variables() - Defining... - sage: polys = [ - ....: x1*x2 + x1*x4 + x1*x5 + x1*x6 + x1 + x2 + x3*x4 + x3*x5 + x3 + x4*x5 + x4*x6 + x4 + x5 + x6, - ....: x1*x2 + x1*x3 + x1*x4 + x1*x6 + x2*x3 + x2*x6 + x2 + x3*x4 + x5*x6, - ....: x1*x3 + x1*x4 + x1*x6 + x1 + x2*x5 + x2*x6 + x3*x4 + x3 + x4*x6 + x4 + x5*x6 + x5 + x6, - ....: x1*x2 + x1*x3 + x1*x4 + x1*x5 + x2 + x3*x5 + x3*x6 + x3 + x5 + x6, - ....: x1*x2 + x1*x4 + x1*x5 + x1*x6 + x2*x3 + x2*x4 + x2*x5 + x3*x5 + x5*x6 + x5 + x6, - ....: x1*x2 + x1*x6 + x2*x4 + x2*x5 + x2*x6 + x3*x6 + x4*x6 + x5*x6 + x5] - sage: I = R.ideal( polys ) - sage: print(reproducible_repr(I.variety())) - [{x1: 0, x2: 0, x3: 0, x4: 0, x5: 0, x6: 0}, {x1: 1, x2: 1, x3: 1, x4: 0, x5: 0, x6: 1}] - - sage: R = PolynomialRing(GF(2), 6, ['x%d'%(i+1) for i in range(6)], order='lex') - sage: I = R.ideal( polys ) - sage: v = (I + sage.rings.ideal.FieldIdeal(R)).variety() - sage: print(reproducible_repr(v)) - [{x1: 0, x2: 0, x3: 0, x4: 0, x5: 0, x6: 0}, {x1: 1, x2: 1, x3: 1, x4: 0, x5: 0, x6: 1}] + BooleanIdeal and regular (quotient) Ideal should coincide:: + sage: R = BooleanPolynomialRing(6, ['x%d'%(i+1) for i in range(6)], order='lex') + sage: R.inject_variables() + Defining... + sage: polys = [ + ....: x1*x2 + x1*x4 + x1*x5 + x1*x6 + x1 + x2 + x3*x4 + x3*x5 + x3 + x4*x5 + x4*x6 + x4 + x5 + x6, + ....: x1*x2 + x1*x3 + x1*x4 + x1*x6 + x2*x3 + x2*x6 + x2 + x3*x4 + x5*x6, + ....: x1*x3 + x1*x4 + x1*x6 + x1 + x2*x5 + x2*x6 + x3*x4 + x3 + x4*x6 + x4 + x5*x6 + x5 + x6, + ....: x1*x2 + x1*x3 + x1*x4 + x1*x5 + x2 + x3*x5 + x3*x6 + x3 + x5 + x6, + ....: x1*x2 + x1*x4 + x1*x5 + x1*x6 + x2*x3 + x2*x4 + x2*x5 + x3*x5 + x5*x6 + x5 + x6, + ....: x1*x2 + x1*x6 + x2*x4 + x2*x5 + x2*x6 + x3*x6 + x4*x6 + x5*x6 + x5] + sage: I = R.ideal( polys ) + sage: print(reproducible_repr(I.variety())) + [{x1: 0, x2: 0, x3: 0, x4: 0, x5: 0, x6: 0}, {x1: 1, x2: 1, x3: 1, x4: 0, x5: 0, x6: 1}] + + sage: R = PolynomialRing(GF(2), 6, ['x%d'%(i+1) for i in range(6)], order='lex') + sage: I = R.ideal( polys ) + sage: v = (I + sage.rings.ideal.FieldIdeal(R)).variety() + sage: print(reproducible_repr(v)) + [{x1: 0, x2: 0, x3: 0, x4: 0, x5: 0, x6: 0}, {x1: 1, x2: 1, x3: 1, x4: 0, x5: 0, x6: 1}] + + + Check that :trac:`13976` is fixed:: + + sage: R. = BooleanPolynomialRing() + sage: I = ideal( [ x*y*z + x*z + y + 1, x+y+z+1 ] ) + sage: sols = I.variety() + sage: sols[0][y] + 1 - Check that :trac:`13976` is fixed:: - - sage: R. = BooleanPolynomialRing() - sage: I = ideal( [ x*y*z + x*z + y + 1, x+y+z+1 ] ) - sage: sols = I.variety() - sage: sols[0][y] - 1 - - Make sure the result is a key converting dict, as discussed in - :trac:`9788` and consistent with - :meth:`sage.rings.polynomial.multi_polynomial_ideal.MPolynomialIdeal_singular_repr.variety`:: + Make sure the result is a key converting dict, as discussed in + :trac:`9788` and consistent with + :meth:`sage.rings.polynomial.multi_polynomial_ideal.MPolynomialIdeal_singular_repr.variety`:: - sage: sols[0]["y"] - 1 + sage: sols[0]["y"] + 1 """ from sage.misc.converting_dict import KeyConvertingDict @@ -6555,14 +6547,14 @@ cdef class FGLMStrategy: elif isinstance(from_ring.ring, BooleanPolynomialRing): _from_ring = from_ring.ring else: - raise TypeError("from_ring has wrong type %s"%(type(from_ring),)) + raise TypeError("from_ring has wrong type %s" % (type(from_ring),)) if isinstance(to_ring, BooleanPolynomialRing): _to_ring = to_ring elif isinstance(to_ring.ring, BooleanPolynomialRing): _to_ring = to_ring.ring else: - raise TypeError("to_ring has wrong type %s"%(type(to_ring),)) + raise TypeError("to_ring has wrong type %s" % (type(to_ring),)) cdef PBFGLMStrategy* strat = new PBFGLMStrategy(_from_ring._pbring, _to_ring._pbring, vec._vec) self._strat = unique_ptr[PBFGLMStrategy](strat) self._parent = to_ring @@ -7066,7 +7058,8 @@ cdef class GroebnerStrategy: cdef class BooleanMulAction(Action): cpdef _act_(self, g, x): """ - EXAMPLES: + EXAMPLES:: + sage: from brial import BooleanMonomialMonoid sage: P. = BooleanPolynomialRing(3) sage: M = BooleanMonomialMonoid(P) diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 4607545bb7f..e6cad378c6c 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -718,10 +718,15 @@ cdef class NCPolynomialRing_plural(Ring): sage: y*x -x*y """ - varstr = ", ".join([char_to_str(rRingVar(i, self._ring)) - for i in range(self.__ngens)]) + from sage.repl.rich_output.backend_base import BackendBase + from sage.repl.display.pretty_print import SagePrettyPrinter + varstr = ", ".join(char_to_str(rRingVar(i, self._ring)) + for i in range(self.__ngens)) + backend = BackendBase() + relations = backend._apply_pretty_printer(SagePrettyPrinter, + self.relations()) return (f"Noncommutative Multivariate Polynomial Ring in {varstr} " - f"over {self.base_ring()}, nc-relations: {self.relations()}") + f"over {self.base_ring()}, nc-relations: {relations}") def _ringlist(self): """ @@ -743,7 +748,8 @@ cdef class NCPolynomialRing_plural(Ring): ] """ cdef ring* _ring = self._ring - if(_ring != currRing): rChangeCurrRing(_ring) + if _ring != currRing: + rChangeCurrRing(_ring) from sage.libs.singular.function import singular_function ringlist = singular_function('ringlist') result = ringlist(self, ring=self) @@ -1836,7 +1842,7 @@ cdef class NCPolynomial_plural(RingElement): Defining x, z, y sage: f = - 1*x^2*y - 25/27 * y^3 - z^2 sage: latex(f) # indirect doctest - - x^{2} y - z^{2} - \frac{25}{27} y^{3} + -x^{2} y - z^{2} - \frac{25}{27} y^{3} """ cdef ring *_ring = (self._parent)._ring gens = self.parent().latex_variable_names() diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index a711e94cb80..ae42664a03e 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -92,9 +92,10 @@ from sage.rings.real_double import is_RealDoubleField, RDF from sage.rings.complex_double import is_ComplexDoubleField, CDF from sage.rings.real_mpfi import is_RealIntervalField +from sage.structure.coerce cimport coercion_model from sage.structure.element import coerce_binop from sage.structure.element cimport (parent, have_same_parent, - Element, RingElement, coercion_model) + Element, RingElement) from sage.rings.rational_field import QQ, is_RationalField from sage.rings.integer_ring import ZZ, is_IntegerRing @@ -1369,21 +1370,29 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: f.inverse_of_unit() Traceback (most recent call last): ... - ValueError: self is not a unit + ArithmeticError: x - 90283 is not a unit in Univariate Polynomial Ring in x over Rational Field sage: f = R(-90283); g = f.inverse_of_unit(); g -1/90283 sage: parent(g) Univariate Polynomial Ring in x over Rational Field + + TESTS:: + + sage: Integers(1)['x'](0).inverse_of_unit() + 0 """ d = self.degree() if d > 0: if not self.is_unit(): - raise ValueError("self is not a unit") + raise ArithmeticError(f"{self} is not a unit in {self.parent()}") else: raise NotImplementedError("polynomial inversion over non-integral domains not implemented") elif d == -1: - return self._parent(~self._parent._base.zero()) - return self._parent(~self.get_unsafe(0)) + cst = self._parent._base.zero() + else: + cst = self.get_unsafe(0) + inv = cst.inverse_of_unit() + return self._parent([inv]) def inverse_mod(a, m): """ @@ -4363,8 +4372,7 @@ cdef class Polynomial(CommutativeAlgebraElement): sage: G.prod() == g True """ - pols = G[0] - exps = G[1] + pols, exps = G R = self._parent F = [(R(f), int(e)) for f, e in zip(pols, exps)] @@ -6087,7 +6095,7 @@ cdef class Polynomial(CommutativeAlgebraElement): For internal use only. - EXAMPLES: + EXAMPLES:: sage: R. = PolynomialRing(ZZ) sage: (2*a^2 + a)._pari_with_name() @@ -10904,7 +10912,8 @@ cdef class Polynomial_generic_dense(Polynomial): OUTPUT: element of base ring - EXAMPLES: + EXAMPLES:: + sage: R. = QQ[] sage: S. = R[] sage: f = x*t + x + t @@ -11045,6 +11054,14 @@ cdef class Polynomial_generic_dense(Polynomial): sage: q,r = h.quo_rem(f) sage: h == q*f + r and r.degree() < f.degree() True + + :trac:`26907`:: + + sage: P. = ZZ[] + sage: R. = P[] + sage: a = 3*y + 1 + sage: a//a + 1 """ if other.is_zero(): raise ZeroDivisionError("division by zero polynomial") @@ -11495,7 +11512,7 @@ cdef class PolynomialBaseringInjection(Morphism): By :trac:`9944`, there are now only very few exceptions:: sage: PolynomialRing(QQ,names=[]).coerce_map_from(QQ) - Generic morphism: + Call morphism: From: Rational Field To: Multivariate Polynomial Ring in no variables over Rational Field """ diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index c94b7fc8d33..c1de1b91d4c 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -283,7 +283,7 @@ def _richcmp_(self, other, op): Compare this element with something else, where equality testing coerces the object on the right, if possible (and necessary). - EXAMPLES: + EXAMPLES:: sage: R. = PolynomialRing(QQ) sage: S. = R.quotient(x^3-2) diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index d13cb8d04e7..347f3f69d5f 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -26,7 +26,8 @@ from __future__ import absolute_import from cysignals.memory cimport check_allocarray, check_reallocarray, sig_free from cysignals.signals cimport sig_on, sig_off -from cpython cimport PyInt_AS_LONG, PyFloat_AS_DOUBLE +from cpython.int cimport PyInt_AS_LONG +from cpython.float cimport PyFloat_AS_DOUBLE from sage.structure.parent cimport Parent from .polynomial_element cimport Polynomial, _dict_to_list diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index c8f300a0478..71afb398b5c 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -175,7 +175,6 @@ from sage.rings.polynomial.polynomial_singular_interface import PolynomialRing_singular_repr from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular - _CommutativeRings = categories.commutative_rings.CommutativeRings() from . import cyclotomic @@ -263,7 +262,24 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ Check that category for zero ring:: sage: PolynomialRing(Zmod(1), 'x').category() - Category of finite rings + Category of finite commutative algebras over + (finite commutative rings and subquotients of monoids and + quotients of semigroups and finite enumerated sets) + + Check `is_finite` inherited from category (:trac:`24432`):: + + sage: Zmod(1)['x'].is_finite() + True + + sage: GF(7)['x'].is_finite() + False + + sage: Zmod(1)['x']['y'].is_finite() + True + + sage: GF(7)['x']['y'].is_finite() + False + """ # We trust that, if category is given, it is useful and does not need to be joined # with the default category @@ -1189,27 +1205,6 @@ def parameter(self): """ return self.gen() - def is_finite(self): - """ - Return False since polynomial rings are not finite (unless the base - ring is 0.) - - EXAMPLES:: - - sage: R = Integers(1)['x'] - sage: R.is_finite() - True - sage: R = GF(7)['x'] - sage: R.is_finite() - False - sage: R['x']['y'].is_finite() - False - """ - R = self.base_ring() - if R.is_finite() and R.order() == 1: - return True - return False - @cached_method def is_exact(self): return self.base_ring().is_exact() @@ -1636,7 +1631,7 @@ def __init__(self, base_ring, name=None, sparse=False, element_class=None, categ # We trust that, if a category is given, that it is useful. if category is None: if base_ring.is_zero(): - category = categories.rings.Rings().Finite() + category = categories.algebras.Algebras(base_ring.category()).Commutative().Finite() else: category = polynomial_default_category(base_ring.category(), 1) PolynomialRing_general.__init__(self, base_ring, name=name, diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index 3929be1755e..378d4125128 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -16,7 +16,7 @@ Polynomial Template for C/C++ Library Interfaces from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.structure.element cimport ModuleElement, Element, RingElement -from sage.structure.element import coerce_binop, bin_op +from sage.structure.element import coerce_binop from sage.structure.richcmp cimport rich_to_bool from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.integer cimport Integer diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pyx b/src/sage/rings/polynomial/skew_polynomial_element.pyx index 6f22c02c8f5..0f75b12901b 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_element.pyx @@ -2251,7 +2251,7 @@ cdef class SkewPolynomial_generic_dense(SkewPolynomial): Return the generic dense skew polynomial corresponding to the current parameters provided ``self``. - EXAMPLES: + EXAMPLES:: sage: R. = QQ[] sage: sigma = R.hom([t+1]) diff --git a/src/sage/rings/polynomial/skew_polynomial_ring.py b/src/sage/rings/polynomial/skew_polynomial_ring.py index 9dfeb17182b..9aa25f80da0 100644 --- a/src/sage/rings/polynomial/skew_polynomial_ring.py +++ b/src/sage/rings/polynomial/skew_polynomial_ring.py @@ -105,7 +105,7 @@ def _minimal_vanishing_polynomial(R, eval_pts): The minimal vanishing polynomial. - EXAMPLES: + EXAMPLES:: sage: from sage.rings.polynomial.skew_polynomial_ring import _minimal_vanishing_polynomial sage: k. = GF(5^3) @@ -738,7 +738,7 @@ def is_sparse(self): Since sparse skew polynomials are not yet implemented, this function always returns ``False``. - EXAMPLES: + EXAMPLES:: sage: R. = RR[] sage: sigma = R.hom([t+1]) diff --git a/src/sage/rings/polynomial/term_order.py b/src/sage/rings/polynomial/term_order.py index 76bc777865a..0e4925b2d8d 100644 --- a/src/sage/rings/polynomial/term_order.py +++ b/src/sage/rings/polynomial/term_order.py @@ -1777,7 +1777,7 @@ def __eq__(self, other): sage: T1 = TermOrder('lex',2)+TermOrder('lex',3) sage: T2 = TermOrder('lex',3)+TermOrder('lex',2) sage: T1 == T2 - True + False :: @@ -1785,6 +1785,20 @@ def __eq__(self, other): sage: T2 = TermOrder('lex',2)+TermOrder('neglex',3) sage: T1 == T2 True + + TESTS:: + + We assert that comparisons take into account the block size of + orderings (cf. :trac:`24981`):: + + sage: R = PolynomialRing(QQ, 6, 'x', order="lex(1),degrevlex(5)") + sage: S = R.change_ring(order="lex(2),degrevlex(4)") + sage: R == S + False + sage: S.term_order() == R.term_order() + False + sage: S.term_order() == TermOrder('lex', 2) + TermOrder('degrevlex', 4) + True """ if not isinstance(other, TermOrder): try: @@ -1792,8 +1806,10 @@ def __eq__(self, other): except Exception: return False - return (self._name == other._name # note that length is not considered. + return (self._name == other._name and self._blocks == other._blocks + and (not self.is_block_order() + or all(len(t1) == len(t2) for (t1, t2) in zip(self._blocks, other._blocks))) and self._weights == other._weights and self._matrix == other._matrix) @@ -1806,7 +1822,7 @@ def __ne__(self, other): sage: T1 = TermOrder('lex',2)+TermOrder('lex',3) sage: T2 = TermOrder('lex',3)+TermOrder('lex',2) sage: T1 != T2 - False + True """ return not self == other diff --git a/src/sage/rings/power_series_pari.pyx b/src/sage/rings/power_series_pari.pyx index e37e0a37186..2e03adea2d4 100644 --- a/src/sage/rings/power_series_pari.pyx +++ b/src/sage/rings/power_series_pari.pyx @@ -678,7 +678,8 @@ cdef class PowerSeries_pari(PowerSeries): g = g.truncate() if typ(g.g) == t_POL and varn(g.g) == vn: # t_POL has 2 codewords. Use new_ref instead of g[i] for speed. - return [R(g.new_ref(gel(g.g, i))) for i in range(2, lg(g.g))] + G = g.fixGEN() + return [R(g.new_ref(gel(G, i))) for i in range(2, lg(G))] else: return [R(g)] @@ -729,6 +730,7 @@ cdef class PowerSeries_pari(PowerSeries): return [] cdef pari_gen g = self.g + g.fixGEN() cdef long l, m R = self.base_ring() diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 21783111474..b2af6bf132d 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -79,7 +79,7 @@ With power series the behavior is the same. x """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # 2017 Vincent Delecroix <20100.delecroix@gmail.com> # @@ -92,8 +92,8 @@ With power series the behavior is the same. # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import import operator @@ -111,7 +111,6 @@ from . import rational_field from . import integer_ring from .integer import Integer from sage.rings.finite_rings.integer_mod_ring import IntegerModRing -from sage.misc.superseded import deprecated_function_alias, deprecation from warnings import warn from sage.categories.fields import Fields @@ -2188,9 +2187,6 @@ cdef class PowerSeries(AlgebraElement): """ return self.parent()([self[i] / arith.factorial(i) for i in range(self.degree()+1)]) - ogf = deprecated_function_alias(15705, egf_to_ogf) - egf = deprecated_function_alias(15705, ogf_to_egf) - def __pari__(self): """ Return a PARI representation of this series. @@ -2227,28 +2223,28 @@ cdef class PowerSeries(AlgebraElement): s = s.Ser(v, n - s.valuation(v) if s else n) return s + def _solve_linear_de(R, N, L, a, b, f0): r""" Internal function used by PowerSeries.solve_linear_de(). INPUT: + - ``R`` -- a PolynomialRing - - ``R`` - a PolynomialRing - - - ``N`` - integer = 0 + - ``N`` -- integer >= 0 - - ``L`` - integer = 1 + - ``L`` -- integer >= 1 - - ``a`` - list of coefficients of `a`, any - length, all coefficients should belong to base ring of R. + - ``a`` -- list of coefficients of `a`, any + length, all coefficients should belong to base ring of R. - - ``b`` - list of coefficients of `b`, length - at least `L` (only first `L` coefficients are - used), all coefficients should belong to base ring of R. + - ``b`` -- list of coefficients of `b`, length + at least `L` (only first `L` coefficients are + used), all coefficients should belong to base ring of R. - - ``f0`` - constant term of `f` (only used if - `N == 0`), should belong to base ring of R. + - ``f0`` -- constant term of `f` (only used if + `N == 0`), should belong to base ring of R. OUTPUT: List of coefficients of `f` (length exactly diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 26509b1ee9d..5e7fcdf3187 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -151,7 +151,7 @@ 0.500000000000000? + 0.866025403784439?*I We can explicitly coerce from `\QQ[I]`. (Technically, this is not quite -kosher, since `\QQ[I]` doesn't come with an embedding; we do not know +kosher, since `\QQ[I]` does not come with an embedding; we do not know whether the field generator is supposed to map to `+I` or `-I`. We assume that for any quadratic field with polynomial `x^2+1`, the generator maps to `+I`.):: @@ -549,6 +549,13 @@ class AlgebraicField_common(sage.rings.ring.Field): r""" Common base class for the classes :class:`~AlgebraicRealField` and :class:`~AlgebraicField`. + + TESTS:: + + sage: AA.is_finite() + False + sage: QQbar.is_finite() + False """ class options(GlobalOptions): @@ -569,18 +576,6 @@ def default_interval_prec(self): return 64 - def is_finite(self): - r""" - Check whether this field is finite. Since this class is only used for - fields of characteristic 0, always returns False. - - EXAMPLES:: - - sage: QQbar.is_finite() - False - """ - return False - def characteristic(self): r""" Return the characteristic of this field. Since this class is only used @@ -702,10 +697,11 @@ def __new__(cls): ....: b'\xb1.~\x000\xc2\xe0\xa1') sage: s is AA True - """ - try: return AA - except BaseException: return AlgebraicField_common.__new__(cls) + try: + return AA + except BaseException: + return AlgebraicField_common.__new__(cls) def __init__(self): r""" @@ -716,9 +712,10 @@ def __init__(self): This function calls functions in superclasses which set the category, so we check that. sage: QQbar.category() # indirect doctest - Category of fields + Category of infinite fields """ - AlgebraicField_common.__init__(self, self, ('x',), normalize=False) + from sage.categories.fields import Fields + AlgebraicField_common.__init__(self, self, ('x',), normalize=False, category=Fields().Infinite()) def _element_constructor_(self, x): r""" @@ -824,7 +821,7 @@ def _coerce_map_from_(self, from_par): return (from_par is ZZ or from_par is QQ or from_par is AA) - def completion(self, p, prec, extras = {}): + def completion(self, p, prec, extras={}): r""" Return the completion of self at the place `p`. Only implemented for `p = \infty` at present. @@ -833,8 +830,8 @@ def completion(self, p, prec, extras = {}): - ``p`` -- either a prime (not implemented at present) or Infinity - ``prec`` -- precision of approximate field to return - - ``extras`` -- a dict of extra keyword arguments for the ``RealField`` - constructor + - ``extras`` -- (optional) a dict of extra keyword arguments + for the ``RealField`` constructor EXAMPLES:: @@ -1060,14 +1057,15 @@ def _factor_univariate_polynomial(self, f): """ rr = f.roots() - cr = [(r,e) for r,e in f.roots(QQbar) if r.imag()>0] + cr = [(r, e) for r, e in f.roots(QQbar) if r.imag() > 0] from sage.structure.factorization import Factorization return Factorization( - [(f.parent()([-r,1]),e) for r,e in rr] + - [(f.parent()([r.norm(),-2*r.real(),1]),e) for r,e in cr], + [(f.parent()([-r, 1]), e) for r, e in rr] + + [(f.parent()([r.norm(), -2 * r.real(), 1]), e) for r, e in cr], unit=f.leading_coefficient()) + def is_AlgebraicRealField(F): r""" Check whether ``F`` is an :class:`~AlgebraicRealField` instance. For internal use. @@ -1080,9 +1078,11 @@ def is_AlgebraicRealField(F): """ return isinstance(F, AlgebraicRealField) + # Create the globally unique AlgebraicRealField object. AA = AlgebraicRealField() + class AlgebraicField(Singleton, AlgebraicField_common): """ The field of all algebraic complex numbers. @@ -1122,8 +1122,10 @@ def __new__(cls): sage: s is QQbar True """ - try: return QQbar - except BaseException: return AlgebraicField_common.__new__(cls) + try: + return QQbar + except BaseException: + return AlgebraicField_common.__new__(cls) def __init__(self): r""" @@ -1132,7 +1134,7 @@ def __init__(self): We test by setting the category:: sage: QQbar.category() # indirect doctest - Category of fields + Category of infinite fields sage: QQbar.base_ring() Algebraic Real Field @@ -1141,7 +1143,8 @@ def __init__(self): sage: QQbar._repr_option('element_is_atomic') False """ - AlgebraicField_common.__init__(self, AA, ('I',), normalize=False) + from sage.categories.fields import Fields + AlgebraicField_common.__init__(self, AA, ('I',), normalize=False, category=Fields().Infinite()) def _element_constructor_(self, x): """ @@ -1219,7 +1222,7 @@ def _coerce_map_from_(self, from_par): return (from_par is ZZ or from_par is QQ or from_par is AA or from_par is QQbar) - def completion(self, p, prec, extras = {}): + def completion(self, p, prec, extras={}): r""" Return the completion of self at the place `p`. Only implemented for `p = \infty` at present. @@ -1228,8 +1231,8 @@ def completion(self, p, prec, extras = {}): - ``p`` -- either a prime (not implemented at present) or Infinity - ``prec`` -- precision of approximate field to return - - ``extras`` -- a dict of extra keyword arguments for the ``RealField`` - constructor + - ``extras`` -- (optional) a dict of extra keyword arguments + for the ``RealField`` constructor EXAMPLES:: @@ -1319,7 +1322,7 @@ def ngens(self): @cached_method def zeta(self, n=4): r""" - Returns a primitive `n`'th root of unity, specifically `\exp(2*\pi*i/n)`. + Return a primitive `n`'th root of unity, specifically `\exp(2*\pi*i/n)`. INPUT: @@ -1398,7 +1401,7 @@ def polynomial_root(self, poly, interval, multiplicity=1): def random_element(self, poly_degree=2, *args, **kwds): r""" - Returns a random algebraic number. + Return a random algebraic number. INPUT: @@ -1506,7 +1509,7 @@ def random_element(self, poly_degree=2, *args, **kwds): # p will have at least one root; pick one at random # could we instead just compute one root "randomly"? - m = sage.misc.prandom.randint(0, len(roots)-1) + m = sage.misc.prandom.randint(0, len(roots) - 1) return roots[m] def _is_irreducible_univariate_polynomial(self, f): @@ -1583,7 +1586,9 @@ def _factor_univariate_polynomial(self, f): """ from sage.structure.factorization import Factorization - return Factorization([(f.parent()([-r,1]),e) for r,e in f.roots()], unit=f.leading_coefficient()) + return Factorization([(f.parent()([-r, 1]), e) for r, e in f.roots()], + unit=f.leading_coefficient()) + def is_AlgebraicField(F): r""" @@ -1597,9 +1602,11 @@ def is_AlgebraicField(F): """ return isinstance(F, AlgebraicField) + # Create the globally unique AlgebraicField object. QQbar = AlgebraicField() + def is_AlgebraicField_common(F): r""" Check whether ``F`` is an :class:`~AlgebraicField_common` instance. @@ -1612,6 +1619,7 @@ def is_AlgebraicField_common(F): """ return isinstance(F, AlgebraicField_common) + def prec_seq(): r""" Return a generator object which iterates over an infinite increasing @@ -1633,7 +1641,10 @@ def prec_seq(): yield bits bits = bits * 2 + _short_prec_seq = (64, 128, None) + + def short_prec_seq(): r""" Return a sequence of precisions to try in cases when an infinite-precision @@ -1648,6 +1659,7 @@ def short_prec_seq(): """ return _short_prec_seq + def tail_prec_seq(): r""" A generator over precisions larger than those in :func:`~short_prec_seq`. @@ -1664,6 +1676,7 @@ def tail_prec_seq(): yield bits bits = bits * 2 + def rational_exact_root(r, d): r""" Checks whether the rational `r` is an exact `d`'th power. If so, returns @@ -1681,23 +1694,27 @@ def rational_exact_root(r, d): den = r.denominator() (num_rt, num_exact) = num.nth_root(d, truncate_mode=1) - if not num_exact: return None + if not num_exact: + return None (den_rt, den_exact) = den.nth_root(d, truncate_mode=1) - if not den_exact: return None + if not den_exact: + return None return (num_rt / den_rt) def clear_denominators(poly): r""" - Takes a monic polynomial and rescales the variable to get a monic - polynomial with "integral" coefficients. Works on any univariate + Take a monic polynomial and rescale the variable to get a monic + polynomial with "integral" coefficients. + + This works on any univariate polynomial whose base ring has a ``denominator()`` method that returns integers; for example, the base ring might be `\QQ` or a number field. Returns the scale factor and the new polynomial. - (Inspired by Pari's ``primitive_pol_to_monic()``.) + (Inspired by :pari:`primitive_pol_to_monic` .) We assume that coefficient denominators are "small"; the algorithm factors the denominators, to give the smallest possible scale factor. @@ -1717,7 +1734,7 @@ def clear_denominators(poly): # We should check the size of the denominators and switch to # an alternate, less precise algorithm if we decide factoring # would be too slow. - + d = poly.denominator() if d == 1: return d, poly @@ -1730,15 +1747,16 @@ def clear_denominators(poly): oe = 0 if f in factors: oe = factors[f] - min_e = (e + (deg-i) - 1) // (deg-i) + min_e = (e + (deg - i) - 1) // (deg - i) factors[f] = max(oe, min_e) change = 1 for f, e in iteritems(factors): change = change * f**e - poly = poly * (change ** deg) + poly = poly * (change**deg) poly = poly(poly.parent().gen() / change) return change, poly + def do_polred(poly, threshold=32): r""" Find a polynomial of reasonably small discriminant that generates @@ -1787,13 +1805,14 @@ def do_polred(poly, threshold=32): parent = poly.parent() bitsize = ZZ(poly[0].numerator().nbits() + poly[0].denominator().nbits()) # time(polredbest) ≈ b²d⁵ - cost = 2*bitsize.nbits() + 5*poly.degree().nbits() + cost = 2 * bitsize.nbits() + 5 * poly.degree().nbits() if cost > threshold: return parent.gen(), parent.gen(), poly new_poly, elt_back = poly.__pari__().polredbest(flag=1) elt_fwd = elt_back.modreverse() return parent(elt_fwd.lift()), parent(elt_back.lift()), parent(new_poly) + def isolating_interval(intv_fn, pol): """ ``intv_fn`` is a function that takes a precision and returns an @@ -1877,6 +1896,7 @@ def find_zero_result(fn, l): raise ValueError('find_zero_result could not find any zeroes') return result + def conjugate_expand(v): r""" If the interval ``v`` (which may be real or complex) includes some @@ -1891,11 +1911,11 @@ def conjugate_expand(v): sage: from sage.rings.qqbar import conjugate_expand sage: conjugate_expand(CIF(RIF(0, 1), RIF(1, 2))).str(style='brackets') - '[0.00000000000000000 .. 1.0000000000000000] + [1.0000000000000000 .. 2.0000000000000000]*I' + '[0.0000000000000000 .. 1.0000000000000000] + [1.0000000000000000 .. 2.0000000000000000]*I' sage: conjugate_expand(CIF(RIF(0, 1), RIF(0, 1))).str(style='brackets') - '[0.00000000000000000 .. 1.0000000000000000] + [-1.0000000000000000 .. 1.0000000000000000]*I' + '[0.0000000000000000 .. 1.0000000000000000] + [-1.0000000000000000 .. 1.0000000000000000]*I' sage: conjugate_expand(CIF(RIF(0, 1), RIF(-2, 1))).str(style='brackets') - '[0.00000000000000000 .. 1.0000000000000000] + [-2.0000000000000000 .. 2.0000000000000000]*I' + '[0.0000000000000000 .. 1.0000000000000000] + [-2.0000000000000000 .. 2.0000000000000000]*I' sage: conjugate_expand(RIF(1, 2)).str(style='brackets') '[1.0000000000000000 .. 2.0000000000000000]' """ @@ -1908,6 +1928,7 @@ def conjugate_expand(v): fld = ComplexIntervalField(v.prec()) return fld(re, im.union(-im)) + def conjugate_shrink(v): r""" If the interval ``v`` includes some purely real numbers, return @@ -1938,6 +1959,7 @@ def conjugate_shrink(v): return v.real() return v + def number_field_elements_from_algebraics(numbers, minimal=False, same_field=False): r""" Given a sequence of elements of either ``AA`` or ``QQbar`` @@ -2020,7 +2042,7 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal To: Algebraic Field Defn: a |--> 1.732050807568878?) - We've created ``rt2b`` in such a way that \sage doesn't initially know + We've created ``rt2b`` in such a way that \sage does not initially know that it's in a degree-2 extension of `\QQ`:: sage: number_field_elements_from_algebraics(rt2b) @@ -2096,7 +2118,7 @@ def number_field_elements_from_algebraics(numbers, minimal=False, same_field=Fal To: Algebraic Field Defn: a |--> 0.7071067811865475? + 0.7071067811865475?*I) - Note that for the first example, where \sage doesn't realize that + Note that for the first example, where \sage does not realize that the number is real, we get a homomorphism to ``QQbar``; but with ``minimal=True``, we get a homomorphism to ``AA``. If we specify both ``minimal=True`` and ``same_field=True``, we get a second @@ -2163,6 +2185,7 @@ def mk_algebraic(x): return (fld, nums, hom) + # Cache some commonly-used polynomial rings QQx = QQ['x'] QQx_x = QQx.gen() @@ -2224,7 +2247,7 @@ def cmp_elements_with_same_minpoly(a, b, p): imag = ai.union(bi) oroots = [r for r in roots if r._value.real().overlaps(real) and r._value.imag().overlaps(imag)] - if len(oroots) == 0: + if not oroots: raise RuntimeError('a = {}\nb = {}\np = {}'.format(a, b, p)) if len(oroots) == 1: # There is a single root matching both descriptors @@ -2237,7 +2260,7 @@ def cmp_elements_with_same_minpoly(a, b, p): oroots = [r for r in roots if r._value.real().overlaps(real) and r._value.imag().abs().overlaps(imag)] if (len(oroots) == 2 and - not oroots[0]._value.imag().contains_zero()): + not oroots[0]._value.imag().contains_zero()): # There is a complex conjugate pair of roots matching both # descriptors, so compare by imaginary value. while ai.contains_zero(): @@ -2273,6 +2296,7 @@ def __init__(self, child1, child1_poly, child2, child2_poly, parent): self.child2_poly = child2_poly self.parent = parent + algebraic_generator_counter = 0 @@ -2344,7 +2368,7 @@ def __hash__(self): r""" Return a hash value for self. This will depend on the order that commands get executed at load time, so we do not test the value that is - returned, just that it doesn't raise an error. + returned, just that it does not raise an error. EXAMPLES:: @@ -2419,7 +2443,8 @@ def _repr_(self): if self._trivial: return 'Trivial generator' else: - return '%s with a in %s'%(self._field, self._root._interval_fast(53)) + return '%s with a in %s' % (self._field, + self._root._interval_fast(53)) def root_as_algebraic(self): r""" @@ -2436,7 +2461,7 @@ def root_as_algebraic(self): def is_trivial(self): """ - Returns true iff this is the trivial generator (alpha == 1), which + Return true iff this is the trivial generator (alpha == 1), which does not actually extend the rationals. EXAMPLES:: @@ -2481,7 +2506,8 @@ def pari_field(self): sage: gen.pari_field() [y^2 - y - 1, [2, 0], ...] """ - if self.is_trivial(): raise ValueError("No PARI field attached to trivial generator") + if self.is_trivial(): + raise ValueError("No PARI field attached to trivial generator") if self._pari_field is None: pari_pol = self._field.pari_polynomial("y") self._pari_field = pari_pol.nfinit(1) @@ -2521,7 +2547,7 @@ def conjugate(self): def _interval_fast(self, prec): """ - Returns an interval containing this generator, to the specified + Return an interval containing this generator, to the specified precision. EXAMPLES:: @@ -2622,7 +2648,8 @@ def intv_fn(prec): new_gen = AlgebraicGenerator(new_nf, ANRoot(QQx(red_pol), new_intv)) rel = AlgebraicGeneratorRelation(self, self_pol_sage(red_back_x), - other, (QQx_x - k*self_pol_sage)(red_back_x), + other, + (QQx_x - k * self_pol_sage)(red_back_x), new_gen) self._unions[other] = rel other._unions[self] = rel @@ -2731,6 +2758,7 @@ def __call__(self, elt): # dictionary for multimethod dispatch _binop_algo = {} + class ANDescr(SageObject): r""" An ``AlgebraicNumber`` or ``AlgebraicReal`` is a wrapper around an @@ -2742,10 +2770,10 @@ class ANDescr(SageObject): """ def is_simple(self): r""" - Checks whether this descriptor represents a value with the same + Check whether this descriptor represents a value with the same algebraic degree as the number field associated with the descriptor. - Returns ``True`` if self is an ``ANRational``, or a minimal + This returns ``True`` if self is an ``ANRational``, or a minimal ``ANExtensionElement``. EXAMPLES:: @@ -2873,7 +2901,7 @@ def norm(self, n): if self.is_complex(): return ANUnaryExpr(n, 'norm') else: - return (n*n)._descr + return (n * n)._descr class AlgebraicNumber_base(sage.structure.element.FieldElement): @@ -2963,7 +2991,7 @@ def __init__(self, parent, x): def _repr_(self): """ - Returns the print representation of this number. + Return the print representation of this number. :class:`AlgebraicField_common`'s option display_format controls whether irrational numbers will always be printed using a decimal @@ -3010,7 +3038,7 @@ def _repr_(self): def _latex_(self): r""" - Returns the latex representation of this number. + Return the latex representation of this number. EXAMPLES:: @@ -3111,7 +3139,7 @@ def _mul_(self, other): """ sk = type(self._descr) ok = type(other._descr) - return type(self)(_binop_algo[sk,ok](self, other, operator.mul)) + return type(self)(_binop_algo[sk, ok](self, other, operator.mul)) def _div_(self, other): """ @@ -3144,7 +3172,7 @@ def _add_(self, other): """ sk = type(self._descr) ok = type(other._descr) - return type(self)(_binop_algo[sk,ok](self, other, operator.add)) + return type(self)(_binop_algo[sk, ok](self, other, operator.add)) def _sub_(self, other): """ @@ -3155,7 +3183,7 @@ def _sub_(self, other): """ sk = type(self._descr) ok = type(other._descr) - return type(self)(_binop_algo[sk,ok](self, other, operator.sub)) + return type(self)(_binop_algo[sk, ok](self, other, operator.sub)) def _neg_(self): """ @@ -3467,7 +3495,7 @@ def sqrt(self, all=False, extend=True): sage: a.sqrt(all=True) [0] - This second example just shows that the program doesn't care where 0 + This second example just shows that the program does not care where 0 is defined, it gives the same answer regardless. After all, how many ways can you square-root zero? @@ -3496,9 +3524,9 @@ def sqrt(self, all=False, extend=True): # raise an error if appropriate: - if self.parent() is AA and self<0 and not extend: + if self.parent() is AA and self < 0 and not extend: if not all: - raise ValueError("%s is not a square in AA, being negative. Use extend = True for a square root in QQbar."%self) + raise ValueError("%s is not a square in AA, being negative. Use extend = True for a square root in QQbar." % self) else: return [] @@ -3507,7 +3535,7 @@ def sqrt(self, all=False, extend=True): if all: return [root, -root] else: - return root + return root def nth_root(self, n, all=False): r""" @@ -3570,7 +3598,7 @@ def nth_root(self, n, all=False): def as_number_field_element(self, minimal=False): r""" - Returns a number field containing this value, a representation of + Return a number field containing this value, a representation of this value as an element of that number field, and a homomorphism from the number field back to ``AA`` or ``QQbar``. @@ -3634,7 +3662,8 @@ def exactify(self): 2 """ od = self._descr - if isinstance(od, (ANRational, ANExtensionElement)): return + if isinstance(od, (ANRational, ANExtensionElement)): + return self._set_descr(self._descr.exactify()) def _set_descr(self, new_descr): @@ -3679,12 +3708,13 @@ def simplify(self): """ self.exactify() od = self._descr - if od.is_simple(): return + if od.is_simple(): + return self._set_descr(od.simplify(self)) def _exact_field(self): """ - Returns a generator for a number field that includes this number + Return a generator for a number field that includes this number (not necessarily the smallest such number field). EXAMPLES:: @@ -3705,7 +3735,7 @@ def _exact_field(self): def _exact_value(self): r""" - Returns an ``ANRational`` or an ``ANExtensionElement`` representing this + Return an ``ANRational`` or an ``ANExtensionElement`` representing this value. EXAMPLES:: @@ -3741,7 +3771,7 @@ def _more_precision(self): 1.41421356237309504880168872420969807856967187537694807317667973799073247846211? """ prec = self._value.prec() - self._value = self._descr._interval_fast(prec*2) + self._value = self._descr._interval_fast(prec * 2) def minpoly(self): """ @@ -3957,7 +3987,7 @@ def radical_expression(self): sage: a.radical_expression() sqrt(2) + 10000000000000000000000000 """ - from sage.symbolic.ring import SR # Lazy to avoid cyclic dependency + from sage.symbolic.ring import SR # Lazy to avoid cyclic dependency # Adapted from NumberFieldElement._symbolic_() poly = self.minpoly() @@ -3976,7 +4006,7 @@ def radical_expression(self): if len(candidates) == 1: return candidates[0] roots = candidates - interval_field = interval_field.to_prec(interval_field.prec()*2) + interval_field = interval_field.to_prec(interval_field.prec() * 2) class AlgebraicNumber(AlgebraicNumber_base): @@ -4316,7 +4346,7 @@ def imag(self): def conjugate(self): """ - Returns the complex conjugate of self. + Return the complex conjugate of ``self``. EXAMPLES:: @@ -4331,8 +4361,10 @@ def conjugate(self): def norm(self): r""" - Returns ``self * self.conjugate()``. This is the algebraic - definition of norm, if we view ``QQbar`` as ``AA[I]``. + Return ``self * self.conjugate()``. + + This is the algebraic definition of norm, if we view ``QQbar`` + as ``AA[I]``. EXAMPLES:: @@ -4462,8 +4494,8 @@ def multiplicative_order(self): def rational_argument(self): r""" - Returns the argument of self, divided by `2\pi`, as long as this - result is rational. Otherwise returns None. Always triggers + Return the argument of ``self``, divided by `2\pi`, as long as this + result is rational. Otherwise returns ``None``. Always triggers exact computation. EXAMPLES:: @@ -4580,7 +4612,7 @@ def _more_precision(self): TESTS: We have to ensure after doing this that self._value is still - real which isn't the case without calling _ensure_real (see + real which is not the case without calling _ensure_real (see :trac:`11728`):: sage: P = AA['x'](1+x^4); a1,a2 = P.factor()[0][0],P.factor()[1][0]; a1*a2 @@ -4673,7 +4705,7 @@ def _richcmp_(self, other, op): if not self._value.overlaps(other._value): return richcmp(self._value, other._value, op) - return rich_to_bool(op, (self-other).sign()) + return rich_to_bool(op, (self - other).sign()) def _integer_(self, Z=None): """ @@ -4838,8 +4870,9 @@ def _rational_(self): def real(self): """ - Returns the real part of this algebraic real (so it always returns - self). + Return the real part of this algebraic real. + + It always returns ``self``. EXAMPLES:: @@ -4853,8 +4886,9 @@ def real(self): def imag(self): """ - Returns the imaginary part of this algebraic real (so it always - returns 0). + Return the imaginary part of this algebraic real. + + It always returns 0. EXAMPLES:: @@ -4868,7 +4902,7 @@ def imag(self): def conjugate(self): """ - Returns the complex conjugate of self, i.e. returns itself. + Return the complex conjugate of ``self``, i.e. returns itself. EXAMPLES:: @@ -4885,7 +4919,7 @@ def sign(self): Compute the sign of this algebraic number (return -1 if negative, 0 if zero, or 1 if positive). - Computes an interval enclosing this number using 128-bit interval + This computes an interval enclosing this number using 128-bit interval arithmetic; if this interval includes 0, then fall back to exact computation (which can be very slow). @@ -5014,7 +5048,7 @@ def interval_exact(self, field): TESTS:: Check that :trac:`26898` is fixed. This calculation triggers the 40 bits - of extra precision below, and the point isn't that the length of the list + of extra precision below, and the point is not that the length of the list is seven, but that the code runs in a reasonable time:: sage: R. = QQbar[] @@ -5039,7 +5073,7 @@ def interval_exact(self, field): prbot < pbot and ptop < prtop): return val - # Even 40 extra bits of precision aren't enough to prove that + # Even 40 extra bits of precision are not enough to prove that # self is not an exactly representable float. self.exactify() while True: @@ -5206,7 +5240,7 @@ def real_exact(self, field): if fbot == ftop: return ftop - # Even 40 extra bits of precision aren't enough to determine the + # Even 40 extra bits of precision are not enough to determine the # answer. rifp1 = RealIntervalField(field.prec() + 1) rifp2 = RealIntervalField(field.prec() + 2) @@ -5384,7 +5418,7 @@ def _act_(self, e, x): if S is AA: return AlgebraicReal(ANRational((-rt)**n)) else: - z = QQbar.zeta(2*d)._pow_int(n) + z = QQbar.zeta(2 * d)._pow_int(n) return z * AlgebraicNumber(ANRational(rt**n)) return S(ANRational(rt**n)) @@ -5551,7 +5585,7 @@ def _interval_fast(self, prec): def generator(self): r""" Return an :class:`AlgebraicGenerator` object associated to this - element. Returns the trivial generator, since self is rational. + element. Returns the trivial generator, since ``self`` is rational. EXAMPLES:: @@ -5664,9 +5698,9 @@ def rational_argument(self, n): True """ if self._value > 0: - return QQ(0) + return QQ.zero() if self._value < 0: - return QQ(1)/2 + return QQ((1, 2)) return None def angle(self): @@ -5698,6 +5732,7 @@ def scale(self): """ return self._value + def is_AlgebraicReal(x): r""" Test if ``x`` is an instance of :class:`~AlgebraicReal`. For internal use. @@ -5714,6 +5749,7 @@ def is_AlgebraicReal(x): """ return isinstance(x, AlgebraicReal) + def is_AlgebraicNumber(x): r""" Test if ``x`` is an instance of :class:`~AlgebraicNumber`. For internal use. @@ -5730,9 +5766,11 @@ def is_AlgebraicNumber(x): """ return isinstance(x, AlgebraicNumber) + QQbarPoly = PolynomialRing(QQbar, 'x') AAPoly = PolynomialRing(AA, 'x') + class AlgebraicPolynomialTracker(SageObject): r""" Keeps track of a polynomial used for algebraic numbers. @@ -5745,7 +5783,7 @@ class AlgebraicPolynomialTracker(SageObject): This class is private, and should only be constructed by ``AA.common_polynomial()`` or ``QQbar.common_polynomial()``, and should only be used as an argument to ``AA.polynomial_root()`` or - ``QQbar.polynomial_root()``. (It doesn't matter whether you create + ``QQbar.polynomial_root()``. (It does not matter whether you create the common polynomial with ``AA.common_polynomial()`` or ``QQbar.common_polynomial()``.) @@ -5825,7 +5863,7 @@ def _sage_input_(self, sib, coerce): """ # XXX It would be nicer to skip the "AA.common_polynomial()" # wrapper if the polynomial is not actually shared. But - # sage_input.py isn't quite that generic. + # sage_input.py is not quite that generic. v = sib.name('AA').common_polynomial(self._poly) sib.id_cache(self, v, 'cp') return v @@ -5974,6 +6012,7 @@ def generator(self): self.exactify() return self._gen + class ANRoot(ANDescr): """ The subclass of ``ANDescr`` that represents a particular @@ -6023,7 +6062,7 @@ def _repr_(self): sage: v._descr._repr_() 'Root 1.618033988749894849? of x^2 - x - 1' """ - return 'Root %s of %s'%(self._interval, self._poly) + return 'Root %s of %s' % (self._interval, self._poly) def handle_sage_input(self, sib, coerce, is_qqbar): r""" @@ -6172,7 +6211,7 @@ def _real_refine_interval(self, interval, prec): sage: rt2.refine_interval(RIF(0, 2), 75) # indirect doctest 1.4142135623730950488017? """ - # Don't throw away bits in the original interval; doing so might + # Do not throw away bits in the original interval; doing so might # invalidate it (include an extra root) field = RealIntervalField(max(prec, interval.prec())) @@ -6496,7 +6535,7 @@ def _complex_isolate_interval(self, interval, prec): if len(our_root) == 1: return our_root[0] - if len(our_root) == 0: + if not our_root: raise ValueError("Complex root interval does not include any roots") # We have more than one root that overlap the current interval. @@ -6511,7 +6550,7 @@ def _complex_isolate_interval(self, interval, prec): def exactify(self): """ - Returns either an ``ANRational`` or an + Return either an ``ANRational`` or an ``ANExtensionElement`` with the same value as this number. EXAMPLES:: @@ -6539,6 +6578,7 @@ def exactify(self): if gen.is_trivial(): qpf = self._poly.factors() + def find_fn(factor, prec): return factor(self._interval_fast(prec)) my_factor = find_zero_result(find_fn, qpf) @@ -6561,7 +6601,7 @@ def intv_fn(rif): root = ANRoot(QQx(red_pol), new_intv) new_gen = AlgebraicGenerator(field, root) - return ANExtensionElement(new_gen, red_back(field.gen())/den) + return ANExtensionElement(new_gen, red_back(field.gen()) / den) else: fpf = self._poly.factors() @@ -6597,7 +6637,6 @@ def find_fn(factor, prec): den, my_factor = clear_denominators(my_factor) - pari_nf = gen.pari_field() x, y = QQxy.gens() @@ -6625,7 +6664,7 @@ def intv_fn(prec): root = ANRoot(QQx(red_pol), new_intv) new_gen = AlgebraicGenerator(new_nf, root) red_back_a = red_back(new_nf.gen()) - new_poly = ((QQx_x - k * self_pol_sage)(red_back_a)/den) + new_poly = ((QQx_x - k * self_pol_sage)(red_back_a) / den) return ANExtensionElement(new_gen, new_poly) def _more_precision(self): @@ -6644,7 +6683,7 @@ def _more_precision(self): 128 """ prec = self._interval.prec() - self._interval = self.refine_interval(self._interval, prec*2) + self._interval = self.refine_interval(self._interval, prec * 2) def _interval_fast(self, prec): """ @@ -6671,6 +6710,7 @@ def _interval_fast(self, prec): self._more_precision() return self._interval_fast(prec) + class ANExtensionElement(ANDescr): r""" The subclass of ``ANDescr`` that represents a number field @@ -6709,10 +6749,10 @@ def __reduce__(self): def _repr_(self): fgen = self._generator._field.gen() sgen = str(fgen) - return '%s where %s = 0 and %s in %s'%(self._value, - self._generator.field().polynomial()._repr(name=sgen), - sgen, - self._generator._interval_fast(53)) + return '%s where %s = 0 and %s in %s' % (self._value, + self._generator.field().polynomial()._repr(name=sgen), + sgen, + self._generator._interval_fast(53)) def handle_sage_input(self, sib, coerce, is_qqbar): r""" @@ -6770,7 +6810,7 @@ def handle_sage_input(self, sib, coerce, is_qqbar): # The following is copied with slight mods from polynomial_element.pyx coeffs = [sib(c, True) for c in self._value.list()] terms = [] - for i in range(len(coeffs)-1, -1, -1): + for i in range(len(coeffs) - 1, -1, -1): if i > 0: if i > 1: rt_pow = rt**sib.int(i) @@ -6787,6 +6827,7 @@ def handle_sage_input(self, sib, coerce, is_qqbar): def is_complex(self): r""" Return True if the number field that defines this element is not real. + This does not imply that the element itself is definitely non-real, as in the example below. @@ -6808,7 +6849,7 @@ def is_complex(self): def is_simple(self): r""" - Checks whether this descriptor represents a value with the same + Check whether this descriptor represents a value with the same algebraic degree as the number field associated with the descriptor. For ``ANExtensionElement`` elements, we check this by @@ -6852,8 +6893,9 @@ def generator(self): def exactify(self): r""" - Return an exact representation of self. Since self is already exact, - just return self. + Return an exact representation of ``self``. + + Since ``self`` is already exact, just return ``self``. EXAMPLES:: @@ -7014,7 +7056,7 @@ def norm(self, n): """ if self._exactly_real: - return (n*n)._descr + return (n * n)._descr elif self._generator is QQbar_I_generator: return ANRational(self._value.norm()) else: @@ -7072,13 +7114,13 @@ def rational_argument(self, n): if n > 0: return QQ.zero() else: - return QQ((1,2)) + return QQ((1, 2)) gen_degree = self._generator._field.degree() if gen_degree <= 2: max_b = 6 else: - max_b = gen_degree*gen_degree + max_b = gen_degree * gen_degree rat_arg_fl = n._interval_fast(128).argument() / RealIntervalField(128).pi() / 2 rat_arg = rat_arg_fl.simplest_rational() if rat_arg.denominator() > max_b: @@ -7091,6 +7133,7 @@ def rational_argument(self, n): # For now, we just punt. raise NotImplementedError + class ANUnaryExpr(ANDescr): def __init__(self, arg, op): r""" @@ -7196,10 +7239,10 @@ def handle_sage_input(self, sib, coerce, is_qqbar): # The following version is not safe with respect to caching; # with the current sage_input.py, anything that gets entered # into the cache must be safe at all coercion levels. -# if is_qqbar and not coerce: -# v = sib.name('QQbar')(v) -# if not is_qqbar and coerce != 2: -# v = sib.name('AA')(v) + # if is_qqbar and not coerce: + # v = sib.name('QQbar')(v) + # if not is_qqbar and coerce != 2: + # v = sib.name('AA')(v) v = sib.name('QQbar' if is_qqbar else 'AA')(v) return (v, True) @@ -7345,6 +7388,7 @@ def exactify(self): arg.exactify() return arg._descr.conjugate(None) + class ANBinaryExpr(ANDescr): def __init__(self, left, right, op): r""" @@ -7475,10 +7519,10 @@ def handle_sage_input(self, sib, coerce, is_qqbar): # The following version is not safe with respect to caching; # with the current sage_input.py, anything that gets entered # into the cache must be safe at all coercion levels. -# if is_qqbar and not coerce: -# v = sib.name('QQbar')(v) -# if not is_qqbar and coerce != 2: -# v = sib.name('AA')(v) + # if is_qqbar and not coerce: + # v = sib.name('QQbar')(v) + # if not is_qqbar and coerce != 2: + # v = sib.name('AA')(v) v = sib.name('QQbar' if is_qqbar else 'AA')(v) return (v, True) @@ -7566,6 +7610,7 @@ def exactify(self): # we fall back to floating-point computation to be backed up by exact # symbolic computation only as required. + def an_binop_rational(a, b, op): r""" Used to add, subtract, multiply or divide algebraic numbers. @@ -7589,6 +7634,7 @@ def an_binop_rational(a, b, op): """ return ANRational(op(a._descr._value, b._descr._value)) + def an_binop_expr(a, b, op): r""" Add, subtract, multiply or divide algebraic numbers represented as @@ -7624,6 +7670,7 @@ def an_binop_expr(a, b, op): """ return ANBinaryExpr(a, b, op) + def an_binop_element(a, b, op): r""" Add, subtract, multiply or divide two elements represented as elements of @@ -7693,11 +7740,12 @@ def an_binop_element(a, b, op): return ANBinaryExpr(a, b, op) + # instanciation of the multimethod dispatch _binop_algo[ANRational, ANRational] = an_binop_rational _binop_algo[ANRational, ANExtensionElement] = \ _binop_algo[ANExtensionElement, ANRational] = \ -_binop_algo[ANExtensionElement, ANExtensionElement ] = an_binop_element +_binop_algo[ANExtensionElement, ANExtensionElement] = an_binop_element for t1 in (ANRational, ANRoot, ANExtensionElement, ANUnaryExpr, ANBinaryExpr): for t2 in (ANUnaryExpr, ANBinaryExpr, ANRoot): _binop_algo[t1, t2] = _binop_algo[t2, t1] = an_binop_expr @@ -7719,11 +7767,11 @@ def _init_qqbar(): global ZZX_x, AA_0, QQbar_I, AA_hash_offset, QQbar_hash_offset, QQbar_I_generator, QQbar_I_nf global QQ_0, QQ_1, QQ_1_2, QQ_1_4, RR_1_10 - RR_1_10 = RR(1)/10 + RR_1_10 = RR(1) / 10 QQ_0 = QQ.zero() QQ_1 = QQ.one() - QQ_1_2 = QQ((1,2)) - QQ_1_4 = QQ((1,4)) + QQ_1_2 = QQ((1, 2)) + QQ_1_4 = QQ((1, 4)) AA_0 = AA.zero() @@ -7733,14 +7781,16 @@ def _init_qqbar(): AA_hash_offset = AA(~ZZ(123456789)) - QQbar_hash_offset = AlgebraicNumber(ANExtensionElement(QQbar_I_generator, ~ZZ(123456789) + QQbar_I_nf.gen()/ZZ(987654321))) + QQbar_hash_offset = AlgebraicNumber(ANExtensionElement(QQbar_I_generator, ~ZZ(123456789) + QQbar_I_nf.gen() / ZZ(987654321))) ZZX_x = ZZ['x'].gen() + # This is used in the _algebraic_ method of the golden_ratio constant, # in sage/symbolic/constants.py AA_golden_ratio = None + def get_AA_golden_ratio(): r""" Return the golden ratio as an element of the algebraic real field. Used by @@ -7757,24 +7807,3 @@ def get_AA_golden_ratio(): AA_golden_ratio_generator = AlgebraicGenerator(AA_golden_ratio_nf, ANRoot(AAPoly.gen()**2 - AAPoly.gen() - 1, RIF(1.618, 1.6181))) AA_golden_ratio = AlgebraicReal(ANExtensionElement(AA_golden_ratio_generator, AA_golden_ratio_nf.gen())) return AA_golden_ratio - -class ANRootOfUnity(ANExtensionElement): - r""" - Deprecated class to support unpickling - - TESTS:: - - sage: from sage.rings.qqbar import ANRootOfUnity - sage: ANRootOfUnity(1/5, 3/2) - doctest:...: DeprecationWarning: ANRootOfUnity is deprecated - See http://trac.sagemath.org/19954 for details. - 3/2*zeta5 where zeta5^4 + zeta5^3 + zeta5^2 + zeta5 + 1 = 0 - and zeta5 in 0.3090169943749474? + 0.9510565162951536?*I - """ - def __new__(self, a, b): - from sage.misc.superseded import deprecation - deprecation(19954, "ANRootOfUnity is deprecated") - descr = QQbar.zeta(a.denominator())._descr - generator = descr._generator - value = b * descr._value ** (a.numerator()) - return ANExtensionElement(generator, value) diff --git a/src/sage/rings/quotient_ring_element.py b/src/sage/rings/quotient_ring_element.py index 396424d8b40..00ba54b8741 100644 --- a/src/sage/rings/quotient_ring_element.py +++ b/src/sage/rings/quotient_ring_element.py @@ -597,9 +597,9 @@ def __hash__(self): sage: R. = QQ[] sage: S. = R.quo(x^2 + y^2) - sage: hash(a) - 15360174650385711 # 64-bit - 1505322287 # 32-bit + sage: c = a*a + b + sage: hash(a) != hash(b) + True """ return hash(self.__rep) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 2320daacf1e..5e5e3666a1c 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -85,8 +85,9 @@ from sage.structure.coerce cimport is_numpy_type from sage.libs.gmp.pylong cimport mpz_set_pylong -from sage.structure.element cimport Element, RingElement, ModuleElement, coercion_model -from sage.structure.element import bin_op, coerce_binop +from sage.structure.coerce cimport coercion_model +from sage.structure.element cimport Element +from sage.structure.element import coerce_binop from sage.structure.parent cimport Parent from sage.categories.morphism cimport Morphism from sage.categories.map cimport Map @@ -114,9 +115,8 @@ cdef object numpy_double_interface = {'typestr': '=f8'} from libc.math cimport ldexp from sage.libs.gmp.all cimport * -IF HAVE_GMPY2: - cimport gmpy2 - gmpy2.import_gmpy2() +cimport gmpy2 +gmpy2.import_gmpy2() cdef class Rational(sage.structure.element.FieldElement) @@ -455,14 +455,14 @@ cdef class Rational(sage.structure.element.FieldElement): Conversions from gmpy2:: - sage: from gmpy2 import * # optional - gmpy2 - sage: QQ(mpq('3/4')) # optional - gmpy2 + sage: from gmpy2 import * + sage: QQ(mpq('3/4')) 3/4 - sage: QQ(mpz(42)) # optional - gmpy2 + sage: QQ(mpz(42)) 42 - sage: Rational(mpq(2/3)) # optional - gmpy2 + sage: Rational(mpq(2/3)) 2/3 - sage: Rational(mpz(5)) # optional - gmpy2 + sage: Rational(mpz(5)) 5 """ def __cinit__(self): @@ -500,8 +500,8 @@ cdef class Rational(sage.structure.element.FieldElement): 2/3 sage: a.__init__('-h/3ki', 32); a -17/3730 - sage: from gmpy2 import mpq # optional - gmpy2 - sage: a.__init__(mpq('3/5')); a # optional - gmpy2 + sage: from gmpy2 import mpq + sage: a.__init__(mpq('3/5')); a 3/5 TESTS: @@ -660,10 +660,10 @@ cdef class Rational(sage.structure.element.FieldElement): mpz_set(mpq_numref(self.value), ( integer.Integer(x.numerator)).value) mpz_set(mpq_denref(self.value), ( integer.Integer(x.denominator)).value) - elif HAVE_GMPY2 and type(x) is gmpy2.mpq: + elif type(x) is gmpy2.mpq: mpq_set(self.value, (x).q) - elif HAVE_GMPY2 and type(x) is gmpy2.mpz: + elif type(x) is gmpy2.mpz: mpq_set_z(self.value, (x).z) else: @@ -988,10 +988,10 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: sage: q = 6/2 - sage: q.__mpz__() # optional - gmpy2 + sage: q.__mpz__() mpz(3) sage: q = 1/4 - sage: q.__mpz__() # optional - gmpy2 + sage: q.__mpz__() Traceback (most recent call last): ... TypeError: unable to convert rational 1/4 to an integer @@ -1014,23 +1014,13 @@ cdef class Rational(sage.structure.element.FieldElement): EXAMPLES:: sage: r = 5/3 - sage: r.__mpq__() # optional - gmpy2 + sage: r.__mpq__() mpq(5,3) - sage: from gmpy2 import mpq # optional - gmpy2 - sage: mpq(r) # optional - gmpy2 + sage: from gmpy2 import mpq + sage: mpq(r) mpq(5,3) - - TESTS:: - - sage: r.__mpq__(); raise NotImplementedError("gmpy2 is not installed") - Traceback (most recent call last): - ... - NotImplementedError: gmpy2 is not installed """ - IF HAVE_GMPY2: - return gmpy2.GMPy_MPQ_From_mpq(self.value) - ELSE: - raise NotImplementedError("gmpy2 is not installed") + return gmpy2.GMPy_MPQ_From_mpq(self.value) def _magma_init_(self, magma): """ @@ -2197,7 +2187,7 @@ cdef class Rational(sage.structure.element.FieldElement): Test that conversion agrees with `RR`:: sage: Q = [a/b for a in [-99..99] for b in [1..99]] - sage: all([RDF(q) == RR(q) for q in Q]) + sage: all(RDF(q) == RR(q) for q in Q) True Test that the conversion has correct rounding on simple rationals:: @@ -2210,14 +2200,14 @@ cdef class Rational(sage.structure.element.FieldElement): Test larger rationals:: sage: Q = continued_fraction(pi).convergents()[:100] - sage: all([RDF(q) == RR(q) for q in Q]) + sage: all(RDF(q) == RR(q) for q in Q) True At some point, the continued fraction and direct conversion to ``RDF`` should agree:: sage: RDFpi = RDF(pi) - sage: all([RDF(q) == RDFpi for q in Q[20:]]) + sage: all(RDF(q) == RDFpi for q in Q[20:]) True """ return mpq_get_d_nearest(self.value) @@ -3154,19 +3144,30 @@ cdef class Rational(sage.structure.element.FieldElement): 3 sage: (125/8).log(5/2,prec=53) 3.00000000000000 - """ - if self.denom() == ZZ.one(): + + TESTS:: + + sage: (25/2).log(5/2) + log(25/2)/log(5/2) + sage: (-1/2).log(3) + (I*pi + log(1/2))/log(3) + """ + cdef int self_sgn + if self.denom().is_one(): return ZZ(self.numer()).log(m, prec) - if mpz_sgn(mpq_numref(self.value)) < 0: - from sage.symbolic.all import SR - return SR(self).log() if m is not None and m <= 0: 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 + return SR(self).log(m) if prec: - from sage.rings.real_mpfr import RealField - if m is None: - return RealField(prec)(self).log() - return RealField(prec)(self).log(m) + if self_sgn >= 0: + from sage.rings.real_mpfr import RealField + return RealField(prec)(self).log(m) + else: + from sage.rings.complex_field import ComplexField + return ComplexField(prec)(self).log(m) from sage.functions.log import function_log if m is None: @@ -3182,24 +3183,29 @@ cdef class Rational(sage.structure.element.FieldElement): bnp = bnum.perfect_power() adp = aden.perfect_power() bdp = bden.perfect_power() - if (anp[0] == bnp[0] and adp[0] == bdp[0]): - nu_ratio = Rational((anp[1], bnp[1])) - de_ratio = Rational((adp[1], bdp[1])) - if nu_ratio == de_ratio: - return nu_ratio - if nu_ratio == ZZ.one(): - return de_ratio - if de_ratio == ZZ.one(): - return nu_ratio - elif (anp[0] == bdp[0] and adp[0] == bnp[0]): - up_ratio = Rational((anp[1], bdp[1])) - lo_ratio = Rational((adp[1], bnp[1])) - if up_ratio == lo_ratio: - return -up_ratio - if up_ratio == ZZ.one(): - return -lo_ratio - if lo_ratio == ZZ.one(): - return -up_ratio + + if anum.is_one(): + a_exp=adp[1] + a_base=1/adp[0] + # we already know that aden!=0 + else: + a_exp=anp[1].gcd(adp[1]) + a_base=(anp[0]**(anp[1]//a_exp))/(adp[0]**(adp[1]//a_exp)) + + if bnum.is_one(): + b_exp=bdp[1] + b_base=1/bdp[0] + elif bden.is_one(): + b_exp=bnp[1] + b_base=bnp[0] + else: + b_exp=bnp[1].gcd(bdp[1]) + b_base=(bnp[0]**(bnp[1]//b_exp))/(bdp[0]**(bdp[1]//b_exp)) + + if a_base == b_base: + return a_exp/b_exp + elif a_base*b_base == 1: + return -a_exp/b_exp return (function_log(self, dont_call_method_on_arg=True) / function_log(m, dont_call_method_on_arg=True)) @@ -3672,7 +3678,7 @@ cdef class Rational(sage.structure.element.FieldElement): if mpz_cmp_si(mpq_denref((y).value), 1) != 0: raise ValueError("denominator must be 1") return (x)._lshift(y) - return bin_op(x, y, operator.lshift) + return coercion_model.bin_op(x, y, operator.lshift) cdef _rshift(self, long int exp): r""" @@ -3720,7 +3726,7 @@ cdef class Rational(sage.structure.element.FieldElement): if mpz_cmp_si(mpq_denref((y).value), 1) != 0: raise ValueError("denominator must be 1") return (x)._rshift(y) - return bin_op(x, y, operator.rshift) + return coercion_model.bin_op(x, y, operator.rshift) def conjugate(self): """ diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index b8850bb434f..f46d36df0f1 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -149,10 +149,8 @@ def __new__(cls): sage: RationalField() in Fields() # indirect doctest True - """ try: - from sage.rings.rational_field import QQ return QQ except BaseException: from sage.rings.number_field.number_field_base import NumberField @@ -234,12 +232,18 @@ def __init__(self): ('x',) sage: QQ._element_constructor_((2, 3)) 2/3 + + sage: QQ.is_finite() + False + + sage: QQ.is_field() + True """ from sage.categories.basic import QuotientFields from sage.categories.number_fields import NumberFields ParentWithGens.__init__(self, self, category=[QuotientFields().Metric(), NumberFields()]) - self._assign_names(('x',),normalize=False) # ??? + self._assign_names(('x',), normalize=False) # ????? self._populate_coercion_lists_(init_no_parent=True) _element_constructor_ = Rational @@ -810,28 +814,6 @@ def is_absolute(self): """ return True - def is_field(self, proof = True): - """ - Return ``True``, since the rational field is a field. - - EXAMPLES:: - - sage: QQ.is_field() - True - """ - return True - - def is_finite(self): - """ - Return ``False``, since the rational field is not finite. - - EXAMPLES:: - - sage: QQ.is_finite() - False - """ - return False - def is_prime_field(self): r""" Return ``True`` since `\QQ` is a prime field. diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index adcd7cf0a83..d54eb0f8bc0 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -359,6 +359,9 @@ class RealBallField(UniqueRepresentation, Field): sage: a = (sqrt2 - 1)^1000 sage: RBF(a) [1.676156872756536e-383 +/- ...e-399] + + sage: RealBallField().is_finite() + False """ Element = RealBall @@ -618,21 +621,6 @@ class RealBallField(UniqueRepresentation, Field): """ return False - def is_finite(self): - """ - Real ball fields are infinite. - - They already specify it via their category, but we currently need to - re-implement this method due to the legacy implementation in - :class:`sage.rings.ring.Ring`. - - EXAMPLES:: - - sage: RealBallField().is_finite() - False - """ - return False - def characteristic(self): """ Real ball fields have characteristic zero. @@ -3172,6 +3160,36 @@ cdef class RealBall(RingElement): if _do_sig(prec(self)): sig_off() return res + def sec(self): + """ + Return the secant of this ball. + + EXAMPLES:: + + sage: RBF(1).sec() + [1.850815717680925 +/- ...e-16] + """ + cdef RealBall res = self._new() + if _do_sig(prec(self)): sig_on() + arb_sec(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def csc(self): + """ + Return the cosecant of this ball. + + EXAMPLES:: + + sage: RBF(1).csc() + [1.188395105778121 +/- ...e-16] + """ + cdef RealBall res = self._new() + if _do_sig(prec(self)): sig_on() + arb_csc(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + def arcsin(self): """ Return the arcsine of this ball. @@ -3283,6 +3301,36 @@ cdef class RealBall(RingElement): if _do_sig(prec(self)): sig_off() return res + def sech(self): + """ + Return the hyperbolic secant of this ball. + + EXAMPLES:: + + sage: RBF(1).sech() + [0.648054273663885 +/- ...e-16] + """ + cdef RealBall res = self._new() + if _do_sig(prec(self)): sig_on() + arb_sech(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + + def csch(self): + """ + Return the hyperbolic cosecant of this ball. + + EXAMPLES:: + + sage: RBF(1).csch() + [0.850918128239321 +/- ...e-16] + """ + cdef RealBall res = self._new() + if _do_sig(prec(self)): sig_on() + arb_csch(res.value, self.value, prec(self)) + if _do_sig(prec(self)): sig_off() + return res + def arcsinh(self): """ Return the inverse hyperbolic sine of this ball. diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 3d7367ab5dd..7bf61d2bc81 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -72,8 +72,7 @@ from sage.misc.randstate cimport randstate, current_randstate from sage.structure.richcmp cimport rich_to_bool from sage.arith.constants cimport * -IF HAVE_GMPY2: - cimport gmpy2 +cimport gmpy2 def is_RealDoubleField(x): @@ -137,6 +136,10 @@ cdef class RealDoubleField_class(Field): sage: b == RR(a) True + TESTS:: + + sage: RDF.is_finite() + False """ def __init__(self): """ @@ -148,7 +151,7 @@ cdef class RealDoubleField_class(Field): sage: TestSuite(R).run() """ from sage.categories.fields import Fields - Field.__init__(self, self, category=Fields().Metric().Complete()) + Field.__init__(self, self, category=Fields().Infinite().Metric().Complete()) self._populate_coercion_lists_(init_no_parent=True, convert_method_name='_real_double_') @@ -470,20 +473,6 @@ cdef class RealDoubleField_class(Field): """ return 1 - def is_finite(self): - """ - Return ``False``, since the field of real numbers is not finite. - - Technical note: There exists an upper bound on the double - representation. - - EXAMPLES:: - - sage: RDF.is_finite() - False - """ - return False - def characteristic(self): """ Returns 0, since the field of real numbers has characteristic 0. @@ -532,12 +521,16 @@ cdef class RealDoubleField_class(Field): """ Return the hash value of ``self``. + This class is intended for use as a singleton so any instance + of it should be equivalent from a hashing perspective. + TESTS:: - sage: hash(RDF) % 2^32 == hash(str(RDF)) % 2^32 + sage: from sage.rings.real_double import RealDoubleField_class + sage: hash(RDF) == hash(RealDoubleField_class()) True """ - return 1157042230 #return hash(str(self)) + return 1157042230 def pi(self): r""" @@ -722,12 +715,12 @@ cdef class RealDoubleElement(FieldElement): TESTS:: - sage: from gmpy2 import * # optional - gmpy2 - sage: RDF(mpz(42)) # optional - gmpy2 + sage: from gmpy2 import * + sage: RDF(mpz(42)) 42.0 - sage: RDF(mpq(3/4)) # optional - gmpy2 + sage: RDF(mpq(3/4)) 0.75 - sage: RDF(mpq('4.1')) # optional - gmpy2 + sage: RDF(mpq('4.1')) 4.1 """ self._value = float(x) @@ -951,10 +944,10 @@ cdef class RealDoubleElement(FieldElement): EXAMPLES:: - sage: RDF(42.2).__mpfr__() # optional - gmpy2 + sage: RDF(42.2).__mpfr__() mpfr('42.200000000000003') - sage: from gmpy2 import mpfr # optional - gmpy2 - sage: mpfr(RDF(5.1)) # optional - gmpy2 + sage: from gmpy2 import mpfr + sage: mpfr(RDF(5.1)) mpfr('5.0999999999999996') TESTS:: @@ -964,10 +957,7 @@ cdef class RealDoubleElement(FieldElement): ... NotImplementedError: gmpy2 is not installed """ - IF HAVE_GMPY2: - return gmpy2.mpfr(self._value) - ELSE: - raise NotImplementedError("gmpy2 is not installed") + return gmpy2.mpfr(self._value) def _interface_init_(self, I=None): """ diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index 6c13be234e1..952ce0a6f32 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -11,17 +11,17 @@ number fields) to embed for the coercion model (as only one embedding can be specified in the forward direction). """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Robert Bradshaw # # 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 __future__ import absolute_import, division, print_function -import math +import math, cmath cdef add, sub, mul, truediv, pow, neg, inv from operator import add, sub, mul, pow, neg, inv, truediv @@ -315,7 +315,7 @@ class RealLazyField_class(LazyField): EXAMPLES:: - sage: hash(RLF) % 2^32 == hash(str(RLF)) % 2^32 + sage: hash(RLF) == hash(RealLazyField()) True """ return 1501555429 @@ -397,7 +397,8 @@ class ComplexLazyField_class(LazyField): This lazy field doesn't evaluate its elements until they are cast into a field of fixed precision. - EXAMPLES: + EXAMPLES:: + sage: a = RLF(1/3); a 0.3333333333333334? sage: Reals(200)(a) @@ -486,7 +487,8 @@ class ComplexLazyField_class(LazyField): EXAMPLES:: - sage: hash(CLF) % 2^32 == hash(str(CLF)) % 2^32 + sage: from sage.rings.real_lazy import ComplexLazyField_class + sage: hash(CLF) == hash(ComplexLazyField_class()) True """ return -1382606040 @@ -1442,7 +1444,6 @@ cdef class LazyConstant(LazyFieldElement): cdef readonly _name cdef readonly _extra_args - cdef readonly bint _is_special def __init__(self, LazyField parent, name, extra_args=None): """ @@ -1464,7 +1465,6 @@ cdef class LazyConstant(LazyFieldElement): LazyFieldElement.__init__(self, parent) self._name = name self._extra_args = extra_args - self._is_special = name in ['e', 'I'] cpdef eval(self, R): """ @@ -1479,21 +1479,60 @@ cdef class LazyConstant(LazyFieldElement): sage: a = LazyConstant(CLF, 'I') sage: CC(a) 1.00000000000000*I + + TESTS: + + Check that :trac:`26839` is fixed:: + + sage: RLF.pi().eval(float) + 3.141592653589793 + sage: type(RLF.pi().eval(float)) is float + True + + sage: RLF.pi().eval(complex) + (3.141592653589793+0j) + sage: type(RLF.pi().eval(complex)) is complex + True + + sage: RLF.pi().eval(RealBallField(128)) + [3.1415926535897932384626433832795028842 +/- 1.06e-38] + + sage: float(sin(RLF.pi())) + 1.2246467991473532e-16 """ - if self._is_special: - if self._name == 'e': - return R(1).exp() - elif self._name == 'I': + # special handling of e and I + if self._name == 'I': + if R is float: + raise ValueError('I is not a real number') + elif R is complex: + return 1j + else: I = R.gen() - if I*I < 0: - return I - else: - raise TypeError("The complex constant I is not in this real field.") - f = getattr(R, self._name) - if self._extra_args is None: - return f() + if I*I != -R.one(): + raise TypeError("The complex constant I is not in this complex field.") + return I + + elif self._name == 'e': + if R is float: + return math.e + elif R is complex: + return complex(math.e) + else: + return R(1).exp() + + elif R is float: + # generic float + return getattr(math, self._name) + elif R is complex: + # generic complex + return complex(getattr(cmath, self._name)) else: - return f(*self._extra_args) + # generic Sage parent + f = getattr(R, self._name) + if self._extra_args is None: + return f() + else: + return f(*self._extra_args) def __call__(self, *args): """ diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 091292fa491..c6d9bc4dda6 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -500,6 +500,9 @@ cdef class RealIntervalField_class(Field): sage: RIF.middle_field() is RR True sage: TestSuite(RIF).run() + + sage: RealIntervalField(10).is_finite() + False """ Element = RealIntervalFieldElement @@ -976,17 +979,6 @@ cdef class RealIntervalField_class(Field): return True return super(RealIntervalField_class, self)._repr_option(key) - def is_finite(self): - """ - Return ``False``, since the field of real numbers is not finite. - - EXAMPLES:: - - sage: RealIntervalField(10).is_finite() - False - """ - return False - def characteristic(self): """ Returns 0, since the field of real numbers has characteristic 0. @@ -2773,7 +2765,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: RIF(1, 2).square().str(style='brackets') '[1.0000000000000000 .. 4.0000000000000000]' sage: RIF(-1, 1).square().str(style='brackets') - '[0.00000000000000000 .. 1.0000000000000000]' + '[0.0000000000000000 .. 1.0000000000000000]' sage: (RIF(-1, 1) * RIF(-1, 1)).str(style='brackets') '[-1.0000000000000000 .. 1.0000000000000000]' """ @@ -3960,7 +3952,7 @@ cdef class RealIntervalFieldElement(RingElement): sage: RIF(1, 2).union(pi).str(style='brackets') '[1.0000000000000000 .. 3.1415926535897936]' sage: RIF(1).union(RIF(0, 2)).str(style='brackets') - '[0.00000000000000000 .. 2.0000000000000000]' + '[0.0000000000000000 .. 2.0000000000000000]' sage: RIF(1).union(RIF(-1)).str(style='brackets') '[-1.0000000000000000 .. 1.0000000000000000]' """ diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index e273190e57f..ae741197957 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -114,7 +114,7 @@ Make sure we don't have a new field for every new literal:: # 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 __future__ import absolute_import, print_function @@ -168,9 +168,8 @@ from sage.structure.parent_gens cimport ParentWithGens from sage.arith.numerical_approx cimport digits_to_bits from sage.arith.constants cimport M_LN2_LN10 -IF HAVE_GMPY2: - cimport gmpy2 - gmpy2.import_gmpy2() +cimport gmpy2 +gmpy2.import_gmpy2() #***************************************************************************** @@ -515,6 +514,11 @@ cdef class RealField_class(sage.rings.ring.Field): Traceback (most recent call last): ... OverflowError: Sage Integer too large to convert to C long + + Check methods inherited from categories:: + + sage: RealField(10).is_finite() + False """ global MY_MPFR_PREC_MAX if prec < MPFR_PREC_MIN or prec > MY_MPFR_PREC_MAX: @@ -530,7 +534,7 @@ cdef class RealField_class(sage.rings.ring.Field): self.rnd_str = char_to_str(rnd_str + 5) # Strip "MPFR_" from sage.categories.fields import Fields - ParentWithGens.__init__(self, self, tuple([]), False, category=Fields().Metric().Complete()) + ParentWithGens.__init__(self, self, tuple([]), False, category=Fields().Infinite().Metric().Complete()) # Initialize zero and one cdef RealNumber rn @@ -937,17 +941,6 @@ cdef class RealField_class(sage.rings.ring.Field): return True return super(RealField_class, self)._repr_option(key) - def is_finite(self): - """ - Return ``False``, since the field of real numbers is not finite. - - EXAMPLES:: - - sage: RealField(10).is_finite() - False - """ - return False - def characteristic(self): """ Returns 0, since the field of real numbers has characteristic 0. @@ -1385,12 +1378,12 @@ cdef class RealNumber(sage.structure.element.RingElement): Conversion from gmpy2 numbers:: - sage: from gmpy2 import * # optional - gmpy2 - sage: RR(mpz(5)) # optional - gmpy2 + sage: from gmpy2 import * + sage: RR(mpz(5)) 5.00000000000000 - sage: RR(mpq(1/2)) # optional - gmpy2 + sage: RR(mpq(1/2)) 0.500000000000000 - sage: RR(mpfr('42.1')) # optional - gmpy2 + sage: RR(mpfr('42.1')) 42.1000000000000 .. NOTE:: @@ -1483,11 +1476,11 @@ cdef class RealNumber(sage.structure.element.RingElement): mpfr_set_d(self.value, x.real, parent.rnd) elif isinstance(x, RealDoubleElement): mpfr_set_d(self.value, (x)._value, parent.rnd) - elif HAVE_GMPY2 and type(x) is gmpy2.mpfr: + elif type(x) is gmpy2.mpfr: mpfr_set(self.value, (x).f, parent.rnd) - elif HAVE_GMPY2 and type(x) is gmpy2.mpq: + elif type(x) is gmpy2.mpq: mpfr_set_q(self.value, (x).q, parent.rnd) - elif HAVE_GMPY2 and type(x) is gmpy2.mpz: + elif type(x) is gmpy2.mpz: mpfr_set_z(self.value, (x).z, parent.rnd) else: s = str(x).replace(' ','') @@ -1935,6 +1928,16 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: y.str(digits=1) '-4.' + Zero has the correct number of digits:: + + sage: zero = RR.zero() + sage: print(zero.str(digits=3)) + 0.00 + sage: print(zero.str(digits=3, no_sci=False)) + 0.00e0 + sage: print(zero.str(digits=3, skip_zeroes=True)) + 0. + The output always contains a decimal point, except when using scientific notation with exactly one digit:: @@ -2023,6 +2026,10 @@ cdef class RealNumber(sage.structure.element.RingElement): if digits < 2: digits = 2 + # For backwards compatibility, add one extra digit for 0.0 + if mpfr_zero_p(self.value): + digits += 1 + sig_on() cdef char *s cdef mp_exp_t exponent @@ -2043,6 +2050,11 @@ cdef class RealNumber(sage.structure.element.RingElement): if skip_zeroes: t = _re_skip_zeroes.match(t).group(1) + # Treat 0.0 as having exponent 1, this gives better results + # (effectively treating it as 0. instead of .0) + if mpfr_zero_p(self.value): + exponent = 1 + if no_sci is None: use_sci = (self._parent).sci_not or abs(exponent-1) >= 6 elif no_sci is True: @@ -3212,7 +3224,6 @@ cdef class RealNumber(sage.structure.element.RingElement): # by using internal interfaces of MPFR, which are documented # as subject-to-change. - sig_on() if mpfr_nan_p(self.value) or mpfr_inf_p(self.value): raise ValueError('Cannot convert NaN or infinity to Pari float') @@ -3234,6 +3245,7 @@ cdef class RealNumber(sage.structure.element.RingElement): cdef mp_exp_t exponent cdef GEN pari_float + sig_on() if mpfr_zero_p(self.value): pari_float = real_0_bit(-rounded_prec) else: @@ -3245,7 +3257,7 @@ cdef class RealNumber(sage.structure.element.RingElement): # Create a PARI REAL pari_float = cgetr(2 + rounded_prec / wordsize) pari_float[1] = evalexpo(exponent + rounded_prec - 1) + evalsigne(mpfr_sgn(self.value)) - mpz_export(&pari_float[2], NULL, 1, wordsize/8, 0, 0, mantissa) + mpz_export(&pari_float[2], NULL, 1, wordsize // 8, 0, 0, mantissa) mpz_clear(mantissa) return new_gen(pari_float) @@ -3777,40 +3789,30 @@ cdef class RealNumber(sage.structure.element.RingElement): EXAMPLES:: sage: r = RR(4.12) - sage: r.__mpfr__() # optional - gmpy2 + sage: r.__mpfr__() mpfr('4.1200000000000001') - sage: from gmpy2 import mpfr # optional - gmpy2 - sage: mpfr(RR(4.5)) # optional - gmpy2 + sage: from gmpy2 import mpfr + sage: mpfr(RR(4.5)) mpfr('4.5') sage: R = RealField(127) - sage: mpfr(R.pi()).precision # optional - gmpy2 + sage: mpfr(R.pi()).precision 127 sage: R = RealField(42) - sage: mpfr(R.pi()).precision # optional - gmpy2 + sage: mpfr(R.pi()).precision 42 sage: R = RealField(256) - sage: x = mpfr(R.pi()) # optional - gmpy2 - sage: x.precision # optional - gmpy2 + sage: x = mpfr(R.pi()) + sage: x.precision 256 - sage: y = R(x) # optional - gmpy2 - sage: mpfr(y) == x # optional - gmpy2 + sage: y = R(x) + sage: mpfr(y) == x True - sage: x = mpfr('2.567e42', precision=128) # optional - gmpy2 - sage: y = RealField(128)(x) # optional - gmpy2 - sage: mpfr(y) == x # optional - gmpy2 + sage: x = mpfr('2.567e42', precision=128) + sage: y = RealField(128)(x) + sage: mpfr(y) == x True - - TESTS:: - - sage: r.__mpfr__(); raise NotImplementedError("gmpy2 is not installed") - Traceback (most recent call last): - ... - NotImplementedError: gmpy2 is not installed """ - IF HAVE_GMPY2: - return gmpy2.GMPy_MPFR_From_mpfr(self.value) - ELSE: - raise NotImplementedError("gmpy2 is not installed") + return gmpy2.GMPy_MPFR_From_mpfr(self.value) ########################################### # Comparisons: ==, !=, <, <=, >, >= @@ -5608,7 +5610,7 @@ def create_RealNumber(s, int base=10, int pad=0, rnd="RNDN", int min_prec=53): - ``base`` -- an integer between 2 and 62 - - ``pad`` -- an integer = 0. + - ``pad`` -- an integer >= 0. - ``rnd`` -- rounding mode: @@ -5719,7 +5721,7 @@ def create_RealNumber(s, int base=10, int pad=0, rnd="RNDN", int min_prec=53): else: bits = int(math.log(base,2)*1.00001*sigfigs)+1 - R = RealField(prec=max(bits+pad, min_prec), rnd=rnd) + R = RealField(prec=max(bits + pad, min_prec), rnd=rnd) return RealLiteral(R, s, base) diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index dbc4f8e3e7a..f9aa0b52936 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -69,7 +69,7 @@ from __future__ import print_function, absolute_import from sage.misc.cachefunc import cached_method -from sage.structure.element cimport coercion_model +from sage.structure.coerce cimport coercion_model from sage.structure.parent cimport Parent from sage.structure.category_object import check_default_category from sage.structure.sequence import Sequence @@ -158,7 +158,25 @@ cdef class Ring(ParentWithGens): True sage: CDF._repr_option('element_is_atomic') False - """ + + Check that categories correctly implement `is_finite` and `cardinality`:: + + sage: QQ.is_finite() + False + sage: GF(2^10,'a').is_finite() + True + sage: R. = GF(7)[] + sage: R.is_finite() + False + sage: S. = R.quo(x^2+1) + sage: S.is_finite() + True + + sage: Integers(7).cardinality() + 7 + sage: QQ.cardinality() + +Infinity + """ def __init__(self, base, names=None, normalize=True, category = None): """ Initialize ``self``. @@ -895,47 +913,6 @@ cdef class Ring(ParentWithGens): """ return False - def is_finite(self): - """ - Return ``True`` if this ring is finite. - - EXAMPLES:: - - sage: QQ.is_finite() - False - sage: GF(2^10,'a').is_finite() - True - sage: R. = GF(7)[] - sage: R.is_finite() - False - sage: S. = R.quo(x^2+1) - sage: S.is_finite() - True - """ - if self.is_zero(): - return True - return super(Ring, self).is_finite() - - def cardinality(self): - """ - Return the cardinality of the underlying set. - - OUTPUT: - - Either an integer or ``+Infinity``. - - EXAMPLES:: - - sage: Integers(7).cardinality() - 7 - sage: QQ.cardinality() - +Infinity - """ - if not self.is_finite(): - from .infinity import Infinity - return Infinity - raise NotImplementedError - def is_integral_domain(self, proof = True): """ Return ``True`` if this ring is an integral domain. @@ -1858,14 +1835,6 @@ cdef class IntegralDomain(CommutativeRing): True sage: R. = PolynomialRing(QQ); R.is_field() False - - An example where we raise a ``NotImplementedError``:: - - sage: R = IntegralDomain(ZZ) - sage: R.is_field() - Traceback (most recent call last): - ... - NotImplementedError: cannot construct elements of """ if self.is_finite(): return True diff --git a/src/sage/rings/tate_algebra.py b/src/sage/rings/tate_algebra.py index cd6af342ba8..461d648b6d2 100644 --- a/src/sage/rings/tate_algebra.py +++ b/src/sage/rings/tate_algebra.py @@ -494,7 +494,7 @@ def prime(self): """ Return the prime, that is the characteristic of the residue field. - EXAMPLES: + EXAMPLES:: sage: R = Zp(3) sage: A. = TateAlgebra(R) diff --git a/src/sage/rings/tate_algebra_element.pyx b/src/sage/rings/tate_algebra_element.pyx index 1d60ca757a9..c0a8e07c5c5 100644 --- a/src/sage/rings/tate_algebra_element.pyx +++ b/src/sage/rings/tate_algebra_element.pyx @@ -51,7 +51,7 @@ def _pushout_family(elements, initial=ZZ): - ``initial`` -- a parent - EXAMPLES: + EXAMPLES:: sage: from sage.rings.tate_algebra_element import _pushout_family diff --git a/src/sage/rings/universal_cyclotomic_field.py b/src/sage/rings/universal_cyclotomic_field.py index 0e3d4880906..2bad636d66e 100644 --- a/src/sage/rings/universal_cyclotomic_field.py +++ b/src/sage/rings/universal_cyclotomic_field.py @@ -14,10 +14,10 @@ There used to be a native Sage version of the universal cyclotomic field written by Christian Stump (see :trac:`8327`). It was slower on most - operations and it was decided to use a version based on libGAP instead (see + operations and it was decided to use a version based on GAP instead (see :trac:`18152`). One main difference in the design choices is that GAP stores dense vectors whereas the native ones used Python dictionaries (storing only - nonzero coefficients). Most operations are faster with libGAP except some + nonzero coefficients). Most operations are faster with GAP except some operation on very sparse elements. All details can be found in :trac:`18152`. @@ -783,7 +783,7 @@ def multiplicative_order(self): sage: UniversalCyclotomicField().zero().multiplicative_order() Traceback (most recent call last): ... - ValueError: libGAP: Error, argument must be nonzero + GAPError: Error, argument must be nonzero """ return self._obj.Order().sage() @@ -1013,19 +1013,31 @@ def galois_conjugates(self, n=None): return [P.element_class(P, obj.GaloisCyc(i)) for i in n.coprime_integers(n)] - def abs(self): + def __abs__(self): """ - Return the absolute value of ``self`` as an algebraic real number. + Return the absolute value (or complex modulus) of ``self``. + + The absolute value is returned as an algebraic real number. EXAMPLES:: sage: f = 5/2*E(3)+E(5)/7 sage: f.abs() 2.597760303873084? + sage: abs(f) + 2.597760303873084? + sage: a = E(8) + sage: abs(a) + 1 + sage: v, w = vector([a]), vector([a, a]) + sage: v.norm(), w.norm() + (1, 1.414213562373095?) + sage: v.norm().parent() + Algebraic Real Field TESTS:: - sage: [E(n).abs() for n in range(1, 11)] + sage: [abs(E(n)) for n in range(1, 11)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] sage: UniversalCyclotomicField().zero().abs() 0 @@ -1033,6 +1045,8 @@ def abs(self): square = self * self.conjugate() return AA(square).sqrt() + abs = __abs__ + def norm_of_galois_extension(self): r""" Return the norm as a Galois extension of `\QQ`, which is @@ -1126,6 +1140,9 @@ def __init__(self, names=None): sage: UCF = UniversalCyclotomicField() sage: TestSuite(UCF).run() + + sage: UniversalCyclotomicField().is_finite() + False """ from sage.categories.fields import Fields Field.__init__(self, base_ring=QQ, category=Fields().Infinite()) diff --git a/src/sage/rings/valuation/trivial_valuation.py b/src/sage/rings/valuation/trivial_valuation.py index 51f15fc2b75..a6ff2a3e49c 100644 --- a/src/sage/rings/valuation/trivial_valuation.py +++ b/src/sage/rings/valuation/trivial_valuation.py @@ -381,10 +381,8 @@ def extensions(self, ring): sage: v = valuations.TrivialValuation(ZZ) sage: v.extensions(QQ) [Trivial valuation on Rational Field] - """ if self.domain().is_subring(ring): - from sage.rings.valuation.trivial_valuation import TrivialValuation return [TrivialValuation(ring)] return super(DiscretePseudoValuation, self).extensions(ring) diff --git a/src/sage/rings/valuation/valuation_space.py b/src/sage/rings/valuation/valuation_space.py index 1e0a1696183..2607857f051 100644 --- a/src/sage/rings/valuation/valuation_space.py +++ b/src/sage/rings/valuation/valuation_space.py @@ -1031,10 +1031,7 @@ def inverse(self, x, precision): 1/2 """ - try: - return x.inverse_of_unit() - except: - raise NotImplementedError("can not compute approximate inverse with respect to this valuation") + return x.inverse_of_unit() def _relative_size(self, x): r""" @@ -1636,7 +1633,7 @@ def _test_inverse(self, **options): for prec in (0, 1, 42, infinity): try: y = self.inverse(x, prec) - except NotImplementedError: + except ArithmeticError: # Inverse does not exist continue except ValueError: if prec is not infinity: diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index a5d0c8eff1b..3a368796dec 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -321,6 +321,8 @@ from inspect import getdoc from textwrap import dedent +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 @@ -2004,7 +2006,7 @@ def _set_jacobian_representatives(self): r""" Find representatives for the elements of the Jacobian group. - EXAMPLES: + EXAMPLES:: sage: s = sandpiles.Complete(3) sage: s._set_jacobian_representatives() @@ -3468,8 +3470,9 @@ def sandpile(self): def values(self): r""" - The values of the configuration as a list. The list is sorted in the - order of the vertices. + The values of the configuration as a list. + + The list is sorted in the order of the vertices. OUTPUT: @@ -3479,14 +3482,14 @@ def values(self): EXAMPLES:: - sage: S = Sandpile({'a':[1,'b'], 'b':[1,'a'], 1:['a']},'a') - sage: c = SandpileConfig(S, {'b':1, 1:2}) + sage: S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') + sage: c = SandpileConfig(S, {'b':1, 'c':2}) sage: c - {1: 2, 'b': 1} + {'b': 1, 'c': 2} sage: c.values() - [2, 1] + [1, 2] sage: S.nonsink_vertices() - [1, 'b'] + ['b', 'c'] """ return [self[v] for v in self._vertices] @@ -4175,6 +4178,15 @@ def show(self, sink=True, colors=True, heights=False, directed=None, **kwds): else: T.show(**kwds) + +# Note: There ought to be a better way to do this: sage.repl.display is +# intended to help extend pretty-printing capabilities but it still doesn't +# provide an interface to do something as simple as this (in this case we are +# informing IPython that SandpileConfig, being a dict subclass, should be +# pretty-printed in the same way a dict) +pretty.for_type(SandpileConfig, pretty.for_type(dict, None)) + + ############################################### ########### SandpileDivisor Class ############# ############################################### @@ -4738,8 +4750,9 @@ def sandpile(self): def values(self): r""" - The values of the divisor as a list. The list is sorted in the order of - the vertices. + The values of the divisor as a list. + + The list is sorted in the order of the vertices. OUTPUT: @@ -4749,14 +4762,14 @@ def values(self): EXAMPLES:: - sage: S = Sandpile({'a':[1,'b'], 'b':[1,'a'], 1:['a']},'a') - sage: D = SandpileDivisor(S, {'a':0, 'b':1, 1:2}) + sage: S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') + sage: D = SandpileDivisor(S, {'a':0, 'b':1, 'c':2}) sage: D - {'a': 0, 1: 2, 'b': 1} + {'a': 0, 'b': 1, 'c': 2} sage: D.values() - [2, 0, 1] + [0, 1, 2] sage: S.vertices() - [1, 'a', 'b'] + ['a', 'b', 'c'] """ return [self[v] for v in self._vertices] @@ -6053,6 +6066,10 @@ def show(self, heights=True, directed=None, **kwds): T.relabel(a) T.show(**kwds) + +# See note about this after the definition of SandpileConfig +pretty.for_type(SandpileDivisor, pretty.for_type(dict, None)) + ####################################### ######### Some test graphs ############ ####################################### @@ -6153,7 +6170,6 @@ def sandlib(selector=None): ################################################# - def triangle_sandpile(n): r""" A triangular sandpile. Each nonsink vertex has out-degree six. The @@ -6174,7 +6190,7 @@ def triangle_sandpile(n): sage: T.group_order() 135418115000 """ - T = {'sink':{}} + T = {(-1, -1):{}} for i in range(n): for j in range(n-i): T[(i,j)] = {} @@ -6189,17 +6205,18 @@ def triangle_sandpile(n): T[(i,j)][(i+1,j-1)] = 1 d = len(T[(i,j)]) if d<6: - T[(i,j)]['sink'] = 6-d - T = Sandpile(T,'sink') + T[(i,j)][(-1, -1)] = 6-d + T = Sandpile(T, (-1, -1)) pos = {} for x in T.nonsink_vertices(): coords = list(x) coords[0]+=QQ(1)/2*coords[1] pos[x] = coords - pos['sink'] = (-1,-1) + pos[(-1, -1)] = (-1,-1) T.set_pos(pos) return T + def aztec_sandpile(n): r""" The aztec diamond graph. @@ -6215,31 +6232,10 @@ def aztec_sandpile(n): EXAMPLES:: sage: from sage.sandpiles.sandpile import aztec_sandpile - sage: aztec_sandpile(2) - {'sink': {(-3/2, -1/2): 2, - (-3/2, 1/2): 2, - (-1/2, -3/2): 2, - (-1/2, 3/2): 2, - (1/2, -3/2): 2, - (1/2, 3/2): 2, - (3/2, -1/2): 2, - (3/2, 1/2): 2}, - (-3/2, -1/2): {'sink': 2, (-3/2, 1/2): 1, (-1/2, -1/2): 1}, - (-3/2, 1/2): {'sink': 2, (-3/2, -1/2): 1, (-1/2, 1/2): 1}, - (-1/2, -3/2): {'sink': 2, (-1/2, -1/2): 1, (1/2, -3/2): 1}, - (-1/2, -1/2): {(-3/2, -1/2): 1, - (-1/2, -3/2): 1, - (-1/2, 1/2): 1, - (1/2, -1/2): 1}, - (-1/2, 1/2): {(-3/2, 1/2): 1, (-1/2, -1/2): 1, (-1/2, 3/2): 1, (1/2, 1/2): 1}, - (-1/2, 3/2): {'sink': 2, (-1/2, 1/2): 1, (1/2, 3/2): 1}, - (1/2, -3/2): {'sink': 2, (-1/2, -3/2): 1, (1/2, -1/2): 1}, - (1/2, -1/2): {(-1/2, -1/2): 1, (1/2, -3/2): 1, (1/2, 1/2): 1, (3/2, -1/2): 1}, - (1/2, 1/2): {(-1/2, 1/2): 1, (1/2, -1/2): 1, (1/2, 3/2): 1, (3/2, 1/2): 1}, - (1/2, 3/2): {'sink': 2, (-1/2, 3/2): 1, (1/2, 1/2): 1}, - (3/2, -1/2): {'sink': 2, (1/2, -1/2): 1, (3/2, 1/2): 1}, - (3/2, 1/2): {'sink': 2, (1/2, 1/2): 1, (3/2, -1/2): 1}} - sage: Sandpile(aztec_sandpile(2),'sink').group_order() + sage: T = aztec_sandpile(2) + sage: sorted(len(v) for u, v in T.items()) + [3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 8] + sage: Sandpile(T,(0, 0)).group_order() 4542720 .. NOTE:: @@ -6248,7 +6244,7 @@ def aztec_sandpile(n): vertices have edges to the sink so that each vertex has degree 4. """ aztec_sandpile = {} - half = QQ(1)/2 + half = QQ((1, 2)) for i in xsrange(n): for j in xsrange(n-i): aztec_sandpile[(half+i,half+j)] = {} @@ -6256,7 +6252,7 @@ def aztec_sandpile(n): aztec_sandpile[(half+i,-half-j)] = {} aztec_sandpile[(-half-i,-half-j)] = {} non_sinks = list(aztec_sandpile) - aztec_sandpile['sink'] = {} + aztec_sandpile[(0, 0)] = {} for vert in non_sinks: weight = abs(vert[0]) + abs(vert[1]) x = vert[0] @@ -6274,10 +6270,11 @@ def aztec_sandpile(n): aztec_sandpile[vert][(x,y-1)] = 1 if len(aztec_sandpile[vert]) < 4: out_degree = 4 - len(aztec_sandpile[vert]) - aztec_sandpile[vert]['sink'] = out_degree - aztec_sandpile['sink'][vert] = out_degree + aztec_sandpile[vert][(0, 0)] = out_degree + aztec_sandpile[(0, 0)][vert] = out_degree return aztec_sandpile + def random_DAG(num_verts, p=0.5, weight_max=1): r""" A random directed acyclic graph with ``num_verts`` vertices. @@ -6362,15 +6359,15 @@ def glue_graphs(g, h, glue_g, glue_h): sage: glue_x = {1: 1, 3: 2} sage: glue_y = {0: 1, 1: 2, 3: 1} sage: z = glue_graphs(x,y,glue_x,glue_y); z - {0: {}, - 'x0': {0: 1, 'x1': 1, 'x3': 2, 'y1': 2, 'y3': 1}, + {'sink': {}, + 'x0': {'sink': 1, 'x1': 1, 'x3': 2, 'y1': 2, 'y3': 1}, 'x1': {'x0': 1}, 'x2': {'x0': 1, 'x1': 1}, 'x3': {'x0': 1, 'x1': 1, 'x2': 1}, - 'y1': {0: 2}, + 'y1': {'sink': 2}, 'y2': {'y1': 2}, - 'y3': {0: 1, 'y2': 1}} - sage: S = Sandpile(z,0) + 'y3': {'sink': 1, 'y2': 1}} + sage: S = Sandpile(z,'sink') sage: S.h_vector() [1, 6, 17, 31, 41, 41, 31, 17, 6, 1] sage: S.resolution() @@ -6382,7 +6379,7 @@ def glue_graphs(g, h, glue_g, glue_h): `g` and `h`. The sink of `g` is replaced by a vertex that is connected to the vertices of `g` as specified by ``glue_g`` the vertices of `h` as specified in ``glue_h``. The sink of the glued - graph is `0`. + graph is ``'sink'``. Both ``glue_g`` and ``glue_h`` are dictionaries with entries of the form ``v:w`` where ``v`` is the vertex to be connected to and ``w`` is the weight @@ -6397,7 +6394,7 @@ def glue_graphs(g, h, glue_g, glue_h): if h[i] == {}: h_sink = i break - k = {0: {}} # the new graph dictionary, starting with the sink + k = {'sink': {}} # the new graph dictionary, starting with the sink for i in g: if i != g_sink: new_edges = {} @@ -6409,7 +6406,7 @@ def glue_graphs(g, h, glue_g, glue_h): new_edges = {} for j in h[i]: if j == h_sink: - new_edges[0] = h[i][j] + new_edges['sink'] = h[i][j] else: new_edges['y'+str(j)] = h[i][j] k['y'+str(i)] = new_edges @@ -6419,12 +6416,13 @@ def glue_graphs(g, h, glue_g, glue_h): new_edges['x'+str(i)] = glue_g[i] for i in glue_h: if i == h_sink: - new_edges[0] = glue_h[i] + new_edges['sink'] = glue_h[i] else: new_edges['y'+str(i)] = glue_h[i] k['x'+str(g_sink)] = new_edges return k + def firing_graph(S, eff): r""" Creates a digraph with divisors as vertices and edges between two divisors diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index 972d4c8a316..a92c01e5535 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -166,11 +166,11 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): ....: k11 + k20] sage: from sage.sat.boolean_polynomials import solve as solve_sat sage: solve_sat(keqs, n=1, solver=SAT('cryptominisat')) # optional - cryptominisat - [{k28: 1, - k26: 0, + [{k28: 0, + k26: 1, k24: 0, k20: 0, - k19: 1, + k19: 0, k18: 0, k17: 0, k16: 0, @@ -180,16 +180,16 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): k12: 0, k11: 0, k10: 0, - k9: 1, + k9: 0, k8: 0, k7: 0, - k6: 0, + k6: 1, k5: 0, k4: 0, - k3: 0, + k3: 1, k2: 0, k1: 0, - k0: 1}] + k0: 0}] sage: solve_sat(keqs, n=1, solver=SAT('picosat')) # optional - pycosat [{k28: 0, k26: 1, diff --git a/src/sage/sat/solvers/dimacs.py b/src/sage/sat/solvers/dimacs.py index 26b447128a2..21cd6fb577f 100644 --- a/src/sage/sat/solvers/dimacs.py +++ b/src/sage/sat/solvers/dimacs.py @@ -462,10 +462,23 @@ class Glucose(DIMACS): """ An instance of the Glucose solver. - For information on Glucose see: http://www.lri.fr/~simon/?page=glucose + For information on Glucose see: http://www.labri.fr/perso/lsimon/glucose/ + + EXAMPLES:: + + sage: from sage.sat.solvers import Glucose + sage: solver = Glucose() + sage: solver + DIMACS Solver: 'glucose -verb=2 {input} {output}' + sage: solver.add_clause( (1, 2, 3) ) + sage: solver.add_clause( (-1,) ) + sage: solver.add_clause( (-2,) ) + sage: solver() # optional - glucose + (None, False, False, True) + """ - command = "glucose_static -verb=2 {input} {output}" + command = "glucose -verb=2 {input} {output}" def __call__(self, **kwds): """ @@ -486,9 +499,42 @@ def __call__(self, **kwds): EXAMPLES:: - sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: F,s = mq.SR(1,1,1,4,gf2=True,polybori=True).polynomial_system() - sage: solve_sat(F, solver=sage.sat.solvers.Glucose) # optional - Glucose + sage: from sage.sat.boolean_polynomials import solve as solve_sat + sage: F,s = mq.SR(1,1,1,4,gf2=True,polybori=True).polynomial_system() + sage: solve_sat(F, solver=sage.sat.solvers.Glucose) # optional - glucose + [{k003: 1, + k002: 1, + k001: 0, + k000: 1, + s003: 1, + s002: 0, + s001: 1, + s000: 0, + w103: 1, + w102: 1, + w101: 1, + w100: 1, + x103: 0, + x102: 0, + x101: 0, + x100: 1, + k103: 1, + k102: 0, + k101: 1, + k100: 1}] + + :: + + sage: from sage.sat.solvers.dimacs import Glucose + sage: solver = Glucose() + sage: solver.add_clause((1,2)) + sage: solver.add_clause((-1,2)) + sage: solver.add_clause((1,-2)) + sage: solver() # optional - glucose + (None, True, True) + sage: solver.add_clause((-1,-2)) + sage: solver() # optional - glucose + False """ DIMACS.__call__(self) diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index b7499fcae8a..974195b3243 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -327,6 +327,8 @@ def SAT(solver=None, *args, **kwds): - ``"picosat"`` -- note that the pycosat package must be installed. + - ``"glucose"`` -- note that the glucose package must be installed. + - ``"LP"`` -- use :class:`~sage.sat.solvers.sat_lp.SatLP` to solve the SAT instance. @@ -354,6 +356,11 @@ def SAT(solver=None, *args, **kwds): sage: SAT(solver="picosat") # optional - pycosat PicoSAT solver: 0 variables, 0 clauses. + + Forcing Glucose:: + + sage: SAT(solver="glucose") + DIMACS Solver: 'glucose -verb=2 {input} {output}' """ if solver is None: import pkgutil @@ -373,6 +380,9 @@ def SAT(solver=None, *args, **kwds): elif solver == "LP": from .sat_lp import SatLP return SatLP() + elif solver == 'glucose': + from .dimacs import Glucose + return Glucose(*args, **kwds) else: raise ValueError("Solver '{}' is not available".format(solver)) diff --git a/src/sage/schemes/affine/affine_homset.py b/src/sage/schemes/affine/affine_homset.py index 5e2d17193ce..db2cabf9e5f 100644 --- a/src/sage/schemes/affine/affine_homset.py +++ b/src/sage/schemes/affine/affine_homset.py @@ -296,7 +296,7 @@ def points(self, **kwds): if numerical: if len(points[i]) == N: S = AS([points[i][R.gen(j)] for j in range(N)]) - if all([g(list(S)) < zero_tol for g in X.defining_polynomials()]): + if all(g(list(S)) < zero_tol for g in X.defining_polynomials()): rat_points.append(S) else: if len(points[i]) == N and I.subs(points[i]) == I0: @@ -464,7 +464,7 @@ def numerical_points(self, F=None, **kwds): for P in points: if len(P) == N: S = AA([P[R.gen(j)] for j in range(N)]) - if all([g(list(S)) < zero_tol for g in polys]): + if all(g(list(S)) < zero_tol for g in polys): rat_points.append(S) rat_points = sorted(rat_points) diff --git a/src/sage/schemes/affine/affine_rational_point.py b/src/sage/schemes/affine/affine_rational_point.py index 1370639ce8d..a8f6fca351e 100644 --- a/src/sage/schemes/affine/affine_rational_point.py +++ b/src/sage/schemes/affine/affine_rational_point.py @@ -109,13 +109,12 @@ def enum_affine_rational_field(X, B): - Raman Raghukul 2018: updated. """ from sage.schemes.affine.affine_space import is_AffineSpace - if(is_Scheme(X)): - if (not is_AffineSpace(X.ambient_space())): + if is_Scheme(X): + if not is_AffineSpace(X.ambient_space()): raise TypeError("ambient space must be affine space over the rational field") X = X(X.base_ring()) - else: - if (not is_AffineSpace(X.codomain().ambient_space())): - raise TypeError("codomain must be affine space over the rational field") + elif not is_AffineSpace(X.codomain().ambient_space()): + raise TypeError("codomain must be affine space over the rational field") n = X.codomain().ambient_space().ngens() VR = X.value_ring() @@ -214,13 +213,12 @@ def enum_affine_number_field(X, **kwds): tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) from sage.schemes.affine.affine_space import is_AffineSpace - if(is_Scheme(X)): - if (not is_AffineSpace(X.ambient_space())): + if is_Scheme(X): + if not is_AffineSpace(X.ambient_space()): raise TypeError("ambient space must be affine space over a number field") X = X(X.base_ring()) - else: - if (not is_AffineSpace(X.codomain().ambient_space())): - raise TypeError("codomain must be affine space over a number field") + elif not is_AffineSpace(X.codomain().ambient_space()): + raise TypeError("codomain must be affine space over a number field") R = X.codomain().ambient_space() @@ -289,13 +287,12 @@ def enum_affine_finite_field(X): - John Cremona and Charlie Turner (06-2010) """ from sage.schemes.affine.affine_space import is_AffineSpace - if(is_Scheme(X)): - if (not is_AffineSpace(X.ambient_space())): + if is_Scheme(X): + if not is_AffineSpace(X.ambient_space()): raise TypeError("ambient space must be affine space over a finite field") X = X(X.base_ring()) - else: - if (not is_AffineSpace(X.codomain().ambient_space())): - raise TypeError("codomain must be affine space over a finite field") + elif not is_AffineSpace(X.codomain().ambient_space()): + raise TypeError("codomain must be affine space over a finite field") n = X.codomain().ambient_space().ngens() F = X.value_ring() diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index e3e098e4a97..2a6e32a7eae 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -443,7 +443,7 @@ def _latex_generic_point(self, v=None): sage: A. = AffineSpace(2, ZZ) sage: A._latex_generic_point([y-x^2]) - '\\left(- x^{2} + y\\right)' + '\\left(-x^{2} + y\\right)' sage: A._latex_generic_point() '\\left(x, y\\right)' """ diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 4e683c482d3..fc5ac92937a 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -26,21 +26,20 @@ - Grayson Jorgenson (2016-8) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from __future__ import absolute_import from sage.arith.misc import binomial from sage.categories.fields import Fields from sage.categories.finite_fields import FiniteFields -from copy import copy from sage.categories.homset import Hom, End from sage.categories.number_fields import NumberFields from sage.interfaces.all import singular @@ -59,12 +58,9 @@ from . import point from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine - -from sage.schemes.affine.affine_space import AffineSpace, is_AffineSpace -from sage.schemes.projective.projective_space import ProjectiveSpace - from .curve import Curve_generic + class AffineCurve(Curve_generic, AlgebraicScheme_subscheme_affine): _point = point.AffineCurvePoint_field @@ -102,11 +98,11 @@ def __init__(self, A, X): Affine Curve over Finite Field of size 7 defined by x^2 - z, -x + z """ if not is_AffineSpace(A): - raise TypeError("A (=%s) must be an affine space"%A) + raise TypeError("A (=%s) must be an affine space" % A) Curve_generic.__init__(self, A, X) d = self.dimension() if d != 1: - raise ValueError("defining equations (=%s) define a scheme of dimension %s != 1"%(X,d)) + raise ValueError("defining equations (=%s) define a scheme of dimension %s != 1" % (X, d)) def projective_closure(self, i=0, PP=None): r""" @@ -282,14 +278,14 @@ def projection(self, indices, AS=None): if self.base_ring() not in Fields(): raise TypeError("this curve must be defined over a field") if len(indices) < 2 or len(indices) >= n: - raise ValueError("(=%s) must be a list or tuple of length between 2 and (=%s), inclusive"%(indices,n - 1)) + raise ValueError("(=%s) must be a list or tuple of length between 2 and (=%s), inclusive" % (indices, n - 1)) if len(set(indices)) < len(indices): - raise ValueError("(=%s) must be a list or tuple of distinct indices or variables"%indices) + raise ValueError("(=%s) must be a list or tuple of distinct indices or variables" % indices) if not AS is None: if not is_AffineSpace(AS): - raise TypeError("(=%s) must be an affine space"%AS) + raise TypeError("(=%s) must be an affine space" % AS) if AS.dimension_relative() != len(indices): - raise TypeError("(=%s) must have dimension (=%s)"%(AS, len(indices))) + raise TypeError("(=%s) must have dimension (=%s)" % (AS, len(indices))) if AS.base_ring() != AA.base_ring(): raise TypeError("(=%s) must be defined over the same base field as this curve" % AS) indices = list(indices) @@ -570,7 +566,7 @@ def blowup(self, P=None): try: self(P) except TypeError: - raise TypeError("(=%s) must be a point on this curve"%P) + raise TypeError("(=%s) must be a point on this curve" % P) if not self.base_ring() in Fields(): raise TypeError("the base ring of this curve must be a field") if not self.is_irreducible(): @@ -955,7 +951,7 @@ def __init__(self, A, f): by x^2 + y^2 """ if not (is_AffineSpace(A) and A.dimension != 2): - raise TypeError("Argument A (= %s) must be an affine plane."%A) + raise TypeError("Argument A (= %s) must be an affine plane." % A) Curve_generic.__init__(self, A, [f]) def _repr_type(self): @@ -1004,21 +1000,20 @@ def divisor_of_function(self, r): F = self.base_ring() f = self.defining_polynomial() pts = self.places_on_curve() - numpts = len(pts) R = f.parent() - x,y = R.gens() - R0 = PolynomialRing(F,3,names = [str(x),str(y),"t"]) + x, y = R.gens() + R0 = PolynomialRing(F, 3, names=[str(x), str(y), "t"]) vars0 = R0.gens() t = vars0[2] divf = [] for pt0 in pts: if pt0[2] != F(0): - lcs = self.local_coordinates(pt0,5) + lcs = self.local_coordinates(pt0, 5) yt = lcs[1] xt = lcs[0] - ldg = degree_lowest_rational_function(r(xt,yt),t) + ldg = degree_lowest_rational_function(r(xt, yt), t) if ldg[0] != 0: - divf.append([ldg[0],pt0]) + divf.append([ldg[0], pt0]) return divf def local_coordinates(self, pt, n): @@ -1068,9 +1063,9 @@ def local_coordinates(self, pt, n): S = singular S.eval('ring s = '+str(p)+','+str(R0.gens())+',lp;') S.eval('poly f = '+str(ft) + ';') - c = S('coeffs(%s, t)'%ft) + c = S('coeffs(%s, t)' % ft) N = int(c.size()) - b = ["%s[%s,1],"%(c.name(), i) for i in range(2,N//2-4)] + b = ["%s[%s,1]," % (c.name(), i) for i in range(2,N//2-4)] b = ''.join(b) b = b[:len(b)-1] # to cut off the trailing comma cmd = 'ideal I = '+b @@ -1187,7 +1182,7 @@ def is_transverse(self, C, P): True """ if not self.intersects_at(C, P): - raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve"%(P,C)) + raise TypeError("(=%s) must be a point in the intersection of (=%s) and this curve" % (P, C)) if self.is_singular(P) or C.is_singular(P): return False @@ -1252,7 +1247,7 @@ def multiplicity(self, P): try: P = self(P) except TypeError: - raise TypeError("(=%s) is not a point on (=%s)"%(P,self)) + raise TypeError("(=%s) is not a point on (=%s)" % (P, self)) # Apply a linear change of coordinates to self so that P becomes (0,0) AA = self.ambient_space() @@ -1412,7 +1407,7 @@ def is_ordinary_singularity(self, P): """ r = self.multiplicity(P) if r < 2: - raise TypeError("(=%s) is not a singular point of (=%s)"%(P,self)) + raise TypeError("(=%s) is not a singular point of (=%s)" % (P,self)) T = self.tangents(P, factor=False)[0] vars = self.ambient_space().gens() @@ -1612,36 +1607,22 @@ def riemann_roch_basis(self, D): sage: C = Curve(f) sage: D = [6,0,0,0,0,0] sage: C.riemann_roch_basis(D) - [1, (y^2*z^4 - x*z^5)/x^6, (y^2*z^5 - x*z^6)/x^7, (y^2*z^6 - x*z^7)/x^8] + [1, (-x*z^5 + y^2*z^4)/x^6, (-x*z^6 + y^2*z^5)/x^7, (-x*z^7 + y^2*z^6)/x^8] """ f = self.defining_polynomial() - R = f.parent() - F = self.base_ring() - p = F.characteristic() - Dstr = str(tuple(D)) - G = singular(','.join([str(x) for x in D]), type='intvec') - - singular.LIB('brnoeth.lib') + gens = f.parent().gens() + p = self.base_ring().characteristic() + G = singular(','.join(str(x) for x in D), type='intvec') - S = singular.ring(p, R.gens(), 'lp') - fsing = singular(str(f)) + singular.lib('brnoeth') + singular.ring(p, gens, 'lp') - X = fsing.Adj_div() + X = singular(f).Adj_div() P = singular.NSplaces(1, X) T = P[1][2] - T.set_ring() - - LG = G.BrillNoether(P) - - dim = len(LG) - basis = [(LG[i][1], LG[i][2]) for i in range(1,dim+1)] - x, y, z = PolynomialRing(F, 3, names = ["x","y","z"]).gens() - V = [] - for g in basis: - T.set_ring() # necessary... - V.append(eval(g[0].sage_polystring())/eval(g[1].sage_polystring())) - return V + T.set_ring() # necessary + return [g[1].sage() / g[2].sage() for g in G.BrillNoether(P)] def rational_points(self, algorithm="enum"): r""" @@ -1711,18 +1692,18 @@ def rational_points(self, algorithm="enum"): # with the expect interface could crop up. Also, this is vastly # faster (and more robust). v = singular('POINTS').sage_flattened_str_list() - pnts = [self(int(v[3*i]), int(v[3*i+1])) for i in range(len(v)//3) if int(v[3*i+2])!=0] + pnts = [self(int(v[3*i]), int(v[3*i+1])) + for i in range(len(v)//3) if int(v[3*i+2])] # remove multiple points - pnts = sorted(set(pnts)) - return pnts + return sorted(set(pnts)) elif algorithm == "all": S_enum = self.rational_points(algorithm = "enum") S_bn = self.rational_points(algorithm = "bn") if S_enum != S_bn: - raise RuntimeError("Bug in rational_points -- different algorithms give different answers for curve %s!"%self) + raise RuntimeError("Bug in rational_points -- different algorithms give different answers for curve %s!" % self) return S_enum else: - raise ValueError("No algorithm '%s' known"%algorithm) + raise ValueError("No algorithm '%s' known" % algorithm) diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 36fb6a3e12f..c6f5403aeb2 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -67,13 +67,13 @@ def _latex_(self): sage: x,y,z = PolynomialRing(QQ, 3, names='x,y,z').gens() sage: C = Curve(y^2*z - x^3 - 17*x*z^2 + y*z^2) sage: latex(C) - - x^{3} + y^{2} z - 17 x z^{2} + y z^{2} + -x^{3} + y^{2} z - 17 x z^{2} + y z^{2} sage: A2 = AffineSpace(2, QQ, names=['x','y']) sage: x, y = A2.coordinate_ring().gens() sage: C = Curve(y^2 - x^3 - 17*x + y) sage: latex(C) - - x^{3} + y^{2} - 17 x + y + -x^{3} + y^{2} - 17 x + y """ return latex(self.defining_polynomial()) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 7f67ac1a0dd..35f67b8ab16 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1316,7 +1316,7 @@ def ordinary_model(self): -1/64*x^4 + 3/64*x^2*y^2 - 1/32*x*y^3 + 1/16*x*y^2*z - 1/16*y^3*z + 1/16*y^2*z^2 : 3/64*x^4 - 3/32*x^3*y + 3/64*x^2*y^2 + 1/16*x^3*z - 3/16*x^2*y*z + 1/8*x*y^2*z - 1/8*x*y*z^2 + 1/16*y^2*z^2) - sage: all([D.codomain().is_ordinary_singularity(Q) for Q in D.codomain().singular_points()]) # long time + sage: all(D.codomain().is_ordinary_singularity(Q) for Q in D.codomain().singular_points()) # long time True :: diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index aa8d757a3ea..2fb1cd10069 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -49,7 +49,7 @@ 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, CIF +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 diff --git a/src/sage/schemes/elliptic_curves/cardinality.py b/src/sage/schemes/elliptic_curves/cardinality.py index 3da5295ea48..5e6ee6364b0 100644 --- a/src/sage/schemes/elliptic_curves/cardinality.py +++ b/src/sage/schemes/elliptic_curves/cardinality.py @@ -61,8 +61,8 @@ def _cardinality_with_j_invariant_1728(self): sage: F. = GF(2**15,'a') sage: ais = [[0,0,1,0,0],[0,0,1,1,0],[0,0,1,1,1]] - sage: curves=[EllipticCurve(F,ai) for ai in ais] - sage: all([all([e1==e2 or not e1.is_isomorphic(e2) for e1 in curves]) for e2 in curves]) + sage: curves = [EllipticCurve(F,ai) for ai in ais] + sage: all((e1 == e2 or not e1.is_isomorphic(e2)) for e1 in curves for e2 in curves) True sage: [_cardinality_with_j_invariant_1728(e) for e in curves] [32769, 33025, 32513] @@ -72,8 +72,8 @@ def _cardinality_with_j_invariant_1728(self): sage: F. = GF(2**16,'a') sage: b = a^11 # trace 1 sage: ais = [[0,0,1,0,0],[0,0,1,0,b],[0,0,1,b,0],[0,0,a,0,0],[0,0,a,0,a^2*b],[0,0,a^2,0,0],[0,0,a^2,0,a^4*b]] - sage: curves=[EllipticCurve(F,ai) for ai in ais] - sage: all([all([e1==e2 or not e1.is_isomorphic(e2) for e1 in curves]) for e2 in curves]) + sage: curves = [EllipticCurve(F,ai) for ai in ais] + sage: all((e1 == e2 or not e1.is_isomorphic(e2)) for e1 in curves for e2 in curves) True sage: [_cardinality_with_j_invariant_1728(e) for e in curves] [65025, 66049, 65537, 65793, 65281, 65793, 65281] @@ -81,10 +81,10 @@ def _cardinality_with_j_invariant_1728(self): Examples with `q=3^d`, d odd (4 isomorphism classes):: sage: F. = GF(3**15,'a') - sage: b=a^7 # has trace 1 - sage: ais=[[0,0,0,1,0],[0,0,0,-1,0],[0,0,0,-1,b],[0,0,0,-1,-b]] - sage: curves=[EllipticCurve(F,ai) for ai in ais] - sage: all([all([e1==e2 or not e1.is_isomorphic(e2) for e1 in curves]) for e2 in curves]) + sage: b = a^7 # has trace 1 + sage: ais = [[0,0,0,1,0],[0,0,0,-1,0],[0,0,0,-1,b],[0,0,0,-1,-b]] + sage: curves = [EllipticCurve(F,ai) for ai in ais] + sage: all((e1 == e2 or not e1.is_isomorphic(e2)) for e1 in curves for e2 in curves) True sage: [_cardinality_with_j_invariant_1728(e) for e in curves] [14348908, 14348908, 14342347, 14355469] @@ -96,7 +96,7 @@ def _cardinality_with_j_invariant_1728(self): sage: a=g^8 # has trace 1 sage: ais= [[0,0,0,1,0],[0,0,0,1,i*a],[0,0,0,g,0],[0,0,0,g^3,0],[0,0,0,g^2,0], [0,0,0,g^2,i*a*g^3]] sage: curves=[EllipticCurve(F,ai) for ai in ais] - sage: all([all([e1==e2 or not e1.is_isomorphic(e2) for e1 in curves]) for e2 in curves]) + sage: all((e1 == e2 or not e1.is_isomorphic(e2)) for e1 in curves for e2 in curves) True sage: [_cardinality_with_j_invariant_1728(e) for e in curves] [387459856, 387400807, 387420490, 387420490, 387381124, 387440173] diff --git a/src/sage/schemes/elliptic_curves/cm.py b/src/sage/schemes/elliptic_curves/cm.py index 7b9e98169a8..e66c819b595 100644 --- a/src/sage/schemes/elliptic_curves/cm.py +++ b/src/sage/schemes/elliptic_curves/cm.py @@ -97,11 +97,10 @@ def hilbert_class_polynomial(D, algorithm=None): TESTS:: - sage: all([hilbert_class_polynomial(d, algorithm="arb") == \ - ....: hilbert_class_polynomial(d, algorithm="sage") \ - ....: for d in range(-1,-100,-1) if d%4 in [0,1]]) + sage: all(hilbert_class_polynomial(d, algorithm="arb") == + ....: hilbert_class_polynomial(d, algorithm="sage") + ....: for d in range(-1,-100,-1) if d % 4 in [0, 1]) True - """ if algorithm is None: algorithm = "arb" @@ -617,9 +616,8 @@ def is_cm_j_invariant(j, method='new'): TESTS:: sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant - sage: all([is_cm_j_invariant(j) == (True, (d,f)) for d,f,j in cm_j_invariants_and_orders(QQ)]) + sage: all(is_cm_j_invariant(j) == (True, (d,f)) for d,f,j in cm_j_invariants_and_orders(QQ)) True - """ # First we check that j is an algebraic number: diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx index 25d28f16fb4..e988637c771 100644 --- a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx +++ b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx @@ -50,6 +50,7 @@ cdef unsigned long valuation(mpz_t a, mpz_t p): mpz_clear(aa) return v + def test_valuation(a, p): """ Doctest function for cdef long valuation(mpz_t, mpz_t). @@ -58,7 +59,7 @@ def test_valuation(a, p): sage: from sage.schemes.elliptic_curves.descent_two_isogeny import test_valuation as tv sage: for i in [1..20]: - ....: print('{:>10} {} {} {}'.format(factor(i), tv(i,2), tv(i,3), tv(i,5))) + ....: print('{:>10} {} {} {}'.format(str(factor(i)), tv(i,2), tv(i,3), tv(i,5))) 1 0 0 0 2 1 0 0 3 0 1 0 @@ -85,6 +86,7 @@ def test_valuation(a, p): cdef Integer P = Integer(p) return valuation(A.value, P.value) + cdef int padic_square(mpz_t a, mpz_t p): """ Test if a is a p-adic square. diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 1ea26451d36..a122572ac0c 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -56,13 +56,13 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Daniel Shumow # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** -from __future__ import print_function +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import print_function, absolute_import from six import itervalues from six.moves import range @@ -1003,7 +1003,7 @@ def __init__(self, E, kernel, codomain=None, degree=None, model=None, check=True if (degree is None): raise ValueError("If specifying isogeny by domain and codomain, degree parameter must be set.") - # save the domain/codomain: really used now (trac #7096) + # save the codomain: really used now (trac #7096) old_codomain = codomain (pre_isom, post_isom, E, codomain, kernel) = compute_sequence_of_maps(E, codomain, degree) @@ -1105,19 +1105,19 @@ def _call_(self, P): TypeError: (20 : 90 : 1) fails to convert into the map's domain Elliptic Curve defined by y^2 = x^3 + 7*x over Number Field in th with defining polynomial x^2 + 3, but a `pushforward` method is not properly implemented """ - if(P.is_zero()): + if P.is_zero(): return self.__E2(0) (xP, yP) = P.xy() # if there is a pre isomorphism, apply it - if (self.__pre_isomorphism is not None): + if self.__pre_isomorphism is not None: temp_xP = self.__prei_x_coord_ratl_map(xP) temp_yP = self.__prei_y_coord_ratl_map(xP, yP) (xP, yP) = (temp_xP, temp_yP) - if ("velu" == self.__algorithm): + if "velu" == self.__algorithm: outP = self.__compute_via_velu_numeric(xP, yP) - elif ("kohel" == self.__algorithm): + elif "kohel" == self.__algorithm: outP = self.__compute_via_kohel_numeric(xP,yP) # the intermediate functions return the point at infinity @@ -1664,7 +1664,7 @@ def __init_kernel_polynomial(self): if ("velu" == self.__algorithm): ker_poly_list = self.__init_kernel_polynomial_velu() else: - raise RuntimeError("The kernel polynomial should already be defined!") + raise ValueError("The kernel polynomial should already be defined!") return ker_poly_list @@ -2324,7 +2324,7 @@ def __init_even_kernel_polynomial(self, E, psi_G): """ #check if the polynomial really divides the two_torsion_polynomial if self.__check and E.division_polynomial(2, x=self.__poly_ring.gen()) % psi_G != 0 : - raise ValueError("The polynomial does not define a finite subgroup of the elliptic curve.") + raise ValueError("The polynomial {} does not define a finite subgroup of {}.".format(psi_G,E)) n = psi_G.degree() # 1 or 3 d = n+1 # 2 or 4 @@ -2434,7 +2434,7 @@ def __init_odd_kernel_polynomial(self, E, psi): sage: f = (E.isogenies_prime_degree()[0]).kernel_polynomial() sage: f.degree() 81 - sage: E.isogeny(kernel=f) # long time (3.6s, 2014) + sage: E.isogeny(kernel=f, check=False) Isogeny of degree 163 from Elliptic Curve defined by y^2 + y = x^3 - 2174420*x + 1234136692 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field """ n = psi.degree() @@ -2442,9 +2442,9 @@ def __init_odd_kernel_polynomial(self, E, psi): # check if the polynomial really divides the torsion polynomial : if self.__check: - alpha = psi.parent().quotient(psi).gen() - if not E.division_polynomial(d, x=alpha).is_zero(): - raise ValueError("The polynomial does not define a finite subgroup of the elliptic curve.") + from .isogeny_small_degree import is_kernel_polynomial + if not is_kernel_polynomial(E, d, psi): + raise ValueError("The polynomial {} does not define a finite subgroup of {}.".format(psi,E)) b2, b4, b6, _ = E.b_invariants() @@ -2661,10 +2661,10 @@ def __compute_via_kohel_numeric(self, xP, yP): """ # first check if this point is in the kernel: - if(0 == self.__inner_kernel_polynomial(x=xP)): + if 0 == self.__inner_kernel_polynomial(x=xP): return self.__intermediate_codomain(0) - (xP_out, yP_out) = self.__compute_via_kohel(xP,yP) + (xP_out, yP_out) = self.__compute_via_kohel(xP, yP) # xP_out and yP_out do not always get evaluated to field # elements but rather constant polynomials, so we do some diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 43be89ebcb6..52395a95519 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -646,7 +646,7 @@ def descend_to(self, K, f=None): sage: E = EllipticCurve(j=1728*b).change_ring(G) sage: EF = E.descend_to(F); EF [Elliptic Curve defined by y^2 = x^3 + (27*b-621)*x + (-1296*b+2484) over Number Field in b with defining polynomial x^2 - 23] - sage: all([Ei.change_ring(G).is_isomorphic(E) for Ei in EF]) + sage: all(Ei.change_ring(G).is_isomorphic(E) for Ei in EF) True :: @@ -657,7 +657,7 @@ def descend_to(self, K, f=None): sage: EK = E.descend_to(K); EK [Elliptic Curve defined by y^2 = x^3 + b*x over Number Field in b with defining polynomial x^2 - 7, Elliptic Curve defined by y^2 = x^3 + 7*b*x over Number Field in b with defining polynomial x^2 - 7] - sage: all([Ei.change_ring(L).is_isomorphic(E) for Ei in EK]) + sage: all(Ei.change_ring(L).is_isomorphic(E) for Ei in EK) True :: @@ -723,7 +723,7 @@ def descend_to(self, K, f=None): if f.codomain() != L: raise ValueError("embedding has wrong codomain") except AttributeError: - raise ValueError("invalid embedding: %s" % f) + raise ValueError("invalid embedding: {}".format(f)) try: jK = f.preimage(j) except Exception: @@ -791,10 +791,12 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True): - ``E`` - an elliptic curve, the domain of the isogeny to initialize. - - ``kernel`` - a kernel, either a point in ``E``, a list of points - in ``E``, a univariate kernel polynomial or ``None``. - If initiating from a domain/codomain, this must be - set to None. Validity of input is *not* fully checked. + - ``kernel`` - a kernel, either a point in ``E``, a list of + points in ``E``, a univariate kernel + polynomial or ``None``. If initiating from + a domain/codomain, this must be set to None. + Validity of input is checked (unless + check=False). - ``codomain`` - an elliptic curve (default:None). If ``kernel`` is None, then this must be the codomain of a separable @@ -819,12 +821,10 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True): number field, then the codomain is a global minimum model where this exists. - - ``check`` (default: True) does some partial checks that the - input is valid (e.g., that the points - defined by the kernel polynomial are - torsion); however, invalid input can in some - cases still pass, since that the points define - a group is not checked. + - ``check`` (default: True) checks that the input is valid, + i.e., that the polynomial provided is a + kernel polynomial, meaning that its roots + are the x-coordinates of a finite subgroup. OUTPUT: @@ -859,21 +859,20 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True): sage: phi = E.isogeny([14,27,4,1]) Traceback (most recent call last): ... - ValueError: The polynomial does not define a finite subgroup of the elliptic curve. + ValueError: The polynomial x^3 + 4*x^2 + 27*x + 14 does not define a finite subgroup of Elliptic Curve defined by y^2 + x*y = x^3 + x + 2 over Finite Field of size 31. - An example in which we construct an invalid morphism, which - illustrates that the check for correctness of the input is not - sufficient. (See :trac:`11578`.):: + Until the checking of kernel polynomials was implemented in + :trac:`23222`, the following raised no error but returned an + invalid morphism. See also :trac:`11578`:: sage: R. = QQ[] sage: K. = NumberField(x^2-x-1) sage: E = EllipticCurve(K, [-13392, -1080432]) sage: R. = K[] sage: phi = E.isogeny( (x-564)*(x - 396/5*a + 348/5) ) - sage: phi.codomain().conductor().norm().factor() - 5^2 * 11^2 * 3271 * 15806939 * 4169267639351 - sage: phi.domain().conductor().norm().factor() - 11^2 + Traceback (most recent call last): + ... + ValueError: The polynomial x^2 + (-396/5*a - 2472/5)*x + 223344/5*a - 196272/5 does not define a finite subgroup of Elliptic Curve defined by y^2 = x^3 + (-13392)*x + (-1080432) over Number Field in a with defining polynomial x^2 - x - 1. """ try: return EllipticCurveIsogeny(self, kernel, codomain, degree, model, check=check) diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index 55a1b3b0ad1..822baf54b10 100644 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -13,15 +13,15 @@ - Mariah Lenox (2011-03): Added set_order method """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # This 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 __future__ import print_function, absolute_import @@ -1106,9 +1106,8 @@ def abelian_group(self, debug=False): # Finished: record group order, structure and generators from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper - self._order = n1*n2 + self._order = n1 * n2 if n1 == 1: - gens = orders = tuple() return AdditiveAbelianGroupWrapper(self.point_homset(), [], []) elif n2 == 1: gens = (P1,) @@ -1122,7 +1121,7 @@ def abelian_group(self, debug=False): def is_isogenous(self, other, field=None, proof=True): """ - Returns whether or not self is isogenous to other + Return whether or not self is isogenous to other INPUT: diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index a2911823e32..cd2f11922fc 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -33,7 +33,7 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # Copyright (C) 2014 Julian Rueth # @@ -41,8 +41,8 @@ # 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 __future__ import print_function, absolute_import from six import integer_types @@ -172,7 +172,7 @@ def _defining_params_(self): EXAMPLES:: - sage: E=EllipticCurve(QQ,[1,1]) + sage: E = EllipticCurve(QQ,[1,1]) sage: E._defining_params_() (Rational Field, [0, 0, 0, 1, 1]) sage: EllipticCurve(*E._defining_params_()) == E @@ -186,7 +186,7 @@ def _repr_(self): EXAMPLES:: - sage: E=EllipticCurve([1,2,3,4,5]); E._repr_() + sage: E = EllipticCurve([1,2,3,4,5]); E._repr_() 'Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field' :: @@ -281,7 +281,7 @@ def _pari_init_(self): EXAMPLES:: - sage: E=EllipticCurve(QQ,[1,1]) + sage: E = EllipticCurve(QQ,[1,1]) sage: E._pari_init_() 'ellinit([0/1,0/1,0/1,1/1,1/1])' """ @@ -647,15 +647,15 @@ def is_x_coord(self, x): TESTS:: - sage: E=EllipticCurve('5077a1') + sage: E = EllipticCurve('5077a1') sage: [x for x in srange(-10,10) if E.is_x_coord (x)] [-3, -2, -1, 0, 1, 2, 3, 4, 8] :: - sage: F=GF(32,'a') - sage: E=EllipticCurve(F,[1,0,0,0,1]) - sage: set([P[0] for P in E.points() if P!=E(0)]) == set([x for x in F if E.is_x_coord(x)]) + sage: F = GF(32,'a') + sage: E = EllipticCurve(F,[1,0,0,0,1]) + sage: set(P[0] for P in E.points() if P!=E(0)) == set(x for x in F if E.is_x_coord(x)) True """ K = self.base_ring() @@ -907,7 +907,7 @@ def _point_homset(self, *args, **kwds): EXAMPLES:: - sage: E=EllipticCurve(GF(5),[1,1]) + sage: E = EllipticCurve(GF(5),[1,1]) sage: E._point_homset(Spec(GF(5^10,'a'),GF(5)), E) Abelian group of points on Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 5^10 @@ -936,7 +936,7 @@ def __getitem__(self, n): EXAMPLES:: - sage: E=EllipticCurve(QQ,[1,1]) + sage: E = EllipticCurve(QQ,[1,1]) sage: E[2] Traceback (most recent call last): ... @@ -951,10 +951,10 @@ def __is_over_RationalField(self): EXAMPLES:: - sage: E=EllipticCurve(QQ,[1,1]) + sage: E = EllipticCurve(QQ,[1,1]) sage: E._EllipticCurve_generic__is_over_RationalField() True - sage: E=EllipticCurve(GF(5),[1,1]) + sage: E = EllipticCurve(GF(5),[1,1]) sage: E._EllipticCurve_generic__is_over_RationalField() False """ @@ -970,7 +970,7 @@ def is_on_curve(self, x, y): EXAMPLES:: - sage: E=EllipticCurve(QQ,[1,1]) + sage: E = EllipticCurve(QQ,[1,1]) sage: E.is_on_curve(0,1) True sage: E.is_on_curve(1,1) @@ -1321,9 +1321,9 @@ def base_extend(self, R): EXAMPLES:: - sage: E=EllipticCurve(GF(5),[1,1]); E + sage: E = EllipticCurve(GF(5),[1,1]); E Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5 - sage: E1=E.base_extend(GF(125,'a')); E1 + sage: E1 = E.base_extend(GF(125,'a')); E1 Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field in a of size 5^3 """ return constructor.EllipticCurve([R(a) for a in self.a_invariants()]) @@ -1336,10 +1336,10 @@ def change_ring(self, R): EXAMPLES:: - sage: F2=GF(5^2,'a'); a=F2.gen() - sage: F4=GF(5^4,'b'); b=F4.gen() - sage: h=F2.hom([a.charpoly().roots(ring=F4,multiplicities=False)[0]],F4) - sage: E=EllipticCurve(F2,[1,a]); E + sage: F2 = GF(5^2,'a'); a = F2.gen() + sage: F4 = GF(5^4,'b'); b = F4.gen() + sage: h = F2.hom([a.charpoly().roots(ring=F4,multiplicities=False)[0]],F4) + sage: E = EllipticCurve(F2,[1,a]); E Elliptic Curve defined by y^2 = x^3 + x + a over Finite Field in a of size 5^2 sage: E.change_ring(h) Elliptic Curve defined by y^2 = x^3 + x + (4*b^3+4*b^2+4*b+3) over Finite Field in b of size 5^4 @@ -1382,12 +1382,12 @@ def gens(self): EXAMPLES:: sage: R.=QQ[] - sage: E=EllipticCurve([a1,a2,a3,a4,a6]) + sage: E = EllipticCurve([a1,a2,a3,a4,a6]) sage: E.gens() Traceback (most recent call last): ... NotImplementedError: not implemented. - sage: E=EllipticCurve(QQ,[1,1]) + sage: E = EllipticCurve(QQ,[1,1]) sage: E.gens() [(0 : 1 : 1)] """ @@ -1404,7 +1404,7 @@ def gen(self, i): EXAMPLES:: sage: R.=QQ[] - sage: E=EllipticCurve([a1,a2,a3,a4,a6]) + sage: E = EllipticCurve([a1,a2,a3,a4,a6]) sage: E.gen(0) Traceback (most recent call last): ... @@ -1432,7 +1432,7 @@ def rst_transform(self, r, s, t): EXAMPLES:: sage: R.=QQ[] - sage: E=EllipticCurve([1,2,3,4,5]) + sage: E = EllipticCurve([1,2,3,4,5]) sage: E.rst_transform(r,s,t) Elliptic Curve defined by y^2 + (2*s+1)*x*y + (r+2*t+3)*y = x^3 + (-s^2+3*r-s+2)*x^2 + (3*r^2-r*s-2*s*t+4*r-3*s-t+4)*x + (r^3+2*r^2-r*t-t^2+4*r-3*t+5) over Multivariate Polynomial Ring in r, s, t over Rational Field """ @@ -1457,9 +1457,9 @@ def scale_curve(self, u): EXAMPLES:: - sage: K=Frac(PolynomialRing(QQ,'u')) - sage: u=K.gen() - sage: E=EllipticCurve([1,2,3,4,5]) + sage: K = Frac(PolynomialRing(QQ,'u')) + sage: u = K.gen() + sage: E = EllipticCurve([1,2,3,4,5]) sage: E.scale_curve(u) Elliptic Curve defined by y^2 + u*x*y + 3*u^3*y = x^3 + 2*u^2*x^2 + 4*u^4*x + 5*u^6 over Fraction Field of Univariate Polynomial Ring in u over Rational Field """ @@ -1623,8 +1623,8 @@ def division_polynomial_0(self, n, x=None): The roots of the polynomial are the `x`-coordinates of the points `P` such that `mP=0` but `2P\not=0`:: - sage: E=EllipticCurve('14a1') - sage: T=E.torsion_subgroup() + sage: E = EllipticCurve('14a1') + sage: T = E.torsion_subgroup() sage: [n*T.0 for n in range(6)] [(0 : 1 : 0), (9 : 23 : 1), @@ -1632,8 +1632,8 @@ def division_polynomial_0(self, n, x=None): (1 : -1 : 1), (2 : -5 : 1), (9 : -33 : 1)] - sage: pol=E.division_polynomial_0(6) - sage: xlist=pol.roots(multiplicities=False); xlist + sage: pol = E.division_polynomial_0(6) + sage: xlist = pol.roots(multiplicities=False); xlist [9, 2, -1/3, -5] sage: [E.lift_x(x, all=True) for x in xlist] [[(9 : 23 : 1), (9 : -33 : 1)], [(2 : 2 : 1), (2 : -5 : 1)], [], []] @@ -1694,10 +1694,10 @@ def two_division_polynomial(self, x = None): EXAMPLES:: - sage: E=EllipticCurve('5077a1') + sage: E = EllipticCurve('5077a1') sage: E.two_division_polynomial() 4*x^3 - 28*x + 25 - sage: E=EllipticCurve(GF(3^2,'a'),[1,1,1,1,1]) + sage: E = EllipticCurve(GF(3^2,'a'),[1,1,1,1,1]) sage: E.two_division_polynomial() x^3 + 2*x^2 + 2 sage: E.two_division_polynomial().roots() @@ -2294,10 +2294,10 @@ def automorphisms(self, field=None): """ if field is None: return [wm.WeierstrassIsomorphism(self, urst, self) - for urst in wm.isomorphisms(self,self)] - E=self.change_ring(field) + for urst in wm.isomorphisms(self, self)] + E = self.change_ring(field) return [wm.WeierstrassIsomorphism(E, urst, E) - for urst in wm.isomorphisms(E,E)] + for urst in wm.isomorphisms(E, E)] def isomorphisms(self, other, field=None): """ @@ -2329,8 +2329,8 @@ def isomorphisms(self, other, field=None): We can also find isomorphisms defined over extension fields:: - sage: E=EllipticCurve(GF(7),[0,0,0,1,1]) - sage: F=EllipticCurve(GF(7),[0,0,0,1,-1]) + sage: E = EllipticCurve(GF(7),[0,0,0,1,1]) + sage: F = EllipticCurve(GF(7),[0,0,0,1,-1]) sage: E.isomorphisms(F) [] sage: E.isomorphisms(F,GF(49,'a')) @@ -2344,11 +2344,11 @@ def isomorphisms(self, other, field=None): """ if field is None: return [wm.WeierstrassIsomorphism(self, urst, other) - for urst in wm.isomorphisms(self,other)] - E=self.change_ring(field) - F=other.change_ring(field) + for urst in wm.isomorphisms(self, other)] + E = self.change_ring(field) + F = other.change_ring(field) return [wm.WeierstrassIsomorphism(E, urst, F) - for urst in wm.isomorphisms(E,F)] + for urst in wm.isomorphisms(E, F)] def is_isomorphic(self, other, field=None): """ @@ -2385,14 +2385,14 @@ def is_isomorphic(self, other, field=None): elif self.j_invariant() != other.j_invariant(): # easy check return False else: - return wm.isomorphisms(self,other,True) is not None + return wm.isomorphisms(self, other, True) is not None else: - E=self.base_extend(field) - F=other.base_extend(field) + E = self.base_extend(field) + F = other.base_extend(field) if E.j_invariant() != F.j_invariant(): # easy check return False else: - return wm.isomorphisms(E,other,F) is not None + return wm.isomorphisms(E, other, F) is not None def change_weierstrass_model(self, *urst): r""" @@ -2486,28 +2486,28 @@ def short_weierstrass_model(self, complete_cube=True): # in characteristic 3 we can complete the square but we can only complete the cube if b2 is 0 if K.characteristic() == 3: - b2,b4,b6,_ = self.b_invariants() + b2, b4, b6,_ = self.b_invariants() if complete_cube and b2 != 0: - raise ValueError("short_weierstrass_model(): no short model for %s (characteristic is %s)"%(self,K.characteristic())) + raise ValueError("short_weierstrass_model(): no short model for %s (characteristic is %s)" % (self,K.characteristic())) else: return constructor.EllipticCurve([0,b2,0,8*b4,16*b6]) a1,a2,a3,_,_ = self.a_invariants() if complete_cube: - if a1==0 and a2==0 and a3==0: + if a1 == 0 and a2 == 0 and a3 == 0: return self else: - b2,b4,b6,_ = self.b_invariants() - if b2==0: + b2, b4, b6, _ = self.b_invariants() + if b2 == 0: return constructor.EllipticCurve([0,0,0,8*b4,16*b6]) else: c4, c6 = self.c_invariants() return constructor.EllipticCurve([0,0,0,-27*c4, -54*c6]) else: - if a1==0 and a3==0: + if a1 == 0 and a3 == 0: return self else: - b2,b4,b6,_ = self.b_invariants() + b2, b4, b6, _ = self.b_invariants() return constructor.EllipticCurve([0,b2,0,8*b4,16*b6]) @@ -2652,8 +2652,9 @@ def plot(self, xmin=None, xmax=None, components='both', **args): # y' = 0 ==> y = (3*x^2 + 2*a2*x + a4) / a1 y = (3*x**2 + 2*a2*x + a4) / a1 Ederiv = y**2 + a1*x*y + a3*y - (x**3 + a2*x**2 + a4*x + a6) - critx = [a for a in Ederiv.roots(RR, multiplicities=False) if r[0] < a < r[1]] - if len(critx) == 0: + critx = [a for a in Ederiv.roots(RR, multiplicities=False) + if r[0] < a < r[1]] + if not critx: raise RuntimeError("No horizontal tangent lines on bounded component") # The 2.5 here is an aesthetic choice ymax = 2.5 * max([f1(a) for a in critx]) @@ -2797,41 +2798,40 @@ def _p_primary_torsion_basis(self,p,m=None): # First find the p-torsion: Ep = self(0).division_points(p) p_rank = rings.Integer(len(Ep)).exact_log(p) - assert p_rank in [0,1,2] + assert p_rank in [0, 1, 2] if p_rank == 0: return [] - assert p_rank in [1,2] - if p_rank == 1: P = Ep[0] - if P.is_zero(): P=Ep[1] + if P.is_zero(): + P = Ep[1] k = 1 - if m==1: - return [[P,k]] + if m == 1: + return [[P, k]] pts = P.division_points(p) # length 0 or p - while len(pts)>0: + while pts: k += 1 P = pts[0] - if m<=k: - return [[P,k]] + if m <= k: + return [[P, k]] pts = P.division_points(p) # now P generates the p-power-torsion and has order p^k - return [[P,k]] - - assert p_rank == 2 + return [[P, k]] Epi = iter(Ep) # used to iterate through Ep # Find P1,P2 which generate the p-torsion: P1 = next(Epi) - while P1.is_zero(): P1 = next(Epi) + while P1.is_zero(): + P1 = next(Epi) P2 = next(Epi) - while generic.linear_relation(P1,P2,'+')[0] != 0: P2 = next(Epi) + while generic.linear_relation(P1, P2, '+')[0] != 0: + P2 = next(Epi) k = 1 log_order = 2 - if m<=log_order: + if m <= log_order: return [[P1,1],[P2,1]] pts1 = P1.division_points(p) @@ -2856,21 +2856,21 @@ def _p_primary_torsion_basis(self,p,m=None): # solutions Q to p*Q=P1. If no combination can be divided, # then the structure is (p^k,p^k) and we can stop. - if len(pts1) > 0: + if pts1: pts = pts1 - elif len(pts2) > 0: + elif pts2: P1, P2 = P2, P1 pts = pts2 else: - for Q in generic.multiples(P2,p-1,P1+P2,operation='+'): + for Q in generic.multiples(P2, p-1, P1 + P2, operation='+'): # Q runs through P1+a*P2 for a=1,2,...,p-1 pts = Q.division_points(p) - if len(pts) > 0: + if pts: P1 = Q break - if len(pts)==0: - return [[P1,k],[P2,k]] + if not pts: + return [[P1, k], [P2, k]] # Now the structure is (p^n,p^k) for some n>k. We need to # replace P1 by an element of maximal order p^n. So far we @@ -2884,27 +2884,26 @@ def _p_primary_torsion_basis(self,p,m=None): # If all fail, the structure is (p^n,p^k) and P1,P2 are # generators. - n=k + n = k while True: - P1=pts[0] + P1 = pts[0] n += 1 log_order += 1 - if m<=log_order: - return [[P1,n],[P2,k]] + if m <= log_order: + return [[P1, n], [P2, k]] pts = P1.division_points(p) - if len(pts)==0: + if not pts: for Q in generic.multiples(P2,p-1,P1+P2,operation='+'): # Q runs through P1+a*P2 for a=1,2,...,p-1 pts = Q.division_points(p) - if len(pts)>0: + if pts: break - if len(pts)==0: - return [[P1,n],[P2,k]] - + if not pts: + return [[P1, n], [P2, k]] def hyperelliptic_polynomials(self): r""" - Returns a pair of polynomials `g(x)`, `h(x)` such that this elliptic + Return a pair of polynomials `g(x)`, `h(x)` such that this elliptic curve can be defined by the standard hyperelliptic equation .. MATH:: @@ -2914,7 +2913,7 @@ def hyperelliptic_polynomials(self): EXAMPLES:: sage: R.=QQ[] - sage: E=EllipticCurve([a1,a2,a3,a4,a6]) + sage: E = EllipticCurve([a1,a2,a3,a4,a6]) sage: E.hyperelliptic_polynomials() (x^3 + a2*x^2 + a4*x + a6, a1*x + a3) """ diff --git a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py index 5c44a2b46c6..8952fc912d3 100644 --- a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py +++ b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py @@ -95,7 +95,6 @@ from sage.structure.sage_object import SageObject from sage.modular.modsym.all import ModularSymbols -from sage.libs.eclib.newforms import ECModularSymbol from sage.databases.cremona import parse_cremona_label from sage.arith.all import next_prime, kronecker_symbol, prime_divisors, valuation @@ -304,6 +303,8 @@ def __init__(self, E, sign): sage: m(0) 1/5 """ + from sage.libs.eclib.newforms import ECModularSymbol + if not sign in [-1,1]: raise TypeError('sign must -1 or 1') self._sign = ZZ(sign) @@ -399,7 +400,7 @@ def __init__(self, E, sign, normalize="L_ratio"): sage: M(1/3) 1 sage: M._scaling - -1 + 1 sage: M = EllipticCurve('121d1').modular_symbol(implementation="sage") sage: M(0) @@ -468,7 +469,7 @@ def _find_scaling_L_ratio(self): 1/25 sage: m = EllipticCurve('37a1').modular_symbol(implementation="sage") sage: m._scaling - 1 + -1 sage: m = EllipticCurve('37a1').modular_symbol() sage: m._scaling 1 @@ -477,10 +478,10 @@ def _find_scaling_L_ratio(self): 1 sage: m = EllipticCurve('389a1').modular_symbol(implementation="sage") sage: m._scaling - 2 + 1 sage: m = EllipticCurve('196a1').modular_symbol(implementation="sage") sage: m._scaling - 1/2 + 1 Some harder cases fail:: @@ -625,15 +626,15 @@ def _find_scaling_period(self): sage: E = EllipticCurve('11a1') sage: m = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,+1,normalize='period') sage: m._e - (1/5, 1) + (1/5, 1/2) sage: E = EllipticCurve('11a2') sage: m = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,+1,normalize='period') sage: m._e - (1, 5) + (1, 5/2) sage: E = EllipticCurve('121b2') sage: m = sage.schemes.elliptic_curves.ell_modular_symbols.ModularSymbolSage(E,+1,normalize='period') sage: m._e - (0, 11/2, 0, 11/2, 11/2, 0, 0, -3, 2, 1/2, -1, 3/2) + (0, 0, 0, 11/2, 11/2, 11/2, 11/2, -3, 3/2, 1/2, -1, 2) TESTS:: diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 731523d69d7..0520bf6aaa3 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -3834,6 +3834,14 @@ def saturation(self, points, verbose=False, ([(-3/4 : -15/8 : 1), (159965/16129 : -67536260/2048383 : 1)], 45, 0.152460177943144) + + See :trac:`27387`:: + + sage: K. = NumberField(x^2-x-26) + sage: E = EllipticCurve([a,1-a,0,93-16*a, 3150-560*a]) + sage: P = E([65-35*a/3, (959*a-5377)/9]) + sage: E.saturation([P],one_prime=2) + ([(-1/4*a + 3/4 : 59/8*a - 317/8 : 1)], 2, 0.344624259712631) """ full_saturation = (max_prime == 0) and (one_prime == 0) Plist = [self(P) for P in points] diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index df494acd9f3..74546ac7966 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -129,7 +129,6 @@ from sage.rings.real_mpfr import is_RealField from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper import sage.groups.generic as generic from sage.libs.pari import pari from cypari2.pari_instance import prec_words_to_bits @@ -142,7 +141,6 @@ from sage.schemes.generic.morphism import is_SchemeMorphism from .constructor import EllipticCurve -from sage.misc.superseded import deprecated_function_alias oo = rings.infinity # infinity @@ -2881,8 +2879,6 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): h *= 2 return h - archimedian_local_height = deprecated_function_alias(13951, archimedean_local_height) - def non_archimedean_local_height(self, v=None, prec=None, weighted=False, is_minimal=None): """ @@ -3067,12 +3063,10 @@ def non_archimedean_local_height(self, v=None, prec=None, r = r / (v.ramification_index() * v.residue_class_degree()) return r * log(Nv) - nonarchimedian_local_height = deprecated_function_alias(13951, non_archimedean_local_height) - def elliptic_logarithm(self, embedding=None, precision=100, algorithm='pari'): r""" - Returns the elliptic logarithm of this elliptic curve point. + Return the elliptic logarithm of this elliptic curve point. An embedding of the base field into `\RR` or `\CC` (with arbitrary precision) may be given; otherwise the first real diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 1d9d7c592c8..053eb9b774e 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -73,7 +73,6 @@ import sage.modular.modform.constructor import sage.modular.modform.element -import sage.libs.eclib.all as mwrank import sage.databases.cremona import sage.arith.all as arith @@ -791,8 +790,8 @@ def mwrank_curve(self, verbose=False): return self.__mwrank_curve except AttributeError: pass - self.__mwrank_curve = mwrank.mwrank_EllipticCurve( - list(self.ainvs()), verbose=verbose) + from sage.libs.eclib.all import mwrank_EllipticCurve + self.__mwrank_curve = mwrank_EllipticCurve(self.ainvs(), verbose=verbose) return self.__mwrank_curve def two_descent(self, verbose=True, @@ -2599,7 +2598,8 @@ def saturation(self, points, verbose=False, max_prime=0, odd_primes_only=False): v.append((x*d, y*d, d)) c = Emin.mwrank_curve() - mw = mwrank.mwrank_MordellWeil(c, verbose) + from sage.libs.eclib.all import mwrank_MordellWeil + mw = mwrank_MordellWeil(c, verbose) mw.process(v) repeat_until_saturated = False if max_prime == 0: @@ -5355,56 +5355,56 @@ def ordinary_primes(self, B): sage: e.ordinary_primes(1) [] """ - v = self.aplist(max(B, 3) ) - P = rings.prime_range(max(B,3) +1) - return [P[i] for i in [0,1] if P[i] <= B and v[i]%P[i]!=0] +\ - [P[i] for i in range(2,len(v)) if v[i] != 0] + v = self.aplist(max(B, 3)) + P = rings.prime_range(max(B, 3) + 1) + result = [P[i] for i in [0, 1] if P[i] <= B and v[i] % P[i]] + result += [P[i] for i in range(2, len(v)) if v[i] != 0] + return result - def eval_modular_form(self, points, prec): + def eval_modular_form(self, points, order): r""" Evaluate the modular form of this elliptic curve at points in `\CC`. INPUT: + - ``points`` -- a list of points in the upper half-plane - - ``points`` - a list of points in the half-plane of - convergence - - - ``prec`` - precision + - ``order`` -- a nonnegative integer + The ``order`` parameter is the number of terms used in the summation. - OUTPUT: A list of values L(E,s) for s in points - - .. note:: - - Better examples are welcome. + OUTPUT: A list of values for `s` in ``points`` EXAMPLES:: sage: E = EllipticCurve('37a1') - sage: E.eval_modular_form([1.5+I,2.0+I,2.5+I],0.000001) - [0, 0, 0] + sage: E.eval_modular_form([1.5+I,2.0+I,2.5+I],100) # abs tol 1e-20 + [-0.0018743978548152085771342944989052703431, + 0.0018604485340371083710285594393397945456, + -0.0018743978548152085771342944989052703431] + + sage: E.eval_modular_form(2.1+I, 100) # abs tol 1e-20 + [0.00150864362757267079 + 0.00109100341113449845*I] """ if not isinstance(points, list): try: points = list(points) except TypeError: - return self.eval_modular_form([points], prec) - an = self.pari_mincurve().ellan(prec) + return self.eval_modular_form([points], order) + an = self.pari_mincurve().ellan(order) s = 0 c = pari('2 * Pi * I') ans = [] for z in points: s = pari(0) - r0 = (c*z).exp() + r0 = (c * z).exp() r = r0 - for n in range(1, prec): - s += an[n-1]*r + for n in range(1, order + 1): + s += an[n - 1] * r r *= r0 ans.append(s.sage()) return ans - ######################################################################## # The Tate-Shafarevich group ######################################################################## diff --git a/src/sage/schemes/elliptic_curves/ell_torsion.py b/src/sage/schemes/elliptic_curves/ell_torsion.py index 58874554a24..91d229a53b6 100644 --- a/src/sage/schemes/elliptic_curves/ell_torsion.py +++ b/src/sage/schemes/elliptic_curves/ell_torsion.py @@ -10,7 +10,7 @@ polynomials, added some features, unified Number Field and `\QQ` code. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -23,7 +23,7 @@ # The full text of the GPL is available at: # # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from sage.misc.cachefunc import cached_method from sage.rings.all import RationalField @@ -97,16 +97,16 @@ class EllipticCurveTorsionSubgroup(groups.AdditiveAbelianGroupWrapper): Examples over other Number Fields:: - sage: E=EllipticCurve('11a1') - sage: K.=NumberField(x^2+1) - sage: EK=E.change_ring(K) + sage: E = EllipticCurve('11a1') + sage: K. = NumberField(x^2+1) + sage: EK = E.change_ring(K) sage: from sage.schemes.elliptic_curves.ell_torsion import EllipticCurveTorsionSubgroup sage: EllipticCurveTorsionSubgroup(EK) Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in i with defining polynomial x^2 + 1 - sage: E=EllipticCurve('11a1') - sage: K.=NumberField(x^2+1) - sage: EK=E.change_ring(K) + sage: E = EllipticCurve('11a1') + sage: K. = NumberField(x^2+1) + sage: EK = E.change_ring(K) sage: T = EK.torsion_subgroup() sage: T.ngens() 1 @@ -138,9 +138,9 @@ def __init__(self, E): EXAMPLES:: sage: from sage.schemes.elliptic_curves.ell_torsion import EllipticCurveTorsionSubgroup - sage: E=EllipticCurve('11a1') - sage: K.=NumberField(x^2+1) - sage: EK=E.change_ring(K) + sage: E = EllipticCurve('11a1') + sage: K. = NumberField(x^2+1) + sage: EK = E.change_ring(K) sage: EllipticCurveTorsionSubgroup(EK) Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in i with defining polynomial x^2 + 1 @@ -162,7 +162,7 @@ def __init__(self, E): structure = G[1].sage() gens = G[2].sage() - self.__torsion_gens = [ self.__E(P) for P in gens ] + self.__torsion_gens = [self.__E(P) for P in gens] groups.AdditiveAbelianGroupWrapper.__init__(self, self.__E(0).parent(), self.__torsion_gens, structure) return @@ -175,13 +175,12 @@ def __init__(self, E): bound = E._torsion_bound(number_of_places=20) # now do prime by prime - for p,e in bound.factor(): - ptor = E._p_primary_torsion_basis(p,e) - # print p,'-primary part is ',ptor - if len(ptor)>0: + for p, e in bound.factor(): + ptor = E._p_primary_torsion_basis(p, e) + if ptor: T1 += ptor[0][0] k1 *= p**(ptor[0][1]) - if len(ptor)>1: + if len(ptor) > 1: T2 += ptor[1][0] k2 *= p**(ptor[1][1]) @@ -206,9 +205,9 @@ def _repr_(self): EXAMPLES:: - sage: E=EllipticCurve('11a1') - sage: K.=NumberField(x^2+1) - sage: EK=E.change_ring(K) + sage: E = EllipticCurve('11a1') + sage: K. = NumberField(x^2+1) + sage: EK = E.change_ring(K) sage: T = EK.torsion_subgroup(); T._repr_() 'Torsion Subgroup isomorphic to Z/5 associated to the Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20) over Number Field in i with defining polynomial x^2 + 1' """ @@ -221,7 +220,7 @@ def __richcmp__(self, other, op): EXAMPLES:: sage: E = EllipticCurve('37a1') - sage: tor = E.torsion_subgroup() + sage: tor = E.torsion_subgroup() sage: tor == tor True """ @@ -235,9 +234,9 @@ def curve(self): EXAMPLES:: - sage: E=EllipticCurve('11a1') - sage: K.=NumberField(x^2+1) - sage: EK=E.change_ring(K) + sage: E = EllipticCurve('11a1') + sage: K. = NumberField(x^2+1) + sage: EK = E.change_ring(K) sage: T = EK.torsion_subgroup() sage: T.curve() is EK True @@ -248,11 +247,12 @@ def curve(self): def points(self): """ Return a list of all the points in this torsion subgroup. + The list is cached. EXAMPLES:: - sage: K.=NumberField(x^2 + 1) + sage: K. = NumberField(x^2 + 1) sage: E = EllipticCurve(K,[0,0,0,1,0]) sage: tor = E.torsion_subgroup() sage: tor.points() diff --git a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py index 7400422ecab..7450d9d05b9 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py +++ b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py @@ -1534,12 +1534,11 @@ def reducible_primes_Billerey(E, num_l=None, max_l=None, verbose=False): if verbose: print("Naive test of primes up to {} returns {}.".format(max_small_prime, OK_small_primes)) - from sage.schemes.elliptic_curves.gal_reps_number_field import Billerey_B_bound B1 = Billerey_B_bound(E, max_l, num_l, max_small_prime, verbose) if B1 == [0]: if verbose: print("... B_bound ineffective using max_l={}, moving on to R-bound".format(max_l)) - from sage.schemes.elliptic_curves.gal_reps_number_field import Billerey_R_bound + B1 = Billerey_R_bound(E,max_l, num_l, max_small_prime, verbose) if B1 == [0]: if verbose: @@ -1553,7 +1552,7 @@ def reducible_primes_Billerey(E, num_l=None, max_l=None, verbose=False): B = sorted(set(B0 + B1 + OK_small_primes)) if verbose: print("... combined bound = {}".format(B)) - from sage.schemes.elliptic_curves.gal_reps_number_field import Frobenius_filter + num_p = 100 B = Frobenius_filter(E, B, num_p) if verbose: @@ -1596,7 +1595,6 @@ def reducible_primes_naive(E, max_l=None, num_P=None, verbose=False): [2, 5] sage: [phi.degree() for phi in E.isogenies_prime_degree()] [2, 2, 2, 5] - """ if max_l is None: max_l = 1000 @@ -1604,7 +1602,7 @@ def reducible_primes_naive(E, max_l=None, num_P=None, verbose=False): num_P = 100 if verbose: print("E = {}, finding reducible primes up to {} using Frobenius filter with {} primes".format(E.ainvs(), max_l, num_P)) - from sage.schemes.elliptic_curves.gal_reps_number_field import Frobenius_filter + B = Frobenius_filter(E, primes(max_l), num_P) if verbose: print("... returning {}".format(B)) diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 590454328dd..170898dbf67 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -4232,7 +4232,7 @@ def trace_to_real_numerical(self, prec=53): sage: PP = P.numerical_approx() sage: [c.real() for c in PP] [6.00000000000000, -15.0000000000000, 1.00000000000000] - sage: all([c.imag().abs() < 1e-14 for c in PP]) + sage: all(c.imag().abs() < 1e-14 for c in PP) True sage: P.trace_to_real_numerical() (1.61355529131986 : -2.18446840788880 : 1.00000000000000) diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index 8effb4afb45..90c2d1a5066 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -1902,7 +1902,7 @@ def min_gr(self, tol, n_max, verbose=False): sage: K. = QuadraticField(-1) sage: E = EllipticCurve([0,1-i,i,-i,0]) sage: H = E.height_function() - sage: H.min_gr(0.01,5) + sage: H.min_gr(0.01, 5) # long time 0.020153685521979152 In this example the point `P=(0,0)` has height 0.023 so our @@ -1927,11 +1927,10 @@ def min_gr(self, tol, n_max, verbose=False): This example from the LMFDB gave problems before the fix in :trac:`8829`:: - sage: K. = NumberField(x^2-x-1) - sage: phi = a + sage: K. = NumberField(x^2-x-1) sage: E = EllipticCurve([phi + 1, -phi + 1, 1, 20*phi - 39, 196*phi + 237]) sage: H = E.height_function() - sage: H.min_gr(.1,5,True) # long time (~22s) + sage: H.min_gr(.1, 5, verbose=True) # long time (~22s) B_1(1) = 1540.199246369678 ... halving mu to 0.25 and increasing n_max to 6 @@ -1941,42 +1940,42 @@ def min_gr(self, tol, n_max, verbose=False): doubling mu to 0.015625 height bound in [0.0078125, 0.015625] using n_max = 13 ... - height bound in [0.0120485220735, 0.0131390064883] using n_max = 13 + height bound in [0.012048522073499539, 0.01313900648833929] using n_max = 13 0.012048522073499539 """ test = self.test_mu if test(1, n_max, verbose): - mu = 2 + mu = 2.0 while test(mu, n_max, False): mu *= 2 - mu /= 2 + mu *= 0.5 else: - mu = .5 + mu = 0.5 while not test(mu, n_max, False): - mu /= 2 + mu *= 0.5 n_max += 1 if verbose: - print("halving mu to %s and increasing n_max to %s" % (mu,n_max)) + print("halving mu to %r and increasing n_max to %r" % (mu, n_max)) # now we have (mu,n_max) which work we can try to increase # mu again using this larger n_max: mu *= 2 while test(mu, n_max, False): mu *= 2 if verbose: - print("doubling mu to %s" % mu) - mu /= 2 + print("doubling mu to %r" % mu) + mu *= 0.5 # The true value lies between mu and eps * mu. eps = 2.0 while eps > tol + 1: if verbose: - print("height bound in [%s, %s] using n_max = %s" + print("height bound in [%r, %r] using n_max = %r" % (mu, mu * eps, n_max)) eps = math.sqrt(eps) if test(mu * eps, n_max, False): mu = mu * eps if verbose: - print("height bound in [%s, %s] using n_max = %s" + print("height bound in [%r, %r] using n_max = %r" % (mu, mu * eps, n_max)) return RDF(mu) diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py index d30ec0ebdb9..39be33c94c2 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py +++ b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py @@ -21,14 +21,14 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012-2013 John Cremona, Jenny Cooley, Kimi Tsukazaki # # 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 sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import polygen @@ -80,16 +80,21 @@ def Fricke_polynomial(l): sage: Fricke_polynomial(13) t^14 + 26*t^13 + 325*t^12 + 2548*t^11 + 13832*t^10 + 54340*t^9 + 157118*t^8 + 333580*t^7 + 509366*t^6 + 534820*t^5 + 354536*t^4 + 124852*t^3 + 15145*t^2 + 746*t + 13 """ - Zt = PolynomialRing(ZZ,'t') - t = Zt.gen() - if l==2: return (t+16)**3 - elif l==3: return (t+3)**3*(t+27) - elif l==5: return (t**2+10*t+5)**3 - elif l==7: return (t**2+5*t+1)**3 * (t**2+13*t+49) - elif l==13: return (t**2+5*t+13)*(t**4+7*t**3+20*t**2+19*t+1)**3 + t = PolynomialRing(ZZ, 't').gen() + if l == 2: + return (t+16)**3 + elif l == 3: + return (t+3)**3*(t+27) + elif l == 5: + return (t**2+10*t+5)**3 + elif l == 7: + return (t**2+5*t+1)**3 * (t**2+13*t+49) + elif l == 13: + return (t**2+5*t+13)*(t**4+7*t**3+20*t**2+19*t+1)**3 else: raise ValueError("The only genus zero primes are 2, 3, 5, 7 or 13.") + @cached_function def Fricke_module(l): r""" @@ -125,11 +130,9 @@ def Fricke_module(l): sage: Fricke_module(13) (t^14 + 26*t^13 + 325*t^12 + 2548*t^11 + 13832*t^10 + 54340*t^9 + 157118*t^8 + 333580*t^7 + 509366*t^6 + 534820*t^5 + 354536*t^4 + 124852*t^3 + 15145*t^2 + 746*t + 13)/t """ - try: - t = PolynomialRing(QQ,'t').gen() - return Fricke_polynomial(l) / t - except ValueError: - raise ValueError("The only genus zero primes are 2, 3, 5, 7 or 13.") + t = PolynomialRing(QQ, 't').gen() + return Fricke_polynomial(l) / t + @cached_function def Psi(l, use_stored=True): @@ -184,24 +187,24 @@ def Psi(l, use_stored=True): sage: assert Psi(7, use_stored=True) == Psi(7, use_stored=False) sage: assert Psi(13, use_stored=True) == Psi(13, use_stored=False) # not tested (very long time) """ - if not l in [2,3,5,7,13]: + if not l in [2, 3, 5, 7, 13]: raise ValueError("Genus zero primes are 2, 3, 5, 7 or 13.") - R = PolynomialRing(ZZ,2,'Xt') - X,t = R.gens() + R = PolynomialRing(ZZ, 2, 'Xt') + X, t = R.gens() if use_stored: - if l==2: + if l == 2: return X + t + 64 - if l==3: + if l == 3: return X + t + 27 - if l==5: + if l == 5: return X**2 + 2*X*(t**2 + 22*t + 125)+ (t**2 + 22*t + 89) * (t**2 + 22*t + 125) - if l==7: + if l == 7: return (X**3 + 3*(t**2 + 13*t + 49)*X**2 + 3*(t**2 + 13*t + 33)*(t**2 + 13*t + 49)*X + (t**2 + 13*t + 49)*(t**4 + 26*t**3 + 219*t**2 + 778*t + 881)) - if l==13: + if l == 13: return (t**24 + 66*t**23 + 2091*t**22 + 6*X*t**20 + 42582*t**21 + 330*X*t**19 + 627603*t**20 + 8700*X*t**18 + 7134744*t**19 + 15*X**2*t**16 + 146886*X*t**17 + 65042724*t**18 + 660*X**2*t**15 + 1784532*X*t**16 + 487778988*t**17 + 13890*X**2*t**14 + 16594230*X*t**15 + 3061861065*t**16 + 20*X**3*t**12 + 186024*X**2*t**13 + 122552328*X*t**14 + 16280123754*t**15 + 660*X**3*t**11 + 1774887*X**2*t**12 + 735836862*X*t**13 + 73911331425*t**14 + 10380*X**3*t**10 + 12787272*X**2*t**11 + 3646188342*X*t**12 + 287938949178*t**13 + 15*X**4*t**8 + 102576*X**3*t**9 + 71909658*X**2*t**10 + 15047141292*X*t**11 + 964903805434*t**12 + 330*X**4*t**7 + 707604*X**3*t**8 + 321704316*X**2*t**9 + 51955096824*X*t**10 + 2781843718722*t**11 + 3435*X**4*t**6 + 3582876*X**3*t**7 + 1155971196*X**2*t**8 + 150205315932*X*t**9 + 6885805359741*t**10 + 6*X**5*t**4 + 21714*X**4*t**5 + 13632168*X**3*t**6 + 3343499244*X**2*t**7 + 362526695094*X*t**8 + 14569390179114*t**9 + 66*X**5*t**3 + 90660*X**4*t**4 + 39215388*X**3*t**5 + 7747596090*X**2*t**6 + 725403501318*X*t**7 + 26165223178293*t**8 + 336*X**5*t**2 + 255090*X**4*t**3 + 84525732*X**3*t**4 + 14206132008*X**2*t**5 + 1189398495432*X*t**6 + 39474479008356*t**7 + X**6 + 858*X**5*t + 472143*X**4*t**2 + 132886992*X**3*t**3 + 20157510639*X**2*t**4 + 1569568001646*X*t**5 + 49303015587132*t**6 + 1014*X**5 + 525954*X**4*t + 144222780*X**3*t**2 + 21320908440*X**2*t**3 + 1622460290100*X*t**4 + 49941619724976*t**5 + 272259*X**4 + 96482100*X**3*t + 15765293778*X**2*t**2 + 1260038295438*X*t**3 + 39836631701295*t**4 + 29641924*X**3 + 7210949460*X**2*t + 686651250012*X*t**2 + 23947528862166*t**3 + 1506392823*X**2 + 231462513906*X*t + 10114876838391*t**2 + 35655266790*X + 2644809206442*t + 317295487717) # The coefficients for l=13 are: # X**6: 1 @@ -211,23 +214,23 @@ def Psi(l, use_stored=True): # X**2: (3) * (t**2 + 5*t + 13)**2 * (t**2 + 6*t + 13)**2 * (5*t**8 + 110*t**7 + 1045*t**6 + 5798*t**5 + 20508*t**4 + 47134*t**3 + 67685*t**2 + 54406*t + 17581) # X**1: (6) * (t**2 + 5*t + 13)**2 * (t**2 + 6*t + 13)**3 * (t**10 + 27*t**9 + 316*t**8 + 2225*t**7 + 10463*t**6 + 34232*t**5 + 78299*t**4 + 122305*t**3 + 122892*t**2 + 69427*t + 16005) # X**0: (t**2 + 5*t + 13)**2 * (t**2 + 6*t + 13)**3 * (t**14 + 38*t**13 + 649*t**12 + 6844*t**11 + 50216*t**10 + 271612*t**9 + 1115174*t**8 + 3520132*t**7 + 8549270*t**6 + 15812476*t**5 + 21764840*t**4 + 21384124*t**3 + 13952929*t**2 + 5282630*t + 854569) -# # Here the generic kernel polynomials are actually calculated: j = Fricke_module(l) - k = j-1728 + k = j - 1728 from sage.misc.all import prod - f = prod( [p for p,e in j.factor() if e==3] - +[p for p,e in k.factor() if e==2]) + 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 A6 = -2*t**3*j*k**2 // f**3 - E = EllipticCurve([0,0,0,A4,A6]) + E = EllipticCurve([0, 0, 0, A4, A6]) assert E.j_invariant() == j - return E.division_polynomial(l,X).factor()[0][0] + return E.division_polynomial(l, X).factor()[0][0] def isogenies_prime_degree_genus_0(E, l=None, minimal_models=True): - """Returns list of ``l`` -isogenies with domain ``E``. + """ + Return list of ``l`` -isogenies with domain ``E``. INPUT: @@ -278,23 +281,23 @@ def isogenies_prime_degree_genus_0(E, l=None, minimal_models=True): j = E.j_invariant() if F.characteristic() in [2, 3, l]: raise NotImplementedError("2, 3, 5, 7 and 13-isogenies are not yet implemented in characteristic 2 and 3, and when the characteristic is the same as the degree of the isogeny.") - if l==2: + if l == 2: return isogenies_2(E, minimal_models=minimal_models) - if l==3: + if l == 3: return isogenies_3(E, minimal_models=minimal_models) - if j==F(0): - if l==5: + if j == F(0): + if l == 5: return isogenies_5_0(E, minimal_models=minimal_models) - if l==7: + if l == 7: return isogenies_7_0(E, minimal_models=minimal_models) - if l==13: + if l == 13: return isogenies_13_0(E, minimal_models=minimal_models) - if j==F(1728): - if l==5: + if j == F(1728): + if l == 5: return isogenies_5_1728(E, minimal_models=minimal_models) - if l==7: + if l == 7: return isogenies_7_1728(E, minimal_models=minimal_models) - if l==13: + if l == 13: return isogenies_13_1728(E, minimal_models=minimal_models) if l is not None: @@ -355,7 +358,7 @@ def isogenies_prime_degree_genus_0(E, l=None, minimal_models=True): @cached_function def _sporadic_Q_data(j): r""" - Returns technical data used in computing sporadic isogenies over `\QQ`. + Return technical data used in computing sporadic isogenies over `\QQ`. INPUT: @@ -531,7 +534,7 @@ def _sporadic_Q_data(j): ....: E = EllipticCurve(j=j).short_weierstrass_model() ....: f = R(_sporadic_Q_data(j)[1]) ....: g = E.division_polynomial(ell) - ....: assert g%f==0 + ....: assert g % f == 0 """ from sage.rings.all import RealField from sage.misc.all import prod @@ -812,7 +815,7 @@ def isogenies_5_0(E, minimal_models=True): a = Ew.a6() x = polygen(F) betas = sorted((x**6-160*a*x**3-80*a**2).roots(multiplicities=False)) - if len(betas)==0: + if not betas: return [] gammas = [(beta**2 *(beta**3-140*a))/(120*a) for beta in betas] from sage.rings.number_field.number_field_base import is_NumberField @@ -823,7 +826,8 @@ def isogenies_5_0(E, minimal_models=True): return isogs def isogenies_5_1728(E, minimal_models=True): - r"""Returns a list of 5-isogenies with domain ``E`` when the j-invariant is + r""" + Return a list of 5-isogenies with domain ``E`` when the j-invariant is 1728. INPUT: @@ -927,7 +931,8 @@ def isogenies_5_1728(E, minimal_models=True): return isogs def isogenies_7_0(E, minimal_models=True): - r"""Returns list of all 7-isogenies from E when the j-invariant is 0. + r""" + Return list of all 7-isogenies from E when the j-invariant is 0. INPUT: @@ -1021,7 +1026,7 @@ def isogenies_7_0(E, minimal_models=True): kers = [7*x-(2+6*t) for t in ts] kers = [k(x**3/a).monic() for k in kers] isogs = [Ew.isogeny(k,model=model) for k in kers] - if len(isogs)>0: + if isogs: [endo.set_post_isomorphism(endo.codomain().isomorphism_to(E)) for endo in isogs] # we may have up to 6 other isogenies: @@ -1037,7 +1042,8 @@ def isogenies_7_0(E, minimal_models=True): return isogs def isogenies_7_1728(E, minimal_models=True): - r"""Returns list of all 7-isogenies from E when the j-invariant is 1728. + r""" + Return list of all 7-isogenies from E when the j-invariant is 1728. INPUT: @@ -1107,7 +1113,7 @@ def isogenies_7_1728(E, minimal_models=True): a = Ew.a4() ts = (Fricke_module(7)-1728).numerator().roots(F,multiplicities=False) - if len(ts)==0: + if not ts: return [] ts.sort() isogs = [] @@ -1126,7 +1132,7 @@ def isogenies_7_1728(E, minimal_models=True): def isogenies_13_0(E, minimal_models=True): """ - Returns list of all 13-isogenies from E when the j-invariant is 0. + Return list of all 13-isogenies from E when the j-invariant is 0. INPUT: @@ -1230,7 +1236,7 @@ def isogenies_13_0(E, minimal_models=True): kers = [13*x**2 + (78*t + 26)*x + 24*t + 40 for t in ts] kers = [k(x**3/a).monic() for k in kers] isogs = [Ew.isogeny(k,model=model) for k in kers] - if len(isogs)>0: + if isogs: [endo.set_post_isomorphism(endo.codomain().isomorphism_to(E)) for endo in isogs] # we may have up to 12 other isogenies: @@ -1251,8 +1257,10 @@ def isogenies_13_0(E, minimal_models=True): return isogs + def isogenies_13_1728(E, minimal_models=True): - r"""Returns list of all 13-isogenies from E when the j-invariant is 1728. + r""" + Return list of all 13-isogenies from E when the j-invariant is 1728. INPUT: @@ -1347,7 +1355,7 @@ def isogenies_13_1728(E, minimal_models=True): kers = [13*x**3 + (-26*i - 13)*x**2 + (-52*i - 13)*x - 2*i - 3 for i in ts] kers = [k(x**2/a).monic() for k in kers] isogs = [Ew.isogeny(k,model=model) for k in kers] - if len(isogs)>0: + if isogs: [endo.set_post_isomorphism(endo.codomain().isomorphism_to(E)) for endo in isogs] # we may have up to 12 other isogenies: @@ -1529,7 +1537,7 @@ def _hyperelliptic_isogeny_data(l): @cached_function def Psi2(l): """ - Returns the generic kernel polynomial for hyperelliptic `l`-isogenies. + Return the generic kernel polynomial for hyperelliptic `l`-isogenies. INPUT: @@ -1591,7 +1599,7 @@ def Psi2(l): def isogenies_prime_degree_genus_plus_0(E, l=None, minimal_models=True): """ - Returns list of ``l`` -isogenies with domain ``E``. + Return list of ``l`` -isogenies with domain ``E``. INPUT: @@ -1734,9 +1742,10 @@ def isogenies_prime_degree_genus_plus_0(E, l=None, minimal_models=True): kernels += [psi((36*X+3*b2)*T,u0,v0).monic()] return [E.isogeny(ker) for ker in kernels] + def isogenies_prime_degree_genus_plus_0_j0(E, l, minimal_models=True): """ - Returns a list of hyperelliptic ``l`` -isogenies with domain ``E`` when `j(E)=0`. + Return a list of hyperelliptic ``l`` -isogenies with domain ``E`` when `j(E)=0`. INPUT: @@ -1810,7 +1819,7 @@ def isogenies_prime_degree_genus_plus_0_j0(E, l, minimal_models=True): S += [[u0,v0] for v0 in (X**2-f(u0)).roots(multiplicities=False)] else: S += [[u0,-a(u0)/b(u0)]] - if len(S)==0 and len(kernels) == 0: + if not S and not kernels: return [] S.sort() @@ -1820,9 +1829,10 @@ def isogenies_prime_degree_genus_plus_0_j0(E, l, minimal_models=True): kernels += [psi((36*X+3*b2)*T,u0,v0).monic() for T in (X**3-A6/(-54*c6)).roots(multiplicities=False)] return [E.isogeny(ker) for ker in kernels] + def isogenies_prime_degree_genus_plus_0_j1728(E, l, minimal_models=True): """ - Returns a list of ``l`` -isogenies with domain ``E`` when `j(E)=1728`. + Return a list of ``l`` -isogenies with domain ``E`` when `j(E)=1728`. INPUT: @@ -1901,7 +1911,7 @@ def isogenies_prime_degree_genus_plus_0_j1728(E, l, minimal_models=True): S += [[u0,v0] for v0 in (X**2-f(u0)).roots(multiplicities=False)] else: S += [[u0,(2*1728-a(u0))/b(u0)]] - if len(S)==0 and len(kernels) == 0: + if not S and not kernels: return [] S.sort() @@ -1919,7 +1929,7 @@ def _least_semi_primitive(p): INPUT: - - ``p`` -- an odd prime. + - ``p`` -- an odd prime power. OUTPUT: @@ -1943,21 +1953,122 @@ def _least_semi_primitive(p): sage: _least_semi_primitive(997) 7 """ - if not p.is_prime() or p<3: - raise ValueError("%s is not an odd prime"%p) - - def is_semi_primitive(a,p): - from sage.rings.finite_rings.integer_mod_ring import Integers - d = Integers(p)(a).multiplicative_order() - if p%4==1: - return (d==p-1) - else: - return d >= (p-1)/2 + if p % 2 == 0 or not p.is_prime_power(): + raise ValueError("{} is not an odd prime power".format(p)) + + from sage.arith.misc import euler_phi + from sage.rings.finite_rings.integer_mod_ring import Integers + phip = euler_phi(p) + ord = phip if p % 4 == 1 else phip // 2 + R = Integers(p) + return next((a for a in range(2, p) if p.gcd(a) == 1 + and R(a).multiplicative_order() >= ord), 0) - a = 2 - while not is_semi_primitive(a,p): - a += 1 - return a + +def is_kernel_polynomial(E, m, f): + r""" + Test whether ``E`` has a cyclic isogeny of degree ``m`` with kernel + polynomial ``f``. + + INPUT: + + - ``E`` -- an elliptic curve. + + - ``m`` -- a positive integer. + + - ``f`` -- a polynomial over the base field of ``E``. + + OUTPUT: + + (bool) ``True`` if ``E`` has a cyclic isogeny of degree ``m`` with + kernel polynomial ``f``, else ``False``. + + ALGORITHM: + + `f` must have degree `(m-1)/2` (if `m` is odd) or degree `m/2` (if + `m` is even), and have the property that for each root `x` of `f`, + `\mu(x)` is also a root where `\mu` is the multiplication-by-`m` + map on `E` and `m` runs over a set of generators of + `(\ZZ/m\ZZ)^*/\{1,-1\}`. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.isogeny_small_degree import is_kernel_polynomial + sage: E = EllipticCurve([0, -1, 1, -10, -20]) + sage: x = polygen(QQ) + sage: is_kernel_polynomial(E,5,x^2 + x - 29/5) + True + sage: is_kernel_polynomial(E,5,(x - 16) * (x - 5)) + True + + An example from [KT2013]_, where the 13-division polynomial splits + into 14 factors each of degree 6, but only two of these is a + kernel polynomial for a 13-isogeny:: + + sage: F = GF(3) + sage: E = EllipticCurve(F,[0,0,0,-1,0]) + sage: f13 = E.division_polynomial(13) + sage: factors = [f for f,e in f13.factor()] + sage: all([f.degree()==6 for f in factors]) + True + sage: [is_kernel_polynomial(E,13,f) for f in factors] + [True, + True, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False] + + See :trac:`22232`:: + + sage: K =GF(47^2) + sage: E = EllipticCurve([0, K.gen()]) + sage: psi7 = E.division_polynomial(7) + sage: f = psi7.factor()[4][0] + sage: f + x^3 + (7*z2 + 11)*x^2 + (25*z2 + 33)*x + 25*z2 + sage: f.divides(psi7) + True + sage: is_kernel_polynomial(E,7, f) + False + + """ + m2 = m // 2 + if f.degree() != m2: + return False + if m == 1: + return True + + # Compute the quotient polynomial ring mod (f) + S = f.parent().quotient_ring(f) + + # test if the m-division polynomial is a multiple of f by computing it in the quotient: + if E.division_polynomial(m, x=S.gen()) != 0: + return False + + if m == 2 or m == 3: + return True + + # For each a in a set of generators of (Z/mZ)^* we check that the + # multiplcation-by-a map permutes the roots of f. It would be + # enough to take a generating (Z/mZ)^*/{1,-1} but that is not + # implemented. If m is prime (or more generally, has a primitive + # root) then only one a will be needed. + + from sage.rings.finite_rings.integer_mod_ring import Integers + for a in Integers(m).unit_gens(): + mu = E.multiplication_by_m(a, x_only=True) + if f( S(mu.numerator()) / S(mu.denominator()) ) != 0: + return False + return True def isogenies_prime_degree_general(E, l, minimal_models=True): @@ -2070,10 +2181,10 @@ def isogenies_prime_degree_general(E, l, minimal_models=True): [(0, 0, 0, -840*i + 1081, 0), (0, 0, 0, 840*i + 1081, 0)] """ if not l.is_prime(): - raise ValueError("%s is not prime."%l) - if l==2: + raise ValueError("%s is not prime." % l) + if l == 2: return isogenies_2(E, minimal_models=minimal_models) - if l==3: + if l == 3: return isogenies_3(E, minimal_models=minimal_models) psi_l = E.division_polynomial(l) diff --git a/src/sage/schemes/elliptic_curves/kodaira_symbol.py b/src/sage/schemes/elliptic_curves/kodaira_symbol.py index 38af9138d51..e968d21a7d0 100644 --- a/src/sage/schemes/elliptic_curves/kodaira_symbol.py +++ b/src/sage/schemes/elliptic_curves/kodaira_symbol.py @@ -325,7 +325,7 @@ def KodairaSymbol(symbol): [I0, II, III, IV, I1, I2, I3, I4, I5] sage: [KS(-n) for n in range(1,10)] [I0*, II*, III*, IV*, I1*, I2*, I3*, I4*, I5*] - sage: all([KS(str(KS(n)))==KS(n) for n in range(-10,10) if n!=0]) + sage: all(KS(str(KS(n))) == KS(n) for n in range(-10,10) if n != 0) True """ if symbol in _ks_cache: diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py index fa19ee352c1..76604766998 100644 --- a/src/sage/schemes/elliptic_curves/padics.py +++ b/src/sage/schemes/elliptic_curves/padics.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- +# +# All these methods are imported in EllipticCurve_rational_field, +# so there is no reason to add this module to the documentation. """ -Miscellaneous `p`-adic functions - -`p`-adic functions from ell_rational_field.py, moved here to reduce -crowding in that file. +Miscellaneous `p`-adic methods """ ###################################################################### @@ -18,7 +18,7 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ###################################################################### from __future__ import absolute_import @@ -217,23 +217,20 @@ def padic_lseries(self, p, normalize = None, implementation = 'eclib', precision def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): r""" - Computes the cyclotomic `p`-adic regulator of this curve. - + Compute the cyclotomic `p`-adic regulator of this curve. INPUT: + - ``p`` -- prime >= 5 - - ``p`` - prime = 5 + - ``prec`` -- answer will be returned modulo + `p^{\mathrm{prec}}` - - ``prec`` - answer will be returned modulo - `p^{\mathrm{prec}}` - - - ``height`` - precomputed height function. If not - supplied, this function will call padic_height to compute it. - - - ``check_hypotheses`` - boolean, whether to check - that this is a curve for which the p-adic height makes sense + - ``height`` -- precomputed height function. If not + supplied, this function will call padic_height to compute it. + - ``check_hypotheses`` -- boolean, whether to check + that this is a curve for which the p-adic height makes sense OUTPUT: The p-adic cyclotomic regulator of this curve, to the requested precision. @@ -339,7 +336,7 @@ def padic_height_pairing_matrix(self, p, prec=20, height=None, check_hypotheses= INPUT: - - ``p`` - prime = 5 + - ``p`` - prime >= 5 - ``prec`` - answer will be returned modulo `p^{\mathrm{prec}}` @@ -587,10 +584,10 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): INPUT: - - ``p`` - prime = 5 for which the curve has + - ``p`` - prime >= 5 for which the curve has semi-stable reduction - - ``prec`` - integer = 1, desired precision of result + - ``prec`` - integer >= 1 (default 20), desired precision of result - ``sigma`` - precomputed value of sigma. If not supplied, this function will call padic_sigma to compute it. @@ -796,10 +793,10 @@ def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): INPUT: - - ``p`` - prime = 5 for which the curve has good + - ``p`` - prime >= 5 for which the curve has good ordinary reduction - - ``prec`` - integer = 2, desired precision of result + - ``prec`` - integer >= 2 (default 20), desired precision of result - ``E2`` - precomputed value of E2. If not supplied, this function will call padic_E2 to compute it. The value supplied @@ -948,10 +945,10 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): INPUT: - - ``p`` - prime = 5 for which the curve has good + - ``p`` - prime >= 5 for which the curve has good ordinary reduction - - ``N`` - integer = 1, indicates precision of result; + - ``N`` - integer >= 1 (default 20), indicates precision of result; see OUTPUT section for description - ``E2`` - precomputed value of E2. If not supplied, @@ -1157,30 +1154,27 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): return sigma - - def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True): r""" - Computes the p-adic sigma function with respect to the standard + Compute the p-adic sigma function with respect to the standard invariant differential `dx/(2y + a_1 x + a_3)`, as defined by Mazur and Tate, as a power series in the usual uniformiser `t` at the origin. The equation of the curve must be minimal at `p`. - This function differs from padic_sigma() in the precision profile + This function differs from :func:`padic_sigma` in the precision profile of the returned power series; see OUTPUT below. INPUT: - - - ``p`` - prime = 5 for which the curve has good + - ``p`` - prime >= 5 for which the curve has good ordinary reduction - - ``N`` - integer = 2, indicates precision of result; + - ``N`` - integer >= 2 (default 20), indicates precision of result; see OUTPUT section for description - - ``lamb`` - integer = 0, see OUTPUT section for + - ``lamb`` - integer >= 0, see OUTPUT section for description - ``E2`` - precomputed value of E2. If not supplied, @@ -1210,7 +1204,7 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) AUTHOR: - David Harvey (2008-01): wrote based on previous - padic_sigma function + :func:`padic_sigma function` EXAMPLES:: diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 7141b6cac42..6b75fc477d5 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -594,18 +594,19 @@ def _compute_periods_real(self, prec=None, algorithm='sage'): 1.9072648860892725468182549468 - 1.3404778596244020196600112394*I) """ if prec is None: - prec = RealField().precision() + prec = 53 R = RealField(prec) C = ComplexField(prec) - if algorithm=='pari': - if self.E.base_field() is QQ: - periods = self.E.pari_curve().omega(prec).sage() - return (R(periods[0]), C(periods[1])) + if algorithm == 'pari': + ainvs = self.E.a_invariants() + if self.E.base_field() is not QQ: + ainvs = [C(self.embedding(ai)).real() for ai in ainvs] - E_pari = pari([R(self.embedding(ai).real()) for ai in self.E.a_invariants()]).ellinit() - periods = E_pari.omega(prec).sage() - return (R(periods[0]), C(periods[1])) + # The precision for omega() is determined by ellinit() + E_pari = pari.ellinit(ainvs, precision=prec) + w1, w2 = E_pari.omega() + return R(w1), C(w2) if algorithm!='sage': raise ValueError("invalid value of 'algorithm' parameter") diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index a5d325d41a1..6d6459079d4 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -131,6 +131,24 @@ def p_saturation(Plist, p, sieve=True, lin_combs = dict(), verbose=False): sage: p_saturation([res[2],P-6*Q,R],11) (True, {}) + + TESTS: + + See :trac:`27387`:: + + sage: K. = NumberField(x^2-x-26) + sage: E = EllipticCurve([a,1-a,0,93-16*a, 3150-560*a]) + sage: P = E([65-35*a/3, (959*a-5377)/9]) + sage: T = E.torsion_points()[0] + sage: from sage.schemes.elliptic_curves.saturation import p_saturation + sage: p_saturation([P,T],2,True, {}, True) + Using sieve method to saturate... + ... + -- points were not 2-saturated, gaining index 2 + (False, 0, (-1/4*a + 3/4 : 59/8*a - 317/8 : 1)) + sage: p_saturation([P,T],2,False, {}) + (False, 0, (-1/4*a + 3/4 : 59/8*a - 317/8 : 1)) + """ # This code does a lot of residue field construction and elliptic curve # group structure computations, and would benefit immensely if those @@ -184,7 +202,10 @@ def projections(Q, p): Returns a list of 0, 1 or 2 vectors in \F_p^n """ - Ek = E.reduction(Q) + # NB we do not do E.reduction(Q) since that may change the + # model which will cause problems when we reduce points. + # see trac #27387 + Ek = E.change_ring(K.residue_field(Q)) G = Ek.abelian_group() # cached! if not p.divides(G.order()): @@ -282,9 +303,10 @@ def a(pt,g): rankA = 0 count = 0 from sage.sets.primes import Primes + Edisc = E.discriminant() for q in Primes(): for Q in K.primes_above(q, degree=1): - if E.has_bad_reduction(Q): + if not E.is_local_integral_model(Q) or Edisc.valuation(Q)!=0: continue vecs = projections(Q,p) if len(vecs) == 0: diff --git a/src/sage/schemes/generic/divisor.py b/src/sage/schemes/generic/divisor.py index c3538fdca47..49e07357223 100644 --- a/src/sage/schemes/generic/divisor.py +++ b/src/sage/schemes/generic/divisor.py @@ -295,12 +295,12 @@ def __init__(self, v, parent=None, check=True, reduce=True): sage: Divisor_curve([(1,P)], parent=DivisorGroup(E)) (x, y) """ - from sage.schemes.generic.divisor_group import DivisorGroup_generic, DivisorGroup_curve + from sage.schemes.generic.divisor_group import DivisorGroup_curve if not isinstance(v, (list, tuple)): v = [(1,v)] if parent is None: - if len(v) > 0: + if v: t = v[0] if isinstance(t, tuple) and len(t) == 2: try: @@ -312,12 +312,12 @@ def __init__(self, v, parent=None, check=True, reduce=True): C = t.scheme() except TypeError: raise TypeError("Argument v (= %s) must consist of multiplicities and points on a scheme.") - parent = DivisorGroup(C) + parent = DivisorGroup_curve(C) else: raise TypeError("Argument v (= %s) must consist of multiplicities and points on a scheme.") else: if not isinstance(parent, DivisorGroup_curve): - raise TypeError("parent (of type %s) must be a DivisorGroup_curve"%type(parent)) + raise TypeError("parent (of type %s) must be a DivisorGroup_curve" % type(parent)) C = parent.scheme() if len(v) < 1: diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index d49bfc9fc3c..eac17abfeb4 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -40,11 +40,7 @@ from sage.categories.homset import HomsetWithBase from sage.structure.factory import UniqueFactory -from sage.rings.all import ZZ, QQ, CommutativeRing -from sage.arith.all import gcd - -from sage.rings.rational_field import is_RationalField -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.all import ZZ from sage.rings.ring import CommutativeRing from sage.schemes.generic.scheme import AffineScheme, is_AffineScheme diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index 286f70a1063..a50d866cdc2 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -7,9 +7,7 @@ - Volker Braun (2011-08-11): documenting, improving, refactoring. """ - - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Volker Braun # Copyright (C) 2008 Kiran Kedlaya # Copyright (C) 2005 David Kohel @@ -18,14 +16,12 @@ # 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 sage.structure.parent import Parent from sage.misc.all import cached_method -from sage.rings.all import (IntegerRing, - ZZ, GF, PowerSeriesRing, - Rationals, CommutativeRing) +from sage.rings.all import (ZZ, CommutativeRing) from sage.rings.ideal import is_Ideal from sage.structure.unique_representation import UniqueRepresentation @@ -1142,13 +1138,16 @@ def base_extend(self, R): Spectrum of Integer Ring sage: Spec_ZZ.base_extend(QQ) Spectrum of Rational Field + + sage: Spec(ZZ['x']).base_extend(Spec(QQ)) + Spectrum of Univariate Polynomial Ring in x over Rational Field """ from sage.categories.commutative_rings import CommutativeRings if R in CommutativeRings(): return AffineScheme(self.coordinate_ring().base_extend(R), self.base_ring()) if not self.base_scheme() == R.base_scheme(): raise ValueError('the new base scheme must be a scheme over the old base scheme') - return AffineScheme(self.coordinate_ring().base_extend(new_base.coordinate_ring()), + return AffineScheme(self.coordinate_ring().base_extend(R.coordinate_ring()), self.base_ring()) def _point_homset(self, *args, **kwds): diff --git a/src/sage/schemes/generic/spec.py b/src/sage/schemes/generic/spec.py index 30dcdd05544..346d6ff793d 100644 --- a/src/sage/schemes/generic/spec.py +++ b/src/sage/schemes/generic/spec.py @@ -8,17 +8,18 @@ - Peter Bruin (2014): rewrite Spec as a functor """ -#******************************************************************************* +# ****************************************************************************** # Copyright (C) 2006 William Stein # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#******************************************************************************* +# https://www.gnu.org/licenses/ +# ****************************************************************************** from sage.categories.functor import Functor from sage.rings.integer_ring import ZZ -from sage.schemes.generic.scheme import AffineScheme, is_AffineScheme +from sage.schemes.generic.scheme import AffineScheme from sage.structure.unique_representation import UniqueRepresentation + def Spec(R, S=None): r""" Apply the Spec functor to `R`. @@ -81,6 +82,7 @@ def Spec(R, S=None): """ return SpecFunctor(S)(R) + class SpecFunctor(Functor, UniqueRepresentation): """ The Spec functor. @@ -96,7 +98,7 @@ def __init__(self, base_ring=None): Spec functor from Category of commutative rings to Category of schemes over Rational Field """ - from sage.categories.all import CommutativeAlgebras, CommutativeRings, Schemes + from sage.categories.all import CommutativeRings, Schemes if base_ring is None: domain = CommutativeRings() @@ -189,8 +191,5 @@ def _apply_functor_to_morphism(self, f): # Compatibility with older versions of this module -from sage.misc.superseded import deprecated_function_alias -is_Spec = deprecated_function_alias(16158, is_AffineScheme) - from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.schemes.generic.spec', 'Spec', AffineScheme) diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2_generic.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2_generic.py index 8acd3c95047..472b650f4b1 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2_generic.py @@ -1,12 +1,12 @@ """ Hyperelliptic curves of genus 2 over a general ring """ -from __future__ import absolute_import -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 David Kohel # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import absolute_import from . import hyperelliptic_generic from . import jacobian_g2 @@ -69,8 +69,7 @@ def kummer_morphism(self): pass if not self.is_odd_degree(): raise TypeError("Kummer embedding not determined for even degree model curves.") - J = self.jacobian() - K = J.kummer_surface() + self.jacobian().kummer_surface() return self._kummer_morphism def clebsch_invariants(self): diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py index 2aa2ce0e6e7..24a1c988f15 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py @@ -17,7 +17,8 @@ from . import hyperelliptic_generic -from sage.rings.all import PowerSeriesRing, PolynomialRing, ZZ, QQ, O, pAdicField, GF, RR, RationalField, Infinity +from sage.rings.all import (PowerSeriesRing, PolynomialRing, ZZ, QQ, + pAdicField, GF, RR, RationalField, Infinity) from sage.functions.log import log from sage.modules.free_module import VectorSpace from sage.matrix.constructor import matrix @@ -471,7 +472,6 @@ def teichmuller(self, P): K = P[0].parent() x = K.teichmuller(P[0]) pts = self.lift_x(x, all=True) - p = K.prime() if (pts[0][1] - P[1]).valuation() > 0: return pts[0] else: @@ -585,7 +585,6 @@ def coleman_integrals_on_basis(self, P, Q, algorithm=None): prof("teichmuller") PP = TP = self.teichmuller(P) QQ = TQ = self.teichmuller(Q) - evalP, evalQ = TP, TQ else: prof("frobPQ") TP = self.frobenius(P) @@ -1163,9 +1162,8 @@ def coleman_integral_P_to_S(self,w,P,S): """ prec = self.base_ring().precision_cap() deg = S[0].parent().defining_polynomial().degree() - prec2= prec*deg + prec2 = prec * deg x,y = self.local_coord(P,prec2) - g = self.genus() int_sing = (w.coeff()(x,y)*x.derivative()/(2*y)).integral() int_sing_a = int_sing(S[1]) return int_sing_a @@ -1250,16 +1248,15 @@ def S_to_Q(self,S,Q): b = V(L) M_sys = matrix(K, M_frob).transpose() - 1 B = (~M_sys) - BL = B.list() v = [c.valuation() for c in B.list()] - vv= min(v) + vv = min(v) B = (p**(-vv)*B).change_ring(K) B = p**(vv)*B return B*(b-S_to_FS-FQ_to_Q) def coleman_integral_S_to_Q(self,w,S,Q): r""" - Computes the Coleman integral `\int_S^Q w` + Compute the Coleman integral `\int_S^Q w` **one should be able to feed `S,Q` into coleman_integral, but currently that segfaults** diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 35d261786db..ee97899b903 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -1375,7 +1375,7 @@ def adjusted_prec(p, prec): def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): r""" - Computes the matrix of Frobenius on Monsky-Washnitzer cohomology, + Compute the matrix of Frobenius on Monsky-Washnitzer cohomology, with respect to the basis `(dx/y, x dx/y)`. INPUT: @@ -1386,10 +1386,9 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): `\ZZ/(p^M)\ZZ`-algebra in which the matrix of frobenius will be constructed. - - ``p`` -- prime = 5 for which E has good reduction + - ``p`` -- prime >= 5 for which E has good reduction - - ``M`` -- integer = 2; `p` -adic precision of - the coefficient ring + - ``M`` -- integer >= 2; `p` -adic precision of the coefficient ring - ``trace`` -- (optional) the trace of the matrix, if known in advance. This is easy to compute because it is just the @@ -1576,10 +1575,10 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): [ 847 + 668*t + 81*t^2 + 424*t^3 + O(t^4) 185 + 341*t + 171*t^2 + 642*t^3 + O(t^4)] The trace trick should work for power series rings too, even in the - badly- conditioned case. Unfortunately I don't know how to compute - the trace in advance, so I'm not sure exactly how this would help. + badly-conditioned case. Unfortunately I do not know how to compute + the trace in advance, so I am not sure exactly how this would help. Also, I suspect the running time will be dominated by the - expansion, so the trace trick won't really speed things up anyway. + expansion, so the trace trick will not really speed things up anyway. Another problem is that the determinant is not always p:: sage: B.det() # long time @@ -1589,7 +1588,7 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): that if you substitute t - 11t, you do get the constant series p (mod p\*\*prec). Similarly for the trace. And since the parameter only really makes sense when it is divisible by p anyway, perhaps - this isn't a problem after all. + this is not a problem after all. """ M = int(M) if M < 2: diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index 1a294126b05..b4714f86dc5 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -411,7 +411,7 @@ def has_rational_point(self, point = False, delegates the task to the Magma computer algebra system. - EXAMPLES: + EXAMPLES:: sage: Conic(RR, [1, 1, 1]).has_rational_point() False diff --git a/src/sage/schemes/product_projective/homset.py b/src/sage/schemes/product_projective/homset.py index bf1810b07e5..0b1f050bd8c 100644 --- a/src/sage/schemes/product_projective/homset.py +++ b/src/sage/schemes/product_projective/homset.py @@ -146,10 +146,7 @@ def points(self, **kwds): (2 : 1 : 1 , 0 : 1), (2 : 1 : 1 , 1 : 0), (2 : 1 : 1 , 1 : 1), (2 : 1 : 1 , 2 : 1), (2 : 2 : 1 , 0 : 1), (2 : 2 : 1 , 1 : 0), (2 : 2 : 1 , 1 : 1), (2 : 2 : 1 , 2 : 1)] """ - B = kwds.pop('bound', 0) - tol = kwds.pop('tolerance', 1e-2) - prec = kwds.pop('precision', 53) - + B = kwds.pop('bound', 0) X = self.codomain() from sage.schemes.product_projective.space import is_ProductProjectiveSpaces @@ -183,4 +180,4 @@ def points(self, **kwds): from sage.schemes.product_projective.rational_point import enum_product_projective_finite_field return enum_product_projective_finite_field(self) else: - raise TypeError("unable to enumerate points over %s"%R) + raise TypeError("unable to enumerate points over %s" % R) diff --git a/src/sage/schemes/product_projective/point.py b/src/sage/schemes/product_projective/point.py index 585bdfa6802..5dedc7a17a6 100644 --- a/src/sage/schemes/product_projective/point.py +++ b/src/sage/schemes/product_projective/point.py @@ -11,15 +11,15 @@ sage: P1xP1([2, 1, 3, 1]) (2 : 1 , 3 : 1) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Volker Braun # Ben Hutz # # 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 copy import copy from sage.categories.integral_domains import IntegralDomains from sage.categories.number_fields import NumberFields @@ -125,7 +125,7 @@ def __getitem__(self, i): sage: P[1][0] 1 """ - return(self._points[i]) + return self._points[i] def _repr_(self): r""" @@ -140,7 +140,8 @@ def _repr_(self): sage: P._repr_() '(1 : 2 : 3 , 4 : 5 : 6)' """ - return('(%s)'%(" , ".join((" : ".join([repr(f) for f in Q])) for Q in self._points))) + return '(%s)' % (" , ".join((" : ".join(repr(f) for f in Q)) + for Q in self._points)) def _richcmp_(self, right, op): r""" @@ -219,7 +220,7 @@ def __copy__(self): True """ P = [copy(self[i]) for i in range(self.codomain().ambient_space().num_components())] - return(self.codomain().point(P, False)) + return (self.codomain().point(P, False)) def __iter__(self): r""" @@ -239,10 +240,21 @@ def __iter__(self): sage: list(P) [2, 1, 0, 1] """ - L = [] - for P in self._points: - L += P._coords - return iter(L) + return (x for P in self._points for x in P._coords) + + def __len__(self): + """ + Return the total number of coordinates in ``self``. + + EXAMPLES:: + + sage: T = ProductProjectiveSpaces([1, 1], QQ, 'x') + sage: P = T([2, 1, 0, 1]) + sage: len(P) + 4 + """ + image = self.codomain().ambient_space() + return image.dimension() + image.num_components() def __hash__(self): """ @@ -292,7 +304,7 @@ def __hash__(self): def normalize_coordinates(self): r""" - Removes common factors (componentwise) from the coordinates of this point (including `-1`). + Remove common factors (componentwise) from the coordinates of this point (including `-1`). OUTPUT: None. @@ -309,7 +321,7 @@ def normalize_coordinates(self): def dehomogenize(self, L): r""" - Dehomogenizes `k^{th}` point at `L[k]^{th}` coordinate. + Dehomogenize `k^{th}` point at `L[k]^{th}` coordinate. This function computes the appropriate affine patch using ``L`` and then returns the dehomogenized point on of this affine space. @@ -373,15 +385,15 @@ def scale_by(self, t): (10 : 20 , 15 : 4 , 2 : 6) """ if not isinstance(t, (tuple, list)): - raise TypeError("%s must be a list or tuple"%t) + raise TypeError("%s must be a list or tuple" % t) if len(t) != self.codomain().ambient_space().num_components(): - raise TypeError("%s must have same number of components as %r"%(t, self)) + raise TypeError("%s must have same number of components as %r" % (t, self)) for i in range(self.codomain().ambient_space().num_components()): self[i].scale_by(t[i]) def change_ring(self, R, **kwds): r""" - Returns a new :class:`ProductProjectiveSpaces_point` which is this point coerced to ``R``. + Return a new :class:`ProductProjectiveSpaces_point` which is this point coerced to ``R``. If the keyword ``check`` is ``True``, then the initialization checks are performed. The user may specify the embedding into ``R`` with a keyword. @@ -409,8 +421,8 @@ def change_ring(self, R, **kwds): """ check = kwds.get('check', True) S = self.codomain().change_ring(R) - Q = [P.change_ring(R,**kwds) for P in self._points] - return(S.point(Q, check)) + Q = [P.change_ring(R, **kwds) for P in self._points] + return S.point(Q, check) def nth_iterate(self, f, n, normalize=False): r""" @@ -445,12 +457,12 @@ def nth_iterate(self, f, n, normalize=False): .. TODO:: Is there a more efficient way to do this? """ from sage.misc.superseded import deprecation - deprecation(23479, "use f.nth_iterate(P, n, normalize) instead") + deprecation(23497, "use f.nth_iterate(P, n, normalize) instead") return f.nth_iterate(self, n, normalize) def orbit(self, f, N, **kwds): r""" - Returns the orbit this point by ``f``. + Return the orbit this point by ``f``. If ``N`` is an integer it returns `[P, self(P), \ldots,self^N(P)]`. @@ -487,12 +499,12 @@ def orbit(self, f, N, **kwds): [(1 : 3 , 1 : 2), (1 : 3 , -7 : 4), (1 : 3 , 407 : 112), (1 : 3 , 66014215 : 5105408)] """ from sage.misc.superseded import deprecation - deprecation(23479, "use f.orbit(P, N, **kwds) instead") + deprecation(23497, "use f.orbit(P, N, **kwds) instead") return f.orbit(self, N, **kwds) def global_height(self, prec=None): r""" - Returns the absolute logarithmic height of the point. + Return the absolute logarithmic height of the point. This function computes the maximum of global height of each component point in the product. Global height of component @@ -546,11 +558,11 @@ def global_height(self, prec=None): def local_height(self, v, prec=None): r""" - Returns the maximum of the local height of the coordinates of this point. + Return the maximum of the local height of the coordinates of this point. - This function computes the maximum of local height of each component point - in the product. Local height of component point is computed using function - for projective point. + This function computes the maximum of local height of each + component point in the product. Local height of component + point is computed using function for projective point. INPUT: @@ -580,10 +592,11 @@ def local_height(self, v, prec=None): K = FractionField(self.domain().base_ring()) if K not in NumberFields(): raise TypeError("must be over a number field or a number field order") - + n = self.codomain().ambient_space().num_components() return max(self[i].local_height(v, prec=prec) for i in range(n)) + class ProductProjectiveSpaces_point_field(ProductProjectiveSpaces_point_ring): def intersection_multiplicity(self, X): @@ -641,5 +654,6 @@ def multiplicity(self): raise TypeError("this point must be a point on a subscheme of a product of projective spaces") return self.codomain().multiplicity(self) + class ProductProjectiveSpaces_point_finite_field(ProductProjectiveSpaces_point_field): pass diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 54d38d6181d..3559538bd0b 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -44,7 +44,7 @@ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Volker Braun # Ben Hutz # @@ -52,23 +52,23 @@ # 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.schemes.generic.scheme import is_Scheme from sage.schemes.product_projective.space import is_ProductProjectiveSpaces -from sage.misc.mrange import xmrange + def enum_product_projective_rational_field(X, B): r""" - Enumerates projective, rational points on scheme ``X`` of height up to + Enumerate projective, rational points on scheme ``X`` of height up to bound ``B``. INPUT: - - ``X`` - a scheme or set of abstract rational points of a scheme + - ``X`` -- a scheme or set of abstract rational points of a scheme - - ``B`` - a positive integer bound + - ``B`` -- a positive integer bound OUTPUT: diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index 3b8cd8ff246..17e071483df 100644 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -42,7 +42,6 @@ import six from sage.misc.cachefunc import cached_method -from sage.misc.mrange import xmrange from sage.misc.all import prod from sage.rings.all import (PolynomialRing, QQ, Integer, CommutativeRing) from sage.rings.finite_rings.finite_field_constructor import is_FiniteField @@ -78,9 +77,10 @@ def is_ProductProjectiveSpaces(x): """ return isinstance(x, ProductProjectiveSpaces_ring) + def ProductProjectiveSpaces(n, R=None, names='x'): r""" - Returns the Cartesian product of projective spaces. + Return the Cartesian product of projective spaces. Can input either a list of projective space over the same base \ ring or the list of dimensions, the base ring, and the variable names. @@ -1210,7 +1210,6 @@ def points_of_bounded_height(self, **kwds): for i in range(1, len(dim)): dim_prefix.append(dim_prefix[i] + dim[i]) - pts = [] P = [] for i in range(m): pt = next(iters[i]) diff --git a/src/sage/schemes/projective/projective_homset.py b/src/sage/schemes/projective/projective_homset.py index bc9e7277a47..c609fdfbd2b 100644 --- a/src/sage/schemes/projective/projective_homset.py +++ b/src/sage/schemes/projective/projective_homset.py @@ -379,7 +379,6 @@ def numerical_points(self, F=None, **kwds): raise TypeError('base ring must be a number field') PP = X.ambient_space().change_ring(F) - from sage.schemes.projective.projective_space import is_ProjectiveSpace if not is_ProjectiveSpace(X) and X.base_ring() in Fields(): #Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() @@ -398,7 +397,6 @@ def numerical_points(self, F=None, **kwds): R = PolynomialRing(BR, N + 1, PS.variable_names(), order='lex') RF = R.change_ring(F) I = R.ideal(X.defining_polynomials()) - I0 = R.ideal(0) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): diff --git a/src/sage/schemes/projective/projective_rational_point.py b/src/sage/schemes/projective/projective_rational_point.py index 361f9f4f002..30a3198ac4f 100644 --- a/src/sage/schemes/projective/projective_rational_point.py +++ b/src/sage/schemes/projective/projective_rational_point.py @@ -127,13 +127,12 @@ def enum_projective_rational_field(X, B): - John Cremona and Charlie Turner (06-2010) """ from sage.schemes.projective.projective_space import is_ProjectiveSpace - if(is_Scheme(X)): - if (not is_ProjectiveSpace(X.ambient_space())): + if is_Scheme(X): + if not is_ProjectiveSpace(X.ambient_space()): raise TypeError("ambient space must be projective space over the rational field") X = X(X.base_ring()) - else: - if (not is_ProjectiveSpace(X.codomain().ambient_space())): - raise TypeError("codomain must be projective space over the rational field") + elif not is_ProjectiveSpace(X.codomain().ambient_space()): + raise TypeError("codomain must be projective space over the rational field") n = X.codomain().ambient_space().ngens() zero = (0,) * n @@ -286,13 +285,12 @@ def enum_projective_finite_field(X): - John Cremona and Charlie Turner (06-2010). """ from sage.schemes.projective.projective_space import is_ProjectiveSpace - if(is_Scheme(X)): - if (not is_ProjectiveSpace(X.ambient_space())): + if is_Scheme(X): + if not is_ProjectiveSpace(X.ambient_space()): raise TypeError("ambient space must be projective space over a finite") X = X(X.base_ring()) - else: - if (not is_ProjectiveSpace(X.codomain().ambient_space())): - raise TypeError("codomain must be projective space over a finite field") + elif not is_ProjectiveSpace(X.codomain().ambient_space()): + raise TypeError("codomain must be projective space over a finite field") n = X.codomain().ambient_space().ngens()-1 F = X.value_ring() @@ -511,9 +509,11 @@ def parallel_function_combination(point_p_max): continue try: - rat_points.add(X(list(A[1]))) # checks if this point lies on X or not - except: + pt = X(list(A[1])) + except TypeError: pass + else: + rat_points.add(pt) return [list(_) for _ in rat_points] diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index d2d8f8bfb2b..94c753c6082 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -837,7 +837,7 @@ def _latex_generic_point(self, v=None): sage: P. = ProjectiveSpace(2, ZZ) sage: P._latex_generic_point([z*y-x^2]) - '\\left(- x^{2} + y z\\right)' + '\\left(-x^{2} + y z\\right)' sage: P._latex_generic_point() '\\left(x : y : z\\right)' """ diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py index 59e86092532..b6374ec408b 100644 --- a/src/sage/schemes/projective/projective_subscheme.py +++ b/src/sage/schemes/projective/projective_subscheme.py @@ -11,14 +11,14 @@ """ #***************************************************************************** -# Copyright (C) 2005 William Stein -# Copyright (C) 2013 Ben Hutz - +# Copyright (C) 2005 William Stein +# Copyright (C) 2013 Ben Hutz # -# 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/ +# This 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.arith.misc import binomial diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 8ee7c2407f8..d0975e773b7 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -36,7 +36,7 @@ sage: all(abs(a) < 1e-20 for a in (M-M.T).list()) True - sage: iM=Matrix(RDF,3,3,[a.imag_part() for a in M.list()]) + sage: iM = Matrix(RDF,3,3,[a.imag_part() for a in M.list()]) sage: iM.is_positive_definite() True @@ -53,38 +53,39 @@ sage: all(len(a.minpoly().roots(K)) == a.minpoly().degree() for a in A) True """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Alexandre Zotine, Nils Bruin # # This 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 __future__ import division +from six.moves import range from scipy.spatial import Voronoi -from sage.misc.cachefunc import cached_method -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.rings.complex_field import ComplexField, CDF -from sage.rings.real_mpfr import RealField -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.groups.perm_gps.permgroup_named import SymmetricGroup +from sage.arith.misc import GCD, algdep from sage.arith.srange import srange from sage.ext.fast_callable import fast_callable from sage.graphs.graph import Graph +from sage.groups.matrix_gps.finitely_generated import MatrixGroup +from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.matrix.constructor import Matrix, matrix +from sage.matrix.special import block_matrix +from sage.misc.cachefunc import cached_method +from sage.misc.misc_c import prod from sage.modules.free_module import VectorSpace from sage.numerical.gauss_legendre import integrate_vector -from sage.misc.misc_c import prod -from sage.arith.misc import algdep -from sage.groups.matrix_gps.finitely_generated import MatrixGroup +from sage.rings.complex_field import ComplexField, CDF +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.qqbar import number_field_elements_from_algebraics -from sage.matrix.special import block_matrix +from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RealField import sage.libs.mpmath.all as mpall -from sage.arith.misc import GCD + def voronoi_ghost(cpoints, n=6, CC=CDF): r""" @@ -132,7 +133,8 @@ def voronoi_ghost(cpoints, n=6, CC=CDF): extra_points = [average+radius*z**i for i in range(n)] return [(c.real_part(),c.imag_part()) for c in cpoints+extra_points] -def bisect(L,t): + +def bisect(L, t): r""" Find position in a sorted list using bisection. @@ -592,7 +594,7 @@ def _compute_delta(self, z1, epsilon, wvalues=None): - ``epsilon`` -- a real number, which is the minimum distance between the w-values above ``z1`` - - ``wvalues`` -- a list (default: None). If specified, saves + - ``wvalues`` -- a list (default: ``None``). If specified, saves recomputation. OUTPUT: @@ -608,7 +610,7 @@ def _compute_delta(self, z1, epsilon, wvalues=None): sage: f = w^2 - z^4 + 1 sage: S = RiemannSurface(f) - Pick a point which lies on the voronoi diagram, and compute an + Pick a point which lies on the Voronoi diagram, and compute an appropriate epsilon:: sage: z1 = S._vertices[0] @@ -618,7 +620,7 @@ def _compute_delta(self, z1, epsilon, wvalues=None): sage: S._compute_delta(z1, epsilon) # abs tol 1e-8 0.152628501142363 - If the Riemann surface doesn't have certified homotopy continuation, + If the Riemann surface does not have certified homotopy continuation, then the delta will just be the minimum distance away from a branch point:: @@ -635,23 +637,27 @@ def _compute_delta(self, z1, epsilon, wvalues=None): wvalues = self.w_values(z1) # For computation of rho. Need the branch locus + roots of a0. badpoints = self.branch_locus + self._a0roots - rho = min(abs(z1 - z) for z in badpoints)/2 - Y = max(abs(self._fastcall_dfdz(z1,wi)/self._fastcall_dfdw(z1,wi)) for wi in wvalues) + rho = min(abs(z1 - z) for z in badpoints) / 2 + Y = max(abs(self._fastcall_dfdz(z1, wi)/self._fastcall_dfdw(z1, wi)) + for wi in wvalues) # compute M - upperbounds = [sum(ak[k]*(abs(z1) + rho)**k for k in range(ak.degree())) for ak in self._aks] + upperbounds = [sum(ak[k] * (abs(z1) + rho)**k + for k in range(ak.degree())) + for ak in self._aks] upperbounds.reverse() # If a0 is a constant polynomial, it is obviously bounded below. if self._a0roots == []: - lowerbound = self._CC(self._a0)/2 + lowerbound = self._CC(self._a0) / 2 else: - lowerbound = self._a0[self._a0.degree()]*prod(abs((zk - z1) - rho) for zk in self._a0roots)/2 - M = 2*max(abs((upperbounds[k]/lowerbound))**(1/(k+1)) for k in range(self.degree-1)) - return rho*( ((rho*Y - epsilon)**2 + 4*epsilon*M).sqrt() - (rho*Y + epsilon))/(2*M - 2*rho*Y) + lowerbound = self._a0[self._a0.degree()]*prod(abs((zk - z1) - rho) for zk in self._a0roots) / 2 + M = 2 * max((upperbounds[k]/lowerbound).abs().nth_root(k+1) + for k in range(self.degree-1)) + return rho*(((rho*Y - epsilon)**2 + 4*epsilon*M).sqrt() - (rho*Y + epsilon))/(2*M - 2*rho*Y) else: # Instead, we just compute the minimum distance between branch # points and the point in question. - return min([abs(b-z1) for b in self.branch_locus])/2 + return min(abs(b - z1) for b in self.branch_locus) / 2 def homotopy_continuation(self, edge): r""" @@ -1136,28 +1142,32 @@ def homology_basis(self): sage: R. = QQ[] sage: g = w^2 - z^4 + 1 sage: S = RiemannSurface(g) - sage: S.homology_basis() - [[(1, - [(3, 1), - (5, 0), - (9, 0), - (10, 0), - (2, 0), - (4, 0), - (7, 1), - (10, 1), - (3, 1)])], - [(1, - [(8, 0), - (6, 0), - (7, 0), - (10, 0), - (2, 0), - (4, 0), - (7, 1), - (10, 1), - (9, 1), - (8, 0)])]] + sage: S.homology_basis() #random + [[(1, [(3, 1), (5, 0), (9, 0), (10, 0), (2, 0), (4, 0), + (7, 1), (10, 1), (3, 1)])], + [(1, [(8, 0), (6, 0), (7, 0), (10, 0), (2, 0), (4, 0), + (7, 1), (10, 1), (9, 1), (8, 0)])]] + + In order to check that the answer returned above is reasonable, we + test some basic properties. We express the faces of the downstairs graph + as ZZ-linear combinations of the edges and check that the projection + of the homology basis upstairs projects down to independent linear + combinations of an even number of faces:: + + sage: dg = S.downstairs_graph() + sage: edges = dg.edges() + sage: E = ZZ^len(edges) + sage: edge_to_E = { e[:2]: E.gen(i) for i,e in enumerate(edges)} + sage: edge_to_E.update({ (e[1],e[0]): -E.gen(i) for i,e in enumerate(edges)}) + sage: face_span = E.submodule([sum(edge_to_E[e] for e in f) for f in dg.faces()]) + sage: def path_to_E(path): + ....: k,P = path + ....: return k*sum(edge_to_E[(P[i][0],P[i+1][0])] for i in range(len(P)-1)) + sage: hom_basis = [sum(path_to_E(p) for p in loop) for loop in S.homology_basis()] + sage: face_span.submodule(hom_basis).rank() + 2 + sage: [sum(face_span.coordinate_vector(b))%2 for b in hom_basis] + [0, 0] """ if self.genus == 0: return [] @@ -1416,7 +1426,7 @@ def cohomology_basis(self, option=1): differentials `g/(df/dw) dz`, where `f(z,w)=0` is the equation specifying the Riemann surface. - EXAMPLES: + EXAMPLES:: sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R. = QQ[] @@ -1488,8 +1498,12 @@ def matrix_of_integral_values(self, differentials): sage: R. = QQ[] sage: S = RiemannSurface(x^3 + y^3 + 1) sage: B = S.cohomology_basis() - sage: S.matrix_of_integral_values(B) #abs tol 1e-12 - [ 0.883319375142725 - 1.52995403705719*I 1.76663875028545 + 5.55111512312578e-17*I] + sage: m = S.matrix_of_integral_values(B) + sage: parent(m) + Full MatrixSpace of 1 by 2 dense matrices over Complex Field with 53 bits of precision + sage: (m[0,0]/m[0,1]).algdep(3).degree() #curve is CM, so the period is quadratic + 2 + """ cycles = self.homology_basis() def normalize_pairs(L): @@ -1693,11 +1707,14 @@ def endomorphism_basis(self, b=None, r=None): sage: from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface sage: R. = QQ[] sage: S = RiemannSurface(x^3 + y^3 + 1) - sage: S.endomorphism_basis() + sage: B = S.endomorphism_basis(); B #random [ [1 0] [ 0 -1] [0 1], [ 1 1] ] + sage: sorted([b.minpoly().disc() for b in B]) + [-3, 1] + """ M = self.riemann_matrix() return integer_matrix_relations(M,M,b,r) @@ -1775,7 +1792,7 @@ def tangent_representation_numerical(self, Rs, other = None): sage: P = S.period_matrix() sage: Rs = S.endomorphism_basis() sage: Ts = S.tangent_representation_numerical(Rs) - sage: all([ ((T*P - P*R).norm() < 2^(-80)) for [ T, R ] in zip(Ts, Rs) ]) + sage: all(((T*P - P*R).norm() < 2^(-80)) for [T, R] in zip(Ts, Rs)) True """ if not other: @@ -1784,16 +1801,16 @@ def tangent_representation_numerical(self, Rs, other = None): CCP = P.base_ring() g = self.genus Q = other.period_matrix() - Ptsubinv = numerical_inverse((P.transpose())[range(g)]) - Ts = [ ] + Ptsubinv = numerical_inverse((P.transpose())[list(range(g))]) + Ts = [] for R in Rs: - QRtsub = ((Q * R).transpose())[range(g)] + QRtsub = ((Q * R).transpose())[list(range(g))] Tt = Ptsubinv * QRtsub T = Tt.transpose().change_ring(CCP) Ts.append(T) return Ts - def tangent_representation_algebraic(self, Rs, other = None, epscomp = None): + def tangent_representation_algebraic(self, Rs, other=None, epscomp=None): r""" Compute the algebraic tangent representations corresponding to the homology representations in ``Rs``. @@ -1949,8 +1966,8 @@ def symplectic_isomorphisms(self, other = None, hom_basis = None, b = None, r = sage: Q = Y.period_matrix() sage: Rs = X.symplectic_isomorphisms(Y) sage: Ts = X.tangent_representation_numerical(Rs, other = Y) - sage: test1 = all([ ((T*P - Q*R).norm() < 2^(-80)) for [ T, R ] in zip(Ts, Rs) ]) - sage: test2 = all([ det(R) == 1 for R in Rs ]) + sage: test1 = all(((T*P - Q*R).norm() < 2^(-80)) for [T, R] in zip(Ts, Rs)) + sage: test2 = all(det(R) == 1 for R in Rs) sage: test1 and test2 True """ diff --git a/src/sage/schemes/toric/chow_group.py b/src/sage/schemes/toric/chow_group.py index 23b8162ef96..1aed9c9e0b6 100644 --- a/src/sage/schemes/toric/chow_group.py +++ b/src/sage/schemes/toric/chow_group.py @@ -69,7 +69,7 @@ (Z, C7, C2 x C2 x Z^5, Z) sage: A.degree(2).ngens() 7 - sage: a = sum( A.gen(i) * (i+1) for i in range(0,A.ngens()) ) # an element of A + sage: a = sum( A.gen(i) * (i+1) for i in range(A.ngens()) ) # an element of A sage: a # long time (2s on sage.math, 2011) ( 3 | 1 mod 7 | 0 mod 2, 1 mod 2, 4, 5, 6, 7, 8 | 9 ) @@ -116,17 +116,17 @@ ( 1 | 4 mod 7 | 1 mod 2, 1 mod 2, 1, 1, 1, 1, 1 | 1 ) sage: mixed.project_to_degree(1) ( 0 | 4 mod 7 | 0 mod 2, 0 mod 2, 0, 0, 0, 0, 0 | 0 ) - sage: sum( mixed.project_to_degree(i) for i in range(0,X.dimension()+1) ) == mixed + sage: sum( mixed.project_to_degree(i) for i in range(X.dimension()+1) ) == mixed True """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.all import flatten from sage.misc.fast_methods import WithEqualityById @@ -193,7 +193,6 @@ def __init__(self, parent, v, check=True): """ FGP_Element.__init__(self, parent, v, check) - def _repr_(self): r""" Return a string representation of the Chow cycle. @@ -217,30 +216,29 @@ def _repr_(self): sage: A = X.Chow_group() sage: A.degree() (Z, 0, C2 x Z^5, Z) - sage: sum( A.gen(i) * (i+1) for i in range(0,A.ngens()) ) + sage: sum( A.gen(i) * (i+1) for i in range(A.ngens()) ) ( 2 || 1 mod 2, 3, 4, 5, 6, 7 | 8 ) """ A = self.parent() s = '(' - for degree in range(0,A.scheme().dimension()+1): - if degree>0: + for degree in range(A.scheme().dimension() + 1): + if degree: s += '|' generators = A.gens(degree=degree) coefficients = A.coordinate_vector(self, degree=degree) - if len(generators)>0: + if generators: s += ' ' for i, gen in enumerate(generators): - if i>0: + if i > 0: s += ', ' s += str(coefficients[i]) if gen.order() != Infinity: - s += ' mod '+str(gen.order()) - if len(generators)>0: + s += ' mod ' + str(gen.order()) + if generators: s += ' ' s += ')' return s - def degree(self): r""" The degree of the Chow cycle. @@ -296,7 +294,7 @@ def project_to_degree(self, degree): """ ambient_dim = self.parent()._variety.dimension() v = list(self.lift()) - for i in range(0,len(v)): + for i in range(len(v)): cone = self.parent()._cones[i] if cone.dim() != ambient_dim-degree: v[i] = 0 @@ -951,7 +949,7 @@ def degree(self, k=None): pass self._degree = tuple(ChowGroup_degree_class(self,d) - for d in range(0,self._variety.dimension()+1)) + for d in range(self._variety.dimension() + 1)) return self._degree @@ -1153,27 +1151,26 @@ def _repr_(self): 'Q' """ invariants = self._module.invariants() - if len(invariants)==0: + if not invariants: return '0' - free = [x for x in invariants if x==0] - tors = [x for x in invariants if x> 0] + free = [x for x in invariants if x == 0] + tors = [x for x in invariants if x > 0] - if self._Chow_group.base_ring()==ZZ: + if self._Chow_group.base_ring() is ZZ: ring = 'Z' - elif self._Chow_group.base_ring()==QQ: + elif self._Chow_group.base_ring() is QQ: ring = 'Q' else: raise NotImplementedError('Base ring must be ZZ or QQ.') s = ['C' + str(x) for x in tors] - if len(free)==1: + if len(free) == 1: s.append(ring) - if len(free)>1: + elif len(free) > 1: s.append(ring + '^' + str(len(free))) return ' x '.join(s) - def module(self): """ Return the submodule of the toric Chow group generated. @@ -1191,7 +1188,6 @@ def module(self): """ return self._module - def ngens(self): """ Return the number of generators. @@ -1209,7 +1205,6 @@ def ngens(self): """ return len(self._gens) - def gen(self, i): """ Return the ``i``-th generator of the Chow group of fixed @@ -1233,7 +1228,6 @@ def gen(self, i): """ return self._gens[i] - def gens(self): """ Return the generators of the Chow group of fixed degree. @@ -1268,7 +1262,7 @@ def is_ChowGroup(x): EXAMPLES:: - sage: P2=toric_varieties.P2() + sage: P2 = toric_varieties.P2() sage: A = P2.Chow_group() sage: from sage.schemes.toric.chow_group import is_ChowGroup sage: is_ChowGroup(A) diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index ed6dfe6c317..13d7b4b88b9 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -1110,7 +1110,7 @@ def Chow_cycle(self, ring=ZZ): The :class:`~sage.schemes.toric.chow_group.ChowCycle` represented by the divisor. - EXAMPLES: + EXAMPLES:: sage: dP6 = toric_varieties.dP6() sage: cone = dP6.fan(1)[0] diff --git a/src/sage/schemes/toric/points.py b/src/sage/schemes/toric/points.py index 117c4b74278..71e496603e4 100644 --- a/src/sage/schemes/toric/points.py +++ b/src/sage/schemes/toric/points.py @@ -437,7 +437,7 @@ def multiplicative_generator(self): A finite field element. - EXAMPLES: + EXAMPLES:: sage: point_set = toric_varieties.P2(base_ring=GF(5^2, 'a')).point_set() sage: ffe = point_set._finite_field_enumerator() @@ -1031,4 +1031,3 @@ def cardinality(self): for log_t in self.solutions(inhomogeneous, log_range): n += 1 return n - diff --git a/src/sage/schemes/toric/weierstrass.py b/src/sage/schemes/toric/weierstrass.py index 2025db421ac..eaebb84c9fd 100644 --- a/src/sage/schemes/toric/weierstrass.py +++ b/src/sage/schemes/toric/weierstrass.py @@ -649,7 +649,7 @@ def _check_polynomial_P2(cubic, variables): polynomial ring. A ``ValueError`` is raised if the polynomial is not homogeneous. - EXAMPLES: + EXAMPLES:: sage: from sage.schemes.toric.weierstrass import _check_polynomial_P2 sage: R. = QQ[] @@ -990,7 +990,7 @@ def _check_polynomial_P2_112(polynomial, variables): polynomial ring. A ``ValueError`` is raised if the polynomial is not homogeneous. - EXAMPLES: + EXAMPLES:: sage: from sage.schemes.toric.weierstrass import _check_polynomial_P2_112 sage: R. = QQ[] diff --git a/src/sage/schemes/toric/weierstrass_higher.py b/src/sage/schemes/toric/weierstrass_higher.py index 23042d5a6d8..7dc779d5cae 100644 --- a/src/sage/schemes/toric/weierstrass_higher.py +++ b/src/sage/schemes/toric/weierstrass_higher.py @@ -83,7 +83,7 @@ def _check_polynomials_P3(quadratic1, quadratic2, variables): polynomial ring. A ``ValueError`` is raised if the polynomial is not homogeneous. - EXAMPLES: + EXAMPLES:: sage: from sage.schemes.toric.weierstrass_higher import _check_polynomials_P3 sage: R. = QQ[] @@ -106,9 +106,8 @@ def _check_polynomials_P3(quadratic1, quadratic2, variables): if quadratic1.parent() is not quadratic2.parent(): raise ValueError('The two quadratics must be in the same polynomial ring.') if variables is None: - from sage.misc.misc import uniq - variables = uniq(quadratic1.variables() + quadratic2.variables()) - variables.reverse() + variables = quadratic1.variables() + quadratic2.variables() + variables = sorted(set(variables), reverse=True) if len(variables) == 4: w, x, y, z = variables _check_homogeneity(quadratic1, [w, x, y, z], (1, 1, 1, 1), 2) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index f3354107fb6..c11d062c039 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -17,7 +17,6 @@ from sage.misc.misc import attrcall from sage.misc.cachefunc import cached_method -from sage.misc.superseded import deprecated_function_alias from sage.categories.sets_cat import Sets @@ -213,8 +212,6 @@ def cartesian_projection(self, i): raise ValueError("i (={}) must be in {}".format(i, self._sets_keys())) return attrcall("cartesian_projection", i) - summand_projection = deprecated_function_alias(10963, cartesian_projection) - def _cartesian_product_of_elements(self, elements): """ Return the Cartesian product of the given ``elements``. @@ -308,11 +305,6 @@ def cartesian_projection(self, i): (47, 42, 1) sage: x.cartesian_projection(1) 42 - - sage: x.summand_projection(1) - doctest:...: DeprecationWarning: summand_projection is deprecated. Please use cartesian_projection instead. - See http://trac.sagemath.org/10963 for details. - 42 """ return self.value[i] diff --git a/src/sage/sets/recursively_enumerated_set.pyx b/src/sage/sets/recursively_enumerated_set.pyx index 74f1b52cb80..e6dbb386f09 100644 --- a/src/sage/sets/recursively_enumerated_set.pyx +++ b/src/sage/sets/recursively_enumerated_set.pyx @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- r""" Recursively enumerated set @@ -17,7 +18,7 @@ description of the inputs. AUTHORS: -- Sebastien Labbe, April 2014, at Sage Days 57, Cernay-la-ville +- Sébastien Labbé, April 2014, at Sage Days 57, Cernay-la-ville EXAMPLES: @@ -158,7 +159,7 @@ Depth first search:: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Sebastien Labbe # # Distributed under the terms of the GNU General Public License (GPL) @@ -170,14 +171,14 @@ Depth first search:: # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.parent cimport Parent from sage.categories.enumerated_sets import EnumeratedSets from sage.combinat.backtrack import SearchForest -#from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall from collections import deque + def RecursivelyEnumeratedSet(seeds, successors, structure=None, enumeration=None, max_depth=float("inf"), post_process=None, facade=None, category=None): @@ -302,21 +303,25 @@ def RecursivelyEnumeratedSet(seeds, successors, structure=None, return RecursivelyEnumeratedSet_generic(seeds, successors, enumeration, max_depth, facade=facade, category=category) if structure == 'symmetric': - if enumeration is None: enumeration = 'breadth' + if enumeration is None: + enumeration = 'breadth' return RecursivelyEnumeratedSet_symmetric(seeds, successors, enumeration, max_depth, facade=facade, category=category) if structure == 'forest': - if enumeration is None: enumeration = 'depth' + if enumeration is None: + enumeration = 'depth' return RecursivelyEnumeratedSet_forest(roots=seeds, children=successors, algorithm=enumeration, post_process=post_process, facade=facade, category=category) if structure == 'graded': - if enumeration is None: enumeration = 'breadth' + if enumeration is None: + enumeration = 'breadth' return RecursivelyEnumeratedSet_graded(seeds, successors, enumeration, max_depth, facade=facade, category=category) raise ValueError("Unknown value for structure (={})".format(structure)) + cdef class RecursivelyEnumeratedSet_generic(Parent): r""" A generic recursively enumerated set. @@ -886,10 +891,11 @@ cdef class RecursivelyEnumeratedSet_generic(Parent): """ successors = self.successors it = self.breadth_first_search_iterator(max_depth=max_depth) - E = [(u,v) for u in it for v in successors(u)] + E = [(u, v) for u in it for v in successors(u)] from sage.graphs.digraph import DiGraph return DiGraph(E, format='list_of_edges', loops=loops, - multiedges=multiedges) + multiedges=multiedges) + cdef class RecursivelyEnumeratedSet_symmetric(RecursivelyEnumeratedSet_generic): r""" @@ -921,7 +927,7 @@ cdef class RecursivelyEnumeratedSet_symmetric(RecursivelyEnumeratedSet_generic): sage: loads(dumps(C)) Traceback (most recent call last): ... - PicklingError: Can't pickle <... 'function'>: attribute lookup __builtin__.function failed + PicklingError: ... This works in the command line but apparently not as a doctest:: @@ -930,7 +936,7 @@ cdef class RecursivelyEnumeratedSet_symmetric(RecursivelyEnumeratedSet_generic): sage: loads(dumps(C)) Traceback (most recent call last): ... - PicklingError: Can't pickle <... 'function'>: attribute lookup __builtin__.function failed + PicklingError: ... """ breadth_first_search_iterator = RecursivelyEnumeratedSet_generic._breadth_first_search_iterator_from_graded_component_iterator @@ -1001,12 +1007,12 @@ cdef class RecursivelyEnumeratedSet_symmetric(RecursivelyEnumeratedSet_generic): ... StopIteration """ - cdef set A,B + cdef set A, B A = set() B = set(self._seeds) while B: yield B - A,B = B, self._get_next_graded_component(A, B) + A, B = B, self._get_next_graded_component(A, B) cpdef graded_component(self, depth): r""" @@ -1110,6 +1116,7 @@ cdef class RecursivelyEnumeratedSet_symmetric(RecursivelyEnumeratedSet_generic): C.add(y) return C + cdef class RecursivelyEnumeratedSet_graded(RecursivelyEnumeratedSet_generic): r""" Generic tool for constructing ideals of a graded relation. @@ -1312,4 +1319,5 @@ cdef class RecursivelyEnumeratedSet_graded(RecursivelyEnumeratedSet_generic): C.add(y) return C + RecursivelyEnumeratedSet_forest = SearchForest diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 42ef33c0f58..fe4d1949ca4 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -399,7 +399,7 @@ def __richcmp__(self, right, op): The following is random, illustrating that comparison of sets is not the subset relation, when they are not equal:: - sage: Primes() < Set(QQ) # random + sage: Primes() < Set(QQ) # random # py2 True or False """ if not isinstance(right, Set_object): @@ -892,9 +892,10 @@ def frozenset(self): TypeError: unhashable type: 'set' sage: s = X.frozenset(); s frozenset({0, 1, c, c + 1, c^2, c^2 + 1, c^2 + c, c^2 + c + 1}) - sage: hash(s) - -1390224788 # 32-bit - 561411537695332972 # 64-bit + + sage: hash(s) != hash(tuple(X.set())) + True + sage: type(s) <... 'frozenset'> """ diff --git a/src/sage/structure/__init__.py b/src/sage/structure/__init__.py index e69de29bb2d..8689eb1717f 100644 --- a/src/sage/structure/__init__.py +++ b/src/sage/structure/__init__.py @@ -0,0 +1,2 @@ +# Resolve a cyclic import +import sage.structure.element diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index 82fa70337ae..6bf1b854225 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -257,7 +257,14 @@ cdef class CategoryObject(SageObject): # Generators ############################################################################## - def gens_dict(self): + @cached_method + def __gens_dict(self): + cdef dict v = {} + for x in self._defining_names(): + v[str(x)] = x + return v + + def gens_dict(self, *, copy=True): r""" Return a dictionary whose entries are ``{name:variable,...}``, where ``name`` stands for the variable names of this @@ -269,11 +276,19 @@ cdef class CategoryObject(SageObject): sage: B. = BooleanPolynomialRing() sage: B.gens_dict() {'a': a, 'b': b, 'c': c, 'd': d} + + TESTS:: + + sage: B. = PolynomialRing(QQ) + sage: B.gens_dict(copy=False) is B.gens_dict(copy=False) + True + sage: B.gens_dict(copy=False) is B.gens_dict() + False """ - cdef dict v = {} - for x in self._defining_names(): - v[str(x)] = x - return v + if copy: + return dict(self.__gens_dict()) + else: + return self.__gens_dict() def gens_dict_recursive(self): r""" diff --git a/src/sage/structure/coerce.pxd b/src/sage/structure/coerce.pxd index 6d9fdabcd04..e070d1c32e4 100644 --- a/src/sage/structure/coerce.pxd +++ b/src/sage/structure/coerce.pxd @@ -1,4 +1,3 @@ -from .element cimport CoercionModel from .parent cimport Parent from .coerce_dict cimport TripleDict @@ -8,7 +7,8 @@ cpdef bint parent_is_integers(P) except -1 cpdef bint is_numpy_type(t) cpdef bint is_mpmath_type(t) -cdef class CoercionModel_cache_maps(CoercionModel): + +cdef class CoercionModel: # This MUST be a mapping to tuples, where each # tuple contains at least two elements that are either # None or of type Morphism. @@ -17,6 +17,10 @@ cdef class CoercionModel_cache_maps(CoercionModel): # This MUST be a mapping to actions. cdef readonly TripleDict _action_maps + cpdef canonical_coercion(self, x, y) + cpdef bin_op(self, x, y, op) + cpdef richcmp(self, x, y, int op) + cpdef coercion_maps(self, R, S) cpdef discover_coercion(self, R, S) cpdef verify_coercion_maps(self, R, S, homs, bint fix=*) @@ -33,3 +37,7 @@ cdef class CoercionModel_cache_maps(CoercionModel): cdef TripleDict _division_parents cpdef analyse(self, xp, yp, op=*) cpdef division_parent(self, Parent P) + + +# Unique global coercion_model instance +cdef CoercionModel coercion_model diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 79010831c8e..e8ba0dc6a62 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -76,12 +76,11 @@ see the documentation for :class:`Parent`. from __future__ import print_function, absolute_import from cpython.object cimport (PyObject, PyTypeObject, - PyObject_CallObject, PyObject_RichCompare, Py_TYPE) + PyObject_CallObject, PyObject_RichCompare, Py_TYPE, + Py_EQ, Py_NE, Py_LT, Py_LE, Py_GT, Py_GE) from cpython.weakref cimport PyWeakref_GET_OBJECT, PyWeakref_NewRef from libc.string cimport strncmp - -IF HAVE_GMPY2: - import gmpy2 +import gmpy2 cdef add, mul, truediv from operator import add, mul, truediv @@ -144,14 +143,14 @@ cpdef py_scalar_parent(py_type): sage: py_scalar_parent(numpy.complex) Complex Double Field - sage: import gmpy2 # optional - gmpy2 - sage: py_scalar_parent(gmpy2.mpz) # optional - gmpy2 + sage: import gmpy2 + sage: py_scalar_parent(gmpy2.mpz) Integer Ring - sage: py_scalar_parent(gmpy2.mpq) # optional - gmpy2 + sage: py_scalar_parent(gmpy2.mpq) Rational Field - sage: py_scalar_parent(gmpy2.mpfr) # optional - gmpy2 + sage: py_scalar_parent(gmpy2.mpfr) Real Double Field - sage: py_scalar_parent(gmpy2.mpc) # optional - gmpy2 + sage: py_scalar_parent(gmpy2.mpc) Complex Double Field """ if issubclass(py_type, int) or issubclass(py_type, long): @@ -179,16 +178,16 @@ cpdef py_scalar_parent(py_type): return sage.rings.complex_double.CDF else: return None - elif HAVE_GMPY2 and issubclass(py_type, gmpy2.mpz): + elif issubclass(py_type, gmpy2.mpz): import sage.rings.integer_ring return sage.rings.integer_ring.ZZ - elif HAVE_GMPY2 and issubclass(py_type, gmpy2.mpq): + elif issubclass(py_type, gmpy2.mpq): import sage.rings.rational_field return sage.rings.rational_field.QQ - elif HAVE_GMPY2 and issubclass(py_type, gmpy2.mpfr): + elif issubclass(py_type, gmpy2.mpfr): import sage.rings.real_double return sage.rings.real_double.RDF - elif HAVE_GMPY2 and issubclass(py_type, gmpy2.mpc): + elif issubclass(py_type, gmpy2.mpc): import sage.rings.complex_double return sage.rings.complex_double.CDF else: @@ -234,18 +233,18 @@ cpdef py_scalar_to_element(x): Test gmpy2's types:: - sage: import gmpy2 # optional - gmpy2 - sage: x = py_scalar_to_element(gmpy2.mpz(42)) # optional - gmpy2 - sage: x, parent(x) # optional - gmpy2 + sage: import gmpy2 + sage: x = py_scalar_to_element(gmpy2.mpz(42)) + sage: x, parent(x) (42, Integer Ring) - sage: x = py_scalar_to_element(gmpy2.mpq('3/4')) # optional - gmpy2 - sage: x, parent(x) # optional - gmpy2 + sage: x = py_scalar_to_element(gmpy2.mpq('3/4')) + sage: x, parent(x) (3/4, Rational Field) - sage: x = py_scalar_to_element(gmpy2.mpfr(42.57))# optional - gmpy2 - sage: x, parent(x) # optional - gmpy2 + sage: x = py_scalar_to_element(gmpy2.mpfr(42.57)) + sage: x, parent(x) (42.57, Real Double Field) - sage: x = py_scalar_to_element(gmpy2.mpc(int(42), int(42))) # optional - gmpy2 - sage: x, parent(x) # optional - gmpy2 + sage: x = py_scalar_to_element(gmpy2.mpc(int(42), int(42))) + sage: x, parent(x) (42.0 + 42.0*I, Complex Double Field) Test compatibility with :func:`py_scalar_parent`:: @@ -266,9 +265,9 @@ cpdef py_scalar_to_element(x): sage: for x in elt: ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() - sage: elt = [gmpy2.mpz(42), gmpy2.mpq('3/4'), # optional - gmpy2 + sage: elt = [gmpy2.mpz(42), gmpy2.mpq('3/4'), ....: gmpy2.mpfr(42.57), gmpy2.mpc(int(42), int(42))] - sage: for x in elt: # optional - gmpy2 + sage: for x in elt: ....: assert py_scalar_parent(type(x)) == py_scalar_to_element(x).parent() """ if isinstance(x, Element): @@ -298,16 +297,16 @@ cpdef py_scalar_to_element(x): return CDF(x) else: return x - elif HAVE_GMPY2 and type(x) is gmpy2.mpz: + elif type(x) is gmpy2.mpz: from sage.rings.integer import Integer return Integer(x) - elif HAVE_GMPY2 and type(x) is gmpy2.mpq: + elif type(x) is gmpy2.mpq: from sage.rings.rational import Rational return Rational(x) - elif HAVE_GMPY2 and type(x) is gmpy2.mpfr: + elif type(x) is gmpy2.mpfr: from sage.rings.real_double import RDF return RDF(x) - elif HAVE_GMPY2 and type(x) is gmpy2.mpc: + elif type(x) is gmpy2.mpc: from sage.rings.complex_double import CDF return CDF(x) else: @@ -425,7 +424,7 @@ cpdef bint is_mpmath_type(t): strncmp((t).tp_name, "sage.libs.mpmath.", 17) == 0 -cdef class CoercionModel_cache_maps(CoercionModel): +cdef class CoercionModel: """ See also sage.categories.pushout @@ -495,8 +494,8 @@ cdef class CoercionModel_cache_maps(CoercionModel): """ EXAMPLES:: - sage: from sage.structure.coerce import CoercionModel_cache_maps - sage: cm = CoercionModel_cache_maps() + sage: from sage.structure.coerce import CoercionModel + sage: cm = CoercionModel() sage: K = NumberField(x^2-2, 'a') sage: A = cm.get_action(ZZ, K, operator.mul) sage: f, g = cm.coercion_maps(QQ, int) @@ -504,7 +503,7 @@ cdef class CoercionModel_cache_maps(CoercionModel): TESTS:: - sage: cm = CoercionModel_cache_maps(4, .95) + sage: cm = CoercionModel(4, .95) doctest:...: DeprecationWarning: the 'lookup_dict_size' argument is deprecated See http://trac.sagemath.org/24135 for details. doctest:...: DeprecationWarning: the 'lookup_dict_threshold' argument is deprecated @@ -1893,14 +1892,17 @@ cdef class CoercionModel_cache_maps(CoercionModel): sage: richcmp(int(1), float(2), op_GE) False - If there is no coercion, only comparisons for equality make - sense:: + If there is no coercion, we only support ``==`` and ``!=``:: sage: x = QQ.one(); y = GF(2).one() sage: richcmp(x, y, op_EQ) False sage: richcmp(x, y, op_NE) True + sage: richcmp(x, y, op_GT) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for >: 'Rational Field' and 'Finite Field of size 2' We support non-Sage types with the usual Python convention:: @@ -1950,13 +1952,23 @@ cdef class CoercionModel_cache_maps(CoercionModel): if res is not NotImplemented: return res - # Final attempt: compare by id() - if (x) >= (y): - # It cannot happen that x is y, since they don't - # have the same parent. - return rich_to_bool(op, 1) + # At this point, we have 2 objects which cannot be coerced to + # a common parent. So we assume that they are not equal. + if op == Py_EQ: + return False + if op == Py_NE: + return True + + # It does not make sense to compare x and y with an inequality, + # so we raise an exception. + if op == Py_LT: + raise bin_op_exception('<', x, y) + elif op == Py_LE: + raise bin_op_exception('<=', x, y) + elif op == Py_GT: + raise bin_op_exception('>', x, y) else: - return rich_to_bool(op, -1) + raise bin_op_exception('>=', x, y) def _coercion_error(self, x, x_map, x_elt, y, y_map, y_elt): """ @@ -1986,3 +1998,6 @@ Original elements %r (parent %s) and %r (parent %s) and maps %s %r""" % (x_elt, y_elt, parent(x_elt), parent(y_elt), x, parent(x), y, parent(y), type(x_map), x_map, type(y_map), y_map)) + + +coercion_model = CoercionModel() diff --git a/src/sage/structure/coerce_actions.pyx b/src/sage/structure/coerce_actions.pyx index cc8f0214e55..36a5e6e52ff 100644 --- a/src/sage/structure/coerce_actions.pyx +++ b/src/sage/structure/coerce_actions.pyx @@ -19,7 +19,8 @@ from cpython.int cimport * from cpython.number cimport * from cysignals.signals cimport sig_check -from .element cimport parent, coercion_model, Element, ModuleElement +from .coerce cimport coercion_model +from .element cimport parent, Element, ModuleElement from .parent cimport Parent from .coerce_exceptions import CoercionException from sage.categories.action cimport InverseAction, PrecomposedAction @@ -735,10 +736,17 @@ cdef class IntegerMulAction(IntegerAction): Check that large multiplications can be interrupted:: - sage: alarm(0.5); (2^(10^7)) * P # not tested; see trac:#24986 + sage: alarm(0.5); (2^(10^6)) * P Traceback (most recent call last): ... AlarmInterrupt + + Verify that cysignals correctly detects that the above + exception has been handled:: + + sage: from cysignals.tests import print_sig_occurred + sage: print_sig_occurred() + No current exception """ cdef int err = 0 cdef long n_long diff --git a/src/sage/structure/coerce_dict.pxd b/src/sage/structure/coerce_dict.pxd index d6929950f59..be14effa0f8 100644 --- a/src/sage/structure/coerce_dict.pxd +++ b/src/sage/structure/coerce_dict.pxd @@ -1,5 +1,5 @@ cimport cython -from cpython cimport PyObject +from cpython.object cimport PyObject cdef struct mono_cell: diff --git a/src/sage/structure/coerce_dict.pyx b/src/sage/structure/coerce_dict.pyx index d1ebea3a138..cea72a219ae 100644 --- a/src/sage/structure/coerce_dict.pyx +++ b/src/sage/structure/coerce_dict.pyx @@ -271,12 +271,6 @@ cdef class MonoDict: It is implemented as a hash table with open addressing, similar to python's dict. - If ki supports weak references then ri is a weak reference to ki with a - callback to remove the entry from the dictionary if ki gets garbage - collected. If ki is does not support weak references then ri is identical to ki. - In the latter case the presence of the key in the dictionary prevents it from - being garbage collected. - INPUT: - ``data`` -- optional iterable defining initial data, as dict or @@ -546,7 +540,7 @@ cdef class MonoDict: self.used = 0 self.fill = 0 - def __init__(self, data=None, size=None, threshold=None, *, weak_values=False): + def __init__(self, data=None, *, weak_values=False): """ Create a special dict using singletons for keys. @@ -565,36 +559,8 @@ cdef class MonoDict: sage: L[a] 1 - TESTS:: - - sage: L = MonoDict(31) - doctest:...: DeprecationWarning: the 'size' argument to MonoDict is deprecated - See http://trac.sagemath.org/24135 for details. - sage: list(L.items()) - [] - sage: L = MonoDict(31, {"x": 1}) - sage: list(L.items()) - [('x', 1)] - sage: L = MonoDict(threshold=0.9) - doctest:...: DeprecationWarning: the 'threshold' argument to MonoDict is deprecated - See http://trac.sagemath.org/24135 for details. """ self.weak_values = weak_values - if size is not None: - # Use size as data argument - data = size - from sage.misc.superseded import deprecation - deprecation(24135, "the 'size' argument to MonoDict is deprecated") - elif data is not None: - try: - iter(data) - except TypeError: - data = None - from sage.misc.superseded import deprecation - deprecation(24135, "the 'size' argument to MonoDict is deprecated") - if threshold is not None: - from sage.misc.superseded import deprecation - deprecation(24135, "the 'threshold' argument to MonoDict is deprecated") if data: try: data = data.items() @@ -804,20 +770,6 @@ cdef class MonoDict: L = extract_mono_cell(cursor) self.used -= 1 - def iteritems(self): - """ - EXAMPLES:: - - sage: from sage.structure.coerce_dict import MonoDict - sage: MonoDict().iteritems() - doctest:...: DeprecationWarning: MonoDict.iteritems is deprecated, use MonoDict.items instead - See http://trac.sagemath.org/24135 for details. - - """ - from sage.misc.superseded import deprecation - deprecation(24135, "MonoDict.iteritems is deprecated, use MonoDict.items instead") - return self.items() - def items(self): """ Iterate over the ``(key, value)`` pairs of this :class:`MonoDict`. @@ -1042,18 +994,18 @@ cdef class TripleDict: - All keys must be sequence of exactly three elements. All sequence types (tuple, list, etc.) map to the same item. + + - Any of the three key components that support weak-refs are stored + via a weakref. If any of these components gets garbage collected + then the entire entry is removed. In that sense, this structure + behaves like a nested :class:`~weakref.WeakKeyDictionary`. + - Comparison is done using the 'is' rather than '==' operator. There are special cdef set/get methods for faster access. It is bare-bones in the sense that not all dictionary methods are implemented. - It is implemented as a list of lists (hereafter called buckets). The bucket is - chosen according to a very simple hash based on the object pointer, and each - bucket is of the form [id(k1), id(k2), id(k3), r1, r2, r3, value, id(k1), - id(k2), id(k3), r1, r2, r3, value, ...], on which a linear search is performed. - If a key component ki supports weak references then ri is a weak reference to - ki; otherwise ri is identical to ki. INPUT: @@ -1064,10 +1016,12 @@ cdef class TripleDict: weak references to the values in this dictionary will be used, when possible. - If any of the key components k1,k2,k3 (this can happen for a key component - that supports weak references) gets garbage collected then the entire - entry disappears. In that sense this structure behaves like a nested - :class:`~weakref.WeakKeyDictionary`. + + IMPLEMENTATION: + + It is implemented as a hash table with open addressing, similar to python's + dict. + EXAMPLES:: @@ -1256,7 +1210,7 @@ cdef class TripleDict: self.used = 0 self.fill = 0 - def __init__(self, data=None, size=None, threshold=None, *, weak_values=False): + def __init__(self, data=None, *, weak_values=False): """ Create a special dict using triples for keys. @@ -1276,36 +1230,8 @@ cdef class TripleDict: sage: L[key] 42 - TESTS:: - - sage: L = TripleDict(31) - doctest:...: DeprecationWarning: the 'size' argument to TripleDict is deprecated - See http://trac.sagemath.org/24135 for details. - sage: list(L.items()) - [] - sage: L = TripleDict(31, {key: 42}) - sage: list(L.items()) - [(('x', 'y', 'z'), 42)] - sage: L = TripleDict(threshold=0.9) - doctest:...: DeprecationWarning: the 'threshold' argument to TripleDict is deprecated - See http://trac.sagemath.org/24135 for details. """ self.weak_values = weak_values - if size is not None: - # Use size as data argument - data = size - from sage.misc.superseded import deprecation - deprecation(24135, "the 'size' argument to TripleDict is deprecated") - elif data is not None: - try: - iter(data) - except TypeError: - data = None - from sage.misc.superseded import deprecation - deprecation(24135, "the 'size' argument to TripleDict is deprecated") - if threshold is not None: - from sage.misc.superseded import deprecation - deprecation(24135, "the 'threshold' argument to TripleDict is deprecated") if data: try: data = data.items() @@ -1520,20 +1446,6 @@ cdef class TripleDict: L = extract_triple_cell(cursor) self.used -= 1 - def iteritems(self): - """ - EXAMPLES:: - - sage: from sage.structure.coerce_dict import TripleDict - sage: TripleDict().iteritems() - doctest:...: DeprecationWarning: TripleDict.iteritems is deprecated, use TripleDict.items instead - See http://trac.sagemath.org/24135 for details. - - """ - from sage.misc.superseded import deprecation - deprecation(24135, "TripleDict.iteritems is deprecated, use TripleDict.items instead") - return self.items() - def items(self): """ Iterate over the ``(key, value)`` pairs of this :class:`TripleDict`. diff --git a/src/sage/structure/dynamic_class.py b/src/sage/structure/dynamic_class.py index 3b44c980ebe..2904843c893 100644 --- a/src/sage/structure/dynamic_class.py +++ b/src/sage/structure/dynamic_class.py @@ -211,13 +211,14 @@ def dynamic_class(name, bases, cls=None, reduction=None, doccls=None, sage: FooBar.mro() # py3 [, , ] - If all the base classes are extension types, the dynamic class is - also considered to be an extension type (see :trac:`23435`):: + If all the base classes have a zero ``__dictoffset__``, the dynamic + class also has a zero ``__dictoffset__``. This means that the + instances of the class don't have a ``__dict__`` + (see :trac:`23435`):: sage: dyn = dynamic_class("dyn", (Integer,)) - sage: from sage.structure.misc import is_extension_type - sage: is_extension_type(dyn) - True + sage: dyn.__dictoffset__ + 0 .. RUBRIC:: Pickling @@ -431,7 +432,7 @@ def dynamic_class_internal(name, bases, cls=None, reduction=None, doccls=None, p # NOTE: we need the isinstance(b, type) check to exclude old-style # classes. if all(isinstance(b, type) and not b.__dictoffset__ for b in bases): - methods['__slots__'] = [] + methods['__slots__'] = () metaclass = DynamicMetaclass # The metaclass of a class must derive from the metaclasses of its diff --git a/src/sage/structure/element.pxd b/src/sage/structure/element.pxd index d130db11979..a6838d8c6b1 100644 --- a/src/sage/structure/element.pxd +++ b/src/sage/structure/element.pxd @@ -1,6 +1,5 @@ from .sage_object cimport SageObject from .parent cimport Parent -from cpython.number cimport PyNumber_Check from sage.misc.inherit_comparison cimport InheritComparisonMetaclass @@ -261,11 +260,3 @@ cdef class Matrix(ModuleElement): cdef bint is_sparse_c(self) cdef bint is_dense_c(self) - - -cdef class CoercionModel: - cpdef canonical_coercion(self, x, y) - cpdef bin_op(self, x, y, op) - cpdef richcmp(self, x, y, int op) - -cdef CoercionModel coercion_model diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 1066e504681..c481be1f822 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -300,7 +300,7 @@ cdef dict _coerce_op_symbols = dict( iadd='+', isub='-', imul='*', itruediv='/', ifloordiv='//', imod='%', ipow='^') from sage.structure.richcmp cimport rich_to_bool -from sage.structure.coerce cimport py_scalar_to_element +from sage.structure.coerce cimport py_scalar_to_element, coercion_model from sage.structure.parent cimport Parent from sage.cpython.type cimport can_assign_class from sage.cpython.getattr cimport getattr_from_other_class @@ -3508,6 +3508,15 @@ cdef class Matrix(ModuleElement): ... TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field' and 'Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in y over Rational Field' + We test that the bug reported in :trac:`27352` has been fixed:: + + sage: A = matrix(QQ, [[1, 2], [-1, 0], [1, 1]]) + sage: B = matrix(QQ, [[0, 4], [1, -1], [1, 2]]) + sage: A*B + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 3 by 2 dense matrices over Rational Field' and 'Full MatrixSpace of 3 by 2 dense matrices over Rational Field' + Here we test (matrix * vector) multiplication:: sage: parent(matrix(ZZ,2,2,[1,2,3,4])*vector(ZZ,[1,2])) @@ -3676,7 +3685,14 @@ cdef class Matrix(ModuleElement): """ cdef int cl = classify_elements(left, right) if HAVE_SAME_PARENT(cl): - return (left)._matrix_times_matrix_(right) + # If they are matrices with the same parent, they had + # better be square for the product to be defined. + if (left)._nrows == (left)._ncols: + return (left)._matrix_times_matrix_(right) + else: + parent = (left)._parent + raise TypeError("unsupported operand parent(s) for *: '{}' and '{}'".format(parent, parent)) + if BOTH_ARE_ELEMENT(cl): return coercion_model.bin_op(left, right, mul) @@ -4105,30 +4121,8 @@ def coerce(Parent p, x): except AttributeError: return p(x) -# We define this base class here to avoid circular cimports. -cdef class CoercionModel: - """ - Most basic coercion scheme. If it doesn't already match, throw an error. - """ - cpdef canonical_coercion(self, x, y): - if parent(x) is parent(y): - return x,y - raise TypeError("no common canonical parent for objects with parents: '%s' and '%s'"%(parent(x), parent(y))) - - cpdef bin_op(self, x, y, op): - if parent(x) is parent(y): - return op(x,y) - raise bin_op_exception(op, x, y) - - cpdef richcmp(self, x, y, int op): - x, y = self.canonical_coercion(x, y) - return PyObject_RichCompare(x, y, op) - - -from . import coerce -cdef CoercionModel coercion_model = coerce.CoercionModel_cache_maps() -# Make this accessible as Python object +# Make coercion_model accessible as Python object globals()["coercion_model"] = coercion_model @@ -4141,7 +4135,7 @@ def get_coercion_model(): sage: import sage.structure.element as e sage: cm = e.get_coercion_model() sage: cm - + sage: cm is coercion_model True """ diff --git a/src/sage/structure/element_wrapper.pyx b/src/sage/structure/element_wrapper.pyx index f3628a81d8c..9b798e8ef56 100644 --- a/src/sage/structure/element_wrapper.pyx +++ b/src/sage/structure/element_wrapper.pyx @@ -21,8 +21,9 @@ AUTHORS: from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, PyObject_RichCompare +from sage.structure.coerce cimport coercion_model +from sage.structure.element cimport Element from sage.structure.parent cimport Parent -from sage.structure.element cimport Element, coercion_model from sage.structure.unique_representation import UniqueRepresentation from copy import copy @@ -366,8 +367,6 @@ cdef class ElementWrapper(Element): False sage: l11 < 1 # class differ False - sage: 1 < l11 # random, since it depends on what the Integer 1 decides to do, which may just involve memory locations - False """ return (self.__class__ is other.__class__ and self._parent is other.parent() diff --git a/src/sage/structure/factorization.py b/src/sage/structure/factorization.py index e30d82dcc78..6d92c464afb 100644 --- a/src/sage/structure/factorization.py +++ b/src/sage/structure/factorization.py @@ -1299,9 +1299,8 @@ def is_integral(self): -1 * 2^-3 * 5 sage: F.is_integral() False - """ - return all([e >=0 for p,e in self.__x]) + return all(e >= 0 for p, e in self.__x) def radical(self): """ @@ -1323,7 +1322,7 @@ def radical(self): ... ValueError: All exponents in the factorization must be positive. """ - if not all([e > 0 for p,e in self.__x]): + if not all(e > 0 for p, e in self.__x): raise ValueError("All exponents in the factorization must be positive.") return Factorization([(p,1) for p,e in self.__x], unit=self.unit().parent()(1), cr=self.__cr, sort=False, simplify=False) @@ -1348,7 +1347,6 @@ def radical_value(self): ... ValueError: All exponents in the factorization must be positive. """ - if not all([e > 0 for p,e in self.__x]): + if not all(e > 0 for p, e in self.__x): raise ValueError("All exponents in the factorization must be positive.") - return prod([p for p,e in self.__x]) - + return prod([p for p, e in self.__x]) diff --git a/src/sage/structure/misc.pyx b/src/sage/structure/misc.pyx index 64648528a74..cd402266178 100644 --- a/src/sage/structure/misc.pyx +++ b/src/sage/structure/misc.pyx @@ -2,17 +2,24 @@ Miscellaneous utilities """ +from sage.misc.superseded import deprecation +deprecation(27099, "the module sage.structure.misc is deprecated") + def is_extension_type(cls): """ - INPUT: + Return whether or not instances of ``cls`` have a ``__dict__``. - - cls: a class + This is deprecated as there should not be any use case for it. + + INPUT: - Tests whether cls is an extension type (int, list, cython compiled classes, ...) + - ``cls`` -- a class EXAMPLES:: - sage: from sage.structure.parent import is_extension_type + sage: from sage.structure.misc import is_extension_type + doctest:...: DeprecationWarning: the module sage.structure.misc is deprecated + See https://trac.sagemath.org/27099 for details. sage: is_extension_type(int) True sage: is_extension_type(list) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 68177338dfb..1abe3dddcf8 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -112,7 +112,8 @@ import operator from copy import copy from sage.cpython.type cimport can_assign_class -from sage.structure.element cimport parent, coercion_model +from .coerce cimport coercion_model +from sage.structure.element cimport parent cimport sage.categories.morphism as morphism cimport sage.categories.map as map from .category_object import CategoryObject @@ -121,10 +122,10 @@ from .coerce_exceptions import CoercionException from sage.structure.debug_options cimport debug from sage.structure.richcmp cimport rich_to_bool from sage.structure.sage_object cimport SageObject -from sage.structure.misc import is_extension_type from sage.misc.lazy_attribute import lazy_attribute from sage.categories.sets_cat import Sets, EmptySetError from sage.misc.lazy_format import LazyFormat +from sage.misc.lazy_string cimport _LazyString from .coerce_maps cimport (NamedConvertMap, DefaultConvertMap, DefaultConvertMap_unique, CallableConvertMap) from sage.sets.pythonclass cimport Set_PythonType_class, Set_PythonType @@ -545,17 +546,27 @@ cdef class Parent(sage.structure.category_object.CategoryObject): except AttributeError: #else: return NotImplemented - - def __make_element_class__(self, cls, name = None, module=None, inherit = None): + def __make_element_class__(self, cls, name=None, module=None, inherit=None): """ A utility to construct classes for the elements of this parent, with appropriate inheritance from the element class of - the category (only for pure python types so far). + the category. + + It used to be the case that this didn't work for extension + types, which used to never support a ``__dict__`` for instances. + So for backwards compatibility, we only use dynamic classes by + default if the class has a non-zero ``__dictoffset__``. But it + works regardless: just pass ``inherit=True`` to + ``__make_element_class__``. See also :trac:`24715`. + + When we don't use a dynamic element class, the ``__getattr__`` + implementation from :class:`Element` provides fake + inheritance from categories. """ - # By default, don't fiddle with extension types yet; inheritance from - # categories will probably be achieved in a different way + if not isinstance(cls, type): + raise TypeError(f"element class {cls!r} should be a type") if inherit is None: - inherit = not is_extension_type(cls) + inherit = (cls.__dictoffset__ != 0) if inherit: if name is None: name = "%s_with_category"%cls.__name__ @@ -890,7 +901,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): else: return mor._call_with_args(x, args, kwds) - raise TypeError("No conversion defined from %s to %s"%(R, self)) + raise TypeError(_LazyString(_lazy_format, ("No conversion defined from %s to %s", R, self), {})) def __mul__(self,x): """ @@ -1120,14 +1131,17 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: V.coerce(0) (0, 0, 0, 0, 0, 0, 0) """ - mor = self._internal_coerce_map_from(parent(x)) + cdef R = parent(x) + if R is self: + return x + mor = self._internal_coerce_map_from(R) if mor is None: if is_Integer(x) and not x: try: return self(0) except Exception: _record_exception() - raise TypeError("no canonical coercion from %s to %s" % (parent(x), self)) + raise TypeError(_LazyString(_lazy_format, ("no canonical coercion from %s to %s", parent(x), self), {})) else: return (mor)._call_(x) @@ -2858,3 +2872,6 @@ cdef bint _unregister_pair(x, y, tag) except -1: _coerce_test_dict.pop(EltPair(x,y,tag), None) except (ValueError, CoercionException): pass + +def _lazy_format(msg, *args): + return msg % args diff --git a/src/sage/structure/sequence.py b/src/sage/structure/sequence.py index 795f1dfac8a..ef275c0b009 100644 --- a/src/sage/structure/sequence.py +++ b/src/sage/structure/sequence.py @@ -57,25 +57,18 @@ specifying the universe of the sequence:: sage: v = Sequence(range(10000), universe=ZZ) - -TESTS:: - - sage: v = Sequence([1..5]) - sage: loads(dumps(v)) == v - True - """ - -########################################################################## -# -# Sage: System for Algebra and Geometry Experimentation -# +#***************************************************************************** # Copyright (C) 2006 William Stein # -# Distributed under the terms of the GNU General Public License (GPL) -# http://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 __future__ import print_function from six.moves import range @@ -83,7 +76,6 @@ import sage.structure.sage_object import sage.structure.coerce -#from mutability import Mutability #we cannot inherit from Mutability and list at the same time def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=None, use_sage_types=False): """ @@ -805,6 +797,26 @@ def is_mutable(self): except AttributeError: return True + def __reduce__(self): + """ + Implement pickling for sequences. + + TESTS:: + + sage: v = Sequence([1..5]) + sage: w = loads(dumps(v)) + sage: v == w + True + sage: w.is_mutable() + True + sage: v.set_immutable() + sage: w = loads(dumps(v)) + sage: w.is_mutable() + False + """ + args = (list(self), self.__universe, False, + self._is_immutable, self.__cr_str) + return type(self), args def __copy__(self): """ diff --git a/src/sage/symbolic/benchmark.py b/src/sage/symbolic/benchmark.py index 6318ac864b6..1325f24acd5 100644 --- a/src/sage/symbolic/benchmark.py +++ b/src/sage/symbolic/benchmark.py @@ -43,7 +43,7 @@ ....: L.append( (L[i] + L[i+1]) * L[i+2] ) sage: L = list(var('x,y,z')) sage: blowup(L,15) - sage: len(uniq(L)) + sage: len(set(L)) 19 Problem R6:: diff --git a/src/sage/symbolic/constants.py b/src/sage/symbolic/constants.py index 44f9b15d519..c651cb217af 100644 --- a/src/sage/symbolic/constants.py +++ b/src/sage/symbolic/constants.py @@ -947,7 +947,7 @@ def __init__(self, name='euler_gamma'): """ conversions = dict(kash='EulerGamma(R)', maple='gamma', mathematica='EulerGamma', pari='Euler', - maxima='%gamma', pynac='Euler') + maxima='%gamma', pynac='Euler', giac='euler_gamma') Constant.__init__(self, name, conversions=conversions, latex=r'\gamma', domain='positive') diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 586d4aba576..d9a07469062 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -165,8 +165,6 @@ import sage.rings.rational from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, Py_GT from sage.cpython.string cimport str_to_bytes -from sage.structure.element cimport ModuleElement, RingElement, Element, \ - classify_elements, HAVE_SAME_PARENT, BOTH_ARE_ELEMENT, coercion_model from sage.symbolic.comparison import mixed_order from sage.symbolic.getitem cimport OperandsWrapper from sage.symbolic.series cimport SymbolicSeries @@ -1273,12 +1271,7 @@ cdef class Expression(CommutativeRingElement): sage: f._convert({'parent':int}) 0 """ - cdef GEx res - sig_on() - try: - res = self._gobj.evalf(0, kwds) - finally: - sig_off() + cdef GEx res = self._gobj.evalf(0, kwds) return new_Expression_from_GEx(self._parent, res) def _mpfr_(self, R): @@ -1554,8 +1547,8 @@ cdef class Expression(CommutativeRingElement): In this example hashing is important otherwise the answer is wrong:: - sage: uniq([x-x, -x+x]) - [0] + sage: set([x-x, -x+x]) + {0} Test if exceptions during hashing are handled properly:: @@ -2839,11 +2832,7 @@ cdef class Expression(CommutativeRingElement): # constants are wrappers around Sage objects, compare directly if is_a_constant(self._gobj.lhs()) and is_a_constant(self._gobj.rhs()): return self.operator()(self.lhs().pyobject(), self.rhs().pyobject()) - sig_on() - try: - pynac_result = decide_relational(self._gobj) - finally: - sig_off() + pynac_result = decide_relational(self._gobj) if pynac_result == relational_undecidable: raise ValueError('undecidable relation: ' + repr(self)) @@ -3233,27 +3222,23 @@ cdef class Expression(CommutativeRingElement): cdef GEx x cdef Expression _right = right cdef operators op - sig_on() - try: - if is_a_relational(left._gobj): - if is_a_relational(_right._gobj): - op = compatible_relation(relational_operator(left._gobj), - relational_operator(_right._gobj)) - x = relational(left._gobj.lhs() + _right._gobj.lhs(), - left._gobj.rhs() + _right._gobj.rhs(), - op) - else: - x = relational(left._gobj.lhs() + _right._gobj, - left._gobj.rhs() + _right._gobj, - relational_operator(left._gobj)) - elif is_a_relational(_right._gobj): - x = relational(left._gobj + _right._gobj.lhs(), - left._gobj + _right._gobj.rhs(), - relational_operator(_right._gobj)) + if is_a_relational(left._gobj): + if is_a_relational(_right._gobj): + op = compatible_relation(relational_operator(left._gobj), + relational_operator(_right._gobj)) + x = relational(left._gobj.lhs() + _right._gobj.lhs(), + left._gobj.rhs() + _right._gobj.rhs(), + op) else: - x = left._gobj + _right._gobj - finally: - sig_off() + x = relational(left._gobj.lhs() + _right._gobj, + left._gobj.rhs() + _right._gobj, + relational_operator(left._gobj)) + elif is_a_relational(_right._gobj): + x = relational(left._gobj + _right._gobj.lhs(), + left._gobj + _right._gobj.rhs(), + relational_operator(_right._gobj)) + else: + x = left._gobj + _right._gobj return new_Expression_from_GEx(left._parent, x) cpdef _sub_(left, right): @@ -3289,27 +3274,23 @@ cdef class Expression(CommutativeRingElement): """ cdef GEx x cdef Expression _right = right - sig_on() - try: - if is_a_relational(left._gobj): - if is_a_relational(_right._gobj): - op = compatible_relation(relational_operator(left._gobj), - relational_operator(_right._gobj)) - x = relational(left._gobj.lhs() - _right._gobj.lhs(), - left._gobj.rhs() - _right._gobj.rhs(), - op) - else: - x = relational(left._gobj.lhs() - _right._gobj, - left._gobj.rhs() - _right._gobj, - relational_operator(left._gobj)) - elif is_a_relational(_right._gobj): - x = relational(left._gobj - _right._gobj.lhs(), - left._gobj - _right._gobj.rhs(), - relational_operator(_right._gobj)) + if is_a_relational(left._gobj): + if is_a_relational(_right._gobj): + op = compatible_relation(relational_operator(left._gobj), + relational_operator(_right._gobj)) + x = relational(left._gobj.lhs() - _right._gobj.lhs(), + left._gobj.rhs() - _right._gobj.rhs(), + op) else: - x = left._gobj - _right._gobj - finally: - sig_off() + x = relational(left._gobj.lhs() - _right._gobj, + left._gobj.rhs() - _right._gobj, + relational_operator(left._gobj)) + elif is_a_relational(_right._gobj): + x = relational(left._gobj - _right._gobj.lhs(), + left._gobj - _right._gobj.rhs(), + relational_operator(_right._gobj)) + else: + x = left._gobj - _right._gobj return new_Expression_from_GEx(left._parent, x) cpdef _mul_(left, right): @@ -3457,29 +3438,25 @@ cdef class Expression(CommutativeRingElement): cdef GEx x cdef Expression _right = right cdef operators o - sig_on() - try: - if is_a_relational(left._gobj): - if is_a_relational(_right._gobj): - op = compatible_relation(relational_operator(left._gobj), - relational_operator(_right._gobj)) - x = relational(left._gobj.lhs() * _right._gobj.lhs(), - left._gobj.rhs() * _right._gobj.rhs(), - op) - else: - o = relational_operator(left._gobj) - x = relational(left._gobj.lhs() * _right._gobj, - left._gobj.rhs() * _right._gobj, - o) - elif is_a_relational(_right._gobj): - o = relational_operator(_right._gobj) - x = relational(left._gobj * _right._gobj.lhs(), - left._gobj * _right._gobj.rhs(), - o) + if is_a_relational(left._gobj): + if is_a_relational(_right._gobj): + op = compatible_relation(relational_operator(left._gobj), + relational_operator(_right._gobj)) + x = relational(left._gobj.lhs() * _right._gobj.lhs(), + left._gobj.rhs() * _right._gobj.rhs(), + op) else: - x = left._gobj * _right._gobj - finally: - sig_off() + o = relational_operator(left._gobj) + x = relational(left._gobj.lhs() * _right._gobj, + left._gobj.rhs() * _right._gobj, + o) + elif is_a_relational(_right._gobj): + o = relational_operator(_right._gobj) + x = relational(left._gobj * _right._gobj.lhs(), + left._gobj * _right._gobj.rhs(), + o) + else: + x = left._gobj * _right._gobj return new_Expression_from_GEx(left._parent, x) cpdef _div_(left, right): @@ -3553,7 +3530,7 @@ cdef class Expression(CommutativeRingElement): sage: x/0 Traceback (most recent call last): ... - ZeroDivisionError: Symbolic division by zero + ZeroDivisionError: symbolic division by zero Check if Pynac can compute divisions of Python longs (:trac:`13107`):: @@ -3563,7 +3540,6 @@ cdef class Expression(CommutativeRingElement): cdef GEx x cdef Expression _right = right cdef operators o - sig_on() try: if is_a_relational(left._gobj): if is_a_relational(_right._gobj): @@ -3589,11 +3565,9 @@ cdef class Expression(CommutativeRingElement): # TODO: change this to maybe cleverly do something involving Cython C++ exception handling. # See http://docs.cython.org/docs/wrapping_CPlusPlus.html if 'division by zero' in str(msg): - raise ZeroDivisionError("Symbolic division by zero") + raise ZeroDivisionError("symbolic division by zero") else: raise - finally: - sig_off() def __invert__(self): """ @@ -5314,11 +5288,7 @@ cdef class Expression(CommutativeRingElement): for k, v in sdict.iteritems(): smap.insert(make_pair((self.coerce_in(k))._gobj, (self.coerce_in(v))._gobj)) - sig_on() - try: - res = self._gobj.subs_map(smap, 0) - finally: - sig_off() + res = self._gobj.subs_map(smap, 0) return new_Expression_from_GEx(self._parent, res) subs = substitute @@ -6861,7 +6831,7 @@ cdef class Expression(CommutativeRingElement): sage: f = pi^3*x - y^2*e - I; f pi^3*x - y^2*e - I sage: f.polynomial(CDF) # abs tol 1e-15 - (-2.718281828459045)*y^2 + 31.006276680299827*x - 1.0*I + (-2.718281828459045)*y^2 + 31.006276680299816*x - 1.0*I sage: f.polynomial(CC) (-2.71828182845905)*y^2 + 31.0062766802998*x - 1.00000000000000*I sage: f.polynomial(ComplexField(70)) @@ -7183,12 +7153,7 @@ cdef class Expression(CommutativeRingElement): x^2 + 2*x + 2 """ cdef Expression r = self.coerce_in(b) - cdef GEx x - sig_on() - try: - x = g_gcd(self._gobj, r._gobj) - finally: - sig_off() + cdef GEx x = g_gcd(self._gobj, r._gobj) return new_Expression_from_GEx(self._parent, x) def gosper_sum(self, *args): @@ -8983,12 +8948,7 @@ cdef class Expression(CommutativeRingElement): sage: t = SR(1).zeta(); t Infinity """ - cdef GEx x - sig_on() - try: - x = g_hold_wrapper(g_zeta, self._gobj, hold) - finally: - sig_off() + cdef GEx x = g_hold_wrapper(g_zeta, self._gobj, hold) return new_Expression_from_GEx(self._parent, x) def factorial(self, hold=False): diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 138ad632a72..444503c2825 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -22,8 +22,8 @@ from sage.structure.element cimport Element, parent from .expression cimport new_Expression_from_GEx, Expression from .ring import SR -from sage.structure.coerce cimport py_scalar_to_element, is_numpy_type, is_mpmath_type -from sage.structure.element cimport coercion_model +from sage.structure.coerce cimport (coercion_model, + py_scalar_to_element, is_numpy_type, is_mpmath_type) from sage.structure.richcmp cimport richcmp # we keep a database of symbolic functions initialized in a session diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index fe4a4747724..09a0c58b254 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -409,7 +409,6 @@ def coeff_generator(): return randint(-100,100)/randint(1,100) def make_random_expr(): - from sage.symbolic.random_tests import random_expr, fast_nodes while True: try: return random_expr( diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 8b95ffa7e70..c6e3b4da8d0 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -622,12 +622,12 @@ def solve(f, *args, **kwds): some solutions of trigonometric equations are lost). - ``algorithm`` - string (default: 'maxima'); to use SymPy's - solvers set this to 'sympy'. Note that SymPy is always used - for diophantine equations. + solvers set this to 'sympy'. Note that SymPy is always used + for diophantine equations. - ``domain`` - string (default: 'complex'); setting this to 'real' - changes the way SymPy solves single equations; inequalities - are always solvedin the real domain. + changes the way SymPy solves single equations; inequalities + are always solved in the real domain. EXAMPLES:: diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 3d0cbb56693..f6bd6a823db 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -32,7 +32,8 @@ from sage.structure.coerce cimport is_numpy_type from sage.rings.all import RR, CC, ZZ import operator - +import parser + cdef class SymbolicRing(CommutativeRing): """ Symbolic Ring, parent object for all symbolic expressions. @@ -1331,6 +1332,7 @@ def is_SymbolicVariable(x): """ return is_Expression(x) and is_a_symbol((x)._gobj) + def isidentifier(x): """ Return whether ``x`` is a valid identifier. @@ -1340,7 +1342,7 @@ def isidentifier(x): INPUT: - - ``x`` -- a string. + - ``x`` -- a string OUTPUT: @@ -1363,10 +1365,15 @@ def isidentifier(x): True sage: isidentifier('lambda s:s+1') False + sage: isidentifier('None') + True """ - import parser + try: + return x.isidentifier() # py3 + except AttributeError: + pass # py2 try: code = parser.expr(x).compile() - except (MemoryError, OverflowError, SyntaxError, SystemError, parser.ParserError), msg: + except (MemoryError, OverflowError, SyntaxError, SystemError, parser.ParserError): return False return len(code.co_names) == 1 and code.co_names[0] == x diff --git a/src/sage/tests/all.py b/src/sage/tests/all.py index 628788f324e..8a5929fd50d 100644 --- a/src/sage/tests/all.py +++ b/src/sage/tests/all.py @@ -1,2 +1,24 @@ -from sage.modular.modsym.tests import Test as modsym -from sage.tests.arxiv_0812_2725 import * +""" +TESTS: + +Test the deprecation warnings:: + + sage: tests.CompleteMatchings + doctest:warning + ... + DeprecationWarning: + Importing CompleteMatchings from here is deprecated. If you need to use it, please import it directly from sage.tests.arxiv_0812_2725 + See https://trac.sagemath.org/27337 for details. + + sage: tests.modsym + doctest:warning + ... + DeprecationWarning: + Importing modsym from here is deprecated. If you need to use it, please import it directly from sage.modular.modsym.tests + See https://trac.sagemath.org/27337 for details. + +""" + +from sage.misc.lazy_import import lazy_import +lazy_import('sage.modular.modsym.tests', 'Test', as_='modsym', deprecation=27337) +lazy_import('sage.tests.arxiv_0812_2725', '*', deprecation=27337) diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/README b/src/sage/tests/books/computational-mathematics-with-sagemath/README new file mode 100644 index 00000000000..c1c375296d5 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/README @@ -0,0 +1,6 @@ +This directory contains all the example code from the book +"Computational Mathematics with SageMath" by Paul Zimmermann et al, +freely available from http://sagebook.gforge.inria.fr/english.html + +Each file corresponds to a chapter of the book. +The directory "sol" contains the code for Annex A: answers to exercises diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py new file mode 100644 index 00000000000..2e188829ed8 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py @@ -0,0 +1,555 @@ +## -*- encoding: utf-8 -*- +""" +This file (./calculus_doctest.sage) was *autogenerated* from ./calculus.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./calculus_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./calculus.tex, line 76:: + + sage: bool(arctan(1+abs(x)) == pi/2 - arctan(1/(1+abs(x)))) + False + +Sage example in ./calculus.tex, line 121:: + + sage: a, x = var('a, x'); y = cos(x+a) * (x+1); y + (x + 1)*cos(a + x) + sage: y.subs(a=-x); y.subs(x=pi/2, a=pi/3); y.subs(x=0.5, a=2.3) + x + 1 + -1/4*sqrt(3)*(pi + 2) + -1.41333351100299 + sage: y(a=-x); y(x=pi/2, a=pi/3); y(x=0.5, a=2.3) + x + 1 + -1/4*sqrt(3)*(pi + 2) + -1.41333351100299 + +Sage example in ./calculus.tex, line 143:: + + sage: x, y, z = var('x, y, z') ; q = x*y + y*z + z*x + sage: bool(q(x=y, y=z, z=x) == q), bool(q(z=y)(y=x) == 3*x^2) + (True, True) + +Sage example in ./calculus.tex, line 155:: + + sage: y, z = var('y, z'); f = x^3 + y^2 + z + sage: f.substitute(x^3 == y^2, z==1) + 2*y^2 + 1 + +Sage example in ./calculus.tex, line 176:: + + sage: f(x)=(2*x+1)^3 ; f(-3) + -125 + sage: f.expand() + x |--> 8*x^3 + 12*x^2 + 6*x + 1 + +Sage example in ./calculus.tex, line 193:: + + sage: y = var('y'); u = sin(x) + x*cos(y) + sage: v = u.function(x, y); v + (x, y) |--> x*cos(y) + sin(x) + sage: w(x, y) = u; w + (x, y) |--> x*cos(y) + sin(x) + +Sage example in ./calculus.tex, line 240:: + + sage: x, y = SR.var('x,y') + sage: p = (x+y)*(x+1)^2 + sage: p2 = p.expand(); p2 + x^3 + x^2*y + 2*x^2 + 2*x*y + x + y + +Sage example in ./calculus.tex, line 251:: + + sage: p2.collect(x) + x^3 + x^2*(y + 2) + x*(2*y + 1) + y + +Sage example in ./calculus.tex, line 260:: + + sage: ((x+y+sin(x))^2).expand().collect(sin(x)) + x^2 + 2*x*y + y^2 + 2*(x + y)*sin(x) + sin(x)^2 + +Sage example in ./calculus.tex, line 416:: + + sage: (x^x/x).simplify() + x^(x - 1) + +Sage example in ./calculus.tex, line 426:: + + sage: f = (e^x-1) / (1+e^(x/2)); f.canonicalize_radical() + e^(1/2*x) - 1 + +Sage example in ./calculus.tex, line 435:: + + sage: f = cos(x)^6 + sin(x)^6 + 3 * sin(x)^2 * cos(x)^2 + sage: f.simplify_trig() + 1 + +Sage example in ./calculus.tex, line 447:: + + sage: f = cos(x)^6; f.reduce_trig() + 1/32*cos(6*x) + 3/16*cos(4*x) + 15/32*cos(2*x) + 5/16 + sage: f = sin(5 * x); f.expand_trig() + 5*cos(x)^4*sin(x) - 10*cos(x)^2*sin(x)^3 + sin(x)^5 + +Sage example in ./calculus.tex, line 482:: + + sage: n = var('n'); f = factorial(n+1)/factorial(n) + sage: f.simplify_factorial() + n + 1 + +Sage example in ./calculus.tex, line 502:: + + sage: f = sqrt(abs(x)^2); f.canonicalize_radical() + abs(x) + sage: f = log(x*y); f.canonicalize_radical() + log(x) + log(y) + +Sage example in ./calculus.tex, line 592:: + + sage: assume(x > 0); bool(sqrt(x^2) == x) + True + sage: forget(x > 0); bool(sqrt(x^2) == x) + False + sage: n = var('n'); assume(n, 'integer'); sin(n*pi) + 0 + +Sage example in ./calculus.tex, line 600:: + + sage: forget(n, 'integer'); + +Sage example in ./calculus.tex, line 690:: + + sage: a = var('a') + sage: c = (a+1)^2 - (a^2+2*a+1) + +Sage example in ./calculus.tex, line 700:: + + sage: eq = c * x == 0 + +Sage example in ./calculus.tex, line 707:: + + sage: eq2 = eq / c; eq2 + x == 0 + sage: solve(eq2, x) + [x == 0] + +Sage example in ./calculus.tex, line 715:: + + sage: solve(eq, x) + [x == x] + +Sage example in ./calculus.tex, line 725:: + + sage: expand(c) + 0 + +Sage example in ./calculus.tex, line 738:: + + sage: c = cos(a)^2 + sin(a)^2 - 1 + sage: eq = c*x == 0 + sage: solve(eq, x) + [x == 0] + +Sage example in ./calculus.tex, line 750:: + + sage: c.simplify_trig() + 0 + sage: c.is_zero() + True + +Sage example in ./calculus.tex, line 839:: + + sage: z, phi = var('z, phi') + sage: eq = z**2 - 2/cos(phi)*z + 5/cos(phi)**2 - 4 == 0; eq + z^2 - 2*z/cos(phi) + 5/cos(phi)^2 - 4 == 0 + +Sage example in ./calculus.tex, line 852:: + + sage: eq.lhs() + z^2 - 2*z/cos(phi) + 5/cos(phi)^2 - 4 + sage: eq.rhs() + 0 + +Sage example in ./calculus.tex, line 861:: + + sage: solve(eq, z) + [z == -(2*sqrt(cos(phi)^2 - 1) - 1)/cos(phi), + z == (2*sqrt(cos(phi)^2 - 1) + 1)/cos(phi)] + +Sage example in ./calculus.tex, line 871:: + + sage: y = var('y'); solve(y^7==y, y) + [y == 1/2*I*sqrt(3) + 1/2, y == 1/2*I*sqrt(3) - 1/2, y == -1, + y == -1/2*I*sqrt(3) - 1/2, y == -1/2*I*sqrt(3) + 1/2, y == 1, y == 0] + +Sage example in ./calculus.tex, line 880:: + + sage: solve(x^2-1, x, solution_dict=True) + [{x: -1}, {x: 1}] + +Sage example in ./calculus.tex, line 894:: + + sage: solve([x+y == 3, 2*x+2*y == 6], x, y) + [[x == -r1 + 3, y == r1]] + +Sage example in ./calculus.tex, line 910:: + + sage: solve([cos(x)*sin(x) == 1/2, x+y == 0], x, y) + [[x == 1/4*pi + pi*z..., y == -1/4*pi - pi*z...]] + +Sage example in ./calculus.tex, line 920:: + + sage: solve(x^2+x-1 > 0, x) + [[x < -1/2*sqrt(5) - 1/2], [x > 1/2*sqrt(5) - 1/2]] + +Sage example in ./calculus.tex, line 943:: + + sage: x, y, z = var('x, y, z') + sage: solve([x^2 * y * z == 18, x * y^3 * z == 24,\ + ....: x * y * z^4 == 6], x, y, z) + [[x == 3, y == 2, z == 1], + [x == (1.3372150673296... - 2.685489874065...*I), + y == (-1.7004342714592... + 1.0528643257547...*I), + z == (0.93247222940435... - 0.36124166618715...*I)], ...] + +Sage example in ./calculus.tex, line 975:: + + sage: expr = sin(x) + sin(2 * x) + sin(3 * x) + sage: solve(expr, x) + [sin(3*x) == -sin(2*x) - sin(x)] + +Sage example in ./calculus.tex, line 983:: + + sage: find_root(expr, 0.1, pi) # abs tol 1e-12 + 2.0943951023931957 + +Sage example in ./calculus.tex, line 989:: + + sage: f = expr.simplify_trig(); f + 2*(2*cos(x)^2 + cos(x))*sin(x) + sage: solve(f, x) + [x == 0, x == 2/3*pi, x == 1/2*pi] + +Sage example in ./calculus.tex, line 1022:: + + sage: (x^3+2*x+1).roots(x) + [(-1/2*(1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) + - 1/3*(I*sqrt(3) - 1)/(1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3), 1), + (-1/2*(1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3)*(-I*sqrt(3) + 1) + - 1/3*(-I*sqrt(3) - 1)/(1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3), 1), + ((1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3) + - 2/3/(1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3), 1)] + +Sage example in ./calculus.tex, line 1058:: + + sage: (x^3+2*x+1).roots(x, ring=RR) + [(-0.453397651516404, 1)] + +Sage example in ./calculus.tex, line 1062:: + + sage: (x^3+2*x+1).roots(x, ring=CC) + [(-0.453397651516404, 1), + (0.226698825758202 - 1.46771150871022*I, 1), + (0.226698825758202 + 1.46771150871022*I, 1)] + +Sage example in ./calculus.tex, line 1086:: + + sage: solve(x^(1/x)==(1/x)^x, x) + [(1/x)^x == x^(1/x)] + +Sage example in ./calculus.tex, line 1124:: + + sage: y = function('y')(x) + sage: desolve(diff(y,x,x) + x*diff(y,x) + y == 0, y, [0,0,1]) + -1/2*I*sqrt(2)*sqrt(pi)*erf(1/2*I*sqrt(2)*x)*e^(-1/2*x^2) + +Sage example in ./calculus.tex, line 1171:: + + sage: k, n = var('k, n') + sage: sum(k, k, 1, n).factor() + 1/2*(n + 1)*n + +Sage example in ./calculus.tex, line 1179:: + + sage: n, k, y = var('n, k, y') + sage: sum(binomial(n,k) * x^k * y^(n-k), k, 0, n) + (x + y)^n + +Sage example in ./calculus.tex, line 1189:: + + sage: k, n = var('k, n') + sage: sum(binomial(n,k), k, 0, n),\ + ....: sum(k * binomial(n, k), k, 0, n),\ + ....: sum((-1)^k*binomial(n,k), k, 0, n) + (2^n, 2^(n - 1)*n, 0) + +Sage example in ./calculus.tex, line 1199:: + + sage: a, q, k, n = var('a, q, k, n') + sage: sum(a*q^k, k, 0, n) + (a*q^(n + 1) - a)/(q - 1) + +Sage example in ./calculus.tex, line 1212:: + + sage: assume(abs(q) < 1) + sage: sum(a*q^k, k, 0, infinity) + -a/(q - 1) + +Sage example in ./calculus.tex, line 1218:: + + sage: forget(); assume(q > 1); sum(a*q^k, k, 0, infinity) + Traceback (most recent call last): + ... + ValueError: Sum is divergent. + +Sage example in ./calculus.tex, line 1300:: + + sage: limit((x**(1/3) - 2) / ((x + 19)**(1/3) - 3), x = 8) + 9/4 + sage: f(x) = (cos(pi/4-x)-tan(x))/(1-sin(pi/4 + x)) + sage: limit(f(x), x = pi/4) + Infinity + +Sage example in ./calculus.tex, line 1317:: + + sage: limit(f(x), x = pi/4, dir='minus') + +Infinity + sage: limit(f(x), x = pi/4, dir='plus') + -Infinity + +Sage example in ./calculus.tex, line 1368:: + + sage: u(n) = n^100 / 100^n + sage: u(1.);u(2.);u(3.);u(4.);u(5.);u(6.);u(7.);u(8.);u(9.);u(10.) + 0.0100000000000000 + 1.26765060022823e26 + 5.15377520732011e41 + 1.60693804425899e52 + 7.88860905221012e59 + 6.53318623500071e65 + 3.23447650962476e70 + 2.03703597633449e74 + 2.65613988875875e77 + 1.00000000000000e80 + +Sage example in ./calculus.tex, line 1389:: + + sage: plot(u(x), x, 1, 40) + Graphics object consisting of 1 graphics primitive + +Sage example in ./calculus.tex, line 1407:: + + sage: v(x) = diff(u(x), x); sol = solve(v(x) == 0, x); sol + [x == 50/log(10), x == 0] + sage: floor(sol[0].rhs()) + 21 + +Sage example in ./calculus.tex, line 1420:: + + sage: limit(u(n), n=infinity) + 0 + sage: n0 = find_root(u(n) - 1e-8 == 0, 22, 1000); n0 + 105.07496210187252 + +Sage example in ./calculus.tex, line 1502:: + + sage: ((1+arctan(x))^(1/x)).series(x==0, 3) + (e) + (-1/2*e)*x + (1/8*e)*x^2 + Order(x^3) + +Sage example in ./calculus.tex, line 1507:: + + sage: (ln(2*sin(x))).series(x==pi/6, 3) + (sqrt(3))*(-1/6*pi + x) + (-2)*(-1/6*pi + x)^2 + + Order(-1/216*(pi - 6*x)^3) + +Sage example in ./calculus.tex, line 1520:: + + sage: (ln(2*sin(x))).series(x==pi/6, 3).truncate() + -1/18*(pi - 6*x)^2 - 1/6*sqrt(3)*(pi - 6*x) + +Sage example in ./calculus.tex, line 1537:: + + sage: taylor((x**3+x)**(1/3) - (x**3-x)**(1/3), x, infinity, 2) + 2/3/x + +Sage example in ./calculus.tex, line 1577:: + + sage: tan(4*arctan(1/5)).simplify_trig() + 120/119 + sage: tan(pi/4+arctan(1/239)).simplify_trig() + 120/119 + +Sage example in ./calculus.tex, line 1591:: + + sage: f = arctan(x).series(x, 10); f + 1*x + (-1/3)*x^3 + 1/5*x^5 + (-1/7)*x^7 + 1/9*x^9 + Order(x^10) + sage: (16*f.subs(x==1/5) - 4*f.subs(x==1/239)).n(); pi.n() + 3.14159268240440 + 3.14159265358979 + +Sage example in ./calculus.tex, line 1662:: + + sage: k = var('k') + sage: sum(1/k^2, k, 1, infinity),\ + ....: sum(1/k^4, k, 1, infinity),\ + ....: sum(1/k^5, k, 1, infinity) + (1/6*pi^2, 1/90*pi^4, zeta(5)) + +Sage example in ./calculus.tex, line 1689:: + + sage: s = 2*sqrt(2)/9801*(sum((factorial(4*k)) * (1103+26390*k) / + ....: ((factorial(k)) ^ 4 * 396 ^ (4 * k)) for k in (0..11))) + sage: (1/s).n(digits=100) + 3.141592653589793238462643383279502884197169399375105820974... + sage: (pi-1/s).n(digits=100).n() + -4.36415445739398e-96 + +Sage example in ./calculus.tex, line 1722:: + + sage: n = var('n'); u = sin(pi*(sqrt(4*n^2+1)-2*n)) + sage: taylor(u, n, infinity, 3) + 1/4*pi/n - 1/384*(6*pi + pi^3)/n^3 + +Sage example in ./calculus.tex, line 1762:: + + sage: diff(sin(x^2), x) + 2*x*cos(x^2) + sage: function('f')(x); function('g')(x); diff(f(g(x)), x) + f(x) + g(x) + D[0](f)(g(x))*diff(g(x), x) + sage: diff(ln(f(x)), x) + diff(f(x), x)/f(x) + +Sage example in ./calculus.tex, line 1780:: + + sage: f(x,y) = x*y + sin(x^2) + e^(-x); derivative(f, x) + (x, y) |--> 2*x*cos(x^2) + y - e^(-x) + sage: derivative(f, y) + (x, y) |--> x + +Sage example in ./calculus.tex, line 1803:: + + sage: x, y = var('x, y'); f = ln(x**2+y**2) / 2 + sage: delta = diff(f,x,2) + diff(f,y,2) + sage: delta.simplify_rational() + 0 + +Sage example in ./calculus.tex, line 1854:: + + sage: sin(x).integral(x, 0, pi/2) + 1 + sage: integrate(1/(1+x^2), x) + arctan(x) + sage: integrate(1/(1+x^2), x, -infinity, infinity) + pi + sage: integrate(exp(-x**2), x, 0, infinity) + 1/2*sqrt(pi) + +Sage example in ./calculus.tex, line 1864:: + + sage: integrate(exp(-x), x, -infinity, infinity) + Traceback (most recent call last): + ... + ValueError: Integral is divergent. + +Sage example in ./calculus.tex, line 1878:: + + sage: u = var('u'); f = x * cos(u) / (u^2 + x^2) + sage: assume(x>0); f.integrate(u, 0, infinity) + 1/2*pi*e^(-x) + sage: forget(); assume(x<0); f.integrate(u, 0, infinity) + -1/2*pi*e^x + +Sage example in ./calculus.tex, line 1904:: + + sage: integral_numerical(sin(x)/x, 0, 1) # abs tol 1e-12 + (0.946083070367183, 1.0503632079297087e-14) + sage: g = integrate(exp(-x**2), x, 0, infinity) + sage: g, g.n() # abs tol 1e-12 + (1/2*sqrt(pi), 0.886226925452758) + sage: approx = integral_numerical(exp(-x**2), 0, infinity) + sage: approx # abs tol 1e-12 + (0.8862269254527568, 1.714774436012769e-08) + sage: approx[0]-g.n() # abs tol 1e-12 + -1.11022302462516e-15 + +Sage example in ./calculus.tex, line 2228:: + + sage: A = matrix(QQ, [[1,2],[3,4]]); A + [1 2] + [3 4] + +Sage example in ./calculus.tex, line 2468:: + + sage: A = matrix(QQ, [[2,4,3],[-4,-6,-3],[3,3,1]]) + sage: A.characteristic_polynomial() + x^3 + 3*x^2 - 4 + sage: A.eigenvalues() + [1, -2, -2] + sage: A.minimal_polynomial().factor() + (x - 1) * (x + 2)^2 + +Sage example in ./calculus.tex, line 2487:: + + sage: A.eigenvectors_right() + [(1, [ + (1, -1, 1) + ], 1), (-2, [ + (1, -1, 0) + ], 2)] + +Sage example in ./calculus.tex, line 2499:: + + sage: A.jordan_form(transformation=True) + ( + [ 1| 0 0] + [--+-----] [ 1 1 1] + [ 0|-2 1] [-1 -1 0] + [ 0| 0 -2], [ 1 0 -1] + ) + +Sage example in ./calculus.tex, line 2533:: + + sage: A = matrix(QQ, [[1,-1/2],[-1/2,-1]]) + sage: A.jordan_form() + Traceback (most recent call last): + ... + RuntimeError: Some eigenvalue does not exist in Rational Field. + +Sage example in ./calculus.tex, line 2543:: + + sage: A = matrix(QQ, [[1,-1/2],[-1/2,-1]]) + sage: A.minimal_polynomial() + x^2 - 5/4 + +Sage example in ./calculus.tex, line 2557:: + + sage: R = QQ[sqrt(5)] + sage: A = A.change_ring(R) + sage: A.jordan_form(transformation=True, subdivide=False) + ( + [ 1/2*sqrt5 0] [ 1 1] + [ 0 -1/2*sqrt5], [-sqrt5 + 2 sqrt5 + 2] + ) + +Sage example in ./calculus.tex, line 2597:: + + sage: K. = NumberField(x^2 - 2) + sage: L. = K.extension(x^2 - 3) + sage: A = matrix(L, [[2, sqrt2*sqrt3, sqrt2], \ + ....: [sqrt2*sqrt3, 3, sqrt3], \ + ....: [sqrt2, sqrt3, 1]]) + sage: A.jordan_form(transformation=True) + ( + [6|0|0] + [-+-+-] + [0|0|0] [ 1 1 0] + [-+-+-] [1/2*sqrt2*sqrt3 0 1] + [0|0|0], [ 1/2*sqrt2 -sqrt2 -sqrt3] + ) + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py new file mode 100644 index 00000000000..65e77a91e63 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/combinat_doctest.py @@ -0,0 +1,1063 @@ +## -*- encoding: utf-8 -*- +""" +This file (./combinat_doctest.sage) was *autogenerated* from ./combinat.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./combinat_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./combinat.tex, line 147:: + + sage: Suits = Set(["Hearts", "Diamonds", "Spades", "Clubs"]) + sage: Values = Set([2, 3, 4, 5, 6, 7, 8, 9, 10, + ....: "Jack", "Queen", "King", "Ace"]) + sage: Cards = cartesian_product([Values, Suits]) + +Sage example in ./combinat.tex, line 167:: + + sage: Suits.cardinality() + 4 + sage: Values.cardinality() + 13 + sage: Cards.cardinality() + 52 + +Sage example in ./combinat.tex, line 184:: + + sage: Cards.random_element() # random + (6, 'Clubs') + +Sage example in ./combinat.tex, line 196:: + + sage: Set([Cards.random_element(), Cards.random_element()]) # random + {(2, 'Hearts'), (4, 'Spades')} + +Sage example in ./combinat.tex, line 221:: + + sage: Hands = Subsets(Cards, 5) + sage: Hands.random_element() # random + {(4, 'Hearts'), (9, 'Diamonds'), (8, 'Spades'), + (9, 'Clubs'), (7, 'Hearts')} + +Sage example in ./combinat.tex, line 236:: + + sage: binomial(52, 5) + 2598960 + +Sage example in ./combinat.tex, line 250:: + + sage: Hands.cardinality() + 2598960 + +Sage example in ./combinat.tex, line 283:: + + sage: Flushes = cartesian_product([Subsets(Values, 5), Suits]) + sage: Flushes.cardinality() + 5148 + +Sage example in ./combinat.tex, line 305:: + + sage: Flushes.cardinality() / Hands.cardinality() + 33/16660 + +Sage example in ./combinat.tex, line 310:: + + sage: 1000.0 * Flushes.cardinality() / Hands.cardinality() + 1.98079231692677 + +Sage example in ./combinat.tex, line 345:: + + sage: def is_flush(hand): + ....: return len(set(suit for (val, suit) in hand)) == 1 + +Sage example in ./combinat.tex, line 354:: + + sage: n = 10000 + sage: nflush = 0 + sage: for i in range(n): + ....: hand = Hands.random_element() + ....: if is_flush(hand): + ....: nflush += 1 + sage: print(n, nflush) # random + 10000, 18 + +Sage example in ./combinat.tex, line 600:: + + sage: C, z = var('C, z'); sys = [ C == z + C*C ] + +Sage example in ./combinat.tex, line 605:: + + sage: sol = solve(sys, C, solution_dict=True); sol + [{C: -1/2*sqrt(-4*z + 1) + 1/2}, {C: 1/2*sqrt(-4*z + 1) + 1/2}] + sage: s0 = sol[0][C]; s1 = sol[1][C] + +Sage example in ./combinat.tex, line 612:: + + sage: s0.series(z, 6) + 1*z + 1*z^2 + 2*z^3 + 5*z^4 + 14*z^5 + Order(z^6) + sage: s1.series(z, 6) + 1 + (-1)*z + (-1)*z^2 + (-2)*z^3 + (-5)*z^4 + (-14)*z^5 + Order(z^6) + +Sage example in ./combinat.tex, line 622:: + + sage: C = s0 + +Sage example in ./combinat.tex, line 627:: + + sage: C.series(z, 11) + 1*z + 1*z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + + 132*z^7 + 429*z^8 + 1430*z^9 + 4862*z^10 + Order(z^11) + +Sage example in ./combinat.tex, line 634:: + + sage: C.series(z, 101).coefficient(z,100) + 227508830794229349661819540395688853956041682601541047340 + +Sage example in ./combinat.tex, line 654:: + + sage: L. = LazyPowerSeriesRing(QQ) + +Sage example in ./combinat.tex, line 661:: + + sage: C = L() + sage: C._name = 'C' + sage: C.define( z + C * C ) + +Sage example in ./combinat.tex, line 666:: + + sage: [C.coefficient(i) for i in range(11)] + [0, 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862] + +Sage example in ./combinat.tex, line 674:: + + sage: C.coefficient(100) + 227508830794229349661819540395688853956041682601541047340 + +Sage example in ./combinat.tex, line 684:: + + sage: C.coefficient(200) + 129013158064429114001222907669676675134349530552728882499810851598901419013348319045534580850847735528275750122188940 + +Sage example in ./combinat.tex, line 693:: + + sage: z = var('z'); C = s0; C + -1/2*sqrt(-4*z + 1) + 1/2 + +Sage example in ./combinat.tex, line 703:: + + sage: derivative(C, z, 1) + 1/sqrt(-4*z + 1) + sage: derivative(C, z, 2) + 2/(-4*z + 1)^(3/2) + sage: derivative(C, z, 3) + 12/(-4*z + 1)^(5/2) + +Sage example in ./combinat.tex, line 716:: + + sage: def d(n): return derivative(C, n).subs(z=0) + +Sage example in ./combinat.tex, line 721:: + + sage: [ (d(n+1) / d(n)) for n in range(1,17) ] + [2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62] + +Sage example in ./combinat.tex, line 737:: + + sage: def c(n): return 1/n*binomial(2*(n-1),n-1) + sage: [c(k) for k in range(1, 11)] + [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862] + sage: [catalan_number(k-1) for k in range(1, 11)] + [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862] + +Sage example in ./combinat.tex, line 814:: + + sage: x, y, z = var('x, y, z') + sage: P = function('P')(x, y); C = function('C')(z) + sage: equation = P(x=z, y=C) == 0 + sage: diff(equation, z) + diff(C(z), z)*D[1](P)(z, C(z)) + D[0](P)(z, C(z)) == 0 + +Sage example in ./combinat.tex, line 834:: + + sage: P = y^2 - y + x; Px = diff(P, x); Py = diff(P, y) + sage: - Px / Py + -1/(2*y - 1) + +Sage example in ./combinat.tex, line 847:: + + sage: Qx = QQ['x'].fraction_field(); Qxy = Qx['y'] + sage: R = Qxy.quo(P); R + Univariate Quotient Polynomial Ring in ybar + over Fraction Field of Univariate Polynomial Ring in x + over Rational Field with modulus y^2 - y + x + +Sage example in ./combinat.tex, line 863:: + + sage: fraction = R( - Px / Py ); fraction + Traceback (most recent call last): + ... + TypeError: unable to convert -1/(2*y - 1) to an element of Univariate Quotient Polynomial Ring in ybar over Fraction Field of Univariate Polynomial Ring in x over Rational Field with modulus y^2 - y + x + +Sage example in ./combinat.tex, line 869:: + + sage: fraction = - R(Px) / R(Py); fraction + (1/2/(x - 1/4))*ybar - 1/4/(x - 1/4) + +Sage example in ./combinat.tex, line 877:: + + sage: fraction = fraction.lift(); fraction + (1/2/(x - 1/4))*y - 1/4/(x - 1/4) + sage: fraction(x=z, y=C) + 2*C(z)/(4*z - 1) - 1/(4*z - 1) + +Sage example in ./combinat.tex, line 894:: + + sage: equadiff = diff(C,z) == fraction(x=z, y=C); equadiff + diff(C(z), z) == 2*C(z)/(4*z - 1) - 1/(4*z - 1) + sage: equadiff = equadiff.simplify_rational() + sage: equadiff = equadiff * equadiff.rhs().denominator() + sage: equadiff = equadiff - equadiff.rhs() + sage: equadiff + (4*z - 1)*diff(C(z), z) - 2*C(z) + 1 == 0 + +Sage example in ./combinat.tex, line 913:: + + sage: Cf = sage.symbolic.function_factory.function('C') + sage: equadiff.substitute_function(Cf, lambda z: s0(z=z)) + (4*z - 1)/sqrt(-4*z + 1) + sqrt(-4*z + 1) == 0 + +Sage example in ./combinat.tex, line 923:: + + sage: Cf = sage.symbolic.function_factory.function('C') + sage: bool(equadiff.substitute_function(Cf, lambda z: s0(z=z))) + True + +Sage example in ./combinat.tex, line 959:: + + sage: def C(n): return n if n <= 1 else (4*n-6)/n * C(n-1) + sage: [ C(i) for i in range(10) ] + [0, 1, 1, 2, 5, 14, 42, 132, 429, 1430] + +Sage example in ./combinat.tex, line 1078:: + + sage: binomial(4, 2) + 6 + +Sage example in ./combinat.tex, line 1088:: + + sage: S = Subsets([1,2,3,4], 2); S.cardinality() + 6 + +Sage example in ./combinat.tex, line 1097:: + + sage: S.list() + [{1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 4}] + sage: S.random_element() # random + {1, 4} + sage: S.an_element() + {2, 3} + +Sage example in ./combinat.tex, line 1118:: + + sage: S.unrank(4) + {2, 4} + sage: S[4] + {2, 4} + +Sage example in ./combinat.tex, line 1133:: + + sage: s = S([2,4]); S.rank(s) + 4 + +Sage example in ./combinat.tex, line 1145:: + + sage: E = Set([1,2,3,4]) + sage: S = Subsets(Subsets(Subsets(E))); S.cardinality() + 2003529930406846464979072351560255750447825475569751419265016...736 + +Sage example in ./combinat.tex, line 1167:: + + sage: S.cardinality().ndigits() + 19729 + +Sage example in ./combinat.tex, line 1179:: + + sage: sorted(sorted(sorted(x) for x in y) for y in S.unrank(237102123) ) + [[[], [1, 2, 4], [1, 3], [1, 3, 4], [1, 4], [2], [2, 3], [2, 4], [4]], + [[], [1, 2, 4], [1, 3], [2, 4], [3, 4]]] + +Sage example in ./combinat.tex, line 1203:: + + sage: len(S) # py2 + Traceback (most recent call last): + ... + OverflowError: Python int too large to convert to C long + +Sage example in ./combinat.tex, line 1237:: + + sage: P5 = Partitions(5); P5 + Partitions of the integer 5 + +Sage example in ./combinat.tex, line 1243:: + + sage: P5.cardinality() + 7 + +Sage example in ./combinat.tex, line 1251:: + + sage: P5.list() + [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1], [2, 1, 1, 1], + [1, 1, 1, 1, 1]] + +Sage example in ./combinat.tex, line 1279:: + + sage: Partitions(100000).cardinality() + 27493510569775696512677516320986352688173429315980054758203125984302147328114964173055050741660736621590157844774296248940493063070200461792764493033510116079342457190155718943509725312466108452006369558934464248716828789832182345009262853831404597021307130674510624419227311238999702284408609370935531629697851569569892196108480158600569421098519 + +Sage example in ./combinat.tex, line 1291:: + + sage: P7 = Partitions(7); p = P7.unrank(5); p + [4, 2, 1] + +Sage example in ./combinat.tex, line 1295:: + + sage: type(p) + + +Sage example in ./combinat.tex, line 1302:: + + sage: print(p.ferrers_diagram()) + **** + ** + * + +Sage example in ./combinat.tex, line 1315:: + + sage: Partition([4,2,1]) + [4, 2, 1] + sage: P7([4,2,1]) + [4, 2, 1] + +Sage example in ./combinat.tex, line 1330:: + + sage: WeightedIntegerVectors(8, [2,3,5]).list() + [[0, 1, 1], [1, 2, 0], [4, 0, 0]] + +Sage example in ./combinat.tex, line 1343:: + + sage: C5 = Compositions(5); C5 + Compositions of 5 + sage: C5.cardinality() + 16 + sage: C5.list() + [[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 1, 2, 1], [1, 1, 3], + [1, 2, 1, 1], [1, 2, 2], [1, 3, 1], [1, 4], [2, 1, 1, 1], + [2, 1, 2], [2, 2, 1], [2, 3], [3, 1, 1], [3, 2], [4, 1], [5]] + +Sage example in ./combinat.tex, line 1360:: + + sage: [ Compositions(n).cardinality() for n in range(10) ] + [1, 1, 2, 4, 8, 16, 32, 64, 128, 256] + +Sage example in ./combinat.tex, line 1368:: + + sage: x = var('x'); sum( x^len(c) for c in C5 ) + x^5 + 4*x^4 + 6*x^3 + 4*x^2 + x + +Sage example in ./combinat.tex, line 1414:: + + sage: C = IntegerRange(3, 21, 2); C + {3, 5, ..., 19} + sage: C.cardinality() + 9 + sage: C.list() + [3, 5, 7, 9, 11, 13, 15, 17, 19] + +Sage example in ./combinat.tex, line 1424:: + + sage: C = Permutations(4); C + Standard permutations of 4 + sage: C.cardinality() + 24 + sage: C.list() + [[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], + [1, 4, 2, 3], [1, 4, 3, 2], [2, 1, 3, 4], [2, 1, 4, 3], + [2, 3, 1, 4], [2, 3, 4, 1], [2, 4, 1, 3], [2, 4, 3, 1], + [3, 1, 2, 4], [3, 1, 4, 2], [3, 2, 1, 4], [3, 2, 4, 1], + [3, 4, 1, 2], [3, 4, 2, 1], [4, 1, 2, 3], [4, 1, 3, 2], + [4, 2, 1, 3], [4, 2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]] + +Sage example in ./combinat.tex, line 1455:: + + sage: C = SetPartitions([1,2,3]); C + Set partitions of {1, 2, 3} + sage: C.cardinality() + 5 + sage: C.list() # random + [{{1, 2, 3}}, {{1}, {2, 3}}, {{1, 3}, {2}}, {{1, 2}, {3}}, {{1}, {2}, {3}}] + +Sage example in ./combinat.tex, line 1466:: + + sage: C = Posets(8); C + Posets containing 8 elements + sage: C.cardinality() + 16999 + +Sage example in ./combinat.tex, line 1475:: + + sage: show(C.unrank(20)) + ... + +Sage example in ./combinat.tex, line 1496:: + + sage: len(list(graphs(5))) + 34 + +Sage example in ./combinat.tex, line 1504:: + + sage: for g in graphs(5, lambda G: G.size() <= 4): + ....: show(g) + +Sage example in ./combinat.tex, line 1528:: + + sage: G = DihedralGroup(4); G + Dihedral group of order 8 as a permutation group + sage: G.cardinality() + 8 + sage: sorted(G.list(), key=str) + [(), (1,2)(3,4), (1,2,3,4), (1,3), (1,3)(2,4), (1,4)(2,3), (1,4,3,2), (2,4)] + +Sage example in ./combinat.tex, line 1542:: + + sage: import sage.repl.display.util + sage: sage.repl.display.util.TallListFormatter.MAX_COLUMN = 67 + +Sage example in ./combinat.tex, line 1547:: + + sage: C = MatrixSpace(GF(2), 2); C.list() + [ + [0 0] [1 0] [0 1] [0 0] [0 0] [1 1] [1 0] [1 0] [0 1] + [0 0], [0 0], [0 0], [1 0], [0 1], [0 0], [1 0], [0 1], [1 0], + + [0 1] [0 0] [1 1] [1 1] [1 0] [0 1] [1 1] + [0 1], [1 1], [1 0], [0 1], [1 1], [1 1], [1 1] + ] + +Sage example in ./combinat.tex, line 1557:: + + sage: C.cardinality() + 16 + +Sage example in ./combinat.tex, line 1634:: + + sage: [ i^2 for i in [1, 3, 7] ] + [1, 9, 49] + +Sage example in ./combinat.tex, line 1640:: + + sage: [ i^2 for i in range(1,10) ] + [1, 4, 9, 16, 25, 36, 49, 64, 81] + +Sage example in ./combinat.tex, line 1651:: + + sage: [ i^2 for i in range(1,10) if is_prime(i) ] + [4, 9, 25, 49] + +Sage example in ./combinat.tex, line 1661:: + + sage: [ (i,j) for i in range(1,6) for j in range(1,i) ] + [(2, 1), (3, 1), (3, 2), (4, 1), (4, 2), (4, 3), + (5, 1), (5, 2), (5, 3), (5, 4)] + +Sage example in ./combinat.tex, line 1668:: + + sage: [[binomial(n, i) for i in range(n+1)] for n in range(10)] + [[1], + [1, 1], + [1, 2, 1], + [1, 3, 3, 1], + [1, 4, 6, 4, 1], + [1, 5, 10, 10, 5, 1], + [1, 6, 15, 20, 15, 6, 1], + [1, 7, 21, 35, 35, 21, 7, 1], + [1, 8, 28, 56, 70, 56, 28, 8, 1], + [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]] + +Sage example in ./combinat.tex, line 1718:: + + sage: it = (binomial(3, i) for i in range(4)) + +Sage example in ./combinat.tex, line 1724:: + + sage: next(it) + 1 + sage: next(it) + 3 + sage: next(it) + 3 + sage: next(it) + 1 + +Sage example in ./combinat.tex, line 1736:: + + sage: next(it) + Traceback (most recent call last): + ... + StopIteration + +Sage example in ./combinat.tex, line 1754:: + + sage: for s in Subsets(3): s + {} + {1} + {2} + {3} + {1, 2} + {1, 3} + {2, 3} + {1, 2, 3} + +Sage example in ./combinat.tex, line 1765:: + + sage: [ s.cardinality() for s in Subsets(3) ] + [0, 1, 1, 1, 2, 2, 2, 3] + +Sage example in ./combinat.tex, line 1772:: + + sage: sum( [ binomial(8, i) for i in range(9) ] ) + 256 + +Sage example in ./combinat.tex, line 1784:: + + sage: sum( binomial(8, i) for i in range(9) ) + 256 + +Sage example in ./combinat.tex, line 1811:: + + sage: list(binomial(8, i) for i in range(9)) + [1, 8, 28, 56, 70, 56, 28, 8, 1] + sage: tuple(binomial(8, i) for i in range(9)) + (1, 8, 28, 56, 70, 56, 28, 8, 1) + +Sage example in ./combinat.tex, line 1823:: + + sage: all([True, True, True, True]) + True + sage: all([True, False, True, True]) + False + sage: any([False, False, False, False]) + False + sage: any([False, False, True, False]) + True + +Sage example in ./combinat.tex, line 1839:: + + sage: all( is_odd(p) for p in range(3,100) if is_prime(p) ) + True + +Sage example in ./combinat.tex, line 1852:: + + sage: def mersenne(p): return 2^p - 1 + sage: [ is_prime(p) for p in range(1000) if is_prime(mersenne(p)) ] + [True, True, True, True, True, True, True, True, True, True, + True, True, True, True] + +Sage example in ./combinat.tex, line 1867:: + + sage: all( [ is_prime(mersenne(p)) for p in range(1000) if is_prime(p)] ) + False + sage: all( is_prime(mersenne(p)) for p in range(1000) if is_prime(p) ) + False + +Sage example in ./combinat.tex, line 1879:: + + sage: exists( (p for p in range(1000) if is_prime(p)), + ....: lambda p: not is_prime(mersenne(p)) ) + (True, 11) + +Sage example in ./combinat.tex, line 1895:: + + sage: counter_examples = \ + ....: (p for p in range(1000) + ....: if is_prime(p) and not is_prime(mersenne(p))) + sage: next(counter_examples) + 11 + sage: next(counter_examples) + 23 + +Sage example in ./combinat.tex, line 1909:: + + sage: cubes = [t**3 for t in range(-999,1000)] + sage: exists([(x,y) for x in cubes for y in cubes], lambda xy: sum(xy) == 218) # long time + (True, (-125, 343)) + sage: exists(((x,y) for x in cubes for y in cubes), lambda xy: sum(xy) == 218) # long time + (True, (-125, 343)) + +Sage example in ./combinat.tex, line 1927:: + + sage: x = var('x'); sum( x^len(s) for s in Subsets(8) ) + x^8 + 8*x^7 + 28*x^6 + 56*x^5 + 70*x^4 + 56*x^3 + 28*x^2 + 8*x + 1 + +Sage example in ./combinat.tex, line 1931:: + + sage: sum( x^p.length() for p in Permutations(3) ) + x^3 + 2*x^2 + 2*x + 1 + +Sage example in ./combinat.tex, line 1940:: + + sage: P = Permutations(5) + sage: all( p in P for p in P ) + True + +Sage example in ./combinat.tex, line 1945:: + + sage: for p in GL(2, 2): print(p); print("-----") + [1 0] + [0 1] + ----- + [0 1] + [1 0] + ----- + [0 1] + [1 1] + ----- + [1 1] + [0 1] + ----- + [1 1] + [1 0] + ----- + [1 0] + [1 1] + ----- + +Sage example in ./combinat.tex, line 1966:: + + sage: for p in Partitions(3): print(p) + [3] + [2, 1] + [1, 1, 1] + +Sage example in ./combinat.tex, line 1987:: + + sage: exists( Primes(), lambda p: not is_prime(mersenne(p)) ) + (True, 11) + +Sage example in ./combinat.tex, line 2026:: + + sage: import itertools + +Sage example in ./combinat.tex, line 2033:: + + sage: list(Permutations(3)) + [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] + +Sage example in ./combinat.tex, line 2039:: + + sage: list(enumerate(Permutations(3))) + [(0, [1, 2, 3]), (1, [1, 3, 2]), (2, [2, 1, 3]), + (3, [2, 3, 1]), (4, [3, 1, 2]), (5, [3, 2, 1])] + +Sage example in ./combinat.tex, line 2048:: + + sage: list(itertools.islice(Permutations(3), 1r, 4r)) + [[1, 3, 2], [2, 1, 3], [2, 3, 1]] + +Sage example in ./combinat.tex, line 2054:: + + sage: list(map(lambda z: z.cycle_type(), Permutations(3))) + [[1, 1, 1], [2, 1], [2, 1], [3], [3], [2, 1]] + +Sage example in ./combinat.tex, line 2060:: + + sage: list(filter(lambda z: z.has_pattern([1,2]), + ....: Permutations(3))) + [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2]] + +Sage example in ./combinat.tex, line 2069:: + + sage: list(map(attrcall("cycle_type"), Permutations(3))) + [[1, 1, 1], [2, 1], [2, 1], [3], [3], [2, 1]] + +Sage example in ./combinat.tex, line 2084:: + + sage: def f(n): + ....: for i in range(n): + ....: yield i + +Sage example in ./combinat.tex, line 2097:: + + sage: g = f(4) + sage: next(g) + 0 + sage: next(g) + 1 + sage: next(g) + 2 + sage: next(g) + 3 + +Sage example in ./combinat.tex, line 2108:: + + sage: next(g) + Traceback (most recent call last): + ... + StopIteration + +Sage example in ./combinat.tex, line 2116:: + + sage: [ x for x in f(5) ] + [0, 1, 2, 3, 4] + +Sage example in ./combinat.tex, line 2130:: + + sage: def words(alphabet,l): + ....: if l == 0: yield [] + ....: else: + ....: for word in words(alphabet, l-1): + ....: for l in alphabet: yield word + [l] + sage: [ w for w in words(['a','b'], 3) ] + [['a', 'a', 'a'], ['a', 'a', 'b'], ['a', 'b', 'a'], ['a', 'b', 'b'], + ['b', 'a', 'a'], ['b', 'a', 'b'], ['b', 'b', 'a'], ['b', 'b', 'b']] + +Sage example in ./combinat.tex, line 2142:: + + sage: sum(1 for w in words(['a','b','c','d'], 10)) + 1048576 + +Sage example in ./combinat.tex, line 2169:: + + sage: def dyck_words(l): + ....: if l == 0: yield '' + ....: else: + ....: for k in range(l): + ....: for w1 in dyck_words(k): + ....: for w2 in dyck_words(l-k-1): + ....: yield '(' + w1 + ')' + w2 + +Sage example in ./combinat.tex, line 2180:: + + sage: list(dyck_words(4)) + ['()()()()', '()()(())', '()(())()', '()(()())', '()((()))', + '(())()()', '(())(())', '(()())()', '((()))()', '(()()())', + '(()(()))', '((())())', '((()()))', '(((())))'] + +Sage example in ./combinat.tex, line 2188:: + + sage: [ sum(1 for w in dyck_words(l)) for l in range(10) ] + [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862] + +Sage example in ./combinat.tex, line 2208:: + + sage: BT = BinaryTree + sage: BT() + . + sage: t = BT([BT([BT(), BT([BT(),BT()])]), BT()]); t + [[., [., .]], .] + +Sage example in ./combinat.tex, line 2261:: + + sage: C = cartesian_product([Compositions(8), Permutations(20)]); C + The Cartesian product of (Compositions of 8, Standard permutations of 20) + sage: C.cardinality() + 311411457046609920000 + +Sage example in ./combinat.tex, line 2274:: + + sage: C.random_element() # random + ([2, 3, 2, 1], [10, 6, 11, 13, 14, 3, 4, 19, 5, 12, 7, 18, 15, 8, 20, 1, 17, 2, 9, 16]) + +Sage example in ./combinat.tex, line 2288:: + + sage: G = DihedralGroup(4) + sage: H = cartesian_product([G,G]) + sage: H.cardinality() + 64 + sage: H in Sets().Enumerated().Finite() + True + sage: H in Groups() + True + +Sage example in ./combinat.tex, line 2305:: + + sage: C = DisjointUnionEnumeratedSets([Compositions(4),Permutations(3)]) + sage: C + Disjoint union of Family (Compositions of 4, Standard permutations of 3) + sage: C.cardinality() + 14 + sage: C.list() + [[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], + [4], [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] + +Sage example in ./combinat.tex, line 2328:: + + sage: F = Family(NonNegativeIntegers(), Permutations); F + Lazy family ((i))_{i in Non negative integers} + sage: F.keys() + Non negative integers + sage: F[1000] + Standard permutations of 1000 + +Sage example in ./combinat.tex, line 2339:: + + sage: U = DisjointUnionEnumeratedSets(F); U + Disjoint union of + Lazy family ((i))_{i in Non negative integers} + +Sage example in ./combinat.tex, line 2346:: + + sage: U.cardinality() + +Infinity + +Sage example in ./combinat.tex, line 2372:: + + sage: U = Permutations(); U + Standard permutations + +Sage example in ./combinat.tex, line 2450:: + + sage: IntegerVectors(10, 3, min_part = 2, max_part = 5, + ....: inner = [2, 4, 2]).list() + [[4, 4, 2], [3, 5, 2], [3, 4, 3], [2, 5, 3], [2, 4, 4]] + +Sage example in ./combinat.tex, line 2459:: + + sage: Compositions(5, max_part = 3, + ....: min_length = 2, max_length = 3).list() + [[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [1, 3, 1], + [1, 2, 2], [1, 1, 3]] + +Sage example in ./combinat.tex, line 2467:: + + sage: Partitions(5, max_slope = -1).list() + [[5], [4, 1], [3, 2]] + +Sage example in ./combinat.tex, line 2484:: + + sage: IntegerListsLex(10, length=3, min_part = 2, max_part = 5, + ....: floor = [2, 4, 2]).list() + [[4, 4, 2], [3, 5, 2], [3, 4, 3], [2, 5, 3], [2, 4, 4]] + +Sage example in ./combinat.tex, line 2489:: + + sage: IntegerListsLex(5, min_part = 1, max_part = 3, + ....: min_length = 2, max_length = 3).list() + [[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [1, 3, 1], + [1, 2, 2], [1, 1, 3]] + +Sage example in ./combinat.tex, line 2495:: + + sage: IntegerListsLex(5, min_part = 1, max_slope = -1).list() + [[5], [4, 1], [3, 2]] + +Sage example in ./combinat.tex, line 2499:: + + sage: list(Compositions(5, max_length=2)) + [[5], [4, 1], [3, 2], [2, 3], [1, 4]] + +Sage example in ./combinat.tex, line 2503:: + + sage: list(IntegerListsLex(5, max_length=2, min_part=1)) + [[5], [4, 1], [3, 2], [2, 3], [1, 4]] + +Sage example in ./combinat.tex, line 2625:: + + sage: A = random_matrix(ZZ, 6, 3, x=7) + sage: L = LatticePolytope(A.rows()) + sage: L.points() # random + M(1, 4, 3), + M(6, 4, 1), + ... + M(3, 5, 5) + in 3-d lattice M + sage: L.points().cardinality() # random + 23 + +Sage example in ./combinat.tex, line 2637:: + + sage: L.points() + M(...), + M(...), + ... + M(...) + in 3-d lattice M + +Sage example in ./combinat.tex, line 2647:: + + sage: L.plot3d() + Graphics3d Object + +Sage example in ./combinat.tex, line 2688:: + + sage: from sage.combinat.species.library import * + sage: o = var('o') + +Sage example in ./combinat.tex, line 2697:: + + sage: BT = CombinatorialSpecies() + sage: Leaf = SingletonSpecies() + sage: BT.define( Leaf + (BT*BT) ) + +Sage example in ./combinat.tex, line 2707:: + + sage: BT5 = BT.isotypes([o]*5); BT5.cardinality() + 14 + sage: BT5.list() + [o*(o*(o*(o*o))), o*(o*((o*o)*o)), o*((o*o)*(o*o)), o*((o*(o*o))*o), + o*(((o*o)*o)*o), (o*o)*(o*(o*o)), (o*o)*((o*o)*o), (o*(o*o))*(o*o), + ((o*o)*o)*(o*o), (o*(o*(o*o)))*o, (o*((o*o)*o))*o, ((o*o)*(o*o))*o, + ((o*(o*o))*o)*o, (((o*o)*o)*o)*o] + +Sage example in ./combinat.tex, line 2727:: + + sage: g = BT.isotype_generating_series(); g + x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + O(x^6) + +Sage example in ./combinat.tex, line 2733:: + + sage: g[100] + 227508830794229349661819540395688853956041682601541047340 + +Sage example in ./combinat.tex, line 2743:: + + sage: Eps = EmptySetSpecies(); Z0 = SingletonSpecies() + sage: Z1 = Eps*SingletonSpecies() + sage: FW = CombinatorialSpecies() + sage: FW.define(Eps + Z0*FW + Z1*Eps + Z1*Z0*FW) + +Sage example in ./combinat.tex, line 2752:: + + sage: L = FW.isotype_generating_series().coefficients(15); L + [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987] + +Sage example in ./combinat.tex, line 2769:: + + sage: FW3 = FW.isotypes([o]*3) + sage: FW3.list() + [o*(o*(o*{})), o*(o*(({}*o)*{})), o*((({}*o)*o)*{}), + (({}*o)*o)*(o*{}), (({}*o)*o)*(({}*o)*{})] + +Sage example in ./combinat.tex, line 3007:: + + sage: [len(list(graphs(n, property = lambda G: G.is_planar()))) + ....: for n in range(7)] + [1, 1, 2, 4, 11, 33, 142] + +Sage example in ./combinat.tex, line 3066:: + + sage: V = [1,2,3,4] + sage: F = Subsets(V, 2); F.list() + [{1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 4}] + +Sage example in ./combinat.tex, line 3072:: + + sage: S = SymmetricGroup(V) + +Sage example in ./combinat.tex, line 3077:: + + sage: def on_pair(sigma, pair): + ....: return Set(sigma(i) for i in pair) + sage: def on_pairs(sigma): + ....: return [on_pair(sigma, e) for e in F] + +Sage example in ./combinat.tex, line 3086:: + + sage: sigma = S([(1,2,3,4)]); sigma + (1,2,3,4) + sage: for e in F: print((e, on_pair(sigma, e))) + ({1, 2}, {2, 3}) + ({1, 3}, {2, 4}) + ({1, 4}, {1, 2}) + ({2, 3}, {3, 4}) + ({2, 4}, {1, 3}) + ({3, 4}, {1, 4}) + sage: on_pairs(sigma) + [{2, 3}, {2, 4}, {1, 2}, {3, 4}, {1, 3}, {1, 4}] + +Sage example in ./combinat.tex, line 3102:: + + sage: G = PermutationGroup([ on_pairs(sigma) for sigma in S.gens() ], + ....: domain=F) + +Sage example in ./combinat.tex, line 3109:: + + sage: Z = G.cycle_index(); Z + 1/24*p[1, 1, 1, 1, 1, 1] + 3/8*p[2, 2, 1, 1] + 1/3*p[3, 3] + 1/4*p[4, 2] + +Sage example in ./combinat.tex, line 3117:: + + sage: sorted(sigma for sigma in G if sigma.cycle_type() == [4,2]) + [({1,2},{1,3},{3,4},{2,4})({1,4},{2,3}), + ({1,2},{1,4},{3,4},{2,3})({1,3},{2,4}), + ({1,2},{2,3},{3,4},{1,4})({1,3},{2,4}), + ({1,2},{2,4},{3,4},{1,3})({1,4},{2,3}), + ({1,2},{3,4})({1,3},{1,4},{2,4},{2,3}), + ({1,2},{3,4})({1,3},{2,3},{2,4},{1,4})] + +Sage example in ./combinat.tex, line 3136:: + + sage: q,t = QQ['q,t'].gens() + sage: p = Z.expand(2, [q,t]); p + q^6 + q^5*t + 2*q^4*t^2 + 3*q^3*t^3 + 2*q^2*t^4 + q*t^5 + t^6 + +Sage example in ./combinat.tex, line 3146:: + + sage: p(q=1,t=1) + 11 + +Sage example in ./combinat.tex, line 3159:: + + sage: q = var('q') + sage: H = sum( c * prod( 1/(1-q^k) for k in partition ) + ....: for partition, c in Z ) + sage: H + 1/3/(q^3 - 1)^2 + 1/4/((q^4 - 1)*(q^2 - 1)) + + 3/8/((q^2 - 1)^2*(q - 1)^2) + 1/24/(q - 1)^6 + +Sage example in ./combinat.tex, line 3171:: + + sage: H.series(q) + 1 + 1*q + 3*q^2 + 6*q^3 + 11*q^4 + 18*q^5 + 32*q^6 + 48*q^7 + + 75*q^8 + 111*q^9 + 160*q^10 + 224*q^11 + 313*q^12 + 420*q^13 + + 562*q^14 + 738*q^15 + 956*q^16 + 1221*q^17 + 1550*q^18 + 1936*q^19 + + Order(q^20) + +Sage example in ./combinat.tex, line 3185:: + + sage: n = 10 + sage: V = range(1,n+1) + sage: F = Subsets(V, 2) + sage: S = SymmetricGroup(V) + sage: G = PermutationGroup([ on_pairs(sigma) for sigma in S.gens() ], + ....: domain=F) + sage: q,t = QQ['q,t'].gens() + sage: Z = G.cycle_index() + sage: Z.expand(2, [q,t])(q=1,t=1) + 12005168 + +Sage example in ./combinat.tex, line 3202:: + + sage: n = 20 + sage: V = range(1,n+1) + sage: F = Subsets(V, 2) + sage: S = SymmetricGroup(V) + sage: CC = S.conjugacy_classes(); CC # long time + [... + Conjugacy class of cycle type [19, 1] in Symmetric group of order 20! as a permutation group, + Conjugacy class of cycle type [20] in Symmetric group of order 20! as a permutation group] + +Sage example in ./combinat.tex, line 3214:: + + sage: p = SymmetricFunctions(QQ).powersum() + sage: G = PermutationGroup([ on_pairs(sigma) for sigma in S.gens() ], + ....: domain=F) + sage: Z = p.sum_of_terms([G(on_pairs(c.representative())).cycle_type(), # long time + ....: c.cardinality()] + ....: for c in CC) / factorial(n) + sage: Z.expand(2, [q,t])(q=1,t=1) # long time + 645490122795799841856164638490742749440 + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py new file mode 100644 index 00000000000..705a2282609 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py @@ -0,0 +1,446 @@ +## -*- encoding: utf-8 -*- +""" +This file (./domaines_doctest.sage) was *autogenerated* from ./domaines.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./domaines_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./domaines.tex, line 10:: + + sage: x = var('x') + +Sage example in ./domaines.tex, line 69:: + + sage: o = 12/35 + sage: type(o) + <... 'sage.rings.rational.Rational'> + +Sage example in ./domaines.tex, line 82:: + + sage: type(12/35) + <... 'sage.rings.rational.Rational'> + +Sage example in ./domaines.tex, line 131:: + + sage: o = 720 + sage: o.factor() + 2^4 * 3^2 * 5 + +Sage example in ./domaines.tex, line 142:: + + sage: type(o).factor(o) + 2^4 * 3^2 * 5 + +Sage example in ./domaines.tex, line 157:: + + sage: 720.factor() + 2^4 * 3^2 * 5 + +Sage example in ./domaines.tex, line 166:: + + sage: o = 720 / 133 + sage: o.numerator().factor() + 2^4 * 3^2 * 5 + +Sage example in ./domaines.tex, line 253:: + + sage: 3 * 7 + 21 + +Sage example in ./domaines.tex, line 261:: + + sage: (2/3) * (6/5) + 4/5 + +Sage example in ./domaines.tex, line 267:: + + sage: (1 + I) * (1 - I) + 2 + +Sage example in ./domaines.tex, line 274:: + + sage: (x + 2) * (x + 1) + (x + 2)*(x + 1) + sage: (x + 1) * (x + 2) + (x + 2)*(x + 1) + +Sage example in ./domaines.tex, line 308:: + + sage: def fourth_power(a): + ....: a = a * a + ....: a = a * a + ....: return a + +Sage example in ./domaines.tex, line 330:: + + sage: fourth_power(2) + 16 + sage: fourth_power(3/2) + 81/16 + sage: fourth_power(I) + 1 + sage: fourth_power(x+1) + (x + 1)^4 + sage: M = matrix([[0,-1],[1,0]]); M + [ 0 -1] + [ 1 0] + sage: fourth_power(M) + [1 0] + [0 1] + +Sage example in ./domaines.tex, line 375:: + + sage: t = type(5/1); t + <... 'sage.rings.rational.Rational'> + sage: t == type(5) + False + +Sage example in ./domaines.tex, line 476:: + + sage: a = 5; a + 5 + sage: a.is_unit() + False + +Sage example in ./domaines.tex, line 484:: + + sage: a = 5/1; a + 5 + sage: a.is_unit() + True + +Sage example in ./domaines.tex, line 507:: + + sage: parent(5) + Integer Ring + sage: parent(5/1) + Rational Field + +Sage example in ./domaines.tex, line 515:: + + sage: ZZ + Integer Ring + sage: QQ + Rational Field + +Sage example in ./domaines.tex, line 525:: + + sage: QQ(5).parent() + Rational Field + sage: ZZ(5/1).parent() + Integer Ring + sage: ZZ(1/5) + Traceback (most recent call last): + ... + TypeError: no conversion of this rational to integer + +Sage example in ./domaines.tex, line 543:: + + sage: ZZ(1), QQ(1), RR(1), CC(1) + (1, 1, 1.00000000000000, 1.00000000000000) + +Sage example in ./domaines.tex, line 568:: + + sage: cartesian_product([QQ, QQ]) + The Cartesian product of (Rational Field, Rational Field) + +Sage example in ./domaines.tex, line 574:: + + sage: ZZ.fraction_field() + Rational Field + +Sage example in ./domaines.tex, line 580:: + + sage: ZZ['x'] + Univariate Polynomial Ring in x over Integer Ring + +Sage example in ./domaines.tex, line 591:: + + sage: Z5 = GF(5); Z5 + Finite Field of size 5 + sage: P = Z5['x']; P + Univariate Polynomial Ring in x over Finite Field of size 5 + sage: M = MatrixSpace(P, 3, 3); M + Full MatrixSpace of 3 by 3 dense matrices over + Univariate Polynomial Ring in x over Finite Field of size 5 + +Sage example in ./domaines.tex, line 602:: + + sage: M.random_element() # random + [2*x^2 + 3*x + 4 4*x^2 + 2*x + 2 4*x^2 + 2*x] + [ 3*x 2*x^2 + x + 3 3*x^2 + 4*x] + [ 4*x^2 + 3 3*x^2 + 2*x + 4 2*x + 4] + +Sage example in ./domaines.tex, line 697:: + + sage: QQ.category() + Join of Category of number fields and Category of quotient fields and Category of metric spaces + +Sage example in ./domaines.tex, line 704:: + + sage: QQ in Fields() + True + +Sage example in ./domaines.tex, line 712:: + + sage: QQ in CommutativeAdditiveGroups() + True + +Sage example in ./domaines.tex, line 718:: + + sage: QQ['x'] in EuclideanDomains() + True + +Sage example in ./domaines.tex, line 859:: + + sage: 5.parent() + Integer Ring + +Sage example in ./domaines.tex, line 872:: + + sage: type(factor(4)) + + +Sage example in ./domaines.tex, line 895:: + + sage: int(5) + 5 + sage: type(int(5)) + <... 'int'> + +Sage example in ./domaines.tex, line 909:: + + sage: Integer(5) + 5 + sage: type(Integer(5)) + <... 'sage.rings.integer.Integer'> + +Sage example in ./domaines.tex, line 926:: + + sage: factorial(99) / factorial(100) - 1 / 50 + -1/100 + +Sage example in ./domaines.tex, line 974:: + + sage: 72/53 - 5/3 * 2.7 + -3.14150943396227 + +Sage example in ./domaines.tex, line 982:: + + sage: cos(1), cos(1.) + (cos(1), 0.540302305868140) + +Sage example in ./domaines.tex, line 1000:: + + sage: pi.n(digits=50) # variant: n(pi,digits=50) + 3.1415926535897932384626433832795028841971693993751 + +Sage example in ./domaines.tex, line 1020:: + + sage: z = CC(1,2); z.arg() + 1.10714871779409 + +Sage example in ./domaines.tex, line 1036:: + + sage: I.parent() + Symbolic Ring + +Sage example in ./domaines.tex, line 1043:: + + sage: (1.+2.*I).parent() + Symbolic Ring + sage: CC(1.+2.*I).parent() + Complex Field with 53 bits of precision + +Sage example in ./domaines.tex, line 1064:: + + sage: z = 3 * exp(I*pi/4) + sage: z.real(), z.imag(), z.abs().canonicalize_radical() + (3/2*sqrt(2), 3/2*sqrt(2), 3) + +Sage example in ./domaines.tex, line 1094:: + + sage: a, b, c = 0, 2, 3 + sage: a == 1 or (b == 2 and c == 3) + True + +Sage example in ./domaines.tex, line 1147:: + + sage: x, y = var('x, y') + sage: bool( (x-y)*(x+y) == x^2-y^2 ) + True + +Sage example in ./domaines.tex, line 1171:: + + sage: Z4 = IntegerModRing(4); Z4 + Ring of integers modulo 4 + sage: m = Z4(7); m + 3 + +Sage example in ./domaines.tex, line 1184:: + + sage: 3 * m + 1 + 2 + +Sage example in ./domaines.tex, line 1191:: + + sage: Z3 = GF(3); Z3 + Finite Field of size 3 + +Sage example in ./domaines.tex, line 1243:: + + sage: a = matrix(QQ, [[1,2,3],[2,4,8],[3,9,27]]) + sage: (a^2 + 1) * a^(-1) + [ -5 13/2 7/3] + [ 7 1 25/3] + [ 2 19/2 27] + +Sage example in ./domaines.tex, line 1259:: + + sage: M = MatrixSpace(QQ,3,3); M + Full MatrixSpace of 3 by 3 dense matrices over Rational Field + sage: a = M([[1,2,3],[2,4,8],[3,9,27]]) + sage: (a^2 + 1) * a^(-1) + [ -5 13/2 7/3] + [ 7 1 25/3] + [ 2 19/2 27] + +Sage example in ./domaines.tex, line 1283:: + + sage: P = ZZ['x']; P + Univariate Polynomial Ring in x over Integer Ring + sage: F = P.fraction_field(); F + Fraction Field of Univariate Polynomial Ring in x over Integer Ring + sage: p = P(x+1) * P(x); p + x^2 + x + sage: p + 1/p + (x^4 + 2*x^3 + x^2 + 1)/(x^2 + x) + sage: parent(p + 1/p) + Fraction Field of Univariate Polynomial Ring in x over Integer Ring + +Sage example in ./domaines.tex, line 1382:: + + sage: k. = NumberField(x^3 + x + 1); a^3; a^4+3*a + -a - 1 + -a^2 + 2*a + +Sage example in ./domaines.tex, line 1416:: + + sage: parent(sin(x)) + Symbolic Ring + +Sage example in ./domaines.tex, line 1422:: + + sage: SR + Symbolic Ring + +Sage example in ./domaines.tex, line 1428:: + + sage: SR.category() + Category of commutative rings + +Sage example in ./domaines.tex, line 1482:: + + sage: R = QQ['x1,x2,x3,x4']; R + Multivariate Polynomial Ring in x1, x2, x3, x4 over Rational Field + sage: x1, x2, x3, x4 = R.gens() + +Sage example in ./domaines.tex, line 1489:: + + sage: x1 * (x2 - x3) + x1*x2 - x1*x3 + +Sage example in ./domaines.tex, line 1496:: + + sage: (x1+x2)*(x1-x2) - (x1^2 - x2^2) + 0 + +Sage example in ./domaines.tex, line 1509:: + + sage: prod( (a-b) for (a,b) in Subsets([x1,x2,x3,x4],2) ) + x1^3*x2^2*x3 - x1^2*x2^3*x3 - x1^3*x2*x3^2 + x1*x2^3*x3^2 + + x1^2*x2*x3^3 - x1*x2^2*x3^3 - x1^3*x2^2*x4 + x1^2*x2^3*x4 + + x1^3*x3^2*x4 - x2^3*x3^2*x4 - x1^2*x3^3*x4 + x2^2*x3^3*x4 + + x1^3*x2*x4^2 - x1*x2^3*x4^2 - x1^3*x3*x4^2 + x2^3*x3*x4^2 + + x1*x3^3*x4^2 - x2*x3^3*x4^2 - x1^2*x2*x4^3 + x1*x2^2*x4^3 + + x1^2*x3*x4^3 - x2^2*x3*x4^3 - x1*x3^2*x4^3 + x2*x3^2*x4^3 + +Sage example in ./domaines.tex, line 1531:: + + sage: x1, x2, x3, x4 = SR.var('x1, x2, x3, x4') + sage: got = prod( (a-b) for (a,b) in Subsets([x1,x2,x3,x4],2) ) + sage: expected1 = -(x1 - x2)*(x1 - x3)*(x1 - x4)*(x2 - x3)*(x2 - x4)*(x3 - x4) + sage: expected2 = (x1 - x2)*(x1 - x3)*(x1 - x4)*(x2 - x3)*(x2 - x4)*(x3 - x4) + sage: bool(got == expected1 or got == expected2) + True + +Sage example in ./domaines.tex, line 1581:: + + sage: x = var('x') + sage: p = 54*x^4+36*x^3-102*x^2-72*x-12 + sage: factor(p) + 6*(x^2 - 2)*(3*x + 1)^2 + +Sage example in ./domaines.tex, line 1616:: + + sage: R = ZZ['x']; R + Univariate Polynomial Ring in x over Integer Ring + +Sage example in ./domaines.tex, line 1622:: + + sage: q = R(p); q + 54*x^4 + 36*x^3 - 102*x^2 - 72*x - 12 + +Sage example in ./domaines.tex, line 1629:: + + sage: parent(q) + Univariate Polynomial Ring in x over Integer Ring + +Sage example in ./domaines.tex, line 1635:: + + sage: factor(q) + 2 * 3 * (3*x + 1)^2 * (x^2 - 2) + +Sage example in ./domaines.tex, line 1642:: + + sage: R = QQ['x']; R + Univariate Polynomial Ring in x over Rational Field + sage: q = R(p); q + 54*x^4 + 36*x^3 - 102*x^2 - 72*x - 12 + sage: factor(q) + (54) * (x + 1/3)^2 * (x^2 - 2) + +Sage example in ./domaines.tex, line 1665:: + + sage: R = ComplexField(16)['x']; R + Univariate Polynomial Ring in x over Complex Field + with 16 bits of precision + sage: q = R(p); q + 54.00*x^4 + 36.00*x^3 - 102.0*x^2 - 72.00*x - 12.00 + sage: factor(q) + (54.00) * (x - 1.414) * (x + 0.3333)^2 * (x + 1.414) + +Sage example in ./domaines.tex, line 1685:: + + sage: R = QQ[sqrt(2)]['x']; R + Univariate Polynomial Ring in x over Number Field in sqrt2 + with defining polynomial x^2 - 2 + sage: q = R(p); q + 54*x^4 + 36*x^3 - 102*x^2 - 72*x - 12 + sage: factor(q) + (54) * (x - sqrt2) * (x + sqrt2) * (x + 1/3)^2 + +Sage example in ./domaines.tex, line 1698:: + + sage: R = GF(5)['x']; R + Univariate Polynomial Ring in x over Finite Field of size 5 + sage: q = R(p); q + 4*x^4 + x^3 + 3*x^2 + 3*x + 3 + sage: factor(q) + (4) * (x + 2)^2 * (x^2 + 3) + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py new file mode 100644 index 00000000000..4ffae764638 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py @@ -0,0 +1,479 @@ +## -*- encoding: utf-8 -*- +""" +This file (./float_doctest.sage) was *autogenerated* from ./float.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./float_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./float.tex, line 251:: + + sage: xrdf = RDF(3.0) + +Sage example in ./float.tex, line 276:: + + sage: R100 = RealField(100) # precision: 100 bits. + sage: x100 = R100(3/8); x100 + 0.37500000000000000000000000000 + +Sage example in ./float.tex, line 300:: + + sage: Rdefault = RealField() # default precision of 53 bits + sage: xdefault = Rdefault(2/3) + +Sage example in ./float.tex, line 319:: + + sage: xrdf.prec() + 53 + sage: x100.prec() + 100 + sage: xdefault.prec() + 53 + +Sage example in ./float.tex, line 347:: + + sage: x = 1.0; type(x) + <... 'sage.rings.real_mpfr.RealLiteral'> + sage: x.prec() + 53 + +Sage example in ./float.tex, line 384:: + + sage: x = 1.0 # x belongs to RealField() + sage: x = 0.1e+1 # idem: x belongs to RealField() + sage: x = 1 # x is an integer + sage: x = RDF(1) # x is a machine double-precision number + sage: x = RDF(1.) # idem: x is a machine double-precision number + sage: x = RDF(0.1e+1) # idem + sage: x = 4/3 # x is a rational number + sage: R = RealField(20) + sage: x = R(1) # x is a 20-bit floating-point number + +Sage example in ./float.tex, line 400:: + + sage: RDF(8/3) + 2.6666666666666665 + sage: R100 = RealField(100); R100(8/3) + 2.6666666666666666666666666667 + +Sage example in ./float.tex, line 412:: + + sage: x = R100(8/3) + sage: R = RealField(); R(x) + 2.66666666666667 + sage: RDF(x) + 2.6666666666666665 + +Sage example in ./float.tex, line 431:: + + sage: 1.0/0.0 + +infinity + sage: RDF(1)/RDF(0) + +infinity + sage: RDF(-1.0)/RDF(0.) + -infinity + +Sage example in ./float.tex, line 441:: + + sage: 0.0/0.0 + NaN + sage: RDF(0.0)/RDF(0.0) + NaN + +Sage example in ./float.tex, line 496:: + + sage: R2 = RealField(2) + +Sage example in ./float.tex, line 545:: + + sage: x2 = R2(1.); x2.ulp() + 0.50 + sage: xr = 1.; xr.ulp() + 2.22044604925031e-16 + +Sage example in ./float.tex, line 655:: + + sage: a = 10000.0; b = 9999.5; c = 0.1; c + 0.100000000000000 + sage: a1 = a+c # add a small perturbation to a. + sage: a1-b + 0.600000000000364 + +Sage example in ./float.tex, line 680:: + + sage: a = 1.0; b = 10.0^4; c = 1.0 + sage: delta = b^2-4*a*c + sage: x = (-b-sqrt(delta))/(2*a); y = (-b+sqrt(delta))/(2*a) + sage: x, y + (-9999.99990000000, -0.000100000001111766) + +Sage example in ./float.tex, line 692:: + + sage: x+y+b/a + 0.000000000000000 + sage: x*y-c/a + 1.11766307320238e-9 + +Sage example in ./float.tex, line 713:: + + sage: y = (c/a)/x; y + -0.000100000001000000 + sage: x+y+b/a + 0.000000000000000 + sage: x*y-c/a + -1.11022302462516e-16 + +Sage example in ./float.tex, line 746:: + + sage: x1 = R2(1/2); x2 = R2(4); x3 = R2(-4) + sage: x1, x2, x3 + (0.50, 4.0, -4.0) + sage: x1+(x2+x3) + 0.50 + sage: (x1+x2)+x3 + 0.00 + +Sage example in ./float.tex, line 781:: + + sage: x = RDF(1/3) + sage: for i in range(1,100): x = 4*x-1; print(x) + 0.33333333333333326 + 0.33333333333333304 + 0.33333333333333215 + ... + -1.0 + -5.0 + -21.0 + -85.0 + -341.0 + -1365.0 + -5461.0 + -21845.0 + ... + +Sage example in ./float.tex, line 824:: + + sage: x = RDF(1/2) + sage: for i in range(1,100): x = 3*x-1; print(x) + 0.5 + 0.5 + 0.5 + ... + 0.5 + +Sage example in ./float.tex, line 863:: + + sage: x = RDF(1/3) + +Sage example in ./float.tex, line 867:: + + sage: x = 1/3 + +Sage example in ./float.tex, line 990:: + + sage: def sumharmo(p): + ....: RFP = RealField(p) + ....: y = RFP(1.); x = RFP(0.); n = 1 + ....: while x != y: + ....: y = x; x += 1/n; n += 1 + ....: return p, n, x + +Sage example in ./float.tex, line 1003:: + + sage: sumharmo(2) + (2, 5, 2.0) + sage: sumharmo(20) + (20, 131073, 12.631) + +Sage example in ./float.tex, line 1072:: + + sage: def iter(y,delta,a,n): + ....: for i in range(0,n): + ....: y += delta + ....: delta *= a + ....: return y + +Sage example in ./float.tex, line 1087:: + + sage: def exact(y,delta,a,n): + ....: return y+delta*(1-a^n)/(1-a) + +Sage example in ./float.tex, line 1106:: + + sage: y0 = RDF(10^13); delta0 = RDF(1); a = RDF(1-10^(-8)); n = 100000 + sage: ii = iter(y0,delta0,a,n) + sage: s = exact(10^13,1,1-10^(-8),n) + sage: print("exact - classical summation: %.1f" % (s-ii)) # abs tol 0.1 + exact - classical summation: -45.6 + +Sage example in ./float.tex, line 1128:: + + sage: def sumcomp(y,delta,e,n,a): + ....: for i in range(0,n): + ....: b = y + ....: e += delta + ....: y = b+e + ....: e += (b-y) + ....: delta = a*delta # new value of delta + ....: return y + +Sage example in ./float.tex, line 1194:: + + sage: c = sumcomp(y0,delta0,RDF(0.0),n,a) + sage: print("exact - compensated summation: %.5f" \ + % RDF(s-RR(c).exact_rational())) + exact - compensated summation: -0.00042 + +Sage example in ./float.tex, line 1242:: + + sage: x = CDF(2,1.); x + 2.0 + 1.0*I + sage: y = CDF(20,0); y + 20.0 + +Sage example in ./float.tex, line 1249:: + + sage: z = ComplexDoubleElement(2.,1.); z + 2.0 + 1.0*I + +Sage example in ./float.tex, line 1269:: + + sage: C = ComplexField(); C(2,3) + 2.00000000000000 + 3.00000000000000*I + sage: C100 = ComplexField(100); C100(2,3) + 2.0000000000000000000000000000 + 3.0000000000000000000000000000*I + +Sage example in ./float.tex, line 1297:: + + sage: R200 = RealField(200); R200.pi() + 3.1415926535897932384626433832795028841971693993751058209749 + sage: R200.euler_constant() + 0.57721566490153286060651209008240243104215933593992359880577 + +Sage example in ./float.tex, line 1314:: + + sage: x = RDF.pi()/2; x.cos() # floating-point approximation of zero! + 6.123233995736757e-17 + sage: x.cos().arccos() - x + 0.0 + +Sage example in ./float.tex, line 1564:: + + sage: r3 = RIF(sqrt(3)); r3 + 1.732050807568877? + sage: print(r3.str(style="brackets")) + [1.7320508075688769 .. 1.7320508075688775] + +Sage example in ./float.tex, line 1602:: + + sage: sage.rings.real_mpfi.printing_style = 'brackets' + +Sage example in ./float.tex, line 1616:: + + sage: r2 = RIF(2); r2, r2.diameter() + ([2.0000000000000000 .. 2.0000000000000000], 0.000000000000000) + +Sage example in ./float.tex, line 1628:: + + sage: rpi = RIF(sqrt(2),pi); rpi + [1.4142135623730949 .. 3.1415926535897936] + sage: RIF(0,+infinity) + [0.0000000000000000 .. +infinity] + +Sage example in ./float.tex, line 1649:: + + sage: RBF(pi) + [3.141592653589793 +/- ...e-16] + sage: RealBallField(100)(pi) + [3.14159265358979323846264338328 +/- ...e-30] + +Sage example in ./float.tex, line 1662:: + + sage: RBF(2).rad() + 0.00000000 + +Sage example in ./float.tex, line 1675:: + + sage: si = sin(RIF(pi)) + sage: si.contains_zero() + True + sage: sb = sin(RBF(pi)) + sage: sb.contains_zero() + True + +Sage example in ./float.tex, line 1704:: + + sage: a = RealIntervalField(30)(1, RR(1).nextabove()) + sage: a.bisection() + ([1.0000000000 .. 1.0000000000], [1.0000000000 .. 1.0000000019]) + +Sage example in ./float.tex, line 1713:: + + sage: b = RealIntervalField(2)(-1,6) + sage: b.center(), b.diameter() + (2.0, 8.0) + +Sage example in ./float.tex, line 1725:: + + sage: s = RIF(1,2) + sage: b = RBF(s) + sage: bpi = RBF(pi) + sage: ipi = RIF(bpi) + +Sage example in ./float.tex, line 1735:: + + sage: RIF(RBF(RIF(1,2))) == RIF(1,2) + False + sage: RBF(RIF(RBF(pi))) == RBF(pi) + False + +Sage example in ./float.tex, line 1810:: + + sage: E = RIF(-pi/4,pi) + sage: sin(E) + [-0.70710678118654769 .. 1.0000000000000000] + sage: E = RIF(-1,2); exp(E) + [0.36787944117144227 .. 7.3890560989306505] + sage: E = RIF(0,1); log(E) + [-infinity .. -0.0000000000000000] + +Sage example in ./float.tex, line 1838:: + + sage: E=RIF(-pi,pi) + sage: f = lambda x: sin(x)/x + sage: f(E) + [-infinity .. +infinity] + +Sage example in ./float.tex, line 1913:: + + sage: x = RIF(-1,1) + sage: 1-x^2 + [0.0000000000000000 .. 1.0000000000000000] + sage: 1-x*x + [0.0000000000000000 .. 2.0000000000000000] + sage: (1-x)*(1+x) + [0.0000000000000000 .. 4.0000000000000000] + +Sage example in ./float.tex, line 1975:: + + sage: def bisect(funct,x,tol,zeros): + ....: if 0 in funct(x): + ....: if x.diameter()>tol: + ....: x1,x2 = x.bisection() + ....: bisect(funct,x1,tol,zeros) + ....: bisect(funct,x2,tol,zeros) + ....: else: + ....: zeros.append(x) + sage: sage.rings.real_mpfi.printing_style = 'question' + sage: fs = lambda x: sin(1/x) + sage: d = RealIntervalField(100)(1/64,1/32) + sage: zeros = [] + sage: bisect(fs,d,10^(-25),zeros) + sage: for s in zeros: + ....: s + 0.015915494309189533576888377? + 0.01675315190441003534409303? + 0.01768388256576614841876487? + 0.018724110951987686561045148? + 0.01989436788648691697111047? + 0.021220659078919378102517835? + 0.02273642044169933368126911? + 0.024485375860291590118289809? + 0.026525823848649222628147293? + 0.02893726238034460650343342? + sage: dfs = lambda x: -cos(1/x)/x^2 + sage: not any([dfs(z).contains_zero() for z in zeros]) + True + +Sage example in ./float.tex, line 2022:: + + sage: def NearlySingularMatrix(R,n): + ....: M=matrix(R,n,n) + ....: for i in range(0,n): + ....: for j in range(0,n): + ....: M[i,j]= (1+log(R(1+i)))/((i+1)^2+(j+1)^2) + ....: return M + +Sage example in ./float.tex, line 2044:: + + sage: n=35 + sage: NearlySingularMatrix(RDF,n).det() == 0.0 + True + +Sage example in ./float.tex, line 2053:: + + sage: NearlySingularMatrix(RBF,n).det().contains_zero() + True + +Sage example in ./float.tex, line 2064:: + + sage: def tryDet(R,n): + ....: p = 53 + ....: z = True + ....: while z: + ....: p += 100 + ....: MRF=NearlySingularMatrix(R(p),n) + ....: d = MRF.det() + ....: z = d.contains_zero() + ....: return p,d + sage: tryDet(RealBallField,n) # long time + (1653, [9.552323592707808e-485 +/- 1.65e-501]) + +Sage example in ./float.tex, line 2095:: + + sage: tryDet(RealIntervalField,n) # long time + (1653, 9.552323592707808?e-485) + +Sage example in ./float.tex, line 2135:: + + sage: CBF(sqrt(2),pi) + [1.414213562373095 +/- 4.10e-16] + [3.141592653589793 +/- ...e-16]*I + sage: CIF(sqrt(2),pi) + 1.414213562373095? + 3.141592653589794?*I + sage: CIF(sqrt(2)+pi*I) + 1.414213562373095? + 3.141592653589794?*I + sage: CBF(sqrt(2)+pi*I) + [1.414213562373095 +/- 4.10e-16] + [3.141592653589793 +/- ...e-16]*I + +Sage example in ./float.tex, line 2146:: + + sage: sage.rings.real_mpfi.printing_style = 'brackets' + +Sage example in ./float.tex, line 2149:: + + sage: c = CIF(RIF(1,2),RIF(-3,3)) + sage: c.real() + [1.0000000000000000 .. 2.0000000000000000] + sage: c.imag() + [-3.0000000000000000 .. 3.0000000000000000] + sage: CBF(RIF(1,2),RIF(-3,3)) + [+/- 2.01] + [+/- 3.01]*I + +Sage example in ./float.tex, line 2164:: + + sage: sage.rings.real_mpfi.printing_style = 'question' + +Sage example in ./float.tex, line 2167:: + + sage: ComplexIntervalField(100)(1+I*pi).arg() + 1.26262725567891168344432208361? + sage: ComplexBallField(100)(1+I*pi).arg() + [1.26262725567891168344432208360 +/- ...e-30] + sage: ComplexIntervalField(100)(1+I*pi).norm() + 10.8696044010893586188344909999? + +Sage example in ./float.tex, line 2242:: + + sage: sage.rings.real_mpfi.printing_style = 'question' + +Sage example in ./float.tex, line 2245:: + + sage: x=QQbar(sqrt(3)); x + 1.732050807568878? + sage: x.interval(RealIntervalField(100)) + 1.73205080756887729352744634151? + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py new file mode 100644 index 00000000000..48e9d11f4dc --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py @@ -0,0 +1,254 @@ +## -*- encoding: utf-8 -*- +""" +This file (./graphique_doctest.sage) was *autogenerated* from ./graphique.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./graphique_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./graphique.tex, line 18:: + + sage: reset() + +Sage example in ./graphique.tex, line 61:: + + sage: plot(x * sin(1/x), x, -2, 2, plot_points=500) + Graphics object consisting of 1 graphics primitive + +Sage example in ./graphique.tex, line 156:: + + sage: def p(x, n): + ....: return(taylor(sin(x), x, 0, n)) + sage: xmax = 15 ; n = 15 + sage: g = plot(sin(x), x, -xmax, xmax) + sage: for d in range(n): # long time + ....: g += plot(p(x, 2 * d + 1), x, -xmax, xmax,\ + ....: color=(1.7*d/(2*n), 1.5*d/(2*n), 1-3*d/(4*n))) + sage: g.show(ymin=-2, ymax=2) + +Sage example in ./graphique.tex, line 237:: + + sage: f2(x) = 1; f1(x) = -1 + sage: f = piecewise([[(-pi,0),f1],[(0,pi),f2]]) + sage: S = f.fourier_series_partial_sum(20,pi) + sage: g = plot(S, x, -8, 8, color='blue') + sage: saw(x) = x - 2 * pi * floor((x + pi) / (2 * pi)) + sage: g += plot(saw(x) / abs(saw(x)), x, -8, 8, color='red') + sage: g + Graphics object consisting of 2 graphics primitives + +Sage example in ./graphique.tex, line 311:: + + sage: t = var('t') + sage: x = cos(t) + cos(7*t)/2 + sin(17*t)/3 + sage: y = sin(t) + sin(7*t)/2 + cos(17*t)/3 + sage: g = parametric_plot((x, y), (t, 0, 2*pi)) + sage: g.show(aspect_ratio=1) + +Sage example in ./graphique.tex, line 364:: + + sage: t = var('t'); n = 20/19 + sage: g1 = polar_plot(1+2*cos(n*t),(t,0,n*36*pi),plot_points=5000) + sage: g2 = polar_plot(1+1/3*cos(n*t),(t,0,n*36*pi),plot_points=5000) + sage: g1.show(aspect_ratio=1); g2.show(aspect_ratio=1) + +Sage example in ./graphique.tex, line 500:: + + sage: bar_chart([randrange(15) for i in range(20)]) + Graphics object consisting of 1 graphics primitive + sage: bar_chart([x^2 for x in range(1,20)], width=0.2) + Graphics object consisting of 1 graphics primitive + +Sage example in ./graphique.tex, line 550:: + + sage: liste = [10 + floor(10*sin(i)) for i in range(100)] + sage: bar_chart(liste) + Graphics object consisting of 1 graphics primitive + sage: finance.TimeSeries(liste).plot_histogram(bins=20) + Graphics object consisting of 20 graphics primitives + +Sage example in ./graphique.tex, line 714:: + + sage: n, l, x, y = 10000, 1, 0, 0; p = [[0, 0]] + sage: for k in range(n): + ....: theta = (2 * pi * random()).n(digits=5) + ....: x, y = x + l * cos(theta), y + l * sin(theta) + ....: p.append([x, y]) + sage: g1 = line([p[n], [0, 0]], color='red', thickness=2) + sage: g1 += line(p, thickness=.4); g1.show(aspect_ratio=1) + +Sage example in ./graphique.tex, line 777:: + + sage: length = 200; n = var('n') + sage: u = lambda n: n * sqrt(2) + sage: z = lambda n: exp(2 * I * pi * u(n)).n() + sage: vertices = [CC(0, 0)] + sage: for n in range(1, length): + ....: vertices.append(vertices[n - 1] + CC(z(n))) + sage: line(vertices).show(aspect_ratio=1) + +Sage example in ./graphique.tex, line 968:: + + sage: x = var('x'); y = function('y') + sage: DE = x*diff(y(x), x) == 2*y(x) + x^3 + sage: desolve(DE, [y(x),x]) + (_C + x)*x^2 + sage: sol = [] + sage: for i in srange(-2, 2, 0.2): + ....: sol.append(desolve(DE, [y(x), x], ics=[1, i])) + ....: sol.append(desolve(DE, [y(x), x], ics=[-1, i])) + sage: g = plot(sol, x, -2, 2) + sage: y = var('y') + sage: g += plot_vector_field((x, 2*y+x^3), (x,-2,2), (y,-1,1)) + sage: g.show(ymin=-1, ymax=1) + +Sage example in ./graphique.tex, line 1029:: + + sage: x = var('x'); y = function('y') + sage: DE = x*diff(y(x), x) == 2*y(x) + x^3 + sage: g = Graphics() # creates an empty graph + sage: for i in srange(-2, 2, 0.2): # long time + ....: g += line(desolve_rk4(DE, y(x), ics=[1, i],\ + ....: step=0.05, end_points=[0,2])) + ....: g += line(desolve_rk4(DE, y(x), ics=[-1, i],\ + ....: step=0.05, end_points=[-2,0])) + sage: y = var('y') + sage: g += plot_vector_field((x, 2*y+x^3), (x,-2,2), (y,-1,1)) + sage: g.show(ymin=-1, ymax=1) + +Sage example in ./graphique.tex, line 1120:: + + sage: import scipy; from scipy import integrate + sage: f = lambda y, t: - cos(y * t) + sage: t = srange(0, 5, 0.1); p = Graphics() + sage: for k in srange(0, 10, 0.15): + ....: y = integrate.odeint(f, k, t) + ....: p += line(zip(t, flatten(y))) + sage: t = srange(0, -5, -0.1); q = Graphics() + sage: for k in srange(0, 10, 0.15): + ....: y = integrate.odeint(f, k, t) + ....: q += line(zip(t, flatten(y))) + sage: y = var('y') + sage: v = plot_vector_field((1, -cos(x*y)), (x,-5,5), (y,-2,11)) + sage: g = p + q + v; g.show() + +Sage example in ./graphique.tex, line 1229:: + + sage: import scipy; from scipy import integrate + sage: a, b, c, d = 1., 0.1, 1.5, 0.75 + sage: def dX_dt(X, t=0): # returns the population variation + ....: return [a*X[0] - b*X[0]*X[1], -c*X[1] + d*b*X[0]*X[1]] + sage: t = srange(0, 15, .01) # time scale + sage: X0 = [10, 5] # initial conditions: 10 rabbits and 5 foxes + sage: X = integrate.odeint(dX_dt, X0, t) # numerical solution + sage: rabbits, foxes = X.T # shortcut for X.transpose() + sage: p = line(zip(t, rabbits), color='red') # number of rabbits graph + sage: p += text("Rabbits",(12,37), fontsize=10, color='red') + sage: p += line(zip(t, foxes), color='blue') # idem for foxes + sage: p += text("Foxes",(12,7), fontsize=10, color='blue') + sage: p.axes_labels(["time", "population"]); p.show(gridlines=True) + +Sage example in ./graphique.tex, line 1266:: + + sage: n = 11; L = srange(6, 18, 12 / n); R = srange(3, 9, 6 / n) + sage: CI = list(zip(L, R)) # list of initial conditions + sage: def g(x,y): + ....: v = vector(dX_dt([x, y])) # for a nicer graph, we + ....: return v/v.norm() # normalise the vector field + sage: x, y = var('x, y') + sage: q = plot_vector_field(g(x, y), (x, 0, 60), (y, 0, 36)) + sage: for j in range(n): + ....: X = integrate.odeint(dX_dt, CI[j], t) # resolution + ....: q += line(X, color=hue(.8-float(j)/(1.8*n))) # graph plot + sage: q.axes_labels(["rabbits","foxes"]); q.show() + +Sage example in ./graphique.tex, line 1501:: + + sage: x, y, t = var('x, y, t') + sage: alpha(t) = 1; beta(t) = t / 2; gamma(t) = t + t^3 / 8 + sage: env = solve([alpha(t) * x + beta(t) * y == gamma(t),\ + ....: diff(alpha(t), t) * x + diff(beta(t), t) * y == \ + ....: diff(gamma(t), t)], [x,y]) + +Sage example in ./graphique.tex, line 1541:: + + sage: f(x) = x^2 / 4 + sage: p = plot(f, -8, 8, rgbcolor=(0.2,0.2,0.4)) # the parabola + sage: for u in srange(0, 8, 0.1): # normals to the parabola + ....: p += line([[u, f(u)], [-8*u, f(u) + 18]], thickness=.3) + ....: p += line([[-u, f(u)], [8*u, f(u) + 18]], thickness=.3) + sage: p += parametric_plot((env[0][0].rhs(),env[0][1].rhs()),\ + ....: (t, -8, 8),color='red') # draws the evolute + sage: p.show(xmin=-8, xmax=8, ymin=-1, ymax=12, aspect_ratio=1) + +Sage example in ./graphique.tex, line 1604:: + + sage: t = var('t'); p = 2 + sage: x(t) = t; y(t) = t^2 / (2 * p); f(t) = [x(t), y(t)] + sage: df(t) = [x(t).diff(t), y(t).diff(t)] + sage: d2f(t) = [x(t).diff(t, 2), y(t).diff(t, 2)] + sage: T(t) = [df(t)[0] / df(t).norm(), df[1](t) / df(t).norm()] + sage: N(t) = [-df(t)[1] / df(t).norm(), df[0](t) / df(t).norm()] + sage: R(t) = (df(t).norm())^3 / (df(t)[0]*d2f(t)[1]-df(t)[1]*d2f(t)[0]) + sage: Omega(t) = [f(t)[0] + R(t)*N(t)[0], f(t)[1] + R(t)*N(t)[1]] + sage: g = parametric_plot(f(t), (t,-8,8), color='green',thickness=2) + sage: for u in srange(.4, 4, .2): + ....: g += line([f(t=u), Omega(t=u)], color='red', alpha = .5) + ....: g += circle(Omega(t=u), R(t=u), color='blue') + sage: g.show(aspect_ratio=1,xmin=-12,xmax=7,ymin=-3,ymax=12) + +Sage example in ./graphique.tex, line 1781:: + + sage: u, v = var('u, v') + sage: h = lambda u,v: u^2 + 2*v^2 + sage: plot3d(h, (u,-1,1), (v,-1,1), aspect_ratio=[1,1,1]) + Graphics3d Object + +Sage example in ./graphique.tex, line 1833:: + + sage: f(x, y) = x^2 * y / (x^4 + y^2) + sage: t, theta = var('t, theta') + sage: limit(f(t * cos(theta), t * sin(theta)) / t, t=0) + cos(theta)^2/sin(theta) + +Sage example in ./graphique.tex, line 1847:: + + sage: solve(f(x,y) == 1/2, y) + [y == x^2] + sage: a = var('a'); h = f(x, a*x^2).simplify_rational(); h + a/(a^2 + 1) + +Sage example in ./graphique.tex, line 1861:: + + sage: plot(h, a, -4, 4) + Graphics object consisting of 1 graphics primitive + +Sage example in ./graphique.tex, line 1908:: + + sage: p = plot3d(f(x,y),(x,-2,2),(y,-2,2),plot_points=[150,150]) + +Sage example in ./graphique.tex, line 1937:: + + sage: for i in range(1,4): + ....: p += plot3d(-0.5 + i / 4, (x, -2, 2), (y, -2, 2),\ + ....: color=hue(i / 10), opacity=.1) + +Sage example in ./graphique.tex, line 1956:: + + sage: x, y, z = var('x, y, z'); a = 1 + sage: h = lambda x, y, z:(a^2 + x^2 + y^2)^2 - 4*a^2*x^2-z^4 + sage: implicit_plot3d(h, (x,-3,3), (y,-3,3), (z,-2,2), # long time + ....: plot_points=100) + Graphics3d Object + +Sage example in ./graphique.tex, line 2004:: + + sage: line3d([(-10*cos(t)-2*cos(5*t)+15*sin(2*t),\ + ....: -15*cos(2*t)+10*sin(t)-2*sin(5*t),\ + ....: 10*cos(3*t)) for t in srange(0,6.4,.1)],radius=.5) + Graphics3d Object + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py new file mode 100644 index 00000000000..2bea1f75f1b --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py @@ -0,0 +1,419 @@ +## -*- encoding: utf-8 -*- +""" +This file (./graphtheory_doctest.sage) was *autogenerated* from ./graphtheory.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./graphtheory_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./graphtheory.tex, line 12:: + + sage: set_random_seed(1588) + sage: sage.numerical.backends.generic_backend.default_solver = "Glpk" + +Sage example in ./graphtheory.tex, line 59:: + + sage: g = Graph() + +Sage example in ./graphtheory.tex, line 87:: + + sage: g.order(), g.size() + (0, 0) + sage: g.add_vertex(0) + sage: g.order(), g.size() + (1, 0) + sage: g.add_vertices([1, 2, 5, 9]) + sage: g.order(), g.size() + (5, 0) + sage: g.add_edges([(1,5), (9,2), (2,5), (1,9)]) + sage: g.order(), g.size() + (5, 4) + sage: g.add_edge("Madrid", "Edinburgh") + sage: g.order(), g.size() + (7, 5) + +Sage example in ./graphtheory.tex, line 128:: + + sage: g.delete_vertex(0) + sage: g.delete_edges([(1,5), (2,5)]) + sage: g.order(), g.size() + (6, 3) + sage: g.vertices() + [1, 2, 5, 9, 'Edinburgh', 'Madrid'] + sage: g.edges() + [(1, 9, None), (2, 9, None), ('Edinburgh', 'Madrid', None)] + +Sage example in ./graphtheory.tex, line 159:: + + sage: g = Graph({ + ....: 0: [], + ....: 1: [5, 9], + ....: 2: [1, 5, 9], + ....: 'Edinburgh': ['Madrid']}) + +Sage example in ./graphtheory.tex, line 212:: + + sage: P = graphs.PetersenGraph() + sage: C = graphs.ChvatalGraph() + +Sage example in ./graphtheory.tex, line 252:: + + sage: P = graphs.PetersenGraph() + sage: P.is_planar() + False + sage: P.minor(graphs.CompleteBipartiteGraph(3,3)) # random + {0: [1], 1: [8], 2: [4], 3: [6, 7, 9], 4: [2, 3], 5: [0, 5]} + sage: P.minor(graphs.CompleteGraph(5)) # random + {0: [1, 6], 1: [0, 5], 2: [2, 7], 3: [4, 9], 4: [3, 8]} + sage: P.girth() + 5 + sage: P.is_regular(3) + True + sage: P.chromatic_number() + 3 + sage: P.is_vertex_transitive() + True + sage: P.show() + +Sage example in ./graphtheory.tex, line 332:: + + sage: K = graphs.KneserGraph(5, 2); P = graphs.PetersenGraph() + sage: K.is_isomorphic(P) + True + +Sage example in ./graphtheory.tex, line 340:: + + sage: all( graphs.KneserGraph(n,k).chromatic_number() == n - 2*k + 2 + ....: for n in range(5,9) for k in range(2,floor(n/2)) ) + True + +Sage example in ./graphtheory.tex, line 459:: + + sage: H = graphs.ClawGraph() + sage: def test(): + ....: g = graphs.RandomGNP(20,2/5) + ....: return not g.subgraph_search(H, induced=True) is None + sage: sum( test() for i in range(100) ) >= 80 + True + +Sage example in ./graphtheory.tex, line 485:: + + sage: P = graphs.PetersenGraph() + sage: H = graphs.HoffmanSingletonGraph() + sage: U = P + H; U2 = P.disjoint_union(H) + sage: U.is_isomorphic(U2) + True + +Sage example in ./graphtheory.tex, line 496:: + + sage: C = graphs.ChvatalGraph() + sage: U = 3 * C; U2 = C.disjoint_union(C.disjoint_union(C)) + sage: U2.is_isomorphic(U) + True + +Sage example in ./graphtheory.tex, line 506:: + + sage: U = 3*P + 2*C + +Sage example in ./graphtheory.tex, line 513:: + + sage: all( (CC.is_isomorphic(P) or CC.is_isomorphic(C)) + ....: for CC in U.connected_components_subgraphs() ) + True + +Sage example in ./graphtheory.tex, line 522:: + + sage: sum( CC.is_isomorphic(P) + ....: for CC in U.connected_components_subgraphs() ) + 3 + sage: sum( CC.is_isomorphic(C) + ....: for CC in U.connected_components_subgraphs() ) + 2 + +Sage example in ./graphtheory.tex, line 568:: + + sage: C = graphs.ChvatalGraph(); C.show() + +Sage example in ./graphtheory.tex, line 583:: + + sage: C.show(partition = [C.independent_set()]) + +Sage example in ./graphtheory.tex, line 597:: + + sage: C.show(vertex_colors = { + ....: "red" : [0, 1, 2], "blue" : [3, 4, 5], + ....: "yellow" : [6, 7, 8], "purple" : [9, 10, 11]}) + +Sage example in ./graphtheory.tex, line 608:: + + sage: C.coloring(hex_colors = True) + {'#00ffff': [3, 8, 5], + '#7f00ff': [11], + '#7fff00': [1, 4, 6, 9], + '#ff0000': [0, 2, 7, 10]} + sage: C.show(vertex_colors = C.coloring(hex_colors = True)) + +Sage example in ./graphtheory.tex, line 644:: + + sage: L = [graphs.CompleteGraph(i) for i in range(3,3+10)] + sage: for number, G in enumerate(L): + ....: G.plot().save(tmp_filename(ext=".png")) + +Sage example in ./graphtheory.tex, line 782:: + + sage: P5 = graphs.PathGraph(5); House = graphs.HouseGraph() + sage: P5.complement().is_isomorphic(House) + True + sage: P4 = graphs.PathGraph(4); P4.complement().is_isomorphic(P4) + True + sage: C5 = graphs.CycleGraph(5); C5.complement().is_isomorphic(C5) + True + +Sage example in ./graphtheory.tex, line 852:: + + sage: n = 5; Path = graphs.PathGraph(n) + sage: Grid = Path.cartesian_product(Path) + sage: Grid.is_isomorphic(graphs.GridGraph([n,n])) + True + +Sage example in ./graphtheory.tex, line 1144:: + + sage: n = 30; p = 0.3; trials = 50 + sage: def equality(G): + ....: return G.edge_connectivity() == min(G.degree()) + sage: sum(equality(graphs.RandomGNP(n,p)) for i in range(trials))/trials + 1 + +Sage example in ./graphtheory.tex, line 1319:: + + sage: g = graphs.ChvatalGraph(); cycle = g.hamiltonian_cycle() + sage: g.show(vertex_labels = False); cycle.show(vertex_labels = False) + +Sage example in ./graphtheory.tex, line 1586:: + + sage: set_random_seed(3291) + +Sage example in ./graphtheory.tex, line 1589:: + + sage: n = 100; p = 5/n; g = graphs.RandomGNP(n, p) + +Sage example in ./graphtheory.tex, line 1597:: + + sage: # Set of available colors. + sage: # In the worst-case scenario up to n colors suffice + sage: available_colors = Set(range(n)) + +Sage example in ./graphtheory.tex, line 1611:: + + sage: # This dictionary contains the color associated + sage: # with each vertex of the graph + sage: color = {} + sage: for u in g: + ....: forbidden = Set([color[v] for v in g.neighbors(u) + ....: if v in color]) + ....: color[u] = min(available_colors - forbidden) + +Sage example in ./graphtheory.tex, line 1625:: + + sage: # Number of colors used + sage: max(color.values()) + 1 + 6 + +Sage example in ./graphtheory.tex, line 1635:: + + sage: P = Permutations([0,1,2,3]); P.random_element() + [2, 0, 1, 3] + +Sage example in ./graphtheory.tex, line 1646:: + + sage: available_colors = Set(range(n)) + +Sage example in ./graphtheory.tex, line 1656:: + + sage: n_tests = 30 + sage: vertices = g.vertices() + sage: P = Permutations(range(n)) + sage: best_coloring = {} + sage: best_chromatic_number = +oo + +Sage example in ./graphtheory.tex, line 1678:: + + sage: for t in range(n_tests): + ....: # Random ordering of vertices + ....: p = P.random_element() + ....: color = {} + ....: for i in range(g.order()): + ....: u = vertices[p[i]] + ....: forbidden = Set([color[v] for v in g.neighbors(u) + ....: if v in color]) + ....: color[u] = min(available_colors - forbidden) + ....: # Update the best coloring + ....: if max(color.values()) + 1 < best_chromatic_number: + ....: best_coloring = color + ....: best_chromatic_number = 1 + max(color.values()) + +Sage example in ./graphtheory.tex, line 1697:: + + sage: best_chromatic_number # Number of colors used + 4 + +Sage example in ./graphtheory.tex, line 1718:: + + sage: def greedy_coloring(g, permutation): + ....: n = g.order() + ....: available_colors = Set(range(n)) + ....: vertices = g.vertices() + ....: color = {} + ....: for i in range(n): + ....: u = vertices[permutation[i]] + ....: forbidden = Set([color[v] for v in g.neighbors(u) + ....: if v in color]) + ....: color[u] = min(available_colors - forbidden) + ....: return max(color.values()) + 1, color + +Sage example in ./graphtheory.tex, line 1736:: + + sage: set_random_seed(0) + +Sage example in ./graphtheory.tex, line 1746:: + + sage: P = Permutations(range(g.order())) + sage: n_colors, coloration = min( + ....: greedy_coloring(g, P.random_element()) for i in range(50)) + sage: n_colors + 4 + +Sage example in ./graphtheory.tex, line 1782:: + + sage: n = 20; k = 4; g = graphs.RandomGNP(n, 0.5) + sage: g = g.subgraph(edges = g.min_spanning_tree()) + +Sage example in ./graphtheory.tex, line 1786:: + + sage: while True: + ....: _, edges, [S,Sb] = g.edge_connectivity(vertices = True) + ....: cardinality = len(edges) + ....: if cardinality < k: + ....: CP = cartesian_product([S, Sb]) + ....: g.add_edges([CP.random_element() + ....: for i in range(k - len(edges))]) + ....: else: + ....: break + +Sage example in ./graphtheory.tex, line 1844:: + + sage: g = graphs.RandomGNP(40, 0.4) + sage: P = Permutations(range(g.order())) + sage: mean = sum( 1/(g.degree(v)+1) for v in g ) + +Sage example in ./graphtheory.tex, line 1849:: + + sage: while True: + ....: n = P.random_element() + ....: S = [v for v in g if all( n[v] < n[u] for u in g.neighbors(v))] + ....: if len(S) >= mean: + ....: break + +Sage example in ./graphtheory.tex, line 1989:: + + sage: def find_induced(H, G): + ....: # the function from V(H) to V(G) we aim to define: + ....: f = {} + ....: # set of vertices of G not yet used by f: + ....: G_remain = G.vertices() + ....: # set of vertices having no representative yet: + ....: H_remain = H.vertices() + ....: # while the function is not complete: + ....: while H_remain: + ....: v = H_remain.pop(0) # look for the next vertex of H + ....: # and its potential images in G + ....: candidates = [u for u in G_remain if + ....: all([H.has_edge(h,v) == G.has_edge(f_h,u) + ....: for h, f_h in f.items()])] + ....: # if no candidate is found, we abort immediately + ....: if not candidates: + ....: raise ValueError("No copy of H has been found in G") + ....: # otherwise we select the first candidate + ....: f[v] = candidates[0] + ....: G_remain.remove(f[v]) + ....: return f + +Sage example in ./graphtheory.tex, line 2012:: + + sage: set_random_seed(3) + +Sage example in ./graphtheory.tex, line 2021:: + + sage: H = graphs.PetersenGraph() + sage: G = graphs.RandomGNP(500,0.5) + sage: find_induced(H,G) + {0: 0, 1: 4, 2: 3, 3: 7, 4: 35, 5: 10, 6: 67, 7: 108, 8: 240, 9: 39} + +Sage example in ./graphtheory.tex, line 2070:: + + sage: n = 100; V = range(n+1) + sage: G = Graph() + sage: G.add_edges([ + ....: (i,j) for i,j in Subsets(V,2) if is_square(abs(i-j)) ]) + +Sage example in ./graphtheory.tex, line 2084:: + + sage: X = G.independent_set(); X # random with python3 + [4, 6, 9, 11, 16, 21, 23, 26, 28, 33, 38, 43, 50, + 56, 61, 71, 76, 78, 83, 88, 93, 95, 98, 100] + sage: G.is_independent_set(X) + True + +Sage example in ./graphtheory.tex, line 2139:: + + sage: tasks = {0: [2, 5, 3, 7], 1: [0, 1, 4], + ....: 2: [5, 0, 4], 3: [0, 1], + ....: 4: [8], 5: [2], + ....: 6: [8, 9, 7], 7: [5, 8, 7], + ....: 8: [2, 5, 3, 6, 4], 9: [2, 5, 8, 6, 1]} + sage: G = Graph() + sage: for i in tasks: + ....: G.add_edges(("w" + str(i), "t" + str(j)) for j in tasks[i]) + +Sage example in ./graphtheory.tex, line 2182:: + + sage: M = Graph(G.matching()) + sage: for i in tasks: + ....: print("t{} assigned to {}".format(i,M.neighbors('t'+str(i))[0])) + t0 assigned to w2 + t1 assigned to w3 + t2 assigned to w5 + t3 assigned to w8 + t4 assigned to w1 + t5 assigned to w7 + t6 assigned to w9 + t7 assigned to w0 + t8 assigned to w4 + t9 assigned to w6 + +Sage example in ./graphtheory.tex, line 2232:: + + sage: n = 10 + sage: G = graphs.CompleteGraph(n) + sage: from sage.graphs.graph_coloring import edge_coloring + sage: for day, matches in enumerate(edge_coloring(G)): + ....: print("Matches of day {}: {}".format(day, matches)) + Matches of day 0: [(0, 9), (1, 8), (2, 7), (3, 6), (4, 5)] + Matches of day 1: [(0, 2), (1, 9), (3, 8), (4, 7), (5, 6)] + Matches of day 2: [(0, 4), (1, 3), (2, 9), (5, 8), (6, 7)] + Matches of day 3: [(0, 6), (1, 5), (2, 4), (3, 9), (7, 8)] + Matches of day 4: [(0, 8), (1, 7), (2, 6), (3, 5), (4, 9)] + Matches of day 5: [(0, 1), (2, 8), (3, 7), (4, 6), (5, 9)] + Matches of day 6: [(0, 3), (1, 2), (4, 8), (5, 7), (6, 9)] + Matches of day 7: [(0, 5), (1, 4), (2, 3), (6, 8), (7, 9)] + Matches of day 8: [(0, 7), (1, 6), (2, 5), (3, 4), (8, 9)] + +Sage example in ./graphtheory.tex, line 2260:: + + sage: g = graphs.CompleteGraph(10) + sage: g.show(edge_colors=edge_coloring(g, hex_colors=True)) + +""" + 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 new file mode 100644 index 00000000000..a133113fe09 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py @@ -0,0 +1,289 @@ +## -*- encoding: utf-8 -*- +""" +This file (./integration_doctest.sage) was *autogenerated* from ./integration.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./integration_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./integration.tex, line 73:: + + sage: x = var('x'); f(x) = exp(-x^2) * log(x) + sage: N(integrate(f, x, 1, 3)) + 0.035860294991267694 + +Sage example in ./integration.tex, line 78:: + + sage: plot(f, 1, 3, fill='axis') + Graphics object consisting of 2 graphics primitives + +Sage example in ./integration.tex, line 104:: + + sage: N(integrate(sin(x^2)/(x^2), x, 1, infinity)) # abs tol 2e-15 + 0.285736646322853 - 6.93889390390723e-18*I + +Sage example in ./integration.tex, line 108:: + + sage: plot(sin(x^2)/(x^2), x, 1, 10, fill='axis') + Graphics object consisting of 2 graphics primitives + +Sage example in ./integration.tex, line 162:: + + sage: fp = plot(f, 1, 3, color='red') + sage: n = 4 + sage: interp_points = [(1+2*u/(n-1), N(f(1+2*u/(n-1)))) + ....: for u in range(n)] + sage: A = PolynomialRing(RR, 'x') + sage: pp = plot(A.lagrange_polynomial(interp_points), 1, 3, fill='axis') + sage: fp+pp + Graphics object consisting of 3 graphics primitives + +Sage example in ./integration.tex, line 522:: + + sage: N(integrate(exp(-x^2)*log(x), x, 17, 42)) # rel tol 2e-12 + 2.5657285006962035e-127 + +Sage example in ./integration.tex, line 536:: + + sage: integrate(log(1+x)*x, x, 0, 1) + 1/4 + sage: N(integrate(log(1+x)*x, x, 0, 1)) + 0.250000000000000 + +Sage example in ./integration.tex, line 562:: + + sage: numerical_integral(exp(-x^2)*log(x), 17, 42) # rel tol 2e-11 + (2.5657285006962035e-127, 3.3540254049238093e-128) + +Sage example in ./integration.tex, line 600:: + + sage: numerical_integral(exp(-x^100), 0, 1.1) + (0.99432585119150..., 4.0775730...e-09) + sage: numerical_integral(exp(-x^100), 0, 1.1, algorithm='qng') # abs tol 2e-12 + (0.9943275385765319, 0.016840666914705607) + +Sage example in ./integration.tex, line 612:: + + sage: integrate(exp(-x^2)*log(x), x, 17, 42) + integrate(e^(-x^2)*log(x), x, 17, 42) + +Sage example in ./integration.tex, line 622:: + + sage: N(integrate(exp(-x^2)*log(x), x, 17, 42), digits=60) # rel tol 2e-12 + 2.5657285006962035e-127 + +Sage example in ./integration.tex, line 628:: + + sage: N(integrate(sin(x)*exp(cos(x)), x, 0, pi), digits=60) + 2.35040238728760291376476370119120163031143596266819174045913 + +Sage example in ./integration.tex, line 644:: + + sage: sage.calculus.calculus.nintegral(sin(sin(x)), x, 0, 1) + (0.430606103120690..., 4.78068810228705...e-15, 21, 0) + +Sage example in ./integration.tex, line 654:: + + sage: g = sin(sin(x)) + sage: g.nintegral(x, 0, 1) + (0.430606103120690..., 4.78068810228705...e-15, 21, 0) + +Ensure consistent results on 32-bit and 64-bit systems by using the same +precision:: + + sage: _ = gp.default('realprecision', 38) + +Sage example in ./integration.tex, line 703:: + + sage: gp('intnum(x=17, 20, exp(-x^2)*log(x))') + 2.5657285005610514829173563961304785900 E-127 + +Sage example in ./integration.tex, line 717:: + + sage: gp('intnum(x=0, 1, sin(sin(x)))') + 0.43060610312069060491237735524846578643 + sage: old_prec = gp.set_precision(50) + sage: gp('intnum(x=0, 1, sin(sin(x)))') + 0.43060610312069060491237735524846578643360804182200 + +Sage example in ./integration.tex, line 746:: + + sage: p = gp.set_precision(old_prec) # we reset the default precision + sage: gp('intnum(x=0, 1, x^(-99/100))') # rel tol 1e-9 + 73.629142577870966597465391764897770039 + +Sage example in ./integration.tex, line 754:: + + sage: gp('intnum(x=[0, -99/100], 1, x^(-99/100))') + 100.00000000000000000000000000000000000 + +Sage example in ./integration.tex, line 766:: + + sage: gp('intnum(x=[0, -1/42], 1, x^(-99/100))') # rel tol 1e-9 + 74.472749314025559405335761513474670714 + +Sage example in ./integration.tex, line 785:: + + sage: import mpmath + sage: mpmath.mp.prec = 53 + sage: mpmath.quad(lambda x: mpmath.sin(mpmath.sin(x)), [0, 1]) + mpf('0.43060610312069059') + +Sage example in ./integration.tex, line 795:: + + sage: a = RDF(pi); b = mpmath.mpf(a); b + mpf('3.1415926535897931') + sage: c = RDF(b); c + 3.141592653589793 + +Sage example in ./integration.tex, line 824:: + + sage: mpmath.mp.prec = 113 + sage: mpmath.quad(lambda x: mpmath.sin(mpmath.sin(x)), [0, 1]) + mpf('0.430606103120690604912377355248465809') + +Sage example in ./integration.tex, line 846:: + + sage: mpmath.quad(sin(sin(x)), [0, 1]) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from to Symbolic Ring + +Sage example in ./integration.tex, line 866:: + + sage: g(x) = max_symbolic(sin(x), cos(x)) + sage: mpmath.mp.prec = 100 + sage: mpmath.quadts(lambda x: g(N(x, 100)), [0, 1]) + mpf('0.873912416263035435957979086252') + +Sage example in ./integration.tex, line 878:: + + sage: mpmath.mp.prec = 170 + sage: mpmath.quadts(lambda x: g(N(x, 190)), [0, 1]) + mpf('0.87391090757400975205393005981962476344054148354188794') + sage: N(sqrt(2) - cos(1), 100) + 0.87391125650495533140075211677 + +Sage example in ./integration.tex, line 892:: + + sage: mpmath.quadts(lambda x: g(N(x, 170)), [0, mpmath.pi / 4, 1]) + mpf('0.87391125650495533140075211676672147483736145475902551') + +Sage example in ./integration.tex, line 979:: + + sage: y = var('y'); integrate(exp(y*sin(x)), (x, 0, sqrt(y))) # long time + integrate(e^(y*sin(x)), x, 0, sqrt(y)) + +Sage example in ./integration.tex, line 990:: + + sage: f = lambda y: numerical_integral(lambda x: exp(y*sin(x)), \ + 0, sqrt(y))[0] + sage: f(0.0), f(0.5), f(1.0) # abs tol 2e-15 + (0.0, 0.8414895067661431, 1.6318696084180513) + +Sage example in ./integration.tex, line 998:: + + sage: numerical_integral(f, 0, 1) # abs tol 2e-16 + (0.8606791942204567, 6.301207560882073e-07) + +Sage example in ./integration.tex, line 1008:: + + sage: f = lambda y: sage.calculus.calculus.nintegral(exp(y*sin(x)), \ + x, 0, sqrt(y))[0] + sage: numerical_integral(f, 0, 1) # abs tol 2e-16 + (0.8606791942204567, 6.301207560882096e-07) + +Sage example in ./integration.tex, line 1016:: + + sage: f = lambda y: RDF(mpmath.quad(lambda x: mpmath.exp(y*mpmath.sin(x)), \ + [0, sqrt(y)])) + sage: numerical_integral(f, 0, 1) # abs tol 2e-16 + (0.8606791942204567, 6.301207561187562e-07) + +Sage example in ./integration.tex, line 1027:: + + sage: mpmath.mp.dps = 60 + sage: f = lambda x, y: mpmath.exp(y*mpmath.sin(x)) + sage: mpmath.quad(f, [0,1], [0,1]) + mpf('1.28392205755238471754385917646324675741664250325189751108716305') + +Sage example in ./integration.tex, line 1044:: + + sage: def evalI(n): + ....: f = lambda y: numerical_integral(lambda x: exp(y*sin(x)), + ....: 0, sqrt(y), algorithm='qng', max_points=n)[0] + ....: return numerical_integral(f, 0, 1, algorithm='qng', max_points=n) + sage: evalI(100) # abs tol 2e-12 + (0.8606792028826138, 5.553962923506737e-07) + +Sage example in ./integration.tex, line 1228:: + + sage: T = ode_solver() + +Sage example in ./integration.tex, line 1244:: + + sage: def f_1(t,y,params): return [y[1],params[0]*(1-y[0]^2)*y[1]-y[0]] + sage: T.function = f_1 + +Sage example in ./integration.tex, line 1266:: + + sage: def j_1(t,y,params): + ....: return [[0, 1], + ....: [-2*params[0]*y[0]*y[1]-1, params[0]*(1-y[0]^2)], + ....: [0,0]] + sage: T.jacobian = j_1 + +Sage example in ./integration.tex, line 1279:: + + sage: T.algorithm = "rk8pd" + sage: T.ode_solve(y_0=[1,0], t_span=[0,100], params=[10], + ....: num_points=1000) + sage: f = T.interpolate_solution() + +Sage example in ./integration.tex, line 1302:: + + sage: plot(f, 0, 100) + Graphics object consisting of 1 graphics primitive + +Sage example in ./integration.tex, line 1363:: + + sage: t, y = var('t, y') + sage: desolve_rk4(t*y*(2-y), y, ics=[0,1], end_points=[0, 1], step=0.5) + [[0, 1], [0.5, 1.12419127424558], [1.0, 1.461590162288825]] + +Sage example in ./integration.tex, line 1399:: + + sage: import mpmath + sage: mpmath.mp.prec = 53 + sage: sol = mpmath.odefun(lambda t, y: y, 0, 1) + sage: sol(1) + mpf('2.7182818284590451') + sage: mpmath.mp.prec = 100 + sage: sol(1) + mpf('2.7182818284590452353602874802307') + sage: N(exp(1), 100) + 2.7182818284590452353602874714 + +Sage example in ./integration.tex, line 1436:: + + sage: mpmath.mp.prec = 53 + sage: f = mpmath.odefun(lambda t, y: [-y[1], y[0]], 0, [1, 0]) + sage: f(3) + [mpf('-0.98999249660044542'), mpf('0.14112000805986721')] + sage: (cos(3.), sin(3.)) + (-0.989992496600445, 0.141120008059867) + +Sage example in ./integration.tex, line 1497:: + + sage: mpmath.mp.prec = 10 + sage: sol = mpmath.odefun(lambda t, y: y, 0, 1) + sage: sol(1) + mpf('2.7148') + sage: mpmath.mp.prec = 100 + sage: sol(1) + mpf('2.7135204235459511323824699502438') + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py new file mode 100644 index 00000000000..d67a33e7c4a --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py @@ -0,0 +1,459 @@ +## -*- encoding: utf-8 -*- +""" +This file (./linalg_doctest.sage) was *autogenerated* from ./linalg.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./linalg_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./linalg.tex, line 168:: + + sage: MS = MatrixSpace(ZZ,2,3); MS + Full MatrixSpace of 2 by 3 dense matrices over Integer Ring + sage: VS = VectorSpace(GF(3^2,'x'),3); VS + Vector space of dimension 3 over Finite Field in x of size 3^2 + +Sage example in ./linalg.tex, line 184:: + + sage: B = MatrixSpace(ZZ,2,3).basis() + sage: list(B) + [ + [1 0 0] [0 1 0] [0 0 1] [0 0 0] [0 0 0] [0 0 0] + [0 0 0], [0 0 0], [0 0 0], [1 0 0], [0 1 0], [0 0 1] + ] + +Sage example in ./linalg.tex, line 220:: + + sage: B[1,2] + [0 0 0] + [0 0 1] + +Sage example in ./linalg.tex, line 260:: + + sage: A = matrix(GF(11), 2, 2, [1,0,0,2]) + sage: B = matrix(GF(11), 2, 2, [0,1,1,0]) + sage: MG = MatrixGroup([A,B]) + sage: MG.cardinality() + 200 + sage: identity_matrix(GF(11),2) in MG + True + +Sage example in ./linalg.tex, line 292:: + + sage: MS = MatrixSpace(ZZ,2,3); A = MS([1,2,3,4,5,6]); A + [1 2 3] + [4 5 6] + +Sage example in ./linalg.tex, line 323:: + + sage: a = matrix(); a.parent() + Full MatrixSpace of 0 by 0 dense matrices over Integer Ring + +Sage example in ./linalg.tex, line 341:: + + sage: a = matrix(GF(8,'x'),3,4); a.parent() + Full MatrixSpace of 3 by 4 dense matrices over Finite Field + in x of size 2^3 + +Sage example in ./linalg.tex, line 356:: + + sage: g = graphs.PetersenGraph() + sage: m = matrix(g); m; m.parent() + [0 1 0 0 1 1 0 0 0 0] + [1 0 1 0 0 0 1 0 0 0] + [0 1 0 1 0 0 0 1 0 0] + [0 0 1 0 1 0 0 0 1 0] + [1 0 0 1 0 0 0 0 0 1] + [1 0 0 0 0 0 0 1 1 0] + [0 1 0 0 0 0 0 0 1 1] + [0 0 1 0 0 1 0 0 0 1] + [0 0 0 1 0 1 1 0 0 0] + [0 0 0 0 1 0 1 1 0 0] + Full MatrixSpace of 10 by 10 dense matrices over Integer Ring + +Sage example in ./linalg.tex, line 380:: + + sage: A = matrix([[1,2],[3,4]]) + sage: block_matrix([[A,-A],[2*A, A^2]]) + [ 1 2|-1 -2] + [ 3 4|-3 -4] + [-----+-----] + [ 2 4| 7 10] + [ 6 8|15 22] + +Sage example in ./linalg.tex, line 413:: + + sage: A = matrix([[1,2,3],[4,5,6]]) + sage: block_matrix([1,A,0,0,-A,2], ncols=3) + [ 1 0| 1 2 3| 0 0] + [ 0 1| 4 5 6| 0 0] + [-----+--------+-----] + [ 0 0|-1 -2 -3| 2 0] + [ 0 0|-4 -5 -6| 0 2] + +Sage example in ./linalg.tex, line 443:: + + sage: A = matrix([[1,2,3],[0,1,0]]) + sage: block_diagonal_matrix(A, A.transpose()) + [1 2 3|0 0] + [0 1 0|0 0] + [-----+---] + [0 0 0|1 0] + [0 0 0|2 1] + [0 0 0|3 0] + +Sage example in ./linalg.tex, line 517:: + + sage: A = matrix(3,3,range(9)) + sage: A[:,1] = vector([1,1,1]); A + [0 1 2] + [3 1 5] + [6 1 8] + +Sage example in ./linalg.tex, line 535:: + + sage: A[::-1], A[:,::-1], A[::2,-1] + ( + [6 1 8] [2 1 0] + [3 1 5] [5 1 3] [2] + [0 1 2], [8 1 6], [8] + ) + +Sage example in ./linalg.tex, line 571:: + + sage: A = matrix(ZZ,4,4,range(16)); A + [ 0 1 2 3] + [ 4 5 6 7] + [ 8 9 10 11] + [12 13 14 15] + + +Sage example in ./linalg.tex, line 587:: + + sage: A.matrix_from_rows_and_columns([0,2,3],[1,2]) + [ 1 2] + [ 9 10] + [13 14] + +Sage example in ./linalg.tex, line 639:: + + sage: MS = MatrixSpace(GF(3),2,3) + sage: MS.base_extend(GF(9,'x')) + Full MatrixSpace of 2 by 3 dense matrices over Finite Field + in x of size 3^2 + sage: MS = MatrixSpace(ZZ,2,3) + sage: MS.change_ring(GF(3)) + Full MatrixSpace of 2 by 3 dense matrices over Finite Field of size 3 + +Sage example in ./linalg.tex, line 1167:: + + sage: a = matrix(GF(7),4,3,[6,2,2,5,4,4,6,4,5,5,1,3]); a + [6 2 2] + [5 4 4] + [6 4 5] + [5 1 3] + +Sage example in ./linalg.tex, line 1181:: + + sage: u = copy(identity_matrix(GF(7),4)); u[1:,0] = -a[1:,0]/a[0,0] + sage: u, u*a + ( + [1 0 0 0] [6 2 2] + [5 1 0 0] [0 0 0] + [6 0 1 0] [0 2 3] + [5 0 0 1], [0 4 6] + ) + +Sage example in ./linalg.tex, line 1203:: + + sage: v = copy(identity_matrix(GF(7),4)); v.swap_rows(1,2) + sage: b = v*u*a; v, b + ( + [1 0 0 0] [6 2 2] + [0 0 1 0] [0 2 3] + [0 1 0 0] [0 0 0] + [0 0 0 1], [0 4 6] + ) + +Sage example in ./linalg.tex, line 1225:: + + sage: w = copy(identity_matrix(GF(7),4)) + sage: w[2:,1] = -b[2:,1]/b[1,1]; w, w*b + ( + [1 0 0 0] [6 2 2] + [0 1 0 0] [0 2 3] + [0 0 1 0] [0 0 0] + [0 5 0 1], [0 0 0] + ) + +Sage example in ./linalg.tex, line 1325:: + + sage: A = matrix(GF(7),4,5,[4,4,0,2,4,5,1,6,5,4,1,1,0,1,0,5,1,6,6,2]) + sage: A, A.echelon_form() + ( + [4 4 0 2 4] [1 0 5 0 3] + [5 1 6 5 4] [0 1 2 0 6] + [1 1 0 1 0] [0 0 0 1 5] + [5 1 6 6 2], [0 0 0 0 0] + ) + +Sage example in ./linalg.tex, line 1512:: + + sage: a = matrix(ZZ, 4, 6, [2,1,2,2,2,-1,1,2,-1,2,1,-1,2,1,-1,\ + ....: -1,2,2,2,1,1,-1,-1,-1]); a.echelon_form() + [ 1 2 0 5 4 -1] + [ 0 3 0 2 -6 -7] + [ 0 0 1 3 3 0] + [ 0 0 0 6 9 3] + +Sage example in ./linalg.tex, line 1528:: + + sage: a.base_extend(QQ).echelon_form() + [ 1 0 0 0 5/2 11/6] + [ 0 1 0 0 -3 -8/3] + [ 0 0 1 0 -3/2 -3/2] + [ 0 0 0 1 3/2 1/2] + +Sage example in ./linalg.tex, line 1561:: + + sage: A = matrix(ZZ,4,5,[4,4,0,2,4,5,1,6,5,4,1,1,0,1,0,5,1,6,6,2]) + sage: H, U = A.echelon_form(transformation=True); H, U + ( + [ 1 1 0 0 2] [ 0 1 1 -1] + [ 0 4 -6 0 -4] [ 0 -1 5 0] + [ 0 0 0 1 -2] [ 0 -1 0 1] + [ 0 0 0 0 0], [ 1 -2 -4 2] + ) + +Sage example in ./linalg.tex, line 1640:: + + sage: A = matrix(ZZ, 4, 5,\ + ....: [-1,-1,-1,-2,-2,-2,1,1,-1,2,2,2,2,2,-1,2,2,2,2,2]) + sage: S,U,V = A.smith_form(); S,U,V + ( + [ 0 -2 -1 -5 0] + [1 0 0 0 0] [ 1 0 0 0] [ 1 0 1 -1 -1] + [0 1 0 0 0] [ 0 0 1 0] [ 0 0 0 0 1] + [0 0 3 0 0] [-2 1 0 0] [-1 2 0 5 0] + [0 0 0 6 0], [ 0 0 -2 -1], [ 0 -1 0 -2 0] + ) + +Sage example in ./linalg.tex, line 1674:: + + sage: A.elementary_divisors() + [1, 1, 3, 6] + sage: S == U*A*V + True + +Sage example in ./linalg.tex, line 1746:: + + sage: B = matrix(GF(7),5,4,[4,5,1,5,4,1,1,1,0,6,0,6,2,5,1,6,4,4,0,2]) + sage: B.transpose().echelon_form() + [1 0 5 0 3] + [0 1 2 0 6] + [0 0 0 1 5] + [0 0 0 0 0] + +Sage example in ./linalg.tex, line 1761:: + + sage: B.pivot_rows() + (0, 1, 3) + sage: B.transpose().pivots() == B.pivot_rows() + True + +Sage example in ./linalg.tex, line 1818:: + + sage: R. = PolynomialRing(GF(5),'x') + sage: A = random_matrix(R,2,3); A # random + [ 3*x^2 + x x^2 + 2*x 2*x^2 + 2] + [ x^2 + x + 2 2*x^2 + 4*x + 3 x^2 + 4*x + 3] + +Sage example in ./linalg.tex, line 1830:: + + sage: b = random_matrix(R,2,1); b # random + [ 4*x^2 + 1] + [3*x^2 + 2*x] + +Sage example in ./linalg.tex, line 1841:: + + sage: A.solve_right(b) # random + [(4*x^3 + 2*x + 4)/(3*x^3 + 2*x^2 + 2*x)] + [ (3*x^2 + 4*x + 3)/(x^3 + 4*x^2 + 4*x)] + [ 0] + +Sage example in ./linalg.tex, line 1855:: + + sage: A.solve_right(b) == A\b + True + +Sage example in ./linalg.tex, line 1910:: + + sage: a = matrix(QQ,3,5,[2,2,-1,-2,-1,2,-1,1,2,-1/2,2,-2,-1,2,-1/2]) + sage: a.image() + Vector space of degree 5 and dimension 3 over Rational Field + Basis matrix: + [ 1 0 0 1/4 -11/32] + [ 0 1 0 -1 -1/8] + [ 0 0 1 1/2 1/16] + sage: a.right_kernel() + Vector space of degree 5 and dimension 2 over Rational Field + Basis matrix: + [ 1 0 0 -1/3 8/3] + [ 0 1 -1/2 11/12 2/3] + +Sage example in ./linalg.tex, line 1941:: + + sage: a = matrix(ZZ,5,3,[1,1,122,-1,-2,1,-188,2,1,1,-10,1,-1,-1,-1]) + sage: a.kernel() + Free module of degree 5 and rank 2 over Integer Ring + Echelon basis matrix: + [ 1 979 -11 -279 811] + [ 0 2079 -22 -569 1488] + sage: b = a.base_extend(QQ) + sage: b.kernel() + Vector space of degree 5 and dimension 2 over Rational Field + Basis matrix: + [ 1 0 -121/189 -2090/189 6949/63] + [ 0 1 -2/189 -569/2079 496/693] + sage: b.integer_kernel() + Free module of degree 5 and rank 2 over Integer Ring + Echelon basis matrix: + [ 1 979 -11 -279 811] + [ 0 2079 -22 -569 1488] + +Sage example in ./linalg.tex, line 2301:: + + sage: A = matrix(GF(97), 4, 4,\ + ....: [86,1,6,68,34,24,8,35,15,36,68,42,27,1,78,26]) + sage: e1 = identity_matrix(GF(97),4)[0] + sage: U = matrix(A.transpose().maxspin(e1)).transpose() + sage: F = U^-1*A*U; F + [ 0 0 0 83] + [ 1 0 0 77] + [ 0 1 0 20] + [ 0 0 1 10] + +Sage example in ./linalg.tex, line 2320:: + + sage: K. = GF(97)[] + sage: P = x^4-sum(F[i,3]*x^i for i in range(4)); P + x^4 + 87*x^3 + 77*x^2 + 20*x + 14 + +Sage example in ./linalg.tex, line 2326:: + + sage: P == A.charpoly() + True + +Sage example in ./linalg.tex, line 2502:: + + sage: A = matrix(ZZ,8,[[6,0,-2,4,0,0,0,-2],[14,-1,0,6,0,-1,-1,1],\ + ....: [2,2,0,1,0,0,1,0],[-12,0,5,-8,0,0,0,4],\ + ....: [0,4,0,0,0,0,4,0],[0,0,0,0,1,0,0,0],\ + ....: [-14,2,0,-6,0,2,2,-1],[-4,0,2,-4,0,0,0,4]]) + sage: A.frobenius() + [0 0 0 4 0 0 0 0] + [1 0 0 4 0 0 0 0] + [0 1 0 1 0 0 0 0] + [0 0 1 0 0 0 0 0] + [0 0 0 0 0 0 4 0] + [0 0 0 0 1 0 0 0] + [0 0 0 0 0 1 1 0] + [0 0 0 0 0 0 0 2] + +Sage example in ./linalg.tex, line 2540:: + + sage: A.frobenius(1) + [x^4 - x^2 - 4*x - 4, x^3 - x^2 - 4, x - 2] + +Sage example in ./linalg.tex, line 2547:: + + sage: F,K = A.frobenius(2) + sage: K + [ 1 -15/56 17/224 15/56 -17/896 0 -15/112 17/64] + [ 0 29/224 -13/224 -23/448 -17/896 -17/896 29/448 13/128] + [ 0 -75/896 75/896 -47/896 0 -17/896 -23/448 11/128] + [ 0 17/896 -29/896 15/896 0 0 0 0] + [ 0 0 0 0 1 0 0 0] + [ 0 0 0 0 0 1 0 0] + [ 0 1 0 0 0 0 1 0] + [ 0 -4/21 -4/21 -10/21 0 0 -2/21 1] + +Sage example in ./linalg.tex, line 2573:: + + sage: K^-1*F*K == A + True + +Sage example in ./linalg.tex, line 2621:: + + sage: S. = QQ[] + sage: B = x*identity_matrix(8) - A + sage: B.elementary_divisors() + [1, 1, 1, 1, 1, x - 2, x^3 - x^2 - 4, x^4 - x^2 - 4*x - 4] + +Sage example in ./linalg.tex, line 2629:: + + sage: A.frobenius(1) + [x^4 - x^2 - 4*x - 4, x^3 - x^2 - 4, x - 2] + +Sage example in ./linalg.tex, line 2726:: + + sage: A = matrix(GF(7),4,[5,5,4,3,0,3,3,4,0,1,5,4,6,0,6,3]) + sage: A.eigenvalues() + [4, 1, 2, 2] + sage: A.eigenvectors_right() + [(4, [ + (1, 5, 5, 1) + ], 1), (1, [ + (0, 1, 1, 4) + ], 1), (2, [ + (1, 3, 0, 1), + (0, 0, 1, 1) + ], 2)] + sage: A.eigenspaces_right() + [ + (4, Vector space of degree 4 and dimension 1 over Finite Field + of size 7 + User basis matrix: + [1 5 5 1]), + (1, Vector space of degree 4 and dimension 1 over Finite Field + of size 7 + User basis matrix: + [0 1 1 4]), + (2, Vector space of degree 4 and dimension 2 over Finite Field + of size 7 + User basis matrix: + [1 3 0 1] + [0 0 1 1]) + ] + +Sage example in ./linalg.tex, line 2770:: + + sage: A.eigenmatrix_right() + ( + [4 0 0 0] [1 0 1 0] + [0 1 0 0] [5 1 3 0] + [0 0 2 0] [5 1 0 1] + [0 0 0 2], [1 4 1 1] + ) + +Sage example in ./linalg.tex, line 2930:: + + sage: A = matrix(ZZ,4,[3,-1,0,-1,0,2,0,-1,1,-1,2,0,1,-1,-1,3]) + sage: A.jordan_form() + [3|0|0 0] + [-+-+---] + [0|3|0 0] + [-+-+---] + [0|0|2 1] + [0|0|0 2] + +Sage example in ./linalg.tex, line 2949:: + + sage: J,U = A.jordan_form(transformation=True) + sage: U^-1*A*U == J + True + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/linsolve_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/linsolve_doctest.py new file mode 100644 index 00000000000..e9b60dae5ec --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/linsolve_doctest.py @@ -0,0 +1,421 @@ +## -*- encoding: utf-8 -*- +r""" +This file (./linsolve_doctest.sage) was *autogenerated* from ./linsolve.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./linsolve_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./linsolve.tex, line 294:: + + sage: def cond_hilbert(n): + ....: A = matrix(QQ, [[1/(i+j-1) for j in [1..n]] for i in [1..n]]) + ....: return A.norm(Infinity) * (A^-1).norm(Infinity) + +Sage example in ./linsolve.tex, line 346:: + + sage: def diff_hilbert(n): + ....: x = vector(QQ,[1 for i in range(0,n)]) + ....: A = matrix(QQ, [[1/(i+j-1) for j in [1..n]] for i in [1..n]]) + ....: y = A*x + ....: A[n-1,n-1] = (1/(2*n-1))*(1+1/(10^5)) # modifies the matrix + ....: s = A\y + ....: return max(abs(float(s[i]-x[i])) for i in range(0,n)) + +Sage example in ./linsolve.tex, line 396:: + + sage: def hilbert_diff(n): + ....: j = var("j") + ....: f = lambda i: sum(1/(i+j-1),j,1,n) + ....: y = vector(RDF, [f(i+1) for i in range(0,n)]) + ....: A = matrix(RDF, [[1/(i+j-1) for i in [1..n]] for j in [1..n]]) + ....: x = A.solve_right(y) + ....: return max(abs(x[i]-1.0) for i in range(0,n)) + +Sage example in ./linsolve.tex, line 543:: + + sage: n = 20; cost = (n+1)*factorial(n); cost + 51090942171709440000 + +Sage example in ./linsolve.tex, line 559:: + + sage: v = 3*10^9 + sage: print("%3.3f" % float(cost/v/3600/24/365)) + 540.028 + +Sage example in ./linsolve.tex, line 653:: + + sage: A = matrix(RDF, [[-1,2],[3,4]]) + sage: b = vector(RDF, [2,3]) + sage: x = A\b; x + (-0.20000000000000018, 0.9000000000000001) + +Sage example in ./linsolve.tex, line 666:: + + sage: x = A.solve_right(b) + +Sage example in ./linsolve.tex, line 678:: + + sage: A = matrix(RDF, [[-1,2],[3,4]]) + sage: P, L, U = A.LU() + +Sage example in ./linsolve.tex, line 723:: + + sage: eps = 1e-16 + sage: y = (1-2*eps)/(1-eps) + sage: x = (1-y)/eps + sage: x, y + (1.11022302462516, 1.00000000000000) + +Sage example in ./linsolve.tex, line 736:: + + sage: 1. + eps == 1. + True + +Sage example in ./linsolve.tex, line 758:: + + sage: y = (1-2*eps)/(1-eps) + sage: x = 2-y + sage: x, y + (1.00000000000000, 1.00000000000000) + +Sage example in ./linsolve.tex, line 803:: + + sage: A = random_matrix(RDF, 1000) + sage: b = vector(RDF, range(1000)) + sage: c = vector(RDF, 2*list(range(500))) + +Sage example in ./linsolve.tex, line 858:: + + sage: m = random_matrix(RDF, 10) + sage: A = transpose(m)*m + sage: C = A.cholesky() + +Sage example in ./linsolve.tex, line 946:: + + sage: A = random_matrix(RDF,6,5) + sage: Q, R = A.QR() + +Sage example in ./linsolve.tex, line 1012:: + + sage: A = matrix(RDF, [[1,3,2],[1,2,3],[0,5,2],[1,1,1]]) + sage: U, Sig, V = A.SVD() + sage: A1 = A - U*Sig*transpose(V); A1 # abs tol 1e-9 + [ 2.220446049250313e-16 0.0 0.0] + [3.3306690738754696e-16 -4.440892098500626e-16 -4.440892098500626e-16] + [-9.298117831235686e-16 1.7763568394002505e-15 -4.440892098500626e-16] + [ 4.440892098500626e-16 -8.881784197001252e-16 -4.440892098500626e-16] + +Sage example in ./linsolve.tex, line 1123:: + + sage: A = matrix(RDF, [[1,3,2],[1,4,2],[0,5,2],[1,3,2]]) + sage: b = vector(RDF, [1,2,3,4]) + sage: Z = transpose(A)*A + sage: C = Z.cholesky() + sage: R = transpose(A)*b + sage: Z.solve_right(R) # abs tol 2e-13 + (-1.5000000000000135, -0.5000000000000085, 2.7500000000000213) + +Sage example in ./linsolve.tex, line 1188:: + + sage: A = matrix(RDF, [[1,3,2],[1,4,2],[0,5,2],[1,3,2]]) + sage: b = vector(RDF, [1,2,3,4]) + sage: Q, R = A.QR() + sage: R1 = R[0:3,0:3] + sage: b1 = transpose(Q)*b + sage: c = b1[0:3] + sage: R1.solve_right(c) # abs tol 1e-13 + (-1.499999999999999, -0.49999999999999867, 2.749999999999997) + +Sage example in ./linsolve.tex, line 1202:: + + sage: Z = A.transpose()*A + sage: Z.norm(Infinity)*(Z^-1).norm(Infinity) # abs tol 2e-10 + 1992.3750000000168 + +Sage example in ./linsolve.tex, line 1256:: + + sage: A = matrix(RDF, [[1,3,2],[1,3,2],[0,5,2],[1,3,2]]) + sage: B = vector(RDF, [1,2,3,4]) + sage: U, Sig, V = A.SVD() + sage: m = A.ncols() + sage: x = vector(RDF, [0]*m) + sage: lamb = vector(RDF, [0]*m) + sage: for i in range(0,m): + ....: s = Sig[i,i] + ....: if s!=0.0: + ....: lamb[i]=U.column(i)*B/s + sage: x = V*lamb; x # random + (0.2370370370370367, 0.4518518518518521, 0.3703703703703702) + +Sage example in ./linsolve.tex, line 1289:: + + sage: m = 3; [ Sig[i,i] for i in range(0,m) ] # abs tol 1e-15 + [8.309316833256451, 1.3983038884881154, 0.0] + +Sage example in ./linsolve.tex, line 1358:: + + sage: A = matrix(RDF, [[1,2],[3,4],[5,6],[7,8]]) + +Sage example in ./linsolve.tex, line 1366:: + + sage: set_random_seed(0) # to get reproducible values below + +Sage example in ./linsolve.tex, line 1369:: + + sage: th = 0.7 + sage: R = matrix(RDF, [[cos(th),sin(th)],[-sin(th),cos(th)]]) + sage: B = (A + 0.1*random_matrix(RDF,4,2)) * transpose(R) + +Sage example in ./linsolve.tex, line 1374:: + + sage: C = transpose(B)*A + sage: U, Sigma, V = C.SVD() + sage: Q = U*transpose(V) + +Sage example in ./linsolve.tex, line 1381:: + + sage: Q # rel tol 1e-15 + [ 0.7612151656410957 0.648499399843978] + [-0.6484993998439779 0.7612151656410955] + sage: R + [0.7648421872844885 0.644217687237691] + [-0.644217687237691 0.7648421872844885] + +Sage example in ./linsolve.tex, line 1562:: + + sage: set_random_seed(0) # to get reproducible values below + +Sage example in ./linsolve.tex, line 1675:: + + sage: A = matrix(RDF, [[1,3,2],[1,2,3],[0,5,2]]) + +Sage example in ./linsolve.tex, line 1698:: + + sage: A = matrix(RDF,[[1,3,2],[1,2,3],[0,5,2]]) + sage: mu = 0.56 + sage: AT = A - mu*identity_matrix(RDF,3) + sage: X = vector(RDF,[1 for i in range(0,A.nrows())]) + sage: lam_old = 0 + sage: for i in range(1,1000): # abs tol 1e-9 + ....: Z = AT.solve_right(X) + ....: X = Z/Z.norm() + ....: lam = X.dot_product(A*X) + ....: s = abs(lam - lam_old) + ....: print("{i} s={s} lambda={lam}".format(i=i, s=s, lam=lam)) + ....: lam_old = lam + ....: if s<1.e-10: + ....: break + 1 s=0.56423627407 lambda=0.56423627407 + 2 s=0.00371649959176 lambda=0.560519774478 + 3 s=2.9833340176e-07 lambda=0.560519476145 + 4 s=3.30288019157e-11 lambda=0.560519476112 + sage: X # abs tol 1e-15 + (0.9276845629439007, 0.10329475725387141, -0.3587917847435305) + +Sage example in ./linsolve.tex, line 1724:: + + sage: A*X-lam*X # abs tol 1e-14 + (2.886579864025407e-15, 1.672273430841642e-15, 8.326672684688674e-15) + +Sage example in ./linsolve.tex, line 1801:: + + sage: m = matrix(RDF, [[1,2,3,4],[1,0,2,6],[1,8,4,-2],[1,5,-10,-20]]) + sage: Aref = transpose(m)*m + sage: A = copy(Aref) + sage: for i in range(0,20): + ....: Q, R = A.QR() + ....: A = R*Q + +Sage example in ./linsolve.tex, line 1835:: + + sage: Aref.eigenvalues() # abs tol 1e-12 + [585.0305586200212, 92.91426499150643, 0.03226690899408103, 4.022909479477674] + +Sage example in ./linsolve.tex, line 1895:: + + sage: A = matrix(RDF, [[1,3,2],[1,2,3],[0,5,2]]) + sage: eigen_vals, eigen_vects = A.eigenmatrix_right() + sage: eigen_vals # abs tol 1e-12 + [ 6.39294791648918 0.0 0.0] + [ 0.0 0.560519476111939 0.0] + [ 0.0 0.0 -1.9534673926011215] + sage: eigen_vects # abs tol 2e-15 + [ 0.5424840601106511 0.9276845629439008 0.09834254667424457] + [ 0.5544692861094349 0.10329475725386986 -0.617227053099068] + [ 0.6310902116870117 -0.3587917847435306 0.780614827194734] + +Sage example in ./linsolve.tex, line 1939:: + + sage: def pol2companion(p): + ....: n = len(p) + ....: m = matrix(RDF,n) + ....: for i in range(1,n): + ....: m[i,i-1]=1 + ....: m.set_column(n-1,-p) + ....: return m + +Sage example in ./linsolve.tex, line 1965:: + + sage: q = vector(RDF,[1,-1,2,3,5,-1,10,11]) + sage: comp = pol2companion(q); comp + [ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0] + [ 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0] + [ 0.0 1.0 0.0 0.0 0.0 0.0 0.0 -2.0] + [ 0.0 0.0 1.0 0.0 0.0 0.0 0.0 -3.0] + [ 0.0 0.0 0.0 1.0 0.0 0.0 0.0 -5.0] + [ 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0] + [ 0.0 0.0 0.0 0.0 0.0 1.0 0.0 -10.0] + [ 0.0 0.0 0.0 0.0 0.0 0.0 1.0 -11.0] + sage: roots = comp.eigenvalues(); roots # abs tol 1e-12 + [0.3475215101190289 + 0.5665505533984981*I, 0.3475215101190289 - 0.5665505533984981*I, + 0.34502377696179265 + 0.43990870238588275*I, 0.34502377696179265 - 0.43990870238588275*I, + -0.5172576143252197 + 0.5129582067889322*I, -0.5172576143252197 - 0.5129582067889322*I, + -1.3669971645459291, -9.983578180965276] + +Sage example in ./linsolve.tex, line 2121:: + + sage: reset() + +Sage example in ./linsolve.tex, line 2124:: + + sage: def eval(P,x): + ....: if len(P) == 0: + ....: return 0 + ....: else: + ....: return P[0]+x*eval(P[1:],x) + +Sage example in ./linsolve.tex, line 2133:: + + sage: def pscal(P,Q,lx): + ....: return float(sum(eval(P,s)*eval(Q,s) for s in lx)) + +Sage example in ./linsolve.tex, line 2139:: + + sage: def padd(P,a,Q): + ....: for i in range(0,len(Q)): + ....: P[i] += a*Q[i] + +Sage example in ./linsolve.tex, line 2149:: + + sage: class BadParamsforOrthop(Exception): + ....: def __init__(self, degreeplusone, npoints): + ....: self.deg = degreeplusone - 1 + ....: self.np = npoints + ....: def __str__(self): + ....: return "degree: " + str(self.deg) + \ + ....: " nb. points: " + repr(self.np) + +Sage example in ./linsolve.tex, line 2160:: + + sage: def orthopoly(n,x): + ....: if n > len(x): + ....: raise BadParamsforOrthop(n, len(x)) + ....: orth = [[1./sqrt(float(len(x)))]] + ....: for p in range(1,n): + ....: nextp = copy(orth[p-1]) + ....: nextp.insert(0,0) + ....: s = [] + ....: for i in range(p-1,max(p-3,-1),-1): + ....: s.append(pscal(nextp, orth[i], x)) + ....: j = 0 + ....: for i in range(p-1,max(p-3,-1),-1): + ....: padd(nextp, -s[j], orth[i]) + ....: j += 1 + ....: norm = sqrt(pscal(nextp, nextp, x)) + ....: nextpn = [nextp[i]/norm for i in range(len(nextp))] + ....: orth.append(nextpn) + ....: return orth + +Sage example in ./linsolve.tex, line 2209:: + + sage: set_random_seed(3) # to get reproducible values below + +Sage example in ./linsolve.tex, line 2212:: + + sage: L = 40 + sage: X = [100*float(i)/L for i in range(40)] + sage: Y = [float(1/(1+25*X[i]^2)+0.25*random()) for i in range(40)] + sage: n = 15; orth = orthopoly(n, X) + +Sage example in ./linsolve.tex, line 2222:: + + sage: coeff = [sum(Y[j]*eval(orth[i],X[j]) for j in + ....: range(0,len(X))) for i in range(0,n)] + +Sage example in ./linsolve.tex, line 2230:: + + sage: polmin = [0 for i in range(0,n)] + sage: for i in range(0,n): + ....: padd(polmin, coeff[i], orth[i]) + sage: p = lambda x: eval(polmin, x) + sage: plot(p(x), x, 0, X[len(X)-1]) + Graphics object consisting of 1 graphics primitive + +Sage example in ./linsolve.tex, line 2609:: + + sage: from scipy.sparse.linalg.dsolve import * + sage: from scipy.sparse import lil_matrix + sage: from numpy import array + sage: n = 200 + sage: n2 = n*n + sage: A = lil_matrix((n2, n2)) + sage: h2 = 1./float((n+1)^2) + sage: for i in range(0,n2): + ....: A[i,i]=4*h2+1. + ....: if i+10: A[i,int(i-1)]=-h2 + ....: if i+n=0: A[i,int(i-n)]=-h2 + sage: Acsc = A.tocsc() + sage: b = array([1 for i in range(0,n2)]) + sage: solve = factorized(Acsc) # LU factorization + sage: S = solve(b) # resolution + +Sage example in ./linsolve.tex, line 2784:: + + sage: from numpy.random import seed + sage: seed(0) # to get reproducible values below + +Sage example in ./linsolve.tex, line 2828:: + + sage: from scipy import sparse + sage: from numpy.linalg import * + sage: from numpy import array + sage: from numpy.random import rand + sage: def power(A,x,N): # power iteration + ....: for i in range(N): + ....: y = A*x + ....: z = y/norm(y) + ....: lam = sum(x*y) + ....: s = norm(x-z) + ....: print("{i} s={s} lambda={lam}".format(i=i, s=s, lam=lam)) + ....: if s < 1e-3: + ....: break + ....: x = z + ....: return x + sage: n = 1000 + sage: m = 5 + sage: # build a stochastic matrix of size n + sage: # with m non-zero coefficients per row + sage: A1 = sparse.lil_matrix((n, n)) + sage: for i in range(0,n): + ....: for j in range(0,m): + ....: l = int(n*rand()) + ....: A1[l,i] = rand() + sage: for i in range(0,n): + ....: s = sum(A1[i,0:n]) + ....: A1[i,0:n] /= s + sage: At = A1.transpose().tocsc() + sage: x = array([rand() for i in range(0,n)]) + sage: # compute the dominant eigenvalue + sage: # and the associated eigenvector + sage: y = power(At, x, 5) # rel tol 1e-10 + 0 s=17.0241218112 lambda=235.567796432 + 1 s=0.39337173784 lambda=0.908668201953 + 2 s=0.230865716856 lambda=0.967356896036 + 3 s=0.134156683993 lambda=0.986660315554 + 4 s=0.0789423487458 lambda=0.995424635219 +""" diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py new file mode 100644 index 00000000000..e2bfb72b0ab --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py @@ -0,0 +1,236 @@ +## -*- encoding: utf-8 -*- +""" +This file (./lp_doctest.sage) was *autogenerated* from ./lp.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./lp_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./lp.tex, line 14:: + + sage: set_random_seed(158888) + sage: sage.numerical.backends.generic_backend.default_solver = "Glpk" + +Sage example in ./lp.tex, line 124:: + + sage: p = MixedIntegerLinearProgram() + +Sage example in ./lp.tex, line 137:: + + sage: x, y, z = p['x'], p['y'], p['z'] + sage: p.set_min(x, 0) + sage: p.set_min(y, 0) + sage: p.set_min(z, 0) + +Sage example in ./lp.tex, line 154:: + + sage: p.set_objective( x + y + 3*z ) + +Sage example in ./lp.tex, line 166:: + + sage: p.add_constraint( x + 2*y <= 4 ) + sage: p.add_constraint( 5*z - y <= 8 ) + +Sage example in ./lp.tex, line 180:: + + sage: p.solve() # abs tol 1e-10 + 8.8 + +Sage example in ./lp.tex, line 194:: + + sage: p.get_values(x), p.get_values(y), p.get_values(z) # abs tol 1e-10 + (4.0, 0.0, 1.6) + +Sage example in ./lp.tex, line 214:: + + sage: x = p.new_variable() + +Sage example in ./lp.tex, line 224:: + + sage: p.add_constraint( x[1] + x[12] - x[14] >= 8 ) + +Sage example in ./lp.tex, line 236:: + + sage: p.add_constraint( x["i_am_a_valid_index"] + x["a",pi] <= 3 ) + +Sage example in ./lp.tex, line 248:: + + sage: p.add_constraint( p.sum( + ....: x[i,j] for i in range(4) for j in range(4)) <= 1 ) + +Sage example in ./lp.tex, line 287:: + + sage: p = MixedIntegerLinearProgram() + sage: p.set_objective( p[3] + p[2] ) + sage: p.add_constraint( p[3] <= 5 ) + +Sage example in ./lp.tex, line 293:: + + sage: p.solve() + Traceback (most recent call last): + ... + MIPSolverException: GLPK: The LP (relaxation) problem has no dual feasible solution + +Sage example in ./lp.tex, line 301:: + + sage: p.add_constraint( p[2] <= 8 ) + sage: p.solve() # abs tol 1e-10 + 13.0 + +Sage example in ./lp.tex, line 306:: + + sage: p.add_constraint( p[3] >= 6 ); p.solve() + Traceback (most recent call last): + ... + MIPSolverException: GLPK: Problem has no feasible solution + +Sage example in ./lp.tex, line 319:: + + sage: p = MixedIntegerLinearProgram() + sage: p.set_objective( p[3] ) + sage: p.add_constraint( p[3] <= 4.75 ); p.add_constraint( p[3] >= 4.25 ) + sage: p.solve() # abs tol 1e-10 + 4.75 + sage: p.set_integer(p[3]); p.solve() + Traceback (most recent call last): + ... + MIPSolverException: GLPK: Problem has no feasible solution + +Sage example in ./lp.tex, line 360:: + + sage: try: + ....: p.solve() + ....: print("The problem has a solution!") + ....: except RuntimeError: + ....: print("The problem is infeasible!") + The problem is infeasible! + +Sage example in ./lp.tex, line 429:: + + sage: C = 1 + sage: L = ["Pan", "Book", "Knife", "Flask", "Flashlight"] + sage: w = [0.57,0.35,0.98,0.39,0.08]; u = [0.57,0.26,0.29,0.85,0.23] + sage: weight = {}; utility = {} + sage: for o in L: + ....: weight[o] = w[L.index(o)]; utility[o] = u[L.index(o)] + +Sage example in ./lp.tex, line 451:: + + sage: p = MixedIntegerLinearProgram() + sage: taken = p.new_variable( binary = True ) + sage: p.add_constraint( + ....: p.sum( weight[o] * taken[o] for o in L ) <= C ) + sage: p.set_objective( + ....: p.sum( utility[o] * taken[o] for o in L ) ) + sage: p.solve() # abs tol 1e-10 + 1.4199999999999999 + sage: taken = p.get_values(taken) + +Sage example in ./lp.tex, line 470:: + + sage: sum( weight[o] * taken[o] for o in L ) # abs tol 1e-10 + 0.960000000000000 + +Sage example in ./lp.tex, line 482:: + + sage: taken["Flask"] + 1.0 + +Sage example in ./lp.tex, line 551:: + + sage: g = graphs.PetersenGraph() + sage: p = MixedIntegerLinearProgram() + sage: matching = p.new_variable(binary = True) + +Sage example in ./lp.tex, line 561:: + + sage: p.set_objective(p.sum(matching[e] + ....: for e in g.edges(labels = False))) + +Sage example in ./lp.tex, line 573:: + + sage: for v in g: + ....: p.add_constraint(p.sum(matching[e] + ....: for e in g.edges_incident(v, labels = False)) <= 1) + sage: p.solve() + 5.0 + +Sage example in ./lp.tex, line 586:: + + sage: matching = p.get_values(matching) + sage: sorted(e for e, b in matching.items() if b == 1) + [(0, 1), (2, 3), (4, 9), (5, 7), (6, 8)] + +Sage example in ./lp.tex, line 665:: + + sage: g = graphs.ChvatalGraph() + sage: g = g.minimum_outdegree_orientation() + +Sage example in ./lp.tex, line 669:: + + sage: p = MixedIntegerLinearProgram() + sage: f = p.new_variable() + sage: s, t = 0, 2 + +Sage example in ./lp.tex, line 674:: + + sage: for v in g: + ....: if v == s or v == t: continue + ....: p.add_constraint( + ....: p.sum(f[v,u] for u in g.neighbors_out(v)) == + ....: p.sum(f[u,v] for u in g.neighbors_in(v))) + +Sage example in ./lp.tex, line 681:: + + sage: for e in g.edges(labels = False): p.add_constraint( f[e] <= 1 ) + +Sage example in ./lp.tex, line 684:: + + sage: p.set_objective(p.sum( f[s,u] for u in g.neighbors_out(s))) + +Sage example in ./lp.tex, line 687:: + + sage: p.solve() + 2.0 + +Sage example in ./lp.tex, line 847:: + + sage: g = graphs.Grid2dGraph(4, 6) + sage: p = MixedIntegerLinearProgram() + sage: b = p.new_variable(binary = True) + +Sage example in ./lp.tex, line 861:: + + sage: B = lambda x,y : b[frozenset([x,y])] + +Sage example in ./lp.tex, line 874:: + + sage: for u in g: + ....: p.add_constraint( p.sum( B(u,v) for v in g.neighbors(u) ) == 2 ) + +Sage example in ./lp.tex, line 892:: + + sage: p.solve() + 0.0 + sage: h = Graph() + sage: h.add_edges( [(u,v) for u, v in g.edges(labels = False) + ....: if p.get_values(B(u,v)) == 1.0 ] ) + +Sage example in ./lp.tex, line 906:: + + sage: while not h.is_connected(): + ....: S = h.connected_components()[0] + ....: p.add_constraint( + ....: p.sum( B(u,v) for u,v + ....: in g.edge_boundary(S, labels = False)) + ....: >= 2) + ....: zero = p.solve() + ....: h = Graph() + ....: h.add_edges( [(u,v) for u,v in + ....: g.edges(labels = False) + ....: if p.get_values(B(u,v)) == 1.0 ] ) + +""" + diff --git a/src/sage/tests/french_book/mpoly.py b/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py similarity index 55% rename from src/sage/tests/french_book/mpoly.py rename to src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py index 977d04e2c46..8909b178aef 100644 --- a/src/sage/tests/french_book/mpoly.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py @@ -1,24 +1,29 @@ ## -*- encoding: utf-8 -*- """ -Doctests from French Sage book -Test file for chapter "Systèmes polynomiaux" ("Polynomial systems") +This file (./mpoly_doctest.sage) was *autogenerated* from ./mpoly.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./mpoly_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. -Sage example in ./mpoly.tex, line 35 (in svn rev 1261):: +Sage example in ./mpoly.tex, line 65:: sage: R = PolynomialRing(QQ, 'x,y,z') - sage: x,y,z = R.gens() # donne le n-uplet des indéterminées + sage: x,y,z = R.gens() # gives the tuples of indeterminates -Sage example in ./mpoly.tex, line 40:: +Sage example in ./mpoly.tex, line 78:: sage: R = PolynomialRing(QQ, 'x', 10) -Sage example in ./mpoly.tex, line 44:: +Sage example in ./mpoly.tex, line 84:: sage: x = R.gens() sage: sum(x[i] for i in range(5)) x0 + x1 + x2 + x3 + x4 -Sage example in ./mpoly.tex, line 52:: +Sage example in ./mpoly.tex, line 96:: sage: def test_poly(ring, deg=3): ....: monomials = Subsets( @@ -26,21 +31,21 @@ ....: deg, submultiset=True) ....: return add(mul(m) for m in monomials) -Sage example in ./mpoly.tex, line 59:: +Sage example in ./mpoly.tex, line 103:: - sage: test_poly(QQ['x,y']) + sage: test_poly(QQ['x,y']) # py2 x^3 + x^2*y + x*y^2 + y^3 + x^2 + x*y + y^2 + x + y + 1 - sage: test_poly(QQ['y,x']) + sage: test_poly(QQ['y,x']) # py2 y^3 + y^2*x + y*x^2 + x^3 + y^2 + y*x + x^2 + y + x + 1 - sage: test_poly(QQ['x,y']) == test_poly(QQ['y,x']) + sage: test_poly(QQ['x,y']) == test_poly(QQ['y,x']) # py2 True -Sage example in ./mpoly.tex, line 74:: +Sage example in ./mpoly.tex, line 127:: - sage: test_poly(PolynomialRing(QQ, 'x,y', order='deglex')) + sage: test_poly(PolynomialRing(QQ, 'x,y', order='deglex')) # py2 x^3 + x^2*y + x*y^2 + y^3 + x^2 + x*y + y^2 + x + y + 1 -Sage example in ./mpoly.tex, line 138:: +Sage example in ./mpoly.tex, line 230:: sage: R. = InfinitePolynomialRing(ZZ, order='lex') sage: p = mul(x[k] - y[k] for k in range(2)); p @@ -48,116 +53,121 @@ sage: p + x[100] x_100 + x_1*x_0 - x_1*y_0 - x_0*y_1 + y_1*y_0 -Sage example in ./mpoly.tex, line 188:: +Sage example in ./mpoly.tex, line 343:: sage: R. = QQ[] sage: p = 7*y^2*x^2 + 3*y*x^2 + 2*y*z + x^3 + 6 sage: p.lt() 7*x^2*y^2 -Sage example in ./mpoly.tex, line 196:: +Sage example in ./mpoly.tex, line 358:: sage: p[x^2*y] == p[(2,1,0)] == p[2,1,0] == 3 True -Sage example in ./mpoly.tex, line 202:: +Sage example in ./mpoly.tex, line 366:: sage: p(0, 3, -1) 0 sage: p.subs(x = 1, z = x^2+1) 2*x^2*y + 7*y^2 + 5*y + 7 -Sage example in ./mpoly.tex, line 209:: +Sage example in ./mpoly.tex, line 381:: - sage: print("total={d} (en x)={dx} partiels={ds}" - ....: .format(d=p.degree(), dx=p.degree(x), ds=p.degrees())) - total=4 (en x)=3 partiels=(3, 2, 1) + sage: print("total={d} (in x)={dx} partial={ds}"\ + ....: .format(d=p.degree(), dx=p.degree(x), ds=p.degrees())) + total=4 (in x)=3 partial=(3, 2, 1) -Sage example in ./mpoly.tex, line 255:: +Sage example in ./mpoly.tex, line 441:: sage: R. = QQ[]; p = x^2 + y^2; q = x + y sage: print("({quo})*({q}) + ({rem}) == {p}".format( \ ....: quo=p//q, q=q, rem=p%q, p=p//q*q+p%q)) (-x + y)*(x + y) + (2*x^2) == x^2 + y^2 - sage: p.mod(q) # n'est PAS équivalent à p%q + sage: p.mod(q) # is NOT equivalent to p%q 2*y^2 -Sage example in ./mpoly.tex, line 277:: +Sage example in ./mpoly.tex, line 459:: - sage: k. = GF(9); R. = k[] - sage: (a*x^2*z^2 + x*y*z - y^2).factor(proof=False) - ((a)) * (x*z + (-a - 1)*y) * (x*z + (-a)*y) + sage: R. = QQ[exp(2*I*pi/5)][] + sage: (x^10 + y^5).gcd(x^4 - y^2) + x^2 + y + sage: (x^10 + y^5).factor() + (x^2 + y) * (x^2 + (a^3)*y) * (x^2 + (a^2)*y) * (x^2 + (a)*y) * (x^2 + (-a^3 - a^2 - a - 1)*y) -Sage example in ./mpoly.tex, line 325:: +Sage example in ./mpoly.tex, line 564:: sage: R. = QQ[] sage: J = R.ideal(x^2 * y * z - 18, ....: x * y^3 * z - 24, - ....: x * y * z^4 - 6); + ....: x * y * z^4 - 6) -Sage example in ./mpoly.tex, line 333:: +Sage example in ./mpoly.tex, line 575:: sage: J.dimension() 0 -Sage example in ./mpoly.tex, line 339:: +Sage example in ./mpoly.tex, line 584:: - sage: J.variety() + sage: J.variety() # py2 [{y: 2, z: 1, x: 3}] + sage: J.variety() # py3 + [{z: 1, y: 2, x: 3}] -Sage example in ./mpoly.tex, line 347:: +Sage example in ./mpoly.tex, line 596:: sage: V = J.variety(QQbar) sage: len(V) 17 -Sage example in ./mpoly.tex, line 353:: +Sage example in ./mpoly.tex, line 603:: - sage: V[-3:] - [{z: 0.9324722294043558? - 0.3612416661871530?*I, - y: -1.700434271459229? + 1.052864325754712?*I, - x: 1.337215067329615? - 2.685489874065187?*I}, - {z: 0.9324722294043558? + 0.3612416661871530?*I, + sage: sorted(V, key=str)[-3:] + [{z: 0.9324722294043558? + 0.3612416661871530?*I, y: -1.700434271459229? - 1.052864325754712?*I, x: 1.337215067329615? + 2.685489874065187?*I}, - {z: 1, y: 2, x: 3}] + {z: 0.9324722294043558? - 0.3612416661871530?*I, + y: -1.700434271459229? + 1.052864325754712?*I, + x: 1.337215067329615? - 2.685489874065187?*I}, + {z: 1, y: 2, x: 3}] -Sage example in ./mpoly.tex, line 364:: +Sage example in ./mpoly.tex, line 619:: sage: (xx, yy, zz) = QQbar['x,y,z'].gens() - sage: [ pt[xx].degree() for pt in V ] - [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 1] + sage: sorted([pt[xx].degree() for pt in V]) + [1, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16] -Sage example in ./mpoly.tex, line 376:: +Sage example in ./mpoly.tex, line 640:: sage: Set(tuple(abs(pt[i]) for i in (xx,yy,zz)) for pt in V) {(3, 2, 1)} -Sage example in ./mpoly.tex, line 387:: +Sage example in ./mpoly.tex, line 662:: - sage: w = QQbar.zeta(17); w # racine primitive de 1 + sage: w = QQbar.zeta(17); w # primitive root of 1 0.9324722294043558? + 0.3612416661871530?*I sage: Set(pt[zz] for pt in V) == Set(w^i for i in range(17)) True -Sage example in ./mpoly.tex, line 401:: +Sage example in ./mpoly.tex, line 690:: - sage: set(pt[zz].minpoly() for pt in V[:-1]) + sage: set(pt[zz].minpoly() for pt in sorted(V, key=str)[:-1]) {x^16 + x^15 + x^14 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1} -Sage example in ./mpoly.tex, line 413:: +Sage example in ./mpoly.tex, line 706:: sage: def polar_form(z): ....: rho = z.abs(); rho.simplify() ....: theta = 2 * pi * z.rational_argument() ....: return (SR(rho) * exp(I*theta)) - sage: [tuple(polar_form(pt[i]) for i in [xx,yy,zz]) - ....: for pt in V[-3:]] - [(3*e^(-6/17*I*pi), 2*e^(14/17*I*pi), e^(-2/17*I*pi)), - (3*e^(6/17*I*pi), 2*e^(-14/17*I*pi), e^(2/17*I*pi)), (3, 2, 1)] + sage: sorted([tuple(polar_form(pt[i]) for i in [xx,yy,zz]) + ....: for pt in sorted(V, key=str)[-3:]]) + [(3*e^(6/17*I*pi), 2*e^(-14/17*I*pi), e^(2/17*I*pi)), + (3*e^(-6/17*I*pi), 2*e^(14/17*I*pi), e^(-2/17*I*pi)), + (3, 2, 1)] -Sage example in ./mpoly.tex, line 432:: +Sage example in ./mpoly.tex, line 733:: sage: J.triangular_decomposition() [Ideal (z^17 - 1, y - 2*z^10, x - 3*z^3) of Multivariate @@ -165,12 +175,12 @@ sage: J.transformed_basis() [z^17 - 1, -2*z^10 + y, -3/4*y^2 + x] -Sage example in ./mpoly.tex, line 534:: +Sage example in ./mpoly.tex, line 909:: sage: R. = QQ[] sage: J = R.ideal(x^2 + y^2 - 1, 16*x^2*y^2 - 1) -Sage example in ./mpoly.tex, line 539:: +Sage example in ./mpoly.tex, line 917:: sage: ybar2 = R.quo(J)(y^2) sage: [ybar2^i for i in range(3)] @@ -178,34 +188,34 @@ sage: ((ybar2 + 1)^2).lift() 3*y^2 + 15/16 -Sage example in ./mpoly.tex, line 561:: +Sage example in ./mpoly.tex, line 958:: sage: u = (16*y^4 - 16*y^2 + 1).lift(J); u [16*y^2, -1] sage: u[0]*J.0 + u[1]*J.1 16*y^4 - 16*y^2 + 1 -Sage example in ./mpoly.tex, line 569:: +Sage example in ./mpoly.tex, line 968:: sage: (y^4).mod(J) y^2 - 1/16 -Sage example in ./mpoly.tex, line 575:: +Sage example in ./mpoly.tex, line 978:: sage: (y^4).reduce([x^2 + y^2 - 1, 16*x^2*y^2 - 1]) y^4 -Sage example in ./mpoly.tex, line 629:: +Sage example in ./mpoly.tex, line 1047:: sage: 1 in ideal(x^2+y^2-1, (x-4)^2+y^2-1) False -Sage example in ./mpoly.tex, line 634:: +Sage example in ./mpoly.tex, line 1056:: sage: R(1).lift(ideal(x^2+y^2-1, (x-4)^2+y^2-1, x-y)) [-1/28*y + 1/14, 1/28*y + 1/14, -1/7*x + 1/7*y + 4/7] -Sage example in ./mpoly.tex, line 650:: +Sage example in ./mpoly.tex, line 1079:: sage: J1 = (x^2 + y^2 - 1, 16*x^2*y^2 - 1)*R sage: J2 = (x^2 + y^2 - 1, 4*x^2*y^2 - 1)*R @@ -217,13 +227,13 @@ sage: 2*y^2 - 1 in J2 False -Sage example in ./mpoly.tex, line 680:: +Sage example in ./mpoly.tex, line 1122:: sage: C = ideal(x^2 + y^2 - 1); H = ideal(16*x^2*y^2 - 1) sage: C + H == J1 True -Sage example in ./mpoly.tex, line 697:: +Sage example in ./mpoly.tex, line 1151:: sage: CH = C.intersection(H).quotient(ideal(4*x*y-1)); CH Ideal (4*x^3*y + 4*x*y^3 + x^2 - 4*x*y + y^2 - 1) of @@ -231,107 +241,133 @@ sage: CH.gen(0).factor() (4*x*y + 1) * (x^2 + y^2 - 1) -Sage example in ./mpoly.tex, line 705:: +Sage example in ./mpoly.tex, line 1161:: sage: H.quotient(C) == H True -Sage example in ./mpoly.tex, line 720:: +Sage example in ./mpoly.tex, line 1184:: sage: [J.dimension() for J in [J1, J2, C, H, H*J2, J1+J2]] [0, 0, 1, 1, 1, -1] -Sage example in ./mpoly.tex, line 780:: +Sage example in ./mpoly.tex, line 1285:: sage: R. = QQ[] sage: J = ideal(2*x+y-2*z, 2*x+2*y+z-1) sage: J.elimination_ideal(x) Ideal (y + 3*z - 1) of Multivariate Polynomial Ring in x, y, z over Rational Field - sage: J.elimination_ideal([x,y]).gens() - [0] + sage: J.elimination_ideal([x,y]) + Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field + +Sage example in ./mpoly.tex, line 1312:: + + sage: R. = QQ[] + sage: J1 = ideal(x^2 + y^2 - 1, 16*x^2*y^2 - 1) -Sage example in ./mpoly.tex, line 794:: +Sage example in ./mpoly.tex, line 1328:: - sage: J1.gens() - [x^2 + y^2 - 1, 16*x^2*y^2 - 1] + sage: g = J1.elimination_ideal(y).gens(); g + [16*x^4 - 16*x^2 + 1] + sage: SR(g[0]).solve(SR(x)) # solves by radicals + [x == -1/2*sqrt(sqrt(3) + 2), x == 1/2*sqrt(sqrt(3) + 2), + x == -1/2*sqrt(-sqrt(3) + 2), x == 1/2*sqrt(-sqrt(3) + 2)] -Sage example in ./mpoly.tex, line 858:: +Sage example in ./mpoly.tex, line 1351:: + + sage: C.elimination_ideal(y).gens() + [0] + sage: H.elimination_ideal(y).gens() + [0] + +Sage example in ./mpoly.tex, line 1431:: sage: R. = QQ[] sage: Param = R.ideal((1-t^2)-(1+t^2)*x, 2*t-(1+t^2)*y) -Sage example in ./mpoly.tex, line 863:: +Sage example in ./mpoly.tex, line 1437:: sage: Param.elimination_ideal(t).gens() [x^2 + y^2 - 1] -Sage example in ./mpoly.tex, line 886:: +Sage example in ./mpoly.tex, line 1469:: sage: R. = QQ[] sage: eq = x^2 + (y-t)^2 - 1/2*(t^2+1) sage: fig = add((eq(t=k/5)*QQ[x,y]).plot() for k in (-15..15)) - sage: fig.show(aspect_ratio=1,xmin=-2,xmax=2,ymin=-3,ymax=3) + sage: fig.show(aspect_ratio=1, xmin=-2, xmax=2, ymin=-3, ymax=3) -Sage example in ./mpoly.tex, line 900:: +Sage example in ./mpoly.tex, line 1494:: sage: env = ideal(eq, eq.derivative(t)).elimination_ideal(t) sage: env.gens() [2*x^2 - 2*y^2 - 1] -Sage example in ./mpoly.tex, line 906:: +Sage example in ./mpoly.tex, line 1502:: - sage: env.change_ring(QQ[x,y]).plot() + sage: env.change_ring(QQ[x,y]).plot((x,-2,2),(y,-3,3)) Graphics object consisting of 1 graphics primitive -Sage example in ./mpoly.tex, line 933:: +Sage example in ./mpoly.tex, line 1538:: sage: R. = QQ[] sage: J = (y-t*x, y-t*(1-x))*R sage: (x^2+y^2) - ((1-x)^2+y^2) in J False -Sage example in ./mpoly.tex, line 942:: +Sage example in ./mpoly.tex, line 1553:: sage: R. = QQ[] sage: J = (y-t*x, y-t*(1-x), t*u-1)*R sage: (x^2+y^2) - ((1-x)^2+y^2) in J True -Sage example in ./mpoly.tex, line 965:: +Sage example in ./mpoly.tex, line 1615:: sage: R. = QQ[] -Sage example in ./mpoly.tex, line 968:: +Sage example in ./mpoly.tex, line 1618:: sage: eq.derivative(t).resultant(eq, t) x^2 - y^2 - 1/2 -Sage example in ./mpoly.tex, line 982:: +Sage example in ./mpoly.tex, line 1636:: + + sage: R. = QQ[] + sage: p = y^2 - x; q = y^2 + x + sage: p.resultant(q, y) + 4*x^2 + sage: ideal(p, q).elimination_ideal(y) + Ideal (x) of Multivariate Polynomial Ring in x, y over Rational Field + +Sage example in ./mpoly.tex, line 1665:: sage: R. = QQ[] sage: ((x^2 + y^2)*(x^2 + y^2 + 1)*R).dimension() 1 -Sage example in ./mpoly.tex, line 996:: +Sage example in ./mpoly.tex, line 1690:: + sage: R. = QQ[] + sage: J1 = (x^2 + y^2 - 1, 16*x^2*y^2 - 1)*R sage: J1.variety() [] -Sage example in ./mpoly.tex, line 1002:: +Sage example in ./mpoly.tex, line 1705:: sage: J1.variety(QQbar)[0:2] [{y: -0.9659258262890683?, x: -0.2588190451025208?}, {y: -0.9659258262890683?, x: 0.2588190451025208?}] -Sage example in ./mpoly.tex, line 1037:: +Sage example in ./mpoly.tex, line 1759:: sage: R. = PolynomialRing(QQ, order='lex') sage: C = ideal(x^2+y^2-1) sage: D = ideal((x+y-1)*(x+y+1)) sage: J = C + D -Sage example in ./mpoly.tex, line 1054:: +Sage example in ./mpoly.tex, line 1786:: sage: J.triangular_decomposition() [Ideal (y, x^2 - 1) of Multivariate Polynomial Ring in x, y @@ -339,112 +375,119 @@ Ideal (y^2 - 1, x) of Multivariate Polynomial Ring in x, y over Rational Field] -Sage example in ./mpoly.tex, line 1094:: +Sage example in ./mpoly.tex, line 1840:: sage: D = ideal((x+2*y-1)*(x+2*y+1)); J = C + D sage: J.variety() - [{y: -4/5, x: 3/5}, {y: 0, x: -1}, {y: 0, x: 1}, {y: 4/5, x: -3/5}] - sage: [ T.gens() for T in J.triangular_decomposition()] + [{y: 0, x: 1}, {y: 0, x: -1}, {y: 4/5, x: -3/5}, {y: -4/5, x: 3/5}] + sage: [T.gens() for T in J.triangular_decomposition()] [[y, x^2 - 1], [25*y^2 - 16, 4*x + 3*y]] -Sage example in ./mpoly.tex, line 1104:: +Sage example in ./mpoly.tex, line 1855:: sage: Jy = J.elimination_ideal(x); Jy.gens() [25*y^3 - 16*y] -Sage example in ./mpoly.tex, line 1109:: +Sage example in ./mpoly.tex, line 1863:: sage: ys = QQ['y'](Jy.0).roots(); ys [(4/5, 1), (0, 1), (-4/5, 1)] sage: QQ['x'](J.1(y=ys[0][0])).roots() [(-3/5, 1), (-13/5, 1)] -Sage example in ./mpoly.tex, line 1119 (edited manually):: +Sage example in ./mpoly.tex, line 1882:: - sage: ys = CDF['y'](Jy.0).roots(); ys # abs tol 3e-16 - [(-0.8000000000000002, 1), (0.0, 1), (0.8, 1)] - sage: [CDF['x'](p(y=ys[0][0])).roots() for p in J.gens()] # abs tol 1e-14 - [[(-0.5999999999999999 - 1.306289919090511e-16*I, 1), (0.6000000000000001 + 1.3062899190905113e-16*I, 1)], [(0.6000000000000001 - 3.135095805817224e-16*I, 1), (2.600000000000001 + 3.1350958058172237e-16*I, 1)]] + sage: ys = CDF['y'](Jy.0).roots(); ys # abs tol 2e-15 + [(-0.8, 1), (0.0, 1), (0.8, 1)] + sage: [CDF['x'](p(y=ys[0][0])).roots() for p in J.gens()] # abs tol 2e-15 + [[(-0.5999999999999999, 1), (0.6000000000000001, 1)], [(0.6000000000000001, 1), (2.600000000000001, 1)]] -Sage example in ./mpoly.tex, line 1135:: +Sage example in ./mpoly.tex, line 1911:: sage: R. = QQ[]; J = ideal([ x^7-(100*x-1)^2, y-x^7+1 ]) + sage: J.variety(RealField(51)) + [{y: 396340.890166545, x: -14.1660266425312}] -Sage example in ./mpoly.tex, line 1138:: +Sage example in ./mpoly.tex, line 1923:: - sage: J.variety(AA) + sage: J.variety(AA) # py2 [{x: 0.00999999900000035?, y: -0.999999999999990?}, {x: 0.01000000100000035?, y: -0.999999999999990?}, {x: 6.305568998641385?, y: 396340.8901665450?}] + sage: J.variety(AA) # py3 + [{y: -0.999999999999990?, x: 0.00999999900000035?}, + {y: -0.999999999999990?, x: 0.01000000100000035?}, + {y: 396340.8901665450?, x: 6.305568998641385?}] + -Sage example in ./mpoly.tex, line 1170:: +Sage example in ./mpoly.tex, line 1983:: sage: len(J2.variety(QQbar)), J2.vector_space_dimension() (4, 8) -Sage example in ./mpoly.tex, line 1177:: +Sage example in ./mpoly.tex, line 1993:: sage: J2.normal_basis() [x*y^3, y^3, x*y^2, y^2, x*y, y, x, 1] -Sage example in ./mpoly.tex, line 1325:: +Sage example in ./mpoly.tex, line 2187:: sage: R. = PolynomialRing(QQ, order='lex') -Sage example in ./mpoly.tex, line 1343:: +Sage example in ./mpoly.tex, line 2243:: sage: ((x+y+z)^2).reduce([x-t, y-t^2, z^2-t]) 2*z*t^2 + 2*z*t + t^4 + 2*t^3 + t^2 + t -Sage example in ./mpoly.tex, line 1364:: +Sage example in ./mpoly.tex, line 2298:: sage: R. = PolynomialRing(QQ, order='lex') sage: (g, h) = (x-y, x-y^2); p = x*y - x - sage: p.reduce([g, h]) # deux réductions par h + sage: p.reduce([g, h]) # two reductions by h y^3 - y^2 - sage: p.reduce([h, g]) # deux réductions par g + sage: p.reduce([h, g]) # two reductions by g y^2 - y -Sage example in ./mpoly.tex, line 1373:: +Sage example in ./mpoly.tex, line 2311:: sage: p - y*g + h 0 -Sage example in ./mpoly.tex, line 1572:: +Sage example in ./mpoly.tex, line 2575:: sage: R. = PolynomialRing(QQ, order='lex') sage: R.ideal(x*y^4, x^2*y^3, x^4*y, x^5).basis_is_groebner() True -Sage example in ./mpoly.tex, line 1578:: +Sage example in ./mpoly.tex, line 2584:: sage: R.ideal(x^2+y^2-1, 16*x^2*y^2-1).basis_is_groebner() False -Sage example in ./mpoly.tex, line 1593:: +Sage example in ./mpoly.tex, line 2610:: sage: R.ideal(x^2+y^2-1, 16*x^2*y^2-1).groebner_basis() [x^2 + y^2 - 1, y^4 - y^2 + 1/16] -Sage example in ./mpoly.tex, line 1598:: +Sage example in ./mpoly.tex, line 2618:: sage: R.ideal(16*x^2*y^2-1).groebner_basis() [x^2*y^2 - 1/16] -Sage example in ./mpoly.tex, line 1603:: +Sage example in ./mpoly.tex, line 2626:: sage: R.ideal(x^2+y^2-1, (x+y)^2-1).groebner_basis() [x^2 + y^2 - 1, x*y, y^3 - y] -Sage example in ./mpoly.tex, line 1609:: +Sage example in ./mpoly.tex, line 2636:: sage: R_lex. = PolynomialRing(QQ, order='lex') - sage: J_lex = (x*y+x+y^2+1,x^2*y+x*y^2+1)*R_lex; J_lex.gens() + sage: J_lex = (x*y+x+y^2+1, x^2*y+x*y^2+1)*R_lex; J_lex.gens() [x*y + x + y^2 + 1, x^2*y + x*y^2 + 1] sage: J_lex.groebner_basis() [x - 1/2*y^3 + y^2 + 3/2, y^4 - y^3 - 3*y - 1] -Sage example in ./mpoly.tex, line 1616:: +Sage example in ./mpoly.tex, line 2644:: sage: R_invlex = PolynomialRing(QQ, 'x,y', order='invlex') sage: J_invlex = J_lex.change_ring(R_invlex); J_invlex.gens() @@ -452,7 +495,7 @@ sage: J_invlex.groebner_basis() [y^2 + x*y + x + 1, x^2 + x - 1] -Sage example in ./mpoly.tex, line 1623:: +Sage example in ./mpoly.tex, line 2651:: sage: R_drl = PolynomialRing(QQ, 'x,y', order='degrevlex') sage: J_drl = J_lex.change_ring(R_drl); J_drl.gens() @@ -460,28 +503,28 @@ sage: J_drl.groebner_basis() [y^3 - 2*y^2 - 2*x - 3, x^2 + x - 1, x*y + y^2 + x + 1] -Sage example in ./mpoly.tex, line 1662:: +Sage example in ./mpoly.tex, line 2719:: sage: p = (x + y)^5 sage: J_lex.reduce(p) 17/2*y^3 - 12*y^2 + 4*y - 49/2 -Sage example in ./mpoly.tex, line 1668:: +Sage example in ./mpoly.tex, line 2726:: sage: p.reduce(J_lex.groebner_basis()) 17/2*y^3 - 12*y^2 + 4*y - 49/2 -Sage example in ./mpoly.tex, line 1673:: +Sage example in ./mpoly.tex, line 2732:: sage: R_lex.quo(J_lex)(p) 17/2*ybar^3 - 12*ybar^2 + 4*ybar - 49/2 -Sage example in ./mpoly.tex, line 1678:: +Sage example in ./mpoly.tex, line 2738:: sage: R_drl.quo(J_drl)(p) 5*ybar^2 + 17*xbar + 4*ybar + 1 -Sage example in ./mpoly.tex, line 1685:: +Sage example in ./mpoly.tex, line 2751:: sage: J_lex.normal_basis() [y^3, y^2, y, 1] @@ -490,37 +533,37 @@ sage: J_drl.normal_basis() [y^2, y, x, 1] -Sage example in ./mpoly.tex, line 1701:: +Sage example in ./mpoly.tex, line 2775:: sage: ideal(16*x^2*y^2-1).dimension() 1 -Sage example in ./mpoly.tex, line 1736:: +Sage example in ./mpoly.tex, line 2851:: sage: R. = PolynomialRing(QQ, order='lex') - sage: J = R.ideal( t+x+y+z-1, t^2-x^2-y^2-z^2-1, t-x*y) + sage: J = R.ideal(t+x+y+z-1, t^2-x^2-y^2-z^2-1, t-x*y) sage: [u.polynomial(u.variable(0)) for u in J.groebner_basis()] [t + x + y + z - 1, (y + 1)*x + y + z - 1, (z - 2)*x + y*z - 2*y - 2*z + 1, (z - 2)*y^2 + (-2*z + 1)*y - z^2 + z - 1] -Sage example in ./mpoly.tex, line 1801:: +Sage example in ./mpoly.tex, line 2970:: sage: from sage.rings.ideal import Cyclic sage: Cyclic(QQ['x,y,z']) Ideal (x + y + z, x*y + x*z + y*z, x*y*z - 1) of Multivariate Polynomial Ring in x, y, z over Rational Field -Sage example in ./mpoly.tex, line 1808:: +Sage example in ./mpoly.tex, line 2980:: sage: def C(R, n): return Cyclic(PolynomialRing(R, 'x', n)) -Sage example in ./mpoly.tex, line 1822:: +Sage example in ./mpoly.tex, line 3010:: sage: p = previous_prime(2^30) sage: len(C(GF(p), 6).groebner_basis()) 45 """ -from sage.all_cmdline import * # import sage library + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py new file mode 100644 index 00000000000..9fcb4a1aade --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py @@ -0,0 +1,492 @@ +## -*- encoding: utf-8 -*- +""" +This file (./nonlinear_doctest.sage) was *autogenerated* from ./nonlinear.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./nonlinear_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./nonlinear.tex, line 102:: + + sage: R. = PolynomialRing(RealField(prec=10)) + sage: p = 2*x^7 - 21*x^6 + 64*x^5 - 67*x^4 + 90*x^3 \ + ....: + 265*x^2 - 900*x + 375 + sage: p.roots() + [(-1.7, 1), (0.50, 1), (1.7, 1), (5.0, 2)] + sage: p.roots(ring=ComplexField(10), multiplicities=False) + [-1.7, 0.50, 1.7, 5.0, -2.2*I, 2.2*I] + sage: p.roots(ring=RationalField()) + [(1/2, 1), (5, 2)] + +Sage example in ./nonlinear.tex, line 246:: + + sage: R. = PolynomialRing(QQ, 'x') + sage: p = x^4 + x^3 + x^2 + x + 1 + sage: K. = p.root_field() + sage: p.roots(ring=K, multiplicities=None) + [alpha, alpha^2, alpha^3, -alpha^3 - alpha^2 - alpha - 1] + sage: alpha^5 + 1 + +Sage example in ./nonlinear.tex, line 309:: + + sage: R. = PolynomialRing(RR, 'x') + sage: d = ZZ.random_element(1, 15) + sage: p = R.random_element(d) + sage: p.degree() == sum(r[1] for r in p.roots(CC)) + True + +Sage example in ./nonlinear.tex, line 348:: + + sage: def build_complex_roots(degree): + ....: R. = PolynomialRing(CDF, 'x') + ....: v = [] + ....: for c in cartesian_product([[-1, 1]] * (degree + 1)): + ....: v.extend(R(list(c)).roots(multiplicities=False)) + ....: return v + sage: data = build_complex_roots(12) # long time + sage: points(data, pointsize=1, aspect_ratio=1) # long time + Graphics object consisting of 1 graphics primitive + +Sage example in ./nonlinear.tex, line 420:: + + sage: a, b, c, x = var('a, b, c, x') + sage: p = a * x^2 + b * x + c + sage: type(p) + <... 'sage.symbolic.expression.Expression'> + sage: p.parent() + Symbolic Ring + sage: p.roots(x) + [(-1/2*(b + sqrt(b^2 - 4*a*c))/a, 1), + (-1/2*(b - sqrt(b^2 - 4*a*c))/a, 1)] + +Sage example in ./nonlinear.tex, line 450:: + + sage: a, b, c, d, e, f, x = var('a, b, c, d, e, f, x') + sage: p = a*x^5+b*x^4+c*x^3+d*x^2+e*x+f + sage: p.roots(x) + Traceback (most recent call last): + ... + RuntimeError: no explicit roots found + +Sage example in ./nonlinear.tex, line 467:: + + sage: x, a, b, c, d = var('x, a, b, c, d') + sage: P = a * x^3 + b * x^2 + c * x + d + sage: alpha = var('alpha') + sage: P.subs(x = x + alpha).expand().coefficient(x, 2) + 3*a*alpha + b + sage: P.subs(x = x - b / (3 * a)).expand().collect(x) + a*x^3 - 1/3*(b^2/a - 3*c)*x + 2/27*b^3/a^2 - 1/3*b*c/a + d + +Sage example in ./nonlinear.tex, line 482:: + + sage: p, q, u, v = var('p, q, u, v') + sage: P = x^3 + p * x + q + sage: P.subs(x = u + v).expand() + u^3 + 3*u^2*v + 3*u*v^2 + v^3 + p*u + p*v + q + +Sage example in ./nonlinear.tex, line 498:: + + sage: P.subs({x: u + v, q: -u^3 - v^3}).factor() + (3*u*v + p)*(u + v) + sage: P.subs({x: u+v, q: -u^3 - v^3, p: -3 * u * v}).expand() + 0 + sage: X = var('X') + sage: solve([X^2 + q*X - p^3 / 27 == 0], X, solution_dict=True) + [{X: -1/2*q - 1/18*sqrt(12*p^3 + 81*q^2)}, + {X: -1/2*q + 1/18*sqrt(12*p^3 + 81*q^2)}] + +Sage example in ./nonlinear.tex, line 539:: + + sage: e = sin(x) * (x^3 + 1) * (x^5 + x^4 + 1) + sage: roots = e.roots(); len(roots) + 9 + sage: roots + [(0, 1), + (-1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3), + 1), + (-1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(-I*sqrt(3) + 1) - 1/6*(I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3), + 1), + ((1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3) + 1/3/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3), + 1), + (-1/2*I*sqrt(3) - 1/2, 1), + (1/2*I*sqrt(3) - 1/2, 1), + (1/2*I*sqrt(3)*(-1)^(1/3) - 1/2*(-1)^(1/3), 1), + (-1/2*I*sqrt(3)*(-1)^(1/3) - 1/2*(-1)^(1/3), 1), + ((-1)^(1/3), 1)] + +Sage example in ./nonlinear.tex, line 620:: + + sage: alpha, m, x = var('alpha, m, x'); q = function('q')(x) + sage: p = (x - alpha)^m * q + sage: p.derivative(x) + (-alpha + x)^(m - 1)*m*q(x) + (-alpha + x)^m*diff(q(x), x) + sage: simplify(p.derivative(x)(x=alpha)) + 0 + +Sage example in ./nonlinear.tex, line 659:: + + sage: R. = PolynomialRing(QQ, 'x') + sage: p = 128 * x^13 - 1344 * x^12 + 6048 * x^11 - 15632 * x^10 \ + ....: + 28056 * x^9 - 44604 * x^8 + 71198 * x^7 - 98283 * x^6 \ + ....: + 105840 * x^5 - 101304 * x^4 + 99468 * x^3 - 81648 * x^2 \ + ....: + 40824 * x - 8748 + sage: d = gcd(p, p.derivative()) + sage: (p // d).degree() + 4 + sage: roots = SR(p // d).roots(multiplicities=False) + sage: roots + [1/2*I*sqrt(3)*2^(1/3) - 1/2*2^(1/3), + -1/2*I*sqrt(3)*2^(1/3) - 1/2*2^(1/3), + 2^(1/3), + 3/2] + sage: [QQbar(p(alpha)).is_zero() for alpha in roots] # long time + [True, True, True, True] + +Sage example in ./nonlinear.tex, line 732:: + + sage: R. = PolynomialRing(RR, 'x') + sage: p = x^7 - 131/3*x^6 + 1070/3*x^5 - 2927/3*x^4 \ + ....: + 2435/3*x^3 - 806/3*x^2 + 3188/3*x - 680 + sage: l = [c for c in p.coefficients(sparse=False) if not c.is_zero()] + sage: sign_changes = [l[i]*l[i+1] < 0 for i in range(len(l)-1)].count(True) + sage: real_positive_roots = \ + ....: sum([alpha[1] if alpha[0] > 0 else 0 for alpha in p.roots()]) + sage: sign_changes, real_positive_roots + (7, 5) + +Sage example in ./nonlinear.tex, line 831:: + + sage: def count_sign_changes(p): + ....: l = [c for c in p if not c.is_zero()] + ....: changes = [l[i]*l[i + 1] < 0 for i in range(len(l) - 1)] + ....: return changes.count(True) + +Sage example in ./nonlinear.tex, line 837:: + + sage: def sturm(p, a, b): + ....: assert p.degree() > 2 + ....: assert not (p(a) == 0) + ....: assert not (p(b) == 0) + ....: assert a <= b + ....: remains = [p, p.derivative()] + ....: for i in range(p.degree() - 1): + ....: remains.append(-(remains[i] % remains[i + 1])) + ....: evals = [[], []] + ....: for q in remains: + ....: evals[0].append(q(a)) + ....: evals[1].append(q(b)) + ....: return count_sign_changes(evals[0]) \ + ....: - count_sign_changes(evals[1]) + +Sage example in ./nonlinear.tex, line 857:: + + sage: R. = PolynomialRing(QQ, 'x') + sage: p = (x - 34) * (x - 5) * (x - 3) * (x - 2) * (x - 2/3) + sage: sturm(p, 1, 4) + 2 + sage: sturm(p, 1, 10) + 3 + sage: sturm(p, 1, 200) + 4 + sage: p.roots(multiplicities=False) + [34, 5, 3, 2, 2/3] + sage: sturm(p, 1/2, 35) + 5 + +Sage example in ./nonlinear.tex, line 949:: + + sage: f(x) = 4 * sin(x) - exp(x) / 2 + 1 + sage: a, b = RR(-pi), RR(pi) + sage: bool(f(a) * f(b) < 0) + True + +Sage example in ./nonlinear.tex, line 961:: + + sage: solve(f(x) == 0, x) + [sin(x) == 1/8*e^x - 1/4] + +Sage example in ./nonlinear.tex, line 966:: + + sage: f.roots() + Traceback (most recent call last): + ... + RuntimeError: no explicit roots found + +Sage example in ./nonlinear.tex, line 991:: + + sage: a, b = RR(-pi), RR(pi) + sage: g = plot(f, a, b, rgbcolor='blue') + +Sage example in ./nonlinear.tex, line 1045:: + + sage: def phi(s, t): return (s + t) / 2 + sage: def intervalgen(f, phi, s, t): + ....: msg = 'Wrong arguments: f({0})*f({1})>=0)'.format(s, t) + ....: assert (f(s) * f(t) < 0), msg + ....: yield s + ....: yield t + ....: while True: + ....: u = phi(s, t) + ....: yield u + ....: if f(u) * f(s) < 0: + ....: t = u + ....: else: + ....: s = u + +Sage example in ./nonlinear.tex, line 1152:: + + sage: a, b + (-3.14159265358979, 3.14159265358979) + sage: bisection = intervalgen(f, phi, a, b) + sage: next(bisection) + -3.14159265358979 + sage: next(bisection) + 3.14159265358979 + sage: next(bisection) + 0.000000000000000 + +Sage example in ./nonlinear.tex, line 1178:: + + sage: from types import GeneratorType, FunctionType + sage: def checklength(u, v, w, prec): + ....: return abs(v - u) < 2 * prec + sage: def iterate(series, check=checklength, prec=10^-5, maxit=100): + ....: assert isinstance(series, GeneratorType) + ....: assert isinstance(check, FunctionType) + ....: niter = 2 + ....: v, w = next(series), next(series) + ....: while niter <= maxit: + ....: niter += 1 + ....: u, v, w = v, w, next(series) + ....: if check(u, v, w, prec): + ....: print('After {0} iterations: {1}'.format(niter, w)) + ....: return + ....: print('Failed after {0} iterations'.format(maxit)) + +Sage example in ./nonlinear.tex, line 1221:: + + sage: bisection = intervalgen(f, phi, a, b) + sage: iterate(bisection) + After 22 iterations: 2.15847275559132 + +Sage example in ./nonlinear.tex, line 1313:: + + sage: phi(s, t) = s - f(s) * (t - s) / (f(t) - f(s)) + sage: falsepos = intervalgen(f, phi, a, b) + sage: iterate(falsepos) + After 8 iterations: -2.89603757331027 + +Sage example in ./nonlinear.tex, line 1320:: + + sage: a, b = RR(-pi), RR(pi) + sage: g = plot(f, a, b, rgbcolor='blue') + sage: phi(s, t) = s - f(s) * (t - s) /(f(t) - f(s)) + sage: falsepos = intervalgen(f, phi, a, b) + sage: u, v, w = next(falsepos), next(falsepos), next(falsepos) + sage: niter = 3 + sage: while niter < 9: + ....: g += line([(u, 0), (u, f(u))], rgbcolor='red', + ....: linestyle=':') + ....: g += line([(u, f(u)), (v, f(v))], rgbcolor='red') + ....: g += line([(v, 0), (v, f(v))], rgbcolor='red', + ....: linestyle=':') + ....: g += point((w, 0), rgbcolor='red') + ....: if (f(u) * f(w)) < 0: + ....: u, v = u, w + ....: else: + ....: u, v = w, v + ....: w = next(falsepos) + ....: niter += 1 + +Sage example in ./nonlinear.tex, line 1361:: + + sage: a, b = RR(pi/2), RR(pi) + sage: phi(s, t) = t - f(t) * (s - t) / (f(s) - f(t)) + sage: falsepos = intervalgen(f, phi, a, b) + sage: phi(s, t) = (s + t) / 2 + sage: bisection = intervalgen(f, phi, a, b) + sage: iterate(falsepos) + After 15 iterations: 2.15846441170219 + sage: iterate(bisection) + After 20 iterations: 2.15847275559132 + +Sage example in ./nonlinear.tex, line 1373:: + + sage: a, b = RR(pi/2), RR(pi) + sage: g = plot(f, a, b, rgbcolor='blue') + sage: phi(s, t) = t - f(t) * (s - t) / (f(s) - f(t)) + sage: falsepos = intervalgen(f, phi, a, b) + sage: u, v, w = next(falsepos), next(falsepos), next(falsepos) + sage: niter = 3 + sage: while niter < 7: + ....: g += line([(u, 0), (u, f(u))], rgbcolor='red', + ....: linestyle=':') + ....: g += line([(u, f(u)), (v, f(v))], rgbcolor='red') + ....: g += line([(v, 0), (v, f(v))], rgbcolor='red', + ....: linestyle=':') + ....: g += point((w, 0), rgbcolor='red') + ....: if (f(u) * f(w)) < 0: + ....: u, v = u, w + ....: else: + ....: u, v = w, v + ....: w = next(falsepos) + ....: niter += 1 + +Sage example in ./nonlinear.tex, line 1477:: + + sage: f.derivative() + x |--> 4*cos(x) - 1/2*e^x + sage: a, b = RR(pi/2), RR(pi) + +Sage example in ./nonlinear.tex, line 1501:: + + sage: def newtongen(f, u): + ....: while True: + ....: yield u + ....: u -= f(u) / f.derivative()(u) + sage: def checkconv(u, v, w, prec): + ....: return abs(w - v) / abs(w) <= prec + +Sage example in ./nonlinear.tex, line 1513:: + + sage: iterate(newtongen(f, a), check=checkconv) + After 6 iterations: 2.15846852566756 + +Sage example in ./nonlinear.tex, line 1518:: + + sage: generator = newtongen(f, a) + sage: g = plot(f, a, b, rgbcolor='blue') + sage: u, v = next(generator), next(generator) + sage: niter = 2 + sage: while niter < 6: + ....: g += point((u, 0), rgbcolor='red') + ....: g += line([(u, 0), (u, f(u))], rgbcolor='red', + ....: linestyle=':') + ....: g += line([(u, f(u)), (v, 0)], rgbcolor='red') + ....: u, v = v, next(generator) + ....: niter += 1 + +Sage example in ./nonlinear.tex, line 1583:: + + sage: def secantgen(f, a): + ....: yield a + ....: estimate = f.derivative()(a) + ....: b = a - f(a) / estimate + ....: yield b + ....: while True: + ....: fa, fb = f(a), f(b) + ....: if fa == fb: + ....: estimate = f.derivative()(a) + ....: else: + ....: estimate = (fb - fa) / (b - a) + ....: a = b + ....: b -= fb / estimate + ....: yield b + +Sage example in ./nonlinear.tex, line 1609:: + + sage: iterate(secantgen(f, a), check=checkconv) + After 8 iterations: 2.15846852557553 + +Sage example in ./nonlinear.tex, line 1621:: + + sage: g = plot(f, a, b, rgbcolor='blue') + sage: sequence = secantgen(f, a) + sage: u, v = next(sequence), next(sequence) + sage: niter = 2 + sage: while niter < 6: + ....: g += point((u, 0), rgbcolor='red') + ....: g += line([(u, 0), (u, f(u))], rgbcolor='red', + ....: linestyle=':') + ....: g += line([(u, f(u)), (v, 0)], rgbcolor='red') + ....: u, v = v, next(sequence) + ....: niter += 1 + +Sage example in ./nonlinear.tex, line 1697:: + + sage: from collections import deque + sage: basering = PolynomialRing(CC, 'x') + sage: def quadraticgen(f, r, s): + ....: t = (r + s) / 2 + ....: yield t + ....: points = deque([(r,f(r)), (s,f(s)), (t,f(t))], maxlen=3) + ....: while True: + ....: pol = basering.lagrange_polynomial(points) + ....: roots = pol.roots(ring=CC, multiplicities=False) + ....: u = min(roots, key=lambda x: abs(x - points[2][0])) + ....: points.append((u, f(u))) + ....: yield points[2][0] + +Sage example in ./nonlinear.tex, line 1742:: + + sage: generator = quadraticgen(f, a, b) + sage: iterate(generator, check=checkconv) + After 5 iterations: 2.15846852554764 + +Sage example in ./nonlinear.tex, line 1851:: + + sage: for ring in [ZZ, QQ, QQbar, RDF, RIF, RR, AA, CDF, CIF, CC]: + ....: print("{0:50} {1}".format(str(ring), ring.is_exact())) + Integer Ring True + Rational Field True + Algebraic Field True + Real Double Field False + Real Interval Field with 53 bits of precision False + Real Field with 53 bits of precision False + Algebraic Real Field True + Complex Double Field False + Complex Interval Field with 53 bits of precision False + Complex Field with 53 bits of precision False + +Sage example in ./nonlinear.tex, line 2031:: + + sage: def steffensen(sequence): + ....: assert isinstance(sequence, GeneratorType) + ....: values = deque(maxlen=3) + ....: for i in range(3): + ....: values.append(next(sequence)) + ....: yield values[i] + ....: while True: + ....: values.append(next(sequence)) + ....: u, v, w = values + ....: yield u - (v - u)^2 / (w - 2 * v + u) + +Sage example in ./nonlinear.tex, line 2047:: + + sage: g(x) = sin(x^2 - 2) * (x^2 - 2) + sage: sequence = newtongen(g, RR(0.7)) + sage: accelseq = steffensen(newtongen(g, RR(0.7))) + sage: iterate(sequence, check=checkconv) + After 17 iterations: 1.41422192763287 + sage: iterate(accelseq, check=checkconv) + After 10 iterations: 1.41421041980166 + +Sage example in ./nonlinear.tex, line 2062:: + + sage: sequence = newtongen(f, RR(a)) + sage: accelseq = steffensen(newtongen(f, RR(a))) + sage: iterate(sequence, check=checkconv) + After 6 iterations: 2.15846852566756 + sage: iterate(accelseq, check=checkconv) + After 7 iterations: 2.15846852554764 + +Sage example in ./nonlinear.tex, line 2124:: + + sage: result = (f == 0).find_root(a, b, full_output=True) + sage: result[0], result[1].iterations + (2.1584685255476415, 9) + +Sage example in ./nonlinear.tex, line 2183:: + + sage: a, b = pi/2, pi + sage: generator = newtongen(f, a) + sage: next(generator); next(generator) + 1/2*pi + 1/2*pi - (e^(1/2*pi) - 10)*e^(-1/2*pi) + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py new file mode 100644 index 00000000000..d161d0d208f --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py @@ -0,0 +1,157 @@ +## -*- encoding: utf-8 -*- +""" +This file (./numbertheory_doctest.sage) was *autogenerated* from ./numbertheory.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./numbertheory_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./numbertheory.tex, line 107:: + + sage: a = IntegerModRing(15)(3); b = IntegerModRing(17)(3); a, b + (3, 3) + sage: a == b + False + +Sage example in ./numbertheory.tex, line 135:: + + sage: R = a.parent(); R + Ring of integers modulo 15 + sage: R.characteristic() + 15 + +Sage example in ./numbertheory.tex, line 157:: + + sage: a + a, a - 17, a * a + 1, a^3 + (6, 1, 10, 12) + +Sage example in ./numbertheory.tex, line 199:: + + sage: z = a.lift(); y = ZZ(a); y, type(y), y == z + (3, <... 'sage.rings.integer.Integer'>, True) + +Sage example in ./numbertheory.tex, line 228:: + + sage: [Mod(x,15).additive_order() for x in range(0,15)] + [1, 15, 15, 5, 15, 3, 5, 15, 15, 5, 3, 15, 5, 15, 15] + +Sage example in ./numbertheory.tex, line 261:: + + sage: [[x, Mod(x,15).multiplicative_order()] + ....: for x in range(1,15) if gcd(x,15) == 1] + [[1, 1], [2, 4], [4, 2], [7, 4], [8, 4], [11, 2], [13, 4], [14, 2]] + +Sage example in ./numbertheory.tex, line 276:: + + sage: p = 10^20 + 39; mod(2,p).multiplicative_order() + 50000000000000000019 + sage: mod(3,p).multiplicative_order() + 100000000000000000038 + +Sage example in ./numbertheory.tex, line 367:: + + sage: R = GF(17); [1/R(x) for x in range(1,17)] + [1, 9, 6, 13, 7, 3, 5, 15, 2, 12, 14, 10, 4, 11, 8, 16] + +Sage example in ./numbertheory.tex, line 403:: + + sage: R = GF(9,name='x'); R + Finite Field in x of size 3^2 + +Sage example in ./numbertheory.tex, line 409:: + + sage: R.polynomial() + x^2 + 2*x + 2 + +Sage example in ./numbertheory.tex, line 423:: + + sage: Set([r for r in R]) + {0, 1, 2, x, x + 1, x + 2, 2*x, 2*x + 1, 2*x + 2} + +Sage example in ./numbertheory.tex, line 429:: + + sage: Q. = PolynomialRing(GF(3)) + sage: R2 = GF(9, name='x', modulus=x^2+1); R2 + Finite Field in x of size 3^2 + +Sage example in ./numbertheory.tex, line 463:: + + sage: p = R(x+1); R2(p) + Traceback (most recent call last): + ... + TypeError: unable to coerce from a finite field other than the prime subfield + +Sage example in ./numbertheory.tex, line 548:: + + sage: rational_reconstruction(411,1000) + -13/17 + sage: rational_reconstruction(409,1000) + Traceback (most recent call last): + ... + ArithmeticError: rational reconstruction of 409 (mod 1000) does not exist + +Sage example in ./numbertheory.tex, line 571:: + + sage: def harmonic(n): + ....: return add([1/x for x in range(1,n+1)]) + +Sage example in ./numbertheory.tex, line 593:: + + sage: def harmonic_mod(n,m): + ....: return add([1/x % m for x in range(1,n+1)]) + sage: def harmonic2(n): + ....: q = lcm(range(1,n+1)) + ....: pmax = RR(q*(log(n)+1)) + ....: m = ZZ(2*pmax^2) + ....: m = ceil(m/q)*q + 1 + ....: a = harmonic_mod(n,m) + ....: return rational_reconstruction(a,m) + +Sage example in ./numbertheory.tex, line 707:: + + sage: a = 2; b = 3; m = 5; n = 7; lambda0 = (b-a)/m % n; a + lambda0 * m + 17 + sage: crt(2,3,5,7) + 17 + +Sage example in ./numbertheory.tex, line 726:: + + sage: def harmonic3(n): + ....: q = lcm(range(1,n+1)) + ....: pmax = RR(q*(log(n)+1)) + ....: B = ZZ(2*pmax^2) + ....: a = 0; m = 1; p = 2^63 + ....: while m < B: + ....: p = next_prime(p) + ....: b = harmonic_mod(n,p) + ....: a = crt(a,b,m,p) + ....: m = m*p + ....: return rational_reconstruction(a,m) + sage: harmonic(100) == harmonic3(100) + True + +Sage example in ./numbertheory.tex, line 755:: + + sage: crt(15,1,30,4) + 45 + sage: crt(15,2,30,4) + Traceback (most recent call last): + ... + ValueError: No solution to crt problem since gcd(30,4) does not divide 15-2 + +Sage example in ./numbertheory.tex, line 1008:: + + sage: [560 % (x-1) for x in [3,11,17]] + [0, 0, 0] + +Sage example in ./numbertheory.tex, line 1226:: + + sage: p = 10^10+19; a = mod(17,p); a.log(2) + 6954104378 + sage: mod(2,p)^6954104378 + 17 + +""" + diff --git a/src/sage/tests/french_book/polynomes.py b/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py similarity index 58% rename from src/sage/tests/french_book/polynomes.py rename to src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py index 593fcd68239..ecea49862ef 100644 --- a/src/sage/tests/french_book/polynomes.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py @@ -1,52 +1,57 @@ ## -*- encoding: utf-8 -*- """ -Doctests from French Sage book -Test file for chapter "Polynômes" ("Polynomials") +This file (./polynomes_doctest.sage) was *autogenerated* from ./polynomes.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./polynomes_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. -Sage example in ./polynomes.tex, line 55 (in svn rev 1261):: +Sage example in ./polynomes.tex, line 97:: sage: x = var('x'); p = (2*x+1)*(x+2)*(x^4-1) - sage: print("{} est de degré {}".format(p, p.degree(x))) - (x^4 - 1)*(2*x + 1)*(x + 2) est de degré 6 + sage: print("{} is of degree {}".format(p, p.degree(x))) + (x^4 - 1)*(2*x + 1)*(x + 2) is of degree 6 -Sage example in ./polynomes.tex, line 69:: +Sage example in ./polynomes.tex, line 123:: sage: x = polygen(QQ, 'x'); p = (2*x+1)*(x+2)*(x^4-1) - sage: print("{} est de degré {}".format(p, p.degree())) - 2*x^6 + 5*x^5 + 2*x^4 - 2*x^2 - 5*x - 2 est de degré 6 + sage: print("{} is of degree {}".format(p, p.degree())) + 2*x^6 + 5*x^5 + 2*x^4 - 2*x^2 - 5*x - 2 is of degree 6 -Sage example in ./polynomes.tex, line 97:: +Sage example in ./polynomes.tex, line 167:: sage: R = PolynomialRing(QQ, 'x') sage: x = R.gen() -Sage example in ./polynomes.tex, line 104:: +Sage example in ./polynomes.tex, line 182:: sage: x.parent() Univariate Polynomial Ring in x over Rational Field -Sage example in ./polynomes.tex, line 125:: +Sage example in ./polynomes.tex, line 223:: sage: x = polygen(QQ, 'y'); y = polygen(QQ, 'x') -Sage example in ./polynomes.tex, line 128:: +Sage example in ./polynomes.tex, line 226:: sage: x^2 + 1 y^2 + 1 sage: (y^2 + 1).parent() Univariate Polynomial Ring in x over Rational Field -Sage example in ./polynomes.tex, line 135:: +Sage example in ./polynomes.tex, line 233:: sage: Q. = QQ[]; p = x + 1; x = 2; p = p + x -Sage example in ./polynomes.tex, line 154:: +Sage example in ./polynomes.tex, line 268:: sage: R. = QQ[]; p = (x+y+z*t)^2 sage: p.polynomial(t).reverse() (x^2 + 2*x*y + y^2)*t^2 + (2*x*z + 2*y*z)*t + z^2 -Sage example in ./polynomes.tex, line 162:: +Sage example in ./polynomes.tex, line 281:: sage: x = polygen(QQ); y = polygen(QQ[x], 'y') sage: p = x^3 + x*y + y + y^2; p @@ -56,38 +61,46 @@ sage: QQ['x']['y'](q) y^2 + (x + 1)*y + x^3 -Sage example in ./polynomes.tex, line 217:: +Sage example in ./polynomes.tex, line 355:: sage: def rook_polynomial(n, var='x'): ....: return ZZ[var]([binomial(n, k)^2 * factorial(k) ....: for k in (0..n) ]) -Sage example in ./polynomes.tex, line 259:: +Sage example in ./polynomes.tex, line 452:: sage: x = polygen(QQ) sage: p = x^2 - 16*x + 3 sage: p.factor() x^2 - 16*x + 3 - sage: p.change_ring(RDF).factor() - (x - 15.8102496...) * (x - 0.189750324...) + sage: p.change_ring(RDF).factor() # abs tol 2e-15 + (x - 15.810249675906654) * (x - 0.18975032409334563) -Sage example in ./polynomes.tex, line 270:: +Sage example in ./polynomes.tex, line 476:: sage: p.change_ring(GF(3)) x^2 + 2*x -Sage example in ./polynomes.tex, line 317:: +Sage example in ./polynomes.tex, line 511:: + + sage: QQi. = QQ[I] # myI is the i of QQi, I that of SR + sage: R. = QQi[]; p = (x + 2*myI)^3; p + x^3 + 6*I*x^2 - 12*x - 8*I + sage: p.map_coefficients(lambda z: z.conjugate()) + x^3 - 6*I*x^2 - 12*x + 8*I + +Sage example in ./polynomes.tex, line 536:: sage: list(GF(2)['x'].polynomials(of_degree=2)) [x^2, x^2 + 1, x^2 + x, x^2 + x + 1] -Sage example in ./polynomes.tex, line 326:: +Sage example in ./polynomes.tex, line 551:: sage: A = QQ['x'] sage: A.is_ring() and A.is_noetherian() True -Sage example in ./polynomes.tex, line 332:: +Sage example in ./polynomes.tex, line 559:: sage: ZZ.is_subring(A) True @@ -95,12 +108,12 @@ ....: if Integers(n)['x'].is_integral_domain()] [0, 2, 3, 5, 7, 11, 13, 17, 19] -Sage example in ./polynomes.tex, line 395:: +Sage example in ./polynomes.tex, line 646:: sage: R. = Integers(42)[]; (t^20-1) % (t^5+8*t+7) 22*t^4 + 14*t^3 + 14*t + 6 -Sage example in ./polynomes.tex, line 407:: +Sage example in ./polynomes.tex, line 666:: sage: ((t^2+t)//t).parent() Univariate Polynomial Ring in t over Ring of integers modulo 42 @@ -109,80 +122,102 @@ ... TypeError: self must be an integral domain. -Sage example in ./polynomes.tex, line 420:: +Sage example in ./polynomes.tex, line 685:: sage: x = polygen(QQ); [chebyshev_T(n, x) for n in (0..4)] [1, x, 2*x^2 - 1, 4*x^3 - 3*x, 8*x^4 - 8*x^2 + 1] -Sage example in ./polynomes.tex, line 436:: +Sage example in ./polynomes.tex, line 712:: sage: S. = ZZ[]; p = 2*(x^10-1)*(x^8-1) sage: p.gcd(p.derivative()) 2*x^2 - 2 -Sage example in ./polynomes.tex, line 447:: +Sage example in ./polynomes.tex, line 736:: + + sage: R. = QQ[]; p = x^5-1; q = x^3-1 + sage: print("the gcd is %s = (%s)*p + (%s)*q" % p.xgcd(q)) + the gcd is x - 1 = (-x)*p + (x^3 + 1)*q + +Sage example in ./polynomes.tex, line 773:: + + sage: R. = QQ[] + sage: J1 = (x^2 - 2*x + 1, 2*x^2 + x - 3)*R; J1 + Principal ideal (x - 1) of Univariate Polynomial Ring in x + over Rational Field + +Sage example in ./polynomes.tex, line 782:: + + sage: J2 = R.ideal(x^5 + 2) + sage: ((3*x+5)*J1*J2).reduce(x^10) + 421/81*x^6 - 502/81*x^5 + 842/81*x - 680/81 + +Sage example in ./polynomes.tex, line 800:: - sage: R. = QQ[]; p = (x^5-1); q = (x^3-1) - sage: print("le pgcd est %s = (%s)*p + (%s)*q" % p.xgcd(q)) - le pgcd est x - 1 = (-x)*p + (x^3 + 1)*q + sage: B = R.quo((3*x+5)*J1*J2) # quo automatically names 'xbar' which is + sage: B(x^10) # the generator of B image of x + 421/81*xbar^6 - 502/81*xbar^5 + 842/81*xbar - 680/81 + sage: B(x^10).lift() + 421/81*x^6 - 502/81*x^5 + 842/81*x - 680/81 -Sage example in ./polynomes.tex, line 484:: +Sage example in ./polynomes.tex, line 920:: sage: R. = QQ[]; p = 3*x^2 - 6 sage: p.is_irreducible(), p.change_ring(ZZ).is_irreducible() (True, False) -Sage example in ./polynomes.tex, line 527:: +Sage example in ./polynomes.tex, line 976:: sage: x = polygen(ZZ); p = 54*x^4+36*x^3-102*x^2-72*x-12 sage: p.factor() 2 * 3 * (3*x + 1)^2 * (x^2 - 2) -Sage example in ./polynomes.tex, line 533:: +Sage example in ./polynomes.tex, line 997:: sage: for A in [QQ, ComplexField(16), GF(5), QQ[sqrt(2)]]: - ....: print("{} :".format(A)); print(A['x'](p).factor()) - Rational Field : + ....: print(str(A) + ":") + ....: print(A['x'](p).factor()) + Rational Field: (54) * (x + 1/3)^2 * (x^2 - 2) - Complex Field with 16 bits of precision : + Complex Field with 16 bits of precision: (54.00) * (x - 1.414) * (x + 0.3333)^2 * (x + 1.414) - Finite Field of size 5 : + Finite Field of size 5: (4) * (x + 2)^2 * (x^2 + 3) - Number Field in sqrt2 with defining polynomial x^2 - 2 : + Number Field in sqrt2 with defining polynomial x^2 - 2: (54) * (x - sqrt2) * (x + sqrt2) * (x + 1/3)^2 -Sage example in ./polynomes.tex, line 601:: +Sage example in ./polynomes.tex, line 1100:: sage: R. = ZZ[]; p = (2*x^2-5*x+2)^2 * (x^4-7); p.roots() [(2, 2)] -Sage example in ./polynomes.tex, line 608:: +Sage example in ./polynomes.tex, line 1113:: sage: p.roots(QQ) [(2, 2), (1/2, 2)] sage: p.roots(Zp(19, print_max_terms=3)) [(7 + 16*19 + 17*19^2 + ... + O(19^20), 1), - (12 + 2*19 + 19^2 + ... + O(19^20), 1), - (10 + 9*19 + 9*19^2 + ... + O(19^20), 2), - (2 + O(19^20), 2)] + (12 + 2*19 + 19^2 + ... + O(19^20), 1), + (10 + 9*19 + 9*19^2 + ... + O(19^20), 2), + (2 + O(19^20), 2)] -Sage example in ./polynomes.tex, line 623:: +Sage example in ./polynomes.tex, line 1137:: - sage: racines = p.roots(AA); racines + sage: roots = p.roots(AA); roots [(-1.626576561697786?, 1), (0.500000000000000?, 2), (1.626576561697786?, 1), (2.000000000000000?, 2)] -Sage example in ./polynomes.tex, line 629:: +Sage example in ./polynomes.tex, line 1153:: - sage: a = racines[0][0]^4; a.simplify(); a + sage: a = roots[0][0]^4; a.simplify(); a 7 -Sage example in ./polynomes.tex, line 646:: +Sage example in ./polynomes.tex, line 1208:: sage: x = polygen(ZZ); (x-12).resultant(x-20) -8 -Sage example in ./polynomes.tex, line 701:: +Sage example in ./polynomes.tex, line 1295:: sage: R. = QQ[]; x = polygen(R); p = a*x^2+b*x+c sage: p.resultant(p.derivative()) @@ -192,28 +227,7 @@ sage: (a*x^3 + b*x^2 + c*x + d).discriminant() b^2*c^2 - 4*a*c^3 - 4*b^3*d + 18*a*b*c*d - 27*a^2*d^2 -Sage example in ./polynomes.tex, line 770:: - - sage: R. = QQ[] - sage: J1 = (x^2 - 2*x + 1, 2*x^2 + x - 3)*R; J1 - Principal ideal (x - 1) of Univariate Polynomial Ring in x - over Rational Field - -Sage example in ./polynomes.tex, line 778:: - - sage: J2 = R.ideal(x^5 + 2) - sage: ((3*x+5)*J1*J2).reduce(x^10) - 421/81*x^6 - 502/81*x^5 + 842/81*x - 680/81 - -Sage example in ./polynomes.tex, line 785:: - - sage: B = R.quo((3*x+5)*J1*J2) # quo nomme automatiquement 'xbar' - sage: B(x^10) # le générateur de B image de x - 421/81*xbar^6 - 502/81*xbar^5 + 842/81*xbar - 680/81 - sage: B(x^10).lift() - 421/81*x^6 - 502/81*x^5 + 842/81*x - 680/81 - -Sage example in ./polynomes.tex, line 856:: +Sage example in ./polynomes.tex, line 1399:: sage: x = polygen(RR); r = (1 + x)/(1 - x^2); r.parent() Fraction Field of Univariate Polynomial Ring in x over Real @@ -221,37 +235,34 @@ sage: r (x + 1.00000000000000)/(-x^2 + 1.00000000000000) -Sage example in ./polynomes.tex, line 864:: +Sage example in ./polynomes.tex, line 1416:: - sage: r.reduce(); r - -1.00000000000000/(x - 1.00000000000000) + % for the doctests + sage: r.reduce(); repr(r) in ['1.00000000000000/(-x + 1.00000000000000)', '-1.00000000000000/(x - 1.00000000000000)'] + True -Sage example in ./polynomes.tex, line 907:: +Sage example in ./polynomes.tex, line 1492:: - sage: R. = QQ[]; r = x^10/((x^2-1)^2*(x^2+3)) + sage: R. = QQ[]; r = x^10 / ((x^2-1)^2 * (x^2+3)) sage: poly, parts = r.partial_fraction_decomposition() sage: poly x^4 - x^2 + 6 - sage: for part in parts: print(part.factor()) + sage: for part in parts: part.factor() (17/32) * (x - 1)^-1 (1/16) * (x - 1)^-2 (-17/32) * (x + 1)^-1 (1/16) * (x + 1)^-2 (-243/16) * (x^2 + 3)^-1 -Sage example in ./polynomes.tex, line 931:: +Sage example in ./polynomes.tex, line 1531:: sage: C = ComplexField(15) sage: Frac(C['x'])(r).partial_fraction_decomposition() - (x^4 - x^2 + 6.000, - [0.5312/(x - 1.000), - 0.06250/(x^2 - 2.000*x + 1.000), - 4.385*I/(x - 1.732*I), - (-4.385*I)/(x + 1.732*I), - (-0.5312)/(x + 1.000), - 0.06250/(x^2 + 2.000*x + 1.000)]) + (x^4 - x^2 + 6.000, [0.5312/(x - 1.000), 0.06250/(x^2 - 2.000*x + 1.000), + 4.385*I/(x - 1.732*I), (-4.385*I)/(x + 1.732*I), + (-0.5312)/(x + 1.000), 0.06250/(x^2 + 2.000*x + 1.000)]) -Sage example in ./polynomes.tex, line 966:: +Sage example in ./polynomes.tex, line 1600:: sage: A = Integers(101); R. = A[] sage: f6 = sum( (i+1)^2 * x^i for i in (0..5) ); f6 @@ -259,24 +270,24 @@ sage: num, den = f6.rational_reconstruct(x^6, 1, 3); num/den (100*x + 100)/(x^3 + 98*x^2 + 3*x + 100) -Sage example in ./polynomes.tex, line 974:: +Sage example in ./polynomes.tex, line 1611:: sage: S = PowerSeriesRing(A, 'x', 7); S(num)/S(den) 1 + 4*x + 9*x^2 + 16*x^3 + 25*x^4 + 36*x^5 + 49*x^6 + O(x^7) -Sage example in ./polynomes.tex, line 1015:: +Sage example in ./polynomes.tex, line 1672:: sage: x = var('x'); s = tan(x).taylor(x, 0, 20) sage: p = previous_prime(2^30); ZpZx = Integers(p)['x'] sage: Qx = QQ['x'] -Sage example in ./polynomes.tex, line 1020:: +Sage example in ./polynomes.tex, line 1677:: sage: num, den = ZpZx(s).rational_reconstruct(ZpZx(x)^10,4,5) sage: num/den (1073741779*x^3 + 105*x)/(x^4 + 1073741744*x^2 + 105) -Sage example in ./polynomes.tex, line 1026:: +Sage example in ./polynomes.tex, line 1685:: sage: def lift_sym(a): ....: m = a.parent().defining_ideal().gen() @@ -284,23 +295,23 @@ ....: if n <= m // 2: return n ....: else: return n - m -Sage example in ./polynomes.tex, line 1034:: +Sage example in ./polynomes.tex, line 1694:: - sage: Qx([lift_sym(a) for a in num]) / Qx([lift_sym(b) for b in den]) + sage: Qx(list(map(lift_sym, num)))/Qx(list(map(lift_sym, den))) (-10*x^3 + 105*x)/(x^4 - 45*x^2 + 105) -Sage example in ./polynomes.tex, line 1042:: +Sage example in ./polynomes.tex, line 1713:: sage: def mypade(pol, n, k): ....: x = ZpZx.gen(); ....: n,d = ZpZx(pol).rational_reconstruct(x^n, k-1, n-k) - ....: return Qx([lift_sym(a) for a in n]) / Qx([lift_sym(b) for b in d]) + ....: return Qx(list(map(lift_sym, n)))/Qx(list(map(lift_sym, d))) -Sage example in ./polynomes.tex, line 1109:: +Sage example in ./polynomes.tex, line 1813:: sage: R. = PowerSeriesRing(QQ) -Sage example in ./polynomes.tex, line 1126:: +Sage example in ./polynomes.tex, line 1845:: sage: R. = QQ[[]] sage: f = 1 + x + O(x^2); g = x + 2*x^2 + O(x^4) @@ -309,34 +320,34 @@ sage: f * g x + 3*x^2 + O(x^3) -Sage example in ./polynomes.tex, line 1136:: +Sage example in ./polynomes.tex, line 1857:: sage: (1 + x^3).prec() +Infinity -Sage example in ./polynomes.tex, line 1141:: +Sage example in ./polynomes.tex, line 1865:: sage: R. = PowerSeriesRing(Reals(24), default_prec=4) sage: 1/(1 + RR.pi() * x)^2 1.00000 - 6.28319*x + 29.6088*x^2 - 124.025*x^3 + O(x^4) -Sage example in ./polynomes.tex, line 1148:: +Sage example in ./polynomes.tex, line 1877:: sage: R. = QQ[[]] sage: 1 + x + O(x^2) == 1 + x + x^2 + O(x^3) True -Sage example in ./polynomes.tex, line 1158:: +Sage example in ./polynomes.tex, line 1893:: - sage: (1/(1+x)).sqrt().integral().exp()/x^2 + O(x^4) + sage: (1/(1+x)).sqrt().integral().exp() / x^2 + O(x^4) x^-2 + x^-1 + 1/4 + 1/24*x - 1/192*x^2 + 11/1920*x^3 + O(x^4) -Sage example in ./polynomes.tex, line 1178:: +Sage example in ./polynomes.tex, line 1940:: sage: (1+x^2).sqrt().solve_linear_de(prec=6, b=x.exp()) 1 + 2*x + 3/2*x^2 + 5/6*x^3 + 1/2*x^4 + 7/30*x^5 + O(x^6) -Sage example in ./polynomes.tex, line 1186:: +Sage example in ./polynomes.tex, line 1957:: sage: S. = PowerSeriesRing(QQ, default_prec=5) sage: f = S(1) @@ -349,38 +360,38 @@ 1 + x + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + O(x^5) 1 + x + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + O(x^5) -Sage example in ./polynomes.tex, line 1233:: +Sage example in ./polynomes.tex, line 2028:: sage: L. = LazyPowerSeriesRing(QQ) sage: lazy_exp = x.exponential(); lazy_exp O(1) -Sage example in ./polynomes.tex, line 1239:: +Sage example in ./polynomes.tex, line 2039:: sage: lazy_exp[5] 1/120 sage: lazy_exp 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + O(x^6) -Sage example in ./polynomes.tex, line 1247:: +Sage example in ./polynomes.tex, line 2062:: - sage: f = L(1) # la série paresseuse constante 1 + sage: f = L(1) # the constant lazy series 1 sage: for i in range(5): ....: f = (x*f).exponential() - ....: f.compute_coefficients(5) # force le calcul des - ....: print(f) # premiers coefficients + ....: f.compute_coefficients(5) # forces the computation + ....: print(f) # of the first coefficients 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + O(x^6) 1 + x + 3/2*x^2 + 5/3*x^3 + 41/24*x^4 + 49/30*x^5 + O(x^6) 1 + x + 3/2*x^2 + 8/3*x^3 + 101/24*x^4 + 63/10*x^5 + O(x^6) 1 + x + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + 49/5*x^5 + O(x^6) 1 + x + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + 54/5*x^5 + O(x^6) -Sage example in ./polynomes.tex, line 1264:: +Sage example in ./polynomes.tex, line 2091:: sage: f[7] 28673/630 -Sage example in ./polynomes.tex, line 1271:: +Sage example in ./polynomes.tex, line 2105:: sage: from sage.combinat.species.series import LazyPowerSeries sage: f = LazyPowerSeries(L, name='f') @@ -388,11 +399,11 @@ sage: f.coefficients(8) [1, 1, 3/2, 8/3, 125/24, 54/5, 16807/720, 16384/315] -Sage example in ./polynomes.tex, line 1309:: +Sage example in ./polynomes.tex, line 2158:: sage: R = PolynomialRing(ZZ, 'x', sparse=True) sage: p = R.cyclotomic_polynomial(2^50); p, p.derivative() (x^562949953421312 + 1, 562949953421312*x^562949953421311) """ -from sage.all_cmdline import * # import sage library + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py new file mode 100644 index 00000000000..7b8218b4899 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py @@ -0,0 +1,182 @@ +## -*- encoding: utf-8 -*- +""" +This file (./premierspas_doctest.sage) was *autogenerated* from ./premierspas.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./premierspas_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./premierspas.tex, line 589:: + + sage: 1+1 + 2 + +Sage example in ./premierspas.tex, line 645:: + + sage: ( 1 + 2 * (3 + 5) ) * 2 + 34 + +Sage example in ./premierspas.tex, line 656:: + + sage: 2^3 + 8 + sage: 2**3 + 8 + +Sage example in ./premierspas.tex, line 664:: + + sage: 20/6 + 10/3 + +Sage example in ./premierspas.tex, line 700:: + + sage: 20.0 / 14 + 1.42857142857143 + +Sage example in ./premierspas.tex, line 724:: + + sage: numerical_approx(20/14, digits=60) + 1.42857142857142857142857142857142857142857142857142857142857 + +Sage example in ./premierspas.tex, line 792:: + + sage: 20 // 6 + 3 + sage: 20 % 6 + 2 + +Sage example in ./premierspas.tex, line 818:: + + sage: factor(2^(2^5)+1) + 641 * 6700417 + +Sage example in ./premierspas.tex, line 952:: + + sage: sin(pi) + 0 + sage: tan(pi/3) + sqrt(3) + sage: arctan(1) + 1/4*pi + sage: exp(2 * I * pi) + 1 + +Sage example in ./premierspas.tex, line 967:: + + sage: arccos(sin(pi/3)) + arccos(1/2*sqrt(3)) + sage: sqrt(2) + sqrt(2) + sage: exp(I*pi/7) + e^(1/7*I*pi) + +Sage example in ./premierspas.tex, line 987:: + + sage: simplify(arccos(sin(pi/3))) + 1/6*pi + +Sage example in ./premierspas.tex, line 1000:: + + sage: numerical_approx(6*arccos(sin(pi/3)), digits=60) + 3.14159265358979323846264338327950288419716939937510582097494 + sage: numerical_approx(sqrt(2), digits=60) + 1.41421356237309504880168872420969807856967187537694807317668 + +Sage example in ./premierspas.tex, line 1139:: + + sage: y = 1 + 2 + +Sage example in ./premierspas.tex, line 1144:: + + sage: y + 3 + sage: (2 + y) * y + 15 + +Sage example in ./premierspas.tex, line 1156:: + + sage: y = 1 + 2; y + 3 + +Sage example in ./premierspas.tex, line 1168:: + + sage: y = 3 * y + 1; y + 10 + sage: y = 3 * y + 1; y + 31 + sage: y = 3 * y + 1; y + 94 + +Sage example in ./premierspas.tex, line 1208:: + + sage: pi = -I/2 + sage: exp(2*I*pi) + e + +Sage example in ./premierspas.tex, line 1217:: + + sage: from sage.all import pi + +Sage example in ./premierspas.tex, line 1224:: + + sage: restore() + +Sage example in ./premierspas.tex, line 1267:: + + sage: z = SR.var('z') + sage: 2*z + 3 + 2*z + 3 + +Sage example in ./premierspas.tex, line 1290:: + + sage: y = SR.var('z') + sage: 2*y + 3 + 2*z + 3 + +Sage example in ./premierspas.tex, line 1306:: + + sage: c = 2 * y + 3 + sage: z = 1 + sage: 2*y + 3 + 2*z + 3 + sage: c + 2*z + 3 + +Sage example in ./premierspas.tex, line 1318:: + + sage: x = SR.var('x') + sage: expr = sin(x); expr + sin(x) + sage: expr(x=1) + sin(1) + +Sage example in ./premierspas.tex, line 1332:: + + sage: u = SR.var('u') + sage: u = u+1 + sage: u = u+1 + sage: u + u + 2 + +Sage example in ./premierspas.tex, line 1347:: + + sage: x = SR.var('x', 100) + sage: (x[0] + x[1])*x[99] + (x0 + x1)*x99 + +Sage example in ./premierspas.tex, line 1357:: + + sage: var('a, b, c, x, y') + (a, b, c, x, y) + sage: a * x + b * y + c + a*x + b*y + c + +Sage example in ./premierspas.tex, line 1380:: + + sage: var('bla') + bla + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py new file mode 100644 index 00000000000..3ad8f36758d --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py @@ -0,0 +1,683 @@ +## -*- encoding: utf-8 -*- +""" +This file (./programmation_doctest.sage) was *autogenerated* from ./programmation.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./programmation_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./programmation.tex, line 118:: + + sage: 2*3; 3*4; 4*5 # one comment, 3 results + 6 + 12 + 20 + +Sage example in ./programmation.tex, line 137:: + + sage: 123 + \ + ....: 345 + 468 + +Sage example in ./programmation.tex, line 201:: + + sage: import keyword; sorted(keyword.kwlist) + [...'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del'...] + +Sage example in ./programmation.tex, line 338:: + + sage: y = 3; y = 3 * y + 1; y = 3 * y + 1; y + 31 + +Sage example in ./programmation.tex, line 368:: + + sage: a, b = 10, 20 # (a, b) = (10, 20) and [10, 20] are also possible + sage: a, b = b, a + sage: a, b + (20, 10) + +Sage example in ./programmation.tex, line 382:: + + sage: temp = a; a = b; b = temp # equivalent to: a, b = b, a + +Sage example in ./programmation.tex, line 391:: + + sage: x, y = var('x, y'); a = x ; b = y + sage: a, b + (x, y) + sage: a = a + b ; b = a - b ; a = a - b + sage: a, b + (y, x) + +Sage example in ./programmation.tex, line 416:: + + sage: 2 + 2 == 2^2, 3 * 3 == 3^3 + (True, False) + +Sage example in ./programmation.tex, line 483:: + + sage: for k in [1..5]: + ....: print(7*k) # block containing a single instruction + 7 + 14 + 21 + 28 + 35 + +Sage example in ./programmation.tex, line 687:: + + sage: S = 0 ; k = 0 # The sum S starts to 0 + sage: while e^k <= 10^6: # e^13 <= 10^6 < e^14 + ....: S = S + k^2 # accumulates the squares k^2 + ....: k = k + 1 + sage: S + 819 + +Sage example in ./programmation.tex, line 734:: + + sage: x = 10^4; u = 1; n = 0 # invariant: u = 2^n + sage: while u <= x: n = n+1; u = 2*u # or n += 1; u *= 2 + sage: n + 14 + +Sage example in ./programmation.tex, line 880:: + + sage: U = 1.0 # or U = 1. or U = 1.000 + sage: for n in [1..20]: + ....: U = 1 / (1 + U^2) + sage: U + 0.682360434761105 + +Sage example in ./programmation.tex, line 942:: + + sage: S = 0 ; n = 10 + sage: for k in [1..n]: + ....: S = S + (2*k) * (2*k+1) + sage: S + 1650 + +Sage example in ./programmation.tex, line 961:: + + sage: n, k = var('n, k') ; res = sum(2*k*(2*k+1), k, 1, n) + sage: res, factor(res) # result expanded, factorised + (4/3*n^3 + 3*n^2 + 5/3*n, 1/3*(4*n + 5)*(n + 1)*n) + +Sage example in ./programmation.tex, line 1074:: + + sage: U = 2.0; V = 50.0 + sage: while V-U >= 1.0e-6: # 1.0e-6 stands for 1.0*10^-6 + ....: temp = U + ....: U = 2 * U * V / (U + V) + ....: V = (temp + V) / 2 + sage: U, V + (9.99999999989256, 10.0000000001074) + +Sage example in ./programmation.tex, line 1166:: + + sage: U = 0.0 # the sum S0 is empty, of value zero + sage: V = -1.0 # S1 = -1/1^3 + sage: n = 0 # U and V contain S(2n) and S(2n+1) + sage: while U-V >= 1.0e-6: + ....: n = n+1 # n += 1 is equivalent + ....: U = V + 1/(2*n)^3 # going from S(2n-1) to S(2n) + ....: V = U - 1/(2*n+1)^3 # going from S(2n) to S(2n+1) + sage: V, U + (-0.901543155458595, -0.901542184868447) + +Sage example in ./programmation.tex, line 1404:: + + sage: u = 6 ; n = 0 + sage: while u != 1: + ....: if u % 2 == 0: # the operator % yields the remainder + ....: u = u//2 # //: Euclidean division quotient + ....: else: + ....: u = 3*u+1 + ....: n = n+1 + sage: n + 8 + +Sage example in ./programmation.tex, line 1508:: + + sage: def fct2 (x, y): + ....: return x^2 + y^2 + sage: a = var('a') + sage: fct2 (a, 2*a) + 5*a^2 + +Sage example in ./programmation.tex, line 1557:: + + sage: def foo (u): + ....: t = u^2 + ....: return t*(t+1) + sage: t = 1 ; u = 2 + sage: foo(3), t, u + (90, 1, 2) + +Sage example in ./programmation.tex, line 1570:: + + sage: a = b = 1 + sage: def f(): global a; a = b = 2 + sage: f(); a, b + (2, 1) + +Sage example in ./programmation.tex, line 1591:: + + sage: def AHmean (u, v): + ....: u, v = min(u, v), max(u, v) + ....: while v-u > 2.0e-8: + ....: u, v = 2*u*v/(u+v), (u+v)/2 + ....: return (u+v) / 2 + +Sage example in ./programmation.tex, line 1604:: + + sage: AHmean (1., 2.) + 1.41421356237309 + sage: AHmean # corresponds to a function + + +Sage example in ./programmation.tex, line 1687:: + + sage: def fact1 (n): + ....: res = 1 + ....: for k in [1..n]: res = res*k + ....: return res + +Sage example in ./programmation.tex, line 1693:: + + sage: def fact2 (n): + ....: if n == 0: return 1 + ....: else: return n*fact2(n-1) + +Sage example in ./programmation.tex, line 1728:: + + sage: def fib1 (n): + ....: if n == 0 or n == 1: return n + ....: else: + ....: U = 0 ; V = 1 # the initial terms u0 and u1 + ....: for k in [2..n]: W = U+V ; U = V ; V = W + ....: return V + sage: fib1(8) + 21 + +Sage example in ./programmation.tex, line 1769:: + + sage: def fib2 (n): + ....: if 0 <= n <= 1: return n # for n = 0 or n = 1 + ....: else: return fib2(n-1) + fib2(n-2) + +Sage example in ./programmation.tex, line 1857:: + + sage: a = 2; n = 6; res = 1 # 1 is the product neutral element + sage: for k in [1..n]: res = res*a + sage: res # the value of res is 2^6 + 64 + +Sage example in ./programmation.tex, line 1958:: + + sage: def pow1 (a, n): + ....: if n == 0: return 1 + ....: elif n % 2 == 0: b = pow1 (a, n//2); return b*b + ....: else: return a * pow1(a, n-1) + +Sage example in ./programmation.tex, line 1968:: + + sage: pow1 (2, 11) # result is 2^11 + 2048 + +Sage example in ./programmation.tex, line 2010:: + + sage: def pow2 (u, k): + ....: v = 1 + ....: while k != 0: + ....: if k % 2 == 0: u = u*u ; k = k//2 + ....: else: v = v*u ; k = k-1 + ....: return v + +Sage example in ./programmation.tex, line 2022:: + + sage: pow2 (2, 10) # result is 2^10 + 1024 + +Sage example in ./programmation.tex, line 2109:: + + sage: def fib3 (n): + ....: A = matrix ([[0, 1], [1, 1]]) ; X0 = vector ([0, 1]) + ....: return (A^n*X0)[0] + +Sage example in ./programmation.tex, line 2114:: + + sage: def fib4 (n): + ....: return (matrix([[0,1], [1,1]])^n * vector([0,1]))[0] + +Sage example in ./programmation.tex, line 2195:: + + sage: for k in [1..6]: print('%2d^4 = %4d' % (k, k^4)) + 1^4 = 1 + 2^4 = 16 + 3^4 = 81 + 4^4 = 256 + 5^4 = 625 + 6^4 = 1296 + +Sage example in ./programmation.tex, line 2274:: + + sage: L = [10, 20, 30] + sage: L + [10, 20, 30] + sage: [] # [] is the empty list + [] + +Sage example in ./programmation.tex, line 2299:: + + sage: L[1], len(L), len([]) + (20, 3, 0) + +Sage example in ./programmation.tex, line 2309:: + + sage: L[2] = 33 + sage: L + [10, 20, 33] + +Sage example in ./programmation.tex, line 2318:: + + sage: L = [11, 22, 33] + sage: L[-1], L[-2], L[-3] + (33, 22, 11) + +Sage example in ./programmation.tex, line 2336:: + + sage: L = [0, 11, 22, 33, 44, 55] + sage: L[2:4] + [22, 33] + sage: L[-4:4] + [22, 33] + sage: L[2:-2] + [22, 33] + sage: L[:4] + [0, 11, 22, 33] + sage: L[4:] + [44, 55] + +Sage example in ./programmation.tex, line 2359:: + + sage: L = [0, 11, 22, 33, 44, 55, 66, 77] + sage: L[2:6] = [12, 13, 14] # substitutes [22, 33, 44, 55] + +Sage example in ./programmation.tex, line 2393:: + + sage: L = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] + sage: L[3:len(L)-5] == L[3-len(L):-5] + True + sage: [5 in L, 6 in L] + [True, False] + +Sage example in ./programmation.tex, line 2417:: + + sage: L = [1, 2, 3] ; L + [10, 20, 30] + [1, 2, 3, 10, 20, 30] + sage: 4 * [1, 2, 3] + [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] + +Sage example in ./programmation.tex, line 2441:: + + sage: L = 5*[10, 20, 30] ; L[:3]+L[3:] == L + True + +Sage example in ./programmation.tex, line 2459:: + + sage: [1..3, 7, 10..13] + [1, 2, 3, 7, 10, 11, 12, 13] + +Sage example in ./programmation.tex, line 2485:: + + sage: list(map (cos, [0, pi/6, pi/4, pi/3, pi/2])) + [1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0] + +Sage example in ./programmation.tex, line 2496:: + + sage: list(map (lambda t: cos(t), [0, pi/6, pi/4, pi/3, pi/2])) + [1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0] + +Sage example in ./programmation.tex, line 2534:: + + sage: list(map (lambda t: N(cos(t)), [0, pi/6, pi/4, pi/3, pi/2])) + [1.00000000000000, 0.866025403784439, 0.707106781186548, + 0.500000000000000, 0.000000000000000] + +Sage example in ./programmation.tex, line 2546:: + + sage: list(map (N, map (cos, [0, pi/6, pi/4, pi/3, pi/2]))) + [1.00000000000000, 0.866025403784439, 0.707106781186548, + 0.500000000000000, 0.000000000000000] + +Sage example in ./programmation.tex, line 2551:: + + sage: list(map (compose(N, cos), [0, pi/6, pi/4, pi/3, pi/2])) + [1.00000000000000, 0.866025403784439, 0.707106781186548, + 0.500000000000000, 0.000000000000000] + +Sage example in ./programmation.tex, line 2564:: + + sage: list(filter (is_prime, [1..55])) + [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53] + +Sage example in ./programmation.tex, line 2578:: + + sage: p = 37 ; list(filter (lambda n: n^4 % p == 7, [0..p-1])) + [3, 18, 19, 34] + +Sage example in ./programmation.tex, line 2595:: + + sage: list(map(lambda n:2*n+1, [0..15])) + [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31] + sage: [2*n+1 for n in [0..15]] + [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31] + +Sage example in ./programmation.tex, line 2607:: + + sage: list(filter (is_prime, [1..55])) + [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53] + sage: [p for p in [1..55] if is_prime(p)] + [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53] + +Sage example in ./programmation.tex, line 2621:: + + sage: list(filter (is_prime, [4*n+1 for n in [0..20]])) + [5, 13, 17, 29, 37, 41, 53, 61, 73] + sage: [n^2 for n in [1..20] if is_prime(n)] + [4, 9, 25, 49, 121, 169, 289, 361] + +Sage example in ./programmation.tex, line 2651:: + + sage: reduce (lambda x, y: 10*x+y, [1, 2, 3, 4]) + 1234 + +Sage example in ./programmation.tex, line 2657:: + + sage: reduce (lambda x, y: 10*x+y, [9, 8, 7, 6], 1) + 19876 + +Sage example in ./programmation.tex, line 2667:: + + sage: L = [2*n+1 for n in [0..9]] + sage: reduce (lambda x, y: x*y, L, 1) + 654729075 + +Sage example in ./programmation.tex, line 2743:: + + sage: prod ([2*n+1 for n in [0..9]], 1) # a list with for + 654729075 + sage: prod ( 2*n+1 for n in [0..9]) # without a list + 654729075 + sage: prod (n for n in [0..19] if n%2 == 1) + 654729075 + +Sage example in ./programmation.tex, line 2764:: + + sage: def fct (x): return 4/x == 2 + sage: all (fct(x) for x in [2, 1, 0]) + False + sage: any (fct(x) for x in [2, 1, 0]) + True + +Sage example in ./programmation.tex, line 2793:: + + sage: [[x, y] for x in [1..2] for y in [6..8]] + [[1, 6], [1, 7], [1, 8], [2, 6], [2, 7], [2, 8]] + +Sage example in ./programmation.tex, line 2800:: + + sage: [[[x, y] for x in [1..2]] for y in [6..8]] + [[[1, 6], [2, 6]], [[1, 7], [2, 7]], [[1, 8], [2, 8]]] + +Sage example in ./programmation.tex, line 2810:: + + sage: list(map (lambda x, y: [x, y], [1..3], [6..8])) + [[1, 6], [2, 7], [3, 8]] + +Sage example in ./programmation.tex, line 2829:: + + sage: L = [[1, 2, [3]], [4, [5, 6]], [7, [8, [9]]]] + sage: flatten (L, max_level = 1) + [1, 2, [3], 4, [5, 6], 7, [8, [9]]] + sage: flatten (L, max_level = 2) + [1, 2, 3, 4, 5, 6, 7, 8, [9]] + sage: flatten (L) # equivalent to flatten (L, max_level = 3) + [1, 2, 3, 4, 5, 6, 7, 8, 9] + +Sage example in ./programmation.tex, line 2852:: + + sage: x = var('x') + sage: factor(diff(x*exp(x), [x, x])) + (x + 2)*e^x + sage: list(map(lambda n: factor(diff(x*exp(x), n*[x])), [0..6])) + [x*e^x, (x + 1)*e^x, (x + 2)*e^x, (x + 3)*e^x, (x + 4)*e^x, + (x + 5)*e^x, (x + 6)*e^x] + sage: [factor (diff (x*exp(x), n*[x])) for n in [0..6]] + [x*e^x, (x + 1)*e^x, (x + 2)*e^x, (x + 3)*e^x, (x + 4)*e^x, + (x + 5)*e^x, (x + 6)*e^x] + +Sage example in ./programmation.tex, line 2907:: + + sage: L = [1, 8, 5, 2, 9] ; L.reverse() ; L + [9, 2, 5, 8, 1] + sage: L.sort() ; L + [1, 2, 5, 8, 9] + sage: L.sort(reverse = True) ; L + [9, 8, 5, 2, 1] + +Sage example in ./programmation.tex, line 2986:: + + sage: def alpha (P, Q): # len(P) = len(Q) by hypothesis + ....: i = 0 + ....: while True: + ....: if i == len(P): return int(0) + ....: elif P[i] < Q[i]: return int(-1) + ....: elif P[i] > Q[i]: return int(1) + ....: else: i = i+1 + sage: alpha ([2, 3, 4, 6, 5], [2, 3, 4, 5, 6]) + 1 + +Sage example in ./programmation.tex, line 3006:: + + sage: L = [[2, 2, 5], [2, 3, 4], [3, 2, 4], [3, 3, 3],\ + ....: [1, 1, 2], [1, 2, 7]] + sage: L.sort (cmp = alpha) ; L # py2 + [[1, 1, 2], [1, 2, 7], [2, 2, 5], [2, 3, 4], [3, 2, 4], [3, 3, 3]] + +Sage example in ./programmation.tex, line 3031:: + + sage: def homogLex (P, Q): + ....: sp = sum (P) ; sq = sum (Q) + ....: if sp < sq: return int(-1) + ....: elif sp > sq: return int(1) + ....: else: return alpha (P, Q) + +Sage example in ./programmation.tex, line 3038:: + + sage: homogLex ([2, 3, 4, 6, 4], [2, 3, 4, 5, 6]) + -1 + +Sage example in ./programmation.tex, line 3121:: + + sage: def fct1(L): + ....: return [list(filter(lambda n: n % 2 == 0, L)), + ....: list(filter(lambda n: n % 2 == 1, L))] + +Sage example in ./programmation.tex, line 3126:: + + sage: fct1([1..10]) + [[2, 4, 6, 8, 10], [1, 3, 5, 7, 9]] + +Sage example in ./programmation.tex, line 3145:: + + sage: def fct2 (L): + ....: res0 = [] ; res1 = [] + ....: for k in L: + ....: if k%2 == 0: res0.append(k) # or res0[len(res0):] = [k] + ....: else: res1.append(k) # or res1[len(res1):] = [k] + ....: return [res0, res1] + +Sage example in ./programmation.tex, line 3157:: + + sage: def fct3a (L, res0, res1): + ....: if L == []: return [res0, res1] + ....: elif L[0]%2 == 0: return fct3a(L[1:], res0+[L[0]], res1) + ....: else: return fct3a (L[1:], res0, res1+[L[0]]) + +Sage example in ./programmation.tex, line 3163:: + + sage: def fct3 (L): return fct3a (L, [], []) + +Sage example in ./programmation.tex, line 3195:: + + sage: def subSequences (L): + ....: if L == []: return [] + ....: res = [] ; start = 0 ; k = 1 + ....: while k < len(L): # 2 consecutive terms are defined + ....: if L[k-1] > L[k]: + ....: res.append (L[start:k]) ; start = k + ....: k = k+1 + ....: res.append (L[start:k]) + ....: return res + +Sage example in ./programmation.tex, line 3212:: + + sage: subSequences([1, 4, 1, 5]) + [[1, 4], [1, 5]] + sage: subSequences([4, 1, 5, 1]) + [[4], [1, 5], [1]] + +Sage example in ./programmation.tex, line 3255:: + + sage: S = 'This is a character string.' + +Sage example in ./programmation.tex, line 3277:: + + sage: S = 'This is a déjà-vu example.' + sage: print(S) + This is a déjà-vu example. + +Sage example in ./programmation.tex, line 3322:: + + sage: S='one two three four five six seven'; L=S.split(); L + ['one', 'two', 'three', 'four', 'five', 'six', 'seven'] + +Sage example in ./programmation.tex, line 3368:: + + sage: L1 = [11, 22, 33] ; L2 = L1 + sage: L1[1] = 222 ; L2.sort() ; L1, L2 + ([11, 33, 222], [11, 33, 222]) + sage: L1[2:3] = []; L2[0:0] = [6, 7, 8] + sage: L1, L2 + ([6, 7, 8, 11, 33], [6, 7, 8, 11, 33]) + +Sage example in ./programmation.tex, line 3422:: + + sage: L1 = [11, 22, 33] ; L2 = L1 ; L3 = L1[:] + sage: [L1 is L2, L2 is L1, L1 is L3, L1 == L3] + [True, True, False, True] + +Sage example in ./programmation.tex, line 3439:: + + sage: La = [1, 2, 3] ; L1 = [1, La] ; L2 = copy(L1) + sage: L1[1][0] = 5 # [1, [5, 2, 3]] for L1 and L2 + sage: [L1 == L2, L1 is L2, L1[1] is L2[1]] + [True, False, True] + +Sage example in ./programmation.tex, line 3498:: + + sage: def lexInverse (P, Q): + ....: P1 = copy(P) ; P1.reverse() + ....: Q1 = copy(Q) ; Q1.reverse() + ....: return - alpha (P1, Q1) + +Sage example in ./programmation.tex, line 3593:: + + sage: S0 = (); S1 = (1, ); S2 = (1, 2) + sage: [1 in S1, 1 == (1)] + [True, True] + +Sage example in ./programmation.tex, line 3610:: + + sage: S1 = (1, 4, 9, 16, 25); [k for k in S1] + [1, 4, 9, 16, 25] + +Sage example in ./programmation.tex, line 3627:: + + sage: L1 = [0..4]; L2 = [5..9] + sage: list(zip(L1, L2)) + [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)] + sage: list(map(lambda x, y:(x, y), L1, L2)) + [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)] + +Sage example in ./programmation.tex, line 3656:: + + sage: E = Set([1, 2, 4, 8, 2, 2, 2]); F = Set([7, 5, 3, 1]); E, F + ({8, 1, 2, 4}, {1, 3, 5, 7}) + +Sage example in ./programmation.tex, line 3678:: + + sage: E = Set([1, 2, 4, 8, 2, 2, 2]); F = Set([7, 5, 3, 1]) + sage: 5 in E, 5 in F, E + F == F | E + (False, True, True) + sage: E & F, E - F, E ^^ F + ({1}, {8, 2, 4}, {2, 3, 4, 5, 7, 8}) + +Sage example in ./programmation.tex, line 3700:: + + sage: E = Set([1, 2, 4, 8, 2, 2, 2]) + sage: [E[k] for k in [0..len(E)-1]], [t for t in E] + ([8, 1, 2, 4], [8, 1, 2, 4]) + +Sage example in ./programmation.tex, line 3713:: + + sage: def included (E, F): return E+F == F + +Sage example in ./programmation.tex, line 3728:: + + sage: sorted(Set([Set([]), Set([1]), Set([2]), Set([1, 2])]), key=str) + [{1, 2}, {1}, {2}, {}] + sage: sorted(Set([ (), (1, ), (2, ), (1, 2) ])) + [(), (1,), (1, 2), (2,)] + +Sage example in ./programmation.tex, line 3744:: + + sage: def Parts (EE): + ....: if EE == Set([]): return Set([EE]) + ....: else: + ....: return withOrWithout (EE[0], Parts(Set(EE[1:]))) + +Sage example in ./programmation.tex, line 3754:: + + sage: def withOrWithout (a, E): + ....: return Set (map (lambda F: Set([a])+F, E)) + E + +Sage example in ./programmation.tex, line 3762:: + + sage: sorted(Parts(Set([1, 2, 3])), key=str) + [{1, 2, 3}, {1, 2}, {1, 3}, {1}, {2, 3}, {2}, {3}, {}] + +Sage example in ./programmation.tex, line 3804:: + + sage: D={}; D['one']=1; D['two']=2; D['three']=3; D['ten']=10 + sage: D['two'] + D['three'] + 5 + +Sage example in ./programmation.tex, line 3857:: + + sage: D = {'a0':'b0', 'a1':'b1', 'a2':'b2', 'a3':'b0',\ + ....: 'a4':'b3', 'a5':'b3'} + sage: E = Set(D.keys()) ; Imf = Set(D.values()) + sage: Imf == Set(map (lambda t:D[t], E)) # is equivalent + True + +Sage example in ./programmation.tex, line 3894:: + + sage: def injective(D): + ....: return len(D) == len (Set(D.values())) + +""" + diff --git a/src/sage/tests/french_book/recequadiff.py b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py similarity index 62% rename from src/sage/tests/french_book/recequadiff.py rename to src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py index 88e6860925c..97ac97b81d8 100644 --- a/src/sage/tests/french_book/recequadiff.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py @@ -8,276 +8,265 @@ It is always safe to delete this file; it is not used in typesetting your document. -Sage example in ./recequadiff.tex, line 110:: +Sage example in ./recequadiff.tex, line 182:: sage: x = var('x') sage: y = function('y')(x) - sage: _C = SR.var("_C") - sage: _K1 = SR.var("_K1") - sage: _K2 = SR.var("_K2") -Sage example in ./recequadiff.tex, line 179:: +Sage example in ./recequadiff.tex, line 295:: sage: x = var('x'); y = function('y')(x) -Sage example in ./recequadiff.tex, line 182:: +Sage example in ./recequadiff.tex, line 298:: sage: desolve(diff(y,x) + 3*y == exp(x), y, show_method=True) [1/4*(4*_C + e^(4*x))*e^(-3*x), 'linear'] -Sage example in ./recequadiff.tex, line 194:: +Sage example in ./recequadiff.tex, line 320:: sage: desolve(y*diff(y,x) == x, y, show_method=True) [1/2*y(x)^2 == 1/2*x^2 + _C, 'separable'] -Sage example in ./recequadiff.tex, line 204:: +Sage example in ./recequadiff.tex, line 332:: sage: desolve(diff(y,x) == exp(x+y), y, show_method=True) [-(e^(x + y(x)) + 1)*e^(-y(x)) == _C, 'exact'] -Sage example in ./recequadiff.tex, line 215:: +Sage example in ./recequadiff.tex, line 350:: sage: desolve(diff(y,x)-y == x*y^4, y, show_method=True) [e^x/(-1/3*(3*x - 1)*e^(3*x) + _C)^(1/3), 'bernoulli'] -Sage example in ./recequadiff.tex, line 227:: +Sage example in ./recequadiff.tex, line 371:: sage: desolve(x^2*diff(y,x) == y^2+x*y+x^2, y, show_method=True) [_C*x == e^(arctan(y(x)/x)), 'homogeneous'] -Sage example in ./recequadiff.tex, line 244:: +Sage example in ./recequadiff.tex, line 399:: sage: desolve(diff(y,x) == (cos(y)-2*x)/(y+x*sin(y)), y, ....: show_method=True) [x^2 - x*cos(y(x)) + 1/2*y(x)^2 == _C, 'exact'] -Sage example in ./recequadiff.tex, line 263:: +Sage example in ./recequadiff.tex, line 431:: sage: desolve(diff(y,x) == x*y^2+y/x-1/x^2, y, ....: contrib_ode=True, show_method=True)[1] 'riccati' -Sage example in ./recequadiff.tex, line 279:: +Sage example in ./recequadiff.tex, line 459:: sage: desolve(y == x*diff(y,x)-diff(y,x)^2, y, ....: contrib_ode=True, show_method=True) [[y(x) == -_C^2 + _C*x, y(x) == 1/4*x^2], 'clairault'] -Sage example in ./recequadiff.tex, line 293:: +Sage example in ./recequadiff.tex, line 487:: sage: x = var('x'); y = function('y')(x) -Sage example in ./recequadiff.tex, line 297:: +Sage example in ./recequadiff.tex, line 491:: sage: DE = diff(y,x)+2*y == x**2-2*x+3 sage: desolve(DE, y) 1/4*((2*x^2 - 2*x + 1)*e^(2*x) - 2*(2*x - 1)*e^(2*x) + 4*_C + 6*e^(2*x))*e^(-2*x) -Sage example in ./recequadiff.tex, line 305:: +Sage example in ./recequadiff.tex, line 499:: sage: desolve(DE, y).expand() 1/2*x^2 + _C*e^(-2*x) - 3/2*x + 9/4 -Sage example in ./recequadiff.tex, line 321:: +Sage example in ./recequadiff.tex, line 518:: sage: desolve(DE, y, show_method=True)[1] 'linear' -Sage example in ./recequadiff.tex, line 327:: +Sage example in ./recequadiff.tex, line 526:: sage: desolve(DE, y, ics=[0,1]).expand() 1/2*x^2 - 3/2*x - 5/4*e^(-2*x) + 9/4 -Sage example in ./recequadiff.tex, line 338:: +Sage example in ./recequadiff.tex, line 541:: sage: x = var('x'); y = function('y')(x) sage: desolve(diff(y,x)*log(y) == y*sin(x), y, show_method=True) [1/2*log(y(x))^2 == _C - cos(x), 'separable'] -Sage example in ./recequadiff.tex, line 348:: +Sage example in ./recequadiff.tex, line 552:: - sage: ed(x) = desolve(diff(y,x)*log(y) == y*sin(x), y); ed(x) + sage: ed = desolve(diff(y,x)*log(y) == y*sin(x), y); ed 1/2*log(y(x))^2 == _C - cos(x) -Sage example in ./recequadiff.tex, line 356:: +Sage example in ./recequadiff.tex, line 565:: sage: solve(ed, y) [y(x) == e^(-sqrt(2*_C - 2*cos(x))), y(x) == e^(sqrt(2*_C - 2*cos(x)))] -Sage example in ./recequadiff.tex, line 367:: +Sage example in ./recequadiff.tex, line 581:: - sage: solve(ed, y)[0].subs(_C == 5).rhs() - e^(-sqrt(-2*cos(x) + 10)) + sage: solve(ed, y)[0].substitute(_C==5).rhs() + Traceback (most recent call last): + ... + NameError: name '_C' is not defined -Sage example in ./recequadiff.tex, line 377:: +Sage example in ./recequadiff.tex, line 593:: sage: ed.variables() (_C, x) -Sage example in ./recequadiff.tex, line 384:: +Sage example in ./recequadiff.tex, line 604:: sage: c = ed.variables()[0] - sage: solve(ed, y)[0].subs(c == 5).rhs() + sage: solve(ed, y)[0].substitute(c == 5).rhs() e^(-sqrt(-2*cos(x) + 10)) -Sage example in ./recequadiff.tex, line 396:: +Sage example in ./recequadiff.tex, line 624:: - sage: plot(solve(ed, y)[0].subs(c == 2).rhs(), x, -3, 3) + sage: plot(solve(ed, y)[0].substitute(c == 2).rhs(), x, -3, 3) Graphics object consisting of 1 graphics primitive -Sage example in ./recequadiff.tex, line 408:: +Sage example in ./recequadiff.tex, line 640:: sage: P = Graphics() sage: for k in range(1,20,2): - ....: P += plot(solve(ed, y)[0].subs(c == 1+k/4).rhs(), x, -3, 3) - sage: P - Graphics object consisting of 1... graphics primitives + ....: P += plot(solve(ed, y)[0].substitute(c==1+k/4).rhs(), x, -3, 3) -Sage example in ./recequadiff.tex, line 426:: +Sage example in ./recequadiff.tex, line 660:: sage: P = Graphics() sage: for j in [0,1]: ....: for k in range(1,10,2): - ....: f = solve(ed,y)[j].subs(c == 2+0.25*k).rhs() + ....: f = solve(ed,y)[j].substitute(c==2+0.25*k).rhs() ....: P += plot(f, x, -3, 3) sage: P Graphics object consisting of 10 graphics primitives -Sage example in ./recequadiff.tex, line 472:: +Sage example in ./recequadiff.tex, line 731:: sage: u = function('u')(x) sage: y = x*u sage: DE = x*diff(y,x) == y + sqrt(x**2 + y**2) -Sage example in ./recequadiff.tex, line 484:: +Sage example in ./recequadiff.tex, line 746:: sage: forget() -Sage example in ./recequadiff.tex, line 488:: +Sage example in ./recequadiff.tex, line 750:: sage: assume(x>0) sage: desolve(DE, u) x == _C*e^arcsinh(u(x)) -Sage example in ./recequadiff.tex, line 505:: +Sage example in ./recequadiff.tex, line 773:: sage: S = desolve(DE,u)._maxima_().ev(logarc=True).sage().solve(u); S [u(x) == -(sqrt(u(x)^2 + 1)*_C - x)/_C] -Sage example in ./recequadiff.tex, line 519:: +Sage example in ./recequadiff.tex, line 792:: sage: solu = (x-S[0]*c)^2; solu (_C*u(x) - x)^2 == (u(x)^2 + 1)*_C^2 sage: sol = solu.solve(u); sol [u(x) == -1/2*(_C^2 - x^2)/(_C*x)] -Sage example in ./recequadiff.tex, line 526:: +Sage example in ./recequadiff.tex, line 801:: sage: y(x) = x*sol[0].rhs(); y(x) -1/2*(_C^2 - x^2)/_C -Sage example in ./recequadiff.tex, line 535:: +Sage example in ./recequadiff.tex, line 820:: + sage: c = y(x).variables()[0] sage: P = Graphics() sage: for k in range(-19,19,2): - ....: P += plot(y(x).subs(c == 1/k), x, 0, 3) + ....: P += plot(y(x).substitute(c == 1/k), x, 0, 3) sage: P Graphics object consisting of 19 graphics primitives -Sage example in ./recequadiff.tex, line 567:: +Sage example in ./recequadiff.tex, line 870:: sage: x = var('x'); y = function('y')(x); a, b = var('a, b') sage: DE = diff(y,x) - a*y == -b*y**2 - sage: sol(x) = desolve(DE,[y,x]); sol(x) + sage: sol = desolve(DE,[y,x]); sol -(log(b*y(x) - a) - log(y(x)))/a == _C + x -Sage example in ./recequadiff.tex, line 575:: +Sage example in ./recequadiff.tex, line 880:: - sage: Sol(x) = solve(sol, y)[0]; Sol(x) + sage: Sol = solve(sol, y)[0]; Sol log(y(x)) == _C*a + a*x + log(b*y(x) - a) -Sage example in ./recequadiff.tex, line 582:: +Sage example in ./recequadiff.tex, line 892:: - sage: Sol(x) = Sol(x).lhs()-Sol(x).rhs(); Sol(x) + sage: Sol(x) = Sol.lhs()-Sol.rhs(); Sol(x) -_C*a - a*x - log(b*y(x) - a) + log(y(x)) sage: Sol = Sol.simplify_log(); Sol(x) -_C*a - a*x + log(y(x)/(b*y(x) - a)) sage: solve(Sol, y)[0].simplify() y(x) == a*e^(_C*a + a*x)/(b*e^(_C*a + a*x) - 1) -Sage example in ./recequadiff.tex, line 602:: +Sage example in ./recequadiff.tex, line 928:: sage: x = var('x'); y = function('y')(x) sage: DE = diff(y,x,2)+3*y == x^2-7*x+31 sage: desolve(DE, y).expand() 1/3*x^2 + _K2*cos(sqrt(3)*x) + _K1*sin(sqrt(3)*x) - 7/3*x + 91/9 -Sage example in ./recequadiff.tex, line 611:: +Sage example in ./recequadiff.tex, line 938:: sage: desolve(DE, y, ics=[0,1,2]).expand() - 1/3*x^2 + 13/9*sqrt(3)*sin(sqrt(3)*x) - 7/3*x - - 82/9*cos(sqrt(3)*x) + 91/9 + 1/3*x^2 + 13/9*sqrt(3)*sin(sqrt(3)*x) - 7/3*x - 82/9*cos(sqrt(3)*x) + 91/9 -Sage example in ./recequadiff.tex, line 621:: +Sage example in ./recequadiff.tex, line 948:: sage: desolve(DE, y, ics=[0,1,-1,0]).expand() 1/3*x^2 - 7/3*x - 82/9*cos(sqrt(3))*sin(sqrt(3)*x)/sin(sqrt(3)) + 115/9*sin(sqrt(3)*x)/sin(sqrt(3)) - 82/9*cos(sqrt(3)*x) + 91/9 -Sage example in ./recequadiff.tex, line 674:: +Sage example in ./recequadiff.tex, line 1022:: sage: x, t = var('x, t'); f = function('f')(x); g = function('g')(t) sage: z = f*g sage: eq(x,t) = diff(z,x,2) == diff(z,t); eq(x,t) - g(t)*diff(f(x), x, x) == f(x)*diff(g(t), t) + g(t)*diff(f(x), x, x) == f(x)*diff(g(t), t) -Sage example in ./recequadiff.tex, line 688:: +Sage example in ./recequadiff.tex, line 1042:: sage: eqn = eq/z; eqn(x,t) - diff(f(x), x, x)/f(x) == diff(g(t), t)/g(t) + diff(f(x), x, x)/f(x) == diff(g(t), t)/g(t) -Sage example in ./recequadiff.tex, line 702:: +Sage example in ./recequadiff.tex, line 1061:: sage: k = var('k') sage: eq1(x,t) = eqn(x,t).lhs() == k; eq2(x,t) = eqn(x,t).rhs() == k -Sage example in ./recequadiff.tex, line 709:: +Sage example in ./recequadiff.tex, line 1069:: sage: g(t) = desolve(eq2(x,t),[g,t]); g(t) _C*e^(k*t) -Sage example in ./recequadiff.tex, line 717:: - - sage: desolve(eq1,[f,x]) - Traceback (most recent call last): - ... - TypeError: Computation failed ... - Is k positive, negative or zero? - -Sage example in ./recequadiff.tex, line 728:: +Sage example in ./recequadiff.tex, line 1092:: sage: assume(k>0); desolve(eq1,[f,x]) _K1*e^(sqrt(k)*x) + _K2*e^(-sqrt(k)*x) -Sage example in ./recequadiff.tex, line 782:: +Sage example in ./recequadiff.tex, line 1176:: sage: x, s = var('x, s'); f = function('f')(x) sage: f(x) = sin(x); f.laplace(x,s) x |--> 1/(s^2 + 1) -Sage example in ./recequadiff.tex, line 795:: +Sage example in ./recequadiff.tex, line 1191:: sage: X(s) = 1/(s^2-3*s-4)/(s^2+1) + (s-4)/(s^2-3*s-4) sage: X(s).inverse_laplace(s, x) 3/34*cos(x) + 1/85*e^(4*x) + 9/10*e^(-x) - 5/34*sin(x) -Sage example in ./recequadiff.tex, line 807:: +Sage example in ./recequadiff.tex, line 1206:: sage: X(s).partial_fraction() 1/34*(3*s - 5)/(s^2 + 1) + 9/10/(s + 1) + 1/85/(s - 4) -Sage example in ./recequadiff.tex, line 818:: +Sage example in ./recequadiff.tex, line 1221:: sage: x = var('x'); y = function('y')(x) sage: eq = diff(y,x,x) - 3*diff(y,x) - 4*y - sin(x) == 0 @@ -287,7 +276,7 @@ sage: desolve_laplace(eq, y, ics=[0,1,-1]) 3/34*cos(x) + 1/85*e^(4*x) + 9/10*e^(-x) - 5/34*sin(x) -Sage example in ./recequadiff.tex, line 869:: +Sage example in ./recequadiff.tex, line 1279:: sage: x = var('x'); y1 = function('y1')(x) sage: y2 = function('y2')(x); y3 = function('y3')(x) @@ -299,7 +288,7 @@ y2(x) == -e^(4*x) + 2*e^(-2*x), y3(x) == -e^(4*x) - e^(-2*x)] -Sage example in ./recequadiff.tex, line 913:: +Sage example in ./recequadiff.tex, line 1328:: sage: x = var('x'); y1 = function('y1')(x); y2 = function('y2')(x) sage: y = vector([y1,y2]) @@ -308,7 +297,7 @@ sage: desolve_system(system, [y1, y2], ics=[0,2,0]) [y1(x) == 2*cos(2*x)*e^(3*x), y2(x) == e^(3*x)*sin(2*x)] -Sage example in ./recequadiff.tex, line 966:: +Sage example in ./recequadiff.tex, line 1385:: sage: x = var('x'); u1 = function('u1')(x); u2 = function('u2')(x) sage: u3 = function('u3')(x); u4 = function('u4')(x) @@ -317,19 +306,18 @@ sage: system = [diff(u[i], x) - (A*u)[i] for i in range(4)] sage: sol = desolve_system(system, [u1, u2, u3, u4]) -Sage example in ./recequadiff.tex, line 977:: +Sage example in ./recequadiff.tex, line 1399:: sage: sol[0] u1(x) == 1/12*(2*u1(0) - 6*u2(0) + 5*u3(0) + 3*u4(0))*e^(2*x) - + 1/24*(2*u1(0) - 6*u2(0) - u3(0) + 3*u4(0))*e^(-4*x) - + 3/4*u1(0) + 3/4*u2(0) - 3/8*u3(0) - 3/8*u4(0) - + + 1/24*(2*u1(0) - 6*u2(0) - u3(0) + 3*u4(0))*e^(-4*x) + 3/4*u1(0) + + 3/4*u2(0) - 3/8*u3(0) - 3/8*u4(0) sage: sol[1] u2(x) == -1/12*(2*u1(0) - 6*u2(0) - u3(0) - 3*u4(0))*e^(2*x) - - 1/24*(2*u1(0) - 6*u2(0) - u3(0) + 3*u4(0))*e^(-4*x) - + 1/4*u1(0) + 1/4*u2(0) - 1/8*u3(0) - 1/8*u4(0) + - 1/24*(2*u1(0) - 6*u2(0) - u3(0) + 3*u4(0))*e^(-4*x) + 1/4*u1(0) + + 1/4*u2(0) - 1/8*u3(0) - 1/8*u4(0) -Sage example in ./recequadiff.tex, line 1095:: +Sage example in ./recequadiff.tex, line 1557:: sage: x = var('x'); f = function('f')(x) sage: f(x) = 3.83*x*(1 - x/100000) @@ -337,7 +325,7 @@ ....: if n==0: return(20000) ....: else: return f(u(n-1)) -Sage example in ./recequadiff.tex, line 1105:: +Sage example in ./recequadiff.tex, line 1568:: sage: def v(n): ....: V = 20000; @@ -345,55 +333,56 @@ ....: V = f(V) ....: return V -Sage example in ./recequadiff.tex, line 1118:: +Sage example in ./recequadiff.tex, line 1582:: - sage: def nuage(u,n): + sage: def cloud(u,n): ....: L = [[0,u(0)]]; ....: for k in [1..n]: ....: L += [[k,u(k)]] ....: points(L).show() -Sage example in ./recequadiff.tex, line 1128:: +Sage example in ./recequadiff.tex, line 1598:: - sage: nuage(u,50) + sage: cloud(u,50) -Sage example in ./recequadiff.tex, line 1144:: +Sage example in ./recequadiff.tex, line 1619:: - sage: def escargot(f,x,u0,n,xmin,xmax): + sage: def snail(f,x,u0,n,xmin,xmax): ....: u = u0 ....: P = plot(x, x, xmin, xmax, color='gray') ....: for i in range(n): ....: P += line([[u,u],[u,f(u)],[f(u),f(u)]], color = 'red') ....: u = f(u) - ....: P += f.plot(x, xmin, xmax, color='blue') # Courbe de f + ....: P += f.plot(x, xmin, xmax, color='blue') ....: P.show() -Sage example in ./recequadiff.tex, line 1157:: +Sage example in ./recequadiff.tex, line 1637:: sage: f(x) = 3.83*x*(1 - x/100000) - sage: escargot(f,x,20000,100,0,100000) + sage: snail(f,x,20000,100,0,100000) -Sage example in ./recequadiff.tex, line 1197:: +Sage example in ./recequadiff.tex, line 1687:: - sage: from sympy import Function, Symbol - sage: u = Function('u'); n = Symbol('n', integer=True) + sage: from sympy import Function + sage: from sympy.abc import n + sage: u = Function('u') -Sage example in ./recequadiff.tex, line 1208 (WARNING: the order of factors is -inverted, see :trac:`23496` ):: +Sage example in ./recequadiff.tex, line 1700:: - sage: f = u(n+2)-u(n+1)*(3/2)+u(n)*(1/2) + sage: f = u(n+2)-(3/2)*u(n+1)+(1/2)*u(n) -Sage example in ./recequadiff.tex, line 1214:: +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 example in ./recequadiff.tex, line 1265:: +Sage example in ./recequadiff.tex, line 1798:: sage: from sympy import rsolve_hyper - sage: n = Symbol('n', integer=True) - sage: rsolve_hyper([-2,1],2**(n+2),n) # known bug (Trac #24334) + sage: from sympy.abc import n + sage: rsolve_hyper([-2,1],2**(n+2),n) 2**n*C0 + 2**(n + 2)*(C0 + n/2) """ + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py new file mode 100644 index 00000000000..ca748ba2059 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py @@ -0,0 +1,266 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/calculus_doctest.sage) was *autogenerated* from ./sol/calculus.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/calculus_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/calculus.tex, line 3:: + + sage: reset() + +Sage example in ./sol/calculus.tex, line 10:: + + sage: n = var('n'); pmax = 4; s = [n + 1] + sage: for p in [1..pmax]: + ....: s += [factor(((n+1)^(p+1) - sum(binomial(p+1, j) * s[j] + ....: for j in [0..p-1])) / (p+1))] + sage: s + [n + 1, + 1/2*(n + 1)*n, + 1/6*(2*n + 1)*(n + 1)*n, + 1/4*(n + 1)^2*n^2, + 1/30*(3*n^2 + 3*n - 1)*(2*n + 1)*(n + 1)*n] + +Sage example in ./sol/calculus.tex, line 42:: + + sage: x, h, a = var('x, h, a'); f = function('f') + sage: g(x) = taylor(f(x), x, a, 3) + sage: phi(h) = (g(a+3*h) - 3*g(a+2*h) + 3*g(a+h) - g(a)) / h^3; phi(h) + diff(f(a), a, a, a) + +Sage example in ./sol/calculus.tex, line 75:: + + sage: n = 7; x, h, a = var('x h a'); f = function('f') + sage: g(x) = taylor(f(x), x, a, n) + sage: sum((-1)^(n-k) * binomial(n,k) * g(a+k*h) for k in (0..n)) / h^n + diff(f(a), a, a, a, a, a, a, a) + +Sage example in ./sol/calculus.tex, line 100:: + + sage: theta = 12*arctan(1/38) + 20*arctan(1/57) \ + ....: + 7*arctan(1/239) + 24*arctan(1/268) + sage: tan(theta).trig_expand().trig_simplify() + 1 + +Sage example in ./sol/calculus.tex, line 110:: + + sage: 12*(1/38) + 20*(1/57) + 7*(1/239) + 24*(1/268) + 37735/48039 + +Sage example in ./sol/calculus.tex, line 135:: + + sage: x = var('x'); f(x) = taylor(arctan(x), x, 0, 21) + sage: approx = 4 * (12 * f(1/38) + 20 * f(1/57) + ....: + 7 * f(1/239) + 24 * f(1/268)) + sage: approx.n(digits = 50); pi.n(digits = 50) + 3.1415926535897932384626433832795028851616168852864 + 3.1415926535897932384626433832795028841971693993751 + sage: approx.n(digits = 50) - pi.n(digits = 50) + 9.6444748591132486785420917537404705292978817080880e-37 + +Sage example in ./sol/calculus.tex, line 182:: + + sage: n = var('n'); phi = lambda x: n*pi + pi/2 - arctan(1/x) + sage: x = n*pi + sage: for i in range(4): + ....: x = taylor(phi(x), n, infinity, 2*i); x + 1/2*pi + pi*n + 1/2*pi + pi*n - 1/(pi*n) + 1/2/(pi*n^2) + 1/2*pi + pi*n - 1/(pi*n) + 1/2/(pi*n^2) + - 1/12*(3*pi^2 + 8)/(pi^3*n^3) + 1/8*(pi^2 + 8)/(pi^3*n^4) + 1/2*pi + pi*n - 1/(pi*n) + 1/2/(pi*n^2) + - 1/12*(3*pi^2 + 8)/(pi^3*n^3) + 1/8*(pi^2 + 8)/(pi^3*n^4) + - 1/240*(15*pi^4 + 240*pi^2 + 208)/(pi^5*n^5) + + 1/96*(3*pi^4 + 80*pi^2 + 208)/(pi^5*n^6) + +Sage example in ./sol/calculus.tex, line 239:: + + sage: h = var('h'); f(x, y) = x * y * (x^2 - y^2) / (x^2 + y^2) + sage: D1f(x, y) = diff(f(x,y), x); limit((D1f(0,h) - 0) / h, h=0) + -1 + sage: D2f(x, y) = diff(f(x,y), y); limit((D2f(h,0) - 0) / h, h=0) + 1 + sage: g = plot3d(f(x, y), (x, -3, 3), (y, -3, 3)) + +Sage example in ./sol/calculus.tex, line 285:: + + sage: n, t = var('n, t') + sage: v(n) = (4/(8*n+1)-2/(8*n+4)-1/(8*n+5)-1/(8*n+6))*1/16^n + sage: assume(8*n+1>0) + sage: f(t) = 4*sqrt(2)-8*t^3-4*sqrt(2)*t^4-8*t^5 + sage: u(n) = integrate(f(t) * t^(8*n), t, 0, 1/sqrt(2)) + sage: (u(n)-v(n)).canonicalize_radical() + 0 + +Sage example in ./sol/calculus.tex, line 317:: + + sage: t = var('t'); J = integrate(f(t) / (1-t^8), t, 0, 1/sqrt(2)) + sage: J.canonicalize_radical() + pi + 2*log(sqrt(2) + 1) + 2*log(sqrt(2) - 1) + +Sage example in ./sol/calculus.tex, line 325:: + + sage: J.simplify_log().canonicalize_radical() + pi + +Sage example in ./sol/calculus.tex, line 337:: + + sage: l = sum(v(n) for n in (0..40)); l.n(digits=60) + 3.14159265358979323846264338327950288419716939937510581474759 + sage: pi.n(digits=60) + 3.14159265358979323846264338327950288419716939937510582097494 + sage: print("%e" % (l-pi).n(digits=60)) + -6.227358e-54 + +Sage example in ./sol/calculus.tex, line 369:: + + sage: x = var('x'); ps = lambda f, g : integral(f * g, x, -pi, pi) + sage: n = 5; a = var('a0, a1, a2, a3, a4, a5') + sage: P = sum(a[k] * x^k for k in (0..n)) + sage: equ = [ps(P - sin(x), x^k) for k in (0..n)] + sage: sol = solve(equ, a) + sage: P = sum(sol[0][k].rhs() * x^k for k in (0..n)); P + 105/8*(pi^4 - 153*pi^2 + 1485)*x/pi^6 - 315/4*(pi^4 - 125*pi^2 + + 1155)*x^3/pi^8 + 693/8*(pi^4 - 105*pi^2 + 945)*x^5/pi^10 + sage: g = plot(P,x,-6,6,color='red') + plot(sin(x),x,-6,6,color='blue') + sage: g.show(ymin = -1.5, ymax = 1.5) + +Sage example in ./sol/calculus.tex, line 430:: + + sage: p, e = var('p, e') + sage: theta1, theta2, theta3 = var('theta1, theta2, theta3') + sage: r(theta) = p / (1 - e * cos(theta)) + sage: r1 = r(theta1); r2 = r(theta2); r3 = r(theta3) + sage: R1 = vector([r1 * cos(theta1), r1 * sin(theta1), 0]) + sage: R2 = vector([r2 * cos(theta2), r2 * sin(theta2), 0]) + sage: R3 = vector([r3 * cos(theta3), r3 * sin(theta3), 0]) + +Sage example in ./sol/calculus.tex, line 446:: + + sage: D = R1.cross_product(R2)+R2.cross_product(R3)+R3.cross_product(R1) + sage: S = (r1 - r3) * R2 + (r3 - r2) * R1 + (r2 - r1) * R3 + sage: i = vector([1, 0, 0]); V = S + e * i.cross_product(D) + sage: V.simplify_full() + (0, 0, 0) + +Sage example in ./sol/calculus.tex, line 466:: + + sage: S.cross_product(D).simplify_full()[1:3] + (0, 0) + +Sage example in ./sol/calculus.tex, line 479:: + + sage: N = r3 * R1.cross_product(R2) + r1 * R2.cross_product(R3)\ + ....: + r2 * R3.cross_product(R1) + sage: W = p * S + e * i.cross_product(N) + sage: W.simplify_full() + (0, 0, 0) + +Sage example in ./sol/calculus.tex, line 504:: + + sage: R1=vector([0,1,0]); R2=vector([2,2,0]); R3=vector([3.5,0,0]) + sage: r1 = R1.norm(); r2 = R2.norm(); r3 = R3.norm() + sage: D = R1.cross_product(R2) + R2.cross_product(R3) \ + ....: + R3.cross_product(R1) + sage: S = (r1 - r3) * R2 + (r3 - r2) * R1 + (r2 - r1) * R3 + sage: N = r3 * R1.cross_product(R2) + r1 * R2.cross_product(R3) \ + ....: + r2 * R3.cross_product(R1) + sage: e = S.norm() / D.norm(); p = N.norm() / D.norm() + sage: a = p/(1-e^2); c = a * e; b = sqrt(a^2 - c^2) + sage: X = S.cross_product(D); i = X / X.norm() + sage: phi = atan2(i[1], i[0]) * 180 / pi.n() + sage: print("%.3f %.3f %.3f %.3f %.3f %.3f" % (a, b, c, e, p, phi)) + 2.360 1.326 1.952 0.827 0.746 17.917 + +Sage example in ./sol/calculus.tex, line 544:: + + sage: A = matrix(QQ, [[ 2, -3, 2, -12, 33], + ....: [ 6, 1, 26, -16, 69], + ....: [10, -29, -18, -53, 32], + ....: [ 2, 0, 8, -18, 84]]) + sage: A.right_kernel() + Vector space of degree 5 and dimension 2 over Rational Field + Basis matrix: + [ 1 0 -7/34 5/17 1/17] + [ 0 1 -3/34 -10/17 -2/17] + +Sage example in ./sol/calculus.tex, line 571:: + + sage: H = A.echelon_form(); H + [ 1 0 4 0 -3] + [ 0 1 2 0 7] + [ 0 0 0 1 -5] + [ 0 0 0 0 0] + +Sage example in ./sol/calculus.tex, line 608:: + + sage: A.column_space() + Vector space of degree 4 and dimension 3 over Rational Field + Basis matrix: + [ 1 0 0 1139/350] + [ 0 1 0 -9/50] + [ 0 0 1 -12/35] + +Sage example in ./sol/calculus.tex, line 624:: + + sage: S. = QQ[] + sage: C = matrix(S, 4, 1, [x, y, z, t]) + sage: B = block_matrix([A, C], ncols=2) + sage: C = B.echelon_form() + sage: C[3,5]*350 + -1139*x + 63*y + 120*z + 350*t + +Sage example in ./sol/calculus.tex, line 643:: + + sage: K = A.left_kernel(); K + Vector space of degree 4 and dimension 1 over Rational Field + Basis matrix: + [ 1 -63/1139 -120/1139 -350/1139] + +Sage example in ./sol/calculus.tex, line 653:: + + sage: matrix(K.0).right_kernel() + Vector space of degree 4 and dimension 3 over Rational Field + Basis matrix: + [ 1 0 0 1139/350] + [ 0 1 0 -9/50] + [ 0 0 1 -12/35] + +Sage example in ./sol/calculus.tex, line 668:: + + sage: A = matrix(QQ, [[-2, 1, 1], [8, 1, -5], [4, 3, -3]]) + sage: C = matrix(QQ, [[1, 2, -1], [2, -1, -1], [-5, 0, 3]]) + +Sage example in ./sol/calculus.tex, line 680:: + + sage: B = C.solve_left(A); B + [ 0 -1 0] + [ 2 3 0] + [ 2 1 0] + +Sage example in ./sol/calculus.tex, line 691:: + + sage: C.left_kernel() + Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: + [1 2 1] + +Sage example in ./sol/calculus.tex, line 699:: + + sage: x, y, z = var('x, y, z'); v = matrix([[1, 2, 1]]) + sage: B = B + (x*v).stack(y*v).stack(z*v); B + [ x 2*x - 1 x] + [ y + 2 2*y + 3 y] + [ z + 2 2*z + 1 z] + +Sage example in ./sol/calculus.tex, line 708:: + + sage: A == B*C + True + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py new file mode 100644 index 00000000000..4cd1f78259c --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py @@ -0,0 +1,219 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/combinat_doctest.sage) was *autogenerated* from ./sol/combinat.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/combinat_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/combinat.tex, line 15:: + + sage: Suits = FiniteEnumeratedSet( + ....: ["Hearts", "Diamonds", "Spades", "Clubs"]) + sage: Values = FiniteEnumeratedSet([2, 3, 4, 5, 6, 7, 8, 9, 10, + ....: "Jack", "Queen", "King", "Ace"]) + sage: FourOfaKind = cartesian_product([Arrangements(Values,2), Suits]) + +Sage example in ./sol/combinat.tex, line 34:: + + sage: FourOfaKind.list() + [([2, 3], 'Hearts'), + ([2, 3], 'Diamonds'), + ... + (['Ace', 'King'], 'Clubs')] + +Sage example in ./sol/combinat.tex, line 51:: + + sage: FourOfaKind.cardinality() + 624 + +Sage example in ./sol/combinat.tex, line 66:: + + sage: Cards = cartesian_product([Values, Suits]) + sage: Hands = Subsets(Cards, 5) + sage: FourOfaKind.cardinality() / Hands.cardinality() + 1/4165 + +Sage example in ./sol/combinat.tex, line 86:: + + sage: StraightFlush = cartesian_product([range(1, 11), Suits]) + sage: StraightFlush.cardinality() + 40 + +Sage example in ./sol/combinat.tex, line 98:: + + sage: AllFlush = cartesian_product([Subsets(Values,5),Suits]) + sage: AllFlush.cardinality() - StraightFlush.cardinality() + 5108 + +Sage example in ./sol/combinat.tex, line 113:: + + sage: _ / Hands.cardinality() + 1277/649740 + sage: float(_) + 0.001965401545233478 + +Sage example in ./sol/combinat.tex, line 153:: + + sage: Word(['a','b','b','a','a','b','a']).evaluation_dict() + {'a': 4, 'b': 3} + +Sage example in ./sol/combinat.tex, line 170:: + + sage: def is_full_hand(hand): + ....: suits = Word([value for (value, suit) in hand]) + ....: repetitions = sorted(suits.evaluation_dict().values()) + ....: return repetitions == [2,3] + sage: is_full_hand({(5, 'Diamonds'), (6, 'Diamonds'), (6, 'Hearts'), + ....: (5, 'Spades'), (1, 'Spades')}) + False + sage: is_full_hand({(3, 'Clubs'), (3, 'Spades'), (3, 'Hearts'), + ....: (2, 'Clubs'), (2, 'Spades')}) + True + +Sage example in ./sol/combinat.tex, line 200:: + + sage: def estimate_proportion(S, predicate, n): + ....: count = 0 + ....: for i in range(n): + ....: if predicate(S.random_element()): + ....: count += 1 + ....: return count/n + +Sage example in ./sol/combinat.tex, line 212:: + + sage: float(estimate_proportion(Hands, is_full_hand, 10000)) # random + 0.0014 + +Sage example in ./sol/combinat.tex, line 229:: + + sage: FullHands = cartesian_product([Arrangements(Values, 2), + ....: Subsets(Suits, 3), Subsets(Suits, 2)]) + +Sage example in ./sol/combinat.tex, line 242:: + + sage: [sorted(v) for v in FullHands.first()] + [[2, 3], ['Diamonds', 'Hearts', 'Spades'], ['Diamonds', 'Hearts']] + +Sage example in ./sol/combinat.tex, line 252:: + + sage: float(FullHands.cardinality() / Hands.cardinality()) + 0.0014405762304921968 + +Sage example in ./sol/combinat.tex, line 312:: + + sage: C = Compositions(5,length=3) + sage: C.cardinality + + +Sage example in ./sol/combinat.tex, line 322:: + + sage: IntegerVectors(5,3).list() + [[5, 0, 0], [4, 1, 0], [4, 0, 1], [3, 2, 0], [3, 1, 1], [3, 0, 2], + ... + [0, 4, 1], [0, 3, 2], [0, 2, 3], [0, 1, 4], [0, 0, 5]] + +Sage example in ./sol/combinat.tex, line 328:: + + sage: OrderedSetPartitions(3).cardinality() + 13 + sage: OrderedSetPartitions(3).list() + [[{1}, {2}, {3}], [{1}, {3}, {2}], [{2}, {1}, {3}], [{3}, {1}, {2}], + ... + [{1, 2}, {3}], [{1, 3}, {2}], [{2, 3}, {1}], [{1, 2, 3}]] + sage: OrderedSetPartitions(3,2).random_element() # random + [{1, 3}, {2}] + +Sage example in ./sol/combinat.tex, line 338:: + + sage: StandardTableaux([3,2]).cardinality() + 5 + sage: StandardTableaux([3,2]).an_element() + [[1, 3, 5], [2, 4]] + +Sage example in ./sol/combinat.tex, line 350:: + + sage: list(AlternatingSignMatrices(1)) + [[1]] + sage: list(AlternatingSignMatrices(2)) + [ + [1 0] [0 1] + [0 1], [1 0] + ] + +Sage example in ./sol/combinat.tex, line 361:: + + sage: list(AlternatingSignMatrices(3)) + [ + [1 0 0] [0 1 0] [1 0 0] [ 0 1 0] [0 0 1] [0 1 0] [0 0 1] + [0 1 0] [1 0 0] [0 0 1] [ 1 -1 1] [1 0 0] [0 0 1] [0 1 0] + [0 0 1], [0 0 1], [0 1 0], [ 0 1 0], [0 1 0], [1 0 0], [1 0 0] + ] + +Sage example in ./sol/combinat.tex, line 383:: + + sage: GF(2)^5 + Vector space of dimension 5 over Finite Field of size 2 + sage: _.cardinality() + 32 + +Sage example in ./sol/combinat.tex, line 400:: + + sage: (2^3-2^0)*(2^3-2^1)*(2^3-2^2) + 168 + +Sage example in ./sol/combinat.tex, line 406:: + + sage: GL(3,2) + General Linear Group of degree 3 over Finite Field of size 2 + sage: _.cardinality() + 168 + +Sage example in ./sol/combinat.tex, line 423:: + + sage: from sage.combinat.q_analogues import q_factorial + sage: q = 2; n = 3 + sage: q^(n*(n-1)/2) * (q-1)^n * q_factorial(n,q) + 168 + sage: q = 3; n = 5 + sage: GL(n, q).cardinality() + 475566474240 + sage: q^(n*(n-1)/2) * (q-1)^n * q_factorial(n,q) + 475566474240 + +Sage example in ./sol/combinat.tex, line 537:: + + sage: def C(n): + ....: if n == 1: + ....: yield BinaryTree() + ....: elif n > 1: + ....: for k in range(1,n): + ....: for t1 in C(k): + ....: for t2 in C(n-k): + ....: yield BinaryTree([t1,t2]) + +Sage example in ./sol/combinat.tex, line 549:: + + sage: list(C(1)) + [.] + sage: list(C(2)) + [[., .]] + sage: list(C(3)) + [[., [., .]], + [[., .], .]] + sage: list(C(4)) + [[., [., [., .]]], + [., [[., .], .]], + [[., .], [., .]], + [[., [., .]], .], + [[[., .], .], .]] + +Sage example in ./sol/combinat.tex, line 566:: + + sage: [len(list(C(n))) for n in range(9)] + [0, 1, 1, 2, 5, 14, 42, 132, 429] + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py new file mode 100644 index 00000000000..03b4731f545 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py @@ -0,0 +1,61 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/domaines_doctest.sage) was *autogenerated* from ./sol/domaines.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/domaines_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/domaines.tex, line 4:: + + sage: def ndigits(x): return x.ndigits() + sage: o = 720; ndigits(o) + 3 + +Sage example in ./sol/domaines.tex, line 28:: + + sage: a = Reals(17)(pi); b = Reals(42)(pi) + sage: type(a) == type(b) + True + sage: parent(a), parent(b) + (Real Field with 17 bits of precision, Real Field with 42 bits of precision) + +Sage example in ./sol/domaines.tex, line 46:: + + sage: a = 0.1; b = 0.1*1 + sage: type(a), type(b) + (<... 'sage.rings.real_mpfr.RealLiteral'>, <... 'sage.rings.real_mpfr.RealNumber'>) + sage: parent(a) == parent(b) + True + +Sage example in ./sol/domaines.tex, line 70:: + + sage: Reals(100)(a)-1/10 + 0.00000000000000000000000000000 + sage: Reals(100)(b)-1/10 + 5.5511151231257629805955278152e-18 + +Sage example in ./sol/domaines.tex, line 80:: + + sage: E = CombinatorialFreeModule(QQ, [1,2,3]) + sage: H = Hom(E,E); H.rename("H") + sage: C = E.category(); C + Category of finite dimensional vector spaces with basis over Rational Field + sage: phi1 = E.module_morphism(on_basis=lambda i: E.term(i), codomain=E) + sage: phi2 = E.module_morphism(on_basis=lambda i: E.term(i), + ....: triangular="lower", codomain=E) + sage: phi3 = E.module_morphism(diagonal=lambda i: 1, codomain=E, + ....: category=C) + sage: phi1.parent() == phi2.parent() == phi3.parent() == H + True + sage: type(phi1) + + sage: type(phi2) + + sage: type(phi3) + + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py new file mode 100644 index 00000000000..7e1d7f0c0e4 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py @@ -0,0 +1,143 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/float_doctest.sage) was *autogenerated* from ./sol/float.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/float_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/float.tex, line 17:: + + sage: R100=RealField(100) + sage: x=R100(10^30) + sage: x>2^99 + True + sage: x<2^100 + True + +Sage example in ./sol/float.tex, line 48:: + + sage: e=2^100 + sage: s1=10^30 + sage: significand=[] + sage: nbdigits=0 # number of significant digits + sage: while s1>0: + ....: e/=2 + ....: if e<=s1: + ....: significand.append(1) + ....: s1-=e + ....: else: + ....: significand.append(0) + ....: nbdigits+=1 + sage: print(significand) + [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, + 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, + 1, 1, 1, 0, 1, 0, 1, 0, 0, 1] + sage: print("number of significant digits: " + str(nbdigits)) + number of significant digits: 70 + +Sage example in ./sol/float.tex, line 86:: + + sage: R100=RealField(100) + sage: x=R100(10^30) + sage: s,m,e = x.sign_mantissa_exponent() + sage: s,m,e + (1, 1000000000000000000000000000000, 0) + +Sage example in ./sol/float.tex, line 126:: + + sage: var("u0 u1 u2 alpha beta gamma n") + (u0, u1, u2, alpha, beta, gamma, n) + sage: recurrence = lambda a,b: 111-1130/a+3000/(a*b) + sage: gener1 = lambda n: (alpha*100^n+beta*6^n+gamma*5^n) + sage: solGen = lambda n: gener1(n+1)/gener1(n) + +Sage example in ./sol/float.tex, line 137:: + + sage: u2 = recurrence(u1,u0) + sage: s = [u2==solGen(2),u1==solGen(1),u0==solGen(0)] + sage: t = [s[i].substitute(u0=2,u1=-4) for i in range(0,3)] + +Sage example in ./sol/float.tex, line 143:: + + sage: solve(t,alpha,beta,gamma) + [[alpha == 0, beta == -3/4*r1, gamma == r1]] + +Sage example in ./sol/float.tex, line 157:: + + sage: alpha=0 + sage: beta = -3/4*gamma + sage: final=solGen(n)-recurrence(solGen(n-1),solGen(n-2)) + sage: final.simplify_full() + 0 + +Sage example in ./sol/float.tex, line 179:: + + sage: def recur(x1,x0): + ....: return 111 - 1130/x1 + 3000/(x0*x1) + +Sage example in ./sol/float.tex, line 190:: + + sage: u0 = 2. + sage: u1 = -4. + sage: for i in range(1,25): + ....: x = recur(u1,u0) + ....: print((i, x)) + ....: u0 = u1 + ....: u1 = x + (1, 18.5000000000000) + (2, 9.37837837837838) + (3, 7.80115273775217) + (4, 7.15441448097533) + (5, 6.80678473692481) + (6, 6.59263276872179) + .................. + (23, 99.9999986592167) + (24, 99.9999999193218) + +Sage example in ./sol/float.tex, line 229:: + + sage: var("x") + x + sage: solve(x==recurrence(x,x),x) + [x == 100, x == 5, x == 6] + +Sage example in ./sol/float.tex, line 256:: + + sage: RL = RealField(5000) + sage: u0 = RL(2) + sage: u1 = RL(-4) + sage: for i in range(1,2500): + ....: x = recur(u1,u0) + ....: u0 = u1 + ....: u1= x + sage: x + 100.00000000000000000000000000000000000000000000000000000... + +Sage example in ./sol/float.tex, line 281:: + + sage: u0 = 2 + sage: u1 = -4 + sage: for i in range(1,2500): + ....: x = recur(u1,u0) + ....: u0 = u1 + ....: u1 = x + sage: float(x) + 6.0 + +Sage example in ./sol/float.tex, line 325:: + + sage: f = lambda x: x^2 + sage: g = lambda x: x*x + sage: sage.rings.real_mpfi.printing_style = 'brackets' + sage: I = RIF(-1,1) + sage: f(I) + [0.0000000000000000 .. 1.0000000000000000] + sage: g(I) + [-1.0000000000000000 .. 1.0000000000000000] + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphique_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphique_doctest.py new file mode 100644 index 00000000000..95e7f328255 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphique_doctest.py @@ -0,0 +1,106 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/graphique_doctest.sage) was *autogenerated* from ./sol/graphique.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/graphique_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/graphique.tex, line 3:: + + sage: reset() + +Sage example in ./sol/graphique.tex, line 10:: + + sage: t = var('t'); liste = [a + cos(t) for a in srange(0, 2, 0.1)] + sage: g = polar_plot(liste, (t, 0, 2 * pi)); g.show(aspect_ratio = 1) + +Sage example in ./sol/graphique.tex, line 38:: + + sage: f = lambda x: abs(x**2 - 1/4) + sage: def liste_pts(u0, n): + ....: u = u0; liste = [[u0,0]] + ....: for k in range(n): + ....: v, u = u, f(u) + ....: liste.extend([[v,u], [u,u]]) + ....: return(liste) + sage: g = line(liste_pts(1.1, 8), rgbcolor = (.9,0,0)) + sage: g += line(liste_pts(-.4, 8), rgbcolor = (.01,0,0)) + sage: g += line(liste_pts(1.3, 3), rgbcolor = (.5,0,0)) + sage: g += plot(f, -1, 3, rgbcolor = 'blue') + sage: g += plot(x, -1, 3, rgbcolor = 'green') + sage: g.show(aspect_ratio = 1, ymin = -.2, ymax = 3) + +Sage example in ./sol/graphique.tex, line 78:: + + sage: x = var('x'); y = function('y') + sage: DE = x^2 * diff(y(x), x) - y(x) == 0 + sage: desolve(DE, y(x)) + _C*e^(-1/x) + sage: g = plot([c*e^(-1/x) for c in srange(-8, 8, 0.4)], (x, -3, 3)) + sage: y = var('y') + sage: g += plot_vector_field((x^2, y), (x,-3,3), (y,-5,5)) + sage: g.show() + +Sage example in ./sol/graphique.tex, line 124:: + + sage: from sage.calculus.desolvers import desolve_system_rk4 + sage: f = lambda x, y: [a*x-b*x*y,-c*y+d*b*x*y] + sage: x, y, t = var('x, y, t') + sage: a, b, c, d = 1., 0.1, 1.5, 0.75 + sage: P = desolve_system_rk4(f(x,y), [x,y],\ + ....: ics=[0,10,5], ivar=t, end_points=15) + sage: Ql = [[i,j] for i,j,k in P]; p = line(Ql, color='red') + sage: p += text("Rabbits", (12,37), fontsize=10, color='red') + sage: Qr = [[i,k] for i,j,k in P]; p += line(Qr, color='blue') + sage: p += text("Foxes", (12,7), fontsize=10, color='blue') + sage: p.axes_labels(["time", "population"]) + sage: p.show(gridlines = True) + +Sage example in ./sol/graphique.tex, line 154:: + + sage: n = 10; L = srange(6, 18, 12 / n); R = srange(3, 9, 6 / n) + sage: def g(x,y): v = vector(f(x, y)); return v / v.norm() + sage: q = plot_vector_field(g(x, y), (x, 0, 60), (y, 0, 36)) + sage: for j in range(n): + ....: P = desolve_system_rk4(f(x,y), [x,y], + ....: ics=[0,L[j],R[j]], ivar=t, end_points=15) + ....: Q = [[j,k] for i,j,k in P] + ....: q += line(Q, color=hue(.8-j/(2*n))) + sage: q.axes_labels(["rabbits", "foxes"]); q.show() + +Sage example in ./sol/graphique.tex, line 185:: + + sage: from scipy import integrate + sage: def dX_dt(X, t=0): return [X[1], 0.5*X[1] - X[0] - X[1]^3] + sage: t = srange(0, 40, 0.01); x0 = srange(-2, 2, 0.1); y0 = 2.5 + sage: CI = [[i, y0] for i in x0] + [[i, -y0] for i in x0] + sage: def g(x,y): v = vector(dX_dt([x, y])); return v / v.norm() + sage: x, y = var('x, y'); n = len(CI) + sage: q = plot_vector_field(g(x, y), (x, -3, 3), (y, -y0, y0)) + sage: for j in range(n): # long time + ....: X = integrate.odeint(dX_dt, CI[j], t) + ....: q += line(X, color=(1.7*j/(4*n),1.5*j/(4*n),1-3*j/(8*n))) + sage: X = integrate.odeint(dX_dt, [0.01,0], t) + sage: q += line(X, color = 'red'); q.show() + +Sage example in ./sol/graphique.tex, line 234:: + + sage: from scipy import integrate + sage: t = srange(0, 40, 0.2) + sage: n = 35; CI_cart = [[4, .2 * i] for i in range(n)] + sage: CI = list(map(lambda x: [sqrt(x[0]^2+x[1]^2), + ....: pi - arctan(x[1]/x[0])], CI_cart)) + sage: for alpha in [0.1, 0.5, 1, 1.25]: # long time + ....: dX_dt = lambda X, t=0: [cos(X[1])*(1-1/X[0]^2), + ....: -sin(X[1]) * (1/X[0]+1/X[0]^3) + 2*alpha/X[0]^2] + ....: q = circle((0, 0), 1, fill=True, rgbcolor='purple') + ....: for j in range(n): + ....: X = integrate.odeint(dX_dt, CI[j], t) + ....: Y = [[u[0]*cos(u[1]), u[0]*sin(u[1])] for u in X] + ....: q += line(Y, xmin = -4, xmax = 4, color='blue') + ....: q.show(aspect_ratio = 1, axes = False) + +""" diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphtheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphtheory_doctest.py new file mode 100644 index 00000000000..fc676f83bb3 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/graphtheory_doctest.py @@ -0,0 +1,55 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/graphtheory_doctest.sage) was *autogenerated* from ./sol/graphtheory.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/graphtheory_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/graphtheory.tex, line 5:: + + sage: def circulant(n,d): + ....: g = Graph(n) + ....: for u in range(n): + ....: for c in range(d): + ....: g.add_edge(u,(u+c)%n) + ....: return g + +Sage example in ./sol/graphtheory.tex, line 19:: + + sage: def kneser(n,k): + ....: g = Graph() + ....: g.add_vertices(Subsets(n,k)) + ....: for u in g: + ....: for v in g: + ....: if not u & v: + ....: g.add_edge(u,v) + ....: return g + +Sage example in ./sol/graphtheory.tex, line 33:: + + sage: def kneser(n,k): + ....: g = Graph() + ....: sommets = Set(range(n)) + ....: g.add_vertices(Subsets(sommets,k)) + ....: for u in g: + ....: for v in Subsets(sommets - u,k): + ....: g.add_edge(u,v) + ....: return g + +Sage example in ./sol/graphtheory.tex, line 59:: + + sage: g = graphs.PetersenGraph() + sage: def optimal_order(g): + ....: order = [] + ....: for color_class in g.coloring(): + ....: for v in color_class: + ....: order.append(v) + ....: return order + sage: optimal_order(g) + [1, 3, 5, 9, 0, 2, 6, 4, 7, 8] + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py new file mode 100644 index 00000000000..e11b6bad8d9 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py @@ -0,0 +1,58 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/integration_doctest.sage) was *autogenerated* from ./sol/integration.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/integration_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/integration.tex, line 22:: + + sage: x = var('x') + sage: def NCRule(n): + ....: P = prod([x - j for j in range(n)]) + ....: return [integrate(P / (x-i), x, 0, n-1) \ + ....: / (P/(x-i)).subs(x=i) for i in range(n)] + +Sage example in ./sol/integration.tex, line 35:: + + sage: def QuadNC(f, a, b, n): + ....: W = NCRule(n) + ....: ret = 0 + ....: for i in range(n): + ....: ret += f(a + (b-a)/(n-1)*i) * W[i] + ....: return (b-a)/(n-1)*ret + +Sage example in ./sol/integration.tex, line 49:: + + sage: QuadNC(lambda u: 1, 0, 1, 12) + 1 + sage: N(QuadNC(sin, 0, pi, 10)) + 1.99999989482634 + +Sage example in ./sol/integration.tex, line 59:: + + sage: numerical_integral(x * log(1+x), 0, 1) + (0.25, 2.7755575615628914e-15) + sage: N(QuadNC(lambda x: x * log(1+x), 0, 1, 19)) # abs tol 2e-14 + 0.250000000000001 + sage: numerical_integral(sqrt(1-x^2), 0, 1) # abs tol 2e-14 + (0.7853981677264822, 9.042725224536535e-07) + sage: N(pi/4) + 0.785398163397448 + sage: N(QuadNC(lambda x: sqrt(1-x^2), 0, 1, 20)) + 0.784586419900198 + +Sage example in ./sol/integration.tex, line 74:: + + sage: [N(QuadNC(lambda x: x * log(1+x), 0, 1, n) - 1/4) # abs tol 3e-16 + ....: for n in [2, 8, 16]] + [0.0965735902799726, 1.17408932933522e-7, 2.13449050101566e-13] + sage: [N(QuadNC(lambda x: sqrt(1-x^2), 0, 1, n) - pi/4) # abs tol 1e-13 + ....: for n in [2, 8, 16]] + [-0.285398163397448, -0.00524656673640445, -0.00125482109302663] + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py new file mode 100644 index 00000000000..4e24775c753 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py @@ -0,0 +1,58 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/linalg_doctest.sage) was *autogenerated* from ./sol/linalg.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/linalg_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/linalg.tex, line 89:: + + sage: A = matrix(GF(7),[[0,0,3,0,0],[1,0,6,0,0],[0,1,5,0,0], + ....: [0,0,0,0,5],[0,0,0,1,5]]) + sage: P = A.minpoly(); P + x^5 + 4*x^4 + 3*x^2 + 3*x + 1 + sage: P.factor() + (x^2 + 2*x + 2) * (x^3 + 2*x^2 + x + 4) + +Sage example in ./sol/linalg.tex, line 100:: + + sage: e1 = identity_matrix(GF(7),5)[0] + sage: e4 = identity_matrix(GF(7),5)[3] + sage: A.transpose().maxspin(e1) + [(1, 0, 0, 0, 0), (0, 1, 0, 0, 0), (0, 0, 1, 0, 0)] + sage: A.transpose().maxspin(e4) + [(0, 0, 0, 1, 0), (0, 0, 0, 0, 1)] + sage: A.transpose().maxspin(e1 + e4) + [(1, 0, 0, 1, 0), (0, 1, 0, 0, 1), (0, 0, 1, 5, 5), + (3, 6, 5, 4, 2), (1, 5, 3, 3, 0)] + +Sage example in ./sol/linalg.tex, line 168:: + + sage: def Similar(A, B): + ....: F1, U1 = A.frobenius(2) + ....: F2, U2 = B.frobenius(2) + ....: if F1 == F2: + ....: return True, ~U2*U1 + ....: else: + ....: return False, F1 - F2 + sage: B = matrix(ZZ, [[0,1,4,0,4],[4,-2,0,-4,-2],[0,0,0,2,1], + ....: [-4,2,2,0,-1],[-4,-2,1,2,0]]) + sage: U = matrix(ZZ, [[3,3,-9,-14,40],[-1,-2,4,2,1],[2,4,-7,-1,-13], + ....: [-1,0,1,4,-15],[-4,-13,26,8,30]]) + sage: A = (U^-1 * B * U).change_ring(ZZ) + sage: ok, V = Similar(A, B); ok + True + sage: V + [ 1 2824643/1601680 -6818729/1601680 -43439399/11211760 73108601/11211760] + [ 0 342591/320336 -695773/320336 -2360063/11211760 -10291875/2242352] + [ 0 -367393/640672 673091/640672 -888723/4484704 15889341/4484704] + [ 0 661457/3203360 -565971/3203360 13485411/22423520 -69159661/22423520] + [ 0 -4846439/3203360 7915157/3203360 -32420037/22423520 285914347/22423520] + sage: ok, V = Similar(2*A, B); ok + False + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py new file mode 100644 index 00000000000..14208cd98ba --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py @@ -0,0 +1,27 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/linsolve_doctest.sage) was *autogenerated* from ./sol/linsolve.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/linsolve_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/linsolve.tex, line 72:: + + sage: m = random_matrix(RDF,4) + sage: a = transpose(m)*m + sage: c = a.cholesky() + sage: U,S,V = c.SVD() + sage: X = U*S*transpose(U) + +Sage example in ./sol/linsolve.tex, line 84:: + + sage: M = (X*X-a) + sage: all(abs(M[i,j]) < 10^-14 + ....: for i in range(4) for j in range(4) ) + True + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py new file mode 100644 index 00000000000..8d11b0c1989 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py @@ -0,0 +1,49 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/lp_doctest.sage) was *autogenerated* from ./sol/lp.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/lp_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/lp.tex, line 1:: + + sage: sage.numerical.backends.generic_backend.default_solver = "Glpk" + +Sage example in ./sol/lp.tex, line 28:: + + sage: l = [28, 10, -89, 69, 42, -37, 76, 78, -40, 92, -93, 45] + sage: p = MixedIntegerLinearProgram() + sage: b = p.new_variable(binary = True) + sage: p.add_constraint(p.sum([ v*b[v] for v in l ]) == 0) + sage: p.add_constraint(p.sum([ b[v] for v in l ]) >= 1) + sage: p.solve() + 0.0 + sage: b = p.get_values(b) + sage: len([v for v in b if b[v] == 1]) + 5 + sage: sum([v for v in b if b[v] == 1]) + 0 + +Sage example in ./sol/lp.tex, line 64:: + + sage: g = graphs.PetersenGraph() + sage: p = MixedIntegerLinearProgram(maximization = False) + sage: b = p.new_variable(binary = True) + sage: for v in g: + ....: p.add_constraint( p.sum([b[u] for u in g.neighbors(v)]) + ....: + b[v] >= 1) + sage: p.set_objective( p.sum([ b[v] for v in g ]) ) + sage: p.solve() + 3.0 + sage: b = p.get_values(b) + sage: dom = [v for v in b if b[v] == 1] + sage: len(dom) + 3 + sage: all((v in dom or any(g.has_edge(x,v) for x in dom)) for v in g) + True + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py new file mode 100644 index 00000000000..356dd213697 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py @@ -0,0 +1,119 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/mpoly_doctest.sage) was *autogenerated* from ./sol/mpoly.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/mpoly_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/mpoly.tex, line 27:: + + sage: ring = QQ['x,y,z']; deg = 2 + sage: tmp1 = [(x,)*deg for x in (1,) + ring.gens()]; tmp1 + [(1, 1), (x, x), (y, y), (z, z)] + sage: tmp2 = flatten(tmp1); tmp2 + [1, 1, x, x, y, y, z, z] + sage: monomials = Subsets(tmp2, deg, submultiset=True); monomials + SubMultiset of [y, y, 1, 1, z, z, x, x] of size 2 + sage: monomials.list() + [[y, y], [y, 1], [y, z], [y, x], [1, 1], [1, z], [1, x], [z, z], [z, x], [x, x]] + +Sage example in ./sol/mpoly.tex, line 98:: + + sage: ['x%d' % n for n in [2,3,5,7]] + ['x2', 'x3', 'x5', 'x7'] + sage: R = PolynomialRing(QQ, ['x%d' % n for n in primes(40)]) + sage: R.inject_variables() + Defining x2, x3, x5, x7, x11, x13, x17, x19, x23, x29, x31, x37 + +Sage example in ./sol/mpoly.tex, line 116:: + + sage: R. = QQ[] + sage: J = R.ideal(x^2*y*z-18, x*y^3*z-24, x*y*z^4-6) + sage: J.variety(AA) # py2 + [{x: 3, z: 1, y: 2}] + sage: J.variety(AA) # py3 + [{z: 1, y: 2, x: 3}] + +Sage example in ./sol/mpoly.tex, line 124:: + + sage: V = J.variety(QQbar) + sage: [u for u in V if all(a in AA for a in u.values())] + [{z: 1, y: 2, x: 3}] + +Sage example in ./sol/mpoly.tex, line 137:: + + sage: M = matrix([ [p.degree(v) for v in (x,y,z)] + ....: for p in J.gens()]); M + [2 1 1] + [1 3 1] + [1 1 4] + +Sage example in ./sol/mpoly.tex, line 146:: + + sage: M.det() + 17 + +Sage example in ./sol/mpoly.tex, line 154:: + + sage: M.change_ring(GF(17)).right_kernel() + Vector space of degree 3 and dimension 1 over Finite Field of size 17 + Basis matrix: + [1 9 6] + +Sage example in ./sol/mpoly.tex, line 166:: + + sage: L. = QQ[sqrt(2-sqrt(3))]; L + Number Field in a with defining polynomial x^4 - 4*x^2 + 1 + sage: R. = QQ[] + sage: J1 = (x^2 + y^2 - 1, 16*x^2*y^2 - 1)*R + sage: sorted(J1.variety(L), key=str) + [{y: -1/2*a, x: -1/2*a^3 + 2*a}, + {y: -1/2*a, x: 1/2*a^3 - 2*a}, + {y: -1/2*a^3 + 2*a, x: -1/2*a}, + {y: -1/2*a^3 + 2*a, x: 1/2*a}, + {y: 1/2*a, x: -1/2*a^3 + 2*a}, + {y: 1/2*a, x: 1/2*a^3 - 2*a}, + {y: 1/2*a^3 - 2*a, x: -1/2*a}, + {y: 1/2*a^3 - 2*a, x: 1/2*a}] + +Sage example in ./sol/mpoly.tex, line 191:: + + sage: R. = QQ[]; J2 = (x^2+y^2-1, 4*x^2*y^2-1)*R + sage: basis = J2.normal_basis(); basis + [x*y^3, y^3, x*y^2, y^2, x*y, y, x, 1] + +Sage example in ./sol/mpoly.tex, line 200:: + + sage: xbasis = [(x*p).reduce(J2) for p in basis]; xbasis + [1/4*y, x*y^3, 1/4, x*y^2, -y^3 + y, x*y, -y^2 + 1, x] + sage: mat = matrix([ [xp[q] for q in basis] + ....: for xp in xbasis]) + sage: mat + [ 0 0 0 0 0 1/4 0 0] + [ 1 0 0 0 0 0 0 0] + [ 0 0 0 0 0 0 0 1/4] + [ 0 0 1 0 0 0 0 0] + [ 0 -1 0 0 0 1 0 0] + [ 0 0 0 0 1 0 0 0] + [ 0 0 0 -1 0 0 0 1] + [ 0 0 0 0 0 0 1 0] + +Sage example in ./sol/mpoly.tex, line 219:: + + sage: charpoly = mat.characteristic_polynomial(); charpoly + x^8 - 2*x^6 + 3/2*x^4 - 1/2*x^2 + 1/16 + sage: solve(SR(charpoly), SR(x)) + [x == -1/2*sqrt(2), x == 1/2*sqrt(2)] + +Sage example in ./sol/mpoly.tex, line 278:: + + sage: R. = PolynomialRing(QQ, order='lex') + sage: Rel = ideal(u-(s+c), v-(2*s*c+c^2-s^2), s^2+c^2-1) + sage: Rel.reduce(s^6) + 1/16*u^2*v^2 - 3/8*u^2*v + 7/16*u^2 + 1/8*v^2 - 1/8*v - 1/8 + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py new file mode 100644 index 00000000000..afa1a637b7e --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py @@ -0,0 +1,113 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/nonlinear_doctest.sage) was *autogenerated* from ./sol/nonlinear.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/nonlinear_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/nonlinear.tex, line 17:: + + sage: def intervalgen(f, phi, s, t): + ....: assert (f(s) * f(t) < 0), \ + ....: 'Wrong arguments: f(%s) * f(%s) >= 0)'%(s, t) + ....: yield s + ....: yield t + ....: while 1: + ....: u = phi(s, t) + ....: yield u + ....: fu = f(u) + ....: if fu == 0: + ....: return + ....: if fu * f(s) < 0: + ....: t = u + ....: else: + ....: s = u + +Sage example in ./sol/nonlinear.tex, line 40:: + + sage: f(x) = 4 * x - 1 + sage: a, b = 0, 1 + sage: phi(s, t) = (s + t) / 2 + sage: list(intervalgen(f, phi, a, b)) + [0, 1, 1/2, 1/4] + +Sage example in ./sol/nonlinear.tex, line 49:: + + sage: from types import GeneratorType, FunctionType + sage: def checklength(u, v, w, prec): + ....: return abs(v - u) < 2 * prec + sage: def iterate(series,check=checklength,prec=10^-5,maxit=100): + ....: assert isinstance(series, GeneratorType) + ....: assert isinstance(check, FunctionType) + ....: niter = 2 + ....: v, w = next(series), next(series) + ....: while (niter <= maxit): + ....: niter += 1 + ....: u, v, w = v, w, next(series) + ....: if check(u, v, w, prec): + ....: print('After {0} iterations: {1}'.format(niter, w)) + ....: return + ....: print('Failed after {0} iterations'.format(maxit)) + +Sage example in ./sol/nonlinear.tex, line 76:: + + sage: f(x) = 4 * sin(x) - exp(x) / 2 + 1 + sage: a, b = RR(-pi), RR(pi) + sage: def phi(s, t): return RR.random_element(s, t) + sage: random = intervalgen(f, phi, a, b) + sage: iterate(random, maxit=10000) # random + After 19 iterations: 2.15848379485564 + +Sage example in ./sol/nonlinear.tex, line 93:: + + sage: basering. = PolynomialRing(SR, 'x') + sage: p = x^2 + x + sage: p.roots(multiplicities=False) + [-1, 0] + +Sage example in ./sol/nonlinear.tex, line 101:: + + sage: from collections import deque + sage: basering = PolynomialRing(SR, 'x') + sage: q, method = None, None + sage: def quadraticgen(f, r, s): + ....: global q, method + ....: t = r - f(r) / f.derivative()(r) + ....: method = 'newton' + ....: yield t + ....: pts = deque([(p, f(p)) for p in (r, s, t)], maxlen=3) + ....: while True: + ....: q = basering.lagrange_polynomial(pts) + ....: roots = [r for r in q.roots(multiplicities=False) \ + ....: if CC(r).is_real()] + ....: approx = None + ....: for root in roots: + ....: if (root - pts[2][0]) * (root - pts[1][0]) < 0: + ....: approx = root + ....: break + ....: elif (root - pts[0][0]) * (root - pts[1][0]) < 0: + ....: pts.pop() + ....: approx = root + ....: break + ....: if approx: + ....: method = 'quadratic' + ....: else: + ....: method = 'dichotomy' + ....: approx = (pts[1][0] + pts[2][0]) / 2 + ....: pts.append((approx, f(approx))) + ....: yield pts[2][0] + +Sage example in ./sol/nonlinear.tex, line 141:: + + sage: basering = PolynomialRing(SR, 'x') + sage: a, b = pi/2, pi + sage: f(x) = 4 * sin(x) - exp(x) / 2 + 1 + sage: generator = quadraticgen(f, a, b) + sage: next(generator) + 1/2*pi - (e^(1/2*pi) - 10)*e^(-1/2*pi) + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py new file mode 100644 index 00000000000..ceae289f561 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py @@ -0,0 +1,169 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/numbertheory_doctest.sage) was *autogenerated* from ./sol/numbertheory.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/numbertheory_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/numbertheory.tex, line 9:: + + sage: def enum_carmichael(N, verbose=True): + ....: p = 3; s = 0 + ....: while p^3 <= N: + ....: s += enum_carmichael_p(N, p, verbose); p = next_prime(p) + ....: return s + +Sage example in ./sol/numbertheory.tex, line 26:: + + sage: def enum_carmichael_p (n, p, verbose): + ....: a = p; m = p*(p-1); q = p; s = 0 + ....: while p*q^2 <= n: + ....: q = next_prime(q) + ....: s += enum_carmichael_pq(n, a, m, p, q, verbose) + ....: return s + +Sage example in ./sol/numbertheory.tex, line 52:: + + sage: def enum_carmichael_pq(n,a,m,p,q,verbose): + ....: if (a-q) % gcd(m,q*(q-1)) != 0: return 0 + ....: s = 0 + ....: a = crt (a, q, m, q*(q-1)); m = lcm(m,q*(q-1)) + ....: while a <= p*q^2: a += m + ....: for t in range(a, n+1, m): + ....: r = t // (p*q) + ....: if is_prime(r) and t % (r-1) == 1: + ....: if verbose: + ....: print((p*q*r, factor(p*q*r))) + ....: s += 1 + ....: return s + +Sage example in ./sol/numbertheory.tex, line 68:: + + sage: enum_carmichael(10^4) + (561, 3 * 11 * 17) + (1105, 5 * 13 * 17) + (2465, 5 * 17 * 29) + (1729, 7 * 13 * 19) + (2821, 7 * 13 * 31) + (8911, 7 * 19 * 67) + (6601, 7 * 23 * 41) + 7 + sage: enum_carmichael(10^5, False) + 12 + sage: enum_carmichael(10^6, False) + 23 + sage: enum_carmichael(10^7, False) + 47 + +Sage example in ./sol/numbertheory.tex, line 94:: + + sage: def aliq(n): + ....: l = [n] + ....: while n != 1: + ....: n = sigma(n) - n + ....: if n in l: break + ....: l.append(n) + ....: return l + sage: l = aliq(840) # long time + sage: len(l), l[:5], l[-5:] # long time + (748, [840, 2040, 4440, 9240, 25320], [2714, 1606, 1058, 601, 1]) + +Sage example in ./sol/numbertheory.tex, line 106:: + + sage: p = points([(i, log(l[i])/log(10)) for i in range(len(l))]) # long time + +Sage example in ./sol/numbertheory.tex, line 173:: + + sage: def rk_aux(xc, yc, d, r2): + ....: s = 0 + ....: xmin = ceil((xc - sqrt(r2))/d) + ....: xmax = floor((xc + sqrt(r2))/d) + ....: for x in range(xmin,xmax+1): + ....: r3 = r2 - (d*x-xc)^2 # (d*y-yc)^2 <= r2 - (d*x-xc)^2 + ....: ymin = ceil((yc - sqrt(r3))/d) + ....: ymax = floor((yc + sqrt(r3))/d) + ....: s += ymax + 1 - ymin + ....: return s + +Sage example in ./sol/numbertheory.tex, line 219:: + + sage: def rk(k): # returns (r_k^2, xc, yc) + ....: if k == 2: return 1/4, 1/2, 0 + ....: dmax = (2*sqrt(k/pi)).n(); xamax = (sqrt(2*k/pi)).n() + ....: sol = (dmax/2)^2, 0, 0, 0 + ....: for xa in range(0, floor(xamax)+1): + ....: # if xa=0, ya > 0 since A should differ from O + ....: yamin = max(xa, 1) + ....: for ya in range(yamin, floor(sqrt(dmax^2-xa^2))+1): + ....: xbmin = 0 # we want xb*ya <= xa^2+ya^2 + ....: if xa == 0: + ....: xbmin = 1 # O, A, B should not be aligned + ....: xbmax = min(floor(dmax), floor((xa*xa+ya*ya)/ya)) + ....: for xb in range(xbmin, xbmax+1): + ....: ybmax = floor(sqrt(dmax^2-xb^2)) + ....: if xa > 0: # we want xb*ya+yb*xa <= xa^2+ya^2 + ....: tmp = floor((xa*xa+ya*ya-xb*ya)/xa) + ....: ybmax = min(ybmax, tmp) + ....: # if xb=0, yb > 0 since B should differ from O + ....: ybmin = 0 + ....: if xb == 0: + ....: ybmin = 1 + ....: for yb in range(ybmin,ybmax+1): + ....: d = 2*abs(xb*ya - xa*yb) + ....: if d != 0: + ....: ra2 = xa^2+ya^2; rb2 = xb^2+yb^2 + ....: xc = abs(ra2*yb - rb2*ya) + ....: yc = abs(rb2*xa - ra2*xb) + ....: r2 = ra2*rb2*((xa-xb)^2+(ya-yb)^2) + ....: m = rk_aux(xc,yc,d,r2) + ....: if m >= k and r2/d^2 < sol[0]: + ....: sol = r2/d^2, xc/d, yc/d + ....: return sol + +Sage example in ./sol/numbertheory.tex, line 253:: + + sage: for k in range(2,10): print((k, rk(k))) + (2, (1/4, 1/2, 0)) + (3, (1/2, 1/2, 1/2)) + (4, (1/2, 1/2, 1/2)) + (5, (1, 0, 1)) + (6, (5/4, 1/2, 1)) + (7, (25/16, 3/4, 1)) + (8, (2, 1, 1)) + (9, (2, 1, 1)) + +Sage example in ./sol/numbertheory.tex, line 283:: + + sage: def plotrk(k): + ....: r2, x0, y0 = rk(k); r = n(sqrt(r2)) + ....: var('x, y') + ....: c = implicit_plot((x-x0)^2+(y-y0)^2-r2, + ....: (x, x0-r-1/2, x0+r+1/2),(y, y0-r-1/2, y0+r+1/2)) + ....: center = points([(x0,y0)], pointsize=50, color='black') + ....: # we want (i-x0)^2+(j-y0)^2 <= r2 + ....: # thus |i-x0| <= r and |j-y0| <= r2 - (i-x0)^2 + ....: l = [(i, j) for i in range(ceil(x0-r), floor(x0+r)+1) + ....: for j in range(ceil(y0-sqrt(r^2-(i-x0)^2)), + ....: floor(y0+sqrt(r2-(i-x0)^2))+1)] + ....: d = points(l, pointsize=100) + ....: return (c+center+d).show(aspect_ratio=1, axes=True) + +Sage example in ./sol/numbertheory.tex, line 377:: + + sage: x1, x2, s2 = var('x1, x2, s2') + sage: n1 = 9; C1 = integrate(x1^n1, x1, x2, s2); C1 + 1/10*s2^10 - 1/10*x2^10 + +Sage example in ./sol/numbertheory.tex, line 390:: + + sage: x3, s3 = var('x3, s3') + sage: n2 = 7; C2 = integrate(C1.subs(s2=s3-x2)*x2^n2, x2, x3, s3/2); C2 + 44923/229417943040*s3^18 - 1/80*s3^10*x3^8 + 1/9*s3^9*x3^9 - 9/20*s3^8*x3^10 + + 12/11*s3^7*x3^11 - 7/4*s3^6*x3^12 + 126/65*s3^5*x3^13 - 3/2*s3^4*x3^14 + + 4/5*s3^3*x3^15 - 9/32*s3^2*x3^16 + 1/17*s3*x3^17 + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py new file mode 100644 index 00000000000..15f60192153 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py @@ -0,0 +1,109 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/polynomes_doctest.sage) was *autogenerated* from ./sol/polynomes.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/polynomes_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/polynomes.tex, line 10:: + + sage: x = polygen(QQ, 'y'); y = polygen(QQ, 'x') + +Sage example in ./sol/polynomes.tex, line 78:: + + sage: T = sage.symbolic.function_factory.function('T', nargs=2) + sage: def to_chebyshev_basis(pol): + ....: (x,) = pol.variables() + ....: res = 0 + ....: for n in range(pol.degree(), -1, -1): + ....: quo, pol = pol.quo_rem(chebyshev_T(n, x)) + ....: res += quo * T(n, x) + ....: return res + +Sage example in ./sol/polynomes.tex, line 105:: + + sage: x = polygen(QQ) + sage: p = 4*x^6 + 4*x^5 + 1/9*x^4 - 2*x^3 + 2/19*x^2 + 1 + sage: p_cheb = to_chebyshev_basis(p); p_cheb + 1/8*T(6, x) + 1/4*T(5, x) + 55/72*T(4, x) + 3/4*T(3, x) + + 2713/1368*T(2, x) + T(1, x) + 1069/456*T(0, x) + sage: p_cheb.substitute_function(T, chebyshev_T).expand() + 4*x^6 + 4*x^5 + 1/9*x^4 - 2*x^3 + 2/19*x^2 + 1 + +Sage example in ./sol/polynomes.tex, line 131:: + + sage: def mydiv(u, v, n): + ....: v0 = v.constant_coefficient() + ....: quo = 0; rem = u + ....: for k in range(n+1): + ....: c = rem[0]/v0 + ....: rem = (rem - c*v) >> 1 # shifting the coefficients + ....: quo += c*x^k + ....: return quo, rem + +Sage example in ./sol/polynomes.tex, line 161:: + + sage: def mydiv2(u, v, n): + ....: x = u.parent().gen() + ....: quo = (u / (v + O(x^(n+1)))).polynomial() + ....: rem = (u - quo*v) >> (n+1) + ....: return quo, rem + +Sage example in ./sol/polynomes.tex, line 179:: + + sage: x = polygen(QQ) + sage: u = -5*x^10 + 7/2*x^9 + 3*x^8 - x^6 - 1/3*x^5 - x^4 - 1/2*x^3 + 15*x^2 - 1/42*x + 2 + sage: v = 3*x^4 + 3/8*x^3 - 1/2*x^2 + x + 5/2 + sage: n = 8 + sage: q, r = mydiv(u, v, n) + sage: u - q*v - x^(n+1)*r + 0 + sage: q, r = mydiv2(u, v, n) + sage: u - q*v - x^(n+1)*r + 0 + +Sage example in ./sol/polynomes.tex, line 296:: + + sage: Poly. = Integers(10^5)[] + sage: P = x^1000 - 23*x^729 + 5*x^2 - 12*x - 7 + sage: Quo. = Poly.quo(P) + sage: op = s^(10^10000) # long time + sage: add(op[n]*(n+7) for n in range(1000)) # long time + 63477 + +Sage example in ./sol/polynomes.tex, line 383:: + + sage: from sage.matrix.berlekamp_massey import berlekamp_massey + sage: berlekamp_massey([1, 1, 2, 3, 8, 11, 34, 39, 148, 127]) + x^3 - 5*x + 2 + +Sage example in ./sol/polynomes.tex, line 408:: + + sage: R. = GF(17)[] + sage: pairs = [(0,-1), (1,0), (2,7), (3,5)] + sage: s = R(QQ['x'].lagrange_polynomial(pairs)); s + 6*x^3 + 2*x^2 + 10*x + 16 + sage: [s(i) for i in range(4)] + [16, 0, 7, 5] + +Sage example in ./sol/polynomes.tex, line 428:: + + sage: s.rational_reconstruct(mul(x-i for i in range(4)), 1, 2) + (15*x + 2, x^2 + 11*x + 15) + +Sage example in ./sol/polynomes.tex, line 454:: + + sage: S. = PowerSeriesRing(QQ) + sage: t = S(0) + sage: for i in range(7): # here t is correct up to degree 2i+1 + ....: # with O(x^15) we prevent the truncation order to grow + ....: t = (1+t^2).integral() + O(x^15) + sage: t + x + 1/3*x^3 + 2/15*x^5 + 17/315*x^7 + 62/2835*x^9 + 1382/155925*x^11 + + 21844/6081075*x^13 + O(x^15) + +""" + diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py new file mode 100644 index 00000000000..2dfe2109434 --- /dev/null +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py @@ -0,0 +1,60 @@ +## -*- encoding: utf-8 -*- +""" +This file (./sol/recequadiff_doctest.sage) was *autogenerated* from ./sol/recequadiff.tex, +with sagetex.sty version 2011/05/27 v2.3.1. +It contains the contents of all the sageexample environments from this file. +You should be able to doctest this file with: +sage -t ./sol/recequadiff_doctest.sage +It is always safe to delete this file; it is not used in typesetting your +document. + +Sage example in ./sol/recequadiff.tex, line 16:: + + sage: x = var('x') + sage: y = function('y')(x) + sage: ed = (desolve(y*diff(y,x)/sqrt(1+y^2) == sin(x),y)); ed + sqrt(y(x)^2 + 1) == _C - cos(x) + +Sage example in ./sol/recequadiff.tex, line 27:: + + sage: c = ed.variables()[0] + sage: assume(c-cos(x) > 0) + sage: sol = solve(ed,y) ; sol + [y(x) == -sqrt(_C^2 - 2*_C*cos(x) + cos(x)^2 - 1), + y(x) == sqrt(_C^2 - 2*_C*cos(x) + cos(x)^2 - 1)] + +Sage example in ./sol/recequadiff.tex, line 34:: + + sage: P = Graphics() + sage: for j in [0,1]: + ....: for k in range(0,20,2): + ....: P += plot(sol[j].substitute(c==2+0.25*k).rhs(),x,-3,3) + sage: P + Graphics object consisting of 20 graphics primitives + +Sage example in ./sol/recequadiff.tex, line 52:: + + sage: sol = desolve(diff(y,x)==sin(x)/cos(y), y, show_method=True) + sage: sol + [sin(y(x)) == _C - cos(x), 'separable'] + sage: solve(sol[0],y) + [y(x) == -arcsin(-_C + cos(x))] + +Sage example in ./sol/recequadiff.tex, line 80:: + + sage: x = var('x') + sage: y = function('y')(x) + sage: id(x) = x + sage: u = function('u')(x) + sage: d = diff(u*id,x) + sage: DE = (x*y*d == x**2+y**2).substitute(y == u*id) + sage: eq = desolve(DE,u) + sage: sol = solve(eq,u) + sage: sol + [u(x) == -sqrt(2*_C + 2*log(x)), u(x) == sqrt(2*_C + 2*log(x))] + sage: Y = [x*sol[0].rhs() , x*sol[1].rhs()] + sage: Y[0] + -sqrt(2*_C + 2*log(x))*x + +""" + diff --git a/src/sage/tests/books/judson-abstract-algebra/actions-sage.py b/src/sage/tests/books/judson-abstract-algebra/actions-sage.py index a80fe6f9683..bc26e3e56a1 100644 --- a/src/sage/tests/books/judson-abstract-algebra/actions-sage.py +++ b/src/sage/tests/books/judson-abstract-algebra/actions-sage.py @@ -42,8 +42,8 @@ sage: D = DihedralGroup(8) sage: C = D.center(); C - Subgroup of (Dihedral group of order 16 as a permutation group) - generated by [(1,5)(2,6)(3,7)(4,8)] + Subgroup generated by [(1,5)(2,6)(3,7)(4,8)] + of (Dihedral group of order 16 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: diff --git a/src/sage/tests/books/judson-abstract-algebra/cosets-sage.py b/src/sage/tests/books/judson-abstract-algebra/cosets-sage.py index 7018024d77b..0a6f355624c 100644 --- a/src/sage/tests/books/judson-abstract-algebra/cosets-sage.py +++ b/src/sage/tests/books/judson-abstract-algebra/cosets-sage.py @@ -90,17 +90,17 @@ sage: G = SymmetricGroup(3) sage: sg = G.subgroups(); sg - [Subgroup of (Symmetric group of order 3! as a permutation group) generated by [()], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(2,3)], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2)], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,3)], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2,3)], - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(2,3), (1,2,3)]] + [Subgroup generated by [()] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,2)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,3)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(1,2,3)] of (Symmetric group of order 3! as a permutation group), + Subgroup generated by [(2,3), (1,2,3)] of (Symmetric group of order 3! as a permutation group)] ~~~~~~~~~~~~~~~~~~~~~~ :: sage: H = sg[4]; H - Subgroup of (Symmetric group of order 3! as a permutation group) generated by [(1,2,3)] + Subgroup generated by [(1,2,3)] of (Symmetric group of order 3! as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: diff --git a/src/sage/tests/books/judson-abstract-algebra/homomorph-sage.py b/src/sage/tests/books/judson-abstract-algebra/homomorph-sage.py index 0aef924983d..822fd2bbdce 100644 --- a/src/sage/tests/books/judson-abstract-algebra/homomorph-sage.py +++ b/src/sage/tests/books/judson-abstract-algebra/homomorph-sage.py @@ -84,14 +84,15 @@ ~~~~~~~~~~~~~~~~~~~~~~ :: sage: K = phi.kernel(); K - Subgroup of (Cyclic group of order 12 as a permutation group) - generated by [(1,5,9)(2,6,10)(3,7,11)(4,8,12)] + Subgroup generated by [(1,5,9)(2,6,10)(3,7,11)(4,8,12)] + of (Cyclic group of order 12 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: sage: Im = phi.image(C12); Im - Subgroup of (Cyclic group of order 20 as a permutation group) - generated by [(1,6,11,16)(2,7,12,17)(3,8,13,18)(4,9,14,19)(5,10,15,20)] + Subgroup generated by + [(1,6,11,16)(2,7,12,17)(3,8,13,18)(4,9,14,19)(5,10,15,20)] + of (Cyclic group of order 20 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: @@ -117,16 +118,16 @@ sage: y = H.gen(1) sage: rho = PermutationGroupMorphism(G, H, [x, y]) sage: rho.kernel() - Subgroup of (Dihedral group of order 10 as a permutation group) - generated by [()] + Subgroup generated by + [()] of (Dihedral group of order 10 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: sage: Im = rho.image(G); Im - Subgroup of (Dihedral group of order 40 as a permutation group) - generated by + Subgroup generated by [(1,5,9,13,17)(2,6,10,14,18)(3,7,11,15,19)(4,8,12,16,20), - (1,20)(2,19)(3,18)(4,17)(5,16)(6,15)(7,14)(8,13)(9,12)(10,11)] + (1,20)(2,19)(3,18)(4,17)(5,16)(6,15)(7,14)(8,13)(9,12)(10,11)] + of (Dihedral group of order 40 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: diff --git a/src/sage/tests/books/judson-abstract-algebra/permute-sage.py b/src/sage/tests/books/judson-abstract-algebra/permute-sage.py index e31d14dd1f4..6c80a0611d6 100644 --- a/src/sage/tests/books/judson-abstract-algebra/permute-sage.py +++ b/src/sage/tests/books/judson-abstract-algebra/permute-sage.py @@ -231,8 +231,8 @@ sage: sigma = A4("(1,2,4)") sage: sg = A4.subgroup([sigma]) sage: sg - Subgroup of (Alternating group of order 4!/2 as a permutation group) - generated by [(1,2,4)] + Subgroup generated by + [(1,2,4)] of (Alternating group of order 4!/2 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: diff --git a/src/sage/tests/books/judson-abstract-algebra/sylow-sage.py b/src/sage/tests/books/judson-abstract-algebra/sylow-sage.py index 8b32726da91..b3312b83546 100644 --- a/src/sage/tests/books/judson-abstract-algebra/sylow-sage.py +++ b/src/sage/tests/books/judson-abstract-algebra/sylow-sage.py @@ -54,10 +54,10 @@ sage: G = DihedralGroup(18) sage: S2 = G.sylow_subgroup(2); S2 - Subgroup of (Dihedral group of order 36 as a permutation group) - generated by + Subgroup generated by [(2,18)(3,17)(4,16)(5,15)(6,14)(7,13)(8,12)(9,11), - (1,10)(2,11)(3,12)(4,13)(5,14)(6,15)(7,16)(8,17)(9,18)] + (1,10)(2,11)(3,12)(4,13)(5,14)(6,15)(7,16)(8,17)(9,18)] + of (Dihedral group of order 36 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: @@ -82,10 +82,10 @@ sage: G = DihedralGroup(18) sage: S3 = G.sylow_subgroup(3); S3 - Subgroup of (Dihedral group of order 36 as a permutation group) - generated by + Subgroup generated by [(1,7,13)(2,8,14)(3,9,15)(4,10,16)(5,11,17)(6,12,18), - (1,15,11,7,3,17,13,9,5)(2,16,12,8,4,18,14,10,6)] + (1,15,11,7,3,17,13,9,5)(2,16,12,8,4,18,14,10,6)] + of (Dihedral group of order 36 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: @@ -116,10 +116,10 @@ sage: S2 = G.sylow_subgroup(2) sage: S3 = G.sylow_subgroup(3) sage: N2 = G.normalizer(S2); N2 - Subgroup of (Dihedral group of order 36 as a permutation group) - generated by + Subgroup generated by [(2,18)(3,17)(4,16)(5,15)(6,14)(7,13)(8,12)(9,11), - (1,10)(2,11)(3,12)(4,13)(5,14)(6,15)(7,16)(8,17)(9,18)] + (1,10)(2,11)(3,12)(4,13)(5,14)(6,15)(7,16)(8,17)(9,18)] + of (Dihedral group of order 36 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: @@ -129,12 +129,12 @@ ~~~~~~~~~~~~~~~~~~~~~~ :: sage: N3 = G.normalizer(S3); N3 - Subgroup of (Dihedral group of order 36 as a permutation group) - generated by + Subgroup generated by [(2,18)(3,17)(4,16)(5,15)(6,14)(7,13)(8,12)(9,11), - (1,2)(3,18)(4,17)(5,16)(6,15)(7,14)(8,13)(9,12)(10,11), - (1,7,13)(2,8,14)(3,9,15)(4,10,16)(5,11,17)(6,12,18), - (1,15,11,7,3,17,13,9,5)(2,16,12,8,4,18,14,10,6)] + (1,2)(3,18)(4,17)(5,16)(6,15)(7,14)(8,13)(9,12)(10,11), + (1,7,13)(2,8,14)(3,9,15)(4,10,16)(5,11,17)(6,12,18), + (1,15,11,7,3,17,13,9,5)(2,16,12,8,4,18,14,10,6)] + of (Dihedral group of order 36 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: @@ -154,11 +154,11 @@ sage: N = G.normalizer(H) sage: N - Subgroup of (Dihedral group of order 36 as a permutation group) - generated by + Subgroup generated by [(1,2)(3,18)(4,17)(5,16)(6,15)(7,14)(8,13)(9,12)(10,11), - (1,5)(2,4)(6,18)(7,17)(8,16)(9,15)(10,14)(11,13), - (1,13,7)(2,14,8)(3,15,9)(4,16,10)(5,17,11)(6,18,12)] + (1,5)(2,4)(6,18)(7,17)(8,16)(9,15)(10,14)(11,13), + (1,13,7)(2,14,8)(3,15,9)(4,16,10)(5,17,11)(6,18,12)] + of (Dihedral group of order 36 as a permutation group) ~~~~~~~~~~~~~~~~~~~~~~ :: diff --git a/src/sage/tests/cmdline.py b/src/sage/tests/cmdline.py index 9edf619621f..08bda7c435b 100644 --- a/src/sage/tests/cmdline.py +++ b/src/sage/tests/cmdline.py @@ -55,7 +55,7 @@ - Jeroen Demeyer (2010-11-20): initial version (:trac:`10300`) """ -from subprocess import * +from subprocess import Popen, PIPE import os import select @@ -410,12 +410,10 @@ def test_executable(args, input="", timeout=100.0, **kwds): sage: os.chmod(d, 0o777) sage: (out, err, ret) = test_executable(["sage", "-t", "nonexisting.py"], cwd=d) sage: print(err) - Traceback (most recent call last): ... RuntimeError: refusing to run doctests... sage: (out, err, ret) = test_executable(["sage", "-tp", "1", "nonexisting.py"], cwd=d) sage: print(err) - Traceback (most recent call last): ... RuntimeError: refusing to run doctests... @@ -810,7 +808,7 @@ def test_executable(args, input="", timeout=100.0, **kwds): ....: "nbformat_minor": 2 ....: } ....: ''' - sage: t = '.. escape-backslashes\n.. default-role:: math\n\n\n::\n\n sage: 1+1\n 2\n\n\n' + sage: t = '.. escape-backslashes\n.. default-role:: math\n\n\n::\n\n sage: 1+1\n 2\n\n\n\n\n' sage: input = tmp_filename(ext='.ipynb') sage: output = tmp_filename(ext='.rst') sage: with open(input, 'w') as F: @@ -839,7 +837,7 @@ def test_executable(args, input="", timeout=100.0, **kwds): /// 4 }}} - sage: err + sage: err # py2 '' sage: ret 0 @@ -852,7 +850,7 @@ def test_executable(args, input="", timeout=100.0, **kwds): sage: with open(input, 'w') as F: ....: _ = F.write(s) sage: test_executable(["sage", "--rst2txt", input, output]) - ('', '', 0) + ('', ..., 0) sage: print(open(output, 'r').read()) {{{id=0| 2^10 @@ -873,11 +871,11 @@ def test_executable(args, input="", timeout=100.0, **kwds): sage: output = tmp_filename(ext='.sws') sage: with open(input, 'w') as F: ....: _ = F.write(s) - sage: test_executable(["sage", "--rst2sws", input, output]) + sage: test_executable(["sage", "--rst2sws", input, output]) # py2 ('', '', 0) - sage: import tarfile - sage: f = tarfile.open(output, 'r') - sage: print(f.extractfile('sage_worksheet/worksheet.html').read()) + sage: import tarfile # py2 + sage: f = tarfile.open(output, 'r') # py2 + sage: print(f.extractfile('sage_worksheet/worksheet.html').read()) # py2

    Thetitle

    {{{id=0| @@ -891,7 +889,7 @@ def test_executable(args, input="", timeout=100.0, **kwds): /// 4 }}} - sage: print(f.extractfile('sage_worksheet/worksheet.txt').read()) + sage: print(f.extractfile('sage_worksheet/worksheet.txt').read()) # py2 Thetitle system:sage diff --git a/src/sage/tests/french_book/README b/src/sage/tests/french_book/README deleted file mode 100644 index 58bc38d995f..00000000000 --- a/src/sage/tests/french_book/README +++ /dev/null @@ -1,7 +0,0 @@ -This directory contains all the example code from the french book -about Sage by Alexandre Casamayou, Guillaume Connan, Thierry Dumont, -Laurent Fousse, Franois Maltey, Matthias Meulien, Marc Mezzarobba, -Clment Pernet, Nicolas Thiry and Paul Zimmermann. Each file corresponds -to a chapter of the book. - -The book is freely available from http://sagebook.gforge.inria.fr/ diff --git a/src/sage/tests/french_book/__init__.py b/src/sage/tests/french_book/__init__.py deleted file mode 100644 index 2ef28f2f31e..00000000000 --- a/src/sage/tests/french_book/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# This comment is here so the file is non-empty (so Mercurial will check it in). diff --git a/src/sage/tests/french_book/calculus_doctest.py b/src/sage/tests/french_book/calculus_doctest.py deleted file mode 100644 index 1cd78b3d7af..00000000000 --- a/src/sage/tests/french_book/calculus_doctest.py +++ /dev/null @@ -1,813 +0,0 @@ -## -*- encoding: utf-8 -*- -""" -Doctests from French Sage book -Test file for chapter "Analyse et algèbre avec Sage" ("Calculus and -algebra with Sage") - -Tests extracted from ./calculus.tex. - -Sage example in ./calculus.tex, line 37:: - - sage: bool(x^2 + 3*x + 1 == (x+1)*(x+2)) - False - -Sage example in ./calculus.tex, line 74:: - - sage: a, x = var('a, x'); y = cos(x+a) * (x+1); y - (x + 1)*cos(a + x) - sage: y.subs(a=-x); y.subs(x=pi/2, a=pi/3); y.subs(x=0.5, a=2.3) - x + 1 - -1/4*sqrt(3)*(pi + 2) - -1.41333351100299 - sage: y(a=-x); y(x=pi/2, a=pi/3); y(x=0.5, a=2.3) - x + 1 - -1/4*sqrt(3)*(pi + 2) - -1.41333351100299 - -Sage example in ./calculus.tex, line 91:: - - sage: x, y, z = var('x, y, z') ; q = x*y + y*z + z*x - sage: bool(q(x=y, y=z, z=x) == q), bool(q(z=y)(y=x) == 3*x^2) - (True, True) - -Sage example in ./calculus.tex, line 99:: - - sage: y, z = var('y, z'); f = x^3 + y^2 + z - sage: f.subs(x^3 == y^2, z==1) - 2*y^2 + 1 - -Sage example in ./calculus.tex, line 110:: - - sage: f(x)=(2*x+1)^3 ; f(-3) - -125 - sage: f.expand() - x |--> 8*x^3 + 12*x^2 + 6*x + 1 - -Sage example in ./calculus.tex, line 122:: - - sage: y = var('y'); u = sin(x) + x*cos(y) - sage: v = u.function(x,y); v - (x, y) |--> x*cos(y) + sin(x) - sage: w(x, y) = u; w - (x, y) |--> x*cos(y) + sin(x) - -Sage example in ./calculus.tex, line 153:: - - sage: x, y = SR.var('x,y') - sage: p = (x+y)*(x+1)^2 - sage: p2 = p.expand(); p2 - x^3 + x^2*y + 2*x^2 + 2*x*y + x + y - -Sage example in ./calculus.tex, line 160:: - - sage: p2.collect(x) - x^3 + x^2*(y + 2) + x*(2*y + 1) + y - -Sage example in ./calculus.tex, line 165:: - - sage: ((x+y+sin(x))^2).expand().collect(sin(x)) - x^2 + 2*x*y + y^2 + 2*(x + y)*sin(x) + sin(x)^2 - -Sage example in ./calculus.tex, line 254:: - - sage: (x^x/x).simplify() - x^(x - 1) - -Sage example in ./calculus.tex, line 260:: - - sage: f = (e^x-1) / (1+e^(x/2)); f.canonicalize_radical() - e^(1/2*x) - 1 - -Sage example in ./calculus.tex, line 266:: - - sage: f = cos(x)^6 + sin(x)^6 + 3 * sin(x)^2 * cos(x)^2 - sage: f.simplify_trig() - 1 - -Sage example in ./calculus.tex, line 273:: - - sage: f = cos(x)^6; f.reduce_trig() - 1/32*cos(6*x) + 3/16*cos(4*x) + 15/32*cos(2*x) + 5/16 - sage: f = sin(5 * x); f.expand_trig() - 5*cos(x)^4*sin(x) - 10*cos(x)^2*sin(x)^3 + sin(x)^5 - -Sage example in ./calculus.tex, line 306:: - - sage: n = var('n'); f = factorial(n+1)/factorial(n) - sage: f.simplify_factorial() - n + 1 - -Sage example in ./calculus.tex, line 318:: - - sage: f = sqrt(abs(x)^2); f.canonicalize_radical() - abs(x) - sage: f = log(x*y); f.canonicalize_radical() - log(x) + log(y) - -Sage example in ./calculus.tex, line 371:: - - sage: assume(x > 0); bool(sqrt(x^2) == x) - True - sage: forget(x > 0); bool(sqrt(x^2) == x) - False - sage: n = var('n'); assume(n, 'integer'); sin(n*pi).simplify() - 0 - -Sage example in ./calculus.tex, line 420:: - - sage: a = var('a') - sage: c = (a+1)^2 - (a^2+2*a+1) - -Sage example in ./calculus.tex, line 425:: - - sage: eq = c * x == 0 - -Sage example in ./calculus.tex, line 430:: - - sage: eq2 = eq / c; eq2 - x == 0 - sage: solve(eq2, x) - [x == 0] - -Sage example in ./calculus.tex, line 437:: - - sage: solve(eq, x) - [x == x] - -Sage example in ./calculus.tex, line 444:: - - sage: expand(c) - 0 - -Sage example in ./calculus.tex, line 452:: - - sage: c = cos(a)^2 + sin(a)^2 - 1 - sage: eq = c*x == 0 - sage: solve(eq, x) - [x == 0] - -Sage example in ./calculus.tex, line 460:: - - sage: c.simplify_trig() - 0 - sage: c.is_zero() - True - -Sage example in ./calculus.tex, line 516:: - - sage: z, phi = var('z, phi') - sage: eq = z**2 - 2/cos(phi)*z + 5/cos(phi)**2 - 4 == 0; eq - z^2 - 2*z/cos(phi) + 5/cos(phi)^2 - 4 == 0 - -Sage example in ./calculus.tex, line 523:: - - sage: eq.lhs() - z^2 - 2*z/cos(phi) + 5/cos(phi)^2 - 4 - sage: eq.rhs() - 0 - -Sage example in ./calculus.tex, line 531:: - - sage: solve(eq, z) - [z == -(2*sqrt(cos(phi)^2 - 1) - 1)/cos(phi), - z == (2*sqrt(cos(phi)^2 - 1) + 1)/cos(phi)] - -Sage example in ./calculus.tex, line 537:: - - sage: y = var('y'); solve(y^6==y, y) - [y == 1/4*sqrt(5) + 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, y == -1/4*sqrt(5) + 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, y == -1/4*sqrt(5) - 1/4*I*sqrt(-2*sqrt(5) + 10) - 1/4, y == 1/4*sqrt(5) - 1/4*I*sqrt(2*sqrt(5) + 10) - 1/4, y == 1, y == 0] - -Sage example in ./calculus.tex, line 544:: - - sage: solve(x^2-1, x, solution_dict=True) - [{x: -1}, {x: 1}] - -Sage example in ./calculus.tex, line 550:: - - sage: solve([x+y == 3, 2*x+2*y == 6], x, y) - [[x == -r1 + 3, y == r1]] - -Sage example in ./calculus.tex, line 560:: - - sage: solve([cos(x)*sin(x) == 1/2, x+y == 0], x, y) - [[x == 1/4*pi + pi*z..., y == -1/4*pi - pi*z...]] - -Sage example in ./calculus.tex, line 565:: - - sage: solve(x^2+x-1 > 0, x) - [[x < -1/2*sqrt(5) - 1/2], [x > 1/2*sqrt(5) - 1/2]] - -Sage example in ./calculus.tex, line 583:: - - sage: x, y, z = var('x, y, z') - sage: solve([x^2 * y * z == 18, x * y^3 * z == 24,\ - ....: x * y * z^4 == 3], x, y, z) - [[x == (-2.767364733... - 1.713479699...*I), y == (-0.5701035039... + 2.003705978...*I), z == (-0.8016843376... - 0.1498607749...*I)], ...] - -Sage example in ./calculus.tex, line 597:: - - sage: expr = sin(x) + sin(2 * x) + sin(3 * x) - sage: solve(expr, x) - [sin(3*x) == -sin(2*x) - sin(x)] - -Sage example in ./calculus.tex, line 605:: - - sage: find_root(expr, 0.1, pi) - 2.094395102393195... - -Sage example in ./calculus.tex, line 610:: - - sage: f = expr.simplify_trig(); f - 2*(2*cos(x)^2 + cos(x))*sin(x) - sage: solve(f, x) - [x == 0, x == 2/3*pi, x == 1/2*pi] - -Sage example in ./calculus.tex, line 629:: - - sage: (x^3+2*x+1).roots(x) - [(-1/2*(1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) - - 1/3*(I*sqrt(3) - 1)/(1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3), 1), - (-1/2*(1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3)*(-I*sqrt(3) + 1) - - 1/3*(-I*sqrt(3) - 1)/(1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3), 1), - ((1/18*sqrt(59)*sqrt(3) - 1/2)^(1/3) - 2/3/(1/18*sqrt(59)*sqrt(3) - - 1/2)^(1/3), 1)] - -Sage example in ./calculus.tex, line 658:: - - sage: (x^3+2*x+1).roots(x, ring=RR) - [(-0.453397651516404, 1)] - -Sage example in ./calculus.tex, line 662:: - - sage: (x^3+2*x+1).roots(x, ring=CC) - [(-0.453397651516404, 1), - (0.226698825758202 - 1.46771150871022*I, 1), - (0.226698825758202 + 1.46771150871022*I, 1)] - -Sage example in ./calculus.tex, line 680:: - - sage: solve(x^(1/x)==(1/x)^x, x) - [(1/x)^x == x^(1/x)] - -Sage example in ./calculus.tex, line 706:: - - sage: y = function('y')(x) - sage: desolve(diff(y,x,x) + x*diff(y,x) + y == 0, y, [0,0,1]) - -1/2*I*sqrt(2)*sqrt(pi)*erf(1/2*I*sqrt(2)*x)*e^(-1/2*x^2) - -Sage example in ./calculus.tex, line 733:: - - sage: k, n = var('k, n') - sage: sum(k, k, 1, n).factor() - 1/2*(n + 1)*n - -Sage example in ./calculus.tex, line 739:: - - sage: n, k, y = var('n, k, y') - sage: sum(binomial(n,k) * x^k * y^(n-k), k, 0, n) - (x + y)^n - -Sage example in ./calculus.tex, line 745:: - - sage: k, n = var('k, n') - sage: sum(binomial(n,k), k, 0, n),\ - ....: sum(k * binomial(n, k), k, 0, n),\ - ....: sum((-1)^k*binomial(n,k), k, 0, n) - (2^n, 2^(n - 1)*n, 0) - -Sage example in ./calculus.tex, line 753:: - - sage: a, q, k, n = var('a, q, k, n') - sage: sum(a*q^k, k, 0, n) - (a*q^(n + 1) - a)/(q - 1) - -Sage example in ./calculus.tex, line 760:: - - sage: assume(abs(q) < 1) - sage: sum(a*q^k, k, 0, infinity) - -a/(q - 1) - -Sage example in ./calculus.tex, line 766:: - - sage: forget(); assume(q > 1); sum(a*q^k, k, 0, infinity) - Traceback (most recent call last): - ... - ValueError: Sum is divergent. - -Sage example in ./calculus.tex, line 842:: - - sage: limit((x**(1/3) - 2) / ((x + 19)**(1/3) - 3), x = 8) - 9/4 - sage: f(x) = (cos(pi/4-x)-tan(x))/(1-sin(pi/4 + x)) - sage: limit(f(x), x = pi/4) - Infinity - -Sage example in ./calculus.tex, line 855:: - - sage: limit(f(x), x = pi/4, dir='minus') - +Infinity - sage: limit(f(x), x = pi/4, dir='plus') - -Infinity - -Sage example in ./calculus.tex, line 898:: - - sage: u(n) = n^100 / 100^n - sage: u(2.);u(3.);u(4.);u(5.);u(6.);u(7.);u(8.);u(9.);u(10.) - 1.26765060022823e26 - 5.15377520732011e41 - 1.60693804425899e52 - 7.88860905221012e59 - 6.53318623500071e65 - 3.23447650962476e70 - 2.03703597633449e74 - 2.65613988875875e77 - 1.00000000000000e80 - -Sage example in ./calculus.tex, line 914:: - - sage: plot(u(x), x, 1, 40) - Graphics object consisting of 1 graphics primitive - -Sage example in ./calculus.tex, line 929:: - - sage: v(x) = diff(u(x), x); sol = solve(v(x) == 0, x); sol - [x == 50/log(10), x == 0] - sage: floor(sol[0].rhs()) - 21 - -Sage example in ./calculus.tex, line 938:: - - sage: limit(u(n), n=infinity) - 0 - sage: n0 = find_root(u(n) - 1e-8 == 0, 22, 1000); n0 - 105.07496210187252 - -Sage example in ./calculus.tex, line 988:: - - sage: taylor((1+arctan(x))**(1/x), x, 0, 3) - 1/16*x^3*e + 1/8*x^2*e - 1/2*x*e + e - -Sage example in ./calculus.tex, line 993:: - - sage: (ln(2*sin(x))).series(x==pi/6, 3) - (sqrt(3))*(-1/6*pi + x) + (-2)*(-1/6*pi + x)^2 - + Order(-1/216*(pi - 6*x)^3) - -Sage example in ./calculus.tex, line 1002:: - - sage: (ln(2*sin(x))).series(x==pi/6, 3).truncate() - -1/18*(pi - 6*x)^2 - 1/6*sqrt(3)*(pi - 6*x) - -Sage example in ./calculus.tex, line 1017:: - - sage: taylor((x**3+x)**(1/3) - (x**3-x)**(1/3), x, infinity, 2) - 2/3/x - -Sage example in ./calculus.tex, line 1041:: - - sage: tan(4*arctan(1/5)).simplify_trig() - 120/119 - sage: tan(pi/4+arctan(1/239)).simplify_trig() - 120/119 - -Sage example in ./calculus.tex, line 1052:: - - sage: f = arctan(x).series(x, 10); f - 1*x + (-1/3)*x^3 + 1/5*x^5 + (-1/7)*x^7 + 1/9*x^9 + Order(x^10) - sage: (16*f.subs(x==1/5) - 4*f.subs(x==1/239)).n(); pi.n() - 3.14159268240440 - 3.14159265358979 - -Sage example in ./calculus.tex, line 1093:: - - sage: k = var('k') - sage: sum(1/k^2, k, 1, infinity),\ - ....: sum(1/k^4, k, 1, infinity),\ - ....: sum(1/k^5, k, 1, infinity) - (1/6*pi^2, 1/90*pi^4, zeta(5)) - -Sage example in ./calculus.tex, line 1111:: - - sage: s = 2*sqrt(2)/9801*(sum((factorial(4*k)) * (1103+26390*k) / - ....: ((factorial(k)) ^ 4 * 396 ^ (4 * k)) for k in (0..11))) - sage: (1/s).n(digits=100) - 3.141592653589793238462643383279502884197169399375105820974... - sage: (pi-1/s).n(digits=100).n() - -4.36415445739398e-96 - -Sage example in ./calculus.tex, line 1139:: - - sage: n = var('n'); u = sin(pi*(sqrt(4*n^2+1)-2*n)) - sage: taylor(u, n, infinity, 3) - 1/4*pi/n - 1/384*(6*pi + pi^3)/n^3 - -Sage example in ./calculus.tex, line 1163:: - - sage: diff(sin(x^2), x) - 2*x*cos(x^2) - sage: function('f')(x); function('g')(x); diff(f(g(x)), x) - f(x) - g(x) - D[0](f)(g(x))*diff(g(x), x) - sage: diff(ln(f(x)), x) - diff(f(x), x)/f(x) - -Sage example in ./calculus.tex, line 1180:: - - sage: f(x,y) = x*y + sin(x^2) + e^(-x); derivative(f, x) - (x, y) |--> 2*x*cos(x^2) + y - e^(-x) - sage: derivative(f, y) - (x, y) |--> x - -Sage example in ./calculus.tex, line 1195:: - - sage: x, y = var('x, y'); f = ln(x**2+y**2) / 2 - sage: delta = diff(f,x,2) + diff(f,y,2) - sage: delta.simplify_full() - 0 - -Sage example in ./calculus.tex, line 1231:: - - sage: sin(x).integral(x, 0, pi/2) - 1 - sage: integrate(1/(1+x^2), x) - arctan(x) - sage: integrate(1/(1+x^2), x, -infinity, infinity) - pi - sage: integrate(exp(-x**2), x, 0, infinity) - 1/2*sqrt(pi) - -Sage example in ./calculus.tex, line 1241:: - - sage: integrate(exp(-x), x, -infinity, infinity) - Traceback (most recent call last): - ... - ValueError: Integral is divergent. - -Sage example in ./calculus.tex, line 1254:: - - sage: u = var('u'); f = x * cos(u) / (u^2 + x^2) - sage: assume(x>0); f.integrate(u, 0, infinity) - 1/2*pi*e^(-x) - sage: forget(); assume(x<0); f.integrate(u, 0, infinity) - -1/2*pi*e^x - -Sage example in ./calculus.tex, line 1270:: - - sage: integral_numerical(sin(x)/x, 0, 1) # abs tol 1e-12 - (0.94608307036718287, 1.0503632079297086e-14) - sage: g = integrate(exp(-x**2), x, 0, infinity) - sage: g, g.n() # abs tol 1e-12 - (1/2*sqrt(pi), 0.886226925452758) - sage: approx = integral_numerical(exp(-x**2), 0, infinity) - sage: approx # abs tol 1e-12 - (0.88622692545275705, 1.7147744320162414e-08) - sage: approx[0]-g.n() # abs tol 1e-12 - -8.88178419700125e-16 - -Sage example in ./calculus.tex, line 1482:: - - sage: A = matrix(QQ, [[1,2],[3,4]]); A - [1 2] - [3 4] - -Sage example in ./calculus.tex, line 1629:: - - sage: A = matrix(QQ, [[2,4,3],[-4,-6,-3],[3,3,1]]) - sage: A.characteristic_polynomial() - x^3 + 3*x^2 - 4 - sage: A.eigenvalues() - [1, -2, -2] - sage: A.minimal_polynomial().factor() - (x - 1) * (x + 2)^2 - -Sage example in ./calculus.tex, line 1641:: - - sage: A.eigenvectors_right() - [(1, [ - (1, -1, 1) - ], 1), (-2, [ - (1, -1, 0) - ], 2)] - -Sage example in ./calculus.tex, line 1652:: - - sage: A.jordan_form(transformation=True) - ( - [ 1| 0 0] - [--+-----] [ 1 1 1] - [ 0|-2 1] [-1 -1 0] - [ 0| 0 -2], [ 1 0 -1] - ) - -Sage example in ./calculus.tex, line 1686:: - - sage: A = matrix(QQ, [[1,-1/2],[-1/2,-1]]) - sage: A.jordan_form() - Traceback (most recent call last): - ... - RuntimeError: Some eigenvalue does not exist in Rational Field. - -Sage example in ./calculus.tex, line 1695:: - - sage: A = matrix(QQ, [[1,-1/2],[-1/2,-1]]) - sage: A.minimal_polynomial() - x^2 - 5/4 - -Sage example in ./calculus.tex, line 1701:: - - sage: R = QQ[sqrt(5)] - sage: A = A.change_ring(R) - sage: A.jordan_form(transformation=True, subdivide=False) - ( - [ 1/2*sqrt5 0] [ 1 1] - [ 0 -1/2*sqrt5], [-sqrt5 + 2 sqrt5 + 2] - ) - -Sage example in ./calculus.tex, line 1734:: - - sage: K. = NumberField(x^2 - 2) - sage: L. = K.extension(x^2 - 3) - sage: A = matrix(L, [[2, sqrt2*sqrt3, sqrt2], \ - ....: [sqrt2*sqrt3, 3, sqrt3], \ - ....: [sqrt2, sqrt3, 1]]) - sage: A.jordan_form(transformation=True) - ( - [6|0|0] - [-+-+-] - [0|0|0] [ 1 1 0] - [-+-+-] [1/2*sqrt2*sqrt3 0 1] - [0|0|0], [ 1/2*sqrt2 -sqrt2 -sqrt3] - ) - -""" - -""" -Tests extracted from sol/calculus.tex. - -Sage example in ./sol/calculus.tex, line 3:: - - sage: reset() - -Sage example in ./sol/calculus.tex, line 9:: - - sage: n, k = var('n, k'); p = 4; s = [n + 1] - sage: for k in (1..p): - ....: s += [factor((((n+1)^(k+1) \ - ....: - sum(binomial(k+1, j)\ - ....: * s[j] for j in (0..k-1))) / (k+1)))] - ... - sage: s - [n + 1, 1/2*(n + 1)*n, 1/6*(2*n + 1)*(n + 1)*n, - 1/4*(n + 1)^2*n^2, 1/30*(3*n^2 + 3*n - 1)*(2*n + 1)*(n + 1)*n] - -Sage example in ./sol/calculus.tex, line 34:: - - sage: x, h, a = var('x, h, a'); f = function('f') - sage: g(x) = taylor(f(x), x, a, 3) - sage: phi(h) = (g(a+3*h) - 3*g(a+2*h) \ - ....: + 3*g(a+h) - g(a)) / h^3 - sage: phi(h).expand() - diff(f(a), a, a, a) - -Sage example in ./sol/calculus.tex, line 57:: - - sage: n = 7; x, h, a = var('x h a') - sage: f = function('f') - sage: g(x) = taylor(f(x), x, a, n) - sage: phi(h) = sum(binomial(n,k)*(-1)^(n-k) \ - ....: * g(a+k*h) for k in (0..n)) / h^n - sage: phi(h).expand() - diff(f(a), a, a, a, a, a, a, a) - -Sage example in ./sol/calculus.tex, line 82:: - - sage: theta = 12*arctan(1/38) + 20*arctan(1/57) \ - ....: + 7*arctan(1/239) + 24*arctan(1/268) - sage: x = tan(theta) - sage: y = x.trig_expand() - sage: y.trig_simplify() - 1 - -Sage example in ./sol/calculus.tex, line 94:: - - sage: M = 12*(1/38)+20*(1/57)+ 7*(1/239)+24*(1/268) - sage: M - 37735/48039 - -Sage example in ./sol/calculus.tex, line 113:: - - sage: x = var('x') - sage: f(x) = taylor(arctan(x), x, 0, 21) - sage: approx = 4 * (12 * f(1/38) + 20 * f(1/57) - ....: + 7 * f(1/239) + 24 * f(1/268)) - sage: approx.n(digits = 50); pi.n(digits = 50) - 3.1415926535897932384626433832795028851616168852864 - 3.1415926535897932384626433832795028841971693993751 - sage: approx.n(digits = 50) - pi.n(digits = 50) - 9.6444748591132486785420917537404705292978817080880e-37 - -Sage example in ./sol/calculus.tex, line 143:: - - sage: n = var('n') - sage: phi = lambda x: n*pi+pi/2-arctan(1/x) - sage: x = pi*n - sage: for i in range(4): - ....: x = taylor(phi(x), n, oo, 2*i); x - 1/2*pi + pi*n - 1/2*pi + pi*n - 1/(pi*n) + 1/2/(pi*n^2) - 1/2*pi + pi*n - 1/(pi*n) + 1/2/(pi*n^2) - - 1/12*(3*pi^2 + 8)/(pi^3*n^3) + 1/8*(pi^2 + 8)/(pi^3*n^4) - 1/2*pi + pi*n - 1/(pi*n) + 1/2/(pi*n^2) - - 1/12*(3*pi^2 + 8)/(pi^3*n^3) + 1/8*(pi^2 + 8)/(pi^3*n^4) - - 1/240*(15*pi^4 + 240*pi^2 + 208)/(pi^5*n^5) - + 1/96*(3*pi^4 + 80*pi^2 + 208)/(pi^5*n^6) - -Sage example in ./sol/calculus.tex, line 192:: - - sage: h = var('h') - sage: f(x, y) = x * y * (x**2 - y**2) / (x**2 + y**2) - sage: D1f(x, y) = diff(f(x,y), x) - sage: limit((D1f(0,h) - 0) / h, h=0) - -1 - sage: D2f(x, y) = diff(f(x,y), y) - sage: limit((D2f(h,0) - 0) / h, h=0) - 1 - sage: g = plot3d(f(x, y), (x, -3, 3), (y, -3, 3)) - -Sage example in ./sol/calculus.tex, line 230:: - - sage: n, t = var('n, t') - sage: v(n)=(4/(8*n+1)-2/(8*n+4)-1/(8*n+5)-1/(8*n+6))*1/16^n - sage: assume(8*n+1>0) - sage: u(n) = integrate((4*sqrt(2)-8*t^3-4*sqrt(2)*t^4\ - ....: -8*t^5) * t^(8*n), t, 0, 1/sqrt(2)) - sage: (u(n)-v(n)).canonicalize_radical() - 0 - -Sage example in ./sol/calculus.tex, line 258:: - - sage: t = var('t') - sage: J = integrate((4*sqrt(2)-8*t^3 \ - ....: - 4*sqrt(2)*t^4-8*t^5)\ - ....: / (1-t^8), t, 0, 1/sqrt(2)) - sage: J.canonicalize_radical() - pi + 2*log(sqrt(2) + 1) + 2*log(sqrt(2) - 1) - -Sage example in ./sol/calculus.tex, line 272:: - - sage: ln(exp(J).simplify_log()) - pi - -Sage example in ./sol/calculus.tex, line 281:: - - sage: l = sum(v(n) for n in (0..40)); l.n(digits=60) - 3.14159265358979323846264338327950288419716939937510581474759 - sage: pi.n(digits=60) - 3.14159265358979323846264338327950288419716939937510582097494 - sage: print("%e" % (l-pi).n(digits=60)) - -6.227358e-54 - -Sage example in ./sol/calculus.tex, line 302:: - - sage: X = var('X') - sage: ps = lambda f,g : integral(f * g, X, -pi, pi) - sage: n = 5; Q = sin(X) - sage: a, a0, a1, a2, a3, a4, a5 = var('a a0 a1 a2 a3 a4 a5') - sage: a= [a0, a1, a2, a3, a4, a5] - sage: P = sum(a[k] * X^k for k in (0..n)) - sage: equ = [ps(P - Q, X^k) for k in (0..n)] - sage: sol = solve(equ, a) - sage: P = sum(sol[0][k].rhs() * X^k for k in (0..n)) - sage: g = plot(P,X,-6,6,color='red') + plot(Q,X,-6,6,color='blue') - -Sage example in ./sol/calculus.tex, line 353:: - - sage: p, e = var('p e') - sage: theta1, theta2, theta3 = var('theta1 theta2 theta3') - sage: r(theta) = p / (1-e * cos(theta)) - sage: r1 = r(theta1); r2 = r(theta2); r3 = r(theta3) - sage: R1 = vector([r1 * cos(theta1), r1 * sin(theta1), 0]) - sage: R2 = vector([r2 * cos(theta2), r2 * sin(theta2), 0]) - sage: R3 = vector([r3 * cos(theta3), r3 * sin(theta3), 0]) - -Sage example in ./sol/calculus.tex, line 365:: - - sage: D = R1.cross_product(R2) + R2.cross_product(R3) \ - ....: + R3.cross_product(R1) - sage: i = vector([1, 0, 0]) - sage: S = (r1 - r3) * R2 + (r3 - r2) * R1 + (r2 - r1) * R3 - sage: V = S + e * i.cross_product(D) - sage: [x.simplify_full() for x in V] - [0, 0, 0] - -Sage example in ./sol/calculus.tex, line 390:: - - sage: N = r3 * R1.cross_product(R2) + r1 * R2.cross_product(R3)\ - ....: + r2 * R3.cross_product(R1) - sage: W = p * S + e * i.cross_product(N) - sage: [x.simplify_full() for x in W] - [0, 0, 0] - -Sage example in ./sol/calculus.tex, line 409:: - - sage: R1=vector([0,1.,0]);R2=vector([2.,2.,0]);R3=vector([3.5,0,0]) - sage: r1 = R1.norm(); r2 = R2.norm(); r3 = R3.norm() - sage: D = R1.cross_product(R2) + R2.cross_product(R3) \ - ....: + R3.cross_product(R1) - sage: S = (r1 - r3) * R2 + (r3 - r2) * R1 + (r2 - r1) * R3 - sage: V = S + e * i.cross_product(D) - sage: N = r3 * R1.cross_product(R2) + r1 * R2.cross_product(R3) \ - ....: + r2 * R3.cross_product(R1) - sage: i = vector([1, 0, 0]); W = p * S + e * i.cross_product(N) - sage: e = S.norm() / D.norm(); p = N.norm() / D.norm() - sage: a = p/(1-e^2); c = a * e; b = sqrt(a^2 - c^2) - sage: X = S.cross_product(D); i = X / X.norm() - sage: phi = atan2(i[1],i[0]) * 180 / pi.n() - sage: print("%.3f %.3f %.3f %.3f %.3f %.3f" % (a, b, c, e, p, phi)) - 2.360 1.326 1.952 0.827 0.746 17.917 - -Sage example in ./sol/calculus.tex, line 445:: - - sage: A = matrix(QQ, [[2, -3, 2, -12, 33], - ....: [ 6, 1, 26, -16, 69], - ....: [10, -29, -18, -53, 32], - ....: [2, 0, 8, -18, 84]]) - sage: A.right_kernel() - Vector space of degree 5 and dimension 2 over Rational Field - Basis matrix: - [ 1 0 -7/34 5/17 1/17] - [ 0 1 -3/34 -10/17 -2/17] - -Sage example in ./sol/calculus.tex, line 463:: - - sage: H = A.echelon_form() - -Sage example in ./sol/calculus.tex, line 484:: - - sage: A.column_space() - Vector space of degree 4 and dimension 3 over Rational Field - Basis matrix: - [ 1 0 0 1139/350] - [ 0 1 0 -9/50] - [ 0 0 1 -12/35] - -Sage example in ./sol/calculus.tex, line 496:: - - sage: S.=QQ[] - sage: C = matrix(S, 4, 1, [x, y, z, t]) - sage: B = block_matrix([A, C], ncols=2) - sage: C = B.echelon_form() - sage: C[3,5]*350 - -1139*x + 63*y + 120*z + 350*t - -Sage example in ./sol/calculus.tex, line 511:: - - sage: K = A.kernel(); K - Vector space of degree 4 and dimension 1 over Rational Field - Basis matrix: - [ 1 -63/1139 -120/1139 -350/1139] - -Sage example in ./sol/calculus.tex, line 519:: - - sage: matrix(K.0).right_kernel() - Vector space of degree 4 and dimension 3 over Rational Field - Basis matrix: - [ 1 0 0 1139/350] - [ 0 1 0 -9/50] - [ 0 0 1 -12/35] - -Sage example in ./sol/calculus.tex, line 533:: - - sage: A = matrix(QQ, [[-2, 1, 1], [8, 1, -5], [4, 3, -3]]) - sage: C = matrix(QQ, [[1, 2, -1], [2, -1, -1], [-5, 0, 3]]) - -Sage example in ./sol/calculus.tex, line 540:: - - sage: B = C.solve_left(A); B - [ 0 -1 0] - [ 2 3 0] - [ 2 1 0] - -Sage example in ./sol/calculus.tex, line 548:: - - sage: C.left_kernel() - Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [1 2 1] - -Sage example in ./sol/calculus.tex, line 560:: - - sage: x, y, z = var('x, y, z'); v = matrix([[1, 2, 1]]) - sage: B = B+(x*v).stack(y*v).stack(z*v); B - [ x 2*x - 1 x] - [ y + 2 2*y + 3 y] - [ z + 2 2*z + 1 z] - -Sage example in ./sol/calculus.tex, line 568:: - - sage: A == B*C - True - -""" -# This file was *autogenerated* from the file calculus_doctest.sage. diff --git a/src/sage/tests/french_book/domaines_doctest.py b/src/sage/tests/french_book/domaines_doctest.py deleted file mode 100644 index 32f0ae461d0..00000000000 --- a/src/sage/tests/french_book/domaines_doctest.py +++ /dev/null @@ -1,441 +0,0 @@ -## -*- encoding: utf-8 -*- -""" -Doctests from French Sage book -Test file for chapter "Domaines de calcul" ("Computation Domains") - -Tests extracted from ./domaines.tex. - -Sage example in ./domaines.tex, line 6:: - - sage: x = var('x') - -Sage example in ./domaines.tex, line 38:: - - sage: o = 12/35 - sage: type(o) - - -Sage example in ./domaines.tex, line 45:: - - sage: type(12/35) - - -Sage example in ./domaines.tex, line 77:: - - sage: o = 720 - sage: o.factor() - 2^4 * 3^2 * 5 - -Sage example in ./domaines.tex, line 85:: - - sage: type(o).factor(o) - 2^4 * 3^2 * 5 - -Sage example in ./domaines.tex, line 95:: - - sage: 720.factor() - 2^4 * 3^2 * 5 - -Sage example in ./domaines.tex, line 102:: - - sage: o = 720 / 133 - sage: o.numerator().factor() - 2^4 * 3^2 * 5 - -Sage example in ./domaines.tex, line 140:: - - sage: 3 * 7 - 21 - -Sage example in ./domaines.tex, line 146:: - - sage: (2/3) * (6/5) - 4/5 - -Sage example in ./domaines.tex, line 151:: - - sage: (1 + I) * (1 - I) - 2 - -Sage example in ./domaines.tex, line 156:: - - sage: (x + 2) * (x + 1) - (x + 2)*(x + 1) - sage: (x + 1) * (x + 2) - (x + 2)*(x + 1) - -Sage example in ./domaines.tex, line 177:: - - sage: def puissance_quatre(a): - ....: a = a * a - ....: a = a * a - ....: return a - -Sage example in ./domaines.tex, line 185:: - - sage: puissance_quatre(2) - 16 - sage: puissance_quatre(3/2) - 81/16 - sage: puissance_quatre(I) - 1 - sage: puissance_quatre(x+1) - (x + 1)^4 - sage: M = matrix([[0,-1],[1,0]]); M - [ 0 -1] - [ 1 0] - sage: puissance_quatre(M) - [1 0] - [0 1] - -Sage example in ./domaines.tex, line 215:: - - sage: t = type(5/1); t - - sage: t == type(5) - False - -Sage example in ./domaines.tex, line 288:: - - sage: a = 5; a - 5 - sage: a.is_unit() - False - -Sage example in ./domaines.tex, line 295:: - - sage: a = 5/1; a - 5 - sage: a.is_unit() - True - -Sage example in ./domaines.tex, line 311:: - - sage: parent(5) - Integer Ring - sage: parent(5/1) - Rational Field - -Sage example in ./domaines.tex, line 318:: - - sage: ZZ - Integer Ring - sage: QQ - Rational Field - -Sage example in ./domaines.tex, line 326:: - - sage: QQ(5).parent() - Rational Field - sage: ZZ(5/1).parent() - Integer Ring - sage: ZZ(1/5) - Traceback (most recent call last): - ... - TypeError: no conversion of this rational to integer - -Sage example in ./domaines.tex, line 340:: - - sage: ZZ(1), QQ(1), RR(1), CC(1) - (1, 1, 1.00000000000000, 1.00000000000000) - -Sage example in ./domaines.tex, line 355:: - - sage: cartesian_product([QQ, QQ]) - The Cartesian product of (Rational Field, Rational Field) - -Sage example in ./domaines.tex, line 360:: - - sage: ZZ.fraction_field() - Rational Field - -Sage example in ./domaines.tex, line 365:: - - sage: ZZ['x'] - Univariate Polynomial Ring in x over Integer Ring - -Sage example in ./domaines.tex, line 373:: - - sage: Z5 = GF(5); Z5 - Finite Field of size 5 - sage: P = Z5['x']; P - Univariate Polynomial Ring in x over Finite Field of size 5 - sage: M = MatrixSpace(P, 3, 3); M - Full MatrixSpace of 3 by 3 dense matrices over - Univariate Polynomial Ring in x over Finite Field of size 5 - -Sage example in ./domaines.tex, line 383:: - - sage: M.random_element() # random - [2*x^2 + 3*x + 4 4*x^2 + 2*x + 2 4*x^2 + 2*x] - [ 3*x 2*x^2 + x + 3 3*x^2 + 4*x] - [ 4*x^2 + 3 3*x^2 + 2*x + 4 2*x + 4] - -Sage example in ./domaines.tex, line 415:: - - sage: QQ.category() - Join of Category of number fields - and Category of quotient fields - and Category of metric spaces - -Sage example in ./domaines.tex, line 421:: - - sage: QQ in Fields() - True - -Sage example in ./domaines.tex, line 427:: - - sage: QQ in CommutativeAdditiveGroups() - True - -Sage example in ./domaines.tex, line 432:: - - sage: QQ['x'] in EuclideanDomains() - True - -Sage example in ./domaines.tex, line 514:: - - sage: 5.parent() - Integer Ring - -Sage example in ./domaines.tex, line 521:: - - sage: type(factor(4)) - - -Sage example in ./domaines.tex, line 532:: - - sage: int(5) - 5 - sage: type(int(5)) - <... 'int'> - -Sage example in ./domaines.tex, line 539:: - - sage: Integer(5) - 5 - sage: type(Integer(5)) - - -Sage example in ./domaines.tex, line 551:: - - sage: factorial(99) / factorial(100) - 1 / 50 - -1/100 - -Sage example in ./domaines.tex, line 574:: - - sage: 72/53-5/3*2.7 - -3.14150943396227 - -Sage example in ./domaines.tex, line 580:: - - sage: cos(1), cos(1.) - (cos(1), 0.540302305868140) - -Sage example in ./domaines.tex, line 589:: - - sage: pi.n(digits=50) # N(pi,digits=10^6) aussi possible - 3.1415926535897932384626433832795028841971693993751 - -Sage example in ./domaines.tex, line 600:: - - sage: z = CC(1,2); z.arg() - 1.10714871779409 - -Sage example in ./domaines.tex, line 608:: - - sage: I.parent() - Symbolic Ring - -Sage example in ./domaines.tex, line 613:: - - sage: (1.+2.*I).parent() - Symbolic Ring - sage: CC(1.+2.*I).parent() - Complex Field with 53 bits of precision - -Sage example in ./domaines.tex, line 623:: - - sage: z = 3 * exp(I*pi/4) - sage: z.real(), z.imag(), z.abs().canonicalize_radical() - (3/2*sqrt(2), 3/2*sqrt(2), 3) - -Sage example in ./domaines.tex, line 679:: - - sage: x, y = var('x, y') - sage: bool( (x-y)*(x+y) == x^2-y^2 ) - True - -Sage example in ./domaines.tex, line 697:: - - sage: Z4 = IntegerModRing(4); Z4 - Ring of integers modulo 4 - sage: m = Z4(7); m - 3 - -Sage example in ./domaines.tex, line 706:: - - sage: 3 * m + 1 - 2 - -Sage example in ./domaines.tex, line 712:: - - sage: Z3 = GF(3); Z3 - Finite Field of size 3 - -Sage example in ./domaines.tex, line 740:: - - sage: a = matrix(QQ, [[1,2,3],[2,4,8],[3,9,27]]) - sage: (a^2 + 1) * a^(-1) - [ -5 13/2 7/3] - [ 7 1 25/3] - [ 2 19/2 27] - -Sage example in ./domaines.tex, line 752:: - - sage: M = MatrixSpace(QQ,3,3) - sage: M - Full MatrixSpace of 3 by 3 dense matrices over Rational Field - sage: a = M([[1,2,3],[2,4,8],[3,9,27]]) - sage: (a^2 + 1) * a^(-1) - [ -5 13/2 7/3] - [ 7 1 25/3] - [ 2 19/2 27] - -Sage example in ./domaines.tex, line 771:: - - sage: P = ZZ['x']; P - Univariate Polynomial Ring in x over Integer Ring - sage: F = P.fraction_field(); F - Fraction Field of - Univariate Polynomial Ring in x over Integer Ring - sage: p = P(x+1) * P(x); p - x^2 + x - sage: p + 1/p - (x^4 + 2*x^3 + x^2 + 1)/(x^2 + x) - sage: parent(p + 1/p) - Fraction Field of - Univariate Polynomial Ring in x over Integer Ring - -Sage example in ./domaines.tex, line 826:: - - sage: k.
    = NumberField(x^3 + x + 1); a^3; a^4+3*a - -a - 1 - -a^2 + 2*a - -Sage example in ./domaines.tex, line 845:: - - sage: parent(sin(x)) - Symbolic Ring - -Sage example in ./domaines.tex, line 850:: - - sage: SR - Symbolic Ring - -Sage example in ./domaines.tex, line 855:: - - sage: SR.category() - Category of commutative rings - -Sage example in ./domaines.tex, line 884:: - - sage: R = QQ['x1,x2,x3,x4']; R - Multivariate Polynomial Ring in x1, x2, x3, x4 over Rational Field - sage: x1, x2, x3, x4 = R.gens() - -Sage example in ./domaines.tex, line 890:: - - sage: x1 * (x2 - x3) - x1*x2 - x1*x3 - -Sage example in ./domaines.tex, line 895:: - - sage: (x1+x2)*(x1-x2) - (x1^2 -x2^2) - 0 - -Sage example in ./domaines.tex, line 902:: - - sage: prod( (a-b) for (a,b) in Subsets([x1,x2,x3,x4],2) ) - x1^3*x2^2*x3 - x1^2*x2^3*x3 - x1^3*x2*x3^2 + x1*x2^3*x3^2 - + x1^2*x2*x3^3 - x1*x2^2*x3^3 - x1^3*x2^2*x4 + x1^2*x2^3*x4 - + x1^3*x3^2*x4 - x2^3*x3^2*x4 - x1^2*x3^3*x4 + x2^2*x3^3*x4 - + x1^3*x2*x4^2 - x1*x2^3*x4^2 - x1^3*x3*x4^2 + x2^3*x3*x4^2 - + x1*x3^3*x4^2 - x2*x3^3*x4^2 - x1^2*x2*x4^3 + x1*x2^2*x4^3 - + x1^2*x3*x4^3 - x2^2*x3*x4^3 - x1*x3^2*x4^3 + x2*x3^2*x4^3 - -Sage example in ./domaines.tex, line 914:: - - # example slightly modified with respect to the book, since on some - # machines we get a negative sign - sage: x1, x2, x3, x4 = SR.var('x1, x2, x3, x4') - sage: p = prod( (a-b) for (a,b) in Subsets([x1,x2,x3,x4],2) ) - sage: bool(p == (x1 - x2)*(x1 - x3)*(x1 - x4)*(x2 - x3)*(x2 - x4)*(x3 - x4)) or bool(p == -(x1 - x2)*(x1 - x3)*(x1 - x4)*(x2 - x3)*(x2 - x4)*(x3 - x4)) - True - -Sage example in ./domaines.tex, line 938:: - - sage: x = var('x') - sage: p = 54*x^4+36*x^3-102*x^2-72*x-12 - sage: factor(p) - 6*(x^2 - 2)*(3*x + 1)^2 - -Sage example in ./domaines.tex, line 963:: - - sage: R = ZZ['x']; R - Univariate Polynomial Ring in x over Integer Ring - -Sage example in ./domaines.tex, line 968:: - - sage: q = R(p); q - 54*x^4 + 36*x^3 - 102*x^2 - 72*x - 12 - -Sage example in ./domaines.tex, line 974:: - - sage: parent(q) - Univariate Polynomial Ring in x over Integer Ring - -Sage example in ./domaines.tex, line 979:: - - sage: factor(q) - 2 * 3 * (3*x + 1)^2 * (x^2 - 2) - -Sage example in ./domaines.tex, line 985:: - - sage: R = QQ['x']; R - Univariate Polynomial Ring in x over Rational Field - sage: q = R(p); q - 54*x^4 + 36*x^3 - 102*x^2 - 72*x - 12 - sage: factor(q) - (54) * (x + 1/3)^2 * (x^2 - 2) - -Sage example in ./domaines.tex, line 1001:: - - sage: R = ComplexField(16)['x']; R - Univariate Polynomial Ring in x over Complex Field - with 16 bits of precision - sage: q = R(p); q - 54.00*x^4 + 36.00*x^3 - 102.0*x^2 - 72.00*x - 12.00 - sage: factor(q) - (54.00) * (x - 1.414) * (x + 0.3333)^2 * (x + 1.414) - -Sage example in ./domaines.tex, line 1012:: - - sage: R = QQ[sqrt(2)]['x']; R - Univariate Polynomial Ring in x over Number Field in sqrt2 - with defining polynomial x^2 - 2 - sage: q = R(p); q - 54*x^4 + 36*x^3 - 102*x^2 - 72*x - 12 - sage: factor(q) - (54) * (x - sqrt2) * (x + sqrt2) * (x + 1/3)^2 - -Sage example in ./domaines.tex, line 1025:: - - sage: R = GF(5)['x']; R - Univariate Polynomial Ring in x over Finite Field of size 5 - sage: q = R(p); q - 4*x^4 + x^3 + 3*x^2 + 3*x + 3 - sage: factor(q) - (4) * (x + 2)^2 * (x^2 + 3) - -""" diff --git a/src/sage/tests/french_book/float_doctest.py b/src/sage/tests/french_book/float_doctest.py deleted file mode 100644 index e63a410646b..00000000000 --- a/src/sage/tests/french_book/float_doctest.py +++ /dev/null @@ -1,259 +0,0 @@ -## -*- encoding: utf-8 -*- -""" -This file (./float_doctest.sage) was *autogenerated* from ./float.tex, -with sagetex.sty version 2011/05/27 v2.3.1. -It contains the contents of all the sageexample environments from this file. -You should be able to doctest this file with: -sage -t ./float_doctest.sage -It is always safe to delete this file; it is not used in typesetting your -document. - -Sage example in ./float.tex, line 127:: - - sage: xrdf = RDF(3.0) - -Sage example in ./float.tex, line 137:: - - sage: R100 = RealField(100) # précision : 100 bits. - sage: x100 = R100(3/8); x100 - 0.37500000000000000000000000000 - -Sage example in ./float.tex, line 148:: - - sage: Rdefaut = RealField() # précision par défaut de 53 bits - sage: xdefaut = Rdefaut(2/3) - -Sage example in ./float.tex, line 154:: - - sage: xrdf.prec() - 53 - sage: x100.prec() - 100 - sage: xdefaut.prec() - 53 - -Sage example in ./float.tex, line 168:: - - sage: x = 1.0; print(type(x)) - - sage: x.prec() - 53 - -Sage example in ./float.tex, line 182:: - - sage: x = 1.0 # x appartient à RealField() - sage: x = 0.1e+1 # idem : x appartient à RealField() - sage: x = 1 # x est entier - sage: x = RDF(1) # x est un flottant double précision machine - sage: x = RDF(1.) # idem : x est un flottant double précision - sage: x = RDF(0.1e+1) # idem - sage: x = 4/3 # x est un nombre rationnel - sage: R = RealField(20) - sage: x = R(1) # x est un flottant de précision 20 bits - -Sage example in ./float.tex, line 194:: - - sage: RDF(8/3) - 2.6666666666666665 - sage: R100 = RealField(100); R100(8/3) - 2.6666666666666666666666666667 - -Sage example in ./float.tex, line 202:: - - sage: x = R100(8/3) - sage: R = RealField(); R(x) - 2.66666666666667 - sage: RDF(x) - 2.6666666666666665 - -Sage example in ./float.tex, line 216:: - - sage: 1.0/0.0 - +infinity - sage: RDF(1)/RDF(0) - +infinity - sage: RDF(-1.0)/RDF(0.) - -infinity - -Sage example in ./float.tex, line 225:: - - sage: 0.0/0.0 - NaN - sage: RDF(0.0)/RDF(0.0) - NaN - -Sage example in ./float.tex, line 256:: - - sage: R2 = RealField(2) - -Sage example in ./float.tex, line 303:: - - sage: x2 = R2(1.); x2.ulp() - 0.50 - sage: xr = 1.; xr.ulp() - 2.22044604925031e-16 - -Sage example in ./float.tex, line 356:: - - sage: a = 10000.0; b = 9999.5; c = 0.1; c - 0.100000000000000 - sage: a1 = a+c # on perturbe a - sage: a1-b - 0.600000000000364 - -Sage example in ./float.tex, line 373:: - - sage: a = 1.0; b = 10.0^4; c = 1.0 - sage: delta = b^2-4*a*c - sage: x = (-b-sqrt(delta))/(2*a); y = (-b+sqrt(delta))/(2*a) - sage: x, y - (-9999.99990000000, -0.000100000001111766) - -Sage example in ./float.tex, line 382:: - - sage: x+y+b/a - 0.000000000000000 - sage: x*y-c/a - 1.11766307320238e-9 - -Sage example in ./float.tex, line 394:: - - sage: y = (c/a)/x; y - -0.000100000001000000 - sage: x+y+b/a - 0.000000000000000 - -Sage example in ./float.tex, line 410:: - - sage: x1 = R2(1/2); x2 = R2(4); x3 = R2(-4) - sage: x1, x2, x3 - (0.50, 4.0, -4.0) - sage: x1+(x2+x3) - 0.50 - sage: (x1+x2)+x3 - 0.00 - -Sage example in ./float.tex, line 431:: - - sage: x = RDF(1/3) - sage: for i in range(1,100): x = 4*x-1; print(x) - 0.33333333333333326 - 0.33333333333333304 - 0.33333333333333215 - ... - -1.0 - -5.0 - -21.0 - -85.0 - -341.0 - -1365.0 - -5461.0 - -21845.0 - ... - -Sage example in ./float.tex, line 461:: - - sage: x = RDF(1/2) - sage: for i in range(1,100): x = 3*x-1; print(x) - 0.5 - 0.5 - 0.5 - ... - 0.5 - -Sage example in ./float.tex, line 484:: - - sage: x = RDF(1/3) - -Sage example in ./float.tex, line 488:: - - sage: x = 1/3 - -Sage example in ./float.tex, line 545:: - - sage: def sumharmo(P): - ....: RFP = RealField(P) - ....: y = RFP(1.); x = RFP(0.); n = 1 - ....: while x != y: - ....: y = x; x += 1/n; n += 1 - ....: return P, n, x - -Sage example in ./float.tex, line 556:: - - sage: sumharmo(2) - (2, 5, 2.0) - sage: sumharmo(20) - (20, 131073, 12.631) - -Sage example in ./float.tex, line 590:: - - sage: def iter(y,delta,a,n): - ....: for i in range(0,n): - ....: y += delta - ....: delta *= a - ....: return y - -Sage example in ./float.tex, line 600:: - - sage: def exact(y,delta,a,n): - ....: return y+delta*(1-a^n)/(1-a) - -Sage example in ./float.tex, line 608:: - - sage: y0 = RDF(10^13); delta0 = RDF(1); a = RDF(1-10^(-8)); n = 100000 - sage: ii = iter(y0,delta0,a,n) - sage: s = exact(10^13,1,1-10^(-8),n) - sage: print("exact - sommation classique: {}".format(s-ii)) # abs tol 0.1 - exact - sommation classique: -45.5 - -Sage example in ./float.tex, line 618:: - - sage: def sumcomp(y,delta,e,n,a): - ....: for i in range(0,n): - ....: b = y - ....: e += delta - ....: y = b+e - ....: e += (b-y) - ....: delta = a*delta # nouvelle valeur de delta - ....: return y - -Sage example in ./float.tex, line 662:: - - sage: c = sumcomp(y0,delta0,RDF(0.0),n,a) - sage: print("exact-sommation compensee: {}".format(s-c)) - exact-sommation compensee: 0.0 - -Sage example in ./float.tex, line 681:: - - sage: x = CDF(2,1.); x - 2.0 + 1.0*I - sage: y = CDF(20,0); y - 20.0 - -Sage example in ./float.tex, line 688:: - - sage: z = ComplexDoubleElement(2.,1.); z - 2.0 + 1.0*I - -Sage example in ./float.tex, line 697:: - - sage: C = ComplexField(); C(2,3) - 2.00000000000000 + 3.00000000000000*I - sage: C100 = ComplexField(100); C100(2,3) - 2.0000000000000000000000000000 + 3.0000000000000000000000000000*I - -Sage example in ./float.tex, line 714:: - - sage: R200 = RealField(200); R200.pi() - 3.1415926535897932384626433832795028841971693993751058209749 - sage: R200.euler_constant() - 0.57721566490153286060651209008240243104215933593992359880577 - -Sage example in ./float.tex, line 723:: - - sage: x = RDF.pi()/2; x.cos() # approximation flottante de zero! - 6.123233995736757e-17 - sage: x.cos().arccos() - x - 0.0 - -""" diff --git a/src/sage/tests/french_book/integration_doctest.py b/src/sage/tests/french_book/integration_doctest.py deleted file mode 100644 index b975ce79701..00000000000 --- a/src/sage/tests/french_book/integration_doctest.py +++ /dev/null @@ -1,220 +0,0 @@ -## -*- encoding: utf-8 -*- -""" -This file (./integration_doctest.sage) was *autogenerated* from ./integration.tex, -with sagetex.sty version 2011/05/27 v2.3.1. -It contains the contents of all the sageexample environments from this file. -You should be able to doctest this file with: -sage -t ./integration_doctest.sage -It is always safe to delete this file; it is not used in typesetting your -document. - -Sage example in ./integration.tex, line 44:: - - sage: x = var('x'); f(x) = exp(-x^2) * log(x) - sage: N(integrate(f, x, 1, 3)) - 0.035860294991267694 - sage: plot(f, 1, 3, fill='axis') - Graphics object consisting of 2 graphics primitives - -Sage example in ./integration.tex, line 103:: - - sage: fp = plot(f, 1, 3, color='red') - sage: n = 4 - sage: interp_points = [(1+2*u/(n-1), N(f(1+2*u/(n-1)))) - ....: for u in range(n)] - sage: A = PolynomialRing(RR, 'x') - sage: pp = plot(A.lagrange_polynomial(interp_points), 1, 3, fill='axis') - sage: show(fp+pp) - -Sage example in ./integration.tex, line 346:: - - sage: N(integrate(exp(-x^2)*log(x), x, 17, 42)) # rel tol 7e-15 - 2.5657285006962035e-127 - -Sage example in ./integration.tex, line 355:: - - sage: integrate(log(1+x)*x, x, 0, 1) - 1/4 - sage: N(integrate(log(1+x)*x, x, 0, 1)) - 0.250000000000000 - -Sage example in ./integration.tex, line 372:: - - sage: numerical_integral(exp(-x^2)*log(x), 17, 42) # rel tol 7e-12 - (2.5657285006962035e-127, 3.3540254049238093e-128) - -Sage example in ./integration.tex, line 394:: - - sage: numerical_integral(exp(-x^100), 0, 1.1) - (0.99432585119150..., 4.0775730...e-09) - sage: numerical_integral(exp(-x^100), 0, 1.1, algorithm='qng') - (0.994327538576531..., 0.016840666914...) - -Sage example in ./integration.tex, line 404:: - - sage: integrate(exp(-x^2)*log(x), x, 17, 42) - integrate(e^(-x^2)*log(x), x, 17, 42) - -Sage example in ./integration.tex, line 412:: - - sage: N(integrate(exp(-x^2)*log(x), x, 17, 42), 200) # rel tol 7e-15 - 2.5657285006962035e-127 - -Sage example in ./integration.tex, line 417:: - - sage: N(integrate(sin(x)*exp(cos(x)), x, 0, pi), 200) - 2.3504023872876029137647637011912016303114359626681917404591 - -Sage example in ./integration.tex, line 430:: - - sage: sage.calculus.calculus.nintegral(sin(sin(x)), x, 0, 1) - (0.430606103120690..., 4.78068810228705...e-15, 21, 0) - -Sage example in ./integration.tex, line 436:: - - sage: g(x) = sin(sin(x)) - sage: g.nintegral(x, 0, 1) - (0.430606103120690..., 4.78068810228705...e-15, 21, 0) - -Sage example in ./integration.tex, line 465:: - - sage: gp('intnum(x=17, 42, exp(-x^2)*log(x))') # rel tol 1e-17 - 2.5657285005610514829176211363206621657 E-127 - -Sage example in ./integration.tex, line 474:: - - sage: gp('intnum(x=0, 1, sin(sin(x)))') - 0.430606103120690604912377355... - sage: old_prec = gp.set_precision(50) - sage: gp('intnum(x=0, 1, sin(sin(x)))') - 0.43060610312069060491237735524846578643360804182200 - -Sage example in ./integration.tex, line 490:: - - sage: p = gp.set_precision(old_prec) # on remet la précision par défaut - sage: gp('intnum(x=0, 1, x^(-1/2))') - 1.99999999999999999999... - -Sage example in ./integration.tex, line 496:: - - sage: gp('intnum(x=[0, -1/2], 1, x^(-1/2))') - 2.000000000000000000000000000... - -Sage example in ./integration.tex, line 504:: - - sage: gp('intnum(x=[0, -1/42], 1, x^(-1/2))') - 1.99999999999999999999... - -Sage example in ./integration.tex, line 518:: - - sage: import mpmath - sage: mpmath.mp.prec = 53 - sage: mpmath.quad(lambda x: mpmath.sin(mpmath.sin(x)), [0, 1]) - mpf('0.43060610312069059') - -Sage example in ./integration.tex, line 526:: - - sage: mpmath.mp.prec = 113 - sage: mpmath.quad(lambda x: mpmath.sin(mpmath.sin(x)), [0, 1]) - mpf('0.430606103120690604912377355248465809') - sage: mpmath.mp.prec = 114 - sage: mpmath.quad(lambda x: mpmath.sin(mpmath.sin(x)), [0, 1]) - mpf('0.430606103120690604912377355248465785') - -Sage example in ./integration.tex, line 550:: - - sage: mpmath.quad(sin(sin(x)), [0, 1]) - Traceback (most recent call last): - ... - TypeError: no canonical coercion from - to Symbolic Ring - -Sage example in ./integration.tex, line 565:: - - sage: g(x) = max_symbolic(sin(x), cos(x)) - sage: mpmath.mp.prec = 100 - sage: mpmath.quadts(lambda x: g(N(x, 100)), [0, 1]) - mpf('0.873912416263035435957979086252') - -Sage example in ./integration.tex, line 574:: - - sage: mpmath.mp.prec = 170 - sage: mpmath.quadts(lambda x: g(N(x, 190)), [0, 1]) - mpf('0.87391090757400975205393005981962476344054148354188794') - sage: N(sqrt(2) - cos(1), 100) - 0.87391125650495533140075211677 - -Sage example in ./integration.tex, line 585:: - - sage: mpmath.quadts(lambda x: g(N(x, 170)), [0, mpmath.pi / 4, 1]) - mpf('0.87391125650495533140075211676672147483736145475902551') - -Sage example in ./integration.tex, line 750:: - - sage: T = ode_solver() - -Sage example in ./integration.tex, line 761:: - - sage: def f_1(t,y,params): return [y[1],params[0]*(1-y[0]^2)*y[1]-y[0]] - sage: T.function = f_1 - -Sage example in ./integration.tex, line 776:: - - sage: def j_1(t,y,params): - ....: return [[0, 1], - ....: [-2*params[0]*y[0]*y[1]-1, params[0]*(1-y[0]^2)], - ....: [0,0]] - sage: T.jacobian = j_1 - -Sage example in ./integration.tex, line 786:: - - sage: T.algorithm = "rk8pd" - sage: T.ode_solve(y_0=[1,0], t_span=[0,100], params=[10], - ....: num_points=1000) - sage: f = T.interpolate_solution() - -Sage example in ./integration.tex, line 801:: - - sage: plot(f, 0, 100) - Graphics object consisting of 1 graphics primitive - -Sage example in ./integration.tex, line 838:: - - sage: t, y = var('t, y') - sage: desolve_rk4(t*y*(2-y), y, ics=[0,1], end_points=[0, 1], step=0.5) - [[0, 1], [0.5, 1.12419127424558], [1.0, 1.461590162288825]] - -Sage example in ./integration.tex, line 861:: - - sage: import mpmath - sage: mpmath.mp.prec = 53 - sage: sol = mpmath.odefun(lambda t, y: y, 0, 1) - sage: sol(1) - mpf('2.7182818284590451') - sage: mpmath.mp.prec = 100 - sage: sol(1) - mpf('2.7182818284590452353602874802307') - sage: N(exp(1), 100) - 2.7182818284590452353602874714 - -Sage example in ./integration.tex, line 889:: - - sage: mpmath.mp.prec = 53 - sage: f = mpmath.odefun(lambda t, y: [-y[1], y[0]], 0, [1, 0]) - sage: f(3) - [mpf('-0.98999249660044542'), mpf('0.14112000805986721')] - sage: (cos(3.), sin(3.)) - (-0.989992496600445, 0.141120008059867) - -Sage example in ./integration.tex, line 939:: - - sage: mpmath.mp.prec = 10 - sage: sol = mpmath.odefun(lambda t, y: y, 0, 1) - sage: sol(1) - mpf('2.7148') - sage: mpmath.mp.prec = 100 - sage: sol(1) - mpf('2.7135204235459511323824699502438') - -""" -# This file was *autogenerated* from the file integration_doctest.sage. diff --git a/src/sage/tests/french_book/linalg_doctest.py b/src/sage/tests/french_book/linalg_doctest.py deleted file mode 100644 index 3a55a7562cb..00000000000 --- a/src/sage/tests/french_book/linalg_doctest.py +++ /dev/null @@ -1,453 +0,0 @@ - -## -*- encoding: utf-8 -*- -""" -This file (./linalg_doctest.sage) was *autogenerated* from ./linalg.tex, -with sagetex.sty version 2011/05/27 v2.3.1. -It contains the contents of all the sageexample environments from this file. -You should be able to doctest this file with: -sage -t ./linalg_doctest.sage -It is always safe to delete this file; it is not used in typesetting your -document. - -Sage example in ./linalg.tex, line 136:: - - sage: MS = MatrixSpace(ZZ,2,3); MS - Full MatrixSpace of 2 by 3 dense matrices over Integer Ring - sage: VS = VectorSpace(GF(3^2,'x'),3); VS - Vector space of dimension 3 over Finite Field in x of size 3^2 - -Sage example in ./linalg.tex, line 148:: - - sage: list(MatrixSpace(ZZ,2,3).basis()) - [ - [1 0 0] [0 1 0] [0 0 1] [0 0 0] [0 0 0] [0 0 0] - [0 0 0], [0 0 0], [0 0 0], [1 0 0], [0 1 0], [0 0 1] - ] - -Sage example in ./linalg.tex, line 190:: - - sage: A = matrix(GF(11), 2, 2, [1,0,0,2]) - sage: B = matrix(GF(11), 2, 2, [0,1,1,0]) - sage: MG = MatrixGroup([A,B]) - sage: MG.cardinality() - 200 - sage: identity_matrix(GF(11),2) in MG - True - -Sage example in ./linalg.tex, line 226:: - - sage: MS = MatrixSpace(ZZ,2,3); A = MS([1,2,3,4,5,6]); A - [1 2 3] - [4 5 6] - -Sage example in ./linalg.tex, line 247:: - - sage: a = matrix(); a.parent() - Full MatrixSpace of 0 by 0 dense matrices over Integer Ring - -Sage example in ./linalg.tex, line 263:: - - sage: a = matrix(GF(8,'x'),3,4); a.parent() - Full MatrixSpace of 3 by 4 dense matrices over Finite Field - in x of size 2^3 - -Sage example in ./linalg.tex, line 274:: - - sage: g = graphs.PetersenGraph() - sage: m = matrix(g); m; m.parent() - [0 1 0 0 1 1 0 0 0 0] - [1 0 1 0 0 0 1 0 0 0] - [0 1 0 1 0 0 0 1 0 0] - [0 0 1 0 1 0 0 0 1 0] - [1 0 0 1 0 0 0 0 0 1] - [1 0 0 0 0 0 0 1 1 0] - [0 1 0 0 0 0 0 0 1 1] - [0 0 1 0 0 1 0 0 0 1] - [0 0 0 1 0 1 1 0 0 0] - [0 0 0 0 1 0 1 1 0 0] - Full MatrixSpace of 10 by 10 dense matrices over Integer Ring - -Sage example in ./linalg.tex, line 295:: - - sage: A = matrix([[1,2],[3,4]]) - sage: block_matrix([[A,-A],[2*A, A^2]]) - [ 1 2|-1 -2] - [ 3 4|-3 -4] - [-----+-----] - [ 2 4| 7 10] - [ 6 8|15 22] - -Sage example in ./linalg.tex, line 320:: - - sage: A = matrix([[1,2,3],[4,5,6]]) - sage: block_matrix([1,A,0,0,-A,2], ncols=3) - [ 1 0| 1 2 3| 0 0] - [ 0 1| 4 5 6| 0 0] - [-----+--------+-----] - [ 0 0|-1 -2 -3| 2 0] - [ 0 0|-4 -5 -6| 0 2] - -Sage example in ./linalg.tex, line 346:: - - sage: A = matrix([[1,2,3],[0,1,0]]) - sage: block_diagonal_matrix(A, A.transpose()) - [1 2 3|0 0] - [0 1 0|0 0] - [-----+---] - [0 0 0|1 0] - [0 0 0|2 1] - [0 0 0|3 0] - -Sage example in ./linalg.tex, line 397:: - - sage: A = matrix(3,3,range(9)) - sage: A[:,1] = vector([1,1,1]); A - [0 1 2] - [3 1 5] - [6 1 8] - -Sage example in ./linalg.tex, line 414:: - - sage: A[::-1], A[:,::-1], A[::2,-1] - ( - [6 1 8] [2 1 0] - [3 1 5] [5 1 3] [2] - [0 1 2], [8 1 6], [8] - ) - -Sage example in ./linalg.tex, line 446:: - - sage: A = matrix(ZZ,4,4,range(16)); A - [ 0 1 2 3] - [ 4 5 6 7] - [ 8 9 10 11] - [12 13 14 15] - - -Sage example in ./linalg.tex, line 462:: - - sage: A.matrix_from_rows_and_columns([0,2,3],[1,2]) - [ 1 2] - [ 9 10] - [13 14] - -Sage example in ./linalg.tex, line 505:: - - sage: MS = MatrixSpace(GF(3),2,3) - sage: MS.base_extend(GF(9,'x')) - Full MatrixSpace of 2 by 3 dense matrices over Finite Field - in x of size 3^2 - sage: MS = MatrixSpace(ZZ,2,3) - sage: MS.change_ring(GF(3)) - Full MatrixSpace of 2 by 3 dense matrices over Finite Field of size 3 - -Sage example in ./linalg.tex, line 896:: - - sage: a = matrix(GF(7),4,3,[6,2,2,5,4,4,6,4,5,5,1,3]); a - [6 2 2] - [5 4 4] - [6 4 5] - [5 1 3] - -Sage example in ./linalg.tex, line 910:: - - sage: u = copy(identity_matrix(GF(7),4)); u[1:,0] = -a[1:,0]/a[0,0] - sage: u, u*a - ( - [1 0 0 0] [6 2 2] - [5 1 0 0] [0 0 0] - [6 0 1 0] [0 2 3] - [5 0 0 1], [0 4 6] - ) - -Sage example in ./linalg.tex, line 932:: - - sage: v = copy(identity_matrix(GF(7),4)); v.swap_rows(1,2) - sage: b = v*u*a; v, b - ( - [1 0 0 0] [6 2 2] - [0 0 1 0] [0 2 3] - [0 1 0 0] [0 0 0] - [0 0 0 1], [0 4 6] - ) - -Sage example in ./linalg.tex, line 954:: - - sage: w = copy(identity_matrix(GF(7),4)) - sage: w[2:,1] = -b[2:,1]/b[1,1]; w, w*b - ( - [1 0 0 0] [6 2 2] - [0 1 0 0] [0 2 3] - [0 0 1 0] [0 0 0] - [0 5 0 1], [0 0 0] - ) - -Sage example in ./linalg.tex, line 1024:: - - sage: A = matrix(GF(7),4,5,[4,4,0,2,4,5,1,6,5,4,1,1,0,1,0,5,1,6,6,2]) - sage: A, A.echelon_form() - ( - [4 4 0 2 4] [1 0 5 0 3] - [5 1 6 5 4] [0 1 2 0 6] - [1 1 0 1 0] [0 0 0 1 5] - [5 1 6 6 2], [0 0 0 0 0] - ) - -Sage example in ./linalg.tex, line 1147:: - - sage: a = matrix(ZZ, 4, 6, [2,1,2,2,2,-1,1,2,-1,2,1,-1,2,1,-1,\ - ....: -1,2,2,2,1,1,-1,-1,-1]); a.echelon_form() - [ 1 2 0 5 4 -1] - [ 0 3 0 2 -6 -7] - [ 0 0 1 3 3 0] - [ 0 0 0 6 9 3] - -Sage example in ./linalg.tex, line 1163:: - - sage: a.base_extend(QQ).echelon_form() - [ 1 0 0 0 5/2 11/6] - [ 0 1 0 0 -3 -8/3] - [ 0 0 1 0 -3/2 -3/2] - [ 0 0 0 1 3/2 1/2] - -Sage example in ./linalg.tex, line 1189:: - - sage: A = matrix(ZZ,4,5,[4,4,0,2,4,5,1,6,5,4,1,1,0,1,0,5,1,6,6,2]) - sage: H, U = A.echelon_form(transformation=True); H, U - ( - [ 1 1 0 0 2] [ 0 1 1 -1] - [ 0 4 -6 0 -4] [ 0 -1 5 0] - [ 0 0 0 1 -2] [ 0 -1 0 1] - [ 0 0 0 0 0], [ 1 -2 -4 2] - ) - -Sage example in ./linalg.tex, line 1250:: - - sage: A = matrix(ZZ, 4, 5,\ - ....: [-1,-1,-1,-2,-2,-2,1,1,-1,2,2,2,2,2,-1,2,2,2,2,2]) - sage: S,U,V = A.smith_form(); S,U,V - ( - [ 0 -2 -1 -5 0] - [1 0 0 0 0] [ 1 0 0 0] [ 1 0 1 -1 -1] - [0 1 0 0 0] [ 0 0 1 0] [ 0 0 0 0 1] - [0 0 3 0 0] [-2 1 0 0] [-1 2 0 5 0] - [0 0 0 6 0], [ 0 0 -2 -1], [ 0 -1 0 -2 0] - ) - -Sage example in ./linalg.tex, line 1284:: - - sage: A.elementary_divisors() - [1, 1, 3, 6] - sage: S == U*A*V - True - -Sage example in ./linalg.tex, line 1329:: - - sage: B = matrix(GF(7),5,4,[4,5,1,5,4,1,1,1,0,6,0,6,2,5,1,6,4,4,0,2]) - sage: B.transpose().echelon_form() - [1 0 5 0 3] - [0 1 2 0 6] - [0 0 0 1 5] - [0 0 0 0 0] - -Sage example in ./linalg.tex, line 1344:: - - sage: B.pivot_rows() - (0, 1, 3) - sage: B.transpose().pivots() == B.pivot_rows() - True - -Sage example in ./linalg.tex, line 1381:: - - sage: R. = PolynomialRing(GF(5),'x') - sage: A = random_matrix(R,2,3); A # random - [ 3*x^2 + x x^2 + 2*x 2*x^2 + 2] - [ x^2 + x + 2 2*x^2 + 4*x + 3 x^2 + 4*x + 3] - -Sage example in ./linalg.tex, line 1393:: - - sage: b = random_matrix(R,2,1); b # random - [ 4*x^2 + 1] - [3*x^2 + 2*x] - -Sage example in ./linalg.tex, line 1404:: - - sage: A.solve_right(b) # random - [(4*x^3 + 2*x + 4)/(3*x^3 + 2*x^2 + 2*x)] - [ (3*x^2 + 4*x + 3)/(x^3 + 4*x^2 + 4*x)] - [ 0] - -Sage example in ./linalg.tex, line 1418:: - - sage: A.solve_right(b) == A\b - True - -Sage example in ./linalg.tex, line 1449:: - - sage: a = matrix(QQ,3,5,[2,2,-1,-2,-1,2,-1,1,2,-1/2,2,-2,-1,2,-1/2]) - sage: a.image() - Vector space of degree 5 and dimension 3 over Rational Field - Basis matrix: - [ 1 0 0 1/4 -11/32] - [ 0 1 0 -1 -1/8] - [ 0 0 1 1/2 1/16] - sage: a.right_kernel() - Vector space of degree 5 and dimension 2 over Rational Field - Basis matrix: - [ 1 0 0 -1/3 8/3] - [ 0 1 -1/2 11/12 2/3] - -Sage example in ./linalg.tex, line 1472:: - - sage: a = matrix(ZZ,5,3,[1,1,122,-1,-2,1,-188,2,1,1,-10,1,-1,-1,-1]) - sage: a.kernel() - Free module of degree 5 and rank 2 over Integer Ring - Echelon basis matrix: - [ 1 979 -11 -279 811] - [ 0 2079 -22 -569 1488] - sage: b = a.base_extend(QQ) - sage: b.kernel() - Vector space of degree 5 and dimension 2 over Rational Field - Basis matrix: - [ 1 0 -121/189 -2090/189 6949/63] - [ 0 1 -2/189 -569/2079 496/693] - sage: b.integer_kernel() - Free module of degree 5 and rank 2 over Integer Ring - Echelon basis matrix: - [ 1 979 -11 -279 811] - [ 0 2079 -22 -569 1488] - -Sage example in ./linalg.tex, line 1684:: - - sage: A = matrix(GF(97), 4, 4,\ - ....: [86,1,6,68,34,24,8,35,15,36,68,42,27,1,78,26]) - sage: e1 = identity_matrix(GF(97),4)[0] - sage: U = matrix(A.transpose().maxspin(e1)).transpose() - sage: F = U^-1*A*U; F - [ 0 0 0 83] - [ 1 0 0 77] - [ 0 1 0 20] - [ 0 0 1 10] - -Sage example in ./linalg.tex, line 1703:: - - sage: K. = GF(97)[] - sage: P = x^4-sum(F[i,3]*x^i for i in range(4)); P - x^4 + 87*x^3 + 77*x^2 + 20*x + 14 - -Sage example in ./linalg.tex, line 1709:: - - sage: P == A.charpoly() - True - -Sage example in ./linalg.tex, line 1813:: - - sage: A = matrix(ZZ,8,[[6,0,-2,4,0,0,0,-2],[14,-1,0,6,0,-1,-1,1],\ - ....: [2,2,0,1,0,0,1,0],[-12,0,5,-8,0,0,0,4],\ - ....: [0,4,0,0,0,0,4,0],[0,0,0,0,1,0,0,0],\ - ....: [-14,2,0,-6,0,2,2,-1],[-4,0,2,-4,0,0,0,4]]) - sage: A.frobenius() - [0 0 0 4 0 0 0 0] - [1 0 0 4 0 0 0 0] - [0 1 0 1 0 0 0 0] - [0 0 1 0 0 0 0 0] - [0 0 0 0 0 0 4 0] - [0 0 0 0 1 0 0 0] - [0 0 0 0 0 1 1 0] - [0 0 0 0 0 0 0 2] - -Sage example in ./linalg.tex, line 1845:: - - sage: A.frobenius(1) - [x^4 - x^2 - 4*x - 4, x^3 - x^2 - 4, x - 2] - -Sage example in ./linalg.tex, line 1851:: - - sage: F,K = A.frobenius(2) - sage: K - [ 1 -15/56 17/224 15/56 -17/896 0 -15/112 17/64] - [ 0 29/224 -13/224 -23/448 -17/896 -17/896 29/448 13/128] - [ 0 -75/896 75/896 -47/896 0 -17/896 -23/448 11/128] - [ 0 17/896 -29/896 15/896 0 0 0 0] - [ 0 0 0 0 1 0 0 0] - [ 0 0 0 0 0 1 0 0] - [ 0 1 0 0 0 0 1 0] - [ 0 -4/21 -4/21 -10/21 0 0 -2/21 1] - -Sage example in ./linalg.tex, line 1877:: - - sage: K^-1*F*K == A - True - -Sage example in ./linalg.tex, line 1905:: - - sage: S. = QQ[] - sage: B = x*identity_matrix(8) - A - sage: B.elementary_divisors() - [1, 1, 1, 1, 1, x - 2, x^3 - x^2 - 4, x^4 - x^2 - 4*x - 4] - -Sage example in ./linalg.tex, line 1913:: - - sage: A.frobenius(1) - [x^4 - x^2 - 4*x - 4, x^3 - x^2 - 4, x - 2] - -Sage example in ./linalg.tex, line 1981:: - - sage: A = matrix(GF(7),4,[5,5,4,3,0,3,3,4,0,1,5,4,6,0,6,3]) - sage: A.eigenvalues() - [4, 1, 2, 2] - sage: A.eigenvectors_right() - [(4, [ - (1, 5, 5, 1) - ], 1), (1, [ - (0, 1, 1, 4) - ], 1), (2, [ - (1, 3, 0, 1), - (0, 0, 1, 1) - ], 2)] - sage: A.eigenspaces_right() - [ - (4, Vector space of degree 4 and dimension 1 over Finite Field - of size 7 - User basis matrix: - [1 5 5 1]), - (1, Vector space of degree 4 and dimension 1 over Finite Field - of size 7 - User basis matrix: - [0 1 1 4]), - (2, Vector space of degree 4 and dimension 2 over Finite Field - of size 7 - User basis matrix: - [1 3 0 1] - [0 0 1 1]) - ] - -Sage example in ./linalg.tex, line 2019:: - - sage: A.eigenmatrix_right() - ( - [4 0 0 0] [1 0 1 0] - [0 1 0 0] [5 1 3 0] - [0 0 2 0] [5 1 0 1] - [0 0 0 2], [1 4 1 1] - ) - -Sage example in ./linalg.tex, line 2144:: - - sage: A = matrix(ZZ,4,[3,-1,0,-1,0,2,0,-1,1,-1,2,0,1,-1,-1,3]) - sage: A.jordan_form() - [3|0|0 0] - [-+-+---] - [0|3|0 0] - [-+-+---] - [0|0|2 1] - [0|0|0 2] - -Sage example in ./linalg.tex, line 2163:: - - sage: J,U = A.jordan_form(transformation=True) - sage: U^-1*A*U == J - True -""" -# This file was *autogenerated* from the file linalg_doctest.sage. -from sage.all_cmdline import * # import sage library diff --git a/src/sage/tests/french_book/linsolve_doctest.py b/src/sage/tests/french_book/linsolve_doctest.py deleted file mode 100644 index 5c0a77c2a60..00000000000 --- a/src/sage/tests/french_book/linsolve_doctest.py +++ /dev/null @@ -1,220 +0,0 @@ -## -*- encoding: utf-8 -*- -r""" -This file (./linsolve_doctest.sage) was *autogenerated* from ./linsolve.tex, -with sagetex.sty version 2011/05/27 v2.3.1. -It contains the contents of all the sageexample environments from this file. -You should be able to doctest this file with: -sage -t ./linsolve_doctest.sage -It is always safe to delete this file; it is not used in typesetting your -document. - -Sage example in ./linsolve.tex, line 235:: - - sage: def cond_hilbert(n): - ....: A = matrix(QQ, [[1/(i+j-1) for j in [1..n]] for i in [1..n]]) - ....: return A.norm(Infinity) * (A^-1).norm(Infinity) - -Sage example in ./linsolve.tex, line 269:: - - sage: n = 8 - sage: x = vector(QQ,[1 for i in range(0,n)]) - sage: A = matrix(QQ, [[1/(i+j-1) for j in [1..n]] for i in [1..n]]) - sage: y = A*x - sage: A[n-1,n-1] = (1/(2*n-1))*(1+1/(10^5)) # perturbe la matrice - sage: sol = A\y - sage: diff = max(float(sol[i]-x[i]) for i in range(0,n)) - -Sage example in ./linsolve.tex, line 313:: - - sage: n = 8 - sage: A = matrix(RR, [[1/(i+j-1) for j in [1..n]] for i in [1..n]]) - sage: x = vector(RR, [1 for i in range(0,n)]) - sage: y = A*x - sage: s = A.solve_right(y) - sage: diff = [float(s[i]-x[i]) for i in range(0,n)] - -Sage example in ./linsolve.tex, line 422:: - - sage: n = 20; cout = (n+1)*factorial(n); cout - 51090942171709440000 - -Sage example in ./linsolve.tex, line 433:: - - sage: v = 3*10^9 - sage: print("%3.3f" % float(cout/v/3600/24/365)) - 540.028 - -Sage example in ./linsolve.tex, line 502:: - - sage: A = matrix(RDF, [[-1,2],[3,4]]) - sage: b = vector(RDF, [2,3]) - sage: x = A\b; x # rel tol 3e-15 - (-0.20000000000000018, 0.9000000000000001) - -Sage example in ./linsolve.tex, line 512:: - - sage: x = A.solve_right(b) - -Sage example in ./linsolve.tex, line 520:: - - sage: A = matrix(RDF, [[-1,2],[3,4]]) - sage: P, L, U = A.LU() - -Sage example in ./linsolve.tex, line 561:: - - sage: A = random_matrix(RDF, 1000) - sage: b = vector(RDF, range(1000)) - -Sage example in ./linsolve.tex, line 600:: - - sage: m = random_matrix(RDF, 10) - sage: A = transpose(m)*m - sage: C = A.cholesky() - -Sage example in ./linsolve.tex, line 655:: - - sage: A = random_matrix(RDF,6,5) - sage: Q, R = A.QR() - -Sage example in ./linsolve.tex, line 786:: - - sage: A = matrix(RDF, [[1,3,2],[1,4,2],[0,5,2],[1,3,2]]) - sage: b = vector(RDF, [1,2,3,4]) - sage: Z = transpose(A)*A - sage: C = Z.cholesky() - sage: R = transpose(A)*b - sage: Z.solve_right(R) # rel tol 1e-13 - (-1.5000000000000044, -0.5000000000000009, 2.750000000000003) - -Sage example in ./linsolve.tex, line 822:: - - sage: A = matrix(RDF, [[1,3,2],[1,4,2],[0,5,2],[1,3,2]]) - sage: b = vector(RDF, [1,2,3,4]) - sage: Q, R = A.QR() - sage: R1 = R[0:3,0:3] - sage: b1 = transpose(Q)*b - sage: c = b1[0:3] - sage: R1.solve_right(c) # rel tol 2e-14 - (-1.499999999999999, -0.49999999999999867, 2.7499999999999973) - -Sage example in ./linsolve.tex, line 834:: - - sage: Z = A.transpose()*A - sage: Z.norm(Infinity)*(Z^-1).norm(Infinity) # rel tol 1e-14 - 1992.3750000000084 - -Sage example in ./linsolve.tex, line 876:: - - sage: A = matrix(RDF, [[1,3,2],[1,3,2],[0,5,2],[1,3,2]]) - sage: b = vector(RDF, [1,2,3,4]) - sage: U, Sig, V = A.SVD() - sage: m = A.ncols() - sage: x = vector(RDF, [0]*m) - sage: lamb = vector(RDF, [0]*m) - sage: for i in range(0,m): - ....: s = Sig[i,i] - ....: if s < 1e-12: - ....: break - ....: lamb[i] = U.column(i)*b / s - sage: x = V*lamb; x # rel tol 1e-14 - (0.2370370370370367, 0.4518518518518521, 0.3703703703703702) - -Sage example in ./linsolve.tex, line 968:: - - sage: A = matrix(RDF, [[1,2],[3,4],[5,6],[7,8]]) - -Sage example in ./linsolve.tex, line 974:: - - sage: th = 0.7 - sage: R = matrix(RDF, [[cos(th),sin(th)],[-sin(th),cos(th)]]) - sage: B = (A + 0.1*random_matrix(RDF,4,2)) * transpose(R) - -Sage example in ./linsolve.tex, line 1189:: - - sage: A = matrix(RDF, [[1,3,2],[1,2,3],[0,5,2]]) - -Sage example in ./linsolve.tex, line 1382:: - - sage: def pol2companion(p): - ....: n = len(p) - ....: m = matrix(RDF,n) - ....: for i in range(1,n): - ....: m[i,i-1]=1 - ....: for i in range(0,n): - ....: m[i,n-1]=-p[i] - ....: return m - -Sage example in ./linsolve.tex, line 1392:: - - sage: q = [1,-1,2,3,5,-1,10,11] - sage: comp = pol2companion(q); comp - [ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0] - [ 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0] - [ 0.0 1.0 0.0 0.0 0.0 0.0 0.0 -2.0] - [ 0.0 0.0 1.0 0.0 0.0 0.0 0.0 -3.0] - [ 0.0 0.0 0.0 1.0 0.0 0.0 0.0 -5.0] - [ 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0] - [ 0.0 0.0 0.0 0.0 0.0 1.0 0.0 -10.0] - [ 0.0 0.0 0.0 0.0 0.0 0.0 1.0 -11.0] - sage: racines = comp.eigenvalues(); racines # abs tol 1e-10 - [0.347521510119 + 0.566550553398*I, - 0.347521510119 - 0.566550553398*I, - 0.345023776962 + 0.439908702386*I, - 0.345023776962 - 0.439908702386*I, - -0.517257614325 + 0.512958206789*I, - -0.517257614325 - 0.512958206789*I, - -1.36699716455, - -9.98357818097] - -Sage example in ./linsolve.tex, line 1515:: - - sage: def eval(P,x): - ....: if len(P) == 0: - ....: return 0 - ....: else: - ....: return P[0]+x*eval(P[1:],x) - -Sage example in ./linsolve.tex, line 1523:: - - sage: def pscal(P,Q,lx): - ....: return float(sum(eval(P,s)*eval(Q,s) for s in lx)) - -Sage example in ./linsolve.tex, line 1528:: - - sage: def padd(P,a,Q): - ....: for i in range(0,len(Q)): - ....: P[i] += a*Q[i] - -Sage example in ./linsolve.tex, line 1536:: - - sage: class BadParamsforOrthop(Exception): - ....: def __init__(self, degreplusun, npoints): - ....: self.deg = degreplusun - ....: self.np = npoints - ....: def __str__(self): - ....: return "degre: " + str(self.deg) + \ - ....: " nb. points: " + repr(self.np) - -Sage example in ./linsolve.tex, line 1546:: - - sage: def orthopoly(n,x): - ....: if n > len(x): - ....: raise BadParamsforOrthop(n-1, len(x)) - ....: orth = [[1./sqrt(float(len(x)))]] - ....: for p in range(1,n): - ....: nextp = copy(orth[p-1]) - ....: nextp.insert(0,0) - ....: s = [] - ....: for i in range(p-1,max(p-3,-1),-1): - ....: s.append(pscal(nextp, orth[i], x)) - ....: j = 0 - ....: for i in range(p-1,max(p-3,-1),-1): - ....: padd(nextp, -s[j], orth[i]) - ....: j += 1 - ....: norm = sqrt(pscal(nextp, nextp, x)) - ....: nextpn = [nextp[i]/norm for i in range(len(nextp))] - ....: orth.append(nextpn) - ....: return orth - -""" -# This file was *autogenerated* from the file linsolve_doctest.sage. diff --git a/src/sage/tests/french_book/nonlinear_doctest.py b/src/sage/tests/french_book/nonlinear_doctest.py deleted file mode 100644 index 2343abe47f8..00000000000 --- a/src/sage/tests/french_book/nonlinear_doctest.py +++ /dev/null @@ -1,493 +0,0 @@ -## -*- encoding: utf-8 -*- -""" -Doctests from French Sage book -Test file for chapter "Équations non linéaires" ("Nonlinear Equations") - -Tests extracted from ./nonlinear.tex. - -Sage example in ./nonlinear.tex, line 61:: - - sage: R. = PolynomialRing(RealField(prec=10)) - sage: p = 2*x^7 - 21*x^6 + 64*x^5 - 67*x^4 + 90*x^3 \ - ....: + 265*x^2 - 900*x + 375 - sage: p.roots() - [(-1.7, 1), (0.50, 1), (1.7, 1), (5.0, 2)] - sage: p.roots(ring=ComplexField(10), multiplicities=False) - [-1.7, 0.50, 1.7, 5.0, -2.2*I, 2.2*I] - sage: p.roots(ring=RationalField()) - [(1/2, 1), (5, 2)] - -Sage example in ./nonlinear.tex, line 158:: - - sage: R. = PolynomialRing(QQ, 'x') - sage: p = x^4 + x^3 + x^2 + x + 1 - sage: K. = p.root_field() - sage: p.roots(ring=K, multiplicities=None) - [alpha, alpha^2, alpha^3, -alpha^3 - alpha^2 - alpha - 1] - sage: alpha^5 - 1 - -Sage example in ./nonlinear.tex, line 202:: - - sage: R. = PolynomialRing(RR, 'x') - sage: d = ZZ.random_element(1, 15) - sage: p = R.random_element(d) - sage: p.degree() == sum(r[1] for r in p.roots(CC)) - True - -Sage example in ./nonlinear.tex, line 231:: - - sage: from itertools import product - sage: def build_complex_roots(degree): - ....: R. = PolynomialRing(CDF, 'x') - ....: v = [] - ....: for c in product([-1, 1], repeat=degree+1): - ....: v.extend(R(c).roots(multiplicities=False)) - ....: return v - sage: data = build_complex_roots(12) # long time - sage: g = points(data, pointsize=1, aspect_ratio=1) # long time - -Sage example in ./nonlinear.tex, line 275:: - - sage: a, b, c, x = var('a, b, c, x') - sage: p = a * x^2 + b * x + c - sage: type(p) - - sage: p.parent() - Symbolic Ring - sage: p.roots(x) - [(-1/2*(b + sqrt(b^2 - 4*a*c))/a, 1), - (-1/2*(b - sqrt(b^2 - 4*a*c))/a, 1)] - -Sage example in ./nonlinear.tex, line 299:: - - sage: a, b, c, d, e, f, x = var('a, b, c, d, e, f, x') - sage: p = a*x^5+b*x^4+c*x^3+d*x^2+e*x+f - sage: try: - ....: p.roots(x) - ....: except RuntimeError: - ....: print('No explicit roots found') - No explicit roots found - -Sage example in ./nonlinear.tex, line 315:: - - sage: x, a, b, c, d = var('x, a, b, c, d') - sage: P = a * x^3 + b * x^2 + c * x + d - sage: alpha = var('alpha') - sage: P.subs(x=x + alpha).expand().coefficient(x, 2) - 3*a*alpha + b - sage: P.subs(x = x - b / (3 * a)).expand().collect(x) - a*x^3 - 1/3*(b^2/a - 3*c)*x + 2/27*b^3/a^2 - 1/3*b*c/a + d - -Sage example in ./nonlinear.tex, line 328:: - - sage: p, q, u, v = var('p, q, u, v') - sage: P = x^3 + p * x + q - sage: P.subs(x = u + v).expand() - u^3 + 3*u^2*v + 3*u*v^2 + v^3 + p*u + p*v + q - -Sage example in ./nonlinear.tex, line 340:: - - sage: P.subs({x: u + v, q: -u^3 - v^3}).factor() - (3*u*v + p)*(u + v) - sage: P.subs({x: u+v, q: -u^3 - v^3, p: -3 * u * v}).expand() - 0 - sage: X = var('X') - sage: solve([X^2 + q*X - p^3 / 27 == 0], X, solution_dict=True) - [{X: -1/2*q - 1/18*sqrt(12*p^3 + 81*q^2)}, - {X: -1/2*q + 1/18*sqrt(12*p^3 + 81*q^2)}] - -Sage example in ./nonlinear.tex, line 367:: - - sage: e = sin(x) * (x^3 + 1) * (x^5 + x^4 + 1) - sage: roots = e.roots() - sage: print(len(roots)) - 9 - sage: print(roots) - [(0, 1), - (-1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(I*sqrt(3) + 1) - - 1/6*(-I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3), 1), - (-1/2*(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3)*(-I*sqrt(3) + 1) - - 1/6*(I*sqrt(3) + 1)/(1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3), 1), - ((1/18*sqrt(23)*sqrt(3) - 1/2)^(1/3) + 1/3/(1/18*sqrt(23)*sqrt(3) - - 1/2)^(1/3), 1), - (-1/2*I*sqrt(3) - 1/2, 1), - (1/2*I*sqrt(3) - 1/2, 1), - (1/2*I*sqrt(3)*(-1)^(1/3) - 1/2*(-1)^(1/3), 1), - (-1/2*I*sqrt(3)*(-1)^(1/3) - 1/2*(-1)^(1/3), 1), ((-1)^(1/3), 1)] - -Sage example in ./nonlinear.tex, line 424:: - - sage: alpha, m, x = var('alpha, m, x') - sage: p = function('p')(x) - sage: q = function('q')(x) - sage: p = (x - alpha)^m * q - sage: p.derivative(x) - (-alpha + x)^(m - 1)*m*q(x) + (-alpha + x)^m*diff(q(x), x) - sage: simplify(p.derivative(x)(x=alpha)) - 0 - -Sage example in ./nonlinear.tex, line 450:: - - sage: R. = PolynomialRing(QQ, 'x') - sage: p = 128 * x^13 - 1344 * x^12 + 6048 * x^11 \ - ....: - 15632 * x^10 + 28056 * x^9 - 44604 * x^8 \ - ....: + 71198 * x^7 - 98283 * x^6 + 105840 * x^5 \ - ....: - 101304 * x^4 + 99468 * x^3 - 81648 * x^2 \ - ....: + 40824 * x - 8748 - sage: d = gcd(p, p.derivative()) - sage: (p // d).degree() - 4 - sage: roots = SR(p // d).roots(multiplicities=False) - sage: roots - [1/2*I*sqrt(3)*2^(1/3) - 1/2*2^(1/3), - -1/2*I*sqrt(3)*2^(1/3) - 1/2*2^(1/3), - 2^(1/3), 3/2] - sage: [QQbar(p(alpha)).is_zero() for alpha in roots] # long time - [True, True, True, True] - -Sage example in ./nonlinear.tex, line 504:: - - sage: R. = PolynomialRing(RR, 'x') - sage: p = x^7 - 131/3*x^6 + 1070/3*x^5 - 2927/3*x^4 \ - ....: + 2435/3*x^3 - 806/3*x^2 + 3188/3*x - 680 - sage: sign_changes = \ - ....: [p[i] * p[i + 1] < 0 \ - ....: for i in range(p.degree())].count(True) - sage: real_positive_roots = \ - ....: sum([alpha[1] \ - ....: if alpha[0] > 0 else 0 for alpha in p.roots()]) - sage: sign_changes, real_positive_roots - (7, 5) - -Sage example in ./nonlinear.tex, line 567:: - - sage: def count_sign_changes(l): - ....: changes = [l[i]*l[i + 1] < 0 \ - ....: for i in range(len(l) - 1)] - ....: return changes.count(True) - sage: def sturm(p, a, b): - ....: assert p.degree() > 2 - ....: assert not (p(a) == 0) - ....: assert not (p(b) == 0) - ....: if a > b: - ....: a, b = b, a - ....: remains = [p, p.derivative()] - ....: for i in range(p.degree()): - ....: remains.append(-(remains[i] % remains[i + 1])) - ....: evals = [[], []] - ....: for q in remains: - ....: evals[0].append(q(a)) - ....: evals[1].append(q(b)) - ....: return count_sign_changes(evals[0]) \ - ....: - count_sign_changes(evals[1]) - -Sage example in ./nonlinear.tex, line 591:: - - sage: R. = PolynomialRing(QQ, 'x') - sage: p = (x - 34) * (x - 5) * (x - 3) * (x - 2) * (x - 2/3) - sage: sturm(p, 1, 4) - 2 - sage: sturm(p, 1, 10) - 3 - sage: sturm(p, 1, 200) - 4 - sage: p.roots(multiplicities=False) - [34, 5, 3, 2, 2/3] - sage: sturm(p, 1/2, 35) - 5 - -Sage example in ./nonlinear.tex, line 651:: - - sage: f(x) = 4 * sin(x) - exp(x) / 2 + 1 - sage: a, b = RR(-pi), RR(pi) - sage: bool(f(a) * f(b) < 0) - True - -Sage example in ./nonlinear.tex, line 661:: - - sage: solve(f(x) == 0, x) - [sin(x) == 1/8*e^x - 1/4] - -Sage example in ./nonlinear.tex, line 666:: - - sage: f.roots() - Traceback (most recent call last): - ... - RuntimeError: no explicit roots found - -Sage example in ./nonlinear.tex, line 684:: - - sage: a, b = RR(-pi), RR(pi) - sage: g = plot(f, a, b, rgbcolor='blue') - -Sage example in ./nonlinear.tex, line 720:: - - sage: def phi(s, t): return (s + t) / 2 - sage: def intervalgen(f, phi, s, t): - ....: msg = 'Wrong arguments: f({0})*f({1})>=0)'.format(s, t) - ....: assert (f(s) * f(t) < 0), msg - ....: yield s - ....: yield t - ....: while True: - ....: u = phi(s, t) - ....: yield u - ....: if f(u) * f(s) < 0: - ....: t = u - ....: else: - ....: s = u - -Sage example in ./nonlinear.tex, line 785:: - - sage: a, b - (-3.14159265358979, 3.14159265358979) - sage: bisection = intervalgen(f, phi, a, b) - sage: next(bisection) - -3.14159265358979 - sage: next(bisection) - 3.14159265358979 - sage: next(bisection) - 0.000000000000000 - -Sage example in ./nonlinear.tex, line 805:: - - sage: from types import GeneratorType, FunctionType - sage: def checklength(u, v, w, prec): - ....: return abs(v - u) < 2 * prec - sage: def iterate(series, check=checklength,prec=10^-5, maxit=100): - ....: assert isinstance(series, GeneratorType) - ....: assert isinstance(check, FunctionType) - ....: niter = 2 - ....: v, w = next(series), next(series) - ....: while (niter <= maxit): - ....: niter += 1 - ....: u, v, w = v, w, next(series) - ....: if check(u, v, w, prec): - ....: print('After {0} iterations: {1}'.format(niter, w)) - ....: return - ....: print('Failed after {0} iterations'.format(maxit)) - -Sage example in ./nonlinear.tex, line 837:: - - sage: bisection = intervalgen(f, phi, a, b) - sage: iterate(bisection) - After 22 iterations: 2.15847275559132 - -Sage example in ./nonlinear.tex, line 899:: - - sage: phi(s, t) = t - f(t) * (s - t) / (f(s) - f(t)) - sage: falsepos = intervalgen(f, phi, a, b) - sage: iterate(falsepos) - After 8 iterations: -2.89603757331027 - -Sage example in ./nonlinear.tex, line 906:: - - sage: a, b = RR(-pi), RR(pi) - sage: g = plot(f, a, b, rgbcolor='blue') - sage: phi(s, t) = t - f(t) * (s - t) / (f(s) - f(t)) - sage: falsepos = intervalgen(f, phi, a, b) - sage: u, v, w = next(falsepos), next(falsepos), next(falsepos) - sage: niter = 3 - sage: while niter < 9: - ....: g += line([(u, 0), (u, f(u))], rgbcolor='red', - ....: linestyle=':') - ....: g += line([(u, f(u)), (v, f(v))], rgbcolor='red') - ....: g += line([(v, 0), (v, f(v))], rgbcolor='red', - ....: linestyle=':') - ....: g += point((w, 0), rgbcolor='red') - ....: if (f(u) * f(w)) < 0: - ....: u, v = u, w - ....: else: - ....: u, v = w, v - ....: w = next(falsepos) - ....: niter += 1 - -Sage example in ./nonlinear.tex, line 942:: - - sage: a, b = RR(pi/2), RR(pi) - sage: phi(s, t) = t - f(t) * (s - t) / (f(s) - f(t)) - sage: falsepos = intervalgen(f, phi, a, b) - sage: phi(s, t) = (s + t) / 2 - sage: bisection = intervalgen(f, phi, a, b) - sage: iterate(falsepos) - After 15 iterations: 2.15846441170219 - sage: iterate(bisection) - After 20 iterations: 2.15847275559132 - -Sage example in ./nonlinear.tex, line 954:: - - sage: a, b = RR(pi/2), RR(pi) - sage: g = plot(f, a, b, rgbcolor='blue') - sage: phi(s, t) = t - f(t) * (s - t) / (f(s) - f(t)) - sage: falsepos = intervalgen(f, phi, a, b) - sage: u, v, w = next(falsepos), next(falsepos), next(falsepos) - sage: niter = 3 - sage: while niter < 7: - ....: g += line([(u, 0), (u, f(u))], rgbcolor='red', - ....: linestyle=':') - ....: g += line([(u, f(u)), (v, f(v))], rgbcolor='red') - ....: g += line([(v, 0), (v, f(v))], rgbcolor='red', - ....: linestyle=':') - ....: g += point((w, 0), rgbcolor='red') - ....: if (f(u) * f(w)) < 0: - ....: u, v = u, w - ....: else: - ....: u, v = w, v - ....: w = next(falsepos) - ....: niter += 1 - -Sage example in ./nonlinear.tex, line 1025:: - - sage: f.derivative() - x |--> 4*cos(x) - 1/2*e^x - sage: a, b = RR(pi/2), RR(pi) - -Sage example in ./nonlinear.tex, line 1042:: - - sage: def newtongen(f, u): - ....: while 1: - ....: yield u - ....: u -= f(u) / (f.derivative()(u)) - sage: def checkconv(u, v, w, prec): - ....: return abs(w - v) / abs(w) <= prec - -Sage example in ./nonlinear.tex, line 1053:: - - sage: iterate(newtongen(f, a), check=checkconv) - After 6 iterations: 2.15846852566756 - -Sage example in ./nonlinear.tex, line 1058:: - - sage: generator = newtongen(f, a) - sage: g = plot(f, a, b, rgbcolor='blue') - sage: u, v = next(generator), next(generator) - sage: niter = 2 - sage: while niter < 6: - ....: g += point((u, 0), rgbcolor='red') - ....: g += line([(u, 0), (u, f(u))], rgbcolor='red', - ....: linestyle=':') - ....: g += line([(u, f(u)), (v, 0)], rgbcolor='red') - ....: u, v = v, next(generator) - ....: niter += 1 - -Sage example in ./nonlinear.tex, line 1109:: - - sage: def secantgen(f, a): - ....: yield a - ....: estimate = f.derivative()(a) - ....: b = a - f(a) / estimate - ....: yield b - ....: while True: - ....: fa, fb = f(a), f(b) - ....: if fa == fb: - ....: estimate = f.derivative()(a) - ....: else: - ....: estimate = (fb - fa) / (b - a) - ....: a = b - ....: b -= fb / estimate - ....: yield b - -Sage example in ./nonlinear.tex, line 1136:: - - sage: iterate(secantgen(f, a), check=checkconv) - After 8 iterations: 2.15846852557553 - -Sage example in ./nonlinear.tex, line 1148:: - - sage: g = plot(f, a, b, rgbcolor='blue') - sage: sequence = secantgen(f, a) - sage: u, v = next(sequence), next(sequence) - sage: niter = 2 - sage: while niter < 6: - ....: g += point((u, 0), rgbcolor='red') - ....: g += line([(u, 0), (u, f(u))], rgbcolor='red', - ....: linestyle=':') - ....: g += line([(u, f(u)), (v, 0)], rgbcolor='red') - ....: u, v = v, next(sequence) - ....: niter += 1 - -Sage example in ./nonlinear.tex, line 1198:: - - sage: from collections import deque - sage: basering = PolynomialRing(CC, 'x') - sage: def quadraticgen(f, r, s): - ....: t = (r + s) / 2 - ....: yield t - ....: points = deque([(r,f(r)), (s,f(s)), (t,f(t))], maxlen=3) - ....: while True: - ....: pol = basering.lagrange_polynomial(points) - ....: roots = pol.roots(ring=CC, multiplicities=False) - ....: u = min(roots, key=lambda x: abs(x - points[2][0])) - ....: points.append((u, f(u))) - ....: yield points[2][0] - -Sage example in ./nonlinear.tex, line 1230:: - - sage: generator = quadraticgen(f, a, b) - sage: iterate(generator, check=checkconv) - After 5 iterations: 2.15846852554764 - -Sage example in ./nonlinear.tex, line 1287:: - - sage: rings = [ZZ, QQ, QQbar, RDF, RIF, RR, AA, CDF, CIF, CC] - sage: for ring in rings: - ....: print("{0:50} {1}".format(ring, ring.is_exact())) - Integer Ring True - Rational Field True - Algebraic Field True - Real Double Field False - Real Interval Field with 53 bits of precision False - Real Field with 53 bits of precision False - Algebraic Real Field True - Complex Double Field False - Complex Interval Field with 53 bits of precision False - Complex Field with 53 bits of precision False - -Sage example in ./nonlinear.tex, line 1403:: - - sage: def steffensen(sequence): - ....: assert isinstance(sequence, GeneratorType) - ....: values = deque(maxlen=3) - ....: for i in range(3): - ....: values.append(next(sequence)) - ....: yield values[i] - ....: while 1: - ....: values.append(next(sequence)) - ....: u, v, w = values - ....: yield u - (v - u)^2 / (w - 2 * v + u) - -Sage example in ./nonlinear.tex, line 1419:: - - sage: g(x) = sin(x^2 - 2) * (x^2 - 2) - sage: sequence = newtongen(g, RR(0.7)) - sage: accelseq = steffensen(newtongen(g, RR(0.7))) - sage: iterate(sequence, check=checkconv) - After 17 iterations: 1.41422192763287 - sage: iterate(accelseq, check=checkconv) - After 10 iterations: 1.41421041980166 - -Sage example in ./nonlinear.tex, line 1432:: - - sage: sequence = newtongen(f, RR(a)) - sage: accelseq = steffensen(newtongen(f, RR(a))) - sage: iterate(sequence, check=checkconv) - After 6 iterations: 2.15846852566756 - sage: iterate(accelseq, check=checkconv) - After 7 iterations: 2.15846852554764 - -Sage example in ./nonlinear.tex, line 1457:: - - sage: result = (f == 0).find_root(a, b, full_output=True) - sage: result[0], result[1].iterations - (2.1584685255476415, 9) - -Sage example in ./nonlinear.tex, line 1494:: - - sage: a, b = pi/2, pi - sage: generator = newtongen(f, a) - sage: next(generator) - 1/2*pi - sage: next(generator) - 1/2*pi - (e^(1/2*pi) - 10)*e^(-1/2*pi) - -""" diff --git a/src/sage/tests/french_book/numbertheory.py b/src/sage/tests/french_book/numbertheory.py deleted file mode 100644 index 1d8624fb527..00000000000 --- a/src/sage/tests/french_book/numbertheory.py +++ /dev/null @@ -1,139 +0,0 @@ -""" -Test file for Chapter Number Theory. -""" - -r""" -sage: a=IntegerModRing(15)(3); b=IntegerModRing(17)(3); a, b -(3, 3) -sage: a == b -False -sage: R=a.base_ring(); R -Ring of integers modulo 15 -sage: R.characteristic() -15 -sage: a+a, a-17, a*a+1, a^3 -(6, 1, 10, 12) -sage: 1/(a+1) -4 -sage: 1/a -Traceback (most recent call last): -... -ZeroDivisionError: inverse of Mod(3, 15) does not exist -sage: z=lift(a); y=ZZ(a); y, type(y), y==z -(3, , True) -sage: [Mod(x,15).additive_order() for x in range(0,15)] -[1, 15, 15, 5, 15, 3, 5, 15, 15, 5, 3, 15, 5, 15, 15] -sage: [[x,Mod(x,15).multiplicative_order()] for x in range(1,15) if gcd(x,15)==1] -[[1, 1], [2, 4], [4, 2], [7, 4], [8, 4], [11, 2], [13, 4], [14, 2]] -sage: p=10^20+39; mod(2,p).multiplicative_order() -50000000000000000019 -sage: mod(3,p).multiplicative_order() -100000000000000000038 -sage: n=3^100000; a=n-1; e=100 -sage: timeit('(a^e) % n') # random long time -5 loops, best of 3: 387 ms per loop -sage: timeit('power_mod(a,e,n)') # random -125 loops, best of 3: 3.46 ms per loop -sage: R = GF(17); [1/R(x) for x in range(1,17)] -[1, 9, 6, 13, 7, 3, 5, 15, 2, 12, 14, 10, 4, 11, 8, 16] -sage: R = GF(9,name='x'); R -Finite Field in x of size 3^2 -sage: R.polynomial() -x^2 + 2*x + 2 -sage: Set([r for r in R]) -{0, 1, 2, x, x + 1, x + 2, 2*x, 2*x + 1, 2*x + 2} -sage: Q. = PolynomialRing(GF(3)) -sage: R2 = GF(9,name='x',modulus=x^2+1); R2 -Finite Field in x of size 3^2 -sage: p = R(x+1); R2(p) -Traceback (most recent call last): -... -TypeError: unable to coerce from a finite field other than the prime subfield -sage: rational_reconstruction(411,1000) --13/17 -sage: rational_reconstruction(409,1000) -Traceback (most recent call last): -... -ArithmeticError: rational reconstruction of 409 (mod 1000) does not exist -sage: def harmonic(n): -....: return sum([1/x for x in range(1,n+1)]) -sage: def harmonic_mod(n,m): -....: return add([1/x % m for x in range(1,n+1)]) -sage: def harmonic2(n): -....: q = lcm(range(1,n+1)) -....: pmax = RR(q*(log(n)+1)) -....: m = ZZ(2*pmax^2) -....: m = ceil(m/q)*q + 1 -....: a = harmonic_mod(n,m) -....: return rational_reconstruction(a,m) -sage: harmonic(100) == harmonic2(100) -True -sage: a=2; b=3; m=5; n=7; lambda0=(b-a)/m % n; a+lambda0*m -17 -sage: crt(2,3,5,7) -17 -sage: def harmonic3(n): -....: q = lcm(range(1,n+1)) -....: pmax = RR(q*(log(n)+1)) -....: B = ZZ(2*pmax^2) -....: m = 1; a = 0; p = 2^63 -....: while m= 1.0e-6: # 1.0e-6 signifie 1.0*10^-6 - ....: temp = U - ....: U = 2 * U * V / (U + V) - ....: V = (temp + V) / 2 - sage: U, V - (9.99999999989..., 10.0000000001...) - -Sage example in ./programmation.tex, line 635:: - - sage: U = 0.0 # la somme S0 est vide, de valeur nulle - sage: V = -1.0 # S1 = -1/1^3 - sage: n = 0 # U et V contiennent S(2n) et S(2n+1) - sage: while U-V >= 1.0e-6: - ....: n = n+1 # n += 1 est équivalent - ....: U = V + 1/(2*n)^3 # passage de S(2n-1) à S(2n) - ....: V = U - 1/(2*n+1)^3 # passage de S(2n) à S(2n+1) - sage: V, U - (-0.901543155458595, -0.901542184868447) - -Sage example in ./programmation.tex, line 807:: - - sage: u = 6 ; n = 0 - sage: while u != 1: # test "différent de" - ....: if u % 2 == 0: # l'opérateur % donne le reste euclidien - ....: u = u//2 # // : quotient de la division euclidienne - ....: else: - ....: u = 3*u+1 - ....: n = n+1 - sage: n - 8 - -Sage example in ./programmation.tex, line 883:: - - sage: def fct2 (x, y): - ....: return x^2 + y^2 - sage: a = var('a') - sage: fct2 (a, 2*a) - 5*a^2 - -Sage example in ./programmation.tex, line 908:: - - sage: def essai (u): - ....: t = u^2 - ....: return t*(t+1) - sage: t = 1 ; u = 2 - sage: essai(3), t, u - (90, 1, 2) - -Sage example in ./programmation.tex, line 918:: - - sage: a = b = 1 - sage: def f(): global a; a = b = 2 - sage: f(); a, b - (2, 1) - -Sage example in ./programmation.tex, line 928:: - - sage: def MoyAH (u, v): - ....: u, v = min(u, v), max(u, v) - ....: while v-u > 2.0e-8: - ....: u, v = 2*u*v/(u+v), (u+v)/2 - ....: return (u+v) / 2 - -Sage example in ./programmation.tex, line 935:: - - sage: MoyAH (1., 2.) - 1.41421... - sage: MoyAH # correspond à une fonction - - -Sage example in ./programmation.tex, line 990:: - - sage: def fact1 (n): - ....: res = 1 - ....: for k in [1..n]: res = res*k - ....: return res - -Sage example in ./programmation.tex, line 996:: - - sage: def fact2 (n): - ....: if n == 0: return 1 - ....: else: return n*fact2(n-1) - -Sage example in ./programmation.tex, line 1013:: - - sage: def fib1 (n): - ....: if n == 0 or n == 1: return n - ....: else: - ....: U = 0 ; V = 1 # les termes initiaux u0 et u1 - ....: for k in [2..n]: W = U+V ; U = V ; V = W - ....: return V - sage: fib1(8) - 21 - -Sage example in ./programmation.tex, line 1037:: - - sage: def fib2 (n): - ....: if 0 <= n <= 1: return n # pour n = 0 ou n = 1 - ....: else: return fib2(n-1) + fib2(n-2) - -Sage example in ./programmation.tex, line 1079:: - - sage: a = 2; n = 6; res = 1 # 1 est le neutre du produit - sage: for k in [1..n]: res = res*a - sage: res # La valeur de res est 2^6 - 64 - -Sage example in ./programmation.tex, line 1150:: - - sage: def puiss1 (a, n): - ....: if n == 0: return 1 - ....: elif n % 2 == 0: b = puiss1 (a, n//2); return b*b - ....: else: return a * puiss1(a, n-1) - -Sage example in ./programmation.tex, line 1156:: - - sage: puiss1 (2, 11) # a pour résultat 2^11 - 2048 - -Sage example in ./programmation.tex, line 1177:: - - sage: def puiss2 (u, k): - ....: v = 1 - ....: while k != 0: - ....: if k % 2 == 0: u = u*u ; k = k//2 - ....: else: v = v*u ; k = k-1 - ....: return v - -Sage example in ./programmation.tex, line 1185:: - - sage: puiss2 (2, 10) # a pour résultat 2^10 - 1024 - -Sage example in ./programmation.tex, line 1238:: - - sage: def fib3 (n): - ....: A = matrix ([[0, 1], [1, 1]]) ; X0 = vector ([0, 1]) - ....: return (A^n*X0)[0] - -Sage example in ./programmation.tex, line 1243:: - - sage: def fib4 (n): - ....: return (matrix([[0,1], [1,1]])^n * vector([0,1]))[0] - -Sage example in ./programmation.tex, line 1257:: - - sage: print 2^2, 3^3, 4^4 ; print 5^5, 6^6 # not tested - python2 - 4 27 256 - 3125 46656 - -Sage example in ./programmation.tex, line 1265:: - - sage: for k in [1..10]: print '+', k, # not tested - python2 - + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 - -Sage example in ./programmation.tex, line 1273:: - - sage: print 10, 0.5 ; print(10+0.5) ; print 10.0, 5 # not tested - python2 - 10 0.500000000000000 - 10.5000000000000 - 10.0000000000000 5 - sage: print 10+0, 5 ; print(str(10)+str(0.5)) # not tested - python2 - 10 5 - 100.500000000000000 - -Sage example in ./programmation.tex, line 1294:: - - sage: for k in [1..6]: print('%2d^4 = %4d' % (k, k^4)) - 1^4 = 1 - 2^4 = 16 - 3^4 = 81 - 4^4 = 256 - 5^4 = 625 - 6^4 = 1296 - -Sage example in ./programmation.tex, line 1344:: - - sage: L = [10, 20, 30] - sage: L - [10, 20, 30] - sage: [] # [] est la liste vide - [] - -Sage example in ./programmation.tex, line 1361:: - - sage: L[1], len(L), len([]) - (20, 3, 0) - -Sage example in ./programmation.tex, line 1368:: - - sage: L[2] = 33 - sage: L - [10, 20, 33] - -Sage example in ./programmation.tex, line 1375:: - - sage: L = [11, 22, 33] - sage: L[-1], L[-2], L[-3] - (33, 22, 11) - -Sage example in ./programmation.tex, line 1388:: - - sage: L = [0, 11, 22, 33, 44, 55] - sage: L[2:4] - [22, 33] - sage: L[-4:4] - [22, 33] - sage: L[2:-2] - [22, 33] - sage: L[:4] - [0, 11, 22, 33] - sage: L[4:] - [44, 55] - -Sage example in ./programmation.tex, line 1404:: - - sage: L = [0, 11, 22, 33, 44, 55, 66, 77] - sage: L[2:6] = [12, 13, 14] # remplace [22, 33, 44, 55] - -Sage example in ./programmation.tex, line 1429:: - - sage: L = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] - sage: L[3:len(L)-5] == L[3-len(L):-5] - True - sage: [5 in L, 6 in L] - [True, False] - -Sage example in ./programmation.tex, line 1448:: - - sage: L = [1, 2, 3] ; L + [10, 20, 30] - [1, 2, 3, 10, 20, 30] - sage: 4 * [1, 2, 3] - [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] - -Sage example in ./programmation.tex, line 1467:: - - sage: L = 5*[10, 20, 30] ; L[:3]+L[3:] == L - True - -Sage example in ./programmation.tex, line 1476:: - - sage: [1..3, 7, 10..13] - [1, 2, 3, 7, 10, 11, 12, 13] - -Sage example in ./programmation.tex, line 1493:: - - sage: map (cos, [0, pi/6, pi/4, pi/3, pi/2]) - [1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0] - -Sage example in ./programmation.tex, line 1501:: - - sage: map (lambda t: cos(t), [0, pi/6, pi/4, pi/3, pi/2]) - [1, 1/2*sqrt(3), 1/2*sqrt(2), 1/2, 0] - -Sage example in ./programmation.tex, line 1526:: - - sage: map (lambda t: N(cos(t)), [0, pi/6, pi/4, pi/3, pi/2]) - [1.00000000000000, 0.866025403784439, 0.707106781186548, - 0.500000000000000, 0.000000000000000] - -Sage example in ./programmation.tex, line 1538:: - - sage: map (N, map (cos, [0, pi/6, pi/4, pi/3, pi/2])) - [1.00000000000000, 0.866025403784439, 0.707106781186548, - 0.500000000000000, 0.000000000000000] - -Sage example in ./programmation.tex, line 1543:: - - sage: map (compose(N, cos), [0, pi/6, pi/4, pi/3, pi/2]) - [1.00000000000000, 0.866025403784439, 0.707106781186548, - 0.500000000000000, 0.000000000000000] - -Sage example in ./programmation.tex, line 1552:: - - sage: list(filter(is_prime, [1..55])) - [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53] - -Sage example in ./programmation.tex, line 1562:: - - sage: p = 37 ; list(filter (lambda n: n^4 % p == 7, [0..p-1])) - [3, 18, 19, 34] - -Sage example in ./programmation.tex, line 1571:: - - sage: list(map(lambda n:2*n+1, [0..15])) - [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31] - sage: [2*n+1 for n in [0..15]] - [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31] - -Sage example in ./programmation.tex, line 1580:: - - sage: list(filter (is_prime, [1..55])) - [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53] - sage: [p for p in [1..55] if is_prime(p)] - [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53] - -Sage example in ./programmation.tex, line 1590:: - - sage: list(filter (is_prime, [4*n+1 for n in [0..20]])) - [5, 13, 17, 29, 37, 41, 53, 61, 73] - sage: [n^2 for n in [1..20] if is_prime(n)] - [4, 9, 25, 49, 121, 169, 289, 361] - -Sage example in ./programmation.tex, line 1609:: - - sage: reduce (lambda x, y: 10*x+y, [1, 2, 3, 4]) - 1234 - -Sage example in ./programmation.tex, line 1614:: - - sage: reduce (lambda x, y: 10*x+y, [9, 8, 7, 6], 1) - 19876 - -Sage example in ./programmation.tex, line 1621:: - - sage: L = [2*n+1 for n in [0..9]] - sage: reduce (lambda x, y: x*y, L, 1) - 654729075 - -Sage example in ./programmation.tex, line 1672:: - - sage: prod ([2*n+1 for n in [0..9]], 1) # une liste avec for - 654729075 - sage: prod ( 2*n+1 for n in [0..9]) # sans liste - 654729075 - sage: prod (n for n in [0..19] if n%2 == 1) - 654729075 - -Sage example in ./programmation.tex, line 1686:: - - sage: def fct (x): return 4/x == 2 - sage: all (fct(x) for x in [2, 1, 0]) - False - sage: any (fct(x) for x in [2, 1, 0]) - True - -Sage example in ./programmation.tex, line 1704:: - - sage: [[x, y] for x in [1..2] for y in [6..8]] - [[1, 6], [1, 7], [1, 8], [2, 6], [2, 7], [2, 8]] - -Sage example in ./programmation.tex, line 1709:: - - sage: [[[x, y] for x in [1..2]] for y in [6..8]] - [[[1, 6], [2, 6]], [[1, 7], [2, 7]], [[1, 8], [2, 8]]] - -Sage example in ./programmation.tex, line 1716:: - - sage: map (lambda x, y: [x, y], [1..3], [6..8]) - [[1, 6], [2, 7], [3, 8]] - -Sage example in ./programmation.tex, line 1723:: - - sage: L = [[1, 2, [3]], [4, [5, 6]], [7, [8, [9]]]] - sage: flatten (L, max_level = 1) - [1, 2, [3], 4, [5, 6], 7, [8, [9]]] - sage: flatten (L, max_level = 2) - [1, 2, 3, 4, 5, 6, 7, 8, [9]] - sage: flatten (L) # équivaut à flatten (L, max_level = 3) - [1, 2, 3, 4, 5, 6, 7, 8, 9] - -Sage example in ./programmation.tex, line 1740:: - - sage: x = var('x') - sage: factor(diff(x*exp(x), [x, x])) - (x + 2)*e^x - sage: list(map(lambda n: factor(diff(x*exp(x), n*[x])), [0..6])) - [x*e^x, (x + 1)*e^x, (x + 2)*e^x, (x + 3)*e^x, (x + 4)*e^x, - (x + 5)*e^x, (x + 6)*e^x] - sage: [factor (diff (x*exp(x), n*[x])) for n in [0..6]] - [x*e^x, (x + 1)*e^x, (x + 2)*e^x, (x + 3)*e^x, (x + 4)*e^x, - (x + 5)*e^x, (x + 6)*e^x] - -Sage example in ./programmation.tex, line 1774:: - - sage: L = [1, 8, 5, 2, 9] ; L.reverse() ; L - [9, 2, 5, 8, 1] - sage: L.sort() ; L - [1, 2, 5, 8, 9] - sage: L.sort(reverse = True) ; L - [9, 8, 5, 2, 1] - -Sage example in ./programmation.tex, line 1818:: - - sage: def alpha (P, Q): # len(P) = len(Q) par hypothèse - ....: i = 0 - ....: while True: - ....: if i == len(P): return int(0) - ....: elif P[i] < Q[i]: return int(-1) - ....: elif P[i] > Q[i]: return int(1) - ....: else: i = i+1 - sage: alpha ([2, 3, 4, 6, 5], [2, 3, 4, 5, 6]) - 1 - -Sage example in ./programmation.tex, line 1835:: - - sage: L = [[2, 2, 5], [2, 3, 4], [3, 2, 4], [3, 3, 3],\ - ....: [1, 1, 2], [1, 2, 7]] - sage: L.sort (cmp = alpha) ; L # py2 - [[1, 1, 2], [1, 2, 7], [2, 2, 5], [2, 3, 4], [3, 2, 4], [3, 3, 3]] - -Sage example in ./programmation.tex, line 1856:: - - sage: def homogLex (P, Q): - ....: sp = sum (P) ; sq = sum (Q) - ....: if sp < sq: return int(-1) - ....: elif sp > sq: return int(1) - ....: else: return alpha (P, Q) - -Sage example in ./programmation.tex, line 1863:: - - sage: homogLex ([2, 3, 4, 6, 4], [2, 3, 4, 5, 6]) - -1 - -Sage example in ./programmation.tex, line 1914:: - - sage: def fct1(L): - ....: return [list(filter (lambda n: n % 2 == 0, L)), - ....: list(filter (lambda n: n % 2 == 1, L))] - -Sage example in ./programmation.tex, line 1919:: - - sage: fct1([1..10]) - [[2, 4, 6, 8, 10], [1, 3, 5, 7, 9]] - -Sage example in ./programmation.tex, line 1926:: - - sage: def fct2 (L): - ....: res0 = [] ; res1 = [] - ....: for k in L: - ....: if k%2 == 0: res0.append(k) # ou res0[len(res0):] = [k] - ....: else: res1.append(k) # ou res1[len(res1):] = [k] - ....: return [res0, res1] - -Sage example in ./programmation.tex, line 1936:: - - sage: def fct3a (L, res0, res1): - ....: if L == []: return [res0, res1] - ....: elif L[0]%2 == 0: return fct3a(L[1:], res0+[L[0]], res1) - ....: else: return fct3a (L[1:], res0, res1+[L[0]]) - -Sage example in ./programmation.tex, line 1942:: - - sage: def fct3 (L): return fct3a (L, [], []) - -Sage example in ./programmation.tex, line 1955:: - - sage: def sousSuites (L): - ....: if L == []: return [] - ....: res = [] ; debut = 0 ; k = 1 - ....: while k < len(L): # 2 termes consécutifs sont définis - ....: if L[k-1] > L[k]: - ....: res.append (L[debut:k]) ; debut = k - ....: k = k+1 - ....: res.append (L[debut:k]) - ....: return res - -Sage example in ./programmation.tex, line 1966:: - - sage: sousSuites([1, 4, 1, 5]) - [[1, 4], [1, 5]] - sage: sousSuites([4, 1, 5, 1]) - [[4], [1, 5], [1]] - -Sage example in ./programmation.tex, line 1991:: - - sage: S = 'Ceci est une chaîne de caractères.' - -Sage example in ./programmation.tex, line 2001:: - - sage: S = 'Ceci est une chaîne de caractères.'; S - 'Ceci est une cha\xc3\xaene de caract\xc3\xa8res.' - sage: print(S) - Ceci est une chaîne de caractères. - -Sage example in ./programmation.tex, line 2026:: - - sage: S='un deux trois quatre cinq six sept'; L=S.split(); L - ['un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept'] - -Sage example in ./programmation.tex, line 2052:: - - sage: L1 = [11, 22, 33] ; L2 = L1 - sage: L1[1] = 222 ; L2.sort() ; L1, L2 - ([11, 33, 222], [11, 33, 222]) - sage: L1[2:3] = []; L2[0:0] = [6, 7, 8] - sage: L1, L2 - ([6, 7, 8, 11, 33], [6, 7, 8, 11, 33]) - -Sage example in ./programmation.tex, line 2088:: - - sage: L1 = [11, 22, 33] ; L2 = L1 ; L3 = L1[:] - sage: [L1 is L2, L2 is L1, L1 is L3, L1 == L3] - [True, True, False, True] - -Sage example in ./programmation.tex, line 2096:: - - sage: La = [1, 2, 3] ; L1 = [1, La] ; L2 = copy(L1) - sage: L1[1][0] = 5 # [1, [5, 2, 3]] pour L1 et L2 - sage: [L1 == L2, L1 is L2, L1[1] is L2[1]] - [True, False, True] - -Sage example in ./programmation.tex, line 2141:: - - sage: def lexInverse (P, Q): - ....: P1 = copy(P) ; P1.reverse() - ....: Q1 = copy(Q) ; Q1.reverse() - ....: return - alpha (P1, Q1) - -Sage example in ./programmation.tex, line 2202:: - - sage: S0 = (); S1 = (1, ); S2 = (1, 2) - sage: [1 in S1, 1 == (1)] - [True, True] - -Sage example in ./programmation.tex, line 2214:: - - sage: S1 = (1, 4, 9, 16, 25); [k for k in S1] - [1, 4, 9, 16, 25] - -Sage example in ./programmation.tex, line 2221:: - - sage: L1 = [0..4]; L2 = [5..9] - sage: list(zip(L1, L2)) - [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)] - sage: list(map(lambda x, y:(x, y), L1, L2)) - [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)] - -Sage example in ./programmation.tex, line 2238:: - - sage: E=Set([1, 2, 4, 8, 2, 2, 2]); F=Set([7, 5, 3, 1]); E, F - ({8, 1, 2, 4}, {1, 3, 5, 7}) - -Sage example in ./programmation.tex, line 2252:: - - sage: E = Set([1, 2, 4, 8, 2, 2, 2]); F = Set([7, 5, 3, 1]) - sage: 5 in E, 5 in F, E + F == F | E - (False, True, True) - sage: E & F, E - F, E ^^ F - ({1}, {8, 2, 4}, {2, 3, 4, 5, 7, 8}) - -Sage example in ./programmation.tex, line 2267:: - - sage: E = Set([1, 2, 4, 8, 2, 2, 2]) - sage: [E[k] for k in [0..len(E)-1]], [t for t in E] - ([8, 1, 2, 4], [8, 1, 2, 4]) - -Sage example in ./programmation.tex, line 2275:: - - sage: def inclus (E, F): return E+F == F - -Sage example in ./programmation.tex, line 2283:: - - sage: Set([Set([]), Set([1]), Set([2]), Set([1, 2])]) - {{1, 2}, {}, {2}, {1}} - sage: Set([ (), (1, ), (2, ), (1, 2) ]) - {(1, 2), (2,), (), (1,)} - -Sage example in ./programmation.tex, line 2292:: - - sage: def Parties (EE): - ....: if EE == Set([]): return Set([EE]) - ....: else: - ....: return avecOuSansElt (EE[0], Parties(Set(EE[1:]))) - -Sage example in ./programmation.tex, line 2298:: - - sage: def avecOuSansElt (a, E): - ....: return Set (map (lambda F: Set([a])+F, E)) + E - -Sage example in ./programmation.tex, line 2302:: - - sage: Parties(Set([1, 2, 3])) - {{3}, {1, 2}, {}, {2, 3}, {1}, {1, 3}, {1, 2, 3}, {2}} - -Sage example in ./programmation.tex, line 2324:: - - sage: D={}; D['un']=1; D['deux']=2; D['trois']=3; D['dix']=10 - sage: D['deux'] + D['trois'] - 5 - -Sage example in ./programmation.tex, line 2354:: - - sage: D = {'a0':'b0', 'a1':'b1', 'a2':'b2', 'a3':'b0',\ - ....: 'a4':'b3', 'a5':'b3'} - sage: E = Set(D) ; Imf = Set(D.values()) - sage: Imf == Set(map (lambda t:D[t], E)) # est équivalent - True - -Sage example in ./programmation.tex, line 2381:: - - sage: def injective(D): - ....: return len(D) == len (Set(D.values())) - -""" diff --git a/src/sage/tests/py3_syntax.py b/src/sage/tests/py3_syntax.py index bb90332fdc7..6207c870dfa 100644 --- a/src/sage/tests/py3_syntax.py +++ b/src/sage/tests/py3_syntax.py @@ -16,7 +16,7 @@ sage: py3_syntax = Python3SyntaxTest('sage', 'sage_setup') sage: py3_syntax.run_tests('.py') # long time """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Volker Braun # 2017 Frédéric Chapoton # 2017 Julian Rüth @@ -25,9 +25,8 @@ # 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 __future__ import print_function import os @@ -77,9 +76,10 @@ def __iter__(self): EXAMPLES:: sage: from sage.tests.py3_syntax import Python3SyntaxTest - sage: test = Python3SyntaxTest('sage/tests/french_book') + sage: name = 'sage/tests/books/computational-mathematics-with-sagemath' + sage: test = Python3SyntaxTest(name) sage: next(iter(test)) - ('...src/sage/tests/french_book', 'README', '') + ('...src/sage/tests/books/computational-mathematics-with-sagemath', 'README', '') """ tree_walk = itertools.chain(*map(os.walk, self._directories)) for path, _, files in tree_walk: diff --git a/src/sage/tests/stl_vector.pyx b/src/sage/tests/stl_vector.pyx index 7baccb6fec8..5eb733dacd3 100644 --- a/src/sage/tests/stl_vector.pyx +++ b/src/sage/tests/stl_vector.pyx @@ -15,15 +15,14 @@ AUTHORS: - Volker Braun (2012-01-18): initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 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/ -#***************************************************************************** +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off @@ -33,6 +32,7 @@ from sage.libs.gmp.mpz cimport mpz_add_ui from libcpp.vector cimport vector from libcpp.string cimport string from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool +from sage.cpython.string cimport char_to_str cdef class stl_int_vector(SageObject): @@ -90,7 +90,7 @@ cdef class stl_int_vector(SageObject): sage: v[1] 456 """ - assert i>=0 and i(zz if isinstance(zz, ComplexDoubleElement) else CDF(zz)) - return z._complex.dat[0] + _Complex_I * z._complex.dat[1] + return z._complex.real + _Complex_I * z._complex.imag cdef inline ComplexDoubleElement dz_to_CDE(double_complex dz): cdef ComplexDoubleElement z = ComplexDoubleElement.__new__(ComplexDoubleElement) - z._complex.dat[0] = creal(dz) - z._complex.dat[1] = cimag(dz) + z._complex.real = creal(dz) + z._complex.imag = cimag(dz) return z cdef public bint cdf_py_call_helper(object fn, diff --git a/src/sage_setup/docbuild/__init__.py b/src/sage_setup/docbuild/__init__.py index 0b24b1a60b8..4546f87cb23 100644 --- a/src/sage_setup/docbuild/__init__.py +++ b/src/sage_setup/docbuild/__init__.py @@ -35,15 +35,21 @@ # 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 __future__ import absolute_import -from __future__ import print_function +from __future__ import absolute_import, print_function from six.moves import range -import optparse, os, shutil, subprocess, sys, re -import logging, warnings +import logging +import optparse +import os +import re +import shutil +import subprocess +import sys +import time +import warnings logger = logging.getLogger(__name__) @@ -54,7 +60,7 @@ import sage.all from sage.misc.cachefunc import cached_method from sage.misc.misc import sage_makedirs -from sage.env import SAGE_DOC_SRC, SAGE_DOC, SAGE_SRC +from sage.env import SAGE_DOC_SRC, SAGE_DOC, SAGE_SRC, CYGWIN_VERSION from .build_options import (LANGUAGES, SPHINXOPTS, PAPER, OMIT, PAPEROPTS, ALLSPHINXOPTS, NUM_THREADS, WEBSITESPHINXOPTS, @@ -265,29 +271,44 @@ def clean(self, *args): # import the customized builder for object.inv files inventory = builder_helper('inventory') -def build_many(target, args): - # Pool() uses an actual fork() to run each new instance. This is important - # for performance reasons, i.e., don't use a forkserver when it becomes - # available with Python 3: Here, sage is already initialized which is quite - # costly, with a forkserver we would have to reinitialize it for every - # document we build. At the same time, don't serialize this by taking the - # pool (and thus the call to fork()) out completely: The call to Sphinx - # leaks memory, so we need to build each document in its own process to - # control the RAM usage. - from multiprocessing import Pool - pool = Pool(NUM_THREADS, maxtasksperchild=1) - # map_async handles KeyboardInterrupt correctly. Plain map and - # apply_async does not, so don't use it. - x = pool.map_async(target, args, 1) - try: - ret = x.get(99999) - pool.close() - pool.join() - except Exception: - pool.terminate() - if ABORT_ON_ERROR: - raise - return ret + +if not (CYGWIN_VERSION and CYGWIN_VERSION[0] < 3): + def build_many(target, args): + # Pool() uses an actual fork() to run each new instance. This is + # important for performance reasons, i.e., don't use a forkserver when + # it becomes available with Python 3: Here, sage is already initialized + # which is quite costly, with a forkserver we would have to + # reinitialize it for every document we build. At the same time, don't + # serialize this by taking the pool (and thus the call to fork()) out + # completely: The call to Sphinx leaks memory, so we need to build each + # document in its own process to control the RAM usage. + from multiprocessing import Pool + pool = Pool(NUM_THREADS, maxtasksperchild=1) + # map_async handles KeyboardInterrupt correctly. Plain map and + # apply_async does not, so don't use it. + x = pool.map_async(target, args, 1) + try: + ret = x.get(99999) + pool.close() + pool.join() + except Exception: + pool.terminate() + if ABORT_ON_ERROR: + raise + return ret +else: + # Cygwin 64-bit < 3.0.0 has a bug with exception handling when exceptions + # occur in pthreads, so it's dangerous to use multiprocessing.Pool, as + # signals can't be properly handled in worker processes, and they can crash + # causing the docbuild to hang. But where are these pthreads, you ask? + # Well, multiprocessing.Pool runs a thread from which it starts new worker + # processes when old workers complete/die, so the worker processes behave + # as though they were started from a pthread, even after fork(), and are + # actually succeptible to this bug. As a workaround, here's a naïve but + # good-enough "pool" replacement that does not use threads + # https://trac.sagemath.org/ticket/27214#comment:25 for further discussion. + from .utils import _build_many as build_many + ########################################## # Parallel Building Ref Manual # @@ -319,7 +340,6 @@ def _wrapper(self, name, *args, **kwds): This is the function which goes through all of the documents and does the actual building. """ - import time start = time.time() docs = self.get_all_documents() refs = [x for x in docs if x.endswith('reference')] @@ -804,7 +824,6 @@ def __init__(self, dir): return env except IOError as err: logger.debug("Failed to open Sphinx environment: %s", err) - pass def update_mtimes(self): """ @@ -813,7 +832,6 @@ def update_mtimes(self): """ env = self.get_sphinx_environment() if env is not None: - import time for doc in env.all_docs: env.all_docs[doc] = time.time() logger.info("Updated %d reST file mtimes", len(env.all_docs)) @@ -1068,7 +1086,6 @@ def clean_auto(self): """ Remove all autogenerated reST files. """ - import shutil try: shutil.rmtree(os.path.join(self.dir, 'sage')) logger.debug("Deleted auto-generated reST files in: %s", @@ -1562,6 +1579,7 @@ def setup_parser(): return parser + def setup_logger(verbose=1, color=True): r""" Set up a Python Logger instance for the Sage documentation builder. The @@ -1571,9 +1589,8 @@ def setup_logger(verbose=1, color=True): sage: from sage_setup.docbuild import setup_logger, logger sage: setup_logger() - sage: logger - - + sage: type(logger) + """ # Set up colors. Adapted from sphinx.cmdline. import sphinx.util.console as c diff --git a/src/sage_setup/docbuild/build_options.py b/src/sage_setup/docbuild/build_options.py index 1168f025110..ddc88a39f0e 100644 --- a/src/sage_setup/docbuild/build_options.py +++ b/src/sage_setup/docbuild/build_options.py @@ -23,7 +23,7 @@ # Number of threads to use for parallel-building the documentation. NUM_THREADS = int(os.environ.get('SAGE_NUM_THREADS', 1)) -# Minimize GAP/libGAP RAM usage in the builder, docbuild already uses too much +# Minimize GAP RAM usage in the builder, docbuild already uses too much from sage.interfaces.gap import set_gap_memory_pool_size set_gap_memory_pool_size(80 * 1024 * 1024) diff --git a/src/sage_setup/docbuild/ext/multidocs.py b/src/sage_setup/docbuild/ext/multidocs.py index dc2e065e7e2..15c7ca5d77f 100644 --- a/src/sage_setup/docbuild/ext/multidocs.py +++ b/src/sage_setup/docbuild/ext/multidocs.py @@ -50,7 +50,7 @@ def merge_environment(app, env): """ app.info(bold('Merging environment/index files...')) for curdoc in app.env.config.multidocs_subdoc_list: - app.info(" %s:"%curdoc, nonl=1) + app.info(" %s:" % curdoc, nonl=1) docenv = get_env(app, curdoc) if docenv is not None: fixpath = lambda path: os.path.join(curdoc, path) @@ -189,8 +189,10 @@ def get_js_index(app, curdoc): return indexer -mustbefixed = ['search', 'genindex', 'genindex-all' +mustbefixed = ['search', 'genindex', 'genindex-all', 'py-modindex', 'searchindex.js'] + + def fix_path_html(app, pagename, templatename, ctx, event_arg): """ Fixes the context so that the files diff --git a/src/sage_setup/docbuild/ext/sage_autodoc.py b/src/sage_setup/docbuild/ext/sage_autodoc.py index 2c399bad51b..25895d3adc4 100644 --- a/src/sage_setup/docbuild/ext/sage_autodoc.py +++ b/src/sage_setup/docbuild/ext/sage_autodoc.py @@ -1,69 +1,70 @@ # -*- coding: utf-8 -*- """ - sage_autodoc - ~~~~~~~~~~~~ +Sage autodoc extension based on sphinx.ext.autodoc from Sphinx - Based on sphinx.ext.autodoc from Sphinx. - The upstream original can be found at - https://github.com/sphinx-doc/sphinx/blob/v1.5.3/sphinx/ext/autodoc.py +From sphinx.ext.autodoc: Automatically insert docstrings for functions, classes or whole modules into the doctree, thus avoiding duplication between docstrings and documentation for those who like elaborate docstrings. - :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + :copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. - AUTHORS: +The upstream original can be found at +https://github.com/sphinx-doc/sphinx/blob/master/sphinx/ext/autodoc/__init__.py - - ? (before 2011) - Initial version derived from sphinx.ext.autodoc - - Johan S. R. Nielsen - Support for _sage_argspec_ - - Simon King (2011-04) - Use sageinspect. Include public cython attributes - only in the documentation if they have a docstring. +AUTHORS: + +- ? (before 2011): initial version derived from sphinx.ext.autodoc + +- Johan S. R. Nielsen: support for _sage_argspec_ + +- Simon King (2011-04): use sageinspect; include public cython attributes + only in the documentation if they have a docstring + +- Kwankyu Lee (2018-12-26): rebase on the latest sphinx.ext.autodoc """ +import inspect import re import sys -import inspect -import traceback import warnings -from types import FunctionType, BuiltinFunctionType, MethodType -from six import PY2, iterkeys, iteritems, itervalues, text_type, class_types, \ - string_types, StringIO -from docutils import nodes -from docutils.utils import assemble_option_dict from docutils.statemachine import ViewList +from six import PY2, iteritems, itervalues, text_type, class_types, string_types import sphinx -from sphinx.util import rpartition, force_decode -from sphinx.locale import _ +from sphinx.errors import ExtensionError +from sphinx.ext.autodoc.importer import mock, import_object, get_object_members +from sphinx.ext.autodoc.inspector import format_annotation, formatargspec +from sphinx.locale import _, __ from sphinx.pycode import ModuleAnalyzer, PycodeError -from sphinx.application import ExtensionError -from sphinx.util.nodes import nested_parse_with_titles -from docutils.parsers.rst import Directive -from sphinx.util.inspect import getargspec, isdescriptor, safe_getmembers, \ - safe_getattr, object_description, is_builtin_class_method, \ - isenumclass, isenumattribute +from sphinx.util import logging +from sphinx.util import rpartition, force_decode from sphinx.util.docstrings import prepare_docstring +from sphinx.util.inspect import Signature, isdescriptor, safe_getmembers, \ + safe_getattr, object_description, is_builtin_class_method, \ + isenumattribute, isclassmethod, isstaticmethod, getdoc +from sphinx.util.inspect import getargspec + +from sage.misc.sageinspect import (sage_getdoc_original, + sage_getargspec, isclassinstance) +from sage.misc.lazy_import import LazyImport + +# This is used to filter objects of classes that inherit from +# ClasscallMetaclass. See the class AttributeDocumenter below. +from sage.misc.classcall_metaclass import ClasscallMetaclass + + +logger = logging.getLogger(__name__) -try: - if sys.version_info >= (3,): - import typing - else: - typing = None -except ImportError: - typing = None # This type isn't exposed directly in any modules, but can be found # here in most Python versions MethodDescriptorType = type(type.__subclasses__) -from sage.misc.sageinspect import (sage_getdoc_original, - sage_getargspec, isclassinstance) -from sage.misc.lazy_import import LazyImport - #: extended signature RE: with explicit module name separated by :: py_ext_sig_re = re.compile( @@ -76,82 +77,17 @@ ''', re.VERBOSE) -class DefDict(dict): - """A dict that returns a default on nonexisting keys.""" - def __init__(self, default): - dict.__init__(self) - self.default = default - - def __getitem__(self, key): - try: - return dict.__getitem__(self, key) - except KeyError: - return self.default - - def __bool__(self): - # docutils check "if option_spec" - return True - __nonzero__ = __bool__ # for python2 compatibility - - def identity(x): + # type: (Any) -> Any return x -class Options(dict): - """A dict/attribute hybrid that returns None on nonexisting keys.""" - def __getattr__(self, name): - try: - return self[name.replace('_', '-')] - except KeyError: - return None - - -class _MockModule(object): - """Used by autodoc_mock_imports.""" - __file__ = '/dev/null' - __path__ = '/dev/null' - - def __init__(self, *args, **kwargs): - self.__all__ = [] - - def __call__(self, *args, **kwargs): - if args and type(args[0]) in [FunctionType, MethodType]: - # Appears to be a decorator, pass through unchanged - return args[0] - return _MockModule() - - def _append_submodule(self, submod): - self.__all__.append(submod) - - @classmethod - def __getattr__(cls, name): - if name[0] == name[0].upper(): - # Not very good, we assume Uppercase names are classes... - mocktype = type(name, (), {}) - mocktype.__module__ = __name__ - return mocktype - else: - return _MockModule() - - -def mock_import(modname): - if '.' in modname: - pkg, _n, mods = modname.rpartition('.') - mock_import(pkg) - if isinstance(sys.modules[pkg], _MockModule): - sys.modules[pkg]._append_submodule(mods) - - if modname not in sys.modules: - mod = _MockModule() - sys.modules[modname] = mod - - ALL = object() INSTANCEATTR = object() def members_option(arg): + # type: (Any) -> Union[object, List[unicode]] """Used to convert the :members: option to auto directives.""" if arg is None: return ALL @@ -159,6 +95,7 @@ def members_option(arg): def members_set_option(arg): + # type: (Any) -> Union[object, Set[unicode]] """Used to convert the :members: option to auto directives.""" if arg is None: return ALL @@ -169,6 +106,7 @@ def members_set_option(arg): def annotation_option(arg): + # type: (Any) -> Any if arg is None: # suppress showing the representation of the object return SUPPRESS @@ -177,6 +115,7 @@ def annotation_option(arg): def bool_option(arg): + # type: (Any) -> bool """Used to convert flag options to auto directives. (Instead of directives.flag(), which returns None). """ @@ -189,13 +128,16 @@ class AutodocReporter(object): and line number to a system message, as recorded in a ViewList. """ def __init__(self, viewlist, reporter): + # type: (ViewList, Reporter) -> None self.viewlist = viewlist self.reporter = reporter def __getattr__(self, name): + # type: (unicode) -> Any return getattr(self.reporter, name) def system_message(self, level, message, *children, **kwargs): + # type: (int, unicode, Any, Any) -> nodes.system_message if 'line' in kwargs and 'source' not in kwargs: try: source, line = self.viewlist.items[kwargs['line']] @@ -208,25 +150,31 @@ def system_message(self, level, message, *children, **kwargs): *children, **kwargs) def debug(self, *args, **kwargs): + # type: (Any, Any) -> nodes.system_message if self.reporter.debug_flag: return self.system_message(0, *args, **kwargs) def info(self, *args, **kwargs): + # type: (Any, Any) -> nodes.system_message return self.system_message(1, *args, **kwargs) def warning(self, *args, **kwargs): + # type: (Any, Any) -> nodes.system_message return self.system_message(2, *args, **kwargs) def error(self, *args, **kwargs): + # type: (Any, Any) -> nodes.system_message return self.system_message(3, *args, **kwargs) def severe(self, *args, **kwargs): + # type: (Any, Any) -> nodes.system_message return self.system_message(4, *args, **kwargs) # Some useful event listener factories for autodoc-process-docstring. def cut_lines(pre, post=0, what=None): + # type: (int, int, unicode) -> Callable """Return a listener that removes the first *pre* and last *post* lines of every docstring. If *what* is a sequence of strings, only docstrings of a type in *what* will be processed. @@ -239,6 +187,7 @@ def cut_lines(pre, post=0, what=None): This can (and should) be used in place of :confval:`automodule_skip_lines`. """ def process(app, what_, name, obj, options, lines): + # type: (Sphinx, unicode, unicode, Any, Any, List[unicode]) -> None if what and what_ not in what: return del lines[:pre] @@ -254,6 +203,7 @@ def process(app, what_, name, obj, options, lines): def between(marker, what=None, keepempty=False, exclude=False): + # type: (unicode, Sequence[unicode], bool, bool) -> Callable """Return a listener that either keeps, or if *exclude* is True excludes, lines between lines that match the *marker* regular expression. If no line matches, the resulting docstring would be empty, so no change will be made @@ -265,6 +215,7 @@ def between(marker, what=None, keepempty=False, exclude=False): marker_re = re.compile(marker) def process(app, what_, name, obj, options, lines): + # type: (Sphinx, unicode, unicode, Any, Any, List[unicode]) -> None if what and what_ not in what: return deleted = 0 @@ -287,147 +238,6 @@ def process(app, what_, name, obj, options, lines): return process -def format_annotation(annotation): - """Return formatted representation of a type annotation. - - Show qualified names for types and additional details for types from - the ``typing`` module. - - Displaying complex types from ``typing`` relies on its private API. - """ - if typing and isinstance(annotation, typing.TypeVar): - return annotation.__name__ - if annotation == Ellipsis: - return '...' - if not isinstance(annotation, type): - return repr(annotation) - - qualified_name = (annotation.__module__ + '.' + annotation.__qualname__ - if annotation else repr(annotation)) - - if annotation.__module__ == 'builtins': - return annotation.__qualname__ - elif typing: - if hasattr(typing, 'GenericMeta') and \ - isinstance(annotation, typing.GenericMeta): - # In Python 3.5.2+, all arguments are stored in __args__, - # whereas __parameters__ only contains generic parameters. - # - # Prior to Python 3.5.2, __args__ is not available, and all - # arguments are in __parameters__. - params = None - if hasattr(annotation, '__args__'): - if annotation.__args__ is None or len(annotation.__args__) <= 2: - params = annotation.__args__ - else: # typing.Callable - args = ', '.join(format_annotation(a) for a in annotation.__args__[:-1]) - result = format_annotation(annotation.__args__[-1]) - return '%s[[%s], %s]' % (qualified_name, args, result) - elif hasattr(annotation, '__parameters__'): - params = annotation.__parameters__ - if params is not None: - param_str = ', '.join(format_annotation(p) for p in params) - return '%s[%s]' % (qualified_name, param_str) - elif hasattr(typing, 'UnionMeta') and \ - isinstance(annotation, typing.UnionMeta) and \ - hasattr(annotation, '__union_params__'): - params = annotation.__union_params__ - if params is not None: - param_str = ', '.join(format_annotation(p) for p in params) - return '%s[%s]' % (qualified_name, param_str) - elif hasattr(typing, 'CallableMeta') and \ - isinstance(annotation, typing.CallableMeta) and \ - getattr(annotation, '__args__', None) is not None and \ - hasattr(annotation, '__result__'): - # Skipped in the case of plain typing.Callable - args = annotation.__args__ - if args is None: - return qualified_name - elif args is Ellipsis: - args_str = '...' - else: - formatted_args = (format_annotation(a) for a in args) - args_str = '[%s]' % ', '.join(formatted_args) - return '%s[%s, %s]' % (qualified_name, - args_str, - format_annotation(annotation.__result__)) - elif hasattr(typing, 'TupleMeta') and \ - isinstance(annotation, typing.TupleMeta) and \ - hasattr(annotation, '__tuple_params__') and \ - hasattr(annotation, '__tuple_use_ellipsis__'): - params = annotation.__tuple_params__ - if params is not None: - param_strings = [format_annotation(p) for p in params] - if annotation.__tuple_use_ellipsis__: - param_strings.append('...') - return '%s[%s]' % (qualified_name, - ', '.join(param_strings)) - return qualified_name - - -def formatargspec(function, args, varargs=None, varkw=None, defaults=None, - kwonlyargs=(), kwonlydefaults={}, annotations={}): - """Return a string representation of an ``inspect.FullArgSpec`` tuple. - - An enhanced version of ``inspect.formatargspec()`` that handles typing - annotations better. - """ - - def format_arg_with_annotation(name): - if name in annotations: - return '%s: %s' % (name, format_annotation(get_annotation(name))) - return name - - def get_annotation(name): - value = annotations[name] - if isinstance(value, string_types): - return introspected_hints.get(name, value) - else: - return value - - introspected_hints = (typing.get_type_hints(function) - if typing and hasattr(function, '__code__') else {}) - - fd = StringIO() - fd.write('(') - - formatted = [] - defaults_start = len(args) - len(defaults) if defaults else len(args) - - for i, arg in enumerate(args): - arg_fd = StringIO() - arg_fd.write(format_arg_with_annotation(arg)) - if defaults and i >= defaults_start: - arg_fd.write(' = ' if arg in annotations else '=') - arg_fd.write(object_description(defaults[i - defaults_start])) - formatted.append(arg_fd.getvalue()) - - if varargs: - formatted.append('*' + format_arg_with_annotation(varargs)) - - if kwonlyargs: - if not varargs: - formatted.append('*') - - for kwarg in kwonlyargs: - arg_fd = StringIO() - arg_fd.write(format_arg_with_annotation(kwarg)) - if kwonlydefaults and kwarg in kwonlydefaults: - arg_fd.write(' = ' if kwarg in annotations else '=') - arg_fd.write(object_description(kwonlydefaults[kwarg])) - formatted.append(arg_fd.getvalue()) - - if varkw: - formatted.append('**' + format_arg_with_annotation(varkw)) - - fd.write(', '.join(formatted)) - fd.write(')') - - if 'return' in annotations: - fd.write(' -> ') - fd.write(format_annotation(get_annotation('return'))) - - return fd.getvalue() class Documenter(object): @@ -457,50 +267,57 @@ class Documenter(object): #: true if the generated content may contain titles titles_allowed = False - option_spec = {'noindex': bool_option} + option_spec = {'noindex': bool_option} # type: Dict[unicode, Callable] - @staticmethod - def get_attr(obj, name, *defargs): + def get_attr(self, obj, name, *defargs): + # type: (Any, unicode, Any) -> Any """getattr() override for types such as Zope interfaces.""" - for typ, func in iteritems(AutoDirective._special_attrgetters): - if isinstance(obj, typ): - return func(obj, name, *defargs) - return safe_getattr(obj, name, *defargs) + return autodoc_attrgetter(self.env.app, obj, name, *defargs) @classmethod def can_document_member(cls, member, membername, isattr, parent): + # type: (Any, unicode, bool, Any) -> bool """Called to see if a member can be documented by this documenter.""" raise NotImplementedError('must be implemented in subclasses') def __init__(self, directive, name, indent=u''): + # type: (DocumenterBridge, unicode, unicode) -> None self.directive = directive - self.env = directive.env + self.env = directive.env # type: BuildEnvironment self.options = directive.genopt self.name = name self.indent = indent # the module and object path within the module, and the fully # qualified name (all set after resolve_name succeeds) - self.modname = None - self.module = None - self.objpath = None - self.fullname = None + self.modname = None # type: str + self.module = None # type: ModuleType + self.objpath = None # type: List[unicode] + self.fullname = None # type: unicode # extra signature items (arguments and return annotation, # also set after resolve_name succeeds) - self.args = None - self.retann = None + self.args = None # type: unicode + self.retann = None # type: unicode # the object to document (set after import_object succeeds) - self.object = None - self.object_name = None + self.object = None # type: Any + self.object_name = None # type: unicode # the parent/owner of the object to document - self.parent = None + self.parent = None # type: Any # the module analyzer to get at attribute docs, or None - self.analyzer = None + self.analyzer = None # type: Any + + @property + def documenters(self): + # type: () -> Dict[unicode, Type[Documenter]] + """Returns registered Documenter classes""" + return get_documenters(self.env.app) def add_line(self, line, source, *lineno): + # type: (unicode, unicode, int) -> None """Append one line of generated reST to the output.""" self.directive.result.append(self.indent + line, source, *lineno) def resolve_name(self, modname, parents, path, base): + # type: (str, Any, str, Any) -> Tuple[str, List[unicode]] """Resolve the module and name of the object to document given by the arguments and the current module/class. @@ -511,6 +328,7 @@ def resolve_name(self, modname, parents, path, base): raise NotImplementedError('must be implemented in subclasses') def parse_name(self): + # type: () -> bool """Determine what module to import and what attribute to document. Returns True and sets *self.modname*, *self.objpath*, *self.fullname*, @@ -521,10 +339,9 @@ def parse_name(self): # an autogenerated one try: explicit_modname, path, base, args, retann = \ - py_ext_sig_re.match(self.name).groups() + py_ext_sig_re.match(self.name).groups() # type: ignore except AttributeError: - self.directive.warn('invalid signature for auto%s (%r)' % - (self.objtype, self.name)) + logger.warning('invalid signature for auto%s (%r)' % (self.objtype, self.name)) return False # support explicit module and class name separation via :: @@ -535,8 +352,7 @@ def parse_name(self): modname = None parents = [] - self.modname, self.objpath = \ - self.resolve_name(modname, parents, path, base) + self.modname, self.objpath = self.resolve_name(modname, parents, path, base) if not self.modname: return False @@ -548,58 +364,26 @@ def parse_name(self): return True def import_object(self): + # type: () -> bool """Import the object given by *self.modname* and *self.objpath* and set it as *self.object*. Returns True if successful, False if an error occurred. """ - dbg = self.env.app.debug - if self.objpath: - dbg('[autodoc] from %s import %s', - self.modname, '.'.join(self.objpath)) - try: - dbg('[autodoc] import %s', self.modname) - for modname in self.env.config.autodoc_mock_imports: - dbg('[autodoc] adding a mock module %s!', modname) - mock_import(modname) - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=ImportWarning) - __import__(self.modname) - parent = None - obj = self.module = sys.modules[self.modname] - dbg('[autodoc] => %r', obj) - for part in self.objpath: - parent = obj - dbg('[autodoc] getattr(_, %r)', part) - obj = self.get_attr(obj, part) - dbg('[autodoc] => %r', obj) - self.object_name = part - self.parent = parent - self.object = obj - return True - # this used to only catch SyntaxError, ImportError and AttributeError, - # but importing modules with side effects can raise all kinds of errors - except (Exception, SystemExit) as e: - if self.objpath: - errmsg = 'autodoc: failed to import %s %r from module %r' % \ - (self.objtype, '.'.join(self.objpath), self.modname) - else: - errmsg = 'autodoc: failed to import %s %r' % \ - (self.objtype, self.fullname) - if isinstance(e, SystemExit): - errmsg += ('; the module executes module level statement ' + - 'and it might call sys.exit().') - else: - errmsg += '; the following exception was raised:\n%s' % \ - traceback.format_exc() - if PY2: - errmsg = errmsg.decode('utf-8') - dbg(errmsg) - self.directive.warn(errmsg) - self.env.note_reread() - return False + with mock(self.env.config.autodoc_mock_imports): + try: + ret = import_object(self.modname, self.objpath, self.objtype, + attrgetter=self.get_attr, + warningiserror=self.env.config.autodoc_warningiserror) + self.module, self.parent, self.object_name, self.object = ret + return True + except ImportError as exc: + logger.warning(exc.args[0], type='autodoc', subtype='import_object') + self.env.note_reread() + return False def get_real_modname(self): + # type: () -> str """Get the real module name of an object to document. It can differ from the name of the module through which the object was @@ -608,6 +392,7 @@ def get_real_modname(self): return self.get_attr(self.object, '__module__', None) or self.modname def check_module(self): + # type: () -> bool """Check if *self.object* is really defined in the module given by *self.modname*. """ @@ -620,6 +405,7 @@ def check_module(self): return True def format_args(self): + # type: () -> unicode """Format the argument signature of *self.object*. Should return None if the object does not have a signature. @@ -627,6 +413,7 @@ def format_args(self): return None def format_name(self): + # type: () -> unicode """Format the name of *self.object*. This normally should be something that can be parsed by the generated @@ -638,20 +425,21 @@ def format_name(self): return '.'.join(self.objpath) or self.modname def format_signature(self): + # type: () -> unicode """Format the signature (arguments and return annotation) of the object. Let the user process it via the ``autodoc-process-signature`` event. """ if self.args is not None: # signature given explicitly - args = "(%s)" % self.args + args = "(%s)" % self.args # type: unicode else: # try to introspect the signature try: args = self.format_args() except Exception as err: - self.directive.warn('error while formatting arguments for ' - '%s: %s' % (self.fullname, err)) + logger.warning('error while formatting arguments for %s: %s' % + (self.fullname, err)) args = None retann = self.retann @@ -668,6 +456,7 @@ def format_signature(self): return '' def add_directive_header(self, sig): + # type: (unicode) -> None """Add the directive header and options to the generated content.""" domain = getattr(self, 'domain', 'py') directive = getattr(self, 'directivetype', self.objtype) @@ -683,8 +472,11 @@ def add_directive_header(self, sig): self.add_line(u' :module: %s' % self.modname, sourcename) def get_doc(self, encoding=None, ignore=1): + # type: (unicode, int) -> List[List[unicode]] """Decode and return lines of the docstring(s) for the object.""" docstring = sage_getdoc_original(self.object) + if docstring is None and self.env.config.autodoc_inherit_docstrings: + docstring = getdoc(self.object) # make sure we have Unicode docstrings, then sanitize and split # into lines if isinstance(docstring, text_type): @@ -696,6 +488,7 @@ def get_doc(self, encoding=None, ignore=1): return [] def process_doc(self, docstrings): + # type: (List[List[unicode]]) -> Iterator[unicode] """Let the user process the docstrings before adding them.""" for docstringlines in docstrings: if self.env.app: @@ -707,6 +500,7 @@ def process_doc(self, docstrings): yield line def get_sourcename(self): + # type: () -> unicode if self.analyzer: # prevent encoding errors when the file name is non-ASCII if not isinstance(self.analyzer.srcname, text_type): @@ -718,6 +512,7 @@ def get_sourcename(self): return u'docstring of %s' % self.fullname def add_content(self, more_content, no_docstring=False): + # type: (Any, bool) -> None """Add content from docstrings, attribute documentation and user.""" # set sourcename and add content from attribute documentation sourcename = self.get_sourcename() @@ -749,65 +544,34 @@ def add_content(self, more_content, no_docstring=False): self.add_line(line, src[0], src[1]) def get_object_members(self, want_all): + # type: (bool) -> Tuple[bool, List[Tuple[unicode, Any]]] """Return `(members_check_module, members)` where `members` is a list of `(membername, member)` pairs of the members of *self.object*. If *want_all* is True, return all members. Else, only return those members given by *self.options.members* (which may also be none). """ - analyzed_member_names = set() - if self.analyzer: - attr_docs = self.analyzer.find_attr_docs() - namespace = '.'.join(self.objpath) - for item in iteritems(attr_docs): - if item[0][0] == namespace: - analyzed_member_names.add(item[0][1]) + members = get_object_members(self.object, self.objpath, self.get_attr, self.analyzer) if not want_all: if not self.options.members: return False, [] # specific members given - members = [] - for mname in self.options.members: - try: - members.append((mname, self.get_attr(self.object, mname))) - except AttributeError: - if mname not in analyzed_member_names: - self.directive.warn('missing attribute %s in object %s' - % (mname, self.fullname)) + selected = [] + for name in self.options.members: + if name in members: + selected.append((name, members[name].value)) + else: + logger.warning('missing attribute %s in object %s' % + (name, self.fullname)) + return False, sorted(selected) elif self.options.inherited_members: - # safe_getmembers() uses dir() which pulls in members from all - # base classes - members = safe_getmembers(self.object, attr_getter=self.get_attr) + return False, sorted((m.name, m.value) for m in members.values()) else: - # __dict__ contains only the members directly defined in - # the class (but get them via getattr anyway, to e.g. get - # unbound method objects instead of function objects); - # using list(iterkeys()) because apparently there are objects for which - # __dict__ changes while getting attributes - try: - obj_dict = self.get_attr(self.object, '__dict__') - except AttributeError: - members = [] - else: - members = [(mname, self.get_attr(self.object, mname, None)) - for mname in list(iterkeys(obj_dict))] - - # Py34 doesn't have enum members in __dict__. - if isenumclass(self.object): - members.extend( - item for item in self.object.__members__.items() - if item not in members - ) - - membernames = set(m[0] for m in members) - # add instance attributes from the analyzer - for aname in analyzed_member_names: - if aname not in membernames and \ - (want_all or aname in self.options.members): - members.append((aname, INSTANCEATTR)) - return False, sorted(members) + return False, sorted((m.name, m.value) for m in members.values() + if m.directly_defined) def filter_members(self, members, want_all): + # type: (List[Tuple[unicode, Any]], bool) -> List[Tuple[unicode, Any, bool]] """Filter the given member list. Members are skipped if @@ -842,6 +606,9 @@ def filter_members(self, members, want_all): isattr = False doc = self.get_attr(member, '__doc__', None) + if doc is None and self.env.config.autodoc_inherit_docstrings: + doc = getdoc(member) + # if the member __doc__ is the same as self's __doc__, it's just # inherited and therefore not the member's doc cls = self.get_attr(member, '__class__', None) @@ -862,14 +629,18 @@ def filter_members(self, members, want_all): self.options.special_members is not ALL and \ membername in self.options.special_members: keep = has_doc or self.options.undoc_members + elif (namespace, membername) in attr_docs: + if want_all and membername.startswith('_'): + # ignore members whose name starts with _ by default + keep = self.options.private_members + else: + # keep documented attributes + keep = True + isattr = True elif want_all and membername.startswith('_'): # ignore members whose name starts with _ by default keep = self.options.private_members and \ (has_doc or self.options.undoc_members) - elif (namespace, membername) in attr_docs: - # keep documented attributes - keep = True - isattr = True else: # ignore undocumented members if :undoc-members: is not given keep = has_doc or self.options.undoc_members @@ -878,11 +649,17 @@ def filter_members(self, members, want_all): # should be skipped if self.env.app: # let extensions preprocess docstrings - skip_user = self.env.app.emit_firstresult( - 'autodoc-skip-member', self.objtype, membername, member, - not keep, self.options) - if skip_user is not None: - keep = not skip_user + try: + skip_user = self.env.app.emit_firstresult( + 'autodoc-skip-member', self.objtype, membername, member, + not keep, self.options) + if skip_user is not None: + keep = not skip_user + except Exception as exc: + logger.warning(__('autodoc: failed to determine %r to be documented.' + 'the following exception was raised:\n%s'), + member, exc) + keep = False if keep: ret.append((membername, member, isattr)) @@ -890,6 +667,7 @@ def filter_members(self, members, want_all): return ret def document_members(self, all_members=False): + # type: (bool) -> None """Generate reST for member documentation. If *all_members* is True, do all members, else those given by @@ -911,9 +689,9 @@ def document_members(self, all_members=False): if membername not in self.options.exclude_members] # document non-skipped members - memberdocumenters = [] + memberdocumenters = [] # type: List[Tuple[Documenter, bool]] for (mname, member, isattr) in self.filter_members(members, want_all): - classes = [cls for cls in itervalues(AutoDirective._registry) + classes = [cls for cls in itervalues(self.documenters) if cls.can_document_member(member, mname, isattr, self)] if not classes: # don't know how to document this member @@ -937,6 +715,7 @@ def document_members(self, all_members=False): tagorder = self.analyzer.tagorder def keyfunc(entry): + # type: (Tuple[Documenter, bool]) -> int fullname = entry[0].name.split('::')[1] return tagorder.get(fullname, len(tagorder)) memberdocumenters.sort(key=keyfunc) @@ -952,6 +731,7 @@ def keyfunc(entry): def generate(self, more_content=None, real_modname=None, check_module=False, all_members=False): + # type: (Any, str, bool, bool) -> None """Generate reST for the object given by *self.name*, and possibly for its members. @@ -962,11 +742,11 @@ def generate(self, more_content=None, real_modname=None, """ if not self.parse_name(): # need a module to import - self.directive.warn( + logger.warning( 'don\'t know which module to import for autodocumenting ' '%r (try placing a "module" or "currentmodule" directive ' - 'in the document, or giving an explicit module name)' - % self.name) + 'in the document, or giving an explicit module name)' % + self.name) return # now, import the module and get object to document @@ -978,7 +758,7 @@ def generate(self, more_content=None, real_modname=None, # where the attribute documentation would actually be found in. # This is used for situations where you have a module that collects the # functions and classes of internal submodules. - self.real_modname = real_modname or self.get_real_modname() + self.real_modname = real_modname or self.get_real_modname() # type: str # try to also get a source code analyzer for attribute docs try: @@ -987,13 +767,8 @@ def generate(self, more_content=None, real_modname=None, # be cached anyway) self.analyzer.find_attr_docs() except PycodeError as err: - self.env.app.debug('[autodoc] module analyzer failed: %s', err) - # A few things could have happened here: - # * there is no source file -- e.g. for builtin and C modules - # * the source file contains syntax that Sphinx can not parse, - # e.g., "print(1, end=' ')"; see - # https://github.com/sphinx-doc/sphinx/issues/1641, - # fixed in Sphinx 1.7. + logger.debug('[autodoc] module analyzer failed: %s', err) + # no source file -- e.g. for builtin and C modules self.analyzer = None # at least add the module.__file__ as a dependency if hasattr(self.module, '__file__') and self.module.__file__: @@ -1011,14 +786,14 @@ def generate(self, more_content=None, real_modname=None, # make sure that the result starts with an empty line. This is # necessary for some situations where another directive preprocesses # reST and no starting newline is present - self.add_line(u'', sourcename) + self.add_line('', sourcename) # format the object's signature, if any sig = self.format_signature() # generate the directive header and options, if applicable self.add_directive_header(sig) - self.add_line(u'', sourcename) + self.add_line('', sourcename) # e.g. the module directive doesn't have content self.indent += self.content_indent @@ -1046,26 +821,30 @@ class ModuleDocumenter(Documenter): 'member-order': identity, 'exclude-members': members_set_option, 'private-members': bool_option, 'special-members': members_option, 'imported-members': bool_option, - } + } # type: Dict[unicode, Callable] @classmethod def can_document_member(cls, member, membername, isattr, parent): + # type: (Any, unicode, bool, Any) -> bool # don't document submodules automatically return False def resolve_name(self, modname, parents, path, base): + # type: (str, Any, str, Any) -> Tuple[str, List[unicode]] if modname is not None: - self.directive.warn('"::" in automodule name doesn\'t make sense') + logger.warning('"::" in automodule name doesn\'t make sense') return (path or '') + base, [] def parse_name(self): + # type: () -> bool ret = Documenter.parse_name(self) if self.args or self.retann: - self.directive.warn('signature arguments or return annotation ' - 'given for automodule %s' % self.fullname) + logger.warning('signature arguments or return annotation ' + 'given for automodule %s' % self.fullname) return ret def add_directive_header(self, sig): + # type: (unicode) -> None Documenter.add_directive_header(self, sig) sourcename = self.get_sourcename() @@ -1081,6 +860,7 @@ def add_directive_header(self, sig): self.add_line(u' :deprecated:', sourcename) def get_object_members(self, want_all): + # type: (bool) -> Tuple[bool, List[Tuple[unicode, object]]] if want_all: if not hasattr(self.object, '__all__'): # for implicit module members, check __module__ to avoid @@ -1091,7 +871,7 @@ def get_object_members(self, want_all): # Sometimes __all__ is broken... if not isinstance(memberlist, (list, tuple)) or not \ all(isinstance(entry, string_types) for entry in memberlist): - self.directive.warn( + logger.warning( '__all__ should be a list of strings, not %r ' '(in module %s) -- ignoring __all__' % (memberlist, self.fullname)) @@ -1104,10 +884,10 @@ def get_object_members(self, want_all): try: ret.append((mname, safe_getattr(self.object, mname))) except AttributeError: - self.directive.warn( + logger.warning( 'missing attribute mentioned in :members: or __all__: ' - 'module %s, attribute %s' % ( - safe_getattr(self.object, '__name__', '???'), mname)) + 'module %s, attribute %s' % + (safe_getattr(self.object, '__name__', '???'), mname)) return False, ret @@ -1117,6 +897,7 @@ class ModuleLevelDocumenter(Documenter): classes, data/constants). """ def resolve_name(self, modname, parents, path, base): + # type: (str, Any, str, Any) -> Tuple[str, List[unicode]] if modname is None: if path: modname = path.rstrip('.') @@ -1137,6 +918,7 @@ class ClassLevelDocumenter(Documenter): attributes). """ def resolve_name(self, modname, parents, path, base): + # type: (str, Any, str, Any) -> Tuple[str, List[unicode]] if modname is None: if path: mod_cls = path.rstrip('.') @@ -1152,7 +934,7 @@ def resolve_name(self, modname, parents, path, base): # ... if still None, there's no way to know if mod_cls is None: return None, [] - modname, cls = rpartition(mod_cls, '.') + modname, cls = rpartition(mod_cls, '.') # type: ignore parents = [cls] # if the module name is still missing, get it like above if not modname: @@ -1170,6 +952,7 @@ class DocstringSignatureMixin(object): """ def _find_signature(self, encoding=None): + # type: (unicode) -> Tuple[str, str] docstrings = self.get_doc(encoding) self._new_docstrings = docstrings[:] result = None @@ -1178,12 +961,12 @@ def _find_signature(self, encoding=None): if not doclines: continue # match first line of docstring against signature RE - match = py_ext_sig_re.match(doclines[0]) + match = py_ext_sig_re.match(doclines[0]) # type: ignore if not match: continue exmod, path, base, args, retann = match.groups() # the base name must match ours - valid_names = [self.objpath[-1]] + valid_names = [self.objpath[-1]] # type: ignore if isinstance(self, ClassDocumenter): valid_names.append('__init__') if hasattr(self.object, '__mro__'): @@ -1198,13 +981,15 @@ def _find_signature(self, encoding=None): return result def get_doc(self, encoding=None, ignore=1): + # type: (unicode, int) -> List[List[unicode]] lines = getattr(self, '_new_docstrings', None) if lines is not None: return lines - return Documenter.get_doc(self, encoding, ignore) + return Documenter.get_doc(self, encoding, ignore) # type: ignore def format_signature(self): - if self.args is None and self.env.config.autodoc_docstring_signature: + # type: () -> unicode + if self.args is None and self.env.config.autodoc_docstring_signature: # type: ignore # only act if a signature is not explicitly given already, and if # the feature is enabled result = self._find_signature() @@ -1219,6 +1004,7 @@ class DocstringStripSignatureMixin(DocstringSignatureMixin): feature of stripping any function signature from the docstring. """ def format_signature(self): + # type: () -> unicode if self.args is None and self.env.config.autodoc_docstring_signature: # only act if a signature is not explicitly given already, and if # the feature is enabled @@ -1240,6 +1026,7 @@ class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): @classmethod def can_document_member(cls, member, membername, isattr, parent): + # type: (Any, unicode, bool, Any) -> bool # It can be documented if it is a genuine function. # Often, a class instance has the same documentation as its class, # and then we typically want to document the class and not the instance. @@ -1247,7 +1034,7 @@ def can_document_member(cls, member, membername, isattr, parent): # whose doc string coincides with that of f and is thus different from # that of the class CachedFunction. In that situation, we want that f is documented. # This is part of SAGE TRAC 9976 - return (isinstance(member, (FunctionType, BuiltinFunctionType)) + return (inspect.isfunction(member) or inspect.isbuiltin(member) or (isclassinstance(member) and sage_getdoc_original(member) != sage_getdoc_original(member.__class__))) @@ -1277,6 +1064,7 @@ def args_on_obj(self, obj): return argspec def format_args(self): + # type: () -> unicode argspec = self.args_on_obj(self.object) if argspec is None: return None @@ -1286,6 +1074,7 @@ def format_args(self): return args def document_members(self, all_members=False): + # type: (bool) -> None pass @@ -1305,9 +1094,11 @@ class ClassDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter): @classmethod def can_document_member(cls, member, membername, isattr, parent): + # type: (Any, unicode, bool, Any) -> bool return isinstance(member, class_types) def import_object(self): + # type: () -> Any ret = ModuleLevelDocumenter.import_object(self) # if the class is documented under another name, document it # as data/attribute @@ -1362,6 +1153,7 @@ def import_object(self): return ret def format_args(self): + # type: () -> unicode # for classes, the relevant signature is the __init__ method's initmeth = self.get_attr(self.object, '__init__', None) # classes without __init__ method, default __init__ or @@ -1372,21 +1164,23 @@ def format_args(self): return None try: argspec = sage_getargspec(initmeth) + if argspec[0] and argspec[0][0] in ('cls', 'self'): + del argspec[0][0] + return formatargspec(initmeth, *argspec) except TypeError: # still not possible: happens e.g. for old-style classes # with __init__ in C return None - if argspec[0] and argspec[0][0] in ('cls', 'self'): - del argspec[0][0] - return formatargspec(initmeth, *argspec) def format_signature(self): + # type: () -> unicode if self.doc_as_attr: return '' return DocstringSignatureMixin.format_signature(self) def add_directive_header(self, sig): + # type: (unicode) -> None if self.doc_as_attr: self.directivetype = 'attribute' Documenter.add_directive_header(self, sig) @@ -1404,6 +1198,7 @@ def add_directive_header(self, sig): sourcename) def get_doc(self, encoding=None, ignore=1): + # type: (unicode, int) -> List[List[unicode]] lines = getattr(self, '_new_docstrings', None) if lines is not None: return lines @@ -1449,9 +1244,19 @@ def get_doc(self, encoding=None, ignore=1): return doc def add_content(self, more_content, no_docstring=False): + # type: (Any, bool) -> None if self.doc_as_attr: - classname = safe_getattr(self.object, '__name__', None) + # We cannot rely on __qualname__ yet for Python 2, because of a + # Cython bug: https://github.com/cython/cython/issues/2772. See + # trac #27002. + classname = None if PY2 else safe_getattr(self.object, '__qualname__', None) + if not classname: + classname = safe_getattr(self.object, '__name__', None) if classname: + module = safe_getattr(self.object, '__module__', None) + parentmodule = safe_getattr(self.parent, '__module__', None) + if module and module != parentmodule: + classname = str(module) + u'.' + str(classname) content = ViewList( [_('alias of :class:`%s`') % classname], source='') ModuleLevelDocumenter.add_content(self, content, @@ -1460,10 +1265,21 @@ def add_content(self, more_content, no_docstring=False): ModuleLevelDocumenter.add_content(self, more_content) def document_members(self, all_members=False): + # type: (bool) -> None if self.doc_as_attr: return ModuleLevelDocumenter.document_members(self, all_members) + def generate(self, more_content=None, real_modname=None, + check_module=False, all_members=False): + # Do not pass real_modname and use the name from the __module__ + # attribute of the class. + # If a class gets imported into the module real_modname + # the analyzer won't find the source of the class, if + # it looks in real_modname. + return super(ClassDocumenter, self).generate(more_content=more_content, + check_module=check_module, + all_members=all_members) class ExceptionDocumenter(ClassDocumenter): """ @@ -1477,6 +1293,7 @@ class ExceptionDocumenter(ClassDocumenter): @classmethod def can_document_member(cls, member, membername, isattr, parent): + # type: (Any, unicode, bool, Any) -> bool return isinstance(member, class_types) and \ issubclass(member, BaseException) @@ -1493,9 +1310,11 @@ class DataDocumenter(ModuleLevelDocumenter): @classmethod def can_document_member(cls, member, membername, isattr, parent): + # type: (Any, unicode, bool, Any) -> bool return isinstance(parent, ModuleDocumenter) and isattr def add_directive_header(self, sig): + # type: (unicode) -> None ModuleLevelDocumenter.add_directive_header(self, sig) sourcename = self.get_sourcename() if not self.options.annotation: @@ -1512,6 +1331,7 @@ def add_directive_header(self, sig): sourcename) def document_members(self, all_members=False): + # type: (bool) -> None pass @@ -1525,22 +1345,26 @@ class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter): @classmethod def can_document_member(cls, member, membername, isattr, parent): - return inspect.isroutine(member) and \ - not isinstance(parent, ModuleDocumenter) + # type: (Any, unicode, bool, Any) -> bool + return inspect.isroutine(member) and not \ + isinstance(parent, ModuleDocumenter) def import_object(self): + # type: () -> Any ret = ClassLevelDocumenter.import_object(self) if not ret: return ret # to distinguish classmethod/staticmethod obj = self.parent.__dict__.get(self.object_name) + if obj is None: + obj = self.object - if isinstance(obj, classmethod): + if isclassmethod(obj): self.directivetype = 'classmethod' # document class and static members before ordinary ones self.member_order = self.member_order - 1 - elif isinstance(obj, staticmethod): + elif isstaticmethod(obj, cls=self.parent, name=self.object_name): self.directivetype = 'staticmethod' # document class and static members before ordinary ones self.member_order = self.member_order - 1 @@ -1548,7 +1372,6 @@ def import_object(self): self.directivetype = 'method' return ret - # Sage Trac #9976: This function has been rewritten to support the # _sage_argspec_ attribute which makes it possible to get argument # specification of decorated callables in documentation correct. @@ -1575,6 +1398,7 @@ def args_on_obj(self, obj): return argspec def format_args(self): + # type: () -> unicode argspec = self.args_on_obj(self.object) if argspec is None: return None @@ -1584,10 +1408,11 @@ def format_args(self): return args def document_members(self, all_members=False): + # type: (bool) -> None pass -class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): +class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): # type: ignore """ Specialized Documenter subclass for attributes. """ @@ -1596,27 +1421,51 @@ class AttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): option_spec = dict(ModuleLevelDocumenter.option_spec) option_spec["annotation"] = annotation_option - method_types = (FunctionType, BuiltinFunctionType, MethodType) + # must be higher than the MethodDocumenter, else it will recognize + # some non-data descriptors as methods + priority = 10 + + @staticmethod + def is_function_or_method(obj): + return inspect.isfunction(obj) or inspect.isbuiltin(obj) or inspect.ismethod(obj) @classmethod def can_document_member(cls, member, membername, isattr, parent): - # "isdescriptor(member) and not isinstance(member, (FunctionType, BuiltinFunctionType))" - # is true for public cython attributes of a class. But in this case, the doc string is None, - # and so we would not include it into the documentation. - return (isdescriptor(member) and not - isinstance(member, (FunctionType, BuiltinFunctionType)) - and (hasattr(member,'__doc__') and member.__doc__ is not None)) \ - or (not isinstance(parent, ModuleDocumenter) and isattr) + # type: (Any, unicode, bool, Any) -> bool + non_attr_types = (type, MethodDescriptorType) + isdatadesc = isdescriptor(member) and not \ + inspect.isroutine(member) and not \ + isinstance(member, non_attr_types) and not \ + type(member).__name__ == "instancemethod" + + isattribute = isdatadesc or (not isinstance(parent, ModuleDocumenter) and isattr) + + # Trac #26522: This condition is here just to pass objects of classes + # that inherit ClasscallMetaclass as attributes rather than method + # descriptors. + isattribute = isattribute or isinstance(type(member), ClasscallMetaclass) + + if PY2: + return isattribute + + # That last condition addresses an obscure case of C-defined + # methods using a deprecated type in Python 3, that is not otherwise + # exported anywhere by Python + return isattribute or (not isinstance(parent, ModuleDocumenter) and + not inspect.isroutine(member) and + not isinstance(member, type)) def document_members(self, all_members=False): + # type: (bool) -> None pass def import_object(self): + # type: () -> Any ret = ClassLevelDocumenter.import_object(self) if isenumattribute(self.object): self.object = self.object.value if isdescriptor(self.object) and \ - not isinstance(self.object, self.method_types): + not self.is_function_or_method(self.object): self._datadescriptor = True else: # if it's not a data descriptor @@ -1624,10 +1473,12 @@ def import_object(self): return ret def get_real_modname(self): + # type: () -> str return self.get_attr(self.parent or self.object, '__module__', None) \ or self.modname def add_directive_header(self, sig): + # type: (unicode) -> None ClassLevelDocumenter.add_directive_header(self, sig) sourcename = self.get_sourcename() if not self.options.annotation: @@ -1645,6 +1496,7 @@ def add_directive_header(self, sig): sourcename) def add_content(self, more_content, no_docstring=False): + # type: (Any, bool) -> None if not self._datadescriptor: # if it's not a data descriptor, its docstring is very probably the # wrong thing to display @@ -1666,10 +1518,12 @@ class InstanceAttributeDocumenter(AttributeDocumenter): @classmethod def can_document_member(cls, member, membername, isattr, parent): + # type: (Any, unicode, bool, Any) -> bool """This documents only INSTANCEATTR members.""" return isattr and (member is INSTANCEATTR) def import_object(self): + # type: () -> bool """Never import anything.""" # disguise as an attribute self.objtype = 'attribute' @@ -1677,141 +1531,29 @@ def import_object(self): return True def add_content(self, more_content, no_docstring=False): + # type: (Any, bool) -> None """Never try to get a docstring from the object.""" AttributeDocumenter.add_content(self, more_content, no_docstring=True) -class AutoDirective(Directive): - """ - The AutoDirective class is used for all autodoc directives. It dispatches - most of the work to one of the Documenters, which it selects through its - *_registry* dictionary. - - The *_special_attrgetters* attribute is used to customize ``getattr()`` - calls that the Documenters make; its entries are of the form ``type: - getattr_function``. - - Note: When importing an object, all items along the import chain are - accessed using the descendant's *_special_attrgetters*, thus this - dictionary should include all necessary functions for accessing - attributes of the parents. - """ - # a registry of objtype -> documenter class - _registry = {} - - # a registry of type -> getattr function - _special_attrgetters = {} - - # flags that can be given in autodoc_default_flags - _default_flags = set([ - 'members', 'undoc-members', 'inherited-members', 'show-inheritance', - 'private-members', 'special-members', - ]) - - # standard docutils directive settings - has_content = True - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = True - # allow any options to be passed; the options are parsed further - # by the selected Documenter - option_spec = DefDict(identity) - - def warn(self, msg): - self.warnings.append(self.reporter.warning(msg, line=self.lineno)) - - def run(self): - self.filename_set = set() # a set of dependent filenames - self.reporter = self.state.document.reporter - self.env = self.state.document.settings.env - self.warnings = [] - self.result = ViewList() +def get_documenters(app): + # type: (Sphinx) -> Dict[unicode, Type[Documenter]] + """Returns registered Documenter classes""" + return app.registry.documenters - try: - source, lineno = self.reporter.get_source_and_line(self.lineno) - except AttributeError: - source = lineno = None - self.env.app.debug('[autodoc] %s:%s: input:\n%s', - source, lineno, self.block_text) - - # find out what documenter to call - objtype = self.name[4:] - doc_class = self._registry[objtype] - # add default flags - for flag in self._default_flags: - if flag not in doc_class.option_spec: - continue - negated = self.options.pop('no-' + flag, 'not given') is None - if flag in self.env.config.autodoc_default_flags and \ - not negated: - self.options[flag] = None - # process the options with the selected documenter's option_spec - try: - self.genopt = Options(assemble_option_dict( - self.options.items(), doc_class.option_spec)) - except (KeyError, ValueError, TypeError) as err: - # an option is either unknown or has a wrong type - msg = self.reporter.error('An option to %s is either unknown or ' - 'has an invalid value: %s' % (self.name, err), - line=self.lineno) - return [msg] - # generate the output - documenter = doc_class(self, self.arguments[0]) - documenter.generate(more_content=self.content) - if not self.result: - return self.warnings - - self.env.app.debug2('[autodoc] output:\n%s', '\n'.join(self.result)) - - # record all filenames as dependencies -- this will at least - # partially make automatic invalidation possible - for fn in self.filename_set: - self.state.document.settings.record_dependencies.add(fn) - - # use a custom reporter that correctly assigns lines to source - # filename/description and lineno - old_reporter = self.state.memo.reporter - self.state.memo.reporter = AutodocReporter(self.result, - self.state.memo.reporter) - - if documenter.titles_allowed: - node = nodes.section() - # necessary so that the child nodes get the right source/line set - node.document = self.state.document - nested_parse_with_titles(self.state, self.result, node) - else: - node = nodes.paragraph() - node.document = self.state.document - self.state.nested_parse(self.result, 0, node) - self.state.memo.reporter = old_reporter - return self.warnings + node.children +def autodoc_attrgetter(app, obj, name, *defargs): + # type: (Sphinx, Any, unicode, Any) -> Any + """Alternative getattr() for types""" + for typ, func in app.registry.autodoc_attrgettrs.items(): + if isinstance(obj, typ): + return func(obj, name, *defargs) -def add_documenter(cls): - """Register a new Documenter.""" - if not issubclass(cls, Documenter): - raise ExtensionError('autodoc documenter %r must be a subclass ' - 'of Documenter' % cls) - # actually, it should be possible to override Documenters - # if cls.objtype in AutoDirective._registry: - # raise ExtensionError('autodoc documenter for %r is already ' - # 'registered' % cls.objtype) - AutoDirective._registry[cls.objtype] = cls + return safe_getattr(obj, name, *defargs) def setup(app): - # Override hard-coded 'from sphinx.ext import autodoc' in - # sphinx.application. - def add_autodocumenter(cls): - add_documenter(cls) - app.add_directive('auto' + cls.objtype, AutoDirective) - - def add_autodoc_attrgetter(type, getter): - AutoDirective._special_attrgetters[type] = getter - - app.add_autodocumenter = add_autodocumenter - app.add_autodoc_attrgetter = add_autodoc_attrgetter - + # type: (Sphinx) -> Dict[unicode, Any] app.add_autodocumenter(ModuleDocumenter) app.add_autodocumenter(ClassDocumenter) app.add_autodocumenter(ExceptionDocumenter) @@ -1823,10 +1565,14 @@ def add_autodoc_attrgetter(type, getter): app.add_config_value('autoclass_content', 'class', True) app.add_config_value('autodoc_member_order', 'alphabetic', True) - app.add_config_value('autodoc_builtin_argspec', None, True) - app.add_config_value('autodoc_default_flags', [], True) + app.add_config_value('autodoc_default_flags', [], True) # deprecated since Sphinx 1.8 + app.add_config_value('autodoc_default_options', {}, True) app.add_config_value('autodoc_docstring_signature', False, True) app.add_config_value('autodoc_mock_imports', [], True) + app.add_config_value('autodoc_warningiserror', True, True) + app.add_config_value('autodoc_inherit_docstrings', True, True) + app.add_config_value('autodoc_builtin_argspec', None, True) + app.add_event('autodoc-process-docstring') app.add_event('autodoc-process-signature') app.add_event('autodoc-skip-member') @@ -1838,7 +1584,9 @@ class testcls: """test doc string""" def __getattr__(self, x): + # type: (Any) -> Any return x def __setattr__(self, x, y): + # type: (Any, Any) -> None """Attr setter.""" diff --git a/src/sage_setup/docbuild/sphinxbuild.py b/src/sage_setup/docbuild/sphinxbuild.py index 8f7034fcb84..8c7efbe6c86 100644 --- a/src/sage_setup/docbuild/sphinxbuild.py +++ b/src/sage_setup/docbuild/sphinxbuild.py @@ -204,22 +204,16 @@ def _log_line(self, line): Verify that :trac:`25160` has been resolved:: sage: logger = SageSphinxLogger(stdout, "#25160") - sage: raise Exception("artificial exception") - Traceback (most recent call last): - ... - Exception: artificial exception sage: import traceback - sage: for line in traceback.format_exc().split('\n'): - ....: logger._log_line(line) + sage: try: + ....: raise Exception("artificial exception") + ....: except Exception: + ....: for line in traceback.format_exc().split('\n'): + ....: logger._log_line(line) [#25160 ] Traceback (most recent call last): [#25160 ] File ... - [#25160 ] self.compile_and_execute(example, compiler, test.globs) - [#25160 ] File ... - [#25160 ] exec(compiled, globs) - [#25160 ] File ... [#25160 ] raise Exception("artificial exception") [#25160 ] Exception: artificial exception - """ skip_this_line = self._filter_out(line) self._check_errors(line) diff --git a/src/sage_setup/docbuild/utils.py b/src/sage_setup/docbuild/utils.py new file mode 100644 index 00000000000..3f7142dc3db --- /dev/null +++ b/src/sage_setup/docbuild/utils.py @@ -0,0 +1,214 @@ +"""Miscellaneous utilities for running the docbuilder.""" + +import errno +import os + + +class WorkerDiedException(RuntimeError): + """Raised if a worker process dies unexpected.""" + + +def _build_many(target, args, processes=None): + """ + Map a list of arguments in ``args`` to a single-argument target function + ``target`` in parallel using ``NUM_THREADS`` (or ``processes`` if given) + simultaneous processes. + + This is a simplified version of ``multiprocessing.Pool.map`` from the + Python standard library which avoids a couple of its pitfalls. In + particular, it can abort (with a `RuntimeError`) without hanging if one of + the worker processes unexpectedly dies. It also avoids starting new + processes from a pthread, which is known to result in bugs on versions of + Cygwin prior to 3.0.0 (see + https://trac.sagemath.org/ticket/27214#comment:25). + + On the other hand, unlike ``multiprocessing.Pool.map`` it does not return + a result. This is fine for the purpose of building multiple Sphinx + documents in parallel. + + In the future this may be replaced by a generalized version of the more + robust parallel processing implementation from ``sage.doctest.forker``. + + EXAMPLES:: + + sage: from sage_setup.docbuild.utils import _build_many + sage: def target(N): + ....: import time + ....: time.sleep(float(0.1)) + ....: print('Processed task %s' % N) + ....: + sage: _build_many(target, range(8), processes=8) + Processed task ... + Processed task ... + Processed task ... + Processed task ... + Processed task ... + Processed task ... + Processed task ... + Processed task ... + + If one of the worker processes errors out from an unhandled exception, or + otherwise exits non-zero (e.g. killed by a signal) any in-progress tasks + will be completed gracefully, but then a `RuntimeError` is raised and + pending tasks are not started:: + + sage: def target(N): + ....: import time + ....: if N == 4: + ....: # Task 4 is a poison pill + ....: 1 / 0 + ....: else: + ....: time.sleep(0.5) + ....: print('Processed task %s' % N) + ....: + + Note: In practice this test might still show output from the other worker + processes before the poison-pill is executed. It may also display the + traceback from the failing process on stderr. However, due to how the + doctest runner works, the doctest will only expect the final exception:: + + sage: _build_many(target, range(8), processes=8) + Traceback (most recent call last): + ... + WorkerDiedException: worker for 4 died with non-zero exit code 1 + """ + from multiprocessing import Process + from .build_options import NUM_THREADS, ABORT_ON_ERROR + + if processes is None: + processes = NUM_THREADS + + workers = [None] * processes + queue = list(args) + + # Maps worker process PIDs to the name of the document it's working + # on (the argument it was passed). This is primarily used just for + # debugging/information purposes. + jobs = {} + + ### Utility functions ### + + def bring_out_yer_dead(w, exitcode): + """ + Handle a dead / completed worker. Raises WorkerDiedError if it + returned with a non-zero exit code. + """ + + if w is None or exitcode is None: + # I'm not dead yet! (or I haven't even been born yet) + return w + + # Hack: If we wait()ed on this worker manually we have to tell it + # it's dead: + if w._popen.returncode is None: + w._popen.returncode = exitcode + + if exitcode != 0 and ABORT_ON_ERROR: + raise WorkerDiedException( + "worker for {} died with non-zero exit code " + "{}".format(jobs[w.pid], w.exitcode)) + + jobs.pop(w.pid) + # Helps multiprocessing with some internal bookkeeping + w.join() + + return None + + def wait_for_one(): + """Wait for a single process and return its pid and exit code.""" + try: + pid, sts = os.wait() + except OSError as exc: + # No more processes to wait on if ECHILD + if exc.errno != errno.ECHILD: + raise + else: + return None, None + + if os.WIFSIGNALED(sts): + exitcode = -os.WTERMSIG(sts) + else: + exitcode = os.WEXITSTATUS(sts) + + return pid, exitcode + + def reap_workers(waited_pid=None, waited_exitcode=None): + """ + This is the main worker handling loop. + + Checks if workers have completed their tasks and spawns new workers if + there are more tasks on the queue. Returns `False` if there is more + work to be done or `True` if the work is complete. + + Raises a ``WorkerDiedException`` if a worker exits unexpectedly. + """ + + all_done = True + + for idx, w in enumerate(workers): + if w is not None: + if w.pid == waited_pid: + exitcode = waited_exitcode + else: + exitcode = w.exitcode + + w = bring_out_yer_dead(w, exitcode) + + # Worker w is dead/not started, so start a new worker + # in its place with the next document from the queue + if w is None and queue: + job = queue.pop(0) + w = Process(target=target, args=(job,)) + w.start() + jobs[w.pid] = job + + workers[idx] = w + + if w is not None: + all_done = False + + # If all workers are dead and there are no more items to + # process in the queue then we are done + return all_done + + ### Main loop ### + + waited_pid = None # Set along with waited_exitcode by calls to + # wait_for_one() + waited_exitcode = None + worker_exc = None # Set to a WorkerDiedException if one occurs + + try: + while True: + # Check the status of each worker and break out of the loop if + # all work is done. + # We'll check each worker process against the returned + # pid back at the top of the `while True` loop. We also + # check any other processes that may have exited in the + # meantime + try: + if reap_workers(waited_pid, waited_exitcode): + break + except WorkerDiedException as exc: + worker_exc = exc + break + + waited_pid, waited_exitcode = wait_for_one() + finally: + try: + remaining_workers = [w for w in workers if w is not None] + for w in remaining_workers: + # Give any remaining workers a chance to shut down gracefully + try: + w.terminate() + except OSError as exc: + if exc.errno != errno.ESRCH: + # Otherwise it was already dead so this was expected + raise + for w in remaining_workers: + w.join() + finally: + if worker_exc is not None: + # Re-raise the RuntimeError from bring_out_yer_dead set if a + # worker died unexpectedly + raise worker_exc diff --git a/src/sage_setup/find.py b/src/sage_setup/find.py index bf166b9ef5f..83d1803f957 100644 --- a/src/sage_setup/find.py +++ b/src/sage_setup/find.py @@ -184,11 +184,13 @@ def installed_files_by_module(site_packages, modules=('sage',)): sage: from sage_setup.find import installed_files_by_module sage: files_by_module = installed_files_by_module(site_packages) sage: from sage.misc.sageinspect import loadable_module_extension - sage: 'sage/structure/sage_object' + loadable_module_extension() in \ - ....: files_by_module['sage.structure.sage_object'] - True - sage: sorted(files_by_module['sage.structure']) - ['sage/structure/__init__.py', 'sage/structure/__init__.pyc'] + sage: (f,) = files_by_module['sage.structure.sage_object']; f + 'sage/structure/sage_object...' + sage: (f1, f2) = sorted(files_by_module['sage.structure']) + sage: f1 + 'sage/structure/__init__.py' + sage: f2 + 'sage/structure/....pyc' This takes about 30ms with warm cache: diff --git a/src/sage_setup/optional_extension.py b/src/sage_setup/optional_extension.py index ad9e10c215e..ae75e55e822 100644 --- a/src/sage_setup/optional_extension.py +++ b/src/sage_setup/optional_extension.py @@ -60,17 +60,17 @@ def OptionalExtension(*args, **kwds): sage: from sage_setup.optional_extension import OptionalExtension sage: ext = OptionalExtension("foo", ["foo.c"], condition=False) - sage: print(ext.__class__) - sage_setup.optional_extension.CythonizeExtension + sage: print(ext.__class__.__name__) + CythonizeExtension sage: ext = OptionalExtension("foo", ["foo.c"], condition=True) - sage: print(ext.__class__) - distutils.extension.Extension + sage: print(ext.__class__.__name__) + Extension sage: ext = OptionalExtension("foo", ["foo.c"], package="no_such_package") - sage: print(ext.__class__) - sage_setup.optional_extension.CythonizeExtension + sage: print(ext.__class__.__name__) + CythonizeExtension sage: ext = OptionalExtension("foo", ["foo.c"], package="pari") - sage: print(ext.__class__) - distutils.extension.Extension + sage: print(ext.__class__.__name__) + Extension """ try: condition = kwds.pop("condition") diff --git a/src/setup.py b/src/setup.py index 9d31c9d186d..28ba0bea822 100755 --- a/src/setup.py +++ b/src/setup.py @@ -1,7 +1,12 @@ #!/usr/bin/env python + from __future__ import print_function -import os, sys, time, errno, platform, subprocess +import os +import sys +import time +import errno +import subprocess import json from distutils import log from distutils.core import setup @@ -76,12 +81,7 @@ def excepthook(*exc): else: sdist = False -try: - compile_result_dir = os.environ['XML_RESULTS'] - keep_going = True -except KeyError: - compile_result_dir = None - keep_going = False +keep_going = False # search for dependencies and add to gcc -I include_dirs = sage_include_directories(use_sources=True) @@ -115,58 +115,6 @@ def excepthook(*exc): ### Testing related stuff ######################################################### -class CompileRecorder(object): - - def __init__(self, f): - self._f = f - self._obj = None - - def __get__(self, obj, type=None): - # Act like a method... - self._obj = obj - return self - - def __call__(self, *args): - t = time.time() - try: - if self._obj: - res = self._f(self._obj, *args) - else: - res = self._f(*args) - except Exception as ex: - print(ex) - res = ex - t = time.time() - t - - errors = failures = 0 - if self._f is compile_command0: - name = "cythonize." + args[0][1].name - failures = int(bool(res)) - else: - name = "gcc." + args[0][1].name - errors = int(bool(res)) - if errors or failures: - type = "failure" if failures else "error" - failure_item = """<%(type)s/>""" % locals() - else: - failure_item = "" - output = open("%s/%s.xml" % (compile_result_dir, name), "w") - output.write(""" - - - - %(failure_item)s - - - """.strip() % locals()) - output.close() - return res - -if compile_result_dir: - record_compile = CompileRecorder -else: - record_compile = lambda x: x - # Remove (potentially invalid) star import caches import sage.misc.lazy_import_cache if os.path.exists(sage.misc.lazy_import_cache.get_cache_file()): @@ -291,7 +239,6 @@ def finalize_options(self): self.compile_time_env = dict( PY_VERSION_HEX=sys.hexversion, PY_MAJOR_VERSION=sys.version_info[0], - HAVE_GMPY2=have_module("gmpy2"), ) # We check the Cython version and some relevant configuration @@ -707,7 +654,7 @@ def build_extensions(self): for ext in self.extensions: need_to_compile, p = self.prepare_extension(ext) if need_to_compile: - compile_commands.append((record_compile(self.build_extension), p)) + compile_commands.append((self.build_extension, p)) execute_list_of_commands(compile_commands)