"""
- 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.
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 =