From b10efb9c13a7ef5313ca4598d1814a4a84420833 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Wed, 20 May 2020 16:19:43 +0200 Subject: [PATCH 001/591] 29717: initial version --- build/pkgs/cubic_hecke_marin/SPKG.txt | 17 + build/pkgs/cubic_hecke_marin/checksums.ini | 5 + build/pkgs/cubic_hecke_marin/dependencies | 5 + .../cubic_hecke_marin/package-version.txt | 1 + build/pkgs/cubic_hecke_marin/spkg-install.in | 21 + build/pkgs/cubic_hecke_marin/spkg-install.py | 17 + build/pkgs/cubic_hecke_marin/type | 1 + .../algebras/cubic_hecke_algebra.rst | 10 + src/doc/en/reference/algebras/index.rst | 1 + src/doc/en/reference/references/index.rst | 15 + src/sage/algebras/catalog.py | 3 + .../base_rings_of_definition/__init__.py | 0 .../cubic_hecke_base_ring.py | 1231 +++++++ .../hecke_algebras/cubic_hecke_algebra.py | 3273 +++++++++++++++++ .../matrix_representations/__init__.py | 0 .../cubic_hecke_matrix_rep.py | 994 +++++ src/sage/databases/cubic_hecke_db.py | 1167 ++++++ 17 files changed, 6761 insertions(+) create mode 100644 build/pkgs/cubic_hecke_marin/SPKG.txt create mode 100644 build/pkgs/cubic_hecke_marin/checksums.ini create mode 100644 build/pkgs/cubic_hecke_marin/dependencies create mode 100644 build/pkgs/cubic_hecke_marin/package-version.txt create mode 100644 build/pkgs/cubic_hecke_marin/spkg-install.in create mode 100644 build/pkgs/cubic_hecke_marin/spkg-install.py create mode 100644 build/pkgs/cubic_hecke_marin/type create mode 100644 src/doc/en/reference/algebras/cubic_hecke_algebra.rst create mode 100644 src/sage/algebras/hecke_algebras/base_rings_of_definition/__init__.py create mode 100644 src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py create mode 100644 src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py create mode 100644 src/sage/algebras/hecke_algebras/matrix_representations/__init__.py create mode 100644 src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py create mode 100644 src/sage/databases/cubic_hecke_db.py diff --git a/build/pkgs/cubic_hecke_marin/SPKG.txt b/build/pkgs/cubic_hecke_marin/SPKG.txt new file mode 100644 index 00000000000..bbfeae7f9d7 --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/SPKG.txt @@ -0,0 +1,17 @@ += Cubic Hecke Algebra Database = + +== Description == + +Iwan Marin's basis and matrix representations for the cubic Hecke algebra on 4 strands +as given on 'http://www.lamfa.u-picardie.fr/marin/softs/H4 + +== Dependencies == + + * Sage library + +== Changelog == + +=== cubic_hecke_marin-20200513.tar.bz2 (Sebastian Oehms, 13 May 2020) === + + * #?????: Initial version + diff --git a/build/pkgs/cubic_hecke_marin/checksums.ini b/build/pkgs/cubic_hecke_marin/checksums.ini new file mode 100644 index 00000000000..299e4ddd97a --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/checksums.ini @@ -0,0 +1,5 @@ +tarball=cubic_hecke_marin-20200513.tar.bz2 +sha1=0afb0716b224b66fdd67b9b6e75b911030d15e1c +md5=3ee0a0a4fc5a7739ad9932391d2d10b5 +cksum=398008749 +upstream_url=https://trac.sagemath.org/attachment/ticket/29717/cubic_hecke_marin-20200513.tar.bz2 diff --git a/build/pkgs/cubic_hecke_marin/dependencies b/build/pkgs/cubic_hecke_marin/dependencies new file mode 100644 index 00000000000..c1b713883fe --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/dependencies @@ -0,0 +1,5 @@ +| $(SAGERUNTIME) + +---------- +All lines of this file are ignored except the first. +It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/cubic_hecke_marin/package-version.txt b/build/pkgs/cubic_hecke_marin/package-version.txt new file mode 100644 index 00000000000..aa5d21b148b --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/package-version.txt @@ -0,0 +1 @@ +20200513 diff --git a/build/pkgs/cubic_hecke_marin/spkg-install.in b/build/pkgs/cubic_hecke_marin/spkg-install.in new file mode 100644 index 00000000000..0d3fba4325b --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/spkg-install.in @@ -0,0 +1,21 @@ +INSTALL="yes" +TARGET="${SAGE_SHARE}/cubic_hecke_marin" +VERSION=`cat package-version.txt` +if [ -d $TARGET ] +then + diff package-version.txt $TARGET > /dev/null 2>&1 + if [ $? -eq 0 ] + then + INSTALL="no" + echo "Version $VERSION of cubic_hecke_marin already installed" + else + OLD_VERSION=`cat $TARGET/package-version.txt` + echo "Removing former version $OLD_VERSION of cubic_hecke_marin" + rm -rf $TARGET + fi +fi + +if [ "$INSTALL" = "yes" ] +then + exec sage-python23 spkg-install.py +fi diff --git a/build/pkgs/cubic_hecke_marin/spkg-install.py b/build/pkgs/cubic_hecke_marin/spkg-install.py new file mode 100644 index 00000000000..2109e57fb9b --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/spkg-install.py @@ -0,0 +1,17 @@ +import os +from sage.all import save +from sage.env import SAGE_SHARE +from sage.misc.misc import sage_makedirs +from sage.databases.cubic_hecke_db import CubicHeckeDataBase + +install_root = os.path.join(SAGE_SHARE, 'cubic_hecke_marin') + +if __name__ == '__main__': + sage_makedirs(install_root) + print("Creating Iwan Marin's Cubic Hecke database.") + cha_db = CubicHeckeDataBase() + cha_db.create_static_db_marin_basis() + cha_db.create_static_db_marin_regular() + cha_db.create_static_db_marin_regular(right=True) + cha_db.create_static_db_marin_split() + os.system('cp package-version.txt %s' %install_root) diff --git a/build/pkgs/cubic_hecke_marin/type b/build/pkgs/cubic_hecke_marin/type new file mode 100644 index 00000000000..a6a7b9cd726 --- /dev/null +++ b/build/pkgs/cubic_hecke_marin/type @@ -0,0 +1 @@ +standard diff --git a/src/doc/en/reference/algebras/cubic_hecke_algebra.rst b/src/doc/en/reference/algebras/cubic_hecke_algebra.rst new file mode 100644 index 00000000000..c0dccab3dd1 --- /dev/null +++ b/src/doc/en/reference/algebras/cubic_hecke_algebra.rst @@ -0,0 +1,10 @@ +Cubic Hecke Algebras +==================== + +.. toctree:: + :maxdepth: 2 + + sage/algebras/hecke_algebras/cubic_hecke_algebra + sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring + sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep + diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 2a7c43950da..5168de1f119 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -77,6 +77,7 @@ Hecke algebras sage/algebras/iwahori_hecke_algebra sage/algebras/nil_coxeter_algebra sage/algebras/yokonuma_hecke_algebra + cubic_hecke_algebra Various associative algebras ---------------------------- diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 8c5c36ff174..dd5b2a9af5d 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1418,6 +1418,10 @@ REFERENCES: \J. Algebr. Comb. **39** (2014) pp. 17-51. :doi:`10.1007/s10801-013-0437-x`, :arxiv:`1108.1776`. +.. [CM2012] \M. Cabanes, I. Marin, *On ternary quotients of cubic Hecke + algebras*, Comm. Math. Phys. (2012), Volume 314, Issue 1, + pp 57-92. :doi:`10.1007/s00220-012-1519-7`, :arxiv:`1010.1465`. + .. [CMN2014] David Coudert, Dorian Mazauric, and Nicolas Nisse, *Experimental Evaluation of a Branch and Bound Algorithm for computing Pathwidth*. In Symposium on Experimental Algorithms (SEA), volume @@ -3742,6 +3746,14 @@ REFERENCES: .. [Mar2004] \S. Marcus, Quasiperiodic infinite words, Bull. Eur. Assoc. Theor. Comput. Sci. 82 (2004) 170-174. +.. [Mar2012] \I. Marin, *The cubic Hecke algebra on at most 5 strands*, + Journal of Pure and Applied Algebra 216 (2012) 2754-2782. + :doi:`10.1016/j.jpaa.2012.04.013`, :arxiv:`1110.6621`. + +.. [Mar2018] \I. Marin, *Maximal cubic quotient of the braid algebra*, + preprint, 2018. available at + http://www.lamfa.u-picardie.fr/marin/arts/GQ.pdf + .. [Mas1994] James L. Massey, *SAFER K-64: A byte-oriented block-ciphering algorithm*; in FSE’93, Volume 809 of LNCS, pages 1-17. @@ -4052,6 +4064,9 @@ REFERENCES: .. [MW2009] Meshulam and Wallach, "Homological connectivity of random `k`-dimensional complexes", preprint, math.CO/0609773. +.. [MW2012] Ivan Marin and Emmanuel Wagner, *A CUBIC DEFINING ALGEBRA FOR THE + LINKS-GOULD POLYNOMIAL* (:arxiv:`1203.5981v1` [mathGT] 27. Mar 2012) + .. _ref-N: **N** diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index e3824417e89..78ee670fa74 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -9,6 +9,8 @@ Let ```` indicate pressing the tab key. So begin by typing ``algebras.`` to the see the currently implemented named algebras. +- :class:`algebras.CubicHecke + ` - :class:`algebras.ArikiKoike ` - :class:`algebras.AskeyWilson ` @@ -94,6 +96,7 @@ lazy_import('sage.algebras.schur_algebra', 'SchurAlgebra', 'Schur') lazy_import('sage.algebras.commutative_dga', 'GradedCommutativeAlgebra', 'GradedCommutative') lazy_import('sage.algebras.hecke_algebras.ariki_koike_algebra', 'ArikiKoikeAlgebra', 'ArikiKoike') +lazy_import('sage.algebras.hecke_algebras.cubic_hecke_algebra', 'CubicHeckeAlgebra', 'CubicHecke') lazy_import('sage.algebras.rational_cherednik_algebra', 'RationalCherednikAlgebra', 'RationalCherednik') lazy_import('sage.algebras.yokonuma_hecke_algebra', 'YokonumaHeckeAlgebra', 'YokonumaHecke') lazy_import('sage.combinat.posets.incidence_algebras', 'IncidenceAlgebra', 'Incidence') diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/__init__.py b/src/sage/algebras/hecke_algebras/base_rings_of_definition/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py new file mode 100644 index 00000000000..a89f3f51b5b --- /dev/null +++ b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py @@ -0,0 +1,1231 @@ +# -*- coding: utf-8 -*- +r""" +Cubic Hecke Base Rings + +This module contains special classes of polynomial rings (:class:`CubicHeckeRingOfDefinition` and :class:`CubicHeckeExtensionRing`) +used in the context of cubic Hecke algebras (:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra`). + +AUTHORS: + +- Sebastian Oehms May 2020: initial version +""" + + + +############################################################################## +# Copyright (C) 2020 Sebastian Oehms +# +# 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 sage.structure.category_object import normalize_names +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element import get_coercion_model +from sage.categories.action import Action +from sage.misc.misc import verbose +from sage.misc.functional import cyclotomic_polynomial +from sage.misc.cachefunc import cached_method +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict +from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, LaurentPolynomialRing_mpair +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.algebras.splitting_algebra import solve_with_extension, SplittingAlgebra + + + + +# --------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------- +# helper functions and classes +# --------------------------------------------------------------------------------- +# --------------------------------------------------------------------------------- + +# --------------------------------------------------------------------------------- +# local helper functions +# --------------------------------------------------------------------------------- +def register_ring_hom(ring_hom): + r""" + This function tries to register the given ring homomorphism as conversion map + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.create_specialization([E(5), E(7), E(3)]) # indirect doctest + Universal Cyclotomic Field + sage: _.convert_map_from(BR) + Ring morphism: + From: Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w + over Integer Ring + To: Universal Cyclotomic Field + Defn: u |--> E(5) + v |--> E(7) + with map of base ring + """ + domain = ring_hom.domain() + codomain = ring_hom.codomain() + conversion_cached = codomain._is_conversion_cached(domain) + + if conversion_cached: + test_map = codomain.convert_map_from(domain) + try: + if test_map != ring_hom: + verbose('\nConversion:\n%s\n already exists and is different from:\n%s\n' %(test_map,ring_hom)) + except TypeError: + verbose('\n Conversion:\n%s\n already exists and is not comparable to:\n%s\n' %(test_map,ring_hom)) + else: + try: + codomain.register_conversion(ring_hom) + except ValueError: + verbose('\nthe map:\n%s\ncannot be registerd as conversion\n' %(ring_hom)) + + return + + +def preparse_mvp(string, mvp_indet): + r""" + Preparse a string produced via GAP3 interface and containing Jean Michel's ``MVP`` (multivariate polynomials) + such that it can be evaluated by ``sage_eval``. In particular missing multiplication signs are inserted. + Furthermore, exponentiation is replaced by a special function ``xpow`` which must be defined before the + function's result can be evaluated. + + INPUT: + + - ``string`` -- string produced via ``GAP3`` interface and containing Jean Michel's ``MVP`` (multivariate polynomials) + - ``mvp_indet`` -- list of strings containing the names of the ``MVP``-variables. + + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: chbr.preparse_mvp('2+a^-2bc+a^-1b^-1c^2', ['a', 'b', 'c']) + '2+xpow(a,1)^-2*xpow(b,1)*xpow(c,1)+xpow(a,1)^-1*xpow(b,1)^-1*xpow(c,1)^2' + """ + + def erase_useless_whitespace(strg): + res = strg.strip() + if res.find(' ') < 0: + return res + pos = int(len(res)/2) # len(res) must be > 1 since it is stripped and contains whitespaces + + if res[pos] != ' ': + # find a pos near to that on a whitespace + left = res[:pos] + right = res[pos+1:] + pos = right.find(' ') + if pos >= 0: + # first whitespace position in the right part + pos += len(left) + 1 + else: + # last whitespace position in the left part + left_rev = list(left) + left_rev.reverse() + pos = len(left) - left_rev.index(' ') - 1 + + end_left = res[pos-1] + start_right = res[pos+1] + left = res[:pos] + right = res[pos+1:] + if end_left.isdigit() and start_right.isdigit(): + return erase_useless_whitespace(left) + ' ' + erase_useless_whitespace(right) + return erase_useless_whitespace(left) + erase_useless_whitespace(right) + + # ------------------------------------------------------------------------ + # first erase carriage returns and useless whitespaces + # ------------------------------------------------------------------------ + new_string = string.replace('\n', ' ') + new_string = erase_useless_whitespace(new_string) + + # ------------------------------------------------------------------------------ + # Because of exponentiation with fractions we need to obtain the indeterminates + # as functions having the exponent as argument + # ------------------------------------------------------------------------------ + for indet in mvp_indet: # first the critical cases (protecting them by upper for following change) + new_string = new_string.replace('%s^(' %(indet), 'xpow(%s,' %(indet.upper())) + + for indet in mvp_indet: # than remaining trivial cases + new_string = new_string.replace('%s' %(indet), 'xpow(%s,1)' %(indet)) + + for indet in mvp_indet: # rename protected items of the first change + new_string = new_string.replace(indet.upper(), indet) + + # ------------------------------------------------------------------------------ + # Now start to insert missing '*' signs taking a pseudonym '?' for it, first + # ------------------------------------------------------------------------------ + # Insert '*' left of 'xpow' + # ------------------------------------------------------------------------------ + new_string = new_string.replace('xpow', '?xpow' ) + + # ------------------------------------------------------------------------------ + # Insert '*' right of ')' + # ------------------------------------------------------------------------------ + new_string = new_string.replace(')', ')?' ) + + # ------------------------------------------------------------------------------ + # Insert '*' left of 'E' (starting a roots of unity or a functions ('ER') of + # roots of integers) + # ------------------------------------------------------------------------------ + new_string = new_string.replace('E', '?E' ) + + # ------------------------------------------------------------------------------ + # Insert '*' left and right of 'I' (root of -1) + # ------------------------------------------------------------------------------ + new_string = new_string.replace('I', '?I?' ) + + # ------------------------------------------------------------------------------ + # remove multiples + # ------------------------------------------------------------------------------ + while '??' in new_string: + new_string = new_string.replace('??', '?') + + # ------------------------------------------------------------------------------ + # remove impossible neighbouring + # ------------------------------------------------------------------------------ + new_string = new_string.replace('^?', '^') + new_string = new_string.replace('?^', '^') + new_string = new_string.replace('+?', '+') + new_string = new_string.replace('?+', '+') + new_string = new_string.replace('-?', '-') + new_string = new_string.replace('?-', '-') + new_string = new_string.replace('/?', '/') + new_string = new_string.replace('?/', '/') + new_string = new_string.replace('[?', '[') + new_string = new_string.replace('?]', ']') + new_string = new_string.replace('(?', '(') + new_string = new_string.replace('?)', ')') + new_string = new_string.replace('?,', ',') + new_string = new_string.replace(',?', ',') + if new_string.startswith('?'): + new_string = new_string[1:] + if new_string.endswith('?'): + new_string = new_string[:len(new_string)-1] + + # ------------------------------------------------------------------------------ + # replace pseudonym + # ------------------------------------------------------------------------------ + new_string = new_string.replace('?', '*') + return new_string + + + + + +# --------------------------------------------------------------------------------- +# class for the Galois Group action on the generic extension ring corresponding +# to the cubic equation +# --------------------------------------------------------------------------------- +class GaloisGroupAction(Action): + r""" + Action on a multivariate polynomial ring by permuting the generators. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from operator import mul + sage: R. = ZZ[] + sage: G = SymmetricGroup(3) + sage: p = 5*x*y + 3*z**2 + sage: R._unset_coercions_used() + sage: R.register_action(chbr.GaloisGroupAction(G, R, op=mul)) + sage: s = G([2,3,1]) + sage: s*p + 3*x^2 + 5*y*z + """ + def _act_(self, perm, pol): + r""" + Application of the action + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from operator import mul + sage: R. = QQ[] + sage: G = SymmetricGroup(2) + sage: A = chbr.GaloisGroupAction(G, R, op=mul) + sage: p = ~5*x*y**2 + 3*x**2 + sage: s = G([2,1]) + sage: A._act_(s, p) + 1/5*x^2*y + 3*y^2 + """ + if not self.is_left(): + perm, pol = pol, perm + pol_dict = {} + for key, value in pol.dict().items(): + newkey = [0]*len(key) + for pos in range(len(key)): + newkey[perm(pos+1)-1] = key[pos] + pol_dict[tuple(newkey)] = value + return self.domain()(pol_dict) + + + + + + + + + + + +####################################################################################################################### +# EXTENSION RING +####################################################################################################################### + +# ------------------------------------------------------------------------------------------------------------------ +# Definition of the generic extension ring for the cubic Hecke algebra as Laurent polynomial ring in 3 indeterminates +# over the cyclotomic field of a third root of unity +# This is the most general ring over which the cubic Hecke algebra is semi-simple +# In opposite to the generic base ring class, this class does not inherits from UniqueRepresentation +# since _test_pickling fails +# -------------------------------------------------------------------------------------------------------- +class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): + r""" + This class implements the generic splitting algebra for the irreducible representations of the cubic Hecke algebra. + + This ring must contain three invertible indeterminats (representing the roots of the cubic equation) + together with a third root of unity (needed for the 18-dimensional irreducibles of the cubic Hecke algebra + on 4 strands). + + Therefore this ring is constructed as a multivariate Laurent polynomial ring in three indeterminates over a + polynomial quotient ring over the integers with respect to the minimal polynomial of a third root of unity. + + The polynomial quotient ring is constructed as instance of :class:`SplittingAlgebra`. The name of the third + root of unity is fixed to be ``e3``. + + INPUT: + + - ``names`` -- string containing the names of the indeterminates separated by ',' or a triple of strings each of + which is the name of one of the three indeterminates + - ``order`` -- string (optional, default='degrevlex') transferred to the corresponding input of + LaurentPolynomialRing_mpair + - ``ring_of_definition`` -- instance of CubicHeckeRingOfDefinition (optional, default=None) to specify the generic + cubic Hecke base ring over which self may be realized as splitting ring via the as_splitting_algebra method + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: chbr.CubicHeckeExtensionRing('a, b, c') + Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] + over Integer Ring + sage: _.an_element() + b^2*c^-1 + e3*a + """ + + + def __init__(self, names, order='degrevlex', ring_of_definition=None, third_unity_root_name='e3'): + r""" + Python constructor. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: TestSuite(ER).run() + """ + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # Setting connection with generic base ring (if given) + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._ring_of_definition = None + self._splitting_algebra = None + + if ring_of_definition != None: + if not isinstance(ring_of_definition, CubicHeckeRingOfDefinition): + raise TypeError( "generic base ring must be an instance of CubicHeckeRingOfDefinition") + self._ring_of_definition = ring_of_definition + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining the base ring + # note that we can't use ZZ.extension since it isn't possible to define + # homomorphisms from orders in number fields, yet + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + base_ring = SplittingAlgebra(cyclotomic_polynomial(3), [third_unity_root_name]) + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining the ring itself + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._names = normalize_names(3, names) + self._order = order + + pol_ring = PolynomialRing(base_ring, names=self._names, order=self._order, implementation=None) + LaurentPolynomialRing_mpair.__init__(self, pol_ring) + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # setting Galois group action + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + from sage.groups.perm_gps.permgroup_named import SymmetricGroup + from operator import mul + self._galois_group = SymmetricGroup(3) + galois_group_action = GaloisGroupAction(self._galois_group, self, op=mul) + self._unset_coercions_used() + self.register_action(galois_group_action) + + # --------------------------------------------------------------------------------- + # Init of data used on demand + # --------------------------------------------------------------------------------- + self._mirror = None + + return + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # overloaded inherited methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + def __reduce__(self): + r""" + Used in pickling. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: loads(dumps(ER)) == ER + True + """ + return CubicHeckeExtensionRing, (self._names, self._order, self._ring_of_definition) + + def _element_constructor_(self, x, mon=None): + r""" + Inherited element constructor overloaded to allow construction from + GAP3 Mvp exressions. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: GER = CHA3.extension_ring(generic=True) # optional gap3 + sage: sch7 = CHA3.chevie().SchurElements()[7] # optional gap3 + sage: GER(sch7) # optional gap3 + a*b*c^-2 + a^2*b^-1*c^-1 + a^-1*b^2*c^-1 + 2 + a*b^-2*c + a^-2*b*c + a^-1*b^-1*c^2 + sage: rep4_gap3 = CHA3.chevie().Representations(4) # optional gap3 + sage: matrix(GER, rep4_gap3[1]) # optional gap3 + [ b 0] + [-b c] + """ + from sage.interfaces.gap3 import GAP3Element + if isinstance(x, GAP3Element): + return self._convert_from_gap3_mvp(x) + return super(CubicHeckeExtensionRing, self)._element_constructor_(x, mon=mon) + + + def hom(self, im_gens, codomain=None, check=True, base_map=None): + r""" + Custom version overloading the corresponding method of class :class:`~sage.structure.parent_gens.ParentWithGens` + because of special effort with respect to the third root of unity. + + INPUT: according to the class :class:`~sage.structure.parent_gens.ParentWithGens`. For more information type ``ParentWithGens.hom?`` + + OUTPUT: according to the :class:`~sage.structure.parent_gens.ParentWithGens`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: UCF = UniversalCyclotomicField() + sage: map = ER.hom((UCF.gen(3),) + (UCF(3),UCF(4),UCF(5))) + sage: ER.an_element() + b^2*c^-1 + e3*a + sage: map(_) + -1/5*E(3) - 16/5*E(3)^2 + """ + + if not isinstance(im_gens, (list,tuple)): + im_gens = [im_gens] + + if len(im_gens) == 4: + e3, ia, ib, ic = im_gens + hom_cycl_gen = self.base_ring().hom([e3], codomain=e3.parent(), check=check, base_map=base_map) + verbose( "hom_cycl_gen %s" %(hom_cycl_gen)) + return super(CubicHeckeExtensionRing, self).hom([ia, ib, ic], codomain=codomain, check=check, base_map=hom_cycl_gen) + else: + if base_map is None: + raise ValueError("number of images must be four (inculding a third root of unity at first position) or a base_map (on %s) must be given" %self.base_ring()) + return super(CubicHeckeExtensionRing, self).hom([ia, ib, ic], codomain=codomain, check=check, base_map=base_map) + + def _an_element_(self): + r""" + Overwriting the original method to obtain an more interesting element for ``TestSuite``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('x, y, z') + sage: ER.an_element() # indirect doctest + y^2*z^-1 + e3*x + """ + + a, b, c = self.gens() + e3 = self.cyclotomic_generator() + return b**2/c+a*e3 + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # local methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + # ------------------------------------------------------------------------------- + # helper for element construction + # ------------------------------------------------------------------------------- + def _convert_from_gap3_mvp(self, mvp_expression): + r""" + Convert a string produced via GAP3 interface and containing Jean Michel's ``MVP`` (multivariate polynomials) + to an element of ``self``. + + INPUT: + + - ``string`` -- string produced via GAP3 interface and containing Jean Michel's ``MVP`` (multivariate polynomials) + + OUTPUT: + + An instance of the element class of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: ER._convert_from_gap3_mvp('2+a^-2bc+a^-1b^-1c^2+a^-1b^2c^-1+ab^-2c') + a^-1*b^2*c^-1 + 2 + a*b^-2*c + a^-2*b*c + a^-1*b^-1*c^2 + """ + E3 = self.cyclotomic_generator() + + def xpow(indet, exp): + r""" + Realizing power. + """ + return indet**exp + + a, b, c = self.gens() + na, nb, nc = var_names = self.variable_names() + lc={na:a, nb:b, nc:c, 'E3':E3} + lc['xpow'] = xpow + + sage_expression = preparse_mvp('%s' %(mvp_expression), var_names) + + from sage.misc.sage_eval import sage_eval + return sage_eval(sage_expression, locals=lc) + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # global methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + def cyclotomic_generator(self): + r""" + Return the third root of unity as generator of the base ring of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: ER.cyclotomic_generator() + e3 + sage: _**3 == 1 + True + """ + return self(self.base_ring().gen()) + + + + def cubic_equation_galois_group(self): + r""" + Return the Galois group of the cubic equation, which is the permutation group on the three generators + together with its action on ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: G = ER.cubic_equation_galois_group() + sage: t = ER.an_element() + sage: [(g ,g*t) for g in G] + [((), b^2*c^-1 + e3*a), + ((1,3,2), a^2*b^-1 + e3*c), + ((1,2,3), e3*b + a^-1*c^2), + ((2,3), e3*a + b^-1*c^2), + ((1,3), a^-1*b^2 + e3*c), + ((1,2), a^2*c^-1 + e3*b)] + """ + + return self._galois_group + + + def mirror_involution(self): + r""" + Return the involution of ``self`` corresponding to the involution of the cubic Hecke algebra + (with the same name). This means that it maps the generators of ``self`` to their inverses. + + .. NOTE:: + + The mirror involution of the braid group does not factor through the cubic hecke algebra over its + base ring, but it does if it is considered as `\ZZ`-algebra. The base ring elements are transformed by + this automorphism. + + OUTPUT: + + The involution as automorphism of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('p, q, r') + sage: ER.mirror_involution() + Ring endomorphism of Multivariate Laurent Polynomial Ring in p, q, r + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] + over Integer Ring + Defn: p |--> p^-1 + q |--> q^-1 + r |--> r^-1 + with map of base ring + sage: _(ER.an_element()) + e3*p^-1 + q^-2*r + """ + if self._mirror == None: + a, b, c = self.gens() + e3 = self.base_ring().gen() + self._mirror = self.hom([e3, ~a, ~b, ~c]) + + return self._mirror + + + + + def create_specialization(self, im_cubic_equation_roots, var='T', third_unity_root_name='E3'): + r""" + Return an appropriate Ring containing the elements from the list ``im_cubic_equation_roots`` + defining a conversion map from self mapping the cubic equation roots of ``self`` to + ``im_cubic_equation_roots``. + + INPUT: + + - ``im_cubic_equation_roots`` -- list or tuple of three ring elements such that there exists + a ring homomorphism from the corresponding elements of ``self`` to them + + OUTPUT: + + A common parent containing the elements of ``im_cubic_equation_roots`` together with their inverses. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: t = ER.an_element(); t + b^2*c^-1 + e3*a + sage: Sp1 = ER.create_specialization([E(5), E(7), E(3)]); Sp1 + Universal Cyclotomic Field + sage: Sp1(t) + -E(105)^11 - E(105)^16 - E(105)^26 - E(105)^37 - E(105)^41 + - E(105)^58 - E(105)^71 - E(105)^79 - E(105)^86 - E(105)^101 + + sage: Z3 = CyclotomicField(3); E3=Z3.gen() + sage: Sp2 = ER.create_specialization([E3, E3**2, Z3(1)]) + sage: Sp2(t) + -1 + + sage: Sp3 = ER.create_specialization([5, 7, 11]) + sage: Sp3(t) + 5*E3 + 49/11 + """ + # --------------------------------------------------------------------------------- + # interpreting user given cubic equation roots and define the corresponding + # specialized extension ring + # --------------------------------------------------------------------------------- + + if type(im_cubic_equation_roots) == tuple: + im_cubic_equation_roots = list(im_cubic_equation_roots) + + if type(im_cubic_equation_roots) != list: + raise TypeError( "cubic_equation_roots must be a list of three elements" ) + + if len(im_cubic_equation_roots) != 3: + raise ValueError( "there must be exactly three cubic_equation_roots" ) + + image_ring = get_coercion_model().common_parent(*(im_cubic_equation_roots)) + + # --------------------------------------------------------------------------------------------------------- + # make sure that all given cubic equation roots and their inverses belongs to image_ring + # --------------------------------------------------------------------------------------------------------- + try: + image_ring = image_ring.localization(tuple(im_cubic_equation_roots)) + except ValueError: + pass + + im_cubic_equation_roots = [image_ring(root) for root in im_cubic_equation_roots] + verbose("common parent of roots and inverses: %s" %(image_ring)) + + image_ring_base = image_ring.base_ring() + image_ring_map = None + + verbose("first choice: image_ring %s, image_ring_base %s" %(image_ring, image_ring_base)) + + # --------------------------------------------------------------------------------------------------------- + # make sure that a third root of unity belongs to image_ring + # --------------------------------------------------------------------------------------------------------- + + E3 = None + cp3 = cyclotomic_polynomial(3, var=var).change_ring(image_ring) + cyclotomic_roots = solve_with_extension(cp3, [third_unity_root_name], var=var, flatten=True, warning=False) + + if len(cyclotomic_roots) > 0: + E3 = cyclotomic_roots[0] + verbose("thrird root of unity %s found in %s" %(E3, E3.parent())) + + if E3 == None: + raise RuntimeError( "cannot find a ring containing a third root of unity for the this choice of cubic roots!" ) + + hom_gens = [E3] + im_cubic_equation_roots + verbose("hom_gens %s" %(hom_gens)) + + image_ring = get_coercion_model().common_parent(*(hom_gens)) + verbose("common parent of roots and third root: %s" %(image_ring)) + + hom_gens = [image_ring(gen) for gen in hom_gens] + + image_ring_base = image_ring.base_ring() + + verbose("second choice: image_ring %s, image_ring_base %s" %(image_ring, image_ring_base)) + + try: + image_ring_map = self.hom(hom_gens, codomain=image_ring) + except (ValueError, NotImplementedError): + image_ring_map = self.hom(hom_gens, codomain=image_ring, check=False) + verbose('check failed for embedding as ring morphism') + + verbose("specializing map defined %s" %(image_ring_map)) + + register_ring_hom(image_ring_map) + return image_ring + + + + def as_splitting_algebra(self): + r""" + Return ``self`` as instance of class :class:`SplittingAlgebra` that is as an + extension ring of the corresponding cubic Hecke algebra base ring + (``self._ring_of_definition``, an instance of class + :class:`CubicHeckeRingOfDefinition`) splitting its cubic equation into + linear factors, such that the roots are images of the generators + of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: GBR = chbr.CubicHeckeRingOfDefinition() + sage: GER = GBR.extension_ring() + sage: ER = GER.as_splitting_algebra(); ER + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Splitting Algebra of h^3 - u*h^2 + v*h - w + with roots [a, b, -b - a + u] + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + sage: ER(GER.an_element()) + a*E3 + (((-w^-1)*u)*a^2 + ((w^-1)*u^2 + (-w^-1)*v)*a)*b + a - u + sage: ER(GBR.an_element()) + (w^-1)*u^2 + v + """ + + if self._splitting_algebra != None: + verbose("End (short)") + return self._splitting_algebra + + if self._ring_of_definition == None: + verbose("constructing generic base ring") + self._ring_of_definition = CubicHeckeRingOfDefinition() + + BR = self._ring_of_definition + root_names = list(self._names) + root_names.pop() # Z not needed + + FSR = SplittingAlgebra(BR.cubic_equation(), root_names, warning=False) + splitting_roots = FSR.splitting_roots() + verbose("splitting roots %s" %(splitting_roots)) + + A, B, C = splitting_roots + S = self.create_specialization([A, B, C]) + a, b, c = self.gens() + e3 = self.cyclotomic_generator() + map_back = S.hom([e3, b, a, a + b + c, a*b+a*c+b*c, a*b*c]) + self.register_coercion(map_back) + + self._splitting_algebra = S + + return self._splitting_algebra + + + + + + + + + +####################################################################################################################### +# Ring of Definition +####################################################################################################################### + + + + +# -------------------------------------------------------------------------------------------------------- +# Definition of the ring of definition for the cubic hecke algebra as polynomial ring in 2 indeterminates +# over univariate Laurent polynomial ring over the integers. +# This is the most general ring over which the cubic Hecke algebra may be defined. +# This class inherits from UniqueRepresentation since otherwise an error occurs when a second instance +# is declared. This error occurs in as_splitting_algebra of the associated extension ring. +# -------------------------------------------------------------------------------------------------------- +class CubicHeckeRingOfDefinition(MPolynomialRing_polydict, UniqueRepresentation): + r""" + This class implements the *ring of definition* of the cubic Hecke algebra. + + It contains one invertible indeterminate (representing the product of the roots + of the cubic equation) and two non invertible indeterminates. + + + INPUT: + + - ``names`` -- string containing the names of the indeterminates seperated by ',' + or a triple of strings each of which is the name of one of the three indeterminates + - ``order`` -- string (optional, default='degrevlex') transferred to the corresponding + input of LaurentPolynomialRing_mpair + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: u, v, w = BR.gens_over_ground() + sage: ele = 3*u*v-5*w**(-2) + sage: ER = BR.extension_ring() + sage: ER(ele) + 3*a^2*b + 3*a*b^2 + 3*a^2*c + 9*a*b*c + 3*b^2*c + + 3*a*c^2 + 3*b*c^2 + (-5)*a^-2*b^-2*c^-2 + sage: phi1 = BR.hom( [4,3,1] ) + sage: phi1(ele) + 31 + + sage: LL. = LaurentPolynomialRing(ZZ) + sage: phi2=BR.hom( [LL(4),LL(3),t] ) + sage: phi2(ele) + -5*t^-2 + 36 + + sage: BR.create_specialization( [E(5), E(7), E(3)] ) + Universal Cyclotomic Field + sage: _(ele) + -3*E(105) - 5*E(105)^2 - 5*E(105)^8 - 5*E(105)^11 - 5*E(105)^17 + - 5*E(105)^23 - 5*E(105)^26 - 5*E(105)^29 - 5*E(105)^32 - 5*E(105)^38 + - 5*E(105)^41 - 5*E(105)^44 - 5*E(105)^47 - 5*E(105)^53 - 5*E(105)^59 + - 5*E(105)^62 - 5*E(105)^68 - 8*E(105)^71 - 5*E(105)^74 - 5*E(105)^83 + - 5*E(105)^86 - 5*E(105)^89 - 5*E(105)^92 - 5*E(105)^101 - 5*E(105)^104 + + """ + + def __init__( self, names=('u', 'v', 'w'), order='degrevlex'): + r""" + Python constructor. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: TestSuite(BR).run() + """ + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # Saving class-globals + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + names = normalize_names(3, names) + self._order = order + self._all_names = names + self._invertible_name = names[2] + self._non_invertible_names = (names[0], names[1]) + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # base ring containing the invertible variable + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._base_ring = LaurentPolynomialRing(ZZ, self._invertible_name) + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # Init of self + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + MPolynomialRing_polydict.__init__(self, self._base_ring, 2, self._non_invertible_names, order) + + # --------------------------------------------------------------------------------- + # Init of data used on demand + # --------------------------------------------------------------------------------- + self._mirror = None + + return + + # note: Element assignment is missing in MPolynomialRing_polydict. It activates the element_class method for self + Element = MPolynomial_polydict + + + + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # overloaded inherited methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + def __reduce__(self): + r""" + Used in pickling. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: loads(dumps(BR)) == BR + True + """ + return CubicHeckeRingOfDefinition, (self._all_names, self._order) + + + def _defining_names(self): + r""" + This method is cached in the parent class. This causes trouble if a second instance of self is used for + another cubic Hecke algebra in the same session. To avoid this it is overloaded without ``cached_method`` + decorator. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR._defining_names() + (u, v) + """ + return self.gens() + + + def __call__(self, x, check=True): + r""" + Overloaded to fix an inherited bug concerning ``_test_category``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.an_element()._test_category() # indirect doctest + """ + result = MPolynomialRing_polydict.__call__(self, x, check=check) + return self.element_class( self, result.dict() ) + + + + def _an_element_(self): + r""" + Overwriting the original method to obtain an more interesting element for ``TestSuite``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.an_element() # indirect doctest + (w^-1)*u^2 + v + """ + + u, v, w = self.gens_over_ground() + return u**2/w+v + + def hom(self, im_gens, codomain=None, check=True, base_map=None): + r""" + Custom version overloading the corresponding method of class :class:`~sage.structure.parent_gens.ParentWithGens` + because of special effort with respect to invertible third parameter. + + INPUT: according to the calss :class:`~sage.structure.parent_gens.ParentWithGens`. For more information type ``ParentWithGens.hom?`` + + OUTPUT: according to the :class:`ParentWithGens`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: R = ZZ.localization((5,)) + sage: im_gens = [R(z) for z in [3, 4, ~5]] + sage: map = BR.hom(im_gens) + sage: BR.an_element() + (w^-1)*u^2 + v + sage: map(_) + 49 + """ + + if not isinstance(im_gens, (list,tuple)): + im_gens = [im_gens] + + if len(im_gens) == 3: + iu, iv, iw = im_gens + hom_on_laur = self.base_ring().hom([iw], base_map=base_map) + return super(CubicHeckeRingOfDefinition, self).hom([iu, iv], codomain=codomain, check=check, base_map=hom_on_laur) + else: + if base_map is None: + raise ValueError("number of images must be three or a base_map (on %s) must be given" %self.base_ring()) + return super(CubicHeckeRingOfDefinition, self).hom([iu, iv], codomain=codomain, check=check, base_map=base_map) + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # Local Methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # Global Methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + def gens_over_ground(self): + r""" + Return the generators of self over the ground ring. These are the generators of self over the base ring (u, v) + together with the generator of the base ring over the ground ring (w). + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition(names='A, B, C') + sage: BR.gens_over_ground() + [A, B, C] + + """ + gen_list = self.gens() + self.base_ring().gens() + return [ self(gen) for gen in gen_list ] + + + + def cubic_equation(self, var='h', as_coefficients=False): + r""" + Return the cubic equation over which the cubic Hecke algebra is defined. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.cubic_equation() + h^3 - u*h^2 + v*h - w + sage: BR.cubic_equation(var='t') + t^3 - u*t^2 + v*t - w + sage: BR.cubic_equation(as_coefficients=True) + [-w, v, -u, 1] + """ + u, v, w = self.gens_over_ground() + cf = [-w, v, -u, 1] + if as_coefficients == True: + return cf + P = PolynomialRing(self, var) + + return P(cf) + + + def mirror_involution(self): + r""" + Return the involution of ``self`` corresponding to the involution of the cubic Hecke algebra + (with the same name). This means that it maps the the last generator of ``self`` to its inverse + and both others to their product with the image of the former. + + From the cubic equation for a braid generator $\beta_i$: + + .. MATH:: + + \beta_i^3 - u \beta_i^2 + v\beta_i -w = 0 + + one deduces the following cubic equation for $\beta_i^{-1}$: + + .. MATH:: + + \beta_i^{-3} -\frac{v}{w} \beta_i^{-2} + \frac{u}{w}\beta_i^{-1} -\frac{1}{w} = 0 + + .. NOTE:: + + The mirror involution of the braid group does not factor through the cubic Hecke algebra over its + base ring, but it does if it is considered as $\ZZ$-algebra. The base ring elements are transformed by + this automorphism. + + OUTPUT: + + The involution as automorphism of ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.mirror_involution() + Ring endomorphism of Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + Defn: u |--> (w^-1)*v + v |--> (w^-1)*u + with map of base ring + sage: _(BR.an_element()) + (w^-1)*v^2 + (w^-1)*u + """ + + if self._mirror == None: + u, v, w = self.gens_over_ground() + self._mirror = self.hom([v/w, u/w, ~w]) + + return self._mirror + + + + def create_specialization( self, im_cubic_equation_parameters): + r""" + Return an appropriate Ring containing the elements from the list ``im_cubic_equation_parameters`` + having a conversion map from ``self`` mapping the cubic equation parameters of ``self`` to + ``im_cubic_equation_parameters``. + + INPUT: + + - ``im_cubic_equation_parameters`` -- list or tuple of three ring elements such that there exists + a ring homomorphism from the corresponding elements of ``self`` to them + + OUTPUT: + + a common parent containing the elements of ``im_cubic_equation_parameters`` together with an inverse + of the third element. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: t = BR.an_element(); t + (w^-1)*u^2 + v + sage: Sp1 = BR.create_specialization([E(5), E(7), E(3)]); Sp1 + Universal Cyclotomic Field + sage: Sp1(t) + E(105) + E(105)^8 + E(105)^29 - E(105)^37 + E(105)^43 - E(105)^52 + E(105)^64 + - E(105)^67 + E(105)^71 - E(105)^82 + E(105)^92 - E(105)^97 + + sage: Z3 = CyclotomicField(3); E3=Z3.gen() + sage: Sp2 = BR.create_specialization([E3, E3**2, Z3(1)]); Sp2 + Cyclotomic Field of order 3 and degree 2 + sage: Sp2(t) + -2*zeta3 - 2 + + sage: Sp3 = BR.create_specialization([5, 7, 11]); Sp3 + Integer Ring localized at (11,) + sage: Sp3(t) + 102/11 + """ + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # setting the base_ring according to the cubic_equation_parameters + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + if type(im_cubic_equation_parameters) == tuple: + im_cubic_equation_parameters = list(im_cubic_equation_parameters) + + if type(im_cubic_equation_parameters) != list: + raise TypeError( "cubic_equation_parameters must be a list of three elements" ) + + if len(im_cubic_equation_parameters) != 3: + raise ValueError( "there must be exactly three cubic_equation_parameters" ) + + image_ring = None + image_ring_map = None + u, v, w = im_cubic_equation_parameters + image_ring_base = w.parent() + + # --------------------------------------------------------------------------------------------------------- + # short exit on trivial invocation + # --------------------------------------------------------------------------------------------------------- + if image_ring_base is self and im_cubic_equation_parameters == self.gens_over_ground(): + return self + + image_ring = get_coercion_model().common_parent(*(im_cubic_equation_parameters)) + + # --------------------------------------------------------------------------------------------------------- + # make sure that the inverse of w belongs to image_ring + # --------------------------------------------------------------------------------------------------------- + try: + image_ring = image_ring.localization(w) + except ValueError: + pass + + im_cubic_equation_parameters = [image_ring(para) for para in im_cubic_equation_parameters] + + verbose("common parent of parameters and inverses: %s" %(image_ring)) + + try: + image_ring_map = self.hom(im_cubic_equation_parameters, codomain=image_ring) + except ValueError: + image_ring_map = self.hom(im_cubic_equation_parameters, codomain=image_ring, check=False) + verbose('Warning: check failed for embedding as ring morphism') + + register_ring_hom(image_ring_map) + + return image_ring + + + # -------------------------------------------------------------------------------------------------------- + # Definition of the generic extension ring for the cubic hecke algebra as Laurent polynomial ring in 3 + # indeterminates over cyclotomic field of order 3. The generic extension ring guarantees semisimplicity + # of the cubic Hecke algebra + # -------------------------------------------------------------------------------------------------------- + @cached_method + def extension_ring(self, names='a, b, c'): + r""" + Return the generic extension ring attached to ``self``. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: BR.extension_ring() + Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] + over Integer Ring + """ + ExtensionRing = CubicHeckeExtensionRing(names, ring_of_definition=self) + a, b, c = ExtensionRing.gens() + + # ---------------------------------------------------------------------------------------------- + # constructing a canonical embedding of the generic base ring into the extension ring + # ---------------------------------------------------------------------------------------------- + iu = a+b+c; iv = a*b+a*c+b*c; iw = a*b*c + self._embedding_into_extension_ring_ = self.hom([iu, iv, iw]) + ExtensionRing.register_conversion( self._embedding_into_extension_ring_ ) + + return ExtensionRing diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py new file mode 100644 index 00000000000..234f358c53b --- /dev/null +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -0,0 +1,3273 @@ +# -*- coding: utf-8 -*- +r""" +Cubic Hecke Algebras + +This module is devoted to factors of the group algebra of the Artin braid groups, +such that the images $s_i$ of the braid generators satisfy a cubic equation: + +.. MATH:: + + s_i^3 = u s_i^2 - v s_i + w + +Here $u, v, w$ are elements in an arbitrary integral domain and $i$ is a positive +integer less than $n$, the number of the braid group's strands. By the analogue to the +*Iwahori Hecke algebras* (see :class:`~sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra`), +in which the braid generators satisfy a quadratic relation these algebras have been called +*cubic Hecke algebras*. The relations inherited from the braid group are: + +.. MATH:: + + s_i s_{i+1} s_i = s_{i+1} s_i s_{i+1} \mbox{ where } 1\leq i < n-1 \mbox{ and } + s_i s_j = s_j s_i \mbox{ where } 1 \leq i < j - 1 < n - 1. + +The algebra epimorphism from the braid group algebra over the same base ring is realized +inside the element constructor of the present class, for example in the case of the 3 +strand cubic Hecke algebra:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: BG3 = CHA3.braid_group() + sage: braid = BG3((1,2,-1,2,2,-1)); braid + c0*c1*c0^-1*c1^2*c0^-1 + sage: braid_image = CHA3(braid); braid_image + (-u*v+w)*c1^-1 + ((w^-1)*u^2+(-w^-1)*v)*c0*c1*c0 + ((-w^-1)*u^3+(w^-1)*u*v)*c0*c1 + + ((w^-1)*u^2*v+(-w^-1)*v^2)*c0*c1*c0^-1 + (-u^2)*c0^-1*c1 + + u*c1*c0^-1*c1 + u*v*c0*c1^-1*c0^-1 + +If the ring elements $u, v, w$ (which will be called the *cubic equation parameters* +in the sequel) are taken to be $u = v = 0, w = 1$ the cubic Hecke algebra specializes to the +group algebra of the *cubic braid group*, which is the factor group of the Artin braid +group under setting the generators order to be three. A sage-class to handle these groups +is attached and can be obtained by :meth:`CubicHeckeAlgebra.cubic_braid_group`. + +It is well known, that these algebras are free of finite rank as long as the number of braid +generators is less than six and infinite dimensional else wise. In the former (non trivial) +cases they are also known as *cyclotomic Hecke algebras* corresponding to the complex reflection +groups having Shepard-Todd number $4, 25$ and $32$. + +Since the *Broué, Malle, Rouquiere* conjecture has been proved in all these cases (for references +see [Mar2012]_) there exists a finite free basis of the cubic Hecke algebra which is in +bijection to the cubic braid group and compatible with the specialization to the cubic braid group +algebra as explained above. + +For the algebras corresponding to braid groups of less than five strands such a basis has been +calculated by Ivan Marin. This one is used here. In the case of 5 strands such a basis is not +available, right now. Instead the elements of the cubic braid group class themselves are used as +basis elements. This is also the case when the cubic braid group is infinite, even though it is +not known if these elements span all of the cubic Hecke algebra. + +Accordingly, be aware that the module embedding of the group algebra of the cubic braid groups +is known to be an isomorphism of free modules only in the cases of less than five strands. + +EXAMPLES: + +1. Consider the obstruction ``b`` of the *triple quadratic algebra* from section 2.6 of [Mar2018]_. +We verify that the third power of it is a scalar multiple of itself (explicitly ``2*w^2`` times the +*Schur element* of the three dimensional irreducible representation):: + + sage: CHA3 = algebras.CubicHecke(3) + sage: c1, c2 = CHA3.gens() + sage: b = c1^2*c2 - c2*c1^2 - c1*c2^2 + c2^2*c1; b + w*c1^-1*c0 + (-w)*c1*c0^-1 + (-w)*c0*c1^-1 + w*c0^-1*c1 + sage: b2 = b*b + sage: b3 = b2*b + sage: BR = CHA3.base_ring() + sage: ER = CHA3.extension_ring() + sage: u, v, w = BR.gens_over_ground() + sage: f = BR(b3.coefficients()[0]/w) + sage: try: + ....: sh = CHA3.schur_element(CHA3.irred_repr.W3_111) + ....: except NotImplementedError: # for the case GAP3 / CHEVIE not available + ....: sh = ER(f/(2*w^2)) + sage: ER(f/(2*w^2)) == sh + True + sage: b3 == f*b + True + +2. Defining the cubic Hecke algebra on 6 strands will need some seconds for initializing. But +than you can do calculations inside the infinite algebra as well:: + + sage: CHA6 = algebras.CubicHecke(6) # long time + sage: CHA6.inject_variables() # long time + Defining c0, c1, c2, c3, c4 + sage: s = c0*c1*c2*c3*c4; s # long time + c0*c1*c2*c3*c4 + sage: s^2 # long time + (c0*c1*c2*c3*c4)^2 + sage: t = CHA6.an_element()*c4; t # long time + (-w)*c0*c1^-1*c4 + v*c0*c2^-1*c4 + u*c2*c1*c4 + ((w^-1)*u-v)*c4 + +REFERENCES: + +- [Mar2012]_ +- [Mar2018]_ +- [CM2012]_ + +AUTHORS: + +- Sebastian Oehms May 2020: initial version +""" + + +############################################################################## +# Copyright (C) 2020 Sebastian Oehms +# +# 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 warnings import warn + +from sage.combinat.free_module import CombinatorialFreeModule +from sage.misc.cachefunc import cached_method +from sage.misc.misc import verbose +from sage.groups.cubic_braid import CubicBraidGroup +from sage.rings.integer_ring import ZZ +from sage.algebras.splitting_algebra import solve_with_extension +from sage.modules.free_module_element import vector +from sage.matrix.matrix_space import MatrixSpace +from .base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeRingOfDefinition +from .matrix_representations.cubic_hecke_matrix_rep import CubicHeckeMatrixSpace, AbsIrreducibeRep, RepresentationType + + + + +############################################################################## +# +# Class CubicHeckeElement (for elements) +# +############################################################################## +class CubicHeckeElement(CombinatorialFreeModule.Element): + r""" + Element class of :class:`CubicHeckeAlgebra`. + + It is inherited from :class:`CombinatorialFreeModule.Element` according to the parent class being + inherited from :class:`CombinatorialFreeModule`. The construction of the elements is + realized via :meth:`_element_constructor_` of the parent class. + + For more information see the parent class. + + EXAMPLES:: + + sage: CHA3. = algebras.CubicHecke(3) + sage: c1**3*~c2 + (-u*v+w)*c2^-1 + (u^2-v)*c1*c2^-1 + w*u*c1^-1*c2^-1 + """ + + # --------------------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------------------- + # Overloading inherited methods + # --------------------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------------------- + + def __invert__(self): + r""" + Return inverse of ``self`` (if possible). + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele1 = CHA3((1,-2,1)); ele1 + c0*c1^-1*c0 + sage: ~ele1 # indirect doctest + c0^-1*c1*c0^-1 + sage: ele2 = CHA3.an_element() + sage: ~ele2 # indirect doctest + Traceback (most recent call last): + ... + NotImplementedError: inversion of non basis elements is not implemented, yet + """ + self_Tietze = self.Tietze() + + if self_Tietze == None: + raise NotImplementedError( "inversion of non basis elements is not implemented, yet" ) + + inverse_Tietze = () + len_self = len(self_Tietze) + + inverse_Tietze = tuple([-1 *self_Tietze[len_self-i-1 ] for i in range(len_self)]) + P = self.parent() + return P(inverse_Tietze) + + + + + def Tietze(self): + r""" + Return the Tietze presentation of ``self`` if ``self`` belongs to the basis of its parent + and ``None`` else. + + OUTPUT: + + A tuple representing the pre image braid of ``self`` if ``self`` is a monomial from the basis + ``None`` else-wise + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: ele.Tietze() is None + True + sage: bas_ele = CHA3(ele.leading_support()) + sage: bas_ele.Tietze() + (1, -2) + """ + vecd = self.to_vector().dict() + if len(vecd) != 1: + return None + ind = list(vecd.keys())[0] + if vecd[ind].is_one(): + P = self.parent() + return P.get_order()[ind].Tietze() + + + + def max_len(self): + r""" + Return the maximum of the length of Tietze expressions among the support of ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: ele.max_len() + 2 + """ + + return max(len(bas_ele.Tietze()) for bas_ele in self.support()) + + + + + def braid_group_algebra_pre_image(self): + r""" + Return a pre image of ``self`` in the group algebra of the braid_group (with respect to the + basis given by Iwan Marin). + + OUTPUT: + + The pre image of ``self`` as instance of the element class of the group algebra of the BraidGroup + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: b_ele = ele.braid_group_algebra_pre_image(); b_ele + ((w^-1)*u-v) + v*c0 + u*c1 + (-w)*c0*c1^-1 + sage: ele in CHA3 + True + sage: b_ele in CHA3 + False + sage: b_ele in CHA3.braid_group_algebra() + True + """ + + + ch_algebra = self.parent() + braid_group_algebra = ch_algebra.braid_group_algebra() + braid_group = ch_algebra.braid_group() + + return ch_algebra._apply_module_morphism(self, lambda bas_ele: braid_group_algebra(braid_group(bas_ele)), codomain=braid_group_algebra) + + + + + def cubic_braid_group_algebra_pre_image(self): + r""" + Return a pre image of ``self`` in the group algebra of the cubic_braid_group. + + OUTPUT: + + The pre image of ``self`` as instance of the element class of the group algebra of the CubicBraidGroup + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: cb_ele = ele.cubic_braid_group_algebra_pre_image(); cb_ele + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + sage: ele in CHA3 + True + sage: cb_ele in CHA3 + False + sage: cb_ele in CHA3.cubic_braid_group_algebra() + True + """ + + ch_algebra = self.parent() + cbraid_group_algebra = ch_algebra.cubic_braid_group_algebra() + cbraid_group = ch_algebra.cubic_braid_group() + + return ch_algebra._apply_module_morphism(self, lambda bas_ele: cbraid_group_algebra(cbraid_group(bas_ele)), codomain=cbraid_group_algebra) + + + + + + @cached_method + def matrix(self, subdivide=False, representation_type=None, original=False): + r""" + Return certain types of matrix representations of ``self``. + + The absolutely irreducible representations of the cubic Hecke algebra are constructed using + the *GAP3*-Interface and the *CHEVIE* package if GAP3 and CHEVIE are installed on the system. + Furthermore, the representations given on Ivan Marin's homepage are used: + + http://www.lamfa.u-picardie.fr/marin/softs/H4 + + INPUT: + + - ``subdivide`` -- boolean (default = False): this boolean is passed to the block_matrix + function + - ``representation_type`` -- instance of enum :class:`RepresentationType`. + This can be obtained by the attribute :attr:`CubicHeckeAlgebra.repr_type` of ``self``. The following values are possible: + + - ``RegularLeft`` -- (regular left representation given on the above URL) + - ``RegularRight`` -- (regular right representation given on the above URL) + - ``SplitIrredChevie`` -- (split irreducible representations given via GAP3 CHEVIE) + - ``SplitIrredMarin`` -- (split irreducible representations given on the above URL) + - default: ``SplitIrredChevie`` taken if GAP3 and CHEVIE are installed on the system, otherwise the + default will be ``SplitIrredMarin`` + - ``original`` -- boolean (default = False): if set to true the base_ring of the matrix will be the + generic base_ring resp. generic extension ring (for the split versions) of the parent of ``self`` + + OUTPUT: + + An instance of the class :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.CubicHeckeMatrixRep` + which is inherited from :class:`~sage.matrix.matrix_generic_dense.Matrix_generic_dense`. In the case of the irreducible representations + the matrix is given as a block matrix. Each single irreducible can be obtained as item indexed by the members of the enum + :class:`AbsIrreducibeRep` available via :attr:`CubicHeckeAlgebra.irred_repr`. For details type: ``CubicHeckeAlgebra.irred_repr?``. + + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3.inject_variables() + Defining c0, c1 + sage: c0m = c0.matrix() + sage: c0m[CHA3.irred_repr.W3_111] + [ -b - a + u 0 0] + [(-2*a + u)*b - 2*a^2 + 2*u*a - v b 0] + [ b 1 a] + + using the the ``representation_type`` option:: + + sage: CHA3. = algebras.CubicHecke(3) # optional gap3 + sage: chevie = CHA3.repr_type.SplitIrredChevie + sage: c0m_ch = c0.matrix(representation_type=chevie) # optional gap3 + sage: c0m_ch[CHA3.irred_repr.W3_011] # optional gap3 + [ b 0] + [ -b -b - a + u] + sage: c0m[CHA3.irred_repr.W3_011] + [ b 0] + [a^2 - u*a + v -b - a + u] + + using the the ``original`` option:: + + sage: c0mo = c0.matrix(original=True) + sage: c0mo_ch = c0.matrix(representation_type=chevie, original=True) # optional gap3 + sage: c0mo[CHA3.irred_repr.W3_011] + [ b 0] + [b*c c] + sage: c0mo_ch[CHA3.irred_repr.W3_011] # optional gap3 + [ b 0] + [-b c] + """ + parent = self.parent() + MS = CubicHeckeMatrixSpace(parent, representation_type=representation_type, subdivide=subdivide, original=original) + return MS(self) + + + + def revert_garside(self): + r""" + Return the image of ``self`` under the Garside involution. + See also :meth:`CubicHeckeAlgebra.garside_involution` of the parent class. + + EXAMPLES:: + + sage: roots = (E(3), ~E(3), 1) + sage: CHA3. = algebras.CubicHecke(3, cubic_equation_roots=roots) + sage: e = CHA3.an_element(); e + -c1*c2^-1 + sage: _.revert_garside() + -c2*c1^-1 + sage: _.revert_garside() + -c1*c2^-1 + """ + return self.parent().garside_involution(self) + + + def revert_mirror(self): + r""" + Return the image of ``self`` under the mirror isomorphism. + See also :meth:`CubicHeckeAlgebra.mirror_isomorphism` of the parent class. + + EXAMPLES:: + + sage: CHA3. = algebras.CubicHecke(3) + sage: e = CHA3.an_element() + sage: e.revert_mirror() + ((-w^-1)*u+v) + ((w^-1)*v)*c1^-1 + ((w^-1)*u)*c0^-1 + (-w^-1)*c0^-1*c1 + sage: _.revert_mirror() == e + True + """ + return self.parent().mirror_isomorphism(self) + + + + def revert_orientation(self): + r""" + Return the image of ``self`` under the anti involution reverting the orientation of braids. + See also :meth:`CubicHeckeAlgebra.orientation_antiinvolution` of the parent class. + + EXAMPLES:: + + sage: CHA3. = algebras.CubicHecke(3) + sage: e = CHA3.an_element() + sage: e.revert_orientation() + ((w^-1)*u-v) + u*c2 + v*c1 + (-w)*c2^-1*c1 + sage: _.revert_orientation() == e + True + """ + return self.parent().orientation_antiinvolution(self) + + + + + + + + + + +class CubicHeckeAlgebra(CombinatorialFreeModule): + r""" + Return the Cubic-Hecke algebra with respect to the Artin braid group on $n$ strands. + + This is a quotient of the group algebra of the Artin braid group, such that the images $s_i$ ($1 \leq i < n$) of the + braid generators satisfy a cubic equation (see module header :mod:`~sage.algebras.hecke_algebras.cubic_hecke_algebra` + for more information, in a session type ``sage.algebras.hecke_algebras.cubic_hecke_algebra?``): + + .. MATH:: + + s_i^3 = u s_i^2 - v s_i + w + + The base ring of this algebra can be specified by giving optional keywords described below. If no keywords are given the + base ring will be an instance of the special class :class:`CubicHeckeRingOfDefinition` which is constructed as the polynomial + ring in $u, v$ over the Laurent polynomial ring in $w$ over the integers. This ring will be called the *ring of + definition* or sometimes for short *generic base ring*. But note, that in this context the word *generic* should + not remind in a generic point of the corresponding scheme. + + In addition to the base ring another ring containing the roots ($a, b$ and $c$) of the cubic equation will be needed + to handle the split irreducible representations. This ring will be called *extension ring*. Generically, the extension + ring will be an instance of the special class + :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeExtensionRing` + which is constructed as the Laurent polynomial ring in $a, b$ and $c$ over the integers adjoined with a primitive third + root of unity. A special form of this *generic extension ring* is constructed as an instance of + :class:`~sage.algebras.splitting_algebra.SplittingAlgebra` for the roots of the cubic equation and a primitive third + root of unity over the ring of definition. This ring will be called the *default extension ring*. + + This class uses a static and a dynamic data library. The first one is defined as instance of + :class:`~sage.databases.cubic_hecke_db.CubicHeckeDataBase` and contains the complete basis for the algebras with + less than 5 strands and various types of representation matrices of the generators. These data have been calculated by + Ivan Marin and have been imported from: + + http://www.lamfa.u-picardie.fr/marin/softs/ + + Furthermore, representation matrices can be obtained from the *CHEVIE* package of *GAP3* via the GAP3 interface + if GAP3 is installed inside sage. For more information on how to obtain representation matrices to elements of this + class see the documentation of the matrix-method of the element class: + + ``algebras.CubicHecke.Element?`` or ``algebras.CubicHecke.Element.matrix?`` + + The second library is created as instance of :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache` and + used while working with the class to achieve a better performance. This file cache contains images of braids and + representation matrices of basis elements from former calculations. A refresh of the file cache can be done + using the :meth:`reset_filecache`. + + INPUT: + + - ``names`` -- string containing the names of the generators as images of the braid group generators + - ``cubic_equation_parameters`` -- tuple ``(u, v, w)`` of three elements in an integral domain used as coefficients + in the cubic equation. If this argument is given the base ring will be set to the common parent of ``u, v, w``. In + addition a conversion map from the generic base ring is supplied. This keyword can also be used to change the + variable names of the generic base ring (see example 3 below). + - ``cubic_equation_roots`` -- tuple ``(a, b, c)`` of three elements in an integral domain which stand for the roots + of the cubic equation. If this argument is given the extension ring will be set to the common parent of ``a, b, c``. + In addition a conversion map from the generic extension ring and the generic base ring is supplied. This keyword + can also be used to change the variable names of the generic extension ring (see example 3 below). + + + EXAMPLES: + + 1. cubic Hecke algebra over the ring of definition:: + + sage: CHA3 = algebras.CubicHecke('s1, s2'); CHA3 + Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + with cubic equation: h^3 - u*h^2 + v*h - w = 0 + sage: CHA3.gens() + (s1, s2) + sage: GER = CHA3.extension_ring(generic=True); GER + Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] over Integer Ring + sage: ER = CHA3.extension_ring(); ER + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Splitting Algebra of h^3 - u*h^2 + v*h - w + with roots [a, b, -b - a + u] + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + + 2. element construction:: + + sage: ele = CHA3.an_element(); ele + ((w^-1)*u-v) + u*s2 + v*s1 + (-w)*s1*s2^-1 + sage: ele2 = ele**2; ele2 + (-u^2*v-v^3+(w^-2)*u^2+(-2*w^-1)*u*v+v^2) + (u^3+(2*w^-1)*u^2+(-2)*u*v)*s2 + + (w*u^2+w*v^2)*s2^-1 + (u*v^2+(2*w^-1)*u*v+(-2)*v^2+(-w)*u)*s1 + + u*v*s2*s1 + w*v^2*s1^-1 + w*u*v*s2*s1^-1 + u*v*s1*s2 + + ((-w)*u^2)*s1*s2*s1^-1 + ((-w)*u)*s1^-1*s2*s1 + + ((-w)*u*v+(-2)*u+2*w*v)*s1*s2^-1 + w*u*s1*s2*s1^-1*s2 + ((-w)*v)*s2*s1^-1*s2 + + ((-w^2)*v)*s1^-1*s2^-1 + ((-w^2)*u)*s1^-1*s2*s1^-1 + w^2*(s1^-1*s2)^2 + sage: B3 = CHA3.braid_group() + sage: braid = B3((2,-1, 2, 1)); braid + s2*s1^-1*s2*s1 + sage: ele3 = CHA3(braid); ele3 + v*s2^-1*s1 + (-u)*s1*s2*s1^-1 + u*s1^-1*s2*s1 + (-v)*s1*s2^-1 + s1*s2*s1^-1*s2 + sage: ele4 = CHA3((2,-1, 2, 1)) + sage: ele3 == ele4 + True + + + 3. cubic Hecke algebra over the ring of definition using different variable names:: + + sage: algebras.CubicHecke(3, cubic_equation_parameters='u, v, w', cubic_equation_roots='p, q, r') + Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + with cubic equation: h^3 - u*h^2 + v*h - w = 0 + sage: _.extension_ring() + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Splitting Algebra of h^3 - u*h^2 + v*h - w + with roots [p, q, -q - p + u] + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + + 4. cubic Hecke algebra over a special base ring with respect to a special cubic equation:: + + sage: algebras.CubicHecke('s1, s2', cubic_equation_parameters=(QQ(1),3,1)) + Cubic Hecke algebra on 3 strands over Rational Field + with cubic equation: h^3 - h^2 + 3*h - 1 = 0 + sage: CHA3 = _ + sage: ER = CHA3.extension_ring(); ER + Number Field in T with defining polynomial T^12 + 4*T^11 + 51*T^10 + + 154*T^9 + 855*T^8 + 1880*T^7 + 5805*T^6 + 8798*T^5 + 15312*T^4 + + 14212*T^3 + 13224*T^2 + 5776*T + 1444 + sage: CHA3.cubic_equation_roots()[0] + -4321/1337904*T^11 - 4181/445968*T^10 - 4064/27873*T^9 - 51725/167238*T^8 + - 2693189/1337904*T^7 - 1272907/445968*T^6 - 704251/74328*T^5 + - 591488/83619*T^4 - 642145/83619*T^3 + 252521/111492*T^2 + 45685/5868*T + + 55187/17604 + + sage: F = GF(25,'u') + sage: algebras.CubicHecke('s1, s2', cubic_equation_parameters=(F(1), F.gen(), F(3))) + Cubic Hecke algebra on 3 strands over Finite Field in u of size 5^2 + with cubic equation: h^3 + 4*h^2 + u*h + 2 = 0 + sage: CHA3 = _ + sage: ER = CHA3.extension_ring(); ER + Finite Field in S of size 5^4 + sage: CHA3.cubic_equation_roots() + [2*S^3 + 2*S^2 + 2*S + 1, 2*S^3 + 3*S^2 + 3*S + 2, S^3 + 3] + + + 5. cubic Hecke algebra over a special extension ring with respect to special roots of the cubic equation:: + + sage: UCF = UniversalCyclotomicField() + sage: e3=UCF.gen(3); e5=UCF.gen(5) + sage: algebras.CubicHecke('s1, s2', cubic_equation_roots=(1, e5, e3)) + Cubic Hecke algebra on 3 strands over Universal Cyclotomic Field + with cubic equation: + h^3 + (-E(15) - E(15)^4 - E(15)^7 + E(15)^8)*h^2 + (-E(15)^2 - E(15)^8 + - E(15)^11 - E(15)^13 - E(15)^14)*h - E(15)^8 = 0 + + TESTS: + + sage: CHA3 = algebras.CubicHecke(3) + sage: TestSuite(CHA3).run() + """ + + Element = CubicHeckeElement + repr_type = RepresentationType + irred_repr = AbsIrreducibeRep + + ########################################################################################### + # private methods + ########################################################################################### + @staticmethod + def __classcall_private__(cls, n=None, names='c', cubic_equation_parameters=None, cubic_equation_roots=None): + r""" + Normalize input to ensure a unique representation. + + INPUT: + + - ``n`` -- integer or None (default). The number of strands. If not specified the "names" are + counted and the algebra is assumed to have one more strand than generators + + - ``names`` -- string or list/tuple/iterable of strings (default:'c'). The generator names or + name prefix. The entry can be either a string with the names of the generators, or the number + of generators and the prefix + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, 'd', cubic_equation_roots=(3,5,7)); CHA2 + Cubic Hecke algebra on 2 strands over Integer Ring localized at (3, 5, 7) + with cubic equation: + h^3 - 15*h^2 + 71*h - 105 = 0 + sage: CHA2.inject_variables() + Defining d + sage: CHA3 = algebras.CubicHecke(3, cubic_equation_parameters=(3,5,7)); CHA3 + Cubic Hecke algebra on 3 strands over Integer Ring localized at (7,) + with cubic equation: + h^3 - 3*h^2 + 5*h - 7 = 0 + sage: CHA3.cubic_equation_roots() + [a, b, -b - a + 3] + """ + # Support Freegroup('a,b') syntax + if n is not None: + try: + n = ZZ(n)-1 + except TypeError: + names = n + + n = None + # derive n from counting names + if n is None: + import six + if isinstance(names, six.string_types): + n = len(names.split(',')) + else: + names = list(names) + n = len(names) + from sage.structure.category_object import normalize_names + names = tuple(normalize_names(n, names)) + return super(CubicHeckeAlgebra, cls).__classcall__(cls, names, cubic_equation_parameters=cubic_equation_parameters, + cubic_equation_roots=cubic_equation_roots) + + + def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=None): + r""" + Python constructor. + + TESTS:: + + sage: CHA2 = algebras.CubicHecke(2, 'd', cubic_equation_roots=(3,5,7)) + sage: TestSuite(CHA2).run() + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_parameters=(3,5,7)) + sage: TestSuite(CHA2).run() + """ + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # saving input + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._names = names + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # Define underlying group + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._cubic_braid_group = CubicBraidGroup(names) + self._braid_group = self._cubic_braid_group.braid_group() + n = len(self._cubic_braid_group.gens()) + self._nstrands = n+1 + self._dim_irr_rep = sum([irr.dimension() for irr in AbsIrreducibeRep if irr.number_gens() == n]) + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # preparing use of data base anf file cache + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + from sage.databases.cubic_hecke_db import CubicHeckeDataBase, CubicHeckeFileCache + self._database = CubicHeckeDataBase() + self._filecache = CubicHeckeFileCache(self._nstrands) + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # interpretation of keywords + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + + # --------------------------------------------------------------------------------- + # type verifications + # --------------------------------------------------------------------------------- + + # --------------------------------------------------------------------------------- + # cubic_equation_parameters + # --------------------------------------------------------------------------------- + ring_of_definition_names = ('u', 'v', 'w') + if cubic_equation_parameters != None: + if isinstance(cubic_equation_parameters, str) == True: + # ----------------------------------------------------------------------------------- + # Input specifies names for the generic base ring + # ----------------------------------------------------------------------------------- + ring_of_definition_names = tuple(cubic_equation_parameters.split(',')) + if len(ring_of_definition_names) != 3 : + raise ValueError('cubic_equation_parameters must consist of exactly 3 elements') + cubic_equation_parameters = None + else: + # ----------------------------------------------------------------------------------- + # Input specifies a specialized base ring + # ----------------------------------------------------------------------------------- + if isinstance(cubic_equation_parameters, list) == True: + cubic_equation_parameters = tuple(cubic_equation_parameters) + if isinstance( cubic_equation_parameters, tuple ) == False: + raise TypeError('cubic_equation_parameters must be a tuple or list') + if len( cubic_equation_parameters ) != 3 : + raise ValueError('cubic_equation_parameters must consist of exactly 3 elements') + + # --------------------------------------------------------------------------------- + # cubic_equation_roots + # --------------------------------------------------------------------------------- + generic_extension_ring_names = ('a', 'b', 'c') + if cubic_equation_roots != None: + if isinstance(cubic_equation_roots, str) == True: + # ----------------------------------------------------------------------------------- + # Input specifies names for the generic extension ring + # ----------------------------------------------------------------------------------- + generic_extension_ring_names = tuple(cubic_equation_roots.split(',')) + if len(generic_extension_ring_names) != 3 : + raise ValueError('cubic_equation_roots must consist of exactly 3 elements') + cubic_equation_roots = None + else: + # ----------------------------------------------------------------------------------- + # Input specifies a specialized base ring + # ----------------------------------------------------------------------------------- + if isinstance( cubic_equation_roots, list ) == True: + cubic_equation_roots = tuple(cubic_equation_roots) + if isinstance( cubic_equation_roots, tuple ) == False: + raise TypeError('cubic_equation_roots must be a tuple or list') + if len( cubic_equation_roots ) != 3 : + raise ValueError('cubic_equation_roots must consist of exactly 3 elements') + + if len(set(ring_of_definition_names + generic_extension_ring_names)) < 6: + raise ValueError('there is an overlap of names between cubic equation parameters (%s) and cubic equation roots (%s)' %(ring_of_definition_names, generic_extension_ring_names) ) + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # setting the generic rings + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + ring_of_definition = CubicHeckeRingOfDefinition(names=ring_of_definition_names) + u, v, w = ring_of_definition.gens_over_ground() + + generic_extension_ring = ring_of_definition.extension_ring(names=generic_extension_ring_names) + a, b, c = generic_extension_ring.gens() + + # --------------------------------------------------------------------------------- + # registering generic items as variables + # --------------------------------------------------------------------------------- + self._ring_of_definition = ring_of_definition + self._generic_extension_ring = generic_extension_ring + self._generic_cubic_equation_parameters = [u, v, w] + self._generic_cubic_equation_roots = [a, b, c] + + + + # --------------------------------------------------------------------------------- + # interpreting user given cubic equation parameters to define the corresponding + # specialized base ring + # --------------------------------------------------------------------------------- + + if cubic_equation_parameters == None and cubic_equation_roots != None: + pa, pb, pc = cubic_equation_roots + cubic_equation_parameters = [ pa+pb+pc, pa*pb+pb*pc+pa*pc, pa*pb*pc ] + verbose('cubic_equation_parameters %s set according to cubic_equation_roots %s' %(cubic_equation_parameters, cubic_equation_roots)) + + if cubic_equation_parameters != None: + base_ring = ring_of_definition.create_specialization(cubic_equation_parameters) + cubic_equation_parameters = [ base_ring(para) for para in cubic_equation_parameters ] + verbose('base_ring %s set according to cubic_equation_parameters %s' %(base_ring, cubic_equation_parameters)) + else: + base_ring = self._ring_of_definition + cubic_equation_parameters = self._generic_cubic_equation_parameters + + + verbose('base_ring %s and cubic_equation_parameters %s defined' %(base_ring, cubic_equation_parameters)) + + + # ------------------------------------------------------------------------------------------ + # defining the cubic equation + # ------------------------------------------------------------------------------------------ + pu, pv, pw = cubic_equation_parameters + pol_bas_ring = base_ring['h'] + cubic_equation = pol_bas_ring([-pw, pv, -pu, 1 ]) + + + verbose('cubic_equation %s defined' %(cubic_equation)) + + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining cubic_equation_roots if not given using the cubic_equation + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + if base_ring != ring_of_definition: + if cubic_equation_roots == None: + # ------------------------------------------------------------------------------ + # No roots given + # ------------------------------------------------------------------------------ + ext_ring_names = list(generic_extension_ring_names) + cubic_equation_roots = solve_with_extension(cubic_equation, ext_ring_names, var='S', flatten=True) + + # --------------------------------------------------------------------------------- + # interpreting user given cubic equation roots to define the corresponding + # specialized extension ring + # --------------------------------------------------------------------------------- + if cubic_equation_roots != None: + extension_ring = generic_extension_ring.create_specialization(cubic_equation_roots) + cubic_equation_roots = [ extension_ring(root) for root in cubic_equation_roots ] + verbose('extension_ring %s set according to cubic_equation_roots %s' %(base_ring, cubic_equation_roots)) + + else: + extension_ring = generic_extension_ring.as_splitting_algebra() + cubic_equation_roots = [extension_ring(a), extension_ring(b), extension_ring(c)] + + verbose('cubic roots %s and extension ring %s defined' %(cubic_equation_roots, extension_ring)) + pa, pb, pc = cubic_equation_roots + + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # check keywords plausibility + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + if base_ring == extension_ring: + val_a = cubic_equation.substitute(h=pa) + val_b = cubic_equation.substitute(h=pb) + val_c = cubic_equation.substitute(h=pc) + if val_a != 0 or val_b != 0 or val_c != 0 : + raise ValueError( 'cubic equation does not vanish on cubic equation roots' ) + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining the base ring embedding into the extension ring + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + + + im_base_gens = [pa+pb+pc, pa*pb+pa*pc+pb*pc, pa*pb*pc] + + base_ring_embedding = extension_ring.coerce_map_from( base_ring ) + + def check_base_ring_embedding(base_ring_embedding): + if base_ring_embedding is None: + return False + try: + ipu = base_ring_embedding(pu) + ipv = base_ring_embedding(pv) + ipw = base_ring_embedding(pw) + if [ipu, ipv, ipw] != im_base_gens: + return False + except (TypeError, ValueError): + return False + return True + + if check_base_ring_embedding(base_ring_embedding): + verbose('base_ring_embedding defined via coercion') + else: + base_ring_embedding = extension_ring.convert_map_from( base_ring ) + if check_base_ring_embedding(base_ring_embedding): + verbose('base_ring_embedding defined via conversion') + else: + try: + if base_ring.gens() == cubic_equation_parameters: + base_ring_embedding = base_ring.hom(im_base_gens, codomain=extension_ring) + except (TypeError, ValueError): + base_ring_embedding = None + + + if base_ring_embedding == None: + warn('Warning: no base_ring_embedding found') + + + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # registering variables + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + self._base_ring = base_ring + self._extension_ring = extension_ring + self._base_ring_embedding = base_ring_embedding + self._ring_of_definition_map = base_ring.convert_map_from(ring_of_definition) + self._generic_extension_ring_map = extension_ring.convert_map_from(generic_extension_ring) + self._cubic_equation_parameters = cubic_equation_parameters + self._cubic_equation_roots = cubic_equation_roots + + + # --------------------------------------------------------------------------------- + # defining the associated group algebras + # --------------------------------------------------------------------------------- + # old base_ring keyword of GroupAlgebra + # self._cubic_braid_group_algebra = GroupAlgebra( self._cubic_braid_group, base_ring=base_ring) + # self._braid_group_algebra = GroupAlgebra( self._braid_group, base_ring=base_ring) + # new base_ring keyword of GroupAlgebra + from sage.algebras.group_algebra import GroupAlgebra + self._cubic_braid_group_algebra = GroupAlgebra(self._cubic_braid_group, R=base_ring) + self._braid_group_algebra = GroupAlgebra(self._braid_group, R=base_ring) + + + # ---------------------------------------------------------------------------------------- + # Setup of Basis + # ---------------------------------------------------------------------------------------- + # init of data libraries and fetch the basis of Ivan Marin for the algebras on at most 4 + # strands. The fetch does not take long time. Therefore we do this absolutely silent + # ---------------------------------------------------------------------------------------- + marin_basis_data = self._database.read(self._database.filename.basis) + + # -------------------------------------------------------------------------------------------------- + # An explicit list of basis element which represents a flat deformation of the cubic braid group + # is only available in the cases where the number of strands is less than 5. In the case of exactly + # 5 strands it is known that such a basis exist by work of Ivan Marin in [Marin2012] but it can not + # be calculated, right now. In the (infinite dimensional) cases of more than 5 strand it is even an + # open problem if the cubic Hecke algebra is a flat deformation of the group algebra of the + # corresponding cubic braid group. + # + # But anyway, we will take the elements of the cubic braid group as a basis of the cubic Hecke + # algebra in all cases. Beware that this might not cover the whole cubic Hecke algebra if the + # number of strands is larger than 4 + # + # Internally the basis is handled using two lists one of which consists of fixed braid preiimages + # of the basis elements and the other (redundant) of the corresponding Tietze expressions. + # + # In the case of less than 5 strands these lists are directly obtained from the list calculated + # by Ivan Marin available at + # + # + # In the other cases these lists are implemented as growing lists which is initialized with Marin's + # list and is extended on demand. + # ----------------------------------------------------------------------------------------------- + + if self.strands() < 5 : + self._basis_static = [bas for bas in marin_basis_data[self.strands()][0]] + else: + self._basis_static = [bas for bas in marin_basis_data[4][0]] + + # --------------------------------------------------------------------------------- + # --------------------------------------------------------------------------------- + # defining the algebra itself + # --------------------------------------------------------------------------------- + # -------------------------------------------------------------------------------- + + if self._cubic_braid_group.is_finite(): + from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis + category = FiniteDimensionalAlgebrasWithBasis(base_ring) + else: + from sage.categories.algebras_with_basis import AlgebrasWithBasis + category = AlgebrasWithBasis(base_ring) + + + CombinatorialFreeModule.__init__(self, base_ring, self._cubic_braid_group, prefix='', bracket=False, category=category) + + # ---------------------------------------------------------------------------------------- + # init the attributes being set on demand + # ---------------------------------------------------------------------------------------- + self._cubic_hecke_subalgebra = None # the cubic Hecke subalgebra with one strand (the highest) less + self._mirror_image = None # the image of self under the mirror isomorphism + self._is_mirror = False # to see if this instance is the mirror or the original + self._base_ring_mirror = None # mirror involution map on base ring + self._gens_reg_repres_matrix = {} # a dictionary recording the generators regular representation matrices + + # ---------------------------------------------------------------------------------------- + # initializing the basis extension (in case of more than 4 strands) + # ---------------------------------------------------------------------------------------- + self._init_basis_extension() # read in the basis extensions from file cache + return + + + + + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # overloaded inherited methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + def _repr_(self): + r""" + Return a string representation + + OUTPUT: + + String describing ``self`` + + TESTS: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3 # indirect doctest + Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w + over Integer Ring with cubic equation: h^3 - u*h^2 + v*h - w = 0 + """ + return "Cubic Hecke algebra on %s strands over %s with cubic equation: %s = 0"%(self.strands(), self.base_ring(), self.cubic_equation()) + + + def _element_constructor_(self, x): + r""" + Extensions to the element constructor of class :class:`CombinatorialFreeModule`. + New functionalities are: + + -- constructing element from a braid (group homomorphism) + -- constructing element from a braid giving in Tietze form + -- constructing element from an element of the braid group algebra (algebra homomorphism) + -- constructing element from an element of the cubic braid group algebra (module homomorphism) + -- constructing element from an element of an other cubic_hecke_algebra over an other base ring or with less strands + -- constructing element from an element of the mirror image of ``self`` (see method mirror_image) + + INPUT: + + - ``x`` -- can be one of the following: + -- an instance of the element class of ``self`` (but possible to a different parent) + -- an instance of the element class of the braid group + -- an instance of the element class of the braid group algebra over the base ring of ``self`` + -- an instance of the element class of the cubic braid group + -- an instance of the element class of the cubic braid group algebra over the base ring of ``self`` + -- an instance of the element class of the mirror image of ``self`` + -- a tuple representing a braid in Tietze form + -- any other object which works for the element constructor of :class:`CombinatorialFreeModule` + + OUTPUT: + + Instance of the element class of ``self``. + + EXAMPLES:: + + sage: B2 = BraidGroup(2) + sage: b, = B2.gens() + sage: b2 = b**2 + sage: CB2 = CubicBraidGroup(2) + sage: cb, = CB2.gens() + sage: cb2 = cb**2 + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2(b2) + (-v) + u*c + w*c^-1 + sage: CHA2(cb2) + c^-1 + sage: CHA3 = algebras.CubicHecke(3) + sage: B3 = CHA3.braid_group() + sage: CB3 = CHA3.cubic_braid_group() + sage: CB3GA = CHA3.cubic_braid_group_algebra() + sage: braid = B3((1,2,2,-1,2,1,1,-1)); braid + c0*c1^2*c0^-1*c1*c0 + sage: img_braid = CHA3(braid); img_braid + (u*v^2+(-w)*v)*c1^-1 + (u^2-v)*c1*c0 + u^2*v*c1*c0^-1 + (-u^3)*c0*c1*c0^-1 + + (-u^2*v+w*u)*c0*c1^-1 + u^2*c0*c1*c0^-1*c1 + (-u*v)*c1*c0^-1*c1 + + ((-w)*u*v+w^2)*c0^-1*c1^-1 + ((-w)*u^2)*c0^-1*c1*c0^-1 + + w*u*(c0^-1*c1)^2 + u*v*c0*c1^-1*c0 + sage: cbraid = CB3(braid); cbraid + c0*c1^2*c0^-1*c1*c0 + sage: img_cbraid = CHA3(cbraid); img_cbraid + c0^-1*c1^-1 + sage: img_cbraid_back = img_cbraid.cubic_braid_group_algebra_pre_image() + sage: img_cbraid_back in CB3GA + True + sage: img_cbraid_back == CB3GA(cbraid) + True + """ + braid_grp = self.braid_group() + braid_grp_alg = self.braid_group_algebra() + braid_img = self._braid_image + + cbraid_grp = self.cubic_braid_group() + cbraid_grp_alg = self.cubic_braid_group_algebra() + cbraid_img = self._cubic_braid_image + + base_ring = self.base_ring() + ngens = self.ngens() + + # ----------------------------------------------------------------------------------------- + # if x is a tuple we may interpret it as a braid in Tietze form + # ----------------------------------------------------------------------------------------- + xb = x + if type(x) in (tuple, list): + x = tuple(x) + result = self._tietze_to_finite_sub_basis_monomial(x) + if result is not None: + # x represents a monomial + verbose("End from tuple %s: %s" %(x, result)) + return result + + try: + xb=braid_grp(x) + except (TypeError, ValueError, NotImplementedError): + pass + + # ----------------------------------------------------------------------------------------- + # embedding of an element of an other cubic Hecke algebra with lower number of strands + # but same base ring + # ----------------------------------------------------------------------------------------- + if isinstance(xb, CubicHeckeElement): + OtherCHA = xb.parent() + other_base_ring = OtherCHA.base_ring() + other_ngens = OtherCHA.ngens() + if other_base_ring != base_ring: + if other_ngens == ngens: + xbv = xb.to_vector() + img_xbv = vector([self.base_ring()(cf) for cf in xbv ]) + return self.from_vector(img_xbv) + elif other_ngens < ngens: + SubAlg = SubAlg = self.cubic_hecke_subalgebra(other_ngens+1) + return self(SubAlg(xb)) + + elif other_ngens < ngens and OtherCHA.cubic_equation_parameters() == self.cubic_equation_parameters(): + + cubic_braid_preimg = xb.cubic_braid_group_algebra_pre_image() + OtherCBGA = OtherCHA.cubic_braid_group_algebra() + + result = OtherCBGA._apply_module_morphism(cubic_braid_preimg, lambda ele: cbraid_img(cbraid_grp(ele)), codomain=self) + verbose("End from smaller cubic Hecke algebra %s: %s" %(xb, result)) + return result + + elif OtherCHA == self._mirror_image: + + result = OtherCHA.mirror_isomorphism(xb) + verbose("End from mirror image %s: %s" %(xb, result)) + return result + + # ----------------------------------------------------------------------------------------- + # if xb is an element of the braid group or its group algebra over the same base ring + # the algebra morphism self._braid_image is applied + # ----------------------------------------------------------------------------------------- + if isinstance(xb, braid_grp_alg.element_class) and xb in braid_grp_alg: + + result = braid_grp_alg._apply_module_morphism(xb, lambda ele: braid_img(ele), codomain=self) + verbose("End from braid_group algebra %s: %s" %(xb, result)) + return result + + from sage.groups.braid import Braid + if isinstance(xb, Braid) and xb.strands() == self.strands(): + + result = braid_img(xb) + verbose("End from braid_group %s: %s" %(xb, result)) + return result + + # ----------------------------------------------------------------------------------------- + # if xb is an element of the cubic_braid group or its group algebra over the same base ring + # xb the module morphism self._braid_image is applied + # ----------------------------------------------------------------------------------------- + if isinstance(xb, cbraid_grp_alg.element_class) and xb in cbraid_grp_alg: + + result = cbraid_grp_alg._apply_module_morphism(xb, cbraid_img, codomain=self) + verbose("End from cubic braid_group algebra %s: %s" %(xb, result)) + return result + + from sage.groups.cubic_braid import CubicBraidElement + if isinstance(xb, CubicBraidElement) and xb.parent().strands() == self.strands(): + + result = cbraid_img(xb) + verbose("End from cubic braid_group %s: %s" %(xb, result)) + return result + + + # ----------------------------------------------------------------------------------------- + # doing the default construction by inheritance + # ----------------------------------------------------------------------------------------- + result = CombinatorialFreeModule._element_constructor_(self, x) + verbose("End (default) %s: %s" %(xb, result)) + return result + + + + def get_order(self): + r""" + Overwrites the corresponding method of :class:`CombinatorialFreeModule`. The reason is that + we have to care about the dynamical growth of the finite sub basis used for the calculation in case of + more than 4 strands. + + To see the documentation of the original method type: + + ``CombinatorialFreeModule.get_order?`` + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: len(CHA3.get_order()) + 24 + """ + if self.strands() < 5: + return self._order + else: + # detect change of order of subalgebra + cbg = self.cubic_braid_group() + sub_alg = self.cubic_hecke_subalgebra() + former_len_sub = len(sub_alg._order) + sub_order = [cbg(cb) for cb in sub_alg.get_order()] + if former_len_sub == len(sub_order): + if len(self._order) == former_len_sub + len(self._basis_extension): + return self._order + # order has changed! recalculation neccessary: + self._order = sub_order + [cbg(tup) for tup in self._basis_extension] + return self._order + + + + def _dense_free_module(self, base_ring=None): + r""" + Overwrites the corresponding method of :class:`CombinatorialFreeModule`. + The only difference is, that the dimension is not the dimension of ``self`` but + the dimension of the submodule generated by the dynamically growing basis given + by the the get_order method. In particular there is no difference if the number + of strands is less than 5. + + To see the documentation of the original method type: + + ``CombinatorialFreeModule._dense_free_module?`` + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._dense_free_module() + Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + """ + + if base_ring is None: + base_ring = self.base_ring() + from sage.modules.free_module import FreeModule + return FreeModule(base_ring, len(self.get_order())) + + + def ngens(self): + r""" + The number of generators of the algebra. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.ngens() + 1 + """ + return self.strands() -1 + + def algebra_generators(self): + r""" + Return the algebra generators of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.algebra_generators() + Finite family {c: c} + """ + from sage.sets.family import Family + return Family(self._cubic_braid_group.gens(), self.monomial) + + + def gens(self): + r""" + Return the generators of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.gens() + (c,) + """ + return tuple(self.algebra_generators()) + + + def gen(self, i): + r""" + The ``i``-th generator of the algebra. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.gen(0) + c + """ + return self.gens()[i] + + + def one_basis(self): + r""" + Return the identity element in the cubic braid group, as per + AlgebrasWithBasis.ParentMethods.one_basis. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.one_basis() + 1 + """ + return self.cubic_braid_group().one() + + + def _an_element_(self): + r""" + Overwrite the original method from :mod:`sage.combinat.free_module` + to obtain an more interesting element for ``TestSuite``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.an_element() # indirect doctest + ((w^-1)*u-v) + v*c + """ + + n = self.ngens()+1 + base_ring = self.base_ring() + u, v, w = [base_ring(para) for para in self._cubic_equation_parameters] + const = (u *~w -v)* self.one() + + gens = self.gens() + first_gens = [gen for gen in gens if gens.index(gen) < 3 ] + if n == 2 : + c1, = first_gens + return const + v*c1 + elif n == 3 : + c1, c2 = first_gens + return const + v*c1 -w*c1*~c2 + u*c2 + else: + c1, c2, c3 = first_gens + return const + v*c1*~c3 -w*c1*~c2 + u*c3*c2 + + + + + @cached_method + def chevie(self): + r""" + Return the *GAP3-CHEVIE* realization of the corresponding *cyclotomic Hecke algebra* + in the finite-dimensional case. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: CHA3.chevie() # optional gap3 + Hecke(G4,[[a,b,c]]) + """ + + from sage.combinat.root_system.reflection_group_real import is_chevie_available + if not is_chevie_available(): + raise NotImplementedError('this functionality needs GAP3 with package CHEVIE') + + n = self._nstrands + + if n == 3: + st_number = 4 + elif n == 4: + st_number = 25 + elif n == 5: + st_number = 32 + else: + raise NotImplementedError('CHEVIE version doesn\'t exist for this cubic Hecke algebra') + + gap3_function_str = """function(st_number, na, nb,nc) + local a, b, c, # embedded Indeterminates + ReflGroup, # Reflection group + HeckeAlg; # Hecke algebra + + a := Mvp(na); b := Mvp(nb); c := Mvp(nc); + ReflGroup := ComplexReflectionGroup(st_number); + HeckeAlg := Hecke(ReflGroup, [[a, b, c]] ); + return HeckeAlg; + end;""" + + from sage.interfaces.gap3 import gap3 + gap3_function = gap3(gap3_function_str) + na, nb, nc = [ '\"%s\"' %(indet) for indet in self.extension_ring(generic=True).variable_names() ] + return gap3_function(st_number, na, nb, nc) + + + @cached_method + def product_on_basis(self, g1, g2): + r""" + Return product on basis elements, as per + :meth:`~sage.categories.magmatic_algebras.MagmaticAlgebras.WithBasis.ParentMethods.product_on_basis` + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: g = CHA3.basis().keys().an_element(); g + c0*c1 + sage: CHA3.product_on_basis(g, ~g) + 1 + sage: CHA3.product_on_basis(g, g) + (-v)*c1*c0 + u*c0*c1*c0 + w*c0^-1*c1*c0 + """ + # ------------------------------------------------------------------------------------------------ + # short way for multiplications with one + # ------------------------------------------------------------------------------------------------ + if g1 == g1.parent().one(): + return self.monomial(g2) + + if g2 == g2.parent().one(): + return self.monomial(g1) + + # ------------------------------------------------------------------------------------------------ + # convert to monomials + # ------------------------------------------------------------------------------------------------ + g1 = self.monomial(g1) + g2 = self.monomial(g2) + + result = None + + g1_Tietze = g1.Tietze() + g2_Tietze = g2.Tietze() + + verbose("Tietze established (%s, %s)" %(g1_Tietze, g2_Tietze)) + + # ---------------------------------------------------------------------------------------------------- + # The product is calculated from the corresponding product of the braids + # ---------------------------------------------------------------------------------------------------- + + braid_group = self.braid_group() + braid_product = braid_group(g1_Tietze+g2_Tietze) + + result = self._braid_image(braid_product) + + return result + + + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # local methods + # --------------------------------------------------------------------------------------------------------------------- + ####################################################################################################################### + + + + def _basis_tietze(self): + r""" + Return the complete finite sub basis as list of Tietze tuples + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._basis_tietze() + [[], [1], [-1]] + """ + if self.strands() > 4 : + self_sub = self.cubic_hecke_subalgebra() + result_list = self_sub._basis_tietze() + self._basis_extension + else: + result_list = self._basis_static + return result_list + + + def _tietze_to_finite_sub_basis_monomial(self, tietze_tup): + r""" + Return the monomial corresponding to a tietze tuple + if it is in the finite sub basis. Else return None. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._tietze_to_finite_sub_basis_monomial([-1]) + c^-1 + sage: CHA2._tietze_to_finite_sub_basis_monomial([-2]) is None + True + """ + tietze_list = list(tietze_tup) + in_basis = False + if tietze_list in self._basis_tietze(): + in_basis = True + elif self.strands() > 4: + fsb_dict = self._finite_sub_basis_tuples + if tietze_list in list(fsb_dict.values()): + in_basis = True + elif self.cubic_hecke_subalgebra()._tietze_to_finite_sub_basis_monomial(tietze_tup) is not None: + in_basis = True + + if in_basis: + # tietze_tup represents a monomial + B = self.basis() + cb = self.cubic_braid_group()(tietze_tup) + return B[cb] + else: + return None + + @cached_method + def _create_matrix_list_for_one(self, representation_type): + r""" + Return the matrix list for the given representation_type for ``self.one()`. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._create_matrix_list_for_one(CHA2.repr_type.SplitIrredMarin) + [[1], [1], [1]] + sage: CHA2._create_matrix_list_for_one(CHA2.repr_type.RegularLeft) + [ + [1 0 0] + [0 1 0] + [0 0 1] + ] + """ + n = self.strands() + if representation_type.is_split(): + gen_base_ring = self.extension_ring(generic=True) + rep_ind = [rep.internal_index() for rep in AbsIrreducibeRep if rep.number_gens() == n-1 ] + rep_dim = [rep.dimension() for rep in AbsIrreducibeRep if rep.number_gens() == n-1 ] + dim_sort = [rep_dim[rep_ind.index(i)] for i in range(len(rep_ind))] + matrix_list = [MatrixSpace(gen_base_ring, dim_sort[i]).one() for i in range(len(rep_ind))] + else: + gen_base_ring = self.base_ring(generic=True) + matrix_list = [MatrixSpace(gen_base_ring, self.dimension()).one()] + return matrix_list + + @cached_method + def _fetch_matrix_list_from_chevie(self, number): + r""" + This method reads irreducible representation of the cubic Hecke algebra via the *GAP3* interface from *CHEVIE* + + INPUT: + + - ``number`` -- integer: number of the representation according to *CHEVIE* + + OUTPUT: + + A list of representing matrices over the generic extension ring, one matrix for each generators. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: CHA3._fetch_matrix_list_from_chevie(5) # optional gap3 + [ + [ a 0] [c c] + [-a c], [0 a] + ] + """ + GER = self.extension_ring(generic=True) + gap3_result = self.chevie().Representations(number) + from sage.matrix.constructor import matrix + matrix_list_gens = [matrix(GER, mat_gap) for mat_gap in gap3_result] + for m in matrix_list_gens: m.set_immutable() + return matrix_list_gens + + + + + # ------------------------------------------------------------------------------- + # ------------------------------------------------------------------------------- + # Methods for test_suite + # ------------------------------------------------------------------------------- + # ------------------------------------------------------------------------------------------------------------- + # _test_ring_constructions + # ------------------------------------------------------------------------------------------------------------- + def _test_ring_constructions(self, **options): + r""" + Method called by TestSuite. + + the following is checked: + - construction of base_ring and extension ring + - construction of maps between generic base and extension ring and the user defined rings + - aplication of the ring homomorphisms + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3,7,11)) + sage: CHA2._test_ring_constructions() + """ + # ------------------------------------------------------------------------ + # testing ring constructions + # ------------------------------------------------------------------------ + + + br=self.base_ring(); er=self.extension_ring() + A, B, C = self.cubic_equation_roots(); a, b, c = self.cubic_equation_roots(generic=True); + U, V, W = self.cubic_equation_parameters(); u, v, w = self.cubic_equation_parameters(generic=True); + eleB = U*V-W**2 ; eleBgen = u*v-w**2 ; eleE = A*B-C**2 ; eleEgen = a*b-c**2 + + mbr = self._ring_of_definition_map + mer = self._generic_extension_ring_map + bri = self._base_ring_embedding + + eleBgenEmb = 0 ; eleEgenEmb = 0 ; eleBembE = 0 + + try: + eleBgenEmb = br(eleBgen) + except (TypeError, ValueError, NotImplementedError): + verbose("Generic base ring map not registered") + try: + eleBgenEmb = mbr(eleBgen) + except (TypeError, ValueError, NotImplementedError): + raise RuntimeError("fatal: generic base ring map %s does not work" %(mbr)) + try: + eleEgenEmb = er(eleEgen) + except (TypeError, ValueError, NotImplementedError): + verbose("Generic extension ring map not registered") + try: + eleEgenEmb = mer(eleEgen) + except (TypeError, ValueError, NotImplementedError): + raise RuntimeError("fatal: generic extension ring map %s does not work" %(mer)) + + try: + eleBembE = er(eleB) + except (TypeError, ValueError, NotImplementedError): + verbose("base ring embedding map not registered") + try: + eleBembE = bri(eleB) + except (TypeError, ValueError, NotImplementedError): + raise RuntimeError( "fatal: base ring embedding %s does not work" %(bri) ) + + test_eleBgenEmb = self._tester(**options) + test_eleBgenEmb.assertTrue( eleBgenEmb == eleB ) + test_eleEgenEmb = self._tester(**options) + test_eleEgenEmb.assertTrue( eleEgenEmb == eleE ) + test_eleBembE = self._tester(**options) + test_eleBembE.assertTrue( eleBembE == eleB ) + + + + # ------------------------------------------------------------------------------------------------------------- + # _test_matrix_constructions + # ------------------------------------------------------------------------------------------------------------- + def _test_matrix_constructions(self, **options): + r""" + Method called by TestSuite + + the following is checked: + - construction of matrices of the following types + + - multiplication of matrices and compare with the matrix of the corresponding product of elements + - construction of maps between generic base and extension ring and the user defined rings + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3,7,11)) + sage: CHA2._test_matrix_constructions() + """ + # ------------------------------------------------------------------------ + # testing matrix constructions + # ------------------------------------------------------------ ------------ + + if self.ngens() > 4 : + return + + gens = self.gens() + b1 = gens[0 ]; b2 = self.an_element() + b12 = b1*b2 + verbose("b12 %s" %(b12)) + + def check_matrix(representation_type): + m1 = b1.matrix(representation_type=representation_type) + m2 = b2.matrix(representation_type=representation_type) + m12mult = m1*m2 + m12mat = b12.matrix(representation_type=representation_type) + test_matrix = self._tester(**options) + test_matrix.assertTrue(m12mult == m12mat) + + from sage.combinat.root_system.reflection_group_real import is_chevie_available + + if is_chevie_available(): + check_matrix(RepresentationType.SplitIrredChevie) + if self.ngens() < 3 : + check_matrix(RepresentationType.SplitIrredMarin) + elif self.ngens() < 4 : + check_matrix(RepresentationType.SplitIrredMarin) + + if self.ngens() < 3 : + check_matrix(RepresentationType.RegularLeft) + + return + + + + + + + + + # ------------------------------------------------------------------------------------------------------------- + # _init_basis_extension + # ------------------------------------------------------------------------------------------------------------- + def _init_basis_extension(self): + r""" + Return the extension of the basis for more than 4 strands hold in file cache. + The basis elements from the file are added to the elements of the Marin basis. + + EXAMPLES:: + + sage: CHA5 = algebras.CubicHecke(5) # long time + sage: fc = CHA5._filecache # long time + sage: basis_extensions = fc.section.basis_extensions # long time + sage: CHA5.reset_filecache(basis_extensions) # long time indirect doctest + sage: fc.read(basis_extensions) # long time + [[4], [-4]] + sage: ele = CHA5.an_element() # long time + sage: CHA5.inject_variables() # long time + Defining c0, c1, c2, c3 + sage: ele2 = ele*c3 # long time + sage: bex = fc.read(basis_extensions) # long time + sage: bex.sort(); bex # long time + [[-4], [1, -3, 4], [1, -2, 4], [3, 2, 4], [4]] + """ + self._basis_extension = [] + + tietze_list = self._basis_tietze() + cbg = self._cubic_braid_group + self._finite_sub_basis_tuples = {} + order_list = [cbg(tup) for tup in tietze_list] + self.set_order(order_list) + verbose('Finite sub basis length: %s' %(len(order_list))) + + if self.strands() < 5: + return + # ------------------------------------------------------------------------------------------------- + # loading the extension of the basis from data file + # ------------------------------------------------------------------------------------------------- + fc = self._filecache + former_bas_ext = fc.read(fc.section.basis_extensions) + + # ------------------------------------------------------------------------------------------------- + # pre definition of additional basis elements + # ------------------------------------------------------------------------------------------------- + cub_braid_group = self.cubic_braid_group() + if len(former_bas_ext) == 0: + gens = cub_braid_group.gens() + last_gen = gens[len(gens)-1] + self._cubic_braid_image(last_gen, check=False) + self._cubic_braid_image(~last_gen, check=False) + self._filecache.update_basis_extensions(self._basis_extension) + return + + # ------------------------------------------------------------------------------------------------- + # Installing the additional basis elements from filecache via the embedding of + # the corresponding cubic braid + # ------------------------------------------------------------------------------------------------- + for bas_Tietze in former_bas_ext: + cub_braid = cub_braid_group(bas_Tietze) + self._cubic_braid_image(cub_braid, check=False) + + verbose('Finite sub basis (extended) length: %s' %(len(self.get_order()))) + self._filecache.update_basis_extensions(self._basis_extension) + return + + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_from_filecache + # ------------------------------------------------------------------------------------------------------------- + def _braid_image_from_filecache(self, braid): + r""" + Return the image of the given braid in ``self`` from file cache (if contained). + + INPUT: + + - ``braid`` -- braid as instance of the braid group of ``self`` + + OUTPUT: + + Image of braid as element of ``self``. None if the product has not been stored. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: b1, b2 = CHA3.braid_group().gens(); br = ~b2*b1*~b2 + sage: CHA3._braid_image_from_filecache(br) + ((w^-1)*v)*c1^-1*c0 + ((-w^-1)*u)*c0*c1*c0^-1 + (w^-1)*c0*c1*c0^-1*c1 + sage: CHA3.reset_filecache(CHA3.select_filecache_section().braid_images) + sage: CHA3._braid_image_from_filecache(br) + """ + + base_ring = self.base_ring() + gen_base_ring = self.base_ring(generic=True) + result_vect = self._filecache.read_braid_image(braid.Tietze(), gen_base_ring) + if not result_vect is None: + if gen_base_ring != base_ring: + base_map = self._ring_of_definition_map + result_vect = base_map(result_vect) + return self.from_vector(result_vect) + return None + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_to_filecache + # ------------------------------------------------------------------------------------------------------------- + def _braid_image_to_filecache(self, braid_tietze, braid_image_vect): + r""" + Write the given braid image of to file cache. + + INPUT: + + - `braid_tietze` -- braid in Tietze form + - `braid_image_vect` -- image of the given braid in ``self`` in vector representation + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: br, = CHA2.braid_group().gens(); br2 = br**2 + sage: CHA2.is_filecache_empty(CHA2.select_filecache_section().braid_images) # note: 2-strand images are not automatically cached in file system + True + sage: CHA2._braid_image_to_filecache(br2.Tietze(), CHA2(br2).to_vector()) + sage: CHA2._braid_image_from_filecache(br2) + (-v) + u*c + w*c^-1 + sage: CHA2.reset_filecache(CHA2.select_filecache_section().braid_images) + sage: CHA2._braid_image_from_filecache(br2) == None + True + """ + if self.base_ring() != self.base_ring(generic=True): + # this should not be done for specialized base rings + return + + self._filecache.write_braid_image(braid_tietze, braid_image_vect) + return + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image + # ------------------------------------------------------------------------------------------------------------- + def _braid_image(self, braid): + r""" + Return the image of the given braid in ``self``. + + INPUT: + + - ``braid`` - instance of :class:`~sage.groups.braid.Braid`, whose image in ``self`` should be calculated + + + OUTPUT: + + An instance of the element class of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: br, = CHA2.braid_group().gens(); br2 = br**2 + sage: CHA2._braid_image(br2) + (-v) + u*c + w*c^-1 + """ + + + # ----------------------------------------------------------------------------------------------------- + # first use the cubic equation to express the braid as a linear combination of braids having no other + # exponent as 1 and -1 in their defining word in the braid generators + # ----------------------------------------------------------------------------------------------------- + coeffs, braids = self._reduce_all_gen_powers(braid.Tietze()) + + # ----------------------------------------------------------------------------------------------------- + # in the second step the images of these "reduced" braids is calculated + # ----------------------------------------------------------------------------------------------------- + result = self.zero() + for i in range(len(coeffs)): + braid_image = self._braid_image_from_reduced_powers(braids[i]) + result += coeffs[i]*braid_image + + return result + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_from_reduced_powers + # ------------------------------------------------------------------------------------------------------------- + @cached_method + def _braid_image_from_reduced_powers(self, braid_tietze): + r""" + Return the image of a braid in ``self`` asuming that no successive repetitions occur in the Tietze form + of the braid. + + INPUT: + + - ``braid_tietze`` -- tuple representing the Braid whose image in ``self`` should be computed. It is assumed + that no successive repetitions occur among the entries (i.e. (1,1) is not allowed but (1, -2, 1) is) + + OUTPUT: + + The image of the braid as an element of ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3._braid_image_from_reduced_powers((1, -2, 1)) + c0*c1^-1*c0 + sage: CHA3._braid_image_from_reduced_powers((1, -2, 1, 2)) + (-v)*c1*c0^-1 + u*c0*c1*c0^-1 + w*c0^-1*c1*c0^-1 + """ + n = self.ngens() + braid_list = list(braid_tietze) + len_braid = len(braid_list) + + # --------------------------------------------------------------------------------------------------- + # in the case of two strands we calculate the power of the generator + # --------------------------------------------------------------------------------------------------- + if n == 1 : + if len_braid == 0 : + return self.one() + k = braid_tietze[0 ]*len_braid + result_vect = self._reduce_gen_power(k) + result = self.from_vector(result_vect) + return result + + # --------------------------------------------------------------------------------------------------- + # Try to use former calculations (from dynamic library) to obtain the braid image + # --------------------------------------------------------------------------------------------------- + result, word_decomposition = self._braid_image_from_former_calculations(braid_tietze) + + if word_decomposition == None: + return result + + # --------------------------------------------------------------------------------------------------- + # proceed the calculation by use of the regular representation matrices (given by Ivan Marin) + # or in case of more than 4 strands by extension of the finite sub basis + # --------------------------------------------------------------------------------------------------- + + if n > 3 and (n in braid_tietze or -n in braid_tietze) : # more than four strands + # --------------------------------------------------------------------------------------------------- + # matrices for the regular representation are at the moment just available in the case of less than + # five strands. In the higher cases the basis is realized to grow up from the basis on 4 strands + # to use the recursion, only those cubic braids are stored as new basis elements if they involve + # the generator with largest index + # --------------------------------------------------------------------------------------------------- + return self._braid_image_by_basis_extension(braid_tietze) + + + word_left, word_result, word_right = word_decomposition + + result_vect = None + + if word_left != None: + # -------------------------------------------------------------------------------------- + # Operating from the left on the precalculated result + # -------------------------------------------------------------------------------------- + + vect = result.to_vector() + braid_preimage = tuple(word_result) + result_vect = self._mult_by_regular_rep(vect, tuple(word_left), RepresentationType.RegularLeft, braid_preimage) + + if word_right != None: + # -------------------------------------------------------------------------------------- + # Operating from the right on the precalculated result + # -------------------------------------------------------------------------------------- + if result_vect != None: + vect = result_vect + braid_preimage = tuple(word_left + word_result) + else: + vect = result.to_vector() + braid_preimage = tuple(word_result) + result_vect = self._mult_by_regular_rep(vect, tuple(word_right), RepresentationType.RegularRight, braid_preimage) + + result = self.from_vector(result_vect) + + return result + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_from_former_calculations + # ------------------------------------------------------------------------------------------------------------- + def _braid_image_from_former_calculations(self, braid_tietze): + r""" + Return the image of a braid in ``self`` as far as this can be done by use of former calculations and is sure not to + go into an endless recursion, that is + + - using the cubic Hecke subalgebra on one strand less + - using the file cache. + + If the image can not be calculated from former registered results this method returns None. + Therefore, it is just intended to be used as as step in the complete calculation. + + INPUT: + + - ``braid_tietze`` -- tuple representing the Braid whose image in ``self`` should be computed. The generator + exponents in the braid word are assumed to be 1 or -1 + + OUTPUT: + + A pair (image, basis_factors) where result is an element of ``self`` representing the image of the input if calculation + was possible and None else-wise. If image == None the output basis_factors is given as a list of basis element whose + product equals the input. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3._braid_image_from_former_calculations((1, -2, 1)) + (c0*c1^-1*c0, None) + sage: CHA3._braid_image_from_former_calculations((1, -2, 1, 2)) + (c0*c1^-1*c0, ([], [1, -2, 1], [2])) + """ + + n = self.ngens() + braid_list = list(braid_tietze) + len_braid = len(braid_list) + + result = None + + # --------------------------------------------------------------------------------------------------- + # if the braid is in the basis take its image to be the corresponding monomial + # --------------------------------------------------------------------------------------------------- + result = self._tietze_to_finite_sub_basis_monomial(braid_tietze) + if result is not None: + return result, None + + # --------------------------------------------------------------------------------------------------- + # if the braid lies in a subalgebra take its image from there + # --------------------------------------------------------------------------------------------------- + SubAlg = self.cubic_hecke_subalgebra() + if n not in braid_list and -n not in braid_list: + + result = self(SubAlg(braid_tietze)) + verbose("End (%s): %s in smaller algebra" %(braid_list, result) ) + return result, None + + # --------------------------------------------------------------------------------------------------- + # proceed the calculation by splitting self into a product of basis elements and try to simplify + # --------------------------------------------------------------------------------------------------- + braid_group = self.braid_group() + braid = braid_group(braid_tietze) + result = self._braid_image_from_filecache(braid) + if result != None: + + verbose("End from file cache (%s)" %(list(braid_tietze))) + return result, None + + + # --------------------------------------------------------------------------------------------------- + # If we come here len_braid must be larger than 1 (otherwise we already have found in in the basis) + # By recursion we check if the subwords with one generator removed on the left (respectively on the + # right) side contain a subword whose image has already been calculated. We choose the longest + # such subword as our result + # --------------------------------------------------------------------------------------------------- + braid_list_red_left = [braid_tietze[j] for j in range(1 , len_braid)] + braid_list_red_right = [braid_tietze[j] for j in range(len_braid-1 )] + + result_left, word_decomp_left = self._braid_image_from_former_calculations(tuple(braid_list_red_left)) + result_right, word_decomp_right = self._braid_image_from_former_calculations(tuple(braid_list_red_right)) + if word_decomp_left == None: + return result_left, ([braid_tietze[0 ]], braid_list_red_left, []) + + if word_decomp_right == None: + return result_right, ([], braid_list_red_right, [braid_tietze[len_braid-1 ]]) + + word_decomp_left_left, word_decomp_left_result, word_decomp_left_right = word_decomp_left + word_decomp_right_left, word_decomp_right_result, word_decomp_right_right = word_decomp_right + + if len(word_decomp_left_result) >= len(word_decomp_right_result): + return result_left, ([braid_tietze[0 ]] + word_decomp_left_left, word_decomp_left_result, word_decomp_left_right) + else: + return result_right, (word_decomp_right_left, word_decomp_right_result, word_decomp_right_right + [braid_tietze[len_braid-1 ]]) + + + + + # ------------------------------------------------------------------------------------------------------------- + # _braid_image_by_basis_expansion_ + # ------------------------------------------------------------------------------------------------------------- + def _braid_image_by_basis_extension(self, braid_tietze): + r""" + Return the given braid as a new basis element of ``self`` expanding the incomplete order (which is just a part + of the whole basis) in the case of more than 4 strands. + + INPUT: + + - ``braid_tietze`` -- tuple representing the Braid whose image in ``self`` should be computed. The generator + exponents in the braid word are assumed to be 1 or -1 + + OUTPUT: + + An instance of the element class of ``self``. + + EXAMPLES:: + + sage: CHA5 = algebras.CubicHecke(5) + sage: basis_extensions = CHA5.select_filecache_section().basis_extensions + sage: CHA5.reset_filecache(basis_extensions) + sage: CHA5._basis_extension + [[4], [-4]] + sage: CHA5._braid_image_by_basis_extension((4,1)) + c3*c0 + sage: CHA5._basis_extension + [[4], [-4], [4, 1]] + + case where the braid already has an corresponding basis element:: + + sage: CHA5._braid_image_by_basis_extension((1,)) + c0 + sage: CHA5._basis_extension + [[4], [-4], [4, 1]] + + case where the braid doesn't have corresponding basis element but depends on them:: + + sage: CHA5._braid_image_by_basis_extension((1,1)) + Traceback (most recent call last): + ... + NotImplementedError: no algorithm available to calculate braid image of (1, 1) + + """ + cubic_braid = self._cubic_braid_group(braid_tietze) + tup = self._cubic_braid_basis_tuple(cubic_braid) + if tup is not None: + bgrp = self.braid_group() + if bgrp(braid_tietze) != bgrp(tup): + raise NotImplementedError("no algorithm available to calculate braid image of %s" %(str(braid_tietze))) + B = self.basis() + verbose("braid-image %s in Basis" %(str(braid_tietze))) + return self.monomial(B[cubic_braid]) + + return self._cubic_braid_append_to_basis(cubic_braid) + + + + + + + + + + + # ------------------------------------------------------------------------------------------------------------- + # _reduce_all_gen_powers + # ------------------------------------------------------------------------------------------------------------- + def _reduce_all_gen_powers(self, braid_tietze): + r""" + Return a linear combination of braids that have no higher powers in the braid generators having the same + image in ``self`` than the given braid. This linear combination is returned as a pair of lists of braids + and corresponding coefficients. + + INPUT: + + - ``braid_tietze`` -- tuple representing the Braid whose powers should be reduced given in Tietze form + + OUTPUT: + + A pair of two lists: ``coeffs``, ``braids``. The fist one contains the coefficients corresponding to the braids + in Tietze form from the second list of braids. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3._reduce_all_gen_powers((1, 1, -2, -2)) + ([(w^-1)*u*v, (-w^-1)*v, (-w^-1)*v^2, (-w^-1)*u^2, (w^-1)*u, (w^-1)*u*v, -u, 1, v], + [(), (2,), (-2,), (1,), (1, 2), (1, -2), (-1,), (-1, 2), (-1, -2)]) + """ + + + braid_list = list(braid_tietze) + len_braid = len(braid_list) + + # ------------------------------------------------------------------------------------------------------------ + # find a higher power position in braid_list + # ------------------------------------------------------------------------------------------------------------ + power=0 + pos =0 + for i in range(len_braid-1 ): + if braid_list[i] != braid_list[i+1 ]: + continue + pos = i + for power in range(1 ,len_braid -pos+1 ): + if pos+power == len_braid: + break + if braid_list[pos] != braid_list[pos+power]: + break + break + + if power == 0 : + verbose("End (%s) no powers" %(braid_list)) + return [self.base_ring().one()], [braid_tietze] + + # ------------------------------------------------------------------------------------------------------------ + # eliminate this power from braid_tietze + # ------------------------------------------------------------------------------------------------------------ + val = braid_list[pos] + if val > 0 : + gen_ind = val + exp = power + else: + gen_ind = -val + exp = -power + + braid_list_start = [braid_list[i] for i in range(pos)] + braid_list_end = [braid_list[i] for i in range(pos+power, len_braid)] + + # ---------------------------------------------------------------------------------------- + # merging the new reduced tuple. Note that all the new tuples are smaller than the + # given one, which will make the recursion terminate + # ---------------------------------------------------------------------------------------- + tuple_one = tuple(braid_list_start + braid_list_end) + tuple_gen = tuple(braid_list_start + [gen_ind] + braid_list_end) + tuple_gen_inv = tuple(braid_list_start + [-gen_ind] + braid_list_end) + + # ---------------------------------------------------------------------------------------- + # convert them to braids (to reduce cancellation of inverses and obvious braid relations) + # Note that this will not increase the length of the word. Thus the recursion still must + # terminate + # ---------------------------------------------------------------------------------------- + braid_group = self.braid_group() + braid_one = braid_group(tuple_one) + braid_gen = braid_group(tuple_gen) + braid_gen_inv = braid_group(tuple_gen_inv) + + # ------------------------------------------------------------------------------------------------------------ + # eliminate all powers from braid_tietze by recursion. The recursion will terminate by the length + # reduction of the Tietze tuple (but not necessarily by the number of generators whose exponent + # must be reduced) + # ------------------------------------------------------------------------------------------------------------ + one_coeffs, one_braids = self._reduce_all_gen_powers(braid_one.Tietze()) + gen_coeffs, gen_braids = self._reduce_all_gen_powers(braid_gen.Tietze()) + gen_inv_coeffs, gen_inv_braids = self._reduce_all_gen_powers(braid_gen_inv.Tietze()) + + cf_one, cf_gen, cf_gen_inv = self._reduce_gen_power(exp) + + one_coeffs = [ cf*cf_one for cf in one_coeffs ] + gen_coeffs = [ cf*cf_gen for cf in gen_coeffs ] + gen_inv_coeffs = [ cf*cf_gen_inv for cf in gen_inv_coeffs ] + + return one_coeffs + gen_coeffs + gen_inv_coeffs, one_braids + gen_braids + gen_inv_braids + + + + + # ------------------------------------------------------------------------------------------------------------- + # _reduce_gen_power + # ------------------------------------------------------------------------------------------------------------- + @cached_method + def _reduce_gen_power(self, k): + r""" + Return the k-th power on an arbitrary generator, for example c0^k. + + + INPUT: + + - ``k`` -- integer giving the power + + OUTPUT: + + A list [coeff_one, coeff_gen, coeff_gen_inverse] of the three coefficients of the generators power in the span of the generator. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._reduce_gen_power(5) + (-u^3*v + 2*u*v^2 + w*u^2 + (-2*w)*v, u^4 + (-3)*u^2*v + + v^2 + 2*w*u, w*u^3 + (-2*w)*u*v + w^2) + """ + + + n = self.ngens() + + # --------------------------------------------------------------------------------------- + # take it from smaller subalgebras if possible + # --------------------------------------------------------------------------------------- + if n > 1 : + + SubAlg = self.cubic_hecke_subalgebra() + return SubAlg._reduce_gen_power(k) + + + # --------------------------------------------------------------------------------------- + # calculate it in the subalgebra on 2 strands + # --------------------------------------------------------------------------------------- + + if k == 0 : + + result_ele = self.one() + result = result_ele.to_vector() + + elif abs(k) == 1 : + + result_ele = self._tietze_to_finite_sub_basis_monomial(tuple([k])) + result = result_ele.to_vector() + + else: + + if k < 0 : + right_vect = self._reduce_gen_power(k+1) + genTietze = (-1 ,) + else: + right_vect = self._reduce_gen_power(k-1) + genTietze = (1 ,) + + result = self._mult_by_regular_rep(right_vect, genTietze, RepresentationType.RegularLeft) + + return result + + + + + # ------------------------------------------------------------------------------------------------------------- + # _mult_by_regular_rep + # ------------------------------------------------------------------------------------------------------------- + def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preimage=None): + r""" + Return the product of an`element of ``self`` given as a coefficient vector with a sequence (tuple) of generators + (that is a braid word) using regular representation matrices. The multiplication will be performed form left or + right according to the given ``representation_type``. + + INPUT: + + - ``vect`` -- element of ``self`` in vector form (obtained by :meth:`to_vector`) + - ``gen_tuple`` -- list of generators (that is a braid in Tietze form) which operates on ``vect`` + - ``representation_type`` -- instance of :class:`RepresentationType` (one of `RegularLeft` or `RegularRight`) + - ``braid_preimage`` -- (optional) a word representing a braid whose image is vect (if it exist). + This is used to record intermediate results to the dynamic library + + + OUTPUT: + + The coefficient vector resulting after applying the multiplication of all matrices corresponding to the + generators from gen_tuple. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: CHA3.inject_variables() + Defining c0, c1 + sage: CHA3._mult_by_regular_rep(c0.to_vector(), (1, -2, -2), CHA3.repr_type.RegularRight) + ((w^-1)*u*v, (-w^-1)*u^2, -u, (-w^-1)*v, (-w^-1)*v^2, (w^-1)*u, (w^-1)*u*v, 1, v, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + """ + verbose("Multiply %s (preimage %s) by %s using %s" %(vect, braid_preimage, gen_tuple, representation_type)) + l = len(gen_tuple) + braid_list = None + if braid_preimage: + braid_list = list(braid_preimage) + + result = vect + for i in range(l): + verbose("Multiply image of %s with position %s" %(braid_list, i)) + + if representation_type == RepresentationType.RegularLeft: + gen_ind = gen_tuple[l-i-1 ] + if braid_list: + braid_list = [gen_ind] + braid_list + else: + gen_ind = gen_tuple[i] + if braid_list: + braid_list = braid_list + [gen_ind] + + if (gen_ind, representation_type) in list(self._gens_reg_repres_matrix.keys()): + mat = self._gens_reg_repres_matrix[(gen_ind, representation_type)] + else: + if gen_ind > 0 : + gen = self.gen(gen_ind-1 ) + mat = gen.matrix(representation_type=representation_type) + else: + # data of inverse of generators is stored under negative strand-index + gen = self.gen(-gen_ind-1 )**(-1 ) + mat = gen.matrix(representation_type=representation_type) + + self._gens_reg_repres_matrix[(gen_ind, representation_type)] = mat + + result = mat * result + + # ---------------------------------------------------------------------------------- + # save this intermediate result to the dynamic library + # ---------------------------------------------------------------------------------- + if braid_list: + verbose("Save image of %s to file cache" %braid_list) + self._braid_image_to_filecache(tuple(braid_list), result) + + verbose("Multiply %s by %s using %s result %s" %(vect, gen_tuple, representation_type, result)) + return result + + + # ------------------------------------------------------------------------------------------------------------- + # _cubic_braid_append_to_basis + # ------------------------------------------------------------------------------------------------------------- + def _cubic_braid_append_to_basis(self, cubic_braid): + r""" + Append the given cubic braid to the finite sub basis which is used for calculation of products + and representation matrices. This only makes sense if the ``cubic_braid`` is not in this + finite sub basis, before. This can happen if the number of strands is more than 4. + + INPUT: + + - ``cubic_braid`` -- instance of the :class:`~sage.groups.cubic_braid.CubicBraid` whose image in ``self`` should be appended + + OUTPUT: + + The new monomial of ``self``. + + EXAMPLES:: + + sage: CHA5 = algebras.CubicHecke(5) + sage: basis_extensions = CHA5.select_filecache_section().basis_extensions + sage: CHA5.reset_filecache(basis_extensions) + sage: CHA5._basis_extension + [[4], [-4]] + sage: CBG = CHA5.cubic_braid_group() + sage: CHA5._cubic_braid_append_to_basis(CBG((4,1))) + c3*c0 + sage: CHA5._basis_extension + [[4], [-4], [4, 1]] + + """ + cbTietze = list(cubic_braid.Tietze()) + order = self.get_order() + next_index = len(order) + self._basis_extension.append(cbTietze) + self._rank_basis.update({cubic_braid:next_index}) # supporting :meth:`get_order_key` + order.append(cubic_braid) + monomial = self.monomial(cubic_braid) + self._finite_sub_basis_tuples.update({cubic_braid:cbTietze}) + + verbose("Registering new basis element: %s (par %s ind %s)" %(cubic_braid, cubic_braid.parent(), next_index)) + self._filecache.update_basis_extensions(self._basis_extension) + return monomial + + + + # ------------------------------------------------------------------------------------------------------------- + # _cubic_braid_basis_tuple + # ------------------------------------------------------------------------------------------------------------- + def _cubic_braid_basis_tuple(self, cubic_braid): + r""" + Return the Tietze tuple that represents the given cubic_braid in the basis of ``self``. In the case ``self`` + has more than 4 strands it may happen that the given cubic braid is not contained in the finite sub basis, so far. + In this case it is automatically added to it. + + INPUT: + + - ``cubic_braid`` -- instance of the :class:`~sage.groups.cubic_braid.CubicBraid` + + OUTPUT: + + A tuple from the basis representing the cubic braid. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CBG = CHA2.cubic_braid_group() + sage: CHA2._cubic_braid_basis_tuple(CBG((1,1))) + (-1,) + """ + tietze_list = self._basis_tietze() + cubic_braid_tietze = cubic_braid.Tietze() + if list(cubic_braid_tietze) in tietze_list: + verbose("cubic_braid_tietze: %s in basis" %(str(cubic_braid_tietze))) + return cubic_braid_tietze + else: + if cubic_braid in self._finite_sub_basis_tuples.keys(): + verbose("cubic_braid: %s in finite_sub_basis" %(cubic_braid)) + return self._finite_sub_basis_tuples[cubic_braid] + + for tup in tietze_list: + cb_tup = self.cubic_braid_group()(tup) + if cubic_braid == cb_tup: + self._finite_sub_basis_tuples.update({cb_tup:tup}) + verbose("cubic_braid: %s added to finite_sub_basis with tuple %s" %(cubic_braid, tup)) + return tuple(tup) + return None + + + # ------------------------------------------------------------------------------------------------------------- + # _cubic_braid_image + # ------------------------------------------------------------------------------------------------------------- + def _cubic_braid_image(self, cubic_braid, check=True): + r""" + Return the given cubic braid as monomial of ``self``, that is the image under the map onto the basis. + If the number of strands is larger than 4, the corresponding basis element may not be + contained in the order of ``self``. In this case it will be appended here. + + INPUT: + + - ``cubic_braid`` -- instance of :class:`~sage.groups.cubic_braid.CubicBraid` whose image in ``self`` should be returned + - ``check`` -- (optional) boolean (default=True) to check in the given cubic braid is already + registered in the finite sub basis. If set to ``False`` duplicate entries can occur. + + OUTPUT: + + Instance of the element class of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CBG = CHA2.cubic_braid_group() + sage: CHA2._cubic_braid_image(CBG((1,1))) + c^-1 + """ + if check: + tup = self._cubic_braid_basis_tuple(cubic_braid) + if tup is not None: + return self._tietze_to_finite_sub_basis_monomial(tup) + + return self._cubic_braid_append_to_basis(cubic_braid) + + + + # ------------------------------------------------------------------------------------------------------------- + # _extend_braid_automorphism + # ------------------------------------------------------------------------------------------------------------- + def _extend_braid_automorphism(self, element, braid_automorphism): + r""" + Return the image of element under the extension of the given braid group automorphism to ``self``. It is assumed + that the given ``braid_automorphism`` factors through ``self``. + + INPUT: + + - ``element`` -- instance of the element class of ``self`` + - ``braid_autompophism`` -- braid group automophism factoring through ``self`` + + OUTPUT: + + Instance of the element class of ``self`` representing the image of element under the extension of the given braid + group automorphism. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: br, = CHA2.gens() + sage: CHA2.mirror_isomorphism(br) # indirect doctest + c^-1 + """ + + result = self.zero() + for braid in element.support(): + autom_braid = braid_automorphism(braid) + img_braid = self._braid_image_from_reduced_powers(autom_braid.Tietze()) + result += element[braid] * img_braid + + return result + + + + + ####################################################################################################################### + # --------------------------------------------------------------------------------------------------------------------- + # public methods + # --------------------------------------------------------------------------------------------------------------------- + + ####################################################################################################################### + + def select_filecache_section(self): + r""" + Return the enum to select a section in the file cache. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: list(CHA2.select_filecache_section()) + [, + , + ] + """ + return self._filecache.section + + def is_filecache_empty(self, section=None): + r""" + Return ``True`` if the file cache of the given ``section`` is empty. If no ``section`` is given + the answer is given for complete file cache. + + INPUT: + + - ``section`` -- (optional, default is ``None`` meaning all sections) instance of enum + :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` which can be selected using :meth:`select_filecache_section` + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.is_filecache_empty() + False + """ + return self._filecache.is_empty(section=section) + + def reset_filecache(self, section=None, commit=True): + r""" + Reset the file cache of the given ``section`` resp. the complete file cache if no ``section`` is given. + + INPUT: + + - ``section`` -- (optional, default is ``None`` meaning all sections) instance of enum + :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` which can be selected using :meth:`select_filecache_section` + + - ``commit`` -- boolean (optional, default is ``True``) if set to ``False`` the reset is not written + to the filesystem. + + + EXAMPLES:: + + sage: CHA5 = algebras.CubicHecke(5) + sage: basis_extensions = CHA5.select_filecache_section().basis_extensions + sage: CHA5.is_filecache_empty(basis_extensions) + False + sage: CHA5.reset_filecache(basis_extensions) + sage: CHA5.is_filecache_empty(basis_extensions) + True + """ + fc = self._filecache + if section == fc.section.basis_extensions: + if self.strands() < 5: + raise ValueError('not allowed for less than 5 strand') + + fc.reset_library(section=section) + + if section == fc.section.basis_extensions: + self._init_basis_extension() + + if commit: + fc.write(section=section) + + def strands(self): + r""" + Return the number of strands of the braid group whose group algebra image is ``self`` + + OUTPUT: Integer. + + EXAMPLES:: + + sage: CHA4 = algebras.CubicHecke(4) + sage: CHA4.strands() + 4 + """ + return self._nstrands + + # ------------------------------------------------------------------------------------------------------------- + # Garside involution + # ------------------------------------------------------------------------------------------------------------- + def garside_involution(self, element): + r""" + Return the image of the given element of ``self`` under the extension of the Garside involution of braids to ``self``. + + This method may be invoked by the ``revert_garside`` method of the element class of ``self``, alternatively. + + INPUT: + + - ``element`` -- instance of the element class of ``self`` + + OUTPUT: + + Instance of the element class of ``self`` representing the image of ``element`` under the extension of the Garside + involution to ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element() + sage: ele_gar = CHA3.garside_involution(ele); ele_gar + ((w^-1)*u-v) + v*c1 + u*c0 + (-w)*c1*c0^-1 + sage: ele == CHA3.garside_involution(ele_gar) + True + """ + + braid_group = self.braid_group() + reverse_gens = [ g for g in braid_group.gens()] + reverse_gens.reverse() + brgrp_garside_involution = braid_group.hom(reverse_gens, check=False) + + return self._extend_braid_automorphism(element, brgrp_garside_involution) + + + + + + # ------------------------------------------------------------------------------------------------------------- + # orientation anti involution + # ------------------------------------------------------------------------------------------------------------- + def orientation_antiinvolution(self, element): + r""" + Return the image of the given element of ``self`` under the extension of the orientation anti involution of braids to ``self``. + The orientation anti involution of a braid is given by reversing the order of generators in the braid word. + + This method may be invoked by the ``revert_orientation`` method of the element class of ``self``, alternatively. + + INPUT: + + - ``element`` -- instance of the element class of ``self`` + + OUTPUT: + + Instance of the element class of ``self`` representing the image of ``element`` under the extension of the orientation + reversing braid involution to ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element() + sage: ele_ori = CHA3.orientation_antiinvolution(ele); ele_ori + ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c1^-1*c0 + sage: ele == CHA3.orientation_antiinvolution(ele_ori) + True + """ + + braid_group = self.braid_group() + def brgrp_orientation_antiinvolution(braid): + braid_list = list(braid.Tietze()) + braid_list.reverse() + return braid_group(tuple(braid_list)) + + return self._extend_braid_automorphism(element, brgrp_orientation_antiinvolution) + + + + # ------------------------------------------------------------------------------------------------------------- + # mirror isomorphism + # ------------------------------------------------------------------------------------------------------------- + def mirror_isomorphism(self, element): + r""" + Return the image of the given element of ``self`` under the extension of the mirror involution of braids to ``self``. + The mirror involution of a braid is given by inverting all generators in the braid word. It does not + factor through ``self`` over the base ring but it factors through ``self`` considered as a $\ZZ$-module relative to the + mirror automorphism of the generic base ring. Considering ``self`` as algebra over its base ring this involution + defines an isomorphism of ``self`` onto a different cubic Hecke algebra with a different cubic equation. This + is defined over a different base (and extension) ring than ``self``. It can be obtained by the method ``mirror_image`` + or as parent of the output of this method. + + This method may be invoked by the ``CubicHeckeElelemnt.revert_mirror`` method of the element class of ``self``, alternatively. + + INPUT: + + - ``element`` -- instance of the element class of ``self`` + + OUTPUT: + + Instance of the element class of the mirror image of ``self`` representing the image of element under the extension of + the braid mirror involution to ``self``. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ele = CHA3.an_element() + sage: ele_mirr = CHA3.mirror_isomorphism(ele); ele_mirr + ((-w^-1)*u+v) + ((w^-1)*v)*c1^-1 + ((w^-1)*u)*c0^-1 + (-w^-1)*c0^-1*c1 + sage: ele_mirr2 = ele.revert_mirror() # indirect doctest + sage: ele_mirr == ele_mirr2 + True + sage: par_mirr = ele_mirr.parent() + sage: par_mirr == CHA3 + False + sage: par_mirr == CHA3.mirror_image() + True + sage: ele == par_mirr.mirror_isomorphism(ele_mirr) + True + """ + + mirror_image = self.mirror_image() + braid_group = self.braid_group() + mirror_involution = braid_group.hom([~g for g in braid_group.gens()], check=False) + # Todo: have mirror_involution be a method of :class:`BraidGroup_class` + base_ring_mirror = self._base_ring_mirror + element_vec = vector( [base_ring_mirror(cf) for cf in list(element.to_vector())]) + element_mirr = mirror_image.from_vector(element_vec) + return mirror_image._extend_braid_automorphism(element_mirr, mirror_involution) + + + + + def cubic_equation(self, var='h', as_coefficients=False, generic=False): + r""" + Return the cubic equation attached to ``self``. + + INPUT: + + - ``var`` -- string (optional, default ``h``) setting the indeterminate of the equation + - ``as_coefficients`` -- boolean (optional, default ``False``) if set to ``True`` the + list of coefficients is returned + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the cubic + equation will be given over the generic base ring + + OUTPUT: + + A polynomial over the base ring (resp. generic base ring if ``generic`` is set to True). + In case ``as_coefficients`` is set to ``True`` a list of them is returned. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (E(3), ~E(3), 1)) + sage: CHA2.cubic_equation() + h^3 - 1 + sage: CHA2.cubic_equation(generic=True) + h^3 - u*h^2 + v*h - w + sage: CHA2.cubic_equation(as_coefficients=True, generic=True) + [-w, v, -u, 1] + sage: CHA2.cubic_equation(as_coefficients=True) + [-1, 0, 0, 1] + """ + + BaseRing = self.base_ring(generic=generic) + + if generic == True: + u, v, w = BaseRing.gens_over_ground() + else: + u, v, w = self._cubic_equation_parameters + + cf = [-w, v, -u, 1 ] + + if as_coefficients == True: + return cf + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + P = PolynomialRing(BaseRing, var) + return P(cf) + + + + + def cubic_equation_roots(self, generic=False): + r""" + Return the roots of the underlying cubic equation. + + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the roots + are returned as elements of the generic extension ring + + OUTPUT: + + A tripple consisting of the roots. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.cubic_equation() + h^3 - 12*h^2 + 47*h - 60 + sage: CHA2.cubic_equation_roots() + [3, 4, 5] + sage: CHA2.cubic_equation_roots(generic=True) + [a, b, c] + """ + if generic == True: + return self._generic_cubic_equation_roots + else: + return self._cubic_equation_roots + + def cubic_equation_parameters(self, generic=False): + r""" + Return the coefficients of the underlying cubic equation. + + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the coefficients + are returned as elements of the generic base ring + + OUTPUT: + + A tripple consisting of the coefficients. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.cubic_equation() + h^3 - 12*h^2 + 47*h - 60 + sage: CHA2.cubic_equation_parameters() + [12, 47, 60] + sage: CHA2.cubic_equation_parameters(generic=True) + [u, v, w] + """ + if generic == True: + return self._generic_cubic_equation_parameters + else: + return self._cubic_equation_parameters + + def base_ring(self, generic=False): + r""" + Return the base ring of the cubic Hecke algebra. + + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the + ring of definition (here often called the generic base ring) is returned + + OUTPUT: + + An instance of :class:`Ring`. If ``generic`` is set ``True`` this will be an + instance of :class:`CubicHeckeRingOfDefinition`, as well. + + EXAMMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.base_ring() + Integer Ring localized at (2, 3, 5) + sage: CHA2.base_ring(generic=True) + Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + """ + if generic == True: + return self._ring_of_definition + else: + return self._base_ring + + + def extension_ring(self, generic=False): + r""" + Return the extension ring of the cubic Hecke algebra. This is an extension + of its base ring containing the roots of the cubic equation. + + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the + extension ring of definition (here often called the generic extension ring) + is returned + + OUTPUT: + + An instance of :class:`Ring`. If ``generic`` is set ``True`` this will be an + instance of :class:`CubicHeckeExtensionRing`, as well. + + EXAMMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.extension_ring() + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Integer Ring localized at (2, 3, 5) + sage: CHA2.extension_ring(generic=True) + Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] over Integer Ring + """ + if generic == True: + return self._generic_extension_ring + else: + return self._extension_ring + + + def cyclotomic_generator(self, generic=False): + r""" + Return the third root of unity as element of the extension ring. + INPUT: + + - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the + cyclotomic_generator is returned as an element extension ring of definition. + + OUTPUT: + + An element with parent :class:`Ring`. If ``generic`` is set ``True`` the parent will be an + instance of :class:`CubicHeckeExtensionRing`, as well. + + EXAMMPLES:: + + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2.cyclotomic_generator() + E3 + sage: CHA2.cyclotomic_generator(generic=True) + e3 + """ + e3gen = self.extension_ring(generic=True).cyclotomic_generator() + if generic == True: + return e3gen + else: + return self._generic_extension_ring_map(e3gen) + + + + + + def braid_group(self): + r""" + Return the braid group attached to ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.braid_group() + Braid group on 2 strands + """ + return self._braid_group + + + def cubic_braid_group(self): + r""" + Return the cubic braid group attached to ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.cubic_braid_group() + Cubic Braid group on 2 strands + """ + return self._cubic_braid_group + + + def braid_group_algebra(self): + r""" + Return the group algebra of braid group attached to ``self`` over the base ring of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.braid_group_algebra() + Algebra of Braid group on 2 strands + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + """ + return self._braid_group_algebra + + + def cubic_braid_group_algebra(self): + r""" + Return the group algebra of cubic braid group attached to ``self`` over the base ring of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2.cubic_braid_group_algebra() + Algebra of Cubic Braid group on 2 strands + over Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w over Integer Ring + """ + return self._cubic_braid_group_algebra + + + + + # ---------------------------------------------------------------------------------- + # creating a CubicHeckeAlgebra as subalgebra of self on less strands + # ---------------------------------------------------------------------------------- + def cubic_hecke_subalgebra( self, nstrands = None): + r""" + Return an instance of :class:`CubicHeckeAlgebra` which realizes a subalgebra of ``self`` on the + first ``n_strands`` strands. + + INPUT: + + - ``nstrands`` -- integer ``> 0`` and `` < self.strands()`` giving the number of strands for the subgroup. + The default is one strand less than ``self`` has + + OUTPUT: + + An instance of this class realizing the subalgebra. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3, cubic_equation_roots = (3, 4, 5)) + sage: CHA3.cubic_hecke_subalgebra() + Cubic Hecke algebra on 2 strands + over Integer Ring localized at (2, 3, 5) + with cubic equation: h^3 - 12*h^2 + 47*h - 60 = 0 + """ + + if nstrands == None: + nstrands = self.strands() -1 + + n = self.strands() + + nstrands = ZZ(nstrands) + + if nstrands >= n or nstrands <= 0 : + raise ValueError( "nstrands must be positive and less than %s" %(self.strands()) ) + + + + Gens = self.gens() + + if nstrands == self.strands() -1 and self._cubic_hecke_subalgebra != None: + return self._cubic_hecke_subalgebra + + gen_range = range(nstrands -1 ) + + GensRed = tuple([Gens[i] for i in gen_range]) + + SubHeckeAlg = CubicHeckeAlgebra(names=GensRed, cubic_equation_parameters=tuple(self._cubic_equation_parameters), + cubic_equation_roots=tuple(self._cubic_equation_roots)) + + if nstrands == self.strands() -1 : + self._cubic_hecke_subalgebra = SubHeckeAlg + + return SubHeckeAlg + + + + + # ------------------------------------------------------------------------------------------------------------- + # mirror image + # ------------------------------------------------------------------------------------------------------------- + def mirror_image(self): + r""" + Return a copy of ``self`` with the mirrored cubic equation, that is: the cubic equation has the + inverse roots to the roots with respect to ``self``. This is needed since the mirror involution of the braid + group does not factor through ``self`` (considered as an algebra over the base ring, just considered as ZZ-algebra). + Therefore, the mirror involution of an element of ``self`` belongs to ``mirror_image``. + + OUTPUT: + + An instance of the class of ``self`` over the same base and extension ring, but whose cubic equation is transformed + by the mirror involution applied to its coefficients resp. roots. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: ce = CHA2.cubic_equation(); ce + h^3 - u*h^2 + v*h - w + sage: CHA2m = CHA2.mirror_image() + sage: cem = CHA2m.cubic_equation(); cem + h^3 + ((-w^-1)*v)*h^2 + ((w^-1)*u)*h - w^-1 + sage: mi = CHA2.base_ring().mirror_involution(); mi + Ring endomorphism of Multivariate Polynomial Ring in u, v + over Univariate Laurent Polynomial Ring in w + over Integer Ring + Defn: u |--> (w^-1)*v + v |--> (w^-1)*u + with map of base ring + sage: cem == cem.parent()([mi(cf) for cf in ce.coefficients()]) + True + + Note, that both cubic Hecke algebras have the same ring of definition and identical generic cubic equation:: + + sage: CHA2.cubic_equation(generic=True) == CHA2m.cubic_equation(generic=True) + True + sage: CHA2.cubic_equation() == CHA2m.cubic_equation(generic=True) + True + sage: CHA2.cubic_equation_roots() == CHA2m.cubic_equation_roots(generic=True) + True + sage: a, b, c = CHA2.cubic_equation_roots() + sage: CHA2m.cubic_equation_roots() + [(w^-1)*a^2 + ((-w^-1)*u)*a + (w^-1)*v, + ((-w^-1)*a)*b + (-w^-1)*a^2 + ((w^-1)*u)*a, ((w^-1)*a)*b] + sage: ai, bi, ci = _ + sage: ai == ~a, bi == ~b, ci == ~c + (True, True, True) + sage: CHA2.extension_ring(generic=True).mirror_involution() + Ring endomorphism of Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] over Integer Ring + Defn: a |--> a^-1 + b |--> b^-1 + c |--> c^-1 + with map of base ring + + the mirror image can not be obtained for specialized cubic Hecke algebras if the specialization does not factor through + the mirror involution on the ring if definition:: + + sage: CHA2s = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)); CHA2s + Cubic Hecke algebra on 2 strands + over Integer Ring localized at (2, 3, 5) + with cubic equation: h^3 - 12*h^2 + 47*h - 60 = 0 + + In the next example it isn't clear what the mirror image of ``7`` should be:: + + sage: CHA2s.mirror_image() + Traceback (most recent call last): + ... + RuntimeError: base ring Integer Ring localized at (2, 3, 5) + does not factor through mirror involution + """ + + base_ring = self.base_ring() + base_gen = self.base_ring(generic=True) + + base_gen_mirror = base_gen.mirror_involution() + base_ring_mirror = self._base_ring_mirror + if not base_ring_mirror: + mirr_paras_gen = [base_gen_mirror(par) for par in self.cubic_equation_parameters(generic=True)] + mirr_paras = [base_ring(mirr_para) for mirr_para in mirr_paras_gen] + try: + base_ring_mirror = base_ring.hom(mirr_paras) + except (TypeError, ValueError, NotImplementedError): + raise RuntimeError("base ring %s does not factor through mirror involution" %(base_ring)) + + # check for involution + mirr_paras_back = [base_ring_mirror(mirr_para) for mirr_para in mirr_paras] + if mirr_paras_back != self.cubic_equation_parameters(): + raise RuntimeError("base ring %s does not factor through mirror involution" %(base_ring)) + + self._base_ring_mirror = base_ring_mirror + + mirror_image = self._mirror_image + if mirror_image == None: + extension_ring = self.extension_ring() + extension_gen = self.extension_ring(generic=True) + extension_gen_mirror = extension_gen.mirror_involution() + + mirr_paras_gen = [base_gen_mirror(par) for par in self.cubic_equation_parameters(generic=True)] + mirr_roots_gen = [extension_gen_mirror(root) for root in self.cubic_equation_roots(generic=True)] + + mirr_paras = tuple([base_ring(par) for par in mirr_paras_gen]) + mirr_roots = tuple([extension_ring(root) for root in mirr_roots_gen]) + n = self.strands() + + mirror_image = CubicHeckeAlgebra(n, cubic_equation_parameters=mirr_paras, cubic_equation_roots=mirr_roots ) + + # go back by involution property + mirror_image._mirror_image = self + mirror_image._base_ring_mirror = base_ring_mirror + mirror_image._ring_of_definition._mirror_ = base_gen_mirror + mirror_image._is_mirror = True + + self._mirror_image = mirror_image + + return mirror_image + + + + # ------------------------------------------------------------------------------------------------------------- + # Schur elements + # ------------------------------------------------------------------------------------------------------------- + def schur_elements(self, generic=False): + r""" + Return the list of Schur elements of ``self`` as elements + of the extension ring of ``self``. + + This method needs *GAP3* installed with package *CHEVIE* + + INPUT: + + - ``generic`` -- boolean (default False). If set to ``True`` + the element is returned as element of the generic + extension ring + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: sch_eles = CHA3.schur_elements() # optional gap3 + sage: sch_eles[6] # optional gap3 + (w^-1)*u^3 + (w^-2)*v^3 + (-6*w^-1)*u*v + 8 + """ + gap3_result = self.chevie().SchurElements() + GER = self.extension_ring(generic=True) + generic_result = [GER(s) for s in gap3_result] + if generic: + return [s for s in generic_result] + else: + ER = self.extension_ring() + return [ER(s) for s in generic_result] + + + # ------------------------------------------------------------------------------------------------------------- + # Schur element + # ------------------------------------------------------------------------------------------------------------- + def schur_element(self, item, generic=False): + r""" + Return a single Schur element of ``self`` as elements + of the extension ring of ``self``. + + This method needs *GAP3* installed with package *CHEVIE* + + INPUT: + + - ``item`` -- instance of Enum :class:`AbsIrreducibeRep` to give + the irreducible representation of ``self`` to which the Schur + element should be returned + - ``generic`` -- boolean (default False). If set to True + the element is returned as element of the generic + extension ring + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: CHA3.schur_element(CHA3.irred_repr.W3_111) # optional gap3 + (w^-1)*u^3 + (w^-2)*v^3 + (-6*w^-1)*u*v + 8 + """ + if not isinstance(item, AbsIrreducibeRep): + raise ValueError('item must be an instance of %s' %(AbsIrreducibeRep)) + return self.schur_elements(generic=generic)[item.gap_index()] diff --git a/src/sage/algebras/hecke_algebras/matrix_representations/__init__.py b/src/sage/algebras/hecke_algebras/matrix_representations/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py new file mode 100644 index 00000000000..cebfb979f26 --- /dev/null +++ b/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py @@ -0,0 +1,994 @@ +# -*- coding: utf-8 -*- +r""" +Cubic Hecke matrix representations + +This module contains the class :class:`CubicHeckeMatrixRep` which is used to handle the matrix representations of the +elements of the cubic Hecke algebra (:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra`) +together with its parent class :class:`CubicHeckeMatrixSpace`. Furthermore, it contains enums for their +types (:class:`RepresentationType`) and names (:class:`AbsIrreducibeRep`). + + +AUTHORS: + +- Sebastian Oehms May 2020: initial version +""" + + + + +############################################################################## +# Copyright (C) 2020 Sebastian Oehms +# +# 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 enum import Enum +from sage.misc.cachefunc import cached_method +from sage.misc.misc import verbose +from sage.rings.integer import Integer +from sage.matrix.matrix_generic_dense import Matrix_generic_dense +from sage.matrix.matrix_space import MatrixSpace +from sage.matrix.constructor import matrix +from sage.matrix.special import block_diagonal_matrix +from sage.databases.cubic_hecke_db import CubicHeckeDataFilename as fn + + + +# -------------------------------------------------------------------------------------- +# Constants +# -------------------------------------------------------------------------------------- + + +# ------------------------------------------- +# Enum for the generators sign (of exponent) +# ------------------------------------------- +class GenSign(Enum): + r""" + Enum class to select the braid generators sign. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.GenSign.pos + + sage: chmr.GenSign.neg + + """ + pos = 1 + neg = -1 + + + +# ------------------------------------------- +# Enum for typ of matrix representation +# ------------------------------------------- +class RepresentationType(Enum): + r""" + Enum class to select a representation type for the cubic Hecke algebra. + + - ``RegularLeft`` -- left regular representations + - ``RegularRight`` -- right regular representations + - ``SplitIrredMarin`` -- split irreducible representations obtained from Ivan Marin's data + - ``SplitIrredChevie`` -- the split irreducible representations obtained from CHEVIE via the GAP3-interface + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.RepresentationType.RegularLeft.is_regular() + True + """ + def is_split(self): + r""" + Return True if this representation type is absolutely split, False else-wise. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chevie = chmr.RepresentationType.SplitIrredChevie + sage: chevie.is_split() + True + """ + return self.value['split'] + + def is_regular(self): + r""" + Return True if this representation type is regular, False else-wise. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: reg_left = chmr.RepresentationType.RegularLeft + sage: reg_left.is_regular() + True + """ + return self.value['regular'] + + def data_filename(self): + r""" + Return the name of the data file. For more information see :class:`~sage.databases.cubic_hecke_db.CubicHeckeDataBase`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: reg_left = chmr.RepresentationType.RegularLeft + sage: reg_left.data_filename() + + """ + return self.value['data'] + + def number_of_representations(self, nstrands): + r""" + Return the number of representations existing to that type. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.RepresentationType.SplitIrredChevie.number_of_representations(4) + 24 + sage: chmr.RepresentationType.SplitIrredMarin.number_of_representations(4) + 24 + """ + if self.value['data'] == None: + if nstrands < 1 or nstrands > 5 : + raise ValueError( "nstrands must be between 1 and 5" ) + elif nstrands < 1 or nstrands > 4 : + raise ValueError( "nstrands must be between 1 and 4" ) + return self.value['num_rep'][nstrands-1 ] + + + RegularLeft = {'split':False, 'regular':True, 'data':fn.regular_left, 'num_rep':[1 ,1 ,1 ,1 ]} + RegularRight = {'split':False, 'regular':True, 'data':fn.regular_right, 'num_rep':[1 ,1 ,1 ,1 ]} + SplitIrredMarin = {'split':True, 'regular':False, 'data':fn.irred_split, 'num_rep':[1 ,3 ,7 ,24 ]} + SplitIrredChevie = {'split':True, 'regular':False, 'data':None, 'num_rep':[1 ,3 ,7 ,24 ,30 ]} + + + + +class AbsIrreducibeRep(Enum): + r""" + Enum class to select an absolutely irreducible representation for the cubic Hecke algebra (``CHAn``) on n-strands. + + The names are build as follows: Take the determinant of one of the generators of the ``CHAn``. This is a monomial + in the the generic extension ring (``GER``) of ``CHA``, say ``a^ib^jc^k`` where ``a, b`` and ``c`` are the generators + of ``GER``. This does not depend on the choice of the generator of ``CHA``, since these are conjugated to each other. + This monomial might be looked as the weight of the representation. Therefore we use as a name: + + ``Wn_ijk`` + + The only ambiguity among the available irreducible representations occurs for the two nine-dimensional modules, which + are conjugated to each other and distinguished by these names: + + ``W4_333`` and ``W4_333bar`` + + Examples of names: + + - ``W2_100`` -- one dimensional representation of the cubic Hecke algebra on 2 strands corresponding to the first root + of the cubic equation + - ``W3_111`` -- three dimensional irreducible representation of the cubic Hecke algebra on 3 strands + - ``W4_242`` -- eight dimensional irreducible representation of the cubic Hecke algebra on 4 strands having the second + root of the cubic equation as weight of dimension 4 + + + Alternative names are taken from [MW2012]_ and can be shown by :meth:`alternative_name`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: [irr.name for irr in chmr.AbsIrreducibeRep] + ['W2_100', 'W2_001', 'W2_010', 'W3_100', 'W3_001', 'W3_010', 'W3_011', 'W3_110', + 'W3_101', 'W3_111', 'W4_100', 'W4_001', 'W4_010', 'W4_011', 'W4_110', 'W4_101', + 'W4_111', 'W4_120', 'W4_201', 'W4_012', 'W4_102', 'W4_210', 'W4_021', 'W4_213', + 'W4_132', 'W4_321', 'W4_231', 'W4_123', 'W4_312', 'W4_422', 'W4_224', 'W4_242', + 'W4_333', 'W4_333bar', 'W5_100', 'W5_001', 'W5_010', 'W5_013', 'W5_130', 'W5_301', + 'W5_031', 'W5_103', 'W5_310', 'W5_203', 'W5_032', 'W5_320', 'W5_230', 'W5_023', + 'W5_302', 'W5_033', 'W5_330', 'W5_303', 'W5_163', 'W5_631', 'W5_316', 'W5_136', + 'W5_613', 'W5_361', 'W5_366', 'W5_663', 'W5_636', 'W5_933', 'W5_339', 'W5_393'] + + REFERENCES: + + [MW2012]_ + """ + + def alternative_name(self): + r""" + Return the name of the split irreducible representation for cubic Hecke algebras for up to four strands + as given in [MW2012]_. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_011.alternative_name() + 'Tyz' + """ + return self.value['alt_name'] + + def dimension(self): + r""" + Return the dimension of the representation. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_111.dimension() + 3 + """ + return self.value['dim'] + + def number_gens(self): + r""" + Return the number of generators of the underlying cubic Hecke algebra. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_001.number_gens() + 2 + sage: chmr.AbsIrreducibeRep.W4_001.number_gens() + 3 + """ + return self.value['ngens'] + + def length_orbit(self): + r""" + Return the length of the orbit of this representation under the action of the Galois group of the cubic equation. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_001.length_orbit() + 3 + sage: chmr.AbsIrreducibeRep.W3_111.length_orbit() + 1 + """ + return self.value['len_orbit'] + + def gap_index(self): + r""" + Return the array index of this representation for the access in GAP3 CHEVIE. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_111.gap_index() + 6 + """ + return self.value['gap_ind'] + + def internal_index(self): + r""" + Return the array index of this representation for the internal access. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: chmr.AbsIrreducibeRep.W3_111.internal_index() + 6 + """ + return self.value['intern_ind'] + + # ------------------------------------------------------------------------------------------------- + # absolutely irreducible representations corresponding to braids on 2 strands + # ------------------------------------------------------------------------------------------------- + W2_100 = {'alt_name':'Sx', 'dim':1 , 'ngens':1 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } + W2_001 = {'alt_name':'Sz', 'dim':1 , 'ngens':1 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } + W2_010 = {'alt_name':'Sy', 'dim':1 , 'ngens':1 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + + # ------------------------------------------------------------------------------------------------- + # absolutely irreducible representations corresponding to braids on 3 strands + # ------------------------------------------------------------------------------------------------- + W3_100 = {'alt_name':'Sx', 'dim':1 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } + W3_001 = {'alt_name':'Sz', 'dim':1 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } + W3_010 = {'alt_name':'Sy', 'dim':1 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + + W3_011 = {'alt_name':'Tyz', 'dim':2 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 3 , 'intern_ind': 3 } + W3_110 = {'alt_name':'Txy', 'dim':2 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 4 , 'intern_ind': 4 } + W3_101 = {'alt_name':'Txz', 'dim':2 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 5 , 'intern_ind': 5 } + + W3_111 = {'alt_name':'V', 'dim':3 , 'ngens':2 , 'len_orbit':1 , 'gap_ind': 6 , 'intern_ind': 6 } + + # ------------------------------------------------------------------------------------------------- + # absolutely irreducible representations corresponding to braids on 4 strands + # ------------------------------------------------------------------------------------------------- + W4_100 = {'alt_name':'Sx', 'dim':1 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } + W4_001 = {'alt_name':'Sz', 'dim':1 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } + W4_010 = {'alt_name':'Sy', 'dim':1 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + + W4_011 = {'alt_name':'Tyz', 'dim':2 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 3 , 'intern_ind': 3 } + W4_110 = {'alt_name':'Txy', 'dim':2 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 4 , 'intern_ind': 4 } + W4_101 = {'alt_name':'Txz', 'dim':2 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 5 , 'intern_ind': 5 } + + W4_111 = {'alt_name':'V', 'dim':3 , 'ngens':3 , 'len_orbit':1 , 'gap_ind': 6 , 'intern_ind': 6 } + + W4_120 = {'alt_name':'Uyx', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 7 , 'intern_ind': 7 } + W4_201 = {'alt_name':'Uxz', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 8 , 'intern_ind': 8 } + W4_012 = {'alt_name':'Uzy', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 9 , 'intern_ind': 9 } + W4_102 = {'alt_name':'Uzx', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 10 , 'intern_ind': 10 } + W4_210 = {'alt_name':'Uxy', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 11 , 'intern_ind': 11 } + W4_021 = {'alt_name':'Vyz', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 12 , 'intern_ind': 12 } + + W4_213 = {'alt_name':'Vzxy', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 13 , 'intern_ind': 13 } + W4_132 = {'alt_name':'Vyzx', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 14 , 'intern_ind': 14 } + W4_321 = {'alt_name':'Vxyz', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 15 , 'intern_ind': 15 } + W4_231 = {'alt_name':'Vyxz', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 16 , 'intern_ind': 16 } + W4_123 = {'alt_name':'Vzyx', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 17 , 'intern_ind': 17 } + W4_312 = {'alt_name':'Vxzy', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 18 , 'intern_ind': 18 } + + W4_422 = {'alt_name':'Wx', 'dim':8 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 19 , 'intern_ind': 19 } + W4_224 = {'alt_name':'Wz', 'dim':8 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 20 , 'intern_ind': 20 } + W4_242 = {'alt_name':'Wy', 'dim':8 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 21 , 'intern_ind': 21 } + + W4_333 = {'alt_name':'X', 'dim':9 , 'ngens':3 , 'len_orbit':2 , 'gap_ind': 22 , 'intern_ind': 22 } + W4_333bar = {'alt_name':'Xbar', 'dim':9 , 'ngens':3 , 'len_orbit':2 , 'gap_ind': 23 , 'intern_ind': 23 } + + + # ------------------------------------------------------------------------------------------------- + # absolutely irreducible representations corresponding to braids on 5 strands + # ------------------------------------------------------------------------------------------------- + W5_100 = {'alt_name':None, 'dim':1 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } + W5_001 = {'alt_name':None, 'dim':1 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } + W5_010 = {'alt_name':None, 'dim':1 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + + W5_013 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 3 , 'intern_ind': 3 } + W5_130 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 4 , 'intern_ind': 4 } + W5_301 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 5 , 'intern_ind': 5 } + W5_031 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 6 , 'intern_ind': 6 } + W5_103 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 7 , 'intern_ind': 7 } + W5_310 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 8 , 'intern_ind': 8 } + + W5_203 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 9 , 'intern_ind': 9 } + W5_032 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 10 , 'intern_ind': 10 } + W5_320 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 11 , 'intern_ind': 11 } + W5_230 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 12 , 'intern_ind': 12 } + W5_023 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 13 , 'intern_ind': 13 } + W5_302 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 14 , 'intern_ind': 14 } + + W5_033 = {'alt_name':None, 'dim':6 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 15 , 'intern_ind': 15 } + W5_330 = {'alt_name':None, 'dim':6 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 16 , 'intern_ind': 16 } + W5_303 = {'alt_name':None, 'dim':6 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 17 , 'intern_ind': 17 } + + W5_163 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 18 , 'intern_ind': 18 } + W5_631 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 19 , 'intern_ind': 19 } + W5_316 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 20 , 'intern_ind': 20 } + W5_136 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 21 , 'intern_ind': 21 } + W5_613 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 22 , 'intern_ind': 22 } + W5_361 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 23 , 'intern_ind': 23 } + + W5_366 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 24 , 'intern_ind': 24 } + W5_663 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 26 , 'intern_ind': 25 } + W5_636 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 27 , 'intern_ind': 26 } + + W5_933 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 25 , 'intern_ind': 27 } + W5_339 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 28 , 'intern_ind': 28 } + W5_393 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 29 , 'intern_ind': 29 } + + + + +# ------------------------------------------------------------------------------------------------------------------ +# Definition of CubicHeckeMatrixRep +# -------------------------------------------------------------------------------------------------------- +class CubicHeckeMatrixRep(Matrix_generic_dense): + r""" + Class to supervise the diagonal block matrix structure arising from cubic Hecke algebra-representations. + I is the element class of :class:`CubicHeckeMatrixSpace`. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) + sage: m1 = MS(c1); m1 + [ a 0 0] + [ 0 b 0] + [ 0 0 -b - a + u] + sage: type(m1) + + sage: m1.block_diagonal_list() + [[a], [b], [-b - a + u]] + + sage: MSo = chmr.CubicHeckeMatrixSpace(CHA2, original=True) + sage: MSo(c1) + [a 0 0] + [0 b 0] + [0 0 c] + + sage: reg_left = chmr.RepresentationType.RegularLeft + sage: MSreg = chmr.CubicHeckeMatrixSpace(CHA2, representation_type=reg_left) + sage: MSreg(c1) + [ 0 -v 1] + [ 1 u 0] + [ 0 w 0] + sage: len(_.block_diagonal_list()) + 1 + """ + + @cached_method + def _get_block(self, ind): + r""" + Return the ``ind``-th submatrix block of ``self`` considered as block diagonal matrix. + + INPUT: + + - ``ind`` -- integer specifying the list index according to :meth:`internal_index` repectively :meth:`gap_index` + + OUTPUT: + + An instance of :class:`Matrix_generic_dense` representing the specified block of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: c1.matrix()._get_block(0) # indirect doctest + [a] + """ + representation_type = self.parent()._representation_type + if not representation_type.is_split(): + return matrix(self) + n = self.parent()._cubic_hecke_algebra.ngens() + s = sum(irr_rep.dimension() for irr_rep in AbsIrreducibeRep if irr_rep.number_gens() == n and irr_rep.internal_index() < ind) + for irr_rep in AbsIrreducibeRep: + if irr_rep.number_gens() == n and irr_rep.internal_index() == ind: + d = irr_rep.dimension() + return matrix(self.submatrix(s, s, d, d)) + raise ValueError('no irreducible representation for this index') + + + @cached_method + def __getitem__(self, item): + r""" + Return the submatrix block of ``self`` considered as block diagonal matrix specified by `item`. + Overloading builtin-method to select a list-item. + + INPUT: + + - ``item`` -- an instance of :class:`AbsIrreducibeRep` specifying an absolute irreducible + representation of the cubic Hecke algebra. Alternatively, it can be specified by list index + (see :meth:`internal_index` repectively :meth:`gap_index`). + + OUTPUT: + + An instance of :class:`Matrix_generic_dense` representing the specified block of ``self``. + + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: c1.matrix()[0] # indirect doctest + [a] + sage: c1.matrix()[CHA2.irred_repr.W2_001] # indirect doctest + [b] + """ + + + if isinstance(item, AbsIrreducibeRep): + representation_type = self.parent()._representation_type + if not representation_type.is_split(): + raise TypeError( "representation type is non split" ) + + ch_algebra = self.parent()._cubic_hecke_algebra + if ch_algebra.strands() != item.number_gens() +1 : + raise TypeError( "representation must have %d generators" %(ch_algebra.strands()-1 ) ) + + ind = item.gap_index() + if representation_type == RepresentationType.SplitIrredMarin: + ind = item.internal_index() + return self._get_block(ind) + elif isinstance(item, (Integer,int)): + return self._get_block(item) + + return super(CubicHeckeMatrixRep, self).__getitem__(item) + + @cached_method + def block_diagonal_list(self): + r""" + Return the list of submatrix blocks of ``self`` considered as block diagonal matrix. + + OUTPUT: + + A list of instances of :class:`Matrix_generic_dense` each of which represents a diagonal block of ``self``. + + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: c1.matrix().block_diagonal_list() + [[a], [b], [-b - a + u]] + """ + representation_type = self.parent()._representation_type + n = self.parent()._cubic_hecke_algebra.strands() + l = representation_type.number_of_representations(n) + return [self._get_block(i) for i in range(l)] + + + +# ------------------------------------------------------------------------------------------------------------------ +# Definition of CubicHeckeMatrixSpace +# -------------------------------------------------------------------------------------------------------- +class CubicHeckeMatrixSpace(MatrixSpace): + r""" + This class defines the matrix space of cubic Hecke algebra-representations. + + INPUT (to the python constructor): + + - ``cubic_hecke_algebra`` -- (default = None) instance of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.cubicHeckeAlgebra` must be given if + `element` fails to be an instance of its element class. + + - ``representation_type`` -- (default RepresentationType.SplitIrredChevie) instance of :class:`RepresentationType` + specifying the type of the represenstation. + + - ``subdivide`` -- boolean (default False) passed to :func:`~sage.matrix.special.block_diagonal_matrix`. + + - ``original`` -- boolean (default False) if set to True the matrix will coefficients in the generic + base / extension ring. + + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: c1.matrix() # indirect doctest + [ a 0 0] + [ 0 b 0] + [ 0 0 -b - a + u] + sage: c1.matrix(original=True) + [a 0 0] + [0 b 0] + [0 0 c] + sage: c1.matrix(representation_type = CHA2.repr_type.RegularLeft) # indirect doctest + [ 0 -v 1] + [ 1 u 0] + [ 0 w 0] + """ + @staticmethod + def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, subdivide=False, original=False): + r""" + Normalize the arguments to call the ``__init__`` constructor. + + See the documentation in ``__init__``. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) + sage: TestSuite(MS).run() + """ + from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra + + if isinstance(cubic_hecke_algebra, CubicHeckeAlgebra) == False: + raise TypeError("cubic_hecke_algebra must be an instance of CubicHeckeAlgebra") + + if representation_type == None: + representation_type = RepresentationType.SplitIrredMarin + + if representation_type == RepresentationType.SplitIrredChevie: + from sage.combinat.root_system.reflection_group_real import is_chevie_available + if not is_chevie_available(): + raise ValueError('CHEVIE is not available') + + base_ring = cubic_hecke_algebra.base_ring(generic=original) + dimension = cubic_hecke_algebra.dimension() + if representation_type.is_split(): + dimension = cubic_hecke_algebra._dim_irr_rep + base_ring = cubic_hecke_algebra.extension_ring(generic=original) + + return super(CubicHeckeMatrixSpace, cls).__classcall__(cls, base_ring, dimension, cubic_hecke_algebra=cubic_hecke_algebra, + representation_type=representation_type, subdivide=subdivide, sparse=True, implementation=Matrix_generic_dense) + + + + def __init__(self, base_ring, dimension, cols, sparse=True, implementation=Matrix_generic_dense, + cubic_hecke_algebra=None, representation_type=RepresentationType.SplitIrredChevie, subdivide=False): + r""" + Python constructor. + + TESTS:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA3. = algebras.CubicHecke(3) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) + sage: TestSuite(MS).run() # long time + """ + + from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra + + if isinstance(cubic_hecke_algebra, CubicHeckeAlgebra) == False: + raise TypeError("cubic_hecke_algebra must be an instance of CubicHeckeAlgebra") + + # ------------------------------------------------------------------------------------------------- + # saving input parameters + # ------------------------------------------------------------------------------------------------- + self._cubic_hecke_algebra = cubic_hecke_algebra + self._representation_type = representation_type + self._subdivide = subdivide + + original_base_ring = cubic_hecke_algebra.base_ring(generic=True) + + if representation_type.is_split(): + original_base_ring = cubic_hecke_algebra.extension_ring(generic=True) + specialize = cubic_hecke_algebra._generic_extension_ring_map + else: + specialize = cubic_hecke_algebra._ring_of_definition_map + + verbose("original_base_ring %s base_ring %s" %(original_base_ring, base_ring)) + + self._original_base_ring = original_base_ring + self._specialize = specialize + + super(CubicHeckeMatrixSpace, self).__init__(base_ring, dimension, cols, sparse=sparse, implementation=implementation) + self.Element = CubicHeckeMatrixRep + return + + def __reduce__(self): + r""" + Used for pickling. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = c1.matrix().parent() + sage: loads(dumps(MS)) == MS # indirect doctest + True + """ + original = self.base_ring() == self._original_base_ring + return CubicHeckeMatrixSpace, (self._cubic_hecke_algebra, self._representation_type, self._subdivide, original) + + + def _element_constructor_(self, x): + r""" + INPUT: + + - ``x`` -- instance of the element class of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra` or an instance + whose parent is in instance of :class:`MatrixSpace` + + EXAMLPES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA3. = algebras.CubicHecke(3) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) + sage: m1 = MS._element_constructor_(c1) + sage: isinstance(m1, MS.element_class) + True + sage: isinstance(MS._element_constructor_(m1), MS.element_class) + True + + sage: m = matrix(MS.base_ring(), 12, 12, lambda i, j: 1) + sage: MS._element_constructor_(m) + Traceback (most recent call last): + ... + TypeError: incompatible block structure + """ + # ------------------------------------------------------------------------------------------------- + # checking input and setting the self._cubic_hecke_algebra + # ------------------------------------------------------------------------------------------------- + ch_algebra = self._cubic_hecke_algebra + ele_parent = x.parent() + ori_base_ring = self._original_base_ring + if isinstance(ele_parent, MatrixSpace): + # ToDo: - Find preimage in cubic hecke algebra + d1, d2 = x.dimensions() + if d1 != self.ncols() or d2 != self.nrows(): + raise ValueError('incompatible dimensions!') + + if ele_parent.base_ring() == ori_base_ring: + x = self._specialize_matrix(x) + elif ele_parent.base_ring() != self.base_ring(): + raise ValueError('incompatible base ring!') + x_in_self = self.element_class(self, x) + matrix_list = x_in_self.block_diagonal_list() + matrix = block_diagonal_matrix(matrix_list, subdivide=self._subdivide, sparse=True) + if matrix != x: + raise TypeError( "incompatible block structure" ) + + elif ele_parent == ch_algebra: + mat = ch_algebra._apply_module_morphism(x, self._image_on_basis) + return self(mat) + + else: + raise TypeError( "element must be an instance of CubicHeckeElement or a matrix" ) + + return self.element_class(self, matrix) + + def __call__(self, entries=None, coerce=True, copy=None): + r""" + Perform the instance call. This method needs to be overloaded here + since :class:`MatrixSpace` has an own implementation of it. + + EXAMLPES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) + sage: MS(c1) + [ a 0 0] + [ 0 b 0] + [ 0 0 -b - a + u] + """ + from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra + if entries is None: + return super(CubicHeckeMatrixSpace,self).__call__(entries=entries, coerce=coerce, copy=copy) + if not hasattr(entries, 'parent'): + return super(CubicHeckeMatrixSpace,self).__call__(entries=entries, coerce=coerce, copy=copy) + ele_parent = entries.parent() + if not isinstance(ele_parent, (CubicHeckeAlgebra, MatrixSpace)): + return super(CubicHeckeMatrixSpace,self).__call__(entries=entries, coerce=coerce, copy=copy) + return self._element_constructor_(entries) + + + + + def _specialize_matrix(self, mat): + r""" + Return the given matrix specializing the original coefficients + from data import to the base ring of ``self``. + + INPUT: + + - ``mat`` -- matrix over the original base ring + + OUTPUT: + + ``mat`` over the base ring of ``self`` + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) + sage: B = MS._original_base_ring + sage: a, b, c = B.gens() + sage: mat = matrix(B, [[a, b], [0, c]]) + sage: MS._specialize_matrix(mat) + [ a b] + [ 0 -b - a + u] + """ + + base_ring = self.base_ring() + original_base_ring = self._original_base_ring + specialize = self._specialize + + if base_ring == original_base_ring: + return mat + + mat_dict = {k: specialize(original_base_ring(v)) for k, v in mat.dict().items()} + return matrix(base_ring, mat_dict) + + + @cached_method + def _image_on_gen(self, gen_ind): + r""" + Return the matrix list corresponding to the generator given by ``(gen_ind,)`` in Tietze form + under the representation_type of ``self`` from the data-file or via the gap3 interface + + INPUT: + + - ``gen_ind`` -- integer, index of a generator of the cubic Hecke algebra attached to ``self`` + 1. + Negative values correspond to the according inverses. + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA3. = algebras.CubicHecke(3) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA3) + sage: MS._image_on_gen(1) + [ + [ b 0] [ a 0] [ a 0] + [a], [c], [b], [b*c c], [a*b b], [a*c c], + + [ c 0 0] + [b^2 + a*c b 0] + [ b 1 a] + ] + + sage: CHA2 = CHA3.cubic_hecke_subalgebra() + sage: MSreg = chmr.CubicHeckeMatrixSpace(CHA2, representation_type=CHA2.repr_type.RegularRight) + sage: MSreg._image_on_gen(-1) + [ + [ 0 1 (-w^-1)*u] + [ 0 0 w^-1] + [ 1 0 (w^-1)*v] + ] + """ + + representation_type = self._representation_type + ch_algebra = self._cubic_hecke_algebra + n = ch_algebra.strands() + original_base_ring = self._original_base_ring + + def invert_gen(matr): + r""" + Return the inverse matrix of generators. + """ + cfs = ch_algebra.cubic_equation(as_coefficients=True, generic=True) + fac =-1 /cfs[0 ] + cf0, cf1, cf2, cf3 = [original_base_ring(cf*fac) for cf in cfs] + + matri = cf1*matr.parent().one() + matri += cf2*matr + matri += cf3*matr**2 + d1, d2 = matr.dimensions() + matrI = matrix(original_base_ring, d1, d2, lambda i,j: original_base_ring(matri[i,j])) + return matrI + + + if n == 2 : + if representation_type.is_split(): + # Split representations for n == 2 are missing in CHEVIE and data files + a, b, c = original_base_ring.gens() + matrix_list = [matrix(1 ,1 , [a]), matrix(1 ,1 , [b]), matrix(1 ,1 , [c])] + if gen_ind < 0 : + matrix_list = [invert_gen(mat) for mat in matrix_list] + return matrix_list + + num_rep = representation_type.number_of_representations(n) + + if representation_type == RepresentationType.SplitIrredChevie: + + rep_list = [ ch_algebra._fetch_matrix_list_from_chevie(i+1) for i in range(num_rep) ] + if gen_ind > 0 : + matrix_list = [ rep[gen_ind-1 ] for rep in rep_list ] + else: + matrix_list = [ invert_gen(rep[-gen_ind-1 ]) for rep in rep_list ] + + else: + + database = ch_algebra._database + matrix_list = database.read_matrix_representation(representation_type, gen_ind, n, original_base_ring) + + return matrix_list + + + @cached_method + def _image_on_basis(self, basis_element): + r""" + Return the image of the given basis element of the cubic Hecke algebra in ``self``. + + INUPUT: + + - ``basis_element`` -- instance of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeElement` which is a monomial + + EXAMPLES:: + + sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: CHA3. = algebras.CubicHecke(3) + sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) + sage: MS._image_on_basis(c1) + [ a 0 0 0 0 0 0 0 0 0 0 0] + [ 0 c 0 0 0 0 0 0 0 0 0 0] + [ 0 0 b 0 0 0 0 0 0 0 0 0] + [ 0 0 0 b 0 0 0 0 0 0 0 0] + [ 0 0 0 b*c c 0 0 0 0 0 0 0] + [ 0 0 0 0 0 a 0 0 0 0 0 0] + [ 0 0 0 0 0 a*b b 0 0 0 0 0] + [ 0 0 0 0 0 0 0 a 0 0 0 0] + [ 0 0 0 0 0 0 0 a*c c 0 0 0] + [ 0 0 0 0 0 0 0 0 0 c 0 0] + [ 0 0 0 0 0 0 0 0 0 b^2 + a*c b 0] + [ 0 0 0 0 0 0 0 0 0 b 1 a] + """ + + representation_type = self._representation_type + ch_algebra = self._cubic_hecke_algebra + filecache = ch_algebra._filecache + + original_base_ring = self._original_base_ring + + ele_Tietze = basis_element.Tietze() + matrix_list = filecache.read_matrix_representation(representation_type, ele_Tietze, original_base_ring) + if matrix_list is None: + verbose("not in memory %s (Tietze %s)" %(basis_element, ele_Tietze)) + if len(ele_Tietze) == 0 : + matrix_list = ch_algebra._create_matrix_list_for_one(representation_type) + else: + for gen_ind in ele_Tietze: + gen_matrix_list = self._image_on_gen(gen_ind) + if matrix_list == None: + matrix_list = [m for m in gen_matrix_list] + else: + for i in range(len(matrix_list)): + matrix_list[i] *= gen_matrix_list[i] + + filecache.write_matrix_representation(representation_type, ele_Tietze, matrix_list) + verbose("%s saved to memory" %(basis_element)) + + mat = block_diagonal_matrix(matrix_list, subdivide=self._subdivide, sparse=True) + return self._specialize_matrix(mat) + + def zero(self): + r""" + Return the zero element of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: m1 = c1.matrix() + sage: m1rl = c1.matrix(representation_type = CHA2.repr_type.RegularLeft) + sage: z = m1.parent().zero() + sage: zrl = m1rl.parent().zero() + sage: matrix(z) == matrix(zrl), z.is_zero(), zrl.is_zero() + (True, True, True) + sage: z.block_diagonal_list() + [[0], [0], [0]] + sage: zrl.block_diagonal_list() + [ + [0 0 0] + [0 0 0] + [0 0 0] + ] + """ + z = self.element_class(self, super(CubicHeckeMatrixSpace, self).zero()) + z._cubic_hecke_element = self._cubic_hecke_algebra.zero() + z.set_immutable() + return z + + def one(self): + r""" + Return the one element of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: m1 = c1.matrix() + sage: m1rl = c1.matrix(representation_type = CHA2.repr_type.RegularLeft) + sage: o = m1.parent().one() + sage: orl = m1rl.parent().one() + sage: matrix(o) == matrix(orl), o.is_one(), orl.is_one() + (True, True, True) + sage: o.block_diagonal_list() + [[1], [1], [1]] + sage: orl.block_diagonal_list() + [ + [1 0 0] + [0 1 0] + [0 0 1] + ] + """ + o = self.element_class(self, super(CubicHeckeMatrixSpace, self).one()) + o._cubic_hecke_element = self._cubic_hecke_algebra.one() + o.set_immutable() + return o + + def _an_element_(self): + r""" + Return an element of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2, cubic_equation_roots=(2, 3, 5)) + sage: c1.matrix() + [2 0 0] + [0 3 0] + [0 0 5] + sage: _.parent()._an_element_() + [ 94/3 0 0] + [ 0 187/3 0] + [ 0 0 373/3] + """ + x = self._cubic_hecke_algebra.an_element() + return self(x) + + def some_elements(self): + r""" + Return a generator of elements of ``self``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2, cubic_equation_roots=(2, 3, 5)) + sage: c1.matrix() + [2 0 0] + [0 3 0] + [0 0 5] + sage: list(_.parent().some_elements()) + [ + [ 94/3 0 0] + [ 0 187/3 0] + [ 0 0 373/3] + ] + """ + for x in self._cubic_hecke_algebra.some_elements(): + yield self(x) diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py new file mode 100644 index 00000000000..dd97f86054f --- /dev/null +++ b/src/sage/databases/cubic_hecke_db.py @@ -0,0 +1,1167 @@ +# -*- coding: utf-8 -*- +r""" +Cubic Hecke Database + +This module contains the class :class:`CubicHeckeDataBase` which serves as an interface to +Ivan Marin's data files with respect to the cubic Hecke algebras. Furthermore, it contains +the class :class:`CubicHeckeFileCache` which enables :class:`CubicHeckeAlgebra` to keep +intermediate results of calculations in the file system. + +AUTHORS: + +- Sebastian Oehms May 2020: initial version +""" + + +############################################################################## +# Copyright (C) 2020 Sebastian Oehms +# +# 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/ +############################################################################## + + +import os +from enum import Enum + +from sage.structure.sage_object import SageObject +from sage.misc.persist import db_save, db, save, load +from sage.misc.misc import verbose +from sage.env import SAGE_SHARE, SAGE_ROOT +from sage.matrix.constructor import matrix, Matrix # uppercase version used in Marin's file `MatricesRegH4.maple` +from sage.rings.integer_ring import ZZ +from sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeRingOfDefinition + + + + + +#---------------------------------------------------------------------------------------------------------------------------- +# functions to convert matrices and ring elements to and from flat python dictionaries in order to save matrices avoiding +# compatibility problems with older or newer sage versions and to save disc space +#---------------------------------------------------------------------------------------------------------------------------- +# conversion of ring element to dictionary +#---------------------------------------------------------------------------------------------------------------------------- +def convert_poly_to_dict_recursive(ring_elem): + r""" + Convert a ring element to a python dictionary recursively using the dict method of it. + By recursion the dictionaries values are converted as well as long as they posses a + ``dict`` method. If the values are sage Integers they are converted into python integers. + + INPUT: + + -- ``ring_elem`` - ring element to be converted into python dictionary + + OUTPUT: + + A python dictionary from which ``ring_elem`` can be reconstructed via element construction by recursion. + The values of the dictionary may be dictionaries again if the parent of ring_elem has a base_ring + different from itself. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import convert_poly_to_dict_recursive + sage: L.=LaurentPolynomialRing(ZZ, 'c') + sage: P. = L['a,b']; P + Multivariate Polynomial Ring in a, b + over Univariate Laurent Polynomial Ring in c over Integer Ring + sage: elem = 5*b-3*a*~c; elem + (-3*c^-1)*a + 5*b + sage: convert_poly_to_dict_recursive(elem) + {(0, 1): {0: 5}, (1, 0): {-1: -3}} + """ + + dict_res = {} + if hasattr(ring_elem, 'dict'): + ring_elem_dict = ring_elem.dict() + for k in ring_elem_dict.keys(): + dict_res[k] = convert_poly_to_dict_recursive(ring_elem_dict[k]) + else: + if ring_elem in ZZ: + return int(ring_elem) + return ring_elem + return dict_res + + + + + + +#--------------------------------------------------------------------------------------------------------------------------- +# conversion of matrix to dictionary +#--------------------------------------------------------------------------------------------------------------------------- +def convert_mat_to_dict_recursive(mat): + r""" + Convert a matrix to a python dictionary using the dict method of it. Furthermore, the dictionaries + values are converted as well by the convert_poly_to_dict_recursive function. + + INPUT: + + - ``mat`` -- matrix to be converted into python dictionary + + OUTPUT: + + A python dictionary from which mat can be reconstructed via element construction. The values of the + dictionary may be dictionaries again if entries of the matrix have a dict method as well. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import convert_mat_to_dict_recursive + sage: L.=LaurentPolynomialRing(ZZ, 'c') + sage: P. = L['a,b']; P + Multivariate Polynomial Ring in a, b + over Univariate Laurent Polynomial Ring in c over Integer Ring + sage: mat = matrix(P, [[2*a, -3], [c, 4*b*~c]]); mat + [ 2*a -3] + [ c (4*c^-1)*b] + sage: convert_mat_to_dict_recursive(mat) + {(0, 0): {(1, 0): {0: 2}}, + (0, 1): {(0, 0): {0: -3}}, + (1, 0): {(0, 0): {1: 1}}, + (1, 1): {(0, 1): {-1: 4}}} + """ + + mat_dict = {} + mat_dict_temp = mat.dict() + for k in mat_dict_temp.keys(): + mat_dict[k] = convert_poly_to_dict_recursive(mat_dict_temp[k]) + return mat_dict + + + + +class CubicHeckeDataFilename(Enum): + r""" + Enum for the different data files. The following choices are possible: + + - ``basis`` -- contains the basis for the cubic Hecke algebra up to 4 strands + - ``regular_left`` -- contains the left regular representation matrices of the generators + - ``regular_right`` -- contains the right regular representation matrices of the generators + - ``irred_split`` -- contains representation matrices of the generators of the split irreducible + representations + + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.filename + + """ + def download(self): + """ + Return the file name to download the data from Ivan Marin's web-page. + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.filename.basis.download() + 'baseH4.maple' + """ + return self.value[0] + def py(self): + """ + Return the file name under which the data from Ivan Marin's web-page + are stored as python file. + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.filename.basis.py() + 'baseH4.maple.py' + """ + return '%s.py' %(self.value[0]) + + def sobj(self, nstrands=None): + """ + Return the file name under which the data from Ivan Marin's web-page + is converted into sobj-files. + + INPUT: + + - ``nstrands`` -- Integer number of strands of the underlying braid group + if the data file depends on it. Otherwise use default None + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.filename.basis.sobj() + 'monomial_basis.sobj' + sage: cha_db.filename.basis.sobj() + 'monomial_basis.sobj' + sage: cha_db.filename.irred_split.sobj(2) + 'irred_split_reprs_2.sobj' + sage: cha_db.filename.regular_left.sobj(3) + 'regular_left_reprs_3.sobj' + """ + if nstrands is None: + return '%s.sobj' %(self.value[1]) + else: + return '%s_%s.sobj' %(self.value[1], nstrands) + + basis = ['baseH4.maple', 'monomial_basis'] + regular_left = ['MatricesRegH4.maple', 'regular_left_reprs'] + regular_right = ['MatricesRegH4right.maple', 'regular_right_reprs'] + irred_split = ['RepresentationsH25', 'irred_split_reprs'] + + + + + +#---------------------------------------------------------------------------------------------------------------------------- +# Class to supply data for the basis and matrix representation for the cubic Hecke algebra +#---------------------------------------------------------------------------------------------------------------------------- +class CubicHeckeDataBase(SageObject): + r""" + Database interface needed for :class:`CubicHeckeAlgebra`. + + The original data are obtained from Ivan Marin's web-page (URL see the example below). In order + to have these data installed during the build process as a sage-package they are converted + as python files into a tarball. This tarball has been created using the method :meth:`create_spkg_tarball`. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db._url_marin + 'http://www.lamfa.u-picardie.fr/marin/softs/H4' + """ + + filename = CubicHeckeDataFilename + + def __init__(self): + r""" + Python constructor. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: from sage.env import SAGE_SHARE + sage: cha_db = CubicHeckeDataBase() + sage: cha_db._import_path_sobj == SAGE_SHARE + '/cubic_hecke_marin/sobj' + True + """ + self._url_marin = 'http://www.lamfa.u-picardie.fr/marin/softs/H4' + + self._package = 'cubic_hecke_marin' + version_file = os.path.join(SAGE_ROOT, 'build/pkgs/%s/package-version.txt' %self._package) + f = open(version_file) + self._version = f.read().splitlines()[0] + f.close() + + self._import_path = os.path.join(SAGE_SHARE, self._package) + self._import_path_py = os.path.join(self._import_path, 'py') + self._import_path_sobj = os.path.join(self._import_path, 'sobj') + + from sage.misc.misc import sage_makedirs + sage_makedirs(self._import_path_py) + sage_makedirs(self._import_path_sobj) + + self._data_library = {} + + def version(self): + r""" + Return the current version. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.version() + '20200513' + """ + return self._version + + def _create_python_file(self, filename): + r""" + Return the data fetched from Iwan Marin's homepage as a python file + such that it can be loaded via `sage_eval`. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: load(cha_db._create_python_file(cha_db.filename.basis)) # not tested (because of internet access) + Importing data for monomial_basis.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/baseH4.maple + sage: len(baseH4) # not tested + 648 + """ + if not isinstance(filename, CubicHeckeDataBase.filename): + raise TypeError('File name must be an instance of enum %s' (CubicHeckeDataBase.filename)) + + import_file = '%s/%s' %(self._import_path_py, filename.py()) + + # import directly from the internet page + from six.moves.urllib.request import urlopen + try: + from urllib.error import HTTPError + except ImportError: + from urllib2 import HTTPError + + try: + url = '%s/%s' %(self._url_marin, filename.download()) + url_data = urlopen(url).read().decode() + print('Importing data for %s from %s' %(filename.sobj(), url)) + preparsed_data =url_data.replace(':=', '=').replace(';', '').replace('^', '**') + f = open(import_file, 'wt') + f.write(preparsed_data) + f.close() + return import_file + except HTTPError: + raise IOError('Data import file %s not found! Internet connection needed!' %(filename)) + + def create_spkg_tarball(self): + r""" + Create a tarball for the sage-package `cubic_heck_marin` in the `upstream` directory. This + utility should only be used by users who know what they do in case of a switch to a new + version of the data files (that is if the original files on Iwan Marin's homepage have changed). + In that case in invocation of `sage -package update cubic_hecke_marin ` and + `sage -package update cubic_hecke_marin` will be necessary. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.create_spkg_tarball() # not tested (because of internet access) + Importing data for monomial_basis.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/baseH4.maple + Importing data for regular_left_reprs.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4.maple + Importing data for regular_right_reprs.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4right.maple + Importing data for irred_split_reprs.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/RepresentationsH25 + py/ + py/MatricesRegH4.maple.py + py/MatricesRegH4right.maple.py + py/RepresentationsH25.py + py/baseH4.maple.py + """ + for filename in CubicHeckeDataBase.filename: + self._create_python_file(filename) + os.system('cd %s; tar -cvjSf %s/upstream/%s-%s.tar.bz2 py' %(self._import_path, SAGE_ROOT, self._package, self._version) ) + + def import_data(self, filename, from_spkg=True): + r""" + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: load(cha_db.import_data(cha_db.filename.basis)) + sage: len(baseH4) + 648 + """ + if not isinstance(filename, CubicHeckeDataBase.filename): + raise TypeError('File name must be an instance of enum %s' (CubicHeckeDataBase.filename)) + + import_file = '%s/%s' %(self._import_path_py, filename.py()) + + try: + open(import_file) + return import_file + except IOError: + if from_spkg: + # import from the spkg tarball + print('Importing cubic Hecke database from SPKG!') + os.system('pwd') + os.system('cp src/*.py %s' %(self._import_path_py)) + open(import_file) + return import_file + else: + return self._create_python_file(filename) + + + def create_static_db_marin_basis(self): + r""" + Create the basis of the cubic Hecke algebra according to the original + data from Iwan Marin's home page. + + This method is called during the build procedure for the sage-package. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.create_static_db_marin_basis() + """ + global baseH4 # set by load + load(self.import_data(self.filename.basis)) + + basis_h1 = [] + basis_h2 = [] + basis_h3 = [] + basis_h4 = baseH4 + + len_baseH4 = len(baseH4) + + ind_h1 = [] + ind_h2 = [] + ind_h3 = [] + ind_h4 = range(len_baseH4) + + for i in ind_h4: + set_i = set(baseH4[i]) + if 3 not in set_i and -3 not in set_i: + basis_h3.append( basis_h4[i] ) + ind_h3.append(i) + if 2 not in set_i and -2 not in set_i: + basis_h2.append( basis_h4[i] ) + ind_h2.append(i) + if 1 not in set_i and -1 not in set_i: + basis_h1.append( basis_h4[i] ) + ind_h1.append(i) + + # len_bas_h1 = len(basis_h1); len_bas_h2 = len(basis_h2); len_bas_h3 = len(basis_h3) + + basis = {1:[basis_h1, ind_h1], 2:[basis_h2, ind_h2], 3: [basis_h3, ind_h3], 4:[basis_h4, ind_h4]} + save(basis, '%s/%s' %(self._import_path_sobj, self.filename.basis.sobj()) ) + + + def create_static_db_marin_regular(self, right=False): + r""" + Create the static data base for regular representations of the cubic + Hecke algebra according to the original data from Iwan Marin's home page. + + This method is called during the build procedure for the sage-package. + + The invocations are not active in the doctest, since they cause a ``MemoryError`` + here. To refresh the data base you may call this method in a session. You will + have to wait (maybe up to several minutes)! + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.create_static_db_marin_regular() # not tested + sage: cha_db.create_static_db_marin_regular(right=True) # not tested + """ + + base_ring = CubicHeckeRingOfDefinition() + global u, v, w, mm1, mm2, mm3, mm1I, mm2I, mm3I, reps # set in load + u, v, w = base_ring.gens_over_ground() + + if right == False: + fname = self.filename.regular_left + else: + fname = self.filename.regular_right + before = verbose('start loading %s' %fname) + load(self.import_data(fname)) + before = verbose('end loading %s' %fname, t=before) + + + def create_mat(ind_h, mat_h4): + """ + Create restriction of regular representation of H4 to H1, H2 and H3 + """ + + dim_mat = len(ind_h) + mat = matrix(dim_mat, dim_mat, lambda i,j: mat_h4[ind_h[i], ind_h[j]]) + return convert_mat_to_dict_recursive(mat) + + basis = self.read(self.filename.basis) + ind_h1 = basis[1][1] + ind_h2 = basis[2][1] + ind_h3 = basis[3][1] + + representationH ={} + representationH[0] = [[create_mat(ind_h1, mm1)]] + representationH[1] = [[create_mat(ind_h2, mm1)]] + representationH[2] = [[create_mat(ind_h3, mm1), create_mat(ind_h3, mm2)]] + representationH[3] = [[convert_mat_to_dict_recursive(mm1), convert_mat_to_dict_recursive(mm2), convert_mat_to_dict_recursive(mm3)]] + + representationHI ={} + representationHI[0] = [[create_mat(ind_h1, mm1I)]] + representationHI[1] = [[create_mat(ind_h2, mm1I)]] + representationHI[2] = [[create_mat(ind_h3, mm1I), create_mat(ind_h3, mm2I)]] + representationHI[3] = [[convert_mat_to_dict_recursive(mm1I), convert_mat_to_dict_recursive(mm2I), convert_mat_to_dict_recursive(mm3I)]] + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import GenSign + + for i in range(4): + if right == False: + sobj_filename = '%s/%s' %(self._import_path_sobj, self.filename.regular_left.sobj(i+1)) + else: + sobj_filename = '%s/%s' %(self._import_path_sobj, self.filename.regular_right.sobj(i+1)) + + RegularMarinDict = {GenSign.pos:representationH[i], GenSign.neg:representationHI[i]} + save(RegularMarinDict, sobj_filename ) + return + + + def create_static_db_marin_split(self): + r""" + Create the static data base for split irreducible representations of the cubic + Hecke algebra according to the original data from Iwan Marin's home page. + + This method is called during the build procedure for the sage-package. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: cha_db.create_static_db_marin_split() + """ + # ------------------------------------------------------ + # Ivan Marin's data file uses a, b, c for the variables + # corresponding to the eigenvalues of the cubic equation. + # Therefore, we have to use them temporarily in that way + # ------------------------------------------------------ + base_ring = CubicHeckeRingOfDefinition() + extension_ring = base_ring.extension_ring() + global a, b, c, j + a, b, c = extension_ring.gens() + j = extension_ring.cyclotomic_generator() + + load(self.import_data(self.filename.irred_split)) + + a, b, c = base_ring.gens_over_ground() # now back to usual nameing + cfs = [-c, b, -a, 1] + cfse = [extension_ring(cf/c) for cf in cfs] + + def invert(matr): + """ + Return inverse matrix for generators + """ + + matri = cfse[1]*matr.parent().one() + matri += cfse[2]*matr + matri += cfse[3]*matr**2 + d1, d2 = matr.dimensions() + matrI = matrix(extension_ring, d1, d2, lambda i,j: extension_ring(matri[i,j])) + return matrI + + # ------------------------------------------------------------------------------------------------ + # Restoring the split irreducibles from Iwan Marin's homepage + # ------------------------------------------------------------------------------------------------ + + anz_reps = len(reps) + + representation_h ={} + representation_h[0] = [[convert_mat_to_dict_recursive(Matrix(1,1,[extension_ring.one()]))]] + representation_h[1] = [] + representation_h[2] = [] + representation_h[3] = [] + + representation_hI ={} + representation_hI[0] = representation_h[0] + representation_hI[1] = [] + representation_hI[2] = [] + representation_hI[3] = [] + for i in range( anz_reps ): + repi = reps[i] + if len(repi) != 3: + raise RuntimeError( 'Error at position %d: three generators expected, got: %d' %( i, len(repi))) + mt = [] + mtI = [] + for j in range(3): + mat = matrix(repi[j]) + matI = invert(mat) + mt.append(convert_mat_to_dict_recursive(mat)) + mtI.append(convert_mat_to_dict_recursive(matI)) + + representation_h[3].append( mt ) + representation_hI[3].append( mtI ) + + if i < 7: + mt7 = [ m for m in mt ] + mt7I = [ m for m in mtI ] + mt7.pop() + mt7I.pop() + representation_h[2].append( mt7 ) + representation_hI[2].append( mt7I ) + + if i < 3: + mt3 = [ m for m in mt7 ] + mt3I = [ m for m in mt7I ] + mt3.pop() + mt3I.pop() + representation_h[1].append( mt3 ) + representation_hI[1].append( mt3I ) + + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import GenSign + for i in range(4): + sobj_filename = '%s/%s' %(self._import_path_sobj, self.filename.irred_split.sobj(i+1)) + SplitIrredMarinDict = {GenSign.pos:representation_h[i], GenSign.neg:representation_hI[i]} + save(SplitIrredMarinDict, sobj_filename) + + return + + # ------------------------------------------------------------------------------------------------------------- + # read from an sobj-file obtained from Ivan Marin's database + # ------------------------------------------------------------------------------------------------------------- + def read(self, db_filename, nstrands=None): + r""" + Access various static data library. + + INPUT: + + ``db_filename`` -- instance of enum :class:`CubicHeckeDataBase.filename` + to select the data to be read in + + OUTPUT: + + A dictionary containing the data corresponding to the db_filename. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: cha_db = CubicHeckeDataBase() + sage: basis = cha_db.read(cha_db.filename.basis) + sage: len(basis[3][0]) + 24 + """ + if not isinstance(db_filename, CubicHeckeDataFilename): + raise TypeError('db_filename must be an instance of enum %s' (CubicHeckeDataBase.filename)) + + data_lib = self._data_library + lib_path = self._import_path_sobj + + if (db_filename, nstrands) in data_lib.keys(): + return data_lib[(db_filename, nstrands)] + + verbose('loading data library %s ...' %(db_filename.sobj(nstrands=nstrands))) + try: + data_lib[(db_filename,nstrands)] = load('%s/%s' %(lib_path, db_filename.sobj(nstrands=nstrands))) + except IOError: + if db_filename == self.filename.basis: + self.create_static_db_marin_basis() + elif db_filename == self.filename.irred_split: + self.create_static_db_marin_split() + elif db_filename == self.filename.regular_right: + self.create_static_db_marin_regular(right=True) + else: + self.create_static_db_marin_regular() + data_lib[(db_filename, nstrands)] = load('%s/%s' %(lib_path, db_filename.sobj(nstrands=nstrands))) + + verbose('... finished!') + + return data_lib[(db_filename,nstrands)] + + + # ------------------------------------------------------------------------------------------------------------- + # matrix_reprs_from_file_cache_ + # ------------------------------------------------------------------------------------------------------------- + def read_matrix_representation(self, representation_type, gen_ind, nstrands, ring_of_definition): + r""" + Return the matrix representations from the database. + + INPUT: + + - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + specifying the type of the representation + + + OUTPUT: + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase + sage: CHA3 = algebras.CubicHecke(2) + sage: GER = CHA3.extension_ring(generic=True) + sage: cha_db = CHA3._database + sage: rt = CHA3.repr_type + sage: m1 =cha_db.read_matrix_representation(rt.SplitIrredMarin, 1, 3, GER) + sage: len(m1) + 7 + sage: GBR = CHA3.base_ring(generic=True) + sage: m1rl = cha_db.read_matrix_representation(rt.RegularLeft, 1, 3, GBR) + sage: m1rl[0].dimensions() + (24, 24) + """ + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType, GenSign + if not isinstance(representation_type, RepresentationType): + raise TypeError('representation_type must be an instance of enum %s' (RepresentationType)) + + num_rep = representation_type.number_of_representations(nstrands) + rep_list = self.read(representation_type.data_filename(), nstrands=nstrands) + if gen_ind > 0 : + rep_list = [rep_list[GenSign.pos][i] for i in range(num_rep)] + matrix_list = [matrix(ring_of_definition, rep[gen_ind-1 ], sparse=True) for rep in rep_list] + else: + # data of inverse of generators is stored under negative strand-index + rep_list = [rep_list[GenSign.neg][i] for i in range(num_rep) ] + matrix_list = [matrix(ring_of_definition, rep[-gen_ind-1 ], sparse=True) for rep in rep_list] + for m in matrix_list: m.set_immutable() + return matrix_list + + + + +class CubicHeckeFileCache(SageObject): + """ + A class to cache calculations of the :class:`CubicHeckeAlgebra` in the local file system. + """ + + class section(Enum): + r""" + Enum for the different sections of file cache. The following choices are possible: + + - ``matrix_representations`` -- file cache for representation matrices of basis elements + - ``braid_images`` -- file cache for images of braids + - ``basis_extensions`` -- file cache for a dynamical growing basis used in the case of + cubic Hecke algebras on more than 4 strands + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: cha_fc = CubicHeckeFileCache(CHA2) + sage: cha_fc.section + + """ + + def filename(self, nstrands=None): + r""" + Return the file name under which the data of this file cache section + is stored as an sobj-file. + + INPUT: + + - ``nstrands`` -- Integer number of strands of the underlying braid group + if the data file depends on it. Otherwise use default None + + Examples:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: cha_fc = CubicHeckeFileCache(CHA2) + sage: cha_fc.section.matrix_representations.filename(2) + 'matrix_representations_2.sobj' + sage: cha_fc.section.braid_images.filename(2) + 'braid_images_2.sobj' + """ + if nstrands is None: + return '%s.sobj' %(self.value) + else: + return '%s_%s.sobj' %(self.value, nstrands) + + matrix_representations = 'matrix_representations' + braid_images = 'braid_images' + basis_extensions = 'basis_extensions' + + + def __init__(self, num_strands): + r""" + Python constructor. + + INPUT: + + - ``cubic_hecke_algebra`` -- instance of :class:`CubicHeckeAlgebra` + whose data should be cached in the file system. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha_fc = CubicHeckeFileCache(2) + sage: cha_fc._file_cache_path == 'cubic_hecke' + True + """ + self._nstrands = num_strands + self._file_cache_path = 'cubic_hecke' + self._data_library = {} + + from sage.misc.misc import sage_makedirs + from sage.misc.persist import SAGE_DB + sage_makedirs(os.path.join(SAGE_DB, self._file_cache_path)) + + def reset_library(self, section=None): + r""" + Reset the file cache corresponding to the specified ``section``. + + INPUT: + + - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + to select the section of the file cache or ``None`` (default) + meaning all sections + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha2_fc = CubicHeckeFileCache(2) + sage: cha2_fc.reset_library(cha2_fc.section.braid_images) + sage: cha2_fc.read(cha2_fc.section.braid_images) + {} + sage: cha2_fc.reset_library(cha2_fc.section.matrix_representations) + sage: data_mat = cha2_fc.read(cha2_fc.section.matrix_representations) + sage: len(data_mat.keys()) + 4 + """ + if section is None: + for sec in self.section: + self.reset_library(section=sec) + return + + if not isinstance(section, CubicHeckeFileCache.section): + raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + data_lib = self._data_library + empty_dict = {} + if section == self.section.matrix_representations: + for rep_type in RepresentationType: + new_dict={} + empty_dict.update({rep_type:new_dict}) + elif section == self.section.basis_extensions: + empty_dict = [] + data_lib.update({section:empty_dict}) + + + def is_empty(self, section=None): + r""" + Return ``True`` if the cache of the given ``section`` is empty. + + INPUT: + + - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + to select the section of the file cache or ``None`` (default) + meaning all sections + + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha2_fc = CubicHeckeFileCache(2) + sage: cha2_fc.reset_library() + sage: cha2_fc.is_empty() + True + """ + if section is None: + return all(self.is_empty(section=sec) for sec in self.section) + + if not isinstance(section, CubicHeckeFileCache.section): + raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + + self.read(section) + data_lib = self._data_library[section] + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + if section == self.section.matrix_representations: + for rep_type in RepresentationType: + if len(data_lib[rep_type]) > 0: + return False + return True + + if section == self.section.basis_extensions and self._nstrands > 4: + # the new generators and their inverses are not counted + # since they are added during initialization + return len(data_lib) <= 2*(self._nstrands -4) + return len(data_lib) == 0 + + + + # ------------------------------------------------------------------------------------------------------------- + # save data file system + # ------------------------------------------------------------------------------------------------------------- + def write(self, section=None): + r""" + Write data from memory to the file system. + + INPUT: + + - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + specifying the section where the corresponding cached data belong to. + If omitted data of all sections is written to the file system + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha2_fc = CubicHeckeFileCache(2) + sage: cha2_fc.reset_library(cha2_fc.section.braid_images) + sage: cha2_fc.write(cha2_fc.section.braid_images) + """ + data_lib = self._data_library + lib_path = self._file_cache_path + + if section is None: + for sec in self.section: + if sec in data_lib.keys(): + self.write(section=sec) + return + + if not isinstance(section, CubicHeckeFileCache.section): + raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + + if section not in data_lib.keys(): + raise ValueError("No data for file %s in memory" %(section)) + + db_save(data_lib[section], '%s/%s' %(lib_path, section.filename(self._nstrands))) + + + # ------------------------------------------------------------------------------------------------------------- + # read from file system + # ------------------------------------------------------------------------------------------------------------- + def read(self, section): + r""" + Read data into memory from the file system. + + + INPUT: + + - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + specifying the section where the corresponding cached data belong to + + OUTPUT: + + Dictionary containing the data library corresponding to the section + of file cache + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha2_fc = CubicHeckeFileCache(2) + sage: cha2_fc.reset_library(cha2_fc.section.braid_images) + sage: cha2_fc.read(cha2_fc.section.braid_images) + {} + """ + if not isinstance(section, CubicHeckeFileCache.section): + raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + + data_lib = self._data_library + lib_path = self._file_cache_path + + if section in data_lib.keys(): + return data_lib[section] + + verbose('loading file cache %s ...' %(section)) + try: + data_lib[section] = db('%s/%s' %(lib_path, section.filename(self._nstrands))) + verbose('... finished!') + except IOError: + self.reset_library(section) + verbose('... not found!') + + return data_lib[section] + + + + + # ------------------------------------------------------------------------------------------------------------- + # matrix_reprs_from_file_cache_ + # ------------------------------------------------------------------------------------------------------------- + def read_matrix_representation(self, representation_type, monomial_tietze, ring_of_definition): + r""" + Return the matrix representations of the given monomial (in Tietze form) + if it has been stored in the file cache before. Otherwise ``None`` is returned. + + INPUT: + + - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + specifying the type of the representation + + - ``monomial_tietze`` -- tuple representing the braid in Tietze form + + - ``ring_of_definition`` -- instance of :class:`CubicHeckeRingOfDefinition` resp. + :class:`CubicHeckeExtensionRing` (depending wether ``representation_type`` + is split or not) + + OUTPUT: + + Dictionary containing all matrix representations of ``self`` of the given representation_type + which have been stored in the file cache. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: R = CHA2.base_ring(generic=True) + sage: cha_fc = CHA2._filecache + sage: g, = CHA2.gens(); gt = g.Tietze() + sage: rt = CHA2.repr_type + sage: g.matrix(representation_type=rt.RegularLeft) + [ 0 -v 1] + [ 1 u 0] + [ 0 w 0] + sage: [_] == cha_fc.read_matrix_representation(rt.RegularLeft, gt, R) + True + sage: cha_fc.reset_library(cha_fc.section.matrix_representations) + sage: cha_fc.write(cha_fc.section.matrix_representations) + sage: cha_fc.read_matrix_representation(rt.RegularLeft, gt, R) == None + True + """ + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + if not isinstance(representation_type, RepresentationType): + raise TypeError('representation_type must be an instance of enum %s' (RepresentationType)) + + matrix_representations = self.read(self.section.matrix_representations)[representation_type] + if monomial_tietze in matrix_representations.keys(): + matrix_list_dict = matrix_representations[monomial_tietze] + matrix_list = [matrix(ring_of_definition, mat_dict, sparse=True) for mat_dict in matrix_list_dict] + for m in matrix_list: m.set_immutable() + return matrix_list + return None + + + + + # ------------------------------------------------------------------------------------------------------------- + # matrix_representation to file cache + # ------------------------------------------------------------------------------------------------------------- + def write_matrix_representation(self, representation_type, monomial_tietze, matrix_list): + r""" + Write the matrix representation of a monomial to the file cache. + + INPUT: + + - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + specifying the type of the representation + + - ``monomial_tietze`` -- tuple representing the braid in Tietze form + + - ``matrix_list`` -- list of matrices corresponding to the irreducible representations + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: R = CHA2.base_ring(generic=True) + sage: cha_fc = CHA2._filecache + sage: g, = CHA2.gens(); gi = ~g; git = gi.Tietze() + sage: rt = CHA2.repr_type + sage: m = gi.matrix(representation_type=rt.RegularRight) + sage: cha_fc.read_matrix_representation(rt.RegularRight, git, R) + [ + [ 0 1 (-w^-1)*u] + [ 0 0 w^-1] + [ 1 0 (w^-1)*v] + ] + sage: CHA2.reset_filecache(cha_fc.section.matrix_representations) + sage: cha_fc.read_matrix_representation(rt.RegularLeft, git, R) == None + True + sage: cha_fc.write_matrix_representation(rt.RegularRight, git, [m]) + sage: [m] == cha_fc.read_matrix_representation(rt.RegularRight, git, R) + True + """ + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + if not isinstance(representation_type, RepresentationType): + raise TypeError('representation_type must be an instance of enum %s' (RepresentationType)) + + matrix_representations = self.read(self.section.matrix_representations)[representation_type] + + if monomial_tietze in matrix_representations.keys(): + # entry already registered + return + + matrix_representation_dict = [convert_mat_to_dict_recursive(mat) for mat in list(matrix_list)] + matrix_representations[monomial_tietze] = matrix_representation_dict + + self.write(self.section.matrix_representations) + return + + # ------------------------------------------------------------------------------------------------------------- + # read braid images from file cache + # ------------------------------------------------------------------------------------------------------------- + def read_braid_image(self, braid_tietze, ring_of_definition): + r""" + Return the list of pre calculated braid images from file cache. + + INPUT: + + - ``braid_tietze`` -- tuple representing the braid in Tietze form + + - ``ring_of_definition`` -- instance of :class:`CubicHeckeRingOfDefinition` + + OUTPUT: + + A dictionary containing the pre calculated braid image of the given braid. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: ring_of_definition = CHA2.base_ring(generic=True) + sage: cha_fc = CubicHeckeFileCache(2) + sage: B2 = BraidGroup(2) + sage: b, = B2.gens(); b2 = b**2 + sage: cha_fc.is_empty(CubicHeckeFileCache.section.braid_images) + True + sage: b2_img = CHA2(b2); b2_img + (-v) + u*c + w*c^-1 + sage: cha_fc.write_braid_image(b2.Tietze(), b2_img.to_vector()) + sage: cha_fc.read_braid_image(b2.Tietze(), ring_of_definition) + (-v, u, w) + """ + braid_images = self.read(self.section.braid_images) + if braid_tietze in braid_images.keys(): + braid_image = braid_images[braid_tietze] + result_list = [ring_of_definition(cf) for cf in list(braid_image)] + from sage.modules.free_module_element import vector + return vector(ring_of_definition, result_list) + return None + + + + + + # ------------------------------------------------------------------------------------------------------------- + # braid image to_file cache + # ------------------------------------------------------------------------------------------------------------- + def write_braid_image(self, braid_tietze, braid_image_vect): + r""" + Write the braid image of the given braid to the file cache. + + INPUT: + + - ``braid_tietze`` -- tuple representing the braid in Tietze form + - ``braid_image_vect`` -- image of the given braid as a vector with respect + to the basis of the cubic Hecke algebra + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: ring_of_definition = CHA2.base_ring(generic=True) + sage: cha_fc = CubicHeckeFileCache(2) + sage: B2 = BraidGroup(2) + sage: b, = B2.gens(); b3 = b**3 + sage: b3_img = CHA2(b3); b3_img + (-u*v+w) + (u^2-v)*c + w*u*c^-1 + sage: cha_fc.write_braid_image(b3.Tietze(), b3_img.to_vector()) + sage: cha_fc.read_braid_image(b3.Tietze(), ring_of_definition) + (-u*v + w, u^2 - v, w*u) + sage: cha_fc.reset_library(CubicHeckeFileCache.section.braid_images) + sage: cha_fc.write(CubicHeckeFileCache.section.braid_images) + sage: cha_fc.is_empty(CubicHeckeFileCache.section.braid_images) + True + """ + braid_images = self.read(self.section.braid_images) + + if braid_tietze in braid_images.keys(): + # entry already registered + return + + braid_image_dict = [convert_poly_to_dict_recursive(cf) for cf in list(braid_image_vect)] + braid_images[braid_tietze] = braid_image_dict + + self.write(self.section.braid_images) + return + + + # ------------------------------------------------------------------------------------------------------------- + # basis to file cache + # ------------------------------------------------------------------------------------------------------------- + def update_basis_extensions(self, new_basis_extensions): + r""" + Update the file cache for basis extensions for cubic Hecke algebras on more than 4 strands + according to the given ``new_basis_extensions``. + + INPUT: + + - ``new_basis_extensions`` -- list of additional (to the static basis) basis elements which should + replace the former such list in the file. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: CHA2 = algebras.CubicHecke(2) + sage: cha_fc = CubicHeckeFileCache(2) + sage: cha_fc.is_empty(CubicHeckeFileCache.section.basis_extensions) + True + sage: cha_fc.update_basis_extensions([(1,), (-1,)]) + sage: cha_fc.read(CubicHeckeFileCache.section.basis_extensions) + [(1,), (-1,)] + sage: cha_fc.reset_library(CubicHeckeFileCache.section.basis_extensions) + sage: cha_fc.write(CubicHeckeFileCache.section.basis_extensions) + sage: cha_fc.is_empty(CubicHeckeFileCache.section.basis_extensions) + True + """ + self._data_library.update({self.section.basis_extensions:new_basis_extensions}) + self.write(self.section.basis_extensions) + return From 8c8a522d2ddc940aa116d549936bf3a477548679 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Thu, 21 May 2020 11:01:36 +0200 Subject: [PATCH 002/591] 29717: fix upstream_url and some docs --- build/pkgs/cubic_hecke_marin/checksums.ini | 8 ++++---- src/doc/en/reference/databases/index.rst | 1 + src/sage/databases/cubic_hecke_db.py | 19 +++++++++++-------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/build/pkgs/cubic_hecke_marin/checksums.ini b/build/pkgs/cubic_hecke_marin/checksums.ini index 299e4ddd97a..1a319078d88 100644 --- a/build/pkgs/cubic_hecke_marin/checksums.ini +++ b/build/pkgs/cubic_hecke_marin/checksums.ini @@ -1,5 +1,5 @@ tarball=cubic_hecke_marin-20200513.tar.bz2 -sha1=0afb0716b224b66fdd67b9b6e75b911030d15e1c -md5=3ee0a0a4fc5a7739ad9932391d2d10b5 -cksum=398008749 -upstream_url=https://trac.sagemath.org/attachment/ticket/29717/cubic_hecke_marin-20200513.tar.bz2 +sha1=db05c5cb7a70b6c6987a1ece67e0a6fc4d11e1a0 +md5=7df73fad972fa6eee774aaae05ecd481 +cksum=3934881041 +upstream_url=https://trac.sagemath.org/raw-attachment/ticket/29717/cubic_hecke_marin-20200513.tar.bz2 diff --git a/src/doc/en/reference/databases/index.rst b/src/doc/en/reference/databases/index.rst index 5c198d9dcdf..49480e62819 100644 --- a/src/doc/en/reference/databases/index.rst +++ b/src/doc/en/reference/databases/index.rst @@ -62,5 +62,6 @@ database engine. sage/databases/cunningham_tables sage/databases/db_class_polynomials sage/databases/db_modular_polynomials + sage/databases/cubic_hecke_db .. include:: ../footer.txt diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index dd97f86054f..c51efdeb67c 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -318,21 +318,24 @@ def _create_python_file(self, filename): def create_spkg_tarball(self): r""" - Create a tarball for the sage-package `cubic_heck_marin` in the `upstream` directory. This + Create a tarball for the sage-package ``cubic_heck_marin`` in the ``upstream`` directory. This utility should only be used by users who know what they do in case of a switch to a new version of the data files (that is if the original files on Iwan Marin's homepage have changed). - In that case in invocation of `sage -package update cubic_hecke_marin ` and - `sage -package update cubic_hecke_marin` will be necessary. + In that case in invocation of ``sage -package fix-checksum cubic_hecke_marin`` will be necessary. EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase sage: cha_db = CubicHeckeDataBase() - sage: cha_db.create_spkg_tarball() # not tested (because of internet access) - Importing data for monomial_basis.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/baseH4.maple - Importing data for regular_left_reprs.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4.maple - Importing data for regular_right_reprs.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4right.maple - Importing data for irred_split_reprs.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/RepresentationsH25 + sage: cha_db.create_spkg_tarball() # not tested (because of internet access) + Importing data for monomial_basis.sobj + from http://www.lamfa.u-picardie.fr/marin/softs/H4/baseH4.maple + Importing data for regular_left_reprs.sobj + from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4.maple + Importing data for regular_right_reprs.sobj + from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4right.maple + Importing data for irred_split_reprs.sobj + from http://www.lamfa.u-picardie.fr/marin/softs/H4/RepresentationsH25 py/ py/MatricesRegH4.maple.py py/MatricesRegH4right.maple.py From 637e7815345896e65181f900497ff0b2fd9e825c Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Sun, 24 May 2020 08:43:56 +0200 Subject: [PATCH 003/591] 29717: fix optional gap3 doctest --- src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 234f358c53b..bc403769328 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -360,7 +360,7 @@ def matrix(self, subdivide=False, representation_type=None, original=False): using the the ``representation_type`` option:: sage: CHA3. = algebras.CubicHecke(3) # optional gap3 - sage: chevie = CHA3.repr_type.SplitIrredChevie + sage: chevie = CHA3.repr_type.SplitIrredChevie # optional gap3 sage: c0m_ch = c0.matrix(representation_type=chevie) # optional gap3 sage: c0m_ch[CHA3.irred_repr.W3_011] # optional gap3 [ b 0] From aea3c5ac50e3d1dc9cb98df681db98691b7b56e9 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Fri, 31 Jul 2020 22:05:50 +0200 Subject: [PATCH 004/591] 29717: adaption to ticket 17815 --- build/pkgs/cubic_hecke_marin/SPKG.txt | 2 +- build/pkgs/cubic_hecke_marin/type | 2 +- .../base_rings_of_definition/cubic_hecke_base_ring.py | 2 +- src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py | 2 +- .../matrix_representations/cubic_hecke_matrix_rep.py | 2 +- src/sage/databases/cubic_hecke_db.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/pkgs/cubic_hecke_marin/SPKG.txt b/build/pkgs/cubic_hecke_marin/SPKG.txt index bbfeae7f9d7..ff9dbab97f7 100644 --- a/build/pkgs/cubic_hecke_marin/SPKG.txt +++ b/build/pkgs/cubic_hecke_marin/SPKG.txt @@ -13,5 +13,5 @@ as given on 'http://www.lamfa.u-picardie.fr/marin/softs/H4 === cubic_hecke_marin-20200513.tar.bz2 (Sebastian Oehms, 13 May 2020) === - * #?????: Initial version + * #29717: Initial version diff --git a/build/pkgs/cubic_hecke_marin/type b/build/pkgs/cubic_hecke_marin/type index a6a7b9cd726..134d9bc32d5 100644 --- a/build/pkgs/cubic_hecke_marin/type +++ b/build/pkgs/cubic_hecke_marin/type @@ -1 +1 @@ -standard +optional diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py index a89f3f51b5b..6787bf2d548 100644 --- a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py @@ -27,7 +27,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element import get_coercion_model from sage.categories.action import Action -from sage.misc.misc import verbose +from sage.misc.verbose import verbose from sage.misc.functional import cyclotomic_polynomial from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index bc403769328..bd2f995bfb0 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -123,7 +123,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.misc.cachefunc import cached_method -from sage.misc.misc import verbose +from sage.misc.verbose import verbose from sage.groups.cubic_braid import CubicBraidGroup from sage.rings.integer_ring import ZZ from sage.algebras.splitting_algebra import solve_with_extension diff --git a/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py index cebfb979f26..e0037a390ae 100644 --- a/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py @@ -30,7 +30,7 @@ from enum import Enum from sage.misc.cachefunc import cached_method -from sage.misc.misc import verbose +from sage.misc.verbose import verbose from sage.rings.integer import Integer from sage.matrix.matrix_generic_dense import Matrix_generic_dense from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index c51efdeb67c..c6bfa751ba2 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -29,7 +29,7 @@ from sage.structure.sage_object import SageObject from sage.misc.persist import db_save, db, save, load -from sage.misc.misc import verbose +from sage.misc.verbose import verbose from sage.env import SAGE_SHARE, SAGE_ROOT from sage.matrix.constructor import matrix, Matrix # uppercase version used in Marin's file `MatricesRegH4.maple` from sage.rings.integer_ring import ZZ From 878cd81b21c7c13e6b7ece9a1167f3dd8f96634a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 2 Oct 2021 10:12:42 +0900 Subject: [PATCH 005/591] Initial rebase of lazy Taylor and SymFuncs. --- src/sage/rings/all.py | 3 +- src/sage/rings/lazy_series.py | 433 ++++++++++++++-- src/sage/rings/lazy_series_ring.py | 768 ++++++++++++++++++++++++++++- 3 files changed, 1164 insertions(+), 40 deletions(-) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index a8a1da9ff3d..1739b09cdaf 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -120,7 +120,8 @@ from .laurent_series_ring_element import LaurentSeries # Lazy Laurent series ring -lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyDirichletSeriesRing']) +lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyTaylorSeriesRing', + 'LazySymmetricFunctions', 'LazyDirichletSeriesRing']) # Tate algebras from .tate_algebra import TateAlgebra diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 23b0027456e..35818298dfe 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -858,7 +858,6 @@ def _unicode_art_(self): return UnicodeArt('Uninitialized Lazy Laurent Series') return self._format_series(unicode_art, True) - def change_ring(self, ring): r""" Return ``self`` with coefficients converted to elements of ``ring``. @@ -906,6 +905,16 @@ def change_ring(self, ring): Lazy Dirichlet Series Ring in z over Rational Field sage: t^-1 1/2 - 1/2/2^z - 1/2/3^z - 1/2/5^z + 1/2/6^z - 1/2/7^z + O(1/(8^z)) + + A Taylor series example:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: s = 2 + z + sage: t = s.change_ring(QQ) + sage: t^-1 + 1/2 - 1/4*z + 1/8*z^2 - 1/16*z^3 + 1/32*z^4 - 1/64*z^5 + 1/128*z^6 + O(z^7) + sage: t.parent() + Lazy Taylor Series Ring in z over Rational Field """ P = self.parent() Q = type(P)(ring, names=P.variable_names(), sparse=P._sparse) @@ -1302,10 +1311,10 @@ def exp(self): ... ValueError: can only compose with a positive valuation series - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: exp(x+y)[4].factor() # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: exp(x+y)[4].factor() (1/24) * (x + y)^4 - sage: exp(x/(1-y)).finite_part(3) # not tested + sage: exp(x/(1-y)).finite_part(3) 1/6*x^3 + x^2*y + x*y^2 + 1/2*x^2 + x*y + x + 1 TESTS:: @@ -1329,8 +1338,8 @@ def log(self): sage: log(1/(1-z)) z + 1/2*z^2 + 1/3*z^3 + 1/4*z^4 + 1/5*z^5 + 1/6*z^6 + 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: log((1 + x/(1-y))).finite_part(3) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: log((1 + x/(1-y))).finite_part(3) 1/3*x^3 - x^2*y + x*y^2 + (-1/2)*x^2 + x*y + x TESTS:: @@ -1366,8 +1375,8 @@ def sin(self): ... ValueError: can only compose with a positive valuation series - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: sin(x/(1-y)).finite_part(3) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: sin(x/(1-y)).finite_part(3) (-1/6)*x^3 + x*y^2 + x*y + x TESTS:: @@ -1392,8 +1401,8 @@ def cos(self): sage: cos(z) 1 - 1/2*z^2 + 1/24*z^4 - 1/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: cos(x/(1-y)).finite_part(4) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: cos(x/(1-y)).finite_part(4) 1/24*x^4 + (-3/2)*x^2*y^2 - x^2*y + (-1/2)*x^2 + 1 TESTS:: @@ -1418,8 +1427,8 @@ def tan(self): sage: tan(z) z + 1/3*z^3 + 2/15*z^5 + 17/315*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: tan(x/(1-y)).finite_part(5) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: tan(x/(1-y)).finite_part(5) 2/15*x^5 + 2*x^3*y^2 + x*y^4 + x^3*y + x*y^3 + 1/3*x^3 + x*y^2 + x*y + x TESTS:: @@ -1484,8 +1493,8 @@ def sec(self): sage: sec(z) 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: sec(x/(1-y)).finite_part(4) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: sec(x/(1-y)).finite_part(4) 5/24*x^4 + 3/2*x^2*y^2 + x^2*y + 1/2*x^2 + 1 TESTS:: @@ -1508,8 +1517,8 @@ def arcsin(self): sage: arcsin(z) z + 1/6*z^3 + 3/40*z^5 + 5/112*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: asin(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: asin(x/(1-y)) x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (3/40*x^5+x^3*y^2+x*y^4) + (3/8*x^5*y+5/3*x^3*y^3+x*y^5) + (5/112*x^7+9/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1545,8 +1554,8 @@ def arccos(self): sage: arccos(z/(1-z)) 1/2*pi - z - z^2 - 7/6*z^3 - 3/2*z^4 - 83/40*z^5 - 73/24*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) # not tested - sage: arccos(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(SR) + sage: arccos(x/(1-y)) 1/2*pi + (-x) + (-x*y) + ((-1/6)*x^3-x*y^2) + ((-1/2)*x^3*y-x*y^3) + ((-3/40)*x^5-x^3*y^2-x*y^4) + ((-3/8)*x^5*y+(-5/3)*x^3*y^3-x*y^5) + O(x,y)^7 @@ -1569,8 +1578,8 @@ def arctan(self): sage: arctan(z) z - 1/3*z^3 + 1/5*z^5 - 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: atan(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: atan(x/(1-y)) x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + (1/5*x^5+(-2)*x^3*y^2+x*y^4) + (x^5*y+(-10/3)*x^3*y^3+x*y^5) + ((-1/7)*x^7+3*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1608,8 +1617,8 @@ def arccot(self): sage: arccot(z/(1-z)) 1/2*pi - z - z^2 - 2/3*z^3 + 4/5*z^5 + 4/3*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) # not tested - sage: acot(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(SR) + sage: acot(x/(1-y)) 1/2*pi + (-x) + (-x*y) + (1/3*x^3-x*y^2) + (x^3*y-x*y^3) + ((-1/5)*x^5+2*x^3*y^2-x*y^4) + (-x^5*y+10/3*x^3*y^3-x*y^5) + O(x,y)^7 @@ -1634,8 +1643,8 @@ def sinh(self): sage: sinh(z) z + 1/6*z^3 + 1/120*z^5 + 1/5040*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: sinh(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: sinh(x/(1-y)) x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (1/120*x^5+x^3*y^2+x*y^4) + (1/24*x^5*y+5/3*x^3*y^3+x*y^5) + (1/5040*x^7+1/8*x^5*y^2+5/2*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1662,8 +1671,8 @@ def cosh(self): sage: cosh(z) 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: cosh(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: cosh(x/(1-y)) 1 + 1/2*x^2 + x^2*y + (1/24*x^4+3/2*x^2*y^2) + (1/6*x^4*y+2*x^2*y^3) + (1/720*x^6+5/12*x^4*y^2+5/2*x^2*y^4) + O(x,y)^7 @@ -1689,8 +1698,8 @@ def tanh(self): sage: tanh(z) z - 1/3*z^3 + 2/15*z^5 - 17/315*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: tanh(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: tanh(x/(1-y)) x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) + (2/15*x^5+(-2)*x^3*y^2+x*y^4) + (2/3*x^5*y+(-10/3)*x^3*y^3+x*y^5) + ((-17/315)*x^7+2*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1751,8 +1760,8 @@ def sech(self): sage: sech(z) 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: sech(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: sech(x/(1-y)) 1 + ((-1/2)*x^2) + (-x^2*y) + (5/24*x^4+(-3/2)*x^2*y^2) + (5/6*x^4*y+(-2)*x^2*y^3) + ((-61/720)*x^6+25/12*x^4*y^2+(-5/2)*x^2*y^4) + O(x,y)^7 @@ -1816,8 +1825,8 @@ def arcsinh(self): sage: asinh(z) z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: asinh(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: asinh(x/(1-y)) x + x*y + ((-1/6)*x^3+x*y^2) + ((-1/2)*x^3*y+x*y^3) + (3/40*x^5-x^3*y^2+x*y^4) + (3/8*x^5*y+(-5/3)*x^3*y^3+x*y^5) + ((-5/112)*x^7+9/8*x^5*y^2+(-5/2)*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1849,8 +1858,8 @@ def arctanh(self): sage: atanh(z) z + 1/3*z^3 + 1/5*z^5 + 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: atanh(x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: atanh(x/(1-y)) x + x*y + (1/3*x^3+x*y^2) + (x^3*y+x*y^3) + (1/5*x^5+2*x^3*y^2+x*y^4) + (x^5*y+10/3*x^3*y^3+x*y^5) + (1/7*x^7+3*x^5*y^2+5*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1945,8 +1954,8 @@ def sqrt(self): sage: sqrt(1+z) 1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) # not tested - sage: sqrt(1+x/(1-y)) # not tested + sage: L. = LazyTaylorSeriesRing(QQ) + sage: sqrt(1+x/(1-y)) 1 + 1/2*x + ((-1/8)*x^2+1/2*x*y) + (1/16*x^3+(-1/4)*x^2*y+1/2*x*y^2) + ((-5/128)*x^4+3/16*x^3*y+(-3/8)*x^2*y^2+1/2*x*y^3) + (7/256*x^5+(-5/32)*x^4*y+3/8*x^3*y^2+(-1/2)*x^2*y^3+1/2*x*y^4) @@ -3095,6 +3104,348 @@ def _format_series(self, formatter, format_strings=False): return strformat("O({})".format(formatter(z**m))) return formatter(poly) + strformat(" + O({})".format(formatter(z**m))) +class LazyTaylorSeries(LazyCauchyProductSeries): + r""" + A Taylor series where the coefficients are computed lazily. + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: f = 1 / (1 - x^2 + y^3); f + 1 + x^2 + (-y^3) + x^4 + (-2*x^2*y^3) + (x^6+y^6) + O(x,y)^7 + sage: P. = PowerSeriesRing(ZZ, default_prec=101) + sage: g = 1 / (1 - x^2 + y^3); f[100] - g[100] + 0 + + Lazy Taylor series is picklable:: + + sage: g = loads(dumps(f)) + sage: g + 1 + x^2 + (-y^3) + x^4 + (-2*x^2*y^3) + (x^6+y^6) + O(x,y)^7 + sage: g == f + True + """ + def __call__(self, *g): + r""" + Return the composition of ``self`` with ``g``. + + The arity of ``self`` must be equal to the number of + arguments provided. + + Given two Taylor Series `f` and `g` over the same base ring, the + composition `(f \circ g)(z) = f(g(z))` is defined if and only if: + + - `g = 0` and `val(f) >= 0`, + - `g` is non-zero and `f` has only finitely many non-zero coefficients, + - `g` is non-zero and `val(g) > 0`. + + INPUT: + + - ``g`` -- other series, all of the same parent. + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: M. = LazyTaylorSeriesRing(ZZ) + sage: g1 = 1/(1-x); g2 = x+y^2 + sage: p = a^2 + b + 1 + sage: p(g1, g2) - g1^2 - g2 - 1 + O(x,y,z)^7 + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: M. = LazyTaylorSeriesRing(QQ) + + The number of mappings from a set with `m` elements to a set + with `n` elements:: + + sage: Ea = M(lambda n: 1/factorial(n)) + sage: Ex = L(lambda n: 1/factorial(n)*x^n) + sage: Ea(Ex*y)[5] + 1/24*x^4*y + 2/3*x^3*y^2 + 3/4*x^2*y^3 + 1/6*x*y^4 + 1/120*y^5 + + So, there are `3! 2! 2/3 = 8` mappings from a three element + set to a two element set. + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: f = 1/(1-x-y) + sage: f(f) + Traceback (most recent call last): + ... + ValueError: arity of must be equal to the number of arguments provided + + """ + if len(g) != len(self.parent().variable_names()): + raise ValueError("arity of must be equal to the number of arguments provided") + + # f has finite length + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: + # constant polynomial + poly = self.finite_part() + if poly.is_constant(): + return self + return poly(g) + + g0 = g[0] + P = g0.parent() + R = P._coeff_ring + if len(g) == 1: + # we assume that the valuation of self[i](g) is at least i + def coefficient(n): + r = R(0) + for i in range(n+1): + r += self[i]*(g0 ** i)[n] + return r + else: + def coefficient(n): + r = R(0) + for i in range(n+1): + r += self[i](g)[n] + return r + coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 0) + return P.element_class(P, coeff_stream) + + def _format_series(self, formatter, format_strings=False): + """ + Return nonzero ``self`` formatted by ``formatter``. + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: f = 1 / (2 - x^2 + y) + sage: f._format_series(repr) + '1/2 + (-1/4*y) + (1/4*x^2+1/8*y^2) + (-1/4*x^2*y-1/16*y^3) + (1/8*x^4+3/16*x^2*y^2+1/32*y^4) + (-3/16*x^4*y-1/8*x^2*y^3-1/64*y^5) + (1/16*x^6+3/16*x^4*y^2+5/64*x^2*y^4+1/128*y^6) + O(x,y)^7' + + sage: f = (2 - x^2 + y) + sage: f._format_series(repr) + '2 + y + (-x^2)' + """ + P = self.parent() + cs = self._coeff_stream + v = cs._approximate_order + if isinstance(cs, Stream_exact): + if not cs._constant: + m = cs._degree + else: + m = cs._degree + P.options.constant_length + else: + m = v + P.options.display_length + + atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] + if not isinstance(cs, Stream_exact) or cs._constant: + if P._coeff_ring is P.base_ring(): + bigO = ["O(%s)" % P._monomial(1, m)] + else: + bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] + else: + bigO = [] + + from sage.misc.latex import latex + from sage.typeset.unicode_art import unicode_art + from sage.typeset.ascii_art import ascii_art + from sage.misc.repr import repr_lincomb + from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis + from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: + poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) + elif formatter == latex: + poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) + elif formatter == ascii_art: + if atomic_repr: + poly = ascii_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = ascii_art(m) + h = a.height() + return ascii_art(ascii_left_parenthesis.character_art(h), + a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + elif formatter == unicode_art: + if atomic_repr: + poly = unicode_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = unicode_art(m) + h = a.height() + return unicode_art(unicode_left_parenthesis.character_art(h), + a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + + return poly + + +class LazySymmetricFunction(LazyCauchyProductSeries): + r""" + A symmetric function where each degree is computed lazily. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(ZZ, "x") + """ + def __call__(self, *args): + r""" + Return the composition of ``self`` with ``args``. + + The arity of ``self`` must be equal to the number of + arguments provided. + + Given two lazy symmetric functions `f` and `g` over the same + base ring, the composition (or plethysm) `(f \circ g)` is + defined if and only if: + + - `g = 0`, + - `g` is non-zero and `f` has only finitely many non-zero coefficients, + - `g` is non-zero and `val(g) > 0`. + + INPUT: + + - ``args`` -- other (lazy) symmetric functions. + + EXAMPLES:: + + sage: P. = QQ[] + sage: s = SymmetricFunctions(P).s() + sage: L = LazySymmetricFunctions(P, "x") + sage: f = s[2]; g = s[3] + sage: L(f)(L(g)) - L(f(g)) + O(x)^7 + + sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] + sage: L(f)(L(g)) - L(f(g)) + O(x)^7 + + sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] + sage: L(f)(L(q*g)) - L(f(q*g)) + O(x)^7 + + The Frobenius character of the permutation action on set + partitions is a plethysm:: + + sage: s = SymmetricFunctions(QQ).s() + sage: S = LazySymmetricFunctions(QQ, "x") + sage: E1 = S(lambda n: s[n], valuation=1) + sage: E = 1 + E1 + sage: P = E(E1) + sage: [s(x) for x in P[:5]] + [s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]] + + """ + if len(args) != len(self.parent().variable_names()): + raise ValueError("arity must be equal to the number of arguments provided") + from sage.combinat.sf.sfa import is_SymmetricFunction + if not all(isinstance(g, LazySymmetricFunction) or is_SymmetricFunction(g) for g in args): + raise ValueError("all arguments must be (possibly lazy) symmetric functions") + from sage.misc.lazy_list import lazy_list + if len(args) == 1: + g = args[0] + P = g.parent() + R = P._coeff_ring + BR = P.base_ring() + p = R.realization_of().power() + g_p = Stream_map_coefficients(g._coeff_stream, lambda c: c, p) + try: + degree_one = [BR(x) for x in BR.variable_names_recursive()] + except AttributeError: + try: + degree_one = BR.gens() + except NotImplementedError: + degree_one = [] + def raise_c(n): + return lambda c: c.subs(**{str(x): x ** n for x in degree_one}) + def scale_part(n): + return lambda m: m.__class__(m.parent(), [i * n for i in m]) + def pn_pleth(f, n): + return f.map_support(scale_part(n)) + def stretched_coefficient(k, n): + q, r = ZZ(n).quo_rem(k) + if r: + return 0 + c = g_p[q] + if c: + return pn_pleth(c.map_coefficients(raise_c(k)), k) + return c + def g_coeff_stream(k): + return Stream_function(lambda n: stretched_coefficient(k, n), + R, P._sparse, 0) + stretched = lazy_list(lambda k: g_coeff_stream(k)) + f_p = Stream_map_coefficients(self._coeff_stream, lambda c: c, p) + def coefficient(n): + r = R(0) + for i in range(n+1): + r += p._apply_module_morphism(f_p[i], + lambda part: p.prod(sum(stretched[j][h] for h in range(n+1)) + for j in part), + codomain=p).homogeneous_component(n) + return r + else: + raise NotImplementedError + + coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 0) + return P.element_class(P, coeff_stream) + + def _format_series(self, formatter, format_strings=False): + """ + Return nonzero ``self`` formatted by ``formatter``. + + TESTS:: + + sage: L = LazySymmetricFunctions(QQ, "x, y") + """ + P = self.parent() + cs = self._coeff_stream + v = cs._approximate_order + if isinstance(cs, Stream_exact): + if not cs._constant: + m = cs._degree + else: + m = cs._degree + P.options.constant_length + else: + m = v + P.options.display_length + + atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] + if not isinstance(cs, Stream_exact) or cs._constant: + if P._coeff_ring is P.base_ring(): + bigO = ["O(%s)" % P._monomial(1, m)] + else: + bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] + else: + bigO = [] + + from sage.misc.latex import latex + from sage.typeset.unicode_art import unicode_art + from sage.typeset.ascii_art import ascii_art + from sage.misc.repr import repr_lincomb + from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis + from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: + poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) + elif formatter == latex: + poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) + elif formatter == ascii_art: + if atomic_repr: + poly = ascii_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = ascii_art(m) + h = a.height() + return ascii_art(ascii_left_parenthesis.character_art(h), + a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + elif formatter == unicode_art: + if atomic_repr: + poly = unicode_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = unicode_art(m) + h = a.height() + return unicode_art(unicode_left_parenthesis.character_art(h), + a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + + return poly class LazyDirichletSeries(LazyModuleElement): r""" @@ -3180,8 +3531,14 @@ def _mul_(self, other): sage: L. = LazyLaurentSeriesRing(D) sage: 1/(1-t*zeta) - (1 + O(1/(8^s))) + (1 + 1/(2^s) + 1/(3^s) + 1/(4^s) + 1/(5^s) + 1/(6^s) + 1/(7^s) + O(1/(8^s)))*t + (1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)))*t^2 + (1 + 3/2^s + 3/3^s + 6/4^s + 3/5^s + 9/6^s + 3/7^s + O(1/(8^s)))*t^3 + (1 + 4/2^s + 4/3^s + 10/4^s + 4/5^s + 16/6^s + 4/7^s + O(1/(8^s)))*t^4 + (1 + 5/2^s + 5/3^s + 15/4^s + 5/5^s + 25/6^s + 5/7^s + O(1/(8^s)))*t^5 + (1 + 6/2^s + 6/3^s + 21/4^s + 6/5^s + 36/6^s + 6/7^s + O(1/(8^s)))*t^6 + O(t^7) - + (1 + O(1/(8^s))) + + (1 + 1/(2^s) + 1/(3^s) + 1/(4^s) + 1/(5^s) + 1/(6^s) + 1/(7^s) + O(1/(8^s)))*t + + (1 + 2/2^s + 2/3^s + 3/4^s + 2/5^s + 4/6^s + 2/7^s + O(1/(8^s)))*t^2 + + (1 + 3/2^s + 3/3^s + 6/4^s + 3/5^s + 9/6^s + 3/7^s + O(1/(8^s)))*t^3 + + (1 + 4/2^s + 4/3^s + 10/4^s + 4/5^s + 16/6^s + 4/7^s + O(1/(8^s)))*t^4 + + (1 + 5/2^s + 5/3^s + 15/4^s + 5/5^s + 25/6^s + 5/7^s + O(1/(8^s)))*t^5 + + (1 + 6/2^s + 6/3^s + 21/4^s + 6/5^s + 36/6^s + 6/7^s + O(1/(8^s)))*t^6 + + O(t^7) """ P = self.parent() left = self._coeff_stream diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 7ff7c45fe95..ecfa5169080 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -26,15 +26,19 @@ from sage.categories.rings import Rings from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields -from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields +from sage.categories.complete_discrete_valuation import (CompleteDiscreteValuationFields, + CompleteDiscreteValuationRings) from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.combinat.sf.sf import SymmetricFunctions from sage.rings.lazy_series import (LazyModuleElement, LazyLaurentSeries, + LazyTaylorSeries, + LazySymmetricFunction, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions from sage.symbolic.ring import SR @@ -979,6 +983,768 @@ def _monomial(self, c, n): """ return self._laurent_poly_ring(c).shift(n) +###################################################################### + +class LazyTaylorSeriesRing(UniqueRepresentation, Parent): + """ + Lazy Taylor series ring. + + INPUT: + + - ``base_ring`` -- base ring of this Taylor series ring + - ``names`` -- name(s) of the generator of this Taylor series ring + - ``sparse`` -- (default: ``True``) whether this series is sparse or not + + EXAMPLES:: + + sage: LazyTaylorSeriesRing(ZZ, 't') + Lazy Taylor Series Ring in t over Integer Ring + + sage: L. = LazyTaylorSeriesRing(QQ); L + Multivariate Lazy Taylor Series Ring in x, y over Rational Field + """ + Element = LazyTaylorSeries + + def __init__(self, base_ring, names, sparse=True, category=None): + """ + Initialize ``self``. + + TESTS:: + + sage: L = LazyTaylorSeriesRing(ZZ, 't') + sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) + """ + from sage.structure.category_object import normalize_names + names = normalize_names(-1, names) + self._sparse = sparse + if len(names) == 1: + self._coeff_ring = base_ring + else: + self._coeff_ring = PolynomialRing(base_ring, names) + self._laurent_poly_ring = PolynomialRing(base_ring, names) + self._internal_poly_ring = self._coeff_ring + category = Algebras(base_ring.category()) + if base_ring in Fields(): + category &= CompleteDiscreteValuationRings() + elif base_ring in IntegralDomains(): + category &= IntegralDomains() + elif base_ring in Rings().Commutative(): + category = category.Commutative() + + if base_ring.is_zero(): + category = category.Finite() + else: + category = category.Infinite() + Parent.__init__(self, base=base_ring, names=names, + category=category) + + def _repr_(self): + """ + String representation of this Taylor series ring. + + EXAMPLES:: + + sage: LazyTaylorSeriesRing(GF(2), 'z') + Lazy Taylor Series Ring in z over Finite Field of size 2 + """ + BR = self.base_ring() + if len(self.variable_names()) == 1: + return "Lazy Taylor Series Ring in {} over {}".format(self.variable_name(), BR) + generators_rep = ", ".join(self.variable_names()) + return "Multivariate Lazy Taylor Series Ring in {} over {}".format(generators_rep, BR) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: latex(L) + \Bold{F}_{2} [\![z]\!] + """ + from sage.misc.latex import latex + generators_rep = ", ".join(self.variable_names()) + return latex(self.base_ring()) + r"[\![{}]\!]".format(generators_rep) + + def _monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L._monomial(2, 3) + 2*z^3 + """ + m = len(self.variable_names()) + L = self._laurent_poly_ring + if m == 1: + return L(c) * L.gen() ** n + return L(c) + + @cached_method + def gen(self, n=0): + """ + Return the ``n``-th generator of ``self``. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.gen() + z + sage: L.gen(3) + Traceback (most recent call last): + ... + IndexError: there is only one generator + """ + m = len(self.variable_names()) + if n > m: + if m == 1: + raise IndexError("there is only one generator") + raise IndexError("there are only %s generators" % m) + + R = self._laurent_poly_ring + BR = self.base_ring() + if len(self.variable_names()) == 1: + coeff_stream = Stream_exact([BR.one()], self._sparse, constant=BR.zero(), order=1) + else: + coeff_stream = Stream_exact([R.gen(n)], self._sparse, constant=BR.zero(), order=1) + return self.element_class(self, coeff_stream) + + def ngens(self): + r""" + Return the number of generators of ``self``. + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L.ngens() + 1 + """ + return len(self.variable_names()) + + @cached_method + def gens(self): + """ + Return the generators of ``self``. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'x,y') + sage: L.gens() + (x, y) + """ + return tuple([self.gen(n) for n in range(self.ngens())]) + + def _coerce_map_from_(self, S): + """ + Return ``True`` if a coercion from ``S`` exists. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(GF(2)) + True + """ + if self.base_ring().has_coerce_map_from(S): + return True + + R = self._laurent_poly_ring + return R.has_coerce_map_from(S) + + def _coerce_map_from_base_ring(self): + """ + Return a coercion map from the base ring of ``self``. + + """ + # Return a DefaultConvertMap_unique; this can pass additional + # arguments to _element_constructor_, unlike the map returned + # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. + return self._generic_coerce_map(self.base_ring()) + + def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None, check=True): + """ + Construct a Taylor series from ``x``. + + INPUT: + + - ``x`` -- data used to the define a Taylor series + - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series + - ``constant`` -- (optional) the eventual constant of the series + - ``degree`` -- (optional) the degree when the series is ``constant`` + - ``check`` -- (optional) check that coefficients are homogeneous of the correct degree when they are retrieved + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: L(2) + 0 + sage: L(3) + 1 + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L(lambda i: i, 5, 1, 10) + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) + sage: L(lambda i: i, 5, (1, 10)) + 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) + + sage: X = L(constant=5, degree=2); X + 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) + sage: X.valuation() + 2 + + sage: e = L(lambda n: n+1); e + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + sage: f = e^-1; f + 1 - 2*z + z^2 + O(z^7) + sage: f.coefficient(10) + 0 + sage: f[20] + 0 + + sage: L(valuation=2, constant=1) + z^2 + z^3 + z^4 + O(z^5) + sage: L(constant=1) + 1 + z + z^2 + O(z^3) + + Alternatively, ``x`` can be a list of elements of the base ring. + Then these elements are read as coefficients of the terms of + degrees starting from the ``valuation``. In this case, ``constant`` + may be just an element of the base ring instead of a tuple or can be + simply omitted if it is zero:: + + sage: f = L([1,2,3,4], 1); f + z + 2*z^2 + 3*z^3 + 4*z^4 + + sage: g = L([1,3,5,7,9], 5, -1); g + z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) + + .. TODO:: + + Add a method to change the sparse/dense implementation. + + Finally, ``x`` can be a polynomial:: + + sage: P. = QQ[] + sage: p = x + 3*x^2 + x^5 + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L(p) + x + 3*x^2 + x^5 + + sage: L(p, valuation=0) + 1 + 3*x + x^4 + + sage: P. = QQ[] + sage: p = x + y^2 + x*y + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L(p) + x + (x*y+y^2) + + TESTS:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L(constant=1) + Traceback (most recent call last): + ... + ValueError: constant must be zero for multivariate Taylor series + + sage: L(lambda n: 0) + O(x,y)^7 + + sage: L(lambda n: n)[3]; + Traceback (most recent call last): + ... + ValueError: coefficient 3 at degree 3 is not a homogeneous polynomial + + sage: L([1, 2, 3]); + Traceback (most recent call last): + ... + ValueError: unable to convert [1, 2, 3] into a lazy Taylor series + + sage: L(lambda n: n, degree=3); + Traceback (most recent call last): + ... + ValueError: coefficients must be homogeneous polynomials of the correct degree + + """ + if valuation is not None: + if valuation < 0: + raise ValueError("the valuation of a Taylor series must be positive") + if len(self.variable_names()) > 1: + raise ValueError(f"valuation must not be specified for multivariate Taylor series") + + R = self._laurent_poly_ring + BR = self.base_ring() + if x is None: + assert degree is None + coeff_stream = Stream_uninitialized(self._sparse, valuation) + return self.element_class(self, coeff_stream) + try: + # Try to build stuff using the polynomial ring constructor + x = R(x) + except (TypeError, ValueError): + pass + if isinstance(constant, (tuple, list)): + constant, degree = constant + if constant is not None: + if len(self.variable_names()) > 1 and constant: + raise ValueError(f"constant must be zero for multivariate Taylor series") + constant = BR(constant) + if x in R: + if not x and not constant: + coeff_stream = Stream_zero(self._sparse) + else: + if not x: + coeff_stream = Stream_exact([], self._sparse, + order=valuation, + degree=degree, + constant=constant) + return self.element_class(self, coeff_stream) + + if len(self.variable_names()) == 1: + v = x.valuation() + d = x.degree() + p_list = [x[i] for i in range(v, d + 1)] + if valuation is not None: + v = valuation + else: + p_dict = x.homogeneous_components() + v = min(p_dict.keys()) + d = max(p_dict.keys()) + p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] + + coeff_stream = Stream_exact(p_list, self._sparse, + order=v, + constant=constant, + degree=degree) + return self.element_class(self, coeff_stream) + + if isinstance(x, LazyTaylorSeries): + if x._coeff_stream._is_sparse is self._sparse: + return self.element_class(self, x._coeff_stream) + # TODO: Implement a way to make a self._sparse copy + raise NotImplementedError("cannot convert between sparse and dense") + if callable(x): + if valuation is None: + valuation = 0 + if degree is not None: + if constant is None: + constant = ZZ.zero() + z = R.gen() + if len(self.variable_names()) == 1: + p = [BR(x(i)) for i in range(valuation, degree)] + else: + p = [R(x(i)) for i in range(valuation, degree)] + if not all(e.is_homogeneous() and e.degree() == i + for i, e in enumerate(p, valuation)): + raise ValueError("coefficients must be homogeneous polynomials of the correct degree") + coeff_stream = Stream_exact(p, self._sparse, + order=valuation, + constant=constant, + degree=degree) + return self.element_class(self, coeff_stream) + if check and len(self.variable_names()) > 1: + def y(n): + e = R(x(n)) + if not e or e.is_homogeneous() and e.degree() == n: + return e + raise ValueError("coefficient %s at degree %s is not a homogeneous polynomial" % (e, n)) + coeff_stream = Stream_function(y, self._coeff_ring, self._sparse, valuation) + else: + coeff_stream = Stream_function(x, self._coeff_ring, self._sparse, valuation) + return self.element_class(self, coeff_stream) + raise ValueError(f"unable to convert {x} into a lazy Taylor series") + + def _an_element_(self): + """ + Return a Taylor series in ``self``. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.an_element() + z + z^2 + z^3 + z^4 + O(z^5) + """ + c = self.base_ring().an_element() + R = self._laurent_poly_ring + coeff_stream = Stream_exact([R.one()], self._sparse, order=1, constant=c) + return self.element_class(self, coeff_stream) + + @cached_method + def one(self): + r""" + Return the constant series `1`. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.one() + 1 + """ + R = self._laurent_poly_ring + coeff_stream = Stream_exact([R.one()], self._sparse, constant=ZZ.zero(), degree=1) + return self.element_class(self, coeff_stream) + + @cached_method + def zero(self): + r""" + Return the zero series. + + EXAMPLES:: + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.zero() + 0 + """ + return self.element_class(self, Stream_zero(self._sparse)) + + options = LazyLaurentSeriesRing.options + +###################################################################### + +class LazySymmetricFunctions(UniqueRepresentation, Parent): + """ + Lazy symmetric functions. + + INPUT: + + - ``base_ring`` -- coefficient ring + - ``names`` -- name(s) of the alphabets + - ``sparse`` -- (default: ``True``) whether we use a sparse or a dense representation + + EXAMPLES:: + + sage: LazySymmetricFunctions(ZZ, 'x') + Lazy Symmetric Functions Ring in x over Integer Ring + + sage: L = LazySymmetricFunctions(QQ, "x, y"); L + Multialphabet Lazy Symmetric Functions Ring in x, y over Rational Field + """ + Element = LazySymmetricFunction + + def __init__(self, base_ring, names, sparse=True, category=None): + """ + Initialize ``self``. + + TESTS:: + + sage: L = LazySymmetricFunctions(ZZ, 't') + sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) + """ + category = Algebras(base_ring.category()) + if base_ring in Fields(): + category &= CompleteDiscreteValuationRings() + elif base_ring in IntegralDomains(): + category &= IntegralDomains() + elif base_ring in Rings().Commutative(): + category = category.Commutative() + + if base_ring.is_zero(): + category = category.Finite() + else: + category = category.Infinite() + Parent.__init__(self, base=base_ring, names=names, + category=category) + self._sparse = sparse + n = len(self.variable_names()) + if n == 1: + self._coeff_ring = SymmetricFunctions(base_ring).m() + else: + from sage.categories.tensor import tensor + m = SymmetricFunctions(base_ring).m() + self._coeff_ring = tensor([m]*len(self.variable_names())) + self._laurent_poly_ring = self._coeff_ring + self._internal_poly_ring = self._coeff_ring + + def _repr_(self): + """ + String representation of the lazy symmetric functions ring. + + EXAMPLES:: + + sage: LazySymmetricFunctions(GF(2), 'z') + Lazy Symmetric Functions Ring in z over Finite Field of size 2 + """ + if len(self.variable_names()) == 1: + return "Lazy Symmetric Functions Ring in {} over {}".format(self.variable_name(), self.base_ring()) + generators_rep = ", ".join(self.variable_names()) + return "Multialphabet Lazy Symmetric Functions Ring in {} over {}".format(generators_rep, self.base_ring()) + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(GF(2), 'z') + sage: latex(L) + \Lambda( \Bold{F}_{2} , z) + """ + from sage.misc.latex import latex + generators_rep = ", ".join(self.variable_names()) + return r"\Lambda(" + latex(self.base_ring()) + r", {})".format(generators_rep) + + def _monomial(self, c, n): + r""" + Return the interpretation of the coefficient ``c`` at index ``n``. + + EXAMPLES:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L._monomial(s[2,1], 3) + 2*m[1, 1, 1] + m[2, 1] + + """ + L = self._laurent_poly_ring + return L(c) + + def _coerce_map_from_(self, S): + """ + Return ``True`` if a coercion from ``S`` exists. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(GF(2), 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(GF(2)) + True + """ + if self.base_ring().has_coerce_map_from(S): + return True + + R = self._laurent_poly_ring + return R.has_coerce_map_from(S) + + def _coerce_map_from_base_ring(self): + """ + Return a coercion map from the base ring of ``self``. + + """ + # Return a DefaultConvertMap_unique; this can pass additional + # arguments to _element_constructor_, unlike the map returned + # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. + return self._generic_coerce_map(self.base_ring()) + + def _element_constructor_(self, x=None, valuation=None, degree=None, check=True): + """ + Construct a lazy symmetric function from ``x``. + + INPUT: + + - ``x`` -- data used to the define a Taylor series + - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series + - ``degree`` -- (optional) the degree when the symmetric function has finite support + - ``check`` -- (optional) check that coefficients are homogeneous of the correct degree when they are retrieved + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(GF(2), 'z') + sage: L(2) + 0 + sage: L(3) + m[] + + sage: m = SymmetricFunctions(ZZ).m() + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: f = L(lambda i: m([i]), valuation=5, degree=10); f + m[5] + m[6] + m[7] + m[8] + m[9] + + sage: f.coefficient(6) + m[6] + sage: f[20] + 0 + + Alternatively, ``x`` can be a list of elements of the base ring. + Then these elements are read as coefficients of the terms of + degrees starting from the ``valuation``:: + + sage: f = L([m[1],m[2],m[3]], valuation=1); f + m[1] + m[2] + m[3] + + .. TODO:: + + Add a method to change the sparse/dense implementation. + + Finally, ``x`` can be a symmetric function:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(ZZ, "x") + sage: L(s.an_element()) + 2*m[] + 2*m[1] + (3*m[1,1]+3*m[2]) + + TESTS:: + + sage: L = LazySymmetricFunctions(ZZ, "x,y") + sage: L(lambda n: 0) + O(x,y)^7 + + sage: L(lambda n: n)[3]; + Traceback (most recent call last): + ... + ValueError: coefficient 3*m[] # m[] at degree 3 is not a symmetric function of the correct homogeneous degree + + sage: L([1, 2, 3]); + Traceback (most recent call last): + ... + ValueError: coefficients must be symmetric functions of the correct homogeneous degree + + sage: L(lambda n: n, degree=3); + Traceback (most recent call last): + ... + ValueError: coefficients must be symmetric functions of the correct homogeneous degree + + """ + if valuation is not None: + if valuation < 0: + raise ValueError("the valuation of a lazy symmetric function must be nonnegative") + + R = self._laurent_poly_ring + BR = self.base_ring() + if x is None: + assert degree is None + coeff_stream = Stream_uninitialized(self._sparse, valuation) + return self.element_class(self, coeff_stream) + try: + # Try to build stuff using the polynomial ring constructor + x = R(x) + except (TypeError, ValueError, NotImplementedError): + pass + if x in R: + if not x: + coeff_stream = Stream_zero(self._sparse) + else: + p_dict = {} + if len(self.variable_names()) == 1: + for f in x.terms(): + d = f.degree() + p_dict[d] = p_dict.get(d, 0) + f + else: + for f in x.terms(): + d = sum(p.size() for p in f.support()) + p_dict[d] = p_dict.get(d, 0) + f + v = min(p_dict.keys()) + d = max(p_dict.keys()) + p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] + + coeff_stream = Stream_exact(p_list, self._sparse, + order=v, + constant=0, + degree=degree) + return self.element_class(self, coeff_stream) + + if isinstance(x, LazySymmetricFunction): + if x._coeff_stream._is_sparse is self._sparse: + return self.element_class(self, x._coeff_stream) + # TODO: Implement a way to make a self._sparse copy + raise NotImplementedError("cannot convert between sparse and dense") + + if len(self.variable_names()) == 1: + def is_homogeneous_of_degree(f, d): + if not f: + return True + try: + return f.homogeneous_degree() == d + except ValueError: + return False + else: + def is_homogeneous_of_degree(f, d): + if not f: + return True + for m in f.monomials(): + for t in m.support(): + if sum(p.size() for p in t) != d: + return False + if isinstance(x, (tuple, list)): + if valuation is None: + valuation = 0 + if degree is None: + degree = valuation + len(x) + p = [R(e) for e in x] + if not all(is_homogeneous_of_degree(e, i) + for i, e in enumerate(p, valuation)): + raise ValueError("coefficients must be symmetric functions of the correct homogeneous degree") + coeff_stream = Stream_exact(p, self._sparse, + order=valuation, + constant=0, + degree=degree) + return self.element_class(self, coeff_stream) + if callable(x): + if valuation is None: + valuation = 0 + if degree is not None: + p = [R(x(i)) for i in range(valuation, degree)] + if not all(is_homogeneous_of_degree(e, i) + for i, e in enumerate(p, valuation)): + raise ValueError("coefficients must be symmetric functions of the correct homogeneous degree") + coeff_stream = Stream_exact(p, self._sparse, + order=valuation, + constant=0, + degree=degree) + return self.element_class(self, coeff_stream) + if check: + def y(n): + e = R(x(n)) + if is_homogeneous_of_degree(e, n): + return e + raise ValueError("coefficient %s at degree %s is not a symmetric function of the correct homogeneous degree" % (e, n)) + coeff_stream = Stream_function(y, self._coeff_ring, self._sparse, valuation) + else: + coeff_stream = Stream_function(x, self._coeff_ring, self._sparse, valuation) + return self.element_class(self, coeff_stream) + raise ValueError(f"unable to convert {x} into a lazy symmetric function") + + def _an_element_(self): + """ + Return a lazy symmetric function in ``self``. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L.an_element() + m[] + """ + c = self.base_ring()(1) + R = self._laurent_poly_ring + coeff_stream = Stream_exact([R.one()], self._sparse, order=1, constant=0) + return self.element_class(self, coeff_stream) + + @cached_method + def one(self): + r""" + Return the constant `1`. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L.one() + m[] + """ + R = self._laurent_poly_ring + coeff_stream = Stream_exact([R.one()], self._sparse, constant=ZZ.zero(), degree=1) + return self.element_class(self, coeff_stream) + + @cached_method + def zero(self): + r""" + Return the zero series. + + EXAMPLES:: + + sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L.zero() + 0 + """ + return self.element_class(self, Stream_zero(self._sparse)) + + options = LazyLaurentSeriesRing.options + +###################################################################### + class LazyDirichletSeriesRing(LazySeriesRing): """ Lazy Dirichlet series ring. From 51ea983c795ebab199e920648e12470a8b22b5a6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 3 Oct 2021 14:53:09 +0900 Subject: [PATCH 006/591] Using _internal_poly_ring and replacing _coeff_ring. --- src/sage/rings/lazy_series.py | 96 +++++++++++++++--------------- src/sage/rings/lazy_series_ring.py | 27 ++++----- 2 files changed, 61 insertions(+), 62 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 35818298dfe..c16ae78032e 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -214,7 +214,7 @@ def __getitem__(self, n): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] """ - R = self.parent()._coeff_ring + R = self.parent()._internal_poly_ring.base_ring() if isinstance(n, slice): if n.stop is None: raise NotImplementedError("cannot list an infinite set") @@ -300,7 +300,8 @@ def map_coefficients(self, func, ring=None): degree=coeff_stream._degree, constant=BR(c)) return P.element_class(P, coeff_stream) - coeff_stream = Stream_map_coefficients(self._coeff_stream, func, P._coeff_ring) + R = P._internal_poly_ring.base_ring() + coeff_stream = Stream_map_coefficients(self._coeff_stream, func, R) return P.element_class(P, coeff_stream) def truncate(self, d): @@ -1314,7 +1315,7 @@ def exp(self): sage: L. = LazyTaylorSeriesRing(QQ) sage: exp(x+y)[4].factor() (1/24) * (x + y)^4 - sage: exp(x/(1-y)).finite_part(3) + sage: exp(x/(1-y)).polynomial(3) 1/6*x^3 + x^2*y + x*y^2 + 1/2*x^2 + x*y + x + 1 TESTS:: @@ -1339,7 +1340,7 @@ def log(self): z + 1/2*z^2 + 1/3*z^3 + 1/4*z^4 + 1/5*z^5 + 1/6*z^6 + 1/7*z^7 + O(z^8) sage: L. = LazyTaylorSeriesRing(QQ) - sage: log((1 + x/(1-y))).finite_part(3) + sage: log((1 + x/(1-y))).polynomial(3) 1/3*x^3 - x^2*y + x*y^2 + (-1/2)*x^2 + x*y + x TESTS:: @@ -1376,7 +1377,7 @@ def sin(self): ValueError: can only compose with a positive valuation series sage: L. = LazyTaylorSeriesRing(QQ) - sage: sin(x/(1-y)).finite_part(3) + sage: sin(x/(1-y)).polynomial(3) (-1/6)*x^3 + x*y^2 + x*y + x TESTS:: @@ -1402,7 +1403,7 @@ def cos(self): 1 - 1/2*z^2 + 1/24*z^4 - 1/720*z^6 + O(z^7) sage: L. = LazyTaylorSeriesRing(QQ) - sage: cos(x/(1-y)).finite_part(4) + sage: cos(x/(1-y)).polynomial(4) 1/24*x^4 + (-3/2)*x^2*y^2 - x^2*y + (-1/2)*x^2 + 1 TESTS:: @@ -1428,7 +1429,7 @@ def tan(self): z + 1/3*z^3 + 2/15*z^5 + 17/315*z^7 + O(z^8) sage: L. = LazyTaylorSeriesRing(QQ) - sage: tan(x/(1-y)).finite_part(5) + sage: tan(x/(1-y)).polynomial(5) 2/15*x^5 + 2*x^3*y^2 + x*y^4 + x^3*y + x*y^3 + 1/3*x^3 + x*y^2 + x*y + x TESTS:: @@ -1494,7 +1495,7 @@ def sec(self): 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) sage: L. = LazyTaylorSeriesRing(QQ) - sage: sec(x/(1-y)).finite_part(4) + sage: sec(x/(1-y)).polynomial(4) 5/24*x^4 + 3/2*x^2*y^2 + x^2*y + 1/2*x^2 + 1 TESTS:: @@ -1580,9 +1581,8 @@ def arctan(self): sage: L. = LazyTaylorSeriesRing(QQ) sage: atan(x/(1-y)) - x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) - + (1/5*x^5+(-2)*x^3*y^2+x*y^4) + (x^5*y+(-10/3)*x^3*y^3+x*y^5) - + ((-1/7)*x^7+3*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 + x + x*y + (-1/3*x^3+x*y^2) + (-x^3*y+x*y^3) + (1/5*x^5-2*x^3*y^2+x*y^4) + + (x^5*y-10/3*x^3*y^3+x*y^5) + (-1/7*x^7+3*x^5*y^2-5*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: @@ -1700,9 +1700,9 @@ def tanh(self): sage: L. = LazyTaylorSeriesRing(QQ) sage: tanh(x/(1-y)) - x + x*y + ((-1/3)*x^3+x*y^2) + (-x^3*y+x*y^3) - + (2/15*x^5+(-2)*x^3*y^2+x*y^4) + (2/3*x^5*y+(-10/3)*x^3*y^3+x*y^5) - + ((-17/315)*x^7+2*x^5*y^2+(-5)*x^3*y^4+x*y^6) + O(x,y)^8 + x + x*y + (-1/3*x^3+x*y^2) + (-x^3*y+x*y^3) + (2/15*x^5-2*x^3*y^2+x*y^4) + + (2/3*x^5*y-10/3*x^3*y^3+x*y^5) + (-17/315*x^7+2*x^5*y^2-5*x^3*y^4+x*y^6) + O(x,y)^8 + TESTS:: @@ -1762,9 +1762,8 @@ def sech(self): sage: L. = LazyTaylorSeriesRing(QQ) sage: sech(x/(1-y)) - 1 + ((-1/2)*x^2) + (-x^2*y) + (5/24*x^4+(-3/2)*x^2*y^2) - + (5/6*x^4*y+(-2)*x^2*y^3) + ((-61/720)*x^6+25/12*x^4*y^2+(-5/2)*x^2*y^4) - + O(x,y)^7 + 1 + (-1/2*x^2) + (-x^2*y) + (5/24*x^4-3/2*x^2*y^2) + (5/6*x^4*y-2*x^2*y^3) + + (-61/720*x^6+25/12*x^4*y^2-5/2*x^2*y^4) + O(x,y)^7 TESTS:: @@ -1827,9 +1826,8 @@ def arcsinh(self): sage: L. = LazyTaylorSeriesRing(QQ) sage: asinh(x/(1-y)) - x + x*y + ((-1/6)*x^3+x*y^2) + ((-1/2)*x^3*y+x*y^3) - + (3/40*x^5-x^3*y^2+x*y^4) + (3/8*x^5*y+(-5/3)*x^3*y^3+x*y^5) - + ((-5/112)*x^7+9/8*x^5*y^2+(-5/2)*x^3*y^4+x*y^6) + O(x,y)^8 + x + x*y + (-1/6*x^3+x*y^2) + (-1/2*x^3*y+x*y^3) + (3/40*x^5-x^3*y^2+x*y^4) + + (3/8*x^5*y-5/3*x^3*y^3+x*y^5) + (-5/112*x^7+9/8*x^5*y^2-5/2*x^3*y^4+x*y^6) + O(x,y)^8 TESTS:: @@ -1956,10 +1954,10 @@ def sqrt(self): sage: L. = LazyTaylorSeriesRing(QQ) sage: sqrt(1+x/(1-y)) - 1 + 1/2*x + ((-1/8)*x^2+1/2*x*y) + (1/16*x^3+(-1/4)*x^2*y+1/2*x*y^2) - + ((-5/128)*x^4+3/16*x^3*y+(-3/8)*x^2*y^2+1/2*x*y^3) - + (7/256*x^5+(-5/32)*x^4*y+3/8*x^3*y^2+(-1/2)*x^2*y^3+1/2*x*y^4) - + ((-21/1024)*x^6+35/256*x^5*y+(-25/64)*x^4*y^2+5/8*x^3*y^3+(-5/8)*x^2*y^4+1/2*x*y^5) + 1 + 1/2*x + (-1/8*x^2+1/2*x*y) + (1/16*x^3-1/4*x^2*y+1/2*x*y^2) + + (-5/128*x^4+3/16*x^3*y-3/8*x^2*y^2+1/2*x*y^3) + + (7/256*x^5-5/32*x^4*y+3/8*x^3*y^2-1/2*x^2*y^3+1/2*x*y^4) + + (-21/1024*x^6+35/256*x^5*y-25/64*x^4*y^2+5/8*x^3*y^3-5/8*x^2*y^4+1/2*x*y^5) + O(x,y)^7 This also works for Dirichlet series:: @@ -2094,9 +2092,9 @@ def _mul_(self, other): # Check some trivial products if isinstance(left, Stream_zero) or isinstance(right, Stream_zero): return P.zero() - if isinstance(left, Stream_exact) and left._initial_coefficients == (P._coeff_ring.one(),) and left.order() == 0: + if isinstance(left, Stream_exact) and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and left.order() == 0: return other # self == 1 - if isinstance(right, Stream_exact) and right._initial_coefficients == (P._coeff_ring.one(),) and right.order() == 0: + if isinstance(right, Stream_exact) and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 0: return self # right == 1 # The product is exact if and only if both factors are exact @@ -2211,7 +2209,7 @@ def __pow__(self, n): # # alternatively: # return P(self.finite_part() ** ZZ(n)) P = self.parent() - ret = cs._polynomial_part(P._laurent_poly_ring) ** ZZ(n) + ret = cs._polynomial_part(P._internal_poly_ring) ** ZZ(n) val = ret.valuation() deg = ret.degree() + 1 initial_coefficients = [ret[i] for i in range(val, deg)] @@ -2273,14 +2271,14 @@ def __invert__(self): if not initial_coefficients: i = ~coeff_stream._constant v = -coeff_stream.order() - c = P._coeff_ring.zero() + c = P._internal_poly_ring.base_ring().zero() coeff_stream = Stream_exact((i, -i), P._sparse, order=v, constant=c) return P.element_class(P, coeff_stream) if len(initial_coefficients) == 1 and not coeff_stream._constant: i = ~initial_coefficients[0] v = -coeff_stream.order() - c = P._coeff_ring.zero() + c = P._internal_poly_ring.base_ring().zero() coeff_stream = Stream_exact((i,), P._sparse, order=v, constant=c) return P.element_class(P, coeff_stream) @@ -2361,12 +2359,12 @@ def _div_(self, other): if (isinstance(left, Stream_exact) and isinstance(right, Stream_exact)): if not left._constant and not right._constant: - R = P._laurent_poly_ring + R = P._internal_poly_ring pl = left._polynomial_part(R) pr = right._polynomial_part(R) try: ret = pl / pr - ret = P._laurent_poly_ring(ret) + ret = R(ret) except (TypeError, ValueError, NotImplementedError): # We cannot divide the polynomials, so the result must be a series pass @@ -2834,7 +2832,8 @@ def __call__(self, g): # we assume that the valuation of self[i](g) is at least i def coefficient(n): return sum(self[i] * (g**i)[n] for i in range(n+1)) - coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 1) + R = P._internal_poly_ring.base_ring() + coeff_stream = Stream_function(coefficient, R, P._sparse, 1) return P.element_class(P, coeff_stream) coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream) @@ -3182,14 +3181,14 @@ def __call__(self, *g): # f has finite length if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: # constant polynomial - poly = self.finite_part() + poly = self.polynomial() if poly.is_constant(): - return self + return poly return poly(g) g0 = g[0] P = g0.parent() - R = P._coeff_ring + R = P._internal_poly_ring.base_ring() if len(g) == 1: # we assume that the valuation of self[i](g) is at least i def coefficient(n): @@ -3203,7 +3202,7 @@ def coefficient(n): for i in range(n+1): r += self[i](g)[n] return r - coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 0) + coeff_stream = Stream_function(coefficient, R, P._sparse, 0) return P.element_class(P, coeff_stream) def _format_series(self, formatter, format_strings=False): @@ -3212,7 +3211,7 @@ def _format_series(self, formatter, format_strings=False): TESTS:: - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyTaylorSeriesRing(QQ) sage: f = 1 / (2 - x^2 + y) sage: f._format_series(repr) '1/2 + (-1/4*y) + (1/4*x^2+1/8*y^2) + (-1/4*x^2*y-1/16*y^3) + (1/8*x^4+3/16*x^2*y^2+1/32*y^4) + (-3/16*x^4*y-1/8*x^2*y^3-1/64*y^5) + (1/16*x^6+3/16*x^4*y^2+5/64*x^2*y^4+1/128*y^6) + O(x,y)^7' @@ -3232,10 +3231,10 @@ def _format_series(self, formatter, format_strings=False): else: m = v + P.options.display_length - atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] if not isinstance(cs, Stream_exact) or cs._constant: - if P._coeff_ring is P.base_ring(): + if P._internal_poly_ring.base_ring() is P.base_ring(): bigO = ["O(%s)" % P._monomial(1, m)] else: bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] @@ -3341,7 +3340,7 @@ def __call__(self, *args): if len(args) == 1: g = args[0] P = g.parent() - R = P._coeff_ring + R = P._internal_poly_ring.base_ring() BR = P.base_ring() p = R.realization_of().power() g_p = Stream_map_coefficients(g._coeff_stream, lambda c: c, p) @@ -3382,7 +3381,7 @@ def coefficient(n): else: raise NotImplementedError - coeff_stream = Stream_function(coefficient, P._coeff_ring, P._sparse, 0) + coeff_stream = Stream_function(coefficient, P._internal_poly_ring.base_ring(), P._sparse, 0) return P.element_class(P, coeff_stream) def _format_series(self, formatter, format_strings=False): @@ -3404,10 +3403,10 @@ def _format_series(self, formatter, format_strings=False): else: m = v + P.options.display_length - atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] if not isinstance(cs, Stream_exact) or cs._constant: - if P._coeff_ring is P.base_ring(): + if P._internal_poly_ring.base_ring() is P.base_ring(): bigO = ["O(%s)" % P._monomial(1, m)] else: bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] @@ -3549,12 +3548,12 @@ def _mul_(self, other): return other if (isinstance(left, Stream_exact) and not left._constant - and left._initial_coefficients == (P._coeff_ring.one(),) + and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and left.order() == 1): return other # self == 1 if (isinstance(right, Stream_exact) and not right._constant - and right._initial_coefficients == (P._coeff_ring.one(),) + and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 1): return self # other == 1 coeff = Stream_dirichlet_convolve(left, right) @@ -3667,7 +3666,8 @@ def coefficient(m): return coeff_stream[n] * n ** (-b) except ValueError: return ZZ.zero() - return P.element_class(P, Stream_function(coefficient, P._coeff_ring, P._sparse, 1)) + R = P._internal_poly_ring.base_ring() + return P.element_class(P, Stream_function(coefficient, R, P._sparse, 1)) def _format_series(self, formatter, format_strings=False): """ @@ -3716,10 +3716,10 @@ def _format_series(self, formatter, format_strings=False): else: m = v + P.options.display_length - atomic_repr = P._coeff_ring._repr_option('element_is_atomic') + atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] if not isinstance(cs, Stream_exact) or cs._constant: - if P._coeff_ring is P.base_ring(): + if P._internal_poly_ring.base_ring() is P.base_ring(): bigO = ["O(%s)" % P._monomial(1, m)] else: bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index ecfa5169080..f7ac442d32f 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -593,7 +593,6 @@ def __init__(self, base_ring, names, sparse=True, category=None): sage: L = LazyLaurentSeriesRing(E, 't') # not tested """ self._sparse = sparse - self._coeff_ring = base_ring # We always use the dense because our CS_exact is implemented densely self._laurent_poly_ring = LaurentPolynomialRing(base_ring, names) self._internal_poly_ring = self._laurent_poly_ring @@ -1017,12 +1016,12 @@ def __init__(self, base_ring, names, sparse=True, category=None): from sage.structure.category_object import normalize_names names = normalize_names(-1, names) self._sparse = sparse + self._laurent_poly_ring = PolynomialRing(base_ring, names) if len(names) == 1: - self._coeff_ring = base_ring + self._internal_poly_ring = self._laurent_poly_ring else: - self._coeff_ring = PolynomialRing(base_ring, names) - self._laurent_poly_ring = PolynomialRing(base_ring, names) - self._internal_poly_ring = self._coeff_ring + coeff_ring = PolynomialRing(base_ring, names) + self._internal_poly_ring = PolynomialRing(coeff_ring, "DUMMY_VARIABLE") category = Algebras(base_ring.category()) if base_ring in Fields(): category &= CompleteDiscreteValuationRings() @@ -1346,15 +1345,16 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No constant=constant, degree=degree) return self.element_class(self, coeff_stream) + coeff_ring = self._internal_poly_ring.base_ring() if check and len(self.variable_names()) > 1: def y(n): e = R(x(n)) if not e or e.is_homogeneous() and e.degree() == n: return e raise ValueError("coefficient %s at degree %s is not a homogeneous polynomial" % (e, n)) - coeff_stream = Stream_function(y, self._coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(y, coeff_ring, self._sparse, valuation) else: - coeff_stream = Stream_function(x, self._coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(x, coeff_ring, self._sparse, valuation) return self.element_class(self, coeff_stream) raise ValueError(f"unable to convert {x} into a lazy Taylor series") @@ -1451,13 +1451,12 @@ def __init__(self, base_ring, names, sparse=True, category=None): self._sparse = sparse n = len(self.variable_names()) if n == 1: - self._coeff_ring = SymmetricFunctions(base_ring).m() + self._laurent_poly_ring = SymmetricFunctions(base_ring).m() else: from sage.categories.tensor import tensor m = SymmetricFunctions(base_ring).m() - self._coeff_ring = tensor([m]*len(self.variable_names())) - self._laurent_poly_ring = self._coeff_ring - self._internal_poly_ring = self._coeff_ring + self._laurent_poly_ring = tensor([m]*len(self.variable_names())) + self._internal_poly_ring = PolynomialRing(self._laurent_poly_ring, "DUMMY_VARIABLE") def _repr_(self): """ @@ -1686,15 +1685,16 @@ def is_homogeneous_of_degree(f, d): constant=0, degree=degree) return self.element_class(self, coeff_stream) + coeff_ring = self._internal_poly_ring.base_ring() if check: def y(n): e = R(x(n)) if is_homogeneous_of_degree(e, n): return e raise ValueError("coefficient %s at degree %s is not a symmetric function of the correct homogeneous degree" % (e, n)) - coeff_stream = Stream_function(y, self._coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(y, coeff_ring, self._sparse, valuation) else: - coeff_stream = Stream_function(x, self._coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(x, coeff_ring, self._sparse, valuation) return self.element_class(self, coeff_stream) raise ValueError(f"unable to convert {x} into a lazy symmetric function") @@ -1775,7 +1775,6 @@ def __init__(self, base_ring, names, sparse=True, category=None): raise ValueError("positive characteristic not allowed for Dirichlet series") self._sparse = sparse - self._coeff_ring = base_ring # TODO: it would be good to have something better than the symbolic ring self._laurent_poly_ring = SR self._internal_poly_ring = PolynomialRing(base_ring, names, sparse=True) From 896574645e816f75e0b7babb8a73155cd267d918 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 3 Feb 2022 18:06:32 +0900 Subject: [PATCH 007/591] Adding polynomial() for LazyTaylorSeries and fixing doctests. --- src/sage/rings/lazy_series.py | 102 +++++++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 3a1ff80e8d9..afa4762abfb 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1341,7 +1341,7 @@ def log(self): sage: L. = LazyTaylorSeriesRing(QQ) sage: log((1 + x/(1-y))).polynomial(3) - 1/3*x^3 - x^2*y + x*y^2 + (-1/2)*x^2 + x*y + x + 1/3*x^3 - x^2*y + x*y^2 - 1/2*x^2 + x*y + x TESTS:: @@ -1378,7 +1378,7 @@ def sin(self): sage: L. = LazyTaylorSeriesRing(QQ) sage: sin(x/(1-y)).polynomial(3) - (-1/6)*x^3 + x*y^2 + x*y + x + -1/6*x^3 + x*y^2 + x*y + x TESTS:: @@ -1404,7 +1404,7 @@ def cos(self): sage: L. = LazyTaylorSeriesRing(QQ) sage: cos(x/(1-y)).polynomial(4) - 1/24*x^4 + (-3/2)*x^2*y^2 - x^2*y + (-1/2)*x^2 + 1 + 1/24*x^4 - 3/2*x^2*y^2 - x^2*y - 1/2*x^2 + 1 TESTS:: @@ -1494,7 +1494,7 @@ def sec(self): sage: sec(z) 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyTaylorSeriesRing(QQ) sage: sec(x/(1-y)).polynomial(4) 5/24*x^4 + 3/2*x^2*y^2 + x^2*y + 1/2*x^2 + 1 @@ -1518,7 +1518,7 @@ def arcsin(self): sage: arcsin(z) z + 1/6*z^3 + 3/40*z^5 + 5/112*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyTaylorSeriesRing(QQ) sage: asin(x/(1-y)) x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (3/40*x^5+x^3*y^2+x*y^4) + (3/8*x^5*y+5/3*x^3*y^3+x*y^5) @@ -1555,7 +1555,7 @@ def arccos(self): sage: arccos(z/(1-z)) 1/2*pi - z - z^2 - 7/6*z^3 - 3/2*z^4 - 83/40*z^5 - 73/24*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) + sage: L. = LazyTaylorSeriesRing(SR) sage: arccos(x/(1-y)) 1/2*pi + (-x) + (-x*y) + ((-1/6)*x^3-x*y^2) + ((-1/2)*x^3*y-x*y^3) + ((-3/40)*x^5-x^3*y^2-x*y^4) + ((-3/8)*x^5*y+(-5/3)*x^3*y^3-x*y^5) + O(x,y)^7 @@ -1579,7 +1579,7 @@ def arctan(self): sage: arctan(z) z - 1/3*z^3 + 1/5*z^5 - 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyTaylorSeriesRing(QQ) sage: atan(x/(1-y)) x + x*y + (-1/3*x^3+x*y^2) + (-x^3*y+x*y^3) + (1/5*x^5-2*x^3*y^2+x*y^4) + (x^5*y-10/3*x^3*y^3+x*y^5) + (-1/7*x^7+3*x^5*y^2-5*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1617,7 +1617,7 @@ def arccot(self): sage: arccot(z/(1-z)) 1/2*pi - z - z^2 - 2/3*z^3 + 4/5*z^5 + 4/3*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) + sage: L. = LazyTaylorSeriesRing(SR) sage: acot(x/(1-y)) 1/2*pi + (-x) + (-x*y) + (1/3*x^3-x*y^2) + (x^3*y-x*y^3) + ((-1/5)*x^5+2*x^3*y^2-x*y^4) + (-x^5*y+10/3*x^3*y^3-x*y^5) + O(x,y)^7 @@ -1643,7 +1643,7 @@ def sinh(self): sage: sinh(z) z + 1/6*z^3 + 1/120*z^5 + 1/5040*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyTaylorSeriesRing(QQ) sage: sinh(x/(1-y)) x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (1/120*x^5+x^3*y^2+x*y^4) + (1/24*x^5*y+5/3*x^3*y^3+x*y^5) @@ -1671,7 +1671,7 @@ def cosh(self): sage: cosh(z) 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyTaylorSeriesRing(QQ) sage: cosh(x/(1-y)) 1 + 1/2*x^2 + x^2*y + (1/24*x^4+3/2*x^2*y^2) + (1/6*x^4*y+2*x^2*y^3) + (1/720*x^6+5/12*x^4*y^2+5/2*x^2*y^4) + O(x,y)^7 @@ -1698,12 +1698,11 @@ def tanh(self): sage: tanh(z) z - 1/3*z^3 + 2/15*z^5 - 17/315*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyTaylorSeriesRing(QQ) sage: tanh(x/(1-y)) x + x*y + (-1/3*x^3+x*y^2) + (-x^3*y+x*y^3) + (2/15*x^5-2*x^3*y^2+x*y^4) + (2/3*x^5*y-10/3*x^3*y^3+x*y^5) + (-17/315*x^7+2*x^5*y^2-5*x^3*y^4+x*y^6) + O(x,y)^8 - TESTS:: sage: L. = LazyLaurentSeriesRing(SR); x = var("x") @@ -1800,7 +1799,6 @@ def csch(self): sage: L. = LazyLaurentSeriesRing(SR); x = var("x") sage: csch(z)[0:6] == csch(x).series(x, 6).coefficients(sparse=False) True - """ from sage.arith.misc import bernoulli from .lazy_series_ring import LazyLaurentSeriesRing @@ -1824,7 +1822,7 @@ def arcsinh(self): sage: asinh(z) z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyTaylorSeriesRing(QQ) sage: asinh(x/(1-y)) x + x*y + (-1/6*x^3+x*y^2) + (-1/2*x^3*y+x*y^3) + (3/40*x^5-x^3*y^2+x*y^4) + (3/8*x^5*y-5/3*x^3*y^3+x*y^5) + (-5/112*x^7+9/8*x^5*y^2-5/2*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1891,6 +1889,11 @@ def hypergeometric(self, a, b): sage: z.hypergeometric([], []) - exp(z) O(z^7) + sage: L. = LazyTaylorSeriesRing(QQ) + sage: (x+y).hypergeometric([1, 1], [1]).polynomial(4) + x^4 + 4*x^3*y + 6*x^2*y^2 + 4*x*y^3 + y^4 + x^3 + 3*x^2*y + + 3*x*y^2 + y^3 + x^2 + 2*x*y + y^2 + x + y + 1 + TESTS:: sage: L. = LazyLaurentSeriesRing(SR); x = var("x") @@ -3165,6 +3168,13 @@ def __call__(self, *g): So, there are `3! 2! 2/3 = 8` mappings from a three element set to a two element set. + We perform the composition with a lazy Laurent series:: + + sage: N. = LazyLaurentSeriesRing(QQ) + sage: f1 = 1/(1-w); f2 = cot(w/(1-w)) + sage: p(f1, f2) + w^-1 + 1 + 5/3*w + 8/3*w^2 + 164/45*w^3 + 23/5*w^4 + 5227/945*w^5 + O(w^6) + TESTS:: sage: L. = LazyTaylorSeriesRing(ZZ) @@ -3274,6 +3284,70 @@ def parenthesize(m): return poly + def polynomial(self, degree=None, names=None): + r""" + Return ``self`` as a polynomial if ``self`` is actually so. + + INPUT: + + - ``degree`` -- ``None`` or an integer + - ``names`` -- names of the variables; if it is ``None``, the name of + the variables of the series is used + + OUTPUT: + + If ``degree`` is not ``None``, the terms of the series of degree greater + than ``degree`` are truncated first. If ``degree`` is ``None`` and the + series is not a polynomial polynomial, a ``ValueError`` is raised. + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: f = x^2 + y*x - x + 2; f + 2 + (-x) + (x^2+x*y) + sage: f.polynomial() + x^2 + x*y - x + 2 + + TESTS:: + + sage: g = 1 / (1 + x + y + x*y) + sage: g3 = g.truncate(4); g3 + 1 + (-x-y) + (x^2+x*y+y^2) + (-x^3-x^2*y-x*y^2-y^3) + sage: g.polynomial() + Traceback (most recent call last): + ... + ValueError: not a polynomial + sage: g3.polynomial() + -x^3 - x^2*y - x*y^2 - y^3 + x^2 + x*y + y^2 - x - y + 1 + sage: L.zero().polynomial() + 0 + sage: g3.polynomial() == g.polynomial(3) + True + sage: g3.polynomial(0) + 1 + """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + S = self.parent() + if names is None: + names = S.variable_names() + R = PolynomialRing(S.base_ring(), names=names) + + if degree is None: + if isinstance(self._coeff_stream, Stream_zero): + return R.zero() + elif (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): + m = self._coeff_stream._degree + else: + raise ValueError("not a polynomial") + else: + m = degree + 1 + + if names is None: + names = S.variable_names() + + return R.sum(self[:m]) + class LazySymmetricFunction(LazyCauchyProductSeries): r""" From 63b8979fa87f62220f45c797bb1019b714dc0324 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 29 Mar 2022 08:03:26 +0200 Subject: [PATCH 008/591] 29717: make smaller algebras independent on optional package --- build/pkgs/cubic_hecke_marin/SPKG.txt | 17 - build/pkgs/cubic_hecke_marin/checksums.ini | 5 - build/pkgs/cubic_hecke_marin/dependencies | 5 - .../cubic_hecke_marin/package-version.txt | 1 - build/pkgs/cubic_hecke_marin/spkg-install.in | 21 - build/pkgs/cubic_hecke_marin/spkg-install.py | 17 - build/pkgs/cubic_hecke_marin/type | 1 - .../cubic_hecke_base_ring.py | 1463 +++++---- .../hecke_algebras/cubic_hecke_algebra.py | 2715 +++++++++-------- .../cubic_hecke_matrix_rep.py | 531 ++-- src/sage/databases/cubic_hecke_db.py | 1596 ++++++---- src/sage/features/databases.py | 22 + 12 files changed, 3634 insertions(+), 2760 deletions(-) delete mode 100644 build/pkgs/cubic_hecke_marin/SPKG.txt delete mode 100644 build/pkgs/cubic_hecke_marin/checksums.ini delete mode 100644 build/pkgs/cubic_hecke_marin/dependencies delete mode 100644 build/pkgs/cubic_hecke_marin/package-version.txt delete mode 100644 build/pkgs/cubic_hecke_marin/spkg-install.in delete mode 100644 build/pkgs/cubic_hecke_marin/spkg-install.py delete mode 100644 build/pkgs/cubic_hecke_marin/type diff --git a/build/pkgs/cubic_hecke_marin/SPKG.txt b/build/pkgs/cubic_hecke_marin/SPKG.txt deleted file mode 100644 index ff9dbab97f7..00000000000 --- a/build/pkgs/cubic_hecke_marin/SPKG.txt +++ /dev/null @@ -1,17 +0,0 @@ -= Cubic Hecke Algebra Database = - -== Description == - -Iwan Marin's basis and matrix representations for the cubic Hecke algebra on 4 strands -as given on 'http://www.lamfa.u-picardie.fr/marin/softs/H4 - -== Dependencies == - - * Sage library - -== Changelog == - -=== cubic_hecke_marin-20200513.tar.bz2 (Sebastian Oehms, 13 May 2020) === - - * #29717: Initial version - diff --git a/build/pkgs/cubic_hecke_marin/checksums.ini b/build/pkgs/cubic_hecke_marin/checksums.ini deleted file mode 100644 index 1a319078d88..00000000000 --- a/build/pkgs/cubic_hecke_marin/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=cubic_hecke_marin-20200513.tar.bz2 -sha1=db05c5cb7a70b6c6987a1ece67e0a6fc4d11e1a0 -md5=7df73fad972fa6eee774aaae05ecd481 -cksum=3934881041 -upstream_url=https://trac.sagemath.org/raw-attachment/ticket/29717/cubic_hecke_marin-20200513.tar.bz2 diff --git a/build/pkgs/cubic_hecke_marin/dependencies b/build/pkgs/cubic_hecke_marin/dependencies deleted file mode 100644 index c1b713883fe..00000000000 --- a/build/pkgs/cubic_hecke_marin/dependencies +++ /dev/null @@ -1,5 +0,0 @@ -| $(SAGERUNTIME) - ----------- -All lines of this file are ignored except the first. -It is copied by SAGE_ROOT/build/make/install into SAGE_ROOT/build/make/Makefile. diff --git a/build/pkgs/cubic_hecke_marin/package-version.txt b/build/pkgs/cubic_hecke_marin/package-version.txt deleted file mode 100644 index aa5d21b148b..00000000000 --- a/build/pkgs/cubic_hecke_marin/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -20200513 diff --git a/build/pkgs/cubic_hecke_marin/spkg-install.in b/build/pkgs/cubic_hecke_marin/spkg-install.in deleted file mode 100644 index 0d3fba4325b..00000000000 --- a/build/pkgs/cubic_hecke_marin/spkg-install.in +++ /dev/null @@ -1,21 +0,0 @@ -INSTALL="yes" -TARGET="${SAGE_SHARE}/cubic_hecke_marin" -VERSION=`cat package-version.txt` -if [ -d $TARGET ] -then - diff package-version.txt $TARGET > /dev/null 2>&1 - if [ $? -eq 0 ] - then - INSTALL="no" - echo "Version $VERSION of cubic_hecke_marin already installed" - else - OLD_VERSION=`cat $TARGET/package-version.txt` - echo "Removing former version $OLD_VERSION of cubic_hecke_marin" - rm -rf $TARGET - fi -fi - -if [ "$INSTALL" = "yes" ] -then - exec sage-python23 spkg-install.py -fi diff --git a/build/pkgs/cubic_hecke_marin/spkg-install.py b/build/pkgs/cubic_hecke_marin/spkg-install.py deleted file mode 100644 index 2109e57fb9b..00000000000 --- a/build/pkgs/cubic_hecke_marin/spkg-install.py +++ /dev/null @@ -1,17 +0,0 @@ -import os -from sage.all import save -from sage.env import SAGE_SHARE -from sage.misc.misc import sage_makedirs -from sage.databases.cubic_hecke_db import CubicHeckeDataBase - -install_root = os.path.join(SAGE_SHARE, 'cubic_hecke_marin') - -if __name__ == '__main__': - sage_makedirs(install_root) - print("Creating Iwan Marin's Cubic Hecke database.") - cha_db = CubicHeckeDataBase() - cha_db.create_static_db_marin_basis() - cha_db.create_static_db_marin_regular() - cha_db.create_static_db_marin_regular(right=True) - cha_db.create_static_db_marin_split() - os.system('cp package-version.txt %s' %install_root) diff --git a/build/pkgs/cubic_hecke_marin/type b/build/pkgs/cubic_hecke_marin/type deleted file mode 100644 index 134d9bc32d5..00000000000 --- a/build/pkgs/cubic_hecke_marin/type +++ /dev/null @@ -1 +0,0 @@ -optional diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py index 6787bf2d548..819d22b1352 100644 --- a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py @@ -2,16 +2,16 @@ r""" Cubic Hecke Base Rings -This module contains special classes of polynomial rings (:class:`CubicHeckeRingOfDefinition` and :class:`CubicHeckeExtensionRing`) -used in the context of cubic Hecke algebras (:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra`). +This module contains special classes of polynomial rings +(:class:`CubicHeckeRingOfDefinition` and :class:`CubicHeckeExtensionRing`) used +in the context of cubic Hecke algebras +(:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra`). AUTHORS: - Sebastian Oehms May 2020: initial version """ - - ############################################################################## # Copyright (C) 2020 Sebastian Oehms # @@ -22,54 +22,77 @@ # http://www.gnu.org/licenses/ ############################################################################## - from sage.structure.category_object import normalize_names -from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element import get_coercion_model from sage.categories.action import Action from sage.misc.verbose import verbose from sage.misc.functional import cyclotomic_polynomial from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict -from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict -from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing, LaurentPolynomialRing_mpair +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_mpair from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.localization import Localization from sage.algebras.splitting_algebra import solve_with_extension, SplittingAlgebra - - -# --------------------------------------------------------------------------------- -# --------------------------------------------------------------------------------- -# helper functions and classes -# --------------------------------------------------------------------------------- -# --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- # local helper functions # --------------------------------------------------------------------------------- +def normalize_names_markov(names, markov_trace_version): + r""" + Return a tuple of strings of variable names of length 3 resp. 4 (if + ``markov_trace_version == True``) according to the given input names. + + INPUT: + + - `names` -- passed to :func:`~sage.structure.category_object.noramize_names` + - `markov_trace_version` -- boolean if set to ``True`` four names are + expected the last of which corresponds to the writhe factor of the + Markov trace + + EXAMPLES:: + + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr + sage: chbr.normalize_names_markov('a, b, c', False) + ('a', 'b', 'c') + sage: chbr.normalize_names_markov(('u', 'v', 'w', 's'), False) + ('u', 'v', 'w') + """ + if markov_trace_version: + names = normalize_names(4, names) + else: + if type(names) == tuple: + names = list(names) + if type(names) == list and len(names) > 3: + names = normalize_names(3, names[0:3]) + else: + names = normalize_names(3, names) + return names + + def register_ring_hom(ring_hom): r""" - This function tries to register the given ring homomorphism as conversion map + This function tries to register the given ring homomorphism as conversion + map. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.create_specialization([E(5), E(7), E(3)]) # indirect doctest Universal Cyclotomic Field sage: _.convert_map_from(BR) Ring morphism: - From: Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w - over Integer Ring + From: Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) To: Universal Cyclotomic Field Defn: u |--> E(5) v |--> E(7) - with map of base ring + w |--> E(3) """ - domain = ring_hom.domain() + domain = ring_hom.domain() codomain = ring_hom.codomain() conversion_cached = codomain._is_conversion_cached(domain) @@ -77,157 +100,30 @@ def register_ring_hom(ring_hom): test_map = codomain.convert_map_from(domain) try: if test_map != ring_hom: - verbose('\nConversion:\n%s\n already exists and is different from:\n%s\n' %(test_map,ring_hom)) + verbose('\nConversion:\n%s\n already exists and is different from:\n%s\n' % (test_map, ring_hom)) except TypeError: - verbose('\n Conversion:\n%s\n already exists and is not comparable to:\n%s\n' %(test_map,ring_hom)) + verbose('\n Conversion:\n%s\n already exists and is not comparable to:\n%s\n' % (test_map, ring_hom)) else: try: codomain.register_conversion(ring_hom) except ValueError: - verbose('\nthe map:\n%s\ncannot be registerd as conversion\n' %(ring_hom)) + verbose('\nthe map:\n%s\ncannot be registerd as conversion\n' % ring_hom) return -def preparse_mvp(string, mvp_indet): - r""" - Preparse a string produced via GAP3 interface and containing Jean Michel's ``MVP`` (multivariate polynomials) - such that it can be evaluated by ``sage_eval``. In particular missing multiplication signs are inserted. - Furthermore, exponentiation is replaced by a special function ``xpow`` which must be defined before the - function's result can be evaluated. - - INPUT: - - - ``string`` -- string produced via ``GAP3`` interface and containing Jean Michel's ``MVP`` (multivariate polynomials) - - ``mvp_indet`` -- list of strings containing the names of the ``MVP``-variables. - - - EXAMPLES:: - - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr - sage: chbr.preparse_mvp('2+a^-2bc+a^-1b^-1c^2', ['a', 'b', 'c']) - '2+xpow(a,1)^-2*xpow(b,1)*xpow(c,1)+xpow(a,1)^-1*xpow(b,1)^-1*xpow(c,1)^2' - """ - - def erase_useless_whitespace(strg): - res = strg.strip() - if res.find(' ') < 0: - return res - pos = int(len(res)/2) # len(res) must be > 1 since it is stripped and contains whitespaces - - if res[pos] != ' ': - # find a pos near to that on a whitespace - left = res[:pos] - right = res[pos+1:] - pos = right.find(' ') - if pos >= 0: - # first whitespace position in the right part - pos += len(left) + 1 - else: - # last whitespace position in the left part - left_rev = list(left) - left_rev.reverse() - pos = len(left) - left_rev.index(' ') - 1 - - end_left = res[pos-1] - start_right = res[pos+1] - left = res[:pos] - right = res[pos+1:] - if end_left.isdigit() and start_right.isdigit(): - return erase_useless_whitespace(left) + ' ' + erase_useless_whitespace(right) - return erase_useless_whitespace(left) + erase_useless_whitespace(right) - - # ------------------------------------------------------------------------ - # first erase carriage returns and useless whitespaces - # ------------------------------------------------------------------------ - new_string = string.replace('\n', ' ') - new_string = erase_useless_whitespace(new_string) - - # ------------------------------------------------------------------------------ - # Because of exponentiation with fractions we need to obtain the indeterminates - # as functions having the exponent as argument - # ------------------------------------------------------------------------------ - for indet in mvp_indet: # first the critical cases (protecting them by upper for following change) - new_string = new_string.replace('%s^(' %(indet), 'xpow(%s,' %(indet.upper())) - - for indet in mvp_indet: # than remaining trivial cases - new_string = new_string.replace('%s' %(indet), 'xpow(%s,1)' %(indet)) - - for indet in mvp_indet: # rename protected items of the first change - new_string = new_string.replace(indet.upper(), indet) - - # ------------------------------------------------------------------------------ - # Now start to insert missing '*' signs taking a pseudonym '?' for it, first - # ------------------------------------------------------------------------------ - # Insert '*' left of 'xpow' - # ------------------------------------------------------------------------------ - new_string = new_string.replace('xpow', '?xpow' ) - - # ------------------------------------------------------------------------------ - # Insert '*' right of ')' - # ------------------------------------------------------------------------------ - new_string = new_string.replace(')', ')?' ) - - # ------------------------------------------------------------------------------ - # Insert '*' left of 'E' (starting a roots of unity or a functions ('ER') of - # roots of integers) - # ------------------------------------------------------------------------------ - new_string = new_string.replace('E', '?E' ) - - # ------------------------------------------------------------------------------ - # Insert '*' left and right of 'I' (root of -1) - # ------------------------------------------------------------------------------ - new_string = new_string.replace('I', '?I?' ) - - # ------------------------------------------------------------------------------ - # remove multiples - # ------------------------------------------------------------------------------ - while '??' in new_string: - new_string = new_string.replace('??', '?') - - # ------------------------------------------------------------------------------ - # remove impossible neighbouring - # ------------------------------------------------------------------------------ - new_string = new_string.replace('^?', '^') - new_string = new_string.replace('?^', '^') - new_string = new_string.replace('+?', '+') - new_string = new_string.replace('?+', '+') - new_string = new_string.replace('-?', '-') - new_string = new_string.replace('?-', '-') - new_string = new_string.replace('/?', '/') - new_string = new_string.replace('?/', '/') - new_string = new_string.replace('[?', '[') - new_string = new_string.replace('?]', ']') - new_string = new_string.replace('(?', '(') - new_string = new_string.replace('?)', ')') - new_string = new_string.replace('?,', ',') - new_string = new_string.replace(',?', ',') - if new_string.startswith('?'): - new_string = new_string[1:] - if new_string.endswith('?'): - new_string = new_string[:len(new_string)-1] - - # ------------------------------------------------------------------------------ - # replace pseudonym - # ------------------------------------------------------------------------------ - new_string = new_string.replace('?', '*') - return new_string - - - - - -# --------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ # class for the Galois Group action on the generic extension ring corresponding # to the cubic equation -# --------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ class GaloisGroupAction(Action): r""" Action on a multivariate polynomial ring by permuting the generators. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: from operator import mul sage: R. = ZZ[] sage: G = SymmetricGroup(3) @@ -241,9 +137,11 @@ class GaloisGroupAction(Action): def _act_(self, perm, pol): r""" Application of the action + EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: from operator import mul sage: R. = QQ[] sage: G = SymmetricGroup(2) @@ -264,52 +162,54 @@ def _act_(self, perm, pol): return self.domain()(pol_dict) - - - - - - - - - -####################################################################################################################### +################################################################################ # EXTENSION RING -####################################################################################################################### - -# ------------------------------------------------------------------------------------------------------------------ -# Definition of the generic extension ring for the cubic Hecke algebra as Laurent polynomial ring in 3 indeterminates -# over the cyclotomic field of a third root of unity -# This is the most general ring over which the cubic Hecke algebra is semi-simple -# In opposite to the generic base ring class, this class does not inherits from UniqueRepresentation -# since _test_pickling fails -# -------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------ +# Definition of the generic extension ring for the cubic Hecke algebra as +# Laurent polynomial ring in 3 indeterminates over the cyclotomic field of a +# third root of unity This is the most general ring over which the cubic Hecke +# algebra is semi-simple. In opposite to the generic base ring class, this class +# does not inherits from UniqueRepresentation since _test_pickling fails +# ------------------------------------------------------------------------------ class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): r""" - This class implements the generic splitting algebra for the irreducible representations of the cubic Hecke algebra. + This class implements the generic splitting algebra for the irreducible + representations of the cubic Hecke algebra. - This ring must contain three invertible indeterminats (representing the roots of the cubic equation) - together with a third root of unity (needed for the 18-dimensional irreducibles of the cubic Hecke algebra - on 4 strands). + This ring must contain three invertible indeterminates (representing the + roots of the cubic equation) together with a third root of unity (needed + for the 18-dimensional irreducibles of the cubic Hecke algebra on 4 strands). - Therefore this ring is constructed as a multivariate Laurent polynomial ring in three indeterminates over a - polynomial quotient ring over the integers with respect to the minimal polynomial of a third root of unity. + Therefore this ring is constructed as a multivariate Laurent polynomial + ring in three indeterminates over a polynomial quotient ring over the + integers with respect to the minimal polynomial of a third root of unity. - The polynomial quotient ring is constructed as instance of :class:`SplittingAlgebra`. The name of the third - root of unity is fixed to be ``e3``. + The polynomial quotient ring is constructed as instance of + :class:`SplittingAlgebra`. INPUT: - - ``names`` -- string containing the names of the indeterminates separated by ',' or a triple of strings each of - which is the name of one of the three indeterminates - - ``order`` -- string (optional, default='degrevlex') transferred to the corresponding input of - LaurentPolynomialRing_mpair - - ``ring_of_definition`` -- instance of CubicHeckeRingOfDefinition (optional, default=None) to specify the generic - cubic Hecke base ring over which self may be realized as splitting ring via the as_splitting_algebra method + - ``names`` -- string containing the names of the indeterminates separated + by ',' or a triple of strings each of which is the name of one of the + three indeterminates. The default is ``u, v, w`` + - ``order`` -- string (optional, default='degrevlex') transferred to the + corresponding input of LaurentPolynomialRing_mpair + - ``ring_of_definition`` -- instance of CubicHeckeRingOfDefinition + (optional, default=None) to specify the generic cubic Hecke base ring + over which self may be realized as splitting ring via the + ``as_splitting_algebra`` method + - ``third_unity_root_name`` -- optional string (default is ``e3``) for + setting the name of the third root if unity of ``self``. + - ``markov_trace_version`` -- optional boolean (default is ``False``). + If this is set to ``True`` then ``self`` contains one invertible + indeterminate in addition which is meant to represent the writhe factor + of a Markov trace on the cubic Hecke algebra and which default name + is ``s`` EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: chbr.CubicHeckeExtensionRing('a, b, c') Multivariate Laurent Polynomial Ring in a, b, c over Splitting Algebra of x^2 + x + 1 @@ -318,79 +218,75 @@ class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): sage: _.an_element() b^2*c^-1 + e3*a """ - - - def __init__(self, names, order='degrevlex', ring_of_definition=None, third_unity_root_name='e3'): + def __init__(self, names, order='degrevlex', ring_of_definition=None, third_unity_root_name='e3', markov_trace_version=False): r""" Python constructor. TESTS:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: TestSuite(ER).run() """ - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # Setting connection with generic base ring (if given) - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- self._ring_of_definition = None self._splitting_algebra = None - if ring_of_definition != None: + if ring_of_definition is not None: if not isinstance(ring_of_definition, CubicHeckeRingOfDefinition): - raise TypeError( "generic base ring must be an instance of CubicHeckeRingOfDefinition") + raise TypeError("generic base ring must be an instance of CubicHeckeRingOfDefinition") self._ring_of_definition = ring_of_definition - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # defining the base ring # note that we can't use ZZ.extension since it isn't possible to define # homomorphisms from orders in number fields, yet - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- base_ring = SplittingAlgebra(cyclotomic_polynomial(3), [third_unity_root_name]) - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # defining the ring itself - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - self._names = normalize_names(3, names) + # ---------------------------------------------------------------------- + self._names = normalize_names_markov(names, markov_trace_version) self._order = order pol_ring = PolynomialRing(base_ring, names=self._names, order=self._order, implementation=None) LaurentPolynomialRing_mpair.__init__(self, pol_ring) - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # setting Galois group action - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- from sage.groups.perm_gps.permgroup_named import SymmetricGroup - from operator import mul - self._galois_group = SymmetricGroup(3) + from operator import mul + self._galois_group = SymmetricGroup(3) galois_group_action = GaloisGroupAction(self._galois_group, self, op=mul) self._unset_coercions_used() self.register_action(galois_group_action) - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # Init of data used on demand - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- self._mirror = None - return - - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ############################################################################ # overloaded inherited methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### + ############################################################################ + def construction(self): + r""" + Return ``None`` since this construction is not functorial. + EXAMPLES:: + + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: ER._test_category() # indirect doctest + """ + return None def __reduce__(self): r""" @@ -398,7 +294,8 @@ def __reduce__(self): TESTS:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: loads(dumps(ER)) == ER True @@ -408,17 +305,18 @@ def __reduce__(self): def _element_constructor_(self, x, mon=None): r""" Inherited element constructor overloaded to allow construction from - GAP3 Mvp exressions. + *GAP3* *Mvp* expressions. EXAMPLES:: - sage: CHA3 = algebras.CubicHecke(3) # optional gap3 - sage: GER = CHA3.extension_ring(generic=True) # optional gap3 - sage: sch7 = CHA3.chevie().SchurElements()[7] # optional gap3 - sage: GER(sch7) # optional gap3 - a*b*c^-2 + a^2*b^-1*c^-1 + a^-1*b^2*c^-1 + 2 + a*b^-2*c + a^-2*b*c + a^-1*b^-1*c^2 - sage: rep4_gap3 = CHA3.chevie().Representations(4) # optional gap3 - sage: matrix(GER, rep4_gap3[1]) # optional gap3 + sage: CHA3 = algebras.CubicHecke(3) # optional gap3 + sage: GER = CHA3.extension_ring(generic=True) # optional gap3 + sage: sch7 = CHA3.chevie().SchurElements()[7] # optional gap3 + sage: GER(sch7) # optional gap3 + a*b*c^-2 + a^2*b^-1*c^-1 + a^-1*b^2*c^-1 + 2 + + a*b^-2*c + a^-2*b*c + a^-1*b^-1*c^2 + sage: rep4_gap3 = CHA3.chevie().Representations(4) # optional gap3 + sage: matrix(GER, rep4_gap3[1]) # optional gap3 [ b 0] [-b c] """ @@ -427,19 +325,21 @@ def _element_constructor_(self, x, mon=None): return self._convert_from_gap3_mvp(x) return super(CubicHeckeExtensionRing, self)._element_constructor_(x, mon=mon) - def hom(self, im_gens, codomain=None, check=True, base_map=None): r""" - Custom version overloading the corresponding method of class :class:`~sage.structure.parent_gens.ParentWithGens` - because of special effort with respect to the third root of unity. + Custom version overloading the corresponding method of class + :class:`~sage.structure.parent_gens.ParentWithGens` because of special + effort with respect to the third root of unity. - INPUT: according to the class :class:`~sage.structure.parent_gens.ParentWithGens`. For more information type ``ParentWithGens.hom?`` + INPUT: according to the class :class:`~sage.structure.parent_gens.ParentWithGens`. + For more information type ``ParentWithGens.hom?`` OUTPUT: according to the :class:`~sage.structure.parent_gens.ParentWithGens`. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: UCF = UniversalCyclotomicField() sage: map = ER.hom((UCF.gen(3),) + (UCF(3),UCF(4),UCF(5))) @@ -448,56 +348,80 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): sage: map(_) -1/5*E(3) - 16/5*E(3)^2 """ + gens = self.gens() + num_gens = len(gens) - if not isinstance(im_gens, (list,tuple)): + if not isinstance(im_gens, (list, tuple)): im_gens = [im_gens] - if len(im_gens) == 4: - e3, ia, ib, ic = im_gens + if len(im_gens) == num_gens + 1: + e3, *im_remain = im_gens hom_cycl_gen = self.base_ring().hom([e3], codomain=e3.parent(), check=check, base_map=base_map) - verbose( "hom_cycl_gen %s" %(hom_cycl_gen)) - return super(CubicHeckeExtensionRing, self).hom([ia, ib, ic], codomain=codomain, check=check, base_map=hom_cycl_gen) + verbose("hom_cycl_gen %s" % hom_cycl_gen, level=2) + return super(CubicHeckeExtensionRing, self).hom(im_remain, codomain=codomain, check=check, base_map=hom_cycl_gen) else: if base_map is None: - raise ValueError("number of images must be four (inculding a third root of unity at first position) or a base_map (on %s) must be given" %self.base_ring()) - return super(CubicHeckeExtensionRing, self).hom([ia, ib, ic], codomain=codomain, check=check, base_map=base_map) + raise ValueError('number of images must be four (inculding a ' + 'third root of unity at first position) or a ' + 'base_map (on %s) must be given' % self.base_ring()) + return super(CubicHeckeExtensionRing, self).hom(im_gens, codomain=codomain, check=check, base_map=base_map) def _an_element_(self): r""" - Overwriting the original method to obtain an more interesting element for ``TestSuite``. + Overwrite the original method to obtain a more interesting element for + ``TestSuite``. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('x, y, z') - sage: ER.an_element() # indirect doctest + sage: ER.an_element() # indirect doctest y^2*z^-1 + e3*x + sage: MER = chbr.CubicHeckeExtensionRing('x, y, z, s', markov_trace_version=True) + sage: MER.an_element() # indirect doctest + y^2*z^-1 + e3*x*s^-1 """ - - a, b, c = self.gens() + a, b, c, *rem = self.gens() e3 = self.cyclotomic_generator() - return b**2/c+a*e3 - + s = self.one() + if rem: + s = rem[0] + return b**2/c+a*e3/s - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ############################################################################ # local methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### + ############################################################################ + def _is_markov_trace_version(self): + r""" + Return whether ``self`` is the version containing the writhe parameter + ``s`` for the Markov trace. + EXAMPLES:: - # ------------------------------------------------------------------------------- + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: ER._is_markov_trace_version() + False + sage: MER = chbr.CubicHeckeExtensionRing('a, b, c, s', markov_trace_version=True) + sage: MER._is_markov_trace_version() + True + """ + return len(self.gens()) == 4 + + # -------------------------------------------------------------------------- # helper for element construction - # ------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _convert_from_gap3_mvp(self, mvp_expression): r""" - Convert a string produced via GAP3 interface and containing Jean Michel's ``MVP`` (multivariate polynomials) - to an element of ``self``. + Convert a string produced via *GAP3* interface and containing Jean + Michel's *MVP* (multivariate polynomials) to an element of ``self``. INPUT: - - ``string`` -- string produced via GAP3 interface and containing Jean Michel's ``MVP`` (multivariate polynomials) + - ``string`` -- string produced via GAP3 interface and containing + Jean Michel's *MVP* (multivariate polynomials) OUTPUT: @@ -505,43 +429,42 @@ def _convert_from_gap3_mvp(self, mvp_expression): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') - sage: ER._convert_from_gap3_mvp('2+a^-2bc+a^-1b^-1c^2+a^-1b^2c^-1+ab^-2c') - a^-1*b^2*c^-1 + 2 + a*b^-2*c + a^-2*b*c + a^-1*b^-1*c^2 + sage: gap3_string = '2+a^-2bc+a^-1b^-1c^2+a^-1b^2c^-1+ab^-2E3c' + sage: ER._convert_from_gap3_mvp(gap3_string) + a^-1*b^2*c^-1 + 2 + e3*a*b^-2*c + a^-2*b*c + a^-1*b^-1*c^2 """ E3 = self.cyclotomic_generator() - - def xpow(indet, exp): - r""" - Realizing power. - """ - return indet**exp - - a, b, c = self.gens() - na, nb, nc = var_names = self.variable_names() - lc={na:a, nb:b, nc:c, 'E3':E3} - lc['xpow'] = xpow - - sage_expression = preparse_mvp('%s' %(mvp_expression), var_names) - + a, b, c, *rem = self.gens() + na, nb, nc = self.variable_names() + lc = {na: a, nb: b, nc: c, 'e': E3} + var_names = list(lc.keys()) + + from sage.repl.preparse import implicit_mul + # since implicit_mul does not know about the choice of variable names + # we have to insert * between them separately + string = str(mvp_expression) + string = string.replace('E3', 'e') + for i in var_names: + for j in var_names: + string = string.replace('%s%s' % (i, j), '%s*%s' % (i, j)) + sage_expression = implicit_mul(string) from sage.misc.sage_eval import sage_eval - return sage_eval(sage_expression, locals=lc) + return sage_eval(sage_expression, locals=lc) - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ############################################################################ # global methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### - + ############################################################################ def cyclotomic_generator(self): r""" Return the third root of unity as generator of the base ring of ``self``. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: ER.cyclotomic_generator() e3 @@ -550,16 +473,36 @@ def cyclotomic_generator(self): """ return self(self.base_ring().gen()) + def conjugation(self): + r""" + Return an involution that performs *complex conjugation* with respect to + base ring considered as order in the complex field. + + EXAMPLES:: + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('x, y, z') + sage: conj = ER.conjugation() + sage: conj(ER.an_element()) + y^2*z^-1 + (-e3 - 1)*x + sage: MER = chbr.CubicHeckeExtensionRing('x, y, z, s', markov_trace_version=True) + sage: conj = MER.conjugation() + sage: conj(MER.an_element()) + y^2*z^-1 + (-e3 - 1)*x*s^-1 + """ + e3 = self.cyclotomic_generator() + return self.hom(tuple([e3**2] + list(self.gens()))) def cubic_equation_galois_group(self): r""" - Return the Galois group of the cubic equation, which is the permutation group on the three generators - together with its action on ``self``. + Return the Galois group of the cubic equation, which is the permutation + group on the three generators together with its action on ``self``. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: G = ER.cubic_equation_galois_group() sage: t = ER.an_element() @@ -574,16 +517,17 @@ def cubic_equation_galois_group(self): return self._galois_group - def mirror_involution(self): r""" - Return the involution of ``self`` corresponding to the involution of the cubic Hecke algebra - (with the same name). This means that it maps the generators of ``self`` to their inverses. + Return the involution of ``self`` corresponding to the involution of + the cubic Hecke algebra (with the same name). This means that it maps + the generators of ``self`` to their inverses. .. NOTE:: - The mirror involution of the braid group does not factor through the cubic hecke algebra over its - base ring, but it does if it is considered as `\ZZ`-algebra. The base ring elements are transformed by + The mirror involution of the braid group does not factor through the + cubic hecke algebra over its base ring, but it does if it is + considered as `\ZZ`-algebra. The base ring elements are transformed by this automorphism. OUTPUT: @@ -592,7 +536,8 @@ def mirror_involution(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('p, q, r') sage: ER.mirror_involution() Ring endomorphism of Multivariate Laurent Polynomial Ring in p, q, r @@ -605,35 +550,52 @@ def mirror_involution(self): with map of base ring sage: _(ER.an_element()) e3*p^-1 + q^-2*r + + sage: MER = chbr.CubicHeckeExtensionRing('p, q, r, s', markov_trace_version=True) + sage: MER.mirror_involution() + Ring endomorphism of Multivariate Laurent Polynomial Ring in p, q, r, s + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] over Integer Ring + Defn: p |--> p^-1 + q |--> q^-1 + r |--> r^-1 + s |--> s^-1 + with map of base ring + sage: _(MER.an_element()) + e3*p^-1*s + q^-2*r """ - if self._mirror == None: - a, b, c = self.gens() + if self._mirror is None: e3 = self.base_ring().gen() - self._mirror = self.hom([e3, ~a, ~b, ~c]) + if self._is_markov_trace_version(): + a, b, c, s = self.gens() + self._mirror = self.hom([e3, ~a, ~b, ~c, ~s]) + else: + a, b, c = self.gens() + self._mirror = self.hom([e3, ~a, ~b, ~c]) return self._mirror - - - - def create_specialization(self, im_cubic_equation_roots, var='T', third_unity_root_name='E3'): + def create_specialization(self, im_cubic_equation_roots, im_writhe_parameter=None, var='T', third_unity_root_name='E3'): r""" - Return an appropriate Ring containing the elements from the list ``im_cubic_equation_roots`` - defining a conversion map from self mapping the cubic equation roots of ``self`` to - ``im_cubic_equation_roots``. + Return an appropriate Ring containing the elements from the list + ``im_cubic_equation_roots`` defining a conversion map from self mapping + the cubic equation roots of ``self`` to ``im_cubic_equation_roots``. INPUT: - - ``im_cubic_equation_roots`` -- list or tuple of three ring elements such that there exists - a ring homomorphism from the corresponding elements of ``self`` to them + - ``im_cubic_equation_roots`` -- list or tuple of three ring elements + such that there exists a ring homomorphism from the corresponding + elements of ``self`` to them OUTPUT: - A common parent containing the elements of ``im_cubic_equation_roots`` together with their inverses. + A common parent containing the elements of ``im_cubic_equation_roots`` + together with their inverses. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: t = ER.an_element(); t b^2*c^-1 + e3*a @@ -642,51 +604,76 @@ def create_specialization(self, im_cubic_equation_roots, var='T', third_unity_ro sage: Sp1(t) -E(105)^11 - E(105)^16 - E(105)^26 - E(105)^37 - E(105)^41 - E(105)^58 - E(105)^71 - E(105)^79 - E(105)^86 - E(105)^101 + sage: MER = chbr.CubicHeckeExtensionRing('a, b, c, s', markov_trace_version=True) + sage: MER.create_specialization([E(5), E(7), E(3)], im_writhe_parameter=E(4)) + Universal Cyclotomic Field + sage: a, b, c, s = MER.gens() + sage: Sp1(MER(t)/s) + E(420) + E(420)^29 + E(420)^89 + E(420)^149 + E(420)^169 + E(420)^209 + + E(420)^253 + E(420)^269 + E(420)^337 + E(420)^389 sage: Z3 = CyclotomicField(3); E3=Z3.gen() sage: Sp2 = ER.create_specialization([E3, E3**2, Z3(1)]) sage: Sp2(t) -1 + sage: MER.create_specialization([E3, E3**2, 1], im_writhe_parameter=2) + Cyclotomic Field of order 3 and degree 2 + sage: Sp2(MER(t)*s) + -2 sage: Sp3 = ER.create_specialization([5, 7, 11]) sage: Sp3(t) 5*E3 + 49/11 """ - # --------------------------------------------------------------------------------- - # interpreting user given cubic equation roots and define the corresponding - # specialized extension ring - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # interpreting user given cubic equation roots and define the + # corresponding specialized extension ring. + # ---------------------------------------------------------------------- if type(im_cubic_equation_roots) == tuple: im_cubic_equation_roots = list(im_cubic_equation_roots) if type(im_cubic_equation_roots) != list: - raise TypeError( "cubic_equation_roots must be a list of three elements" ) + raise TypeError('cubic_equation_roots must be a list of three elements') if len(im_cubic_equation_roots) != 3: - raise ValueError( "there must be exactly three cubic_equation_roots" ) + raise ValueError('there must be exactly three cubic_equation_roots') + + gens = self.gens() + num_gens = len(gens) + if im_writhe_parameter: + if num_gens < 4: + raise ValueError('im_writhe_parameter only possible for Markov-trace extension') + im_gens = im_cubic_equation_roots + [im_writhe_parameter] + a, b, c, s = im_gens + else: + if num_gens == 4: + raise ValueError('im_writhe_parameter must be given for Markov-trace extension') + im_gens = im_cubic_equation_roots + a, b, c = im_gens - image_ring = get_coercion_model().common_parent(*(im_cubic_equation_roots)) + image_ring = get_coercion_model().common_parent(*(im_gens)) - # --------------------------------------------------------------------------------------------------------- - # make sure that all given cubic equation roots and their inverses belongs to image_ring - # --------------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # make sure that all given cubic equation roots and their inverses + # belong to image_ring + # ---------------------------------------------------------------------- try: - image_ring = image_ring.localization(tuple(im_cubic_equation_roots)) + image_ring = image_ring.localization(tuple(im_gens)) except ValueError: pass - im_cubic_equation_roots = [image_ring(root) for root in im_cubic_equation_roots] - verbose("common parent of roots and inverses: %s" %(image_ring)) + im_gens = [image_ring(root) for root in im_gens] + verbose('common parent of roots and inverses: %s' % (image_ring), level=2) image_ring_base = image_ring.base_ring() image_ring_map = None - verbose("first choice: image_ring %s, image_ring_base %s" %(image_ring, image_ring_base)) + verbose('first choice: image_ring %s, image_ring_base %s' % (image_ring, image_ring_base), level=2) - # --------------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # make sure that a third root of unity belongs to image_ring - # --------------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- E3 = None cp3 = cyclotomic_polynomial(3, var=var).change_ring(image_ring) @@ -694,22 +681,22 @@ def create_specialization(self, im_cubic_equation_roots, var='T', third_unity_ro if len(cyclotomic_roots) > 0: E3 = cyclotomic_roots[0] - verbose("thrird root of unity %s found in %s" %(E3, E3.parent())) + verbose('thrird root of unity %s found in %s' % (E3, E3.parent()), level=2) - if E3 == None: - raise RuntimeError( "cannot find a ring containing a third root of unity for the this choice of cubic roots!" ) + if E3 is None: + raise RuntimeError('cannot find a ring containing a third root of unity for the this choice of cubic roots!') - hom_gens = [E3] + im_cubic_equation_roots - verbose("hom_gens %s" %(hom_gens)) + hom_gens = [E3] + im_gens + verbose('hom_gens %s' % hom_gens, level=2) image_ring = get_coercion_model().common_parent(*(hom_gens)) - verbose("common parent of roots and third root: %s" %(image_ring)) + verbose('common parent of roots and third root: %s' % image_ring, level=2) hom_gens = [image_ring(gen) for gen in hom_gens] image_ring_base = image_ring.base_ring() - verbose("second choice: image_ring %s, image_ring_base %s" %(image_ring, image_ring_base)) + verbose('second choice: image_ring %s, image_ring_base %s' % (image_ring, image_ring_base), level=2) try: image_ring_map = self.hom(hom_gens, codomain=image_ring) @@ -717,17 +704,15 @@ def create_specialization(self, im_cubic_equation_roots, var='T', third_unity_ro image_ring_map = self.hom(hom_gens, codomain=image_ring, check=False) verbose('check failed for embedding as ring morphism') - verbose("specializing map defined %s" %(image_ring_map)) + verbose('specializing map defined %s' % image_ring_map, level=2) register_ring_hom(image_ring_map) return image_ring - - def as_splitting_algebra(self): r""" - Return ``self`` as instance of class :class:`SplittingAlgebra` that is as an - extension ring of the corresponding cubic Hecke algebra base ring + Return ``self`` as instance of class :class:`SplittingAlgebra` that is + as an extension ring of the corresponding cubic Hecke algebra base ring (``self._ring_of_definition``, an instance of class :class:`CubicHeckeRingOfDefinition`) splitting its cubic equation into linear factors, such that the roots are images of the generators @@ -735,96 +720,221 @@ def as_splitting_algebra(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: GBR = chbr.CubicHeckeRingOfDefinition() sage: GER = GBR.extension_ring() sage: ER = GER.as_splitting_algebra(); ER Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] over Splitting Algebra of h^3 - u*h^2 + v*h - w with roots [a, b, -b - a + u] - over Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring + over Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) sage: ER(GER.an_element()) - a*E3 + (((-w^-1)*u)*a^2 + ((w^-1)*u^2 + (-w^-1)*v)*a)*b + a - u + a*E3 + ((u/(-w))*a^2 + ((u^2 - v)/w)*a)*b + a - u sage: ER(GBR.an_element()) - (w^-1)*u^2 + v - """ + (u^2 + v*w)/w - if self._splitting_algebra != None: - verbose("End (short)") + sage: MBR = chbr.CubicHeckeRingOfDefinition(markov_trace_version=True) + sage: MER = MBR.extension_ring() + sage: ES = MER.as_splitting_algebra(); ES + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Splitting Algebra of h^3 - u*h^2 + v*h - w + with roots [a, b, -b - a + u] + over Multivariate Polynomial Ring in u, v, w, s + over Integer Ring localized at (s, w, v, u) + sage: ES(MER.an_element()) + (((-1)/(-s))*a)*E3 + ((u/(-w))*a^2 + ((u^2 - v)/w)*a)*b + a - u + sage: ES(MBR.an_element()) + (u^2*s + v*w)/(w*s) + """ + if self._splitting_algebra is not None: + verbose("End (short)", level=2) return self._splitting_algebra - if self._ring_of_definition == None: - verbose("constructing generic base ring") + if self._ring_of_definition is None: + verbose("constructing generic base ring", level=2) self._ring_of_definition = CubicHeckeRingOfDefinition() + markov = self._is_markov_trace_version() + BR = self._ring_of_definition root_names = list(self._names) - root_names.pop() # Z not needed + var_s = None + if markov: + var_s = root_names.pop() # s not needed as root + a, b, c, s = self.gens() + else: + a, b, c = self.gens() + + root_names.pop() # c not needed as root FSR = SplittingAlgebra(BR.cubic_equation(), root_names, warning=False) splitting_roots = FSR.splitting_roots() - verbose("splitting roots %s" %(splitting_roots)) + verbose('splitting roots %s' % splitting_roots, level=2) A, B, C = splitting_roots - S = self.create_specialization([A, B, C]) - a, b, c = self.gens() e3 = self.cyclotomic_generator() - map_back = S.hom([e3, b, a, a + b + c, a*b+a*c+b*c, a*b*c]) + if var_s: + fsr_s = FSR.scalar_base_ring().gens_dict()[var_s] + S = self.create_specialization([A, B, C], im_writhe_parameter=fsr_s) + # check of embedding fails in this case as long as the images of + # ``iu`` and ``iv`` need to be invertible (see comment in + # :meth:`__init__` of :class:`CubicHeckeRingOfDefinition`). + map_back = S.hom([e3, b, a, a + b + c, a*b+a*c+b*c, a*b*c, s], check=False) + else: + S = self.create_specialization([A, B, C]) + map_back = S.hom([e3, b, a, a + b + c, a*b+a*c+b*c, a*b*c]) self.register_coercion(map_back) - self._splitting_algebra = S - return self._splitting_algebra + def field_embedding(self, characteristic=0): + r""" + Return a field embedding of ``self``. + INPUT: + - ``characteristic`` -- integer (optional, default 0) the characteristic + of the field. + EXAMPLES:: + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: ER = BR.extension_ring() + sage: ER.field_embedding() + Ring morphism: + From: Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] + over Integer Ring + To: Fraction Field of Multivariate Polynomial Ring in a, b, c + over Cyclotomic Field of order 3 and degree 2 + Defn: a |--> a + b |--> b + c |--> c + with map of base ring + sage: ER.field_embedding(characteristic=5) + Ring morphism: + From: Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] + over Integer Ring + To: Fraction Field of Multivariate Polynomial Ring in a, b, c + over Finite Field in a of size 5^2 + Defn: a |--> a + b |--> b + c |--> c + with map of base ring + sage: MER = ER.markov_trace_version() + sage: MER.field_embedding() + Ring morphism: + From: Multivariate Laurent Polynomial Ring in a, b, c, s + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] + over Integer Ring + To: Fraction Field of Multivariate Polynomial Ring in a, b, c, s + over Cyclotomic Field of order 3 and degree 2 + Defn: a |--> a + b |--> b + c |--> c + s |--> s + with map of base ring + """ + if characteristic == 0: + from sage.rings.number_field.number_field import CyclotomicField + C3 = CyclotomicField(3) + E3 = C3.gen() + else: + if not ZZ(characteristic).is_prime(): + raise ValueError('characteristic must be a prime integer') + from sage.rings.finite_rings.finite_field_constructor import GF + from sage.misc.functional import cyclotomic_polynomial + G = GF(characteristic) + c3 = cyclotomic_polynomial(3).change_ring(G) + C3 = c3.splitting_field('a') + E3 = c3.change_ring(C3).roots()[0][0] + + B = self.base_ring() + embBase = B.hom((E3,)) + if not C3.has_coerce_map_from(B): + C3._unset_coercions_used() + C3.register_coercion(embBase) + P = C3[self.variable_names()] + F = P.fraction_field() + emb = self.hom((F(E3),) + F.gens()) + F = emb.codomain() + if not F.has_coerce_map_from(self): + F._unset_coercions_used() + F.register_coercion(emb) + return emb + + def markov_trace_version(self): + r""" + Return the Markov trace version of ``self``. + EXAMPLES:: -####################################################################################################################### -# Ring of Definition -####################################################################################################################### - - + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr + sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') + sage: ER.markov_trace_version() + Multivariate Laurent Polynomial Ring in a, b, c, s + over Splitting Algebra of x^2 + x + 1 + with roots [e3, -e3 - 1] over Integer Ring + """ + if self._is_markov_trace_version(): + return self + names = self.variable_names() + ('s',) + return self.__class__(names=names, order=self._order, markov_trace_version=True) -# -------------------------------------------------------------------------------------------------------- -# Definition of the ring of definition for the cubic hecke algebra as polynomial ring in 2 indeterminates -# over univariate Laurent polynomial ring over the integers. -# This is the most general ring over which the cubic Hecke algebra may be defined. -# This class inherits from UniqueRepresentation since otherwise an error occurs when a second instance -# is declared. This error occurs in as_splitting_algebra of the associated extension ring. -# -------------------------------------------------------------------------------------------------------- -class CubicHeckeRingOfDefinition(MPolynomialRing_polydict, UniqueRepresentation): +################################################################################ +# Ring of Definition +# ------------------------------------------------------------------------------ +# Definition of the ring of definition for the cubic Hecke algebra as polynomial +# ring in 2 indeterminates over univariate Laurent polynomial ring over the +# integers. This is the most general ring over which the cubic Hecke algebra may +# be defined. +# ------------------------------------------------------------------------------ +class CubicHeckeRingOfDefinition(Localization): r""" This class implements the *ring of definition* of the cubic Hecke algebra. - It contains one invertible indeterminate (representing the product of the roots - of the cubic equation) and two non invertible indeterminates. + It contains one invertible indeterminate (representing the product of the + roots of the cubic equation) and two non invertible indeterminates. INPUT: - - ``names`` -- string containing the names of the indeterminates seperated by ',' - or a triple of strings each of which is the name of one of the three indeterminates - - ``order`` -- string (optional, default='degrevlex') transferred to the corresponding - input of LaurentPolynomialRing_mpair + - ``names`` -- string containing the names of the indeterminates separated + by ',' or a triple of strings each of which is the name of one of the + three indeterminates. The default is ``u, v, w``. + - ``order`` -- string (optional, default='degrevlex') transferred to the + corresponding input of LaurentPolynomialRing_mpair + - ``markov_trace_version`` -- optional boolean (default is ``False``). + If this is set to ``True`` then ``self`` contains one invertible + indeterminate in addition which is meant to represent the writhe factor + of a Markov trace on the cubic Hecke algebra and which default name + is ``s`` + EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() - sage: u, v, w = BR.gens_over_ground() + sage: u, v, w = BR.gens() sage: ele = 3*u*v-5*w**(-2) sage: ER = BR.extension_ring() sage: ER(ele) 3*a^2*b + 3*a*b^2 + 3*a^2*c + 9*a*b*c + 3*b^2*c + 3*a*c^2 + 3*b*c^2 + (-5)*a^-2*b^-2*c^-2 - sage: phi1 = BR.hom( [4,3,1] ) + sage: phi1 = BR.hom( [4,3,1/1] ) sage: phi1(ele) 31 @@ -843,205 +953,125 @@ class CubicHeckeRingOfDefinition(MPolynomialRing_polydict, UniqueRepresentation) - 5*E(105)^86 - 5*E(105)^89 - 5*E(105)^92 - 5*E(105)^101 - 5*E(105)^104 """ - - def __init__( self, names=('u', 'v', 'w'), order='degrevlex'): + def __init__(self, names=('u', 'v', 'w', 's'), order='degrevlex', markov_trace_version=False): r""" Python constructor. TESTS:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: TestSuite(BR).run() """ - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # ---------------------------------------------------------------------- # Saving class-globals - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - names = normalize_names(3, names) - self._order = order - self._all_names = names - self._invertible_name = names[2] - self._non_invertible_names = (names[0], names[1]) - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - # base ring containing the invertible variable - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - self._base_ring = LaurentPolynomialRing(ZZ, self._invertible_name) + # ---------------------------------------------------------------------- + # ---------------------------------------------------------------------- + names = normalize_names_markov(names, markov_trace_version) + if len(names) == 4: + # invertible_names = names[2:4] # s must be invertible, too + # + # because the formal Markov trace of the both basis elements + # ``self.get_order()[568]`` (``KnotInfo.L8a7_1``) and + # ``self.get_order()[596]`` (mirror image of ``KnotInfo.K9_46``) + # have the indeterminate ``v`` in their denominator we need to have + # all indeterminates invertible (``u`` as well for the mirror images) + invertible_names = names + else: + invertible_names = names[2] + self._order = order - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # --------------------------------------------------------------------- # Init of self - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - MPolynomialRing_polydict.__init__(self, self._base_ring, 2, self._non_invertible_names, order) + # ---------------------------------------------------------------------- + # ---------------------------------------------------------------------- + base_ring = PolynomialRing(ZZ, names, order=order) + Localization.__init__(self, base_ring, invertible_names) - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # Init of data used on demand - # --------------------------------------------------------------------------------- - self._mirror = None - + # ---------------------------------------------------------------------- + self._mirror = None return - # note: Element assignment is missing in MPolynomialRing_polydict. It activates the element_class method for self - Element = MPolynomial_polydict - - - - - - - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ############################################################################ # overloaded inherited methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### - - def __reduce__(self): - r""" - Used in pickling. - - EXAMPLES:: - - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr - sage: BR = chbr.CubicHeckeRingOfDefinition() - sage: loads(dumps(BR)) == BR - True - """ - return CubicHeckeRingOfDefinition, (self._all_names, self._order) - - + ############################################################################ def _defining_names(self): r""" - This method is cached in the parent class. This causes trouble if a second instance of self is used for - another cubic Hecke algebra in the same session. To avoid this it is overloaded without ``cached_method`` + This method is cached in the parent class. This causes trouble if a + second instance of self is used for another cubic Hecke algebra in the + same session. To avoid this it is overloaded without ``cached_method`` decorator. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR._defining_names() - (u, v) + (u, v, w) """ return self.gens() - - def __call__(self, x, check=True): - r""" - Overloaded to fix an inherited bug concerning ``_test_category``. - - EXAMPLES:: - - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr - sage: BR = chbr.CubicHeckeRingOfDefinition() - sage: BR.an_element()._test_category() # indirect doctest - """ - result = MPolynomialRing_polydict.__call__(self, x, check=check) - return self.element_class( self, result.dict() ) - - - def _an_element_(self): r""" - Overwriting the original method to obtain an more interesting element for ``TestSuite``. + Overwriting the original method to obtain an more interesting element + for ``TestSuite``. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.an_element() # indirect doctest - (w^-1)*u^2 + v + (u^2 + v*w)/w + sage: MBR = chbr.CubicHeckeRingOfDefinition(markov_trace_version=True) + sage: MBR.an_element() # indirect doctest + (u^2*s + v*w)/(w*s) """ + u, v, w, *rem = self.gens() + s = self.one() + if rem: + s = rem[0] + return u**2/w+v/s - u, v, w = self.gens_over_ground() - return u**2/w+v - - def hom(self, im_gens, codomain=None, check=True, base_map=None): + ############################################################################ + # Local Methods + ############################################################################ + def _is_markov_trace_version(self): r""" - Custom version overloading the corresponding method of class :class:`~sage.structure.parent_gens.ParentWithGens` - because of special effort with respect to invertible third parameter. - - INPUT: according to the calss :class:`~sage.structure.parent_gens.ParentWithGens`. For more information type ``ParentWithGens.hom?`` - - OUTPUT: according to the :class:`ParentWithGens`. + Return whether ``self`` is the version containing the writhe parameter + ``s`` for the Markov trace. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() - sage: R = ZZ.localization((5,)) - sage: im_gens = [R(z) for z in [3, 4, ~5]] - sage: map = BR.hom(im_gens) - sage: BR.an_element() - (w^-1)*u^2 + v - sage: map(_) - 49 + sage: BR._is_markov_trace_version() + False + sage: MBR = chbr.CubicHeckeRingOfDefinition(markov_trace_version=True) + sage: MBR._is_markov_trace_version() + True """ + return len(self.gens()) == 4 - if not isinstance(im_gens, (list,tuple)): - im_gens = [im_gens] - - if len(im_gens) == 3: - iu, iv, iw = im_gens - hom_on_laur = self.base_ring().hom([iw], base_map=base_map) - return super(CubicHeckeRingOfDefinition, self).hom([iu, iv], codomain=codomain, check=check, base_map=hom_on_laur) - else: - if base_map is None: - raise ValueError("number of images must be three or a base_map (on %s) must be given" %self.base_ring()) - return super(CubicHeckeRingOfDefinition, self).hom([iu, iv], codomain=codomain, check=check, base_map=base_map) - - - - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- - # Local Methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### - - - - - - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ############################################################################ # Global Methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### - - def gens_over_ground(self): - r""" - Return the generators of self over the ground ring. These are the generators of self over the base ring (u, v) - together with the generator of the base ring over the ground ring (w). - - EXAMPLES:: - - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr - sage: BR = chbr.CubicHeckeRingOfDefinition(names='A, B, C') - sage: BR.gens_over_ground() - [A, B, C] - - """ - gen_list = self.gens() + self.base_ring().gens() - return [ self(gen) for gen in gen_list ] - - - + ############################################################################ def cubic_equation(self, var='h', as_coefficients=False): r""" Return the cubic equation over which the cubic Hecke algebra is defined. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.cubic_equation() h^3 - u*h^2 + v*h - w @@ -1050,20 +1080,20 @@ def cubic_equation(self, var='h', as_coefficients=False): sage: BR.cubic_equation(as_coefficients=True) [-w, v, -u, 1] """ - u, v, w = self.gens_over_ground() + u, v, w, *rem = self.gens() cf = [-w, v, -u, 1] - if as_coefficients == True: + if as_coefficients: return cf P = PolynomialRing(self, var) return P(cf) - def mirror_involution(self): r""" - Return the involution of ``self`` corresponding to the involution of the cubic Hecke algebra - (with the same name). This means that it maps the the last generator of ``self`` to its inverse - and both others to their product with the image of the former. + Return the involution of ``self`` corresponding to the involution of the + cubic Hecke algebra (with the same name). This means that it maps the + last generator of ``self`` to its inverse and both others to their + product with the image of the former. From the cubic equation for a braid generator $\beta_i$: @@ -1071,7 +1101,7 @@ def mirror_involution(self): \beta_i^3 - u \beta_i^2 + v\beta_i -w = 0 - one deduces the following cubic equation for $\beta_i^{-1}$: + One deduces the following cubic equation for $\beta_i^{-1}$: .. MATH:: @@ -1079,8 +1109,9 @@ def mirror_involution(self): .. NOTE:: - The mirror involution of the braid group does not factor through the cubic Hecke algebra over its - base ring, but it does if it is considered as $\ZZ$-algebra. The base ring elements are transformed by + The mirror involution of the braid group does not factor through the + cubic Hecke algebra over its base ring, but it does if it is + considered as $\ZZ$-algebra. The base ring elements are transformed by this automorphism. OUTPUT: @@ -1089,128 +1120,168 @@ def mirror_involution(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.mirror_involution() - Ring endomorphism of Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring - Defn: u |--> (w^-1)*v - v |--> (w^-1)*u - with map of base ring + Ring endomorphism of Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) + Defn: u |--> v/w + v |--> u/w + w |--> 1/w sage: _(BR.an_element()) - (w^-1)*v^2 + (w^-1)*u + (v^2 + u)/w + + sage: MBR = chbr.CubicHeckeRingOfDefinition(markov_trace_version=True) + sage: MBR.mirror_involution() + Ring endomorphism of Multivariate Polynomial Ring in u, v, w, s + over Integer Ring localized at (s, w, v, u) + Defn: u |--> v/w + v |--> u/w + w |--> 1/w + s |--> 1/s + sage: _(MBR.an_element()) + (v^2 + u*s)/w """ - - if self._mirror == None: - u, v, w = self.gens_over_ground() - self._mirror = self.hom([v/w, u/w, ~w]) - + if self._mirror is None: + if self._is_markov_trace_version(): + u, v, w, s = self.gens() + self._mirror = self.hom([v/w, u/w, ~w, ~s]) + else: + u, v, w = self.gens() + self._mirror = self.hom([v/w, u/w, ~w]) return self._mirror - - - def create_specialization( self, im_cubic_equation_parameters): + def create_specialization(self, im_cubic_equation_parameters, im_writhe_parameter=None): r""" - Return an appropriate Ring containing the elements from the list ``im_cubic_equation_parameters`` - having a conversion map from ``self`` mapping the cubic equation parameters of ``self`` to + Return an appropriate Ring containing the elements from the list + ``im_cubic_equation_parameters`` having a conversion map from ``self`` + mapping the cubic equation parameters of ``self`` to ``im_cubic_equation_parameters``. INPUT: - - ``im_cubic_equation_parameters`` -- list or tuple of three ring elements such that there exists - a ring homomorphism from the corresponding elements of ``self`` to them + - ``im_cubic_equation_parameters`` -- list or tuple of three ring + elements such that there exists a ring homomorphism from the + corresponding elements of ``self`` to them OUTPUT: - a common parent containing the elements of ``im_cubic_equation_parameters`` together with an inverse - of the third element. + A common parent containing the elements of + ``im_cubic_equation_parameters`` together with an inverse of the third + element. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: t = BR.an_element(); t - (w^-1)*u^2 + v + (u^2 + v*w)/w sage: Sp1 = BR.create_specialization([E(5), E(7), E(3)]); Sp1 Universal Cyclotomic Field sage: Sp1(t) - E(105) + E(105)^8 + E(105)^29 - E(105)^37 + E(105)^43 - E(105)^52 + E(105)^64 - - E(105)^67 + E(105)^71 - E(105)^82 + E(105)^92 - E(105)^97 + E(105) + E(105)^8 + E(105)^29 - E(105)^37 + E(105)^43 - E(105)^52 + + E(105)^64 - E(105)^67 + E(105)^71 - E(105)^82 + E(105)^92 + - E(105)^97 + + sage: MBR = chbr.CubicHeckeRingOfDefinition(markov_trace_version=True) + sage: MBR.create_specialization([E(5), E(7), E(3)], im_writhe_parameter=E(4)) + Universal Cyclotomic Field + sage: u, v, w, s = MBR.gens() + sage: Sp1(MBR(t)/s) + E(420)^13 - E(420)^53 + E(420)^73 - E(420)^109 - E(420)^137 + - E(420)^221 + E(420)^253 - E(420)^277 + E(420)^313 - E(420)^361 + + E(420)^373 - E(420)^389 sage: Z3 = CyclotomicField(3); E3=Z3.gen() - sage: Sp2 = BR.create_specialization([E3, E3**2, Z3(1)]); Sp2 + sage: Sp2 = BR.create_specialization([E3, E3**2, 1]); Sp2 Cyclotomic Field of order 3 and degree 2 sage: Sp2(t) -2*zeta3 - 2 + sage: MBR.create_specialization([E3, E3**2, 1], im_writhe_parameter=2) + Cyclotomic Field of order 3 and degree 2 + sage: Sp2(MBR(t)/s) + -zeta3 - 1 sage: Sp3 = BR.create_specialization([5, 7, 11]); Sp3 Integer Ring localized at (11,) sage: Sp3(t) 102/11 """ - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # setting the base_ring according to the cubic_equation_parameters - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- if type(im_cubic_equation_parameters) == tuple: im_cubic_equation_parameters = list(im_cubic_equation_parameters) if type(im_cubic_equation_parameters) != list: - raise TypeError( "cubic_equation_parameters must be a list of three elements" ) + raise TypeError('cubic_equation_parameters must be a list of three elements') if len(im_cubic_equation_parameters) != 3: - raise ValueError( "there must be exactly three cubic_equation_parameters" ) + raise ValueError('there must be exactly three cubic_equation_parameters') + + gens = self.gens() + num_gens = len(gens) + if im_writhe_parameter: + if num_gens < 4: + raise ValueError('im_writhe_parameter only possible for Markov-trace extension') + im_gens = im_cubic_equation_parameters + [im_writhe_parameter] + u, v, w, s = im_gens + else: + if num_gens == 4: + raise ValueError('im_writhe_parameter must be given for Markov-trace extension') + im_gens = im_cubic_equation_parameters + u, v, w = im_gens image_ring = None image_ring_map = None - u, v, w = im_cubic_equation_parameters image_ring_base = w.parent() - # --------------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # short exit on trivial invocation - # --------------------------------------------------------------------------------------------------------- - if image_ring_base is self and im_cubic_equation_parameters == self.gens_over_ground(): + # ---------------------------------------------------------------------- + if image_ring_base is self and im_gens == gens: return self - image_ring = get_coercion_model().common_parent(*(im_cubic_equation_parameters)) + image_ring = get_coercion_model().common_parent(*(im_gens)) - # --------------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # make sure that the inverse of w belongs to image_ring - # --------------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- try: image_ring = image_ring.localization(w) except ValueError: pass - im_cubic_equation_parameters = [image_ring(para) for para in im_cubic_equation_parameters] + im_gens = [image_ring(para) for para in im_gens] - verbose("common parent of parameters and inverses: %s" %(image_ring)) + verbose('common parent of parameters and inverses: %s' % image_ring, level=2) try: - image_ring_map = self.hom(im_cubic_equation_parameters, codomain=image_ring) + image_ring_map = self.hom(im_gens, codomain=image_ring) except ValueError: - image_ring_map = self.hom(im_cubic_equation_parameters, codomain=image_ring, check=False) + image_ring_map = self.hom(im_gens, codomain=image_ring, check=False) verbose('Warning: check failed for embedding as ring morphism') register_ring_hom(image_ring_map) - return image_ring - - # -------------------------------------------------------------------------------------------------------- - # Definition of the generic extension ring for the cubic hecke algebra as Laurent polynomial ring in 3 - # indeterminates over cyclotomic field of order 3. The generic extension ring guarantees semisimplicity - # of the cubic Hecke algebra - # -------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- + # Definition of the generic extension ring for the cubic hecke algebra as + # Laurent polynomial ring in 3 indeterminates over cyclotomic field of order + # 3. The generic extension ring guarantees semisimplicity of the cubic Hecke + # algebra. + # -------------------------------------------------------------------------- @cached_method - def extension_ring(self, names='a, b, c'): + def extension_ring(self, names=('a', 'b', 'c', 's')): r""" Return the generic extension ring attached to ``self``. EXAMPLES:: - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.extension_ring() Multivariate Laurent Polynomial Ring in a, b, c @@ -1218,14 +1289,208 @@ def extension_ring(self, names='a, b, c'): with roots [e3, -e3 - 1] over Integer Ring """ - ExtensionRing = CubicHeckeExtensionRing(names, ring_of_definition=self) - a, b, c = ExtensionRing.gens() - - # ---------------------------------------------------------------------------------------------- - # constructing a canonical embedding of the generic base ring into the extension ring - # ---------------------------------------------------------------------------------------------- - iu = a+b+c; iv = a*b+a*c+b*c; iw = a*b*c - self._embedding_into_extension_ring_ = self.hom([iu, iv, iw]) - ExtensionRing.register_conversion( self._embedding_into_extension_ring_ ) + markov = self._is_markov_trace_version() + ExtensionRing = CubicHeckeExtensionRing(names, ring_of_definition=self, markov_trace_version=markov) + a, b, c, *rem = ExtensionRing.gens() + + # ---------------------------------------------------------------------- + # constructing a canonical embedding of the generic base ring into the + # extension ring + # ---------------------------------------------------------------------- + iu = a+b+c + iv = a*b+a*c+b*c + iw = a*b*c + im_gens = [iu, iv, iw] + if markov: + im_gens += rem + # check of embedding fails in this case as long as the images of + # ``iu`` and ``iv`` need to be invertible (see comment in + # :meth:`__init__`). # :class:`CubicHeckeRingOfDefinition`). + embedding_into_extension_ring = self.hom(im_gens, check=False) + else: + embedding_into_extension_ring = self.hom(im_gens) + if not ExtensionRing.has_coerce_map_from(self): + ExtensionRing._unset_coercions_used() + ExtensionRing.register_coercion(embedding_into_extension_ring) + ExtensionRing.register_conversion(embedding_into_extension_ring) return ExtensionRing + + def markov_trace_version(self): + r""" + Return the extension of the ring of definition needed to treat the + formal Markov traces. This appends an additional variable ``s`` to + measure the writhe of knots and makes ``u`` and ``v`` invertible. + + EXAMPLES:: + + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr + sage: GBR = chbr.CubicHeckeRingOfDefinition() + sage: GBR.markov_trace_version() + Multivariate Polynomial Ring in u, v, w, s + over Integer Ring localized at (s, w, v, u) + """ + if self._is_markov_trace_version(): + return self + names = self.base_ring().variable_names() + ('s',) + return self.__class__(names=names, order=self._order, markov_trace_version=True) + + def specialize_homfly(self): + r""" + Returns a map to the two variable Laurent polynomial Ring which is + the parent of the HOMFLY-PT polynomial. + + EXAMPLES:: + + sage: from sage.knots.knotinfo import KnotInfo + sage: CHA2 = algebras.CubicHecke(2) + sage: K5_1 = KnotInfo.K5_1.link() + sage: br = CHA2(K5_1.braid()) + sage: mt = br.formal_markov_trace() + sage: MT = mt.base_ring() + sage: f = MT.specialize_homfly(); f + Composite map: + From: Multivariate Polynomial Ring in u, v, w, s over Integer Ring + localized at (s, w, v, u) + To: Multivariate Laurent Polynomial Ring in L, M over Integer Ring + Defn: Ring morphism: + From: Multivariate Polynomial Ring in u, v, w, s + over Integer Ring localized at (s, w, v, u) + To: Multivariate Polynomial Ring in L, M + over Integer Ring localized at (M, M - 1, L) + Defn: u |--> -M + 1 + v |--> -M + 1 + w |--> 1 + s |--> L + then + Conversion map: + From: Multivariate Polynomial Ring in L, M + over Integer Ring localized at (M, M - 1, L) + To: Multivariate Laurent Polynomial Ring in L, M + over Integer Ring + sage: sup = mt.support() + sage: h1 = sum(f(mt.coefficient(b)) * b.regular_homfly_polynomial() for b in sup) + sage: L, M = f.codomain().gens() + sage: h2 = K5_1.homfly_polynomial() + sage: h1*L**(-5) == h2 # since the writhe of K5_1 is 5 + True + """ + if not self._is_markov_trace_version(): + raise ValueError('Functionality available for Markov trace version, only') + from sage.knots.link import Link + H = Link([]).homfly_polynomial().parent() + L, M = H.gens() + HL = H.localization(1-M) + u = HL(1-M) + phi = self.hom((u, u, HL.one(), HL(L))) + inc = H.convert_map_from(HL) + return inc*phi + + def specialize_kauffman(self): + r""" + Returns a map to the two variable Laurent polynomial Ring which is + the parent of the Kauffman polynomial. + + EXAMPLES:: + + sage: from sage.knots.knotinfo import KnotInfo + sage: CHA2 = algebras.CubicHecke(2) + sage: K5_1 = KnotInfo.K5_1.link() + sage: br = CHA2(K5_1.braid()) + sage: mt = br.formal_markov_trace() + sage: MT = mt.base_ring() + sage: f = MT.specialize_kauffman(); f + Composite map: + From: Multivariate Polynomial Ring in u, v, w, s over Integer Ring + localized at (s, w, v, u) + To: Multivariate Laurent Polynomial Ring in a, z over Integer Ring + Defn: Ring morphism: + From: Multivariate Polynomial Ring in u, v, w, s + over Integer Ring localized at (s, w, v, u) + To: Multivariate Polynomial Ring in a, z + over Integer Ring localized at (z, a, a + z, a*z + 1) + Defn: u |--> (a*z + 1)/a + v |--> (a + z)/a + w |--> 1/a + s |--> a + then + Conversion map: + From: Multivariate Polynomial Ring in a, z over Integer Ring + localized at (z, a, a + z, a*z + 1) + To: Multivariate Laurent Polynomial Ring in a, z + over Integer Ring + sage: sup = mt.support() + sage: k1 = sum(f(mt.coefficient(b)) * b.regular_kauffman_polynomial() for b in sup) + sage: a, z = f.codomain().gens() + sage: k2 = KnotInfo.K5_1.kauffman_polynomial() + sage: k1*a**(-5) == k2 # since the writhe of K5_1 is 5 + True + """ + if not self._is_markov_trace_version(): + raise ValueError('Functionality available for Markov trace version, only') + from sage.knots.knotinfo import KnotInfo + K = KnotInfo.L2a1_1.kauffman_polynomial().parent() + a, z = K.gens() + ku = z * a + 1 + kv = z + a + KL = K.localization((ku, kv)) + u = KL(ku/a) + v = KL(kv/a) + phi = self.hom((u, v, KL(~a), KL(a))) + inc = K.convert_map_from(KL) + return inc*phi + + def specialize_links_gould(self): + r""" + Returns a map to the two variable Laurent polynomial Ring which is + the parent of the Links-Gould polynomial. + + EXAMPLES:: + + sage: from sage.knots.knotinfo import KnotInfo + sage: CHA2 = algebras.CubicHecke(2) + sage: K5_1 = KnotInfo.K5_1.link() + sage: br = CHA2(K5_1.braid()) + sage: mt = br.formal_markov_trace() + sage: MT = mt.base_ring() + sage: f = MT.specialize_links_gould(); f + Composite map: + From: Multivariate Polynomial Ring in u, v, w, s over Integer Ring + localized at (s, w, v, u) + To: Multivariate Laurent Polynomial Ring in t0, t1 over Integer Ring + Defn: Ring morphism: + From: Multivariate Polynomial Ring in u, v, w, s + over Integer Ring localized at (s, w, v, u) + To: Multivariate Polynomial Ring in t0, t1 over Integer Ring + localized at (t1, t0, t0 + t1 - 1, t0*t1 - t0 - t1) + Defn: u |--> t0 + t1 - 1 + v |--> t0*t1 - t0 - t1 + w |--> -t0*t1 + s |--> 1 + then + Conversion map: + From: Multivariate Polynomial Ring in t0, t1 over Integer Ring + localized at (t1, t0, t0 + t1 - 1, t0*t1 - t0 - t1) + To: Multivariate Laurent Polynomial Ring in t0, t1 over Integer Ring + sage: sup = mt.support() + sage: sum(f(mt.coefficient(b)) * b.links_gould_polynomial() for b in sup) + -t0^4*t1 - t0^3*t1^2 - t0^2*t1^3 - t0*t1^4 + t0^4 + 2*t0^3*t1 + 2*t0^2*t1^2 + + 2*t0*t1^3 + t1^4 - t0^3 - 2*t0^2*t1 - 2*t0*t1^2 - t1^3 + t0^2 + 2*t0*t1 + + t1^2 - t0 - t1 + 1 + """ + if not self._is_markov_trace_version(): + raise ValueError('Functionality available for Markov trace version, only') + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + L = LaurentPolynomialRing(ZZ, 't0, t1') + t0, t1 = L.gens() + lu = t0 + t1 - 1 + lv = t0*t1 - t0 - t1 + lw = -t0*t1 + LL = L.localization((lu, lv)) + u = LL(lu) + v = LL(lv) + w = LL(lw) + phi = self.hom((u, v, w, LL.one())) + inc = L.convert_map_from(LL) + return inc*phi diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index bd2f995bfb0..77703386520 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -10,69 +10,74 @@ s_i^3 = u s_i^2 - v s_i + w Here $u, v, w$ are elements in an arbitrary integral domain and $i$ is a positive -integer less than $n$, the number of the braid group's strands. By the analogue to the -*Iwahori Hecke algebras* (see :class:`~sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra`), -in which the braid generators satisfy a quadratic relation these algebras have been called -*cubic Hecke algebras*. The relations inherited from the braid group are: +integer less than $n$, the number of the braid group's strands. By the analogue +to the *Iwahori Hecke algebras* (see :class:`~sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra`), +in which the braid generators satisfy a quadratic relation these algebras have been +called *cubic Hecke algebras*. The relations inherited from the braid group are: .. MATH:: s_i s_{i+1} s_i = s_{i+1} s_i s_{i+1} \mbox{ where } 1\leq i < n-1 \mbox{ and } s_i s_j = s_j s_i \mbox{ where } 1 \leq i < j - 1 < n - 1. -The algebra epimorphism from the braid group algebra over the same base ring is realized -inside the element constructor of the present class, for example in the case of the 3 -strand cubic Hecke algebra:: +The algebra epimorphism from the braid group algebra over the same base ring is +realized inside the element constructor of the present class, for example in the +case of the 3 strand cubic Hecke algebra:: sage: CHA3 = algebras.CubicHecke(3) sage: BG3 = CHA3.braid_group() sage: braid = BG3((1,2,-1,2,2,-1)); braid c0*c1*c0^-1*c1^2*c0^-1 sage: braid_image = CHA3(braid); braid_image - (-u*v+w)*c1^-1 + ((w^-1)*u^2+(-w^-1)*v)*c0*c1*c0 + ((-w^-1)*u^3+(w^-1)*u*v)*c0*c1 - + ((w^-1)*u^2*v+(-w^-1)*v^2)*c0*c1*c0^-1 + (-u^2)*c0^-1*c1 - + u*c1*c0^-1*c1 + u*v*c0*c1^-1*c0^-1 - -If the ring elements $u, v, w$ (which will be called the *cubic equation parameters* -in the sequel) are taken to be $u = v = 0, w = 1$ the cubic Hecke algebra specializes to the -group algebra of the *cubic braid group*, which is the factor group of the Artin braid -group under setting the generators order to be three. A sage-class to handle these groups -is attached and can be obtained by :meth:`CubicHeckeAlgebra.cubic_braid_group`. - -It is well known, that these algebras are free of finite rank as long as the number of braid -generators is less than six and infinite dimensional else wise. In the former (non trivial) -cases they are also known as *cyclotomic Hecke algebras* corresponding to the complex reflection -groups having Shepard-Todd number $4, 25$ and $32$. - -Since the *Broué, Malle, Rouquiere* conjecture has been proved in all these cases (for references -see [Mar2012]_) there exists a finite free basis of the cubic Hecke algebra which is in -bijection to the cubic braid group and compatible with the specialization to the cubic braid group -algebra as explained above. - -For the algebras corresponding to braid groups of less than five strands such a basis has been -calculated by Ivan Marin. This one is used here. In the case of 5 strands such a basis is not -available, right now. Instead the elements of the cubic braid group class themselves are used as -basis elements. This is also the case when the cubic braid group is infinite, even though it is -not known if these elements span all of the cubic Hecke algebra. - -Accordingly, be aware that the module embedding of the group algebra of the cubic braid groups -is known to be an isomorphism of free modules only in the cases of less than five strands. + u*c1*c0^-1*c1 + u*v*c0*c1^-1*c0^-1 + (-u^2)*c0^-1*c1 + + ((u^2*v-v^2)/w)*c0*c1*c0^-1 + ((u^2-v)/w)*c0*c1*c0 + + ((-u^3+u*v)/w)*c0*c1 + (-u*v+w)*c1^-1 + +If the ring elements $u, v, w$ (which will be called the *cubic equation +parameters* in the sequel) are taken to be $u = v = 0, w = 1$ the cubic Hecke +algebra specializes to the group algebra of the *cubic braid group*, which is +the factor group of the Artin braid group under setting the generators order to +be three. A sage-class to handle these groups is attached and can be obtained by +:meth:`CubicHeckeAlgebra.cubic_braid_group`. + +It is well known, that these algebras are free of finite rank as long as the +number of braid generators is less than six and infinite dimensional else wise. +In the former (non trivial) cases they are also known as *cyclotomic Hecke +algebras* corresponding to the complex reflection groups having Shepard-Todd +number $4, 25$ and $32$. + +Since the *Broué, Malle, Rouquiere* conjecture has been proved in all these cases +(for references see [Mar2012]_) there exists a finite free basis of the cubic Hecke +algebra which is in bijection to the cubic braid group and compatible with the +specialization to the cubic braid group algebra as explained above. + +For the algebras corresponding to braid groups of less than five strands such a +basis has been calculated by Ivan Marin. This one is used here. In the case of 5 +strands such a basis is not available, right now. Instead the elements of the cubic +braid group class themselves are used as basis elements. This is also the case when +the cubic braid group is infinite, even though it is not known if these elements +span all of the cubic Hecke algebra. + +Accordingly, be aware that the module embedding of the group algebra of the cubic +braid groups is known to be an isomorphism of free modules only in the cases of less +than five strands. EXAMPLES: -1. Consider the obstruction ``b`` of the *triple quadratic algebra* from section 2.6 of [Mar2018]_. -We verify that the third power of it is a scalar multiple of itself (explicitly ``2*w^2`` times the -*Schur element* of the three dimensional irreducible representation):: +1. Consider the obstruction ``b`` of the *triple quadratic algebra* from section +2.6 of [Mar2018]_. We verify that the third power of it is a scalar multiple of +itself (explicitly ``2*w^2`` times the *Schur element* of the three dimensional +irreducible representation):: sage: CHA3 = algebras.CubicHecke(3) sage: c1, c2 = CHA3.gens() sage: b = c1^2*c2 - c2*c1^2 - c1*c2^2 + c2^2*c1; b - w*c1^-1*c0 + (-w)*c1*c0^-1 + (-w)*c0*c1^-1 + w*c0^-1*c1 + w*c0^-1*c1 + (-w)*c0*c1^-1 + (-w)*c1*c0^-1 + w*c1^-1*c0 sage: b2 = b*b sage: b3 = b2*b sage: BR = CHA3.base_ring() sage: ER = CHA3.extension_ring() - sage: u, v, w = BR.gens_over_ground() + sage: u, v, w = BR.gens() sage: f = BR(b3.coefficients()[0]/w) sage: try: ....: sh = CHA3.schur_element(CHA3.irred_repr.W3_111) @@ -83,18 +88,19 @@ sage: b3 == f*b True -2. Defining the cubic Hecke algebra on 6 strands will need some seconds for initializing. But -than you can do calculations inside the infinite algebra as well:: +2. Defining the cubic Hecke algebra on 6 strands will need some seconds for +initializing. But than you can do calculations inside the infinite algebra as +well:: - sage: CHA6 = algebras.CubicHecke(6) # long time - sage: CHA6.inject_variables() # long time + sage: CHA6 = algebras.CubicHecke(6) # optional - database_cubic_hecke + sage: CHA6.inject_variables() # optional - database_cubic_hecke Defining c0, c1, c2, c3, c4 - sage: s = c0*c1*c2*c3*c4; s # long time + sage: s = c0*c1*c2*c3*c4; s # optional - database_cubic_hecke c0*c1*c2*c3*c4 - sage: s^2 # long time + sage: s^2 # optional - database_cubic_hecke (c0*c1*c2*c3*c4)^2 - sage: t = CHA6.an_element()*c4; t # long time - (-w)*c0*c1^-1*c4 + v*c0*c2^-1*c4 + u*c2*c1*c4 + ((w^-1)*u-v)*c4 + sage: t = CHA6.an_element()*c4; t # optional - database_cubic_hecke + (-w)*c0*c1^-1*c4 + v*c0*c2^-1*c4 + u*c2*c1*c4 + ((-v*w+u)/w)*c4 REFERENCES: @@ -107,7 +113,6 @@ - Sebastian Oehms May 2020: initial version """ - ############################################################################## # Copyright (C) 2020 Sebastian Oehms # @@ -118,7 +123,6 @@ # http://www.gnu.org/licenses/ ############################################################################## - from warnings import warn from sage.combinat.free_module import CombinatorialFreeModule @@ -129,10 +133,8 @@ from sage.algebras.splitting_algebra import solve_with_extension from sage.modules.free_module_element import vector from sage.matrix.matrix_space import MatrixSpace -from .base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeRingOfDefinition -from .matrix_representations.cubic_hecke_matrix_rep import CubicHeckeMatrixSpace, AbsIrreducibeRep, RepresentationType - - +from sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeRingOfDefinition +from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import CubicHeckeMatrixSpace, AbsIrreducibeRep, RepresentationType ############################################################################## @@ -144,25 +146,24 @@ class CubicHeckeElement(CombinatorialFreeModule.Element): r""" Element class of :class:`CubicHeckeAlgebra`. - It is inherited from :class:`CombinatorialFreeModule.Element` according to the parent class being - inherited from :class:`CombinatorialFreeModule`. The construction of the elements is - realized via :meth:`_element_constructor_` of the parent class. + It is inherited from :class:`CombinatorialFreeModule.Element` according to + the parent class being inherited from :class:`CombinatorialFreeModule`. The + construction of the elements is realized via + :meth:`CubicHeckeAlgebra._element_constructor_` of the parent class. For more information see the parent class. EXAMPLES:: + sage: CHA3s = algebras.CubicHecke('s1, s2'); CHA3s.an_element() + (-w)*s1*s2^-1 + v*s1 + u*s2 + ((-v*w+u)/w) sage: CHA3. = algebras.CubicHecke(3) sage: c1**3*~c2 - (-u*v+w)*c2^-1 + (u^2-v)*c1*c2^-1 + w*u*c1^-1*c2^-1 + u*w*c1^-1*c2^-1 + (u^2-v)*c1*c2^-1 + (-u*v+w)*c2^-1 """ - - # --------------------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # Overloading inherited methods - # --------------------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------------------- - + # -------------------------------------------------------------------------- def __invert__(self): r""" Return inverse of ``self`` (if possible). @@ -182,39 +183,35 @@ def __invert__(self): """ self_Tietze = self.Tietze() - if self_Tietze == None: - raise NotImplementedError( "inversion of non basis elements is not implemented, yet" ) + if self_Tietze is None: + raise NotImplementedError('inversion of non basis elements is not implemented, yet') inverse_Tietze = () len_self = len(self_Tietze) - inverse_Tietze = tuple([-1 *self_Tietze[len_self-i-1 ] for i in range(len_self)]) + inverse_Tietze = tuple([-1*self_Tietze[len_self - i - 1] for i in range(len_self)]) P = self.parent() return P(inverse_Tietze) - - - def Tietze(self): r""" - Return the Tietze presentation of ``self`` if ``self`` belongs to the basis of its parent - and ``None`` else. + Return the Tietze presentation of ``self`` if ``self`` belongs to the + basis of its parent and ``None`` else. OUTPUT: - A tuple representing the pre image braid of ``self`` if ``self`` is a monomial from the basis - ``None`` else-wise + A tuple representing the pre image braid of ``self`` if ``self`` is a + monomial from the basis ``None`` else-wise EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: ele = CHA3.an_element(); ele - ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + (-w)*c0*c1^-1 + v*c0 + u*c1 + ((-v*w+u)/w) sage: ele.Tietze() is None True - sage: bas_ele = CHA3(ele.leading_support()) - sage: bas_ele.Tietze() - (1, -2) + sage: [CHA3(sp).Tietze() for sp in ele.support()] + [(), (1,), (1, -2), (2,)] """ vecd = self.to_vector().dict() if len(vecd) != 1: @@ -224,42 +221,38 @@ def Tietze(self): P = self.parent() return P.get_order()[ind].Tietze() - - def max_len(self): r""" - Return the maximum of the length of Tietze expressions among the support of ``self``. + Return the maximum of the length of Tietze expressions among the support + of ``self``. EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: ele = CHA3.an_element(); ele - ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + (-w)*c0*c1^-1 + v*c0 + u*c1 + ((-v*w+u)/w) sage: ele.max_len() 2 """ - return max(len(bas_ele.Tietze()) for bas_ele in self.support()) - - - def braid_group_algebra_pre_image(self): r""" - Return a pre image of ``self`` in the group algebra of the braid_group (with respect to the - basis given by Iwan Marin). + Return a pre image of ``self`` in the group algebra of the braid_group + (with respect to the basis given by Ivan Marin). OUTPUT: - The pre image of ``self`` as instance of the element class of the group algebra of the BraidGroup + The pre image of ``self`` as instance of the element class of the group + algebra of the BraidGroup EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: ele = CHA3.an_element(); ele - ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + (-w)*c0*c1^-1 + v*c0 + u*c1 + ((-v*w+u)/w) sage: b_ele = ele.braid_group_algebra_pre_image(); b_ele - ((w^-1)*u-v) + v*c0 + u*c1 + (-w)*c0*c1^-1 + ((-v*w+u)/w) + v*c0 + u*c1 + (-w)*c0*c1^-1 sage: ele in CHA3 True sage: b_ele in CHA3 @@ -267,32 +260,32 @@ def braid_group_algebra_pre_image(self): sage: b_ele in CHA3.braid_group_algebra() True """ - - ch_algebra = self.parent() braid_group_algebra = ch_algebra.braid_group_algebra() - braid_group = ch_algebra.braid_group() - - return ch_algebra._apply_module_morphism(self, lambda bas_ele: braid_group_algebra(braid_group(bas_ele)), codomain=braid_group_algebra) - - + braid_group = ch_algebra.braid_group() + def phi(bas_ele): + return braid_group_algebra(braid_group(bas_ele)) + return ch_algebra._apply_module_morphism(self, phi, + codomain=braid_group_algebra) def cubic_braid_group_algebra_pre_image(self): r""" - Return a pre image of ``self`` in the group algebra of the cubic_braid_group. + Return a pre image of ``self`` in the group algebra of the cubic braid + group. OUTPUT: - The pre image of ``self`` as instance of the element class of the group algebra of the CubicBraidGroup + The pre image of ``self`` as instance of the element class of the group + algebra of the :class:`CubicBraidGroup`. EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: ele = CHA3.an_element(); ele - ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + (-w)*c0*c1^-1 + v*c0 + u*c1 + ((-v*w+u)/w) sage: cb_ele = ele.cubic_braid_group_algebra_pre_image(); cb_ele - ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c0*c1^-1 + (-w)*c0*c1^-1 + v*c0 + u*c1 + ((-v*w+u)/w) sage: ele in CHA3 True sage: cb_ele in CHA3 @@ -300,51 +293,52 @@ def cubic_braid_group_algebra_pre_image(self): sage: cb_ele in CHA3.cubic_braid_group_algebra() True """ - ch_algebra = self.parent() cbraid_group_algebra = ch_algebra.cubic_braid_group_algebra() - cbraid_group = ch_algebra.cubic_braid_group() - - return ch_algebra._apply_module_morphism(self, lambda bas_ele: cbraid_group_algebra(cbraid_group(bas_ele)), codomain=cbraid_group_algebra) - - - + cbraid_group = ch_algebra.cubic_braid_group() + def phi(bas_ele): + return cbraid_group_algebra(cbraid_group(bas_ele)) + return ch_algebra._apply_module_morphism(self, phi, + codomain=cbraid_group_algebra) @cached_method def matrix(self, subdivide=False, representation_type=None, original=False): r""" Return certain types of matrix representations of ``self``. - The absolutely irreducible representations of the cubic Hecke algebra are constructed using - the *GAP3*-Interface and the *CHEVIE* package if GAP3 and CHEVIE are installed on the system. - Furthermore, the representations given on Ivan Marin's homepage are used: - - http://www.lamfa.u-picardie.fr/marin/softs/H4 + The absolutely irreducible representations of the cubic Hecke algebra + are constructed using the *GAP3*-Interface and the *CHEVIE* package if + GAP3 and CHEVIE are installed on the system. Furthermore, the + representations given on `Ivan Marin's homepage `__ + are used: INPUT: - - ``subdivide`` -- boolean (default = False): this boolean is passed to the block_matrix - function + - ``subdivide`` -- boolean (default = False): this boolean is passed + to the block_matrix function - ``representation_type`` -- instance of enum :class:`RepresentationType`. - This can be obtained by the attribute :attr:`CubicHeckeAlgebra.repr_type` of ``self``. The following values are possible: - - - ``RegularLeft`` -- (regular left representation given on the above URL) - - ``RegularRight`` -- (regular right representation given on the above URL) - - ``SplitIrredChevie`` -- (split irreducible representations given via GAP3 CHEVIE) - - ``SplitIrredMarin`` -- (split irreducible representations given on the above URL) - - default: ``SplitIrredChevie`` taken if GAP3 and CHEVIE are installed on the system, otherwise the - default will be ``SplitIrredMarin`` - - ``original`` -- boolean (default = False): if set to true the base_ring of the matrix will be the - generic base_ring resp. generic extension ring (for the split versions) of the parent of ``self`` + This can be obtained by the attribute :attr:`CubicHeckeAlgebra.repr_type` + of ``self``. The following values are possible: + + - ``RegularLeft`` -- (regular left repr. from the above URL) + - ``RegularRight`` -- (regular right repr. from the above URL) + - ``SplitIrredChevie`` -- (split irred. repr. via CHEVIE) + - ``SplitIrredMarin`` -- (split irred. repr. from the above URL) + - default: ``SplitIrredChevie`` taken if GAP3 and CHEVIE are installed + on the system, otherwise the default will be ``SplitIrredMarin`` + - ``original`` -- boolean (default = False): if set to true the base + ring of the matrix will be the generic base_ring resp. generic extension + ring (for the split versions) of the parent of ``self`` OUTPUT: An instance of the class :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.CubicHeckeMatrixRep` - which is inherited from :class:`~sage.matrix.matrix_generic_dense.Matrix_generic_dense`. In the case of the irreducible representations - the matrix is given as a block matrix. Each single irreducible can be obtained as item indexed by the members of the enum - :class:`AbsIrreducibeRep` available via :attr:`CubicHeckeAlgebra.irred_repr`. For details type: ``CubicHeckeAlgebra.irred_repr?``. - + which is inherited from :class:`~sage.matrix.matrix_generic_dense.Matrix_generic_dense`. + In the case of the irreducible representations the matrix is given as a + block matrix. Each single irreducible can be obtained as item indexed by + the members of the enum :class:`AbsIrreducibeRep` available via + :attr:`CubicHeckeAlgebra.irred_repr`. For details type: ``CubicHeckeAlgebra.irred_repr?``. EXAMPLES:: @@ -379,13 +373,33 @@ def matrix(self, subdivide=False, representation_type=None, original=False): sage: c0mo_ch[CHA3.irred_repr.W3_011] # optional gap3 [ b 0] [-b c] + + specialized matrices:: + + sage: t = (3,7,11) + sage: CHA4 = algebras.CubicHecke(4, cubic_equation_roots=t) # optional database_cubic_hecke + sage: e = CHA4.an_element(); e # optional database_cubic_hecke + -231*c0*c1^-1 + 131*c0*c2^-1 + 21*c2*c1 - 1440/11 + sage: em = e.matrix() # optional database_cubic_hecke + sage: em.base_ring() # optional database_cubic_hecke + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Integer Ring localized at (3, 7, 11) + sage: em.dimensions() # optional database_cubic_hecke + (108, 108) + sage: em_irr24 = em[23] # optional database_cubic_hecke + sage: em_irr24.dimensions() # optional database_cubic_hecke + (9, 9) + sage: em_irr24[3,2] # optional database_cubic_hecke + -131*E3 - 393/7 + sage: emg = e.matrix(representation_type=chevie) # optional gap3 + sage: emg_irr24 = emg[23] # optional gap3 + sage: emg_irr24[3,2] # optional gap3 + -131*E3 - 393/7 """ parent = self.parent() MS = CubicHeckeMatrixSpace(parent, representation_type=representation_type, subdivide=subdivide, original=original) return MS(self) - - def revert_garside(self): r""" Return the image of ``self`` under the Garside involution. @@ -404,7 +418,6 @@ def revert_garside(self): """ return self.parent().garside_involution(self) - def revert_mirror(self): r""" Return the image of ``self`` under the mirror isomorphism. @@ -415,105 +428,251 @@ def revert_mirror(self): sage: CHA3. = algebras.CubicHecke(3) sage: e = CHA3.an_element() sage: e.revert_mirror() - ((-w^-1)*u+v) + ((w^-1)*v)*c1^-1 + ((w^-1)*u)*c0^-1 + (-w^-1)*c0^-1*c1 + -1/w*c0^-1*c1 + u/w*c0^-1 + v/w*c1^-1 + ((v*w-u)/w) sage: _.revert_mirror() == e True """ return self.parent().mirror_isomorphism(self) - - def revert_orientation(self): r""" - Return the image of ``self`` under the anti involution reverting the orientation of braids. - See also :meth:`CubicHeckeAlgebra.orientation_antiinvolution` of the parent class. + Return the image of ``self`` under the anti involution reverting the + orientation of braids. See also :meth:`CubicHeckeAlgebra.orientation_antiinvolution` + of the parent class. EXAMPLES:: sage: CHA3. = algebras.CubicHecke(3) sage: e = CHA3.an_element() sage: e.revert_orientation() - ((w^-1)*u-v) + u*c2 + v*c1 + (-w)*c2^-1*c1 + (-w)*c2^-1*c1 + v*c1 + u*c2 + ((-v*w+u)/w) sage: _.revert_orientation() == e True """ return self.parent().orientation_antiinvolution(self) + def formal_markov_trace(self, extended=False, field_embedding=False): + r""" + Return a formal expression which can be specialized to Markov traces + which factor through the cubic Hecke algebra. This covers Markov traces + corresponding to the + + - HOMFLY-PT polynomial + - Kauffman polynomial + - Links-Gould polynomial + + These expressions are elements of a sub-module of the module of linear + forms on ``self`` the base ring of which is an extension of the + generic base ring of ``self`` by an additional variable ``s`` representing + the writhe factor. All variables of this base ring extension are + invertible. + A Markov trace is a family of class functions `tr_n` on the family of + braid groups `B_n` into some commutative ring `R` depending on a + unit `s \in R` such that for all `b in B_n` the following two + conditions are satisfied (see [Kau1991]_, section 7): + ..MATH:: + \begin{array}{lll} + tr_{n+1}(b g_n) & = & s tr_n(b)\\ + tr_{n+1}(b g^{-1}_n) & = & s^{-1} tr_n(b) + \end{array} + The unit `s` is often called the writhe factor and corresponds to the + additional variable mentioned above. + ..NOTE:: + Currently it is not known if all linear forms of this sub-module + belong to a Markov trace, i.e. can be extended to the full tower + of cubic Hecke algebras. Anyway, at least the four basis elements + (``U1, U2, U3`` and ``K4``) can be reconstructed form the HOMFLY-PT + and Kauffman polynomial. + INPUT: + + - ``extended`` -- boolean (optional default ``False``) if set to ``True`` + the base ring of the Markov trace module is constructed as an extension + of generic extension ring of ``self``. Per default it is constructed + upon the generic base ring. + + - ``field_embedding`` -- boolean (optional default ``False``) if set to + ``True` the base ring of the module is the smallest field containing + the generic extension ring of ``self``. The keyword is meaningless + if ``extended=False``. + + + OUTPUT: + + An instance of :class:`~sage.combinat.free_module.CombinatorialFreeModule_with_category.element_class`. + + EXAMPLES:: + + sage: from sage.knots.knotinfo import KnotInfo + sage: CHA2 = algebras.CubicHecke(2) + sage: K3_1 = KnotInfo.K3_1 + sage: b3_1 = CHA2(K3_1.braid()) + sage: mt3_1 = b3_1.formal_markov_trace(); mt3_1 + ((u^2*s^2-v*s^2+u*w)/s)*B[U1] + (-u*v+w)*B[U2] + sage: mt3_1.parent() + Free module generated by {U1, U2} + over Multivariate Polynomial Ring in u, v, w, s + over Integer Ring localized at (s, w, v, u) + + sage: b3_1.formal_markov_trace(extended=True) + (a^2*b*c*s^-1+a*b^2*c*s^-1+a*b*c^2*s^-1+a^2*s+a*b*s+b^2*s+a*c*s+b*c*s+c^2*s)*B[U1] + + (-a^2*b-a*b^2-a^2*c+(-2)*a*b*c-b^2*c-a*c^2-b*c^2)*B[U2] + sage: _.parent().base_ring() + Multivariate Laurent Polynomial Ring in a, b, c, s + over Splitting Algebra of x^2 + x + 1 with roots [e3, -e3 - 1] + over Integer Ring + + sage: b3_1.formal_markov_trace(extended=True, field_embedding=True) + ((a^2*b*c+a*b^2*c+a*b*c^2+a^2*s^2+a*b*s^2+b^2*s^2+a*c*s^2+b*c*s^2+c^2*s^2)/s)*B[U1] + + (-a^2*b-a*b^2-a^2*c-2*a*b*c-b^2*c-a*c^2-b*c^2)*B[U2] + sage: _.parent().base_ring() + Fraction Field of Multivariate Polynomial Ring in a, b, c, s + over Cyclotomic Field of order 3 and degree 2 + + Obtaining the well known link invariants from it:: + + sage: MT = mt3_1.base_ring() + sage: sup = mt3_1.support() + sage: u, v, w, s = mt3_1.base_ring().gens() + sage: LK3_1 = mt3_1*s**-3 # since the writhe of K3_1 is 3 + sage: f = MT.specialize_homfly() + sage: sum(f(LK3_1.coefficient(b)) * b.regular_homfly_polynomial() for b in sup) + L^-2*M^2 - 2*L^-2 - L^-4 + sage: _ == K3_1.link().homfly_polynomial() + True + + sage: f = MT.specialize_kauffman() + sage: sum(f(LK3_1.coefficient(b)) * b.regular_kauffman_polynomial() for b in sup) + a^-2*z^2 - 2*a^-2 + a^-3*z + a^-4*z^2 - a^-4 + a^-5*z + sage: _ == K3_1.kauffman_polynomial() + True + + sage: f = MT.specialize_links_gould() + sage: sum(f(LK3_1.coefficient(b)) * b.links_gould_polynomial() for b in sup) + -t0^2*t1 - t0*t1^2 + t0^2 + 2*t0*t1 + t1^2 - t0 - t1 + 1 + """ + cha = self.parent() + vs = self.to_vector() + mtcf = cha._markov_trace_coeffs() + M = cha._markov_trace_module(extended=extended, field_embedding=field_embedding) + if M != mtcf[0].parent(): + if field_embedding: + # intermediate step needed since internal coercion to the field + # maps (u, v, w ) -> (a, b, c) + MI = cha._markov_trace_module(extended=extended, field_embedding=False) + RI = MI.base_ring() + mtcf = [MI.from_vector(cf.to_vector()) for cf in mtcf] + vs = vs.change_ring(RI) + + mtcf = [M.from_vector(cf.to_vector()) for cf in mtcf] + return sum(vs[i]*mtcf[i] for i in range(len(vs))) class CubicHeckeAlgebra(CombinatorialFreeModule): r""" - Return the Cubic-Hecke algebra with respect to the Artin braid group on $n$ strands. + Return the Cubic-Hecke algebra with respect to the Artin braid group on + $n$ strands. - This is a quotient of the group algebra of the Artin braid group, such that the images $s_i$ ($1 \leq i < n$) of the - braid generators satisfy a cubic equation (see module header :mod:`~sage.algebras.hecke_algebras.cubic_hecke_algebra` - for more information, in a session type ``sage.algebras.hecke_algebras.cubic_hecke_algebra?``): + This is a quotient of the group algebra of the Artin braid group, such that + the images $s_i$ ($1 \leq i < n$) of the braid generators satisfy a cubic + equation (see module header :mod:`~sage.algebras.hecke_algebras.cubic_hecke_algebra` + for more information, in a session type + ``sage.algebras.hecke_algebras.cubic_hecke_algebra?``): .. MATH:: s_i^3 = u s_i^2 - v s_i + w - The base ring of this algebra can be specified by giving optional keywords described below. If no keywords are given the - base ring will be an instance of the special class :class:`CubicHeckeRingOfDefinition` which is constructed as the polynomial - ring in $u, v$ over the Laurent polynomial ring in $w$ over the integers. This ring will be called the *ring of - definition* or sometimes for short *generic base ring*. But note, that in this context the word *generic* should - not remind in a generic point of the corresponding scheme. - - In addition to the base ring another ring containing the roots ($a, b$ and $c$) of the cubic equation will be needed - to handle the split irreducible representations. This ring will be called *extension ring*. Generically, the extension - ring will be an instance of the special class + The base ring of this algebra can be specified by giving optional keywords + described below. If no keywords are given the base ring will be an instance + of the special class :class:`CubicHeckeRingOfDefinition` which is constructed + as the polynomial ring in $u, v$ over the Laurent polynomial ring in $w$ over + the integers. This ring will be called the *ring of definition* or sometimes + for short *generic base ring*. But note, that in this context the word + *generic* should not remind in a generic point of the corresponding scheme. + + In addition to the base ring another ring containing the roots ($a, b$ and $c$) + of the cubic equation will be needed to handle the split irreducible + representations. This ring will be called *extension ring*. Generically, the + extension ring will be an instance of the special class :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeExtensionRing` - which is constructed as the Laurent polynomial ring in $a, b$ and $c$ over the integers adjoined with a primitive third - root of unity. A special form of this *generic extension ring* is constructed as an instance of - :class:`~sage.algebras.splitting_algebra.SplittingAlgebra` for the roots of the cubic equation and a primitive third - root of unity over the ring of definition. This ring will be called the *default extension ring*. - - This class uses a static and a dynamic data library. The first one is defined as instance of - :class:`~sage.databases.cubic_hecke_db.CubicHeckeDataBase` and contains the complete basis for the algebras with - less than 5 strands and various types of representation matrices of the generators. These data have been calculated by - Ivan Marin and have been imported from: - - http://www.lamfa.u-picardie.fr/marin/softs/ - - Furthermore, representation matrices can be obtained from the *CHEVIE* package of *GAP3* via the GAP3 interface - if GAP3 is installed inside sage. For more information on how to obtain representation matrices to elements of this + which is constructed as the Laurent polynomial ring in $a, b$ and $c$ over + the integers adjoined with a primitive third root of unity. A special form + of this *generic extension ring* is constructed as an instance of + :class:`~sage.algebras.splitting_algebra.SplittingAlgebra` for the roots of + the cubic equation and a primitive third root of unity over the ring of + definition. This ring will be called the *default extension ring*. + + This class uses a static and a dynamic data library. The first one is defined + as instance of :class:`~sage.databases.cubic_hecke_db.CubicHeckeDataBase` + and contains the complete basis for the algebras with less than 5 strands + and various types of representation matrices of the generators. These data + have been calculated by `Ivan Marin `__ + and have been imported from his corresponding + `web page `__. + + But note that just the data for the cubic Hecke algebras on less than four + strands is available in Sage per default. To deal with four strands and + more you need to install the optional package + `database_cubic_hecke `__ + by typing + + - ``sage -i database_cubic_hecke`` (first time installation) or + - ``sage -f database_cubic_hecke`` (reinstallation) respective + - ``sage -i -c database_cubic_hecke`` (for running all test in concern) + - ``sage -f -c database_cubic_hecke`` + + This will add a `Python wrapper `__ + around Ivan Marin's data to the Sage library. For more installation hints + see the documentation of this wrapper. + + Furthermore, representation matrices can be obtained from the *CHEVIE* package + of *GAP3* via the GAP3 interface if GAP3 is installed inside sage. For more + information on how to obtain representation matrices to elements of this class see the documentation of the matrix-method of the element class: ``algebras.CubicHecke.Element?`` or ``algebras.CubicHecke.Element.matrix?`` - The second library is created as instance of :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache` and - used while working with the class to achieve a better performance. This file cache contains images of braids and - representation matrices of basis elements from former calculations. A refresh of the file cache can be done - using the :meth:`reset_filecache`. + The second library is created as instance of + :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache` and used while + working with the class to achieve a better performance. This file cache + contains images of braids and representation matrices of basis elements + from former calculations. A refresh of the file cache can be done using + the :meth:`reset_filecache`. INPUT: - - ``names`` -- string containing the names of the generators as images of the braid group generators - - ``cubic_equation_parameters`` -- tuple ``(u, v, w)`` of three elements in an integral domain used as coefficients - in the cubic equation. If this argument is given the base ring will be set to the common parent of ``u, v, w``. In - addition a conversion map from the generic base ring is supplied. This keyword can also be used to change the - variable names of the generic base ring (see example 3 below). - - ``cubic_equation_roots`` -- tuple ``(a, b, c)`` of three elements in an integral domain which stand for the roots - of the cubic equation. If this argument is given the extension ring will be set to the common parent of ``a, b, c``. - In addition a conversion map from the generic extension ring and the generic base ring is supplied. This keyword - can also be used to change the variable names of the generic extension ring (see example 3 below). - + - ``names`` -- string containing the names of the generators as images of + the braid group generators + - ``cubic_equation_parameters`` -- tuple ``(u, v, w)`` of three elements + in an integral domain used as coefficients in the cubic equation. If this + argument is given the base ring will be set to the common parent of + ``u, v, w``. In addition a conversion map from the generic base ring is + supplied. This keyword can also be used to change the variable names of + the generic base ring (see example 3 below). + - ``cubic_equation_roots`` -- tuple ``(a, b, c)`` of three elements in an + integral domain which stand for the roots of the cubic equation. If this + argument is given the extension ring will be set to the common parent of + ``a, b, c``. In addition a conversion map from the generic extension ring + and the generic base ring is supplied. This keyword can also be used to + change the variable names of the generic extension ring (see example 3 + below). EXAMPLES: 1. cubic Hecke algebra over the ring of definition:: sage: CHA3 = algebras.CubicHecke('s1, s2'); CHA3 - Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring - with cubic equation: h^3 - u*h^2 + v*h - w = 0 + Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring + in u, v, w + over Integer Ring localized at (w,) + with cubic equation: h^3 - u*h^2 + v*h - w = 0 sage: CHA3.gens() (s1, s2) sage: GER = CHA3.extension_ring(generic=True); GER @@ -524,44 +683,49 @@ class see the documentation of the matrix-method of the element class: Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] over Splitting Algebra of h^3 - u*h^2 + v*h - w with roots [a, b, -b - a + u] - over Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring + over Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) 2. element construction:: sage: ele = CHA3.an_element(); ele - ((w^-1)*u-v) + u*s2 + v*s1 + (-w)*s1*s2^-1 + (-w)*s1*s2^-1 + v*s1 + u*s2 + ((-v*w+u)/w) sage: ele2 = ele**2; ele2 - (-u^2*v-v^3+(w^-2)*u^2+(-2*w^-1)*u*v+v^2) + (u^3+(2*w^-1)*u^2+(-2)*u*v)*s2 - + (w*u^2+w*v^2)*s2^-1 + (u*v^2+(2*w^-1)*u*v+(-2)*v^2+(-w)*u)*s1 - + u*v*s2*s1 + w*v^2*s1^-1 + w*u*v*s2*s1^-1 + u*v*s1*s2 - + ((-w)*u^2)*s1*s2*s1^-1 + ((-w)*u)*s1^-1*s2*s1 - + ((-w)*u*v+(-2)*u+2*w*v)*s1*s2^-1 + w*u*s1*s2*s1^-1*s2 + ((-w)*v)*s2*s1^-1*s2 - + ((-w^2)*v)*s1^-1*s2^-1 + ((-w^2)*u)*s1^-1*s2*s1^-1 + w^2*(s1^-1*s2)^2 + w^2*(s1^-1*s2)^2 + (-u*w^2)*s1^-1*s2*s1^-1 + (-v*w)*s2*s1^-1*s2 + + (-v*w^2)*s1^-1*s2^-1 + u*w*s1*s2*s1^-1*s2 + (-u*w)*s1^-1*s2*s1 + + (-u*v*w+2*v*w-2*u)*s1*s2^-1 + u*v*w*s2*s1^-1 + u*v*s2*s1 + v^2*w*s1^-1 + + (-u^2*w)*s1*s2*s1^-1 + ((u*v^2*w-2*v^2*w-u*w^2+2*u*v)/w)*s1 + + u*v*s1*s2 + (u^2*w+v^2*w)*s2^-1 + ((u^3*w-2*u*v*w+2*u^2)/w)*s2 + + ((-u^2*v*w^2-v^3*w^2+v^2*w^2-2*u*v*w+u^2)/w^2) sage: B3 = CHA3.braid_group() sage: braid = B3((2,-1, 2, 1)); braid s2*s1^-1*s2*s1 sage: ele3 = CHA3(braid); ele3 - v*s2^-1*s1 + (-u)*s1*s2*s1^-1 + u*s1^-1*s2*s1 + (-v)*s1*s2^-1 + s1*s2*s1^-1*s2 - sage: ele4 = CHA3((2,-1, 2, 1)) - sage: ele3 == ele4 + s1*s2*s1^-1*s2 + u*s1^-1*s2*s1 + (-v)*s1*s2^-1 + v*s2^-1*s1 + (-u)*s1*s2*s1^-1 + sage: ele3t = CHA3((2,-1, 2, 1)) + sage: ele3 == ele3t True + sage: CHA4 = algebras.CubicHecke(4) # optional database_cubic_hecke + sage: ele4 = CHA4(ele3); ele4 # optional database_cubic_hecke + c0*c1*c0^-1*c1 + u*c0^-1*c1*c0 + (-v)*c0*c1^-1 + v*c1^-1*c0 + (-u)*c0*c1*c0^-1 - - 3. cubic Hecke algebra over the ring of definition using different variable names:: + 3. cubic Hecke algebra over the ring of definition using different variable + names:: sage: algebras.CubicHecke(3, cubic_equation_parameters='u, v, w', cubic_equation_roots='p, q, r') - Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring + Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring + in u, v, w + over Integer Ring localized at (w,) with cubic equation: h^3 - u*h^2 + v*h - w = 0 sage: _.extension_ring() Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] over Splitting Algebra of h^3 - u*h^2 + v*h - w with roots [p, q, -q - p + u] - over Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring + over Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) - 4. cubic Hecke algebra over a special base ring with respect to a special cubic equation:: + 4. cubic Hecke algebra over a special base ring with respect to a special + cubic equation:: sage: algebras.CubicHecke('s1, s2', cubic_equation_parameters=(QQ(1),3,1)) Cubic Hecke algebra on 3 strands over Rational Field @@ -588,29 +752,33 @@ class see the documentation of the matrix-method of the element class: [2*S^3 + 2*S^2 + 2*S + 1, 2*S^3 + 3*S^2 + 3*S + 2, S^3 + 3] - 5. cubic Hecke algebra over a special extension ring with respect to special roots of the cubic equation:: + 5. cubic Hecke algebra over a special extension ring with respect to special + roots of the cubic equation:: sage: UCF = UniversalCyclotomicField() sage: e3=UCF.gen(3); e5=UCF.gen(5) - sage: algebras.CubicHecke('s1, s2', cubic_equation_roots=(1, e5, e3)) + sage: algebras.CubicHecke('s1, s2', cubic_equation_roots=(1, e5, e3)) Cubic Hecke algebra on 3 strands over Universal Cyclotomic Field with cubic equation: - h^3 + (-E(15) - E(15)^4 - E(15)^7 + E(15)^8)*h^2 + (-E(15)^2 - E(15)^8 - - E(15)^11 - E(15)^13 - E(15)^14)*h - E(15)^8 = 0 + h^3 + (-E(15) - E(15)^4 - E(15)^7 + E(15)^8)*h^2 + (-E(15)^2 - E(15)^8 + - E(15)^11 - E(15)^13 - E(15)^14)*h - E(15)^8 = 0 TESTS: sage: CHA3 = algebras.CubicHecke(3) sage: TestSuite(CHA3).run() - """ - Element = CubicHeckeElement - repr_type = RepresentationType + Note, that the ``TestSuite`` run on the cubic Hecke algebra on four strands + would take up to half an hour if the file cache is empty. A repetition takes + less than half a minute. + """ + Element = CubicHeckeElement + repr_type = RepresentationType irred_repr = AbsIrreducibeRep - ########################################################################################### + ############################################################################ # private methods - ########################################################################################### + ############################################################################ @staticmethod def __classcall_private__(cls, n=None, names='c', cubic_equation_parameters=None, cubic_equation_roots=None): r""" @@ -618,25 +786,29 @@ def __classcall_private__(cls, n=None, names='c', cubic_equation_parameters=None INPUT: - - ``n`` -- integer or None (default). The number of strands. If not specified the "names" are - counted and the algebra is assumed to have one more strand than generators + - ``n`` -- integer or None (default). The number of strands. If not + specified the "names" are counted and the algebra is assumed to have + one more strand than generators - - ``names`` -- string or list/tuple/iterable of strings (default:'c'). The generator names or - name prefix. The entry can be either a string with the names of the generators, or the number - of generators and the prefix + - ``names`` -- string or list/tuple/iterable of strings (default:'c'). + The generator names or name prefix. The entry can be either a string + with the names of the generators, or the number of generators and the + prefix EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2, 'd', cubic_equation_roots=(3,5,7)); CHA2 - Cubic Hecke algebra on 2 strands over Integer Ring localized at (3, 5, 7) - with cubic equation: - h^3 - 15*h^2 + 71*h - 105 = 0 + Cubic Hecke algebra on 2 strands + over Integer Ring localized at (3, 5, 7) + with cubic equation: + h^3 - 15*h^2 + 71*h - 105 = 0 sage: CHA2.inject_variables() Defining d sage: CHA3 = algebras.CubicHecke(3, cubic_equation_parameters=(3,5,7)); CHA3 - Cubic Hecke algebra on 3 strands over Integer Ring localized at (7,) - with cubic equation: - h^3 - 3*h^2 + 5*h - 7 = 0 + Cubic Hecke algebra on 3 strands + over Integer Ring localized at (7,) + with cubic equation: + h^3 - 3*h^2 + 5*h - 7 = 0 sage: CHA3.cubic_equation_roots() [a, b, -b - a + 3] """ @@ -646,21 +818,21 @@ def __classcall_private__(cls, n=None, names='c', cubic_equation_parameters=None n = ZZ(n)-1 except TypeError: names = n - n = None + # derive n from counting names if n is None: - import six - if isinstance(names, six.string_types): + if type(names) is str: n = len(names.split(',')) else: names = list(names) n = len(names) + from sage.structure.category_object import normalize_names names = tuple(normalize_names(n, names)) - return super(CubicHeckeAlgebra, cls).__classcall__(cls, names, cubic_equation_parameters=cubic_equation_parameters, - cubic_equation_roots=cubic_equation_roots) - + return super(CubicHeckeAlgebra, cls).__classcall__(cls, names, + cubic_equation_parameters=cubic_equation_parameters, + cubic_equation_roots=cubic_equation_roots) def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=None): r""" @@ -673,207 +845,177 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N sage: CHA2 = algebras.CubicHecke(2, cubic_equation_parameters=(3,5,7)) sage: TestSuite(CHA2).run() """ - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # saving input - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- self._names = names - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # Define underlying group - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - self._cubic_braid_group = CubicBraidGroup(names) - self._braid_group = self._cubic_braid_group.braid_group() - n = len(self._cubic_braid_group.gens()) - self._nstrands = n+1 - self._dim_irr_rep = sum([irr.dimension() for irr in AbsIrreducibeRep if irr.number_gens() == n]) - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + self._cubic_braid_group = CubicBraidGroup(names) + self._braid_group = self._cubic_braid_group.braid_group() + n = len(self._cubic_braid_group.gens()) + self._nstrands = n + 1 + self._dim_irr_rep = sum([irr.dimension() for irr in AbsIrreducibeRep if irr.number_gens() == n]) + + # ---------------------------------------------------------------------- # preparing use of data base anf file cache - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- from sage.databases.cubic_hecke_db import CubicHeckeDataBase, CubicHeckeFileCache - self._database = CubicHeckeDataBase() - self._filecache = CubicHeckeFileCache(self._nstrands) - + self._database = CubicHeckeDataBase() + self._filecache = CubicHeckeFileCache(self._nstrands) - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - # interpretation of keywords - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - - # --------------------------------------------------------------------------------- - # type verifications - # --------------------------------------------------------------------------------- - - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # interpretation of keywords and type verifications + # ---------------------------------------------------------------------- # cubic_equation_parameters - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- ring_of_definition_names = ('u', 'v', 'w') - if cubic_equation_parameters != None: - if isinstance(cubic_equation_parameters, str) == True: - # ----------------------------------------------------------------------------------- + if cubic_equation_parameters is not None: + if isinstance(cubic_equation_parameters, str): + # -------------------------------------------------------------- # Input specifies names for the generic base ring - # ----------------------------------------------------------------------------------- + # -------------------------------------------------------------- ring_of_definition_names = tuple(cubic_equation_parameters.split(',')) - if len(ring_of_definition_names) != 3 : + if len(ring_of_definition_names) != 3: raise ValueError('cubic_equation_parameters must consist of exactly 3 elements') cubic_equation_parameters = None else: - # ----------------------------------------------------------------------------------- + # -------------------------------------------------------------- # Input specifies a specialized base ring - # ----------------------------------------------------------------------------------- - if isinstance(cubic_equation_parameters, list) == True: + # -------------------------------------------------------------- + if isinstance(cubic_equation_parameters, list): cubic_equation_parameters = tuple(cubic_equation_parameters) - if isinstance( cubic_equation_parameters, tuple ) == False: + if not isinstance(cubic_equation_parameters, tuple): raise TypeError('cubic_equation_parameters must be a tuple or list') - if len( cubic_equation_parameters ) != 3 : + if len(cubic_equation_parameters) != 3: raise ValueError('cubic_equation_parameters must consist of exactly 3 elements') - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # cubic_equation_roots - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- generic_extension_ring_names = ('a', 'b', 'c') - if cubic_equation_roots != None: - if isinstance(cubic_equation_roots, str) == True: - # ----------------------------------------------------------------------------------- + if cubic_equation_roots is not None: + if isinstance(cubic_equation_roots, str): + # -------------------------------------------------------------- # Input specifies names for the generic extension ring - # ----------------------------------------------------------------------------------- + # -------------------------------------------------------------- generic_extension_ring_names = tuple(cubic_equation_roots.split(',')) - if len(generic_extension_ring_names) != 3 : + if len(generic_extension_ring_names) != 3: raise ValueError('cubic_equation_roots must consist of exactly 3 elements') cubic_equation_roots = None else: - # ----------------------------------------------------------------------------------- + # -------------------------------------------------------------- # Input specifies a specialized base ring - # ----------------------------------------------------------------------------------- - if isinstance( cubic_equation_roots, list ) == True: + # -------------------------------------------------------------- + if isinstance(cubic_equation_roots, list): cubic_equation_roots = tuple(cubic_equation_roots) - if isinstance( cubic_equation_roots, tuple ) == False: + if not isinstance(cubic_equation_roots, tuple): raise TypeError('cubic_equation_roots must be a tuple or list') - if len( cubic_equation_roots ) != 3 : + if len(cubic_equation_roots) != 3: raise ValueError('cubic_equation_roots must consist of exactly 3 elements') if len(set(ring_of_definition_names + generic_extension_ring_names)) < 6: - raise ValueError('there is an overlap of names between cubic equation parameters (%s) and cubic equation roots (%s)' %(ring_of_definition_names, generic_extension_ring_names) ) - + raise ValueError('there is an overlap of names between cubic equation ' + 'parameters (%s) and cubic equation roots (%s)' + % (ring_of_definition_names, generic_extension_ring_names)) - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # setting the generic rings - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- ring_of_definition = CubicHeckeRingOfDefinition(names=ring_of_definition_names) - u, v, w = ring_of_definition.gens_over_ground() + u, v, w = ring_of_definition.gens() generic_extension_ring = ring_of_definition.extension_ring(names=generic_extension_ring_names) a, b, c = generic_extension_ring.gens() - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # registering generic items as variables - # --------------------------------------------------------------------------------- - self._ring_of_definition = ring_of_definition - self._generic_extension_ring = generic_extension_ring - self._generic_cubic_equation_parameters = [u, v, w] - self._generic_cubic_equation_roots = [a, b, c] - - - - # --------------------------------------------------------------------------------- - # interpreting user given cubic equation parameters to define the corresponding - # specialized base ring - # --------------------------------------------------------------------------------- - - if cubic_equation_parameters == None and cubic_equation_roots != None: - pa, pb, pc = cubic_equation_roots - cubic_equation_parameters = [ pa+pb+pc, pa*pb+pb*pc+pa*pc, pa*pb*pc ] - verbose('cubic_equation_parameters %s set according to cubic_equation_roots %s' %(cubic_equation_parameters, cubic_equation_roots)) - - if cubic_equation_parameters != None: + # ---------------------------------------------------------------------- + self._ring_of_definition = ring_of_definition + self._generic_extension_ring = generic_extension_ring + self._generic_cubic_equation_parameters = [u, v, w] + self._generic_cubic_equation_roots = [a, b, c] + + # ---------------------------------------------------------------------- + # interpreting user given cubic equation parameters to define the + # corresponding specialized base ring + # ---------------------------------------------------------------------- + if cubic_equation_parameters is None and cubic_equation_roots is not None: + pa, pb, pc = cubic_equation_roots + cubic_equation_parameters = [pa+pb+pc, pa*pb+pb*pc+pa*pc, pa*pb*pc] + verbose('cubic_equation_parameters %s set according to ' + 'cubic_equation_roots %s' % (cubic_equation_parameters, + cubic_equation_roots), level=2) + + if cubic_equation_parameters is not None: base_ring = ring_of_definition.create_specialization(cubic_equation_parameters) - cubic_equation_parameters = [ base_ring(para) for para in cubic_equation_parameters ] - verbose('base_ring %s set according to cubic_equation_parameters %s' %(base_ring, cubic_equation_parameters)) + cubic_equation_parameters = [base_ring(para) for para in cubic_equation_parameters] + verbose('base_ring %s set according to cubic_equation_parameters %s' + % (base_ring, cubic_equation_parameters), level=2) else: - base_ring = self._ring_of_definition + base_ring = self._ring_of_definition cubic_equation_parameters = self._generic_cubic_equation_parameters + verbose('base_ring %s and cubic_equation_parameters %s defined' + % (base_ring, cubic_equation_parameters), level=2) - verbose('base_ring %s and cubic_equation_parameters %s defined' %(base_ring, cubic_equation_parameters)) - - - # ------------------------------------------------------------------------------------------ + # ---------------------------------------------------------------------- # defining the cubic equation - # ------------------------------------------------------------------------------------------ + # ---------------------------------------------------------------------- pu, pv, pw = cubic_equation_parameters pol_bas_ring = base_ring['h'] - cubic_equation = pol_bas_ring([-pw, pv, -pu, 1 ]) - + cubic_equation = pol_bas_ring([-pw, pv, -pu, 1]) - verbose('cubic_equation %s defined' %(cubic_equation)) + verbose('cubic_equation %s defined' % cubic_equation, level=2) - - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # defining cubic_equation_roots if not given using the cubic_equation - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- if base_ring != ring_of_definition: - if cubic_equation_roots == None: - # ------------------------------------------------------------------------------ + if cubic_equation_roots is None: + # -------------------------------------------------------------- # No roots given - # ------------------------------------------------------------------------------ + # -------------------------------------------------------------- ext_ring_names = list(generic_extension_ring_names) - cubic_equation_roots = solve_with_extension(cubic_equation, ext_ring_names, var='S', flatten=True) - - # --------------------------------------------------------------------------------- - # interpreting user given cubic equation roots to define the corresponding - # specialized extension ring - # --------------------------------------------------------------------------------- - if cubic_equation_roots != None: + cubic_equation_roots = solve_with_extension(cubic_equation, + ext_ring_names, + var='S', flatten=True) + + # ---------------------------------------------------------------------- + # interpreting user given cubic equation roots to define the + # corresponding specialized extension ring + # ---------------------------------------------------------------------- + if cubic_equation_roots is not None: extension_ring = generic_extension_ring.create_specialization(cubic_equation_roots) - cubic_equation_roots = [ extension_ring(root) for root in cubic_equation_roots ] - verbose('extension_ring %s set according to cubic_equation_roots %s' %(base_ring, cubic_equation_roots)) + cubic_equation_roots = [extension_ring(root) for root in cubic_equation_roots] + verbose('extension_ring %s set according to cubic_equation_roots %s' + % (base_ring, cubic_equation_roots), level=2) else: extension_ring = generic_extension_ring.as_splitting_algebra() cubic_equation_roots = [extension_ring(a), extension_ring(b), extension_ring(c)] - verbose('cubic roots %s and extension ring %s defined' %(cubic_equation_roots, extension_ring)) + verbose('cubic roots %s and extension ring %s defined' + % (cubic_equation_roots, extension_ring), level=2) pa, pb, pc = cubic_equation_roots - - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # check keywords plausibility - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- if base_ring == extension_ring: val_a = cubic_equation.substitute(h=pa) val_b = cubic_equation.substitute(h=pb) val_c = cubic_equation.substitute(h=pc) - if val_a != 0 or val_b != 0 or val_c != 0 : - raise ValueError( 'cubic equation does not vanish on cubic equation roots' ) + if val_a != 0 or val_b != 0 or val_c != 0: + raise ValueError('cubic equation does not vanish on cubic equation roots') - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # defining the base ring embedding into the extension ring - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - - + # ---------------------------------------------------------------------- im_base_gens = [pa+pb+pc, pa*pb+pa*pc+pb*pc, pa*pb*pc] - - base_ring_embedding = extension_ring.coerce_map_from( base_ring ) + base_ring_embedding = extension_ring.coerce_map_from(base_ring) def check_base_ring_embedding(base_ring_embedding): if base_ring_embedding is None: @@ -889,11 +1031,11 @@ def check_base_ring_embedding(base_ring_embedding): return True if check_base_ring_embedding(base_ring_embedding): - verbose('base_ring_embedding defined via coercion') + verbose('base_ring_embedding defined via coercion', level=2) else: - base_ring_embedding = extension_ring.convert_map_from( base_ring ) + base_ring_embedding = extension_ring.convert_map_from(base_ring) if check_base_ring_embedding(base_ring_embedding): - verbose('base_ring_embedding defined via conversion') + verbose('base_ring_embedding defined via conversion', level=2) else: try: if base_ring.gens() == cubic_equation_parameters: @@ -901,80 +1043,62 @@ def check_base_ring_embedding(base_ring_embedding): except (TypeError, ValueError): base_ring_embedding = None - - if base_ring_embedding == None: + if base_ring_embedding is None: warn('Warning: no base_ring_embedding found') - - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # registering variables - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- - self._base_ring = base_ring - self._extension_ring = extension_ring - self._base_ring_embedding = base_ring_embedding - self._ring_of_definition_map = base_ring.convert_map_from(ring_of_definition) + # ---------------------------------------------------------------------- + self._base_ring = base_ring + self._extension_ring = extension_ring + self._base_ring_embedding = base_ring_embedding + self._ring_of_definition_map = base_ring.convert_map_from(ring_of_definition) self._generic_extension_ring_map = extension_ring.convert_map_from(generic_extension_ring) - self._cubic_equation_parameters = cubic_equation_parameters - self._cubic_equation_roots = cubic_equation_roots - + self._cubic_equation_parameters = cubic_equation_parameters + self._cubic_equation_roots = cubic_equation_roots - # --------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # defining the associated group algebras - # --------------------------------------------------------------------------------- - # old base_ring keyword of GroupAlgebra - # self._cubic_braid_group_algebra = GroupAlgebra( self._cubic_braid_group, base_ring=base_ring) - # self._braid_group_algebra = GroupAlgebra( self._braid_group, base_ring=base_ring) - # new base_ring keyword of GroupAlgebra + # ---------------------------------------------------------------------- from sage.algebras.group_algebra import GroupAlgebra self._cubic_braid_group_algebra = GroupAlgebra(self._cubic_braid_group, R=base_ring) - self._braid_group_algebra = GroupAlgebra(self._braid_group, R=base_ring) - + self._braid_group_algebra = GroupAlgebra(self._braid_group, R=base_ring) - # ---------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # Setup of Basis - # ---------------------------------------------------------------------------------------- - # init of data libraries and fetch the basis of Ivan Marin for the algebras on at most 4 - # strands. The fetch does not take long time. Therefore we do this absolutely silent - # ---------------------------------------------------------------------------------------- - marin_basis_data = self._database.read(self._database.filename.basis) - - # -------------------------------------------------------------------------------------------------- - # An explicit list of basis element which represents a flat deformation of the cubic braid group - # is only available in the cases where the number of strands is less than 5. In the case of exactly - # 5 strands it is known that such a basis exist by work of Ivan Marin in [Marin2012] but it can not - # be calculated, right now. In the (infinite dimensional) cases of more than 5 strand it is even an - # open problem if the cubic Hecke algebra is a flat deformation of the group algebra of the - # corresponding cubic braid group. + # ---------------------------------------------------------------------- + # Fetch Ivan Marin's basis for the algebras on at most 4 strands. + # An explicit list of basis element which represents a flat deformation + # of the cubic braid group is only available in the cases where the + # number of strands is less than 5. In the case of exactly 5 strands + # it is known that such a basis exist by work of Ivan Marin in + # [Marin2012] but it can not be calculated, right now. In the (infinite + # dimensional) cases of more than 5 strands it is even an open problem + # if the cubic Hecke algebra is a flat deformation of the group algebra + # of the corresponding cubic braid group. # - # But anyway, we will take the elements of the cubic braid group as a basis of the cubic Hecke - # algebra in all cases. Beware that this might not cover the whole cubic Hecke algebra if the - # number of strands is larger than 4 + # But anyway, we will take the elements of the cubic braid group as a + # basis of the cubic Hecke algebra in all cases. Beware that this might + # not cover the whole cubic Hecke algebra if the number of strands is + # larger than 4 # - # Internally the basis is handled using two lists one of which consists of fixed braid preiimages - # of the basis elements and the other (redundant) of the corresponding Tietze expressions. + # Internally the basis is implemented using two lists one of which + # consists of fixed braid pre images of the basis elements and the other + # (redundant) of the corresponding Tietze expressions. # - # In the case of less than 5 strands these lists are directly obtained from the list calculated - # by Ivan Marin available at + # In the case of less than 5 strands these lists are directly obtained + # from the list calculated by Ivan Marin available at # - # - # In the other cases these lists are implemented as growing lists which is initialized with Marin's - # list and is extended on demand. - # ----------------------------------------------------------------------------------------------- - - if self.strands() < 5 : - self._basis_static = [bas for bas in marin_basis_data[self.strands()][0]] - else: - self._basis_static = [bas for bas in marin_basis_data[4][0]] - - # --------------------------------------------------------------------------------- - # --------------------------------------------------------------------------------- + # In the other cases these lists are implemented as growing list which + # is initialized with Marin's list and is extended on demand. + # ---------------------------------------------------------------------- + db = self._database + ns = min(self.strands(), 4) + self._basis_static = db.read(db.section.basis, nstrands=ns) + + # ---------------------------------------------------------------------- # defining the algebra itself - # --------------------------------------------------------------------------------- - # -------------------------------------------------------------------------------- - + # ---------------------------------------------------------------------- if self._cubic_braid_group.is_finite(): from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis category = FiniteDimensionalAlgebrasWithBasis(base_ring) @@ -982,38 +1106,29 @@ def check_base_ring_embedding(base_ring_embedding): from sage.categories.algebras_with_basis import AlgebrasWithBasis category = AlgebrasWithBasis(base_ring) + CombinatorialFreeModule.__init__(self, base_ring, self._cubic_braid_group, + prefix='', bracket=False, category=category) - CombinatorialFreeModule.__init__(self, base_ring, self._cubic_braid_group, prefix='', bracket=False, category=category) - - # ---------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # init the attributes being set on demand - # ---------------------------------------------------------------------------------------- - self._cubic_hecke_subalgebra = None # the cubic Hecke subalgebra with one strand (the highest) less - self._mirror_image = None # the image of self under the mirror isomorphism - self._is_mirror = False # to see if this instance is the mirror or the original - self._base_ring_mirror = None # mirror involution map on base ring - self._gens_reg_repres_matrix = {} # a dictionary recording the generators regular representation matrices - - # ---------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + self._cubic_hecke_subalgebra = None + self._mirror_image = None + self._is_mirror = False + self._base_ring_mirror = None + self._gens_reg_repres_matrix = {} + + # ---------------------------------------------------------------------- # initializing the basis extension (in case of more than 4 strands) - # ---------------------------------------------------------------------------------------- - self._init_basis_extension() # read in the basis extensions from file cache + # ---------------------------------------------------------------------- + self._init_basis_extension() return - - - - - - - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ############################################################################ + # -------------------------------------------------------------------------- # overloaded inherited methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### - - + # -------------------------------------------------------------------------- + ############################################################################ def _repr_(self): r""" Return a string representation @@ -1026,12 +1141,13 @@ def _repr_(self): sage: CHA3 = algebras.CubicHecke(3) sage: CHA3 # indirect doctest - Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w - over Integer Ring with cubic equation: h^3 - u*h^2 + v*h - w = 0 + Cubic Hecke algebra on 3 strands + over Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) + with cubic equation: h^3 - u*h^2 + v*h - w = 0 """ - return "Cubic Hecke algebra on %s strands over %s with cubic equation: %s = 0"%(self.strands(), self.base_ring(), self.cubic_equation()) - + s = 'Cubic Hecke algebra on %s strands over %s with cubic equation: %s = 0' + return s % (self.strands(), self.base_ring(), self.cubic_equation()) def _element_constructor_(self, x): r""" @@ -1040,22 +1156,31 @@ def _element_constructor_(self, x): -- constructing element from a braid (group homomorphism) -- constructing element from a braid giving in Tietze form - -- constructing element from an element of the braid group algebra (algebra homomorphism) - -- constructing element from an element of the cubic braid group algebra (module homomorphism) - -- constructing element from an element of an other cubic_hecke_algebra over an other base ring or with less strands - -- constructing element from an element of the mirror image of ``self`` (see method mirror_image) + -- constructing element from an element of the braid group algebra + (algebra homomorphism) + -- constructing element from an element of the cubic braid group + algebra (module homomorphism) + -- constructing element from an element of an other cubic Hecke + algebra over an other base ring or with less strands + -- constructing element from an element of the mirror image of + ``self`` (see method mirror_image) INPUT: - ``x`` -- can be one of the following: - -- an instance of the element class of ``self`` (but possible to a different parent) + -- an instance of the element class of ``self`` (but possible + to a different parent) -- an instance of the element class of the braid group - -- an instance of the element class of the braid group algebra over the base ring of ``self`` + -- an instance of the element class of the braid group algebra + over the base ring of ``self`` -- an instance of the element class of the cubic braid group - -- an instance of the element class of the cubic braid group algebra over the base ring of ``self`` - -- an instance of the element class of the mirror image of ``self`` + -- an instance of the element class of the cubic braid group + algebra over the base ring of ``self`` + -- an instance of the element class of the mirror image of + ``self`` -- a tuple representing a braid in Tietze form - -- any other object which works for the element constructor of :class:`CombinatorialFreeModule` + -- any other object which works for the element constructor + of :class:`CombinatorialFreeModule` OUTPUT: @@ -1071,7 +1196,7 @@ def _element_constructor_(self, x): sage: cb2 = cb**2 sage: CHA2 = algebras.CubicHecke(2) sage: CHA2(b2) - (-v) + u*c + w*c^-1 + w*c^-1 + u*c + (-v) sage: CHA2(cb2) c^-1 sage: CHA3 = algebras.CubicHecke(3) @@ -1081,10 +1206,10 @@ def _element_constructor_(self, x): sage: braid = B3((1,2,2,-1,2,1,1,-1)); braid c0*c1^2*c0^-1*c1*c0 sage: img_braid = CHA3(braid); img_braid - (u*v^2+(-w)*v)*c1^-1 + (u^2-v)*c1*c0 + u^2*v*c1*c0^-1 + (-u^3)*c0*c1*c0^-1 - + (-u^2*v+w*u)*c0*c1^-1 + u^2*c0*c1*c0^-1*c1 + (-u*v)*c1*c0^-1*c1 - + ((-w)*u*v+w^2)*c0^-1*c1^-1 + ((-w)*u^2)*c0^-1*c1*c0^-1 - + w*u*(c0^-1*c1)^2 + u*v*c0*c1^-1*c0 + u*w*(c0^-1*c1)^2 + u*v*c0*c1^-1*c0 + (-u^2*w)*c0^-1*c1*c0^-1 + + (-u*v)*c1*c0^-1*c1 + (-u*v*w+w^2)*c0^-1*c1^-1 + u^2*c0*c1*c0^-1*c1 + + (-u^2*v+u*w)*c0*c1^-1 + u^2*v*c1*c0^-1 + (u^2-v)*c1*c0 + + (-u^3)*c0*c1*c0^-1 + (u*v^2-v*w)*c1^-1 sage: cbraid = CB3(braid); cbraid c0*c1^2*c0^-1*c1*c0 sage: img_cbraid = CHA3(cbraid); img_cbraid @@ -1095,115 +1220,117 @@ def _element_constructor_(self, x): sage: img_cbraid_back == CB3GA(cbraid) True """ - braid_grp = self.braid_group() - braid_grp_alg = self.braid_group_algebra() - braid_img = self._braid_image + braid_grp = self.braid_group() + braid_grp_alg = self.braid_group_algebra() + braid_img = self._braid_image - cbraid_grp = self.cubic_braid_group() - cbraid_grp_alg = self.cubic_braid_group_algebra() - cbraid_img = self._cubic_braid_image + cbraid_grp = self.cubic_braid_group() + cbraid_grp_alg = self.cubic_braid_group_algebra() + cbraid_img = self._cubic_braid_image - base_ring = self.base_ring() - ngens = self.ngens() + base_ring = self.base_ring() + ngens = self.ngens() + params = self.cubic_equation_parameters() - # ----------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # if x is a tuple we may interpret it as a braid in Tietze form - # ----------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- xb = x if type(x) in (tuple, list): x = tuple(x) result = self._tietze_to_finite_sub_basis_monomial(x) if result is not None: # x represents a monomial - verbose("End from tuple %s: %s" %(x, result)) + verbose('end from tuple %s: %s' % (x, result), level=2) return result try: - xb=braid_grp(x) + xb = braid_grp(x) except (TypeError, ValueError, NotImplementedError): pass - # ----------------------------------------------------------------------------------------- - # embedding of an element of an other cubic Hecke algebra with lower number of strands - # but same base ring - # ----------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # embedding of an element of an other cubic Hecke algebra with lower + # number of strands but same base ring + # ---------------------------------------------------------------------- if isinstance(xb, CubicHeckeElement): - OtherCHA = xb.parent() - other_base_ring = OtherCHA.base_ring() - other_ngens = OtherCHA.ngens() + other_cha = xb.parent() + other_base_ring = other_cha.base_ring() + other_ngens = other_cha.ngens() + other_params = other_cha.cubic_equation_parameters() if other_base_ring != base_ring: if other_ngens == ngens: xbv = xb.to_vector() - img_xbv = vector([self.base_ring()(cf) for cf in xbv ]) + img_xbv = vector([self.base_ring()(cf) for cf in xbv]) return self.from_vector(img_xbv) elif other_ngens < ngens: - SubAlg = SubAlg = self.cubic_hecke_subalgebra(other_ngens+1) - return self(SubAlg(xb)) + sub_alg = self.cubic_hecke_subalgebra(other_ngens+1) + return self(sub_alg(xb)) - elif other_ngens < ngens and OtherCHA.cubic_equation_parameters() == self.cubic_equation_parameters(): + elif other_ngens < ngens and other_params == params: - cubic_braid_preimg = xb.cubic_braid_group_algebra_pre_image() - OtherCBGA = OtherCHA.cubic_braid_group_algebra() + cbraid_preimg = xb.cubic_braid_group_algebra_pre_image() + other_cbga = other_cha.cubic_braid_group_algebra() - result = OtherCBGA._apply_module_morphism(cubic_braid_preimg, lambda ele: cbraid_img(cbraid_grp(ele)), codomain=self) - verbose("End from smaller cubic Hecke algebra %s: %s" %(xb, result)) + def fc(ele): + return cbraid_img(cbraid_grp(ele)) + result = other_cbga._apply_module_morphism(cbraid_preimg, fc, codomain=self) + verbose('end from smaller cubic Hecke algebra %s: %s' % (xb, result), level=2) return result - elif OtherCHA == self._mirror_image: - - result = OtherCHA.mirror_isomorphism(xb) - verbose("End from mirror image %s: %s" %(xb, result)) + elif other_cha == self._mirror_image: + result = other_cha.mirror_isomorphism(xb) + verbose('end from mirror image %s: %s' % (xb, result), level=2) return result - # ----------------------------------------------------------------------------------------- - # if xb is an element of the braid group or its group algebra over the same base ring - # the algebra morphism self._braid_image is applied - # ----------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # if xb is an element of the braid group or its group algebra over the + # same base ring the algebra morphism self._braid_image is applied + # ---------------------------------------------------------------------- if isinstance(xb, braid_grp_alg.element_class) and xb in braid_grp_alg: - result = braid_grp_alg._apply_module_morphism(xb, lambda ele: braid_img(ele), codomain=self) - verbose("End from braid_group algebra %s: %s" %(xb, result)) + def fb(ele): + return braid_img(ele) + result = braid_grp_alg._apply_module_morphism(xb, fb, codomain=self) + verbose('end from braid_group algebra %s: %s' % (xb, result), level=2) return result from sage.groups.braid import Braid if isinstance(xb, Braid) and xb.strands() == self.strands(): result = braid_img(xb) - verbose("End from braid_group %s: %s" %(xb, result)) + verbose('end from braid_group %s: %s' % (xb, result), level=2) return result - # ----------------------------------------------------------------------------------------- - # if xb is an element of the cubic_braid group or its group algebra over the same base ring - # xb the module morphism self._braid_image is applied - # ----------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # if xb is an element of the cubic_braid group or its group algebra over + # the same base ring xb the module morphism self._braid_image is applied + # ---------------------------------------------------------------------- if isinstance(xb, cbraid_grp_alg.element_class) and xb in cbraid_grp_alg: result = cbraid_grp_alg._apply_module_morphism(xb, cbraid_img, codomain=self) - verbose("End from cubic braid_group algebra %s: %s" %(xb, result)) + verbose('end from cubic braid_group algebra %s: %s' % (xb, result), level=2) return result from sage.groups.cubic_braid import CubicBraidElement if isinstance(xb, CubicBraidElement) and xb.parent().strands() == self.strands(): result = cbraid_img(xb) - verbose("End from cubic braid_group %s: %s" %(xb, result)) + verbose('end from cubic braid_group %s: %s' % (xb, result), level=2) return result - - # ----------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # doing the default construction by inheritance - # ----------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- result = CombinatorialFreeModule._element_constructor_(self, x) - verbose("End (default) %s: %s" %(xb, result)) + verbose('end (default) %s: %s' % (xb, result), level=2) return result - - def get_order(self): r""" - Overwrites the corresponding method of :class:`CombinatorialFreeModule`. The reason is that - we have to care about the dynamical growth of the finite sub basis used for the calculation in case of - more than 4 strands. + Overwrites the corresponding method of :class:`CombinatorialFreeModule`. + The reason is that we have to care about the dynamical growth of the + finite sub basis used for the calculation in case of more than 4 strands. To see the documentation of the original method type: @@ -1218,7 +1345,7 @@ def get_order(self): if self.strands() < 5: return self._order else: - # detect change of order of subalgebra + # detect change of order of sub algebra cbg = self.cubic_braid_group() sub_alg = self.cubic_hecke_subalgebra() former_len_sub = len(sub_alg._order) @@ -1226,19 +1353,17 @@ def get_order(self): if former_len_sub == len(sub_order): if len(self._order) == former_len_sub + len(self._basis_extension): return self._order - # order has changed! recalculation neccessary: + # order has changed! re-calculation necessary: self._order = sub_order + [cbg(tup) for tup in self._basis_extension] return self._order - - def _dense_free_module(self, base_ring=None): r""" Overwrites the corresponding method of :class:`CombinatorialFreeModule`. - The only difference is, that the dimension is not the dimension of ``self`` but - the dimension of the submodule generated by the dynamically growing basis given - by the the get_order method. In particular there is no difference if the number - of strands is less than 5. + The only difference is, that the dimension is not the dimension of + ``self`` but the dimension of the sub-module generated by the dynamically + growing basis given by the :meth:`get_order`. In particular there is + no difference if the number of strands is less than 5. To see the documentation of the original method type: @@ -1248,16 +1373,15 @@ def _dense_free_module(self, base_ring=None): sage: CHA2 = algebras.CubicHecke(2) sage: CHA2._dense_free_module() - Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring + Ambient free module of rank 3 + over the integral domain Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) """ - if base_ring is None: base_ring = self.base_ring() from sage.modules.free_module import FreeModule return FreeModule(base_ring, len(self.get_order())) - def ngens(self): r""" The number of generators of the algebra. @@ -1268,7 +1392,7 @@ def ngens(self): sage: CHA2.ngens() 1 """ - return self.strands() -1 + return self.strands() - 1 def algebra_generators(self): r""" @@ -1283,7 +1407,6 @@ def algebra_generators(self): from sage.sets.family import Family return Family(self._cubic_braid_group.gens(), self.monomial) - def gens(self): r""" Return the generators of ``self``. @@ -1296,7 +1419,6 @@ def gens(self): """ return tuple(self.algebra_generators()) - def gen(self, i): r""" The ``i``-th generator of the algebra. @@ -1309,11 +1431,10 @@ def gen(self, i): """ return self.gens()[i] - def one_basis(self): r""" Return the identity element in the cubic braid group, as per - AlgebrasWithBasis.ParentMethods.one_basis. + :meth:`~sage.categories.algebras_with_basis.AlgebrasWithBasis.ParentMethods.one_basis`. EXAMPLES:: @@ -1323,44 +1444,39 @@ def one_basis(self): """ return self.cubic_braid_group().one() - def _an_element_(self): r""" - Overwrite the original method from :mod:`sage.combinat.free_module` + Overwrite the original method from :mod:`~sage.combinat.free_module` to obtain an more interesting element for ``TestSuite``. EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2) sage: CHA2.an_element() # indirect doctest - ((w^-1)*u-v) + v*c + v*c + ((-v*w+u)/w) """ - - n = self.ngens()+1 + n = self.ngens() + 1 base_ring = self.base_ring() u, v, w = [base_ring(para) for para in self._cubic_equation_parameters] - const = (u *~w -v)* self.one() + const = (u*~w - v)*self.one() gens = self.gens() - first_gens = [gen for gen in gens if gens.index(gen) < 3 ] - if n == 2 : + first_gens = [gen for gen in gens if gens.index(gen) < 3] + if n == 2: c1, = first_gens return const + v*c1 - elif n == 3 : + elif n == 3: c1, c2 = first_gens - return const + v*c1 -w*c1*~c2 + u*c2 + return const + v*c1 - w*c1*~c2 + u*c2 else: c1, c2, c3 = first_gens - return const + v*c1*~c3 -w*c1*~c2 + u*c3*c2 - - - + return const + v*c1*~c3 - w*c1*~c2 + u*c3*c2 @cached_method def chevie(self): r""" - Return the *GAP3-CHEVIE* realization of the corresponding *cyclotomic Hecke algebra* - in the finite-dimensional case. + Return the *GAP3-CHEVIE* realization of the corresponding *cyclotomic + Hecke algebra* in the finite-dimensional case. EXAMPLES:: @@ -1374,7 +1490,6 @@ def chevie(self): raise NotImplementedError('this functionality needs GAP3 with package CHEVIE') n = self._nstrands - if n == 3: st_number = 4 elif n == 4: @@ -1397,10 +1512,9 @@ def chevie(self): from sage.interfaces.gap3 import gap3 gap3_function = gap3(gap3_function_str) - na, nb, nc = [ '\"%s\"' %(indet) for indet in self.extension_ring(generic=True).variable_names() ] + na, nb, nc = ['\"%s\"' % indet for indet in self.extension_ring(generic=True).variable_names()] return gap3_function(st_number, na, nb, nc) - @cached_method def product_on_basis(self, g1, g2): r""" @@ -1415,54 +1529,43 @@ def product_on_basis(self, g1, g2): sage: CHA3.product_on_basis(g, ~g) 1 sage: CHA3.product_on_basis(g, g) - (-v)*c1*c0 + u*c0*c1*c0 + w*c0^-1*c1*c0 + w*c0^-1*c1*c0 + (-v)*c1*c0 + u*c0*c1*c0 """ - # ------------------------------------------------------------------------------------------------ + # ---------------------------------------------------------------------- # short way for multiplications with one - # ------------------------------------------------------------------------------------------------ + # ---------------------------------------------------------------------- if g1 == g1.parent().one(): return self.monomial(g2) if g2 == g2.parent().one(): return self.monomial(g1) - # ------------------------------------------------------------------------------------------------ + # ---------------------------------------------------------------------- # convert to monomials - # ------------------------------------------------------------------------------------------------ + # ---------------------------------------------------------------------- g1 = self.monomial(g1) g2 = self.monomial(g2) - result = None + result = None g1_Tietze = g1.Tietze() g2_Tietze = g2.Tietze() - verbose("Tietze established (%s, %s)" %(g1_Tietze, g2_Tietze)) + verbose('Tietze established (%s, %s)' % (g1_Tietze, g2_Tietze), level=2) - # ---------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # The product is calculated from the corresponding product of the braids - # ---------------------------------------------------------------------------------------------------- - + # ---------------------------------------------------------------------- braid_group = self.braid_group() braid_product = braid_group(g1_Tietze+g2_Tietze) - result = self._braid_image(braid_product) - return result - - - - - - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- + ############################################################################ + # -------------------------------------------------------------------------- # local methods - # --------------------------------------------------------------------------------------------------------------------- - ####################################################################################################################### - - - + # -------------------------------------------------------------------------- + ############################################################################ def _basis_tietze(self): r""" Return the complete finite sub basis as list of Tietze tuples @@ -1473,17 +1576,16 @@ def _basis_tietze(self): sage: CHA2._basis_tietze() [[], [1], [-1]] """ - if self.strands() > 4 : - self_sub = self.cubic_hecke_subalgebra() + if self.strands() > 4: + self_sub = self.cubic_hecke_subalgebra() result_list = self_sub._basis_tietze() + self._basis_extension else: result_list = self._basis_static return result_list - def _tietze_to_finite_sub_basis_monomial(self, tietze_tup): r""" - Return the monomial corresponding to a tietze tuple + Return the monomial corresponding to a Tietze tuple if it is in the finite sub basis. Else return None. EXAMPLES:: @@ -1533,8 +1635,8 @@ def _create_matrix_list_for_one(self, representation_type): n = self.strands() if representation_type.is_split(): gen_base_ring = self.extension_ring(generic=True) - rep_ind = [rep.internal_index() for rep in AbsIrreducibeRep if rep.number_gens() == n-1 ] - rep_dim = [rep.dimension() for rep in AbsIrreducibeRep if rep.number_gens() == n-1 ] + rep_ind = [rep.internal_index() for rep in AbsIrreducibeRep if rep.number_gens() == n - 1] + rep_dim = [rep.dimension() for rep in AbsIrreducibeRep if rep.number_gens() == n - 1] dim_sort = [rep_dim[rep_ind.index(i)] for i in range(len(rep_ind))] matrix_list = [MatrixSpace(gen_base_ring, dim_sort[i]).one() for i in range(len(rep_ind))] else: @@ -1545,15 +1647,18 @@ def _create_matrix_list_for_one(self, representation_type): @cached_method def _fetch_matrix_list_from_chevie(self, number): r""" - This method reads irreducible representation of the cubic Hecke algebra via the *GAP3* interface from *CHEVIE* + This method reads irreducible representation of the cubic Hecke algebra + via the *GAP3* interface from *CHEVIE*. INPUT: - - ``number`` -- integer: number of the representation according to *CHEVIE* + - ``number`` -- integer: number of the representation according to + *CHEVIE* OUTPUT: - A list of representing matrices over the generic extension ring, one matrix for each generators. + A list of representing matrices over the generic extension ring, one + matrix for each generators. EXAMPLES:: @@ -1565,30 +1670,28 @@ def _fetch_matrix_list_from_chevie(self, number): ] """ GER = self.extension_ring(generic=True) - gap3_result = self.chevie().Representations(number) + gap3_result = self.chevie().Representations(number) from sage.matrix.constructor import matrix matrix_list_gens = [matrix(GER, mat_gap) for mat_gap in gap3_result] - for m in matrix_list_gens: m.set_immutable() + for m in matrix_list_gens: + m.set_immutable() return matrix_list_gens - - - - # ------------------------------------------------------------------------------- - # ------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # Methods for test_suite - # ------------------------------------------------------------------------------- - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _test_ring_constructions - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _test_ring_constructions(self, **options): r""" - Method called by TestSuite. + Method called by :class:`TestSuite`. - the following is checked: - - construction of base_ring and extension ring - - construction of maps between generic base and extension ring and the user defined rings - - aplication of the ring homomorphisms + The following is checked: + + - construction of base_ring and extension ring + - construction of maps between generic base and extension ring and + the user defined rings + - application of the ring homomorphisms EXAMPLES:: @@ -1598,89 +1701,98 @@ def _test_ring_constructions(self, **options): # ------------------------------------------------------------------------ # testing ring constructions # ------------------------------------------------------------------------ - - - br=self.base_ring(); er=self.extension_ring() - A, B, C = self.cubic_equation_roots(); a, b, c = self.cubic_equation_roots(generic=True); - U, V, W = self.cubic_equation_parameters(); u, v, w = self.cubic_equation_parameters(generic=True); - eleB = U*V-W**2 ; eleBgen = u*v-w**2 ; eleE = A*B-C**2 ; eleEgen = a*b-c**2 + br = self.base_ring() + er = self.extension_ring() + A, B, C = self.cubic_equation_roots() + a, b, c = self.cubic_equation_roots(generic=True) + U, V, W = self.cubic_equation_parameters() + u, v, w = self.cubic_equation_parameters(generic=True) + eleB = U*V - W**2 + eleBgen = u*v - w**2 + eleE = A*B - C**2 + eleEgen = a*b - c**2 mbr = self._ring_of_definition_map mer = self._generic_extension_ring_map bri = self._base_ring_embedding - eleBgenEmb = 0 ; eleEgenEmb = 0 ; eleBembE = 0 + eleBgenEmb = 0 + eleEgenEmb = 0 + eleBembE = 0 try: eleBgenEmb = br(eleBgen) except (TypeError, ValueError, NotImplementedError): - verbose("Generic base ring map not registered") + verbose('generic base ring map not registered') try: eleBgenEmb = mbr(eleBgen) except (TypeError, ValueError, NotImplementedError): - raise RuntimeError("fatal: generic base ring map %s does not work" %(mbr)) + raise RuntimeError('fatal: generic base ring map %s does not work' % mbr) try: eleEgenEmb = er(eleEgen) except (TypeError, ValueError, NotImplementedError): - verbose("Generic extension ring map not registered") + verbose('generic extension ring map not registered') try: eleEgenEmb = mer(eleEgen) except (TypeError, ValueError, NotImplementedError): - raise RuntimeError("fatal: generic extension ring map %s does not work" %(mer)) + raise RuntimeError('fatal: generic extension ring map %s does not work' % mer) try: eleBembE = er(eleB) except (TypeError, ValueError, NotImplementedError): - verbose("base ring embedding map not registered") + verbose('base ring embedding map not registered') try: eleBembE = bri(eleB) except (TypeError, ValueError, NotImplementedError): - raise RuntimeError( "fatal: base ring embedding %s does not work" %(bri) ) + raise RuntimeError('fatal: base ring embedding %s does not work' % bri) test_eleBgenEmb = self._tester(**options) - test_eleBgenEmb.assertTrue( eleBgenEmb == eleB ) + test_eleBgenEmb.assertTrue(eleBgenEmb == eleB) test_eleEgenEmb = self._tester(**options) - test_eleEgenEmb.assertTrue( eleEgenEmb == eleE ) + test_eleEgenEmb.assertTrue(eleEgenEmb == eleE) test_eleBembE = self._tester(**options) - test_eleBembE.assertTrue( eleBembE == eleB ) - - + test_eleBembE.assertTrue(eleBembE == eleB) - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _test_matrix_constructions - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _test_matrix_constructions(self, **options): r""" - Method called by TestSuite + Method called by :class:`TestSuite`. - the following is checked: - - construction of matrices of the following types + The following is checked: - - multiplication of matrices and compare with the matrix of the corresponding product of elements - - construction of maps between generic base and extension ring and the user defined rings + - construction of matrices of the following types + -- ``RepresentationType.SplitIrredChevie`` + -- ``RepresentationType.SplitIrredMarin`` + -- ``RepresentationType.RegularLeft`` + - multiplication of matrices and compare with the matrix of the + corresponding product of elements + - construction of maps between generic base and extension ring and + the user defined rings EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3,7,11)) sage: CHA2._test_matrix_constructions() """ - # ------------------------------------------------------------------------ + # ---------------------------------------------------------------------- # testing matrix constructions - # ------------------------------------------------------------ ------------ - - if self.ngens() > 4 : + # ---------------------------------------------------------------------- + if self.ngens() > 4: return gens = self.gens() - b1 = gens[0 ]; b2 = self.an_element() + b1 = gens[0] + b2 = self.an_element() b12 = b1*b2 - verbose("b12 %s" %(b12)) + verbose('b12 %s' % b12) def check_matrix(representation_type): - m1 = b1.matrix(representation_type=representation_type) - m2 = b2.matrix(representation_type=representation_type) + m1 = b1.matrix(representation_type=representation_type) + m2 = b2.matrix(representation_type=representation_type) m12mult = m1*m2 - m12mat = b12.matrix(representation_type=representation_type) + m12mat = b12.matrix(representation_type=representation_type) test_matrix = self._tester(**options) test_matrix.assertTrue(m12mult == m12mat) @@ -1688,67 +1800,59 @@ def check_matrix(representation_type): if is_chevie_available(): check_matrix(RepresentationType.SplitIrredChevie) - if self.ngens() < 3 : + if self.ngens() < 3: check_matrix(RepresentationType.SplitIrredMarin) - elif self.ngens() < 4 : + elif self.ngens() < 4: check_matrix(RepresentationType.SplitIrredMarin) - if self.ngens() < 3 : + if self.ngens() < 3: check_matrix(RepresentationType.RegularLeft) - return - - - - - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _init_basis_extension - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _init_basis_extension(self): r""" - Return the extension of the basis for more than 4 strands hold in file cache. - The basis elements from the file are added to the elements of the Marin basis. + Return the extension of the basis for more than 4 strands hold in file + cache. The basis elements from the file are added to the elements of the + Marin basis. EXAMPLES:: - sage: CHA5 = algebras.CubicHecke(5) # long time - sage: fc = CHA5._filecache # long time - sage: basis_extensions = fc.section.basis_extensions # long time - sage: CHA5.reset_filecache(basis_extensions) # long time indirect doctest - sage: fc.read(basis_extensions) # long time + sage: CHA5 = algebras.CubicHecke(5) # optional - database_cubic_hecke # indirect doctest + sage: fc = CHA5._filecache # optional - database_cubic_hecke + sage: be = fc.section.basis_extensions # optional - database_cubic_hecke + sage: CHA5.reset_filecache(be) # optional - database_cubic_hecke + sage: fc.read(be) # optional - database_cubic_hecke [[4], [-4]] - sage: ele = CHA5.an_element() # long time - sage: CHA5.inject_variables() # long time + sage: ele = CHA5.an_element() # optional - database_cubic_hecke + sage: CHA5.inject_variables() # optional - database_cubic_hecke Defining c0, c1, c2, c3 - sage: ele2 = ele*c3 # long time - sage: bex = fc.read(basis_extensions) # long time - sage: bex.sort(); bex # long time + sage: ele2 = ele*c3 # optional - database_cubic_hecke + sage: bex = fc.read(be) # optional - database_cubic_hecke + sage: bex.sort(); bex # optional - database_cubic_hecke [[-4], [1, -3, 4], [1, -2, 4], [3, 2, 4], [4]] """ self._basis_extension = [] - tietze_list = self._basis_tietze() cbg = self._cubic_braid_group self._finite_sub_basis_tuples = {} - order_list = [cbg(tup) for tup in tietze_list] + order_list = [cbg(tup) for tup in tietze_list] self.set_order(order_list) - verbose('Finite sub basis length: %s' %(len(order_list))) + verbose('finite sub basis length: %s' % (len(order_list)), level=2) if self.strands() < 5: return - # ------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # loading the extension of the basis from data file - # ------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- fc = self._filecache former_bas_ext = fc.read(fc.section.basis_extensions) - # ------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # pre definition of additional basis elements - # ------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- cub_braid_group = self.cubic_braid_group() if len(former_bas_ext) == 0: gens = cub_braid_group.gens() @@ -1758,28 +1862,25 @@ def _init_basis_extension(self): self._filecache.update_basis_extensions(self._basis_extension) return - # ------------------------------------------------------------------------------------------------- - # Installing the additional basis elements from filecache via the embedding of - # the corresponding cubic braid - # ------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # Installing the additional basis elements from filecache via the + # embedding of the corresponding cubic braid + # ---------------------------------------------------------------------- for bas_Tietze in former_bas_ext: cub_braid = cub_braid_group(bas_Tietze) self._cubic_braid_image(cub_braid, check=False) - verbose('Finite sub basis (extended) length: %s' %(len(self.get_order()))) + verbose('finite sub basis (extended) length: %s' % (len(self.get_order())), level=2) self._filecache.update_basis_extensions(self._basis_extension) return - - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _braid_image_from_filecache - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _braid_image_from_filecache(self, braid): r""" - Return the image of the given braid in ``self`` from file cache (if contained). + Return the image of the given braid in ``self`` from file cache (if + contained). INPUT: @@ -1787,32 +1888,37 @@ def _braid_image_from_filecache(self, braid): OUTPUT: - Image of braid as element of ``self``. None if the product has not been stored. + Image of braid as element of ``self``. None if the product has not been + stored. EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: b1, b2 = CHA3.braid_group().gens(); br = ~b2*b1*~b2 sage: CHA3._braid_image_from_filecache(br) - ((w^-1)*v)*c1^-1*c0 + ((-w^-1)*u)*c0*c1*c0^-1 + (w^-1)*c0*c1*c0^-1*c1 - sage: CHA3.reset_filecache(CHA3.select_filecache_section().braid_images) + 1/w*c0*c1*c0^-1*c1 + v/w*c1^-1*c0 + ((-u)/w)*c0*c1*c0^-1 + sage: F = CHA3.base_ring().fraction_field() + sage: par = tuple([F(p) for p in CHA3.cubic_equation_parameters()]) + sage: CHA3F = algebras.CubicHecke(3, cubic_equation_parameters=par) + sage: CHA3F._braid_image_from_filecache(br) + 1/w*c0*c1*c0^-1*c1 + v/w*c1^-1*c0 + ((-u)/w)*c0*c1*c0^-1 + sage: section = CHA3.select_filecache_section().braid_images + sage: CHA3.reset_filecache(section) sage: CHA3._braid_image_from_filecache(br) """ - base_ring = self.base_ring() gen_base_ring = self.base_ring(generic=True) result_vect = self._filecache.read_braid_image(braid.Tietze(), gen_base_ring) - if not result_vect is None: + if result_vect is not None: if gen_base_ring != base_ring: base_map = self._ring_of_definition_map - result_vect = base_map(result_vect) + result_vect = vector(base_ring, [base_map(cf) for cf in result_vect]) return self.from_vector(result_vect) return None - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _braid_image_to_filecache - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _braid_image_to_filecache(self, braid_tietze, braid_image_vect): r""" Write the given braid image of to file cache. @@ -1820,17 +1926,19 @@ def _braid_image_to_filecache(self, braid_tietze, braid_image_vect): INPUT: - `braid_tietze` -- braid in Tietze form - - `braid_image_vect` -- image of the given braid in ``self`` in vector representation + - `braid_image_vect` -- image of the given braid in ``self`` in vector + representation EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2) sage: br, = CHA2.braid_group().gens(); br2 = br**2 - sage: CHA2.is_filecache_empty(CHA2.select_filecache_section().braid_images) # note: 2-strand images are not automatically cached in file system + sage: section = CHA2.select_filecache_section().braid_images + sage: CHA2.is_filecache_empty(section) # note: 2-strand images are not automatically cached in file system True sage: CHA2._braid_image_to_filecache(br2.Tietze(), CHA2(br2).to_vector()) sage: CHA2._braid_image_from_filecache(br2) - (-v) + u*c + w*c^-1 + w*c^-1 + u*c + (-v) sage: CHA2.reset_filecache(CHA2.select_filecache_section().braid_images) sage: CHA2._braid_image_from_filecache(br2) == None True @@ -1842,20 +1950,18 @@ def _braid_image_to_filecache(self, braid_tietze, braid_image_vect): self._filecache.write_braid_image(braid_tietze, braid_image_vect) return - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _braid_image - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- + @cached_method def _braid_image(self, braid): r""" Return the image of the given braid in ``self``. INPUT: - - ``braid`` - instance of :class:`~sage.groups.braid.Braid`, whose image in ``self`` should be calculated - + - ``braid`` - instance of :class:`~sage.groups.braid.Braid`, whose image + in ``self`` should be calculated OUTPUT: @@ -1866,19 +1972,18 @@ def _braid_image(self, braid): sage: CHA2 = algebras.CubicHecke(2) sage: br, = CHA2.braid_group().gens(); br2 = br**2 sage: CHA2._braid_image(br2) - (-v) + u*c + w*c^-1 + w*c^-1 + u*c + (-v) """ - - - # ----------------------------------------------------------------------------------------------------- - # first use the cubic equation to express the braid as a linear combination of braids having no other - # exponent as 1 and -1 in their defining word in the braid generators - # ----------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # first use the cubic equation to express the braid as a linear + # combination of braids having no other exponent as 1 and -1 in their + # defining word in the braid generators + # ---------------------------------------------------------------------- coeffs, braids = self._reduce_all_gen_powers(braid.Tietze()) - # ----------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # in the second step the images of these "reduced" braids is calculated - # ----------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- result = self.zero() for i in range(len(coeffs)): braid_image = self._braid_image_from_reduced_powers(braids[i]) @@ -1886,22 +1991,21 @@ def _braid_image(self, braid): return result - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _braid_image_from_reduced_powers - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- @cached_method def _braid_image_from_reduced_powers(self, braid_tietze): r""" - Return the image of a braid in ``self`` asuming that no successive repetitions occur in the Tietze form - of the braid. + Return the image of a braid in ``self`` assuming that no successive + repetitions occur in the Tietze form of the braid. INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose image in ``self`` should be computed. It is assumed - that no successive repetitions occur among the entries (i.e. (1,1) is not allowed but (1, -2, 1) is) + - ``braid_tietze`` -- tuple representing the Braid whose image in + ``self`` should be computed. It is assumed that no successive + repetitions occur among the entries (i.e. (1,1) is not allowed + but (1, -2, 1) is) OUTPUT: @@ -1913,64 +2017,64 @@ def _braid_image_from_reduced_powers(self, braid_tietze): sage: CHA3._braid_image_from_reduced_powers((1, -2, 1)) c0*c1^-1*c0 sage: CHA3._braid_image_from_reduced_powers((1, -2, 1, 2)) - (-v)*c1*c0^-1 + u*c0*c1*c0^-1 + w*c0^-1*c1*c0^-1 + w*c0^-1*c1*c0^-1 + (-v)*c1*c0^-1 + u*c0*c1*c0^-1 """ - n = self.ngens() - braid_list = list(braid_tietze) - len_braid = len(braid_list) + n = self.ngens() + braid_list = list(braid_tietze) + len_braid = len(braid_list) - # --------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- # in the case of two strands we calculate the power of the generator - # --------------------------------------------------------------------------------------------------- - if n == 1 : - if len_braid == 0 : + # ---------------------------------------------------------------------- + if n == 1: + if len_braid == 0: return self.one() - k = braid_tietze[0 ]*len_braid + k = braid_tietze[0]*len_braid result_vect = self._reduce_gen_power(k) result = self.from_vector(result_vect) return result - # --------------------------------------------------------------------------------------------------- - # Try to use former calculations (from dynamic library) to obtain the braid image - # --------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # Try to use former calculations (from dynamic library) to obtain the + # braid image + # ---------------------------------------------------------------------- result, word_decomposition = self._braid_image_from_former_calculations(braid_tietze) - if word_decomposition == None: + if word_decomposition is None: return result - # --------------------------------------------------------------------------------------------------- - # proceed the calculation by use of the regular representation matrices (given by Ivan Marin) - # or in case of more than 4 strands by extension of the finite sub basis - # --------------------------------------------------------------------------------------------------- - - if n > 3 and (n in braid_tietze or -n in braid_tietze) : # more than four strands - # --------------------------------------------------------------------------------------------------- - # matrices for the regular representation are at the moment just available in the case of less than - # five strands. In the higher cases the basis is realized to grow up from the basis on 4 strands - # to use the recursion, only those cubic braids are stored as new basis elements if they involve - # the generator with largest index - # --------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # proceed the calculation by use of the regular representation matrices + # (given by Ivan Marin) or in case of more than 4 strands by extension + # of the finite sub basis + # ---------------------------------------------------------------------- + + if n > 3 and (n in braid_tietze or -n in braid_tietze): + # ------------------------------------------------------------------ + # matrices for the regular representation are at the moment just + # available in the case of less than five strands. In the higher + # cases the basis is realized to grow up from the basis on 4 strands + # to use the recursion, only those cubic braids are stored as new + # basis elements if they involve the generator with largest index + # ------------------------------------------------------------------ return self._braid_image_by_basis_extension(braid_tietze) - word_left, word_result, word_right = word_decomposition - result_vect = None - if word_left != None: - # -------------------------------------------------------------------------------------- - # Operating from the left on the precalculated result - # -------------------------------------------------------------------------------------- - + if word_left is not None: + # ------------------------------------------------------------------ + # Operating from the left on the pre-calculated result + # ------------------------------------------------------------------ vect = result.to_vector() braid_preimage = tuple(word_result) result_vect = self._mult_by_regular_rep(vect, tuple(word_left), RepresentationType.RegularLeft, braid_preimage) - if word_right != None: - # -------------------------------------------------------------------------------------- - # Operating from the right on the precalculated result - # -------------------------------------------------------------------------------------- - if result_vect != None: + if word_right is not None: + # ------------------------------------------------------------------ + # Operating from the right on the pre-calculated result + # ------------------------------------------------------------------ + if result_vect is not None: vect = result_vect braid_preimage = tuple(word_left + word_result) else: @@ -1979,36 +2083,36 @@ def _braid_image_from_reduced_powers(self, braid_tietze): result_vect = self._mult_by_regular_rep(vect, tuple(word_right), RepresentationType.RegularRight, braid_preimage) result = self.from_vector(result_vect) - return result - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _braid_image_from_former_calculations - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _braid_image_from_former_calculations(self, braid_tietze): r""" - Return the image of a braid in ``self`` as far as this can be done by use of former calculations and is sure not to - go into an endless recursion, that is + Return the image of a braid in ``self`` as far as this can be done by + use of former calculations and is sure not to go into an endless + recursion, that is - - using the cubic Hecke subalgebra on one strand less + - using the cubic Hecke sub-algebra on one strand less - using the file cache. - If the image can not be calculated from former registered results this method returns None. - Therefore, it is just intended to be used as as step in the complete calculation. + If the image can not be calculated from former registered results this + method returns None. Therefore, it is just intended to be used as as + step in the complete calculation. INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose image in ``self`` should be computed. The generator - exponents in the braid word are assumed to be 1 or -1 + - ``braid_tietze`` -- tuple representing the Braid whose image in + ``self`` should be computed. The generator exponents in the braid + word are assumed to be 1 or -1 OUTPUT: - A pair (image, basis_factors) where result is an element of ``self`` representing the image of the input if calculation - was possible and None else-wise. If image == None the output basis_factors is given as a list of basis element whose - product equals the input. + A pair (image, basis_factors) where result is an element of ``self`` + representing the image of the input if calculation was possible and + ``None`` else-wise. If ``image == None`` the output basis_factors is + given as a list of basis element whose product equals the input. EXAMPLES:: @@ -2018,82 +2122,80 @@ def _braid_image_from_former_calculations(self, braid_tietze): sage: CHA3._braid_image_from_former_calculations((1, -2, 1, 2)) (c0*c1^-1*c0, ([], [1, -2, 1], [2])) """ + braid_list = list(braid_tietze) + len_braid = len(braid_list) + result = None + n = self.ngens() - n = self.ngens() - braid_list = list(braid_tietze) - len_braid = len(braid_list) - - result = None - - # --------------------------------------------------------------------------------------------------- - # if the braid is in the basis take its image to be the corresponding monomial - # --------------------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # if the braid is in the basis take its image to be the corresponding + # monomial + # ---------------------------------------------------------------------- result = self._tietze_to_finite_sub_basis_monomial(braid_tietze) if result is not None: return result, None - # --------------------------------------------------------------------------------------------------- - # if the braid lies in a subalgebra take its image from there - # --------------------------------------------------------------------------------------------------- - SubAlg = self.cubic_hecke_subalgebra() + # ---------------------------------------------------------------------- + # if the braid lies in a sub-algebra take its image from there. + # ---------------------------------------------------------------------- + sub_alg = self.cubic_hecke_subalgebra() if n not in braid_list and -n not in braid_list: - - result = self(SubAlg(braid_tietze)) - verbose("End (%s): %s in smaller algebra" %(braid_list, result) ) + result = self(sub_alg(braid_tietze)) + verbose('end (%s): %s in smaller algebra' % (braid_list, result), level=2) return result, None - # --------------------------------------------------------------------------------------------------- - # proceed the calculation by splitting self into a product of basis elements and try to simplify - # --------------------------------------------------------------------------------------------------- - braid_group = self.braid_group() - braid = braid_group(braid_tietze) + # ---------------------------------------------------------------------- + # proceed the calculation by splitting self into a product of basis + # elements and try to simplify. + # ---------------------------------------------------------------------- + braid_group = self.braid_group() + braid = braid_group(braid_tietze) result = self._braid_image_from_filecache(braid) - if result != None: - - verbose("End from file cache (%s)" %(list(braid_tietze))) + if result is not None: + verbose('end from file cache (%s)' % (list(braid_tietze)), level=2) return result, None - - # --------------------------------------------------------------------------------------------------- - # If we come here len_braid must be larger than 1 (otherwise we already have found in in the basis) - # By recursion we check if the subwords with one generator removed on the left (respectively on the - # right) side contain a subword whose image has already been calculated. We choose the longest - # such subword as our result - # --------------------------------------------------------------------------------------------------- - braid_list_red_left = [braid_tietze[j] for j in range(1 , len_braid)] - braid_list_red_right = [braid_tietze[j] for j in range(len_braid-1 )] - - result_left, word_decomp_left = self._braid_image_from_former_calculations(tuple(braid_list_red_left)) + # ---------------------------------------------------------------------- + # If we come here len_braid must be larger than 1 (otherwise we already + # have found in in the basis). By recursion we check if the subwords + # with one generator removed on the left (respectively on the right) + # side contain a subword whose image has already been calculated. We + # choose the longest such subword as our result. + # ---------------------------------------------------------------------- + braid_list_red_left = [braid_tietze[j] for j in range(1, len_braid)] + braid_list_red_right = [braid_tietze[j] for j in range(len_braid - 1)] + + result_left, word_decomp_left = self._braid_image_from_former_calculations(tuple(braid_list_red_left)) result_right, word_decomp_right = self._braid_image_from_former_calculations(tuple(braid_list_red_right)) - if word_decomp_left == None: - return result_left, ([braid_tietze[0 ]], braid_list_red_left, []) + if word_decomp_left is None: + return result_left, ([braid_tietze[0]], braid_list_red_left, []) - if word_decomp_right == None: - return result_right, ([], braid_list_red_right, [braid_tietze[len_braid-1 ]]) + if word_decomp_right is None: + return result_right, ([], braid_list_red_right, [braid_tietze[len_braid - 1]]) - word_decomp_left_left, word_decomp_left_result, word_decomp_left_right = word_decomp_left + word_decomp_left_left, word_decomp_left_result, word_decomp_left_right = word_decomp_left word_decomp_right_left, word_decomp_right_result, word_decomp_right_right = word_decomp_right if len(word_decomp_left_result) >= len(word_decomp_right_result): - return result_left, ([braid_tietze[0 ]] + word_decomp_left_left, word_decomp_left_result, word_decomp_left_right) + return result_left, ([braid_tietze[0]] + word_decomp_left_left, word_decomp_left_result, word_decomp_left_right) else: - return result_right, (word_decomp_right_left, word_decomp_right_result, word_decomp_right_right + [braid_tietze[len_braid-1 ]]) - - - + return result_right, (word_decomp_right_left, word_decomp_right_result, word_decomp_right_right + [braid_tietze[len_braid - 1]]) - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _braid_image_by_basis_expansion_ - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- + @cached_method def _braid_image_by_basis_extension(self, braid_tietze): r""" - Return the given braid as a new basis element of ``self`` expanding the incomplete order (which is just a part - of the whole basis) in the case of more than 4 strands. + Return the given braid as a new basis element of ``self`` expanding the + incomplete order (which is just a part of the whole basis) in the case + of more than 4 strands. INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose image in ``self`` should be computed. The generator - exponents in the braid word are assumed to be 1 or -1 + - ``braid_tietze`` -- tuple representing the Braid whose image in + ``self`` should be computed. The generator exponents in the braid + word are assumed to be 1 or -1 OUTPUT: @@ -2101,26 +2203,27 @@ def _braid_image_by_basis_extension(self, braid_tietze): EXAMPLES:: - sage: CHA5 = algebras.CubicHecke(5) - sage: basis_extensions = CHA5.select_filecache_section().basis_extensions - sage: CHA5.reset_filecache(basis_extensions) - sage: CHA5._basis_extension + sage: CHA5 = algebras.CubicHecke(5) # optional - database_cubic_hecke + sage: be = CHA5.select_filecache_section().basis_extensions # optional - database_cubic_hecke + sage: CHA5.reset_filecache(be) # optional - database_cubic_hecke + sage: CHA5._basis_extension # optional - database_cubic_hecke [[4], [-4]] - sage: CHA5._braid_image_by_basis_extension((4,1)) + sage: CHA5._braid_image_by_basis_extension((4,1)) # optional - database_cubic_hecke c3*c0 - sage: CHA5._basis_extension + sage: CHA5._basis_extension # optional - database_cubic_hecke [[4], [-4], [4, 1]] case where the braid already has an corresponding basis element:: - sage: CHA5._braid_image_by_basis_extension((1,)) + sage: CHA5._braid_image_by_basis_extension((1,)) # optional - database_cubic_hecke c0 - sage: CHA5._basis_extension + sage: CHA5._basis_extension # optional - database_cubic_hecke [[4], [-4], [4, 1]] - case where the braid doesn't have corresponding basis element but depends on them:: + case where the braid doesn't have corresponding basis element but depends + on them:: - sage: CHA5._braid_image_by_basis_extension((1,1)) + sage: CHA5._braid_image_by_basis_extension((1,1)) # optional - database_cubic_hecke Traceback (most recent call last): ... NotImplementedError: no algorithm available to calculate braid image of (1, 1) @@ -2130,78 +2233,71 @@ def _braid_image_by_basis_extension(self, braid_tietze): tup = self._cubic_braid_basis_tuple(cubic_braid) if tup is not None: bgrp = self.braid_group() - if bgrp(braid_tietze) != bgrp(tup): - raise NotImplementedError("no algorithm available to calculate braid image of %s" %(str(braid_tietze))) + if bgrp(braid_tietze) != bgrp(tup): + raise NotImplementedError('no algorithm available to calculate braid image of %s' % str(braid_tietze)) B = self.basis() - verbose("braid-image %s in Basis" %(str(braid_tietze))) + verbose('braid-image %s in Basis' % str(braid_tietze), level=2) return self.monomial(B[cubic_braid]) return self._cubic_braid_append_to_basis(cubic_braid) - - - - - - - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _reduce_all_gen_powers - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- + @cached_method def _reduce_all_gen_powers(self, braid_tietze): r""" - Return a linear combination of braids that have no higher powers in the braid generators having the same - image in ``self`` than the given braid. This linear combination is returned as a pair of lists of braids - and corresponding coefficients. + Return a linear combination of braids that have no higher powers in the + braid generators having the same image in ``self`` than the given braid. + This linear combination is returned as a pair of lists of braids and + corresponding coefficients. INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose powers should be reduced given in Tietze form + - ``braid_tietze`` -- tuple representing the Braid whose powers should + be reduced given in Tietze form OUTPUT: - A pair of two lists: ``coeffs``, ``braids``. The fist one contains the coefficients corresponding to the braids - in Tietze form from the second list of braids. + A pair of two lists: ``coeffs``, ``braids``. The fist one contains the + coefficients corresponding to the braids in Tietze form from the second + list of braids. EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: CHA3._reduce_all_gen_powers((1, 1, -2, -2)) - ([(w^-1)*u*v, (-w^-1)*v, (-w^-1)*v^2, (-w^-1)*u^2, (w^-1)*u, (w^-1)*u*v, -u, 1, v], + ([u*v/w, (-v)/w, (-v^2)/w, (-u^2)/w, u/w, u*v/w, -u, 1, v], [(), (2,), (-2,), (1,), (1, 2), (1, -2), (-1,), (-1, 2), (-1, -2)]) """ - - braid_list = list(braid_tietze) len_braid = len(braid_list) - # ------------------------------------------------------------------------------------------------------------ + # ---------------------------------------------------------------------- # find a higher power position in braid_list - # ------------------------------------------------------------------------------------------------------------ - power=0 - pos =0 - for i in range(len_braid-1 ): - if braid_list[i] != braid_list[i+1 ]: + # ---------------------------------------------------------------------- + power = 0 + pos = 0 + for i in range(len_braid - 1): + if braid_list[i] != braid_list[i + 1]: continue pos = i - for power in range(1 ,len_braid -pos+1 ): + for power in range(1, len_braid - pos + 1): if pos+power == len_braid: break if braid_list[pos] != braid_list[pos+power]: break break - if power == 0 : - verbose("End (%s) no powers" %(braid_list)) + if power == 0: + verbose('end (%s) no powers' % braid_list, level=2) return [self.base_ring().one()], [braid_tietze] - # ------------------------------------------------------------------------------------------------------------ - # eliminate this power from braid_tietze - # ------------------------------------------------------------------------------------------------------------ + # ---------------------------------------------------------------------- + # eliminate this power from braid_tietze. + # ---------------------------------------------------------------------- val = braid_list[pos] - if val > 0 : + if val > 0: gen_ind = val exp = power else: @@ -2209,54 +2305,50 @@ def _reduce_all_gen_powers(self, braid_tietze): exp = -power braid_list_start = [braid_list[i] for i in range(pos)] - braid_list_end = [braid_list[i] for i in range(pos+power, len_braid)] - - # ---------------------------------------------------------------------------------------- - # merging the new reduced tuple. Note that all the new tuples are smaller than the - # given one, which will make the recursion terminate - # ---------------------------------------------------------------------------------------- - tuple_one = tuple(braid_list_start + braid_list_end) - tuple_gen = tuple(braid_list_start + [gen_ind] + braid_list_end) + braid_list_end = [braid_list[i] for i in range(pos+power, len_braid)] + + # ---------------------------------------------------------------------- + # merging the new reduced tuple. Note that all the new tuples are + # smaller than the given one, which will make the recursion terminate. + # ---------------------------------------------------------------------- + tuple_one = tuple(braid_list_start + braid_list_end) + tuple_gen = tuple(braid_list_start + [gen_ind] + braid_list_end) tuple_gen_inv = tuple(braid_list_start + [-gen_ind] + braid_list_end) - # ---------------------------------------------------------------------------------------- - # convert them to braids (to reduce cancellation of inverses and obvious braid relations) - # Note that this will not increase the length of the word. Thus the recursion still must - # terminate - # ---------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # convert them to braids (to reduce cancellation of inverses and obvious + # braid relations) Note that this will not increase the length of the + # word. Thus the recursion still must terminate. + # ---------------------------------------------------------------------- braid_group = self.braid_group() - braid_one = braid_group(tuple_one) - braid_gen = braid_group(tuple_gen) + braid_one = braid_group(tuple_one) + braid_gen = braid_group(tuple_gen) braid_gen_inv = braid_group(tuple_gen_inv) - # ------------------------------------------------------------------------------------------------------------ - # eliminate all powers from braid_tietze by recursion. The recursion will terminate by the length - # reduction of the Tietze tuple (but not necessarily by the number of generators whose exponent - # must be reduced) - # ------------------------------------------------------------------------------------------------------------ - one_coeffs, one_braids = self._reduce_all_gen_powers(braid_one.Tietze()) - gen_coeffs, gen_braids = self._reduce_all_gen_powers(braid_gen.Tietze()) + # ---------------------------------------------------------------------- + # eliminate all powers from braid_tietze by recursion. The recursion + # will terminate by the length reduction of the Tietze tuple (but not + # necessarily by the number of generators whose exponent must be reduced). + # ---------------------------------------------------------------------- + one_coeffs, one_braids = self._reduce_all_gen_powers(braid_one.Tietze()) + gen_coeffs, gen_braids = self._reduce_all_gen_powers(braid_gen.Tietze()) gen_inv_coeffs, gen_inv_braids = self._reduce_all_gen_powers(braid_gen_inv.Tietze()) cf_one, cf_gen, cf_gen_inv = self._reduce_gen_power(exp) - one_coeffs = [ cf*cf_one for cf in one_coeffs ] - gen_coeffs = [ cf*cf_gen for cf in gen_coeffs ] - gen_inv_coeffs = [ cf*cf_gen_inv for cf in gen_inv_coeffs ] + one_coeffs = [cf*cf_one for cf in one_coeffs] + gen_coeffs = [cf*cf_gen for cf in gen_coeffs] + gen_inv_coeffs = [cf*cf_gen_inv for cf in gen_inv_coeffs] return one_coeffs + gen_coeffs + gen_inv_coeffs, one_braids + gen_braids + gen_inv_braids - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _reduce_gen_power - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- @cached_method def _reduce_gen_power(self, k): r""" - Return the k-th power on an arbitrary generator, for example c0^k. - + Return the ``k``-th power on an arbitrary generator, for example ``c0^k` . INPUT: @@ -2264,102 +2356,99 @@ def _reduce_gen_power(self, k): OUTPUT: - A list [coeff_one, coeff_gen, coeff_gen_inverse] of the three coefficients of the generators power in the span of the generator. + A list [coeff_one, coeff_gen, coeff_gen_inverse] of the three + coefficients of the generators power in the span of the generator. EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2) sage: CHA2._reduce_gen_power(5) - (-u^3*v + 2*u*v^2 + w*u^2 + (-2*w)*v, u^4 + (-3)*u^2*v - + v^2 + 2*w*u, w*u^3 + (-2*w)*u*v + w^2) + (-u^3*v + 2*u*v^2 + u^2*w - 2*v*w, u^4 - 3*u^2*v + + v^2 + 2*u*w, u^3*w - 2*u*v*w + w^2) """ - - n = self.ngens() - # --------------------------------------------------------------------------------------- - # take it from smaller subalgebras if possible - # --------------------------------------------------------------------------------------- - if n > 1 : - - SubAlg = self.cubic_hecke_subalgebra() - return SubAlg._reduce_gen_power(k) - - - # --------------------------------------------------------------------------------------- - # calculate it in the subalgebra on 2 strands - # --------------------------------------------------------------------------------------- + # ---------------------------------------------------------------------- + # take it from smaller sub-algebras if possible + # ---------------------------------------------------------------------- + if n > 1: + sub_alg = self.cubic_hecke_subalgebra() + return sub_alg._reduce_gen_power(k) - if k == 0 : + # ---------------------------------------------------------------------- + # calculate it in the sub-algebra on 2 strands + # ---------------------------------------------------------------------- + if k == 0: result_ele = self.one() result = result_ele.to_vector() - elif abs(k) == 1 : - + elif abs(k) == 1: result_ele = self._tietze_to_finite_sub_basis_monomial(tuple([k])) result = result_ele.to_vector() else: - - if k < 0 : - right_vect = self._reduce_gen_power(k+1) - genTietze = (-1 ,) + if k < 0: + right_vect = self._reduce_gen_power(k + 1) + genTietze = (-1,) else: - right_vect = self._reduce_gen_power(k-1) - genTietze = (1 ,) - + right_vect = self._reduce_gen_power(k - 1) + genTietze = (1,) result = self._mult_by_regular_rep(right_vect, genTietze, RepresentationType.RegularLeft) - return result - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _mult_by_regular_rep - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- + @cached_method def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preimage=None): r""" - Return the product of an`element of ``self`` given as a coefficient vector with a sequence (tuple) of generators - (that is a braid word) using regular representation matrices. The multiplication will be performed form left or - right according to the given ``representation_type``. + Return the product of an`element of ``self`` given as a coefficient + vector with a sequence (tuple) of generators (that is a braid word) + using regular representation matrices. The multiplication will be + performed form left or right according to the given + ``representation_type``. INPUT: - - ``vect`` -- element of ``self`` in vector form (obtained by :meth:`to_vector`) - - ``gen_tuple`` -- list of generators (that is a braid in Tietze form) which operates on ``vect`` - - ``representation_type`` -- instance of :class:`RepresentationType` (one of `RegularLeft` or `RegularRight`) - - ``braid_preimage`` -- (optional) a word representing a braid whose image is vect (if it exist). - This is used to record intermediate results to the dynamic library - + - ``vect`` -- element of ``self`` in vector form (obtained by + :meth:`to_vector`) + - ``gen_tuple`` -- list of generators (that is a braid in Tietze form) + which operates on ``vect`` + - ``representation_type`` -- instance of :class:`RepresentationType` + (one of `RegularLeft` or `RegularRight`) + - ``braid_preimage`` -- (optional) a word representing a braid whose + image is vect (if it exist). This is used to record intermediate + results to the dynamic library OUTPUT: - The coefficient vector resulting after applying the multiplication of all matrices corresponding to the - generators from gen_tuple. + The coefficient vector resulting after applying the multiplication of all + matrices corresponding to the generators from gen_tuple. EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: CHA3.inject_variables() Defining c0, c1 - sage: CHA3._mult_by_regular_rep(c0.to_vector(), (1, -2, -2), CHA3.repr_type.RegularRight) - ((w^-1)*u*v, (-w^-1)*u^2, -u, (-w^-1)*v, (-w^-1)*v^2, (w^-1)*u, (w^-1)*u*v, 1, v, + sage: repr_type = CHA3.repr_type.RegularRight + sage: CHA3._mult_by_regular_rep(c0.to_vector(), (1, -2, -2), repr_type) + (u*v/w, (-u^2)/w, -u, (-v)/w, (-v^2)/w, u/w, u*v/w, 1, v, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) """ - verbose("Multiply %s (preimage %s) by %s using %s" %(vect, braid_preimage, gen_tuple, representation_type)) - l = len(gen_tuple) + verbose('multiply %s (pre-image %s) by %s using %s' + % (vect, braid_preimage, gen_tuple, representation_type), level=2) + m = len(gen_tuple) braid_list = None if braid_preimage: braid_list = list(braid_preimage) result = vect - for i in range(l): - verbose("Multiply image of %s with position %s" %(braid_list, i)) + for i in range(m): + verbose('multiply image of %s with position %s' % (braid_list, i), level=2) if representation_type == RepresentationType.RegularLeft: - gen_ind = gen_tuple[l-i-1 ] + gen_ind = gen_tuple[m - i - 1] if braid_list: braid_list = [gen_ind] + braid_list else: @@ -2370,41 +2459,42 @@ def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preim if (gen_ind, representation_type) in list(self._gens_reg_repres_matrix.keys()): mat = self._gens_reg_repres_matrix[(gen_ind, representation_type)] else: - if gen_ind > 0 : - gen = self.gen(gen_ind-1 ) + if gen_ind > 0: + gen = self.gen(gen_ind - 1) mat = gen.matrix(representation_type=representation_type) else: # data of inverse of generators is stored under negative strand-index - gen = self.gen(-gen_ind-1 )**(-1 ) + gen = self.gen(-gen_ind - 1)**(-1) mat = gen.matrix(representation_type=representation_type) self._gens_reg_repres_matrix[(gen_ind, representation_type)] = mat result = mat * result - # ---------------------------------------------------------------------------------- + # ------------------------------------------------------------------ # save this intermediate result to the dynamic library - # ---------------------------------------------------------------------------------- + # ------------------------------------------------------------------ if braid_list: - verbose("Save image of %s to file cache" %braid_list) + verbose('save image of %s to file cache' % braid_list, level=2) self._braid_image_to_filecache(tuple(braid_list), result) - verbose("Multiply %s by %s using %s result %s" %(vect, gen_tuple, representation_type, result)) + verbose('multiply %s by %s using %s result %s' % (vect, gen_tuple, representation_type, result), level=2) return result - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _cubic_braid_append_to_basis - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _cubic_braid_append_to_basis(self, cubic_braid): r""" - Append the given cubic braid to the finite sub basis which is used for calculation of products - and representation matrices. This only makes sense if the ``cubic_braid`` is not in this - finite sub basis, before. This can happen if the number of strands is more than 4. + Append the given cubic braid to the finite sub basis which is used for + calculation of products and representation matrices. This only makes + sense if the ``cubic_braid`` is not in this finite sub basis, before. + This can happen if the number of strands is more than 4. INPUT: - - ``cubic_braid`` -- instance of the :class:`~sage.groups.cubic_braid.CubicBraid` whose image in ``self`` should be appended + - ``cubic_braid`` -- instance of the :class:`~sage.groups.cubic_braid.CubicBraid` + whose image in ``self`` should be appended OUTPUT: @@ -2412,15 +2502,15 @@ def _cubic_braid_append_to_basis(self, cubic_braid): EXAMPLES:: - sage: CHA5 = algebras.CubicHecke(5) - sage: basis_extensions = CHA5.select_filecache_section().basis_extensions - sage: CHA5.reset_filecache(basis_extensions) - sage: CHA5._basis_extension + sage: CHA5 = algebras.CubicHecke(5) # optional - database_cubic_hecke + sage: be = CHA5.select_filecache_section().basis_extensions # optional - database_cubic_hecke + sage: CHA5.reset_filecache(be) # optional - database_cubic_hecke + sage: CHA5._basis_extension # optional - database_cubic_hecke [[4], [-4]] - sage: CBG = CHA5.cubic_braid_group() - sage: CHA5._cubic_braid_append_to_basis(CBG((4,1))) + sage: CBG = CHA5.cubic_braid_group() # optional - database_cubic_hecke + sage: CHA5._cubic_braid_append_to_basis(CBG((4,1))) # optional - database_cubic_hecke c3*c0 - sage: CHA5._basis_extension + sage: CHA5._basis_extension # optional - database_cubic_hecke [[4], [-4], [4, 1]] """ @@ -2428,25 +2518,25 @@ def _cubic_braid_append_to_basis(self, cubic_braid): order = self.get_order() next_index = len(order) self._basis_extension.append(cbTietze) - self._rank_basis.update({cubic_braid:next_index}) # supporting :meth:`get_order_key` + self._rank_basis.update({cubic_braid: next_index}) # supporting :meth:`get_order_key` order.append(cubic_braid) monomial = self.monomial(cubic_braid) - self._finite_sub_basis_tuples.update({cubic_braid:cbTietze}) + self._finite_sub_basis_tuples.update({cubic_braid: cbTietze}) - verbose("Registering new basis element: %s (par %s ind %s)" %(cubic_braid, cubic_braid.parent(), next_index)) + verbose('registering new basis element: %s (par %s ind %s)' + % (cubic_braid, cubic_braid.parent(), next_index), level=2) self._filecache.update_basis_extensions(self._basis_extension) return monomial - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _cubic_braid_basis_tuple - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _cubic_braid_basis_tuple(self, cubic_braid): r""" - Return the Tietze tuple that represents the given cubic_braid in the basis of ``self``. In the case ``self`` - has more than 4 strands it may happen that the given cubic braid is not contained in the finite sub basis, so far. - In this case it is automatically added to it. + Return the Tietze tuple that represents the given cubic_braid in the + basis of ``self``. In the case ``self`` has more than 4 strands it may + happen that the given cubic braid is not contained in the finite sub + basis, so far. In this case it is automatically added to it. INPUT: @@ -2460,42 +2550,45 @@ def _cubic_braid_basis_tuple(self, cubic_braid): sage: CHA2 = algebras.CubicHecke(2) sage: CBG = CHA2.cubic_braid_group() - sage: CHA2._cubic_braid_basis_tuple(CBG((1,1))) + sage: CHA2._cubic_braid_basis_tuple(CBG((1, 1))) (-1,) """ tietze_list = self._basis_tietze() cubic_braid_tietze = cubic_braid.Tietze() if list(cubic_braid_tietze) in tietze_list: - verbose("cubic_braid_tietze: %s in basis" %(str(cubic_braid_tietze))) + verbose('cubic_braid_tietze: %s in basis' % str(cubic_braid_tietze), level=2) return cubic_braid_tietze else: if cubic_braid in self._finite_sub_basis_tuples.keys(): - verbose("cubic_braid: %s in finite_sub_basis" %(cubic_braid)) + verbose('cubic_braid: %s in finite_sub_basis' % cubic_braid, level=2) return self._finite_sub_basis_tuples[cubic_braid] for tup in tietze_list: cb_tup = self.cubic_braid_group()(tup) if cubic_braid == cb_tup: - self._finite_sub_basis_tuples.update({cb_tup:tup}) - verbose("cubic_braid: %s added to finite_sub_basis with tuple %s" %(cubic_braid, tup)) + self._finite_sub_basis_tuples.update({cb_tup: tup}) + verbose('cubic_braid: %s added to finite_sub_basis with tuple %s' + % (cubic_braid, tup), level=2) return tuple(tup) return None - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _cubic_braid_image - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _cubic_braid_image(self, cubic_braid, check=True): r""" - Return the given cubic braid as monomial of ``self``, that is the image under the map onto the basis. - If the number of strands is larger than 4, the corresponding basis element may not be - contained in the order of ``self``. In this case it will be appended here. + Return the given cubic braid as monomial of ``self``, that is the image + under the map onto the basis. If the number of strands is larger than 4, + the corresponding basis element may not be contained in the order of + ``self``. In this case it will be appended here. INPUT: - - ``cubic_braid`` -- instance of :class:`~sage.groups.cubic_braid.CubicBraid` whose image in ``self`` should be returned - - ``check`` -- (optional) boolean (default=True) to check in the given cubic braid is already - registered in the finite sub basis. If set to ``False`` duplicate entries can occur. + - ``cubic_braid`` -- instance of :class:`~sage.groups.cubic_braid.CubicBraid` + whose image in ``self`` should be returned + - ``check`` -- (optional) boolean (default=True) to check in the given + cubic braid is already registered in the finite sub basis. If set to + ``False`` duplicate entries can occur. OUTPUT: @@ -2512,28 +2605,27 @@ def _cubic_braid_image(self, cubic_braid, check=True): tup = self._cubic_braid_basis_tuple(cubic_braid) if tup is not None: return self._tietze_to_finite_sub_basis_monomial(tup) - return self._cubic_braid_append_to_basis(cubic_braid) - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # _extend_braid_automorphism - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def _extend_braid_automorphism(self, element, braid_automorphism): r""" - Return the image of element under the extension of the given braid group automorphism to ``self``. It is assumed - that the given ``braid_automorphism`` factors through ``self``. + Return the image of element under the extension of the given braid group + automorphism to ``self``. It is assumed that the given + ``braid_automorphism`` factors through ``self``. INPUT: - ``element`` -- instance of the element class of ``self`` - - ``braid_autompophism`` -- braid group automophism factoring through ``self`` + - ``braid_automorphism`` -- braid group automorphism factoring through + ``self`` OUTPUT: - Instance of the element class of ``self`` representing the image of element under the extension of the given braid - group automorphism. + Instance of the element class of ``self`` representing the image of element + under the extension of the given braid group automorphism. EXAMPLES:: @@ -2551,19 +2643,98 @@ def _extend_braid_automorphism(self, element, braid_automorphism): return result + # -------------------------------------------------------------------------- + # _markov_trace_module + # -------------------------------------------------------------------------- + def _markov_trace_module(self, extended=False, field_embedding=False): + r""" + Return the module that contains the formal Markov trace as elements. + + INPUT: + - ``extended`` -- boolean (optional default ``False``) if set to ``True`` + the base ring of the module is the Markov trace version of the + generic extension ring of ``self``. + - ``field_embedding`` -- boolean (optional default ``False``) if set to + ``True` the base ring of the module is the smallest field containing + the generic extension ring of ``self``. The keyword is meaningless + if ``extended=False``. - ####################################################################################################################### - # --------------------------------------------------------------------------------------------------------------------- - # public methods - # --------------------------------------------------------------------------------------------------------------------- + OUTPUT: + + An instance of :class:`~sage.combinat.free_module.CombinatorialFreeModule`. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._markov_trace_module() + Free module generated by {U1, U2} + over Multivariate Polynomial Ring in u, v, w, s + over Integer Ring localized at (s, w, v, u) + + sage: CHA2._markov_trace_module(extended=True) + Free module generated by {U1, U2} + over Multivariate Laurent Polynomial Ring in a, b, c, s + over Splitting Algebra of x^2 + x + 1 with roots [e3, -e3 - 1] + over Integer Ring + + sage: CHA2._markov_trace_module(extended=True, field_embedding=True) + Free module generated by {U1, U2} + over Fraction Field of Multivariate Polynomial Ring in a, b, c, s + over Cyclotomic Field of order 3 and degree 2 + """ + from sage.modules.free_module import FreeModule + from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + basis = [b for b in MarkovTraceModuleBasis if b.strands() <= self.strands()] + BRM = self.base_ring(generic=True).markov_trace_version() + if extended: + BRM = BRM.extension_ring() + if field_embedding: + emb = BRM.field_embedding() + BRM = emb.codomain() + return FreeModule(BRM, basis) + + # -------------------------------------------------------------------------- + # _markov_trace_coeffs + # -------------------------------------------------------------------------- + @cached_method + def _markov_trace_coeffs(self): + r""" + Return a list of formal Markov traces of the basis elements of ``self``. - ####################################################################################################################### + OUTPUT: + A list of elements of the Markov trace module (over the Markov trace + version of the generic base ring). Each entry of the list corresponds + to the according basis element of ``self``. + + EXAMPLES:: + + sage: CHA2 = algebras.CubicHecke(2) + sage: CHA2._markov_trace_coeffs() + [B[U2], s*B[U1], 1/s*B[U1]] + sage: M = _[0].parent(); M + Free module generated by {U1, U2} + over Multivariate Polynomial Ring in u, v, w, s + over Integer Ring localized at (s, w, v, u) + """ + M = self._markov_trace_module() + Mbas = M.basis().keys() + db = self._database + sec = db.section.markov_tr_cfs + cfs = db.read(sec, variables=M.base_ring().gens(), nstrands=self.strands()) + d = self.dimension() + return [sum(cfs[bas_ele][i]*M(bas_ele) for bas_ele in Mbas) for i in range(d)] + + ############################################################################ + # -------------------------------------------------------------------------- + # public methods + # -------------------------------------------------------------------------- + ############################################################################ def select_filecache_section(self): r""" - Return the enum to select a section in the file cache. + Return the ``enum`` to select a section in the file cache. EXAMPLES:: @@ -2571,19 +2742,22 @@ def select_filecache_section(self): sage: list(CHA2.select_filecache_section()) [, , - ] + , + ] """ return self._filecache.section def is_filecache_empty(self, section=None): r""" - Return ``True`` if the file cache of the given ``section`` is empty. If no ``section`` is given - the answer is given for complete file cache. + Return ``True`` if the file cache of the given ``section`` is empty. + If no ``section`` is given the answer is given for the complete + file cache. INPUT: - - ``section`` -- (optional, default is ``None`` meaning all sections) instance of enum - :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` which can be selected using :meth:`select_filecache_section` + - ``section`` -- (optional, default is ``None`` meaning all sections) + instance of enum :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` + which can be selected using :meth:`select_filecache_section` EXAMPLES:: @@ -2595,62 +2769,64 @@ def is_filecache_empty(self, section=None): def reset_filecache(self, section=None, commit=True): r""" - Reset the file cache of the given ``section`` resp. the complete file cache if no ``section`` is given. + Reset the file cache of the given ``section`` resp. the complete + file cache if no ``section`` is given. INPUT: - - ``section`` -- (optional, default is ``None`` meaning all sections) instance of enum - :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` which can be selected using :meth:`select_filecache_section` - - - ``commit`` -- boolean (optional, default is ``True``) if set to ``False`` the reset is not written - to the filesystem. + - ``section`` -- (optional, default is ``None`` meaning all sections) + instance of enum :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` + which can be selected using :meth:`select_filecache_section` + - ``commit`` -- boolean (optional, default is ``True``) if set to ``False`` the reset + is not written to the filesystem EXAMPLES:: - sage: CHA5 = algebras.CubicHecke(5) - sage: basis_extensions = CHA5.select_filecache_section().basis_extensions - sage: CHA5.is_filecache_empty(basis_extensions) + sage: CHA5 = algebras.CubicHecke(5) # optional - database_cubic_hecke + sage: be = CHA5.select_filecache_section().basis_extensions # optional - database_cubic_hecke + sage: CHA5.is_filecache_empty(be) # optional - database_cubic_hecke False - sage: CHA5.reset_filecache(basis_extensions) - sage: CHA5.is_filecache_empty(basis_extensions) + sage: CHA5.reset_filecache(be) # optional - database_cubic_hecke + sage: CHA5.is_filecache_empty(be) # optional - database_cubic_hecke True """ fc = self._filecache if section == fc.section.basis_extensions: if self.strands() < 5: raise ValueError('not allowed for less than 5 strand') - fc.reset_library(section=section) if section == fc.section.basis_extensions: self._init_basis_extension() - if commit: - fc.write(section=section) + fc.write(section=section) def strands(self): r""" - Return the number of strands of the braid group whose group algebra image is ``self`` + Return the number of strands of the braid group whose group algebra + image is ``self``. OUTPUT: Integer. EXAMPLES:: - sage: CHA4 = algebras.CubicHecke(4) - sage: CHA4.strands() + sage: CHA4 = algebras.CubicHecke(4) # optional - database_cubic_hecke + sage: CHA4.strands() # optional - database_cubic_hecke 4 """ return self._nstrands - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # Garside involution - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def garside_involution(self, element): r""" - Return the image of the given element of ``self`` under the extension of the Garside involution of braids to ``self``. + Return the image of the given element of ``self`` under the extension of + the Garside involution of braids to ``self``. - This method may be invoked by the ``revert_garside`` method of the element class of ``self``, alternatively. + This method may be invoked by the ``revert_garside`` method of the + element class of ``self``, alternatively. INPUT: @@ -2658,39 +2834,36 @@ def garside_involution(self, element): OUTPUT: - Instance of the element class of ``self`` representing the image of ``element`` under the extension of the Garside - involution to ``self``. + Instance of the element class of ``self`` representing the image of + ``element`` under the extension of the Garside involution to ``self``. EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: ele = CHA3.an_element() sage: ele_gar = CHA3.garside_involution(ele); ele_gar - ((w^-1)*u-v) + v*c1 + u*c0 + (-w)*c1*c0^-1 + (-w)*c1*c0^-1 + u*c0 + v*c1 + ((-v*w+u)/w) sage: ele == CHA3.garside_involution(ele_gar) True """ - braid_group = self.braid_group() - reverse_gens = [ g for g in braid_group.gens()] + reverse_gens = [g for g in braid_group.gens()] reverse_gens.reverse() brgrp_garside_involution = braid_group.hom(reverse_gens, check=False) - return self._extend_braid_automorphism(element, brgrp_garside_involution) - - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # orientation anti involution - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def orientation_antiinvolution(self, element): r""" - Return the image of the given element of ``self`` under the extension of the orientation anti involution of braids to ``self``. - The orientation anti involution of a braid is given by reversing the order of generators in the braid word. + Return the image of the given element of ``self`` under the extension of + the orientation anti involution of braids to ``self``. The orientation + anti involution of a braid is given by reversing the order of generators + in the braid word. - This method may be invoked by the ``revert_orientation`` method of the element class of ``self``, alternatively. + This method may be invoked by the ``revert_orientation`` method of the + element class of ``self``, alternatively. INPUT: @@ -2698,43 +2871,46 @@ def orientation_antiinvolution(self, element): OUTPUT: - Instance of the element class of ``self`` representing the image of ``element`` under the extension of the orientation - reversing braid involution to ``self``. + Instance of the element class of ``self`` representing the image of + ``element`` under the extension of the orientation reversing braid + involution to ``self``. EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: ele = CHA3.an_element() sage: ele_ori = CHA3.orientation_antiinvolution(ele); ele_ori - ((w^-1)*u-v) + u*c1 + v*c0 + (-w)*c1^-1*c0 + (-w)*c1^-1*c0 + v*c0 + u*c1 + ((-v*w+u)/w) sage: ele == CHA3.orientation_antiinvolution(ele_ori) True """ - braid_group = self.braid_group() + def brgrp_orientation_antiinvolution(braid): - braid_list = list(braid.Tietze()) + braid_list = list(braid.Tietze()) braid_list.reverse() return braid_group(tuple(braid_list)) - return self._extend_braid_automorphism(element, brgrp_orientation_antiinvolution) - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # mirror isomorphism - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def mirror_isomorphism(self, element): r""" - Return the image of the given element of ``self`` under the extension of the mirror involution of braids to ``self``. - The mirror involution of a braid is given by inverting all generators in the braid word. It does not - factor through ``self`` over the base ring but it factors through ``self`` considered as a $\ZZ$-module relative to the - mirror automorphism of the generic base ring. Considering ``self`` as algebra over its base ring this involution - defines an isomorphism of ``self`` onto a different cubic Hecke algebra with a different cubic equation. This - is defined over a different base (and extension) ring than ``self``. It can be obtained by the method ``mirror_image`` - or as parent of the output of this method. - - This method may be invoked by the ``CubicHeckeElelemnt.revert_mirror`` method of the element class of ``self``, alternatively. + Return the image of the given element of ``self`` under the extension + of the mirror involution of braids to ``self``. The mirror involution + of a braid is given by inverting all generators in the braid word. It + does not factor through ``self`` over the base ring but it factors + through ``self`` considered as a $\ZZ$-module relative to the mirror + automorphism of the generic base ring. Considering ``self`` as algebra + over its base ring this involution defines an isomorphism of ``self`` + onto a different cubic Hecke algebra with a different cubic equation. + This is defined over a different base (and extension) ring than + ``self``. It can be obtained by the method ``mirror_image`` or as + parent of the output of this method. + + This method may be invoked by the ``CubicHeckeElelemnt.revert_mirror`` + method of the element class of ``self``, alternatively. INPUT: @@ -2742,15 +2918,16 @@ def mirror_isomorphism(self, element): OUTPUT: - Instance of the element class of the mirror image of ``self`` representing the image of element under the extension of - the braid mirror involution to ``self``. + Instance of the element class of the mirror image of ``self`` + representing the image of element under the extension of the braid + mirror involution to ``self``. EXAMPLES:: sage: CHA3 = algebras.CubicHecke(3) sage: ele = CHA3.an_element() sage: ele_mirr = CHA3.mirror_isomorphism(ele); ele_mirr - ((-w^-1)*u+v) + ((w^-1)*v)*c1^-1 + ((w^-1)*u)*c0^-1 + (-w^-1)*c0^-1*c1 + -1/w*c0^-1*c1 + u/w*c0^-1 + v/w*c1^-1 + ((v*w-u)/w) sage: ele_mirr2 = ele.revert_mirror() # indirect doctest sage: ele_mirr == ele_mirr2 True @@ -2762,35 +2939,37 @@ def mirror_isomorphism(self, element): sage: ele == par_mirr.mirror_isomorphism(ele_mirr) True """ - mirror_image = self.mirror_image() - braid_group = self.braid_group() + braid_group = self.braid_group() mirror_involution = braid_group.hom([~g for g in braid_group.gens()], check=False) # Todo: have mirror_involution be a method of :class:`BraidGroup_class` base_ring_mirror = self._base_ring_mirror - element_vec = vector( [base_ring_mirror(cf) for cf in list(element.to_vector())]) + element_vec = vector([base_ring_mirror(cf) for cf in list(element.to_vector())]) element_mirr = mirror_image.from_vector(element_vec) return mirror_image._extend_braid_automorphism(element_mirr, mirror_involution) - - - + # -------------------------------------------------------------------------- + # cubic_equation + # -------------------------------------------------------------------------- def cubic_equation(self, var='h', as_coefficients=False, generic=False): r""" Return the cubic equation attached to ``self``. INPUT: - - ``var`` -- string (optional, default ``h``) setting the indeterminate of the equation - - ``as_coefficients`` -- boolean (optional, default ``False``) if set to ``True`` the + - ``var`` -- string (optional, default ``h``) setting the indeterminate + of the equation + - ``as_coefficients`` -- boolean (optional, default ``False``) if set + to ``True`` the list of coefficients is returned - - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the cubic - equation will be given over the generic base ring + - ``generic`` -- boolean (optional, default ``False``) if set to + ``True`` the cubic equation will be given over the generic base ring OUTPUT: - A polynomial over the base ring (resp. generic base ring if ``generic`` is set to True). - In case ``as_coefficients`` is set to ``True`` a list of them is returned. + A polynomial over the base ring (resp. generic base ring if ``generic`` + is set to True). In case ``as_coefficients`` is set to ``True`` a list + of them is returned. EXAMPLES:: @@ -2804,38 +2983,34 @@ def cubic_equation(self, var='h', as_coefficients=False, generic=False): sage: CHA2.cubic_equation(as_coefficients=True) [-1, 0, 0, 1] """ - BaseRing = self.base_ring(generic=generic) - - if generic == True: - u, v, w = BaseRing.gens_over_ground() + if generic: + u, v, w = BaseRing.gens() else: u, v, w = self._cubic_equation_parameters - - cf = [-w, v, -u, 1 ] - - if as_coefficients == True: + cf = [-w, v, -u, 1] + if as_coefficients: return cf - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing P = PolynomialRing(BaseRing, var) return P(cf) - - - + # -------------------------------------------------------------------------- + # cubic_equation_roots + # -------------------------------------------------------------------------- def cubic_equation_roots(self, generic=False): r""" Return the roots of the underlying cubic equation. INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the roots - are returned as elements of the generic extension ring + - ``generic`` -- boolean (optional, default ``False``) if set to + ``True`` the roots are returned as elements of the generic + extension ring OUTPUT: - A tripple consisting of the roots. + A triple consisting of the roots. EXAMPLES:: @@ -2847,19 +3022,23 @@ def cubic_equation_roots(self, generic=False): sage: CHA2.cubic_equation_roots(generic=True) [a, b, c] """ - if generic == True: + if generic: return self._generic_cubic_equation_roots else: return self._cubic_equation_roots + # -------------------------------------------------------------------------- + # cubic_equation_roots + # -------------------------------------------------------------------------- def cubic_equation_parameters(self, generic=False): r""" Return the coefficients of the underlying cubic equation. INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the coefficients - are returned as elements of the generic base ring + - ``generic`` -- boolean (optional, default ``False``) if set to + ``True`` the coefficients are returned as elements of the generic + base ring OUTPUT: @@ -2875,24 +3054,28 @@ def cubic_equation_parameters(self, generic=False): sage: CHA2.cubic_equation_parameters(generic=True) [u, v, w] """ - if generic == True: + if generic: return self._generic_cubic_equation_parameters else: return self._cubic_equation_parameters + # -------------------------------------------------------------------------- + # base_ring + # -------------------------------------------------------------------------- def base_ring(self, generic=False): r""" Return the base ring of the cubic Hecke algebra. INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the - ring of definition (here often called the generic base ring) is returned + - ``generic`` -- boolean (optional, default ``False``) if set to + ``True`` the ring of definition (here often called the generic base + ring) is returned OUTPUT: - An instance of :class:`Ring`. If ``generic`` is set ``True`` this will be an - instance of :class:`CubicHeckeRingOfDefinition`, as well. + An instance of :class:`Ring`. If ``generic`` is set ``True`` this will + be an instance of :class:`CubicHeckeRingOfDefinition`, as well. EXAMMPLES:: @@ -2900,30 +3083,32 @@ def base_ring(self, generic=False): sage: CHA2.base_ring() Integer Ring localized at (2, 3, 5) sage: CHA2.base_ring(generic=True) - Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring + Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) """ - if generic == True: + if generic: return self._ring_of_definition else: return self._base_ring - + # -------------------------------------------------------------------------- + # extension_ring + # -------------------------------------------------------------------------- def extension_ring(self, generic=False): r""" - Return the extension ring of the cubic Hecke algebra. This is an extension - of its base ring containing the roots of the cubic equation. + Return the extension ring of the cubic Hecke algebra. This is an + extension of its base ring containing the roots of the cubic equation. INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the - extension ring of definition (here often called the generic extension ring) - is returned + - ``generic`` -- boolean (optional, default ``False``) if set to + ``True`` the extension ring of definition (here often called the + generic extension ring) is returned OUTPUT: - An instance of :class:`Ring`. If ``generic`` is set ``True`` this will be an - instance of :class:`CubicHeckeExtensionRing`, as well. + An instance of :class:`Ring`. If ``generic`` is set ``True`` this will + be an instance of :class:`CubicHeckeExtensionRing`, as well. EXAMMPLES:: @@ -2936,24 +3121,32 @@ def extension_ring(self, generic=False): over Splitting Algebra of x^2 + x + 1 with roots [e3, -e3 - 1] over Integer Ring """ - if generic == True: + if generic: return self._generic_extension_ring else: return self._extension_ring - + # -------------------------------------------------------------------------- + # cyclotomic_generator + # -------------------------------------------------------------------------- def cyclotomic_generator(self, generic=False): r""" - Return the third root of unity as element of the extension ring. + Return the third root of unity as element of the extension ring. The + only thing where this is needed is in the nine dimensional irreducible + representations of the cubic Hecke algebra on four strands (see the + examples of :meth:`CubicHeckeElement.matrix` for instance). + INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to ``True`` the - cyclotomic_generator is returned as an element extension ring of definition. + - ``generic`` -- boolean (optional, default ``False``) if set to + ``True`` the cyclotomic_generator is returned as an element extension + ring of definition. OUTPUT: - An element with parent :class:`Ring`. If ``generic`` is set ``True`` the parent will be an - instance of :class:`CubicHeckeExtensionRing`, as well. + An element with parent :class:`Ring`. If ``generic`` is set ``True`` + the parent will be an instance of :class:`CubicHeckeExtensionRing`, + as well. EXAMMPLES:: @@ -2964,15 +3157,14 @@ def cyclotomic_generator(self, generic=False): e3 """ e3gen = self.extension_ring(generic=True).cyclotomic_generator() - if generic == True: + if generic: return e3gen else: return self._generic_extension_ring_map(e3gen) - - - - + # -------------------------------------------------------------------------- + # braid_group + # -------------------------------------------------------------------------- def braid_group(self): r""" Return the braid group attached to ``self``. @@ -2985,7 +3177,9 @@ def braid_group(self): """ return self._braid_group - + # -------------------------------------------------------------------------- + # cubic_braid_group + # -------------------------------------------------------------------------- def cubic_braid_group(self): r""" Return the cubic braid group attached to ``self``. @@ -2998,55 +3192,59 @@ def cubic_braid_group(self): """ return self._cubic_braid_group - + # -------------------------------------------------------------------------- + # braid_group_algebra + # -------------------------------------------------------------------------- def braid_group_algebra(self): r""" - Return the group algebra of braid group attached to ``self`` over the base ring of ``self``. + Return the group algebra of braid group attached to ``self`` over the + base ring of ``self``. EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2) sage: CHA2.braid_group_algebra() Algebra of Braid group on 2 strands - over Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring + over Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) """ return self._braid_group_algebra - + # -------------------------------------------------------------------------- + # cubic_braid_group_algebra + # -------------------------------------------------------------------------- def cubic_braid_group_algebra(self): r""" - Return the group algebra of cubic braid group attached to ``self`` over the base ring of ``self``. + Return the group algebra of cubic braid group attached to ``self`` over + the base ring of ``self``. EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2) sage: CHA2.cubic_braid_group_algebra() Algebra of Cubic Braid group on 2 strands - over Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w over Integer Ring + over Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) """ return self._cubic_braid_group_algebra - - - - # ---------------------------------------------------------------------------------- - # creating a CubicHeckeAlgebra as subalgebra of self on less strands - # ---------------------------------------------------------------------------------- - def cubic_hecke_subalgebra( self, nstrands = None): + # -------------------------------------------------------------------------- + # creating a CubicHeckeAlgebra as sub-algebra of self on less strands + # -------------------------------------------------------------------------- + def cubic_hecke_subalgebra(self, nstrands=None): r""" - Return an instance of :class:`CubicHeckeAlgebra` which realizes a subalgebra of ``self`` on the - first ``n_strands`` strands. + Return an instance of :class:`CubicHeckeAlgebra` which realizes a + sub-algebra of ``self`` on the first ``n_strands`` strands. INPUT: - - ``nstrands`` -- integer ``> 0`` and `` < self.strands()`` giving the number of strands for the subgroup. - The default is one strand less than ``self`` has + - ``nstrands`` -- integer ``> 0`` and `` < self.strands()`` giving + the number of strands for the subgroup. The default is one strand + less than ``self`` has OUTPUT: - An instance of this class realizing the subalgebra. + An instance of this class realizing the sub-algebra. EXAMPLES:: @@ -3056,53 +3254,48 @@ def cubic_hecke_subalgebra( self, nstrands = None): over Integer Ring localized at (2, 3, 5) with cubic equation: h^3 - 12*h^2 + 47*h - 60 = 0 """ - - if nstrands == None: - nstrands = self.strands() -1 - + if nstrands is None: + nstrands = self.strands() - 1 n = self.strands() - nstrands = ZZ(nstrands) - if nstrands >= n or nstrands <= 0 : - raise ValueError( "nstrands must be positive and less than %s" %(self.strands()) ) - - + if nstrands >= n or nstrands <= 0: + raise ValueError('nstrands must be positive and less than %s' % self.strands()) Gens = self.gens() - - if nstrands == self.strands() -1 and self._cubic_hecke_subalgebra != None: + if nstrands == self.strands() - 1 and self._cubic_hecke_subalgebra is not None: return self._cubic_hecke_subalgebra - gen_range = range(nstrands -1 ) - + gen_range = range(nstrands - 1) GensRed = tuple([Gens[i] for i in gen_range]) + if self.base_ring() == self.base_ring(generic=True): + SubHeckeAlg = CubicHeckeAlgebra(names=GensRed) + else: + SubHeckeAlg = CubicHeckeAlgebra(names=GensRed, + cubic_equation_parameters=tuple(self._cubic_equation_parameters), + cubic_equation_roots=tuple(self._cubic_equation_roots)) - SubHeckeAlg = CubicHeckeAlgebra(names=GensRed, cubic_equation_parameters=tuple(self._cubic_equation_parameters), - cubic_equation_roots=tuple(self._cubic_equation_roots)) - - if nstrands == self.strands() -1 : + if nstrands == self.strands() - 1: self._cubic_hecke_subalgebra = SubHeckeAlg - return SubHeckeAlg - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # mirror image - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def mirror_image(self): r""" - Return a copy of ``self`` with the mirrored cubic equation, that is: the cubic equation has the - inverse roots to the roots with respect to ``self``. This is needed since the mirror involution of the braid - group does not factor through ``self`` (considered as an algebra over the base ring, just considered as ZZ-algebra). - Therefore, the mirror involution of an element of ``self`` belongs to ``mirror_image``. + Return a copy of ``self`` with the mirrored cubic equation, that is: the + cubic equation has the inverse roots to the roots with respect to + ``self``. This is needed since the mirror involution of the braid group + does not factor through ``self`` (considered as an algebra over the base + ring, just considered as ``ZZ``-algebra). Therefore, the mirror involution + of an element of ``self`` belongs to ``mirror_image``. OUTPUT: - An instance of the class of ``self`` over the same base and extension ring, but whose cubic equation is transformed - by the mirror involution applied to its coefficients resp. roots. + An instance of the class of ``self`` over the same base and extension + ring, but whose cubic equation is transformed by the mirror involution + applied to its coefficients resp. roots. EXAMPLES:: @@ -3111,29 +3304,31 @@ def mirror_image(self): h^3 - u*h^2 + v*h - w sage: CHA2m = CHA2.mirror_image() sage: cem = CHA2m.cubic_equation(); cem - h^3 + ((-w^-1)*v)*h^2 + ((w^-1)*u)*h - w^-1 + h^3 + ((-v)/w)*h^2 + u/w*h + (-1)/w sage: mi = CHA2.base_ring().mirror_involution(); mi - Ring endomorphism of Multivariate Polynomial Ring in u, v - over Univariate Laurent Polynomial Ring in w - over Integer Ring - Defn: u |--> (w^-1)*v - v |--> (w^-1)*u - with map of base ring + Ring endomorphism of Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) + Defn: u |--> v/w + v |--> u/w + w |--> 1/w sage: cem == cem.parent()([mi(cf) for cf in ce.coefficients()]) True - Note, that both cubic Hecke algebras have the same ring of definition and identical generic cubic equation:: + Note, that both cubic Hecke algebras have the same ring of definition + and identical generic cubic equation:: - sage: CHA2.cubic_equation(generic=True) == CHA2m.cubic_equation(generic=True) + sage: cemg = CHA2m.cubic_equation(generic=True) + sage: CHA2.cubic_equation(generic=True) == cemg True - sage: CHA2.cubic_equation() == CHA2m.cubic_equation(generic=True) - True - sage: CHA2.cubic_equation_roots() == CHA2m.cubic_equation_roots(generic=True) + sage: CHA2.cubic_equation() == cemg True sage: a, b, c = CHA2.cubic_equation_roots() + sage: CHA2m.cubic_equation_roots(generic=True) == [a, b, c] + True sage: CHA2m.cubic_equation_roots() - [(w^-1)*a^2 + ((-w^-1)*u)*a + (w^-1)*v, - ((-w^-1)*a)*b + (-w^-1)*a^2 + ((w^-1)*u)*a, ((w^-1)*a)*b] + [((-1)/(-w))*a^2 + (u/(-w))*a + (-v)/(-w), + ((1/(-w))*a)*b + (1/(-w))*a^2 + ((-u)/(-w))*a, + (((-1)/(-w))*a)*b] sage: ai, bi, ci = _ sage: ai == ~a, bi == ~b, ci == ~c (True, True, True) @@ -3146,15 +3341,18 @@ def mirror_image(self): c |--> c^-1 with map of base ring - the mirror image can not be obtained for specialized cubic Hecke algebras if the specialization does not factor through - the mirror involution on the ring if definition:: + The mirror image can not be obtained for specialized cubic Hecke + algebras if the specialization does not factor through the mirror + involution on the ring if definition:: - sage: CHA2s = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)); CHA2s + sage: CHA2s = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2s Cubic Hecke algebra on 2 strands over Integer Ring localized at (2, 3, 5) with cubic equation: h^3 - 12*h^2 + 47*h - 60 = 0 - In the next example it isn't clear what the mirror image of ``7`` should be:: + In the next example it isn't clear what the mirror image of ``7`` + should be:: sage: CHA2s.mirror_image() Traceback (most recent call last): @@ -3162,57 +3360,55 @@ def mirror_image(self): RuntimeError: base ring Integer Ring localized at (2, 3, 5) does not factor through mirror involution """ + base_ring = self.base_ring() + base_gen = self.base_ring(generic=True) - base_ring = self.base_ring() - base_gen = self.base_ring(generic=True) - - base_gen_mirror = base_gen.mirror_involution() + base_gen_mirror = base_gen.mirror_involution() base_ring_mirror = self._base_ring_mirror + cepg = self.cubic_equation_parameters(generic=True) + cerg = self.cubic_equation_roots(generic=True) if not base_ring_mirror: - mirr_paras_gen = [base_gen_mirror(par) for par in self.cubic_equation_parameters(generic=True)] - mirr_paras = [base_ring(mirr_para) for mirr_para in mirr_paras_gen] + mirr_paras_gen = [base_gen_mirror(par) for par in cepg] + mirr_paras = [base_ring(mirr_para) for mirr_para in mirr_paras_gen] try: base_ring_mirror = base_ring.hom(mirr_paras) except (TypeError, ValueError, NotImplementedError): - raise RuntimeError("base ring %s does not factor through mirror involution" %(base_ring)) + raise RuntimeError('base ring %s does not factor through mirror involution' % base_ring) # check for involution - mirr_paras_back = [base_ring_mirror(mirr_para) for mirr_para in mirr_paras] + mirr_paras_back = [base_ring_mirror(mirr_para) for mirr_para in mirr_paras] if mirr_paras_back != self.cubic_equation_parameters(): - raise RuntimeError("base ring %s does not factor through mirror involution" %(base_ring)) - + raise RuntimeError('base ring %s does not factor through mirror involution' % base_ring) self._base_ring_mirror = base_ring_mirror mirror_image = self._mirror_image - if mirror_image == None: - extension_ring = self.extension_ring() - extension_gen = self.extension_ring(generic=True) - extension_gen_mirror = extension_gen.mirror_involution() + if mirror_image is None: + extension_ring = self.extension_ring() + extension_gen = self.extension_ring(generic=True) + extension_gen_mirror = extension_gen.mirror_involution() - mirr_paras_gen = [base_gen_mirror(par) for par in self.cubic_equation_parameters(generic=True)] - mirr_roots_gen = [extension_gen_mirror(root) for root in self.cubic_equation_roots(generic=True)] + mirr_paras_gen = [base_gen_mirror(par) for par in cepg] + mirr_roots_gen = [extension_gen_mirror(root) for root in cerg] - mirr_paras = tuple([base_ring(par) for par in mirr_paras_gen]) + mirr_paras = tuple([base_ring(par) for par in mirr_paras_gen]) mirr_roots = tuple([extension_ring(root) for root in mirr_roots_gen]) n = self.strands() - mirror_image = CubicHeckeAlgebra(n, cubic_equation_parameters=mirr_paras, cubic_equation_roots=mirr_roots ) + mirror_image = CubicHeckeAlgebra(n, cubic_equation_parameters=mirr_paras, cubic_equation_roots=mirr_roots) # go back by involution property - mirror_image._mirror_image = self + mirror_image._mirror_image = self mirror_image._base_ring_mirror = base_ring_mirror mirror_image._ring_of_definition._mirror_ = base_gen_mirror - mirror_image._is_mirror = True + mirror_image._is_mirror = True self._mirror_image = mirror_image return mirror_image - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # Schur elements - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def schur_elements(self, generic=False): r""" Return the list of Schur elements of ``self`` as elements @@ -3231,9 +3427,9 @@ def schur_elements(self, generic=False): sage: CHA3 = algebras.CubicHecke(3) # optional gap3 sage: sch_eles = CHA3.schur_elements() # optional gap3 sage: sch_eles[6] # optional gap3 - (w^-1)*u^3 + (w^-2)*v^3 + (-6*w^-1)*u*v + 8 + (u^3*w + v^3 - 6*u*v*w + 8*w^2)/w^2 """ - gap3_result = self.chevie().SchurElements() + gap3_result = self.chevie().SchurElements() GER = self.extension_ring(generic=True) generic_result = [GER(s) for s in gap3_result] if generic: @@ -3242,10 +3438,9 @@ def schur_elements(self, generic=False): ER = self.extension_ring() return [ER(s) for s in generic_result] - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # Schur element - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def schur_element(self, item, generic=False): r""" Return a single Schur element of ``self`` as elements @@ -3266,8 +3461,64 @@ def schur_element(self, item, generic=False): sage: CHA3 = algebras.CubicHecke(3) # optional gap3 sage: CHA3.schur_element(CHA3.irred_repr.W3_111) # optional gap3 - (w^-1)*u^3 + (w^-2)*v^3 + (-6*w^-1)*u*v + 8 + (u^3*w + v^3 - 6*u*v*w + 8*w^2)/w^2 """ if not isinstance(item, AbsIrreducibeRep): - raise ValueError('item must be an instance of %s' %(AbsIrreducibeRep)) + raise ValueError('item must be an instance of %s' % AbsIrreducibeRep) return self.schur_elements(generic=generic)[item.gap_index()] + + # -------------------------------------------------------------------------- + # characters + # -------------------------------------------------------------------------- + def characters(self, irr=None, original=True): + r""" + Return the irreducible characters of ``self``. By default the values + are given in the generic extension ring. Setting the keyword ``original`` + to ``False`` you can obtain the values in the (non generic) extension + ring (compare the same keyword for :meth:`matrix`). + + INPUT: + + - ``irr`` -- (optional) instance of :class:`AbsIrreducibeRep` + selecting the irreducible representation corresponding to the + character. If not given a list of all characters is returned + - ``original`` -- (optional, default ``True``) see description above + + OUTPUT: + + Function or list of Functions from the element class of ``self`` to + the (generic or non generic) extension ring depending on the given + keyword arguments. + + EXAMPLES:: + + sage: CHA3 = algebras.CubicHecke(3) + sage: ch = CHA3.characters() + sage: e = CHA3.an_element() + sage: ch[0](e) + a^2*b + a^2*c + a^2 - b*c + b^-1*c^-1 + a^-1*c^-1 + a^-1*b^-1 + sage: _.parent() + Multivariate Laurent Polynomial Ring in a, b, c + over Splitting Algebra of x^2 + x + 1 with roots [e3, -e3 - 1] + over Integer Ring + sage: ch_w3_100 = CHA3.characters(irr=CHA3.irred_repr.W3_100) + sage: ch_w3_100(e) == ch[0](e) + True + sage: ch_x = CHA3.characters(original=False) + sage: ch_x[0](e) + (u + v)*a + (-v*w - w^2 + u)/w + sage: _.parent() + Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] + over Splitting Algebra of h^3 - u*h^2 + v*h - w + with roots [a, b, -b - a + u] + over Multivariate Polynomial Ring in u, v, w + over Integer Ring localized at (w,) + """ + def char_function(ele): + if isinstance(ele, self.element_class): + m = ele.matrix(original=original) + return m[irr].trace() + if irr: + return char_function + irrs = [irr for irr in self.irred_repr if irr.number_gens() == self.strands() - 1] + return [self.characters(irrs[i], original=original) for i in range(len(irrs))] diff --git a/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py index e0037a390ae..76f46a53f54 100644 --- a/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py @@ -2,10 +2,12 @@ r""" Cubic Hecke matrix representations -This module contains the class :class:`CubicHeckeMatrixRep` which is used to handle the matrix representations of the -elements of the cubic Hecke algebra (:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra`) -together with its parent class :class:`CubicHeckeMatrixSpace`. Furthermore, it contains enums for their -types (:class:`RepresentationType`) and names (:class:`AbsIrreducibeRep`). +This module contains the class :class:`CubicHeckeMatrixRep` which is used to +treat the matrix representations of the elements of the cubic Hecke algebra +(:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra`) +together with its parent class :class:`CubicHeckeMatrixSpace`. Furthermore, +it contains enums for their types (:class:`RepresentationType`) and names +(:class:`AbsIrreducibeRep`). AUTHORS: @@ -13,9 +15,6 @@ - Sebastian Oehms May 2020: initial version """ - - - ############################################################################## # Copyright (C) 2020 Sebastian Oehms # @@ -26,8 +25,6 @@ # http://www.gnu.org/licenses/ ############################################################################## - - from enum import Enum from sage.misc.cachefunc import cached_method from sage.misc.verbose import verbose @@ -36,13 +33,7 @@ from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix from sage.matrix.special import block_diagonal_matrix -from sage.databases.cubic_hecke_db import CubicHeckeDataFilename as fn - - - -# -------------------------------------------------------------------------------------- -# Constants -# -------------------------------------------------------------------------------------- +from sage.databases.cubic_hecke_db import CubicHeckeDataSection as sc # ------------------------------------------- @@ -60,11 +51,10 @@ class GenSign(Enum): sage: chmr.GenSign.neg """ - pos = 1 + pos = 1 neg = -1 - # ------------------------------------------- # Enum for typ of matrix representation # ------------------------------------------- @@ -74,8 +64,10 @@ class RepresentationType(Enum): - ``RegularLeft`` -- left regular representations - ``RegularRight`` -- right regular representations - - ``SplitIrredMarin`` -- split irreducible representations obtained from Ivan Marin's data - - ``SplitIrredChevie`` -- the split irreducible representations obtained from CHEVIE via the GAP3-interface + - ``SplitIrredMarin`` -- split irreducible representations obtained from + Ivan Marin's data + - ``SplitIrredChevie`` -- the split irreducible representations obtained + from CHEVIE via the *GAP3*-interface EXAMPLES:: @@ -85,7 +77,8 @@ class RepresentationType(Enum): """ def is_split(self): r""" - Return True if this representation type is absolutely split, False else-wise. + Return ``True`` if this representation type is absolutely split, + ``False`` else-wise. EXAMPLES:: @@ -98,7 +91,8 @@ def is_split(self): def is_regular(self): r""" - Return True if this representation type is regular, False else-wise. + Return ``True`` if this representation type is regular, ``False`` + else-wise. EXAMPLES:: @@ -109,16 +103,17 @@ def is_regular(self): """ return self.value['regular'] - def data_filename(self): + def data_section(self): r""" - Return the name of the data file. For more information see :class:`~sage.databases.cubic_hecke_db.CubicHeckeDataBase`. + Return the name of the data file. For more information see + :class:`~sage.databases.cubic_hecke_db.CubicHeckeDataBase`. EXAMPLES:: sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr sage: reg_left = chmr.RepresentationType.RegularLeft - sage: reg_left.data_filename() - + sage: reg_left.data_section() + """ return self.value['data'] @@ -134,30 +129,34 @@ def number_of_representations(self, nstrands): sage: chmr.RepresentationType.SplitIrredMarin.number_of_representations(4) 24 """ - if self.value['data'] == None: - if nstrands < 1 or nstrands > 5 : - raise ValueError( "nstrands must be between 1 and 5" ) - elif nstrands < 1 or nstrands > 4 : - raise ValueError( "nstrands must be between 1 and 4" ) - return self.value['num_rep'][nstrands-1 ] - - - RegularLeft = {'split':False, 'regular':True, 'data':fn.regular_left, 'num_rep':[1 ,1 ,1 ,1 ]} - RegularRight = {'split':False, 'regular':True, 'data':fn.regular_right, 'num_rep':[1 ,1 ,1 ,1 ]} - SplitIrredMarin = {'split':True, 'regular':False, 'data':fn.irred_split, 'num_rep':[1 ,3 ,7 ,24 ]} - SplitIrredChevie = {'split':True, 'regular':False, 'data':None, 'num_rep':[1 ,3 ,7 ,24 ,30 ]} - - - - + if self.value['data'] is None: + if nstrands < 1 or nstrands > 5: + raise ValueError("nstrands must be between 1 and 5") + elif nstrands < 1 or nstrands > 4: + raise ValueError("nstrands must be between 1 and 4") + return self.value['num_rep'][nstrands - 1] + + RegularLeft = {'split': False, 'regular': True, 'data': sc.regular_left, 'num_rep': [1, 1, 1, 1]} + RegularRight = {'split': False, 'regular': True, 'data': sc.regular_right, 'num_rep': [1, 1, 1, 1]} + SplitIrredMarin = {'split': True, 'regular': False, 'data': sc.split_irred, 'num_rep': [1, 3, 7, 24]} + SplitIrredChevie = {'split': True, 'regular': False, 'data': None, 'num_rep': [1, 3, 7, 24, 30]} + + +# --------------------------------------------- +# Enum for absolute irreducible representations +# --------------------------------------------- class AbsIrreducibeRep(Enum): r""" - Enum class to select an absolutely irreducible representation for the cubic Hecke algebra (``CHAn``) on n-strands. + Enum class to select an absolutely irreducible representation for the cubic + Hecke algebra (``CHAn``) on n-strands. - The names are build as follows: Take the determinant of one of the generators of the ``CHAn``. This is a monomial - in the the generic extension ring (``GER``) of ``CHA``, say ``a^ib^jc^k`` where ``a, b`` and ``c`` are the generators - of ``GER``. This does not depend on the choice of the generator of ``CHA``, since these are conjugated to each other. - This monomial might be looked as the weight of the representation. Therefore we use as a name: + The names are build as follows: Take the determinant of one of the + generators of the ``CHAn``. This is a monomial in the generic extension + ring (``GER``) of ``CHA``, say ``a^ib^jc^k`` where ``a, b`` and ``c`` are + the generators of ``GER``. This does not depend on the choice of the + generator of ``CHA``, since these are conjugated to each other. This + monomial might be looked as the weight of the representation. Therefore we + use it as a name: ``Wn_ijk`` @@ -194,7 +193,6 @@ class AbsIrreducibeRep(Enum): [MW2012]_ """ - def alternative_name(self): r""" Return the name of the split irreducible representation for cubic Hecke algebras for up to four strands @@ -204,7 +202,7 @@ def alternative_name(self): sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr sage: chmr.AbsIrreducibeRep.W3_011.alternative_name() - 'Tyz' + 'Tbc' """ return self.value['alt_name'] @@ -236,7 +234,8 @@ def number_gens(self): def length_orbit(self): r""" - Return the length of the orbit of this representation under the action of the Galois group of the cubic equation. + Return the length of the orbit of this representation under the action + of the Galois group of the cubic equation. EXAMPLES:: @@ -250,7 +249,8 @@ def length_orbit(self): def gap_index(self): r""" - Return the array index of this representation for the access in GAP3 CHEVIE. + Return the array index of this representation for the access to the *GAP3* + package *CHEVIE*. EXAMPLES:: @@ -275,99 +275,96 @@ def internal_index(self): # ------------------------------------------------------------------------------------------------- # absolutely irreducible representations corresponding to braids on 2 strands # ------------------------------------------------------------------------------------------------- - W2_100 = {'alt_name':'Sx', 'dim':1 , 'ngens':1 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } - W2_001 = {'alt_name':'Sz', 'dim':1 , 'ngens':1 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } - W2_010 = {'alt_name':'Sy', 'dim':1 , 'ngens':1 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + W2_100 = {'alt_name': 'Sa', 'dim': 1, 'ngens': 1, 'len_orbit': 3, 'gap_ind': 0, 'intern_ind': 0} + W2_001 = {'alt_name': 'Sc', 'dim': 1, 'ngens': 1, 'len_orbit': 3, 'gap_ind': 1, 'intern_ind': 1} + W2_010 = {'alt_name': 'Sb', 'dim': 1, 'ngens': 1, 'len_orbit': 3, 'gap_ind': 2, 'intern_ind': 2} # ------------------------------------------------------------------------------------------------- # absolutely irreducible representations corresponding to braids on 3 strands # ------------------------------------------------------------------------------------------------- - W3_100 = {'alt_name':'Sx', 'dim':1 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } - W3_001 = {'alt_name':'Sz', 'dim':1 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } - W3_010 = {'alt_name':'Sy', 'dim':1 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } + W3_100 = {'alt_name': 'Sa', 'dim': 1, 'ngens': 2, 'len_orbit': 3, 'gap_ind': 0, 'intern_ind': 0} + W3_001 = {'alt_name': 'Sc', 'dim': 1, 'ngens': 2, 'len_orbit': 3, 'gap_ind': 1, 'intern_ind': 1} + W3_010 = {'alt_name': 'Sb', 'dim': 1, 'ngens': 2, 'len_orbit': 3, 'gap_ind': 2, 'intern_ind': 2} - W3_011 = {'alt_name':'Tyz', 'dim':2 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 3 , 'intern_ind': 3 } - W3_110 = {'alt_name':'Txy', 'dim':2 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 4 , 'intern_ind': 4 } - W3_101 = {'alt_name':'Txz', 'dim':2 , 'ngens':2 , 'len_orbit':3 , 'gap_ind': 5 , 'intern_ind': 5 } + W3_011 = {'alt_name': 'Tbc', 'dim': 2, 'ngens': 2, 'len_orbit': 3, 'gap_ind': 3, 'intern_ind': 3} + W3_110 = {'alt_name': 'Tab', 'dim': 2, 'ngens': 2, 'len_orbit': 3, 'gap_ind': 4, 'intern_ind': 4} + W3_101 = {'alt_name': 'Tac', 'dim': 2, 'ngens': 2, 'len_orbit': 3, 'gap_ind': 5, 'intern_ind': 5} - W3_111 = {'alt_name':'V', 'dim':3 , 'ngens':2 , 'len_orbit':1 , 'gap_ind': 6 , 'intern_ind': 6 } + W3_111 = {'alt_name': 'V', 'dim': 3, 'ngens': 2, 'len_orbit': 1, 'gap_ind': 6, 'intern_ind': 6} # ------------------------------------------------------------------------------------------------- # absolutely irreducible representations corresponding to braids on 4 strands # ------------------------------------------------------------------------------------------------- - W4_100 = {'alt_name':'Sx', 'dim':1 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } - W4_001 = {'alt_name':'Sz', 'dim':1 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } - W4_010 = {'alt_name':'Sy', 'dim':1 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } - - W4_011 = {'alt_name':'Tyz', 'dim':2 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 3 , 'intern_ind': 3 } - W4_110 = {'alt_name':'Txy', 'dim':2 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 4 , 'intern_ind': 4 } - W4_101 = {'alt_name':'Txz', 'dim':2 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 5 , 'intern_ind': 5 } + W4_100 = {'alt_name': 'Sa', 'dim': 1, 'ngens': 3, 'len_orbit': 3, 'gap_ind': 0, 'intern_ind': 0} + W4_001 = {'alt_name': 'Sc', 'dim': 1, 'ngens': 3, 'len_orbit': 3, 'gap_ind': 1, 'intern_ind': 1} + W4_010 = {'alt_name': 'Sb', 'dim': 1, 'ngens': 3, 'len_orbit': 3, 'gap_ind': 2, 'intern_ind': 2} - W4_111 = {'alt_name':'V', 'dim':3 , 'ngens':3 , 'len_orbit':1 , 'gap_ind': 6 , 'intern_ind': 6 } + W4_011 = {'alt_name': 'Tbc', 'dim': 2, 'ngens': 3, 'len_orbit': 3, 'gap_ind': 3, 'intern_ind': 3} + W4_110 = {'alt_name': 'Tab', 'dim': 2, 'ngens': 3, 'len_orbit': 3, 'gap_ind': 4, 'intern_ind': 4} + W4_101 = {'alt_name': 'Tac', 'dim': 2, 'ngens': 3, 'len_orbit': 3, 'gap_ind': 5, 'intern_ind': 5} - W4_120 = {'alt_name':'Uyx', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 7 , 'intern_ind': 7 } - W4_201 = {'alt_name':'Uxz', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 8 , 'intern_ind': 8 } - W4_012 = {'alt_name':'Uzy', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 9 , 'intern_ind': 9 } - W4_102 = {'alt_name':'Uzx', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 10 , 'intern_ind': 10 } - W4_210 = {'alt_name':'Uxy', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 11 , 'intern_ind': 11 } - W4_021 = {'alt_name':'Vyz', 'dim':3 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 12 , 'intern_ind': 12 } + W4_111 = {'alt_name': 'V', 'dim': 3, 'ngens': 3, 'len_orbit': 1, 'gap_ind': 6, 'intern_ind': 6} - W4_213 = {'alt_name':'Vzxy', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 13 , 'intern_ind': 13 } - W4_132 = {'alt_name':'Vyzx', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 14 , 'intern_ind': 14 } - W4_321 = {'alt_name':'Vxyz', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 15 , 'intern_ind': 15 } - W4_231 = {'alt_name':'Vyxz', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 16 , 'intern_ind': 16 } - W4_123 = {'alt_name':'Vzyx', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 17 , 'intern_ind': 17 } - W4_312 = {'alt_name':'Vxzy', 'dim':6 , 'ngens':3 , 'len_orbit':6 , 'gap_ind': 18 , 'intern_ind': 18 } + W4_120 = {'alt_name': 'Uba', 'dim': 3, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 7, 'intern_ind': 7} + W4_201 = {'alt_name': 'Uac', 'dim': 3, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 8, 'intern_ind': 8} + W4_012 = {'alt_name': 'Ucb', 'dim': 3, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 9, 'intern_ind': 9} + W4_102 = {'alt_name': 'Uca', 'dim': 3, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 10, 'intern_ind': 10} + W4_210 = {'alt_name': 'Uab', 'dim': 3, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 11, 'intern_ind': 11} + W4_021 = {'alt_name': 'Ubc', 'dim': 3, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 12, 'intern_ind': 12} - W4_422 = {'alt_name':'Wx', 'dim':8 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 19 , 'intern_ind': 19 } - W4_224 = {'alt_name':'Wz', 'dim':8 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 20 , 'intern_ind': 20 } - W4_242 = {'alt_name':'Wy', 'dim':8 , 'ngens':3 , 'len_orbit':3 , 'gap_ind': 21 , 'intern_ind': 21 } + W4_213 = {'alt_name': 'Vcab', 'dim': 6, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 13, 'intern_ind': 13} + W4_132 = {'alt_name': 'Vbca', 'dim': 6, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 14, 'intern_ind': 14} + W4_321 = {'alt_name': 'Vabc', 'dim': 6, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 15, 'intern_ind': 15} + W4_231 = {'alt_name': 'Vbac', 'dim': 6, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 16, 'intern_ind': 16} + W4_123 = {'alt_name': 'Vcba', 'dim': 6, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 17, 'intern_ind': 17} + W4_312 = {'alt_name': 'Vacb', 'dim': 6, 'ngens': 3, 'len_orbit': 6, 'gap_ind': 18, 'intern_ind': 18} - W4_333 = {'alt_name':'X', 'dim':9 , 'ngens':3 , 'len_orbit':2 , 'gap_ind': 22 , 'intern_ind': 22 } - W4_333bar = {'alt_name':'Xbar', 'dim':9 , 'ngens':3 , 'len_orbit':2 , 'gap_ind': 23 , 'intern_ind': 23 } + W4_422 = {'alt_name': 'Wa', 'dim': 8, 'ngens': 3, 'len_orbit': 3, 'gap_ind': 19, 'intern_ind': 19} + W4_224 = {'alt_name': 'Wc', 'dim': 8, 'ngens': 3, 'len_orbit': 3, 'gap_ind': 20, 'intern_ind': 20} + W4_242 = {'alt_name': 'Wb', 'dim': 8, 'ngens': 3, 'len_orbit': 3, 'gap_ind': 21, 'intern_ind': 21} + W4_333 = {'alt_name': 'X', 'dim': 9, 'ngens': 3, 'len_orbit': 2, 'gap_ind': 22, 'intern_ind': 22} + W4_333bar = {'alt_name': 'Xbar', 'dim': 9, 'ngens': 3, 'len_orbit': 2, 'gap_ind': 23, 'intern_ind': 23} # ------------------------------------------------------------------------------------------------- # absolutely irreducible representations corresponding to braids on 5 strands # ------------------------------------------------------------------------------------------------- - W5_100 = {'alt_name':None, 'dim':1 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 0 , 'intern_ind': 0 } - W5_001 = {'alt_name':None, 'dim':1 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 1 , 'intern_ind': 1 } - W5_010 = {'alt_name':None, 'dim':1 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 2 , 'intern_ind': 2 } - - W5_013 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 3 , 'intern_ind': 3 } - W5_130 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 4 , 'intern_ind': 4 } - W5_301 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 5 , 'intern_ind': 5 } - W5_031 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 6 , 'intern_ind': 6 } - W5_103 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 7 , 'intern_ind': 7 } - W5_310 = {'alt_name':None, 'dim':4 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 8 , 'intern_ind': 8 } - - W5_203 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 9 , 'intern_ind': 9 } - W5_032 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 10 , 'intern_ind': 10 } - W5_320 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 11 , 'intern_ind': 11 } - W5_230 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 12 , 'intern_ind': 12 } - W5_023 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 13 , 'intern_ind': 13 } - W5_302 = {'alt_name':None, 'dim':5 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 14 , 'intern_ind': 14 } - - W5_033 = {'alt_name':None, 'dim':6 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 15 , 'intern_ind': 15 } - W5_330 = {'alt_name':None, 'dim':6 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 16 , 'intern_ind': 16 } - W5_303 = {'alt_name':None, 'dim':6 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 17 , 'intern_ind': 17 } - - W5_163 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 18 , 'intern_ind': 18 } - W5_631 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 19 , 'intern_ind': 19 } - W5_316 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 20 , 'intern_ind': 20 } - W5_136 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 21 , 'intern_ind': 21 } - W5_613 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 22 , 'intern_ind': 22 } - W5_361 = {'alt_name':None, 'dim':10 , 'ngens':4 , 'len_orbit':6 , 'gap_ind': 23 , 'intern_ind': 23 } - - W5_366 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 24 , 'intern_ind': 24 } - W5_663 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 26 , 'intern_ind': 25 } - W5_636 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 27 , 'intern_ind': 26 } - - W5_933 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 25 , 'intern_ind': 27 } - W5_339 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 28 , 'intern_ind': 28 } - W5_393 = {'alt_name':None, 'dim':15 , 'ngens':4 , 'len_orbit':3 , 'gap_ind': 29 , 'intern_ind': 29 } - - + W5_100 = {'alt_name': None, 'dim': 1, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 0, 'intern_ind': 0} + W5_001 = {'alt_name': None, 'dim': 1, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 1, 'intern_ind': 1} + W5_010 = {'alt_name': None, 'dim': 1, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 2, 'intern_ind': 2} + + W5_013 = {'alt_name': None, 'dim': 4, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 3, 'intern_ind': 3} + W5_130 = {'alt_name': None, 'dim': 4, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 4, 'intern_ind': 4} + W5_301 = {'alt_name': None, 'dim': 4, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 5, 'intern_ind': 5} + W5_031 = {'alt_name': None, 'dim': 4, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 6, 'intern_ind': 6} + W5_103 = {'alt_name': None, 'dim': 4, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 7, 'intern_ind': 7} + W5_310 = {'alt_name': None, 'dim': 4, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 8, 'intern_ind': 8} + + W5_203 = {'alt_name': None, 'dim': 5, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 9, 'intern_ind': 9} + W5_032 = {'alt_name': None, 'dim': 5, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 10, 'intern_ind': 10} + W5_320 = {'alt_name': None, 'dim': 5, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 11, 'intern_ind': 11} + W5_230 = {'alt_name': None, 'dim': 5, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 12, 'intern_ind': 12} + W5_023 = {'alt_name': None, 'dim': 5, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 13, 'intern_ind': 13} + W5_302 = {'alt_name': None, 'dim': 5, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 14, 'intern_ind': 14} + + W5_033 = {'alt_name': None, 'dim': 6, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 15, 'intern_ind': 15} + W5_330 = {'alt_name': None, 'dim': 6, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 16, 'intern_ind': 16} + W5_303 = {'alt_name': None, 'dim': 6, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 17, 'intern_ind': 17} + + W5_163 = {'alt_name': None, 'dim': 10, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 18, 'intern_ind': 18} + W5_631 = {'alt_name': None, 'dim': 10, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 19, 'intern_ind': 19} + W5_316 = {'alt_name': None, 'dim': 10, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 20, 'intern_ind': 20} + W5_136 = {'alt_name': None, 'dim': 10, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 21, 'intern_ind': 21} + W5_613 = {'alt_name': None, 'dim': 10, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 22, 'intern_ind': 22} + W5_361 = {'alt_name': None, 'dim': 10, 'ngens': 4, 'len_orbit': 6, 'gap_ind': 23, 'intern_ind': 23} + + W5_366 = {'alt_name': None, 'dim': 15, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 24, 'intern_ind': 24} + W5_663 = {'alt_name': None, 'dim': 15, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 26, 'intern_ind': 25} + W5_636 = {'alt_name': None, 'dim': 15, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 27, 'intern_ind': 26} + + W5_933 = {'alt_name': None, 'dim': 15, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 25, 'intern_ind': 27} + W5_339 = {'alt_name': None, 'dim': 15, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 28, 'intern_ind': 28} + W5_393 = {'alt_name': None, 'dim': 15, 'ngens': 4, 'len_orbit': 3, 'gap_ind': 29, 'intern_ind': 29} # ------------------------------------------------------------------------------------------------------------------ @@ -411,11 +408,11 @@ class CubicHeckeMatrixRep(Matrix_generic_dense): @cached_method def _get_block(self, ind): r""" - Return the ``ind``-th submatrix block of ``self`` considered as block diagonal matrix. + Return the ``ind``-th sub-matrix block of ``self`` considered as block diagonal matrix. INPUT: - - ``ind`` -- integer specifying the list index according to :meth:`internal_index` repectively :meth:`gap_index` + - ``ind`` -- integer specifying the list index according to :meth:`internal_index` respectively :meth:`gap_index` OUTPUT: @@ -438,11 +435,44 @@ def _get_block(self, ind): return matrix(self.submatrix(s, s, d, d)) raise ValueError('no irreducible representation for this index') + @cached_method + def _irr_to_ind(self, irr): + r""" + Return the index if the given split irreducible representation of ``self``. + + INPUT: + + - ``irr`` -- an instance of :class:`AbsIrreducibeRep` specifying an absolute irreducible + representation of the cubic Hecke algebra + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: m1 = c1.matrix() + sage: m1._irr_to_ind(CHA2.irred_repr.W2_001) + 1 + sage: m1._irr_to_ind(CHA2.irred_repr.W3_001) + Traceback (most recent call last): + ... + TypeError: representation must have 1 generators + """ + representation_type = self.parent()._representation_type + if not representation_type.is_split(): + raise TypeError('representation type is non split') + + ch_algebra = self.parent()._cubic_hecke_algebra + if ch_algebra.strands() != irr.number_gens() + 1: + raise TypeError('representation must have %s generators' % (ch_algebra.strands() - 1)) + + ind = irr.gap_index() + if representation_type == RepresentationType.SplitIrredMarin: + ind = irr.internal_index() + return ind @cached_method def __getitem__(self, item): r""" - Return the submatrix block of ``self`` considered as block diagonal matrix specified by `item`. + Return the sub-matrix block of ``self`` considered as block diagonal matrix specified by `item`. Overloading builtin-method to select a list-item. INPUT: @@ -459,27 +489,15 @@ def __getitem__(self, item): EXAMPLES:: sage: CHA2. = algebras.CubicHecke(2) - sage: c1.matrix()[0] # indirect doctest + sage: m1 = c1.matrix() + sage: m1[0] # indirect doctest [a] - sage: c1.matrix()[CHA2.irred_repr.W2_001] # indirect doctest + sage: m1[CHA2.irred_repr.W2_001] # indirect doctest [b] """ - - if isinstance(item, AbsIrreducibeRep): - representation_type = self.parent()._representation_type - if not representation_type.is_split(): - raise TypeError( "representation type is non split" ) - - ch_algebra = self.parent()._cubic_hecke_algebra - if ch_algebra.strands() != item.number_gens() +1 : - raise TypeError( "representation must have %d generators" %(ch_algebra.strands()-1 ) ) - - ind = item.gap_index() - if representation_type == RepresentationType.SplitIrredMarin: - ind = item.internal_index() - return self._get_block(ind) - elif isinstance(item, (Integer,int)): + return self._get_block(self._irr_to_ind(item)) + elif isinstance(item, (Integer, int)): return self._get_block(item) return super(CubicHeckeMatrixRep, self).__getitem__(item) @@ -487,13 +505,12 @@ def __getitem__(self, item): @cached_method def block_diagonal_list(self): r""" - Return the list of submatrix blocks of ``self`` considered as block diagonal matrix. + Return the list of sub-matrix blocks of ``self`` considered as block diagonal matrix. OUTPUT: A list of instances of :class:`Matrix_generic_dense` each of which represents a diagonal block of ``self``. - EXAMPLES:: sage: CHA2. = algebras.CubicHecke(2) @@ -502,9 +519,48 @@ def block_diagonal_list(self): """ representation_type = self.parent()._representation_type n = self.parent()._cubic_hecke_algebra.strands() - l = representation_type.number_of_representations(n) - return [self._get_block(i) for i in range(l)] + m = representation_type.number_of_representations(n) + return [self._get_block(i) for i in range(m)] + @cached_method + def reduce_to_irr_block(self, irr): + r""" + Return a copy of ``self`` with zeroes outside the block corresponding to + ``irr`` but the block according to the input identical to that of ``self``. + + INPUT: + + - ``irr`` -- an instance of :class:`AbsIrreducibeRep` specifying an + absolute irreducible representation of the cubic Hecke algebra. + Alternatively, it can be specified by list index (see + :meth:`internal_index` respectively :meth:`gap_index`) + + OUTPUT: + + An instance of :class:`Matrix_generic_dense` with exactly one non zero block + according to ``irr``. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: m1 = c1.matrix() + sage: m1.reduce_to_irr_block(0) + [a 0 0] + [0 0 0] + [0 0 0] + sage: m1.reduce_to_irr_block(CHA2.irred_repr.W2_001) + [0 0 0] + [0 b 0] + [0 0 0] + """ + if isinstance(irr, AbsIrreducibeRep): + ind = self._irr_to_ind(irr) + else: + ind = Integer(irr) + from copy import copy + mat_list = copy(self.parent().zero().block_diagonal_list()) + mat_list[ind] = self[ind] + return block_diagonal_matrix(mat_list, subdivide=self.parent()._subdivide, sparse=True) # ------------------------------------------------------------------------------------------------------------------ @@ -520,14 +576,13 @@ class CubicHeckeMatrixSpace(MatrixSpace): `element` fails to be an instance of its element class. - ``representation_type`` -- (default RepresentationType.SplitIrredChevie) instance of :class:`RepresentationType` - specifying the type of the represenstation. + specifying the type of the representation. - ``subdivide`` -- boolean (default False) passed to :func:`~sage.matrix.special.block_diagonal_matrix`. - ``original`` -- boolean (default False) if set to True the matrix will coefficients in the generic base / extension ring. - EXAMPLES:: sage: CHA2. = algebras.CubicHecke(2) @@ -558,12 +613,12 @@ def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, su sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) sage: TestSuite(MS).run() """ - from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra + from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra - if isinstance(cubic_hecke_algebra, CubicHeckeAlgebra) == False: - raise TypeError("cubic_hecke_algebra must be an instance of CubicHeckeAlgebra") + if not isinstance(cubic_hecke_algebra, CubicHeckeAlgebra): + raise TypeError('cubic_hecke_algebra must be an instance of CubicHeckeAlgebra') - if representation_type == None: + if representation_type is None: representation_type = RepresentationType.SplitIrredMarin if representation_type == RepresentationType.SplitIrredChevie: @@ -571,19 +626,22 @@ def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, su if not is_chevie_available(): raise ValueError('CHEVIE is not available') - base_ring = cubic_hecke_algebra.base_ring(generic=original) + base_ring = cubic_hecke_algebra.base_ring(generic=original) dimension = cubic_hecke_algebra.dimension() if representation_type.is_split(): dimension = cubic_hecke_algebra._dim_irr_rep base_ring = cubic_hecke_algebra.extension_ring(generic=original) - - return super(CubicHeckeMatrixSpace, cls).__classcall__(cls, base_ring, dimension, cubic_hecke_algebra=cubic_hecke_algebra, - representation_type=representation_type, subdivide=subdivide, sparse=True, implementation=Matrix_generic_dense) - - - - def __init__(self, base_ring, dimension, cols, sparse=True, implementation=Matrix_generic_dense, - cubic_hecke_algebra=None, representation_type=RepresentationType.SplitIrredChevie, subdivide=False): + return super(CubicHeckeMatrixSpace, cls).__classcall__(cls, base_ring, dimension, + cubic_hecke_algebra=cubic_hecke_algebra, + representation_type=representation_type, + subdivide=subdivide, sparse=True, + implementation=Matrix_generic_dense) + + def __init__(self, base_ring, dimension, cols, sparse=True, + implementation=Matrix_generic_dense, + cubic_hecke_algebra=None, + representation_type=RepresentationType.SplitIrredChevie, + subdivide=False): r""" Python constructor. @@ -594,36 +652,47 @@ def __init__(self, base_ring, dimension, cols, sparse=True, implementation=Matr sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) sage: TestSuite(MS).run() # long time """ + from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra - from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra - - if isinstance(cubic_hecke_algebra, CubicHeckeAlgebra) == False: - raise TypeError("cubic_hecke_algebra must be an instance of CubicHeckeAlgebra") + if not isinstance(cubic_hecke_algebra, CubicHeckeAlgebra): + raise TypeError('cubic_hecke_algebra must be an instance of CubicHeckeAlgebra') # ------------------------------------------------------------------------------------------------- # saving input parameters # ------------------------------------------------------------------------------------------------- self._cubic_hecke_algebra = cubic_hecke_algebra self._representation_type = representation_type - self._subdivide = subdivide + self._subdivide = subdivide original_base_ring = cubic_hecke_algebra.base_ring(generic=True) if representation_type.is_split(): original_base_ring = cubic_hecke_algebra.extension_ring(generic=True) - specialize = cubic_hecke_algebra._generic_extension_ring_map + specialize = cubic_hecke_algebra._generic_extension_ring_map else: - specialize = cubic_hecke_algebra._ring_of_definition_map + specialize = cubic_hecke_algebra._ring_of_definition_map - verbose("original_base_ring %s base_ring %s" %(original_base_ring, base_ring)) + verbose("original_base_ring %s base_ring %s" % (original_base_ring, base_ring), level=2) self._original_base_ring = original_base_ring - self._specialize = specialize + self._specialize = specialize super(CubicHeckeMatrixSpace, self).__init__(base_ring, dimension, cols, sparse=sparse, implementation=implementation) self.Element = CubicHeckeMatrixRep return + def construction(self): + r""" + Return ``None`` since this construction is not functorial. + + EXAMPLES:: + + sage: CHA2. = algebras.CubicHecke(2) + sage: MS = c1.matrix().parent() + sage: MS._test_category() # indirect doctest + """ + return None + def __reduce__(self): r""" Used for pickling. @@ -638,7 +707,6 @@ def __reduce__(self): original = self.base_ring() == self._original_base_ring return CubicHeckeMatrixSpace, (self._cubic_hecke_algebra, self._representation_type, self._subdivide, original) - def _element_constructor_(self, x): r""" INPUT: @@ -666,8 +734,8 @@ def _element_constructor_(self, x): # ------------------------------------------------------------------------------------------------- # checking input and setting the self._cubic_hecke_algebra # ------------------------------------------------------------------------------------------------- - ch_algebra = self._cubic_hecke_algebra - ele_parent = x.parent() + ch_algebra = self._cubic_hecke_algebra + ele_parent = x.parent() ori_base_ring = self._original_base_ring if isinstance(ele_parent, MatrixSpace): # ToDo: - Find preimage in cubic hecke algebra @@ -681,19 +749,20 @@ def _element_constructor_(self, x): raise ValueError('incompatible base ring!') x_in_self = self.element_class(self, x) matrix_list = x_in_self.block_diagonal_list() - matrix = block_diagonal_matrix(matrix_list, subdivide=self._subdivide, sparse=True) + matrix = block_diagonal_matrix(matrix_list, subdivide=self._subdivide, sparse=True) if matrix != x: - raise TypeError( "incompatible block structure" ) + raise TypeError('incompatible block structure') elif ele_parent == ch_algebra: mat = ch_algebra._apply_module_morphism(x, self._image_on_basis) return self(mat) else: - raise TypeError( "element must be an instance of CubicHeckeElement or a matrix" ) + raise TypeError('element must be an instance of CubicHeckeElement or a matrix') return self.element_class(self, matrix) + @cached_method def __call__(self, entries=None, coerce=True, copy=None): r""" Perform the instance call. This method needs to be overloaded here @@ -709,19 +778,17 @@ def __call__(self, entries=None, coerce=True, copy=None): [ 0 b 0] [ 0 0 -b - a + u] """ - from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra + from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra if entries is None: - return super(CubicHeckeMatrixSpace,self).__call__(entries=entries, coerce=coerce, copy=copy) + return super(CubicHeckeMatrixSpace, self).__call__(entries=entries, coerce=coerce, copy=copy) if not hasattr(entries, 'parent'): - return super(CubicHeckeMatrixSpace,self).__call__(entries=entries, coerce=coerce, copy=copy) + return super(CubicHeckeMatrixSpace, self).__call__(entries=entries, coerce=coerce, copy=copy) ele_parent = entries.parent() if not isinstance(ele_parent, (CubicHeckeAlgebra, MatrixSpace)): - return super(CubicHeckeMatrixSpace,self).__call__(entries=entries, coerce=coerce, copy=copy) + return super(CubicHeckeMatrixSpace, self).__call__(entries=entries, coerce=coerce, copy=copy) return self._element_constructor_(entries) - - - + @cached_method def _specialize_matrix(self, mat): r""" Return the given matrix specializing the original coefficients @@ -747,10 +814,9 @@ def _specialize_matrix(self, mat): [ a b] [ 0 -b - a + u] """ - - base_ring = self.base_ring() + base_ring = self.base_ring() original_base_ring = self._original_base_ring - specialize = self._specialize + specialize = self._specialize if base_ring == original_base_ring: return mat @@ -758,12 +824,11 @@ def _specialize_matrix(self, mat): mat_dict = {k: specialize(original_base_ring(v)) for k, v in mat.dict().items()} return matrix(base_ring, mat_dict) - @cached_method def _image_on_gen(self, gen_ind): r""" Return the matrix list corresponding to the generator given by ``(gen_ind,)`` in Tietze form - under the representation_type of ``self`` from the data-file or via the gap3 interface + under the representation_type of ``self`` from the data-file or via the *GAP3* interface INPUT: @@ -789,39 +854,38 @@ def _image_on_gen(self, gen_ind): sage: MSreg = chmr.CubicHeckeMatrixSpace(CHA2, representation_type=CHA2.repr_type.RegularRight) sage: MSreg._image_on_gen(-1) [ - [ 0 1 (-w^-1)*u] - [ 0 0 w^-1] - [ 1 0 (w^-1)*v] + [ 0 1 (-u)/w] + [ 0 0 1/w] + [ 1 0 v/w] ] """ representation_type = self._representation_type - ch_algebra = self._cubic_hecke_algebra - n = ch_algebra.strands() - original_base_ring = self._original_base_ring + original_base_ring = self._original_base_ring + ch_algebra = self._cubic_hecke_algebra + n = ch_algebra.strands() def invert_gen(matr): - r""" - Return the inverse matrix of generators. - """ - cfs = ch_algebra.cubic_equation(as_coefficients=True, generic=True) - fac =-1 /cfs[0 ] - cf0, cf1, cf2, cf3 = [original_base_ring(cf*fac) for cf in cfs] - - matri = cf1*matr.parent().one() - matri += cf2*matr - matri += cf3*matr**2 - d1, d2 = matr.dimensions() - matrI = matrix(original_base_ring, d1, d2, lambda i,j: original_base_ring(matri[i,j])) - return matrI - - - if n == 2 : + r""" + Return the inverse matrix of generators. + """ + cfs = ch_algebra.cubic_equation(as_coefficients=True, generic=True) + fac = - 1/cfs[0] + cf0, cf1, cf2, cf3 = [original_base_ring(cf*fac) for cf in cfs] + + matri = cf1*matr.parent().one() + matri += cf2*matr + matri += cf3*matr**2 + d1, d2 = matr.dimensions() + matrI = matrix(original_base_ring, d1, d2, lambda i, j: original_base_ring(matri[i, j])) + return matrI + + if n == 2: if representation_type.is_split(): # Split representations for n == 2 are missing in CHEVIE and data files a, b, c = original_base_ring.gens() - matrix_list = [matrix(1 ,1 , [a]), matrix(1 ,1 , [b]), matrix(1 ,1 , [c])] - if gen_ind < 0 : + matrix_list = [matrix(1, 1, [a]), matrix(1, 1, [b]), matrix(1, 1, [c])] + if gen_ind < 0: matrix_list = [invert_gen(mat) for mat in matrix_list] return matrix_list @@ -829,28 +893,28 @@ def invert_gen(matr): if representation_type == RepresentationType.SplitIrredChevie: - rep_list = [ ch_algebra._fetch_matrix_list_from_chevie(i+1) for i in range(num_rep) ] - if gen_ind > 0 : - matrix_list = [ rep[gen_ind-1 ] for rep in rep_list ] + rep_list = [ch_algebra._fetch_matrix_list_from_chevie(i+1) for i in range(num_rep)] + if gen_ind > 0: + matrix_list = [rep[gen_ind - 1] for rep in rep_list] else: - matrix_list = [ invert_gen(rep[-gen_ind-1 ]) for rep in rep_list ] - + matrix_list = [invert_gen(rep[-gen_ind - 1]) for rep in rep_list] else: database = ch_algebra._database matrix_list = database.read_matrix_representation(representation_type, gen_ind, n, original_base_ring) - return matrix_list - @cached_method def _image_on_basis(self, basis_element): r""" - Return the image of the given basis element of the cubic Hecke algebra in ``self``. + Return the image of the given basis element of the cubic Hecke algebra + in ``self``. - INUPUT: + INPUT: - - ``basis_element`` -- instance of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeElement` which is a monomial + - ``basis_element`` -- instance of + :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeElement` + which is a monomial EXAMPLES:: @@ -871,9 +935,8 @@ def _image_on_basis(self, basis_element): [ 0 0 0 0 0 0 0 0 0 b^2 + a*c b 0] [ 0 0 0 0 0 0 0 0 0 b 1 a] """ - representation_type = self._representation_type - ch_algebra = self._cubic_hecke_algebra + ch_algebra = self._cubic_hecke_algebra filecache = ch_algebra._filecache original_base_ring = self._original_base_ring @@ -881,24 +944,25 @@ def _image_on_basis(self, basis_element): ele_Tietze = basis_element.Tietze() matrix_list = filecache.read_matrix_representation(representation_type, ele_Tietze, original_base_ring) if matrix_list is None: - verbose("not in memory %s (Tietze %s)" %(basis_element, ele_Tietze)) - if len(ele_Tietze) == 0 : + verbose('not in memory %s (Tietze %s)' % (basis_element, ele_Tietze), level=2) + if len(ele_Tietze) == 0: matrix_list = ch_algebra._create_matrix_list_for_one(representation_type) else: for gen_ind in ele_Tietze: gen_matrix_list = self._image_on_gen(gen_ind) - if matrix_list == None: - matrix_list = [m for m in gen_matrix_list] + if matrix_list is None: + matrix_list = [m for m in gen_matrix_list] else: for i in range(len(matrix_list)): matrix_list[i] *= gen_matrix_list[i] filecache.write_matrix_representation(representation_type, ele_Tietze, matrix_list) - verbose("%s saved to memory" %(basis_element)) + verbose('%s saved to memory' % basis_element, level=2) - mat = block_diagonal_matrix(matrix_list, subdivide=self._subdivide, sparse=True) + mat = block_diagonal_matrix(matrix_list, subdivide=self._subdivide, sparse=True) return self._specialize_matrix(mat) + @cached_method def zero(self): r""" Return the zero element of ``self``. @@ -926,6 +990,7 @@ def zero(self): z.set_immutable() return z + @cached_method def one(self): r""" Return the one element of ``self``. @@ -953,6 +1018,7 @@ def one(self): o.set_immutable() return o + @cached_method def _an_element_(self): r""" Return an element of ``self``. @@ -972,6 +1038,7 @@ def _an_element_(self): x = self._cubic_hecke_algebra.an_element() return self(x) + @cached_method def some_elements(self): r""" Return a generator of elements of ``self``. diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index c6bfa751ba2..98b424551b9 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -2,14 +2,36 @@ r""" Cubic Hecke Database -This module contains the class :class:`CubicHeckeDataBase` which serves as an interface to -Ivan Marin's data files with respect to the cubic Hecke algebras. Furthermore, it contains -the class :class:`CubicHeckeFileCache` which enables :class:`CubicHeckeAlgebra` to keep -intermediate results of calculations in the file system. +This module contains the class :class:`CubicHeckeDataBase` which serves as an +interface to `Ivan Marin's data files `__ +with respect to the cubic Hecke algebras. The data is available via a Python wrapper as a +pip installable package `database_cubic_hecke `__. +For installation hints please see the documentation there. +Anyway, all data needed for the cubic Hecke algebras on less than four strands is +included in this module for demonstration purpose (see for example +:func:`read_basis`, :func:`read_irr` , ... generated with the help of +:func:`create_demo_data`). + +In addition to Ivan Marin's data the package contains a function :func:`read_markov` +to obtain the coefficients of Markov traces on the cubic Hecke algebras. This +data has been precomputed with the help of ``create_markov_trace_data.py`` in the +`database_cubic_hecke repository `__. +Again, for less than four strands, this data is includes here for demonstration +purpose. + +Furthermore, this module contains the class :class:`CubicHeckeFileCache` which +enables :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebras.CubicHeckeAlgebra` +to keep intermediate results of calculations in the file system. + +Finally, there is an enum :class:`MarkovTraceModuleBasis` serving +as basis for the sub-module of linear forms on the cubic Hecke algebra on four +and less strands satisfying the Markov trace condition for its cubic Hecke +sub-algebras. AUTHORS: -- Sebastian Oehms May 2020: initial version +- Sebastian Oehms May 2020: initial version +- Sebastian Oehms March 2022: PyPi version and Markov trace functionality """ @@ -28,212 +50,117 @@ from enum import Enum from sage.structure.sage_object import SageObject -from sage.misc.persist import db_save, db, save, load +from sage.misc.persist import _base_dumps, load +from sage.misc.temporary_file import atomic_write from sage.misc.verbose import verbose -from sage.env import SAGE_SHARE, SAGE_ROOT -from sage.matrix.constructor import matrix, Matrix # uppercase version used in Marin's file `MatricesRegH4.maple` +from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ -from sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeRingOfDefinition +from sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeExtensionRing - - - -#---------------------------------------------------------------------------------------------------------------------------- -# functions to convert matrices and ring elements to and from flat python dictionaries in order to save matrices avoiding -# compatibility problems with older or newer sage versions and to save disc space -#---------------------------------------------------------------------------------------------------------------------------- -# conversion of ring element to dictionary -#---------------------------------------------------------------------------------------------------------------------------- -def convert_poly_to_dict_recursive(ring_elem): +# ------------------------------------------------------------------------------ +# functions to convert matrices and ring elements to and from flat python +# dictionaries in order to save matrices avoiding compatibility problems with +# older or newer sage versions and to save disc space +# ------------------------------------------------------------------------------ +def simplify(mat): r""" - Convert a ring element to a python dictionary recursively using the dict method of it. - By recursion the dictionaries values are converted as well as long as they posses a - ``dict`` method. If the values are sage Integers they are converted into python integers. + Convert a matrix to a dictionary consisting of flat Python objects. INPUT: - -- ``ring_elem`` - ring element to be converted into python dictionary + -- ``mat`` - matrix to be converted into python dictionary OUTPUT: - A python dictionary from which ``ring_elem`` can be reconstructed via element construction by recursion. - The values of the dictionary may be dictionaries again if the parent of ring_elem has a base_ring - different from itself. + A python dictionary from which ``mat`` can be reconstructed via + element construction. The values of the dictionary may be + dictionaries of tuples of integers or strings. EXAMPLES:: - sage: from sage.databases.cubic_hecke_db import convert_poly_to_dict_recursive - sage: L.=LaurentPolynomialRing(ZZ, 'c') - sage: P. = L['a,b']; P - Multivariate Polynomial Ring in a, b - over Univariate Laurent Polynomial Ring in c over Integer Ring - sage: elem = 5*b-3*a*~c; elem - (-3*c^-1)*a + 5*b - sage: convert_poly_to_dict_recursive(elem) - {(0, 1): {0: 5}, (1, 0): {-1: -3}} + sage: from sage.databases.cubic_hecke_db import simplify + sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: ER. = chbr.CubicHeckeExtensionRing() + sage: mat = matrix(ER, [[2*a, -3], [c, 4*b*~c]]); mat + [ 2*a -3] + [ c 4*b*c^-1] + sage: simplify(mat) + {(0, 0): {(1, 0, 0): {0: 2}}, + (0, 1): {(0, 0, 0): {0: -3}}, + (1, 0): {(0, 0, 1): {0: 1}}, + (1, 1): {(0, 1, -1): {0: 4}}} + sage: mat == matrix(ER, _) + True + sage: F = ER.fraction_field() + sage: matf = mat.change_ring(F) + sage: simplify(matf) + {(0, 0): '2*a', (0, 1): '-3', (1, 0): 'c', (1, 1): '4*b/c'} + sage: matf == matrix(F, _) + True """ - - dict_res = {} - if hasattr(ring_elem, 'dict'): - ring_elem_dict = ring_elem.dict() - for k in ring_elem_dict.keys(): - dict_res[k] = convert_poly_to_dict_recursive(ring_elem_dict[k]) + B = mat.base_ring() + d = mat.dict() + if isinstance(B, CubicHeckeExtensionRing): + # Laurent polynomial cannot be reconstructed from string + res = {k: {tuple(j): u.dict() for j, u in v.dict().items()} for k, v in d.items()} else: - if ring_elem in ZZ: - return int(ring_elem) - return ring_elem - return dict_res - - - - - - -#--------------------------------------------------------------------------------------------------------------------------- -# conversion of matrix to dictionary -#--------------------------------------------------------------------------------------------------------------------------- -def convert_mat_to_dict_recursive(mat): - r""" - Convert a matrix to a python dictionary using the dict method of it. Furthermore, the dictionaries - values are converted as well by the convert_poly_to_dict_recursive function. - - INPUT: - - - ``mat`` -- matrix to be converted into python dictionary - - OUTPUT: - - A python dictionary from which mat can be reconstructed via element construction. The values of the - dictionary may be dictionaries again if entries of the matrix have a dict method as well. - - EXAMPLES:: - - sage: from sage.databases.cubic_hecke_db import convert_mat_to_dict_recursive - sage: L.=LaurentPolynomialRing(ZZ, 'c') - sage: P. = L['a,b']; P - Multivariate Polynomial Ring in a, b - over Univariate Laurent Polynomial Ring in c over Integer Ring - sage: mat = matrix(P, [[2*a, -3], [c, 4*b*~c]]); mat - [ 2*a -3] - [ c (4*c^-1)*b] - sage: convert_mat_to_dict_recursive(mat) - {(0, 0): {(1, 0): {0: 2}}, - (0, 1): {(0, 0): {0: -3}}, - (1, 0): {(0, 0): {1: 1}}, - (1, 1): {(0, 1): {-1: 4}}} - """ + res = {k: str(v) for k, v in d.items()} + return res - mat_dict = {} - mat_dict_temp = mat.dict() - for k in mat_dict_temp.keys(): - mat_dict[k] = convert_poly_to_dict_recursive(mat_dict_temp[k]) - return mat_dict - - - -class CubicHeckeDataFilename(Enum): +class CubicHeckeDataSection(Enum): r""" - Enum for the different data files. The following choices are possible: - - - ``basis`` -- contains the basis for the cubic Hecke algebra up to 4 strands - - ``regular_left`` -- contains the left regular representation matrices of the generators - - ``regular_right`` -- contains the right regular representation matrices of the generators - - ``irred_split`` -- contains representation matrices of the generators of the split irreducible - representations + Enum for the different sections of the database. The following choices are + possible: + - ``basis`` -- list of basis elements + - ``reg_left_reprs`` -- data for the left regular representation + - ``reg_right_reprs`` -- data for the right regular representation + - ``irr_reprs`` -- data for the split irreducible representations + - ``markov_tr_cfs`` -- data for the coefficients of the formal Markov traces Examples:: sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase sage: cha_db = CubicHeckeDataBase() - sage: cha_db.filename - + sage: cha_db.section + """ - def download(self): - """ - Return the file name to download the data from Ivan Marin's web-page. - - Examples:: - - sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: cha_db = CubicHeckeDataBase() - sage: cha_db.filename.basis.download() - 'baseH4.maple' - """ - return self.value[0] - def py(self): - """ - Return the file name under which the data from Ivan Marin's web-page - are stored as python file. - - Examples:: - - sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: cha_db = CubicHeckeDataBase() - sage: cha_db.filename.basis.py() - 'baseH4.maple.py' - """ - return '%s.py' %(self.value[0]) - - def sobj(self, nstrands=None): - """ - Return the file name under which the data from Ivan Marin's web-page - is converted into sobj-files. - - INPUT: - - - ``nstrands`` -- Integer number of strands of the underlying braid group - if the data file depends on it. Otherwise use default None - - Examples:: - - sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: cha_db = CubicHeckeDataBase() - sage: cha_db.filename.basis.sobj() - 'monomial_basis.sobj' - sage: cha_db.filename.basis.sobj() - 'monomial_basis.sobj' - sage: cha_db.filename.irred_split.sobj(2) - 'irred_split_reprs_2.sobj' - sage: cha_db.filename.regular_left.sobj(3) - 'regular_left_reprs_3.sobj' - """ - if nstrands is None: - return '%s.sobj' %(self.value[1]) - else: - return '%s_%s.sobj' %(self.value[1], nstrands) - - basis = ['baseH4.maple', 'monomial_basis'] - regular_left = ['MatricesRegH4.maple', 'regular_left_reprs'] - regular_right = ['MatricesRegH4right.maple', 'regular_right_reprs'] - irred_split = ['RepresentationsH25', 'irred_split_reprs'] + basis = 'basis' + regular_left = 'regular_left' + regular_right = 'regular_right' + split_irred = 'split_irred' + markov_tr_cfs = 'markov_tr_cfs' - - - -#---------------------------------------------------------------------------------------------------------------------------- -# Class to supply data for the basis and matrix representation for the cubic Hecke algebra -#---------------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------- +# Class to supply data for the basis and matrix representation for the cubic +# Hecke algebra +# ------------------------------------------------------------------------------- class CubicHeckeDataBase(SageObject): r""" - Database interface needed for :class:`CubicHeckeAlgebra`. + Database interface needed for :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebras.CubicHeckeAlgebra` - The original data are obtained from Ivan Marin's web-page (URL see the example below). In order - to have these data installed during the build process as a sage-package they are converted - as python files into a tarball. This tarball has been created using the method :meth:`create_spkg_tarball`. + The original data are obtained from + `Ivan Marin's web page `__ + + The data needed to work with the cubic Hecke algebras on less than 4 strands + is completely contained in this module. Data needed for the larger algebras + can be installed as an optional Sage package which comes as a *pip* installable + `Python wrapper `__ of + Ivan Marin's data. For more information see the + `corresponding repository `__. EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase sage: cha_db = CubicHeckeDataBase() - sage: cha_db._url_marin - 'http://www.lamfa.u-picardie.fr/marin/softs/H4' + sage: cha_db._feature + Feature('database_cubic_hecke') """ - filename = CubicHeckeDataFilename + section = CubicHeckeDataSection def __init__(self): r""" @@ -242,28 +169,14 @@ def __init__(self): EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: from sage.env import SAGE_SHARE sage: cha_db = CubicHeckeDataBase() - sage: cha_db._import_path_sobj == SAGE_SHARE + '/cubic_hecke_marin/sobj' - True + sage: cha_db._data_library + {} """ - self._url_marin = 'http://www.lamfa.u-picardie.fr/marin/softs/H4' - - self._package = 'cubic_hecke_marin' - version_file = os.path.join(SAGE_ROOT, 'build/pkgs/%s/package-version.txt' %self._package) - f = open(version_file) - self._version = f.read().splitlines()[0] - f.close() - - self._import_path = os.path.join(SAGE_SHARE, self._package) - self._import_path_py = os.path.join(self._import_path, 'py') - self._import_path_sobj = os.path.join(self._import_path, 'sobj') - - from sage.misc.misc import sage_makedirs - sage_makedirs(self._import_path_py) - sage_makedirs(self._import_path_sobj) - + from sage.features.databases import DatabaseCubicHecke + self._feature = DatabaseCubicHecke() self._data_library = {} + self._demo = None def version(self): r""" @@ -273,437 +186,483 @@ def version(self): sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase sage: cha_db = CubicHeckeDataBase() - sage: cha_db.version() - '20200513' + sage: cha_db.version() > '2022.1.1' # optional - database_cubic_hecke + True """ - return self._version + self._feature.require() + from database_cubic_hecke import version + return version() - def _create_python_file(self, filename): + def demo_version(self): r""" - Return the data fetched from Iwan Marin's homepage as a python file - such that it can be loaded via `sage_eval`. + Return whether the cubic Hecke database is installed completely or + just the demo version is used. EXAMPLES:: - sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: cha_db = CubicHeckeDataBase() - sage: load(cha_db._create_python_file(cha_db.filename.basis)) # not tested (because of internet access) - Importing data for monomial_basis.sobj from http://www.lamfa.u-picardie.fr/marin/softs/H4/baseH4.maple - sage: len(baseH4) # not tested - 648 + sage: from sage.databases.knotinfo_db import KnotInfoDataBase + sage: ki_db = KnotInfoDataBase() + sage: ki_db.demo_version() # optional - database_knotinfo + False """ - if not isinstance(filename, CubicHeckeDataBase.filename): - raise TypeError('File name must be an instance of enum %s' (CubicHeckeDataBase.filename)) + if self._demo is None: + if self._feature.is_present(): + self._demo = False + else: + self._demo = True + return self._demo - import_file = '%s/%s' %(self._import_path_py, filename.py()) + # -------------------------------------------------------------------------- + # read from an sobj-file obtained from Ivan Marin's database + # -------------------------------------------------------------------------- + def read(self, section, variables=None, nstrands=4): + r""" + Access various static data library. - # import directly from the internet page - from six.moves.urllib.request import urlopen - try: - from urllib.error import HTTPError - except ImportError: - from urllib2 import HTTPError + INPUT: - try: - url = '%s/%s' %(self._url_marin, filename.download()) - url_data = urlopen(url).read().decode() - print('Importing data for %s from %s' %(filename.sobj(), url)) - preparsed_data =url_data.replace(':=', '=').replace(';', '').replace('^', '**') - f = open(import_file, 'wt') - f.write(preparsed_data) - f.close() - return import_file - except HTTPError: - raise IOError('Data import file %s not found! Internet connection needed!' %(filename)) + ``section`` -- instance of enum :class:`CubicHeckeDataSection` + to select the data to be read in - def create_spkg_tarball(self): - r""" - Create a tarball for the sage-package ``cubic_heck_marin`` in the ``upstream`` directory. This - utility should only be used by users who know what they do in case of a switch to a new - version of the data files (that is if the original files on Iwan Marin's homepage have changed). - In that case in invocation of ``sage -package fix-checksum cubic_hecke_marin`` will be necessary. + OUTPUT: + + A dictionary containing the data corresponding to the section. EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase sage: cha_db = CubicHeckeDataBase() - sage: cha_db.create_spkg_tarball() # not tested (because of internet access) - Importing data for monomial_basis.sobj - from http://www.lamfa.u-picardie.fr/marin/softs/H4/baseH4.maple - Importing data for regular_left_reprs.sobj - from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4.maple - Importing data for regular_right_reprs.sobj - from http://www.lamfa.u-picardie.fr/marin/softs/H4/MatricesRegH4right.maple - Importing data for irred_split_reprs.sobj - from http://www.lamfa.u-picardie.fr/marin/softs/H4/RepresentationsH25 - py/ - py/MatricesRegH4.maple.py - py/MatricesRegH4right.maple.py - py/RepresentationsH25.py - py/baseH4.maple.py + sage: basis = cha_db.read(cha_db.section.basis, nstrands=3) + sage: len(basis) + 24 """ - for filename in CubicHeckeDataBase.filename: - self._create_python_file(filename) - os.system('cd %s; tar -cvjSf %s/upstream/%s-%s.tar.bz2 py' %(self._import_path, SAGE_ROOT, self._package, self._version) ) + if not isinstance(section, CubicHeckeDataSection): + raise TypeError('section must be an instance of enum %s' % CubicHeckeDataBase.section) - def import_data(self, filename, from_spkg=True): - r""" - EXAMPLES:: + data_lib = self._data_library - sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: cha_db = CubicHeckeDataBase() - sage: load(cha_db.import_data(cha_db.filename.basis)) - sage: len(baseH4) - 648 - """ - if not isinstance(filename, CubicHeckeDataBase.filename): - raise TypeError('File name must be an instance of enum %s' (CubicHeckeDataBase.filename)) + nstrands = int(nstrands) + if (section, nstrands) in data_lib.keys(): + return data_lib[(section, nstrands)] - import_file = '%s/%s' %(self._import_path_py, filename.py()) + verbose('loading data library %s for %s strands ...' % (section.value, nstrands)) - try: - open(import_file) - return import_file - except IOError: - if from_spkg: - # import from the spkg tarball - print('Importing cubic Hecke database from SPKG!') - os.system('pwd') - os.system('cp src/*.py %s' %(self._import_path_py)) - open(import_file) - return import_file + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import GenSign + + if self.demo_version(): + if nstrands >= 4: + self._feature.require() + from .cubic_hecke_db import read_basis, read_irr, read_regl, read_regr, read_markov + else: + from database_cubic_hecke import read_basis, read_irr, read_reg + from database_cubic_hecke.markov_trace_coeffs import read_markov + + def read_regl(variables, num_strands): + return read_reg(variables, num_strands=num_strands) + + def read_regr(variables, num_strands): + return read_reg(variables, right=True, num_strands=num_strands) + + if section == CubicHeckeDataSection.basis: + data_lib[(section, nstrands)] = read_basis(nstrands) + elif section == CubicHeckeDataSection.markov_tr_cfs: + keys = [k for k in MarkovTraceModuleBasis if k.strands() <= nstrands] + res = {k: read_markov(k.name, variables, num_strands=nstrands) for k in keys} + data_lib[(section, nstrands)] = res + elif section == CubicHeckeDataSection.split_irred: + dim_list, repr_list, repr_list_inv = read_irr(variables, nstrands) + data_lib[(section, nstrands)] = {GenSign.pos: repr_list, GenSign.neg: repr_list_inv} + else: + if section == CubicHeckeDataSection.regular_right: + dim_list, repr_list, repr_list_inv = read_regr(variables, nstrands) else: - return self._create_python_file(filename) - + dim_list, repr_list, repr_list_inv = read_regl(variables, nstrands) + data_lib[(section, nstrands)] = {GenSign.pos: repr_list, GenSign.neg: repr_list_inv} + + verbose('... finished!') + return data_lib[(section, nstrands)] - def create_static_db_marin_basis(self): + # -------------------------------------------------------------------------- + # matrix_reprs_from_file_cache_ + # -------------------------------------------------------------------------- + def read_matrix_representation(self, representation_type, gen_ind, nstrands, ring_of_definition): r""" - Create the basis of the cubic Hecke algebra according to the original - data from Iwan Marin's home page. + Return the matrix representations from the database. + + INPUT: + + - ``representation_type`` -- instance of enum + :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + specifying the type of the representation - This method is called during the build procedure for the sage-package. + + OUTPUT: EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: cha_db = CubicHeckeDataBase() - sage: cha_db.create_static_db_marin_basis() + sage: CHA3 = algebras.CubicHecke(2) + sage: GER = CHA3.extension_ring(generic=True) + sage: cha_db = CHA3._database + sage: rt = CHA3.repr_type + sage: m1 =cha_db.read_matrix_representation(rt.SplitIrredMarin, 1, 3, GER) + sage: len(m1) + 7 + sage: GBR = CHA3.base_ring(generic=True) + sage: m1rl = cha_db.read_matrix_representation(rt.RegularLeft, 1, 3, GBR) + sage: m1rl[0].dimensions() + (24, 24) """ - global baseH4 # set by load - load(self.import_data(self.filename.basis)) - - basis_h1 = [] - basis_h2 = [] - basis_h3 = [] - basis_h4 = baseH4 - - len_baseH4 = len(baseH4) + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType, GenSign + if not isinstance(representation_type, RepresentationType): + raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) - ind_h1 = [] - ind_h2 = [] - ind_h3 = [] - ind_h4 = range(len_baseH4) + td = ring_of_definition.gens_dict_recursive() + if 'e3' in td.keys(): + td['j'] = td['e3'] + td.pop('e3') + v = tuple(td.values()) - for i in ind_h4: - set_i = set(baseH4[i]) - if 3 not in set_i and -3 not in set_i: - basis_h3.append( basis_h4[i] ) - ind_h3.append(i) - if 2 not in set_i and -2 not in set_i: - basis_h2.append( basis_h4[i] ) - ind_h2.append(i) - if 1 not in set_i and -1 not in set_i: - basis_h1.append( basis_h4[i] ) - ind_h1.append(i) + num_rep = representation_type.number_of_representations(nstrands) + rep_list = self.read(representation_type.data_section(), variables=v, nstrands=nstrands) + if gen_ind > 0: + rep_list = [rep_list[GenSign.pos][i] for i in range(num_rep)] + matrix_list = [matrix(ring_of_definition, rep[gen_ind-1], sparse=True) for rep in rep_list] + else: + # data of inverse of generators is stored under negative strand-index + rep_list = [rep_list[GenSign.neg][i] for i in range(num_rep)] + matrix_list = [matrix(ring_of_definition, rep[-gen_ind-1], sparse=True) for rep in rep_list] + for m in matrix_list: + m.set_immutable() + return matrix_list - # len_bas_h1 = len(basis_h1); len_bas_h2 = len(basis_h2); len_bas_h3 = len(basis_h3) - basis = {1:[basis_h1, ind_h1], 2:[basis_h2, ind_h2], 3: [basis_h3, ind_h3], 4:[basis_h4, ind_h4]} - save(basis, '%s/%s' %(self._import_path_sobj, self.filename.basis.sobj()) ) +class MarkovTraceModuleBasis(Enum): + r""" + Enum for the basis elements for the Markov trace module. The choice of + the basis elements doesn't have a systematically background apart from + generating the sub-module of maximal rank in the module of linear forms + on the cubic Hecke algebra for which the Markov trace condition with + respect to its cubic Hecke sub-algebras hold. The number of crossings in + the corresponding links is chosen as minimal as possible. + EXAMPLES:: - def create_static_db_marin_regular(self, right=False): + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.K92.description() + 'knot 9_34' + """ + def __repr__(self): r""" - Create the static data base for regular representations of the cubic - Hecke algebra according to the original data from Iwan Marin's home page. - - This method is called during the build procedure for the sage-package. - - The invocations are not active in the doctest, since they cause a ``MemoryError`` - here. To refresh the data base you may call this method in a session. You will - have to wait (maybe up to several minutes)! + Return a string representation of ``self``. EXAMPLES:: - sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: cha_db = CubicHeckeDataBase() - sage: cha_db.create_static_db_marin_regular() # not tested - sage: cha_db.create_static_db_marin_regular(right=True) # not tested + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.U2 # indirect doctest + U2 """ - - base_ring = CubicHeckeRingOfDefinition() - global u, v, w, mm1, mm2, mm3, mm1I, mm2I, mm3I, reps # set in load - u, v, w = base_ring.gens_over_ground() - - if right == False: - fname = self.filename.regular_left - else: - fname = self.filename.regular_right - before = verbose('start loading %s' %fname) - load(self.import_data(fname)) - before = verbose('end loading %s' %fname, t=before) + return self.name - - def create_mat(ind_h, mat_h4): - """ - Create restriction of regular representation of H4 to H1, H2 and H3 - """ - - dim_mat = len(ind_h) - mat = matrix(dim_mat, dim_mat, lambda i,j: mat_h4[ind_h[i], ind_h[j]]) - return convert_mat_to_dict_recursive(mat) - - basis = self.read(self.filename.basis) - ind_h1 = basis[1][1] - ind_h2 = basis[2][1] - ind_h3 = basis[3][1] - - representationH ={} - representationH[0] = [[create_mat(ind_h1, mm1)]] - representationH[1] = [[create_mat(ind_h2, mm1)]] - representationH[2] = [[create_mat(ind_h3, mm1), create_mat(ind_h3, mm2)]] - representationH[3] = [[convert_mat_to_dict_recursive(mm1), convert_mat_to_dict_recursive(mm2), convert_mat_to_dict_recursive(mm3)]] - - representationHI ={} - representationHI[0] = [[create_mat(ind_h1, mm1I)]] - representationHI[1] = [[create_mat(ind_h2, mm1I)]] - representationHI[2] = [[create_mat(ind_h3, mm1I), create_mat(ind_h3, mm2I)]] - representationHI[3] = [[convert_mat_to_dict_recursive(mm1I), convert_mat_to_dict_recursive(mm2I), convert_mat_to_dict_recursive(mm3I)]] - from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import GenSign - - for i in range(4): - if right == False: - sobj_filename = '%s/%s' %(self._import_path_sobj, self.filename.regular_left.sobj(i+1)) - else: - sobj_filename = '%s/%s' %(self._import_path_sobj, self.filename.regular_right.sobj(i+1)) + def __gt__(self, other): + r""" + Implement comparison of different items in order to have ``sorted`` work. - RegularMarinDict = {GenSign.pos:representationH[i], GenSign.neg:representationHI[i]} - save(RegularMarinDict, sobj_filename ) - return + EXAMPLES:: + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: sorted(MarkovTraceModuleBasis) + [U1, U2, U3, K4, U4, K4U, K6, K7, K91, K92] + """ + if self.__class__ is other.__class__: + tups = (self.strands(), len(self.braid_tietze()), self.name) + tupo = (other.strands(), len(other.braid_tietze()), other.name) + return tups > tupo + return NotImplemented - def create_static_db_marin_split(self): + def strands(self): r""" - Create the static data base for split irreducible representations of the cubic - Hecke algebra according to the original data from Iwan Marin's home page. - - This method is called during the build procedure for the sage-package. + Return the number of strands of the minimal braid representative of the + link corresponding to ``self``. EXAMPLES:: - sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: cha_db = CubicHeckeDataBase() - sage: cha_db.create_static_db_marin_split() + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.K7.strands() + 4 """ - # ------------------------------------------------------ - # Ivan Marin's data file uses a, b, c for the variables - # corresponding to the eigenvalues of the cubic equation. - # Therefore, we have to use them temporarily in that way - # ------------------------------------------------------ - base_ring = CubicHeckeRingOfDefinition() - extension_ring = base_ring.extension_ring() - global a, b, c, j - a, b, c = extension_ring.gens() - j = extension_ring.cyclotomic_generator() - - load(self.import_data(self.filename.irred_split)) - - a, b, c = base_ring.gens_over_ground() # now back to usual nameing - cfs = [-c, b, -a, 1] - cfse = [extension_ring(cf/c) for cf in cfs] - - def invert(matr): - """ - Return inverse matrix for generators - """ - - matri = cfse[1]*matr.parent().one() - matri += cfse[2]*matr - matri += cfse[3]*matr**2 - d1, d2 = matr.dimensions() - matrI = matrix(extension_ring, d1, d2, lambda i,j: extension_ring(matri[i,j])) - return matrI - - # ------------------------------------------------------------------------------------------------ - # Restoring the split irreducibles from Iwan Marin's homepage - # ------------------------------------------------------------------------------------------------ - - anz_reps = len(reps) - - representation_h ={} - representation_h[0] = [[convert_mat_to_dict_recursive(Matrix(1,1,[extension_ring.one()]))]] - representation_h[1] = [] - representation_h[2] = [] - representation_h[3] = [] - - representation_hI ={} - representation_hI[0] = representation_h[0] - representation_hI[1] = [] - representation_hI[2] = [] - representation_hI[3] = [] - for i in range( anz_reps ): - repi = reps[i] - if len(repi) != 3: - raise RuntimeError( 'Error at position %d: three generators expected, got: %d' %( i, len(repi))) - mt = [] - mtI = [] - for j in range(3): - mat = matrix(repi[j]) - matI = invert(mat) - mt.append(convert_mat_to_dict_recursive(mat)) - mtI.append(convert_mat_to_dict_recursive(matI)) - - representation_h[3].append( mt ) - representation_hI[3].append( mtI ) - - if i < 7: - mt7 = [ m for m in mt ] - mt7I = [ m for m in mtI ] - mt7.pop() - mt7I.pop() - representation_h[2].append( mt7 ) - representation_hI[2].append( mt7I ) - - if i < 3: - mt3 = [ m for m in mt7 ] - mt3I = [ m for m in mt7I ] - mt3.pop() - mt3I.pop() - representation_h[1].append( mt3 ) - representation_hI[1].append( mt3I ) - - from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import GenSign - for i in range(4): - sobj_filename = '%s/%s' %(self._import_path_sobj, self.filename.irred_split.sobj(i+1)) - SplitIrredMarinDict = {GenSign.pos:representation_h[i], GenSign.neg:representation_hI[i]} - save(SplitIrredMarinDict, sobj_filename) + return self.value[1] - return - - # ------------------------------------------------------------------------------------------------------------- - # read from an sobj-file obtained from Ivan Marin's database - # ------------------------------------------------------------------------------------------------------------- - def read(self, db_filename, nstrands=None): + def braid_tietze(self, strands_embed=None): r""" - Access various static data library. + Return the Tietze representation of the braid corresponding to this basis + element. INPUT: - ``db_filename`` -- instance of enum :class:`CubicHeckeDataBase.filename` - to select the data to be read in + - ``strands_embed`` -- (optional) the number of strands of the braid + if strands should be added. OUTPUT: - A dictionary containing the data corresponding to the db_filename. + A tuple representing the braid in Tietze form. EXAMPLES:: - sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: cha_db = CubicHeckeDataBase() - sage: basis = cha_db.read(cha_db.filename.basis) - sage: len(basis[3][0]) - 24 + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.U2.braid_tietze() + () + sage: MarkovTraceModuleBasis.U2.braid_tietze(strands_embed=4) + (2, 3) """ - if not isinstance(db_filename, CubicHeckeDataFilename): - raise TypeError('db_filename must be an instance of enum %s' (CubicHeckeDataBase.filename)) + if not strands_embed: + strands_embed = self.strands() - data_lib = self._data_library - lib_path = self._import_path_sobj + if strands_embed > self.strands(): + last_gen = strands_embed-1 + return self.braid_tietze(strands_embed=last_gen) + (last_gen,) + else: + return self.value[2] - if (db_filename, nstrands) in data_lib.keys(): - return data_lib[(db_filename, nstrands)] + def writhe(self): + r""" + Return the writhe of the link corresponding to this basis element. - verbose('loading data library %s ...' %(db_filename.sobj(nstrands=nstrands))) - try: - data_lib[(db_filename,nstrands)] = load('%s/%s' %(lib_path, db_filename.sobj(nstrands=nstrands))) - except IOError: - if db_filename == self.filename.basis: - self.create_static_db_marin_basis() - elif db_filename == self.filename.irred_split: - self.create_static_db_marin_split() - elif db_filename == self.filename.regular_right: - self.create_static_db_marin_regular(right=True) - else: - self.create_static_db_marin_regular() - data_lib[(db_filename, nstrands)] = load('%s/%s' %(lib_path, db_filename.sobj(nstrands=nstrands))) + EXAMPLES:: - verbose('... finished!') + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.K4.writhe() + 0 + sage: MarkovTraceModuleBasis.K6.writhe() + 1 + """ + from sage.functions.generalized import sign + return sum(sign(t) for t in self.braid_tietze()) - return data_lib[(db_filename,nstrands)] + def description(self): + r""" + Return a description of the link corresponding to this basis element. + In the case of knots it refers to the naming according to + `KnotInfo `__. + EXAMPLES:: - # ------------------------------------------------------------------------------------------------------------- - # matrix_reprs_from_file_cache_ - # ------------------------------------------------------------------------------------------------------------- - def read_matrix_representation(self, representation_type, gen_ind, nstrands, ring_of_definition): + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.U3.description() + 'three unlinks' + """ + return self.value[0] + + def link(self): r""" - Return the matrix representations from the database. + Return the link which represents this basis element as instance of + :class:`Link`. - INPUT: + EXAMPLES:: - - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` - specifying the type of the representation + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.U1.link() + Link with 1 component represented by 0 crossings + sage: MarkovTraceModuleBasis.K4.link() + Link with 1 component represented by 4 crossings + """ + from sage.knots.link import Link + pd_code = self.value[3] + if pd_code is not None: + # since :class:`Link` does not construct disjoint union of unlinks + # from the braid representation, we need a pd_code here + return Link(pd_code) + else: + from sage.groups.braid import BraidGroup + B = BraidGroup(self.strands()) + return Link(B(self.braid_tietze())) + def regular_homfly_polynomial(self): + r""" + Return the regular variant of the KOMFLY-PT polynomial of the link which + represents this basis element. This is the HOMFLY-PT polynomial + renormalized by the writhe factor such that it is an invariant of + regular isotopy. OUTPUT: + An instance of :class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`. + EXAMPLES:: - sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase - sage: CHA3 = algebras.CubicHecke(2) - sage: GER = CHA3.extension_ring(generic=True) - sage: cha_db = CHA3._database - sage: rt = CHA3.repr_type - sage: m1 =cha_db.read_matrix_representation(rt.SplitIrredMarin, 1, 3, GER) - sage: len(m1) - 7 - sage: GBR = CHA3.base_ring(generic=True) - sage: m1rl = cha_db.read_matrix_representation(rt.RegularLeft, 1, 3, GBR) - sage: m1rl[0].dimensions() - (24, 24) + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.U1.regular_homfly_polynomial() + 1 + sage: u2 = MarkovTraceModuleBasis.U2.regular_homfly_polynomial(); u2 + -L*M^-1 - L^-1*M^-1 + sage: u2**2 == MarkovTraceModuleBasis.U3.regular_homfly_polynomial() + True + sage: u2**3 == MarkovTraceModuleBasis.U4.regular_homfly_polynomial() + True """ - from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType, GenSign - if not isinstance(representation_type, RepresentationType): - raise TypeError('representation_type must be an instance of enum %s' (RepresentationType)) + H = self.link().homfly_polynomial() + L, M = H.parent().gens() + return H*L**self.writhe() - num_rep = representation_type.number_of_representations(nstrands) - rep_list = self.read(representation_type.data_filename(), nstrands=nstrands) - if gen_ind > 0 : - rep_list = [rep_list[GenSign.pos][i] for i in range(num_rep)] - matrix_list = [matrix(ring_of_definition, rep[gen_ind-1 ], sparse=True) for rep in rep_list] - else: - # data of inverse of generators is stored under negative strand-index - rep_list = [rep_list[GenSign.neg][i] for i in range(num_rep) ] - matrix_list = [matrix(ring_of_definition, rep[-gen_ind-1 ], sparse=True) for rep in rep_list] - for m in matrix_list: m.set_immutable() - return matrix_list + def regular_kauffman_polynomial(self): + r""" + Return the regular variant of the Kauffman polynomial of the link which + represents this basis element. This is the Kauffman polynomial + renormalized by the writhe factor such that it is an invariant of + regular isotopy. + + OUTPUT: + An instance of :class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`. + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.U1.regular_homfly_polynomial() + 1 + sage: u2 = MarkovTraceModuleBasis.U2.regular_kauffman_polynomial(); u2 + a*z^-1 - 1 + a^-1*z^-1 + sage: u2**2 == MarkovTraceModuleBasis.U3.regular_kauffman_polynomial() + True + sage: u2**3 == MarkovTraceModuleBasis.U4.regular_kauffman_polynomial() + True + """ + from sage.knots.knotinfo import KnotInfo + K = KnotInfo.L2a1_1.kauffman_polynomial().parent() + a, z = K.gens() + d = kauffman[self.name] + if d: + return K(d)*a**self.writhe() + U2rkp = MarkovTraceModuleBasis.U2.regular_kauffman_polynomial() + if self.name == 'K4U': + K4rkp = MarkovTraceModuleBasis.K4.regular_kauffman_polynomial() + return K4rkp * U2rkp + exp = self.strands() - 1 + return U2rkp**exp + + def links_gould_polynomial(self): + r""" + Return the Links-Gould polynomial of the link which represents this + basis element. + + OUTPUT: + + An instance of :class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + sage: MarkovTraceModuleBasis.U1.links_gould_polynomial() + 1 + sage: MarkovTraceModuleBasis.U2.links_gould_polynomial() + 0 + sage: MarkovTraceModuleBasis.K4.links_gould_polynomial() + 2*t0*t1 - 3*t0 - 3*t1 + t0*t1^-1 + 7 + t0^-1*t1 + - 3*t1^-1 - 3*t0^-1 + 2*t0^-1*t1^-1 + """ + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + R = LaurentPolynomialRing(ZZ, 't0, t1') + return R(links_gould[self.name]) + + U1 = ['one unlink', 1, (), []] + U2 = ['two unlinks', 2, (), [[3, 1, 4, 2], [4, 1, 3, 2]]] + U3 = ['three unlinks', 3, (), [[3, 7, 4, 8], [4, 7, 5, 8], + [5, 1, 6, 2], [6, 1, 3, 2]]] + U4 = ['four unlinks', 4, (), [[3, 9, 4, 10], [4, 9, 5, 10], [5, 11, 6, 12], + [6, 11, 7, 12], [7, 1, 8, 2], [8, 1, 3, 2]]] + K4U = ['knot 4_1 plus one unlink', 4, (1, -2, 1, -2), + [[3, 8, 4, 9], [9, 7, 10, 6], [7, 4, 8, 5], [5, 11, 6, 10], + [11, 1, 12, 2], [12, 1, 3, 2]]] + K4 = ['knot 4_1', 3, (1, -2, 1, -2), None] + K6 = ['knot 6_1', 4, (1, 1, 2, -1, -3, 2, -3), None] + K7 = ['knot 7_4', 4, (1, 1, 2, -1, 2, 2, 3, -2, 3), None] + K91 = ['knot 9_29', 4, (1, -2, -2, 3, -2, 1, -2, 3, -2), None] + K92 = ['knot 9_34', 4, (-1, 2, -1, 2, -3, 2, -1, 2, -3), None] + + +kauffman = { + 'U1': 1, + 'U2': {(1, -1): 1, (0, 0): -1, (-1, -1): 1}, + 'U3': None, + 'U4': None, + 'K4U': None, + 'K4': {(2, 2): 1, (1, 3): 1, (2, 0): -1, (1, 1): -1, (0, 2): 2, (-1, 3): 1, + (0, 0): -1, (-1, 1): -1, (-2, 2): 1, (-2, 0): -1}, + 'K6': {(2, 2): 1, (1, 3): 1, (0, 4): 1, (-1, 5): 1, (2, 0): -1, (-1, 3): -2, + (-2, 4): 2, (-3, 5): 1, (-1, 1): 2, (-2, 2): -4, (-3, 3): -3, (-4, 4): 1, + (-2, 0): 1, (-3, 1): 2, (-4, 2): -3, (-4, 0): 1}, + 'K7': {(-2, 2): 1, (-3, 3): 2, (-4, 4): 3, (-5, 5): 2, (-6, 6): 1, (-4, 2): -4, + (-5, 3): -2, (-7, 5): 3, (-8, 6): 1, (-4, 0): 2, (-6, 2): -3, (-7, 3): -8, + (-8, 4): -3, (-9, 5): 1, (-7, 1): 4, (-8, 2): 2, (-9, 3): -4, (-8, 0): -1, + (-9, 1): 4}, + 'K91': {(7, 3): 1, (6, 4): 3, (5, 5): 6, (4, 6): 8, (3, 7): 6, (2, 8): 2, + (5, 3): -5, (4, 4): -13, (3, 5): -8, (2, 6): 6, (1, 7): 9, (0, 8): 2, + (5, 1): 2, (4, 2): 8, (3, 3): -1, (2, 4): -24, (1, 5): -24, (0, 6): -1, + (-1, 7): 3, (4, 0): -2, (3, 1): 2, (2, 2): 17, (1, 3): 14, (0, 4): -11, + (-1, 5): -10, (-2, 6): 1, (2, 0): -5, (1, 1): -1, (0, 2): 12, (-1, 3): 9, + (-2, 4): -3, (0, 0): -3, (-1, 1): -1, (-2, 2): 3, (-2, 0): -1}, + 'K92': {(5, 5): 1, (4, 6): 4, (3, 7): 6, (2, 8): 3, (5, 3): -1, (4, 4): -7, + (3, 5): -11, (2, 6): 5, (1, 7): 14, (0, 8): 3, (4, 2): 3, (3, 3): 5, + (2, 4): -19, (1, 5): -26, (0, 6): 9, (-1, 7): 8, (2, 2): 10, (1, 3): 12, + (0, 4): -23, (-1, 5): -10, (-2, 6): 8, (2, 0): -1, (1, 1): -1, + (0, 2): 11, (-1, 3): 4, (-2, 4): -10, (-3, 5): 4, (0, 0): -1, + (-1, 1): -1, (-2, 2): 4, (-3, 3): -2, (-4, 4): 1, (-2, 0): -1}} + + +links_gould = { + 'U1': 1, + 'U2': 0, + 'U3': 0, + 'U4': 0, + 'K4U': 0, + 'K4': {(1, 1): 2, (1, 0): -3, (0, 1): -3, (1, -1): 1, (0, 0): 7, (-1, 1): 1, + (0, -1): -3, (-1, 0): -3, (-1, -1): 2}, + 'K6': {(2, 2): 2, (2, 1): -3, (1, 2): -3, (2, 0): 1, (1, 1): 10, (0, 2): 1, + (1, 0): -10, (0, 1): -10, (1, -1): 3, (0, 0): 17, (-1, 1): 3, (0, -1): -7, + (-1, 0): -7, (-1, -1): 4}, + 'K7': {(4, 3): -1, (3, 4): -1, (4, 2): 1, (3, 3): 6, (2, 4): 1, (3, 2): -11, + (2, 3): -11, (3, 1): 6, (2, 2): 28, (1, 3): 6, (2, 1): -27, (1, 2): -27, + (2, 0): 9, (1, 1): 38, (0, 2): 9, (1, 0): -17, (0, 1): -17, (0, 0): 9}, + 'K91': {(2, 2): 6, (2, 1): -20, (1, 2): -20, (2, 0): 29, (1, 1): 76, (0, 2): 29, + (2, -1): -25, (1, 0): -123, (0, 1): -123, (-1, 2): -25, (2, -2): 14, + (1, -1): 116, (0, 0): 217, (-1, 1): 116, (-2, 2): 14, (2, -3): -5, + (1, -2): -71, (0, -1): -216, (-1, 0): -216, (-2, 1): -71, (-3, 2): -5, + (2, -4): 1, (1, -3): 27, (0, -2): 136, (-1, -1): 214, (-2, 0): 136, + (-3, 1): 27, (-4, 2): 1, (1, -4): -5, (0, -3): -50, (-1, -2): -122, + (-2, -1): -122, (-3, 0): -50, (-4, 1): -5, (0, -4): 8, (-1, -3): 37, + (-2, -2): 52, (-3, -1): 37, (-4, 0): 8, (-1, -4): -4, (-2, -3): -9, + (-3, -2): -9, (-4, -1): -4}, + 'K92': {(3, 1): 6, (2, 2): 12, (1, 3): 6, (3, 0): -15, (2, 1): -63, (1, 2): -63, + (0, 3): -15, (3, -1): 14, (2, 0): 112, (1, 1): 216, (0, 2): 112, + (-1, 3): 14, (3, -2): -6, (2, -1): -92, (1, 0): -334, (0, 1): -334, + (-1, 2): -92, (-2, 3): -6, (3, -3): 1, (2, -2): 37, (1, -1): 262, + (0, 0): 503, (-1, 1): 262, (-2, 2): 37, (-3, 3): 1, (2, -3): -6, + (1, -2): -104, (0, -1): -400, (-1, 0): -400, (-2, 1): -104, (-3, 2): -6, + (1, -3): 17, (0, -2): 162, (-1, -1): 330, (-2, 0): 162, (-3, 1): 17, + (0, -3): -27, (-1, -2): -136, (-2, -1): -136, (-3, 0): -27, (-1, -3): 22, + (-2, -2): 54, (-3, -1): 22, (-2, -3): -7, (-3, -2): -7}} class CubicHeckeFileCache(SageObject): """ - A class to cache calculations of the :class:`CubicHeckeAlgebra` in the local file system. + A class to cache calculations of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebras.CubicHeckeAlgebra` + in the local file system. """ class section(Enum): r""" - Enum for the different sections of file cache. The following choices are possible: + Enum for the different sections of file cache. The following choices are + possible: - - ``matrix_representations`` -- file cache for representation matrices of basis elements + - ``matrix_representations`` -- file cache for representation matrices + of basis elements - ``braid_images`` -- file cache for images of braids - - ``basis_extensions`` -- file cache for a dynamical growing basis used in the case of - cubic Hecke algebras on more than 4 strands + - ``basis_extensions`` -- file cache for a dynamical growing basis used + in the case of cubic Hecke algebras on more than 4 strands + - ``markov_trace`` -- file cache for intermediate results of long + calculations in order to recover the results already obtained by + preboius attemps of calculation until the corresponding intermediate + step Examples:: @@ -721,8 +680,8 @@ def filename(self, nstrands=None): INPUT: - - ``nstrands`` -- Integer number of strands of the underlying braid group - if the data file depends on it. Otherwise use default None + - ``nstrands`` -- Integer, number of strands of the underlying braid + group if the data file depends on it. Otherwise use default ``None`` Examples:: @@ -735,14 +694,14 @@ def filename(self, nstrands=None): 'braid_images_2.sobj' """ if nstrands is None: - return '%s.sobj' %(self.value) + return '%s.sobj' % self.value else: - return '%s_%s.sobj' %(self.value, nstrands) - - matrix_representations = 'matrix_representations' - braid_images = 'braid_images' - basis_extensions = 'basis_extensions' + return '%s_%s.sobj' % (self.value, nstrands) + matrix_representations = 'matrix_representations' + braid_images = 'braid_images' + basis_extensions = 'basis_extensions' + markov_trace = 'markov_trace' def __init__(self, num_strands): r""" @@ -750,23 +709,22 @@ def __init__(self, num_strands): INPUT: - - ``cubic_hecke_algebra`` -- instance of :class:`CubicHeckeAlgebra` - whose data should be cached in the file system. + - ``num_strands`` -- integer giving the number of strands of the + corresponding cubic Hecke algebra EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache sage: cha_fc = CubicHeckeFileCache(2) - sage: cha_fc._file_cache_path == 'cubic_hecke' + sage: cha_fc._file_cache_path.endswith('cubic_hecke') True """ - self._nstrands = num_strands - self._file_cache_path = 'cubic_hecke' - self._data_library = {} + self._nstrands = num_strands - from sage.misc.misc import sage_makedirs - from sage.misc.persist import SAGE_DB - sage_makedirs(os.path.join(SAGE_DB, self._file_cache_path)) + from sage.env import DOT_SAGE + self._file_cache_path = os.path.join(DOT_SAGE, 'cubic_hecke') + self._data_library = {} + os.makedirs(self._file_cache_path, exist_ok=True) def reset_library(self, section=None): r""" @@ -796,30 +754,29 @@ def reset_library(self, section=None): return if not isinstance(section, CubicHeckeFileCache.section): - raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) - + raise TypeError('section must be an instance of enum %s' % CubicHeckeFileCache.section) + from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType data_lib = self._data_library empty_dict = {} - if section == self.section.matrix_representations: + if section == self.section.matrix_representations: for rep_type in RepresentationType: - new_dict={} - empty_dict.update({rep_type:new_dict}) - elif section == self.section.basis_extensions: + new_dict = {} + empty_dict.update({rep_type: new_dict}) + elif section == self.section.basis_extensions: empty_dict = [] - data_lib.update({section:empty_dict}) - + data_lib.update({section: empty_dict}) def is_empty(self, section=None): r""" - Return ``True`` if the cache of the given ``section`` is empty. + Return ``True`` if the cache of the given ``section`` is empty. INPUT: - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` to select the section of the file cache or ``None`` (default) meaning all sections - + EXAMPLES:: @@ -833,28 +790,26 @@ def is_empty(self, section=None): return all(self.is_empty(section=sec) for sec in self.section) if not isinstance(section, CubicHeckeFileCache.section): - raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) - + raise TypeError('section must be an instance of enum %s' % CubicHeckeFileCache.section) + self.read(section) data_lib = self._data_library[section] from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType - if section == self.section.matrix_representations: + if section == self.section.matrix_representations: for rep_type in RepresentationType: if len(data_lib[rep_type]) > 0: return False return True - if section == self.section.basis_extensions and self._nstrands > 4: + if section == self.section.basis_extensions and self._nstrands > 4: # the new generators and their inverses are not counted # since they are added during initialization - return len(data_lib) <= 2*(self._nstrands -4) + return len(data_lib) <= 2*(self._nstrands - 4) return len(data_lib) == 0 - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # save data file system - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def write(self, section=None): r""" Write data from memory to the file system. @@ -878,25 +833,27 @@ def write(self, section=None): if section is None: for sec in self.section: if sec in data_lib.keys(): - self.write(section=sec) + self.write(section=sec) return if not isinstance(section, CubicHeckeFileCache.section): - raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + raise TypeError('section must be an instance of enum %s' % CubicHeckeFileCache.section) if section not in data_lib.keys(): - raise ValueError("No data for file %s in memory" %(section)) - - db_save(data_lib[section], '%s/%s' %(lib_path, section.filename(self._nstrands))) + raise ValueError("No data for file %s in memory" % section) + verbose('saving file cache %s ...' % section) + fname = os.path.join(lib_path, section.filename(self._nstrands)) + with atomic_write(fname, binary=True) as f: + f.write(_base_dumps(data_lib[section])) + f.close() - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # read from file system - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def read(self, section): r""" Read data into memory from the file system. - INPUT: @@ -907,7 +864,7 @@ def read(self, section): Dictionary containing the data library corresponding to the section of file cache - + EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache @@ -917,7 +874,7 @@ def read(self, section): {} """ if not isinstance(section, CubicHeckeFileCache.section): - raise TypeError('section must be an instance of enum %s' (CubicHeckeFileCache.section)) + raise TypeError('section must be an instance of enum %s' % CubicHeckeFileCache.section) data_lib = self._data_library lib_path = self._file_cache_path @@ -925,9 +882,10 @@ def read(self, section): if section in data_lib.keys(): return data_lib[section] - verbose('loading file cache %s ...' %(section)) + verbose('loading file cache %s ...' % section) + fname = os.path.join(lib_path, section.filename(self._nstrands)) try: - data_lib[section] = db('%s/%s' %(lib_path, section.filename(self._nstrands))) + data_lib[section] = load(fname) verbose('... finished!') except IOError: self.reset_library(section) @@ -935,16 +893,14 @@ def read(self, section): return data_lib[section] - - - - # ------------------------------------------------------------------------------------------------------------- - # matrix_reprs_from_file_cache_ - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- + # read matrix representation from file cache + # -------------------------------------------------------------------------- def read_matrix_representation(self, representation_type, monomial_tietze, ring_of_definition): r""" Return the matrix representations of the given monomial (in Tietze form) - if it has been stored in the file cache before. Otherwise ``None`` is returned. + if it has been stored in the file cache before. Otherwise ``None`` is + returned. INPUT: @@ -953,14 +909,16 @@ def read_matrix_representation(self, representation_type, monomial_tietze, ring_ - ``monomial_tietze`` -- tuple representing the braid in Tietze form - - ``ring_of_definition`` -- instance of :class:`CubicHeckeRingOfDefinition` resp. - :class:`CubicHeckeExtensionRing` (depending wether ``representation_type`` - is split or not) + - ``ring_of_definition`` -- instance of + :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeRingOfDefinition` + respectively + :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeExtensionRing` + depending on whether ``representation_type`` is split or not OUTPUT: - Dictionary containing all matrix representations of ``self`` of the given representation_type - which have been stored in the file cache. + Dictionary containing all matrix representations of ``self`` of the given + ``representation_type`` which have been stored in the file cache. EXAMPLES:: @@ -982,34 +940,34 @@ def read_matrix_representation(self, representation_type, monomial_tietze, ring_ """ from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType if not isinstance(representation_type, RepresentationType): - raise TypeError('representation_type must be an instance of enum %s' (RepresentationType)) + raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) matrix_representations = self.read(self.section.matrix_representations)[representation_type] if monomial_tietze in matrix_representations.keys(): matrix_list_dict = matrix_representations[monomial_tietze] matrix_list = [matrix(ring_of_definition, mat_dict, sparse=True) for mat_dict in matrix_list_dict] - for m in matrix_list: m.set_immutable() + for m in matrix_list: + m.set_immutable() return matrix_list return None - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # matrix_representation to file cache - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def write_matrix_representation(self, representation_type, monomial_tietze, matrix_list): r""" Write the matrix representation of a monomial to the file cache. INPUT: - - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + - ``representation_type`` -- instance of enum + :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` specifying the type of the representation - ``monomial_tietze`` -- tuple representing the braid in Tietze form - - ``matrix_list`` -- list of matrices corresponding to the irreducible representations + - ``matrix_list`` -- list of matrices corresponding to the irreducible + representations EXAMPLES:: @@ -1021,9 +979,9 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr sage: m = gi.matrix(representation_type=rt.RegularRight) sage: cha_fc.read_matrix_representation(rt.RegularRight, git, R) [ - [ 0 1 (-w^-1)*u] - [ 0 0 w^-1] - [ 1 0 (w^-1)*v] + [ 0 1 (-u)/w] + [ 0 0 1/w] + [ 1 0 v/w] ] sage: CHA2.reset_filecache(cha_fc.section.matrix_representations) sage: cha_fc.read_matrix_representation(rt.RegularLeft, git, R) == None @@ -1034,7 +992,7 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr """ from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType if not isinstance(representation_type, RepresentationType): - raise TypeError('representation_type must be an instance of enum %s' (RepresentationType)) + raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) matrix_representations = self.read(self.section.matrix_representations)[representation_type] @@ -1042,15 +1000,15 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr # entry already registered return - matrix_representation_dict = [convert_mat_to_dict_recursive(mat) for mat in list(matrix_list)] + matrix_representation_dict = [simplify(mat) for mat in list(matrix_list)] matrix_representations[monomial_tietze] = matrix_representation_dict self.write(self.section.matrix_representations) return - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # read braid images from file cache - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def read_braid_image(self, braid_tietze, ring_of_definition): r""" Return the list of pre calculated braid images from file cache. @@ -1059,11 +1017,13 @@ def read_braid_image(self, braid_tietze, ring_of_definition): - ``braid_tietze`` -- tuple representing the braid in Tietze form - - ``ring_of_definition`` -- instance of :class:`CubicHeckeRingOfDefinition` + - ``ring_of_definition`` -- instance of + :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeRingOfDefinition` OUTPUT: - A dictionary containing the pre calculated braid image of the given braid. + A dictionary containing the pre calculated braid image of the given + braid. EXAMPLES:: @@ -1076,7 +1036,7 @@ def read_braid_image(self, braid_tietze, ring_of_definition): sage: cha_fc.is_empty(CubicHeckeFileCache.section.braid_images) True sage: b2_img = CHA2(b2); b2_img - (-v) + u*c + w*c^-1 + w*c^-1 + u*c + (-v) sage: cha_fc.write_braid_image(b2.Tietze(), b2_img.to_vector()) sage: cha_fc.read_braid_image(b2.Tietze(), ring_of_definition) (-v, u, w) @@ -1089,13 +1049,9 @@ def read_braid_image(self, braid_tietze, ring_of_definition): return vector(ring_of_definition, result_list) return None - - - - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # braid image to_file cache - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def write_braid_image(self, braid_tietze, braid_image_vect): r""" Write the braid image of the given braid to the file cache. @@ -1103,8 +1059,8 @@ def write_braid_image(self, braid_tietze, braid_image_vect): INPUT: - ``braid_tietze`` -- tuple representing the braid in Tietze form - - ``braid_image_vect`` -- image of the given braid as a vector with respect - to the basis of the cubic Hecke algebra + - ``braid_image_vect`` -- image of the given braid as a vector with + respect to the basis of the cubic Hecke algebra EXAMPLES:: @@ -1115,10 +1071,10 @@ def write_braid_image(self, braid_tietze, braid_image_vect): sage: B2 = BraidGroup(2) sage: b, = B2.gens(); b3 = b**3 sage: b3_img = CHA2(b3); b3_img - (-u*v+w) + (u^2-v)*c + w*u*c^-1 + u*w*c^-1 + (u^2-v)*c + (-u*v+w) sage: cha_fc.write_braid_image(b3.Tietze(), b3_img.to_vector()) sage: cha_fc.read_braid_image(b3.Tietze(), ring_of_definition) - (-u*v + w, u^2 - v, w*u) + (-u*v + w, u^2 - v, u*w) sage: cha_fc.reset_library(CubicHeckeFileCache.section.braid_images) sage: cha_fc.write(CubicHeckeFileCache.section.braid_images) sage: cha_fc.is_empty(CubicHeckeFileCache.section.braid_images) @@ -1130,26 +1086,25 @@ def write_braid_image(self, braid_tietze, braid_image_vect): # entry already registered return - braid_image_dict = [convert_poly_to_dict_recursive(cf) for cf in list(braid_image_vect)] + braid_image_dict = [str(cf) for cf in list(braid_image_vect)] braid_images[braid_tietze] = braid_image_dict self.write(self.section.braid_images) return - - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- # basis to file cache - # ------------------------------------------------------------------------------------------------------------- + # -------------------------------------------------------------------------- def update_basis_extensions(self, new_basis_extensions): r""" - Update the file cache for basis extensions for cubic Hecke algebras on more than 4 strands - according to the given ``new_basis_extensions``. + Update the file cache for basis extensions for cubic Hecke algebras on + more than 4 strands according to the given ``new_basis_extensions``. INPUT: - - ``new_basis_extensions`` -- list of additional (to the static basis) basis elements which should - replace the former such list in the file. - + - ``new_basis_extensions`` -- list of additional (to the static basis) + basis elements which should replace the former such list in the file. + EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache @@ -1165,6 +1120,387 @@ def update_basis_extensions(self, new_basis_extensions): sage: cha_fc.is_empty(CubicHeckeFileCache.section.basis_extensions) True """ - self._data_library.update({self.section.basis_extensions:new_basis_extensions}) + self._data_library.update({self.section.basis_extensions: new_basis_extensions}) self.write(self.section.basis_extensions) return + + +# ----------------------------------------------------------------------------- +# Demo data section +# ----------------------------------------------------------------------------- + +func_name = 'read_%s' + +var_decl = "\n %s = variables" +var_doc_input = "\n - ``variables`` -- tuple containing the indeterminates of the representation" +var_doc_decl = "\n sage: L.<%s> = LaurentPolynomialRing(ZZ)" + +template = """def %s(%snum_strands=3): + %s%s + data = {} + data[2] = %s + data[3] = %s + return data[num_strands] + +""" + + +doc = r"""{} + Return precomputed data of Ivan Marin + + This code was generated by :func:`create_demo_data`, please don't edit. + + INPUT: +%s + - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra + in question + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import %s%s + sage: %s(%s2) + {} +""".format('r"""', '"""') + + +def create_demo_data(filename='demo_data.py'): + r""" + Generate code for the functions inserted below to access the + small cases of less than 4 strands as demonstration cases. + The code is written to a file with the given name from where + it can be copied into this source file (in case a change is needed). + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import create_demo_data + sage: create_demo_data() # not tested + """ + # --------------------------------------------------------------- + # preparations + # --------------------------------------------------------------- + def create_repr_func(name, variables, data2, data3): + fname = func_name % name + if variables: + v = str(variables) + vars2 = v + ', ' + decl = var_decl % v + doc_dec = var_doc_decl % v[1: len(v)-1] + doc_str = doc % (var_doc_input, fname, doc_dec, fname, vars2) + res = template % (fname, 'variables, ', doc_str, decl, data2, data3) + else: + doc_str = doc % ('', fname, '', fname, '') + res = template % (fname, '', doc_str, '', data2, data3) + return res + + from textwrap import fill + + def fl(s): + return fill(str(s), subsequent_indent=' ') + + from sympy import var + from database_cubic_hecke import read_basis, read_irr, read_reg + + vari = var('a, b, c, j') + varr = var('u, v, w') + + # --------------------------------------------------------------- + # read data + # --------------------------------------------------------------- + bas2 = fl(read_basis(num_strands=2)) + bas3 = fl(read_basis(num_strands=3)) + + irr2 = fl(read_irr(variables=vari, num_strands=2)) + irr3 = fl(read_irr(variables=vari, num_strands=3)) + + regl2 = fl(read_reg(variables=varr, num_strands=2)) + regl3 = fl(read_reg(variables=varr, num_strands=3)) + + regr2 = fl(read_reg(variables=varr, num_strands=2, right=True)) + regr3 = fl(read_reg(variables=varr, num_strands=3, right=True)) + + # --------------------------------------------------------------- + # create functions and write them to file + # --------------------------------------------------------------- + bas = create_repr_func('basis', '', bas2, bas3) + irr = create_repr_func('irr', vari, irr2, irr3) + regl = create_repr_func('regl', varr, regl2, regl3) + regr = create_repr_func('regr', varr, regr2, regr3) + + with open(filename, 'w') as f: + f.write(bas) + f.write(irr) + f.write(regl) + f.write(regr) + + +def read_basis(num_strands=3): + r""" + Return precomputed data of Ivan Marin + + This code was generated by ``create_demo_data``, please don't edit. + + INPUT: + + - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra + in question + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import read_basis + sage: read_basis(2) + [[], [1], [-1]] + """ + + data = {} + data[2] = [[], [1], [-1]] + data[3] = [[], [1], [-1], [2], [-2], [1, 2], [1, -2], [-1, 2], [-1, -2], [1, 2, + 1], [1, 2, -1], [-1, 2, 1], [-1, 2, -1], [1, -2, 1], [-1, -2, + 1], [2, 1], [-2, 1], [2, -1], [-2, -1], [1, -2, -1], [-1, -2, + -1], [2, -1, 2], [1, 2, -1, 2], [-1, 2, -1, 2]] + return data[num_strands] + + +def read_irr(variables, num_strands=3): + r""" + Return precomputed data of Ivan Marin + + This code was generated by ``create_demo_data``, please don't edit. + + INPUT: + + - ``variables`` -- tuple containing the indeterminates of the representation + - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra + in question + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import read_irr + sage: L. = LaurentPolynomialRing(ZZ) + sage: read_irr((a, b, c, j), 2) + ([1, 1, 1], + [[{(0, 0): a}], [{(0, 0): c}], [{(0, 0): b}]], + [[{(0, 0): a^-1}], [{(0, 0): c^-1}], [{(0, 0): b^-1}]]) + """ + + (a, b, c, j) = variables + data = {} + data[2] = ([1, 1, 1], [[{(0, 0): a}], [{(0, 0): c}], [{(0, 0): b}]], [[{(0, 0): + 1/a}], [{(0, 0): 1/c}], [{(0, 0): 1/b}]]) + data[3] = ([1, 1, 1, 2, 2, 2, 3], [[{(0, 0): a}, {(0, 0): a}], [{(0, 0): c}, + {(0, 0): c}], [{(0, 0): b}, {(0, 0): b}], [{(0, 0): b, (1, 0): + b*c, (1, 1): c}, {(0, 0): c, (0, 1): -1, (1, 1): b}], [{(0, + 0): a, (1, 0): a*b, (1, 1): b}, {(0, 0): b, (0, 1): -1, (1, + 1): a}], [{(0, 0): a, (1, 0): a*c, (1, 1): c}, {(0, 0): c, (0, + 1): -1, (1, 1): a}], [{(0, 0): c, (1, 0): a*c + b**2, (1, 1): + b, (2, 0): b, (2, 1): 1, (2, 2): a}, {(0, 0): a, (0, 1): -1, + (0, 2): b, (1, 1): b, (1, 2): -a*c - b**2, (2, 2): c}]], + [[{(0, 0): 1/a}, {(0, 0): 1/a}], [{(0, 0): 1/c}, {(0, 0): + 1/c}], [{(0, 0): 1/b}, {(0, 0): 1/b}], [{(0, 0): 1/b, (1, 0): + -1, (1, 1): 1/c}, {(0, 0): 1/c, (0, 1): 1/(b*c), (1, 1): + 1/b}], [{(0, 0): 1/a, (1, 0): -1, (1, 1): 1/b}, {(0, 0): 1/b, + (0, 1): 1/(a*b), (1, 1): 1/a}], [{(0, 0): 1/a, (1, 0): -1, (1, + 1): 1/c}, {(0, 0): 1/c, (0, 1): 1/(a*c), (1, 1): 1/a}], [{(0, + 0): 1/c, (1, 0): -a/b - b/c, (1, 1): 1/b, (2, 0): 1/b, (2, 1): + -1/(a*b), (2, 2): 1/a}, {(0, 0): 1/a, (0, 1): 1/(a*b), (0, 2): + 1/b, (1, 1): 1/b, (1, 2): a/b + b/c, (2, 2): 1/c}]]) + return data[num_strands] + + +def read_regl(variables, num_strands=3): + r""" + Return precomputed data of Ivan Marin + + This code was generated by ``create_demo_data``, please don't edit. + + INPUT: + + - ``variables`` -- tuple containing the indeterminates of the representation + - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra + in question + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import read_regl + sage: L. = LaurentPolynomialRing(ZZ) + sage: read_regl((u, v, w), 2) + ([3], + [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], + [[{(0, 1): 1, (0, 2): -u*w^-1, (1, 2): w^-1, (2, 0): 1, (2, 2): v*w^-1}]]) + """ + + (u, v, w) = variables + data = {} + data[2] = ([3], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], + [[{(0, 1): 1, (0, 2): -u/w, (1, 2): 1/w, (2, 0): 1, (2, 2): + v/w}]]) + data[3] = ([24], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w, (3, + 5): -v, (3, 7): 1, (4, 6): -v, (4, 8): 1, (5, 3): 1, (5, 5): + u, (6, 4): 1, (6, 6): u, (7, 5): w, (8, 6): w, (9, 9): u, (9, + 15): 1, (10, 10): u, (10, 17): 1, (11, 9): w, (12, 10): w, + (13, 13): u, (13, 16): 1, (14, 13): w, (15, 9): -v, (15, 11): + 1, (16, 13): -v, (16, 14): 1, (17, 10): -v, (17, 12): 1, (18, + 19): -v, (18, 20): 1, (19, 18): 1, (19, 19): u, (20, 19): w, + (21, 22): -v, (21, 23): 1, (22, 21): 1, (22, 22): u, (23, 22): + w}, {(0, 3): -v, (0, 4): 1, (1, 15): -v, (1, 16): 1, (1, 22): + -v, (1, 23): u*v/w, (2, 17): -v, (2, 18): 1, (2, 23): v*(u*v - + w)/w, (3, 0): 1, (3, 3): u, (4, 3): w, (5, 9): -v, (5, 10): 1, + (5, 12): -u/w, (5, 22): u, (5, 23): -u**2/w, (6, 11): -v, (6, + 22): w, (6, 23): -u, (7, 12): -u*v/w, (7, 13): -v, (7, 19): 1, + (7, 21): -v, (7, 23): -u**2*v/w, (8, 12): -v, (8, 14): -v, (8, + 20): 1, (8, 23): -u*v, (9, 5): 1, (9, 9): u, (9, 23): u/w, + (10, 9): w, (10, 11): -u, (11, 6): 1, (11, 11): u, (11, 13): + u, (12, 13): w, (12, 23): -v, (13, 23): 1, (14, 8): 1, (14, + 14): u, (14, 23): v, (15, 1): 1, (15, 12): u/w, (15, 15): u, + (16, 11): v, (16, 15): w, (16, 23): -u, (17, 2): 1, (17, 12): + u*v/w, (17, 17): u, (18, 12): v, (18, 17): w, (19, 21): w, + (19, 23): v, (20, 14): w, (21, 7): 1, (21, 21): u, (21, 23): + u*v/w, (22, 11): 1, (23, 12): 1, (23, 23): u}]], [[{(0, 1): 1, + (0, 2): -u/w, (1, 2): 1/w, (2, 0): 1, (2, 2): v/w, (3, 5): 1, + (3, 7): -u/w, (4, 6): 1, (4, 8): -u/w, (5, 7): 1/w, (6, 8): + 1/w, (7, 3): 1, (7, 7): v/w, (8, 4): 1, (8, 8): v/w, (9, 11): + 1/w, (10, 12): 1/w, (11, 11): v/w, (11, 15): 1, (12, 12): v/w, + (12, 17): 1, (13, 14): 1/w, (14, 14): v/w, (14, 16): 1, (15, + 9): 1, (15, 11): -u/w, (16, 13): 1, (16, 14): -u/w, (17, 10): + 1, (17, 12): -u/w, (18, 19): 1, (18, 20): -u/w, (19, 20): 1/w, + (20, 18): 1, (20, 20): v/w, (21, 22): 1, (21, 23): -u/w, (22, + 23): 1/w, (23, 21): 1, (23, 23): v/w}, {(0, 3): 1, (0, 4): + -u/w, (1, 15): 1, (1, 16): -u/w, (1, 22): u*v/w, (1, 23): + -u/w, (2, 17): 1, (2, 18): -u/w, (3, 4): 1/w, (4, 0): 1, (4, + 4): v/w, (5, 9): 1, (5, 10): -u/w, (5, 13): -u/w, (5, 22): + -u**2/w, (6, 11): 1, (6, 12): -u/w, (6, 13): -u*v/w, (6, 22): + -u, (7, 19): -u/w, (7, 21): 1, (8, 13): -v, (8, 14): 1, (8, + 20): -u/w, (9, 10): 1/w, (9, 22): u/w, (10, 5): 1, (10, 6): + -u/w, (10, 10): v/w, (10, 13): -u**2/w, (10, 23): u/w, (11, + 22): 1, (12, 13): -u, (12, 23): 1, (13, 12): 1/w, (13, 13): + v/w, (14, 20): 1/w, (15, 13): u/w, (15, 16): 1/w, (15, 22): + -v/w, (16, 1): 1, (16, 6): v/w, (16, 13): u*v/w, (16, 16): + v/w, (17, 13): u*v/w, (17, 18): 1/w, (17, 23): -v/w, (18, 2): + 1, (18, 13): v, (18, 18): v/w, (18, 23): -v**2/w, (19, 7): 1, + (19, 12): v/w, (19, 19): v/w, (19, 23): u*v/w, (20, 8): 1, + (20, 20): v/w, (20, 23): v, (21, 13): -v/w, (21, 19): 1/w, + (22, 6): 1/w, (22, 13): u/w, (22, 22): v/w, (23, 13): 1}]]) + return data[num_strands] + + +def read_regr(variables, num_strands=3): + r""" + Return precomputed data of Ivan Marin + + This code was generated by ``create_demo_data``, please don't edit. + + INPUT: + + - ``variables`` -- tuple containing the indeterminates of the representation + - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra + in question + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import read_regr + sage: L. = LaurentPolynomialRing(ZZ) + sage: read_regr((u, v, w), 2) + ([3], + [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], + [[{(0, 1): 1, (0, 2): -u*w^-1, (1, 2): w^-1, (2, 0): 1, (2, 2): v*w^-1}]]) + """ + + (u, v, w) = variables + data = {} + data[2] = ([3], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], + [[{(0, 1): 1, (0, 2): -u/w, (1, 2): 1/w, (2, 0): 1, (2, 2): + v/w}]]) + data[3] = ([24], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w, (3, + 15): -v, (3, 17): 1, (4, 16): -v, (4, 18): 1, (4, 22): v**2, + (4, 23): -v, (5, 9): -v, (5, 10): 1, (6, 13): -v, (6, 19): 1, + (6, 21): -v, (6, 22): -u*v, (7, 11): -v, (7, 12): 1, (8, 14): + -v, (8, 20): 1, (8, 22): -v*w, (9, 5): 1, (9, 9): u, (9, 23): + u/w, (10, 9): w, (10, 21): -u, (10, 22): -u**2, (11, 7): 1, + (11, 11): u, (11, 21): u, (11, 23): u*v/w, (12, 11): w, (12, + 22): -u*w, (13, 6): 1, (13, 13): u, (13, 22): v, (14, 8): 1, + (14, 14): u, (14, 23): v, (15, 3): 1, (15, 15): u, (15, 22): + u, (15, 23): -u**2/w, (16, 4): 1, (16, 16): u, (16, 21): v, + (17, 15): w, (17, 22): u*v, (17, 23): -u, (18, 16): w, (19, + 13): w, (20, 14): w, (21, 22): -v, (21, 23): 1, (22, 21): 1, + (22, 22): u, (23, 22): w}, {(0, 3): -v, (0, 4): 1, (1, 5): -v, + (1, 6): 1, (2, 7): -v, (2, 8): 1, (3, 0): 1, (3, 3): u, (4, + 3): w, (5, 1): 1, (5, 5): u, (6, 5): w, (7, 2): 1, (7, 7): u, + (8, 7): w, (9, 9): u, (9, 15): 1, (10, 13): u, (10, 16): 1, + (10, 22): -v, (11, 9): w, (12, 13): w, (12, 23): -v, (13, 23): + 1, (14, 21): w, (14, 23): v, (15, 9): -v, (15, 11): 1, (16, + 22): w, (16, 23): -u, (17, 13): -v, (17, 14): 1, (17, 21): -v, + (18, 19): -v, (18, 20): 1, (19, 18): 1, (19, 19): u, (20, 19): + w, (21, 17): 1, (21, 21): u, (22, 10): 1, (22, 22): u, (23, + 12): 1, (23, 23): u}]], [[{(0, 1): 1, (0, 2): -u/w, (1, 2): + 1/w, (2, 0): 1, (2, 2): v/w, (3, 15): 1, (3, 17): -u/w, (3, + 23): u*(u*v - w)/w**2, (4, 16): 1, (4, 18): -u/w, (4, 22): -v, + (4, 23): u*v/w, (5, 9): 1, (5, 10): -u/w, (5, 21): -u/w, (5, + 22): -u**2/w, (5, 23): -u*v/w**2, (6, 13): 1, (6, 19): -u/w, + (6, 23): -v/w, (7, 11): 1, (7, 12): -u/w, (7, 21): -u*v/w, (7, + 22): -u, (7, 23): -u*v**2/w**2, (8, 14): 1, (8, 20): -u/w, (8, + 21): -v, (8, 23): -v**2/w, (9, 10): 1/w, (9, 22): u/w, (10, + 5): 1, (10, 10): v/w, (10, 22): u*v/w, (11, 12): 1/w, (11, + 23): u/w, (12, 7): 1, (12, 12): v/w, (12, 23): u*v/w, (13, + 19): 1/w, (14, 20): 1/w, (15, 17): 1/w, (15, 21): u/w, (16, + 18): 1/w, (17, 3): 1, (17, 17): v/w, (17, 21): u*v/w, (18, 4): + 1, (18, 18): v/w, (18, 21): v, (19, 6): 1, (19, 19): v/w, (19, + 22): v, (20, 8): 1, (20, 20): v/w, (20, 23): v, (21, 22): 1, + (21, 23): -u/w, (22, 23): 1/w, (23, 21): 1, (23, 23): v/w}, + {(0, 3): 1, (0, 4): -u/w, (1, 5): 1, (1, 6): -u/w, (2, 7): 1, + (2, 8): -u/w, (3, 4): 1/w, (4, 0): 1, (4, 4): v/w, (5, 6): + 1/w, (6, 1): 1, (6, 6): v/w, (7, 8): 1/w, (8, 2): 1, (8, 8): + v/w, (9, 11): 1/w, (10, 13): -u**2/w, (10, 16): -u/w, (10, + 22): 1, (11, 11): v/w, (11, 15): 1, (12, 13): -u, (12, 23): 1, + (13, 12): 1/w, (13, 13): v/w, (14, 12): v/w, (14, 14): v/w, + (14, 17): 1, (15, 9): 1, (15, 11): -u/w, (16, 10): 1, (16, + 12): -u/w, (16, 16): v/w, (17, 13): u*v/w, (17, 14): -u/w, + (17, 21): 1, (18, 19): 1, (18, 20): -u/w, (19, 20): 1/w, (20, + 18): 1, (20, 20): v/w, (21, 13): -v/w, (21, 14): 1/w, (22, + 13): u/w, (22, 16): 1/w, (23, 13): 1}]]) + return data[num_strands] + + +# generated data function for cubic Hecke algebra +def read_markov(bas_ele, variables, num_strands=4): + r""" + Return precomputed Markov trace coefficients. + + This code was generated by ``create_markov_trace_data.py`` (from + the `database_cubic_heck` repository), please don't edit. + + INPUT: + + - ``bas_ele`` -- instance of enum :class:`MarkovTraceModuleBasis` + - ``variables`` -- tuple consisting of the variables used in + the coefficients + - ``num_strands`` -- integer indicating the number of strands (default 4) + + + OUTPUT: + + A list of the coefficients. The i'th member corresponds to the i'th + basis element. + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import read_markov + sage: from sympy import var + sage: u, v, w, s = var('u, v, w, s') + sage: variables = (u, v, w, s) + sage: read_markov('U2', variables, num_strands=3) + [0, s, 1/s, s, 1/s, 0, 0, 0, 0, -s*v, s, s, -s*u/w, -v/s, 1/s, + 0, 0, 0, 0, 1/s, -u/(s*w), -v/s, 0, 0] + """ + + u, v, w, s = variables + data = {} + data[2] = {'U1': [0, s, 1/s], 'U2': [1, 0, 0]} + data[3] = {'U1': [0, 0, 0, 0, 0, s**2, 1, 1, 1/s**2, u*s**2 + w, 0, 0, (s**2 + + v)/w, (u*s**2 + w)/s**2, 0, s**2, 1, 1, 1/s**2, 0, (s**2 + + v)/(w*s**2), (u*s**2 + w)/s**2, s**2, 0], 'U2': [0, s, 1/s, s, + 1/s, 0, 0, 0, 0, -v*s, s, s, (-u*s)/w, (-v)/s, 1/s, 0, 0, 0, + 0, 1/s, (-u)/(w*s), (-v)/s, 0, 0], 'U3': [1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'K4': [0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1]} + + return data[num_strands][bas_ele] diff --git a/src/sage/features/databases.py b/src/sage/features/databases.py index 210229dfe82..d1e77a8ff32 100644 --- a/src/sage/features/databases.py +++ b/src/sage/features/databases.py @@ -127,6 +127,27 @@ def __init__(self): """ PythonModule.__init__(self, 'database_knotinfo', spkg='database_knotinfo') +class DatabaseCubicHecke(PythonModule): + r""" + A :class:`~sage.features.Feature` which describes the presence of the databases at the + web-page `Cubic Hecke algebra on 4 strands `__ + of Ivan Marin. + + EXAMPLES:: + + sage: from sage.features.databases import DatabaseCubicHecke + sage: DatabaseCubicHecke().is_present() # optional - database_cubic_hecke + FeatureTestResult('database_cubic_hecke', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.databases import DatabaseCubicHecke + sage: isinstance(DatabaseCubicHecke(), DatabaseCubicHecke) + True + """ + PythonModule.__init__(self, 'database_cubic_hecke', spkg='database_cubic_hecke') class DatabaseReflexivePolytopes(StaticFile): r""" @@ -158,5 +179,6 @@ def all_features(): DatabaseCremona(), DatabaseCremona('cremona_mini'), DatabaseJones(), DatabaseKnotInfo(), + DatabaseCubicHecke(), DatabaseReflexivePolytopes(), DatabaseReflexivePolytopes('polytopes_db_4d', 'Hodge4d')] From 8b4d2861142ccf4b18780c4ffad1d17c2fcdbab8 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 29 Mar 2022 08:37:32 +0200 Subject: [PATCH 009/591] add missing reference --- src/doc/en/reference/references/index.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 50fb28bd04e..6cd3b33e9f7 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3380,6 +3380,9 @@ REFERENCES: cellular logic networks and machines, AFCRL-68-0668, SRI Project 7258, Final Rep., pp. 20-28, 1968. +.. [Kau1991] \Louis Kauffman. *Knots and Physics*, World Scientific, 1991 + :doi:`10.1142/4256`. + .. [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 From e270a7cb12b5df5423bad23325b8e8bd9c19fc5c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 29 Mar 2022 19:21:30 +0200 Subject: [PATCH 010/591] 33590 initial version --- build/pkgs/database_cubic_hecke/SPKG.rst | 18 ++++++++++++++++++ build/pkgs/database_cubic_hecke/checksums.ini | 5 +++++ build/pkgs/database_cubic_hecke/dependencies | 4 ++++ .../database_cubic_hecke/install-requires.txt | 1 + .../database_cubic_hecke/package-version.txt | 1 + build/pkgs/database_cubic_hecke/spkg-check.in | 5 +++++ .../pkgs/database_cubic_hecke/spkg-install.in | 2 ++ build/pkgs/database_cubic_hecke/type | 1 + 8 files changed, 37 insertions(+) create mode 100644 build/pkgs/database_cubic_hecke/SPKG.rst create mode 100644 build/pkgs/database_cubic_hecke/checksums.ini create mode 100644 build/pkgs/database_cubic_hecke/dependencies create mode 100644 build/pkgs/database_cubic_hecke/install-requires.txt create mode 100644 build/pkgs/database_cubic_hecke/package-version.txt create mode 100644 build/pkgs/database_cubic_hecke/spkg-check.in create mode 100644 build/pkgs/database_cubic_hecke/spkg-install.in create mode 100644 build/pkgs/database_cubic_hecke/type diff --git a/build/pkgs/database_cubic_hecke/SPKG.rst b/build/pkgs/database_cubic_hecke/SPKG.rst new file mode 100644 index 00000000000..e36f6444960 --- /dev/null +++ b/build/pkgs/database_cubic_hecke/SPKG.rst @@ -0,0 +1,18 @@ +database_cubic_hecke: Ivan Marin's representations of the cubic Hecke algebra on 4 strands as Python dictionaries +================================================================================================================= + +Description +----------- + +Ivan Marin's representations of the cubic Hecke algebra on 4 strands as Python dictionaries + +License +------- + +GPL + +Upstream Contact +---------------- + +https://pypi.org/project/database-cubic-hecke/ + diff --git a/build/pkgs/database_cubic_hecke/checksums.ini b/build/pkgs/database_cubic_hecke/checksums.ini new file mode 100644 index 00000000000..b2119998ee2 --- /dev/null +++ b/build/pkgs/database_cubic_hecke/checksums.ini @@ -0,0 +1,5 @@ +tarball=database_cubic_hecke-VERSION.tar.gz +sha1=f78ae31202fe077177f2c5059c028f9d40c20a46 +md5=4f83516e155515f17ebd88c56bc0f31b +cksum=3948466130 +upstream_url=https://pypi.io/packages/source/d/database_cubic_hecke/database_cubic_hecke-VERSION.tar.gz diff --git a/build/pkgs/database_cubic_hecke/dependencies b/build/pkgs/database_cubic_hecke/dependencies new file mode 100644 index 00000000000..0738c2d7777 --- /dev/null +++ b/build/pkgs/database_cubic_hecke/dependencies @@ -0,0 +1,4 @@ +$(PYTHON) | $(PYTHON_TOOLCHAIN) + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/database_cubic_hecke/install-requires.txt b/build/pkgs/database_cubic_hecke/install-requires.txt new file mode 100644 index 00000000000..9aa14e88ee5 --- /dev/null +++ b/build/pkgs/database_cubic_hecke/install-requires.txt @@ -0,0 +1 @@ +database-cubic-hecke diff --git a/build/pkgs/database_cubic_hecke/package-version.txt b/build/pkgs/database_cubic_hecke/package-version.txt new file mode 100644 index 00000000000..7fd3fd9ac54 --- /dev/null +++ b/build/pkgs/database_cubic_hecke/package-version.txt @@ -0,0 +1 @@ +2022.3.1 diff --git a/build/pkgs/database_cubic_hecke/spkg-check.in b/build/pkgs/database_cubic_hecke/spkg-check.in new file mode 100644 index 00000000000..43c4682810d --- /dev/null +++ b/build/pkgs/database_cubic_hecke/spkg-check.in @@ -0,0 +1,5 @@ +cd $SAGE_ROOT/src/sage/ + +FILES="databases/ features/ algebras/hecke_algebras/" +echo "Testing: "$FILES +sage -tp --long --optional="sage,database_cubic_hecke" $FILES || sdh_die "Error testing cubic Hecke algebra database" diff --git a/build/pkgs/database_cubic_hecke/spkg-install.in b/build/pkgs/database_cubic_hecke/spkg-install.in new file mode 100644 index 00000000000..37ac1a53437 --- /dev/null +++ b/build/pkgs/database_cubic_hecke/spkg-install.in @@ -0,0 +1,2 @@ +cd src +sdh_pip_install . diff --git a/build/pkgs/database_cubic_hecke/type b/build/pkgs/database_cubic_hecke/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/database_cubic_hecke/type @@ -0,0 +1 @@ +optional From 211f726899cdb562e9241c15b2c14953020af22a Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 30 Mar 2022 18:06:21 +0200 Subject: [PATCH 011/591] 33590 correct dependencies --- build/pkgs/database_cubic_hecke/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/database_cubic_hecke/dependencies b/build/pkgs/database_cubic_hecke/dependencies index 0738c2d7777..c48de24c023 100644 --- a/build/pkgs/database_cubic_hecke/dependencies +++ b/build/pkgs/database_cubic_hecke/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) +$(PYTHON) | $(PYTHON_TOOLCHAIN) $(and $(filter-out no,$(SAGE_CHECK_database_cubic_hecke)), $(SAGERUNTIME) ipywidgets sympy singular gap libhomfly libbraiding matplotlib) ---------- All lines of this file are ignored except the first. From 0c66a88b70afb70c20eb67e772769145327ec5c2 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 30 Mar 2022 23:13:06 +0200 Subject: [PATCH 012/591] 33590 add conway_polynomials to dependencies --- build/pkgs/database_cubic_hecke/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/database_cubic_hecke/dependencies b/build/pkgs/database_cubic_hecke/dependencies index c48de24c023..b3002bde029 100644 --- a/build/pkgs/database_cubic_hecke/dependencies +++ b/build/pkgs/database_cubic_hecke/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) $(and $(filter-out no,$(SAGE_CHECK_database_cubic_hecke)), $(SAGERUNTIME) ipywidgets sympy singular gap libhomfly libbraiding matplotlib) +$(PYTHON) | $(PYTHON_TOOLCHAIN) $(and $(filter-out no,$(SAGE_CHECK_database_cubic_hecke)), $(SAGERUNTIME) conway_polynomials ipywidgets sympy singular gap libhomfly libbraiding matplotlib) ---------- All lines of this file are ignored except the first. From 16277c4917cd29e30c51c6e93fb5be30d1445e47 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Fri, 1 Apr 2022 08:40:30 +0200 Subject: [PATCH 013/591] 29717: fixes according to review --- .../cubic_hecke_base_ring.py | 78 +++---- .../hecke_algebras/cubic_hecke_algebra.py | 218 +++++++++--------- src/sage/databases/cubic_hecke_db.py | 17 +- 3 files changed, 150 insertions(+), 163 deletions(-) diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py index 819d22b1352..e8b6f107d41 100644 --- a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py @@ -189,22 +189,21 @@ class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): INPUT: - - ``names`` -- string containing the names of the indeterminates separated - by ',' or a triple of strings each of which is the name of one of the - three indeterminates. The default is ``u, v, w`` - - ``order`` -- string (optional, default='degrevlex') transferred to the - corresponding input of LaurentPolynomialRing_mpair - - ``ring_of_definition`` -- instance of CubicHeckeRingOfDefinition - (optional, default=None) to specify the generic cubic Hecke base ring - over which self may be realized as splitting ring via the - ``as_splitting_algebra`` method - - ``third_unity_root_name`` -- optional string (default is ``e3``) for - setting the name of the third root if unity of ``self``. - - ``markov_trace_version`` -- optional boolean (default is ``False``). - If this is set to ``True`` then ``self`` contains one invertible - indeterminate in addition which is meant to represent the writhe factor - of a Markov trace on the cubic Hecke algebra and which default name - is ``s`` + - ``names`` -- string containing the names of the indeterminates separated + by ',' or a triple of strings each of which is the name of one of the + three indeterminates. The default is ``u, v, w`` + - ``order`` -- string (default='degrevlex') transferred to the + corresponding input of LaurentPolynomialRing_mpair + - ``ring_of_definition`` -- instance of CubicHeckeRingOfDefinition + (default=None) to specify the generic cubic Hecke base ring over which + self may be realized as splitting ring via the ``as_splitting_algebra`` + method + - ``third_unity_root_name`` -- string (default is ``e3``) for setting the + name of the third root if unity of ``self`` + - ``markov_trace_version`` -- boolean (default is ``False``). If this is + set to ``True`` then ``self`` contains one invertible indeterminate in + addition which is meant to represent the writhe factor of a Markov trace + on the cubic Hecke algebra and which default name is ``s`` EXAMPLES:: @@ -583,9 +582,9 @@ def create_specialization(self, im_cubic_equation_roots, im_writhe_parameter=Non INPUT: - - ``im_cubic_equation_roots`` -- list or tuple of three ring elements - such that there exists a ring homomorphism from the corresponding - elements of ``self`` to them + - ``im_cubic_equation_roots`` -- list or tuple of three ring elements + such that there exists a ring homomorphism from the corresponding + elements of ``self`` to them OUTPUT: @@ -795,8 +794,8 @@ def field_embedding(self, characteristic=0): INPUT: - - ``characteristic`` -- integer (optional, default 0) the characteristic - of the field. + - ``characteristic`` -- integer (default 0) the characteristic of the + field. EXAMPLES:: @@ -911,16 +910,15 @@ class CubicHeckeRingOfDefinition(Localization): INPUT: - - ``names`` -- string containing the names of the indeterminates separated - by ',' or a triple of strings each of which is the name of one of the - three indeterminates. The default is ``u, v, w``. - - ``order`` -- string (optional, default='degrevlex') transferred to the - corresponding input of LaurentPolynomialRing_mpair - - ``markov_trace_version`` -- optional boolean (default is ``False``). - If this is set to ``True`` then ``self`` contains one invertible - indeterminate in addition which is meant to represent the writhe factor - of a Markov trace on the cubic Hecke algebra and which default name - is ``s`` + - ``names`` -- string containing the names of the indeterminates separated + by ',' or a triple of strings each of which is the name of one of the + three indeterminates. The default is ``u, v, w``. + - ``order`` -- string (default='degrevlex') transferred to the corresponding + input of LaurentPolynomialRing_mpair + - ``markov_trace_version`` -- boolean (default is ``False``). If this is + set to ``True`` then ``self`` contains one invertible indeterminate in + addition which is meant to represent the writhe factor of a Markov trace + on the cubic Hecke algebra and which default name is ``s`` EXAMPLES:: @@ -1095,13 +1093,13 @@ def mirror_involution(self): last generator of ``self`` to its inverse and both others to their product with the image of the former. - From the cubic equation for a braid generator $\beta_i$: + From the cubic equation for a braid generator `\beta_i`: .. MATH:: \beta_i^3 - u \beta_i^2 + v\beta_i -w = 0 - One deduces the following cubic equation for $\beta_i^{-1}$: + One deduces the following cubic equation for `\beta_i^{-1}`: .. MATH:: @@ -1111,7 +1109,7 @@ def mirror_involution(self): The mirror involution of the braid group does not factor through the cubic Hecke algebra over its base ring, but it does if it is - considered as $\ZZ$-algebra. The base ring elements are transformed by + considered as `\ZZ`-algebra. The base ring elements are transformed by this automorphism. OUTPUT: @@ -1161,9 +1159,9 @@ def create_specialization(self, im_cubic_equation_parameters, im_writhe_paramete INPUT: - - ``im_cubic_equation_parameters`` -- list or tuple of three ring - elements such that there exists a ring homomorphism from the - corresponding elements of ``self`` to them + - ``im_cubic_equation_parameters`` -- list or tuple of three ring + elements such that there exists a ring homomorphism from the + corresponding elements of ``self`` to them OUTPUT: @@ -1338,7 +1336,7 @@ def markov_trace_version(self): def specialize_homfly(self): r""" - Returns a map to the two variable Laurent polynomial Ring which is + Return a map to the two variable Laurent polynomial Ring which is the parent of the HOMFLY-PT polynomial. EXAMPLES:: @@ -1389,7 +1387,7 @@ def specialize_homfly(self): def specialize_kauffman(self): r""" - Returns a map to the two variable Laurent polynomial Ring which is + Return a map to the two variable Laurent polynomial Ring which is the parent of the Kauffman polynomial. EXAMPLES:: @@ -1443,7 +1441,7 @@ def specialize_kauffman(self): def specialize_links_gould(self): r""" - Returns a map to the two variable Laurent polynomial Ring which is + Return a map to the two variable Laurent polynomial Ring which is the parent of the Links-Gould polynomial. EXAMPLES:: diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 77703386520..14033012c8b 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -3,14 +3,14 @@ Cubic Hecke Algebras This module is devoted to factors of the group algebra of the Artin braid groups, -such that the images $s_i$ of the braid generators satisfy a cubic equation: +such that the images `s_i` of the braid generators satisfy a cubic equation: .. MATH:: s_i^3 = u s_i^2 - v s_i + w -Here $u, v, w$ are elements in an arbitrary integral domain and $i$ is a positive -integer less than $n$, the number of the braid group's strands. By the analogue +Here `u, v, w` are elements in an arbitrary integral domain and `i` is a positive +integer less than `n`, the number of the braid group's strands. By the analogue to the *Iwahori Hecke algebras* (see :class:`~sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra`), in which the braid generators satisfy a quadratic relation these algebras have been called *cubic Hecke algebras*. The relations inherited from the braid group are: @@ -33,8 +33,8 @@ + ((u^2*v-v^2)/w)*c0*c1*c0^-1 + ((u^2-v)/w)*c0*c1*c0 + ((-u^3+u*v)/w)*c0*c1 + (-u*v+w)*c1^-1 -If the ring elements $u, v, w$ (which will be called the *cubic equation -parameters* in the sequel) are taken to be $u = v = 0, w = 1$ the cubic Hecke +If the ring elements `u, v, w` (which will be called the *cubic equation +parameters* in the sequel) are taken to be `u = v = 0, w = 1` the cubic Hecke algebra specializes to the group algebra of the *cubic braid group*, which is the factor group of the Artin braid group under setting the generators order to be three. A sage-class to handle these groups is attached and can be obtained by @@ -44,7 +44,7 @@ number of braid generators is less than six and infinite dimensional else wise. In the former (non trivial) cases they are also known as *cyclotomic Hecke algebras* corresponding to the complex reflection groups having Shepard-Todd -number $4, 25$ and $32$. +number `4, 25` and `32`. Since the *Broué, Malle, Rouquiere* conjecture has been proved in all these cases (for references see [Mar2012]_) there exists a finite free basis of the cubic Hecke @@ -315,21 +315,21 @@ def matrix(self, subdivide=False, representation_type=None, original=False): INPUT: - - ``subdivide`` -- boolean (default = False): this boolean is passed - to the block_matrix function - - ``representation_type`` -- instance of enum :class:`RepresentationType`. - This can be obtained by the attribute :attr:`CubicHeckeAlgebra.repr_type` - of ``self``. The following values are possible: - - - ``RegularLeft`` -- (regular left repr. from the above URL) - - ``RegularRight`` -- (regular right repr. from the above URL) - - ``SplitIrredChevie`` -- (split irred. repr. via CHEVIE) - - ``SplitIrredMarin`` -- (split irred. repr. from the above URL) - - default: ``SplitIrredChevie`` taken if GAP3 and CHEVIE are installed - on the system, otherwise the default will be ``SplitIrredMarin`` - - ``original`` -- boolean (default = False): if set to true the base - ring of the matrix will be the generic base_ring resp. generic extension - ring (for the split versions) of the parent of ``self`` + - ``subdivide`` -- boolean (default = False): this boolean is passed + to the block_matrix function + - ``representation_type`` -- instance of enum :class:`RepresentationType`. + This can be obtained by the attribute :attr:`CubicHeckeAlgebra.repr_type` + of ``self``. The following values are possible: + + - ``RegularLeft`` -- (regular left repr. from the above URL) + - ``RegularRight`` -- (regular right repr. from the above URL) + - ``SplitIrredChevie`` -- (split irred. repr. via CHEVIE) + - ``SplitIrredMarin`` -- (split irred. repr. from the above URL) + - default: ``SplitIrredChevie`` taken if GAP3 and CHEVIE are installed + on the system, otherwise the default will be ``SplitIrredMarin`` + - ``original`` -- boolean (default = False): if set to true the base + ring of the matrix will be the generic base_ring resp. generic extension + ring (for the split versions) of the parent of ``self`` OUTPUT: @@ -492,15 +492,15 @@ def formal_markov_trace(self, extended=False, field_embedding=False): INPUT: - - ``extended`` -- boolean (optional default ``False``) if set to ``True`` - the base ring of the Markov trace module is constructed as an extension - of generic extension ring of ``self``. Per default it is constructed - upon the generic base ring. + - ``extended`` -- boolean (``False``) if set to ``True`` the base ring + of the Markov trace module is constructed as an extension of generic + extension ring of ``self``. Per default it is constructed upon the + generic base ring. - - ``field_embedding`` -- boolean (optional default ``False``) if set to - ``True` the base ring of the module is the smallest field containing - the generic extension ring of ``self``. The keyword is meaningless - if ``extended=False``. + - ``field_embedding`` -- boolean (default ``False``) if set to ``True` + the base ring of the module is the smallest field containing the + generic extension ring of ``self``. The keyword is meaningless if + ``extended=False``. OUTPUT: @@ -577,10 +577,10 @@ def formal_markov_trace(self, extended=False, field_embedding=False): class CubicHeckeAlgebra(CombinatorialFreeModule): r""" Return the Cubic-Hecke algebra with respect to the Artin braid group on - $n$ strands. + `n` strands. This is a quotient of the group algebra of the Artin braid group, such that - the images $s_i$ ($1 \leq i < n$) of the braid generators satisfy a cubic + the images `s_i` (`1 \leq i < n`) of the braid generators satisfy a cubic equation (see module header :mod:`~sage.algebras.hecke_algebras.cubic_hecke_algebra` for more information, in a session type ``sage.algebras.hecke_algebras.cubic_hecke_algebra?``): @@ -592,17 +592,17 @@ class CubicHeckeAlgebra(CombinatorialFreeModule): The base ring of this algebra can be specified by giving optional keywords described below. If no keywords are given the base ring will be an instance of the special class :class:`CubicHeckeRingOfDefinition` which is constructed - as the polynomial ring in $u, v$ over the Laurent polynomial ring in $w$ over + as the polynomial ring in `u, v` over the Laurent polynomial ring in `w` over the integers. This ring will be called the *ring of definition* or sometimes for short *generic base ring*. But note, that in this context the word *generic* should not remind in a generic point of the corresponding scheme. - In addition to the base ring another ring containing the roots ($a, b$ and $c$) + In addition to the base ring another ring containing the roots (`a, b` and `c`) of the cubic equation will be needed to handle the split irreducible representations. This ring will be called *extension ring*. Generically, the extension ring will be an instance of the special class :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeExtensionRing` - which is constructed as the Laurent polynomial ring in $a, b$ and $c$ over + which is constructed as the Laurent polynomial ring in `a, b` and `c` over the integers adjoined with a primitive third root of unity. A special form of this *generic extension ring* is constructed as an instance of :class:`~sage.algebras.splitting_algebra.SplittingAlgebra` for the roots of @@ -648,21 +648,21 @@ class see the documentation of the matrix-method of the element class: INPUT: - - ``names`` -- string containing the names of the generators as images of - the braid group generators - - ``cubic_equation_parameters`` -- tuple ``(u, v, w)`` of three elements - in an integral domain used as coefficients in the cubic equation. If this - argument is given the base ring will be set to the common parent of - ``u, v, w``. In addition a conversion map from the generic base ring is - supplied. This keyword can also be used to change the variable names of - the generic base ring (see example 3 below). - - ``cubic_equation_roots`` -- tuple ``(a, b, c)`` of three elements in an - integral domain which stand for the roots of the cubic equation. If this - argument is given the extension ring will be set to the common parent of - ``a, b, c``. In addition a conversion map from the generic extension ring - and the generic base ring is supplied. This keyword can also be used to - change the variable names of the generic extension ring (see example 3 - below). + - ``names`` -- string containing the names of the generators as images of + the braid group generators + - ``cubic_equation_parameters`` -- tuple ``(u, v, w)`` of three elements + in an integral domain used as coefficients in the cubic equation. If this + argument is given the base ring will be set to the common parent of + ``u, v, w``. In addition a conversion map from the generic base ring is + supplied. This keyword can also be used to change the variable names of + the generic base ring (see example 3 below) + - ``cubic_equation_roots`` -- tuple ``(a, b, c)`` of three elements in an + integral domain which stand for the roots of the cubic equation. If this + argument is given the extension ring will be set to the common parent of + ``a, b, c``. In addition a conversion map from the generic extension ring + and the generic base ring is supplied. This keyword can also be used to + change the variable names of the generic extension ring (see example 3 + below) EXAMPLES: @@ -763,7 +763,7 @@ class see the documentation of the matrix-method of the element class: h^3 + (-E(15) - E(15)^4 - E(15)^7 + E(15)^8)*h^2 + (-E(15)^2 - E(15)^8 - E(15)^11 - E(15)^13 - E(15)^14)*h - E(15)^8 = 0 - TESTS: + TESTS:: sage: CHA3 = algebras.CubicHecke(3) sage: TestSuite(CHA3).run() @@ -845,11 +845,6 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N sage: CHA2 = algebras.CubicHecke(2, cubic_equation_parameters=(3,5,7)) sage: TestSuite(CHA2).run() """ - # ---------------------------------------------------------------------- - # saving input - # ---------------------------------------------------------------------- - self._names = names - # ---------------------------------------------------------------------- # Define underlying group # ---------------------------------------------------------------------- @@ -1107,7 +1102,8 @@ def check_base_ring_embedding(base_ring_embedding): category = AlgebrasWithBasis(base_ring) CombinatorialFreeModule.__init__(self, base_ring, self._cubic_braid_group, - prefix='', bracket=False, category=category) + prefix='', names=names, bracket=False, + category=category) # ---------------------------------------------------------------------- # init the attributes being set on demand @@ -1137,7 +1133,7 @@ def _repr_(self): String describing ``self`` - TESTS: + TESTS:: sage: CHA3 = algebras.CubicHecke(3) sage: CHA3 # indirect doctest @@ -1925,9 +1921,9 @@ def _braid_image_to_filecache(self, braid_tietze, braid_image_vect): INPUT: - - `braid_tietze` -- braid in Tietze form - - `braid_image_vect` -- image of the given braid in ``self`` in vector - representation + - ``braid_tietze`` -- braid in Tietze form + - ``braid_image_vect`` -- image of the given braid in ``self`` in vector + representation EXAMPLES:: @@ -2002,10 +1998,10 @@ def _braid_image_from_reduced_powers(self, braid_tietze): INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose image in - ``self`` should be computed. It is assumed that no successive - repetitions occur among the entries (i.e. (1,1) is not allowed - but (1, -2, 1) is) + - ``braid_tietze`` -- tuple representing the Braid whose image in + ``self`` should be computed. It is assumed that no successive + repetitions occur among the entries (i.e. (1,1) is not allowed + but (1, -2, 1) is) OUTPUT: @@ -2103,9 +2099,9 @@ def _braid_image_from_former_calculations(self, braid_tietze): INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose image in - ``self`` should be computed. The generator exponents in the braid - word are assumed to be 1 or -1 + - ``braid_tietze`` -- tuple representing the Braid whose image in + ``self`` should be computed. The generator exponents in the braid + word are assumed to be 1 or -1 OUTPUT: @@ -2193,9 +2189,9 @@ def _braid_image_by_basis_extension(self, braid_tietze): INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose image in - ``self`` should be computed. The generator exponents in the braid - word are assumed to be 1 or -1 + - ``braid_tietze`` -- tuple representing the Braid whose image in + ``self`` should be computed. The generator exponents in the braid + word are assumed to be 1 or -1 OUTPUT: @@ -2411,13 +2407,13 @@ def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preim INPUT: - - ``vect`` -- element of ``self`` in vector form (obtained by + - ``vect`` -- element of ``self`` in vector form (obtained by :meth:`to_vector`) - - ``gen_tuple`` -- list of generators (that is a braid in Tietze form) + - ``gen_tuple`` -- list of generators (that is a braid in Tietze form) which operates on ``vect`` - ``representation_type`` -- instance of :class:`RepresentationType` (one of `RegularLeft` or `RegularRight`) - - ``braid_preimage`` -- (optional) a word representing a braid whose + - ``braid_preimage`` -- (optional) a word representing a braid whose image is vect (if it exist). This is used to record intermediate results to the dynamic library @@ -2652,14 +2648,14 @@ def _markov_trace_module(self, extended=False, field_embedding=False): INPUT: - - ``extended`` -- boolean (optional default ``False``) if set to ``True`` - the base ring of the module is the Markov trace version of the - generic extension ring of ``self``. + - ``extended`` -- boolean (default ``False``) if set to ``True`` the + base ring of the module is the Markov trace version of the generic + extension ring of ``self``. - - ``field_embedding`` -- boolean (optional default ``False``) if set to - ``True` the base ring of the module is the smallest field containing - the generic extension ring of ``self``. The keyword is meaningless - if ``extended=False``. + - ``field_embedding`` -- boolean (default ``False``) if set to ``True` + the base ring of the module is the smallest field containing the + generic extension ring of ``self``. The keyword is meaningless if + ``extended=False``. OUTPUT: @@ -2755,9 +2751,9 @@ def is_filecache_empty(self, section=None): INPUT: - - ``section`` -- (optional, default is ``None`` meaning all sections) - instance of enum :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` - which can be selected using :meth:`select_filecache_section` + - ``section`` -- (default is ``None`` meaning all sections) instance + of enum :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` + which can be selected using :meth:`select_filecache_section` EXAMPLES:: @@ -2774,12 +2770,12 @@ def reset_filecache(self, section=None, commit=True): INPUT: - - ``section`` -- (optional, default is ``None`` meaning all sections) - instance of enum :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` - which can be selected using :meth:`select_filecache_section` + - ``section`` -- (default is ``None`` meaning all sections) instance + of enum :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` + which can be selected using :meth:`select_filecache_section` - - ``commit`` -- boolean (optional, default is ``True``) if set to ``False`` the reset - is not written to the filesystem + - ``commit`` -- boolean (default is ``True``) if set to ``False`` the + reset is not written to the filesystem EXAMPLES:: @@ -2901,7 +2897,7 @@ def mirror_isomorphism(self, element): of the mirror involution of braids to ``self``. The mirror involution of a braid is given by inverting all generators in the braid word. It does not factor through ``self`` over the base ring but it factors - through ``self`` considered as a $\ZZ$-module relative to the mirror + through ``self`` considered as a `\ZZ`-module relative to the mirror automorphism of the generic base ring. Considering ``self`` as algebra over its base ring this involution defines an isomorphism of ``self`` onto a different cubic Hecke algebra with a different cubic equation. @@ -2914,7 +2910,7 @@ def mirror_isomorphism(self, element): INPUT: - - ``element`` -- instance of the element class of ``self`` + - ``element`` -- instance of the element class of ``self`` OUTPUT: @@ -2957,13 +2953,12 @@ def cubic_equation(self, var='h', as_coefficients=False, generic=False): INPUT: - - ``var`` -- string (optional, default ``h``) setting the indeterminate - of the equation - - ``as_coefficients`` -- boolean (optional, default ``False``) if set - to ``True`` the - list of coefficients is returned - - ``generic`` -- boolean (optional, default ``False``) if set to - ``True`` the cubic equation will be given over the generic base ring + - ``var`` -- string (default ``h``) setting the indeterminate of the + equation + - ``as_coefficients`` -- boolean (default ``False``) if set to ``True`` + the list of coefficients is returned + - ``generic`` -- boolean (default ``False``) if set to ``True`` the + cubic equation will be given over the generic base ring OUTPUT: @@ -3004,9 +2999,8 @@ def cubic_equation_roots(self, generic=False): INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to - ``True`` the roots are returned as elements of the generic - extension ring + - ``generic`` -- boolean (default ``False``) if set to ``True`` the + roots are returned as elements of the generic extension ring OUTPUT: @@ -3036,9 +3030,8 @@ def cubic_equation_parameters(self, generic=False): INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to - ``True`` the coefficients are returned as elements of the generic - base ring + - ``generic`` -- boolean (default ``False``) if set to ``True`` the + coefficients are returned as elements of the generic base ring OUTPUT: @@ -3068,9 +3061,8 @@ def base_ring(self, generic=False): INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to - ``True`` the ring of definition (here often called the generic base - ring) is returned + - ``generic`` -- boolean (default ``False``) if set to ``True`` the ring + of definition (here often called the generic base ring) is returned OUTPUT: @@ -3101,9 +3093,9 @@ def extension_ring(self, generic=False): INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to - ``True`` the extension ring of definition (here often called the - generic extension ring) is returned + - ``generic`` -- boolean (default ``False``) if set to ``True`` the + extension ring of definition (here often called the generic + extension ring) is returned OUTPUT: @@ -3138,9 +3130,9 @@ def cyclotomic_generator(self, generic=False): INPUT: - - ``generic`` -- boolean (optional, default ``False``) if set to - ``True`` the cyclotomic_generator is returned as an element extension - ring of definition. + - ``generic`` -- boolean (default ``False``) if set to ``True`` the + cyclotomic_generator is returned as an element extension ring of + definition OUTPUT: @@ -3482,7 +3474,7 @@ def characters(self, irr=None, original=True): - ``irr`` -- (optional) instance of :class:`AbsIrreducibeRep` selecting the irreducible representation corresponding to the character. If not given a list of all characters is returned - - ``original`` -- (optional, default ``True``) see description above + - ``original`` -- (default ``True``) see description above OUTPUT: diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 98b424551b9..2b80b83bea3 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -1157,10 +1157,10 @@ def update_basis_extensions(self, new_basis_extensions): EXAMPLES:: - sage: from sage.databases.cubic_hecke_db import %s%s - sage: %s(%s2) + {}age: from sage.databases.cubic_hecke_db import %s%s + {}age: %s(%s2) {} -""".format('r"""', '"""') +""".format('r"""', 's', 's', '"""') # s in the middle to hide these lines from _test_enough_doctests def create_demo_data(filename='demo_data.py'): @@ -1237,7 +1237,7 @@ def read_basis(num_strands=3): r""" Return precomputed data of Ivan Marin - This code was generated by ``create_demo_data``, please don't edit. + This code was generated by :func:`create_demo_data`, please don't edit. INPUT: @@ -1259,12 +1259,11 @@ def read_basis(num_strands=3): -1], [2, -1, 2], [1, 2, -1, 2], [-1, 2, -1, 2]] return data[num_strands] - def read_irr(variables, num_strands=3): r""" Return precomputed data of Ivan Marin - This code was generated by ``create_demo_data``, please don't edit. + This code was generated by :func:`create_demo_data`, please don't edit. INPUT: @@ -1305,12 +1304,11 @@ def read_irr(variables, num_strands=3): 1/b, (1, 1): 1/b, (1, 2): a/b + b/c, (2, 2): 1/c}]]) return data[num_strands] - def read_regl(variables, num_strands=3): r""" Return precomputed data of Ivan Marin - This code was generated by ``create_demo_data``, please don't edit. + This code was generated by :func:`create_demo_data`, please don't edit. INPUT: @@ -1381,12 +1379,11 @@ def read_regl(variables, num_strands=3): (22, 6): 1/w, (22, 13): u/w, (22, 22): v/w, (23, 13): 1}]]) return data[num_strands] - def read_regr(variables, num_strands=3): r""" Return precomputed data of Ivan Marin - This code was generated by ``create_demo_data``, please don't edit. + This code was generated by :func:`create_demo_data`, please don't edit. INPUT: From 86b3f9546aae9dd4d1d9632daafdefe186be7efc Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Fri, 1 Apr 2022 09:02:21 +0200 Subject: [PATCH 014/591] 33590: take care of CHEVIE --- build/pkgs/database_cubic_hecke/spkg-check.in | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build/pkgs/database_cubic_hecke/spkg-check.in b/build/pkgs/database_cubic_hecke/spkg-check.in index 43c4682810d..1929d7e3d69 100644 --- a/build/pkgs/database_cubic_hecke/spkg-check.in +++ b/build/pkgs/database_cubic_hecke/spkg-check.in @@ -1,5 +1,11 @@ cd $SAGE_ROOT/src/sage/ -FILES="databases/ features/ algebras/hecke_algebras/" +OPTIONS="sage,database_cubic_hecke" +CHEVIE=$($SAGE_ROOT/sage -c "from sage.combinat.root_system.reflection_group_real import is_chevie_available; print(is_chevie_available())") +if [ $CHEVIE = "True" ]; then + OPTIONS=$OPTIONS",gap3" +fi + +FILES="databases/cubic_hecke_db.py algebras/hecke_algebras/" echo "Testing: "$FILES -sage -tp --long --optional="sage,database_cubic_hecke" $FILES || sdh_die "Error testing cubic Hecke algebra database" +sage -tp --long --optional=$OPTIONS $FILES || sdh_die "Error testing cubic Hecke algebra database" From cc3c11372283100f85e5513955455726891f0890 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Sun, 3 Apr 2022 22:46:53 +0200 Subject: [PATCH 015/591] 29717: implement _coerce_map_from_ for extension ring --- .../cubic_hecke_base_ring.py | 78 ++++++++++++------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py index e8b6f107d41..4846baf4abf 100644 --- a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py @@ -324,6 +324,45 @@ def _element_constructor_(self, x, mon=None): return self._convert_from_gap3_mvp(x) return super(CubicHeckeExtensionRing, self)._element_constructor_(x, mon=mon) + def _coerce_map_from_(self, R): + r""" + The rings that canonically coerce to ``self`` ar the ones from + inheritence and the base ring of definition of the cubic Hecke algebra. + + EXAMPLES:: + + sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ + ....: import cubic_hecke_base_ring as chbr + sage: BR = chbr.CubicHeckeRingOfDefinition() + sage: ER = BR.extension_ring() + sage: ER(BR.an_element()) + a*b + a*c + b*c + a*b^-1*c^-1 + 2*c^-1 + a^-1*b*c^-1 + 2*b^-1 + + 2*a^-1 + a^-1*b^-1*c + sage: MBR = chbr.CubicHeckeRingOfDefinition(markov_trace_version=True) + sage: MER = MBR.extension_ring() + sage: MER(MBR.an_element()) + a*b*s^-1 + a*c*s^-1 + b*c*s^-1 + a*b^-1*c^-1 + 2*c^-1 + + a^-1*b*c^-1 + 2*b^-1 + 2*a^-1 + a^-1*b^-1*c + """ + if isinstance(R, CubicHeckeRingOfDefinition): + markov = R.markov_trace_version() + a, b, c, *rem = self.gens() + iu = a + b + c + iv = a*b + a*c + b*c + iw = a*b*c + im_gens = [iu, iv, iw] + if markov: + if self.markov_trace_version(): + im_gens += rem + # check of embedding fails in this case as long as the images of + # ``iu`` and ``iv`` need to be invertible (see comment in + # :meth:`__init__`). # :class:`CubicHeckeRingOfDefinition`). + embedding_into_extension_ring = R.hom(im_gens, check=False) + else: + embedding_into_extension_ring = R.hom(im_gens) + return embedding_into_extension_ring + return super(CubicHeckeExtensionRing, self)._coerce_map_from_(R) + def hom(self, im_gens, codomain=None, check=True, base_map=None): r""" Custom version overloading the corresponding method of class @@ -907,6 +946,17 @@ class CubicHeckeRingOfDefinition(Localization): It contains one invertible indeterminate (representing the product of the roots of the cubic equation) and two non invertible indeterminates. + With the name *ring of definition* we follow a suggestion by Ivan Marin. + We avoid alternative names like *generic* or *universal* base ring + as these have some issues. The first option could be misleading + in view of the term *generic point* used in algebraic geometry which would + mean the function field in ``u, v, w``, here. + + The second option is problematic since the base ring itself is not a + universal object. Rather, the universal object is the cubic Hecke algebra + considered as a `ZZ` algebra including ``u, v, w`` as pairwise commuting + indeterminates. From this point of view the base ring appears to be a + subalgebra of this universal object generated by ``u, v, w``. INPUT: @@ -920,7 +970,6 @@ class CubicHeckeRingOfDefinition(Localization): addition which is meant to represent the writhe factor of a Markov trace on the cubic Hecke algebra and which default name is ``s`` - EXAMPLES:: sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ @@ -949,7 +998,6 @@ class CubicHeckeRingOfDefinition(Localization): - 5*E(105)^41 - 5*E(105)^44 - 5*E(105)^47 - 5*E(105)^53 - 5*E(105)^59 - 5*E(105)^62 - 5*E(105)^68 - 8*E(105)^71 - 5*E(105)^74 - 5*E(105)^83 - 5*E(105)^86 - 5*E(105)^89 - 5*E(105)^92 - 5*E(105)^101 - 5*E(105)^104 - """ def __init__(self, names=('u', 'v', 'w', 's'), order='degrevlex', markov_trace_version=False): r""" @@ -1288,31 +1336,7 @@ def extension_ring(self, names=('a', 'b', 'c', 's')): over Integer Ring """ markov = self._is_markov_trace_version() - ExtensionRing = CubicHeckeExtensionRing(names, ring_of_definition=self, markov_trace_version=markov) - a, b, c, *rem = ExtensionRing.gens() - - # ---------------------------------------------------------------------- - # constructing a canonical embedding of the generic base ring into the - # extension ring - # ---------------------------------------------------------------------- - iu = a+b+c - iv = a*b+a*c+b*c - iw = a*b*c - im_gens = [iu, iv, iw] - if markov: - im_gens += rem - # check of embedding fails in this case as long as the images of - # ``iu`` and ``iv`` need to be invertible (see comment in - # :meth:`__init__`). # :class:`CubicHeckeRingOfDefinition`). - embedding_into_extension_ring = self.hom(im_gens, check=False) - else: - embedding_into_extension_ring = self.hom(im_gens) - if not ExtensionRing.has_coerce_map_from(self): - ExtensionRing._unset_coercions_used() - ExtensionRing.register_coercion(embedding_into_extension_ring) - ExtensionRing.register_conversion(embedding_into_extension_ring) - - return ExtensionRing + return CubicHeckeExtensionRing(names, ring_of_definition=self, markov_trace_version=markov) def markov_trace_version(self): r""" From bfcf191800694715005531f09dd83089b054baab Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 4 Apr 2022 08:46:43 +0200 Subject: [PATCH 016/591] 29717: reorganize directories --- .../algebras/cubic_hecke_algebra.rst | 4 +- .../base_rings_of_definition/__init__.py | 0 .../hecke_algebras/cubic_hecke_algebra.py | 8 +- .../cubic_hecke_base_ring.py | 93 +++++++------------ .../cubic_hecke_matrix_rep.py | 44 ++++----- .../matrix_representations/__init__.py | 0 src/sage/databases/cubic_hecke_db.py | 28 +++--- 7 files changed, 73 insertions(+), 104 deletions(-) delete mode 100644 src/sage/algebras/hecke_algebras/base_rings_of_definition/__init__.py rename src/sage/algebras/hecke_algebras/{base_rings_of_definition => }/cubic_hecke_base_ring.py (93%) rename src/sage/algebras/hecke_algebras/{matrix_representations => }/cubic_hecke_matrix_rep.py (94%) delete mode 100644 src/sage/algebras/hecke_algebras/matrix_representations/__init__.py diff --git a/src/doc/en/reference/algebras/cubic_hecke_algebra.rst b/src/doc/en/reference/algebras/cubic_hecke_algebra.rst index c0dccab3dd1..5ba74eb00f0 100644 --- a/src/doc/en/reference/algebras/cubic_hecke_algebra.rst +++ b/src/doc/en/reference/algebras/cubic_hecke_algebra.rst @@ -5,6 +5,6 @@ Cubic Hecke Algebras :maxdepth: 2 sage/algebras/hecke_algebras/cubic_hecke_algebra - sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring - sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep + sage/algebras/hecke_algebras/cubic_hecke_base_ring + sage/algebras/hecke_algebras/cubic_hecke_matrix_rep diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/__init__.py b/src/sage/algebras/hecke_algebras/base_rings_of_definition/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 14033012c8b..b438a1447e0 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -133,8 +133,8 @@ from sage.algebras.splitting_algebra import solve_with_extension from sage.modules.free_module_element import vector from sage.matrix.matrix_space import MatrixSpace -from sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeRingOfDefinition -from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import CubicHeckeMatrixSpace, AbsIrreducibeRep, RepresentationType +from sage.algebras.hecke_algebras.cubic_hecke_base_ring import CubicHeckeRingOfDefinition +from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import CubicHeckeMatrixSpace, AbsIrreducibeRep, RepresentationType ############################################################################## @@ -333,7 +333,7 @@ def matrix(self, subdivide=False, representation_type=None, original=False): OUTPUT: - An instance of the class :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.CubicHeckeMatrixRep` + An instance of the class :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.CubicHeckeMatrixRep` which is inherited from :class:`~sage.matrix.matrix_generic_dense.Matrix_generic_dense`. In the case of the irreducible representations the matrix is given as a block matrix. Each single irreducible can be obtained as item indexed by @@ -601,7 +601,7 @@ class CubicHeckeAlgebra(CombinatorialFreeModule): of the cubic equation will be needed to handle the split irreducible representations. This ring will be called *extension ring*. Generically, the extension ring will be an instance of the special class - :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeExtensionRing` + :class:`~sage.algebras.hecke_algebras.cubic_hecke_base_ring.CubicHeckeExtensionRing` which is constructed as the Laurent polynomial ring in `a, b` and `c` over the integers adjoined with a primitive third root of unity. A special form of this *generic extension ring* is constructed as an instance of diff --git a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py similarity index 93% rename from src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py rename to src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py index 4846baf4abf..7015b438fb3 100644 --- a/src/sage/algebras/hecke_algebras/base_rings_of_definition/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -52,8 +52,7 @@ def normalize_names_markov(names, markov_trace_version): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: chbr.normalize_names_markov('a, b, c', False) ('a', 'b', 'c') sage: chbr.normalize_names_markov(('u', 'v', 'w', 's'), False) @@ -78,8 +77,7 @@ def register_ring_hom(ring_hom): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.create_specialization([E(5), E(7), E(3)]) # indirect doctest Universal Cyclotomic Field @@ -122,8 +120,7 @@ class GaloisGroupAction(Action): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: from operator import mul sage: R. = ZZ[] sage: G = SymmetricGroup(3) @@ -140,8 +137,7 @@ def _act_(self, perm, pol): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: from operator import mul sage: R. = QQ[] sage: G = SymmetricGroup(2) @@ -207,8 +203,7 @@ class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: chbr.CubicHeckeExtensionRing('a, b, c') Multivariate Laurent Polynomial Ring in a, b, c over Splitting Algebra of x^2 + x + 1 @@ -223,8 +218,7 @@ def __init__(self, names, order='degrevlex', ring_of_definition=None, third_unit TESTS:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: TestSuite(ER).run() """ @@ -280,8 +274,7 @@ def construction(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: ER._test_category() # indirect doctest """ @@ -293,8 +286,7 @@ def __reduce__(self): TESTS:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: loads(dumps(ER)) == ER True @@ -331,8 +323,7 @@ def _coerce_map_from_(self, R): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: ER = BR.extension_ring() sage: ER(BR.an_element()) @@ -376,8 +367,7 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: UCF = UniversalCyclotomicField() sage: map = ER.hom((UCF.gen(3),) + (UCF(3),UCF(4),UCF(5))) @@ -411,8 +401,7 @@ def _an_element_(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('x, y, z') sage: ER.an_element() # indirect doctest y^2*z^-1 + e3*x @@ -437,8 +426,7 @@ def _is_markov_trace_version(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: ER._is_markov_trace_version() False @@ -467,8 +455,7 @@ def _convert_from_gap3_mvp(self, mvp_expression): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: gap3_string = '2+a^-2bc+a^-1b^-1c^2+a^-1b^2c^-1+ab^-2E3c' sage: ER._convert_from_gap3_mvp(gap3_string) @@ -501,8 +488,7 @@ def cyclotomic_generator(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: ER.cyclotomic_generator() e3 @@ -518,8 +504,7 @@ def conjugation(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('x, y, z') sage: conj = ER.conjugation() sage: conj(ER.an_element()) @@ -539,8 +524,7 @@ def cubic_equation_galois_group(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: G = ER.cubic_equation_galois_group() sage: t = ER.an_element() @@ -574,8 +558,7 @@ def mirror_involution(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('p, q, r') sage: ER.mirror_involution() Ring endomorphism of Multivariate Laurent Polynomial Ring in p, q, r @@ -632,8 +615,7 @@ def create_specialization(self, im_cubic_equation_roots, im_writhe_parameter=Non EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: t = ER.an_element(); t b^2*c^-1 + e3*a @@ -758,8 +740,7 @@ def as_splitting_algebra(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: GBR = chbr.CubicHeckeRingOfDefinition() sage: GER = GBR.extension_ring() sage: ER = GER.as_splitting_algebra(); ER @@ -838,8 +819,7 @@ def field_embedding(self, characteristic=0): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: ER = BR.extension_ring() sage: ER.field_embedding() @@ -917,8 +897,7 @@ def markov_trace_version(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: ER = chbr.CubicHeckeExtensionRing('a, b, c') sage: ER.markov_trace_version() Multivariate Laurent Polynomial Ring in a, b, c, s @@ -972,8 +951,7 @@ class CubicHeckeRingOfDefinition(Localization): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: u, v, w = BR.gens() sage: ele = 3*u*v-5*w**(-2) @@ -1005,8 +983,7 @@ def __init__(self, names=('u', 'v', 'w', 's'), order='degrevlex', markov_trace_v TESTS:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: TestSuite(BR).run() """ @@ -1056,8 +1033,7 @@ def _defining_names(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR._defining_names() (u, v, w) @@ -1071,8 +1047,7 @@ def _an_element_(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.an_element() # indirect doctest (u^2 + v*w)/w @@ -1096,8 +1071,7 @@ def _is_markov_trace_version(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR._is_markov_trace_version() False @@ -1116,8 +1090,7 @@ def cubic_equation(self, var='h', as_coefficients=False): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.cubic_equation() h^3 - u*h^2 + v*h - w @@ -1166,8 +1139,7 @@ def mirror_involution(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.mirror_involution() Ring endomorphism of Multivariate Polynomial Ring in u, v, w @@ -1219,8 +1191,7 @@ def create_specialization(self, im_cubic_equation_parameters, im_writhe_paramete EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: t = BR.an_element(); t (u^2 + v*w)/w @@ -1326,8 +1297,7 @@ def extension_ring(self, names=('a', 'b', 'c', 's')): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: BR = chbr.CubicHeckeRingOfDefinition() sage: BR.extension_ring() Multivariate Laurent Polynomial Ring in a, b, c @@ -1346,8 +1316,7 @@ def markov_trace_version(self): EXAMPLES:: - sage: from sage.algebras.hecke_algebras.base_rings_of_definition \ - ....: import cubic_hecke_base_ring as chbr + sage: from sage.algebras.hecke_algebras import cubic_hecke_base_ring as chbr sage: GBR = chbr.CubicHeckeRingOfDefinition() sage: GBR.markov_trace_version() Multivariate Polynomial Ring in u, v, w, s diff --git a/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py similarity index 94% rename from src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py rename to src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py index 76f46a53f54..ae20c0f8b6a 100644 --- a/src/sage/algebras/hecke_algebras/matrix_representations/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -45,7 +45,7 @@ class GenSign(Enum): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chmr.GenSign.pos sage: chmr.GenSign.neg @@ -71,7 +71,7 @@ class RepresentationType(Enum): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chmr.RepresentationType.RegularLeft.is_regular() True """ @@ -82,7 +82,7 @@ def is_split(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chevie = chmr.RepresentationType.SplitIrredChevie sage: chevie.is_split() True @@ -96,7 +96,7 @@ def is_regular(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: reg_left = chmr.RepresentationType.RegularLeft sage: reg_left.is_regular() True @@ -110,7 +110,7 @@ def data_section(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: reg_left = chmr.RepresentationType.RegularLeft sage: reg_left.data_section() @@ -123,7 +123,7 @@ def number_of_representations(self, nstrands): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chmr.RepresentationType.SplitIrredChevie.number_of_representations(4) 24 sage: chmr.RepresentationType.SplitIrredMarin.number_of_representations(4) @@ -178,7 +178,7 @@ class AbsIrreducibeRep(Enum): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: [irr.name for irr in chmr.AbsIrreducibeRep] ['W2_100', 'W2_001', 'W2_010', 'W3_100', 'W3_001', 'W3_010', 'W3_011', 'W3_110', 'W3_101', 'W3_111', 'W4_100', 'W4_001', 'W4_010', 'W4_011', 'W4_110', 'W4_101', @@ -200,7 +200,7 @@ def alternative_name(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chmr.AbsIrreducibeRep.W3_011.alternative_name() 'Tbc' """ @@ -212,7 +212,7 @@ def dimension(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chmr.AbsIrreducibeRep.W3_111.dimension() 3 """ @@ -224,7 +224,7 @@ def number_gens(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chmr.AbsIrreducibeRep.W3_001.number_gens() 2 sage: chmr.AbsIrreducibeRep.W4_001.number_gens() @@ -239,7 +239,7 @@ def length_orbit(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chmr.AbsIrreducibeRep.W3_001.length_orbit() 3 sage: chmr.AbsIrreducibeRep.W3_111.length_orbit() @@ -254,7 +254,7 @@ def gap_index(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chmr.AbsIrreducibeRep.W3_111.gap_index() 6 """ @@ -266,7 +266,7 @@ def internal_index(self): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: chmr.AbsIrreducibeRep.W3_111.internal_index() 6 """ @@ -377,7 +377,7 @@ class CubicHeckeMatrixRep(Matrix_generic_dense): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA2. = algebras.CubicHecke(2) sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) sage: m1 = MS(c1); m1 @@ -385,7 +385,7 @@ class CubicHeckeMatrixRep(Matrix_generic_dense): [ 0 b 0] [ 0 0 -b - a + u] sage: type(m1) - + sage: m1.block_diagonal_list() [[a], [b], [-b - a + u]] @@ -608,7 +608,7 @@ def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, su TESTS:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA2. = algebras.CubicHecke(2) sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) sage: TestSuite(MS).run() @@ -647,7 +647,7 @@ def __init__(self, base_ring, dimension, cols, sparse=True, TESTS:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA3. = algebras.CubicHecke(3) sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) sage: TestSuite(MS).run() # long time @@ -716,7 +716,7 @@ def _element_constructor_(self, x): EXAMLPES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA3. = algebras.CubicHecke(3) sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) sage: m1 = MS._element_constructor_(c1) @@ -770,7 +770,7 @@ def __call__(self, entries=None, coerce=True, copy=None): EXAMLPES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA2. = algebras.CubicHecke(2) sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) sage: MS(c1) @@ -804,7 +804,7 @@ def _specialize_matrix(self, mat): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA2. = algebras.CubicHecke(2) sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) sage: B = MS._original_base_ring @@ -837,7 +837,7 @@ def _image_on_gen(self, gen_ind): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA3. = algebras.CubicHecke(3) sage: MS = chmr.CubicHeckeMatrixSpace(CHA3) sage: MS._image_on_gen(1) @@ -918,7 +918,7 @@ def _image_on_basis(self, basis_element): EXAMPLES:: - sage: import sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep as chmr + sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA3. = algebras.CubicHecke(3) sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) sage: MS._image_on_basis(c1) diff --git a/src/sage/algebras/hecke_algebras/matrix_representations/__init__.py b/src/sage/algebras/hecke_algebras/matrix_representations/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 2b80b83bea3..58ae634c55f 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -55,7 +55,7 @@ from sage.misc.verbose import verbose from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ -from sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring import CubicHeckeExtensionRing +from sage.algebras.hecke_algebras.cubic_hecke_base_ring import CubicHeckeExtensionRing # ------------------------------------------------------------------------------ @@ -80,7 +80,7 @@ def simplify(mat): EXAMPLES:: sage: from sage.databases.cubic_hecke_db import simplify - sage: import sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring as chbr + sage: import sage.algebras.hecke_algebras.cubic_hecke_base_ring as chbr sage: ER. = chbr.CubicHeckeExtensionRing() sage: mat = matrix(ER, [[2*a, -3], [c, 4*b*~c]]); mat [ 2*a -3] @@ -247,7 +247,7 @@ def read(self, section, variables=None, nstrands=4): verbose('loading data library %s for %s strands ...' % (section.value, nstrands)) - from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import GenSign + from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import GenSign if self.demo_version(): if nstrands >= 4: @@ -292,7 +292,7 @@ def read_matrix_representation(self, representation_type, gen_ind, nstrands, rin INPUT: - ``representation_type`` -- instance of enum - :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.RepresentationType` specifying the type of the representation @@ -313,7 +313,7 @@ def read_matrix_representation(self, representation_type, gen_ind, nstrands, rin sage: m1rl[0].dimensions() (24, 24) """ - from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType, GenSign + from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType, GenSign if not isinstance(representation_type, RepresentationType): raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) @@ -756,7 +756,7 @@ def reset_library(self, section=None): if not isinstance(section, CubicHeckeFileCache.section): raise TypeError('section must be an instance of enum %s' % CubicHeckeFileCache.section) - from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType data_lib = self._data_library empty_dict = {} if section == self.section.matrix_representations: @@ -794,7 +794,7 @@ def is_empty(self, section=None): self.read(section) data_lib = self._data_library[section] - from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType if section == self.section.matrix_representations: for rep_type in RepresentationType: if len(data_lib[rep_type]) > 0: @@ -904,15 +904,15 @@ def read_matrix_representation(self, representation_type, monomial_tietze, ring_ INPUT: - - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.RepresentationType` specifying the type of the representation - ``monomial_tietze`` -- tuple representing the braid in Tietze form - ``ring_of_definition`` -- instance of - :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeRingOfDefinition` + :class:`~sage.algebras.hecke_algebras.cubic_hecke_base_ring.CubicHeckeRingOfDefinition` respectively - :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeExtensionRing` + :class:`~sage.algebras.hecke_algebras.cubic_hecke_base_ring.CubicHeckeExtensionRing` depending on whether ``representation_type`` is split or not OUTPUT: @@ -938,7 +938,7 @@ def read_matrix_representation(self, representation_type, monomial_tietze, ring_ sage: cha_fc.read_matrix_representation(rt.RegularLeft, gt, R) == None True """ - from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType if not isinstance(representation_type, RepresentationType): raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) @@ -961,7 +961,7 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr INPUT: - ``representation_type`` -- instance of enum - :class:`~sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep.RepresentationType` + :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.RepresentationType` specifying the type of the representation - ``monomial_tietze`` -- tuple representing the braid in Tietze form @@ -990,7 +990,7 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr sage: [m] == cha_fc.read_matrix_representation(rt.RegularRight, git, R) True """ - from sage.algebras.hecke_algebras.matrix_representations.cubic_hecke_matrix_rep import RepresentationType + from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType if not isinstance(representation_type, RepresentationType): raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) @@ -1018,7 +1018,7 @@ def read_braid_image(self, braid_tietze, ring_of_definition): - ``braid_tietze`` -- tuple representing the braid in Tietze form - ``ring_of_definition`` -- instance of - :class:`~sage.algebras.hecke_algebras.base_rings_of_definition.cubic_hecke_base_ring.CubicHeckeRingOfDefinition` + :class:`~sage.algebras.hecke_algebras.cubic_hecke_base_ring.CubicHeckeRingOfDefinition` OUTPUT: From 84619e7e7f00bd761f82578c59477bede06f3e52 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 6 Apr 2022 08:23:29 +0200 Subject: [PATCH 017/591] 29717: fix file-cache issue --- build/pkgs/database_cubic_hecke/SPKG.rst | 4 ++-- src/sage/databases/cubic_hecke_db.py | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/build/pkgs/database_cubic_hecke/SPKG.rst b/build/pkgs/database_cubic_hecke/SPKG.rst index e36f6444960..44a02b3aef5 100644 --- a/build/pkgs/database_cubic_hecke/SPKG.rst +++ b/build/pkgs/database_cubic_hecke/SPKG.rst @@ -1,5 +1,5 @@ -database_cubic_hecke: Ivan Marin's representations of the cubic Hecke algebra on 4 strands as Python dictionaries -================================================================================================================= +database_cubic_hecke: Ivan Marin's representations of the cubic Hecke algebra +============================================================================= Description ----------- diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 58ae634c55f..32e691a4340 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -762,7 +762,7 @@ def reset_library(self, section=None): if section == self.section.matrix_representations: for rep_type in RepresentationType: new_dict = {} - empty_dict.update({rep_type: new_dict}) + empty_dict.update({rep_type.name: new_dict}) elif section == self.section.basis_extensions: empty_dict = [] data_lib.update({section: empty_dict}) @@ -797,7 +797,7 @@ def is_empty(self, section=None): from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType if section == self.section.matrix_representations: for rep_type in RepresentationType: - if len(data_lib[rep_type]) > 0: + if len(data_lib[rep_type.name]) > 0: return False return True @@ -890,6 +890,8 @@ def read(self, section): except IOError: self.reset_library(section) verbose('... not found!') + except (ImportError, ModuleNotFoundError): + raise ImportError('incompatible file cache! Move %s to another directory' % fname) return data_lib[section] @@ -942,7 +944,7 @@ def read_matrix_representation(self, representation_type, monomial_tietze, ring_ if not isinstance(representation_type, RepresentationType): raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) - matrix_representations = self.read(self.section.matrix_representations)[representation_type] + matrix_representations = self.read(self.section.matrix_representations)[representation_type.name] if monomial_tietze in matrix_representations.keys(): matrix_list_dict = matrix_representations[monomial_tietze] matrix_list = [matrix(ring_of_definition, mat_dict, sparse=True) for mat_dict in matrix_list_dict] @@ -994,7 +996,7 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr if not isinstance(representation_type, RepresentationType): raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) - matrix_representations = self.read(self.section.matrix_representations)[representation_type] + matrix_representations = self.read(self.section.matrix_representations)[representation_type.name] if monomial_tietze in matrix_representations.keys(): # entry already registered From 3009364d64c108ae0f9726a88875eb2a15ae0955 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 2 May 2022 18:57:08 +0200 Subject: [PATCH 018/591] 29717: about incompatible file-cache again --- .../hecke_algebras/cubic_hecke_algebra.py | 18 ++++----- src/sage/databases/cubic_hecke_db.py | 40 +++++++++++++++++-- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index b438a1447e0..66e554c85df 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -469,10 +469,10 @@ def formal_markov_trace(self, extended=False, field_embedding=False): A Markov trace is a family of class functions `tr_n` on the family of braid groups `B_n` into some commutative ring `R` depending on a - unit `s \in R` such that for all `b in B_n` the following two + unit `s \in R` such that for all `b \in B_n` the following two conditions are satisfied (see [Kau1991]_, section 7): - ..MATH:: + .. MATH:: \begin{array}{lll} tr_{n+1}(b g_n) & = & s tr_n(b)\\ @@ -482,7 +482,7 @@ def formal_markov_trace(self, extended=False, field_embedding=False): The unit `s` is often called the writhe factor and corresponds to the additional variable mentioned above. - ..NOTE:: + .. NOTE:: Currently it is not known if all linear forms of this sub-module belong to a Markov trace, i.e. can be extended to the full tower @@ -592,13 +592,13 @@ class CubicHeckeAlgebra(CombinatorialFreeModule): The base ring of this algebra can be specified by giving optional keywords described below. If no keywords are given the base ring will be an instance of the special class :class:`CubicHeckeRingOfDefinition` which is constructed - as the polynomial ring in `u, v` over the Laurent polynomial ring in `w` over - the integers. This ring will be called the *ring of definition* or sometimes - for short *generic base ring*. But note, that in this context the word - *generic* should not remind in a generic point of the corresponding scheme. + as the polynomial ring in `u, v, w` over the integers localized at `w`. + This ring will be called the *ring of definition* or sometimes for short + *generic base ring*. But note, that in this context the word *generic* + should not remind in a generic point of the corresponding scheme. - In addition to the base ring another ring containing the roots (`a, b` and `c`) - of the cubic equation will be needed to handle the split irreducible + In addition to the base ring another ring containing the roots (`a, b` and + `c`) of the cubic equation will be needed to handle the split irreducible representations. This ring will be called *extension ring*. Generically, the extension ring will be an instance of the special class :class:`~sage.algebras.hecke_algebras.cubic_hecke_base_ring.CubicHeckeExtensionRing` diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 32e691a4340..52ef0fdb585 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -726,6 +726,31 @@ def __init__(self, num_strands): self._data_library = {} os.makedirs(self._file_cache_path, exist_ok=True) + def _warn_incompatibility(self, fname): + """ + Warn the user that he has an incomaptible file cache under `Sage_DOT` and + move it away to another file (marked with timestamp). + + EXAMPLES:: + + sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache + sage: cha2_fc = CubicHeckeFileCache(2) + sage: path = cha2_fc._file_cache_path + sage: fname = os.path.join(path, 'test') + sage: os.system('touch %s' % fname) + 0 + sage: new_fname = cha2_fc._warn_incompatibility(fname) + doctest:...: UserWarning: incompatible file cache ...test has been saved to ...test_... + sage: os.remove(new_fname) + """ + from warnings import warn + from datetime import date + today = date.today() + new_fname = '%s_%s' % (fname, today) + os.rename(fname, new_fname) + warn('incompatible file cache %s has been saved to %s' % (fname, new_fname)) + return new_fname + def reset_library(self, section=None): r""" Reset the file cache corresponding to the specified ``section``. @@ -891,7 +916,8 @@ def read(self, section): self.reset_library(section) verbose('... not found!') except (ImportError, ModuleNotFoundError): - raise ImportError('incompatible file cache! Move %s to another directory' % fname) + self._warn_incompatibility(fname) + self.reset_library(section) return data_lib[section] @@ -996,7 +1022,15 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr if not isinstance(representation_type, RepresentationType): raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) - matrix_representations = self.read(self.section.matrix_representations)[representation_type.name] + sec = self.section.matrix_representations + all_matrix_representations = self.read(sec) + if representation_type.name not in all_matrix_representations.keys(): + # old file-cache is not compatible with current dictionary keys. + fname = os.path.join(self._file_cache_path, sec.filename(self._nstrands)) + self._warn_incompatibility(fname) + all_matrix_representations = self.read(sec) + + matrix_representations = all_matrix_representations[representation_type.name] if monomial_tietze in matrix_representations.keys(): # entry already registered @@ -1005,7 +1039,7 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr matrix_representation_dict = [simplify(mat) for mat in list(matrix_list)] matrix_representations[monomial_tietze] = matrix_representation_dict - self.write(self.section.matrix_representations) + self.write(sec) return # -------------------------------------------------------------------------- From e27d84e8bfec980d5185d750a8a04b07ae5377a7 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 24 May 2022 02:15:22 -0600 Subject: [PATCH 019/591] test --- build/bin/sage-bootstrap-python | 3 +-- src/sage/groups/generic.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/build/bin/sage-bootstrap-python b/build/bin/sage-bootstrap-python index 38ceeca0f29..a198557daf1 100755 --- a/build/bin/sage-bootstrap-python +++ b/build/bin/sage-bootstrap-python @@ -11,7 +11,6 @@ if [ -z "$SAGE_ORIG_PATH" ]; then # If not we're running from within sage-env just set the existing path SAGE_ORIG_PATH="$PATH" fi - # In particular, it is invoked by "bootstrap -d" for sage-download-file, # i.e., before a configure run, and by "sage-spkg", also for sage-download-file. # So it needs to find a python that has the urllib module. @@ -43,7 +42,7 @@ if [ "$LC_ALL" = "C" -o "$LANG" = "C" -o "$LC_CTYPE" = "C" ]; then export LANG fi -PYTHONS="python python3 python3.10 python3.9 python3.8 python3.7 python2.7 python3.6 python2" +PYTHONS="/usr/bin/python python python3 python3.10 python3.9 python3.8 python3.7 python2.7 python3.6 python2" # Trac #32405: Prefer a Python that provides ssl with SNI, which allows developers # to download from upstream URLs (configure --enable-download-from-upstream-url), # in particular from PyPI, which requires SNI. diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index e1f13a2994c..3521318e22f 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -679,7 +679,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - ``identity`` - the group's identity - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group - + ``a`` and ``base`` must be elements of some group with identity given by identity, inverse of ``x`` by ``inverse(x)``, and group operation on ``x``, ``y`` by ``op(x,y)``. From 2fa02751edfeb64552124e4c32b3a8bfa929d596 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 24 May 2022 17:45:03 -0600 Subject: [PATCH 020/591] Added Pollard's rho support to discrete_log The previous generic discrete log functions didn't seem to have a Pohlig-Hellman+Pollard's rho implementation, which can be useful. --- src/sage/groups/generic.py | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 3521318e22f..2df8ef97c1e 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -665,7 +665,7 @@ def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash): raise ValueError("Pollard rho algorithm failed to find a logarithm") -def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None): +def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None, use_rho=False): r""" Totally generic discrete log function. @@ -679,6 +679,8 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - ``identity`` - the group's identity - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group + - ``use_rho`` - use Pollard's rho instead of BSGS (this option may be + overwritten if the base order is small) ``a`` and ``base`` must be elements of some group with identity given by identity, inverse of ``x`` by ``inverse(x)``, and group @@ -818,16 +820,26 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i for i, (pi, ri) in enumerate(f): for j in range(ri): if operation in multiplication_names: - c = bsgs(base**(ord // pi), - (a / base**l[i])**(ord // pi**(j + 1)), - (0, pi), - operation=operation) + if(not use_rho): + c = bsgs(base**(ord // pi), + (a / base**l[i])**(ord // pi**(j + 1)), + (0, pi), + operation=operation) + else: + c = discrete_log_rho((a / base**l[i])**(ord // pi**(j + 1)), + base**(ord // pi), + operation=operation) l[i] += c * (pi**j) elif operation in addition_names: - c = bsgs(base * (ord // pi), - (a - base * l[i]) * (ord // pi**(j + 1)), - (0, pi), - operation=operation) + if(not use_rho): + c = bsgs(base * (ord // pi), + (a - base * l[i]) * (ord // pi**(j + 1)), + (0, pi), + operation=operation) + else: + c = discrete_log_rho((a - base * l[i]) * (ord // pi**(j + 1)), + base * (ord // pi), + operation=operation) l[i] += c * (pi**j) from sage.arith.all import CRT_list return CRT_list(l, [pi**ri for pi, ri in f]) From 5048adf14484a2375f07f169cb36201e4853ab4d Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 24 May 2022 20:27:46 -0600 Subject: [PATCH 021/591] discrete log functions properly handle op argument --- src/sage/groups/generic.py | 56 ++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 2df8ef97c1e..68003749017 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -465,7 +465,8 @@ def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None): ran = 1 + ub - lb # the length of the interval - c = op(inverse(b), multiple(a, lb, operation=operation)) + mult = lambda x, y: multiple(x, y, operation=operation, identity=identity, inverse=inverse, op=op) + c = op(inverse(b), mult(a, lb)) if ran < 30: # use simple search for small ranges d = c @@ -499,7 +500,7 @@ def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None): raise ValueError("log of %s to the base %s does not exist in %s" % (b, a, bounds)) -def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash): +def discrete_log_rho(a, base, ord=None, operation='*', identity=None, inverse=None, op=None, hash_function=hash): """ Pollard Rho algorithm for computing discrete logarithm in cyclic group of prime order. @@ -514,6 +515,9 @@ def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash): to compute it - ``operation`` -- a string (default: ``'*'``) denoting whether we are in an additive group or a multiplicative one + - ``identity`` - the group's identity + - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` + - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group - ``hash_function`` -- having an efficient hash function is critical for this algorithm (see examples) @@ -587,7 +591,8 @@ def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash): # should be reasonable choices partition_size = 20 memory_size = 4 - + mult = op + power = lambda x, y: multiple(x, y, operation=operation, identity=identity, inverse=inverse, op=op) if operation in addition_names: mult = add power = mul @@ -598,11 +603,10 @@ def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash): power = pow if ord is None: ord = base.multiplicative_order() - else: + elif ord is None or inverse is None or identity is None or op is None: raise ValueError ord = Integer(ord) - if not ord.is_prime(): raise ValueError("for Pollard rho algorithm the order of the group must be prime") @@ -612,7 +616,7 @@ def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash): isqrtord = ord.isqrt() if isqrtord < partition_size: # setup to costly, use bsgs - return bsgs(base, a, bounds=(0, ord), operation=operation) + return bsgs(base, a, bounds=(0, ord), identity=identity, inverse=inverse, op=op, operation=operation) reset_bound = 8 * isqrtord # we take some margin @@ -793,13 +797,22 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - William Stein and David Joyner (2005-01-05) - John Cremona (2008-02-29) rewrite using ``dict()`` and make generic """ + from operator import mul, add, pow + mult = op if op is not None else [add, mul][operation in multiplication_names] + power = [mul, pow][operation in multiplication_names] + if(op is not None): + power = lambda x, y: multiple(x, y, operation=operation, identity=identity, inverse=inverse, op=op) if ord is None: if operation in multiplication_names: + mult = mul + power = pow try: ord = base.multiplicative_order() except Exception: ord = base.order() elif operation in addition_names: + mult = add + power = mul try: ord = base.additive_order() except Exception: @@ -812,35 +825,20 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i try: from sage.rings.infinity import Infinity if ord == +Infinity: - return bsgs(base, a, bounds, operation=operation) + return bsgs(base, a, bounds, identity=identity, inverse=inverse, op=op, operation=operation) if ord == 1 and a != base: raise ValueError f = ord.factor() l = [0] * len(f) for i, (pi, ri) in enumerate(f): for j in range(ri): - if operation in multiplication_names: - if(not use_rho): - c = bsgs(base**(ord // pi), - (a / base**l[i])**(ord // pi**(j + 1)), - (0, pi), - operation=operation) - else: - c = discrete_log_rho((a / base**l[i])**(ord // pi**(j + 1)), - base**(ord // pi), - operation=operation) - l[i] += c * (pi**j) - elif operation in addition_names: - if(not use_rho): - c = bsgs(base * (ord // pi), - (a - base * l[i]) * (ord // pi**(j + 1)), - (0, pi), - operation=operation) - else: - c = discrete_log_rho((a - base * l[i]) * (ord // pi**(j + 1)), - base * (ord // pi), - operation=operation) - l[i] += c * (pi**j) + gamma = power(base, ord // pi) + h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) + if(not use_rho): + c = bsgs(gamma, h, (0, pi), inverse=inverse, identity=identity, op=op, operation=operation) + else: + c = discrete_log_rho(h, gamma, ord=pi, inverse=inverse, identity=identity, op=op, operation=operation) + l[i] += c * (pi**j) from sage.arith.all import CRT_list return CRT_list(l, [pi**ri for pi, ri in f]) except ValueError: From 16c5f45adda6f901948cc8ac1b6f453e44a24ad0 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 24 May 2022 21:41:53 -0600 Subject: [PATCH 022/591] undid irrelevant change --- build/bin/sage-bootstrap-python | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/bin/sage-bootstrap-python b/build/bin/sage-bootstrap-python index a198557daf1..4f2b537e24d 100755 --- a/build/bin/sage-bootstrap-python +++ b/build/bin/sage-bootstrap-python @@ -42,7 +42,7 @@ if [ "$LC_ALL" = "C" -o "$LANG" = "C" -o "$LC_CTYPE" = "C" ]; then export LANG fi -PYTHONS="/usr/bin/python python python3 python3.10 python3.9 python3.8 python3.7 python2.7 python3.6 python2" +PYTHONS="python python3 python3.10 python3.9 python3.8 python3.7 python2.7 python3.6 python2" # Trac #32405: Prefer a Python that provides ssl with SNI, which allows developers # to download from upstream URLs (configure --enable-download-from-upstream-url), # in particular from PyPI, which requires SNI. From abc6d2d67a0d6f6ebc8ee11b3b87654d28e521ee Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Wed, 25 May 2022 14:13:35 -0600 Subject: [PATCH 023/591] fixed docstring --- src/sage/groups/generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 68003749017..4a53985ee77 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -685,7 +685,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group - ``use_rho`` - use Pollard's rho instead of BSGS (this option may be overwritten if the base order is small) - + ``a`` and ``base`` must be elements of some group with identity given by identity, inverse of ``x`` by ``inverse(x)``, and group operation on ``x``, ``y`` by ``op(x,y)``. From 9684efd8eba91bb2e4eab8d7c0c0c9f890120f77 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Wed, 25 May 2022 15:35:22 -0600 Subject: [PATCH 024/591] fixed docstring again --- src/sage/groups/generic.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 4a53985ee77..19ebc406f14 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -683,8 +683,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - ``identity`` - the group's identity - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group - - ``use_rho`` - use Pollard's rho instead of BSGS (this option may be - overwritten if the base order is small) + - ``use_rho`` - use Pollard's rho instead of BSGS (this option may be overwritten if the base order is small) ``a`` and ``base`` must be elements of some group with identity given by identity, inverse of ``x`` by ``inverse(x)``, and group From 18884263a334dda1c3cedeb3b2ae150f6e5902d8 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Wed, 25 May 2022 21:55:23 -0600 Subject: [PATCH 025/591] changed use_rho keyword to algorithm --- src/sage/groups/generic.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 19ebc406f14..db08eef529a 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -669,7 +669,7 @@ def discrete_log_rho(a, base, ord=None, operation='*', identity=None, inverse=No raise ValueError("Pollard rho algorithm failed to find a logarithm") -def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None, use_rho=False): +def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None, algorithm='bsgs'): r""" Totally generic discrete log function. @@ -683,7 +683,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - ``identity`` - the group's identity - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group - - ``use_rho`` - use Pollard's rho instead of BSGS (this option may be overwritten if the base order is small) + - ``algorithm`` - string denoting what algorithm to use for prime-order logarithms: 'bsgs', 'rho' ``a`` and ``base`` must be elements of some group with identity given by identity, inverse of ``x`` by ``inverse(x)``, and group @@ -705,7 +705,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i than using this function. E.g., if ``x`` is an integer modulo `n`, use its log method instead! - ALGORITHM: Pohlig-Hellman and Baby step giant step. + ALGORITHM: Pohlig-Hellman, Baby step giant step, and Pollard's rho. EXAMPLES:: @@ -833,10 +833,12 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i for j in range(ri): gamma = power(base, ord // pi) h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) - if(not use_rho): + if algorithm == 'bsgs': c = bsgs(gamma, h, (0, pi), inverse=inverse, identity=identity, op=op, operation=operation) - else: + elif algorithm == 'rho': c = discrete_log_rho(h, gamma, ord=pi, inverse=inverse, identity=identity, op=op, operation=operation) + else: + raise ValueError("unkown algorithm") l[i] += c * (pi**j) from sage.arith.all import CRT_list return CRT_list(l, [pi**ri for pi, ri in f]) From 54bf499573c8165b3aeff4f63ecc5dbc98773c72 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Thu, 26 May 2022 23:19:42 -0600 Subject: [PATCH 026/591] fix discrete_log_generic discrete_log_generic incorrectly passed parameters on to discrete_log --- src/sage/groups/generic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index db08eef529a..94298069025 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -846,11 +846,11 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i raise ValueError("no discrete log of %s found to base %s" % (a, base)) -def discrete_log_generic(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None): +def discrete_log_generic(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None, algorithm='bsgs'): """ Alias for ``discrete_log``. """ - return discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, inverse=None, op=None) + return discrete_log(a, base, ord=ord, bounds=bounds, operation=operation, identity=identity, inverse=inverse, op=op, algorithm=algorithm) def discrete_log_lambda(a, base, bounds, operation='*', hash_function=hash): From f2cc9775d072728a444f0ab19a9349eef2668225 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Fri, 27 May 2022 00:15:39 -0600 Subject: [PATCH 027/591] more specific bounds passed to bsgs by discrete_log --- src/sage/groups/generic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 94298069025..1d4978dec1f 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -799,6 +799,8 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i from operator import mul, add, pow mult = op if op is not None else [add, mul][operation in multiplication_names] power = [mul, pow][operation in multiplication_names] + if(bounds): + lb, ub = bounds if(op is not None): power = lambda x, y: multiple(x, y, operation=operation, identity=identity, inverse=inverse, op=op) if ord is None: @@ -834,7 +836,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i gamma = power(base, ord // pi) h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) if algorithm == 'bsgs': - c = bsgs(gamma, h, (0, pi), inverse=inverse, identity=identity, op=op, operation=operation) + c = bsgs(gamma, h, (max(0, lb if bounds else 0), min(pi, ub if bounds else pi)), inverse=inverse, identity=identity, op=op, operation=operation) elif algorithm == 'rho': c = discrete_log_rho(h, gamma, ord=pi, inverse=inverse, identity=identity, op=op, operation=operation) else: From 461197a65fb275fa1c0d94578fc014cacf12f238 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Fri, 27 May 2022 00:43:05 -0600 Subject: [PATCH 028/591] a few adjustments - Spurious whitespace change removed from build/bin/sage-bootstrap-python - "unkown algorithm" ValueError removed, gets caught as "no discrete log" - operation logic cleaned up in discrete_log - wording in discrete_log docstring adjusted --- build/bin/sage-bootstrap-python | 1 + src/sage/groups/generic.py | 32 ++++++++++++-------------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/build/bin/sage-bootstrap-python b/build/bin/sage-bootstrap-python index 4f2b537e24d..38ceeca0f29 100755 --- a/build/bin/sage-bootstrap-python +++ b/build/bin/sage-bootstrap-python @@ -11,6 +11,7 @@ if [ -z "$SAGE_ORIG_PATH" ]; then # If not we're running from within sage-env just set the existing path SAGE_ORIG_PATH="$PATH" fi + # In particular, it is invoked by "bootstrap -d" for sage-download-file, # i.e., before a configure run, and by "sage-spkg", also for sage-download-file. # So it needs to find a python that has the urllib module. diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 1d4978dec1f..571d0ea42f8 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -385,7 +385,7 @@ def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None): - ``operation`` - string: '*', '+', 'other' - ``identity`` - the identity element of the group - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group + - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in the group OUTPUT: @@ -517,7 +517,7 @@ def discrete_log_rho(a, base, ord=None, operation='*', identity=None, inverse=No are in an additive group or a multiplicative one - ``identity`` - the group's identity - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group + - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in the group - ``hash_function`` -- having an efficient hash function is critical for this algorithm (see examples) @@ -682,7 +682,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - ``operation`` - string: '*', '+', 'other' - ``identity`` - the group's identity - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in group + - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in the group - ``algorithm`` - string denoting what algorithm to use for prime-order logarithms: 'bsgs', 'rho' ``a`` and ``base`` must be elements of some group with identity @@ -797,32 +797,26 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - John Cremona (2008-02-29) rewrite using ``dict()`` and make generic """ from operator import mul, add, pow - mult = op if op is not None else [add, mul][operation in multiplication_names] - power = [mul, pow][operation in multiplication_names] - if(bounds): - lb, ub = bounds - if(op is not None): + power = mul if operation in addition_names else pow + mult = add if operation in addition_names else mul + if op: + mult = op power = lambda x, y: multiple(x, y, operation=operation, identity=identity, inverse=inverse, op=op) + if bounds: + lb, ub = bounds + if (op is None or identity is None or inverse is None or ord is None) and operation not in addition_names+multiplication_names: + raise ValueError("ord, op, identity, and inverse must all be specified for this operation") if ord is None: if operation in multiplication_names: - mult = mul - power = pow try: ord = base.multiplicative_order() except Exception: ord = base.order() - elif operation in addition_names: - mult = add - power = mul + else: try: ord = base.additive_order() except Exception: ord = base.order() - else: - try: - ord = base.order() - except Exception: - raise ValueError("ord must be specified") try: from sage.rings.infinity import Infinity if ord == +Infinity: @@ -839,8 +833,6 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i c = bsgs(gamma, h, (max(0, lb if bounds else 0), min(pi, ub if bounds else pi)), inverse=inverse, identity=identity, op=op, operation=operation) elif algorithm == 'rho': c = discrete_log_rho(h, gamma, ord=pi, inverse=inverse, identity=identity, op=op, operation=operation) - else: - raise ValueError("unkown algorithm") l[i] += c * (pi**j) from sage.arith.all import CRT_list return CRT_list(l, [pi**ri for pi, ri in f]) From 56526fcdf13e2c8b07f9333d0da4fc75711d425f Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Fri, 27 May 2022 00:57:39 -0600 Subject: [PATCH 029/591] changes to discrete_log bounds handling undid previous commit which used the bounds parameter incorrectly, potentially leading to wrong results added slight optimization when bounds is present --- src/sage/groups/generic.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 571d0ea42f8..5972c8485f9 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -825,17 +825,21 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i raise ValueError f = ord.factor() l = [0] * len(f) + running_mod = 1 for i, (pi, ri) in enumerate(f): for j in range(ri): gamma = power(base, ord // pi) h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) if algorithm == 'bsgs': - c = bsgs(gamma, h, (max(0, lb if bounds else 0), min(pi, ub if bounds else pi)), inverse=inverse, identity=identity, op=op, operation=operation) + c = bsgs(gamma, h, (0, pi), inverse=inverse, identity=identity, op=op, operation=operation) elif algorithm == 'rho': c = discrete_log_rho(h, gamma, ord=pi, inverse=inverse, identity=identity, op=op, operation=operation) l[i] += c * (pi**j) + running_mod*=pi**ri + if(bounds and running_mod>ub): + break # we have log%running_mod. if we know that log Date: Sat, 11 Jun 2022 21:05:41 +0900 Subject: [PATCH 030/591] Add free resolutions --- src/doc/en/reference/index.rst | 12 +- src/doc/en/reference/references/index.rst | 7 +- src/doc/en/reference/resolutions/conf.py | 1 + src/doc/en/reference/resolutions/index.rst | 13 + src/sage/homology/free_resolution.pxd | 3 + src/sage/homology/free_resolution.pyx | 667 +++++++++++++++++++++ src/sage/homology/graded_resolution.pyx | 524 ++++++++++++++++ src/sage/interfaces/singular.py | 62 +- src/sage/libs/singular/decl.pxd | 8 + src/sage/libs/singular/function.pxd | 1 + src/sage/libs/singular/function.pyx | 119 ++-- src/sage/libs/singular/polynomial.pyx | 7 - src/sage/libs/singular/singular.pyx | 7 - 13 files changed, 1308 insertions(+), 123 deletions(-) create mode 120000 src/doc/en/reference/resolutions/conf.py create mode 100644 src/doc/en/reference/resolutions/index.rst create mode 100644 src/sage/homology/free_resolution.pxd create mode 100644 src/sage/homology/free_resolution.pyx create mode 100644 src/sage/homology/graded_resolution.pyx diff --git a/src/doc/en/reference/index.rst b/src/doc/en/reference/index.rst index 065bccac955..9008c78e157 100644 --- a/src/doc/en/reference/index.rst +++ b/src/doc/en/reference/index.rst @@ -92,18 +92,22 @@ Discrete Mathematics * :doc:`Symbolic Logic ` * :doc:`SAT solvers ` -Geometry, Topology, and Homological Algebra -------------------------------------------- +Geometry and Topology +--------------------- * :doc:`Euclidean Spaces and Vector Calculus ` * :doc:`Combinatorial and Discrete Geometry ` -* :doc:`Cell Complexes, Simplicial Complexes, and - Simplicial Sets ` +* :doc:`Cell Complexes, Simplicial Complexes, and Simplicial Sets ` * :doc:`Manifolds and Differential Geometry ` * :doc:`Hyperbolic Geometry ` * :doc:`Parametrized Surfaces ` * :doc:`Knot Theory ` + +Homological Algebra +------------------- + * :doc:`Chain Complexes and their Homology ` +* :doc:`Resolutions ` Number Fields, Function Fields, and Valuations ---------------------------------------------- diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 30a792e8214..70ccf51e48c 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -95,7 +95,7 @@ REFERENCES: graphs and isoperimetric inequalities*, The Annals of Probability 32 (2004), no. 3A, 1727-1745. -.. [ASV2020] Federico Ardila, Mariel Supina, and Andrés R. Vindas-Meléndez, +.. [ASV2020] Federico Ardila, Mariel Supina, and Andrés R. Vindas-Meléndez, *The Equivariant Ehrhart Theory of the Permutahedron*, Proc. Amer. Math. Soc. Volume 148, Number 12, 2020, pp. 5091--5107. @@ -4296,6 +4296,9 @@ REFERENCES: polynomials*. Trans. Amer. Math. Soc., 245 (1978), 89-118. +.. [MilStu2005] Ezra Miller and Bernd Sturmfels, *Combinatorial Commutative Algebra*, + GTM Vol. 227, Springer Science & Business Media, 2005. + .. [Mil2004] Victor S. Miller, "The Weil pairing, and its efficient calculation", J. Cryptol., 17(4):235-261, 2004 @@ -5370,7 +5373,7 @@ REFERENCES: .. [St1986] Richard Stanley. *Two poset polytopes*, Discrete Comput. Geom. (1986), :doi:`10.1007/BF02187680` -.. [Stap2011] Alan Stapledon. *Equivariant Ehrhart Theory*. +.. [Stap2011] Alan Stapledon. *Equivariant Ehrhart Theory*. Advances in Mathematics 226 (2011), no. 4, 3622-3654 .. [Sta1973] \H. M. Stark, Class-Numbers of Complex Quadratic diff --git a/src/doc/en/reference/resolutions/conf.py b/src/doc/en/reference/resolutions/conf.py new file mode 120000 index 00000000000..2bdf7e68470 --- /dev/null +++ b/src/doc/en/reference/resolutions/conf.py @@ -0,0 +1 @@ +../conf_sub.py \ No newline at end of file diff --git a/src/doc/en/reference/resolutions/index.rst b/src/doc/en/reference/resolutions/index.rst new file mode 100644 index 00000000000..82f73cb94c8 --- /dev/null +++ b/src/doc/en/reference/resolutions/index.rst @@ -0,0 +1,13 @@ +Resolutions +=========== + +Free and graded resolutions are tools for commutative algebra and algebraic +geometry. + +.. toctree:: + :maxdepth: 2 + + sage/homology/free_resolution + sage/homology/graded_resolution + +.. include:: ../footer.txt diff --git a/src/sage/homology/free_resolution.pxd b/src/sage/homology/free_resolution.pxd new file mode 100644 index 00000000000..4ad023387d8 --- /dev/null +++ b/src/sage/homology/free_resolution.pxd @@ -0,0 +1,3 @@ +from sage.libs.singular.decl cimport * + +cdef singular_monomial_exponents(poly *p, ring *r) diff --git a/src/sage/homology/free_resolution.pyx b/src/sage/homology/free_resolution.pyx new file mode 100644 index 00000000000..be084842b45 --- /dev/null +++ b/src/sage/homology/free_resolution.pyx @@ -0,0 +1,667 @@ +""" +Free resolutions + +The :class:`FreeResolution` implements a finite free resolution, which is a +chain complex of free modules, terminating with a zero module at the end, whose +homology groups are all zero. + +The class is intended to be subclassed for finite free resolutions in different +subject areas. Thus :meth:`_repr_module` may be overrided by a subclass. See +Examples below. + +EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution_generic + sage: S. = PolynomialRing(QQ) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) + sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + +:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + +The :class:`FreeResolution` computes a minimal free resolution of modules +over a multivariate polynomial ring. + +EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + +An example of a minimal free resolution from [CLO2005]_:: + + sage: R. = QQ[] + sage: I = R.ideal([y*z - x*w, y^3 - x^2*z, x*z^2 - y^2*w, z^3 - y*w^2]) + sage: r = FreeResolution(I) + sage: r + S^1 <-- S^4 <-- S^4 <-- S^1 <-- 0 + sage: len(r) + 3 + sage: r.matrix(2) + [-z^2 -x*z y*w -y^2] + [ y 0 -x 0] + [ -w y z x] + [ 0 w 0 z] + +AUTHORS: + +- Kwankyu Lee (2022-05-13): initial version + +""" + +# **************************************************************************** +# Copyright (C) 2022 Kwankyu Lee +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.libs.singular.decl cimport * +from sage.libs.singular.decl cimport ring +from sage.libs.singular.function cimport Resolution, new_sage_polynomial, access_singular_ring +from sage.libs.singular.function import singular_function +from sage.structure.sequence import Sequence, Sequence_generic +from sage.misc.cachefunc import cached_method +from sage.matrix.constructor import matrix as _matrix +from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense +from sage.modules.free_module_element import vector +from sage.modules.free_module import Module_free_ambient +from sage.rings.integer_ring import ZZ +from sage.rings.ideal import Ideal_generic + +from sage.structure.sage_object import SageObject + + +class FreeResolution_generic(SageObject): + """ + Base class of free resolutions. + + INPUT: + + - ``base_ring`` -- a ring + + - ``maps`` -- list of matrices over the base ring + + The matrix at index `i` in the list defines the differential map from + `(i+1)`-th free module to the `i`-th free module over the base ring by + multiplication on the left. The number of matrices in the list is the + length of the resolution. The number of rows and columns of the matrices + define the ranks of the free modules in the resolution. + + Note that the first matrix in the list defines the differential map at + homological index `1`. A subclass can define ``_initial_differential`` + attribute that contains the `0`-th differential map whose codomain is the + target of the free resolution. + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution_generic + sage: S. = PolynomialRing(QQ) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) + sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + + :: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r.differential(0) + Coercion map: + From: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by Submodule of Ambient free module of rank 1 + over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + def __init__(self, base_ring, maps, name='F'): + """ + Initialize. + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution_generic + sage: S. = PolynomialRing(QQ) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) + sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: TestSuite(r).run(skip=['_test_pickling']) + """ + self.__base_ring = base_ring + self.__maps = maps + self.__name = name + self.__length = len(maps) + + def __repr__(self): + """ + Return the string form of this resolution. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + """ + s = self._repr_module(0) + for i in range(1, self.__length + 1): + s += ' <-- ' + self._repr_module(i) + s += ' <-- 0' + return s + + def _repr_module(self, i): + """ + Return the string form of the `i`-th free module. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution_generic + sage: S. = PolynomialRing(QQ) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) + sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: r # indirect doctest + S^1 <-- S^3 <-- S^2 <-- 0 + """ + if i == 0: + r = self.__maps[0].nrows() + s = f'{self.__name}^{r}' + return s + elif i > self.__length: + s = '0' + else: + r = self.__maps[i - 1].ncols() + if r > 0: + s = f'{self.__name}^{r}' + else: + s = '0' + return s + + def __len__(self): + """ + Return the length of this resolution. + + The length of a free resolution is the index of the last nonzero free module. + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: len(r) + 2 + """ + return self.__length + + def __getitem__(self, i): + """ + Return the `i`-th free module of this resolution. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: r.target() + Quotient module by Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + if i < 0: + raise IndexError('invalid index') + elif i > self.__length: + F = (self.__base_ring)**0 + elif i == self.__length: + F = (self.__base_ring)**(self.__maps[i - 1].ncols()) + else: + F = (self.__base_ring)**(self.__maps[i].nrows()) + return F + + def differential(self, i): + """ + Return the matrix representing the `i`-th differential map. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: r.differential(3) + Free module morphism defined by the matrix + [] + Domain: Ambient free module of rank 0 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 2 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + sage: r.differential(2) + Free module morphism defined as left-multiplication by the matrix + [-y x] + [ z -y] + [-w z] + Domain: Ambient free module of rank 2 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 3 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + sage: r.differential(1) + Free module morphism defined as left-multiplication by the matrix + [z^2 - y*w y*z - x*w y^2 - x*z] + Domain: Ambient free module of rank 3 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + sage: r.differential(0) + Coercion map: + From: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + if i < 0: + raise IndexError('invalid index') + elif i == 0: + try: + return self._initial_differential + except AttributeError: + raise ValueError('0th differential map undefined') + elif i == self.__length + 1: + s = (self.__base_ring)**0 + t = (self.__base_ring)**(self.__maps[i - 2].ncols()) + m = s.hom(0, t) + elif i > self.__length + 1: + s = (self.__base_ring)**0 + t = (self.__base_ring)**0 + m = s.hom(0, t) + else: + s = (self.__base_ring)**(self.__maps[i - 1].ncols()) + t = (self.__base_ring)**(self.__maps[i - 1].nrows()) + m = s.hom(self.__maps[i - 1], t, side='right') + return m + + def target(self): + """ + Return the codomain of the 0-th differential map. + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: r.target() + Quotient module by Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + return self.differential(0).codomain() + + def matrix(self, i): + """ + Return the matrix representing the `i`-th differential map. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: r.matrix(3) + [] + sage: r.matrix(2) + [-y x] + [ z -y] + [-w z] + sage: r.matrix(1) + [z^2 - y*w y*z - x*w y^2 - x*z] + """ + if i <= 0: + raise IndexError(f'invalid index') + elif i <= self.__length: + return self.__maps[i - 1] + else: + return self.differential(i).matrix() + + def chain_complex(self): + """ + Return this resolution as a chain complex. + + A chain complex in Sage has its own useful methods. + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: unicode_art(r.chain_complex()) + ⎛-y x⎞ + ⎜ z -y⎟ + (z^2 - y*w y*z - x*w y^2 - x*z) ⎝-w z⎠ + 0 <── C_0 <────────────────────────────── C_1 <────── C_2 <── 0 + """ + from sage.homology.chain_complex import ChainComplex + mats = {} + for i in range(self.__length, 0, -1): + mats[i] = self.matrix(i) + return ChainComplex(mats, degree_of_differential=-1) + + +class FreeResolution(FreeResolution_generic): + """ + Minimal free resolutions of ideals of multivariate polynomial rings. + + INPUT: + + - ``ideal`` -- a homogeneous ideal of a multi-variate polynomial ring or + a submodule of a free module `M` of rank `n` over `S` + + - ``name`` -- a string; name of the base ring + + - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` + + OUTPUT: a minimal free resolution of the ideal + + The available algorithms and the corresponding Singular commands are shown + below: + + ============= ============================ + algorithm Singular commands + ============= ============================ + ``minimal`` ``mres(ideal)`` + ``shreyer`` ``minres(sres(std(ideal)))`` + ``standard`` ``minres(nres(std(ideal)))`` + ``heuristic`` ``minres(res(std(ideal)))`` + ============= ============================ + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + sage: len(r) + 2 + + :: + + sage: FreeResolution(I, algorithm='minimal') + S^1 <-- S^3 <-- S^2 <-- 0 + sage: FreeResolution(I, algorithm='shreyer') + S^1 <-- S^3 <-- S^2 <-- 0 + sage: FreeResolution(I, algorithm='standard') + S^1 <-- S^3 <-- S^2 <-- 0 + sage: FreeResolution(I, algorithm='heuristic') + S^1 <-- S^3 <-- S^2 <-- 0 + """ + def __init__(self, ideal, name='S', algorithm='heuristic'): + """ + Initialize. + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: TestSuite(r).run(skip=['_test_pickling']) + """ + if isinstance(ideal, Ideal_generic): + S = ideal.ring() + m = ideal + rank = 1 + elif isinstance(ideal, Module_free_ambient): + S = ideal.base_ring() + m = ideal.matrix().transpose() + rank = m.nrows() + elif isinstance(ideal, Matrix_mpolynomial_dense): + S = ideal.base_ring() + m = ideal.transpose() + rank = ideal.ncols() + else: + raise TypeError('no ideal, module, or matrix') + + nvars = S.ngens() + + # This ensures the first component of the Singular resolution to be a + # module, like the later components. This is important when the + # components are converted to Sage modules. + module = singular_function("module") + mod = module(m) + + if algorithm == 'minimal': + mres = singular_function('mres') # syzygy method + r = mres(mod, 0) + elif algorithm == 'shreyer': + std = singular_function('std') + sres = singular_function('sres') # Shreyer method + minres = singular_function('minres') + r = minres(sres(std(mod), 0)) + elif algorithm == 'standard': + nres = singular_function('nres') # standard basis method + minres = singular_function('minres') + r = minres(nres(mod, 0)) + elif algorithm == 'heuristic': + std = singular_function('std') + res = singular_function('res') # heuristic method + minres = singular_function('minres') + r = minres(res(std(mod), 0)) + + res_mats = to_sage_resolution(r) + + super().__init__(S, res_mats, name=name) + + self._ideal = ideal + self._name = name + + @property + @cached_method + def _initial_differential(self): + """ + Defines the `0`-th differential map of this resolution. + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r._initial_differential + Coercion map: + From: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by Submodule of Ambient free module of rank 1 + over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + ideal = self._ideal + if isinstance(ideal, Ideal_generic): + S = ideal.ring() + M = S**1 + N = M.submodule([vector([g]) for g in ideal.gens()]) + elif isinstance(ideal, Module_free_ambient): + S = ideal.base_ring() + M = ideal.ambient_module() + N = ideal + elif isinstance(ideal, Matrix_mpolynomial_dense): + S = ideal.base_ring() + N = ideal.row_space() + M = N.ambient_module() + Q = M.quotient(N) + return Q.coerce_map_from(M) + + +cdef singular_monomial_exponents(poly *p, ring *r): + """ + Return the list of exponents of monomial ``p``. + """ + cdef int v + cdef list ml = list() + + for v in range(1, r.N + 1): + ml.append(p_GetExp(p, v, r)) + return ml + +cdef to_sage_resolution(Resolution res): + """ + Pull the data from Singular resolution ``res`` to construct a Sage + resolution. + + INPUT: + + - ``res`` -- Singular resolution + + The procedure is destructive, and ``res`` is not usable afterward. + """ + cdef ring *singular_ring + cdef syStrategy singular_res + cdef poly *p + cdef poly *p_iter + cdef poly *first + cdef poly *previous + cdef poly *acc + cdef resolvente mods + cdef ideal *mod + cdef int i, j, k, idx, rank, nrows, ncols + cdef bint zero_mat + + singular_res = res._resolution[0] + sage_ring = res.base_ring + singular_ring = access_singular_ring(res.base_ring) + + if singular_res.minres != NULL: + mods = singular_res.minres + elif singular_res.fullres != NULL: + mods = singular_res.fullres + else: + raise ValueError('Singular resolution is not usable') + + res_mats = [] + + # length is the length of fullres. The length of minres + # can be shorter. Hence we avoid SEGFAULT by stopping + # at NULL pointer. + for idx in range(singular_res.length): + mod = mods[idx] + if mod == NULL: + break + rank = mod.rank + free_module = sage_ring ** rank + + nrows = rank + ncols = mod.ncols # IDELEMS(mod) + + mat = _matrix(sage_ring, nrows, ncols) + matdegs = [] + zero_mat = True + for j in range(ncols): + p = mod.m[j] + degs = [] + # code below copied and modified from to_sage_vector_destructive + # in sage.libs.singular.function.Converter + for i in range(1, rank + 1): + previous = NULL + acc = NULL + first = NULL + p_iter = p + while p_iter != NULL: + if p_GetComp(p_iter, singular_ring) == i: + p_SetComp(p_iter, 0, singular_ring) + p_Setm(p_iter, singular_ring) + if acc == NULL: + first = p_iter + else: + acc.next = p_iter + acc = p_iter + if p_iter == p: + p = pNext(p_iter) + if previous != NULL: + previous.next = pNext(p_iter) + p_iter = pNext(p_iter) + acc.next = NULL + else: + previous = p_iter + p_iter = pNext(p_iter) + + if zero_mat: + zero_mat = first == NULL + + mat[i - 1, j] = new_sage_polynomial(sage_ring, first) + + # Singular sometimes leaves zero matrix in the resolution. We can stop + # when one is seen. + if zero_mat: + break + + res_mats.append(mat) + + return res_mats diff --git a/src/sage/homology/graded_resolution.pyx b/src/sage/homology/graded_resolution.pyx new file mode 100644 index 00000000000..03620cdb195 --- /dev/null +++ b/src/sage/homology/graded_resolution.pyx @@ -0,0 +1,524 @@ +r""" +Graded free resolutions + +This module defines :class:`GradedFreeResolution` which computes a +graded free resolution of a homogeneous ideal `I` of a graded multivariate +polynomial ring `S`, or a homogeneous submodule of a graded free module `M` +over `S`. The output resolution is always minimal. + +The degrees given to the variables of `S` are integers or integer vectors of +the same length. In the latter case, `S` is said to be multigraded, and the +resolution is a multigraded free resolution. The standard grading where all +variables have degree `1` is used if the degrees are not specified. + +A summand of the graded free module `M` is a shifted (or twisted) module of +rank one over `S`, denoted `S(-d)` with shift `d`. + +The computation of the resolution is done by the libSingular behind. Different +Singular algorithms can be chosen for best performance. + +EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I, algorithm='minimal') + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: GradedFreeResolution(I, algorithm='shreyer') + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: GradedFreeResolution(I, algorithm='standard') + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: GradedFreeResolution(I, algorithm='heuristic') + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + +:: + + sage: d = r.differential(2) + sage: d + Free module morphism defined as left-multiplication by the matrix + [ y x] + [-z -y] + [ w z] + Domain: Ambient free module of rank 2 over the integral domain Multivariate Polynomial Ring + in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring + in x, y, z, w over Rational Field + sage: d.image() + Submodule of Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring + in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [ y -z w] + [ x -y z] + sage: m = d.image() + sage: GradedFreeResolution(m, shifts=(2,2,2)) + S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + +An example of multigraded resolution from Example 9.1 of [MilStu2005]_:: + + sage: R. = QQ[] + sage: S. = QQ[] + sage: phi = S.hom([s, s*t, s*t^2, s*t^3]) + sage: I = phi.kernel(); I + Ideal (c^2 - b*d, b*c - a*d, b^2 - a*c) of Multivariate Polynomial Ring in a, b, c, d over Rational Field + sage: P3 = ProjectiveSpace(S) + sage: C = P3.subscheme(I) # twisted cubic curve + sage: r = GradedFreeResolution(I, degrees=[(1,0), (1,1), (1,2), (1,3)]) + sage: r + S(0) <-- S(-(2, 4))⊕S(-(2, 3))⊕S(-(2, 2)) <-- S(-(3, 5))⊕S(-(3, 4)) <-- 0 + sage: r.K_polynomial(names='s,t') + s^3*t^5 + s^3*t^4 - s^2*t^4 - s^2*t^3 - s^2*t^2 + 1 + +AUTHORS: + +- Kwankyu Lee (2022-05): initial version + +""" + +# **************************************************************************** +# Copyright (C) 2022 Kwankyu Lee +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.libs.singular.decl cimport * +from sage.libs.singular.decl cimport ring +from sage.libs.singular.function cimport Resolution, new_sage_polynomial, access_singular_ring +from sage.libs.singular.function import singular_function +from sage.structure.sequence import Sequence, Sequence_generic +from sage.misc.cachefunc import cached_method +from sage.matrix.constructor import matrix as _matrix +from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense +from sage.modules.free_module_element import vector +from sage.modules.free_module import Module_free_ambient +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing +from sage.rings.ideal import Ideal_generic + +from sage.homology.free_resolution import FreeResolution +from sage.homology.free_resolution cimport singular_monomial_exponents + + +class GradedFreeResolution(FreeResolution): + """ + Graded free resolutions of ideals of multi-variate polynomial rings. + + INPUT: + + - ``ideal`` -- a homogeneous ideal of a multivariate polynomial ring `S`, or + a homogeneous submodule of a free module `M` of rank `n` over `S` + + - ``degree`` -- a list of integers or integer vectors giving degrees of + variables of `S`; this is a list of 1s by default + + - ``shifts`` -- a list of integers or integer vectors giving shifts of + degrees of `n` summands of the free module `M`; this is a list of zero + degrees of length `n` by default + + - ``name`` -- a string; name of the base ring + + - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` + + If ``ideal`` is an ideal of `S`, then `M = S`, a free module of rank `1` + over `S`. + + OUTPUT: a graded minimal free resolution of ``ideal`` + + The available algorithms and the corresponding Singular commands are shown + below: + + ============= ============================ + algorithm Singular commands + ============= ============================ + ``minimal`` ``mres(ideal)`` + ``shreyer`` ``minres(sres(std(ideal)))`` + ``standard`` ``minres(nres(std(ideal)))`` + ``heuristic`` ``minres(res(std(ideal)))`` + ============= ============================ + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: len(r) + 2 + """ + def __init__(self, ideal, degrees=None, shifts=None, name='S', algorithm='heuristic'): + """ + Initialize. + + TESTS:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: TestSuite(r).run(skip=['_test_pickling']) + """ + cdef int i, j, k, ncols, nrows + cdef list res_shifts, prev_shifts, new_shifts + + if isinstance(ideal, Ideal_generic): + S = ideal.ring() + m = ideal + rank = 1 + elif isinstance(ideal, Module_free_ambient): + S = ideal.base_ring() + m = ideal.matrix().transpose() + rank = m.nrows() + elif isinstance(ideal, Matrix_mpolynomial_dense): + S = ideal.base_ring() + m = ideal.transpose() + rank = ideal.ncols() + else: + raise TypeError('no ideal, module, or matrix') + + nvars = S.ngens() + + if degrees is None: + degrees = nvars*[1] # standard grading + + if len(degrees) != nvars: + raise ValueError('the length of degrees does not match the number of generators') + + if degrees[0] in ZZ: + zero_deg = 0 + multigrade = False + else: # degrees are integer vectors + degrees = [vector(v) for v in degrees] + zero_deg = degrees[0].parent().zero() + multigrade = True + + # This ensures the first component of the Singular resolution to be a + # module, like the later components. This is important when the + # components are converted to Sage modules. + module = singular_function("module") + mod = module(m) + + if shifts is None: + shifts = rank*[zero_deg] + + if algorithm == 'minimal': + mres = singular_function('mres') # syzygy method + r = mres(mod, 0) + elif algorithm == 'shreyer': + std = singular_function('std') + sres = singular_function('sres') # Shreyer method + minres = singular_function('minres') + r = minres(sres(std(mod), 0)) + elif algorithm == 'standard': + nres = singular_function('nres') # standard basis method + minres = singular_function('minres') + r = minres(nres(mod, 0)) + elif algorithm == 'heuristic': + std = singular_function('std') + res = singular_function('res') # heuristic method + minres = singular_function('minres') + r = minres(res(std(mod), 0)) + + res_mats, res_degs = to_sage_resolution_graded(r, degrees) + + # compute shifts of free modules in the resolution + res_shifts = [] + prev_shifts = list(shifts) + for k in range(len(res_degs)): + new_shifts = [] + degs = res_degs[k] + ncols = len(degs) + for j in range(ncols): + col = degs[j] + nrows = len(col) + # should be enough to compute the new shifts + # from any one entry of the column vector + for i in range(nrows): + d = col[i] + if d is not None: + e = prev_shifts[i] + new_shifts.append(d + e) + break + res_shifts.append(new_shifts) + prev_shifts = new_shifts + + super(FreeResolution, self).__init__(S, res_mats, name=name) + + self._ideal = ideal + self._shifts = shifts + self._degrees = degrees + self._res_shifts = res_shifts + self._multigrade = multigrade + self._zero_deg = zero_deg + self._name = name + + def _repr_module(self, i): + """ + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r._repr_module(0) + 'S(0)' + sage: r._repr_module(1) + 'S(-2)⊕S(-2)⊕S(-2)' + sage: r._repr_module(2) + 'S(-3)⊕S(-3)' + sage: r._repr_module(3) + '0' + """ + if i > len(self): + m = '0' + else: + if i == 0: + shifts = self._shifts + else: + shifts = self._res_shifts[i - 1] + + if len(shifts) > 0: + for j in range(len(shifts)): + shift = shifts[j] + if j == 0: + m = f'{self._name}' + \ + (f'(-{shift})' if shift != self._zero_deg else '(0)') + else: + m += f'\u2295{self._name}' + \ + (f'(-{shift})' if shift != self._zero_deg else '(0)') + else: + m = '0' + return m + + def shifts(self, i): + """ + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r.shifts(0) + [0] + sage: r.shifts(1) + [2, 2, 2] + sage: r.shifts(2) + [3, 3] + sage: r.shifts(3) + [] + """ + if i < 0: + raise IndexError('invalid index') + elif i == 0: + shifts = self._shifts + elif i > len(self): + shifts = [] + else: + shifts = self._res_shifts[i - 1] + + return shifts + + def betti(self, i, a=None): + """ + Return the `i`-th Betti number in degree `a`. + + INPUT: + + - ``i`` -- nonnegative integer + + - ``a`` -- a degree; if ``None``, return Betti numbers in all degrees + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r.betti(0) + {0: 1} + sage: r.betti(1) + {2: 3} + sage: r.betti(2) + {3: 2} + sage: r.betti(1, 0) + 0 + sage: r.betti(1, 1) + 0 + sage: r.betti(1, 2) + 3 + """ + shifts = self.shifts(i) + + if a is None: + degrees = shifts + else: + degrees = [a] + + betti = {} + for s in degrees: + betti[s] = len([d for d in shifts if d == s]) + + if a is None: + return betti + else: + return betti[a] if a in betti else 0 + + def K_polynomial(self, names=None): + """ + Return the K-polynomial of this resolution. + + INPUT: + + - ``names`` -- a string of names of the variables of the K-polynomial + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r.K_polynomial() + 2*t^3 - 3*t^2 + 1 + """ + if self._multigrade: + n = self._degrees[0].degree() + else: + n = 1 + + if names is not None: + L = LaurentPolynomialRing(ZZ, names=names) + else: + L = LaurentPolynomialRing(ZZ, 't', n) + + kpoly = 1 + sign = -1 + for j in range(len(self)): + for v in self._res_shifts[j]: + if self._multigrade: + kpoly += sign * L.monomial(*list(v)) + else: + kpoly += sign * L.monomial(v) + sign = -sign + + return kpoly + + +cdef to_sage_resolution_graded(Resolution res, degrees): + """ + Pull the data from Singular resolution ``res`` to construct a Sage + resolution. + + INPUT: + + - ``res`` -- Singular resolution + + - ``degrees`` -- list of integers or integer vectors + + The procedure is destructive, and ``res`` is not usable afterward. + """ + cdef ring *singular_ring + cdef syStrategy singular_res + cdef poly *p + cdef poly *p_iter + cdef poly *first + cdef poly *previous + cdef poly *acc + cdef resolvente mods + cdef ideal *mod + cdef int i, j, k, idx, rank, nrows, ncols + cdef int ngens = len(degrees) + cdef bint zero_mat + + singular_res = res._resolution[0] + sage_ring = res.base_ring + singular_ring = access_singular_ring(res.base_ring) + + if singular_res.minres != NULL: + mods = singular_res.minres + elif singular_res.fullres != NULL: + mods = singular_res.fullres + else: + raise ValueError('Singular resolution is not usable') + + res_mats = [] + res_degs = [] + + # length is the length of fullres. The length of minres + # can be shorter. Hence we avoid SEGFAULT by stopping + # at NULL pointer. + for idx in range(singular_res.length): + mod = mods[idx] + if mod == NULL: + break + rank = mod.rank + free_module = sage_ring ** rank + + nrows = rank + ncols = mod.ncols # IDELEMS(mod) + + mat = _matrix(sage_ring, nrows, ncols) + matdegs = [] + zero_mat = True + for j in range(ncols): + p = mod.m[j] + degs = [] + # code below copied and modified from to_sage_vector_destructive + # in sage.libs.singular.function.Converter + for i in range(1, rank + 1): + previous = NULL + acc = NULL + first = NULL + p_iter = p + while p_iter != NULL: + if p_GetComp(p_iter, singular_ring) == i: + p_SetComp(p_iter, 0, singular_ring) + p_Setm(p_iter, singular_ring) + if acc == NULL: + first = p_iter + else: + acc.next = p_iter + acc = p_iter + if p_iter == p: + p = pNext(p_iter) + if previous != NULL: + previous.next = pNext(p_iter) + p_iter = pNext(p_iter) + acc.next = NULL + else: + previous = p_iter + p_iter = pNext(p_iter) + + if zero_mat: + zero_mat = first == NULL + + mat[i - 1, j] = new_sage_polynomial(sage_ring, first) + + # degree of a homogeneous polynomial can be computed from the + # first monomial + if first != NULL: + exps = singular_monomial_exponents(first, singular_ring) + deg = 0 + for k in range(ngens): + deg += exps[k] * degrees[k] + degs.append(deg) + else: + degs.append(None) + + matdegs.append(degs) # store degrees of the column + + # Singular sometimes leaves zero matrix in the resolution. We can stop + # when one is seen. + if zero_mat: + break + + res_mats.append(mat) + res_degs.append(matdegs) + + return res_mats, res_degs + + diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 41e9c9ff251..1975ffae5fe 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -1,31 +1,6 @@ r""" Interface to Singular -AUTHORS: - -- David Joyner and William Stein (2005): first version - -- Martin Albrecht (2006-03-05): code so singular.[tab] and x = - singular(...), x.[tab] includes all singular commands. - -- Martin Albrecht (2006-03-06): This patch adds the equality symbol to - singular. Also fix a problem in which " " as prompt means comparison - will break all further communication with Singular. - -- Martin Albrecht (2006-03-13): added current_ring() and - current_ring_name() - -- William Stein (2006-04-10): Fixed problems with ideal constructor - -- Martin Albrecht (2006-05-18): added sage_poly. - -- Simon King (2010-11-23): Reduce the overhead caused by waiting for - the Singular prompt by doing garbage collection differently. - -- Simon King (2011-06-06): Make conversion from Singular to Sage more flexible. - -- Simon King (2015): Extend pickling capabilities. - Introduction ------------ @@ -37,7 +12,6 @@ your computer; this should be the case, since Singular is included with Sage. The interface offers three pieces of functionality: - #. ``singular_console()`` - A function that dumps you into an interactive command-line Singular session. @@ -238,10 +212,6 @@ An Important Concept -------------------- -AUTHORS: - -- Neal Harris - The following illustrates an important concept: how Sage interacts with the data being used and returned by Singular. Let's compute a Groebner basis for some ideal, using Singular through Sage. @@ -325,6 +295,34 @@ [Ideal (z) of Multivariate Polynomial Ring in x, z over Number Field in p with defining polynomial p^2 - p - 1] sage: [ J.gens() for J in I.primary_decomposition("gtz")] [[z]] + +AUTHORS: + +- David Joyner and William Stein (2005): first version + +- Neal Harris (unknown): perhaps added "An Important Concept" + +- Martin Albrecht (2006-03-05): code so singular.[tab] and x = + singular(...), x.[tab] includes all singular commands. + +- Martin Albrecht (2006-03-06): This patch adds the equality symbol to + singular. Also fix a problem in which " " as prompt means comparison + will break all further communication with Singular. + +- Martin Albrecht (2006-03-13): added current_ring() and + current_ring_name() + +- William Stein (2006-04-10): Fixed problems with ideal constructor + +- Martin Albrecht (2006-05-18): added sage_poly. + +- Simon King (2010-11-23): Reduce the overhead caused by waiting for + the Singular prompt by doing garbage collection differently. + +- Simon King (2011-06-06): Make conversion from Singular to Sage more flexible. + +- Simon King (2015): Extend pickling capabilities. + """ # **************************************************************************** @@ -1496,8 +1494,6 @@ def __bool__(self): P = self.parent() return P.eval('%s == 0' % self.name()) == '0' - - def sage_polystring(self): r""" If this Singular element is a polynomial, return a string @@ -2069,7 +2065,6 @@ def set_ring(self): """ self.parent().set_ring(self) - def sage_flattened_str_list(self): """ EXAMPLES:: @@ -2596,6 +2591,7 @@ def flush(self): """ sys.stdout.flush() + class SingularGBDefaultContext: """ Within this context all Singular Groebner basis calculations are diff --git a/src/sage/libs/singular/decl.pxd b/src/sage/libs/singular/decl.pxd index d5cf0444119..8eeec084bd4 100644 --- a/src/sage/libs/singular/decl.pxd +++ b/src/sage/libs/singular/decl.pxd @@ -1134,8 +1134,16 @@ cdef extern from "singular/kernel/GBEngine/kstd1.h": cdef extern int Kstd1_deg # degBound, default 0 cdef extern int Kstd1_mu # multBound, default 0 +cdef extern from "singular/kernel/ideals.h": + ctypedef ideal * resolvente + cdef extern from "singular/kernel/GBEngine/syz.h": ctypedef struct syStrategy "ssyStrategy": + resolvente fullres; + resolvente minres; + int length; + int regularity; + short list_length; short references cdef extern from "singular/polys/ext_fields/transext.h": diff --git a/src/sage/libs/singular/function.pxd b/src/sage/libs/singular/function.pxd index 232bf198538..503384004d5 100644 --- a/src/sage/libs/singular/function.pxd +++ b/src/sage/libs/singular/function.pxd @@ -19,6 +19,7 @@ from sage.libs.singular.decl cimport leftv, idhdl, syStrategy, matrix, poly, ide from sage.libs.singular.decl cimport ring as singular_ring from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular, MPolynomial_libsingular +cdef new_sage_polynomial(ring, poly *p) cdef poly* access_singular_poly(p) except -1 cdef singular_ring* access_singular_ring(r) except -1 diff --git a/src/sage/libs/singular/function.pyx b/src/sage/libs/singular/function.pyx index 698cc81f2ad..3ecbeb4ff2a 100644 --- a/src/sage/libs/singular/function.pyx +++ b/src/sage/libs/singular/function.pyx @@ -7,16 +7,6 @@ or interprocess communication overhead. Users who do not want to call Singular functions directly, usually do not have to worry about this interface, since it is handled by higher level functions in Sage. -AUTHORS: - -- Michael Brickenstein (2009-07): initial implementation, overall design -- Martin Albrecht (2009-07): clean up, enhancements, etc. -- Michael Brickenstein (2009-10): extension to more Singular types -- Martin Albrecht (2010-01): clean up, support for attributes -- Simon King (2011-04): include the documentation provided by Singular as a code block. -- Burcin Erocal, Michael Brickenstein, Oleksandr Motsak, Alexander Dreyer, Simon King - (2011-09) plural support - EXAMPLES: The direct approach for loading a Singular function is to call the @@ -62,6 +52,21 @@ TESTS:: sage: std = singular_function('std') sage: loads(dumps(std)) == std True + +AUTHORS: + +- Michael Brickenstein (2009-07): initial implementation, overall design + +- Martin Albrecht (2009-07): clean up, enhancements, etc + +- Michael Brickenstein (2009-10): extension to more Singular types + +- Martin Albrecht (2010-01): clean up, support for attributes + +- Simon King (2011-04): include the documentation provided by Singular as a code block + +- Burcin Erocal, Michael Brickenstein, Oleksandr Motsak, Alexander Dreyer, Simon King (2011-09): plural support + """ #***************************************************************************** @@ -82,36 +87,29 @@ from sage.cpython.string cimport str_to_bytes, char_to_str from sage.structure.sage_object cimport SageObject from sage.structure.richcmp cimport richcmp - -from sage.rings.integer cimport Integer +from sage.structure.sequence import Sequence, Sequence_generic from sage.modules.free_module_element cimport FreeModuleElement_generic_dense +from sage.rings.integer cimport Integer from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular, new_MP from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular - from sage.rings.polynomial.plural cimport NCPolynomialRing_plural, NCPolynomial_plural, new_NCP from sage.rings.polynomial.multi_polynomial_ideal import NCPolynomialIdeal - from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal - from sage.rings.polynomial.multi_polynomial_ideal_libsingular cimport sage_ideal_to_singular_ideal, singular_ideal_to_sage_sequence +from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence, PolynomialSequence_generic from sage.libs.singular.decl cimport * - from sage.libs.singular.option import opt_ctx from sage.libs.singular.polynomial cimport singular_vector_maximal_component, singular_polynomial_check from sage.libs.singular.singular cimport sa2si, si2sa, si2sa_intvec - from sage.libs.singular.singular import error_messages from sage.interfaces.singular import get_docstring from sage.misc.verbose import get_verbose -from sage.structure.sequence import Sequence, Sequence_generic -from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence, PolynomialSequence_generic - cdef poly* sage_vector_to_poly(v, ring *r) except -1: """ @@ -156,7 +154,7 @@ cdef class RingWrap: return "" def __dealloc__(self): - if self._ring!=NULL: + if self._ring != NULL: self._ring.ref -= 1 def ngens(self): @@ -292,6 +290,7 @@ cdef class RingWrap: """ rPrint(self._ring) + cdef class Resolution: """ A simple wrapper around Singular's resolutions. @@ -308,9 +307,10 @@ cdef class Resolution: sage: M = syz(I) sage: resolution = mres(M, 0) """ - #FIXME: still not working noncommutative + # FIXME: still not working noncommutative assert is_sage_wrapper_for_singular_ring(base_ring) self.base_ring = base_ring + def __repr__(self): """ EXAMPLES:: @@ -326,6 +326,7 @@ cdef class Resolution: """ return "" + def __dealloc__(self): """ EXAMPLES:: @@ -342,6 +343,7 @@ cdef class Resolution: if self._resolution != NULL: self._resolution.references -= 1 + cdef leftv* new_leftv(void *data, res_type): """ INPUT: @@ -487,6 +489,7 @@ def all_vectors(s): return False return True + cdef class Converter(SageObject): """ A :class:`Converter` interfaces between Sage objects and Singular @@ -686,8 +689,6 @@ cdef class Converter(SageObject): Convert singular matrix to matrix over the polynomial ring. """ from sage.matrix.constructor import Matrix - #cdef ring *singular_ring = (\ - # self._sage_ring)._ring ncols = mat.ncols nrows = mat.nrows result = Matrix(self._sage_ring, nrows, ncols) @@ -699,7 +700,6 @@ cdef class Converter(SageObject): return result cdef to_sage_vector_destructive(self, poly *p, free_module = None): - #cdef ring *r=self._ring._ring cdef int rank if free_module: rank = free_module.rank() @@ -716,20 +716,20 @@ cdef class Converter(SageObject): previous = NULL acc = NULL first = NULL - p_iter=p + p_iter = p while p_iter != NULL: if p_GetComp(p_iter, self._singular_ring) == i: - p_SetComp(p_iter,0, self._singular_ring) + p_SetComp(p_iter, 0, self._singular_ring) p_Setm(p_iter, self._singular_ring) if acc == NULL: first = p_iter else: acc.next = p_iter acc = p_iter - if p_iter==p: - p=pNext(p_iter) + if p_iter == p: + p = pNext(p_iter) if previous != NULL: - previous.next=pNext(p_iter) + previous.next = pNext(p_iter) p_iter = pNext(p_iter) acc.next = NULL else: @@ -750,7 +750,6 @@ cdef class Converter(SageObject): - ``r`` -- a SINGULAR ring - ``sage_ring`` -- a Sage ring matching r """ - #cdef MPolynomialRing_libsingular sage_ring = self._ring cdef int j cdef int rank=i.rank free_module = self._sage_ring ** rank @@ -758,12 +757,11 @@ cdef class Converter(SageObject): for j from 0 <= j < IDELEMS(i): p = self.to_sage_vector_destructive(i.m[j], free_module) - i.m[j]=NULL#save it from getting freed + i.m[j]=NULL # save it from getting freed l.append( p ) return Sequence(l, check=False, immutable=True) - cdef to_sage_integer_matrix(self, intvec* mat): """ Convert Singular matrix to matrix over the polynomial ring. @@ -780,7 +778,6 @@ cdef class Converter(SageObject): result[i,j] = mat.get(i*ncols+j) return result - cdef leftv *append_polynomial(self, p) except NULL: """ Append the polynomial ``p`` to the list. @@ -808,8 +805,6 @@ cdef class Converter(SageObject): cdef ideal *i cdef int j = 0 - - i = idInit(len(m),rank) for f in m: i.m[j] = sage_vector_to_poly(f, r) @@ -832,7 +827,6 @@ cdef class Converter(SageObject): return self._append(_r, RING_CMD) cdef leftv *append_matrix(self, mat) except NULL: - sage_ring = mat.base_ring() cdef ring *r= access_singular_ring(sage_ring) @@ -854,8 +848,6 @@ cdef class Converter(SageObject): cdef long _n = n return self._append(_n, INT_CMD) - - cdef leftv *append_list(self, l) except NULL: """ Append the list ``l`` to the list. @@ -948,31 +940,26 @@ cdef class Converter(SageObject): sage: sing_genus(I) # known bug -2 """ - #FIXME + # FIXME cdef MPolynomial_libsingular res_poly cdef int rtyp = to_convert.rtyp cdef lists *singular_list cdef Resolution res_resolution + if rtyp == IDEAL_CMD: return singular_ideal_to_sage_sequence(to_convert.data, self._singular_ring, self._sage_ring) - elif rtyp == POLY_CMD: - #FIXME + # FIXME res_poly = MPolynomial_libsingular(self._sage_ring) res_poly._poly = to_convert.data - to_convert.data = NULL - #prevent it getting free, when cleaning the leftv + to_convert.data = NULL # prevent it getting free, when cleaning the leftv return res_poly - elif rtyp == INT_CMD: return to_convert.data - elif rtyp == NUMBER_CMD: return si2sa(to_convert.data, self._singular_ring, self._sage_ring.base_ring()) - elif rtyp == INTVEC_CMD: - return si2sa_intvec(to_convert.data) - + return si2sa_intvec( to_convert.data) elif rtyp == STRING_CMD: # TODO: Need to determine what kind of data can be returned by a # STRING_CMD--is it just ASCII strings or can it be an arbitrary @@ -980,38 +967,26 @@ cdef class Converter(SageObject): ret = char_to_str(to_convert.data) return ret elif rtyp == VECTOR_CMD: - result = self.to_sage_vector_destructive( - to_convert.data) + result = self.to_sage_vector_destructive( to_convert.data) to_convert.data = NULL return result - - elif rtyp == RING_CMD or rtyp==QRING_CMD: return new_RingWrap( to_convert.data ) - elif rtyp == MATRIX_CMD: - return self.to_sage_matrix( to_convert.data ) - + return self.to_sage_matrix( to_convert.data ) elif rtyp == LIST_CMD: singular_list = to_convert.data ret = [] for i in xrange(singular_list.nr+1): - ret.append( - self.to_python( - &(singular_list.m[i]))) + ret.append(self.to_python(&(singular_list.m[i]))) return ret - - elif rtyp == MODUL_CMD: - return self.to_sage_module_element_sequence_destructive( - to_convert.data - ) + return self.to_sage_module_element_sequence_destructive( to_convert.data) elif rtyp == INTMAT_CMD: - return self.to_sage_integer_matrix( - to_convert.data) + return self.to_sage_integer_matrix( to_convert.data) elif rtyp == RESOLUTION_CMD: res_resolution = Resolution(self._sage_ring) - res_resolution._resolution = to_convert.data + res_resolution._resolution = to_convert.data res_resolution._resolution.references += 1 return res_resolution elif rtyp == NONE: @@ -1019,6 +994,7 @@ cdef class Converter(SageObject): else: raise NotImplementedError("rtyp %d not implemented."%(rtyp)) + cdef class BaseCallHandler: """ A call handler is an abstraction which hides the details of the @@ -1036,6 +1012,7 @@ cdef class BaseCallHandler: """ return False + cdef class LibraryCallHandler(BaseCallHandler): """ A call handler is an abstraction which hides the details of the @@ -1077,6 +1054,7 @@ cdef class LibraryCallHandler(BaseCallHandler): """ return False + cdef class KernelCallHandler(BaseCallHandler): """ A call handler is an abstraction which hides the details of the @@ -1163,9 +1141,11 @@ cdef class KernelCallHandler(BaseCallHandler): """ return True + # The Sage ring used as a dummy for singular function calls. cdef object dummy_ring + cdef class SingularFunction(SageObject): """ The base class for Singular functions either from the kernel or @@ -1540,6 +1520,7 @@ cdef inline call_function(SingularFunction self, tuple args, object R, bint sign return res + cdef class SingularLibraryFunction(SingularFunction): """ EXAMPLES:: @@ -1582,6 +1563,7 @@ cdef class SingularLibraryFunction(SingularFunction): cdef idhdl* singular_idhdl = ggetid(str_to_bytes(self._name)) return singular_idhdl!=NULL + cdef class SingularKernelFunction(SingularFunction): """ EXAMPLES:: @@ -1848,7 +1830,6 @@ def lib(name): if failure: raise NameError("Singular library {!r} not found".format(name)) - def list_of_functions(packages=False): """ Return a list of all function names currently available. @@ -1879,7 +1860,6 @@ def list_of_functions(packages=False): h = IDNEXT(h) return l - cdef inline RingWrap new_RingWrap(ring* r): cdef RingWrap ring_wrap_result = RingWrap.__new__(RingWrap) ring_wrap_result._ring = r @@ -1887,7 +1867,6 @@ cdef inline RingWrap new_RingWrap(ring* r): return ring_wrap_result - # Add support for _instancedoc_ from sage.misc.instancedoc import instancedoc instancedoc(SingularFunction) diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index fc6d8113d61..e012da4573c 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -25,7 +25,6 @@ import re plusminus_pattern = re.compile("([^\(^])([\+\-])") parenthvar_pattern = re.compile(r"\(([a-zA-Z][a-zA-Z0-9]*)\)") - from sage.cpython.string cimport bytes_to_str, str_to_bytes from sage.libs.singular.decl cimport number, ideal @@ -38,7 +37,6 @@ from sage.libs.singular.decl cimport p_GetComp, p_SetComp from sage.libs.singular.decl cimport pSubst from sage.libs.singular.decl cimport p_Normalize - from sage.libs.singular.singular cimport sa2si, si2sa, overflow_check from sage.misc.latex import latex @@ -80,7 +78,6 @@ cdef int singular_polynomial_add(poly **ret, poly *p, poly *q, ring *r): ret[0] = p_Add_q(p, q, r) return 0 - cdef int singular_polynomial_sub(poly **ret, poly *p, poly *q, ring *r): """ ``ret[0] = p-q`` where ``p`` and ``p`` in ``r``. @@ -108,7 +105,6 @@ cdef int singular_polynomial_sub(poly **ret, poly *p, poly *q, ring *r): ret[0] = p_Add_q(p, p_Neg(q, r), r) return 0 - cdef int singular_polynomial_rmul(poly **ret, poly *p, RingElement n, ring *r): """ ``ret[0] = n*p`` where ``n`` is a coefficient and ``p`` in ``r``. @@ -319,7 +315,6 @@ cdef int singular_polynomial_mul(poly** ret, poly *p, poly *q, ring *r) except - ret[0] = pp_Mult_qq(p, q, r) return 0 - cdef int singular_polynomial_div_coeff(poly** ret, poly *p, poly *q, ring *r) except -1: """ ``ret[0] = p/n`` where ``p`` and ``q`` in ``r`` and ``q`` constant. @@ -422,7 +417,6 @@ cdef int singular_polynomial_neg(poly **ret, poly *p, ring *r): ret[0] = p_Neg(p_Copy(p,r),r) return 0 - cdef object singular_polynomial_str(poly *p, ring *r): """ Return the string representation of ``p``. @@ -448,7 +442,6 @@ cdef object singular_polynomial_str(poly *p, ring *r): s = parenthvar_pattern.sub("\\1", s) return s - cdef object singular_polynomial_latex(poly *p, ring *r, object base, object latex_gens): r""" Return the LaTeX string representation of ``p``. diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index f57126a6be4..63cb6a9e19e 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -421,7 +421,6 @@ cdef object si2sa_transext_QQ(number *n, ring *_ring, object base): return snumer/sdenom - cdef object si2sa_transext_FF(number *n, ring *_ring, object base): """ Create a sage element of a transcendental extension of a prime field from a @@ -505,7 +504,6 @@ cdef object si2sa_transext_FF(number *n, ring *_ring, object base): return snumer/sdenom - cdef object si2sa_NF(number *n, ring *_ring, object base): """ Create a sage element of a number field from a singular one. @@ -1018,8 +1016,6 @@ cdef number *sa2si_transext_QQ(object elem, ring *_ring): return n1 - - cdef number *sa2si_transext_FF(object elem, ring *_ring): """ Create a singular number from a sage element of a transcendental extension @@ -1123,7 +1119,6 @@ cdef number *sa2si_transext_FF(object elem, ring *_ring): return n1 - cdef number *sa2si_NF(object elem, ring *_ring): """ Create a singular number from a sage element of a number field. @@ -1430,7 +1425,6 @@ cdef number *sa2si(Element elem, ring * _ring): raise ValueError("cannot convert to SINGULAR number") - cdef object si2sa_intvec(intvec *v): r""" create a sage tuple from a singular vector of integers @@ -1495,7 +1489,6 @@ cdef int overflow_check(unsigned long e, ring *_ring) except -1: if unlikely(e > _ring.bitmask): raise OverflowError("exponent overflow (%d)"%(e)) - cdef init_libsingular(): """ This initializes the SINGULAR library. This is a hack to some From e8db5419f184e0f36c1b0f648e71c1e79d2f72de Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sat, 11 Jun 2022 21:20:06 +0900 Subject: [PATCH 031/591] Add some methods to projective morphisms --- .../elliptic_curves/ell_curve_isogeny.py | 30 ++++ src/sage/schemes/plane_conics/con_field.py | 4 - src/sage/schemes/product_projective/space.py | 102 +++++------ .../schemes/projective/projective_morphism.py | 162 ++++++++++++++++-- 4 files changed, 229 insertions(+), 69 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 77768439227..c0436ea33eb 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -2768,6 +2768,36 @@ def x_rational_map(self): self.__initialize_rational_maps() return self.__X_coord_rational_map + def morphism(self): + r""" + Return this isogeny as a morphism of projective schemes. + + EXAMPLES:: + + sage: k = GF(11) + sage: E = EllipticCurve(k, [1,1]) + sage: Q = E(6,5) + sage: phi = E.isogeny(Q) + sage: mor = phi.morphism() + sage: mor.domain() == E + True + sage: mor.codomain() == phi.codomain() + True + sage: mor(Q) == phi(Q) + True + + TESTS:: + + sage: mor(0*Q) + (0 : 1 : 0) + sage: mor(1*Q) + (0 : 1 : 0) + """ + from sage.schemes.curves.constructor import Curve + X_affine = Curve(self.domain()).affine_patch(2) + Y_affine = Curve(self.codomain()).affine_patch(2) + return X_affine.hom(self.rational_maps(), Y_affine).homogenize(2) + def kernel_polynomial(self): r""" Return the kernel polynomial of this isogeny. diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index 3ed2b06e960..dbef426b0a0 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -874,10 +874,6 @@ def parametrization(self, point=None, morphism=True): sage: f([1,1]) (0 : 0 : 1) sage: g([0,0,1]) - Traceback (most recent call last): - ... - ValueError: [0, 0] does not define a point in Projective Space of dimension 1 over Finite Field of size 2 since all entries are zero - sage: g.representatives()[1]([0,0,1]) (1 : 1) An example with ``morphism = False`` :: diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index a7eb86ce43f..2ecfbc5b0ff 100644 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -1,14 +1,14 @@ r""" Products of projective spaces -This class builds on the projective space class and its point and morphism classes. +This class builds on the projective space class and its point and morphism +classes. -Products of projective spaces of varying dimension are convenient -ambient spaces for complete intersections. +Products of projective spaces of varying dimension are convenient ambient +spaces for complete intersections. -Group actions on them, and -the interplay with representation theory, provide many interesting -examples of algebraic varieties. +Group actions on them, and the interplay with representation theory, provide +many interesting examples of algebraic varieties. EXAMPLES: @@ -28,6 +28,7 @@ sage: P2xP2.coordinate_ring().inject_variables() Defining x0, x1, x2, y0, y1, y2 """ + #***************************************************************************** # Copyright (C) 2014 Volker Braun # Copyright (C) 2014 Ben Hutz @@ -39,7 +40,6 @@ # http://www.gnu.org/licenses/ #***************************************************************************** - from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod from sage.rings.all import (PolynomialRing, QQ, Integer, CommutativeRing) @@ -81,16 +81,17 @@ def ProductProjectiveSpaces(n, R=None, names='x'): r""" Return the Cartesian product of projective spaces. - Can input either a list of projective space over the same base \ - ring or the list of dimensions, the base ring, and the variable names. + The input ``n`` is either a list of projective space over the same base + ring or the list of dimensions, ``R`` the base ring, and ``names`` the + variable names. INPUT: - - ``n`` -- a list of integers or a list of projective spaces. + - ``n`` -- a list of integers or a list of projective spaces - - ``R`` -- a ring. + - ``R`` -- a ring - - ``names`` -- a string or list of strings. + - ``names`` -- a string or list of strings EXAMPLES:: @@ -120,7 +121,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): if R is None: R = QQ # default is the rationals if isinstance(n[0], ProjectiveSpace_ring): - #this should be a list of projective spaces + # this should be a list of projective spaces names = [] N = [] R = None @@ -146,7 +147,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): if not isinstance(R, CommutativeRing): raise ValueError("must be a commutative ring") from sage.structure.category_object import normalize_names - n_vars = sum(d+1 for d in n) + n_vars = sum(d + 1 for d in n) if isinstance(names, str): names = normalize_names(n_vars, names) else: @@ -154,7 +155,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): if len(name_list) == len(n): names = [] for name, dim in zip(name_list, n): - names += normalize_names(dim+1, name) + names += normalize_names(dim + 1, name) else: n_vars = sum(1+d for d in n) names = normalize_names(n_vars, name_list) @@ -196,12 +197,12 @@ def __init__(self, N, R = QQ, names = None): INPUT: - - ``N`` - a list or tuple of positive integers. + - ``N`` -- a list or tuple of positive integers - - ``R`` - a ring. + - ``R`` -- a ring - - ``names`` - a tuple or list of strings. This must either be a single variable name - or the complete list of variables. + - ``names`` -- a tuple or list of strings; this must either be a single + variable name or the complete list of variables EXAMPLES:: @@ -236,8 +237,9 @@ def __init__(self, N, R = QQ, names = None): for i in range(len(N)): self._components.append(ProjectiveSpace(N[i],R,names[start:start+N[i]+1])) start += N[i]+1 - #Note that the coordinate ring should really be the tensor product of the component - #coordinate rings. But we just deal with them as multihomogeneous polynomial rings + # Note that the coordinate ring should really be the tensor product of + # the component coordinate rings. But we just deal with them as + # multihomogeneous polynomial rings. self._coordinate_ring = PolynomialRing(R,sum(N)+ len(N),names) self._assign_names(names) @@ -245,29 +247,23 @@ def _repr_(self): r""" Return a string representation of this space. - OUTPUT: String. - EXAMPLES:: sage: ProductProjectiveSpaces([1, 1, 1], ZZ, ['x', 'y', 'z', 'u', 'v', 'w']) Product of projective spaces P^1 x P^1 x P^1 over Integer Ring """ - return ''.join([ - 'Product of projective spaces ', - ' x '.join('P^{0}'.format(d) for d in self._dims), - ' over ', - str(self.base_ring())]) + return ''.join(['Product of projective spaces ', + ' x '.join('P^{0}'.format(d) for d in self._dims), + ' over ', str(self.base_ring())]) def _repr_generic_point(self, v=None): """ Return a string representation of the generic point on this product space. - If ``v`` is None, the representation of the generic point of + If ``v`` is ``None``, the representation of the generic point of the product space is returned. - OUTPUT: String. - EXAMPLES:: sage: T = ProductProjectiveSpaces([1, 2, 1], QQ, 'x') @@ -318,9 +314,9 @@ def __getitem__(self, i): INPUT: - - ``i`` - a positive integer. + - ``i`` -- a positive integer - OUTPUT: A projective space. + OUTPUT: a projective space EXAMPLES:: @@ -416,7 +412,7 @@ def __mul__(self, right): INPUT: - - ``right`` - a projective space, product of projective spaces, or subscheme. + - ``right`` -- a projective space, product of projective spaces, or subscheme OUTPUT: a product of projective spaces or subscheme @@ -476,7 +472,7 @@ def components(self): r""" Return the components of this product of projective spaces. - OUTPUT: A list of projective spaces. + OUTPUT: a list of projective spaces EXAMPLES:: @@ -491,7 +487,7 @@ def dimension_relative(self): r""" Return the relative dimension of the product of projective spaces. - OUTPUT: A positive integer. + OUTPUT: a positive integer EXAMPLES:: @@ -505,7 +501,7 @@ def dimension_absolute(self): r""" Return the absolute dimension of the product of projective spaces. - OUTPUT: A positive integer. + OUTPUT: a positive integer EXAMPLES:: @@ -526,7 +522,7 @@ def dimension_relative_components(self): r""" Return the relative dimension of the product of projective spaces. - OUTPUT: A list of positive integers. + OUTPUT: a list of positive integers EXAMPLES:: @@ -540,7 +536,7 @@ def dimension_absolute_components(self): r""" Return the absolute dimension of the product of projective spaces. - OUTPUT: A list of positive integers. + OUTPUT: a list of positive integers EXAMPLES:: @@ -561,7 +557,7 @@ def num_components(self): r""" Returns the number of components of this space. - OUTPUT: An integer. + OUTPUT: an integer EXAMPLES:: @@ -578,7 +574,7 @@ def ngens(self): This is the number of variables in the coordinate ring of the projective space. - OUTPUT: An integer. + OUTPUT: an integer EXAMPLES:: @@ -594,9 +590,9 @@ def _factors(self, v): INPUT: - - ``v`` -- a list or tuple. + - ``v`` -- a list or tuple - OUTPUT: A list of lists. + OUTPUT: a list of lists EXAMPLES:: @@ -622,11 +618,9 @@ def _degree(self, polynomial): INPUT: - A polynomial in :meth:`coordinate_ring`. + - ``polynomial`` -- a polynomial in the coordinate_ring - OUTPUT: - - A tuple of integers, one for each projective space component. A + OUTPUT: A tuple of integers, one for each projective space component. A ``ValueError`` is raised if the polynomial is not multihomogeneous. EXAMPLES:: @@ -832,7 +826,7 @@ def subscheme(self, X): INPUT: - - ``X`` - a list or tuple of equations. + - ``X`` -- a list or tuple of equations OUTPUT: @@ -872,7 +866,7 @@ def change_ring(self, R): INPUT: - - ``R`` -- commutative ring or morphism. + - ``R`` -- commutative ring or morphism OUTPUT: @@ -1152,15 +1146,13 @@ def points_of_bounded_height(self, **kwds): INPUT: - - ``bound`` - a real number + - ``bound`` -- a real number - - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4 + - ``tolerance`` -- a rational number in (0,1] used in doyle-krumm algorithm-4 - - ``precision`` - the precision to use for computing the elements of bounded height of number fields. - - OUTPUT: + - ``precision`` -- the precision to use for computing the elements of bounded height of number fields. - - an iterator of points in this space + OUTPUT: an iterator of points in this space EXAMPLES:: diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 4fe6d715e4f..e88d191297f 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -45,6 +45,8 @@ - Kwankyu Lee (2020-02): added indeterminacy_locus() and image() +- Kwankyu Lee (2022-05): added graph(), projective_degrees(), and degree() + """ # **************************************************************************** @@ -59,21 +61,14 @@ # http://www.gnu.org/licenses/ # **************************************************************************** - import sys - from sage.arith.all import gcd, lcm - from sage.interfaces.singular import singular - from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute - from sage.ext.fast_callable import fast_callable - from sage.calculus.functions import jacobian - import sage.rings.abc from sage.rings.integer import Integer from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic @@ -87,13 +82,13 @@ from sage.rings.qqbar import QQbar, number_field_elements_from_algebraics from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ - +from sage.modules.free_module_element import vector from sage.schemes.generic.morphism import SchemeMorphism_polynomial - from sage.categories.finite_fields import FiniteFields from sage.categories.number_fields import NumberFields from sage.categories.homset import Hom, End from sage.categories.fields import Fields +from sage.homology.graded_resolution import GradedFreeResolution _NumberFields = NumberFields() _FiniteFields = FiniteFields() @@ -2200,6 +2195,35 @@ class SchemeMorphism_polynomial_projective_subscheme_field(SchemeMorphism_polyno """ Morphisms from subschemes of projective spaces defined over fields. """ + def __call__(self, x): + """ + Apply this morphism to the point ``x``. + + INPUT: + + - ``x`` -- a point in the domain of definition + + OUTPUT: a point in the codomain + + TESTS:: + + sage: R. = QQ[] + sage: C = Curve(7*x^2 + 2*y*z + z^2) + sage: f, g = C.parametrization() + sage: g([0, -1, 2]) + (1 : 0) + sage: f([1, 0]) + (0 : -1/2 : 1) + sage: _ == C([0, -1, 2]) + True + """ + for m in self.representatives(): + try: + return super(SchemeMorphism_polynomial_projective_subscheme_field, m).__call__(x) + except ValueError: + pass + raise ValueError('the morphism is not defined at this point') + @cached_method def representatives(self): """ @@ -2491,7 +2515,7 @@ def image(self): if not Y.is_projective(): e = Y.projective_embedding(0) - return (e*self).image().affine_patch(0, Y.ambient_space()) + return (e * self).image().affine_patch(0, Y.ambient_space()) k = self.base_ring() @@ -2516,3 +2540,121 @@ def image(self): gens = [g.subs(dict(zip(R.gens()[n:],T.gens()))) for g in j] return AY.subscheme(gens) + + def graph(self): + """ + Return the graph of this morphism. + + The graph is a subscheme of the product of the ambient spaces of the + domain and the codomain. If the ambient space of the codomain is an + affine space, it is first embedded into a projective space. + + EXAMPLES: + + We get the standard quadratic curve as the graph of a quadratic function + of an affine line. :: + + sage: A1. = AffineSpace(1, QQ) + sage: X = A1.subscheme(0) # affine line + sage: phi = X.hom([x^2], A1) + sage: mor = phi.homogenize(0) + sage: G = mor.graph(); G + Closed subscheme of Product of projective spaces P^1 x P^1 over Rational Field defined by: + x1^2*x2 - x0^2*x3 + sage: G.affine_patch([0, 0]) + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x0^2 - x1 + """ + X = self.domain() + Y = self.codomain() + + if not Y.is_projective(): + e = Y.projective_embedding(0) + return (e * self).graph() + + AX = X.ambient_space() + AY = Y.ambient_space() + + n = AX.dimension() + m = AY.dimension() + + if any(v in AX.variable_names() for v in AY.variable_names()): + from sage.schemes.product_projective.space import ProductProjectiveSpaces + AXY = ProductProjectiveSpaces([n, m], self.base_ring()) + else: + AXY = AX * AY # product of projective spaces + + R = AXY.coordinate_ring() + F = [R(f) for f in self.defining_polynomials()] + g = R.gens() + + # Suppose R = k[x_0, ..., x_n, y_0, ..., y_m]. Then the bihomogeneous + # ideal of the graph is + # + # I + (y_iF_j - y_jF_i : 0 <= i, j <= m) + # + # saturated with respect to (F_0, F_1, ..., F_m). + n1 = n + 1; m1 = m + 1 + I = X.defining_ideal().change_ring(R) + h = [g[n1 + i] * F[j] - g[n1 + j] * F[i] for i in range(m1) for j in range(i + 1, m1)] + J, _ = (I + R.ideal(h)).saturation(R.ideal(F)) + + return AXY.subscheme(J) + + def projective_degrees(self): + """ + Return the projective degrees of this rational map. + + EXAMPLES:: + + sage: k = GF(11) + sage: E = EllipticCurve(k,[1,1]) + sage: Q = E(6,5) + sage: phi = E.multiplication_by_m_isogeny(2) + sage: mor = phi.morphism() + sage: mor.projective_degrees() + [12, 3] + """ + X = self.domain() + Y = self.codomain() + + if not Y.is_projective(): # Y is affine + e = Y.projective_embedding(0) + return (e * self).projective_degrees() + + AX = X.ambient_space() + AY = Y.ambient_space() + xn = AX.ngens() + yn = AY.ngens() + + G = self.graph() + I = G.defining_ideal() # a bihomogeneous ideal + + degrees = xn*[vector([1,0])] + yn*[vector([0,1])] + res = GradedFreeResolution(I, degrees, algorithm='shreyer') + kpoly = res.K_polynomial() + + L = kpoly.parent() + t1, t2 = L.gens() + poly = kpoly.substitute({t1: 1 - t1, t2: 1 - t2}) + + n = AX.dimension() + m = AY.dimension() + k = X.dimension() + return [poly.monomial_coefficient(L.monomial(n - i, m - k + i)) for i in range(k + 1)] + + def degree(self): + """ + Return the degree of this rational map. + + EXAMPLES:: + + sage: k = GF(11) + sage: E = EllipticCurve(k,[1,1]) + sage: Q = E(6,5) + sage: phi = E.multiplication_by_m_isogeny(2) + sage: mor = phi.morphism() + sage: mor.degree() + 4 + """ + return self.projective_degrees()[0] // self.image().degree() From 452821124d4d9e7e96f22494cb8e4bc0cbf61c94 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Jun 2022 14:25:36 +0200 Subject: [PATCH 032/591] trac #34074: cleanup src/sage/graphs/graph_generators.py --- src/sage/graphs/graph_generators.py | 557 ++++++++++++++-------------- 1 file changed, 285 insertions(+), 272 deletions(-) diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 8a98b0ddc99..df0e5de768f 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -18,6 +18,7 @@ import subprocess + # This method appends a list of methods to the doc as a 3xN table. # Here's the point : @@ -31,24 +32,29 @@ def __append_to_doc(methods): global __doc__ __doc__ += ("\n.. csv-table::\n" - " :class: contentstable\n" - " :widths: 33, 33, 33\n" - " :delim: |\n\n") + " :class: contentstable\n" + " :widths: 33, 33, 33\n" + " :delim: |\n\n") h = (len(methods)+2)//3 # Reorders the list of methods for horizontal reading, the only one Sphinx understands reordered_methods = [0]*3*h for i, m in enumerate(methods): - reordered_methods[3*(i%h)+(i//h)] = m + reordered_methods[3*(i % h) + (i//h)] = m methods = reordered_methods # Adding the list to the __doc__ string - wrap_name = lambda x : ":meth:`"+str(x)+" `" if x else "" + def wrap_name(x): + if x: + return ":meth:`" + str(x) + " `" + return "" + while methods: a = methods.pop(0) b = methods.pop(0) c = methods.pop(0) - __doc__ += " "+wrap_name(a)+" | "+wrap_name(b)+" | "+wrap_name(c)+"\n" + __doc__ += " " + wrap_name(a) + " | " + wrap_name(b) + " | " + wrap_name(c) + "\n" + __doc__ += """ **Basic structures** @@ -450,15 +456,17 @@ def __append_to_doc(methods): --------------------- """ -########################################################################### - -# Copyright (C) 2006 Robert L. Miller -# and Emily A. Kirkman -# Copyright (C) 2009 Michael C. Yurko +# **************************************************************************** +# Copyright (C) 2006 Robert L. Miller +# Emily A. Kirkman +# 2009 Michael C. Yurko # -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -########################################################################### +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** # import from Python standard library @@ -720,8 +728,8 @@ class GraphGenerators(): # Graph Iterators ########################################################################### - def __call__(self, vertices=None, property=None, augment='edges', - size=None, degree_sequence=None, loops=False, sparse=True, copy = True): + def __call__(self, vertices=None, property=None, augment='edges', size=None, + degree_sequence=None, loops=False, sparse=True, copy=True): """ Accesses the generator of isomorphism class representatives. Iterates over distinct, exhaustive representatives. See the docstring @@ -768,8 +776,8 @@ def __call__(self, vertices=None, property=None, augment='edges', """ # Use nauty for the basic case, as it is much faster. if (vertices and property is None and size is None and - degree_sequence is None and not loops and augment == 'edges' and - sparse and copy): + degree_sequence is None and not loops and augment == 'edges' and + sparse and copy): for g in graphs.nauty_geng(vertices): yield g return @@ -784,19 +792,22 @@ def property(x): if degree_sequence is not None: if vertices is None: raise NotImplementedError - if len(degree_sequence) != vertices or sum(degree_sequence)%2 or sum(degree_sequence) > vertices*(vertices-1): + if (len(degree_sequence) != vertices or sum(degree_sequence) % 2 + or sum(degree_sequence) > vertices*(vertices - 1)): raise ValueError("Invalid degree sequence.") degree_sequence = sorted(degree_sequence) if augment == 'edges': def property(x): D = sorted(x.degree()) return all(degree_sequence[i] >= d for i, d in enumerate(D)) + def extra_property(x): return degree_sequence == sorted(x.degree()) else: def property(x): D = sorted(x.degree() + [0] * (vertices - x.num_verts())) return all(degree_sequence[i] >= d for i, d in enumerate(D)) + def extra_property(x): if x.num_verts() != vertices: return False @@ -825,9 +836,9 @@ def extra_property(x): vertices += 1 g = Graph(vertices, loops=loops, sparse=sparse) gens = [] - for i in range(vertices-1): + for i in range(vertices - 1): gen = list(range(i)) - gen.append(i+1) + gen.append(i + 1) gen.append(i) gen += list(range(i + 2, vertices)) gens.append(gen) @@ -837,7 +848,6 @@ def extra_property(x): else: raise NotImplementedError - def nauty_geng(self, options="", debug=False): r""" Return a generator which creates graphs from nauty's geng program. @@ -1190,7 +1200,6 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr A list of lists of graphs. Each sublist will be a list of cospectral graphs (lists of cardinality 1 being omitted). - .. SEEALSO:: :meth:`Graph.is_strongly_regular` -- tests whether a graph is @@ -1253,21 +1262,21 @@ def cospectral_graphs(self, vertices, matrix_function=lambda g: g.adjacency_matr """ from sage.graphs.graph_generators import graphs as graph_gen if graphs is None: - graph_list=graph_gen(vertices, property=lambda _: True) + graph_list = graph_gen(vertices, property=lambda _: True) elif callable(graphs): - graph_list=iter(g for g in graph_gen(vertices, property=lambda _: True) if graphs(g)) + graph_list = iter(g for g in graph_gen(vertices, property=lambda _: True) if graphs(g)) else: - graph_list=iter(graphs) + graph_list = iter(graphs) from collections import defaultdict - charpolys=defaultdict(list) + charpolys = defaultdict(list) for g in graph_list: - cp=matrix_function(g).charpoly() + cp = matrix_function(g).charpoly() charpolys[cp].append(g) - cospectral_graphs=[] - for cp,g_list in charpolys.items(): - if len(g_list)>1: + cospectral_graphs = [] + for cp, g_list in charpolys.items(): + if len(g_list) > 1: cospectral_graphs.append(g_list) return cospectral_graphs @@ -1327,15 +1336,14 @@ def _read_planar_code(self, code_input): 3: [1, 2, 4], 4: [1, 3, 2]} """ - #start of code to read planar code - + # start of code to read planar code header = code_input.read(15) assert header == '>>planar_code<<', 'Not a valid planar code header' - #read graph per graph + # read graph per graph while True: c = code_input.read(1) - if len(c)==0: + if not c: return # Each graph is stored in the following way : @@ -1553,7 +1561,7 @@ def fusenes(self, hexagon_count, benzenoids=False): # there is only one unique fusene with 1 hexagon (and benzene doesn't generate it) if hexagon_count == 1: - g = {1:[6, 2], 2:[1, 3], 3:[2, 4], 4:[3, 5], 5:[4, 6], 6:[5, 1]} + g = {1: [6, 2], 2: [1, 3], 3: [2, 4], 4: [3, 5], 5: [4, 6], 6: [5, 1]} G = graph.Graph(g) G.set_embedding(g) yield(G) @@ -1919,7 +1927,7 @@ def planar_graphs(self, order, minimum_degree=None, if exact_connectivity and minimum_connectivity is None: raise ValueError("Minimum connectivity must be specified to use the exact_connectivity option.") - if minimum_connectivity is not None and not (1 <= minimum_connectivity <= 3): + if minimum_connectivity is not None and not (1 <= minimum_connectivity <= 3): raise ValueError("Minimum connectivity should be a number between 1 and 3.") # minimum degree should be None or a number between 1 and 5 @@ -1944,8 +1952,8 @@ def planar_graphs(self, order, minimum_degree=None, minimum_degree > 0): raise ValueError("Minimum connectivity can be at most the minimum degree.") - #exact connectivity is not implemented for minimum connectivity 3 - if exact_connectivity and minimum_connectivity==3: + # exact connectivity is not implemented for minimum connectivity 3 + if exact_connectivity and minimum_connectivity == 3: raise NotImplementedError("Generation of planar graphs with connectivity exactly 3 is not implemented.") if only_bipartite and minimum_degree > 3: @@ -1979,7 +1987,7 @@ def planar_graphs(self, order, minimum_degree=None, if order == 0: return - minimum_order = {0:1, 1:2, 2:3, 3:4, 4:6, 5:12}[minimum_degree] + minimum_order = {0: 1, 1: 2, 2: 3, 3: 4, 4: 6, 5: 12}[minimum_degree] if order < minimum_order: return @@ -2132,10 +2140,10 @@ def triangulations(self, order, minimum_degree=None, minimum_connectivity=None, if exact_connectivity and minimum_connectivity is None: raise ValueError("Minimum connectivity must be specified to use the exact_connectivity option.") - if minimum_connectivity is not None and not (3 <= minimum_connectivity <= 5): + if minimum_connectivity is not None and not (3 <= minimum_connectivity <= 5): raise ValueError("Minimum connectivity should be None or a number between 3 and 5.") - if minimum_degree is not None and not (3 <= minimum_degree <= 5): + if minimum_degree is not None and not (3 <= minimum_degree <= 5): raise ValueError("Minimum degree should be None or a number between 3 and 5.") # for Eulerian triangulations the minimum degree is set to 4 (unless it was already specifically set) @@ -2154,11 +2162,12 @@ def triangulations(self, order, minimum_degree=None, minimum_connectivity=None, elif minimum_degree < minimum_connectivity: raise ValueError("Minimum connectivity can be at most the minimum degree.") - #exact connectivity is not implemented for minimum connectivity equal to minimum degree - if exact_connectivity and minimum_connectivity==minimum_degree: + # exact connectivity is not implemented for minimum connectivity equal + # to minimum degree + if exact_connectivity and minimum_connectivity == minimum_degree: raise NotImplementedError("Generation of triangulations with minimum connectivity equal to minimum degree is not implemented.") - minimum_order = {3:4, 4:6, 5:12}[minimum_degree] + minimum_order = {3: 4, 4: 6, 5: 12}[minimum_degree] if order < minimum_order: return @@ -2277,8 +2286,9 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None raise ValueError("Minimum degree should be None, 2 or 3.") if (no_nonfacial_quadrangles and - minimum_connectivity == 2): - raise NotImplementedError("Generation of no non-facial quadrangles and minimum connectivity 2 is not implemented") + minimum_connectivity == 2): + raise NotImplementedError("Generation of no non-facial quadrangles " + "and minimum connectivity 2 is not implemented") # check combination of values of minimum degree and minimum connectivity if minimum_connectivity is None: @@ -2292,7 +2302,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None elif minimum_degree < minimum_connectivity: raise ValueError("Minimum connectivity can be at most the minimum degree.") - minimum_order = {2:4, 3:8}[minimum_degree] + minimum_order = {2: 4, 3: 8}[minimum_degree] if order < minimum_order: return @@ -2313,220 +2323,220 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None # Basic Graphs ########################################################################### from .generators import basic - BullGraph = staticmethod(basic.BullGraph) - ButterflyGraph = staticmethod(basic.ButterflyGraph) - CircularLadderGraph = staticmethod(basic.CircularLadderGraph) - ClawGraph = staticmethod(basic.ClawGraph) - CycleGraph = staticmethod(basic.CycleGraph) - CompleteGraph = staticmethod(basic.CompleteGraph) - CompleteBipartiteGraph = staticmethod(basic.CompleteBipartiteGraph) - CompleteMultipartiteGraph= staticmethod(basic.CompleteMultipartiteGraph) - DiamondGraph = staticmethod(basic.DiamondGraph) - GemGraph = staticmethod(basic.GemGraph) - DartGraph = staticmethod(basic.DartGraph) - ForkGraph = staticmethod(basic.ForkGraph) - EmptyGraph = staticmethod(basic.EmptyGraph) - Grid2dGraph = staticmethod(basic.Grid2dGraph) - GridGraph = staticmethod(basic.GridGraph) - HouseGraph = staticmethod(basic.HouseGraph) - HouseXGraph = staticmethod(basic.HouseXGraph) - LadderGraph = staticmethod(basic.LadderGraph) - PathGraph = staticmethod(basic.PathGraph) - StarGraph = staticmethod(basic.StarGraph) + BullGraph = staticmethod(basic.BullGraph) + ButterflyGraph = staticmethod(basic.ButterflyGraph) + CircularLadderGraph = staticmethod(basic.CircularLadderGraph) + ClawGraph = staticmethod(basic.ClawGraph) + CycleGraph = staticmethod(basic.CycleGraph) + CompleteGraph = staticmethod(basic.CompleteGraph) + CompleteBipartiteGraph = staticmethod(basic.CompleteBipartiteGraph) + CompleteMultipartiteGraph = staticmethod(basic.CompleteMultipartiteGraph) + DiamondGraph = staticmethod(basic.DiamondGraph) + GemGraph = staticmethod(basic.GemGraph) + DartGraph = staticmethod(basic.DartGraph) + ForkGraph = staticmethod(basic.ForkGraph) + EmptyGraph = staticmethod(basic.EmptyGraph) + Grid2dGraph = staticmethod(basic.Grid2dGraph) + GridGraph = staticmethod(basic.GridGraph) + HouseGraph = staticmethod(basic.HouseGraph) + HouseXGraph = staticmethod(basic.HouseXGraph) + LadderGraph = staticmethod(basic.LadderGraph) + PathGraph = staticmethod(basic.PathGraph) + StarGraph = staticmethod(basic.StarGraph) Toroidal6RegularGrid2dGraph = staticmethod(basic.Toroidal6RegularGrid2dGraph) - ToroidalGrid2dGraph = staticmethod(basic.ToroidalGrid2dGraph) + ToroidalGrid2dGraph = staticmethod(basic.ToroidalGrid2dGraph) ########################################################################### # Small Graphs ########################################################################### from .generators import smallgraphs, distance_regular - Balaban10Cage = staticmethod(smallgraphs.Balaban10Cage) - Balaban11Cage = staticmethod(smallgraphs.Balaban11Cage) - BidiakisCube = staticmethod(smallgraphs.BidiakisCube) - BiggsSmithGraph = staticmethod(smallgraphs.BiggsSmithGraph) - BlanusaFirstSnarkGraph = staticmethod(smallgraphs.BlanusaFirstSnarkGraph) - BlanusaSecondSnarkGraph = staticmethod(smallgraphs.BlanusaSecondSnarkGraph) - BrinkmannGraph = staticmethod(smallgraphs.BrinkmannGraph) - BrouwerHaemersGraph = staticmethod(smallgraphs.BrouwerHaemersGraph) - BuckyBall = staticmethod(smallgraphs.BuckyBall) - CameronGraph = staticmethod(smallgraphs.CameronGraph) - Cell600 = staticmethod(smallgraphs.Cell600) - Cell120 = staticmethod(smallgraphs.Cell120) - ChvatalGraph = staticmethod(smallgraphs.ChvatalGraph) - ClebschGraph = staticmethod(smallgraphs.ClebschGraph) + Balaban10Cage = staticmethod(smallgraphs.Balaban10Cage) + Balaban11Cage = staticmethod(smallgraphs.Balaban11Cage) + BidiakisCube = staticmethod(smallgraphs.BidiakisCube) + BiggsSmithGraph = staticmethod(smallgraphs.BiggsSmithGraph) + BlanusaFirstSnarkGraph = staticmethod(smallgraphs.BlanusaFirstSnarkGraph) + BlanusaSecondSnarkGraph = staticmethod(smallgraphs.BlanusaSecondSnarkGraph) + BrinkmannGraph = staticmethod(smallgraphs.BrinkmannGraph) + BrouwerHaemersGraph = staticmethod(smallgraphs.BrouwerHaemersGraph) + BuckyBall = staticmethod(smallgraphs.BuckyBall) + CameronGraph = staticmethod(smallgraphs.CameronGraph) + Cell600 = staticmethod(smallgraphs.Cell600) + Cell120 = staticmethod(smallgraphs.Cell120) + ChvatalGraph = staticmethod(smallgraphs.ChvatalGraph) + ClebschGraph = staticmethod(smallgraphs.ClebschGraph) cocliques_HoffmannSingleton = staticmethod(distance_regular.cocliques_HoffmannSingleton) - ConwaySmith_for_3S7 = staticmethod(distance_regular.ConwaySmith_for_3S7) - CoxeterGraph = staticmethod(smallgraphs.CoxeterGraph) - DejterGraph = staticmethod(smallgraphs.DejterGraph) - DesarguesGraph = staticmethod(smallgraphs.DesarguesGraph) + ConwaySmith_for_3S7 = staticmethod(distance_regular.ConwaySmith_for_3S7) + CoxeterGraph = staticmethod(smallgraphs.CoxeterGraph) + DejterGraph = staticmethod(smallgraphs.DejterGraph) + DesarguesGraph = staticmethod(smallgraphs.DesarguesGraph) distance_3_doubly_truncated_Golay_code_graph = staticmethod(distance_regular.distance_3_doubly_truncated_Golay_code_graph) - DoubleStarSnark = staticmethod(smallgraphs.DoubleStarSnark) + DoubleStarSnark = staticmethod(smallgraphs.DoubleStarSnark) DoublyTruncatedWittGraph = staticmethod(distance_regular.DoublyTruncatedWittGraph) - DurerGraph = staticmethod(smallgraphs.DurerGraph) - DyckGraph = staticmethod(smallgraphs.DyckGraph) - EllinghamHorton54Graph = staticmethod(smallgraphs.EllinghamHorton54Graph) - EllinghamHorton78Graph = staticmethod(smallgraphs.EllinghamHorton78Graph) - ErreraGraph = staticmethod(smallgraphs.ErreraGraph) - F26AGraph = staticmethod(smallgraphs.F26AGraph) - FlowerSnark = staticmethod(smallgraphs.FlowerSnark) - FolkmanGraph = staticmethod(smallgraphs.FolkmanGraph) - FosterGraph = staticmethod(smallgraphs.FosterGraph) - FosterGraph3S6 = staticmethod(distance_regular.FosterGraph3S6) - FranklinGraph = staticmethod(smallgraphs.FranklinGraph) - FruchtGraph = staticmethod(smallgraphs.FruchtGraph) - GoldnerHararyGraph = staticmethod(smallgraphs.GoldnerHararyGraph) - GolombGraph = staticmethod(smallgraphs.GolombGraph) - GossetGraph = staticmethod(smallgraphs.GossetGraph) - graph_3O73 = staticmethod(distance_regular.graph_3O73) - GrayGraph = staticmethod(smallgraphs.GrayGraph) - GritsenkoGraph = staticmethod(smallgraphs.GritsenkoGraph) - GrotzschGraph = staticmethod(smallgraphs.GrotzschGraph) - HallJankoGraph = staticmethod(smallgraphs.HallJankoGraph) - WellsGraph = staticmethod(smallgraphs.WellsGraph) - HarborthGraph = staticmethod(smallgraphs.HarborthGraph) - HarriesGraph = staticmethod(smallgraphs.HarriesGraph) - HarriesWongGraph = staticmethod(smallgraphs.HarriesWongGraph) - HeawoodGraph = staticmethod(smallgraphs.HeawoodGraph) - HerschelGraph = staticmethod(smallgraphs.HerschelGraph) - HigmanSimsGraph = staticmethod(smallgraphs.HigmanSimsGraph) - HoffmanGraph = staticmethod(smallgraphs.HoffmanGraph) - HoffmanSingletonGraph = staticmethod(smallgraphs.HoffmanSingletonGraph) - HoltGraph = staticmethod(smallgraphs.HoltGraph) - HortonGraph = staticmethod(smallgraphs.HortonGraph) - IoninKharaghani765Graph = staticmethod(smallgraphs.IoninKharaghani765Graph) + DurerGraph = staticmethod(smallgraphs.DurerGraph) + DyckGraph = staticmethod(smallgraphs.DyckGraph) + EllinghamHorton54Graph = staticmethod(smallgraphs.EllinghamHorton54Graph) + EllinghamHorton78Graph = staticmethod(smallgraphs.EllinghamHorton78Graph) + ErreraGraph = staticmethod(smallgraphs.ErreraGraph) + F26AGraph = staticmethod(smallgraphs.F26AGraph) + FlowerSnark = staticmethod(smallgraphs.FlowerSnark) + FolkmanGraph = staticmethod(smallgraphs.FolkmanGraph) + FosterGraph = staticmethod(smallgraphs.FosterGraph) + FosterGraph3S6 = staticmethod(distance_regular.FosterGraph3S6) + FranklinGraph = staticmethod(smallgraphs.FranklinGraph) + FruchtGraph = staticmethod(smallgraphs.FruchtGraph) + GoldnerHararyGraph = staticmethod(smallgraphs.GoldnerHararyGraph) + GolombGraph = staticmethod(smallgraphs.GolombGraph) + GossetGraph = staticmethod(smallgraphs.GossetGraph) + graph_3O73 = staticmethod(distance_regular.graph_3O73) + GrayGraph = staticmethod(smallgraphs.GrayGraph) + GritsenkoGraph = staticmethod(smallgraphs.GritsenkoGraph) + GrotzschGraph = staticmethod(smallgraphs.GrotzschGraph) + HallJankoGraph = staticmethod(smallgraphs.HallJankoGraph) + WellsGraph = staticmethod(smallgraphs.WellsGraph) + HarborthGraph = staticmethod(smallgraphs.HarborthGraph) + HarriesGraph = staticmethod(smallgraphs.HarriesGraph) + HarriesWongGraph = staticmethod(smallgraphs.HarriesWongGraph) + HeawoodGraph = staticmethod(smallgraphs.HeawoodGraph) + HerschelGraph = staticmethod(smallgraphs.HerschelGraph) + HigmanSimsGraph = staticmethod(smallgraphs.HigmanSimsGraph) + HoffmanGraph = staticmethod(smallgraphs.HoffmanGraph) + HoffmanSingletonGraph = staticmethod(smallgraphs.HoffmanSingletonGraph) + HoltGraph = staticmethod(smallgraphs.HoltGraph) + HortonGraph = staticmethod(smallgraphs.HortonGraph) + IoninKharaghani765Graph = staticmethod(smallgraphs.IoninKharaghani765Graph) IvanovIvanovFaradjevGraph = staticmethod(distance_regular.IvanovIvanovFaradjevGraph) - J2Graph = staticmethod(distance_regular.J2Graph) - JankoKharaghaniGraph = staticmethod(smallgraphs.JankoKharaghaniGraph) - JankoKharaghaniTonchevGraph = staticmethod(smallgraphs.JankoKharaghaniTonchevGraph) - KittellGraph = staticmethod(smallgraphs.KittellGraph) - KrackhardtKiteGraph = staticmethod(smallgraphs.KrackhardtKiteGraph) - Klein3RegularGraph = staticmethod(smallgraphs.Klein3RegularGraph) - Klein7RegularGraph = staticmethod(smallgraphs.Klein7RegularGraph) - LargeWittGraph = staticmethod(distance_regular.LargeWittGraph) - LeonardGraph = staticmethod(distance_regular.LeonardGraph) - LjubljanaGraph = staticmethod(smallgraphs.LjubljanaGraph) - vanLintSchrijverGraph = staticmethod(distance_regular.vanLintSchrijverGraph) - LivingstoneGraph = staticmethod(smallgraphs.LivingstoneGraph) + J2Graph = staticmethod(distance_regular.J2Graph) + JankoKharaghaniGraph = staticmethod(smallgraphs.JankoKharaghaniGraph) + JankoKharaghaniTonchevGraph = staticmethod(smallgraphs.JankoKharaghaniTonchevGraph) + KittellGraph = staticmethod(smallgraphs.KittellGraph) + KrackhardtKiteGraph = staticmethod(smallgraphs.KrackhardtKiteGraph) + Klein3RegularGraph = staticmethod(smallgraphs.Klein3RegularGraph) + Klein7RegularGraph = staticmethod(smallgraphs.Klein7RegularGraph) + LargeWittGraph = staticmethod(distance_regular.LargeWittGraph) + LeonardGraph = staticmethod(distance_regular.LeonardGraph) + LjubljanaGraph = staticmethod(smallgraphs.LjubljanaGraph) + vanLintSchrijverGraph = staticmethod(distance_regular.vanLintSchrijverGraph) + LivingstoneGraph = staticmethod(smallgraphs.LivingstoneGraph) locally_GQ42_distance_transitive_graph = staticmethod(distance_regular.locally_GQ42_distance_transitive_graph) - LocalMcLaughlinGraph = staticmethod(smallgraphs.LocalMcLaughlinGraph) - M22Graph = staticmethod(smallgraphs.M22Graph) - MarkstroemGraph = staticmethod(smallgraphs.MarkstroemGraph) + LocalMcLaughlinGraph = staticmethod(smallgraphs.LocalMcLaughlinGraph) + M22Graph = staticmethod(smallgraphs.M22Graph) + MarkstroemGraph = staticmethod(smallgraphs.MarkstroemGraph) MathonStronglyRegularGraph = staticmethod(smallgraphs.MathonStronglyRegularGraph) - McGeeGraph = staticmethod(smallgraphs.McGeeGraph) - McLaughlinGraph = staticmethod(smallgraphs.McLaughlinGraph) - MeredithGraph = staticmethod(smallgraphs.MeredithGraph) - MoebiusKantorGraph = staticmethod(smallgraphs.MoebiusKantorGraph) - MoserSpindle = staticmethod(smallgraphs.MoserSpindle) - NauruGraph = staticmethod(smallgraphs.NauruGraph) - PappusGraph = staticmethod(smallgraphs.PappusGraph) - PoussinGraph = staticmethod(smallgraphs.PoussinGraph) - PerkelGraph = staticmethod(smallgraphs.PerkelGraph) - PetersenGraph = staticmethod(smallgraphs.PetersenGraph) - RobertsonGraph = staticmethod(smallgraphs.RobertsonGraph) - SchlaefliGraph = staticmethod(smallgraphs.SchlaefliGraph) + McGeeGraph = staticmethod(smallgraphs.McGeeGraph) + McLaughlinGraph = staticmethod(smallgraphs.McLaughlinGraph) + MeredithGraph = staticmethod(smallgraphs.MeredithGraph) + MoebiusKantorGraph = staticmethod(smallgraphs.MoebiusKantorGraph) + MoserSpindle = staticmethod(smallgraphs.MoserSpindle) + NauruGraph = staticmethod(smallgraphs.NauruGraph) + PappusGraph = staticmethod(smallgraphs.PappusGraph) + PoussinGraph = staticmethod(smallgraphs.PoussinGraph) + PerkelGraph = staticmethod(smallgraphs.PerkelGraph) + PetersenGraph = staticmethod(smallgraphs.PetersenGraph) + RobertsonGraph = staticmethod(smallgraphs.RobertsonGraph) + SchlaefliGraph = staticmethod(smallgraphs.SchlaefliGraph) shortened_00_11_binary_Golay_code_graph = staticmethod(distance_regular.shortened_00_11_binary_Golay_code_graph) shortened_000_111_extended_binary_Golay_code_graph = staticmethod(distance_regular.shortened_000_111_extended_binary_Golay_code_graph) - ShrikhandeGraph = staticmethod(smallgraphs.ShrikhandeGraph) - SimsGewirtzGraph = staticmethod(smallgraphs.SimsGewirtzGraph) - SousselierGraph = staticmethod(smallgraphs.SousselierGraph) - SylvesterGraph = staticmethod(smallgraphs.SylvesterGraph) - SzekeresSnarkGraph = staticmethod(smallgraphs.SzekeresSnarkGraph) - ThomsenGraph = staticmethod(smallgraphs.ThomsenGraph) - TietzeGraph = staticmethod(smallgraphs.TietzeGraph) - Tutte12Cage = staticmethod(smallgraphs.Tutte12Cage) + ShrikhandeGraph = staticmethod(smallgraphs.ShrikhandeGraph) + SimsGewirtzGraph = staticmethod(smallgraphs.SimsGewirtzGraph) + SousselierGraph = staticmethod(smallgraphs.SousselierGraph) + SylvesterGraph = staticmethod(smallgraphs.SylvesterGraph) + SzekeresSnarkGraph = staticmethod(smallgraphs.SzekeresSnarkGraph) + ThomsenGraph = staticmethod(smallgraphs.ThomsenGraph) + TietzeGraph = staticmethod(smallgraphs.TietzeGraph) + Tutte12Cage = staticmethod(smallgraphs.Tutte12Cage) TruncatedIcosidodecahedralGraph = staticmethod(smallgraphs.TruncatedIcosidodecahedralGraph) TruncatedTetrahedralGraph = staticmethod(smallgraphs.TruncatedTetrahedralGraph) - TruncatedWittGraph = staticmethod(distance_regular.TruncatedWittGraph) - TutteCoxeterGraph = staticmethod(smallgraphs.TutteCoxeterGraph) - TutteGraph = staticmethod(smallgraphs.TutteGraph) - U42Graph216 = staticmethod(smallgraphs.U42Graph216) - U42Graph540 = staticmethod(smallgraphs.U42Graph540) - WagnerGraph = staticmethod(smallgraphs.WagnerGraph) - WatkinsSnarkGraph = staticmethod(smallgraphs.WatkinsSnarkGraph) - WienerArayaGraph = staticmethod(smallgraphs.WienerArayaGraph) - SuzukiGraph = staticmethod(smallgraphs.SuzukiGraph) + TruncatedWittGraph = staticmethod(distance_regular.TruncatedWittGraph) + TutteCoxeterGraph = staticmethod(smallgraphs.TutteCoxeterGraph) + TutteGraph = staticmethod(smallgraphs.TutteGraph) + U42Graph216 = staticmethod(smallgraphs.U42Graph216) + U42Graph540 = staticmethod(smallgraphs.U42Graph540) + WagnerGraph = staticmethod(smallgraphs.WagnerGraph) + WatkinsSnarkGraph = staticmethod(smallgraphs.WatkinsSnarkGraph) + WienerArayaGraph = staticmethod(smallgraphs.WienerArayaGraph) + SuzukiGraph = staticmethod(smallgraphs.SuzukiGraph) ########################################################################### # Platonic Solids ########################################################################### from .generators import platonic_solids - DodecahedralGraph = staticmethod(platonic_solids.DodecahedralGraph) - HexahedralGraph = staticmethod(platonic_solids.HexahedralGraph) - IcosahedralGraph = staticmethod(platonic_solids.IcosahedralGraph) - OctahedralGraph = staticmethod(platonic_solids.OctahedralGraph) - TetrahedralGraph = staticmethod(platonic_solids.TetrahedralGraph) + DodecahedralGraph = staticmethod(platonic_solids.DodecahedralGraph) + HexahedralGraph = staticmethod(platonic_solids.HexahedralGraph) + IcosahedralGraph = staticmethod(platonic_solids.IcosahedralGraph) + OctahedralGraph = staticmethod(platonic_solids.OctahedralGraph) + TetrahedralGraph = staticmethod(platonic_solids.TetrahedralGraph) ########################################################################### # Families ########################################################################### from .generators import families from . import strongly_regular_db - AlternatingFormsGraph = staticmethod(distance_regular.AlternatingFormsGraph) - AztecDiamondGraph = staticmethod(families.AztecDiamondGraph) - BalancedTree = staticmethod(families.BalancedTree) - BarbellGraph = staticmethod(families.BarbellGraph) - BilinearFormsGraph = staticmethod(distance_regular.BilinearFormsGraph) - BubbleSortGraph = staticmethod(families.BubbleSortGraph) - CaiFurerImmermanGraph = staticmethod(families.CaiFurerImmermanGraph) - chang_graphs = staticmethod(families.chang_graphs) - CirculantGraph = staticmethod(families.CirculantGraph) - CubeGraph = staticmethod(families.CubeGraph) - CubeConnectedCycle = staticmethod(families.CubeConnectedCycle) - DipoleGraph = staticmethod(families.DipoleGraph) + AlternatingFormsGraph = staticmethod(distance_regular.AlternatingFormsGraph) + AztecDiamondGraph = staticmethod(families.AztecDiamondGraph) + BalancedTree = staticmethod(families.BalancedTree) + BarbellGraph = staticmethod(families.BarbellGraph) + BilinearFormsGraph = staticmethod(distance_regular.BilinearFormsGraph) + BubbleSortGraph = staticmethod(families.BubbleSortGraph) + CaiFurerImmermanGraph = staticmethod(families.CaiFurerImmermanGraph) + chang_graphs = staticmethod(families.chang_graphs) + CirculantGraph = staticmethod(families.CirculantGraph) + CubeGraph = staticmethod(families.CubeGraph) + CubeConnectedCycle = staticmethod(families.CubeConnectedCycle) + DipoleGraph = staticmethod(families.DipoleGraph) distance_regular_graph = staticmethod(distance_regular.distance_regular_graph) DorogovtsevGoltsevMendesGraph = staticmethod(families.DorogovtsevGoltsevMendesGraph) DoubleGeneralizedPetersenGraph = staticmethod(families.DoubleGeneralizedPetersenGraph) - DoubleGrassmannGraph = staticmethod(distance_regular.DoubleGrassmannGraph) - DoubleOddGraph = staticmethod(distance_regular.DoubleOddGraph) - EgawaGraph = staticmethod(families.EgawaGraph) - FibonacciTree = staticmethod(families.FibonacciTree) - FoldedCubeGraph = staticmethod(families.FoldedCubeGraph) - FriendshipGraph = staticmethod(families.FriendshipGraph) - FurerGadget = staticmethod(families.FurerGadget) - FuzzyBallGraph = staticmethod(families.FuzzyBallGraph) + DoubleGrassmannGraph = staticmethod(distance_regular.DoubleGrassmannGraph) + DoubleOddGraph = staticmethod(distance_regular.DoubleOddGraph) + EgawaGraph = staticmethod(families.EgawaGraph) + FibonacciTree = staticmethod(families.FibonacciTree) + FoldedCubeGraph = staticmethod(families.FoldedCubeGraph) + FriendshipGraph = staticmethod(families.FriendshipGraph) + FurerGadget = staticmethod(families.FurerGadget) + FuzzyBallGraph = staticmethod(families.FuzzyBallGraph) GeneralisedDodecagonGraph = staticmethod(distance_regular.GeneralisedDodecagonGraph) GeneralisedHexagonGraph = staticmethod(distance_regular.GeneralisedHexagonGraph) GeneralisedOctagonGraph = staticmethod(distance_regular.GeneralisedOctagonGraph) GeneralizedPetersenGraph = staticmethod(families.GeneralizedPetersenGraph) - GoethalsSeidelGraph = staticmethod(families.GoethalsSeidelGraph) - GrassmannGraph = staticmethod(distance_regular.GrassmannGraph) - HalfCube = staticmethod(distance_regular.HalfCube) - HammingGraph = staticmethod(families.HammingGraph) - HanoiTowerGraph = staticmethod(families.HanoiTowerGraph) - HararyGraph = staticmethod(families.HararyGraph) - HermitianFormsGraph = staticmethod(distance_regular.HermitianFormsGraph) - HyperStarGraph = staticmethod(families.HyperStarGraph) - IGraph = staticmethod(families.IGraph) - JohnsonGraph = staticmethod(families.JohnsonGraph) - KneserGraph = staticmethod(families.KneserGraph) - LCFGraph = staticmethod(families.LCFGraph) + GoethalsSeidelGraph = staticmethod(families.GoethalsSeidelGraph) + GrassmannGraph = staticmethod(distance_regular.GrassmannGraph) + HalfCube = staticmethod(distance_regular.HalfCube) + HammingGraph = staticmethod(families.HammingGraph) + HanoiTowerGraph = staticmethod(families.HanoiTowerGraph) + HararyGraph = staticmethod(families.HararyGraph) + HermitianFormsGraph = staticmethod(distance_regular.HermitianFormsGraph) + HyperStarGraph = staticmethod(families.HyperStarGraph) + IGraph = staticmethod(families.IGraph) + JohnsonGraph = staticmethod(families.JohnsonGraph) + KneserGraph = staticmethod(families.KneserGraph) + LCFGraph = staticmethod(families.LCFGraph) line_graph_forbidden_subgraphs = staticmethod(families.line_graph_forbidden_subgraphs) - LollipopGraph = staticmethod(families.LollipopGraph) + LollipopGraph = staticmethod(families.LollipopGraph) MathonPseudocyclicMergingGraph = staticmethod(families.MathonPseudocyclicMergingGraph) MathonPseudocyclicStronglyRegularGraph = staticmethod(families.MathonPseudocyclicStronglyRegularGraph) - MuzychukS6Graph = staticmethod(families.MuzychukS6Graph) - MycielskiGraph = staticmethod(families.MycielskiGraph) - MycielskiStep = staticmethod(families.MycielskiStep) - NKStarGraph = staticmethod(families.NKStarGraph) - NStarGraph = staticmethod(families.NStarGraph) - OddGraph = staticmethod(families.OddGraph) - PaleyGraph = staticmethod(families.PaleyGraph) - PasechnikGraph = staticmethod(families.PasechnikGraph) - petersen_family = staticmethod(families.petersen_family) - RingedTree = staticmethod(families.RingedTree) - RoseWindowGraph = staticmethod(families.RoseWindowGraph) - SierpinskiGasketGraph = staticmethod(families.SierpinskiGasketGraph) + MuzychukS6Graph = staticmethod(families.MuzychukS6Graph) + MycielskiGraph = staticmethod(families.MycielskiGraph) + MycielskiStep = staticmethod(families.MycielskiStep) + NKStarGraph = staticmethod(families.NKStarGraph) + NStarGraph = staticmethod(families.NStarGraph) + OddGraph = staticmethod(families.OddGraph) + PaleyGraph = staticmethod(families.PaleyGraph) + PasechnikGraph = staticmethod(families.PasechnikGraph) + petersen_family = staticmethod(families.petersen_family) + RingedTree = staticmethod(families.RingedTree) + RoseWindowGraph = staticmethod(families.RoseWindowGraph) + SierpinskiGasketGraph = staticmethod(families.SierpinskiGasketGraph) SquaredSkewHadamardMatrixGraph = staticmethod(families.SquaredSkewHadamardMatrixGraph) SwitchedSquaredSkewHadamardMatrixGraph = staticmethod(families.SwitchedSquaredSkewHadamardMatrixGraph) strongly_regular_graph = staticmethod(strongly_regular_db.strongly_regular_graph) - TabacjnGraph = staticmethod(families.TabacjnGraph) - TadpoleGraph = staticmethod(families.TadpoleGraph) - trees = staticmethod(families.trees) - nauty_gentreeg = staticmethod(families.nauty_gentreeg) - TuranGraph = staticmethod(families.TuranGraph) - UstimenkoGraph = staticmethod(distance_regular.UstimenkoGraph) - WheelGraph = staticmethod(families.WheelGraph) - WindmillGraph = staticmethod(families.WindmillGraph) + TabacjnGraph = staticmethod(families.TabacjnGraph) + TadpoleGraph = staticmethod(families.TadpoleGraph) + trees = staticmethod(families.trees) + nauty_gentreeg = staticmethod(families.nauty_gentreeg) + TuranGraph = staticmethod(families.TuranGraph) + UstimenkoGraph = staticmethod(distance_regular.UstimenkoGraph) + WheelGraph = staticmethod(families.WheelGraph) + WindmillGraph = staticmethod(families.WindmillGraph) ########################################################################### # Graphs from classical geometries over `F_q` @@ -2540,8 +2550,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None OrthogonalPolarGraph = staticmethod(classical_geometries.OrthogonalPolarGraph) SymplecticDualPolarGraph = staticmethod(classical_geometries.SymplecticDualPolarGraph) SymplecticPolarGraph = staticmethod(classical_geometries.SymplecticPolarGraph) - TaylorTwographDescendantSRG = \ - staticmethod(classical_geometries.TaylorTwographDescendantSRG) + TaylorTwographDescendantSRG = staticmethod(classical_geometries.TaylorTwographDescendantSRG) TaylorTwographSRG = staticmethod(classical_geometries.TaylorTwographSRG) T2starGeneralizedQuadrangleGraph = staticmethod(classical_geometries.T2starGeneralizedQuadrangleGraph) Nowhere0WordsTwoWeightCodeGraph = staticmethod(classical_geometries.Nowhere0WordsTwoWeightCodeGraph) @@ -2555,46 +2564,46 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None ########################################################################### from .generators import chessboard ChessboardGraphGenerator = staticmethod(chessboard.ChessboardGraphGenerator) - BishopGraph = staticmethod(chessboard.BishopGraph) - KingGraph = staticmethod(chessboard.KingGraph) - KnightGraph = staticmethod(chessboard.KnightGraph) - QueenGraph = staticmethod(chessboard.QueenGraph) - RookGraph = staticmethod(chessboard.RookGraph) + BishopGraph = staticmethod(chessboard.BishopGraph) + KingGraph = staticmethod(chessboard.KingGraph) + KnightGraph = staticmethod(chessboard.KnightGraph) + QueenGraph = staticmethod(chessboard.QueenGraph) + RookGraph = staticmethod(chessboard.RookGraph) ########################################################################### # Intersection graphs ########################################################################### from .generators import intersection - IntervalGraph = staticmethod(intersection.IntervalGraph) - IntersectionGraph = staticmethod(intersection.IntersectionGraph) - PermutationGraph = staticmethod(intersection.PermutationGraph) - OrthogonalArrayBlockGraph = staticmethod(intersection.OrthogonalArrayBlockGraph) - ToleranceGraph = staticmethod(intersection.ToleranceGraph) + IntervalGraph = staticmethod(intersection.IntervalGraph) + IntersectionGraph = staticmethod(intersection.IntersectionGraph) + PermutationGraph = staticmethod(intersection.PermutationGraph) + OrthogonalArrayBlockGraph = staticmethod(intersection.OrthogonalArrayBlockGraph) + ToleranceGraph = staticmethod(intersection.ToleranceGraph) ########################################################################### # Random Graphs ########################################################################### from .generators import random - RandomBarabasiAlbert = staticmethod(random.RandomBarabasiAlbert) - RandomBipartite = staticmethod(random.RandomBipartite) - RandomRegularBipartite = staticmethod(random.RandomRegularBipartite) - RandomBicubicPlanar = staticmethod(random.RandomBicubicPlanar) - RandomBlockGraph = staticmethod(random.RandomBlockGraph) + RandomBarabasiAlbert = staticmethod(random.RandomBarabasiAlbert) + RandomBipartite = staticmethod(random.RandomBipartite) + RandomRegularBipartite = staticmethod(random.RandomRegularBipartite) + RandomBicubicPlanar = staticmethod(random.RandomBicubicPlanar) + RandomBlockGraph = staticmethod(random.RandomBlockGraph) RandomBoundedToleranceGraph = staticmethod(random.RandomBoundedToleranceGraph) - RandomChordalGraph = staticmethod(random.RandomChordalGraph) - RandomGNM = staticmethod(random.RandomGNM) - RandomGNP = staticmethod(random.RandomGNP) - RandomHolmeKim = staticmethod(random.RandomHolmeKim) - RandomIntervalGraph = staticmethod(random.RandomIntervalGraph) - RandomLobster = staticmethod(random.RandomLobster) + RandomChordalGraph = staticmethod(random.RandomChordalGraph) + RandomGNM = staticmethod(random.RandomGNM) + RandomGNP = staticmethod(random.RandomGNP) + RandomHolmeKim = staticmethod(random.RandomHolmeKim) + RandomIntervalGraph = staticmethod(random.RandomIntervalGraph) + RandomLobster = staticmethod(random.RandomLobster) RandomNewmanWattsStrogatz = staticmethod(random.RandomNewmanWattsStrogatz) - RandomRegular = staticmethod(random.RandomRegular) - RandomShell = staticmethod(random.RandomShell) - RandomToleranceGraph = staticmethod(random.RandomToleranceGraph) - RandomTreePowerlaw = staticmethod(random.RandomTreePowerlaw) - RandomTree = staticmethod(random.RandomTree) - RandomTriangulation = staticmethod(random.RandomTriangulation) - RandomUnitDiskGraph = staticmethod(random.RandomUnitDiskGraph) + RandomRegular = staticmethod(random.RandomRegular) + RandomShell = staticmethod(random.RandomShell) + RandomToleranceGraph = staticmethod(random.RandomToleranceGraph) + RandomTreePowerlaw = staticmethod(random.RandomTreePowerlaw) + RandomTree = staticmethod(random.RandomTree) + RandomTriangulation = staticmethod(random.RandomTriangulation) + RandomUnitDiskGraph = staticmethod(random.RandomUnitDiskGraph) ########################################################################### # Maps @@ -2609,11 +2618,12 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None # Degree Sequence ########################################################################### from .generators import degree_sequence - DegreeSequence = staticmethod(degree_sequence.DegreeSequence) - DegreeSequenceBipartite = staticmethod(degree_sequence.DegreeSequenceBipartite) + DegreeSequence = staticmethod(degree_sequence.DegreeSequence) + DegreeSequenceBipartite = staticmethod(degree_sequence.DegreeSequenceBipartite) DegreeSequenceConfigurationModel = staticmethod(degree_sequence.DegreeSequenceConfigurationModel) - DegreeSequenceTree = staticmethod(degree_sequence.DegreeSequenceTree) - DegreeSequenceExpected = staticmethod(degree_sequence.DegreeSequenceExpected) + DegreeSequenceTree = staticmethod(degree_sequence.DegreeSequenceTree) + DegreeSequenceExpected = staticmethod(degree_sequence.DegreeSequenceExpected) + def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=False, sparse=True): """ @@ -2697,9 +2707,9 @@ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=Fals for i in range(len(children)): k = 0 for j in range(possibilities): - if (1 << j)&i: + if (1 << j) & i: if dig and j >= n: - k += (1 << (gen[j-n]+n)) + k += (1 << (gen[j - n] + n)) else: k += (1 << gen[j]) while children[k] != -1: @@ -2708,7 +2718,7 @@ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=Fals i = children[i] if i != k: # union i & k - smaller, larger = sorted([i,k]) + smaller, larger = sorted([i, k]) children[larger] = smaller num_roots -= 1 @@ -2729,18 +2739,18 @@ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=Fals if dig: index = 0 while 2 * index < possibilities: - if (1 << index)&i: - edges.append((index,n)) + if (1 << index) & i: + edges.append((index, n)) index += 1 while index < possibilities: - if (1 << index)&i: - edges.append((n,index-n)) + if (1 << index) & i: + edges.append((n, index - n)) index += 1 else: index = 0 while (1 << index) <= i: - if (1 << index)&i: - edges.append((index,n)) + if (1 << index) & i: + edges.append((index, n)) index += 1 z.add_edges(edges) z_s = [] @@ -2748,7 +2758,7 @@ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=Fals z_s.append(z) if loops: z = z.copy(sparse=sparse) - z.add_edge((n,n)) + z.add_edge((n, n)) if property(z): z_s.append(z) for z in z_s: @@ -2769,6 +2779,7 @@ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=Fals yield a break + def check_aut(aut_gens, cut_vert, n): """ Helper function for exhaustive generation. @@ -2863,18 +2874,18 @@ def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, sparse=T yield g n = g.order() if dig: - max_size = n*(n-1) + max_size = n * (n - 1) else: - max_size = (n*(n-1))>>1 # >> 1 is just / 2 (this is n choose 2) + max_size = (n * (n - 1)) >> 1 # >> 1 is just / 2 (this is n choose 2) if loops: max_size += n if g.size() < max_size: # build a list representing C(g) - the edge to be added # is one of max_size choices if dig: - children = [[(j,i) for i in range(n)] for j in range(n)] + children = [[(j, i) for i in range(n)] for j in range(n)] else: - children = [[(j,i) for i in range(j)] for j in range(n)] + children = [[(j, i) for i in range(j)] for j in range(n)] # union-find C(g) under Aut(g) orbits = list(range(n)) for gen in aut_gens: @@ -2934,12 +2945,12 @@ def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, sparse=T j_range = list(range(i)) for j in j_range: if children[i][j] == (i, j): - roots.append((i,j)) + roots.append((i, j)) if loops: seen = [] for i in range(n): if orbits[i] not in seen: - roots.append((i,i)) + roots.append((i, i)) seen.append(orbits[i]) for i, j in roots: if g.has_edge(i, j): @@ -2974,6 +2985,7 @@ def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, sparse=T yield a break + def check_aut_edge(aut_gens, cut_edge, i, j, n, dig=False): """ Helper function for exhaustive generation. @@ -3013,5 +3025,6 @@ def check_aut_edge(aut_gens, cut_edge, i, j, n, dig=False): if not dig and new_perm[cut_edge[0]] == j and new_perm[cut_edge[1]] == i: yield new_perm + # Easy access to the graph generators from the command line: graphs = GraphGenerators() From fc8db8a5f99a7b405721faa8d159aca4c50ef9f4 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Jun 2022 14:47:01 +0200 Subject: [PATCH 033/591] trac #34075: cleanup bipartite_graph.py and digraph_generators.py --- src/sage/graphs/bipartite_graph.py | 29 ++++++++++++++------------- src/sage/graphs/digraph_generators.py | 19 ++++++++++++------ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 2d421accf32..d87ba6db282 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -434,7 +434,7 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): if check: if (any(left.intersection(self.neighbor_iterator(a)) for a in left) or - any(right.intersection(self.neighbor_iterator(a)) for a in right)): + any(right.intersection(self.neighbor_iterator(a)) for a in right)): raise TypeError("input graph is not bipartite with " "respect to the given partition") else: @@ -453,9 +453,8 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): elif is_Matrix(data): # sanity check for mutually exclusive keywords if kwds.get("multiedges", False) and kwds.get("weighted", False): - raise TypeError( - "weighted multi-edge bipartite graphs from reduced " - "adjacency matrix not supported") + raise TypeError("weighted multi-edge bipartite graphs from " + "reduced adjacency matrix not supported") Graph.__init__(self, *args, **kwds) ncols = data.ncols() nrows = data.nrows() @@ -509,13 +508,12 @@ def __init__(self, data=None, partition=None, check=True, *args, **kwds): elif data.node_type[v] == "Top": self.right.add(v) else: - raise TypeError( - "NetworkX node_type defies bipartite " - "assumption (is not 'Top' or 'Bottom')") + raise TypeError("NetworkX node_type defies bipartite " + "assumption (is not 'Top' or 'Bottom')") elif partition: if check: if (any(left.intersection(self.neighbor_iterator(a)) for a in left) or - any(right.intersection(self.neighbor_iterator(a)) for a in right)): + any(right.intersection(self.neighbor_iterator(a)) for a in right)): raise TypeError("input graph is not bipartite with " "respect to the given partition") else: @@ -672,7 +670,7 @@ def add_vertex(self, name=None, left=False, right=False): # do nothing if we already have this vertex (idempotent) if name is not None and name in self: if ((left and name in self.left) or - (right and name in self.right)): + (right and name in self.right)): return else: raise RuntimeError("cannot add duplicate vertex to other partition") @@ -772,10 +770,9 @@ def add_vertices(self, vertices, left=False, right=False): # check that we're not trying to add vertices to the wrong sets # or that a vertex is to be placed in both if ((new_left & self.right) or - (new_right & self.left) or - (new_right & new_left)): - raise RuntimeError( - "cannot add duplicate vertex to other partition") + (new_right & self.left) or + (new_right & new_left)): + raise RuntimeError("cannot add duplicate vertex to other partition") # add vertices Graph.add_vertices(self, vertices) @@ -2400,7 +2397,11 @@ class by some canonization function `c`. If `G` and `H` are graphs, """ if certificate: - C, cert = GenericGraph.canonical_label(self, partition=partition, certificate=certificate, edge_labels=edge_labels, algorithm=algorithm, return_graph=return_graph) + C, cert = GenericGraph.canonical_label(self, partition=partition, + certificate=certificate, + edge_labels=edge_labels, + algorithm=algorithm, + return_graph=return_graph) else: from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index d464c0e090d..5d258f0503b 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -687,14 +687,14 @@ def nauty_directg(self, graphs, options="", debug=False): if out: print(out) - for l in out.split('\n'): + for line in out.split('\n'): # directg return graphs in the digraph6 format. # digraph6 is very similar with the dig6 format used in sage : # digraph6_string = '&' + dig6_string # digraph6 specifications: # http://users.cecs.anu.edu.au/~bdm/data/formats.txt - if l and l[0] == '&': - yield DiGraph(l[1:], format='dig6') + if line and line[0] == '&': + yield DiGraph(line[1:], format='dig6') def Complete(self, n, loops=False): r""" @@ -1095,12 +1095,19 @@ def Kautz(self, k, D, vertices='strings'): sage: K = digraphs.Kautz([1,'a','B'], 2) sage: K.edges() - [('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'), ('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'), ('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'), ('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')] + [('1B', 'B1', '1'), ('1B', 'Ba', 'a'), ('1a', 'a1', '1'), + ('1a', 'aB', 'B'), ('B1', '1B', 'B'), ('B1', '1a', 'a'), + ('Ba', 'a1', '1'), ('Ba', 'aB', 'B'), ('a1', '1B', 'B'), + ('a1', '1a', 'a'), ('aB', 'B1', '1'), ('aB', 'Ba', 'a')] sage: K = digraphs.Kautz([1,'aA','BB'], 2) sage: K.edges() - [('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'), ('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'), ('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'), ('BB,aA', 'aA,1', '1'), ('BB,aA', 'aA,BB', 'BB'), ('aA,1', '1,BB', 'BB'), ('aA,1', '1,aA', 'aA'), ('aA,BB', 'BB,1', '1'), ('aA,BB', 'BB,aA', 'aA')] - + [('1,BB', 'BB,1', '1'), ('1,BB', 'BB,aA', 'aA'), + ('1,aA', 'aA,1', '1'), ('1,aA', 'aA,BB', 'BB'), + ('BB,1', '1,BB', 'BB'), ('BB,1', '1,aA', 'aA'), + ('BB,aA', 'aA,1', '1'), ('BB,aA', 'aA,BB', 'BB'), + ('aA,1', '1,BB', 'BB'), ('aA,1', '1,aA', 'aA'), + ('aA,BB', 'BB,1', '1'), ('aA,BB', 'BB,aA', 'aA')] TESTS: From 6409fef1b1020a11ba7bf881cdff48bab1583920 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Jun 2022 14:50:06 +0200 Subject: [PATCH 034/591] trac #34075: cleanup domination.py --- src/sage/graphs/domination.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py index 73d8314b69e..6e2248c7030 100644 --- a/src/sage/graphs/domination.py +++ b/src/sage/graphs/domination.py @@ -66,6 +66,7 @@ from copy import copy from sage.rings.integer import Integer + def is_dominating(G, dom, focus=None): r""" Check whether ``dom`` is a dominating set of ``G``. @@ -101,6 +102,7 @@ def is_dominating(G, dom, focus=None): return not to_dom + def is_redundant(G, dom, focus=None): r""" Check whether ``dom`` has redundant vertices. @@ -166,6 +168,7 @@ def is_redundant(G, dom, focus=None): # with_private != set(dom) return len(with_private) != len(dom) + def private_neighbors(G, vertex, dom): r""" Return the private neighbors of a vertex with respect to other vertices. @@ -361,6 +364,7 @@ def neighbors_iter(x): dom = [v for v in g if b[v]] return Integer(len(dom)) if value_only else dom + # ============================================================================== # Enumeration of minimal dominating set as described in [BDHPR2019]_ # ============================================================================== @@ -593,7 +597,7 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=True): - ``work_on_copy`` -- boolean (default: ``True``); whether or not to work on a copy of the input graph; if set to ``False``, the input graph will be modified (relabeled). - + OUTPUT: An iterator over the inclusion-minimal sets of vertices of ``G``. @@ -785,6 +789,7 @@ def tree_search(H, plng, dom, i): for dom in tree_search(G, peeling, set(), 0): yield {int_to_vertex[v] for v in dom} + # ============================================================================== # Greedy heuristic for dominating set # ============================================================================== From 546e83c8cb84f558b497081e065cc1716db08e0f Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Jun 2022 14:54:41 +0200 Subject: [PATCH 035/591] trac #34075: cleanup dot2tex_utils.py --- src/sage/graphs/dot2tex_utils.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/dot2tex_utils.py b/src/sage/graphs/dot2tex_utils.py index 4568fe2287c..ea9167cbc2e 100644 --- a/src/sage/graphs/dot2tex_utils.py +++ b/src/sage/graphs/dot2tex_utils.py @@ -1,17 +1,18 @@ r""" This file contains some utility functions for the interface with dot2tex """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import re from sage.misc.latex import latex from sage.misc.cachefunc import cached_function + @cached_function def have_dot2tex(): """ @@ -28,7 +29,7 @@ def have_dot2tex(): try: import dot2tex # Test for this required feature from dot2tex 2.8.7 - return dot2tex.dot2tex("graph {}", format = "positions") == {} + return dot2tex.dot2tex("graph {}", format="positions") == {} except (Exception, SystemExit): return False @@ -60,11 +61,12 @@ def assert_have_dot2tex(): import dot2tex except ImportError: print(import_error_string) - raise # re-raise current exception + raise # re-raise current exception else: - if dot2tex.dot2tex("graph {}", format = "positions") != {}: + if dot2tex.dot2tex("graph {}", format="positions") != {}: raise RuntimeError(check_error_string) + def quoted_latex(x): """ Strips the latex representation of ``x`` to make it suitable for a @@ -75,7 +77,8 @@ def quoted_latex(x): sage: sage.graphs.dot2tex_utils.quoted_latex(matrix([[1,1],[0,1],[0,0]])) '\\left(\\begin{array}{rr}1 & 1 \\\\0 & 1 \\\\0 & 0\\end{array}\\right)' """ - return re.sub("\"|\r|(%[^\n]*)?\n","", latex(x)) + return re.sub("\"|\r|(%[^\n]*)?\n", "", latex(x)) + def quoted_str(x): """ @@ -92,4 +95,4 @@ def quoted_str(x): [0 1]\n\ [0 0] """ - return re.sub("\n",r"\\n\\"+"\n", re.sub("\"|\r|}|{","", str(x))) + return re.sub("\n", r"\\n\\"+"\n", re.sub("\"|\r|}|{", "", str(x))) From 65aa3cd6f15ad52643f74e538c7e6bcf6f5d4fcf Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 25 Jun 2022 15:09:51 +0200 Subject: [PATCH 036/591] trac #34075: cleanup graph_latex.py --- src/sage/graphs/graph_latex.py | 64 ++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index d3692c609e1..ed9a573ee08 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -385,15 +385,15 @@ GraphLatex class and functions ------------------------------ """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Robert Beezer # Copyright (C) 2009 Fidel Barrera Cruz # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_function @@ -514,7 +514,7 @@ class GraphLatex(SageObject): 'units': 'cm', 'scale': 1.0, 'graphic_size': (5, 5), - 'margins': (0,0,0,0), + 'margins': (0, 0, 0, 0), 'vertex_color': 'black', 'vertex_colors': {}, 'vertex_fill_color': 'white', @@ -1100,8 +1100,8 @@ def set_option(self, option_name, option_value=None): # formats = ('tkz_graph', 'dot2tex') styles = ('Custom', 'Shade', 'Art', 'Normal', 'Dijkstra', 'Welsh', 'Classic', 'Simple') - unit_names = ('in','mm','cm','pt', 'em', 'ex') - shape_names = ('circle', 'sphere','rectangle', 'diamond') + unit_names = ('in', 'mm', 'cm', 'pt', 'em', 'ex') + shape_names = ('circle', 'sphere', 'rectangle', 'diamond') label_places = ('above', 'below', 'right', 'left') compass_points = ('NO', 'SO', 'EA', 'WE') number_types = (int, Integer, float, RealLiteral) @@ -1109,11 +1109,11 @@ def set_option(self, option_name, option_value=None): # Options with structurally similar tests # boolean_options = ('vertex_labels', 'vertex_labels_math', 'edge_fills', - 'edge_labels', 'edge_labels_math', 'edge_label_sloped') + 'edge_labels', 'edge_labels_math', 'edge_label_sloped') color_options = ('vertex_color', 'vertex_fill_color', 'vertex_label_color', - 'edge_color', 'edge_fill_color', 'edge_label_color') + 'edge_color', 'edge_fill_color', 'edge_label_color') color_dicts = ('vertex_colors', 'vertex_fill_colors', 'vertex_label_colors', - 'edge_colors', 'edge_fill_colors', 'edge_label_colors') + 'edge_colors', 'edge_fill_colors', 'edge_label_colors') boolean_dicts = ('edge_label_slopes',) positive_scalars = ('scale', 'vertex_size', 'edge_thickness') positive_scalar_dicts = ('vertex_sizes', 'edge_thicknesses') @@ -1128,7 +1128,7 @@ def set_option(self, option_name, option_value=None): elif name == 'units' and value not in unit_names: raise ValueError('%s option must be one of: in, mm, cm, pt, em, ex, not %s' % (name, value)) elif name == 'graphic_size' and not(isinstance(value, tuple) and (len(value) == 2)): - raise ValueError( '%s option must be an ordered pair, not %s' % (name, value)) + raise ValueError('%s option must be an ordered pair, not %s' % (name, value)) elif name == 'margins' and not((isinstance(value, tuple)) and (len(value) == 4)): raise ValueError('%s option must be 4-tuple, not %s' % (name, value)) elif name in color_options: @@ -1142,12 +1142,19 @@ def set_option(self, option_name, option_value=None): raise ValueError('%s option must be the shape of a vertex, not %s' % (name, value)) elif name in positive_scalars and not (type(value) in number_types and (value >= 0.0)): raise ValueError('%s option must be a positive number, not %s' % (name, value)) - elif name == 'vertex_label_placement' and not(value == 'center') and not(isinstance(value, tuple) and len(value) == 2 and type(value[0]) in number_types and value[0] >= 0 and type(value[1]) in number_types and value[1] >= 0): + elif (name == 'vertex_label_placement' and value != 'center' and + not (isinstance(value, tuple) and len(value) == 2 and + type(value[0]) in number_types and value[0] >= 0 and + type(value[1]) in number_types and value[1] >= 0)): raise ValueError('%s option must be None, or a pair of positive numbers, not %s' % (name, value)) - elif name == 'edge_label_placement' and not(((type(value) in number_types) and (0 <= value) and (value <= 1)) or (value in label_places)): + elif (name == 'edge_label_placement' and + not ((type(value) in number_types and 0 <= value <= 1) + or value in label_places)): raise ValueError('%s option must be a number between 0.0 and 1.0 or a place (like "above"), not %s' % (name, value)) - elif name == 'loop_placement' and not(isinstance(value, tuple) and (len(value) == 2) and (value[0] >= 0) and (value[1] in compass_points)): - raise ValueError( '%s option must be a pair that is a positive number followed by a compass point abbreviation, not %s' % (name, value)) + elif (name == 'loop_placement' and + not (isinstance(value, tuple) and len(value) == 2 and + value[0] >= 0 and value[1] in compass_points)): + raise ValueError('%s option must be a pair that is a positive number followed by a compass point abbreviation, not %s' % (name, value)) # # Checks/test on dictionaries of values (ie per-vertex or per-edge defaults) # @@ -1186,7 +1193,10 @@ def set_option(self, option_name, option_value=None): raise TypeError('%s option must be a dictionary, not %s' % (name, value)) else: for key, p in value.items(): - if not(p == 'center') and not(isinstance(p, tuple) and len(p) == 2 and type(p[0]) in number_types and p[0] >= 0 and type(p[1]) in number_types and p[1] >= 0): + if (p != 'center' and + not (isinstance(p, tuple) and len(p) == 2 and + type(p[0]) in number_types and p[0] >= 0 and + type(p[1]) in number_types and p[1] >= 0)): raise ValueError('%s option for %s needs to be None or a pair of positive numbers, not %s' % (name, key, p)) elif name == 'edge_label_placements': if not isinstance(value, dict): @@ -1205,8 +1215,8 @@ def set_option(self, option_name, option_value=None): # These have been verified as tuples before going into this next check elif name in positive_tuples: for x in value: - if not type(x) in [int, Integer, float, RealLiteral] or not x >= 0.0: - raise ValueError( '%s option of %s cannot contain %s' % (name, value, x)) + if type(x) not in [int, Integer, float, RealLiteral] or not x >= 0.0: + raise ValueError('%s option of %s cannot contain %s' % (name, value, x)) # # Verified. Set it. self._options[option_name] = option_value @@ -1417,7 +1427,7 @@ def dot2tex_picture(self): if 'edge_colors' in options: edge_colors = options['edge_colors'] new_edge_colors = {} - for edge,col in edge_colors.items(): + for edge, col in edge_colors.items(): if col in new_edge_colors: new_edge_colors[col].append(edge) else: @@ -1708,7 +1718,7 @@ def translate(p): c = dvc if u in vertex_colors: c = cc.to_rgb(vertex_colors[u]) - v_color[ u ] = c + v_color[u] = c # c = dvfc if u in vertex_fill_colors: @@ -1890,19 +1900,19 @@ def translate(p): vertex_fill_color_names = {} vertex_label_color_names = {} for u in vertex_list: - vertex_color_names[ u ] = 'c' + prefix + str(index_of_vertex[ u ]) - s += [r'\definecolor{', vertex_color_names[ u ], '}{rgb}', '{'] + vertex_color_names[u] = 'c' + prefix + str(index_of_vertex[u]) + s += [r'\definecolor{', vertex_color_names[u], '}{rgb}', '{'] s += [str(round(v_color[u][0], 4)), ','] s += [str(round(v_color[u][1], 4)), ','] s += [str(round(v_color[u][2], 4)), '}\n'] - vertex_fill_color_names[ u ] = 'cf' + prefix + str(index_of_vertex[ u ]) - s += [r'\definecolor{', vertex_fill_color_names[ u ], '}{rgb}', '{'] + vertex_fill_color_names[u] = 'cf' + prefix + str(index_of_vertex[u]) + s += [r'\definecolor{', vertex_fill_color_names[u], '}{rgb}', '{'] s += [str(round(vf_color[u][0], 4)), ','] s += [str(round(vf_color[u][1], 4)), ','] s += [str(round(vf_color[u][2], 4)), '}\n'] if vertex_labels: - vertex_label_color_names[u] = 'cl' + prefix + str(index_of_vertex[ u ]) - s += [r'\definecolor{', vertex_label_color_names[ u ], '}{rgb}{'] + vertex_label_color_names[u] = 'cl' + prefix + str(index_of_vertex[u]) + s += [r'\definecolor{', vertex_label_color_names[u], '}{rgb}{'] s += [str(round(vl_color[u][0], 4)), ','] s += [str(round(vl_color[u][1], 4)), ','] s += [str(round(vl_color[u][2], 4)), '}\n'] @@ -1954,7 +1964,7 @@ def translate(p): else: s += ['LabelOut=true,'] s += ['Ldist=', str(round(float(scale * vl_placement[u][0]), 4)), units, ','] - s += ['Lpos=',str(round(float(vl_placement[u][1]), 4)), ','] # degrees, no units + s += ['Lpos=', str(round(float(vl_placement[u][1]), 4)), ','] # degrees, no units else: s += ['NoLabel,'] # vertex label information is available to all pre-built styles @@ -2005,7 +2015,7 @@ def translate(p): s += ['pos=', str(round(float(el_placement[edge]), 4)), ','] # no units needed s += ['text=', edge_label_color_names[edge], ','] s += ['},'] - el = self._graph.edge_label(edge[0],edge[1]) + el = self._graph.edge_label(edge[0], edge[1]) if edge_labels_math and not (isinstance(el, str) and el[0] == '$' and el[-1] == '$'): lab = r'\hbox{$%s$}' % latex(el) else: From 0232e9e7dc8d71f5a2576e770bfa1955fbd0b9b0 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 27 Jun 2022 10:20:08 +0900 Subject: [PATCH 037/591] Add free resolutions --- src/doc/en/reference/index.rst | 12 +- src/doc/en/reference/references/index.rst | 7 +- src/doc/en/reference/resolutions/conf.py | 1 + src/doc/en/reference/resolutions/index.rst | 13 + src/sage/homology/free_resolution.pxd | 3 + src/sage/homology/free_resolution.pyx | 667 +++++++++++++++++++++ src/sage/homology/graded_resolution.pyx | 524 ++++++++++++++++ src/sage/interfaces/singular.py | 62 +- src/sage/libs/singular/decl.pxd | 8 + src/sage/libs/singular/function.pxd | 1 + src/sage/libs/singular/function.pyx | 119 ++-- src/sage/libs/singular/polynomial.pyx | 7 - src/sage/libs/singular/singular.pyx | 7 - 13 files changed, 1308 insertions(+), 123 deletions(-) create mode 120000 src/doc/en/reference/resolutions/conf.py create mode 100644 src/doc/en/reference/resolutions/index.rst create mode 100644 src/sage/homology/free_resolution.pxd create mode 100644 src/sage/homology/free_resolution.pyx create mode 100644 src/sage/homology/graded_resolution.pyx diff --git a/src/doc/en/reference/index.rst b/src/doc/en/reference/index.rst index 065bccac955..9008c78e157 100644 --- a/src/doc/en/reference/index.rst +++ b/src/doc/en/reference/index.rst @@ -92,18 +92,22 @@ Discrete Mathematics * :doc:`Symbolic Logic ` * :doc:`SAT solvers ` -Geometry, Topology, and Homological Algebra -------------------------------------------- +Geometry and Topology +--------------------- * :doc:`Euclidean Spaces and Vector Calculus ` * :doc:`Combinatorial and Discrete Geometry ` -* :doc:`Cell Complexes, Simplicial Complexes, and - Simplicial Sets ` +* :doc:`Cell Complexes, Simplicial Complexes, and Simplicial Sets ` * :doc:`Manifolds and Differential Geometry ` * :doc:`Hyperbolic Geometry ` * :doc:`Parametrized Surfaces ` * :doc:`Knot Theory ` + +Homological Algebra +------------------- + * :doc:`Chain Complexes and their Homology ` +* :doc:`Resolutions ` Number Fields, Function Fields, and Valuations ---------------------------------------------- diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 56a9abee345..2a7650f9869 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -95,7 +95,7 @@ REFERENCES: graphs and isoperimetric inequalities*, The Annals of Probability 32 (2004), no. 3A, 1727-1745. -.. [ASV2020] Federico Ardila, Mariel Supina, and Andrés R. Vindas-Meléndez, +.. [ASV2020] Federico Ardila, Mariel Supina, and Andrés R. Vindas-Meléndez, *The Equivariant Ehrhart Theory of the Permutahedron*, Proc. Amer. Math. Soc. Volume 148, Number 12, 2020, pp. 5091--5107. @@ -4299,6 +4299,9 @@ REFERENCES: polynomials*. Trans. Amer. Math. Soc., 245 (1978), 89-118. +.. [MilStu2005] Ezra Miller and Bernd Sturmfels, *Combinatorial Commutative Algebra*, + GTM Vol. 227, Springer Science & Business Media, 2005. + .. [Mil2004] Victor S. Miller, "The Weil pairing, and its efficient calculation", J. Cryptol., 17(4):235-261, 2004 @@ -5376,7 +5379,7 @@ REFERENCES: .. [St1986] Richard Stanley. *Two poset polytopes*, Discrete Comput. Geom. (1986), :doi:`10.1007/BF02187680` -.. [Stap2011] Alan Stapledon. *Equivariant Ehrhart Theory*. +.. [Stap2011] Alan Stapledon. *Equivariant Ehrhart Theory*. Advances in Mathematics 226 (2011), no. 4, 3622-3654 .. [Sta1973] \H. M. Stark, Class-Numbers of Complex Quadratic diff --git a/src/doc/en/reference/resolutions/conf.py b/src/doc/en/reference/resolutions/conf.py new file mode 120000 index 00000000000..2bdf7e68470 --- /dev/null +++ b/src/doc/en/reference/resolutions/conf.py @@ -0,0 +1 @@ +../conf_sub.py \ No newline at end of file diff --git a/src/doc/en/reference/resolutions/index.rst b/src/doc/en/reference/resolutions/index.rst new file mode 100644 index 00000000000..82f73cb94c8 --- /dev/null +++ b/src/doc/en/reference/resolutions/index.rst @@ -0,0 +1,13 @@ +Resolutions +=========== + +Free and graded resolutions are tools for commutative algebra and algebraic +geometry. + +.. toctree:: + :maxdepth: 2 + + sage/homology/free_resolution + sage/homology/graded_resolution + +.. include:: ../footer.txt diff --git a/src/sage/homology/free_resolution.pxd b/src/sage/homology/free_resolution.pxd new file mode 100644 index 00000000000..4ad023387d8 --- /dev/null +++ b/src/sage/homology/free_resolution.pxd @@ -0,0 +1,3 @@ +from sage.libs.singular.decl cimport * + +cdef singular_monomial_exponents(poly *p, ring *r) diff --git a/src/sage/homology/free_resolution.pyx b/src/sage/homology/free_resolution.pyx new file mode 100644 index 00000000000..be084842b45 --- /dev/null +++ b/src/sage/homology/free_resolution.pyx @@ -0,0 +1,667 @@ +""" +Free resolutions + +The :class:`FreeResolution` implements a finite free resolution, which is a +chain complex of free modules, terminating with a zero module at the end, whose +homology groups are all zero. + +The class is intended to be subclassed for finite free resolutions in different +subject areas. Thus :meth:`_repr_module` may be overrided by a subclass. See +Examples below. + +EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution_generic + sage: S. = PolynomialRing(QQ) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) + sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + +:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + +The :class:`FreeResolution` computes a minimal free resolution of modules +over a multivariate polynomial ring. + +EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + +An example of a minimal free resolution from [CLO2005]_:: + + sage: R. = QQ[] + sage: I = R.ideal([y*z - x*w, y^3 - x^2*z, x*z^2 - y^2*w, z^3 - y*w^2]) + sage: r = FreeResolution(I) + sage: r + S^1 <-- S^4 <-- S^4 <-- S^1 <-- 0 + sage: len(r) + 3 + sage: r.matrix(2) + [-z^2 -x*z y*w -y^2] + [ y 0 -x 0] + [ -w y z x] + [ 0 w 0 z] + +AUTHORS: + +- Kwankyu Lee (2022-05-13): initial version + +""" + +# **************************************************************************** +# Copyright (C) 2022 Kwankyu Lee +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.libs.singular.decl cimport * +from sage.libs.singular.decl cimport ring +from sage.libs.singular.function cimport Resolution, new_sage_polynomial, access_singular_ring +from sage.libs.singular.function import singular_function +from sage.structure.sequence import Sequence, Sequence_generic +from sage.misc.cachefunc import cached_method +from sage.matrix.constructor import matrix as _matrix +from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense +from sage.modules.free_module_element import vector +from sage.modules.free_module import Module_free_ambient +from sage.rings.integer_ring import ZZ +from sage.rings.ideal import Ideal_generic + +from sage.structure.sage_object import SageObject + + +class FreeResolution_generic(SageObject): + """ + Base class of free resolutions. + + INPUT: + + - ``base_ring`` -- a ring + + - ``maps`` -- list of matrices over the base ring + + The matrix at index `i` in the list defines the differential map from + `(i+1)`-th free module to the `i`-th free module over the base ring by + multiplication on the left. The number of matrices in the list is the + length of the resolution. The number of rows and columns of the matrices + define the ranks of the free modules in the resolution. + + Note that the first matrix in the list defines the differential map at + homological index `1`. A subclass can define ``_initial_differential`` + attribute that contains the `0`-th differential map whose codomain is the + target of the free resolution. + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution_generic + sage: S. = PolynomialRing(QQ) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) + sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + + :: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r.differential(0) + Coercion map: + From: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by Submodule of Ambient free module of rank 1 + over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + def __init__(self, base_ring, maps, name='F'): + """ + Initialize. + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution_generic + sage: S. = PolynomialRing(QQ) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) + sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: TestSuite(r).run(skip=['_test_pickling']) + """ + self.__base_ring = base_ring + self.__maps = maps + self.__name = name + self.__length = len(maps) + + def __repr__(self): + """ + Return the string form of this resolution. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + """ + s = self._repr_module(0) + for i in range(1, self.__length + 1): + s += ' <-- ' + self._repr_module(i) + s += ' <-- 0' + return s + + def _repr_module(self, i): + """ + Return the string form of the `i`-th free module. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution_generic + sage: S. = PolynomialRing(QQ) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) + sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: r # indirect doctest + S^1 <-- S^3 <-- S^2 <-- 0 + """ + if i == 0: + r = self.__maps[0].nrows() + s = f'{self.__name}^{r}' + return s + elif i > self.__length: + s = '0' + else: + r = self.__maps[i - 1].ncols() + if r > 0: + s = f'{self.__name}^{r}' + else: + s = '0' + return s + + def __len__(self): + """ + Return the length of this resolution. + + The length of a free resolution is the index of the last nonzero free module. + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: len(r) + 2 + """ + return self.__length + + def __getitem__(self, i): + """ + Return the `i`-th free module of this resolution. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: r.target() + Quotient module by Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + if i < 0: + raise IndexError('invalid index') + elif i > self.__length: + F = (self.__base_ring)**0 + elif i == self.__length: + F = (self.__base_ring)**(self.__maps[i - 1].ncols()) + else: + F = (self.__base_ring)**(self.__maps[i].nrows()) + return F + + def differential(self, i): + """ + Return the matrix representing the `i`-th differential map. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: r.differential(3) + Free module morphism defined by the matrix + [] + Domain: Ambient free module of rank 0 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 2 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + sage: r.differential(2) + Free module morphism defined as left-multiplication by the matrix + [-y x] + [ z -y] + [-w z] + Domain: Ambient free module of rank 2 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 3 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + sage: r.differential(1) + Free module morphism defined as left-multiplication by the matrix + [z^2 - y*w y*z - x*w y^2 - x*z] + Domain: Ambient free module of rank 3 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + sage: r.differential(0) + Coercion map: + From: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + if i < 0: + raise IndexError('invalid index') + elif i == 0: + try: + return self._initial_differential + except AttributeError: + raise ValueError('0th differential map undefined') + elif i == self.__length + 1: + s = (self.__base_ring)**0 + t = (self.__base_ring)**(self.__maps[i - 2].ncols()) + m = s.hom(0, t) + elif i > self.__length + 1: + s = (self.__base_ring)**0 + t = (self.__base_ring)**0 + m = s.hom(0, t) + else: + s = (self.__base_ring)**(self.__maps[i - 1].ncols()) + t = (self.__base_ring)**(self.__maps[i - 1].nrows()) + m = s.hom(self.__maps[i - 1], t, side='right') + return m + + def target(self): + """ + Return the codomain of the 0-th differential map. + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: r.target() + Quotient module by Submodule of Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + return self.differential(0).codomain() + + def matrix(self, i): + """ + Return the matrix representing the `i`-th differential map. + + INPUT: + + - ``i`` -- a positive integer + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: r.matrix(3) + [] + sage: r.matrix(2) + [-y x] + [ z -y] + [-w z] + sage: r.matrix(1) + [z^2 - y*w y*z - x*w y^2 - x*z] + """ + if i <= 0: + raise IndexError(f'invalid index') + elif i <= self.__length: + return self.__maps[i - 1] + else: + return self.differential(i).matrix() + + def chain_complex(self): + """ + Return this resolution as a chain complex. + + A chain complex in Sage has its own useful methods. + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: unicode_art(r.chain_complex()) + ⎛-y x⎞ + ⎜ z -y⎟ + (z^2 - y*w y*z - x*w y^2 - x*z) ⎝-w z⎠ + 0 <── C_0 <────────────────────────────── C_1 <────── C_2 <── 0 + """ + from sage.homology.chain_complex import ChainComplex + mats = {} + for i in range(self.__length, 0, -1): + mats[i] = self.matrix(i) + return ChainComplex(mats, degree_of_differential=-1) + + +class FreeResolution(FreeResolution_generic): + """ + Minimal free resolutions of ideals of multivariate polynomial rings. + + INPUT: + + - ``ideal`` -- a homogeneous ideal of a multi-variate polynomial ring or + a submodule of a free module `M` of rank `n` over `S` + + - ``name`` -- a string; name of the base ring + + - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` + + OUTPUT: a minimal free resolution of the ideal + + The available algorithms and the corresponding Singular commands are shown + below: + + ============= ============================ + algorithm Singular commands + ============= ============================ + ``minimal`` ``mres(ideal)`` + ``shreyer`` ``minres(sres(std(ideal)))`` + ``standard`` ``minres(nres(std(ideal)))`` + ``heuristic`` ``minres(res(std(ideal)))`` + ============= ============================ + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + sage: len(r) + 2 + + :: + + sage: FreeResolution(I, algorithm='minimal') + S^1 <-- S^3 <-- S^2 <-- 0 + sage: FreeResolution(I, algorithm='shreyer') + S^1 <-- S^3 <-- S^2 <-- 0 + sage: FreeResolution(I, algorithm='standard') + S^1 <-- S^3 <-- S^2 <-- 0 + sage: FreeResolution(I, algorithm='heuristic') + S^1 <-- S^3 <-- S^2 <-- 0 + """ + def __init__(self, ideal, name='S', algorithm='heuristic'): + """ + Initialize. + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: TestSuite(r).run(skip=['_test_pickling']) + """ + if isinstance(ideal, Ideal_generic): + S = ideal.ring() + m = ideal + rank = 1 + elif isinstance(ideal, Module_free_ambient): + S = ideal.base_ring() + m = ideal.matrix().transpose() + rank = m.nrows() + elif isinstance(ideal, Matrix_mpolynomial_dense): + S = ideal.base_ring() + m = ideal.transpose() + rank = ideal.ncols() + else: + raise TypeError('no ideal, module, or matrix') + + nvars = S.ngens() + + # This ensures the first component of the Singular resolution to be a + # module, like the later components. This is important when the + # components are converted to Sage modules. + module = singular_function("module") + mod = module(m) + + if algorithm == 'minimal': + mres = singular_function('mres') # syzygy method + r = mres(mod, 0) + elif algorithm == 'shreyer': + std = singular_function('std') + sres = singular_function('sres') # Shreyer method + minres = singular_function('minres') + r = minres(sres(std(mod), 0)) + elif algorithm == 'standard': + nres = singular_function('nres') # standard basis method + minres = singular_function('minres') + r = minres(nres(mod, 0)) + elif algorithm == 'heuristic': + std = singular_function('std') + res = singular_function('res') # heuristic method + minres = singular_function('minres') + r = minres(res(std(mod), 0)) + + res_mats = to_sage_resolution(r) + + super().__init__(S, res_mats, name=name) + + self._ideal = ideal + self._name = name + + @property + @cached_method + def _initial_differential(self): + """ + Defines the `0`-th differential map of this resolution. + + EXAMPLES:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r._initial_differential + Coercion map: + From: Ambient free module of rank 1 over the integral domain + Multivariate Polynomial Ring in x, y, z, w over Rational Field + To: Quotient module by Submodule of Ambient free module of rank 1 + over the integral domain Multivariate Polynomial Ring in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [-z^2 + y*w] + [ y*z - x*w] + [-y^2 + x*z] + """ + ideal = self._ideal + if isinstance(ideal, Ideal_generic): + S = ideal.ring() + M = S**1 + N = M.submodule([vector([g]) for g in ideal.gens()]) + elif isinstance(ideal, Module_free_ambient): + S = ideal.base_ring() + M = ideal.ambient_module() + N = ideal + elif isinstance(ideal, Matrix_mpolynomial_dense): + S = ideal.base_ring() + N = ideal.row_space() + M = N.ambient_module() + Q = M.quotient(N) + return Q.coerce_map_from(M) + + +cdef singular_monomial_exponents(poly *p, ring *r): + """ + Return the list of exponents of monomial ``p``. + """ + cdef int v + cdef list ml = list() + + for v in range(1, r.N + 1): + ml.append(p_GetExp(p, v, r)) + return ml + +cdef to_sage_resolution(Resolution res): + """ + Pull the data from Singular resolution ``res`` to construct a Sage + resolution. + + INPUT: + + - ``res`` -- Singular resolution + + The procedure is destructive, and ``res`` is not usable afterward. + """ + cdef ring *singular_ring + cdef syStrategy singular_res + cdef poly *p + cdef poly *p_iter + cdef poly *first + cdef poly *previous + cdef poly *acc + cdef resolvente mods + cdef ideal *mod + cdef int i, j, k, idx, rank, nrows, ncols + cdef bint zero_mat + + singular_res = res._resolution[0] + sage_ring = res.base_ring + singular_ring = access_singular_ring(res.base_ring) + + if singular_res.minres != NULL: + mods = singular_res.minres + elif singular_res.fullres != NULL: + mods = singular_res.fullres + else: + raise ValueError('Singular resolution is not usable') + + res_mats = [] + + # length is the length of fullres. The length of minres + # can be shorter. Hence we avoid SEGFAULT by stopping + # at NULL pointer. + for idx in range(singular_res.length): + mod = mods[idx] + if mod == NULL: + break + rank = mod.rank + free_module = sage_ring ** rank + + nrows = rank + ncols = mod.ncols # IDELEMS(mod) + + mat = _matrix(sage_ring, nrows, ncols) + matdegs = [] + zero_mat = True + for j in range(ncols): + p = mod.m[j] + degs = [] + # code below copied and modified from to_sage_vector_destructive + # in sage.libs.singular.function.Converter + for i in range(1, rank + 1): + previous = NULL + acc = NULL + first = NULL + p_iter = p + while p_iter != NULL: + if p_GetComp(p_iter, singular_ring) == i: + p_SetComp(p_iter, 0, singular_ring) + p_Setm(p_iter, singular_ring) + if acc == NULL: + first = p_iter + else: + acc.next = p_iter + acc = p_iter + if p_iter == p: + p = pNext(p_iter) + if previous != NULL: + previous.next = pNext(p_iter) + p_iter = pNext(p_iter) + acc.next = NULL + else: + previous = p_iter + p_iter = pNext(p_iter) + + if zero_mat: + zero_mat = first == NULL + + mat[i - 1, j] = new_sage_polynomial(sage_ring, first) + + # Singular sometimes leaves zero matrix in the resolution. We can stop + # when one is seen. + if zero_mat: + break + + res_mats.append(mat) + + return res_mats diff --git a/src/sage/homology/graded_resolution.pyx b/src/sage/homology/graded_resolution.pyx new file mode 100644 index 00000000000..03620cdb195 --- /dev/null +++ b/src/sage/homology/graded_resolution.pyx @@ -0,0 +1,524 @@ +r""" +Graded free resolutions + +This module defines :class:`GradedFreeResolution` which computes a +graded free resolution of a homogeneous ideal `I` of a graded multivariate +polynomial ring `S`, or a homogeneous submodule of a graded free module `M` +over `S`. The output resolution is always minimal. + +The degrees given to the variables of `S` are integers or integer vectors of +the same length. In the latter case, `S` is said to be multigraded, and the +resolution is a multigraded free resolution. The standard grading where all +variables have degree `1` is used if the degrees are not specified. + +A summand of the graded free module `M` is a shifted (or twisted) module of +rank one over `S`, denoted `S(-d)` with shift `d`. + +The computation of the resolution is done by the libSingular behind. Different +Singular algorithms can be chosen for best performance. + +EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I, algorithm='minimal') + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: GradedFreeResolution(I, algorithm='shreyer') + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: GradedFreeResolution(I, algorithm='standard') + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: GradedFreeResolution(I, algorithm='heuristic') + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + +:: + + sage: d = r.differential(2) + sage: d + Free module morphism defined as left-multiplication by the matrix + [ y x] + [-z -y] + [ w z] + Domain: Ambient free module of rank 2 over the integral domain Multivariate Polynomial Ring + in x, y, z, w over Rational Field + Codomain: Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring + in x, y, z, w over Rational Field + sage: d.image() + Submodule of Ambient free module of rank 3 over the integral domain Multivariate Polynomial Ring + in x, y, z, w over Rational Field + Generated by the rows of the matrix: + [ y -z w] + [ x -y z] + sage: m = d.image() + sage: GradedFreeResolution(m, shifts=(2,2,2)) + S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + +An example of multigraded resolution from Example 9.1 of [MilStu2005]_:: + + sage: R. = QQ[] + sage: S. = QQ[] + sage: phi = S.hom([s, s*t, s*t^2, s*t^3]) + sage: I = phi.kernel(); I + Ideal (c^2 - b*d, b*c - a*d, b^2 - a*c) of Multivariate Polynomial Ring in a, b, c, d over Rational Field + sage: P3 = ProjectiveSpace(S) + sage: C = P3.subscheme(I) # twisted cubic curve + sage: r = GradedFreeResolution(I, degrees=[(1,0), (1,1), (1,2), (1,3)]) + sage: r + S(0) <-- S(-(2, 4))⊕S(-(2, 3))⊕S(-(2, 2)) <-- S(-(3, 5))⊕S(-(3, 4)) <-- 0 + sage: r.K_polynomial(names='s,t') + s^3*t^5 + s^3*t^4 - s^2*t^4 - s^2*t^3 - s^2*t^2 + 1 + +AUTHORS: + +- Kwankyu Lee (2022-05): initial version + +""" + +# **************************************************************************** +# Copyright (C) 2022 Kwankyu Lee +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.libs.singular.decl cimport * +from sage.libs.singular.decl cimport ring +from sage.libs.singular.function cimport Resolution, new_sage_polynomial, access_singular_ring +from sage.libs.singular.function import singular_function +from sage.structure.sequence import Sequence, Sequence_generic +from sage.misc.cachefunc import cached_method +from sage.matrix.constructor import matrix as _matrix +from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense +from sage.modules.free_module_element import vector +from sage.modules.free_module import Module_free_ambient +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing +from sage.rings.ideal import Ideal_generic + +from sage.homology.free_resolution import FreeResolution +from sage.homology.free_resolution cimport singular_monomial_exponents + + +class GradedFreeResolution(FreeResolution): + """ + Graded free resolutions of ideals of multi-variate polynomial rings. + + INPUT: + + - ``ideal`` -- a homogeneous ideal of a multivariate polynomial ring `S`, or + a homogeneous submodule of a free module `M` of rank `n` over `S` + + - ``degree`` -- a list of integers or integer vectors giving degrees of + variables of `S`; this is a list of 1s by default + + - ``shifts`` -- a list of integers or integer vectors giving shifts of + degrees of `n` summands of the free module `M`; this is a list of zero + degrees of length `n` by default + + - ``name`` -- a string; name of the base ring + + - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` + + If ``ideal`` is an ideal of `S`, then `M = S`, a free module of rank `1` + over `S`. + + OUTPUT: a graded minimal free resolution of ``ideal`` + + The available algorithms and the corresponding Singular commands are shown + below: + + ============= ============================ + algorithm Singular commands + ============= ============================ + ``minimal`` ``mres(ideal)`` + ``shreyer`` ``minres(sres(std(ideal)))`` + ``standard`` ``minres(nres(std(ideal)))`` + ``heuristic`` ``minres(res(std(ideal)))`` + ============= ============================ + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r + S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 + sage: len(r) + 2 + """ + def __init__(self, ideal, degrees=None, shifts=None, name='S', algorithm='heuristic'): + """ + Initialize. + + TESTS:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: TestSuite(r).run(skip=['_test_pickling']) + """ + cdef int i, j, k, ncols, nrows + cdef list res_shifts, prev_shifts, new_shifts + + if isinstance(ideal, Ideal_generic): + S = ideal.ring() + m = ideal + rank = 1 + elif isinstance(ideal, Module_free_ambient): + S = ideal.base_ring() + m = ideal.matrix().transpose() + rank = m.nrows() + elif isinstance(ideal, Matrix_mpolynomial_dense): + S = ideal.base_ring() + m = ideal.transpose() + rank = ideal.ncols() + else: + raise TypeError('no ideal, module, or matrix') + + nvars = S.ngens() + + if degrees is None: + degrees = nvars*[1] # standard grading + + if len(degrees) != nvars: + raise ValueError('the length of degrees does not match the number of generators') + + if degrees[0] in ZZ: + zero_deg = 0 + multigrade = False + else: # degrees are integer vectors + degrees = [vector(v) for v in degrees] + zero_deg = degrees[0].parent().zero() + multigrade = True + + # This ensures the first component of the Singular resolution to be a + # module, like the later components. This is important when the + # components are converted to Sage modules. + module = singular_function("module") + mod = module(m) + + if shifts is None: + shifts = rank*[zero_deg] + + if algorithm == 'minimal': + mres = singular_function('mres') # syzygy method + r = mres(mod, 0) + elif algorithm == 'shreyer': + std = singular_function('std') + sres = singular_function('sres') # Shreyer method + minres = singular_function('minres') + r = minres(sres(std(mod), 0)) + elif algorithm == 'standard': + nres = singular_function('nres') # standard basis method + minres = singular_function('minres') + r = minres(nres(mod, 0)) + elif algorithm == 'heuristic': + std = singular_function('std') + res = singular_function('res') # heuristic method + minres = singular_function('minres') + r = minres(res(std(mod), 0)) + + res_mats, res_degs = to_sage_resolution_graded(r, degrees) + + # compute shifts of free modules in the resolution + res_shifts = [] + prev_shifts = list(shifts) + for k in range(len(res_degs)): + new_shifts = [] + degs = res_degs[k] + ncols = len(degs) + for j in range(ncols): + col = degs[j] + nrows = len(col) + # should be enough to compute the new shifts + # from any one entry of the column vector + for i in range(nrows): + d = col[i] + if d is not None: + e = prev_shifts[i] + new_shifts.append(d + e) + break + res_shifts.append(new_shifts) + prev_shifts = new_shifts + + super(FreeResolution, self).__init__(S, res_mats, name=name) + + self._ideal = ideal + self._shifts = shifts + self._degrees = degrees + self._res_shifts = res_shifts + self._multigrade = multigrade + self._zero_deg = zero_deg + self._name = name + + def _repr_module(self, i): + """ + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r._repr_module(0) + 'S(0)' + sage: r._repr_module(1) + 'S(-2)⊕S(-2)⊕S(-2)' + sage: r._repr_module(2) + 'S(-3)⊕S(-3)' + sage: r._repr_module(3) + '0' + """ + if i > len(self): + m = '0' + else: + if i == 0: + shifts = self._shifts + else: + shifts = self._res_shifts[i - 1] + + if len(shifts) > 0: + for j in range(len(shifts)): + shift = shifts[j] + if j == 0: + m = f'{self._name}' + \ + (f'(-{shift})' if shift != self._zero_deg else '(0)') + else: + m += f'\u2295{self._name}' + \ + (f'(-{shift})' if shift != self._zero_deg else '(0)') + else: + m = '0' + return m + + def shifts(self, i): + """ + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r.shifts(0) + [0] + sage: r.shifts(1) + [2, 2, 2] + sage: r.shifts(2) + [3, 3] + sage: r.shifts(3) + [] + """ + if i < 0: + raise IndexError('invalid index') + elif i == 0: + shifts = self._shifts + elif i > len(self): + shifts = [] + else: + shifts = self._res_shifts[i - 1] + + return shifts + + def betti(self, i, a=None): + """ + Return the `i`-th Betti number in degree `a`. + + INPUT: + + - ``i`` -- nonnegative integer + + - ``a`` -- a degree; if ``None``, return Betti numbers in all degrees + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r.betti(0) + {0: 1} + sage: r.betti(1) + {2: 3} + sage: r.betti(2) + {3: 2} + sage: r.betti(1, 0) + 0 + sage: r.betti(1, 1) + 0 + sage: r.betti(1, 2) + 3 + """ + shifts = self.shifts(i) + + if a is None: + degrees = shifts + else: + degrees = [a] + + betti = {} + for s in degrees: + betti[s] = len([d for d in shifts if d == s]) + + if a is None: + return betti + else: + return betti[a] if a in betti else 0 + + def K_polynomial(self, names=None): + """ + Return the K-polynomial of this resolution. + + INPUT: + + - ``names`` -- a string of names of the variables of the K-polynomial + + EXAMPLES:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r.K_polynomial() + 2*t^3 - 3*t^2 + 1 + """ + if self._multigrade: + n = self._degrees[0].degree() + else: + n = 1 + + if names is not None: + L = LaurentPolynomialRing(ZZ, names=names) + else: + L = LaurentPolynomialRing(ZZ, 't', n) + + kpoly = 1 + sign = -1 + for j in range(len(self)): + for v in self._res_shifts[j]: + if self._multigrade: + kpoly += sign * L.monomial(*list(v)) + else: + kpoly += sign * L.monomial(v) + sign = -sign + + return kpoly + + +cdef to_sage_resolution_graded(Resolution res, degrees): + """ + Pull the data from Singular resolution ``res`` to construct a Sage + resolution. + + INPUT: + + - ``res`` -- Singular resolution + + - ``degrees`` -- list of integers or integer vectors + + The procedure is destructive, and ``res`` is not usable afterward. + """ + cdef ring *singular_ring + cdef syStrategy singular_res + cdef poly *p + cdef poly *p_iter + cdef poly *first + cdef poly *previous + cdef poly *acc + cdef resolvente mods + cdef ideal *mod + cdef int i, j, k, idx, rank, nrows, ncols + cdef int ngens = len(degrees) + cdef bint zero_mat + + singular_res = res._resolution[0] + sage_ring = res.base_ring + singular_ring = access_singular_ring(res.base_ring) + + if singular_res.minres != NULL: + mods = singular_res.minres + elif singular_res.fullres != NULL: + mods = singular_res.fullres + else: + raise ValueError('Singular resolution is not usable') + + res_mats = [] + res_degs = [] + + # length is the length of fullres. The length of minres + # can be shorter. Hence we avoid SEGFAULT by stopping + # at NULL pointer. + for idx in range(singular_res.length): + mod = mods[idx] + if mod == NULL: + break + rank = mod.rank + free_module = sage_ring ** rank + + nrows = rank + ncols = mod.ncols # IDELEMS(mod) + + mat = _matrix(sage_ring, nrows, ncols) + matdegs = [] + zero_mat = True + for j in range(ncols): + p = mod.m[j] + degs = [] + # code below copied and modified from to_sage_vector_destructive + # in sage.libs.singular.function.Converter + for i in range(1, rank + 1): + previous = NULL + acc = NULL + first = NULL + p_iter = p + while p_iter != NULL: + if p_GetComp(p_iter, singular_ring) == i: + p_SetComp(p_iter, 0, singular_ring) + p_Setm(p_iter, singular_ring) + if acc == NULL: + first = p_iter + else: + acc.next = p_iter + acc = p_iter + if p_iter == p: + p = pNext(p_iter) + if previous != NULL: + previous.next = pNext(p_iter) + p_iter = pNext(p_iter) + acc.next = NULL + else: + previous = p_iter + p_iter = pNext(p_iter) + + if zero_mat: + zero_mat = first == NULL + + mat[i - 1, j] = new_sage_polynomial(sage_ring, first) + + # degree of a homogeneous polynomial can be computed from the + # first monomial + if first != NULL: + exps = singular_monomial_exponents(first, singular_ring) + deg = 0 + for k in range(ngens): + deg += exps[k] * degrees[k] + degs.append(deg) + else: + degs.append(None) + + matdegs.append(degs) # store degrees of the column + + # Singular sometimes leaves zero matrix in the resolution. We can stop + # when one is seen. + if zero_mat: + break + + res_mats.append(mat) + res_degs.append(matdegs) + + return res_mats, res_degs + + diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 41e9c9ff251..1975ffae5fe 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -1,31 +1,6 @@ r""" Interface to Singular -AUTHORS: - -- David Joyner and William Stein (2005): first version - -- Martin Albrecht (2006-03-05): code so singular.[tab] and x = - singular(...), x.[tab] includes all singular commands. - -- Martin Albrecht (2006-03-06): This patch adds the equality symbol to - singular. Also fix a problem in which " " as prompt means comparison - will break all further communication with Singular. - -- Martin Albrecht (2006-03-13): added current_ring() and - current_ring_name() - -- William Stein (2006-04-10): Fixed problems with ideal constructor - -- Martin Albrecht (2006-05-18): added sage_poly. - -- Simon King (2010-11-23): Reduce the overhead caused by waiting for - the Singular prompt by doing garbage collection differently. - -- Simon King (2011-06-06): Make conversion from Singular to Sage more flexible. - -- Simon King (2015): Extend pickling capabilities. - Introduction ------------ @@ -37,7 +12,6 @@ your computer; this should be the case, since Singular is included with Sage. The interface offers three pieces of functionality: - #. ``singular_console()`` - A function that dumps you into an interactive command-line Singular session. @@ -238,10 +212,6 @@ An Important Concept -------------------- -AUTHORS: - -- Neal Harris - The following illustrates an important concept: how Sage interacts with the data being used and returned by Singular. Let's compute a Groebner basis for some ideal, using Singular through Sage. @@ -325,6 +295,34 @@ [Ideal (z) of Multivariate Polynomial Ring in x, z over Number Field in p with defining polynomial p^2 - p - 1] sage: [ J.gens() for J in I.primary_decomposition("gtz")] [[z]] + +AUTHORS: + +- David Joyner and William Stein (2005): first version + +- Neal Harris (unknown): perhaps added "An Important Concept" + +- Martin Albrecht (2006-03-05): code so singular.[tab] and x = + singular(...), x.[tab] includes all singular commands. + +- Martin Albrecht (2006-03-06): This patch adds the equality symbol to + singular. Also fix a problem in which " " as prompt means comparison + will break all further communication with Singular. + +- Martin Albrecht (2006-03-13): added current_ring() and + current_ring_name() + +- William Stein (2006-04-10): Fixed problems with ideal constructor + +- Martin Albrecht (2006-05-18): added sage_poly. + +- Simon King (2010-11-23): Reduce the overhead caused by waiting for + the Singular prompt by doing garbage collection differently. + +- Simon King (2011-06-06): Make conversion from Singular to Sage more flexible. + +- Simon King (2015): Extend pickling capabilities. + """ # **************************************************************************** @@ -1496,8 +1494,6 @@ def __bool__(self): P = self.parent() return P.eval('%s == 0' % self.name()) == '0' - - def sage_polystring(self): r""" If this Singular element is a polynomial, return a string @@ -2069,7 +2065,6 @@ def set_ring(self): """ self.parent().set_ring(self) - def sage_flattened_str_list(self): """ EXAMPLES:: @@ -2596,6 +2591,7 @@ def flush(self): """ sys.stdout.flush() + class SingularGBDefaultContext: """ Within this context all Singular Groebner basis calculations are diff --git a/src/sage/libs/singular/decl.pxd b/src/sage/libs/singular/decl.pxd index d6b2f28bf2a..8e3ac314b67 100644 --- a/src/sage/libs/singular/decl.pxd +++ b/src/sage/libs/singular/decl.pxd @@ -1134,8 +1134,16 @@ cdef extern from "singular/kernel/GBEngine/kstd1.h": cdef extern int Kstd1_deg # degBound, default 0 cdef extern int Kstd1_mu # multBound, default 0 +cdef extern from "singular/kernel/ideals.h": + ctypedef ideal * resolvente + cdef extern from "singular/kernel/GBEngine/syz.h": ctypedef struct syStrategy "ssyStrategy": + resolvente fullres; + resolvente minres; + int length; + int regularity; + short list_length; short references cdef extern from "singular/polys/ext_fields/transext.h": diff --git a/src/sage/libs/singular/function.pxd b/src/sage/libs/singular/function.pxd index 232bf198538..503384004d5 100644 --- a/src/sage/libs/singular/function.pxd +++ b/src/sage/libs/singular/function.pxd @@ -19,6 +19,7 @@ from sage.libs.singular.decl cimport leftv, idhdl, syStrategy, matrix, poly, ide from sage.libs.singular.decl cimport ring as singular_ring from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular, MPolynomial_libsingular +cdef new_sage_polynomial(ring, poly *p) cdef poly* access_singular_poly(p) except -1 cdef singular_ring* access_singular_ring(r) except -1 diff --git a/src/sage/libs/singular/function.pyx b/src/sage/libs/singular/function.pyx index 698cc81f2ad..3ecbeb4ff2a 100644 --- a/src/sage/libs/singular/function.pyx +++ b/src/sage/libs/singular/function.pyx @@ -7,16 +7,6 @@ or interprocess communication overhead. Users who do not want to call Singular functions directly, usually do not have to worry about this interface, since it is handled by higher level functions in Sage. -AUTHORS: - -- Michael Brickenstein (2009-07): initial implementation, overall design -- Martin Albrecht (2009-07): clean up, enhancements, etc. -- Michael Brickenstein (2009-10): extension to more Singular types -- Martin Albrecht (2010-01): clean up, support for attributes -- Simon King (2011-04): include the documentation provided by Singular as a code block. -- Burcin Erocal, Michael Brickenstein, Oleksandr Motsak, Alexander Dreyer, Simon King - (2011-09) plural support - EXAMPLES: The direct approach for loading a Singular function is to call the @@ -62,6 +52,21 @@ TESTS:: sage: std = singular_function('std') sage: loads(dumps(std)) == std True + +AUTHORS: + +- Michael Brickenstein (2009-07): initial implementation, overall design + +- Martin Albrecht (2009-07): clean up, enhancements, etc + +- Michael Brickenstein (2009-10): extension to more Singular types + +- Martin Albrecht (2010-01): clean up, support for attributes + +- Simon King (2011-04): include the documentation provided by Singular as a code block + +- Burcin Erocal, Michael Brickenstein, Oleksandr Motsak, Alexander Dreyer, Simon King (2011-09): plural support + """ #***************************************************************************** @@ -82,36 +87,29 @@ from sage.cpython.string cimport str_to_bytes, char_to_str from sage.structure.sage_object cimport SageObject from sage.structure.richcmp cimport richcmp - -from sage.rings.integer cimport Integer +from sage.structure.sequence import Sequence, Sequence_generic from sage.modules.free_module_element cimport FreeModuleElement_generic_dense +from sage.rings.integer cimport Integer from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular, new_MP from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular - from sage.rings.polynomial.plural cimport NCPolynomialRing_plural, NCPolynomial_plural, new_NCP from sage.rings.polynomial.multi_polynomial_ideal import NCPolynomialIdeal - from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal - from sage.rings.polynomial.multi_polynomial_ideal_libsingular cimport sage_ideal_to_singular_ideal, singular_ideal_to_sage_sequence +from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence, PolynomialSequence_generic from sage.libs.singular.decl cimport * - from sage.libs.singular.option import opt_ctx from sage.libs.singular.polynomial cimport singular_vector_maximal_component, singular_polynomial_check from sage.libs.singular.singular cimport sa2si, si2sa, si2sa_intvec - from sage.libs.singular.singular import error_messages from sage.interfaces.singular import get_docstring from sage.misc.verbose import get_verbose -from sage.structure.sequence import Sequence, Sequence_generic -from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence, PolynomialSequence_generic - cdef poly* sage_vector_to_poly(v, ring *r) except -1: """ @@ -156,7 +154,7 @@ cdef class RingWrap: return "" def __dealloc__(self): - if self._ring!=NULL: + if self._ring != NULL: self._ring.ref -= 1 def ngens(self): @@ -292,6 +290,7 @@ cdef class RingWrap: """ rPrint(self._ring) + cdef class Resolution: """ A simple wrapper around Singular's resolutions. @@ -308,9 +307,10 @@ cdef class Resolution: sage: M = syz(I) sage: resolution = mres(M, 0) """ - #FIXME: still not working noncommutative + # FIXME: still not working noncommutative assert is_sage_wrapper_for_singular_ring(base_ring) self.base_ring = base_ring + def __repr__(self): """ EXAMPLES:: @@ -326,6 +326,7 @@ cdef class Resolution: """ return "" + def __dealloc__(self): """ EXAMPLES:: @@ -342,6 +343,7 @@ cdef class Resolution: if self._resolution != NULL: self._resolution.references -= 1 + cdef leftv* new_leftv(void *data, res_type): """ INPUT: @@ -487,6 +489,7 @@ def all_vectors(s): return False return True + cdef class Converter(SageObject): """ A :class:`Converter` interfaces between Sage objects and Singular @@ -686,8 +689,6 @@ cdef class Converter(SageObject): Convert singular matrix to matrix over the polynomial ring. """ from sage.matrix.constructor import Matrix - #cdef ring *singular_ring = (\ - # self._sage_ring)._ring ncols = mat.ncols nrows = mat.nrows result = Matrix(self._sage_ring, nrows, ncols) @@ -699,7 +700,6 @@ cdef class Converter(SageObject): return result cdef to_sage_vector_destructive(self, poly *p, free_module = None): - #cdef ring *r=self._ring._ring cdef int rank if free_module: rank = free_module.rank() @@ -716,20 +716,20 @@ cdef class Converter(SageObject): previous = NULL acc = NULL first = NULL - p_iter=p + p_iter = p while p_iter != NULL: if p_GetComp(p_iter, self._singular_ring) == i: - p_SetComp(p_iter,0, self._singular_ring) + p_SetComp(p_iter, 0, self._singular_ring) p_Setm(p_iter, self._singular_ring) if acc == NULL: first = p_iter else: acc.next = p_iter acc = p_iter - if p_iter==p: - p=pNext(p_iter) + if p_iter == p: + p = pNext(p_iter) if previous != NULL: - previous.next=pNext(p_iter) + previous.next = pNext(p_iter) p_iter = pNext(p_iter) acc.next = NULL else: @@ -750,7 +750,6 @@ cdef class Converter(SageObject): - ``r`` -- a SINGULAR ring - ``sage_ring`` -- a Sage ring matching r """ - #cdef MPolynomialRing_libsingular sage_ring = self._ring cdef int j cdef int rank=i.rank free_module = self._sage_ring ** rank @@ -758,12 +757,11 @@ cdef class Converter(SageObject): for j from 0 <= j < IDELEMS(i): p = self.to_sage_vector_destructive(i.m[j], free_module) - i.m[j]=NULL#save it from getting freed + i.m[j]=NULL # save it from getting freed l.append( p ) return Sequence(l, check=False, immutable=True) - cdef to_sage_integer_matrix(self, intvec* mat): """ Convert Singular matrix to matrix over the polynomial ring. @@ -780,7 +778,6 @@ cdef class Converter(SageObject): result[i,j] = mat.get(i*ncols+j) return result - cdef leftv *append_polynomial(self, p) except NULL: """ Append the polynomial ``p`` to the list. @@ -808,8 +805,6 @@ cdef class Converter(SageObject): cdef ideal *i cdef int j = 0 - - i = idInit(len(m),rank) for f in m: i.m[j] = sage_vector_to_poly(f, r) @@ -832,7 +827,6 @@ cdef class Converter(SageObject): return self._append(_r, RING_CMD) cdef leftv *append_matrix(self, mat) except NULL: - sage_ring = mat.base_ring() cdef ring *r= access_singular_ring(sage_ring) @@ -854,8 +848,6 @@ cdef class Converter(SageObject): cdef long _n = n return self._append(_n, INT_CMD) - - cdef leftv *append_list(self, l) except NULL: """ Append the list ``l`` to the list. @@ -948,31 +940,26 @@ cdef class Converter(SageObject): sage: sing_genus(I) # known bug -2 """ - #FIXME + # FIXME cdef MPolynomial_libsingular res_poly cdef int rtyp = to_convert.rtyp cdef lists *singular_list cdef Resolution res_resolution + if rtyp == IDEAL_CMD: return singular_ideal_to_sage_sequence(to_convert.data, self._singular_ring, self._sage_ring) - elif rtyp == POLY_CMD: - #FIXME + # FIXME res_poly = MPolynomial_libsingular(self._sage_ring) res_poly._poly = to_convert.data - to_convert.data = NULL - #prevent it getting free, when cleaning the leftv + to_convert.data = NULL # prevent it getting free, when cleaning the leftv return res_poly - elif rtyp == INT_CMD: return to_convert.data - elif rtyp == NUMBER_CMD: return si2sa(to_convert.data, self._singular_ring, self._sage_ring.base_ring()) - elif rtyp == INTVEC_CMD: - return si2sa_intvec(to_convert.data) - + return si2sa_intvec( to_convert.data) elif rtyp == STRING_CMD: # TODO: Need to determine what kind of data can be returned by a # STRING_CMD--is it just ASCII strings or can it be an arbitrary @@ -980,38 +967,26 @@ cdef class Converter(SageObject): ret = char_to_str(to_convert.data) return ret elif rtyp == VECTOR_CMD: - result = self.to_sage_vector_destructive( - to_convert.data) + result = self.to_sage_vector_destructive( to_convert.data) to_convert.data = NULL return result - - elif rtyp == RING_CMD or rtyp==QRING_CMD: return new_RingWrap( to_convert.data ) - elif rtyp == MATRIX_CMD: - return self.to_sage_matrix( to_convert.data ) - + return self.to_sage_matrix( to_convert.data ) elif rtyp == LIST_CMD: singular_list = to_convert.data ret = [] for i in xrange(singular_list.nr+1): - ret.append( - self.to_python( - &(singular_list.m[i]))) + ret.append(self.to_python(&(singular_list.m[i]))) return ret - - elif rtyp == MODUL_CMD: - return self.to_sage_module_element_sequence_destructive( - to_convert.data - ) + return self.to_sage_module_element_sequence_destructive( to_convert.data) elif rtyp == INTMAT_CMD: - return self.to_sage_integer_matrix( - to_convert.data) + return self.to_sage_integer_matrix( to_convert.data) elif rtyp == RESOLUTION_CMD: res_resolution = Resolution(self._sage_ring) - res_resolution._resolution = to_convert.data + res_resolution._resolution = to_convert.data res_resolution._resolution.references += 1 return res_resolution elif rtyp == NONE: @@ -1019,6 +994,7 @@ cdef class Converter(SageObject): else: raise NotImplementedError("rtyp %d not implemented."%(rtyp)) + cdef class BaseCallHandler: """ A call handler is an abstraction which hides the details of the @@ -1036,6 +1012,7 @@ cdef class BaseCallHandler: """ return False + cdef class LibraryCallHandler(BaseCallHandler): """ A call handler is an abstraction which hides the details of the @@ -1077,6 +1054,7 @@ cdef class LibraryCallHandler(BaseCallHandler): """ return False + cdef class KernelCallHandler(BaseCallHandler): """ A call handler is an abstraction which hides the details of the @@ -1163,9 +1141,11 @@ cdef class KernelCallHandler(BaseCallHandler): """ return True + # The Sage ring used as a dummy for singular function calls. cdef object dummy_ring + cdef class SingularFunction(SageObject): """ The base class for Singular functions either from the kernel or @@ -1540,6 +1520,7 @@ cdef inline call_function(SingularFunction self, tuple args, object R, bint sign return res + cdef class SingularLibraryFunction(SingularFunction): """ EXAMPLES:: @@ -1582,6 +1563,7 @@ cdef class SingularLibraryFunction(SingularFunction): cdef idhdl* singular_idhdl = ggetid(str_to_bytes(self._name)) return singular_idhdl!=NULL + cdef class SingularKernelFunction(SingularFunction): """ EXAMPLES:: @@ -1848,7 +1830,6 @@ def lib(name): if failure: raise NameError("Singular library {!r} not found".format(name)) - def list_of_functions(packages=False): """ Return a list of all function names currently available. @@ -1879,7 +1860,6 @@ def list_of_functions(packages=False): h = IDNEXT(h) return l - cdef inline RingWrap new_RingWrap(ring* r): cdef RingWrap ring_wrap_result = RingWrap.__new__(RingWrap) ring_wrap_result._ring = r @@ -1887,7 +1867,6 @@ cdef inline RingWrap new_RingWrap(ring* r): return ring_wrap_result - # Add support for _instancedoc_ from sage.misc.instancedoc import instancedoc instancedoc(SingularFunction) diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index fc6d8113d61..e012da4573c 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -25,7 +25,6 @@ import re plusminus_pattern = re.compile("([^\(^])([\+\-])") parenthvar_pattern = re.compile(r"\(([a-zA-Z][a-zA-Z0-9]*)\)") - from sage.cpython.string cimport bytes_to_str, str_to_bytes from sage.libs.singular.decl cimport number, ideal @@ -38,7 +37,6 @@ from sage.libs.singular.decl cimport p_GetComp, p_SetComp from sage.libs.singular.decl cimport pSubst from sage.libs.singular.decl cimport p_Normalize - from sage.libs.singular.singular cimport sa2si, si2sa, overflow_check from sage.misc.latex import latex @@ -80,7 +78,6 @@ cdef int singular_polynomial_add(poly **ret, poly *p, poly *q, ring *r): ret[0] = p_Add_q(p, q, r) return 0 - cdef int singular_polynomial_sub(poly **ret, poly *p, poly *q, ring *r): """ ``ret[0] = p-q`` where ``p`` and ``p`` in ``r``. @@ -108,7 +105,6 @@ cdef int singular_polynomial_sub(poly **ret, poly *p, poly *q, ring *r): ret[0] = p_Add_q(p, p_Neg(q, r), r) return 0 - cdef int singular_polynomial_rmul(poly **ret, poly *p, RingElement n, ring *r): """ ``ret[0] = n*p`` where ``n`` is a coefficient and ``p`` in ``r``. @@ -319,7 +315,6 @@ cdef int singular_polynomial_mul(poly** ret, poly *p, poly *q, ring *r) except - ret[0] = pp_Mult_qq(p, q, r) return 0 - cdef int singular_polynomial_div_coeff(poly** ret, poly *p, poly *q, ring *r) except -1: """ ``ret[0] = p/n`` where ``p`` and ``q`` in ``r`` and ``q`` constant. @@ -422,7 +417,6 @@ cdef int singular_polynomial_neg(poly **ret, poly *p, ring *r): ret[0] = p_Neg(p_Copy(p,r),r) return 0 - cdef object singular_polynomial_str(poly *p, ring *r): """ Return the string representation of ``p``. @@ -448,7 +442,6 @@ cdef object singular_polynomial_str(poly *p, ring *r): s = parenthvar_pattern.sub("\\1", s) return s - cdef object singular_polynomial_latex(poly *p, ring *r, object base, object latex_gens): r""" Return the LaTeX string representation of ``p``. diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index f57126a6be4..63cb6a9e19e 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -421,7 +421,6 @@ cdef object si2sa_transext_QQ(number *n, ring *_ring, object base): return snumer/sdenom - cdef object si2sa_transext_FF(number *n, ring *_ring, object base): """ Create a sage element of a transcendental extension of a prime field from a @@ -505,7 +504,6 @@ cdef object si2sa_transext_FF(number *n, ring *_ring, object base): return snumer/sdenom - cdef object si2sa_NF(number *n, ring *_ring, object base): """ Create a sage element of a number field from a singular one. @@ -1018,8 +1016,6 @@ cdef number *sa2si_transext_QQ(object elem, ring *_ring): return n1 - - cdef number *sa2si_transext_FF(object elem, ring *_ring): """ Create a singular number from a sage element of a transcendental extension @@ -1123,7 +1119,6 @@ cdef number *sa2si_transext_FF(object elem, ring *_ring): return n1 - cdef number *sa2si_NF(object elem, ring *_ring): """ Create a singular number from a sage element of a number field. @@ -1430,7 +1425,6 @@ cdef number *sa2si(Element elem, ring * _ring): raise ValueError("cannot convert to SINGULAR number") - cdef object si2sa_intvec(intvec *v): r""" create a sage tuple from a singular vector of integers @@ -1495,7 +1489,6 @@ cdef int overflow_check(unsigned long e, ring *_ring) except -1: if unlikely(e > _ring.bitmask): raise OverflowError("exponent overflow (%d)"%(e)) - cdef init_libsingular(): """ This initializes the SINGULAR library. This is a hack to some From 06416317f35f0f3f4a603cb8a9bae829b2a5b726 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 8 Jul 2022 17:02:27 -0700 Subject: [PATCH 038/591] Add devcontainer for ubuntu --- .devcontainer/Dockerfile | 6 ++++++ .devcontainer/devcontainer.json | 11 +++++++++++ .vscode/settings.json | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000000..c47e122cf16 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,6 @@ +ARG VARIANT="jammy" +FROM ghcr.io/sagemath/sage/sage-docker-ubuntu-${VARIANT}-standard-with-system-packages:dev + +# Install additional packages needed for devcontainer support in VS code +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends gpgconf openssh-client diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000000..58a523bac20 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,11 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "Ubuntu", + "build": { + "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick an Ubuntu version: hirsute, focal, bionic, xenial, trusty, etc. + "args": { "VARIANT": "jammy" } + }, + // Run commands after the container is started. + "postStartCommand": "configure && make build" +} diff --git a/.vscode/settings.json b/.vscode/settings.json index cb06559edea..af2b4536957 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,8 +24,9 @@ "python.linting.pycodestyleEnabled": true, "python.linting.enabled": true, "cSpell.words": [ - "furo" + "furo", "Conda", + "sagemath", "Cython" ], } From 4b0288e6789bc8293e545474f582cec7d1ec53c7 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 14 May 2022 12:06:26 +0000 Subject: [PATCH 039/591] Add bootstrap --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 58a523bac20..af6c5a23510 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,5 +7,5 @@ "args": { "VARIANT": "jammy" } }, // Run commands after the container is started. - "postStartCommand": "configure && make build" + "postStartCommand": "./bootstrap && ./configure && make build" } From 267085d366fe4f3f51a064b0454ded816ff91b4c Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sat, 14 May 2022 12:18:48 +0000 Subject: [PATCH 040/591] enable-build-as-root --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index af6c5a23510..1e1c610bdac 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -7,5 +7,5 @@ "args": { "VARIANT": "jammy" } }, // Run commands after the container is started. - "postStartCommand": "./bootstrap && ./configure && make build" + "postStartCommand": "./bootstrap && ./configure --enable-build-as-root && make build" } From 63ee3b18af0bf3f52f21d0054e5c539cf6b671f0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 13:16:21 -0700 Subject: [PATCH 041/591] .devcontainer: Generalize to other distros --- .devcontainer/Dockerfile | 10 ++++------ .devcontainer/devcontainer.json | 12 +++++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c47e122cf16..67585ab311b 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,4 @@ -ARG VARIANT="jammy" -FROM ghcr.io/sagemath/sage/sage-docker-ubuntu-${VARIANT}-standard-with-system-packages:dev - -# Install additional packages needed for devcontainer support in VS code -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends gpgconf openssh-client +ARG SYSTEM_FACTOR="ubuntu-jammy" +ARG PACKAGE_FACTOR="standard" +ARG DOCKER_TARGET="with-system-packages" +FROM ghcr.io/sagemath/sage/sage-docker-${SYSTEM_FACTOR}-${PACKAGE_FACTOR}-${DOCKER_TARGET}:dev diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1e1c610bdac..a410d377b16 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,11 +1,17 @@ // For format details, see https://aka.ms/devcontainer.json. { - "name": "Ubuntu", + "name": "Ubuntu jammy", "build": { "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick an Ubuntu version: hirsute, focal, bionic, xenial, trusty, etc. - "args": { "VARIANT": "jammy" } + // See tox.ini for definitions + "args": { "SYSTEM_FACTOR": "ubuntu-jammy", + "PACKAGE_FACTOR": "standard", + "DOCKER_TARGET": "with-system-packages", + "DOCKER_TAG": "dev" + } }, + // Run commands after the container is created: + "postCreateCommand": "export PATH=$(pwd)/build/bin:$PATH && SYSTEM=$(sage-guess-package-system) && eval $(sage-print-system-package-command $SYSTEM install --yes $(sage-get-system-packages $SYSTEM _develop))", // Run commands after the container is started. "postStartCommand": "./bootstrap && ./configure --enable-build-as-root && make build" } From fff0164285210bb50bde1d04ca6e59f062bd85fb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 15:14:40 -0700 Subject: [PATCH 042/591] .devcontainer/devcontainer.json: Use configure --prefix --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a410d377b16..e763221fe15 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,5 +13,5 @@ // Run commands after the container is created: "postCreateCommand": "export PATH=$(pwd)/build/bin:$PATH && SYSTEM=$(sage-guess-package-system) && eval $(sage-print-system-package-command $SYSTEM install --yes $(sage-get-system-packages $SYSTEM _develop))", // Run commands after the container is started. - "postStartCommand": "./bootstrap && ./configure --enable-build-as-root && make build" + "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build" } From a32debfab8c3f0c4d0959c52674de16ab8e6b37d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 15:37:35 -0700 Subject: [PATCH 043/591] .devcontainer/devcontainer.json: Use make build V=0 --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e763221fe15..8686a14bd78 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,5 +13,5 @@ // Run commands after the container is created: "postCreateCommand": "export PATH=$(pwd)/build/bin:$PATH && SYSTEM=$(sage-guess-package-system) && eval $(sage-print-system-package-command $SYSTEM install --yes $(sage-get-system-packages $SYSTEM _develop))", // Run commands after the container is started. - "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build" + "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0" } From dfca38dc74502d7f11c5d7e6e19ad08d960db8f9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 16:00:57 -0700 Subject: [PATCH 044/591] .devcontainer/devcontainer.json: Use with-targets --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 8686a14bd78..0eaf0530286 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,7 +6,7 @@ // See tox.ini for definitions "args": { "SYSTEM_FACTOR": "ubuntu-jammy", "PACKAGE_FACTOR": "standard", - "DOCKER_TARGET": "with-system-packages", + "DOCKER_TARGET": "with-targets", "DOCKER_TAG": "dev" } }, From 28c9d6b287a53bd5e787fce6faf54679ad32896c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 16:36:27 -0700 Subject: [PATCH 045/591] .devcontainer/devcontainer.json: Install python extension --- .devcontainer/devcontainer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0eaf0530286..7807dd6e4cd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,5 +13,8 @@ // Run commands after the container is created: "postCreateCommand": "export PATH=$(pwd)/build/bin:$PATH && SYSTEM=$(sage-guess-package-system) && eval $(sage-print-system-package-command $SYSTEM install --yes $(sage-get-system-packages $SYSTEM _develop))", // Run commands after the container is started. - "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0" + "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", + "extensions": [ + "ms-python.python" + ] } From 09505edb6c07626f5772ad265c28fe556bad6d6b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 15 May 2022 07:53:39 -0700 Subject: [PATCH 046/591] .devcontainer/devcontainer.json: Also install packages from build/pkgs/_develop/dependencies --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7807dd6e4cd..d3e3a81be46 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -11,7 +11,7 @@ } }, // Run commands after the container is created: - "postCreateCommand": "export PATH=$(pwd)/build/bin:$PATH && SYSTEM=$(sage-guess-package-system) && eval $(sage-print-system-package-command $SYSTEM install --yes $(sage-get-system-packages $SYSTEM _develop))", + "postCreateCommand": "export PATH=$(pwd)/build/bin:$PATH && SYSTEM=$(sage-guess-package-system) && eval $(sage-print-system-package-command $SYSTEM install --yes $(sage-get-system-packages $SYSTEM _develop $(head -n 1 build/pkgs/_develop/dependencies)))", // Run commands after the container is started. "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", "extensions": [ From 4bfa47c1b6a25de9aeeeea99d8a9e0d5ec29436b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 15 May 2022 08:17:12 -0700 Subject: [PATCH 047/591] .devcontainer: Fix use of sage-print-system-package-command --- .devcontainer/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d3e3a81be46..9dc38d671fd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -11,7 +11,7 @@ } }, // Run commands after the container is created: - "postCreateCommand": "export PATH=$(pwd)/build/bin:$PATH && SYSTEM=$(sage-guess-package-system) && eval $(sage-print-system-package-command $SYSTEM install --yes $(sage-get-system-packages $SYSTEM _develop $(head -n 1 build/pkgs/_develop/dependencies)))", + "postCreateCommand": "export PATH=$(pwd)/build/bin:$PATH && SYSTEM=$(sage-guess-package-system) && eval $(sage-print-system-package-command $SYSTEM --yes install $(sage-get-system-packages $SYSTEM _develop $(head -n 1 build/pkgs/_develop/dependencies)))", // Run commands after the container is started. "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", "extensions": [ From 65e52925a4425a83269bae18c1304de6353f2e97 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 16 May 2022 11:47:45 -0700 Subject: [PATCH 048/591] .devcontainer/Dockerfile: Add argument DOCKER_TAG --- .devcontainer/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 67585ab311b..22465185f5e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,5 @@ ARG SYSTEM_FACTOR="ubuntu-jammy" ARG PACKAGE_FACTOR="standard" ARG DOCKER_TARGET="with-system-packages" -FROM ghcr.io/sagemath/sage/sage-docker-${SYSTEM_FACTOR}-${PACKAGE_FACTOR}-${DOCKER_TARGET}:dev +ARG DOCKER_TAG="dev" +FROM ghcr.io/sagemath/sage/sage-docker-${SYSTEM_FACTOR}-${PACKAGE_FACTOR}-${DOCKER_TARGET}:${DOCKER_TAG} From af60fe0809eb62a39081d89f9095e5bcea03719c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 16 May 2022 11:49:03 -0700 Subject: [PATCH 049/591] src/doc/en/developer/portability_testing.rst: Add section 'Using our pre-built Docker images published on ghcr.io' --- src/doc/en/developer/portability_testing.rst | 80 ++++++++++++++++++-- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index a0a7cbf40b8..ffa3bc531d0 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -945,19 +945,24 @@ options:: [mkoeppe@sage worktree-local]$ SKIP_SYSTEM_PKG_INSTALL=yes SKIP_BOOTSTRAP=1 SKIP_CONFIGURE=1 tox -e local-homebrew-macos-minimal -- bash -Automatic parallel tox runs on GitHub Actions ---------------------------------------------- +Automatic testing on multiple platforms on GitHub Actions +========================================================= The Sage source tree includes a default configuration for GitHub -Actions that runs tox on a multitude of platforms on every pull -request and on every push of a tag (but not of a branch) to a -repository for which GitHub Actions are enabled. +Actions that runs our portability tests with tox on a multitude of +platforms on every pull request and on every push of a tag (but not of +a branch) to a repository for which GitHub Actions are enabled. -This is defined in the file ``$SAGE_ROOT/.github/workflows/tox.yml``. +In particular, it automatically runs on our main repository on every +release tag. + +This is defined in the files `$SAGE_ROOT/.github/workflows/tox*.yml +`_. An additional GitHub Actions workflow for testing on Cygwin, not based -on tox, is defined in the file -``$SAGE_ROOT/.github/workflows/ci-cygwin.yml``. +on tox, is defined in the files +`$SAGE_ROOT/.github/workflows/ci-cygwin*.yml +`_. GitHub Actions runs these build jobs on 2-core machines with 7 GB of RAM memory and 14 GB of SSD disk space, cf. @@ -1079,3 +1084,62 @@ Now you can pull the image and run it:: $ docker pull docker.pkg.github.com/YOUR-GITHUB-USERNAME/sage/sage-docker-fedora-31-standard-configured:f4bd671 $ docker run -it docker.pkg.github.com/YOUR-GITHUB-USERNAME/sage/sage-docker-fedora-31-standard-configured:f4bd671 bash + + +Using our pre-built Docker images published on ghcr.io +====================================================== + +Our portability CI on GitHub Actions builds `Docker images +`_ +for all tested Linux platforms (and system package configurations) and +makes them available on `GitHub Packages +`_ (ghcr.io). + +This makes it easy for developers to debug problems that showed up in +the build logs for a given platform. + +The image version corresponding to the latest development release +receives the additional Docker tag ``dev``, see for example the Docker +image for the platform `ubuntu-focal-standard +`_. Thus, +for example, the following command will work:: + + $ docker run -it ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional:dev bash + Unable to find image 'ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional:dev' locally + dev: Pulling from sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional + d5fd17ec1767: Already exists + 67586203f0c7: Pull complete + b63c529f4777: Pull complete + ... + 159775d1a3d2: Pull complete + Digest: sha256:e6ba5e12f59c6c4668692ef4cfe4ae5f242556482664fb347bf260f32bf8e698 + Status: Downloaded newer image for ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional:dev + root@8055a7ba0607:/sage# ./sage + ┌────────────────────────────────────────────────────────────────────┐ + │ SageMath version 9.6, Release Date: 2022-05-15 │ + │ Using Python 3.8.10. Type "help()" for help. │ + └────────────────────────────────────────────────────────────────────┘ + sage: + +Images whose names end with the suffix ``-with-targets-optional`` are +the results of full builds and a run of ``make ptest``. They also +contain a copy of the source tree and the full logs of the build and +test. + +Also `smaller images corresponding to earlier build stages +`_ +are available: + + * ``-with-system-packages`` provides a system installation with + system packages installed, no source tree, + + * ``-configured`` contains a partial source tree + (:envvar:`SAGE_ROOT`) and has completed the bootstrapping phase and + the run of the ``configure`` script, + + * ``-with-targets-pre`` contains the full source tree and a full + installation of all non-Python packages (:envvar:`SAGE_LOCAL`), + + * ``-with-targets`` contains the full source tree and a full + installation of Sage, including the HTML documentation, but ``make + ptest`` has not been run yet. From ee58027165f9841aa656ebb361f35af0da7ac312 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 16 May 2022 11:49:18 -0700 Subject: [PATCH 050/591] src/doc/en/developer/portability_testing.rst: Add section 'Developing with our pre-built Docker images as devcontainers in VS Code' --- src/doc/en/developer/portability_testing.rst | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index ffa3bc531d0..befc1e05f41 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1143,3 +1143,31 @@ are available: * ``-with-targets`` contains the full source tree and a full installation of Sage, including the HTML documentation, but ``make ptest`` has not been run yet. + + +Developing with our pre-built Docker images as devcontainers in VS Code +======================================================================= + +VS Code is very +convenient for working with Docker containers thanks to the `Visual +Studio Code Remote - Containers +`_ extension. + +Sage provides a configuration file +`$SAGE_ROOT/.devcontainer/devcontainer.json +`_ +for this purpose. + +Opening the Sage repository in the configured devcontainer pulls the +image from ghcr.io, installs `additional system packages for +development <../reference/spkg/_develop.html>`_, and builds Sage from +source, reusing the installation (:envvar:`SAGE_LOCAL`, +:envvar:`SAGE_VENV`) from the image. + +By default, it uses ``ubuntu-jammy-standard`` and the most recent +development version Sage (``dev`` tag). You can edit the +configuration file to change to a different platform or another +version. After editing, run "Remote-Containers: Rebuild Container" +from the Command Palette. See the `devcontainer.json reference +`_ +for more information. From d7a961f43979593d669dfab51c48b152e6c72b1e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 10:44:21 -0700 Subject: [PATCH 051/591] devcontainer-ubuntu-jammy-standard.json: Renamed from devcontainer.json --- ...{devcontainer.json => devcontainer-ubuntu-jammy-standard.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .devcontainer/{devcontainer.json => devcontainer-ubuntu-jammy-standard.json} (100%) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer-ubuntu-jammy-standard.json similarity index 100% rename from .devcontainer/devcontainer.json rename to .devcontainer/devcontainer-ubuntu-jammy-standard.json From 4ae65bd2d2aca38fd1537d60b31752f472480dd2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 10:59:07 -0700 Subject: [PATCH 052/591] .devcontainer: Factor out script post_create.sh --- .devcontainer/devcontainer-ubuntu-jammy-standard.json | 2 +- .devcontainer/post_create.sh | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100755 .devcontainer/post_create.sh diff --git a/.devcontainer/devcontainer-ubuntu-jammy-standard.json b/.devcontainer/devcontainer-ubuntu-jammy-standard.json index 9dc38d671fd..8b0b9b7ce34 100644 --- a/.devcontainer/devcontainer-ubuntu-jammy-standard.json +++ b/.devcontainer/devcontainer-ubuntu-jammy-standard.json @@ -11,7 +11,7 @@ } }, // Run commands after the container is created: - "postCreateCommand": "export PATH=$(pwd)/build/bin:$PATH && SYSTEM=$(sage-guess-package-system) && eval $(sage-print-system-package-command $SYSTEM --yes install $(sage-get-system-packages $SYSTEM _develop $(head -n 1 build/pkgs/_develop/dependencies)))", + "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", "extensions": [ diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh new file mode 100755 index 00000000000..3bdbdd13763 --- /dev/null +++ b/.devcontainer/post_create.sh @@ -0,0 +1,8 @@ +#! /bin/sh +# Run this script from SAGE_ROOT. +# +# Install standard development tools - see SAGE_ROOT/build/pkgs/_develop +# This includes the prerequisites for VS Code remote containers, +export PATH=$(pwd)/build/bin:$PATH +SYSTEM=$(sage-guess-package-system) +eval $(sage-print-system-package-command $SYSTEM --yes install $(sage-get-system-packages $SYSTEM _develop $(head -n 1 build/pkgs/_develop/dependencies))) From 2a5b1a4a169d2c1fda23beac664b0daa3a1eb733 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 11:02:42 -0700 Subject: [PATCH 053/591] .devcontainer/devcontainer-cocalc.json: New --- .devcontainer/devcontainer-cocalc.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .devcontainer/devcontainer-cocalc.json diff --git a/.devcontainer/devcontainer-cocalc.json b/.devcontainer/devcontainer-cocalc.json new file mode 100644 index 00000000000..ded362a9d88 --- /dev/null +++ b/.devcontainer/devcontainer-cocalc.json @@ -0,0 +1,12 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "CoCalc Docker", + "image": "sagemathinc/cocalc" + // Run commands after the container is created: + "postCreateCommand": ".devcontainer/post_create.sh", + // Run commands after the container is started. + "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv && make build V=0", + "extensions": [ + "ms-python.python" + ] +} From ebd242b8d5433714a5103a4b29825002331f94eb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 11:24:59 -0700 Subject: [PATCH 054/591] src/doc/en/developer/portability_testing.rst: Copy or symlink the devcontainer.json sample file --- src/doc/en/developer/portability_testing.rst | 24 ++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index befc1e05f41..134e059a41e 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1153,21 +1153,27 @@ convenient for working with Docker containers thanks to the `Visual Studio Code Remote - Containers `_ extension. -Sage provides a configuration file -`$SAGE_ROOT/.devcontainer/devcontainer.json -`_ +Sage provides sample ``devcontainer.json`` configuration files +`$SAGE_ROOT/.devcontainer/devcontainer-*.json +`_ for this purpose. -Opening the Sage repository in the configured devcontainer pulls the +To get started, copy (or symlink) the sample file +`devcontainer-ubuntu-jammy-standard.json +`_ +to ``devcontainer.json`` in the same directory. It uses +``ubuntu-jammy-standard`` and the most recent development version Sage +(``dev`` tag). You can edit a copy of the configuration file to +change to a different platform or another version. + +Then, opening the Sage repository in the configured devcontainer pulls the image from ghcr.io, installs `additional system packages for development <../reference/spkg/_develop.html>`_, and builds Sage from source, reusing the installation (:envvar:`SAGE_LOCAL`, :envvar:`SAGE_VENV`) from the image. -By default, it uses ``ubuntu-jammy-standard`` and the most recent -development version Sage (``dev`` tag). You can edit the -configuration file to change to a different platform or another -version. After editing, run "Remote-Containers: Rebuild Container" -from the Command Palette. See the `devcontainer.json reference +After editing the configuration file (or changing the symlink), run +"Remote-Containers: Rebuild Container" from the Command Palette. See +the `devcontainer.json reference `_ for more information. From 8e4f9ce3cc4737d40c97be894c3b91c2ed835b98 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 11:30:08 -0700 Subject: [PATCH 055/591] .devcontainer/devcontainer: Use MAKE='make -j12' --- .devcontainer/devcontainer-cocalc.json | 3 +++ .devcontainer/devcontainer-ubuntu-jammy-standard.json | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.devcontainer/devcontainer-cocalc.json b/.devcontainer/devcontainer-cocalc.json index ded362a9d88..5da9164aaa5 100644 --- a/.devcontainer/devcontainer-cocalc.json +++ b/.devcontainer/devcontainer-cocalc.json @@ -2,6 +2,9 @@ { "name": "CoCalc Docker", "image": "sagemathinc/cocalc" + "containerEnv": { + "MAKE": "make -j12" + }, // Run commands after the container is created: "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. diff --git a/.devcontainer/devcontainer-ubuntu-jammy-standard.json b/.devcontainer/devcontainer-ubuntu-jammy-standard.json index 8b0b9b7ce34..329235ea1ca 100644 --- a/.devcontainer/devcontainer-ubuntu-jammy-standard.json +++ b/.devcontainer/devcontainer-ubuntu-jammy-standard.json @@ -10,6 +10,9 @@ "DOCKER_TAG": "dev" } }, + "containerEnv": { + "MAKE": "make -j12" + }, // Run commands after the container is created: "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. From 48041f2ec2994c4849c064bdaf526ef243ae9d33 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 16:23:09 -0700 Subject: [PATCH 056/591] .devcontainer/post_create.sh: Handle option --sudo --- .devcontainer/post_create.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh index 3bdbdd13763..a64d8007bd0 100755 --- a/.devcontainer/post_create.sh +++ b/.devcontainer/post_create.sh @@ -1,8 +1,8 @@ #! /bin/sh -# Run this script from SAGE_ROOT. +# Run this script from SAGE_ROOT. Invoke with "--sudo" if sudo is needed. # # Install standard development tools - see SAGE_ROOT/build/pkgs/_develop # This includes the prerequisites for VS Code remote containers, export PATH=$(pwd)/build/bin:$PATH SYSTEM=$(sage-guess-package-system) -eval $(sage-print-system-package-command $SYSTEM --yes install $(sage-get-system-packages $SYSTEM _develop $(head -n 1 build/pkgs/_develop/dependencies))) +eval $(sage-print-system-package-command $SYSTEM --yes "$@" install $(sage-get-system-packages $SYSTEM _develop $(head -n 1 build/pkgs/_develop/dependencies))) From 28794f5d8a87ad4602de3388be3d83f3605e3d1e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 16:24:58 -0700 Subject: [PATCH 057/591] .devcontainer/devcontainer-computop-sage.json: New --- .devcontainer/devcontainer-computop-sage.json | 15 +++++++++++++++ .gitignore | 3 +++ 2 files changed, 18 insertions(+) create mode 100644 .devcontainer/devcontainer-computop-sage.json diff --git a/.devcontainer/devcontainer-computop-sage.json b/.devcontainer/devcontainer-computop-sage.json new file mode 100644 index 00000000000..147c9fd6e85 --- /dev/null +++ b/.devcontainer/devcontainer-computop-sage.json @@ -0,0 +1,15 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "computop/sage Docker", + "image": "computop/sage" + "containerEnv": { + "MAKE": "make -j12" + }, + // Run commands after the container is created: + "postCreateCommand": ".devcontainer/post_create.sh --sudo", + // Run commands after the container is started. + "postStartCommand": "./bootstrap && ./configure --prefix=/sage/local --with-sage-venv && make build V=0", + "extensions": [ + "ms-python.python" + ] +} diff --git a/.gitignore b/.gitignore index 59b7fb8b9e4..c19c1ee4576 100644 --- a/.gitignore +++ b/.gitignore @@ -212,6 +212,9 @@ src/ENV/ src/env.bak/ src/venv.bak/ +# devcontainer +/.devcontainer/devcontainer.json + # mypy **/.mypy_cache/ From afae9632023645d0842ecbc660a02cfd7b5a43d0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 16:48:51 -0700 Subject: [PATCH 058/591] .devcontainer/devcontainer-computop-sage.json: Stop it from injecting old SAGE_ROOT into every shell --- .devcontainer/devcontainer-computop-sage.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer-computop-sage.json b/.devcontainer/devcontainer-computop-sage.json index 147c9fd6e85..840de8e9d5e 100644 --- a/.devcontainer/devcontainer-computop-sage.json +++ b/.devcontainer/devcontainer-computop-sage.json @@ -6,7 +6,8 @@ "MAKE": "make -j12" }, // Run commands after the container is created: - "postCreateCommand": ".devcontainer/post_create.sh --sudo", + // Install build tools, get rid of sourcing /sage/activate in non-login shells. + "postCreateCommand": ".devcontainer/post_create.sh --sudo && sed -i.bak '/sage.*activate/d' ~/.bashrc", // Run commands after the container is started. "postStartCommand": "./bootstrap && ./configure --prefix=/sage/local --with-sage-venv && make build V=0", "extensions": [ From ebb73134fd06b478ad0891b020751614c8214236 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 18:49:30 -0700 Subject: [PATCH 059/591] src/bin/sage-env: Key SAGE_ENV_SOURCED also to SAGE_SRC because the PATH setting depends on it --- src/bin/sage-env | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bin/sage-env b/src/bin/sage-env index 5875e617c32..b451326eb7d 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -115,9 +115,8 @@ fi # Don't execute the commands more than once for the same version of # sage-env... for the same combination of SAGE_LOCAL and SAGE_VENV. -# "5" indicates the version of the format of the value of SAGE_ENV_VERSION. -# The current format was introduced in #32745. -SAGE_ENV_VERSION="5:$SAGE_LOCAL:$SAGE_VENV" +# "6" indicates the version of the format of the value of SAGE_ENV_VERSION. +SAGE_ENV_VERSION="6:$SAGE_LOCAL:$SAGE_VENV:$SAGE_SRC" if [ "$SAGE_ENV_SOURCED" = "$SAGE_ENV_VERSION" ]; then # Already sourced, nothing to do. return 0 From a586e4d5dd8df6d2fb80007ad2f160df2086e5c6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 18:53:44 -0700 Subject: [PATCH 060/591] build/make/Makefile.in: Put SAGE_SRC/bin in front of SAGE_VENV/bin so that sage-env-config is sourced from SAGE_SRC --- build/make/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/make/Makefile.in b/build/make/Makefile.in index 6b168c12e1f..a3e13e379e9 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -505,7 +505,7 @@ $(1)-$(4)-no-deps: echo "$$($(4)_DISABLED_MESSAGE)" 2>&1; \ exit 1; \ else \ - sage-logger -p 'SAGE_CHECK=$$(SAGE_CHECK_$(1)) PATH=$$($(4))/bin:$$$$PATH $$(SAGE_SPKG) $$(SAGE_SPKG_OPTIONS) \ + sage-logger -p 'SAGE_CHECK=$$(SAGE_CHECK_$(1)) PATH=$$(SAGE_SRC)/bin:$$($(4))/bin:$$$$PATH $$(SAGE_SPKG) $$(SAGE_SPKG_OPTIONS) \ $(if $(filter $(1),$(TOOLCHAIN_DEPS)),--keep-existing) \ $(1)-$(2) $$($(4))' '$$(SAGE_LOGS)/$(1)-$(2).log'; \ fi From bd9ceaec1bf5e342671d2dc7a40b7ac4d56cceaa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 17 May 2022 23:16:25 -0700 Subject: [PATCH 061/591] .devcontainer/devcontainer-computop-sage.json: More workarounds --- .devcontainer/devcontainer-computop-sage.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer-computop-sage.json b/.devcontainer/devcontainer-computop-sage.json index 840de8e9d5e..54e57b412d2 100644 --- a/.devcontainer/devcontainer-computop-sage.json +++ b/.devcontainer/devcontainer-computop-sage.json @@ -9,7 +9,10 @@ // Install build tools, get rid of sourcing /sage/activate in non-login shells. "postCreateCommand": ".devcontainer/post_create.sh --sudo && sed -i.bak '/sage.*activate/d' ~/.bashrc", // Run commands after the container is started. - "postStartCommand": "./bootstrap && ./configure --prefix=/sage/local --with-sage-venv && make build V=0", + // Do not run configure within a sage-env (see #29485). + // The pari package is broken in the computop/sage 9.5 image, need to reinstall. + // Also libnauty is broken. + "postStartCommand": "./bootstrap && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv) && make pari-clean nauty-clean build V=0", "extensions": [ "ms-python.python" ] From 1cfa0383f227e0774a8abd260c755f337590a91f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 18 May 2022 11:18:48 -0700 Subject: [PATCH 062/591] .devcontainer/post_create.sh: First update package lists, also install _prereq --- .devcontainer/post_create.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh index a64d8007bd0..eb2c70040d2 100755 --- a/.devcontainer/post_create.sh +++ b/.devcontainer/post_create.sh @@ -5,4 +5,5 @@ # This includes the prerequisites for VS Code remote containers, export PATH=$(pwd)/build/bin:$PATH SYSTEM=$(sage-guess-package-system) -eval $(sage-print-system-package-command $SYSTEM --yes "$@" install $(sage-get-system-packages $SYSTEM _develop $(head -n 1 build/pkgs/_develop/dependencies))) +eval $(sage-print-system-package-command $SYSTEM "$@" update) +eval $(sage-print-system-package-command $SYSTEM --yes "$@" install $(sage-get-system-packages $SYSTEM _prereq _develop $(head -n 1 build/pkgs/_develop/dependencies))) From 5ea2bf0e04d5c0611cda82867e4f8c8afd5bc1cf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 18 May 2022 11:19:08 -0700 Subject: [PATCH 063/591] .devcontainer/devcontainer-sagemath-sagemath.json: New --- .../devcontainer-sagemath-sagemath.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .devcontainer/devcontainer-sagemath-sagemath.json diff --git a/.devcontainer/devcontainer-sagemath-sagemath.json b/.devcontainer/devcontainer-sagemath-sagemath.json new file mode 100644 index 00000000000..9225680fb56 --- /dev/null +++ b/.devcontainer/devcontainer-sagemath-sagemath.json @@ -0,0 +1,18 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "sagemath/sagemath Docker", + // sagemath/sagemath-dev as of 9.5 is broken? + "image": "sagemath/sagemath:develop" + "containerEnv": { + "MAKE": "make -j12" + }, + // Run commands after the container is created: + // Install build tools + "postCreateCommand": ".devcontainer/post_create.sh --sudo" + // Run commands after the container is started. + // Do not run configure within a sage-env (see #29485). + "postStartCommand": "./bootstrap && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/home/sage/sage/local --with-sage-venv) && make build V=0", + "extensions": [ + "ms-python.python" + ] +} From ac8bed772941291b7dfb038539716bad3e6f3e3c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 18 May 2022 18:07:20 -0700 Subject: [PATCH 064/591] .devcontainer/devcontainer-archlinux-latest-downstream.json: New --- .../devcontainer-archlinux-latest-downstream.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .devcontainer/devcontainer-archlinux-latest-downstream.json diff --git a/.devcontainer/devcontainer-archlinux-latest-downstream.json b/.devcontainer/devcontainer-archlinux-latest-downstream.json new file mode 100644 index 00000000000..1c59923ab56 --- /dev/null +++ b/.devcontainer/devcontainer-archlinux-latest-downstream.json @@ -0,0 +1,12 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "archlinux:latest downstream Sage", + "image": "archlinux:latest", + // Run commands after the container is created: + "postCreateCommand": ".devcontainer/post_create.sh && pacman -Sy --noconfirm sagemath sagemath-doc", + // Run commands after the container is started. + "postStartCommand": "./bootstrap && ln -sf /usr venv", + "extensions": [ + "ms-python.python" + ] +} From 5380a51ff7fc9490dd24912ea9a91715ad82401d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 18 May 2022 19:56:55 -0700 Subject: [PATCH 065/591] .devcontainer/devcontainer-archlinux-latest-downstream.json: Install pip, notebook --- .devcontainer/devcontainer-archlinux-latest-downstream.json | 2 +- build/pkgs/notebook/distros/arch.txt | 1 + build/pkgs/pip/distros/arch.txt | 1 + build/pkgs/tox/distros/arch.txt | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 build/pkgs/notebook/distros/arch.txt create mode 100644 build/pkgs/pip/distros/arch.txt create mode 100644 build/pkgs/tox/distros/arch.txt diff --git a/.devcontainer/devcontainer-archlinux-latest-downstream.json b/.devcontainer/devcontainer-archlinux-latest-downstream.json index 1c59923ab56..af1a759eec3 100644 --- a/.devcontainer/devcontainer-archlinux-latest-downstream.json +++ b/.devcontainer/devcontainer-archlinux-latest-downstream.json @@ -3,7 +3,7 @@ "name": "archlinux:latest downstream Sage", "image": "archlinux:latest", // Run commands after the container is created: - "postCreateCommand": ".devcontainer/post_create.sh && pacman -Sy --noconfirm sagemath sagemath-doc", + "postCreateCommand": ".devcontainer/post_create.sh && pacman -Sy --noconfirm sagemath sagemath-doc jupyter-notebook python-pip", // Run commands after the container is started. "postStartCommand": "./bootstrap && ln -sf /usr venv", "extensions": [ diff --git a/build/pkgs/notebook/distros/arch.txt b/build/pkgs/notebook/distros/arch.txt new file mode 100644 index 00000000000..4d5656e81e6 --- /dev/null +++ b/build/pkgs/notebook/distros/arch.txt @@ -0,0 +1 @@ +jupyter-notebook diff --git a/build/pkgs/pip/distros/arch.txt b/build/pkgs/pip/distros/arch.txt new file mode 100644 index 00000000000..311c1b821ca --- /dev/null +++ b/build/pkgs/pip/distros/arch.txt @@ -0,0 +1 @@ +python-pip diff --git a/build/pkgs/tox/distros/arch.txt b/build/pkgs/tox/distros/arch.txt new file mode 100644 index 00000000000..cd20859a9df --- /dev/null +++ b/build/pkgs/tox/distros/arch.txt @@ -0,0 +1 @@ +python-tox From ece0fde5cae01eb3af9d3404d8db4a02cddfe804 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 18 May 2022 21:38:43 -0700 Subject: [PATCH 066/591] .devcontainer/devcontainer-conda-forge-latest-downstream.json: New --- .../devcontainer-conda-forge-latest-downstream.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .devcontainer/devcontainer-conda-forge-latest-downstream.json diff --git a/.devcontainer/devcontainer-conda-forge-latest-downstream.json b/.devcontainer/devcontainer-conda-forge-latest-downstream.json new file mode 100644 index 00000000000..45746f374f7 --- /dev/null +++ b/.devcontainer/devcontainer-conda-forge-latest-downstream.json @@ -0,0 +1,12 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "condaforge/mambaforge:latest downstream Sage", + "image": "condaforge/mambaforge:latest", + // Run commands after the container is created: + "postCreateCommand": ".devcontainer/post_create.sh && mamba install --yes sage", + // Run commands after the container is started. + "postStartCommand": "./bootstrap && ln -sf $CONDA_PREFIX venv", + "extensions": [ + "ms-python.python" + ] +} From 9772b1c11dd8d5ebda4d089f4577eb69e1222f59 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 19 May 2022 20:59:02 -0700 Subject: [PATCH 067/591] .devcontainer/post_create.sh: Simplify using new options of sage-print-system-package-command --- .devcontainer/post_create.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh index eb2c70040d2..e7d8ab4db0d 100755 --- a/.devcontainer/post_create.sh +++ b/.devcontainer/post_create.sh @@ -6,4 +6,4 @@ export PATH=$(pwd)/build/bin:$PATH SYSTEM=$(sage-guess-package-system) eval $(sage-print-system-package-command $SYSTEM "$@" update) -eval $(sage-print-system-package-command $SYSTEM --yes "$@" install $(sage-get-system-packages $SYSTEM _prereq _develop $(head -n 1 build/pkgs/_develop/dependencies))) +eval $(sage-print-system-package-command $SYSTEM --yes "$@" --spkg install _prereq _develop $(head -n 1 build/pkgs/_develop/dependencies) $EXTRA_SAGE_PACKAGES) From b44280c724f57e272726af88d903beb16bdaef80 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 19 May 2022 20:59:31 -0700 Subject: [PATCH 068/591] .devcontainer/devcontainer-archlinux-latest-downstream.json: Use spkg _sagemath --- .devcontainer/devcontainer-archlinux-latest-downstream.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer-archlinux-latest-downstream.json b/.devcontainer/devcontainer-archlinux-latest-downstream.json index af1a759eec3..0f733fce0c8 100644 --- a/.devcontainer/devcontainer-archlinux-latest-downstream.json +++ b/.devcontainer/devcontainer-archlinux-latest-downstream.json @@ -3,7 +3,7 @@ "name": "archlinux:latest downstream Sage", "image": "archlinux:latest", // Run commands after the container is created: - "postCreateCommand": ".devcontainer/post_create.sh && pacman -Sy --noconfirm sagemath sagemath-doc jupyter-notebook python-pip", + "postCreateCommand": "EXTRA_SAGE_PACKAGES='_sagemath notebook pip' .devcontainer/post_create.sh", // Run commands after the container is started. "postStartCommand": "./bootstrap && ln -sf /usr venv", "extensions": [ From 64ad9d07ae267816e8138c68a04b3a87937e8785 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 20 May 2022 12:53:26 -0700 Subject: [PATCH 069/591] .devcontainer: Move devcontainer.json files to separate directories for Codespaces --- .../devcontainer.json} | 0 .../{devcontainer-cocalc.json => cocalc/devcontainer.json} | 0 .../devcontainer.json} | 0 .../devcontainer.json} | 0 .../devcontainer.json} | 0 .../devcontainer.json} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename .devcontainer/{devcontainer-archlinux-latest-downstream.json => archlinux-latest-downstream/devcontainer.json} (100%) rename .devcontainer/{devcontainer-cocalc.json => cocalc/devcontainer.json} (100%) rename .devcontainer/{devcontainer-computop-sage.json => computop-sage/devcontainer.json} (100%) rename .devcontainer/{devcontainer-conda-forge-latest-downstream.json => conda-forge-latest-downstream/devcontainer.json} (100%) rename .devcontainer/{devcontainer-sagemath-sagemath.json => sagemath-sagemath/devcontainer.json} (100%) rename .devcontainer/{devcontainer-ubuntu-jammy-standard.json => ubuntu-jammy-standard/devcontainer.json} (100%) diff --git a/.devcontainer/devcontainer-archlinux-latest-downstream.json b/.devcontainer/archlinux-latest-downstream/devcontainer.json similarity index 100% rename from .devcontainer/devcontainer-archlinux-latest-downstream.json rename to .devcontainer/archlinux-latest-downstream/devcontainer.json diff --git a/.devcontainer/devcontainer-cocalc.json b/.devcontainer/cocalc/devcontainer.json similarity index 100% rename from .devcontainer/devcontainer-cocalc.json rename to .devcontainer/cocalc/devcontainer.json diff --git a/.devcontainer/devcontainer-computop-sage.json b/.devcontainer/computop-sage/devcontainer.json similarity index 100% rename from .devcontainer/devcontainer-computop-sage.json rename to .devcontainer/computop-sage/devcontainer.json diff --git a/.devcontainer/devcontainer-conda-forge-latest-downstream.json b/.devcontainer/conda-forge-latest-downstream/devcontainer.json similarity index 100% rename from .devcontainer/devcontainer-conda-forge-latest-downstream.json rename to .devcontainer/conda-forge-latest-downstream/devcontainer.json diff --git a/.devcontainer/devcontainer-sagemath-sagemath.json b/.devcontainer/sagemath-sagemath/devcontainer.json similarity index 100% rename from .devcontainer/devcontainer-sagemath-sagemath.json rename to .devcontainer/sagemath-sagemath/devcontainer.json diff --git a/.devcontainer/devcontainer-ubuntu-jammy-standard.json b/.devcontainer/ubuntu-jammy-standard/devcontainer.json similarity index 100% rename from .devcontainer/devcontainer-ubuntu-jammy-standard.json rename to .devcontainer/ubuntu-jammy-standard/devcontainer.json From a813a75d84ba7fbfc01ec495f8761b497f1fb9c6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 20 May 2022 13:03:14 -0700 Subject: [PATCH 070/591] src/doc/en/developer/portability_testing.rst: Update --- src/doc/en/developer/portability_testing.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 134e059a41e..7fe1bf256b1 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1154,14 +1154,14 @@ Studio Code Remote - Containers `_ extension. Sage provides sample ``devcontainer.json`` configuration files -`$SAGE_ROOT/.devcontainer/devcontainer-*.json +`$SAGE_ROOT/.devcontainer/*/devcontainer.json `_ for this purpose. To get started, copy (or symlink) the sample file -`devcontainer-ubuntu-jammy-standard.json -`_ -to ``devcontainer.json`` in the same directory. It uses +`.devcontainer/ubuntu-jammy-standard/devcontainer.json +`_ +to ``devcontainer.json`` in the directory ``.devcontainer``. It uses ``ubuntu-jammy-standard`` and the most recent development version Sage (``dev`` tag). You can edit a copy of the configuration file to change to a different platform or another version. From 60e58d3b2a66eba9d2465a12d139fa25555d41bb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 20 May 2022 13:18:31 -0700 Subject: [PATCH 071/591] src/doc/en/developer/portability_testing.rst: Add link to GitHub devcontainer doc --- src/doc/en/developer/portability_testing.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 7fe1bf256b1..49fcddd3bd7 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1174,6 +1174,8 @@ source, reusing the installation (:envvar:`SAGE_LOCAL`, After editing the configuration file (or changing the symlink), run "Remote-Containers: Rebuild Container" from the Command Palette. See -the `devcontainer.json reference +the `VS Code devcontainer.json reference `_ +and the `GitHub introduction to dev containers +`_ for more information. From 6137928532ae81548b9c2ac87eb71687022941cd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 20 May 2022 14:32:09 -0700 Subject: [PATCH 072/591] src/doc/en/developer/portability_testing.rst: Fix rst --- src/doc/en/developer/portability_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 49fcddd3bd7..102115aa504 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1148,7 +1148,7 @@ are available: Developing with our pre-built Docker images as devcontainers in VS Code ======================================================================= -VS Code is very +`VS Code ` is very convenient for working with Docker containers thanks to the `Visual Studio Code Remote - Containers `_ extension. From 0b9fc68a6978c78e1fe7b98e6121d187737037aa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 20 May 2022 16:05:46 -0700 Subject: [PATCH 073/591] .devcontainer/*/devcontainer.json: Use 'make configure' instead of './bootstrap' to match instructions in README --- .devcontainer/archlinux-latest-downstream/devcontainer.json | 2 +- .devcontainer/cocalc/devcontainer.json | 2 +- .devcontainer/computop-sage/devcontainer.json | 2 +- .devcontainer/conda-forge-latest-downstream/devcontainer.json | 2 +- .devcontainer/sagemath-sagemath/devcontainer.json | 2 +- .devcontainer/ubuntu-jammy-standard/devcontainer.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.devcontainer/archlinux-latest-downstream/devcontainer.json b/.devcontainer/archlinux-latest-downstream/devcontainer.json index 0f733fce0c8..a52cf869878 100644 --- a/.devcontainer/archlinux-latest-downstream/devcontainer.json +++ b/.devcontainer/archlinux-latest-downstream/devcontainer.json @@ -5,7 +5,7 @@ // Run commands after the container is created: "postCreateCommand": "EXTRA_SAGE_PACKAGES='_sagemath notebook pip' .devcontainer/post_create.sh", // Run commands after the container is started. - "postStartCommand": "./bootstrap && ln -sf /usr venv", + "postStartCommand": "make configure && ln -sf /usr venv", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/cocalc/devcontainer.json b/.devcontainer/cocalc/devcontainer.json index 5da9164aaa5..5a51894682c 100644 --- a/.devcontainer/cocalc/devcontainer.json +++ b/.devcontainer/cocalc/devcontainer.json @@ -8,7 +8,7 @@ // Run commands after the container is created: "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. - "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv && make build V=0", + "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv && make build V=0", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/computop-sage/devcontainer.json b/.devcontainer/computop-sage/devcontainer.json index 54e57b412d2..2228c6699f8 100644 --- a/.devcontainer/computop-sage/devcontainer.json +++ b/.devcontainer/computop-sage/devcontainer.json @@ -12,7 +12,7 @@ // Do not run configure within a sage-env (see #29485). // The pari package is broken in the computop/sage 9.5 image, need to reinstall. // Also libnauty is broken. - "postStartCommand": "./bootstrap && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv) && make pari-clean nauty-clean build V=0", + "postStartCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv) && make pari-clean nauty-clean build V=0", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/conda-forge-latest-downstream/devcontainer.json b/.devcontainer/conda-forge-latest-downstream/devcontainer.json index 45746f374f7..22463c2dd29 100644 --- a/.devcontainer/conda-forge-latest-downstream/devcontainer.json +++ b/.devcontainer/conda-forge-latest-downstream/devcontainer.json @@ -5,7 +5,7 @@ // Run commands after the container is created: "postCreateCommand": ".devcontainer/post_create.sh && mamba install --yes sage", // Run commands after the container is started. - "postStartCommand": "./bootstrap && ln -sf $CONDA_PREFIX venv", + "postStartCommand": "make configure && ln -sf $CONDA_PREFIX venv", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/sagemath-sagemath/devcontainer.json b/.devcontainer/sagemath-sagemath/devcontainer.json index 9225680fb56..214491aef31 100644 --- a/.devcontainer/sagemath-sagemath/devcontainer.json +++ b/.devcontainer/sagemath-sagemath/devcontainer.json @@ -11,7 +11,7 @@ "postCreateCommand": ".devcontainer/post_create.sh --sudo" // Run commands after the container is started. // Do not run configure within a sage-env (see #29485). - "postStartCommand": "./bootstrap && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/home/sage/sage/local --with-sage-venv) && make build V=0", + "postStartCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/home/sage/sage/local --with-sage-venv) && make build V=0", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/ubuntu-jammy-standard/devcontainer.json b/.devcontainer/ubuntu-jammy-standard/devcontainer.json index 329235ea1ca..e544f561a17 100644 --- a/.devcontainer/ubuntu-jammy-standard/devcontainer.json +++ b/.devcontainer/ubuntu-jammy-standard/devcontainer.json @@ -16,7 +16,7 @@ // Run commands after the container is created: "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. - "postStartCommand": "./bootstrap && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", + "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", "extensions": [ "ms-python.python" ] From 17922881e1f198ab7ad145d8f0608ecfdb874d60 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 22 May 2022 07:32:23 -0700 Subject: [PATCH 074/591] .devcontainer: Use prefixes 'downstream-', 'portability-' --- .../devcontainer.json | 0 .../devcontainer.json | 0 .../devcontainer.json | 0 src/doc/en/developer/portability_testing.rst | 4 ++-- 4 files changed, 2 insertions(+), 2 deletions(-) rename .devcontainer/{archlinux-latest-downstream => downstream-archlinux-latest}/devcontainer.json (100%) rename .devcontainer/{conda-forge-latest-downstream => downstream-conda-forge-latest}/devcontainer.json (100%) rename .devcontainer/{ubuntu-jammy-standard => portability-ubuntu-jammy-standard}/devcontainer.json (100%) diff --git a/.devcontainer/archlinux-latest-downstream/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json similarity index 100% rename from .devcontainer/archlinux-latest-downstream/devcontainer.json rename to .devcontainer/downstream-archlinux-latest/devcontainer.json diff --git a/.devcontainer/conda-forge-latest-downstream/devcontainer.json b/.devcontainer/downstream-conda-forge-latest/devcontainer.json similarity index 100% rename from .devcontainer/conda-forge-latest-downstream/devcontainer.json rename to .devcontainer/downstream-conda-forge-latest/devcontainer.json diff --git a/.devcontainer/ubuntu-jammy-standard/devcontainer.json b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json similarity index 100% rename from .devcontainer/ubuntu-jammy-standard/devcontainer.json rename to .devcontainer/portability-ubuntu-jammy-standard/devcontainer.json diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 102115aa504..da95ef4440c 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1159,8 +1159,8 @@ Sage provides sample ``devcontainer.json`` configuration files for this purpose. To get started, copy (or symlink) the sample file -`.devcontainer/ubuntu-jammy-standard/devcontainer.json -`_ +`.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +`_ to ``devcontainer.json`` in the directory ``.devcontainer``. It uses ``ubuntu-jammy-standard`` and the most recent development version Sage (``dev`` tag). You can edit a copy of the configuration file to From b828e559e1851f7ab4c1cdcc851701561bd01bb7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 8 Jul 2022 17:29:01 -0700 Subject: [PATCH 075/591] Remove use of _develop package --- .../downstream-archlinux-latest/devcontainer.json | 2 +- .devcontainer/post_create.sh | 10 ++++++---- src/doc/en/developer/portability_testing.rst | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.devcontainer/downstream-archlinux-latest/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json index a52cf869878..df959894af8 100644 --- a/.devcontainer/downstream-archlinux-latest/devcontainer.json +++ b/.devcontainer/downstream-archlinux-latest/devcontainer.json @@ -3,7 +3,7 @@ "name": "archlinux:latest downstream Sage", "image": "archlinux:latest", // Run commands after the container is created: - "postCreateCommand": "EXTRA_SAGE_PACKAGES='_sagemath notebook pip' .devcontainer/post_create.sh", + "postCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh", // Run commands after the container is started. "postStartCommand": "make configure && ln -sf /usr venv", "extensions": [ diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh index e7d8ab4db0d..d680746fb33 100755 --- a/.devcontainer/post_create.sh +++ b/.devcontainer/post_create.sh @@ -1,9 +1,11 @@ #! /bin/sh # Run this script from SAGE_ROOT. Invoke with "--sudo" if sudo is needed. -# -# Install standard development tools - see SAGE_ROOT/build/pkgs/_develop -# This includes the prerequisites for VS Code remote containers, export PATH=$(pwd)/build/bin:$PATH SYSTEM=$(sage-guess-package-system) eval $(sage-print-system-package-command $SYSTEM "$@" update) -eval $(sage-print-system-package-command $SYSTEM --yes "$@" --spkg install _prereq _develop $(head -n 1 build/pkgs/_develop/dependencies) $EXTRA_SAGE_PACKAGES) +if [ -n "$EXTRA_SAGE_PACKAGES" ]; then + eval $(sage-print-system-package-command $SYSTEM --yes "$@" --spkg install _prereq $EXTRA_SAGE_PACKAGES) +fi +if [ -n "$EXTRA_SYSTEM_PACKAGES" ]; then + eval $(sage-print-system-package-command $SYSTEM --yes "$@" install $EXTRA_SYSTEM_PACKAGES) +fi diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index da95ef4440c..5fd2e051fd4 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1168,7 +1168,7 @@ change to a different platform or another version. Then, opening the Sage repository in the configured devcontainer pulls the image from ghcr.io, installs `additional system packages for -development <../reference/spkg/_develop.html>`_, and builds Sage from +development`_, and builds Sage from source, reusing the installation (:envvar:`SAGE_LOCAL`, :envvar:`SAGE_VENV`) from the image. From e12ca6cf399c6898873de5ebbc363a7e7e442d0e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 8 Jul 2022 17:41:06 -0700 Subject: [PATCH 076/591] .devcontainer: Install git --- .devcontainer/post_create.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh index d680746fb33..0a9dd9951d1 100755 --- a/.devcontainer/post_create.sh +++ b/.devcontainer/post_create.sh @@ -3,9 +3,7 @@ export PATH=$(pwd)/build/bin:$PATH SYSTEM=$(sage-guess-package-system) eval $(sage-print-system-package-command $SYSTEM "$@" update) -if [ -n "$EXTRA_SAGE_PACKAGES" ]; then - eval $(sage-print-system-package-command $SYSTEM --yes "$@" --spkg install _prereq $EXTRA_SAGE_PACKAGES) -fi +eval $(sage-print-system-package-command $SYSTEM --yes "$@" --spkg install _prereq git $EXTRA_SAGE_PACKAGES) if [ -n "$EXTRA_SYSTEM_PACKAGES" ]; then eval $(sage-print-system-package-command $SYSTEM --yes "$@" install $EXTRA_SYSTEM_PACKAGES) fi From 6a6ce788c8de36347a10ad431387fc29b3895b38 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 8 Jul 2022 18:54:38 -0700 Subject: [PATCH 077/591] src/doc/en/developer/portability_testing.rst: Fix markup --- src/doc/en/developer/portability_testing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 5fd2e051fd4..0002c24b17d 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1167,8 +1167,8 @@ to ``devcontainer.json`` in the directory ``.devcontainer``. It uses change to a different platform or another version. Then, opening the Sage repository in the configured devcontainer pulls the -image from ghcr.io, installs `additional system packages for -development`_, and builds Sage from +image from ghcr.io, installs additional system packages for +development, and builds Sage from source, reusing the installation (:envvar:`SAGE_LOCAL`, :envvar:`SAGE_VENV`) from the image. From 6ef8f5fa39ba783d3bf7fa7eef0a882ea2ac774e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 11 Jul 2022 10:58:35 +0900 Subject: [PATCH 078/591] Implementing the quantum Clifford at a root of unity. --- src/sage/algebras/quantum_clifford.py | 573 +++++++++++++++++++++----- 1 file changed, 481 insertions(+), 92 deletions(-) diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index 35b84838f4c..a43e40c14ee 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -26,6 +26,7 @@ from sage.sets.family import Family from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from itertools import product +from sage.misc.misc import powerset class QuantumCliffordAlgebra(CombinatorialFreeModule): r""" @@ -34,7 +35,7 @@ class QuantumCliffordAlgebra(CombinatorialFreeModule): The *quantum Clifford algebra*, or `q`-Clifford algebra, of rank `n` and twist `k` is the unital associative algebra `\mathrm{Cl}_{q}(n, k)` over a field `F` with generators - `\psi_a, \psi_a^*, \omega_a` for `a = 1, \dotsc, n` that + `\psi_a, \psi_a^*, \omega_a` for `a = 1, \ldots, n` that satisfy the following relations: .. MATH:: @@ -46,14 +47,12 @@ class QuantumCliffordAlgebra(CombinatorialFreeModule): & \omega_a \psi^*_b & = \psi^*_b \omega_a, \\ \psi_a \psi_b & + \psi_b \psi_a = 0, & \psi^*_a \psi^*_b & + \psi^*_b \psi^*_a = 0, - \\ \psi_a \psi^*_a & = \frac{q^k \omega_a^{3k} - q^{-k} \omega_a^k}{q^k - q^{-k}}, - & \psi^*_a \psi_a & = \frac{q^{2k} (\omega_a - \omega_a^{3k})}{q^k - q^{-k}}, + \\ \psi_a \psi^*_a & + \q^k \psi^*_a \psi_a = \omega_a^{-k}, + & \psi^*_a \psi_a & + \q^{-k} \psi^*_a \psi_a = \omega_a^k, \\ \psi_a \psi^*_b & + \psi_b^* \psi_a = 0 - & & \text{if } a \neq b, + & & \text{if } a \neq b. \end{aligned} - where `q \in F` such that `q^{2k} \neq 1`. - When `k = 2`, we recover the original definition given by Hayashi in [Hayashi1990]_. The `k = 1` version was used in [Kwon2014]_. @@ -127,6 +126,19 @@ class QuantumCliffordAlgebra(CombinatorialFreeModule): 0 sage: f1 * f1 * f2 - (q^1 + q^-1) * f1 * f2 * f1 + f2 * f1 * f1 0 + + This also can be constructed at the special point when `q^{2k} = 1`, + but the basis used is different:: + + sage: Cl = algebras.QuantumClifford(1, 1, -1) + sage: Cl.inject_variables() + Defining psi0, psid0, w0 + sage: psi0 * psid0 + psi0*psid0 + sage: psid0 * psi0 + -w0 + psi0*psid0 + sage; w0^2 + 1 """ @staticmethod def __classcall_private__(cls, n, k=1, q=None, F=None): @@ -148,40 +160,33 @@ def __classcall_private__(cls, n, k=1, q=None, F=None): F = q.parent() q = F(q) if F not in Fields(): - raise TypeError("base ring must be a field") - return super(QuantumCliffordAlgebra, cls).__classcall__(cls, n, k, q, F) + try: + F = F.fraction_field() + q = F(q) + except Exception: + raise TypeError("base ring must be a field or have a fraction field") - def __init__(self, n, k, q, F): + if bool(q**(2*k) == 1): + return QuantumCliffordAlgebraRootUnity(n, k, q, F) + return QuantumCliffordAlgebraGeneric(n, k, q, F) + + def __init__(self, n, k, q, F, psi, indices): r""" Initialize ``self``. EXAMPLES:: - sage: Cl = algebras.QuantumClifford(1,2) + sage: Cl = algebras.QuantumClifford(1, 2) sage: TestSuite(Cl).run(elements=Cl.basis()) - - sage: Cl = algebras.QuantumClifford(1,3) - sage: TestSuite(Cl).run(elements=Cl.basis()) # long time - - sage: Cl = algebras.QuantumClifford(3) # long time - sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) # long time - sage: TestSuite(Cl).run(elements=elts) # long time - - sage: Cl = algebras.QuantumClifford(2,4) # long time - sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) # long time - sage: TestSuite(Cl).run(elements=elts) # long time """ self._n = n self._k = k self._q = q - self._psi = cartesian_product([(-1,0,1)]*n) self._w_poly = PolynomialRing(F, n, 'w') - indices = [(tuple(psi), tuple(w)) - for psi in self._psi - for w in product(*[list(range((4-2*abs(psi[i]))*k)) for i in range(n)])] + self._psi = psi indices = FiniteEnumeratedSet(indices) - cat = Algebras(F).FiniteDimensional().WithBasis() + cat = Algebras(F).FiniteDimensional().Semisimple().WithBasis() CombinatorialFreeModule.__init__(self, F, indices, category=cat) self._assign_names(self.algebra_generators().keys()) @@ -210,67 +215,6 @@ def _latex_(self): """ return "\\operatorname{Cl}_{%s}(%s, %s)" % (self._q, self._n, self._k) - def _repr_term(self, m): - r""" - Return a string representation of the basis element indexed by ``m``. - - EXAMPLES:: - - sage: Cl = algebras.QuantumClifford(3, 3) - sage: Cl._repr_term( ((1, 0, -1), (0, -2, 5)) ) - 'psi0*psid2*w1^-2*w2^5' - sage: Cl._repr_term( ((1, 0, -1), (0, 0, 0)) ) - 'psi0*psid2' - sage: Cl._repr_term( ((0, 0, 0), (0, -2, 5)) ) - 'w1^-2*w2^5' - sage: Cl._repr_term( ((0, 0, 0), (0, 0, 0)) ) - '1' - - sage: Cl(5) - 5 - """ - p, v = m - rp = '*'.join('psi%s'%i if p[i] > 0 else 'psid%s'%i - for i in range(self._n) if p[i] != 0) - gen_str = lambda e: '' if e == 1 else '^%s'%e - rv = '*'.join('w%s'%i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) - if rp: - if rv: - return rp + '*' + rv - return rp - if rv: - return rv - return '1' - - def _latex_term(self, m): - r""" - Return a latex representation for the basis element indexed by ``m``. - - EXAMPLES:: - - sage: Cl = algebras.QuantumClifford(3, 3) - sage: Cl._latex_term( ((1, 0, -1), (0, -2, 5)) ) - '\\psi_{0}\\psi^{\\dagger}_{2}\\omega_{1}^{-2}\\omega_{2}^{5}' - sage: Cl._latex_term( ((1, 0, -1), (0, 0, 0)) ) - '\\psi_{0}\\psi^{\\dagger}_{2}' - sage: Cl._latex_term( ((0, 0, 0), (0, -2, 5)) ) - '\\omega_{1}^{-2}\\omega_{2}^{5}' - sage: Cl._latex_term( ((0, 0, 0), (0, 0, 0)) ) - '1' - - sage: latex(Cl(5)) - 5 - """ - p, v = m - rp = ''.join('\\psi_{%s}'%i if p[i] > 0 else '\\psi^{\\dagger}_{%s}'%i - for i in range(self._n) if p[i] != 0) - gen_str = lambda e: '' if e == 1 else '^{%s}'%e - rv = ''.join('\\omega_{%s}'%i + gen_str(v[i]) - for i in range(self._n) if v[i] != 0) - if not rp and not rv: - return '1' - return rp + rv - def q(self): r""" Return the `q` of ``self``. @@ -321,8 +265,8 @@ def dimension(self): sage: Cl.dimension() 512 - sage: Cl = algebras.QuantumClifford(4, 2) - sage: Cl.dimension() + sage: Cl = algebras.QuantumClifford(4, 2) # long time + sage: Cl.dimension() # long time 65536 """ return ZZ(8*self._k) ** self._n @@ -382,6 +326,120 @@ def one_basis(self): """ return (self._psi([0]*self._n), (0,)*self._n) +class QuantumCliffordAlgebraGeneric(QuantumCliffordAlgebra): + r""" + The quantum Clifford algebra when `q^{2k} \neq 1`. + + The *quantum Clifford algebra*, or `q`-Clifford algebra, + of rank `n` and twist `k` is the unital associative algebra + `\mathrm{Cl}_{q}(n, k)` over a field `F` with generators + `\psi_a, \psi_a^*, \omega_a` for `a = 1, \ldots, n` that + satisfy the following relations: + + .. MATH:: + + \begin{aligned} + \omega_a \omega_b & = \omega_b \omega_a, + & \omega_a^{4k} & = (1 + q^{-2k}) \omega_a^{2k} - q^{-2k}, + \\ \omega_a \psi_b & = q^{\delta_{ab}} \psi_b \omega_a, + & \omega_a \psi^*_b & = \psi^*_b \omega_a, + \\ \psi_a \psi_b & + \psi_b \psi_a = 0, + & \psi^*_a \psi^*_b & + \psi^*_b \psi^*_a = 0, + \\ \psi_a \psi^*_a & = \frac{q^k \omega_a^{3k} - q^{-k} \omega_a^k}{q^k - q^{-k}}, + & \psi^*_a \psi_a & = \frac{q^{2k} (\omega_a - \omega_a^{3k})}{q^k - q^{-k}}, + \\ \psi_a \psi^*_b & + \psi_b^* \psi_a = 0 + & & \text{if } a \neq b, + \end{aligned} + + where `q \in F` such that `q^{2k} \neq 1`. + + When `k = 2`, we recover the original definition given by Hayashi in + [Hayashi1990]_. The `k = 1` version was used in [Kwon2014]_. + """ + def __init__(self, n, k, q, F): + r""" + Initialize ``self``. + + TESTS:: + + sage: Cl = algebras.QuantumClifford(1,3) + sage: TestSuite(Cl).run(elements=Cl.basis()) # long time + + sage: Cl = algebras.QuantumClifford(3) + sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) + sage: TestSuite(Cl).run(elements=elts) # long time + + sage: Cl = algebras.QuantumClifford(2, 4) + sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) + sage: TestSuite(Cl).run(elements=elts) # long time + """ + psi = cartesian_product([(-1,0,1)]*n) + indices = [(tuple(p), tuple(w)) + for p in psi + for w in product(*[list(range((4-2*abs(p[i]))*k)) for i in range(n)])] + super().__init__(n, k, q, F, psi, indices) + + def _repr_term(self, m): + r""" + Return a string representation of the basis element indexed by ``m``. + + EXAMPLES:: + + sage: Cl = algebras.QuantumClifford(3, 3) + sage: Cl._repr_term( ((1, 0, -1), (0, 2, 5)) ) + 'psi0*psid2*w1^2*w2^5' + sage: Cl._repr_term( ((1, 0, -1), (0, 0, 0)) ) + 'psi0*psid2' + sage: Cl._repr_term( ((0, 0, 0), (0, 2, 5)) ) + 'w1^2*w2^5' + sage: Cl._repr_term( ((0, 0, 0), (0, 0, 0)) ) + '1' + + sage: Cl(5) + 5 + """ + p, v = m + rp = '*'.join('psi%s'%i if p[i] > 0 else 'psid%s'%i + for i in range(self._n) if p[i] != 0) + gen_str = lambda e: '' if e == 1 else '^%s'%e + rv = '*'.join('w%s'%i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) + if rp: + if rv: + return rp + '*' + rv + return rp + if rv: + return rv + return '1' + + def _latex_term(self, m): + r""" + Return a latex representation for the basis element indexed by ``m``. + + EXAMPLES:: + + sage: Cl = algebras.QuantumClifford(3, 3) + sage: Cl._latex_term( ((1, 0, -1), (0, -2, 5)) ) + '\\psi_{0}\\psi^{\\dagger}_{2}\\omega_{1}^{-2}\\omega_{2}^{5}' + sage: Cl._latex_term( ((1, 0, -1), (0, 0, 0)) ) + '\\psi_{0}\\psi^{\\dagger}_{2}' + sage: Cl._latex_term( ((0, 0, 0), (0, -2, 5)) ) + '\\omega_{1}^{-2}\\omega_{2}^{5}' + sage: Cl._latex_term( ((0, 0, 0), (0, 0, 0)) ) + '1' + + sage: latex(Cl(5)) + 5 + """ + p, v = m + rp = ''.join('\\psi_{%s}'%i if p[i] > 0 else '\\psi^{\\dagger}_{%s}'%i + for i in range(self._n) if p[i] != 0) + gen_str = lambda e: '' if e == 1 else '^{%s}'%e + rv = ''.join('\\omega_{%s}'%i + gen_str(v[i]) + for i in range(self._n) if v[i] != 0) + if not rp and not rv: + return '1' + return rp + rv + @cached_method def product_on_basis(self, m1, m2): r""" @@ -407,6 +465,7 @@ def product_on_basis(self, m1, m2): """ p1, w1 = m1 p2, w2 = m2 + # Check for \psi_i^2 == 0 and for the dagger version if any(p1[i] != 0 and p1[i] == p2[i] for i in range(self._n)): return self.zero() @@ -508,6 +567,9 @@ def inverse(self): sage: w * w^-1 1 + sage: (2*w0)^-1 + ((q^2+1)/2)*w0 - q^2/2*w0^3 + sage: (w0 + w1)^-1 Traceback (most recent call last): ... @@ -530,7 +592,7 @@ def inverse(self): if len(self) != 1: raise NotImplementedError("inverse only implemented for basis elements") Cl = self.parent() - p, w = self.support_of_term() + ((p, w), coeff), = list(self._monomial_coefficients.items()) if any(p[i] != 0 for i in range(Cl._n)): raise NotImplementedError("inverse only implemented for" " product of w generators") @@ -543,7 +605,334 @@ def inverse(self): poly = poly.reduce([wi**(4*k) - (1 + q**(-2*k)) * wi**(2*k) + q**(-2*k) for wi in wp]) pdict = poly.dict() - ret = {(p, tuple(e)): c for e, c in pdict.items()} - return Cl._from_dict(ret) + coeff = coeff.inverse_of_unit() + ret = {(p, tuple(e)): coeff * c for e, c in pdict.items()} + return Cl.element_class(Cl, ret) + + __invert__ = inverse + +class QuantumCliffordAlgebraRootUnity(QuantumCliffordAlgebra): + r""" + The quantum Clifford algebra when `q^{2k} = 1`. + + The *quantum Clifford algebra*, or `q`-Clifford algebra, + of rank `n` and twist `k` is the unital associative algebra + `\mathrm{Cl}_{q}(n, k)` over a field `F` with generators + `\psi_a, \psi_a^*, \omega_a` for `a = 1, \ldots, n` that + satisfy the following relations: + + .. MATH:: + + \begin{aligned} + \omega_a \omega_b & = \omega_b \omega_a, + & \omega_a^{2k} & = 1, + \\ \omega_a \psi_b & = q^{\delta_{ab}} \psi_b \omega_a, + & \omega_a \psi^*_b & = \psi^*_b \omega_a, + \\ \psi_a \psi_b & + \psi_b \psi_a = 0, + & \psi^*_a \psi^*_b & + \psi^*_b \psi^*_a = 0, + \\ \psi_a \psi^*_a + q^k \psi^*_a \psi_a & = \omega_a^k + & \psi_a \psi^*_b & + \psi_b^* \psi_a = 0 \quad (a \neq b), + \end{aligned} + + where `q \in F` such that `q^{2k} = 1`. This has further relations of + + .. MATH:: + + \begin{aligned} + \psi^*_a \psi_a \psi^*_a & = \psi^*_a \omega_a^k, + \\ + \psi_a \psi^*_a \psi_a & = q^k \psi_a \omega_a^k, + \\ + (\psi_a \psi^*_a)^2 & = \psi_a \psi^*_a \omega_a^k. + \end{aligned} + """ + def __init__(self, n, k, q, F): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: Cl = algebras.QuantumClifford(1,2,-1) + sage: TestSuite(Cl).run(elements=Cl.basis()) + + sage: z = CyclotomicField(3).gen() + sage: Cl = algebras.QuantumClifford(1,3,z) + sage: TestSuite(Cl).run(elements=Cl.basis()) + + sage: Cl = algebras.QuantumClifford(3,1,-1) + sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) + sage: TestSuite(Cl).run(elements=elts) # long time + + sage: Cl = algebras.QuantumClifford(2,4,-1) + sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) + sage: TestSuite(Cl).run(elements=elts) # long time + """ + psi = cartesian_product([(-1,0,1,2)]*n) + indices = [(tuple(p), tuple(w)) + for p in psi + for w in product(list(range(2*k)), repeat=n)] + super().__init__(n, k, q, F, psi, indices) + + def _repr_term(self, m): + r""" + Return a string representation of the basis element indexed by ``m``. + + EXAMPLES:: + + sage: Cl = algebras.QuantumClifford(3, 3, -1) + sage: Cl._repr_term( ((1, 0, -1), (0, 2, 5)) ) + 'psi0*psid2*w1^2*w2^5' + sage: Cl._repr_term( ((1, 0, 2), (0, 0, 0)) ) + 'psi0*psi2*psid2' + sage: Cl._repr_term( ((0, 0, 0), (0, 2, 5)) ) + 'w1^2*w2^5' + sage: Cl._repr_term( ((0, 0, 0), (0, 0, 0)) ) + '1' + + sage: Cl(5) + 5 + """ + p, v = m + def ppr(i): + val = p[i] + if val == -1: + return 'psid%s'%i + elif val == 1: + return 'psi%s'%i + elif val == 2: + return 'psi%s*psid%s'%(i,i) + rp = '*'.join(ppr(i) for i in range(self._n) if p[i] != 0) + gen_str = lambda e: '' if e == 1 else '^%s'%e + rv = '*'.join('w%s'%i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) + if rp: + if rv: + return rp + '*' + rv + return rp + if rv: + return rv + return '1' + + def _latex_term(self, m): + r""" + Return a latex representation for the basis element indexed by ``m``. + + EXAMPLES:: + + sage: Cl = algebras.QuantumClifford(3, 3, -1) + sage: Cl._latex_term( ((1, 0, -1), (0, 2, 5)) ) + '\\psi_{0}\\psi^{\\dagger}_{2}\\omega_{1}^{2}\\omega_{2}^{5}' + sage: Cl._latex_term( ((1, 0, 2), (0, 0, 0)) ) + '\\psi_{0}\\psi_{2}\\psi^{\\dagger}_{2}' + sage: Cl._latex_term( ((0, 0, 0), (0, 2, 5)) ) + '\\omega_{1}^{2}\\omega_{2}^{5}' + sage: Cl._latex_term( ((0, 0, 0), (0, 0, 0)) ) + '1' + + sage: latex(Cl(5)) + 5 + """ + p, v = m + def ppr(i): + val = p[i] + if val == -1: + return '\\psi^{\\dagger}_{%s}'%i + elif val == 1: + return '\\psi_{%s}'%i + elif val == 2: + return '\\psi_{%s}\\psi^{\\dagger}_{%s}'%(i,i) + rp = ''.join(ppr(i) for i in range(self._n) if p[i] != 0) + gen_str = lambda e: '' if e == 1 else '^{%s}'%e + rv = ''.join('\\omega_{%s}'%i + gen_str(v[i]) + for i in range(self._n) if v[i] != 0) + if not rp and not rv: + return '1' + return rp + rv + + @cached_method + def product_on_basis(self, m1, m2): + r""" + Return the product of the basis elements indexed by ``m1`` and ``m2``. + + EXAMPLES:: + + sage: z = CyclotomicField(3).gen() + sage: Cl = algebras.QuantumClifford(3, 3, z) + sage: Cl.inject_variables() + Defining psi0, psi1, psi2, psid0, psid1, psid2, w0, w1, w2 + sage: psi0^2 # indirect doctest + 0 + sage: psid0^2 + 0 + sage: w0 * psi0 + -(-zeta3)*psi0*w0 + sage: w0 * psid0 + -(zeta3+1)*psid0*w0 + sage: psi0 * psid0 + psi0*psid0 + sage: psid0 * psi0 + w0^3 - psi0*psid0 + sage: w2 * w0 + w0*w2 + sage: w0^6 + 1 + sage: psi0 * psi1 + psi0*psi1 + sage: psi1 * psi0 + -psi0*psi1 + sage: psi1 * (psi0 * psi2) + -psi0*psi1*psi2 + + sage: z = CyclotomicField(6).gen() + sage: Cl = algebras.QuantumClifford(3, 3, z) + sage: Cl.inject_variables() + Defining psi0, psi1, psi2, psid0, psid1, psid2, w0, w1, w2 + + sage: psid1 * (psi1 * psid1) + psid1*w1^3 + sage: (psi1* psid1) * (psi1 * psid1) + psi1*psid1*w1^3 + sage: (psi1 * psid1) * psi1 + -psi1*w1^3 + """ + p1, w1 = m1 + p2, w2 = m2 + k = self._k + tk = 2 * k + + # \psi_i is represented by a 1 in p1[i] and p2[i] + # \psi_i^{\dagger} is represented by a -1 in p1[i] and p2[i] + # \psi_i \psi_i^{\dagger} is a 2 in p1[i] and p2[i] + + # Check for \psi_i^2 == 0 and for the dagger version + if any((p1[i] % 2 != 0 and p1[i] == p2[i]) + or (p1[i] == 2 and p2[i] == -1) or (p2[i] == 2 and p1[i] == 1) + for i in range(self._n)): + return self.zero() + + # Reduce any v_i^{2k} = 1 + v = [(w1[i] + w2[i]) % tk for i in range(self._n)] + + q_power = 0 + sign = 1 + pairings = [] + p = [0] * self._n + # Move w1 * p2 to q^q_power * p2 * w1 + # Also find pairs \psi_i \psi_i^{\dagger} (or vice versa) and + # count the sign from moving \psi_i and \psi_i^{\dagger} into position + num_cross = 0 + total_cross = 0 + for i in range(self._n): + num_cross += p2[i] + if p2[i] == 2: + # By the above check, we cannot have p1[i] == 1 + if p1[i] != 0: + v[i] = (v[i] + k) % tk + p[i] = p1[i] + else: + p[i] = p2[i] + elif p2[i] != 0: # == +1, -1 + q_power += w1[i] * p2[i] + # By the above check, we cannot have p1[i] == p2[i] + if p1[i] == -1: + pairings.append(i) + total_cross -= 1 # correction + p[i] = None + elif p1[i] == 1: + total_cross -= 1 # correction + p[i] = 2 + elif p1[i] == 2: + q_power += k + v[i] = (v[i] + k) % tk + p[i] = p2[i] + else: + p[i] = p2[i] + else: + p[i] = p1[i] # since p2[i] == 0 + + if abs(p1[i]) == 1: + total_cross += num_cross + + # total_cross does not need to actually be the total number of crossings; just correct mod 2 + if total_cross % 2: + sign = -sign + + # Replace \psi_i^{\dagger} \psi_i = q^k ( w^k - \psi_i \psi_i^{\dagger} ) + def key(X): + e = list(v) # Make a copy + for i in pairings: + if i in X: + p[i] = 2 + else: + p[i] = 0 + e[i] = (e[i] + k) % tk + return (self._psi(p), tuple(e)) + + q = self._q + ret = {key(X): (-1)**len(X) * sign * q**(q_power+k*(len(pairings)%2)) + for X in powerset(pairings)} + + return self._from_dict(ret) + + class Element(QuantumCliffordAlgebra.Element): + def inverse(self): + r""" + Return the inverse if ``self`` is a basis element. + + EXAMPLES:: + + sage: Cl = algebras.QuantumClifford(3, 3, -1) + sage: Cl.inject_variables() + Defining psi0, psi1, psi2, psid0, psid1, psid2, w0, w1, w2 + sage: w0^-1 + w0^5 + sage: w0^-1 * w0 + 1 + sage: w0^-2 + w0^4 + sage: w0^-2 * w0^2 + 1 + sage: w0^-2 * w0 == w0^-1 + True + sage: w = w0 * w1^3 + sage: w^-1 + w0^5*w1^3 + sage: w^-1 * w + 1 + sage: w * w^-1 + 1 + + sage: (2*w0)^-1 + 1/2*w0^5 + + sage: (w0 + w1)^-1 + Traceback (most recent call last): + ... + NotImplementedError: inverse only implemented for basis elements + sage: (psi0 * w0)^-1 + Traceback (most recent call last): + ... + NotImplementedError: inverse only implemented for product of w generators + + sage: Cl = algebras.QuantumClifford(2, 2, -1) + sage: Cl.inject_variables() + Defining psi0, psi1, psid0, psid1, w0, w1 + sage: w0^-1 + w0^3 + sage: w0 * w0^-1 + 1 + """ + if not self: + raise ZeroDivisionError + if len(self) != 1: + raise NotImplementedError("inverse only implemented for basis elements") + Cl = self.parent() + ((p, w), coeff), = list(self._monomial_coefficients.items()) + if any(p[i] != 0 for i in range(Cl._n)): + raise NotImplementedError("inverse only implemented for" + " product of w generators") + tk = 2 * Cl._k + w = tuple([tk-val if val else 0 for val in w]) + return Cl.element_class(Cl, {(p, w) : coeff.inverse_of_unit()}) __invert__ = inverse + From e29f11920b8e871088469bd79eec4e938aea6f2e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 11 Jul 2022 11:12:08 +0900 Subject: [PATCH 079/591] Use the generic inverse code when not a special case of a monomial. --- src/sage/algebras/quantum_clifford.py | 41 ++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index a43e40c14ee..dc30f5f57c0 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -137,7 +137,7 @@ class QuantumCliffordAlgebra(CombinatorialFreeModule): psi0*psid0 sage: psid0 * psi0 -w0 + psi0*psid0 - sage; w0^2 + sage: w0^2 1 """ @staticmethod @@ -545,9 +545,9 @@ def inverse(self): EXAMPLES:: - sage: Cl = algebras.QuantumClifford(3) + sage: Cl = algebras.QuantumClifford(2) sage: Cl.inject_variables() - Defining psi0, psi1, psi2, psid0, psid1, psid2, w0, w1, w2 + Defining psi0, psi1, psid0, psid1, w0, w1 sage: w0^-1 (q^2+1)*w0 - q^2*w0^3 sage: w0^-1 * w0 @@ -573,11 +573,17 @@ def inverse(self): sage: (w0 + w1)^-1 Traceback (most recent call last): ... - NotImplementedError: inverse only implemented for basis elements + ValueError: cannot invert self (= w1 + w0) sage: (psi0 * w0)^-1 Traceback (most recent call last): ... - NotImplementedError: inverse only implemented for product of w generators + ValueError: cannot invert self (= psi0*w0) + + sage: Cl = algebras.QuantumClifford(1, 2) + sage: Cl.inject_variables() + Defining psi0, psid0, w0 + sage: (psi0 + psid0).inverse() + psid0*w0^2 + q^2*psi0*w0^2 sage: Cl = algebras.QuantumClifford(2, 2) sage: Cl.inject_variables() @@ -590,12 +596,11 @@ def inverse(self): if not self: raise ZeroDivisionError if len(self) != 1: - raise NotImplementedError("inverse only implemented for basis elements") + return super().__invert__() Cl = self.parent() ((p, w), coeff), = list(self._monomial_coefficients.items()) if any(p[i] != 0 for i in range(Cl._n)): - raise NotImplementedError("inverse only implemented for" - " product of w generators") + return super().__invert__() poly = Cl._w_poly.monomial(*w) wp = Cl._w_poly.gens() q = Cl._q @@ -904,14 +909,25 @@ def inverse(self): sage: (2*w0)^-1 1/2*w0^5 + sage: Cl = algebras.QuantumClifford(3, 1, -1) + sage: Cl.inject_variables() + Defining psi0, psi1, psi2, psid0, psid1, psid2, w0, w1, w2 + sage: (w0 + w1)^-1 Traceback (most recent call last): ... - NotImplementedError: inverse only implemented for basis elements + ValueError: cannot invert self (= w1 + w0) sage: (psi0 * w0)^-1 Traceback (most recent call last): ... - NotImplementedError: inverse only implemented for product of w generators + ValueError: cannot invert self (= psi0*w0) + + sage: z = CyclotomicField(6).gen() + sage: Cl = algebras.QuantumClifford(1, 3, z) + sage: Cl.inject_variables() + Defining psi0, psid0, w0 + sage: (psi0 + psid0).inverse() + psid0*w0^3 - psi0*w0^3 sage: Cl = algebras.QuantumClifford(2, 2, -1) sage: Cl.inject_variables() @@ -924,12 +940,11 @@ def inverse(self): if not self: raise ZeroDivisionError if len(self) != 1: - raise NotImplementedError("inverse only implemented for basis elements") + return super().__invert__() Cl = self.parent() ((p, w), coeff), = list(self._monomial_coefficients.items()) if any(p[i] != 0 for i in range(Cl._n)): - raise NotImplementedError("inverse only implemented for" - " product of w generators") + return super().__invert__() tk = 2 * Cl._k w = tuple([tk-val if val else 0 for val in w]) return Cl.element_class(Cl, {(p, w) : coeff.inverse_of_unit()}) From 2f7cd217ed9a45235f36764576ce6f891dd30c6d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 12 Jul 2022 10:36:46 +0900 Subject: [PATCH 080/591] Fixing the quantum Clifford doc. --- src/sage/algebras/quantum_clifford.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index dc30f5f57c0..e204dc764b0 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -47,8 +47,8 @@ class QuantumCliffordAlgebra(CombinatorialFreeModule): & \omega_a \psi^*_b & = \psi^*_b \omega_a, \\ \psi_a \psi_b & + \psi_b \psi_a = 0, & \psi^*_a \psi^*_b & + \psi^*_b \psi^*_a = 0, - \\ \psi_a \psi^*_a & + \q^k \psi^*_a \psi_a = \omega_a^{-k}, - & \psi^*_a \psi_a & + \q^{-k} \psi^*_a \psi_a = \omega_a^k, + \\ \psi_a \psi^*_a & + q^k \psi^*_a \psi_a = \omega_a^{-k}, + & \psi^*_a \psi_a & + q^{-k} \psi^*_a \psi_a = \omega_a^k, \\ \psi_a \psi^*_b & + \psi_b^* \psi_a = 0 & & \text{if } a \neq b. \end{aligned} @@ -635,7 +635,7 @@ class QuantumCliffordAlgebraRootUnity(QuantumCliffordAlgebra): & \omega_a \psi^*_b & = \psi^*_b \omega_a, \\ \psi_a \psi_b & + \psi_b \psi_a = 0, & \psi^*_a \psi^*_b & + \psi^*_b \psi^*_a = 0, - \\ \psi_a \psi^*_a + q^k \psi^*_a \psi_a & = \omega_a^k + \\ \psi_a \psi^*_a & + q^k \psi^*_a \psi_a = \omega_a^k & \psi_a \psi^*_b & + \psi_b^* \psi_a = 0 \quad (a \neq b), \end{aligned} From 07ffd7a7c00bfeff47bb89aad9759ccaa1bc1c6b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 14 Jul 2022 09:10:27 +0900 Subject: [PATCH 081/591] Do not catch any exceptions; just let it fail. --- src/sage/algebras/quantum_clifford.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index e204dc764b0..9ddf7286070 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -160,11 +160,8 @@ def __classcall_private__(cls, n, k=1, q=None, F=None): F = q.parent() q = F(q) if F not in Fields(): - try: - F = F.fraction_field() - q = F(q) - except Exception: - raise TypeError("base ring must be a field or have a fraction field") + F = F.fraction_field() + q = F(q) if bool(q**(2*k) == 1): return QuantumCliffordAlgebraRootUnity(n, k, q, F) From 5b55aa0b6fd159f374032f6dae7547f60bd4e2b6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 15 Jul 2022 14:34:52 +0900 Subject: [PATCH 082/591] Use the FractionField function instead. --- src/sage/algebras/quantum_clifford.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index 9ddf7286070..4e5570ce6bf 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -24,6 +24,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.categories.cartesian_product import cartesian_product from sage.sets.family import Family +from sage.rings.fraction_field import FractionField from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from itertools import product from sage.misc.misc import powerset @@ -160,7 +161,7 @@ def __classcall_private__(cls, n, k=1, q=None, F=None): F = q.parent() q = F(q) if F not in Fields(): - F = F.fraction_field() + F = FractionField(F) q = F(q) if bool(q**(2*k) == 1): From c89110a60ec29ef94233fe48d51c84538aff93f9 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 15 Jul 2022 17:05:59 +0530 Subject: [PATCH 083/591] add translation for ellipticF --- src/sage/functions/special.py | 45 ++++++++++++++++++++++++++++++++++- src/sage/interfaces/fricas.py | 3 ++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 349553d734c..02596e49620 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -506,6 +506,21 @@ def __init__(self): sage: fricas(elliptic_e(x, y)).D(x).sage()/elliptic_e(x, y).diff(x) # optional - fricas cos(x)/sqrt(-sin(x)^2 + 1) + Numerically:: + + sage: f = lambda x, y: elliptic_e(arcsin(x), y).subs(x=x, y=y) # optional - fricas + sage: g = lambda x, y: fricas.ellipticE(x, y).sage() # optional - fricas + sage: d = lambda x, y: f(x, y) - g(x, y) # optional - fricas + sage: [d(N(-pi/2+x), y) for x in range(1, 3) for y in range(-2,2)] # optional - fricas tol 1e-8 + [0.000000000000000, + 0.000000000000000, + 0.000000000000000, + 0.000000000000000, + 5.55111512312578e-17, + 0.000000000000000, + 0.000000000000000, + 0.000000000000000] + """ BuiltinFunction.__init__(self, 'elliptic_e', nargs=2, # Maple conversion left out since it uses @@ -841,11 +856,39 @@ def __init__(self): elliptic_f sage: elliptic_f(x, 2)._sympy_() elliptic_f(x, 2) + + Check that :trac:`34186` is fixed:: + + sage: _ = var("x y") + sage: fricas(elliptic_f(x, y)) # optional - fricas + ellipticF(sin(x),y) + + However, the conversion is only correct in the interval + `[-\pi/2, \pi/2]`:: + + sage: fricas(elliptic_f(x, y)).D(x).sage()/elliptic_f(x, y).diff(x) # optional - fricas + cos(x)/sqrt(-sin(x)^2 + 1) + + Numerically:: + + sage: f = lambda x, y: elliptic_f(arcsin(x), y).subs(x=x, y=y) # optional - fricas + sage: g = lambda x, y: fricas.ellipticF(x, y).sage() # optional - fricas + sage: d = lambda x, y: f(x, y) - g(x, y) # optional - fricas + sage: [d(N(-pi/2+x), y) for x in range(1, 3) for y in range(-2,2)] # optional - fricas tol 1e-8 + [0.000000000000000, + 0.000000000000000, + 0.000000000000000, + 0.000000000000000, + 5.55111512312578e-17, + 0.000000000000000, + 0.000000000000000, + 0.000000000000000] + """ BuiltinFunction.__init__(self, 'elliptic_f', nargs=2, conversions=dict(mathematica='EllipticF', maxima='elliptic_f', - # fricas='ellipticF', buggy + fricas='((x,y)+->ellipticF(sin(x), y))', sympy='elliptic_f')) def _eval_(self, z, m): diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index dee071c736b..99d481b5bd5 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -576,7 +576,7 @@ def _register_symbols(): from sage.functions.hyperbolic import tanh, sinh, cosh, coth, sech, csch from sage.functions.other import abs from sage.functions.gamma import gamma - from sage.functions.special import elliptic_e + from sage.functions.special import elliptic_e, elliptic_f from sage.misc.functional import symbolic_sum, symbolic_prod from sage.rings.infinity import infinity register_symbol(pi, {'fricas': 'pi'}, 0) # %pi::INFORM is %pi, but (pi) also exists @@ -598,6 +598,7 @@ def _register_symbols(): register_symbol(gamma, {'fricas': 'Gamma'}, 1) register_symbol(gamma, {'fricas': 'Gamma'}, 2) register_symbol(lambda x, y: elliptic_e(asin(x), y), {'fricas': 'ellipticE'}, 2) + register_symbol(lambda x, y: elliptic_f(asin(x), y), {'fricas': 'ellipticF'}, 2) register_symbol(lambda x, y: x + y, {'fricas': '+'}, 2) register_symbol(lambda x, y: x - y, {'fricas': '-'}, 2) register_symbol(lambda x, y: x * y, {'fricas': '*'}, 2) From 0b343bdacca6b2a9985326d3e46ed2f5e701bac3 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 15 Jul 2022 21:53:17 +0530 Subject: [PATCH 084/591] provide hash for decorated permutations --- src/sage/combinat/decorated_permutation.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/combinat/decorated_permutation.py b/src/sage/combinat/decorated_permutation.py index 2632364aff2..03d3e2fb495 100644 --- a/src/sage/combinat/decorated_permutation.py +++ b/src/sage/combinat/decorated_permutation.py @@ -86,6 +86,17 @@ def check(self): if self not in self.parent(): raise ValueError("{} is not a decorated permutation".format(self)) + def __hash__(self): + r""" + Return a hash of ``self``. + + TESTS:: + + sage: len(set(hash(pi) for pi in DecoratedPermutations(3))) + 16 + """ + return hash(tuple(self)) + def __eq__(self, other): """ Check whether ``self`` is equal to ``other``. From 104f997ba8c95292b04c2dc7a2241d7621b51af8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 10:28:06 -0700 Subject: [PATCH 085/591] src/sage/doctest/sources.py: Remove trailing spaces in ... --- src/sage/doctest/sources.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index 3136139e10a..6321e73a5e8 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -764,8 +764,8 @@ def _test_enough_doctests(self, check_extras=True, verbose=True): INPUT: - ``check_extras`` -- bool (default ``True``), whether to check if - doctests are created that do not correspond to either a ``sage: `` - or a ``>>> `` prompt + doctests are created that do not correspond to either a ``sage:`` + or a ``>>>`` prompt - ``verbose`` -- bool (default ``True``), whether to print offending line numbers when there are missing or extra tests From 53f10b4550de55c60acf7d8ef272b310af7c2509 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 13:33:07 -0700 Subject: [PATCH 086/591] src/tox.ini (rst): Exclude sage/graphs/graph_plot.py --- src/tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tox.ini b/src/tox.ini index e95a6dfd466..e06d3b68186 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -218,7 +218,9 @@ extend-ignore = # Ignore RST306 Unknown target name -- because of references to the global bibliography RST306 exclude = + # Avoid errors by exclude files with generated docstring portions such as {PLOT_OPTIONS_TABLE} sage/combinat/designs/database.py + sage/graphs/graph_plot.py sage/misc/sagedoc.py [pytest] From ce10cae6f4b5854b59e46408686adc085138a8f1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 13:38:19 -0700 Subject: [PATCH 087/591] src/sage/repl/interpreter.py: Use directive 'attr' instead of 'attribute' --- src/sage/repl/interpreter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index d7ba014361d..b6a0e5a5b56 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -463,7 +463,7 @@ def __init__(self, *args, **kwds): Initialize this class. All of the arguments get passed to :meth:`PrefilterTransformer.__init__`. - .. attribute:: temporary_objects + .. attr:: temporary_objects a list of hold onto interface objects and keep them from being garbage collected From 1bd6e3c9f5fbfbf8083be9fdf98ca335c6e0c1d7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 13:39:19 -0700 Subject: [PATCH 088/591] .github/workflows/lint.yml: Remove continue-on-error for lint-rst --- .github/workflows/lint.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8456f3666dc..811a61cc928 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -50,5 +50,3 @@ jobs: run: pip install tox - name: Lint using tox -e rst run: tox -e rst - # Until all errors are fixed: - continue-on-error: true From 27040371a15a66f3e75d97de2f30662564e9fa7f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 14:07:22 -0700 Subject: [PATCH 089/591] src/tox.ini (rst): Add rst directive attr --- src/tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tox.ini b/src/tox.ini index e06d3b68186..d4d756979b9 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -206,6 +206,7 @@ rst-roles = trac, wikipedia rst-directives = + attr, automethod, autofunction, toctree, From 0636b813d70fec7ee7ab169f6b2f60c484539b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 11 Oct 2021 20:37:42 +0200 Subject: [PATCH 090/591] some more links in catalog of posets --- src/sage/combinat/posets/poset_examples.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index 38d5fc64c25..d23efbe51e9 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -65,10 +65,20 @@ :meth:`~Posets.YoungsLatticePrincipalOrderIdeal` | Return the principal order ideal of the partition `lam` in Young's Lattice. :meth:`~Posets.YoungFibonacci` | Return the Young-Fibonacci lattice up to rank `n`. +**Other available posets:** + +.. csv-table:: + :class: contentstable + :widths: 30, 70 + :delim: | + + :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.face_lattice` | Return the face lattice of a polyhedron. + :meth:`~sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron.face_lattice` | Return the face lattice of a combinatorial polyhedron. + Constructions ------------- """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Peter Jipsen , # Franco Saliola # @@ -81,8 +91,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.classcall_metaclass import ClasscallMetaclass import sage.categories.posets @@ -130,7 +140,7 @@ class Posets(metaclass=ClasscallMetaclass): sage: TestSuite(P).run() """ @staticmethod - def __classcall__(cls, n = None): + def __classcall__(cls, n=None): r""" Return either the category of all posets, or the finite enumerated set of all finite posets on ``n`` elements up to an From 1a1efcf0a9bb212d39ff656b3f2fae4e7ae382ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 11 Oct 2021 20:37:42 +0200 Subject: [PATCH 091/591] some more links in catalog of posets --- src/sage/combinat/posets/poset_examples.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index 38d5fc64c25..d23efbe51e9 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -65,10 +65,20 @@ :meth:`~Posets.YoungsLatticePrincipalOrderIdeal` | Return the principal order ideal of the partition `lam` in Young's Lattice. :meth:`~Posets.YoungFibonacci` | Return the Young-Fibonacci lattice up to rank `n`. +**Other available posets:** + +.. csv-table:: + :class: contentstable + :widths: 30, 70 + :delim: | + + :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.face_lattice` | Return the face lattice of a polyhedron. + :meth:`~sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron.face_lattice` | Return the face lattice of a combinatorial polyhedron. + Constructions ------------- """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Peter Jipsen , # Franco Saliola # @@ -81,8 +91,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.classcall_metaclass import ClasscallMetaclass import sage.categories.posets @@ -130,7 +140,7 @@ class Posets(metaclass=ClasscallMetaclass): sage: TestSuite(P).run() """ @staticmethod - def __classcall__(cls, n = None): + def __classcall__(cls, n=None): r""" Return either the category of all posets, or the finite enumerated set of all finite posets on ``n`` elements up to an From 69dd9f2569f512e658612a5d04a59461d4a059fa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 15:11:11 -0700 Subject: [PATCH 092/591] src/doc/en/reference/discrete_geometry/index.rst: Add base0 to base7 --- src/doc/en/reference/discrete_geometry/index.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/doc/en/reference/discrete_geometry/index.rst b/src/doc/en/reference/discrete_geometry/index.rst index a5d9663c5d7..d84e72b4816 100644 --- a/src/doc/en/reference/discrete_geometry/index.rst +++ b/src/doc/en/reference/discrete_geometry/index.rst @@ -76,6 +76,14 @@ Base classes for polyhedra .. toctree:: :maxdepth: 1 + sage/geometry/polyhedron/base0 + sage/geometry/polyhedron/base1 + sage/geometry/polyhedron/base2 + sage/geometry/polyhedron/base3 + sage/geometry/polyhedron/base4 + sage/geometry/polyhedron/base5 + sage/geometry/polyhedron/base6 + sage/geometry/polyhedron/base7 sage/geometry/polyhedron/base sage/geometry/polyhedron/base_QQ sage/geometry/polyhedron/base_ZZ From bf4c354d7e0a1d567dc454b1a40a55cc592a56c0 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 16 Jul 2022 15:46:31 -0700 Subject: [PATCH 093/591] trac 25675: correct link to base4 for face_lattice, and add geometry/polyhedron/combinatorial_polyhedron/* to the reference manual --- src/doc/en/reference/discrete_geometry/index.rst | 14 ++++++++++++++ src/sage/combinat/posets/poset_examples.py | 2 +- .../combinatorial_polyhedron/face_iterator.pyx | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/doc/en/reference/discrete_geometry/index.rst b/src/doc/en/reference/discrete_geometry/index.rst index d84e72b4816..fcc197a7462 100644 --- a/src/doc/en/reference/discrete_geometry/index.rst +++ b/src/doc/en/reference/discrete_geometry/index.rst @@ -89,6 +89,20 @@ Base classes for polyhedra sage/geometry/polyhedron/base_ZZ sage/geometry/polyhedron/base_RDF +Combinatorial polyhedra +~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/geometry/polyhedron/combinatorial_polyhedron/base + sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face + sage/geometry/polyhedron/combinatorial_polyhedron/conversions + sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator + sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure + sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces + sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice + Backends for Polyhedra ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index d23efbe51e9..e415dc300f2 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -72,7 +72,7 @@ :widths: 30, 70 :delim: | - :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.face_lattice` | Return the face lattice of a polyhedron. + :meth:`~sage.geometry.polyhedron.base4.Polyhedron_base4.face_lattice` | Return the face lattice of a polyhedron. :meth:`~sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron.face_lattice` | Return the face lattice of a combinatorial polyhedron. Constructions diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 7e854219418..07ba7647feb 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -1119,7 +1119,7 @@ cdef class FaceIterator_base(SageObject): ... ValueError: only possible when not in dual mode - Cannot run ``only_subfaces`` after ``ignore_subfaces:: + Cannot run ``only_subfaces`` after ``ignore_subfaces``:: sage: it = C.face_generator() sage: _ = next(it) From e2c738cb85b6ab1db0d8a3eb5494ef19d0d035f3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 16:00:57 -0700 Subject: [PATCH 094/591] src/sage/geometry/polyhedron/base*.py: Include topic in title for better TOC --- src/sage/geometry/polyhedron/base.py | 5 ++--- src/sage/geometry/polyhedron/base0.py | 4 +--- src/sage/geometry/polyhedron/base1.py | 2 +- src/sage/geometry/polyhedron/base2.py | 4 +--- src/sage/geometry/polyhedron/base3.py | 5 ++--- src/sage/geometry/polyhedron/base4.py | 2 +- src/sage/geometry/polyhedron/base5.py | 5 ++--- src/sage/geometry/polyhedron/base6.py | 4 +--- src/sage/geometry/polyhedron/base7.py | 4 +--- 9 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 576e073a825..fc0e2dcb197 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1,12 +1,11 @@ r""" -Base class for polyhedra +Base class for polyhedra: Miscellaneous methods This is split into several modules, organized as follows: - :mod:`~sage.geometry.polyhedron.base0` -- basic initialization etc. -- :mod:`~sage.geometry.polyhedron.base1` -- methods defined by the - :class:`~sage.geometry.convex_set.ConvexSet_base` API +- :mod:`~sage.geometry.polyhedron.base1` -- methods defined by the :class:`~sage.geometry.convex_set.ConvexSet_base` API - :mod:`~sage.geometry.polyhedron.base2` -- lattice points diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py index 2e0f6a716cf..5cd32a01ac5 100644 --- a/src/sage/geometry/polyhedron/base0.py +++ b/src/sage/geometry/polyhedron/base0.py @@ -1,7 +1,5 @@ r""" -Base class for polyhedra, part 0 - -Initialization and access to Vrepresentation and Hrepresentation. +Base class for polyhedra: Initialization and access to Vrepresentation and Hrepresentation """ # **************************************************************************** diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index e36867647f5..747dab1f8f4 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -1,5 +1,5 @@ r""" -Base class for polyhedra, part 1 +Base class for polyhedra: Implementation of the :class:`ConvexSet_base` API Define methods that exist for convex sets, but not constructions such as dilation or product. diff --git a/src/sage/geometry/polyhedron/base2.py b/src/sage/geometry/polyhedron/base2.py index 44654a024b2..cec3fd2ccd0 100644 --- a/src/sage/geometry/polyhedron/base2.py +++ b/src/sage/geometry/polyhedron/base2.py @@ -1,7 +1,5 @@ r""" -Base class for polyhedra, part 2 - -Define methods related to lattice points. +Base class for polyhedra: Methods related to lattice points """ # **************************************************************************** diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index 3a70cf79afc..fe4a285e90f 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -1,8 +1,7 @@ r""" -Base class for polyhedra, part 3 +Base class for polyhedra: Methods regarding the combinatorics of a polyhedron -Define methods related to the combinatorics of a polyhedron -excluding methods relying on :mod:`sage.graphs`. +Excluding methods relying on :mod:`sage.graphs`. """ # **************************************************************************** diff --git a/src/sage/geometry/polyhedron/base4.py b/src/sage/geometry/polyhedron/base4.py index 8c7dd0c2836..3cd297a2663 100644 --- a/src/sage/geometry/polyhedron/base4.py +++ b/src/sage/geometry/polyhedron/base4.py @@ -1,6 +1,6 @@ # sage.doctest: optional - sage.graphs r""" -Base class for polyhedra, part 4 +Base class for polyhedra: Graph-theoretic methods Define methods relying on :mod:`sage.graphs`. """ diff --git a/src/sage/geometry/polyhedron/base5.py b/src/sage/geometry/polyhedron/base5.py index b94da62a4b8..149d7eb7164 100644 --- a/src/sage/geometry/polyhedron/base5.py +++ b/src/sage/geometry/polyhedron/base5.py @@ -1,8 +1,7 @@ r""" -Base class for polyhedra, part 5 +Base class for polyhedra: Methods for constructing new polyhedra -Define methods constructing new polyhedra -except for affine hull and affine hull projection. +Except for affine hull and affine hull projection. """ # **************************************************************************** diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index b569f40613d..5637e56d890 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -1,7 +1,5 @@ r""" -Base class for polyhedra, part 6 - -Define methods related to plotting including affine hull projection. +Base class for polyhedra: Methods for plotting and affine hull projection """ # **************************************************************************** diff --git a/src/sage/geometry/polyhedron/base7.py b/src/sage/geometry/polyhedron/base7.py index 93138e3dc4f..898c97fb5c8 100644 --- a/src/sage/geometry/polyhedron/base7.py +++ b/src/sage/geometry/polyhedron/base7.py @@ -1,7 +1,5 @@ r""" -Base class for polyhedra, part 7 - -Define methods related to triangulation and volume. +Base class for polyhedra: Methods for triangulation and volume computation """ # **************************************************************************** From 7c1cf3c9e9b3945c1d7e205b64df17e577191354 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 16:28:48 -0700 Subject: [PATCH 095/591] src/doc/en/reference/discrete_geometry/index.rst: Add sage/geometry/polyhedron/combinatorial_polyhedron/* --- src/doc/en/reference/discrete_geometry/index.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/doc/en/reference/discrete_geometry/index.rst b/src/doc/en/reference/discrete_geometry/index.rst index d84e72b4816..89fa315c3d9 100644 --- a/src/doc/en/reference/discrete_geometry/index.rst +++ b/src/doc/en/reference/discrete_geometry/index.rst @@ -47,6 +47,19 @@ Lattice polyhedra sage/geometry/polyhedron/ppl_lattice_polygon sage/geometry/polyhedron/ppl_lattice_polytope +Combinatorial Polyhedra +~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + + sage/geometry/polyhedron/combinatorial_polyhedron/base + sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face + sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice + sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator + sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure + sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces + Polyhedral complexes ~~~~~~~~~~~~~~~~~~~~ From 8985d875b79a0a0719a0ed7e170011356856bb7f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 16:41:58 -0700 Subject: [PATCH 096/591] src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx: Fix some docstring markup --- .../polyhedron/combinatorial_polyhedron/base.pyx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 9811970ed29..90b5f5ea3d1 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -16,13 +16,12 @@ Terminology used in this module: - Facets -- facets of the polyhedron. - Vrepresentation -- represents a face by the list of Vrep it contains. - Hrepresentation -- represents a face by a list of Hrep it is contained in. -- bit representation -- represents incidences as bitset, where - each bit represents one incidence. There might - be trailing zeros, to fit alignment requirements. - In most instances, faces are represented by the - bit representation, where each bit corresponds to - a Vrep or facet. Thus a bit representation can either be - a Vrep or facet representation depending on context. +- bit representation -- represents incidences as bitset, where each bit + represents one incidence. There might be trailing zeros, to fit alignment + requirements. In most instances, faces are represented by the bit + representation, where each bit corresponds to a Vrep or facet. Thus a bit + representation can either be a Vrep or facet representation depending on + context. EXAMPLES: @@ -1552,6 +1551,7 @@ cdef class CombinatorialPolyhedron(SageObject): - ``algorithm`` -- string (optional); specify whether the face generator starts with facets or vertices: + * ``'primal'`` -- start with the facets * ``'dual'`` -- start with the vertices * ``None`` -- choose automatically @@ -1722,6 +1722,7 @@ cdef class CombinatorialPolyhedron(SageObject): - ``algorithm`` -- string (optional); specify whether the face generator starts with facets or vertices: + * ``'primal'`` -- start with the facets * ``'dual'`` -- start with the vertices * ``None`` -- choose automatically @@ -2678,6 +2679,7 @@ cdef class CombinatorialPolyhedron(SageObject): - ``algorithm`` -- string (optional); specify whether the face generator starts with facets or vertices: + * ``'primal'`` -- start with the facets * ``'dual'`` -- start with the vertices * ``None`` -- choose automatically From b0fe3fd0922e46ee25ccff0fdb8a9dde3e007ed0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 16:45:03 -0700 Subject: [PATCH 097/591] src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx: Fix some docstring markup --- .../combinatorial_polyhedron/combinatorial_face.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index 5b40ee42cf2..c1a0b996a8a 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -18,7 +18,7 @@ Obtain a face from a face iterator:: sage: face = next(it); face A 2-dimensional face of a 3-dimensional combinatorial polyhedron -Obtain a face from a face lattice index: +Obtain a face from a face lattice index:: sage: P = polytopes.simplex(2) sage: C = CombinatorialPolyhedron(P) @@ -859,7 +859,7 @@ cdef class CombinatorialFace(SageObject): Let ``G`` be the face corresponding to ``self`` in the dual/polar polytope. The ``quotient`` is the dual/polar of ``G``. - Let `[\hat{0], \hat{1}]` be the face lattice of the ambient polyhedron + Let `[\hat{0}, \hat{1}]` be the face lattice of the ambient polyhedron and `F` be ``self`` as element of the face lattice. The face lattice of ``self`` as polyhedron corresponds to `[\hat{0}, F]` and the face lattice of the quotient by ``self`` From 05059f8bdfa002007fc8ee0b2e9cca2e7b943f1a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 16:50:52 -0700 Subject: [PATCH 098/591] src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx: Fix docstring markup --- .../polyhedron_face_lattice.pyx | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx index 9fd5e1a2f14..4e9ba7e0e99 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx @@ -8,28 +8,29 @@ the face lattice of a polyhedron. Terminology in this module: -- Vrep -- ``[vertices, rays, lines]`` of the polyhedron. -- Hrep -- inequalities and equations of the polyhedron. -- Facets -- facets of the polyhedron. -- Coatoms -- the faces from which all others are constructed in - the face iterator. This will be facets or Vrep. - In non-dual mode, faces are constructed as - intersections of the facets. In dual mode, the are - constructed theoretically as joins of vertices. - The coatoms are repsented as incidences with the - atoms they contain. -- Atoms -- facets or Vrep depending on application of algorithm. - Atoms are repsented as incidences of coatoms they - are contained in. - -- Vrepresentation -- represents a face by a list of Vrep it contains. -- Hrepresentation -- represents a face by a list of Hrep it is contained in. -- bit representation -- represents incidences as ``uint64_t``-array, where - each Bit represents one incidences. There might - be trailing zeros, to fit alignment-requirements. - In most instances, faces are represented by the - Bit-representation, where each bit corresponds to - an atom. +- Vrep -- ``[vertices, rays, lines]`` of the polyhedron. + +- Hrep -- inequalities and equations of the polyhedron. + +- Facets -- facets of the polyhedron. + +- Coatoms -- the faces from which all others are constructed in the face + iterator. This will be facets or Vrep. In non-dual mode, faces are + constructed as intersections of the facets. In dual mode, the are constructed + theoretically as joins of vertices. The coatoms are repsented as incidences + with the atoms they contain. + +- Atoms -- facets or Vrep depending on application of algorithm. Atoms are + repsented as incidences of coatoms they are contained in. + +- Vrepresentation -- represents a face by a list of Vrep it contains. + +- Hrepresentation -- represents a face by a list of Hrep it is contained in. + +- bit representation -- represents incidences as ``uint64_t``-array, where each + bit represents one incidence. There might be trailing zeros, to fit alignment + requirements. In most instances, faces are represented by the bit + representation, where each bit corresponds to an atom. EXAMPLES:: From 5ee31cf8920170a9ed83da9d1d89b0d6143ab4b0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 16:58:04 -0700 Subject: [PATCH 099/591] src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx: Fix docstring markup --- .../face_iterator.pyx | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 7e854219418..cc36509a47e 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -12,16 +12,14 @@ A (slightly generalized) description of the algorithm can be found in [KS2019]_. Terminology in this module: -- Coatoms -- the faces from which all others are constructed in - the face iterator. This will be facets or Vrep. - In non-dual mode, faces are constructed as - intersections of the facets. In dual mode, the are - constructed theoretically as joins of vertices. - The coatoms are repsented as incidences with the - atoms they contain. -- Atoms -- facets or Vrep depending on application of algorithm. - Atoms are repsented as incidences of coatoms they - are contained in. +- Coatoms -- the faces from which all others are constructed in the + face iterator. This will be facets or Vrep. In non-dual mode, faces + are constructed as intersections of the facets. In dual mode, they + are constructed theoretically as joins of vertices. The coatoms are + repsented as incidences with the atoms they contain. + +- Atoms -- facets or Vrep depending on application of algorithm. Atoms are + represented as incidences of coatoms they are contained in. .. SEEALSO:: @@ -1119,7 +1117,7 @@ cdef class FaceIterator_base(SageObject): ... ValueError: only possible when not in dual mode - Cannot run ``only_subfaces`` after ``ignore_subfaces:: + Cannot run ``only_subfaces`` after ``ignore_subfaces``:: sage: it = C.face_generator() sage: _ = next(it) From 63beed6fe225fb68fb946d129e5660118e20f0d2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 17:00:42 -0700 Subject: [PATCH 100/591] src/doc/en/reference/discrete_geometry/index.rst: fix up --- src/doc/en/reference/discrete_geometry/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/en/reference/discrete_geometry/index.rst b/src/doc/en/reference/discrete_geometry/index.rst index 89fa315c3d9..7e959902fe3 100644 --- a/src/doc/en/reference/discrete_geometry/index.rst +++ b/src/doc/en/reference/discrete_geometry/index.rst @@ -57,8 +57,9 @@ Combinatorial Polyhedra sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator - sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces + sage/geometry/polyhedron/combinatorial_polyhedron/conversions + Polyhedral complexes ~~~~~~~~~~~~~~~~~~~~ From 0ca30fb0a421da68d5a4b08f5488b257a37dffe0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 18:04:39 -0700 Subject: [PATCH 101/591] src/sage/geometry/polyhedron/base.py: Fix markup --- src/sage/geometry/polyhedron/base.py | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index fc0e2dcb197..55d51f8d715 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1,23 +1,5 @@ r""" Base class for polyhedra: Miscellaneous methods - -This is split into several modules, organized as follows: - -- :mod:`~sage.geometry.polyhedron.base0` -- basic initialization etc. - -- :mod:`~sage.geometry.polyhedron.base1` -- methods defined by the :class:`~sage.geometry.convex_set.ConvexSet_base` API - -- :mod:`~sage.geometry.polyhedron.base2` -- lattice points - -- :mod:`~sage.geometry.polyhedron.base3` -- combinatorial methods - -- :mod:`~sage.geometry.polyhedron.base4` -- methods relying on graphs - -- :mod:`~sage.geometry.polyhedron.base5` -- constructions of new polyhedra - -- :mod:`~sage.geometry.polyhedron.base6` -- plotting and affine projection - -- :mod:`~sage.geometry.polyhedron.base7` -- triangulation and volume """ # **************************************************************************** @@ -122,8 +104,8 @@ class Polyhedron_base(Polyhedron_base7): - ``Hrep_minimal`` (optional) -- see below - ``pref_rep`` -- string (default: ``None``); - one of``Vrep`` or ``Hrep`` to pick this in case the backend - cannot initialize from complete double description + one of ``Vrep`` or ``Hrep`` to pick this in case the backend + cannot initialize from complete double description - ``mutable`` -- ignored @@ -840,6 +822,7 @@ def barycentric_subdivision(self, subdivision_frac=None): REFERENCE: See :wikipedia:`Barycentric_subdivision` + Section 6.6, Handbook of Convex Geometry, Volume A, edited by P.M. Gruber and J.M. Wills. 1993, North-Holland Publishing Co.. From 1c26f44899001185b43cd83a38eb9d8544467ac5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 19:52:43 -0700 Subject: [PATCH 102/591] src/doc/en/reference/discrete_geometry/index.rst: Add sage/geometry/polyhedron/backend_cdd_rdf --- src/doc/en/reference/discrete_geometry/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/reference/discrete_geometry/index.rst b/src/doc/en/reference/discrete_geometry/index.rst index 7e959902fe3..202c54a912e 100644 --- a/src/doc/en/reference/discrete_geometry/index.rst +++ b/src/doc/en/reference/discrete_geometry/index.rst @@ -110,6 +110,7 @@ Backends for Polyhedra :maxdepth: 1 sage/geometry/polyhedron/backend_cdd + sage/geometry/polyhedron/backend_cdd_rdf sage/geometry/polyhedron/backend_field sage/geometry/polyhedron/backend_normaliz sage/geometry/polyhedron/backend_polymake From b39fed2857a69dfc1524b62c88f914324e5826b3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 19:55:09 -0700 Subject: [PATCH 103/591] src/doc/en/reference/discrete_geometry/index.rst: Add sage/geometry/abc --- src/doc/en/reference/discrete_geometry/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/reference/discrete_geometry/index.rst b/src/doc/en/reference/discrete_geometry/index.rst index 202c54a912e..0289ea570d9 100644 --- a/src/doc/en/reference/discrete_geometry/index.rst +++ b/src/doc/en/reference/discrete_geometry/index.rst @@ -136,6 +136,7 @@ Miscellaneous .. toctree:: :maxdepth: 1 + sage/geometry/abc sage/geometry/convex_set sage/geometry/linear_expression sage/geometry/newton_polygon From e32adee27e12dd933d7d049b04665e84557a3af7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 20:20:19 -0700 Subject: [PATCH 104/591] src/sage/geometry/polyhedron/base0.py: Fix method/class references --- src/sage/geometry/polyhedron/base0.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py index 5cd32a01ac5..a47ee59a9ab 100644 --- a/src/sage/geometry/polyhedron/base0.py +++ b/src/sage/geometry/polyhedron/base0.py @@ -907,7 +907,7 @@ def inequalities_list(self): It is recommended to use :meth:`inequalities` or :meth:`inequality_generator` instead to iterate over the - list of :class:`Inequality` objects. + list of :class:`~sage.geometry.polyhedron.representation.Inequality` objects. EXAMPLES:: @@ -989,7 +989,7 @@ def vertices_list(self): .. NOTE:: It is recommended to use :meth:`vertex_generator` instead to - iterate over the list of :class:`Vertex` objects. + iterate over the list of :class:`~sage.geometry.polyhedron.representation.Vertex` objects. .. WARNING:: @@ -1200,7 +1200,7 @@ def rays_list(self): It is recommended to use :meth:`rays` or :meth:`ray_generator` instead to iterate over the list of - :class:`Ray` objects. + :class:`~sage.geometry.polyhedron.representation.Ray` objects. OUTPUT: @@ -1255,7 +1255,7 @@ def lines_list(self): .. NOTE:: It is recommended to use :meth:`line_generator` instead to - iterate over the list of :class:`Line` objects. + iterate over the list of :class:`~sage.geometry.polyhedron.representation.Line` objects. EXAMPLES:: From 5de3eeccfd4bf916545bf65157a065cd6318becd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 20:20:30 -0700 Subject: [PATCH 105/591] src/sage/geometry/polyhedron/base.py: Fix method/class references --- src/sage/geometry/polyhedron/base.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 55d51f8d715..459cf0b378c 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -397,7 +397,8 @@ def radius_square(self): OUTPUT: - The square of the radius, which is in :meth:`base_ring`. + The square of the radius, which is in + :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.base_ring`. EXAMPLES:: @@ -615,7 +616,7 @@ def hyperplane_arrangement(self): A :class:`hyperplane arrangement ` consisting of the hyperplanes defined by the - :meth:`Hrepresentation`. + :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation`. If the polytope is full-dimensional, this is the hyperplane arrangement spanned by the facets of the polyhedron. @@ -780,7 +781,7 @@ def is_minkowski_summand(self, Y): r""" Test whether ``Y`` is a Minkowski summand. - See :meth:`minkowski_sum`. + See :meth:`~sage.geometry.polyhedron.base5.Polyhedron_base5.minkowski_sum`. OUTPUT: @@ -936,7 +937,8 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona The dictionary has entries for the generators of the ``acting_group`` and the representatives of conjugacy classes in ``conj_class_reps``. By - default, the ``acting_group`` is the ``restricted_automorphism_group`` + default, the ``acting_group`` is the + :meth:`~sage.geometry.polyhedron.base4.Polyhedron_base4.restricted_automorphism_group` of the polytope. Each element in ``additional_elts`` also becomes a key. INPUT: @@ -945,16 +947,16 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona conjugacy classes of the ``acting_group``. - ``acting_group`` -- a subgroup of polytope's - ``restricted_automorphism_group``. + :meth:`~sage.geometry.polyhedron.base4.Polyhedron_base4.restricted_automorphism_group`. - - ``additional_elts`` -- list (default=None). a subset of the - ``restricted_automorphism_group`` of the polytope expressed as - permutations. + - ``additional_elts`` -- list (default=None). A subset of the + :meth:`~sage.geometry.polyhedron.base4.Polyhedron_base4.restricted_automorphism_group` + of the polytope expressed as permutations. OUTPUT: - A dictionary between elements of ``the restricted_automorphism_group`` - or ``acting_group`` expressed as permutations (keys) and matrices (values). + A dictionary between elements of the ``acting_group`` expressed as permutations + (keys) and matrices (values). EXAMPLES: From 8953f059dee9d6b779ed8545d2216c3564b11579 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 20:22:24 -0700 Subject: [PATCH 106/591] src/sage/geometry/polyhedron/base1.py: Fix method/class references --- src/sage/geometry/polyhedron/base1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index 747dab1f8f4..e29983e44f9 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -428,7 +428,7 @@ def an_affine_basis(self): """ Return points in ``self`` that are a basis for the affine span of the polytope. - This implementation of the method :meth:`ConvexSet_base.an_affine_basis` + This implementation of the method :meth:`~sage.geometry.convex_set.ConvexSet_base.an_affine_basis` for polytopes guarantees the following: - All points are vertices. From bb56fc8488459d0e041d84e3a7e5da8f627f3ff5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 20:30:14 -0700 Subject: [PATCH 107/591] src/sage/geometry/polyhedron/base2.py: Fix method/class references --- src/sage/geometry/polyhedron/base2.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/geometry/polyhedron/base2.py b/src/sage/geometry/polyhedron/base2.py index cec3fd2ccd0..0d7606d96d0 100644 --- a/src/sage/geometry/polyhedron/base2.py +++ b/src/sage/geometry/polyhedron/base2.py @@ -343,7 +343,7 @@ def integral_points_count(self, **kwds): r""" Return the number of integral points in the polyhedron. - This generic version of this method simply calls ``integral_points``. + This generic version of this method simply calls :meth:`integral_points`. EXAMPLES:: @@ -527,7 +527,7 @@ def get_integral_point(self, index, **kwds): Return the ``index``-th integral point in this polyhedron. This is equivalent to ``sorted(self.integral_points())[index]``. - However, so long as self.integral_points_count() does not need to + However, so long as :meth:`integral_points_count` does not need to enumerate all integral points, neither does this method. Hence it can be significantly faster. If the polyhedron is not compact, a ``ValueError`` is raised. @@ -539,7 +539,7 @@ def get_integral_point(self, index, **kwds): is raised. - ``**kwds`` -- optional keyword parameters that are passed to - :meth:`self.integral_points_count`. + :meth:`integral_points_count`. ALGORITHM: @@ -625,14 +625,14 @@ def random_integral_point(self, **kwds): INPUT: - ``**kwds`` -- optional keyword parameters that are passed to - :meth:`self.get_integral_point`. + :meth:`get_integral_point`. OUTPUT: The integral point in the polyhedron chosen uniformly at random. If the polyhedron is not compact, a ``ValueError`` is raised. If the - polyhedron does not contain any integral points, an ``EmptySetError`` is - raised. + polyhedron does not contain any integral points, an + :class:`~sage.categories.sets_cat.EmptySetError` is raised. .. SEEALSO:: From 2fbd57880df94b34270ee70874eaec11d83f2280 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 20:58:29 -0700 Subject: [PATCH 108/591] src/sage/geometry/polyhedron/base3.py: Fix method/class references --- src/sage/geometry/polyhedron/base3.py | 34 +++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index c315960b10f..72f0a66bd7d 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -103,9 +103,9 @@ def slack_matrix(self): .. NOTE:: The columns correspond to inequalities/equations in the - order :meth:`Hrepresentation`, the rows correspond to + order :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation`, the rows correspond to vertices/rays/lines in the order - :meth:`Vrepresentation`. + :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Vrepresentation`. .. SEEALSO:: @@ -180,9 +180,9 @@ def incidence_matrix(self): .. NOTE:: The columns correspond to inequalities/equations in the - order :meth:`Hrepresentation`, the rows correspond to + order :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation`, the rows correspond to vertices/rays/lines in the order - :meth:`Vrepresentation`. + :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Vrepresentation`. .. SEEALSO:: @@ -380,8 +380,10 @@ def face_generator(self, face_dimension=None, algorithm=None, **kwds): - ``face_dimension`` -- integer (default ``None``), yield only faces of this dimension if specified + - ``algorithm`` -- string (optional); specify whether to start with facets or vertices: + * ``'primal'`` -- start with the facets * ``'dual'`` -- start with the vertices * ``None`` -- choose automatically @@ -644,13 +646,13 @@ def faces(self, face_dimension): A tuple of :class:`~sage.geometry.polyhedron.face.PolyhedronFace`. See - :mod:`~sage.geometry.polyhedron.face` for details. The order + module :mod:`sage.geometry.polyhedron.face` for details. The order is random but fixed. .. SEEALSO:: :meth:`face_generator`, - :meth:`facet`. + :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.facet`. EXAMPLES: @@ -795,6 +797,7 @@ def f_vector(self, num_threads=None, parallelization_depth=None, algorithm=None) - ``algorithm`` -- string (optional); specify whether the face generator starts with facets or vertices: + * ``'primal'`` -- start with the facets * ``'dual'`` -- start with the vertices * ``None`` -- choose automatically @@ -806,10 +809,10 @@ def f_vector(self, num_threads=None, parallelization_depth=None, algorithm=None) .. NOTE:: - The ``vertices`` as given by :meth:`Polyhedron_base.vertices` + The ``vertices`` as given by :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.vertices` do not need to correspond to `0`-dimensional faces. If a polyhedron contains `k` lines they correspond to `k`-dimensional faces. - See example below + See example below. EXAMPLES:: @@ -892,6 +895,7 @@ def vertex_adjacency_matrix(self, algorithm=None): - ``algorithm`` -- string (optional); specify whether the face generator starts with facets or vertices: + * ``'primal'`` -- start with the facets * ``'dual'`` -- start with the vertices * ``None`` -- choose automatically @@ -1029,6 +1033,7 @@ def facet_adjacency_matrix(self, algorithm=None): - ``algorithm`` -- string (optional); specify whether the face generator starts with facets or vertices: + * ``'primal'`` -- start with the facets * ``'dual'`` -- start with the vertices * ``None`` -- choose automatically @@ -1146,7 +1151,7 @@ def simplicity(self): A polytope `P` is `k`-simple, if every `(d-1-k)`-face is contained in exactly `k+1` facets of `P` for `1 \leq k \leq d-1`. Equivalently it is `k`-simple if the polar/dual polytope is `k`-simplicial. - If `self` is a simplex, it returns its dimension. + If ``self`` is a simplex, it returns its dimension. EXAMPLES:: @@ -1197,7 +1202,7 @@ def simpliciality(self): Return the largest integer `k` such that the polytope is `k`-simplicial. A polytope is `k`-simplicial, if every `k`-face is a simplex. - If `self` is a simplex, returns its dimension. + If ``self`` is a simplex, returns its dimension. EXAMPLES:: @@ -1690,7 +1695,8 @@ def meet_of_Hrep(self, *Hrepresentatives): INPUT: - ``Hrepresentatives`` -- facets or indices of Hrepresentatives; - the indices are assumed to be the indices of the Hrepresentation + the indices are assumed to be the indices of the + :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation` OUTPUT: a :class:`~sage.geometry.polyhedron.face.PolyhedronFace` @@ -1708,7 +1714,8 @@ def meet_of_Hrep(self, *Hrepresentatives): sage: P.meet_of_Hrep(1,3,7).ambient_H_indices() (0, 1, 3, 7) - The indices are the indices of the Hrepresentation. + The indices are the indices of the + :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation`. ``0`` corresponds to an equation and is ignored:: sage: P.meet_of_Hrep(0) @@ -1741,7 +1748,8 @@ def meet_of_Hrep(self, *Hrepresentatives): TESTS: Equations are not considered by the combinatorial polyhedron. - We check that the index corresponds to the Hrepresentation index:: + We check that the index corresponds to the + :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Hrepresentation` index:: sage: P = polytopes.permutahedron(3, backend='field') sage: P.Hrepresentation() From 8eece7c84fdd7dc02a7ced5d18c8bf7199d7972b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 21:11:12 -0700 Subject: [PATCH 109/591] src/sage/geometry/polyhedron/base4.py: Fix method/class references --- src/sage/geometry/polyhedron/base4.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/geometry/polyhedron/base4.py b/src/sage/geometry/polyhedron/base4.py index 3cd297a2663..ba3a1bd084a 100644 --- a/src/sage/geometry/polyhedron/base4.py +++ b/src/sage/geometry/polyhedron/base4.py @@ -152,16 +152,17 @@ def vertex_graph(self, **kwds): - ``algorithm`` -- string (optional); specify whether the face generator starts with facets or vertices: + * ``'primal'`` -- start with the facets * ``'dual'`` -- start with the vertices * ``None`` -- choose automatically - ..NOTE:: + .. NOTE:: The graph of a polyhedron with lines has no vertices, as the polyhedron has no vertices (`0`-faces). - The method :meth:`Polyhedron_base:vertices` returns + The method :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.vertices` returns the defining points in this case. EXAMPLES:: @@ -211,7 +212,7 @@ def vertex_digraph(self, f, increasing=True): - ``f`` -- a linear form. The linear form can be provided as: - a vector space morphism with one-dimensional codomain, (see - :meth:`sage.modules.vector_space_morphism.linear_transformation` + :func:`sage.modules.vector_space_morphism.linear_transformation` and :class:`sage.modules.vector_space_morphism.VectorSpaceMorphism`) - a vector ; in this case the linear form is obtained by duality @@ -778,7 +779,7 @@ def restricted_automorphism_group(self, output="abstract"): - For ``output="abstract"`` and ``output="permutation"``: a :class:`PermutationGroup`. - - For ``output="matrix"``: a :class:`MatrixGroup`. + - For ``output="matrix"``: a :func:`~sage.groups.matrix_gps.finitely_generated.MatrixGroup`. - For ``output="matrixlist"``: a list of matrices. @@ -1052,8 +1053,8 @@ def is_combinatorially_isomorphic(self, other, algorithm='bipartite_graph'): INPUT: - ``other`` -- a polyhedron object - - ``algorithm`` (default = ``bipartite_graph``) -- the algorithm to use. - The other possible value is ``face_lattice``. + - ``algorithm`` (default = ``'bipartite_graph'``) -- the algorithm to use. + The other possible value is ``'face_lattice'``. OUTPUT: From cbfbe284253a7b2e5de6a3ece331655de0814c9b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 21:17:42 -0700 Subject: [PATCH 110/591] src/sage/geometry/polyhedron/base5.py: Fix method/class references --- src/sage/geometry/polyhedron/base5.py | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/geometry/polyhedron/base5.py b/src/sage/geometry/polyhedron/base5.py index 149d7eb7164..f16bce682b9 100644 --- a/src/sage/geometry/polyhedron/base5.py +++ b/src/sage/geometry/polyhedron/base5.py @@ -678,14 +678,14 @@ def minkowski_sum(self, other): .. MATH:: X \oplus Y = - \cup_{y\in Y} (X+y) = - \cup_{x\in X, y\in Y} (x+y) + \bigcup_{y\in Y} (X+y) = + \bigcup_{x\in X, y\in Y} (x+y) See :meth:`minkowski_difference` for a partial inverse operation. INPUT: - - ``other`` -- a :class:`Polyhedron_base` + - ``other`` -- a :class:`~sage.geometry.polyhedron.base.Polyhedron_base` OUTPUT: @@ -736,7 +736,7 @@ def minkowski_difference(self, other): X \ominus Y = (X^c \oplus Y)^c = - \cap_{y\in Y} (X-y) + \bigcap_{y\in Y} (X-y) where superscript-"c" means the complement in the ambient vector space. The Minkowski difference of convex sets is @@ -753,7 +753,7 @@ def minkowski_difference(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron_base` + - ``other`` -- a :class:`~sage.geometry.polyhedron.base.Polyhedron_base` OUTPUT: @@ -884,7 +884,7 @@ def product(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron_base` + - ``other`` -- a :class:`~sage.geometry.polyhedron.base.Polyhedron_base` OUTPUT: @@ -1147,7 +1147,7 @@ def subdirect_sum(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron_base` + - ``other`` -- a :class:`~sage.geometry.polyhedron.base.Polyhedron_base` EXAMPLES:: @@ -1212,7 +1212,7 @@ def direct_sum(self, other): INPUT: - - ``other`` -- a :class:`Polyhedron_base` + - ``other`` -- a :class:`~sage.geometry.polyhedron.base.Polyhedron_base` EXAMPLES:: @@ -1897,17 +1897,17 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None): INPUT: - - ``face`` -- a PolyhedronFace + - ``face`` -- a :class:`~sage.geometry.polyhedron.face.PolyhedronFace` - ``linear_coefficients`` -- tuple of integer. Specifies the coefficient of the normal vector of the cutting hyperplane used to truncate the face. The default direction is determined using the normal fan of the polyhedron. - ``cut_frac`` -- number between 0 and 1. Determines where the - hyperplane cuts the polyhedron. A value close to 0 cuts very close - to the face, whereas a value close to 1 cuts very close to the next - vertex (according to the normal vector of the cutting hyperplane). - Default is `\frac{1}{3}`. + hyperplane cuts the polyhedron. A value close to 0 cuts very close + to the face, whereas a value close to 1 cuts very close to the next + vertex (according to the normal vector of the cutting hyperplane). + Default is `\frac{1}{3}`. OUTPUT: @@ -2269,7 +2269,7 @@ def wedge(self, face, width=1): The backend should be preserved as long as the value of width permits. The base_ring will change to the field of fractions of the current - base_ring, unless width forces a different ring. :: + base_ring, unless ``width`` forces a different ring. :: sage: P = polytopes.cyclic_polytope(3,7, base_ring=ZZ, backend='field') sage: W1 = P.wedge(P.faces(2)[0]); W1.base_ring(); W1.backend() From a485646f504d17a1d059f613cccfda29134bd582 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 21:19:43 -0700 Subject: [PATCH 111/591] src/sage/geometry/cone_catalog.py: Fix references to ConvexRationalPolyhedralCone --- src/sage/geometry/cone_catalog.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/cone_catalog.py b/src/sage/geometry/cone_catalog.py index 43770fddccb..a3d1ffa670f 100644 --- a/src/sage/geometry/cone_catalog.py +++ b/src/sage/geometry/cone_catalog.py @@ -177,7 +177,7 @@ def nonnegative_orthant(ambient_dim=None, lattice=None): OUTPUT: - A :class:`.ConvexRationalPolyhedralCone` living in ``lattice`` + A :class:`~sage.geometry.cone.ConvexRationalPolyhedralCone` living in ``lattice`` and having ``ambient_dim`` standard basis vectors as its generators. Each generating ray has the integer ring as its base ring. @@ -287,7 +287,7 @@ def rearrangement(p, ambient_dim=None, lattice=None): OUTPUT: - A :class:`.ConvexRationalPolyhedralCone` representing the + A :class:`~sage.geometry.cone.ConvexRationalPolyhedralCone` representing the rearrangement cone of order ``p`` living in ``lattice``, with ambient dimension ``ambient_dim``. Each generating ray has the integer ring as its base ring. @@ -506,7 +506,7 @@ def schur(ambient_dim=None, lattice=None): OUTPUT: - A :class:`.ConvexRationalPolyhedralCone` representing the Schur + A :class:`~sage.geometry.cone.ConvexRationalPolyhedralCone` representing the Schur cone living in ``lattice``, with ambient dimension ``ambient_dim``. Each generating ray has the integer ring as its base ring. @@ -635,7 +635,7 @@ def trivial(ambient_dim=None, lattice=None): OUTPUT: - A :class:`.ConvexRationalPolyhedralCone` representing the + A :class:`~sage.geometry.cone.ConvexRationalPolyhedralCone` representing the trivial cone with no nonzero generators living in ``lattice``, with ambient dimension ``ambient_dim``. From b122baf5cc6dff5556270b77593e5ed0c135e6cb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 21:24:12 -0700 Subject: [PATCH 112/591] src/sage/geometry/polyhedron/base6.py: Fix method/class references --- src/sage/geometry/polyhedron/base6.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index 5637e56d890..3257c27fe0a 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -502,7 +502,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, .. NOTE:: This is a wrapper of a method of the projection object - `self.projection()`. See :meth:`~sage.geometry.polyhedron.plot.Projection.tikz` + ``self.projection()``. See :meth:`~sage.geometry.polyhedron.plot.Projection.tikz` for more detail. The inputs ``view`` and ``angle`` can be obtained by visualizing it @@ -638,7 +638,7 @@ def gale_transform(self): .. SEEALSO:: - :func`~sage.geometry.polyhedron.library.gale_transform_to_polyhedron`. + :func:`~sage.geometry.polyhedron.library.gale_transform_to_polyhedron`. TESTS:: @@ -718,7 +718,7 @@ def projection(self, projection=None): .. SEEALSO:: - :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.schlegel_projection` for a more interesting projection. + :meth:`~sage.geometry.polyhedron.base6.Polyhedron_base6.schlegel_projection` for a more interesting projection. EXAMPLES:: @@ -782,8 +782,8 @@ def schlegel_projection(self, facet=None, position=None): INPUT: - - ``facet`` -- a PolyhedronFace. The facet into which the Schlegel - diagram is created. The default is the first facet. + - ``facet`` -- a :class:`~sage.geometry.polyhedron.face.PolyhedronFace`. + The facet into which the Schlegel diagram is created. The default is the first facet. - ``position`` -- a positive number. Determines a relative distance from the barycenter of ``facet``. A value close to 0 will place the From 0d3b5efa15e0c30ef2e079d3bef6af98f27c7f26 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 21:26:59 -0700 Subject: [PATCH 113/591] src/sage/geometry/polyhedron/base7.py: Fix method/class references --- src/sage/geometry/polyhedron/base7.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/base7.py b/src/sage/geometry/polyhedron/base7.py index 898c97fb5c8..634edc2d7a0 100644 --- a/src/sage/geometry/polyhedron/base7.py +++ b/src/sage/geometry/polyhedron/base7.py @@ -216,9 +216,9 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s OUTPUT: A triangulation of the convex hull of the vertices as a - :class:`~sage.geometry.triangulation.point_configuration.Triangulation`. The + :class:`~sage.geometry.triangulation.element.Triangulation`. The indices in the triangulation correspond to the - :meth:`Vrepresentation` objects. + :meth:`~sage.geometry.polyhedron.base0.Polyhedron_base0.Vrepresentation` objects. EXAMPLES:: @@ -515,7 +515,7 @@ def volume(self, measure='ambient', engine='auto', **kwds): When considering lower-dimensional polytopes, we can ask for the ambient (full-dimensional), the induced measure (of the affine hull) or, in the case of lattice polytopes, for the induced rational measure. - This is controlled by the parameter `measure`. Different engines + This is controlled by the parameter ``measure``. Different engines may have different ideas on the definition of volume of a lower-dimensional object:: From 2f29dff0787d154d84ca80fb504250c41dd4ced2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 21:33:27 -0700 Subject: [PATCH 114/591] Revert "src/sage/repl/interpreter.py: Use directive 'attr' instead of 'attribute'" This reverts commit ce10cae6f4b5854b59e46408686adc085138a8f1. --- src/sage/repl/interpreter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index b6a0e5a5b56..d7ba014361d 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -463,7 +463,7 @@ def __init__(self, *args, **kwds): Initialize this class. All of the arguments get passed to :meth:`PrefilterTransformer.__init__`. - .. attr:: temporary_objects + .. attribute:: temporary_objects a list of hold onto interface objects and keep them from being garbage collected From 3b9399d7164f7b792b8942d8159571d5de0cc8c3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 16 Jul 2022 21:34:07 -0700 Subject: [PATCH 115/591] src/tox.ini (rst): Add rst directive attribute (fixup) --- src/tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tox.ini b/src/tox.ini index d4d756979b9..ce9f56b9496 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -206,7 +206,7 @@ rst-roles = trac, wikipedia rst-directives = - attr, + attribute, automethod, autofunction, toctree, From b55efb150585ba4e3140408fc899015a46114ff7 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Fri, 22 Jul 2022 12:08:56 +0200 Subject: [PATCH 116/591] trac #34211: replace call to SSLContext with default_context --- src/sage/graphs/isgci.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index fb1e0c2f49f..455f4f4c29f 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -831,7 +831,7 @@ def _download_db(self): """ import tempfile u = urlopen('https://www.graphclasses.org/data.zip', - context=SSLContext()) + context=default_context()) with tempfile.NamedTemporaryFile(suffix=".zip") as f: f.write(u.read()) z = zipfile.ZipFile(f.name) From 32f05b07acc108c0ac2ddf7e660bd08ff0fc44e7 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Fri, 22 Jul 2022 12:09:47 +0200 Subject: [PATCH 117/591] trac #34211: some care --- src/sage/graphs/isgci.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index 455f4f4c29f..2319df40fe2 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -827,7 +827,7 @@ def _download_db(self): EXAMPLES:: - sage: graph_classes._download_db() # Not tested -- requires internet + sage: graph_classes._download_db() # Not tested -- requires internet """ import tempfile u = urlopen('https://www.graphclasses.org/data.zip', @@ -858,7 +858,6 @@ def _parse_db(self, directory): sage: graph_classes._parse_db(GRAPHS_DATA_DIR) """ import xml.etree.cElementTree as ET - import os.path from sage.graphs.graph import Graph xml_file = os.path.join(GRAPHS_DATA_DIR, _XML_FILE) @@ -903,7 +902,7 @@ def update_db(self): EXAMPLES:: - sage: graph_classes.update_db() # Not tested -- requires internet + sage: graph_classes.update_db() # Not tested -- requires internet """ self._download_db() @@ -935,8 +934,6 @@ def _get_ISGCI(self): sage: graph_classes._get_ISGCI() # long time (4s on sage.math, 2012) """ - - import os.path from sage.misc.misc import SAGE_DB try: From 029c9a08ca06efd08ff10fc3952453b4ad3c2bbb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 23 Jul 2022 14:52:04 -0700 Subject: [PATCH 118/591] .devcontainer/post_create.sh: Install python3 so that python3-venv is available on Debian --- .devcontainer/post_create.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh index 0a9dd9951d1..0e443230898 100755 --- a/.devcontainer/post_create.sh +++ b/.devcontainer/post_create.sh @@ -3,7 +3,7 @@ export PATH=$(pwd)/build/bin:$PATH SYSTEM=$(sage-guess-package-system) eval $(sage-print-system-package-command $SYSTEM "$@" update) -eval $(sage-print-system-package-command $SYSTEM --yes "$@" --spkg install _prereq git $EXTRA_SAGE_PACKAGES) +eval $(sage-print-system-package-command $SYSTEM --yes "$@" --spkg install _prereq python3 git $EXTRA_SAGE_PACKAGES) if [ -n "$EXTRA_SYSTEM_PACKAGES" ]; then eval $(sage-print-system-package-command $SYSTEM --yes "$@" install $EXTRA_SYSTEM_PACKAGES) fi From 4fad776ebb9438d4c01df8b0df5c5e223d03dc18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Mon, 25 Jul 2022 11:34:35 +0200 Subject: [PATCH 119/591] 34219: Document that SageTeX is now in SAGE_ROOT/venv/share --- build/pkgs/sagetex/SPKG.rst | 4 ++-- src/doc/de/tutorial/introduction.rst | 4 ++-- src/doc/de/tutorial/sagetex.rst | 4 ++-- src/doc/en/thematic_tutorials/numtheory_rsa.rst | 4 ++-- src/doc/en/tutorial/introduction.rst | 4 ++-- src/doc/en/tutorial/sagetex.rst | 16 ++++++++-------- src/doc/es/tutorial/introduction.rst | 4 ++-- src/doc/fr/tutorial/introduction.rst | 4 ++-- src/doc/fr/tutorial/sagetex.rst | 4 ++-- src/doc/ja/tutorial/introduction.rst | 4 ++-- src/doc/ja/tutorial/sagetex.rst | 16 ++++++++-------- src/doc/pt/tutorial/introduction.rst | 4 ++-- src/doc/pt/tutorial/sagetex.rst | 4 ++-- src/doc/ru/tutorial/introduction.rst | 4 ++-- src/doc/ru/tutorial/sagetex.rst | 4 ++-- 15 files changed, 42 insertions(+), 42 deletions(-) diff --git a/build/pkgs/sagetex/SPKG.rst b/build/pkgs/sagetex/SPKG.rst index 1a3de2a92b4..b2e3bd85b18 100644 --- a/build/pkgs/sagetex/SPKG.rst +++ b/build/pkgs/sagetex/SPKG.rst @@ -55,9 +55,9 @@ needs. Full details are in the Sage installation guide at http://doc.sagemath.org/html/en/installation/ and http://doc.sagemath.org/html/en/tutorial/sagetex.html . -The directory ``$SAGE_ROOT/local/share/doc/sagetex`` contains +The directory ``$SAGE_ROOT/venv/share/doc/sagetex`` contains documentation and an example file. See -``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex`` for the source code +``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex`` for the source code and some possibly useful scripts. If you have problems or suggestions see `the sage-support group `__. diff --git a/src/doc/de/tutorial/introduction.rst b/src/doc/de/tutorial/introduction.rst index ea3bf00cf34..bb80efc7cec 100644 --- a/src/doc/de/tutorial/introduction.rst +++ b/src/doc/de/tutorial/introduction.rst @@ -98,9 +98,9 @@ Hier geben wir nur ein paar Kommentare ab. einzige Datei in ein Verzeichnis kopieren, welches TeX durchsucht. Die Dokumentation für SageTeX befindet sich in - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, wobei + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, wobei "``$SAGE_ROOT``" auf das Verzeichnis zeigt, in welches Sie Sage - installiert haben, zum Beispiel ``/opt/sage-4.2.1``. + installiert haben, zum Beispiel ``/opt/sage-9.6``. Wie man Sage benutzen kann ========================== diff --git a/src/doc/de/tutorial/sagetex.rst b/src/doc/de/tutorial/sagetex.rst index 8f58e812a78..37780eb6cf2 100644 --- a/src/doc/de/tutorial/sagetex.rst +++ b/src/doc/de/tutorial/sagetex.rst @@ -15,7 +15,7 @@ Tutorial und den Abschnitt "Make SageTeX known to TeX" des `Sage installation gu Installationsanleitung führen) um weitere Informationen zu erhalten. Hier stellen wir ein sehr kurzes Beispiel vor wie man SageTeX nutzt. -Die komplette Dokumentation finden Sie unter ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``, +Die komplette Dokumentation finden Sie unter ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``, wobei ``SAGE_ROOT`` das Installationsverzeichnis von Sage ist. Dieses Verzeichnis enthält die Dokumentation, eine Beispieldatei und einige nützliche Python Skripte. @@ -103,4 +103,4 @@ an den Sage Befehlen in Ihrem Dokument vorgenommen haben. Es gibt noch viel mehr über SageTeX zu sagen, aber da sowohl Sage alsauch LaTeX komplexe und mächtige Werkzeuge sind, sollten Sie die Dokumentation -über SageTeX in ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex`` lesen. +über SageTeX in ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex`` lesen. diff --git a/src/doc/en/thematic_tutorials/numtheory_rsa.rst b/src/doc/en/thematic_tutorials/numtheory_rsa.rst index f321af0ddcd..90a6d9ab675 100644 --- a/src/doc/en/thematic_tutorials/numtheory_rsa.rst +++ b/src/doc/en/thematic_tutorials/numtheory_rsa.rst @@ -429,8 +429,8 @@ given above, we would get an error message similar to the following:: mod(m^e, n) Traceback (most recent call last) - /home/mvngu/ in () - /home/mvngu/usr/bin/sage-3.1.4/local/lib/python2.5/site-packages/sage/rings/integer.so + ... in () + .../sage/rings/integer.so in sage.rings.integer.Integer.__pow__ (sage/rings/integer.c:9650)() RuntimeError: exponent must be at most 2147483647 diff --git a/src/doc/en/tutorial/introduction.rst b/src/doc/en/tutorial/introduction.rst index c9683df4d78..10ebef9f5d6 100644 --- a/src/doc/en/tutorial/introduction.rst +++ b/src/doc/en/tutorial/introduction.rst @@ -89,9 +89,9 @@ computer. Here we merely make a few comments. will search. The documentation for using SageTeX is located in - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, where + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, where "``$SAGE_ROOT``" refers to the directory where you installed Sage -- - for example, ``/opt/sage-4.2.1``. + for example, ``/opt/sage-9.6``. Ways to Use Sage ================ diff --git a/src/doc/en/tutorial/sagetex.rst b/src/doc/en/tutorial/sagetex.rst index 0fdc74b0640..17460be0b49 100644 --- a/src/doc/en/tutorial/sagetex.rst +++ b/src/doc/en/tutorial/sagetex.rst @@ -12,10 +12,10 @@ An example ---------- Here is a very brief example of using SageTeX. The full documentation -can be found in ``SAGE_ROOT/local/share/doc/sagetex``, +can be found in ``SAGE_ROOT/venv/share/doc/sagetex``, where ``SAGE_ROOT`` is the directory where your Sage installation is located. That directory contains the documentation and an example file. -See ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex`` for +See ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex`` for some possibly useful Python scripts. To see how SageTeX works, follow the directions for installing SageTeX (in @@ -105,7 +105,7 @@ commands in your document. There's a lot more to SageTeX, and since both Sage and LaTeX are complex, powerful tools, it's a good idea to read the documentation for SageTeX, which is in -``SAGE_ROOT/local/share/doc/sagetex``. +``SAGE_ROOT/venv/share/doc/sagetex``. .. _sec-sagetex_install: @@ -122,7 +122,7 @@ installation aware of it before it will work. The key to this is that TeX needs to be able to find ``sagetex.sty``, which can be found in -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, where +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, where ``SAGE_ROOT`` is the directory where you built or installed Sage. If TeX can find ``sagetex.sty``, then SageTeX will work. There are several ways to accomplish this. @@ -142,7 +142,7 @@ ways to accomplish this. .. CODE-BLOCK:: shell-session - $ export TEXINPUTS="SAGE_ROOT/local/share/texmf//:" + $ export TEXINPUTS="SAGE_ROOT/venv/share/texmf//:" where ``SAGE_ROOT`` is the location of your Sage installation. Note that the double slash and colon at the end of that line are important. @@ -173,12 +173,12 @@ ways to accomplish this. which will print out a directory, such as ``/home/drake/texmf`` or ``/Users/drake/Library/texmf``. Copy the ``tex/`` directory from - ``SAGE_ROOT/local/share/texmf/`` into your home ``texmf`` directory + ``SAGE_ROOT/venv/share/texmf/`` into your home ``texmf`` directory with a command like .. CODE-BLOCK:: shell-session - $ cp -R SAGE_ROOT/local/share/texmf/tex TEXMFHOME + $ cp -R SAGE_ROOT/venv/share/texmf/tex TEXMFHOME where ``SAGE_ROOT`` is, as usual, replaced with the location of your Sage installation and ``TEXMFHOME`` is the result of the @@ -229,7 +229,7 @@ SageTeX documentation While not strictly part of installation, it bears mentioning here that the documentation for SageTeX is maintained in -``SAGE_ROOT/local/share/doc/sagetex/sagetex.pdf``. There is also an +``SAGE_ROOT/venv/share/doc/sagetex/sagetex.pdf``. There is also an example file in the same directory -- see ``example.tex`` and ``example.pdf``, the pre-built result of typesetting that file with LaTeX and Sage. You can also get those files from the `SageTeX page `_. diff --git a/src/doc/es/tutorial/introduction.rst b/src/doc/es/tutorial/introduction.rst index 7eb55a8d740..fdd811d7f96 100644 --- a/src/doc/es/tutorial/introduction.rst +++ b/src/doc/es/tutorial/introduction.rst @@ -90,9 +90,9 @@ Sage en tu computador. Aquí hacemos simplemente dos comentarios: en un directorio en el que TeX va a buscar. La documentación para usar SageTeX se encuentra en - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, donde + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, donde "``$SAGE_ROOT``" se refiere al directorio donde Sage está instalado -- - por ejemplo, ``/opt/sage-4.2.1``. + por ejemplo, ``/opt/sage-9.6``. Formas de usar Sage diff --git a/src/doc/fr/tutorial/introduction.rst b/src/doc/fr/tutorial/introduction.rst index 875fefbeaa1..6edb2362061 100644 --- a/src/doc/fr/tutorial/introduction.rst +++ b/src/doc/fr/tutorial/introduction.rst @@ -96,9 +96,9 @@ Nous nous limiterons ici à quelques remarques. d'environnement. La documentation de SageTeX se trouve dans le répertoire - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, où + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, où "``$SAGE_ROOT``" est le répertoire où vous avez installé Sage, par - exemple ``/opt/sage-4.3.4``. + exemple ``/opt/sage-9.6``. Les différentes manières d'utiliser Sage ======================================== diff --git a/src/doc/fr/tutorial/sagetex.rst b/src/doc/fr/tutorial/sagetex.rst index 9aa52f3759a..b17f0ad56f7 100644 --- a/src/doc/fr/tutorial/sagetex.rst +++ b/src/doc/fr/tutorial/sagetex.rst @@ -16,7 +16,7 @@ locale) pour plus de détails. Voici un bref exemple d'utilisation de SageTeX. La documentation complète se trouve dans -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``, où ``SAGE_ROOT`` +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``, où ``SAGE_ROOT`` désigne le répertoire racine de votre installation Sage. Elle est accompagnée d'un fichier exemple et de scripts Python potentiellement utiles. @@ -114,4 +114,4 @@ compilation précédente.) SageTeX offre bien d'autres possibilités. Puisque Sage comme LaTeX sont des outils complexes et puissants, le mieux est sans doute de consulter la documentation complète de SageTeX, qui se trouve -dans ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``. +dans ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``. diff --git a/src/doc/ja/tutorial/introduction.rst b/src/doc/ja/tutorial/introduction.rst index 2c4ce235f6a..79d90c9d5c1 100644 --- a/src/doc/ja/tutorial/introduction.rst +++ b/src/doc/ja/tutorial/introduction.rst @@ -73,8 +73,8 @@ Sageを自分のコンピュータへインストールする手順について SageTeXの利用に関する解説は -``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/`` にある. -``$SAGE_ROOT`` はSageがインストールされているディレクトリで,例えば ``/opt/sage-4.2.1`` などとなっているはずだ. +``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/`` にある. +``$SAGE_ROOT`` はSageがインストールされているディレクトリで,例えば ``/opt/sage-9.6`` などとなっているはずだ. diff --git a/src/doc/ja/tutorial/sagetex.rst b/src/doc/ja/tutorial/sagetex.rst index a6e2b40b5b2..dbbdc3ff7bd 100644 --- a/src/doc/ja/tutorial/sagetex.rst +++ b/src/doc/ja/tutorial/sagetex.rst @@ -12,8 +12,8 @@ SageTeXパッケージを使うと,Sageによる処理結果をLaTeX文書に ======= ここでは,ごく簡単な例題を通してSageTeXの利用手順を紹介する. -完全な解説ドキュメントと例題ファイルは,ディレクトリ ``SAGE_ROOT/local/share/doc/sagetex`` に置いてある. -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex`` にあるPythonスクリプトは何か役に立つ場面があるはずだ. +完全な解説ドキュメントと例題ファイルは,ディレクトリ ``SAGE_ROOT/venv/share/doc/sagetex`` に置いてある. +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex`` にあるPythonスクリプトは何か役に立つ場面があるはずだ. 以上の ``SAGE_ROOT`` は,Sageをインストールしたディレクトリである. @@ -98,7 +98,7 @@ SageTeXの動作を体験するために,まずSageTeXのインストール手 SageTeXは到底以上で語り尽せるものでなく,SageとLaTeXは共に複雑で強力なツールだ. -``SAGE_ROOT/local/share/doc/sagetex`` にあるSageTeXのドキュメントを読むことを強くお勧めする. +``SAGE_ROOT/venv/share/doc/sagetex`` にあるSageTeXのドキュメントを読むことを強くお勧めする. .. _sec-sagetex_install: @@ -118,7 +118,7 @@ SageTeXはデフォルトでSageにインストールされるが,LaTeX文書 鍵になるのは, TeXが ``sagetex.sty`` を発見できるかどうかである. この ``sagetex.sty`` は, ``SAGE_ROOT`` をSageがビルトあるいはインストールされたディレクトリとすると, -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex/`` に置かれているはずだ. +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/`` に置かれているはずだ. TeXが ``sagetex.sty`` を読めるようにしてやらなければ,SageTeXも動作できないのである. これを実現するには何通りかのやり方がある. @@ -137,7 +137,7 @@ TeXが ``sagetex.sty`` を読めるようにしてやらなければ,SageTeX :: - export TEXINPUTS="SAGE_ROOT/local/share/texmf//:" + export TEXINPUTS="SAGE_ROOT/venv/share/texmf//:" と実行すればよい.ただし ``SAGE_ROOT`` はSageのインストール先ディレクトリである. 上の実行例では,行末にスラッシュ2個とコロンを付け忘れないでいただきたい. @@ -163,11 +163,11 @@ TeXが ``sagetex.sty`` を読めるようにしてやらなければ,SageTeX kpsewhich -var-value=TEXMFHOME - を実行する.すると ``/home/drake/texmf`` や ``/Users/drake/Library/texmf`` などと表示されるはずだから, ``SAGE_ROOT/local/share/texmf/`` 内の ``tex/`` ディレクトリをホームディレクトリの ``texmf`` にコピーするには + を実行する.すると ``/home/drake/texmf`` や ``/Users/drake/Library/texmf`` などと表示されるはずだから, ``SAGE_ROOT/venv/share/texmf/`` 内の ``tex/`` ディレクトリをホームディレクトリの ``texmf`` にコピーするには :: - cp -R SAGE_ROOT/local/share/texmf/tex TEXMFHOME + cp -R SAGE_ROOT/venv/share/texmf/tex TEXMFHOME などとする. もちろん, ``SAGE_ROOT`` を実際にSageをインストールしたディレクトリとするのはこれまでと同じことで, ``TEXMFHOME`` は上で見た ``kpsewhich`` コマンドの結果で置き換える. @@ -210,7 +210,7 @@ SageTeXドキュメント --------------------- 厳密にはSageのインストール一式には含まれないものの,ここで -SageTeXのドキュメントが ``SAGE_ROOT/local/share/doc/sagetex/sagetex.pdf`` に配置されていることに触れておきたい. +SageTeXのドキュメントが ``SAGE_ROOT/venv/share/doc/sagetex/sagetex.pdf`` に配置されていることに触れておきたい. 同じディレクトリには例題ファイルと,これをLaTeXとSageTeXによってすでに組版処理した結果も用意されている(``example.tex`` と ``example.pdf`` を参照). これらのファイルは `SageTeX ページ `_ からダンロードすることもできる. diff --git a/src/doc/pt/tutorial/introduction.rst b/src/doc/pt/tutorial/introduction.rst index 0a821b3c099..b0b2fac6e1b 100644 --- a/src/doc/pt/tutorial/introduction.rst +++ b/src/doc/pt/tutorial/introduction.rst @@ -90,9 +90,9 @@ computador. Aqui faremos apenas alguns comentários. encontrá-lo. A documentação para usar o SageTex está disponível em - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, onde + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, onde ``$SAGE_ROOT`` refere-se ao diretório onde você instalou o Sage - -- por exemplo, ``/opt/sage-4.2.1``. + -- por exemplo, ``/opt/sage-9.6``. Formas de usar o Sage ===================== diff --git a/src/doc/pt/tutorial/sagetex.rst b/src/doc/pt/tutorial/sagetex.rst index 949b9b3e6db..8b0c47b6891 100644 --- a/src/doc/pt/tutorial/sagetex.rst +++ b/src/doc/pt/tutorial/sagetex.rst @@ -14,7 +14,7 @@ instalação do Sage `_ Aqui vai um breve exemplo de como usar o SageTeX. A documentação completa pode ser encontrada em -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``, onde +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``, onde ``SAGE_ROOT`` é o diretório onde se encontra a sua instalação. Esse diretório contém a documentação, um arquivo de exemplo, e alguns scripts em Python possivelmente úteis. @@ -107,4 +107,4 @@ os comandos em Sage em seu documento. Há muito mais sobre o SageTeX, e como tanto o Sage como o LaTeX são ferramentas complexas e poderosas, é uma boa idéia ler a documentação para o SageTeX que se encontra em -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``. +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``. diff --git a/src/doc/ru/tutorial/introduction.rst b/src/doc/ru/tutorial/introduction.rst index 3f62905cee9..445d17fb505 100644 --- a/src/doc/ru/tutorial/introduction.rst +++ b/src/doc/ru/tutorial/introduction.rst @@ -88,9 +88,9 @@ Sage в разделе документации: [SA]_ Здесь мы прив всего лишь скопировать один файл в директорию поиска TeX. Документация по использованию SageTeX находится в - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, где + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, где "``$SAGE_ROOT``" соответствует директории, где установлен сам Sage, - например, ``/opt/sage-4.2.1``. + например, ``/opt/sage-9.6``. Работа в Sage ================ diff --git a/src/doc/ru/tutorial/sagetex.rst b/src/doc/ru/tutorial/sagetex.rst index d23ebc7fb31..8c930e2de2a 100644 --- a/src/doc/ru/tutorial/sagetex.rst +++ b/src/doc/ru/tutorial/sagetex.rst @@ -12,7 +12,7 @@ SageTeX known to TeX" `Руководства по установке Sage по установке). В этом уроке показан небольшой пример использования SageTeX. Полная документация -находится в ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``, где +находится в ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``, где ``SAGE_ROOT`` - это директория, в которой установлен Sage. Эта папка содержит документацию, файл с примером и полезные скрипты Python. @@ -89,4 +89,4 @@ SageTeX known to TeX" `Руководства по установке Sage SageTeX предлагает много возможностей, и так как Sage и LaTeX являются мощными инструментами, то стоит изучить -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``. +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``. From 752cf3a926ab0b654559314ff74672c02e17b76a Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 25 Jun 2022 11:23:32 -0500 Subject: [PATCH 120/591] Fix comparison with .one_basis() --- src/sage/modules/with_basis/indexed_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 834d92f96d9..76026892820 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -333,7 +333,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): elif coeff == "-1": coeff = "-" elif b._l > 0: - if len(coeff) > 0 and monomial == 1 and strip_one: + if len(coeff) > 0 and monomial == self.parent().one_basis() and strip_one: b = empty_ascii_art # "" else: b = AsciiArt([scalar_mult]) + b From 7cf899081ffe597fae73ead06995a5d028c9837c Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 25 Jul 2022 10:07:45 -0500 Subject: [PATCH 121/591] Fix to work with algebras without a one_basis --- src/sage/modules/with_basis/indexed_element.pyx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 76026892820..9720b9a31fa 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -306,6 +306,13 @@ cdef class IndexedFreeModuleElement(ModuleElement): * * sage: ascii_art(M.zero()) 0 + sage: DA = DescentAlgebra(QQ, 4) + sage: ascii_art(DA.an_element()) + 2*B + 2*B + 3*B + * ** * + * * ** + * * * + * """ from sage.misc.repr import coeff_repr terms = self._sorted_items_for_printing() @@ -322,6 +329,11 @@ cdef class IndexedFreeModuleElement(ModuleElement): if scalar_mult is None: scalar_mult = "*" + try: + one_basis = self.parent().one_basis() + except AttributeError: + one_basis = None + for (monomial,c) in terms: b = repr_monomial(monomial) # PCR if c != 0: @@ -333,7 +345,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): elif coeff == "-1": coeff = "-" elif b._l > 0: - if len(coeff) > 0 and monomial == self.parent().one_basis() and strip_one: + if len(coeff) > 0 and monomial == one_basis and strip_one: b = empty_ascii_art # "" else: b = AsciiArt([scalar_mult]) + b From dc8370dfff5f084535911bfcc132a5c310b8243b Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 25 Jul 2022 10:19:00 -0500 Subject: [PATCH 122/591] Change one in _unicode_art_ --- src/sage/modules/with_basis/indexed_element.pyx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 9720b9a31fa..6b861a42da1 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -403,6 +403,11 @@ cdef class IndexedFreeModuleElement(ModuleElement): if scalar_mult is None: scalar_mult = "*" + try: + one_basis = self.parent().one_basis() + except AttributeError: + one_basis = None + for (monomial, c) in terms: b = repr_monomial(monomial) # PCR if c != 0: @@ -414,7 +419,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): elif coeff == "-1": coeff = "-" elif b._l > 0: - if len(coeff) > 0 and monomial == 1 and strip_one: + if len(coeff) > 0 and monomial == one_basis and strip_one: b = empty_unicode_art # "" else: b = UnicodeArt([scalar_mult]) + b From 0e17b69bb598a0ca5ebb053de142f97559f53dd2 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 20 Jun 2022 12:03:26 -0500 Subject: [PATCH 123/591] Initial commit/minimal change --- src/sage/algebras/clifford_algebra.py | 9 ++++++++- src/sage/data_structures/bitset.pyx | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 0c583b04f6c..b5111e15ee1 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -19,6 +19,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation +from sage.data_structures.bitset import FrozenBitset from copy import copy from sage.categories.algebras_with_basis import AlgebrasWithBasis @@ -493,7 +494,13 @@ def __init__(self, Q, names, category=None): self._quadratic_form = Q R = Q.base_ring() category = AlgebrasWithBasis(R.category()).Super().Filtered().FiniteDimensional().or_subcategory(category) - indices = SubsetsSorted(range(Q.dim())) + format_style = f"0{Q.dim()}b" + from functools import partial + # use a slice to reverse string order because Bitset and format(x, 'b') use different conventions + def index_function(x): + return FrozenBitset(format(x, format_style)[::-1], + capacity=Q.dim()) + indices = Family(range(2**Q.dim()), partial(index_function), lazy=True) CombinatorialFreeModule.__init__(self, R, indices, category=category) self._assign_names(names) diff --git a/src/sage/data_structures/bitset.pyx b/src/sage/data_structures/bitset.pyx index 29bbeeb0d1c..a09387c139a 100644 --- a/src/sage/data_structures/bitset.pyx +++ b/src/sage/data_structures/bitset.pyx @@ -390,6 +390,7 @@ cdef class FrozenBitset: else: # an iterable iter = list(iter) if iter: + print(iter) need_capacity = max(iter) + 1 else: need_capacity = 0 From 212d238ed750dcbce8a232e9fc755c7e9b2fc06a Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 20 Jun 2022 15:41:01 -0500 Subject: [PATCH 124/591] Fix .one_basis() --- src/sage/algebras/clifford_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index b5111e15ee1..fd83ae8fa9d 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -760,7 +760,7 @@ def one_basis(self): sage: Cl.one_basis() () """ - return () + return FrozenBitset('0') def is_commutative(self): """ From 11853bc23d3bb89b6a59a4d5eb0e18141019595b Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 20 Jun 2022 15:54:30 -0500 Subject: [PATCH 125/591] Remove accidental print statement --- src/sage/data_structures/bitset.pyx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/data_structures/bitset.pyx b/src/sage/data_structures/bitset.pyx index a09387c139a..29bbeeb0d1c 100644 --- a/src/sage/data_structures/bitset.pyx +++ b/src/sage/data_structures/bitset.pyx @@ -390,7 +390,6 @@ cdef class FrozenBitset: else: # an iterable iter = list(iter) if iter: - print(iter) need_capacity = max(iter) + 1 else: need_capacity = 0 From a7937836817834d51f2ed0004bf6d02c8a0192c7 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 21 Jun 2022 12:31:12 -0500 Subject: [PATCH 126/591] Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset) --- src/sage/algebras/clifford_algebra.py | 73 ++++++++++++++++++++------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index fd83ae8fa9d..ba222c16cdc 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -19,7 +19,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation -from sage.data_structures.bitset import FrozenBitset +from sage.data_structures.bitset import Bitset, FrozenBitset from copy import copy from sage.categories.algebras_with_basis import AlgebrasWithBasis @@ -178,9 +178,9 @@ def list(self): sage: Cl. = CliffordAlgebra(Q) sage: elt = 5*x + y sage: elt.list() - [((0,), 5), ((1,), 1)] + [(1, 5), (01, 1)] """ - return sorted(self._monomial_coefficients.items(), key=lambda m_c : (-len(m_c[0]), m_c[0])) + return sorted(self._monomial_coefficients.items(), key=lambda m_c : (-len(m_c[0]), m_c)) def support(self): """ @@ -195,7 +195,7 @@ def support(self): sage: Cl. = CliffordAlgebra(Q) sage: elt = 5*x + y sage: elt.support() - [(0,), (1,)] + [1, 01] """ return sorted(self._monomial_coefficients.keys(), key=lambda x: (-len(x), x)) @@ -494,13 +494,8 @@ def __init__(self, Q, names, category=None): self._quadratic_form = Q R = Q.base_ring() category = AlgebrasWithBasis(R.category()).Super().Filtered().FiniteDimensional().or_subcategory(category) - format_style = f"0{Q.dim()}b" from functools import partial - # use a slice to reverse string order because Bitset and format(x, 'b') use different conventions - def index_function(x): - return FrozenBitset(format(x, format_style)[::-1], - capacity=Q.dim()) - indices = Family(range(2**Q.dim()), partial(index_function), lazy=True) + indices = Family(range(2**Q.dim()), partial(self._basis_index_function), lazy=True) CombinatorialFreeModule.__init__(self, R, indices, category=category) self._assign_names(names) @@ -681,15 +676,57 @@ def _element_constructor_(self, x): if x in self.free_module(): R = self.base_ring() if x.parent().base_ring() is R: - return self.element_class(self, {(i,): c for i,c in x.items()}) - return self.element_class(self, {(i,): R(c) for i,c in x.items() if R(c) != R.zero()}) + return self.element_class(self, {FrozenBitset((i,)): c for i,c in x.items()}) + # if the base ring is different, attempt to coerce it into R + return self.element_class(self, {FrozenBitset((i,)): R(c) for i,c in x.items() if R(c) != R.zero()}) if (isinstance(x, CliffordAlgebraElement) and self.has_coerce_map_from(x.parent())): R = self.base_ring() return self.element_class(self, {i: R(c) for i,c in x if R(c) != R.zero()}) - return super()._element_constructor_(x) + if isinstance(x, tuple): + R = self.base_ring() + return self.element_class(self, {FrozenBitset((i,)): R.one() for i in x}) + + return super(CliffordAlgebra, self)._element_constructor_(x) + + def _basis_index_function(self, x): + """ + Given an integer indexing the basis, return the correct + bitset. + + For backwards compatibility, tuples are also accepted. + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl = CliffordAlgebra(Q) + sage: Cl._basis_index_function(7) + 111 + sage: Cl._basis_index_function(5) + 101 + sage: Cl._basis_index_function(4) + 001 + + sage: Cl._basis_index_function((0, 1, 2)) + 111 + sage: Cl._basis_index_function((0, 2)) + 101 + sage: Cl._basis_index_function((2,)) + 001 + """ + Q = self._quadratic_form + format_style = f"0{Q.dim()}b" + + # if the input is a tuple, assume that it has + # entries in {0, ..., 2**Q.dim()-1} + if isinstance(x, tuple): + return FrozenBitset(x, capacity = Q.dim()) + + # slice the output of format in order to make conventions + # of format and FrozenBitset agree. + return FrozenBitset(format(x, format_style)[::-1], capacity=Q.dim()) def gen(self, i): """ @@ -706,7 +743,7 @@ def gen(self, i): sage: [Cl.gen(i) for i in range(3)] [x, y, z] """ - return self._from_dict({(i,): self.base_ring().one()}, remove_zeros=False) + return self._from_dict({FrozenBitset((i,)): self.base_ring().one()}, remove_zeros=False) def algebra_generators(self): """ @@ -751,14 +788,16 @@ def ngens(self): @cached_method def one_basis(self): """ - Return the basis index of the element `1`. + Return the basis index of the element ``1``. The element ``1`` + is indexed by the emptyset, which is represented by the + :class:`sage.data_structures.bitset.Bitset` ``0``. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) sage: Cl. = CliffordAlgebra(Q) sage: Cl.one_basis() - () + 0 """ return FrozenBitset('0') @@ -1032,7 +1071,7 @@ def lift_module_morphism(self, m, names=None): Cl = CliffordAlgebra(Q, names) n = self._quadratic_form.dim() - f = lambda x: self.prod(self._from_dict( {(j,): m[j,i] for j in range(n)}, + f = lambda x: self.prod(self._from_dict( {FrozenBitset((j,)): m[j,i] for j in range(n)}, remove_zeros=True ) for i in x) cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional() From 7803b032af3e5539dace7b73bd73331886301cdf Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 21 Jun 2022 13:21:11 -0500 Subject: [PATCH 127/591] Fix multiplication --- src/sage/algebras/clifford_algebra.py | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index ba222c16cdc..d3eda87f071 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -124,15 +124,16 @@ def _mul_(self, other): # ``e[i]`` * (the element described by the dictionary ``cur``) # (where ``e[i]`` is the ``i``-th standard basis vector). for mr,cr in cur.items(): + # Commute the factor as necessary until we are in order - pos = 0 for j in mr: if i <= j: break # Add the additional term from the commutation - t = list(mr) - t.pop(pos) - t = tuple(t) + # get a non-frozen bitset to manipulate + t = Bitset(mr) # a mutable copy + t.discard(j) + t = FrozenBitset(t) next[t] = next.get(t, zero) + cr * Q[i,j] # Note: ``Q[i,j] == Q(e[i]+e[j]) - Q(e[i]) - Q(e[j])`` for # ``i != j``, where ``e[k]`` is the ``k``-th standard @@ -140,22 +141,21 @@ def _mul_(self, other): cr = -cr if next[t] == zero: del next[t] - pos += 1 # Check to see if we have a squared term or not - t = list(mr) - if i in t: - t.remove(i) + mr = Bitset(mr) # temporarily mutable + if i in mr: + mr.discard(i) cr *= Q[i,i] # Note: ``Q[i,i] == Q(e[i])`` where ``e[i]`` is the # ``i``-th standard basis vector. else: - t.insert(pos, i) - # Note that ``t`` is now sorted. - t = tuple(t) - next[t] = next.get(t, zero) + cr - if next[t] == zero: - del next[t] + # mr is implicitly sorted + mr.add(i) + mr = FrozenBitset(mr) # refreeze it + next[mr] = next.get(mr, zero) + cr + if next[mr] == zero: + del next[mr] cur = next # Add the distributed terms to the total From d353cc8fd3907984f028d0090346058dd549a851 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 21 Jun 2022 14:04:39 -0500 Subject: [PATCH 128/591] Fix repr sorting issue and add some small tests --- src/sage/algebras/clifford_algebra.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index d3eda87f071..470b9bc4847 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -180,7 +180,7 @@ def list(self): sage: elt.list() [(1, 5), (01, 1)] """ - return sorted(self._monomial_coefficients.items(), key=lambda m_c : (-len(m_c[0]), m_c)) + return sorted(self._monomial_coefficients.items(), key=lambda m : (-len(m[0]), list(m[0]))) def support(self): """ @@ -197,7 +197,7 @@ def support(self): sage: elt.support() [1, 01] """ - return sorted(self._monomial_coefficients.keys(), key=lambda x: (-len(x), x)) + return sorted(self._monomial_coefficients.keys(), key=lambda x: (-len(x), list(x))) def reflection(self): r""" @@ -487,8 +487,7 @@ def __init__(self, Q, names, category=None): sage: Q = QuadraticForm(ZZ, 9) sage: Cl = CliffordAlgebra(Q) sage: ba = Cl.basis().keys() - sage: all( tuple(sorted(S)) in ba - ....: for S in Subsets(range(9)) ) + sage: all(FrozenBitset(format(i,'b')[::-1]) in ba for i in range(2**9)) True """ self._quadratic_form = Q @@ -525,6 +524,8 @@ def _repr_term(self, m): sage: Cl. = CliffordAlgebra(Q) sage: Cl._repr_term((0,2)) 'x*z' + sage: Cl._repr_term(FrozenBitset('101')) + 'x*z' sage: Cl._repr_term(()) '1' sage: Cl._repr_term((1,)) From bb0cdd748388cea18e92e27879b8eff5800b64f5 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 21 Jun 2022 14:51:32 -0500 Subject: [PATCH 129/591] First draft of basis iterator --- src/sage/algebras/clifford_algebra.py | 56 +++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 470b9bc4847..f11237fa564 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -32,7 +32,7 @@ from sage.matrix.args import MatrixArgs from sage.sets.family import Family from sage.combinat.free_module import CombinatorialFreeModule -from sage.combinat.subset import SubsetsSorted +from sage.combinat.subset import Subsets from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.algebras.weyl_algebra import repr_from_monomials from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass @@ -657,7 +657,7 @@ def _element_constructor_(self, x): sage: Cl(2/3) Traceback (most recent call last): ... - TypeError: do not know how to make x (= 2/3) an element of self ... + TypeError: do not know how to make x=2/3 an element of self sage: Clp(2/3) 2/3 sage: Clp(x) @@ -690,7 +690,57 @@ def _element_constructor_(self, x): R = self.base_ring() return self.element_class(self, {FrozenBitset((i,)): R.one() for i in x}) - return super(CliffordAlgebra, self)._element_constructor_(x) + try: + return super(CliffordAlgebra, self)._element_constructor_(x) + except TypeError: + raise TypeError(f'do not know how to make {x=} an element of self') + + def _basis_index_keys(self): + r""" + This gives the same values as range(2**Q.dim()), + but starting with elements that have 1 set bit, + then 2, then three, etc. + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl = CliffordAlgebra(Q) + + Notice that the monomial order is strictly lexicographic, + not degree-lexicographic when we use `range`. + + sage: for i in range(2**Q.dim()): print(Cl.basis()[i]) + 1 + x + y + x*y + z + x*z + y*z + x*y*z + + Notice that ``x*y`` comes before ``z`` if we use ``range``. + This isn't mathematically *wrong* but is not usually what + we want. On the other hand, using this method gives a + degree-respecting monomial order:: + + sage: for i in Cl.basis(): print(b) # indirect doctest + 1 + x + y + z + x*y + x*z + y*z + x*y*z + """ + n = self._quadratic_form.dim() + + for s in Subsets(range(n)): # it is ok here because this is only called when iterating over the bases, not in hash etc. + if not s: + yield 0 + continue + yield FrozenBitset(s).__hash__() def _basis_index_function(self, x): """ From 8c06eeda187859aade60a01ce1fd7bd7a385d712 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 21 Jun 2022 18:26:11 -0500 Subject: [PATCH 130/591] Second attempt at iterating --- src/sage/algebras/clifford_algebra.py | 32 ++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index f11237fa564..4188f97ed8a 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -494,7 +494,10 @@ def __init__(self, Q, names, category=None): R = Q.base_ring() category = AlgebrasWithBasis(R.category()).Super().Filtered().FiniteDimensional().or_subcategory(category) from functools import partial - indices = Family(range(2**Q.dim()), partial(self._basis_index_function), lazy=True) + indices = Family(self._basis_index_keys(self), #make basis_index_keys a class so I can give it a len? + partial(self._basis_index_function), + lazy=True, + name = 'Bitsets') CombinatorialFreeModule.__init__(self, R, indices, category=category) self._assign_names(names) @@ -695,7 +698,7 @@ def _element_constructor_(self, x): except TypeError: raise TypeError(f'do not know how to make {x=} an element of self') - def _basis_index_keys(self): + class _basis_index_keys: r""" This gives the same values as range(2**Q.dim()), but starting with elements that have 1 set bit, @@ -734,13 +737,26 @@ def _basis_index_keys(self): y*z x*y*z """ - n = self._quadratic_form.dim() - for s in Subsets(range(n)): # it is ok here because this is only called when iterating over the bases, not in hash etc. - if not s: - yield 0 - continue - yield FrozenBitset(s).__hash__() + def __init__(self, Cl): + self._Cl = Cl + self._quadratic_form = Cl._quadratic_form + + def __repr__(self): # dunder b/c not a parent subclass? + return f"Subsets of {{1,2,...,{self._quadratic_form.dim()}}}" + + def __len__(self): + return 2**self._quadratic_form.dim() + + def __iter__(self): + import itertools + n = self._quadratic_form.dim() + yield 0 + k = 1 + while k <= n: + for C in itertools.combinations(range(n),k): + yield sum(1 << i for i in C) + k += 1 def _basis_index_function(self, x): """ From 67a7b67ecd22359917d791e466c280a0ccb69028 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 23 Jun 2022 15:39:06 -0500 Subject: [PATCH 131/591] Add index class and first draft of exterior __mul__ --- src/sage/algebras/clifford_algebra.py | 183 ++++++++++---------------- 1 file changed, 66 insertions(+), 117 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 4188f97ed8a..f9f78e91bf7 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -19,11 +19,13 @@ from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent from sage.data_structures.bitset import Bitset, FrozenBitset from copy import copy from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.modules.with_basis.morphism import ModuleMorphismByLinearity from sage.categories.poor_man_map import PoorManMap from sage.rings.integer_ring import ZZ @@ -320,6 +322,60 @@ def conjugate(self): clifford_conjugate = conjugate +class CliffordAlgebraIndices(Parent): + r""" + A facade parent for the Clifford algebra + """ + def __call__(self, el): + if not isinstance(el, Element): + return self._element_constructor_(el) + else: + return Parent.__call__(self, el) + + def __init__(self, Qdim): + self._nbits = Qdim + self._cardinality = 2**Qdim + # the if statement here is in case Qdim is 0. + self._maximal_set = FrozenBitset('1'*self._nbits) if self._nbits else FrozenBitset('0') + category = FiniteEnumeratedSets().Facade() + Parent.__init__(self, category=category, facade=True) + + def __element_constructor__(self, x): + + if isinstance(x, (list, tuple, set, frozenset)): + if len(x) > self._nbits: + raise ValueError(f"{x=} is too long") + return FrozenBitset(x) + + if isinstance(x, int): + return FrozenBitset((x,)) + + def cardinality(self): + + return self._cardinality + + def _repr_(self): + return f"Subsets of {{1,2,...,{self._quadratic_form.dim()}}}" + + def __len__(self): + return self._cardinality + + def __iter__(self): + import itertools + n = self._nbits + yield FrozenBitset('0') + k = 1 + while k <= n: + for C in itertools.combinations(range(n),k): + yield FrozenBitset(C) + k += 1 + + def __contains__(self, other): + + if isinstance(other, int): + return (other < self._cardinality) and (other >= 0) + return self._maximal_set.issuperset(other) + class CliffordAlgebra(CombinatorialFreeModule): r""" The Clifford algebra of a quadratic form. @@ -493,11 +549,7 @@ def __init__(self, Q, names, category=None): self._quadratic_form = Q R = Q.base_ring() category = AlgebrasWithBasis(R.category()).Super().Filtered().FiniteDimensional().or_subcategory(category) - from functools import partial - indices = Family(self._basis_index_keys(self), #make basis_index_keys a class so I can give it a len? - partial(self._basis_index_function), - lazy=True, - name = 'Bitsets') + indices = CliffordAlgebraIndices(Q.dim()) CombinatorialFreeModule.__init__(self, R, indices, category=category) self._assign_names(names) @@ -698,103 +750,6 @@ def _element_constructor_(self, x): except TypeError: raise TypeError(f'do not know how to make {x=} an element of self') - class _basis_index_keys: - r""" - This gives the same values as range(2**Q.dim()), - but starting with elements that have 1 set bit, - then 2, then three, etc. - - EXAMPLES:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl = CliffordAlgebra(Q) - - Notice that the monomial order is strictly lexicographic, - not degree-lexicographic when we use `range`. - - sage: for i in range(2**Q.dim()): print(Cl.basis()[i]) - 1 - x - y - x*y - z - x*z - y*z - x*y*z - - Notice that ``x*y`` comes before ``z`` if we use ``range``. - This isn't mathematically *wrong* but is not usually what - we want. On the other hand, using this method gives a - degree-respecting monomial order:: - - sage: for i in Cl.basis(): print(b) # indirect doctest - 1 - x - y - z - x*y - x*z - y*z - x*y*z - """ - - def __init__(self, Cl): - self._Cl = Cl - self._quadratic_form = Cl._quadratic_form - - def __repr__(self): # dunder b/c not a parent subclass? - return f"Subsets of {{1,2,...,{self._quadratic_form.dim()}}}" - - def __len__(self): - return 2**self._quadratic_form.dim() - - def __iter__(self): - import itertools - n = self._quadratic_form.dim() - yield 0 - k = 1 - while k <= n: - for C in itertools.combinations(range(n),k): - yield sum(1 << i for i in C) - k += 1 - - def _basis_index_function(self, x): - """ - Given an integer indexing the basis, return the correct - bitset. - - For backwards compatibility, tuples are also accepted. - - EXAMPLES:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl = CliffordAlgebra(Q) - sage: Cl._basis_index_function(7) - 111 - sage: Cl._basis_index_function(5) - 101 - sage: Cl._basis_index_function(4) - 001 - - sage: Cl._basis_index_function((0, 1, 2)) - 111 - sage: Cl._basis_index_function((0, 2)) - 101 - sage: Cl._basis_index_function((2,)) - 001 - """ - Q = self._quadratic_form - format_style = f"0{Q.dim()}b" - - # if the input is a tuple, assume that it has - # entries in {0, ..., 2**Q.dim()-1} - if isinstance(x, tuple): - return FrozenBitset(x, capacity = Q.dim()) - - # slice the output of format in order to make conventions - # of format and FrozenBitset agree. - return FrozenBitset(format(x, format_style)[::-1], capacity=Q.dim()) - def gen(self, i): """ Return the ``i``-th standard generator of the algebra ``self``. @@ -1225,7 +1180,7 @@ def lift_isometry(self, m, names=None): Cl = CliffordAlgebra(Q, names) n = Q.dim() - f = lambda x: Cl.prod(Cl._from_dict( {(j,): m[j,i] for j in range(n)}, + f = lambda x: Cl.prod(Cl._from_dict( {FrozenBitset((j,)): m[j,i] for j in range(n)}, remove_zeros=True ) for i in x) cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional() @@ -2075,26 +2030,20 @@ def _mul_(self, other): for ml,cl in self: for mr,cr in other: # Create the next term - t = list(mr) + t = Bitset(mr) + + if ml.intersection(mr): + # if they intersect nontrivially, move along. + continue + for i in reversed(ml): - pos = 0 for j in t: - if i == j: - pos = None - break if i < j: break - pos += 1 cr = -cr - if pos is None: - t = None - break - t.insert(pos, i) - - if t is None: # The next term is 0, move along - continue + t.add(i) - t = tuple(t) + t = FrozenBitset(t) d[t] = d.get(t, zero) + cl * cr if d[t] == zero: del d[t] From c50c471ee5efe684ecd8d1190bc989230f7ffa5e Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Fri, 24 Jun 2022 09:11:13 -0500 Subject: [PATCH 132/591] Fix some bugs and rewrite exterior multplication algorithm --- src/sage/algebras/clifford_algebra.py | 53 ++++++++++++++++++--------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index f9f78e91bf7..abe46b6313c 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -355,7 +355,7 @@ def cardinality(self): return self._cardinality def _repr_(self): - return f"Subsets of {{1,2,...,{self._quadratic_form.dim()}}}" + return f"Subsets of {{1,2,...,{self._nbits}}}" def __len__(self): return self._cardinality @@ -1648,7 +1648,7 @@ def lift_morphism(self, phi, names=None): n = phi.nrows() R = self.base_ring() E = ExteriorAlgebra(R, names, n) - f = lambda x: E.prod(E._from_dict( {(j,): phi[j,i] for j in range(n)}, + f = lambda x: E.prod(E._from_dict( {FrozenBitset((j,)): phi[j,i] for j in range(n)}, remove_zeros=True ) for i in x) cat = AlgebrasWithBasis(R).Super().FiniteDimensional() @@ -2024,26 +2024,35 @@ def _mul_(self, other): sage: (x+y) * (y+z) x*y + x*z + y*z """ + n = self.parent().ngens() zero = self.parent().base_ring().zero() d = {} - for ml,cl in self: - for mr,cr in other: - # Create the next term - t = Bitset(mr) - + for ml,cl in self: # ml for "monomial on the left" + for mr,cr in other: # mr for "monomial on the right" if ml.intersection(mr): # if they intersect nontrivially, move along. continue - for i in reversed(ml): - for j in t: - if i < j: - break + if not mr: + t = ml + else: + t = ml.union(mr) + it = iter(mr) + j = next(it) + + num_cross = 0 # keep track of the number of signs + for i in ml: + while i > j: + num_cross += 1 + try: + j = next(it) + except StopIteration: + break + + if num_cross % 2: cr = -cr - t.add(i) - t = FrozenBitset(t) d[t] = d.get(t, zero) + cl * cr if d[t] == zero: del d[t] @@ -2480,7 +2489,7 @@ def _on_basis(self, m): sage: E. = ExteriorAlgebra(QQ) sage: par = E.boundary({(0,1): z, (1,2): x, (2,0): y}) - sage: par._on_basis(()) + sage: par._on_basis(FrozenBitset('0')) 0 sage: par._on_basis((0,)) 0 @@ -2491,12 +2500,22 @@ def _on_basis(self, m): sage: par._on_basis((0,1,2)) 0 """ + from itertools import combinations E = self.domain() sc = self._s_coeff keys = sc.keys() - return E.sum((-1)**b * sc[(i,j)] - * E.monomial(m[:a] + m[a+1:a+b+1] + m[a+b+2:]) - for a,i in enumerate(m) for b,j in enumerate(m[a+1:]) if (i,j) in keys) + + s = E.base_ring().zero() + + for b, (i,j) in enumerate(combinations(m, 2)): + t = Bitset(m) + if (i,j) not in keys: + continue + t.discard(i) + t.discard(j) + s += (-1)**b * sc[(i,j)] * E.monomial(FrozenBitset(t)) + + return s @cached_method def chain_complex(self, R=None): From dcd2c92e76883e97bea83a5572d102588cedf26f Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 25 Jun 2022 10:29:03 -0500 Subject: [PATCH 133/591] Coboundary and boundary fixes --- src/sage/algebras/clifford_algebra.py | 38 ++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index abe46b6313c..380e2120c43 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2023,8 +2023,13 @@ def _mul_(self, other): 0 sage: (x+y) * (y+z) x*y + x*z + y*z + + sage: E. = ExteriorAlgebra(QQ) + sage: (x * y) * (w * z) + -x*y*z*w + sage: x*y*w*z + -x*y*z*w """ - n = self.parent().ngens() zero = self.parent().base_ring().zero() d = {} @@ -2592,7 +2597,10 @@ def chain_complex(self, R=None): mat = [] for b in basis: ret = self._on_basis(b) - mat.append([ret[p] for p in prev_basis]) + try: + mat.append([ret.coefficient(p) for p in prev_basis]) + except AttributeError: # if ret is in E.base_ring() + mat.append([E.base_ring()(ret)]) data[deg] = Matrix(mat).transpose().change_ring(R) prev_basis = basis @@ -2731,7 +2739,7 @@ def __init__(self, E, s_coeff): zero = E.zero() B = E.basis() for k, v in dict(s_coeff).items(): - k = B[k] + k = B[FrozenBitset(k)] for m,c in v: self._cos_coeff[m] = self._cos_coeff.get(m, zero) + c * k ExteriorAlgebraDifferential.__init__(self, E, s_coeff) @@ -2776,8 +2784,23 @@ def _on_basis(self, m): E = self.domain() cc = self._cos_coeff keys = cc.keys() - return E.sum((-1)**a * E.monomial(m[:a]) * cc[(i,)] * E.monomial(m[a+1:]) - for a,i in enumerate(m) if (i,) in keys) + + s = E.base_ring().zero() + + sgn = 0 + + for i in m: + sgn += 1 + if FrozenBitset((i,)) in keys: + key_basis, key_coeff = cc[FrozenBitset((i,))].list()[0] + m_temp = Bitset(m) + if key_basis.intersection(m_temp): + continue + m_temp.discard(i) + m_temp.update(key_basis) + + s = s + (-1)**(sgn % 2) * key_coeff * E.monomial(FrozenBitset(m_temp)) + return s @cached_method def chain_complex(self, R=None): @@ -2854,7 +2877,10 @@ def chain_complex(self, R=None): mat = [] for b in basis: ret = self._on_basis(b) - mat.append([ret[p] for p in next_basis]) + try: + mat.append([ret.coefficient(p) for p in next_basis]) + except AttributeError: # if ret is in E.base_ring() + mat.append([E.base_ring()(ret)]) data[deg] = Matrix(mat).transpose().change_ring(R) basis = next_basis From 9030b03e2e2de680a7b68f4b6e35a936949d24df Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 25 Jun 2022 10:38:10 -0500 Subject: [PATCH 134/591] Fix sum initialization --- src/sage/algebras/clifford_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 380e2120c43..9792bd1005b 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2510,7 +2510,7 @@ def _on_basis(self, m): sc = self._s_coeff keys = sc.keys() - s = E.base_ring().zero() + s = E.zero() for b, (i,j) in enumerate(combinations(m, 2)): t = Bitset(m) From eae2294457a6e2efea29a66ba52a5ca26969a9bd Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 25 Jun 2022 11:17:54 -0500 Subject: [PATCH 135/591] Fix _element_constructor_ and asscii_art --- src/sage/algebras/clifford_algebra.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 9792bd1005b..fb1f9308119 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -340,7 +340,7 @@ def __init__(self, Qdim): category = FiniteEnumeratedSets().Facade() Parent.__init__(self, category=category, facade=True) - def __element_constructor__(self, x): + def _element_constructor_(self, x): if isinstance(x, (list, tuple, set, frozenset)): if len(x) > self._nbits: @@ -1504,7 +1504,7 @@ def _ascii_art_term(self, m): if len(m) == 0: return ascii_art('1') wedge = '/\\' - return ascii_art(*[self.variable_names()[i] for i in m], sep=wedge) + return ascii_art(*[repr(self.basis()[FrozenBitset((i,))]) for i in m], sep=wedge) def _unicode_art_term(self, m): """ From 48c5d074d3299cc550fc81e6baaca55017a52707 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 25 Jun 2022 12:24:41 -0500 Subject: [PATCH 136/591] Fix __getitem__ when using Bitsets --- src/sage/algebras/clifford_algebra.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index fb1f9308119..86b7bff759f 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1774,7 +1774,7 @@ def coproduct_on_basis(self, a): """ from sage.combinat.combinat import unshuffle_iterator one = self.base_ring().one() - return self.tensor_square().sum_of_terms(unshuffle_iterator(a, one), + return self.tensor_square().sum_of_terms(unshuffle_iterator(tuple(a), one), distinct=True) def antipode_on_basis(self, m): @@ -1982,7 +1982,7 @@ def lifted_form(x, y): m = len(my) if m != n: continue - matrix_list = [M[mx[i], my[j]] + matrix_list = [M[next(iter(mx)), next(iter(my))] for i in range(n) for j in range(n)] MA = MatrixArgs(R, n, matrix_list) From 3d4a66d9e7ace7ab85114306bbd5821032554734 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 25 Jun 2022 20:19:19 -0700 Subject: [PATCH 137/591] Fix sign issue --- src/sage/algebras/clifford_algebra.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 86b7bff759f..4b6ac340f5f 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2652,7 +2652,7 @@ class ExteriorAlgebraCoboundary(ExteriorAlgebraDifferential): cross product `\times` of `\RR^3`:: sage: E. = ExteriorAlgebra(QQ) - sage: d = E.coboundary({(0,1): z, (1,2): x, (2,0): y}) + sage: d = E.coboundary({(0,1): z, (1,2): x, (0, 2): -y}) sage: d(x) y*z sage: d(y) @@ -2765,7 +2765,7 @@ def _on_basis(self, m): cross product:: sage: E. = ExteriorAlgebra(QQ) - sage: d = E.coboundary({(0,1): z, (1,2): x, (2,0): y}) + sage: d = E.coboundary({(0,1): z, (1,2): x, (0,2): -y}) sage: d._on_basis(()) 0 sage: d._on_basis((0,)) From afc9948d4584580e06abaf37dd25de31e3726485 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 28 Jun 2022 07:17:44 -0700 Subject: [PATCH 138/591] Fix bug in making codifferential matrices --- src/sage/algebras/clifford_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 4b6ac340f5f..7fac01a2594 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2880,7 +2880,7 @@ def chain_complex(self, R=None): try: mat.append([ret.coefficient(p) for p in next_basis]) except AttributeError: # if ret is in E.base_ring() - mat.append([E.base_ring()(ret)]) + mat.append([E.base_ring()(ret)]*len(next_basis)) data[deg] = Matrix(mat).transpose().change_ring(R) basis = next_basis From 2b75b2ac95f1b05b4a058b5fad4a100574910f08 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sun, 3 Jul 2022 11:57:41 -0700 Subject: [PATCH 139/591] Fix bug with lifted bilinear form, a bug with zeros in module morphisms, and make a check more intuitive --- src/sage/algebras/clifford_algebra.py | 9 ++++++--- src/sage/modules/with_basis/morphism.py | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 7fac01a2594..39b10b1e17b 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1982,9 +1982,7 @@ def lifted_form(x, y): m = len(my) if m != n: continue - matrix_list = [M[next(iter(mx)), next(iter(my))] - for i in range(n) - for j in range(n)] + matrix_list = [M[i,j] for i in mx for j in my] MA = MatrixArgs(R, n, matrix_list) del matrix_list result += cx * cy * MA.matrix(False).determinant() @@ -2739,6 +2737,11 @@ def __init__(self, E, s_coeff): zero = E.zero() B = E.basis() for k, v in dict(s_coeff).items(): + + if k[0] > k[1]: #k will have length 2 + k = sorted(k) + v = -v + k = B[FrozenBitset(k)] for m,c in v: self._cos_coeff[m] = self._cos_coeff.get(m, zero) + c * k diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index b8fe98111b2..2efcc4f25e9 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -404,10 +404,10 @@ def __call__(self, *args): if self._is_module_with_basis_over_same_base_ring: return self.codomain().linear_combination( (self._on_basis(*(before+(index,)+after)), coeff ) - for (index, coeff) in mc.items()) + for (index, coeff) in mc.items() if self._on_basis(index)) else: return sum((coeff * self._on_basis(*(before+(index,)+after)) - for (index, coeff) in mc.items()), self._zero) + for (index, coeff) in mc.items() if self._on_basis(index)), self._zero) # As per the specs of Map, we should in fact implement _call_. # However we currently need to abuse Map.__call__ (which strict From f12b70cf9e9d985b4eb5695038df1b037e2c0aaf Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sun, 3 Jul 2022 13:31:03 -0700 Subject: [PATCH 140/591] Fix sign error --- src/sage/algebras/clifford_algebra.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 39b10b1e17b..5b4ae44c739 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2793,7 +2793,6 @@ def _on_basis(self, m): sgn = 0 for i in m: - sgn += 1 if FrozenBitset((i,)) in keys: key_basis, key_coeff = cc[FrozenBitset((i,))].list()[0] m_temp = Bitset(m) @@ -2803,6 +2802,8 @@ def _on_basis(self, m): m_temp.update(key_basis) s = s + (-1)**(sgn % 2) * key_coeff * E.monomial(FrozenBitset(m_temp)) + + sgn += 1 return s @cached_method From 153ba07797e682d53c86d2cacc190c53c0f9b8e0 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 5 Jul 2022 07:43:35 -0700 Subject: [PATCH 141/591] Fix coboundary on basis --- src/sage/algebras/clifford_algebra.py | 30 +++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 5b4ae44c739..20727291e6d 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2788,23 +2788,27 @@ def _on_basis(self, m): cc = self._cos_coeff keys = cc.keys() - s = E.base_ring().zero() + tot = E.zero() - sgn = 0 + for sgn, i in enumerate(m): + k = FrozenBitset((i,)) + if k in keys: + below = tuple(j for j in m if j < i) + above = tuple(j for j in m if j > i) - for i in m: - if FrozenBitset((i,)) in keys: - key_basis, key_coeff = cc[FrozenBitset((i,))].list()[0] - m_temp = Bitset(m) - if key_basis.intersection(m_temp): - continue - m_temp.discard(i) - m_temp.update(key_basis) + # a hack to deal with empty bitsets + if len(below) == 0: + below = FrozenBitset('0') + else: + below = FrozenBitset(below) + if len(above) == 0: + above = FrozenBitset('0') + else: + above = FrozenBitset(above) - s = s + (-1)**(sgn % 2) * key_coeff * E.monomial(FrozenBitset(m_temp)) + tot = tot + (-1)**sgn * E.monomial(below) * cc[k] * E.monomial(above) - sgn += 1 - return s + return tot @cached_method def chain_complex(self, R=None): From 929f55b8948d4b0f6cd463703fe6d78aea902678 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 5 Jul 2022 07:47:55 -0700 Subject: [PATCH 142/591] Clean up code a bit --- src/sage/algebras/clifford_algebra.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 20727291e6d..0bbc0c2d7dd 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2798,15 +2798,16 @@ def _on_basis(self, m): # a hack to deal with empty bitsets if len(below) == 0: - below = FrozenBitset('0') + below = E.one() else: - below = FrozenBitset(below) + below = E.monomial(FrozenBitset(below)) + if len(above) == 0: - above = FrozenBitset('0') + above = E.one() else: - above = FrozenBitset(above) + above = E.monomial(FrozenBitset(above)) - tot = tot + (-1)**sgn * E.monomial(below) * cc[k] * E.monomial(above) + tot = tot + (-1)**sgn * below * cc[k] * above return tot From e70115aaf15f31ccd8543abbd1ad41a8302b92c0 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 5 Jul 2022 12:28:19 -0700 Subject: [PATCH 143/591] Add doctest --- src/sage/algebras/clifford_algebra.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 0bbc0c2d7dd..071102a84b5 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2025,8 +2025,10 @@ def _mul_(self, other): sage: E. = ExteriorAlgebra(QQ) sage: (x * y) * (w * z) -x*y*z*w - sage: x*y*w*z + sage: x * y * w * z -x*y*z*w + sage: (z * w) * (x * y) + x*y*z*w """ zero = self.parent().base_ring().zero() d = {} From 328897d2a66012ac2c129af39ab4843bd6ef939c Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Fri, 8 Jul 2022 09:41:32 -0500 Subject: [PATCH 144/591] All tests pass --- src/sage/algebras/clifford_algebra.py | 38 ++++++++++++++++++--------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 071102a84b5..8e110e7661f 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -550,7 +550,7 @@ def __init__(self, Q, names, category=None): R = Q.base_ring() category = AlgebrasWithBasis(R.category()).Super().Filtered().FiniteDimensional().or_subcategory(category) indices = CliffordAlgebraIndices(Q.dim()) - CombinatorialFreeModule.__init__(self, R, indices, category=category) + CombinatorialFreeModule.__init__(self, R, indices, category=category, sorting_key=tuple) self._assign_names(names) def _repr_(self): @@ -794,6 +794,7 @@ def gens(self): """ return tuple(self.algebra_generators()) + @cached_method def ngens(self): """ Return the number of algebra generators of ``self``. @@ -1767,15 +1768,19 @@ def coproduct_on_basis(self, a): sage: E.coproduct_on_basis((0,)) 1 # x + x # 1 sage: E.coproduct_on_basis((0,1)) - 1 # x*y + x # y + x*y # 1 - y # x + 1 # x*y + x # y - y # x + x*y # 1 sage: E.coproduct_on_basis((0,1,2)) - 1 # x*y*z + x # y*z + x*y # z + x*y*z # 1 - - x*z # y - y # x*z + y*z # x + z # x*y + 1 # x*y*z + x # y*z - y # x*z + x*y # z + + z # x*y - x*z # y + y*z # x + x*y*z # 1 + """ from sage.combinat.combinat import unshuffle_iterator one = self.base_ring().one() - return self.tensor_square().sum_of_terms(unshuffle_iterator(tuple(a), one), - distinct=True) + L = unshuffle_iterator(tuple(a),one) + return self.tensor_square()._from_dict( + {tuple(FrozenBitset(e) if e else FrozenBitset('0') for e in t): c for t,c in L if c}, + coerce=False, + remove_zeros=False) def antipode_on_basis(self, m): r""" @@ -2030,8 +2035,10 @@ def _mul_(self, other): sage: (z * w) * (x * y) x*y*z*w """ - zero = self.parent().base_ring().zero() + P = self.parent() + zero = P.base_ring().zero() d = {} + n = P.ngens() for ml,cl in self: # ml for "monomial on the left" for mr,cr in other: # mr for "monomial on the right" @@ -2047,22 +2054,23 @@ def _mul_(self, other): j = next(it) num_cross = 0 # keep track of the number of signs + tot_cross = 0 for i in ml: while i > j: num_cross += 1 try: j = next(it) except StopIteration: - break - - if num_cross % 2: + j = n + 1 + tot_cross += num_cross + if tot_cross % 2: cr = -cr d[t] = d.get(t, zero) + cl * cr if d[t] == zero: del d[t] - return self.__class__(self.parent(), d) + return self.__class__(P, d) def interior_product(self, x): r""" @@ -2270,7 +2278,11 @@ def __classcall__(cls, E, s_coeff): sage: par1 = ExteriorAlgebraDifferential(E, {(0,1): z, (1,2): x, (2,0): y}) sage: par2 = ExteriorAlgebraDifferential(E, {(0,1): z, (1,2): x, (0,2): -y}) sage: par3 = ExteriorAlgebraDifferential(E, {(1,0): {2:-1}, (1,2): {0:1}, (2,0):{1:1}}) - sage: par1 is par2 and par2 is par3 + sage: par1 is par2 + True + sage: par1 is par3 + True + sage: par2 is par3 True sage: par4 = ExteriorAlgebraDifferential(E, {}) @@ -2287,7 +2299,7 @@ def __classcall__(cls, E, s_coeff): if isinstance(v, dict): R = E.base_ring() - v = E._from_dict({(i,): R(c) for i, c in v.items()}) + v = E._from_dict({FrozenBitset((i,)): R(c) for i,c in v.items()}) else: # Make sure v is in ``E`` v = E(v) From 8f34ece11cfd7f4e408d58b758576724719018c8 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 5 Jul 2022 13:26:10 -0700 Subject: [PATCH 145/591] Add doctest --- src/sage/algebras/clifford_algebra.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 8e110e7661f..12458bb1aff 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2056,8 +2056,9 @@ def _mul_(self, other): num_cross = 0 # keep track of the number of signs tot_cross = 0 for i in ml: + num_cross_new = 0 while i > j: - num_cross += 1 + num_cross_new += 1 try: j = next(it) except StopIteration: From 326f72abe9f20272a6c0e8de9316ea9fadc9c986 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Fri, 8 Jul 2022 09:50:16 -0500 Subject: [PATCH 146/591] Fix merge error --- src/sage/algebras/clifford_algebra.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 12458bb1aff..8e110e7661f 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2056,9 +2056,8 @@ def _mul_(self, other): num_cross = 0 # keep track of the number of signs tot_cross = 0 for i in ml: - num_cross_new = 0 while i > j: - num_cross_new += 1 + num_cross += 1 try: j = next(it) except StopIteration: From 296edb87aa5d907591921402c5507c5b6021d965 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Fri, 22 Jul 2022 19:39:33 -0500 Subject: [PATCH 147/591] Add tests for index class --- src/sage/algebras/clifford_algebra.py | 94 ++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 8e110e7661f..c0310164da5 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -20,6 +20,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent +from sage.structure.element import Element from sage.data_structures.bitset import Bitset, FrozenBitset from copy import copy @@ -324,15 +325,44 @@ def conjugate(self): class CliffordAlgebraIndices(Parent): r""" - A facade parent for the Clifford algebra + A facade parent for the indices of Clifford algebra. + Users should not create instances of this class directly. """ def __call__(self, el): + r""" + EXAMPLES:: + + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(7) + sage: idx([1,3,6]) + 0101001 + sage: E = ExteriorAlgebra(QQ, 7) + sage: B = E.basis() + + """ + if not isinstance(el, Element): return self._element_constructor_(el) else: return Parent.__call__(self, el) def __init__(self, Qdim): + r""" + EXAMPLES:: + + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(7) + sage: idx._nbits + 7 + sage: idx._cardinality + 128 + sage: idx._maximal_set + 1111111 + sage: i = idx.an_element(); i + 0 + sage: type(i) + + """ self._nbits = Qdim self._cardinality = 2**Qdim # the if statement here is in case Qdim is 0. @@ -341,7 +371,22 @@ def __init__(self, Qdim): Parent.__init__(self, category=category, facade=True) def _element_constructor_(self, x): + r""" + EXAMPLES:: + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(7) + sage: idx([1,3,6]) + 0101001 + sage: for i in range(7): print(idx(i)) + 1 + 01 + 001 + 0001 + 00001 + 000001 + 0000001 + """ if isinstance(x, (list, tuple, set, frozenset)): if len(x) > self._nbits: raise ValueError(f"{x=} is too long") @@ -351,16 +396,53 @@ def _element_constructor_(self, x): return FrozenBitset((x,)) def cardinality(self): + r""" + EXAMPLES:: + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(7) + sage: idx.cardinality() == 2^7 + True + """ return self._cardinality def _repr_(self): + r""" + EXAMPLES:: + + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(7); idx + Subsets of {1,2,...,7} + """ return f"Subsets of {{1,2,...,{self._nbits}}}" def __len__(self): + r""" + EXAMPLES:: + + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(7); + sage: len(idx) == 2^7 + True + """ return self._cardinality def __iter__(self): + r""" + EXAMPLES:: + + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(3); + sage: for i in idx: print(i) + 0 + 1 + 01 + 001 + 11 + 101 + 011 + 111 + """ import itertools n = self._nbits yield FrozenBitset('0') @@ -371,6 +453,16 @@ def __iter__(self): k += 1 def __contains__(self, other): + r""" + EXAMPLES:: + + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(3); + sage: int(8) in idx # representing the set {4} + False + sage: FrozenBitset('1') in idx + True + """ if isinstance(other, int): return (other < self._cardinality) and (other >= 0) From 6dcb98ef550bd94ee0a1df55f74a9dcda65e5be6 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Fri, 22 Jul 2022 20:18:35 -0500 Subject: [PATCH 148/591] PEP8 compliance --- src/sage/algebras/clifford_algebra.py | 198 +++++++++++++++++--------- 1 file changed, 130 insertions(+), 68 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index c0310164da5..dfdafc49a06 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -84,7 +84,9 @@ def _latex_(self): sage: latex( (x1 - x2)*x0 + 5*x0*x1*x2 ) 5 x_{0} x_{1} x_{2} - x_{0} x_{1} + x_{0} x_{2} - 1 """ - return repr_from_monomials(self.list(), self.parent()._latex_term, True) + return repr_from_monomials(self.list(), + self.parent()._latex_term, + True) def _mul_(self, other): """ @@ -115,9 +117,9 @@ def _mul_(self, other): zero = self.parent().base_ring().zero() d = {} - for ml,cl in self: + for ml, cl in self: # Distribute the current term ``cl`` * ``ml`` over ``other``. - cur = copy(other._monomial_coefficients) # The current distribution of the term + cur = copy(other._monomial_coefficients) # The current distribution of the term for i in reversed(ml): # Distribute the current factor ``e[i]`` (the ``i``-th # element of the standard basis). @@ -126,7 +128,7 @@ def _mul_(self, other): # the dictionary describing the element # ``e[i]`` * (the element described by the dictionary ``cur``) # (where ``e[i]`` is the ``i``-th standard basis vector). - for mr,cr in cur.items(): + for mr, cr in cur.items(): # Commute the factor as necessary until we are in order for j in mr: @@ -134,10 +136,10 @@ def _mul_(self, other): break # Add the additional term from the commutation # get a non-frozen bitset to manipulate - t = Bitset(mr) # a mutable copy + t = Bitset(mr) # a mutable copy t.discard(j) t = FrozenBitset(t) - next[t] = next.get(t, zero) + cr * Q[i,j] + next[t] = next.get(t, zero) + cr * Q[i, j] # Note: ``Q[i,j] == Q(e[i]+e[j]) - Q(e[i]) - Q(e[j])`` for # ``i != j``, where ``e[k]`` is the ``k``-th standard # basis vector. @@ -146,23 +148,23 @@ def _mul_(self, other): del next[t] # Check to see if we have a squared term or not - mr = Bitset(mr) # temporarily mutable + mr = Bitset(mr) # temporarily mutable if i in mr: mr.discard(i) - cr *= Q[i,i] + cr *= Q[i, i] # Note: ``Q[i,i] == Q(e[i])`` where ``e[i]`` is the # ``i``-th standard basis vector. else: # mr is implicitly sorted mr.add(i) - mr = FrozenBitset(mr) # refreeze it + mr = FrozenBitset(mr) # refreeze it next[mr] = next.get(mr, zero) + cr if next[mr] == zero: del next[mr] cur = next # Add the distributed terms to the total - for index,coeff in cur.items(): + for index, coeff in cur.items(): d[index] = d.get(index, zero) + cl * coeff if d[index] == zero: del d[index] @@ -183,7 +185,7 @@ def list(self): sage: elt.list() [(1, 5), (01, 1)] """ - return sorted(self._monomial_coefficients.items(), key=lambda m : (-len(m[0]), list(m[0]))) + return sorted(self._monomial_coefficients.items(), key=lambda m: (-len(m[0]), list(m[0]))) def support(self): """ @@ -237,7 +239,7 @@ def reflection(self): sage: all(x.reflection().reflection() == x for x in Cl.basis()) True """ - return self.__class__(self.parent(), {m: (-1)**len(m) * c for m,c in self}) + return self.__class__(self.parent(), {m: (-1)**len(m) * c for m, c in self}) degree_negation = reflection @@ -283,7 +285,7 @@ def transpose(self): if not self._monomial_coefficients: return P.zero() g = P.gens() - return P.sum(c * P.prod(g[i] for i in reversed(m)) for m,c in self) + return P.sum(c * P.prod(g[i] for i in reversed(m)) for m, c in self) def conjugate(self): r""" @@ -322,6 +324,65 @@ def conjugate(self): clifford_conjugate = conjugate + # TODO: This is a general function which should be moved to a + # superalgebras category when one is implemented. + def supercommutator(self, x): + r""" + Return the supercommutator of ``self`` and ``x``. + + Let `A` be a superalgebra. The *supercommutator* of homogeneous + elements `x, y \in A` is defined by + + .. MATH:: + + [x, y\} = x y - (-1)^{|x| |y|} y x + + and extended to all elements by linearity. + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: a = x*y - z + sage: b = x - y + y*z + sage: a.supercommutator(b) + -5*x*y + 8*x*z - 2*y*z - 6*x + 12*y - 5*z + sage: a.supercommutator(Cl.one()) + 0 + sage: Cl.one().supercommutator(a) + 0 + sage: Cl.zero().supercommutator(a) + 0 + sage: a.supercommutator(Cl.zero()) + 0 + + sage: Q = QuadraticForm(ZZ, 2, [-1,1,-3]) + sage: Cl. = CliffordAlgebra(Q) + sage: [a.supercommutator(b) for a in Cl.basis() for b in Cl.basis()] + [0, 0, 0, 0, 0, -2, 1, -x - 2*y, 0, 1, + -6, 6*x + y, 0, x + 2*y, -6*x - y, 0] + sage: [a*b-b*a for a in Cl.basis() for b in Cl.basis()] + [0, 0, 0, 0, 0, 0, 2*x*y - 1, -x - 2*y, 0, + -2*x*y + 1, 0, 6*x + y, 0, x + 2*y, -6*x - y, 0] + + Exterior algebras inherit from Clifford algebras, so + supercommutators work as well. We verify the exterior algebra + is supercommutative:: + + sage: E. = ExteriorAlgebra(QQ) + sage: all(b1.supercommutator(b2) == 0 + ....: for b1 in E.basis() for b2 in E.basis()) + True + """ + P = self.parent() + ret = P.zero() + for ms, cs in self: + for mx, cx in x: + ret += P.term(ms, cs) * P.term(mx, cx) + s = (-1)**(P.degree_on_basis(ms) * P.degree_on_basis(mx)) + ret -= s * P.term(mx, cx) * P.term(ms, cs) + return ret + class CliffordAlgebraIndices(Parent): r""" @@ -338,7 +399,6 @@ def __call__(self, el): 0101001 sage: E = ExteriorAlgebra(QQ, 7) sage: B = E.basis() - """ if not isinstance(el, Element): @@ -421,7 +481,7 @@ def __len__(self): EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices - sage: idx = CliffordAlgebraIndices(7); + sage: idx = CliffordAlgebraIndices(7); sage: len(idx) == 2^7 True """ @@ -432,7 +492,7 @@ def __iter__(self): EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices - sage: idx = CliffordAlgebraIndices(3); + sage: idx = CliffordAlgebraIndices(3); sage: for i in idx: print(i) 0 1 @@ -448,7 +508,7 @@ def __iter__(self): yield FrozenBitset('0') k = 1 while k <= n: - for C in itertools.combinations(range(n),k): + for C in itertools.combinations(range(n), k): yield FrozenBitset(C) k += 1 @@ -457,7 +517,7 @@ def __contains__(self, other): EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices - sage: idx = CliffordAlgebraIndices(3); + sage: idx = CliffordAlgebraIndices(3); sage: int(8) in idx # representing the set {4} False sage: FrozenBitset('1') in idx @@ -468,6 +528,7 @@ def __contains__(self, other): return (other < self._cardinality) and (other >= 0) return self._maximal_set.issuperset(other) + class CliffordAlgebra(CombinatorialFreeModule): r""" The Clifford algebra of a quadratic form. @@ -609,7 +670,7 @@ def __classcall_private__(cls, Q, names=None): names = tuple(names) if len(names) != Q.dim(): if len(names) == 1: - names = tuple( '{}{}'.format(names[0], i) for i in range(Q.dim()) ) + names = tuple('{}{}'.format(names[0], i) for i in range(Q.dim())) else: raise ValueError("the number of variables does not match the number of generators") return super().__classcall__(cls, Q, names) @@ -824,14 +885,14 @@ def _element_constructor_(self, x): if x in self.free_module(): R = self.base_ring() if x.parent().base_ring() is R: - return self.element_class(self, {FrozenBitset((i,)): c for i,c in x.items()}) + return self.element_class(self, {FrozenBitset((i, )): c for i, c in x.items()}) # if the base ring is different, attempt to coerce it into R - return self.element_class(self, {FrozenBitset((i,)): R(c) for i,c in x.items() if R(c) != R.zero()}) + return self.element_class(self, {FrozenBitset((i, )): R(c) for i, c in x.items() if R(c) != R.zero()}) if (isinstance(x, CliffordAlgebraElement) - and self.has_coerce_map_from(x.parent())): + and self.has_coerce_map_from(x.parent())): R = self.base_ring() - return self.element_class(self, {i: R(c) for i,c in x if R(c) != R.zero()}) + return self.element_class(self, {i: R(c) for i, c in x if R(c) != R.zero()}) if isinstance(x, tuple): R = self.base_ring() @@ -857,7 +918,7 @@ def gen(self, i): sage: [Cl.gen(i) for i in range(3)] [x, y, z] """ - return self._from_dict({FrozenBitset((i,)): self.base_ring().one()}, remove_zeros=False) + return self._from_dict({FrozenBitset((i, )): self.base_ring().one()}, remove_zeros=False) def algebra_generators(self): """ @@ -870,7 +931,7 @@ def algebra_generators(self): sage: Cl.algebra_generators() Finite family {'x': x, 'y': y, 'z': z} """ - d = {x: self.gen(i) for i,x in enumerate(self.variable_names())} + d = {x: self.gen(i) for i, x in enumerate(self.variable_names())} return Family(self.variable_names(), lambda x: d[x]) def gens(self): @@ -1186,9 +1247,8 @@ def lift_module_morphism(self, m, names=None): Cl = CliffordAlgebra(Q, names) n = self._quadratic_form.dim() - f = lambda x: self.prod(self._from_dict( {FrozenBitset((j,)): m[j,i] for j in range(n)}, - remove_zeros=True ) - for i in x) + f = lambda x: self.prod(self._from_dict({FrozenBitset((j, )): m[j, i] for j in range(n)}, + remove_zeros=True) for i in x) cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional() return Cl.module_morphism(on_basis=f, codomain=self, category=cat) @@ -1273,9 +1333,8 @@ def lift_isometry(self, m, names=None): Cl = CliffordAlgebra(Q, names) n = Q.dim() - f = lambda x: Cl.prod(Cl._from_dict( {FrozenBitset((j,)): m[j,i] for j in range(n)}, - remove_zeros=True ) - for i in x) + f = lambda x: Cl.prod(Cl._from_dict({FrozenBitset((j, )): m[j, i] for j in range(n)}, + remove_zeros=True) for i in x) cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional() return self.module_morphism(on_basis=f, codomain=Cl, category=cat) @@ -1347,16 +1406,16 @@ def center_basis(self): K = list(B.keys()) k = len(K) d = {} - for a,i in enumerate(K): + for a, i in enumerate(K): Bi = B[i] - for b,j in enumerate(K): + for b, j in enumerate(K): Bj = B[j] - for m,c in (Bi*Bj - Bj*Bi): + for m, c in (Bi*Bj - Bj*Bi): d[(a, K.index(m)+k*b)] = c m = Matrix(R, d, nrows=k, ncols=k*k, sparse=True) - from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in x.items()), + from_vector = lambda x: self.sum_of_terms(((K[i], c) for i, c in x.items()), distinct=True) - return tuple(map( from_vector, m.kernel().basis() )) + return tuple(map(from_vector, m.kernel().basis())) # Same as center except for superalgebras @cached_method @@ -1426,23 +1485,24 @@ def supercenter_basis(self): K = list(B.keys()) k = len(K) d = {} - for a,i in enumerate(K): + for a, i in enumerate(K): Bi = B[i] - for b,j in enumerate(K): + for b, j in enumerate(K): Bj = B[j] if len(i) % 2 and len(j) % 2: supercommutator = Bi * Bj + Bj * Bi else: supercommutator = Bi * Bj - Bj * Bi - for m,c in supercommutator: - d[(a, K.index(m)+k*b)] = c - m = Matrix(R, d, nrows=k, ncols=k*k, sparse=True) - from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in x.items()), + for m, c in supercommutator: + d[(a, K.index(m) + k * b)] = c + m = Matrix(R, d, nrows=k, ncols=k * k, sparse=True) + from_vector = lambda x: self.sum_of_terms(((K[i], c) for i, c in x.items()), distinct=True) - return tuple(map( from_vector, m.kernel().basis() )) + return tuple(map(from_vector, m.kernel().basis())) Element = CliffordAlgebraElement + class ExteriorAlgebra(CliffordAlgebra): r""" An exterior algebra of a free module over a commutative ring. @@ -1527,7 +1587,7 @@ def __classcall_private__(cls, R, names=None, n=None): names = tuple(names) if n is not None and len(names) != n: if len(names) == 1: - names = tuple( '{}{}'.format(names[0], i) for i in range(n) ) + names = tuple('{}{}'.format(names[0], i) for i in range(n)) else: raise ValueError("the number of variables does not match the number of generators") return super().__classcall__(cls, R, names) @@ -1597,7 +1657,7 @@ def _ascii_art_term(self, m): if len(m) == 0: return ascii_art('1') wedge = '/\\' - return ascii_art(*[repr(self.basis()[FrozenBitset((i,))]) for i in m], sep=wedge) + return ascii_art(*[repr(self.basis()[FrozenBitset((i, ))]) for i in m], sep=wedge) def _unicode_art_term(self, m): """ @@ -1741,9 +1801,8 @@ def lift_morphism(self, phi, names=None): n = phi.nrows() R = self.base_ring() E = ExteriorAlgebra(R, names, n) - f = lambda x: E.prod(E._from_dict( {FrozenBitset((j,)): phi[j,i] for j in range(n)}, - remove_zeros=True ) - for i in x) + f = lambda x: E.prod(E._from_dict({FrozenBitset((j, )): phi[j, i] for j in range(n)}, + remove_zeros=True) for i in x) cat = AlgebrasWithBasis(R).Super().FiniteDimensional() return self.module_morphism(on_basis=f, codomain=E, category=cat) @@ -1868,9 +1927,9 @@ def coproduct_on_basis(self, a): """ from sage.combinat.combinat import unshuffle_iterator one = self.base_ring().one() - L = unshuffle_iterator(tuple(a),one) + L = unshuffle_iterator(tuple(a), one) return self.tensor_square()._from_dict( - {tuple(FrozenBitset(e) if e else FrozenBitset('0') for e in t): c for t,c in L if c}, + {tuple(FrozenBitset(e) if e else FrozenBitset('0') for e in t): c for t, c in L if c}, coerce=False, remove_zeros=False) @@ -2079,7 +2138,7 @@ def lifted_form(x, y): m = len(my) if m != n: continue - matrix_list = [M[i,j] for i in mx for j in my] + matrix_list = [M[i, j] for i in mx for j in my] MA = MatrixArgs(R, n, matrix_list) del matrix_list result += cx * cy * MA.matrix(False).determinant() @@ -2132,8 +2191,8 @@ def _mul_(self, other): d = {} n = P.ngens() - for ml,cl in self: # ml for "monomial on the left" - for mr,cr in other: # mr for "monomial on the right" + for ml, cl in self: # ml for "monomial on the left" + for mr, cr in other: # mr for "monomial on the right" if ml.intersection(mr): # if they intersect nontrivially, move along. continue @@ -2145,7 +2204,7 @@ def _mul_(self, other): it = iter(mr) j = next(it) - num_cross = 0 # keep track of the number of signs + num_cross = 0 # keep track of the number of signs tot_cross = 0 for i in ml: while i > j: @@ -2245,7 +2304,7 @@ def interior_product(self, x): """ P = self.parent() return P.sum([c * cx * P.interior_product_on_basis(m, mx) - for m,c in self for mx,cx in x]) + for m, c in self for mx, cx in x]) antiderivation = interior_product @@ -2339,10 +2398,12 @@ def scalar(self, other): return (self.transpose() * other).constant_coefficient() ##################################################################### -## Differentials +# Differentials + class ExteriorAlgebraDifferential(ModuleMorphismByLinearity, - UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): + UniqueRepresentation, + metaclass=InheritComparisonClasscallMetaclass): r""" Internal class to store the data of a boundary or coboundary of an exterior algebra `\Lambda(L)` defined by the structure @@ -2386,12 +2447,12 @@ def __classcall__(cls, E, s_coeff): d = {} for k, v in dict(s_coeff).items(): - if not v: # Strip terms with 0 + if not v: # Strip terms with 0 continue if isinstance(v, dict): R = E.base_ring() - v = E._from_dict({FrozenBitset((i,)): R(c) for i,c in v.items()}) + v = E._from_dict({FrozenBitset((i, )): R(c) for i, c in v.items()}) else: # Make sure v is in ``E`` v = E(v) @@ -2466,6 +2527,7 @@ def homology(self, deg=None, **kwds): """ return self.chain_complex().homology(deg, **kwds) + class ExteriorAlgebraBoundary(ExteriorAlgebraDifferential): r""" The boundary `\partial` of an exterior algebra `\Lambda(L)` defined @@ -2616,13 +2678,13 @@ def _on_basis(self, m): s = E.zero() - for b, (i,j) in enumerate(combinations(m, 2)): + for b, (i, j) in enumerate(combinations(m, 2)): t = Bitset(m) - if (i,j) not in keys: + if (i, j) not in keys: continue t.discard(i) t.discard(j) - s += (-1)**b * sc[(i,j)] * E.monomial(FrozenBitset(t)) + s += (-1)**b * sc[(i, j)] * E.monomial(FrozenBitset(t)) return s @@ -2695,7 +2757,7 @@ def chain_complex(self, R=None): # Construct the transition matrices data = {} prev_basis = basis_by_deg[0] - for deg in range(1,n+1): + for deg in range(1, n+1): # Make sure within each basis we're sorted by lex basis = sorted(basis_by_deg[deg]) mat = [] @@ -2703,13 +2765,14 @@ def chain_complex(self, R=None): ret = self._on_basis(b) try: mat.append([ret.coefficient(p) for p in prev_basis]) - except AttributeError: # if ret is in E.base_ring() + except AttributeError: # if ret is in E.base_ring() mat.append([E.base_ring()(ret)]) data[deg] = Matrix(mat).transpose().change_ring(R) prev_basis = basis return ChainComplex(data, degree=-1) + class ExteriorAlgebraCoboundary(ExteriorAlgebraDifferential): r""" The coboundary `d` of an exterior algebra `\Lambda(L)` defined @@ -2844,12 +2907,12 @@ def __init__(self, E, s_coeff): B = E.basis() for k, v in dict(s_coeff).items(): - if k[0] > k[1]: #k will have length 2 + if k[0] > k[1]: # k will have length 2 k = sorted(k) v = -v k = B[FrozenBitset(k)] - for m,c in v: + for m, c in v: self._cos_coeff[m] = self._cos_coeff.get(m, zero) + c * k ExteriorAlgebraDifferential.__init__(self, E, s_coeff) @@ -2907,7 +2970,6 @@ def _on_basis(self, m): below = E.one() else: below = E.monomial(FrozenBitset(below)) - if len(above) == 0: above = E.one() else: @@ -2994,7 +3056,7 @@ def chain_complex(self, R=None): ret = self._on_basis(b) try: mat.append([ret.coefficient(p) for p in next_basis]) - except AttributeError: # if ret is in E.base_ring() + except AttributeError: # if ret is in E.base_ring() mat.append([E.base_ring()(ret)]*len(next_basis)) data[deg] = Matrix(mat).transpose().change_ring(R) basis = next_basis From 7e72b2adbd3720254a0c4025a04ca9ed8034a2e9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 25 Jul 2022 12:21:05 -0700 Subject: [PATCH 149/591] build/pkgs/cython/patches/4918.patch: New --- build/pkgs/cython/patches/4918.patch | 287 +++++++++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 build/pkgs/cython/patches/4918.patch diff --git a/build/pkgs/cython/patches/4918.patch b/build/pkgs/cython/patches/4918.patch new file mode 100644 index 00000000000..a9dbb0a4a0c --- /dev/null +++ b/build/pkgs/cython/patches/4918.patch @@ -0,0 +1,287 @@ +From 0dade9353e06b052d0da5e512cdc2ce04061904a Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Sat, 23 Jul 2022 10:53:49 -0700 +Subject: [PATCH 1/3] Add PEP420 namespace support + +Backport of https://github.com/cython/cython/pull/2946 to 0.29.x +--- + Cython/Compiler/Main.py | 44 +++++++++++++++---- + Cython/Utils.py | 26 ++++++++--- + runtests.py | 1 + + .../build/cythonize_pep420_namespace.srctree | 44 +++++++++++++++++++ + 4 files changed, 99 insertions(+), 16 deletions(-) + create mode 100644 tests/build/cythonize_pep420_namespace.srctree + +diff --git a/Cython/Compiler/Main.py b/Cython/Compiler/Main.py +index dc4add541e..2be7a06a1c 100644 +--- a/Cython/Compiler/Main.py ++++ b/Cython/Compiler/Main.py +@@ -801,32 +801,58 @@ def search_include_directories(dirs, qualified_name, suffix, pos, include=False) + else: + dirs = (Utils.find_root_package_dir(file_desc.filename),) + dirs + ++ # search for dotted filename e.g. /foo.bar.pxd + dotted_filename = qualified_name + if suffix: + dotted_filename += suffix + ++ for dirname in dirs: ++ path = os.path.join(dirname, dotted_filename) ++ if os.path.exists(path): ++ return path ++ ++ # search for filename in package structure e.g. /foo/bar.pxd or /foo/bar/__init__.pxd + if not include: ++ + names = qualified_name.split('.') + package_names = tuple(names[:-1]) + module_name = names[-1] + module_filename = module_name + suffix + package_filename = "__init__" + suffix + +- for dirname in dirs: +- path = os.path.join(dirname, dotted_filename) +- if os.path.exists(path): +- return path +- +- if not include: +- package_dir = Utils.check_package_dir(dirname, package_names) ++ # search for standard packages first - PEP420 ++ namespace_dirs = [] ++ for dirname in dirs: ++ package_dir, is_namespace = Utils.check_package_dir(dirname, package_names) + if package_dir is not None: ++ ++ if is_namespace: ++ namespace_dirs.append(package_dir) ++ continue ++ ++ # matches modules of the form: /foo/bar.pxd + path = os.path.join(package_dir, module_filename) + if os.path.exists(path): + return path +- path = os.path.join(package_dir, module_name, +- package_filename) ++ ++ # matches modules of the form: /foo/bar/__init__.pxd ++ path = os.path.join(package_dir, module_name, package_filename) + if os.path.exists(path): + return path ++ ++ # search for namespaces second - PEP420 ++ for package_dir in namespace_dirs: ++ ++ # matches modules of the form: /foo/bar.pxd ++ path = os.path.join(package_dir, module_filename) ++ if os.path.exists(path): ++ return path ++ ++ # matches modules of the form: /foo/bar/__init__.pxd ++ path = os.path.join(package_dir, module_name, package_filename) ++ if os.path.exists(path): ++ return path ++ + return None + + +diff --git a/Cython/Utils.py b/Cython/Utils.py +index d59d67d78b..305ebf8412 100644 +--- a/Cython/Utils.py ++++ b/Cython/Utils.py +@@ -134,16 +134,21 @@ def find_root_package_dir(file_path): + else: + return dir + ++ + @cached_function +-def check_package_dir(dir, package_names): ++def check_package_dir(dir_path, package_names): ++ namespace = True + for dirname in package_names: +- dir = os.path.join(dir, dirname) +- if not is_package_dir(dir): +- return None +- return dir ++ dir_path = os.path.join(dir_path, dirname) ++ has_init = contains_init(dir_path) ++ if not namespace and not has_init: ++ return None, False ++ elif has_init: ++ namespace = False ++ return dir_path, namespace + +-@cached_function +-def is_package_dir(dir_path): ++ ++def contains_init(dir_path): + for filename in ("__init__.py", + "__init__.pyc", + "__init__.pyx", +@@ -152,6 +157,13 @@ def is_package_dir(dir_path): + if path_exists(path): + return 1 + ++ ++@cached_function ++def is_package_dir(dir_path): ++ if contains_init(dir_path): ++ return 1 ++ ++ + @cached_function + def path_exists(path): + # try on the filesystem first +diff --git a/runtests.py b/runtests.py +index 91a0dd2570..7d04463846 100755 +--- a/runtests.py ++++ b/runtests.py +@@ -415,6 +415,7 @@ def get_openmp_compiler_flags(language): + 'run.special_methods_T561_py2' + ]), + (3,3) : (operator.lt, lambda x: x in ['build.package_compilation', ++ 'build.cythonize_pep420_namespace', + 'run.yield_from_py33', + 'pyximport.pyximport_namespace', + ]), +diff --git a/tests/build/cythonize_pep420_namespace.srctree b/tests/build/cythonize_pep420_namespace.srctree +new file mode 100644 +index 0000000000..6a031e4170 +--- /dev/null ++++ b/tests/build/cythonize_pep420_namespace.srctree +@@ -0,0 +1,44 @@ ++PYTHON setup.py build_ext --inplace ++PYTHON -c "import runner" ++ ++######## setup.py ######## ++ ++from Cython.Build.Dependencies import cythonize ++ ++from distutils.core import setup, Extension ++ ++setup( ++ ext_modules=cythonize([ ++ Extension("nsp.m1.a", ["nsp/m1/a.pyx"]), ++ Extension("nsp.m2.b", ["nsp/m2/b.pyx"]) ++ ]), ++) ++ ++######## nsp/m1/__init__.py ######## ++ ++######## nsp/m1/a.pyx ######## ++ ++cdef class A: ++ pass ++ ++######## nsp/m1/a.pxd ######## ++ ++cdef class A: ++ pass ++ ++######## nsp/m2/__init__.py ######## ++ ++######## nsp/m2/b.pyx ######## ++ ++from nsp.m1.a cimport A ++ ++cdef class B(A): ++ pass ++ ++######## runner.py ######## ++ ++from nsp.m1.a import A ++from nsp.m2.b import B ++ ++a = A() ++b = B() + +From fcd3e7bd1351a0964704f2921ae33b4b57250668 Mon Sep 17 00:00:00 2001 +From: Fedor Alekseev +Date: Mon, 9 Nov 2020 14:34:01 +0300 +Subject: [PATCH 2/3] Support namespace packages inside regular packages + +--- + Cython/Utils.py | 4 +--- + tests/build/cythonize_pep420_namespace.srctree | 17 ++++++++++++++++- + 2 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/Cython/Utils.py b/Cython/Utils.py +index 305ebf8412..f21d5cddba 100644 +--- a/Cython/Utils.py ++++ b/Cython/Utils.py +@@ -141,9 +141,7 @@ def check_package_dir(dir_path, package_names): + for dirname in package_names: + dir_path = os.path.join(dir_path, dirname) + has_init = contains_init(dir_path) +- if not namespace and not has_init: +- return None, False +- elif has_init: ++ if has_init: + namespace = False + return dir_path, namespace + +diff --git a/tests/build/cythonize_pep420_namespace.srctree b/tests/build/cythonize_pep420_namespace.srctree +index 6a031e4170..04013a3004 100644 +--- a/tests/build/cythonize_pep420_namespace.srctree ++++ b/tests/build/cythonize_pep420_namespace.srctree +@@ -10,7 +10,8 @@ from distutils.core import setup, Extension + setup( + ext_modules=cythonize([ + Extension("nsp.m1.a", ["nsp/m1/a.pyx"]), +- Extension("nsp.m2.b", ["nsp/m2/b.pyx"]) ++ Extension("nsp.m2.b", ["nsp/m2/b.pyx"]), ++ Extension("nsp.m3.c.d", ["nsp/m3/c/d.pyx"]) + ]), + ) + +@@ -31,14 +32,28 @@ cdef class A: + ######## nsp/m2/b.pyx ######## + + from nsp.m1.a cimport A ++from nsp.m3.c.d cimport D + + cdef class B(A): + pass + ++######## nsp/m3/__init__.py ######## ++ ++######## nsp/m3/c/d.pyx ######## ++ ++cdef class D: ++ pass ++ ++######## nsp/m3/c/d.pxd ######## ++ ++cdef class D: ++ pass ++ + ######## runner.py ######## + + from nsp.m1.a import A + from nsp.m2.b import B ++from nsp.m3.c.d import D + + a = A() + b = B() + +From 9d61b95a6a71a4c88a51ab8f30d5b3a8b93998b8 Mon Sep 17 00:00:00 2001 +From: scoder +Date: Sat, 14 Nov 2020 09:42:09 +0100 +Subject: [PATCH 3/3] Anticipate future changes. + +--- + tests/build/cythonize_pep420_namespace.srctree | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/build/cythonize_pep420_namespace.srctree b/tests/build/cythonize_pep420_namespace.srctree +index 04013a3004..99649376a3 100644 +--- a/tests/build/cythonize_pep420_namespace.srctree ++++ b/tests/build/cythonize_pep420_namespace.srctree +@@ -11,7 +11,7 @@ setup( + ext_modules=cythonize([ + Extension("nsp.m1.a", ["nsp/m1/a.pyx"]), + Extension("nsp.m2.b", ["nsp/m2/b.pyx"]), +- Extension("nsp.m3.c.d", ["nsp/m3/c/d.pyx"]) ++ Extension("nsp.m3.c.d", ["nsp/m3/c/d.pyx"]), + ]), + ) + From 176531ab7b3e708a51bcbf1d70b89542b553ddf1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 25 Jul 2022 12:25:14 -0700 Subject: [PATCH 150/591] build/pkgs/cython/package-version.txt: Add patchlevel --- build/pkgs/cython/package-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/cython/package-version.txt b/build/pkgs/cython/package-version.txt index 0498a7acb8d..e9555f0ff14 100644 --- a/build/pkgs/cython/package-version.txt +++ b/build/pkgs/cython/package-version.txt @@ -1 +1 @@ -0.29.30 +0.29.30.p1 From d0ab1a1613d9152c7a518a17b405e3b9b615e0f4 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 21 Jun 2022 12:31:12 -0500 Subject: [PATCH 151/591] Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset) --- src/sage/algebras/clifford_algebra.py | 61 +++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index dfdafc49a06..6aa6b541724 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -885,9 +885,15 @@ def _element_constructor_(self, x): if x in self.free_module(): R = self.base_ring() if x.parent().base_ring() is R: +<<<<<<< HEAD return self.element_class(self, {FrozenBitset((i, )): c for i, c in x.items()}) # if the base ring is different, attempt to coerce it into R return self.element_class(self, {FrozenBitset((i, )): R(c) for i, c in x.items() if R(c) != R.zero()}) +======= + return self.element_class(self, {FrozenBitset((i,)): c for i,c in x.items()}) + # if the base ring is different, attempt to coerce it into R + return self.element_class(self, {FrozenBitset((i,)): R(c) for i,c in x.items() if R(c) != R.zero()}) +>>>>>>> a7cd8bf99e (Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset)) if (isinstance(x, CliffordAlgebraElement) and self.has_coerce_map_from(x.parent())): @@ -898,10 +904,55 @@ def _element_constructor_(self, x): R = self.base_ring() return self.element_class(self, {FrozenBitset((i,)): R.one() for i in x}) +<<<<<<< HEAD try: return super(CliffordAlgebra, self)._element_constructor_(x) except TypeError: raise TypeError(f'do not know how to make {x=} an element of self') +======= + if isinstance(x, tuple): + R = self.base_ring() + return self.element_class(self, {FrozenBitset((i,)): R.one() for i in x}) + + return super(CliffordAlgebra, self)._element_constructor_(x) +>>>>>>> a7cd8bf99e (Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset)) + + def _basis_index_function(self, x): + """ + Given an integer indexing the basis, return the correct + bitset. + + For backwards compatibility, tuples are also accepted. + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl = CliffordAlgebra(Q) + sage: Cl._basis_index_function(7) + 111 + sage: Cl._basis_index_function(5) + 101 + sage: Cl._basis_index_function(4) + 001 + + sage: Cl._basis_index_function((0, 1, 2)) + 111 + sage: Cl._basis_index_function((0, 2)) + 101 + sage: Cl._basis_index_function((2,)) + 001 + """ + Q = self._quadratic_form + format_style = f"0{Q.dim()}b" + + # if the input is a tuple, assume that it has + # entries in {0, ..., 2**Q.dim()-1} + if isinstance(x, tuple): + return FrozenBitset(x, capacity = Q.dim()) + + # slice the output of format in order to make conventions + # of format and FrozenBitset agree. + return FrozenBitset(format(x, format_style)[::-1], capacity=Q.dim()) def gen(self, i): """ @@ -918,7 +969,11 @@ def gen(self, i): sage: [Cl.gen(i) for i in range(3)] [x, y, z] """ +<<<<<<< HEAD return self._from_dict({FrozenBitset((i, )): self.base_ring().one()}, remove_zeros=False) +======= + return self._from_dict({FrozenBitset((i,)): self.base_ring().one()}, remove_zeros=False) +>>>>>>> a7cd8bf99e (Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset)) def algebra_generators(self): """ @@ -1247,8 +1302,14 @@ def lift_module_morphism(self, m, names=None): Cl = CliffordAlgebra(Q, names) n = self._quadratic_form.dim() +<<<<<<< HEAD f = lambda x: self.prod(self._from_dict({FrozenBitset((j, )): m[j, i] for j in range(n)}, remove_zeros=True) for i in x) +======= + f = lambda x: self.prod(self._from_dict( {FrozenBitset((j,)): m[j,i] for j in range(n)}, + remove_zeros=True ) + for i in x) +>>>>>>> a7cd8bf99e (Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset)) cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional() return Cl.module_morphism(on_basis=f, codomain=self, category=cat) From 74d731f2c50e632789d372344e758e35042cda53 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 23 Jun 2022 15:39:06 -0500 Subject: [PATCH 152/591] Add index class and first draft of exterior __mul__ --- src/sage/algebras/clifford_algebra.py | 86 +-------------------------- 1 file changed, 2 insertions(+), 84 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 6aa6b541724..612237c6e85 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -324,65 +324,6 @@ def conjugate(self): clifford_conjugate = conjugate - # TODO: This is a general function which should be moved to a - # superalgebras category when one is implemented. - def supercommutator(self, x): - r""" - Return the supercommutator of ``self`` and ``x``. - - Let `A` be a superalgebra. The *supercommutator* of homogeneous - elements `x, y \in A` is defined by - - .. MATH:: - - [x, y\} = x y - (-1)^{|x| |y|} y x - - and extended to all elements by linearity. - - EXAMPLES:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: a = x*y - z - sage: b = x - y + y*z - sage: a.supercommutator(b) - -5*x*y + 8*x*z - 2*y*z - 6*x + 12*y - 5*z - sage: a.supercommutator(Cl.one()) - 0 - sage: Cl.one().supercommutator(a) - 0 - sage: Cl.zero().supercommutator(a) - 0 - sage: a.supercommutator(Cl.zero()) - 0 - - sage: Q = QuadraticForm(ZZ, 2, [-1,1,-3]) - sage: Cl. = CliffordAlgebra(Q) - sage: [a.supercommutator(b) for a in Cl.basis() for b in Cl.basis()] - [0, 0, 0, 0, 0, -2, 1, -x - 2*y, 0, 1, - -6, 6*x + y, 0, x + 2*y, -6*x - y, 0] - sage: [a*b-b*a for a in Cl.basis() for b in Cl.basis()] - [0, 0, 0, 0, 0, 0, 2*x*y - 1, -x - 2*y, 0, - -2*x*y + 1, 0, 6*x + y, 0, x + 2*y, -6*x - y, 0] - - Exterior algebras inherit from Clifford algebras, so - supercommutators work as well. We verify the exterior algebra - is supercommutative:: - - sage: E. = ExteriorAlgebra(QQ) - sage: all(b1.supercommutator(b2) == 0 - ....: for b1 in E.basis() for b2 in E.basis()) - True - """ - P = self.parent() - ret = P.zero() - for ms, cs in self: - for mx, cx in x: - ret += P.term(ms, cs) * P.term(mx, cx) - s = (-1)**(P.degree_on_basis(ms) * P.degree_on_basis(mx)) - ret -= s * P.term(mx, cx) * P.term(ms, cs) - return ret - class CliffordAlgebraIndices(Parent): r""" @@ -400,7 +341,6 @@ def __call__(self, el): sage: E = ExteriorAlgebra(QQ, 7) sage: B = E.basis() """ - if not isinstance(el, Element): return self._element_constructor_(el) else: @@ -885,15 +825,9 @@ def _element_constructor_(self, x): if x in self.free_module(): R = self.base_ring() if x.parent().base_ring() is R: -<<<<<<< HEAD return self.element_class(self, {FrozenBitset((i, )): c for i, c in x.items()}) # if the base ring is different, attempt to coerce it into R return self.element_class(self, {FrozenBitset((i, )): R(c) for i, c in x.items() if R(c) != R.zero()}) -======= - return self.element_class(self, {FrozenBitset((i,)): c for i,c in x.items()}) - # if the base ring is different, attempt to coerce it into R - return self.element_class(self, {FrozenBitset((i,)): R(c) for i,c in x.items() if R(c) != R.zero()}) ->>>>>>> a7cd8bf99e (Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset)) if (isinstance(x, CliffordAlgebraElement) and self.has_coerce_map_from(x.parent())): @@ -904,18 +838,10 @@ def _element_constructor_(self, x): R = self.base_ring() return self.element_class(self, {FrozenBitset((i,)): R.one() for i in x}) -<<<<<<< HEAD try: return super(CliffordAlgebra, self)._element_constructor_(x) except TypeError: raise TypeError(f'do not know how to make {x=} an element of self') -======= - if isinstance(x, tuple): - R = self.base_ring() - return self.element_class(self, {FrozenBitset((i,)): R.one() for i in x}) - - return super(CliffordAlgebra, self)._element_constructor_(x) ->>>>>>> a7cd8bf99e (Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset)) def _basis_index_function(self, x): """ @@ -969,11 +895,7 @@ def gen(self, i): sage: [Cl.gen(i) for i in range(3)] [x, y, z] """ -<<<<<<< HEAD return self._from_dict({FrozenBitset((i, )): self.base_ring().one()}, remove_zeros=False) -======= - return self._from_dict({FrozenBitset((i,)): self.base_ring().one()}, remove_zeros=False) ->>>>>>> a7cd8bf99e (Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset)) def algebra_generators(self): """ @@ -1302,14 +1224,8 @@ def lift_module_morphism(self, m, names=None): Cl = CliffordAlgebra(Q, names) n = self._quadratic_form.dim() -<<<<<<< HEAD f = lambda x: self.prod(self._from_dict({FrozenBitset((j, )): m[j, i] for j in range(n)}, remove_zeros=True) for i in x) -======= - f = lambda x: self.prod(self._from_dict( {FrozenBitset((j,)): m[j,i] for j in range(n)}, - remove_zeros=True ) - for i in x) ->>>>>>> a7cd8bf99e (Add _basis_index_function as a method, fix some doctests, and fix some type issues (tuple -> FrozenBitset)) cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional() return Cl.module_morphism(on_basis=f, codomain=self, category=cat) @@ -1394,6 +1310,7 @@ def lift_isometry(self, m, names=None): Cl = CliffordAlgebra(Q, names) n = Q.dim() + f = lambda x: Cl.prod(Cl._from_dict({FrozenBitset((j, )): m[j, i] for j in range(n)}, remove_zeros=True) for i in x) cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional() @@ -2252,6 +2169,7 @@ def _mul_(self, other): d = {} n = P.ngens() +<<<<<<< HEAD for ml, cl in self: # ml for "monomial on the left" for mr, cr in other: # mr for "monomial on the right" if ml.intersection(mr): From 4be416f78c285a86972e160d5bbb0958e805bb08 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 5 Jul 2022 13:26:10 -0700 Subject: [PATCH 153/591] Add doctest --- src/sage/algebras/clifford_algebra.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 612237c6e85..49e6b8ccc97 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2169,7 +2169,6 @@ def _mul_(self, other): d = {} n = P.ngens() -<<<<<<< HEAD for ml, cl in self: # ml for "monomial on the left" for mr, cr in other: # mr for "monomial on the right" if ml.intersection(mr): @@ -2186,8 +2185,9 @@ def _mul_(self, other): num_cross = 0 # keep track of the number of signs tot_cross = 0 for i in ml: + num_cross_new = 0 while i > j: - num_cross += 1 + num_cross_new += 1 try: j = next(it) except StopIteration: From 65984c5d2253024d6a5566ab4ce90194332f4299 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 9 Jul 2022 07:23:25 -0500 Subject: [PATCH 154/591] Initial commit of f4 --- src/sage/algebras/clifford_algebra.py | 113 ++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 49e6b8ccc97..df96ebfa4fb 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2126,6 +2126,119 @@ def lifted_form(x, y): codomain=self.base_ring(), name="Bilinear Form") + def exterior_bitset_f4(self, I): + r""" + Return a Groebner basis for an ideal `I` of the exterior algebra. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: rels = [c*d*e - b*d*e + b*c*e - b*c*d, + ....: c*d*e - a*d*e + a*c*e - a*c*d, + ....: b*d*e - a*d*e + a*b*e - a*b*d, + ....: b*c*e - a*c*e + a*b*e - a*b*c, + ....: b*c*d - a*c*d + a*b*d - a*b*c] + sage: I = E.ideal(rels); + sage: exterior_bitset_f4(I) + (b*c*d-b*c*e+b*d*e-c*d*e, + a*c*d-a*c*e+a*d*e-c*d*e, + a*b*d-a*b*e+a*d*e-b*d*e, + a*b*c-a*b*e+a*c*e-b*c*e) + + The example above was computed first using M2: + + E = QQ[a..e, SkewCommutative => true] + I = ideal( c*d*e - b*d*e + b*c*e - b*c*d, + c*d*e - a*d*e + a*c*e - a*c*d, + b*d*e - a*d*e + a*b*e - a*b*d, + b*c*e - a*c*e + a*b*e - a*b*c, + b*c*d - a*c*d + a*b*d - a*b*c) + groebnerBasis(I) + + returns: + o3 = | bcd-bce+bde-cde acd-ace+ade-cde abd-abe+ade-bde abc-abe+ace-bce | + """ + + # following https://pi.math.cornell.edu/~djp282/documents/math6140-2017a.pdf + + def get_pairs(pairs): + # this implements the `select` function of Peifer + + # change pairs in here so I don't have to do it after calling get_pairs. + return pairs.pop() # temporarily do Buchbergers + + def f4_sel(P): + # this is the function on page 13 of the original F4 paper. + + return P + + # P is a list of pairs + # TODO: implement the better choice. + + def symbolic_preprocessing(P, G): + # the first/second terms of the S polynomial might + # have to be adjusted a la Stokes' paper + left = set() # the first term of the S polynomial + right = set() # the second term of the S polynomial + L = left.union(right) + done = set(f.monomials()[0] for f in L) + + from itertools import chain + mon_L = set(chain.from_iterable(f.monomials() for f in L)) + + while done != mon_L: + m = sorted(mon_L.difference(done), key = lambda x: (-len(x.support_of_term()), tuple(x.support_of_term())))[0] + done = done.add(m) + for g in G: + if divides(g.monomials()[0], m): + L.add(m * g/g.monomials()[0]) + break + return L + + def f4_reduce(P, G): + # given a current set of pairs P and a + # current basis G, return G' of new basis + + L = symbolic_preprocessing(P, G) + lm_L = set(f.monomials()[0] for f in L) + + d = dict() + for i, f in enumerate(F): + d.update(((i,hash(m)),c) for m,c in f._monomial_coefficients.items()) + M = MatrixSpace(E.base_ring(), len(L), 2^self.ngens(), sparse=True) + poly_matrix = M(d).rref() + + Lprime = set(E._from_dict(dict((FrozenBitset(format(k,'b')[::-1]),v) for k,v in row.dict().items())) for row in poly_matrix) + + Gprime = set() + + for f in Lprime: + if f.monomials()[0] in lm_L: + continue + Gprime.add(f) + + return Gprime + + F = I.gens() + G = set(F) + k = I.ngens() + + from itertools import combinations + pairs = set(combinations(range(k), 2)) # this is Peifer's P + + while pairs: + P = f4_sel(pairs) # this is different from Buchbergers which would be pairs.pop() + Gtemp = f4_reduce(P, G) + pairs.difference_update(P) + + for h in Gtemp: + G.add(h) + k += 1 + pairs.update((i,k) for i in range(k)) + + return G + + class Element(CliffordAlgebraElement): """ An element of an exterior algebra. From 7a79608e8b39fd52dc0dee2f563d03f6c06dd43f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 12 Jul 2022 18:37:53 +0900 Subject: [PATCH 155/591] Another implementation of Groebner bases for the exterior algebra. --- src/sage/algebras/clifford_algebra.py | 87 +++++++ src/sage/algebras/exterior_algebra_cython.pxd | 20 ++ src/sage/algebras/exterior_algebra_cython.pyx | 245 ++++++++++++++++++ 3 files changed, 352 insertions(+) create mode 100644 src/sage/algebras/exterior_algebra_cython.pxd create mode 100644 src/sage/algebras/exterior_algebra_cython.pyx diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index df96ebfa4fb..7a72cd010c4 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -30,6 +30,7 @@ from sage.modules.with_basis.morphism import ModuleMorphismByLinearity from sage.categories.poor_man_map import PoorManMap from sage.rings.integer_ring import ZZ +from sage.rings.noncommutative_ideals import Ideal_nc from sage.modules.free_module import FreeModule, FreeModule_generic from sage.matrix.constructor import Matrix from sage.matrix.args import MatrixArgs @@ -2238,6 +2239,16 @@ def f4_reduce(P, G): return G + def _ideal_class_(self, n=0): + """ + Return the class that is used to implement ideals of ``self``. + + TESTS:: + + sage: E. = ExteriorAlgebra(QQ) + sage: E._ideal_class_() + """ + return ExteriorAlgebraIdeal class Element(CliffordAlgebraElement): """ @@ -2315,6 +2326,41 @@ def _mul_(self, other): return self.__class__(P, d) + def reduce(self, I, left=True): + r""" + Reduce ``self`` with respect to the elements in ``I``. + + INPUT: + + - ``I`` -- a list of exterior algebra elements or an ideal + - ``side`` -- the side, ignored if ``I`` is an ideal + """ + if isinstance(I, ExteriorAlgebraIdeal): + I = I.groebner_basis() + left = (I.side() == "left") + + E = self.parent() + f = self + from sage.algebras.exterior_algebra_cython import leading_support + for g in I: + lm = leading_support(g) + reduction = True + while reduction: + supp = f.support() + reduction = False + for s in supp: + if lm <= s: + reduction = True + mon = E.monomial(s - lm) + if left: + gp = mon * g + f = f - f[s] / gp[s] * gp + else: + gp = g * mon + f = f - f[s] / gp[s] * gp + break + return f + def interior_product(self, x): r""" Return the interior product (also known as antiderivation) of @@ -3154,3 +3200,44 @@ def chain_complex(self, R=None): basis = next_basis return ChainComplex(data, degree=1) + +class ExteriorAlgebraIdeal(Ideal_nc): + """ + An ideal of the exterior algebra. + """ + def reduce(self, f): + """ + Reduce ``f`` modulo ``self``. + """ + return f.reduce(self.groebner_basis()) + + @cached_method + def groebner_basis(self): + r""" + Return the reduced Gröbner basis of ``self``. + + EXAMPLES: + + We compute an example that was checked against Macaulay2:: + + sage: E. = ExteriorAlgebra(QQ) + sage: rels = [c*d*e - b*d*e + b*c*e - b*c*d, + ....: c*d*e - a*d*e + a*c*e - a*c*d, + ....: b*d*e - a*d*e + a*b*e - a*b*d, + ....: b*c*e - a*c*e + a*b*e - a*b*c, + ....: b*c*d - a*c*d + a*b*d - a*b*c] + sage: I = E.ideal(rels) + sage: I.groebner_basis() + (-b*c*d + b*c*e - b*d*e + c*d*e, + -a*c*d + a*c*e - a*d*e + c*d*e, + -a*b*d + a*b*e - a*d*e + b*d*e, + -a*b*c + a*b*e - a*c*e + b*c*e) + """ + from sage.algebras.exterior_algebra_cython import compute_groebner + side = 2 + if self.side() == "left": + side = 0 + elif self.side() == "right": + side = 1 + return compute_groebner(self, side) + diff --git a/src/sage/algebras/exterior_algebra_cython.pxd b/src/sage/algebras/exterior_algebra_cython.pxd new file mode 100644 index 00000000000..66c33994f23 --- /dev/null +++ b/src/sage/algebras/exterior_algebra_cython.pxd @@ -0,0 +1,20 @@ +""" +Exterior algebras backend +""" + +from sage.data_structures.bitset cimport FrozenBitset +from sage.rings.integer cimport Integer + +cdef inline Integer bitset_to_int(FrozenBitset X) +cdef inline FrozenBitset int_to_bitset(Integer n) +cdef inline unsigned long degree(FrozenBitset X) +cdef inline FrozenBitset leading_supp(f) +cpdef tuple get_leading_supports(tuple I) + +# Grobner basis functions +cdef inline build_monomial(supp, E) +cdef inline partial_S_poly(f, g, E, int side) +cdef inline set preprocessing(list P, list G, E, int side) +cdef inline list reduction(list P, list G, E, int side) +#cpdef tuple compute_groebner(tuple I, int side) + diff --git a/src/sage/algebras/exterior_algebra_cython.pyx b/src/sage/algebras/exterior_algebra_cython.pyx new file mode 100644 index 00000000000..e3c4dc64888 --- /dev/null +++ b/src/sage/algebras/exterior_algebra_cython.pyx @@ -0,0 +1,245 @@ +""" +Exterior algebras backend + +This contains the backend implementations in Cython for the exterior algebra. +""" + +from sage.libs.gmp.mpz cimport mpz_sizeinbase, mpz_setbit, mpz_tstbit, mpz_cmp_si, mpz_sgn +from sage.data_structures.bitset_base cimport bitset_t, bitset_init, bitset_first, bitset_next, bitset_set_to +from sage.structure.parent cimport Parent + +cdef inline Integer bitset_to_int(FrozenBitset X): + """ + Convert ``X`` to an :class:`Integer`. + """ + cdef Integer ret = Integer(0) + cdef long elt = bitset_first(X._bitset) + while elt >= 0: + mpz_setbit(ret.value, elt) + elt = bitset_next(X._bitset, elt + 1) + return ret + +cdef inline FrozenBitset int_to_bitset(Integer n): + """ + Convert a nonnegative integer ``n`` to a :class:`FrozenBitset`. + """ + cdef unsigned long i + + if mpz_sgn(n.value) == 0: + return FrozenBitset() + + cdef FrozenBitset ret = FrozenBitset() + cdef size_t s = mpz_sizeinbase(n.value, 2) + bitset_init(ret._bitset, s) + for i in range(s): + bitset_set_to(ret._bitset, i, mpz_tstbit(n.value, i)) + return ret + + +cdef inline unsigned long degree(FrozenBitset X): + """ + Compute the degree of ``X``. + """ + cdef unsigned long ret = 0 + cdef long elt = bitset_first(X._bitset) + while elt >= 0: + ret += 1 + elt = bitset_next(X._bitset, elt + 1) + return ret + + +#TODO: Bring the exterior algebra elements as a cdef class and make f know its type! +cdef inline FrozenBitset leading_supp(f): + """ + Return the leading support of the exterior algebra element ``f``. + """ + cdef dict mc = f._monomial_coefficients + return int_to_bitset(min(bitset_to_int(k) for k in mc)) + +def leading_support(f): + return leading_supp(f) + +cpdef tuple get_leading_supports(tuple I): + """ + Return the leading supports of the elements in ``I``. + + Used for testing mostly + + INPUT: + + - ``I`` -- a tuple of elements of an exterior algebra + """ + # We filter out any elements that are 0 + return tuple(set([leading_supp(f) for f in I if f._monomial_coefficients])) + + +cdef inline build_monomial(E, supp): + """ + Helper function for the fastest way to build a monomial. + """ + return E.element_class(E, {supp: ( E)._base.one()}) + +cdef inline partial_S_poly(f, g, E, int side): + """ + Compute one half of the `S`-polynomial for ``f`` and ``g``. + + This computes: + + .. MATH:: + + LCM(LM(f), LM(g)) / LT(f) \cdot f. + """ + cdef FrozenBitset lmf = leading_supp(f) + cdef FrozenBitset lmg = leading_supp(g) + cdef FrozenBitset D = lmg.difference(lmf) + if side == 0: + ret = build_monomial(E, D) * f + return (~ret[lmf._union(lmg)]) * ret + ret = f * build_monomial(E, D) + return ret * (~ret[lmf._union(lmg)]) + +cdef inline set preprocessing(list P, list G, E, int side): + """ + Perform the preprocessing step. + """ + #print("Start preprocessing:", P) + cdef set L = set(partial_S_poly(f0, f1, E, side) for f0,f1 in P) + L.update(partial_S_poly(f1, f0, E, side) for f0,f1 in P) + if side == 2: + # in partial_S_poly, side == 2 gets treated like right (== 1) + L.update(partial_S_poly(f0, f1, E, 0) for f0,f1 in P) + L.update(partial_S_poly(f1, f0, E, 0) for f0,f1 in P) + + cdef set done = set(leading_supp(f) for f in L) + cdef set monL = set() + for f in L: + monL.update(f.support()) + monL.difference_update(done) + + while monL: + m = int_to_bitset(max(bitset_to_int(k) for k in monL)) + done.add(m) + monL.remove(m) + for g in G: + lm = leading_supp(g) + if lm <= m: + f = build_monomial(E, m.difference(lm)) * g + if f in L: + break + monL.update(set(f.support()) - done) + L.add(f) + break + #print("preprocessing:", L) + return L + +cdef inline list reduction(list P, list G, E, int side): + """ + Perform the reduction of ``P`` mod ``G`` in ``E``. + """ + cdef set L = preprocessing(P, G, E, side) + cdef Py_ssize_t i + from sage.matrix.constructor import matrix + M = matrix({(i, bitset_to_int( m)): c for i,f in enumerate(L) for m,c in f._monomial_coefficients.items()}, + sparse=True) + M.echelonize() # Do this in place + lead_supports = set(leading_supp(f) for f in L) + return [E.element_class(E, {int_to_bitset(Integer(j)): c for j,c in M[i].iteritems()}) + for i,p in enumerate(M.pivots()) + if int_to_bitset(Integer(p)) not in lead_supports] + +def compute_groebner(I, side): + """ + Compute the reduced ``side`` Gröbner basis for the ideal ``I``. + + INPUT: + + - ``I`` -- the ideal + - ``side`` -- integer; the side of the ideal: ``0`` for left, ``1`` for + right, and ``2`` for two-sided + """ + E = I.ring() + cdef FrozenBitset p0, p1 + cdef unsigned long deg + cdef Py_ssize_t i, j, k + + cdef list G = [f for f in I.gens() if f] # Remove 0s TODO: We should make this unnecessary here + cdef Py_ssize_t n = len(G) + cdef dict P = {} + cdef list Gp + + # for ideals generated by homogeneous (wrt Z_2-grading) polynomials, we can just consider it as a left ideal + # TODO: We can reduce the number of S-poly computations for Z_2-graded homogeneous + # ideals by throwing out those such that LCM(LM(f), LM(g)) == LM(f) * LM(g). + if all(f.is_super_homogeneous() for f in G): + side = 0 + + for i in range(n): + f0 = G[i] + p0 = leading_supp(f0) + for j in range(i+1, n): + f1 = G[j] + p1 = leading_supp(f1) + deg = degree( (p0._union(p1))) + if deg in P: + P[deg].append((f0, f1)) + else: + P[deg] = [(f0, f1)] + + while P: + #print("Cur G:", G) + Pp = P.pop(min(P)) # The selection: lowest lcm degree + Gp = reduction(Pp, G, E, side) + #print("Reduction yielded:", Gp) + G.extend(Gp) + for j in range(n, len(G)): + f1 = G[j] + p1 = leading_supp(f1) + for i in range(j): + f0 = G[i] + p0 = leading_supp(f0) + deg = degree( (p0._union(p1))) + if deg in P: + P[deg].append((f0, f1)) + else: + P[deg] = [(f0, f1)] + n = len(G) + + #print(G) + + # Now that we have a Gröbner basis, we make this into a reduced Gröbner basis + cdef set pairs = set((i, j) for i in range(n) for j in range(n) if i != j) + cdef list supp + cdef bint did_reduction + cdef FrozenBitset lm, s + while pairs: + i,j = pairs.pop() + # We perform the classical reduction algorithm here on each pair + # TODO: Make this faster by using the previous technique + f = G[i] + g = G[j] + lm = leading_supp(g) + did_reduction = True + while did_reduction: + supp = f.support() + did_reduction = False + for s in supp: + if lm <= s: + did_reduction = True + mon = E.monomial(s - lm) + if side == 0: + gp = mon * g + f = f - f[s] / gp[s] * gp + else: + gp = g * mon + f = f - f[s] / gp[s] * gp + break + if G[i] != f: + G[i] = f + #print("reduction:", G) + if not f: + pairs.difference_update((k, i) for k in range(n)) + else: + pairs.update((k, i) for k in range(n) if k != i) + + return tuple([f for f in G if f]) + From c8a3766ef1e6b5d1eebcbd052772b2b61aca013e Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 12 Jul 2022 19:01:16 +0900 Subject: [PATCH 156/591] Fixing some little details. --- src/sage/algebras/clifford_algebra.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 7a72cd010c4..caed257405c 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2336,8 +2336,8 @@ def reduce(self, I, left=True): - ``side`` -- the side, ignored if ``I`` is an ideal """ if isinstance(I, ExteriorAlgebraIdeal): - I = I.groebner_basis() left = (I.side() == "left") + I = I.groebner_basis() E = self.parent() f = self @@ -3209,7 +3209,7 @@ def reduce(self, f): """ Reduce ``f`` modulo ``self``. """ - return f.reduce(self.groebner_basis()) + return f.reduce(self) @cached_method def groebner_basis(self): From b62d5782d78a613b7b0664a895c00fb80298f14a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 13 Jul 2022 14:56:23 +0900 Subject: [PATCH 157/591] Cythonizing the element classes. --- src/sage/algebras/clifford_algebra.py | 301 +----------------- src/sage/algebras/exterior_algebra_cython.pxd | 17 +- 2 files changed, 22 insertions(+), 296 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index caed257405c..91d4efc10e7 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -22,8 +22,8 @@ from sage.structure.parent import Parent from sage.structure.element import Element from sage.data_structures.bitset import Bitset, FrozenBitset -from copy import copy +from sage.algebras.clifford_algebra_element import CliffordAlgebraElement, ExteriorAlgebraElement from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -38,294 +38,12 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.subset import Subsets from sage.quadratic_forms.quadratic_form import QuadraticForm -from sage.algebras.weyl_algebra import repr_from_monomials from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.typeset.ascii_art import ascii_art from sage.typeset.unicode_art import unicode_art import unicodedata -class CliffordAlgebraElement(CombinatorialFreeModule.Element): - """ - An element in a Clifford algebra. - - TESTS:: - - sage: Q = QuadraticForm(ZZ, 3, [1, 2, 3, 4, 5, 6]) - sage: Cl. = CliffordAlgebra(Q) - sage: elt = ((x^3-z)*x + y)^2 - sage: TestSuite(elt).run() - """ - def _repr_(self): - """ - Return a string representation of ``self``. - - TESTS:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: ((x^3-z)*x + y)^2 - -2*x*y*z - x*z + 5*x - 4*y + 2*z + 2 - sage: Cl.zero() - 0 - """ - return repr_from_monomials(self.list(), self.parent()._repr_term) - - def _latex_(self): - r""" - Return a `\LaTeX` representation of ``self``. - - TESTS:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: latex( ((x^3-z)*x + y)^2 ) - -2 x y z - x z + 5 x - 4 y + 2 z + 2 - sage: Cl. = CliffordAlgebra(Q) - sage: latex( (x1 - x2)*x0 + 5*x0*x1*x2 ) - 5 x_{0} x_{1} x_{2} - x_{0} x_{1} + x_{0} x_{2} - 1 - """ - return repr_from_monomials(self.list(), - self.parent()._latex_term, - True) - - def _mul_(self, other): - """ - Return ``self`` multiplied by ``other``. - - INPUT: - - - ``other`` -- element of the same Clifford algebra as ``self`` - - EXAMPLES:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: (x^3 - z*y)*x*(y*z + x*y*z) - x*y*z + y*z - 24*x + 12*y + 2*z - 24 - sage: y*x - -x*y + 2 - sage: z*x - -x*z + 3 - sage: z*z - 6 - sage: x*0 - 0 - sage: 0*x - 0 - """ - Q = self.parent()._quadratic_form - zero = self.parent().base_ring().zero() - d = {} - - for ml, cl in self: - # Distribute the current term ``cl`` * ``ml`` over ``other``. - cur = copy(other._monomial_coefficients) # The current distribution of the term - for i in reversed(ml): - # Distribute the current factor ``e[i]`` (the ``i``-th - # element of the standard basis). - next = {} - # At the end of the following for-loop, ``next`` will be - # the dictionary describing the element - # ``e[i]`` * (the element described by the dictionary ``cur``) - # (where ``e[i]`` is the ``i``-th standard basis vector). - for mr, cr in cur.items(): - - # Commute the factor as necessary until we are in order - for j in mr: - if i <= j: - break - # Add the additional term from the commutation - # get a non-frozen bitset to manipulate - t = Bitset(mr) # a mutable copy - t.discard(j) - t = FrozenBitset(t) - next[t] = next.get(t, zero) + cr * Q[i, j] - # Note: ``Q[i,j] == Q(e[i]+e[j]) - Q(e[i]) - Q(e[j])`` for - # ``i != j``, where ``e[k]`` is the ``k``-th standard - # basis vector. - cr = -cr - if next[t] == zero: - del next[t] - - # Check to see if we have a squared term or not - mr = Bitset(mr) # temporarily mutable - if i in mr: - mr.discard(i) - cr *= Q[i, i] - # Note: ``Q[i,i] == Q(e[i])`` where ``e[i]`` is the - # ``i``-th standard basis vector. - else: - # mr is implicitly sorted - mr.add(i) - mr = FrozenBitset(mr) # refreeze it - next[mr] = next.get(mr, zero) + cr - if next[mr] == zero: - del next[mr] - cur = next - - # Add the distributed terms to the total - for index, coeff in cur.items(): - d[index] = d.get(index, zero) + cl * coeff - if d[index] == zero: - del d[index] - - return self.__class__(self.parent(), d) - - def list(self): - """ - Return the list of monomials and their coefficients in ``self`` - (as a list of `2`-tuples, each of which has the form - ``(monomial, coefficient)``). - - EXAMPLES:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: elt = 5*x + y - sage: elt.list() - [(1, 5), (01, 1)] - """ - return sorted(self._monomial_coefficients.items(), key=lambda m: (-len(m[0]), list(m[0]))) - - def support(self): - """ - Return the support of ``self``. - - This is the list of all monomials which appear with nonzero - coefficient in ``self``. - - EXAMPLES:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: elt = 5*x + y - sage: elt.support() - [1, 01] - """ - return sorted(self._monomial_coefficients.keys(), key=lambda x: (-len(x), list(x))) - - def reflection(self): - r""" - Return the image of the reflection automorphism on ``self``. - - The *reflection automorphism* of a Clifford algebra is defined - as the linear endomorphism of this algebra which maps - - .. MATH:: - - x_1 \wedge x_2 \wedge \cdots \wedge x_m \mapsto - (-1)^m x_1 \wedge x_2 \wedge \cdots \wedge x_m. - - It is an algebra automorphism of the Clifford algebra. - - :meth:`degree_negation` is an alias for :meth:`reflection`. - - EXAMPLES:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: elt = 5*x + y + x*z - sage: r = elt.reflection(); r - x*z - 5*x - y - sage: r.reflection() == elt - True - - TESTS: - - We check that the reflection is an involution:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: all(x.reflection().reflection() == x for x in Cl.basis()) - True - """ - return self.__class__(self.parent(), {m: (-1)**len(m) * c for m, c in self}) - - degree_negation = reflection - - def transpose(self): - r""" - Return the transpose of ``self``. - - The transpose is an anti-algebra involution of a Clifford algebra - and is defined (using linearity) by - - .. MATH:: - - x_1 \wedge x_2 \wedge \cdots \wedge x_m \mapsto - x_m \wedge \cdots \wedge x_2 \wedge x_1. - - EXAMPLES:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: elt = 5*x + y + x*z - sage: t = elt.transpose(); t - -x*z + 5*x + y + 3 - sage: t.transpose() == elt - True - sage: Cl.one().transpose() - 1 - - TESTS: - - We check that the transpose is an involution:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: all(x.transpose().transpose() == x for x in Cl.basis()) - True - - Zero is sent to zero:: - - sage: Cl.zero().transpose() == Cl.zero() - True - """ - P = self.parent() - if not self._monomial_coefficients: - return P.zero() - g = P.gens() - return P.sum(c * P.prod(g[i] for i in reversed(m)) for m, c in self) - - def conjugate(self): - r""" - Return the Clifford conjugate of ``self``. - - The Clifford conjugate of an element `x` of a Clifford algebra is - defined as - - .. MATH:: - - \bar{x} := \alpha(x^t) = \alpha(x)^t - - where `\alpha` denotes the :meth:`reflection ` - automorphism and `t` the :meth:`transposition `. - - EXAMPLES:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: elt = 5*x + y + x*z - sage: c = elt.conjugate(); c - -x*z - 5*x - y + 3 - sage: c.conjugate() == elt - True - - TESTS: - - We check that the conjugate is an involution:: - - sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) - sage: Cl. = CliffordAlgebra(Q) - sage: all(x.conjugate().conjugate() == x for x in Cl.basis()) - True - """ - return self.reflection().transpose() - - clifford_conjugate = conjugate - - class CliffordAlgebraIndices(Parent): r""" A facade parent for the indices of Clifford algebra. @@ -367,7 +85,7 @@ def __init__(self, Qdim): self._nbits = Qdim self._cardinality = 2**Qdim # the if statement here is in case Qdim is 0. - self._maximal_set = FrozenBitset('1'*self._nbits) if self._nbits else FrozenBitset('0') + self._maximal_set = FrozenBitset('1'*self._nbits) if self._nbits else FrozenBitset() category = FiniteEnumeratedSets().Facade() Parent.__init__(self, category=category, facade=True) @@ -446,7 +164,7 @@ def __iter__(self): """ import itertools n = self._nbits - yield FrozenBitset('0') + yield FrozenBitset() k = 1 while k <= n: for C in itertools.combinations(range(n), k): @@ -953,7 +671,7 @@ def one_basis(self): sage: Cl.one_basis() 0 """ - return FrozenBitset('0') + return FrozenBitset() def is_commutative(self): """ @@ -1908,7 +1626,11 @@ def coproduct_on_basis(self, a): one = self.base_ring().one() L = unshuffle_iterator(tuple(a), one) return self.tensor_square()._from_dict( +<<<<<<< HEAD {tuple(FrozenBitset(e) if e else FrozenBitset('0') for e in t): c for t, c in L if c}, +======= + {tuple(FrozenBitset(e) if e else FrozenBitset() for e in t): c for t,c in L if c}, +>>>>>>> b0f66e328e (Cythonizing the element classes.) coerce=False, remove_zeros=False) @@ -2247,9 +1969,11 @@ def _ideal_class_(self, n=0): sage: E. = ExteriorAlgebra(QQ) sage: E._ideal_class_() + """ return ExteriorAlgebraIdeal +<<<<<<< HEAD class Element(CliffordAlgebraElement): """ An element of an exterior algebra. @@ -2534,6 +2258,9 @@ def scalar(self, other): -2*x*y + 5*x*z + y*z """ return (self.transpose() * other).constant_coefficient() +======= + Element = ExteriorAlgebraElement +>>>>>>> b0f66e328e (Cythonizing the element classes.) ##################################################################### # Differentials @@ -2798,7 +2525,7 @@ def _on_basis(self, m): sage: E. = ExteriorAlgebra(QQ) sage: par = E.boundary({(0,1): z, (1,2): x, (2,0): y}) - sage: par._on_basis(FrozenBitset('0')) + sage: par._on_basis(FrozenBitset()) 0 sage: par._on_basis((0,)) 0 diff --git a/src/sage/algebras/exterior_algebra_cython.pxd b/src/sage/algebras/exterior_algebra_cython.pxd index 66c33994f23..022197c2911 100644 --- a/src/sage/algebras/exterior_algebra_cython.pxd +++ b/src/sage/algebras/exterior_algebra_cython.pxd @@ -5,16 +5,15 @@ Exterior algebras backend from sage.data_structures.bitset cimport FrozenBitset from sage.rings.integer cimport Integer -cdef inline Integer bitset_to_int(FrozenBitset X) -cdef inline FrozenBitset int_to_bitset(Integer n) -cdef inline unsigned long degree(FrozenBitset X) -cdef inline FrozenBitset leading_supp(f) +cdef Integer bitset_to_int(FrozenBitset X) +cdef FrozenBitset int_to_bitset(Integer n) +cdef unsigned long degree(FrozenBitset X) +cdef FrozenBitset leading_supp(f) cpdef tuple get_leading_supports(tuple I) # Grobner basis functions -cdef inline build_monomial(supp, E) -cdef inline partial_S_poly(f, g, E, int side) -cdef inline set preprocessing(list P, list G, E, int side) -cdef inline list reduction(list P, list G, E, int side) -#cpdef tuple compute_groebner(tuple I, int side) +cdef build_monomial(supp, E) +cdef partial_S_poly(f, g, E, int side) +cdef set preprocessing(list P, list G, E, int side) +cdef list reduction(list P, list G, E, int side) From d91a556f756dc7248382478ec27c5bd3986b9ba4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 13 Jul 2022 16:09:10 +0900 Subject: [PATCH 158/591] Adding more type declarations and renaming the Groebner file. --- src/sage/algebras/clifford_algebra.py | 2 +- src/sage/algebras/exterior_algebra_cython.pxd | 19 ------ .../algebras/exterior_algebra_groebner.pxd | 21 +++++++ ...thon.pyx => exterior_algebra_groebner.pyx} | 62 ++++++++++++------- 4 files changed, 61 insertions(+), 43 deletions(-) delete mode 100644 src/sage/algebras/exterior_algebra_cython.pxd create mode 100644 src/sage/algebras/exterior_algebra_groebner.pxd rename src/sage/algebras/{exterior_algebra_cython.pyx => exterior_algebra_groebner.pyx} (77%) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 91d4efc10e7..38508538ef9 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2960,7 +2960,7 @@ def groebner_basis(self): -a*b*d + a*b*e - a*d*e + b*d*e, -a*b*c + a*b*e - a*c*e + b*c*e) """ - from sage.algebras.exterior_algebra_cython import compute_groebner + from sage.algebras.exterior_algebra_groebner import compute_groebner side = 2 if self.side() == "left": side = 0 diff --git a/src/sage/algebras/exterior_algebra_cython.pxd b/src/sage/algebras/exterior_algebra_cython.pxd deleted file mode 100644 index 022197c2911..00000000000 --- a/src/sage/algebras/exterior_algebra_cython.pxd +++ /dev/null @@ -1,19 +0,0 @@ -""" -Exterior algebras backend -""" - -from sage.data_structures.bitset cimport FrozenBitset -from sage.rings.integer cimport Integer - -cdef Integer bitset_to_int(FrozenBitset X) -cdef FrozenBitset int_to_bitset(Integer n) -cdef unsigned long degree(FrozenBitset X) -cdef FrozenBitset leading_supp(f) -cpdef tuple get_leading_supports(tuple I) - -# Grobner basis functions -cdef build_monomial(supp, E) -cdef partial_S_poly(f, g, E, int side) -cdef set preprocessing(list P, list G, E, int side) -cdef list reduction(list P, list G, E, int side) - diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd new file mode 100644 index 00000000000..60916f57e0f --- /dev/null +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -0,0 +1,21 @@ +""" +Exterior algebras Gröbner bases +""" + +from sage.data_structures.bitset cimport FrozenBitset +from sage.rings.integer cimport Integer +from sage.algebras.clifford_algebra_element cimport CliffordAlgebraElement +from sage.structure.parent cimport Parent + +cdef Integer bitset_to_int(FrozenBitset X) +cdef FrozenBitset int_to_bitset(Integer n) +cdef long degree(FrozenBitset X) +cdef FrozenBitset leading_supp(CliffordAlgebraElement f) +cpdef tuple get_leading_supports(tuple I) + +# Grobner basis functions +cdef build_monomial(Parent E, FrozenBitset supp) +cdef partial_S_poly(CliffordAlgebraElement f, CliffordAlgebraElement g, Parent E, int side) +cdef set preprocessing(list P, list G, Parent E, int side) +cdef list reduction(list P, list G, Parent E, int side) + diff --git a/src/sage/algebras/exterior_algebra_cython.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx similarity index 77% rename from src/sage/algebras/exterior_algebra_cython.pyx rename to src/sage/algebras/exterior_algebra_groebner.pyx index e3c4dc64888..d0d9ecda1ad 100644 --- a/src/sage/algebras/exterior_algebra_cython.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -1,11 +1,28 @@ """ -Exterior algebras backend +Exterior algebras Gröbner bases -This contains the backend implementations in Cython for the exterior algebra. +This contains the backend implementations in Cython for the Gröbner bases +of exterior algebra. + +AUTHORS: + +- Trevor Karn, Travis Scrimshaw (July 2022): Initial implementation """ +#***************************************************************************** +# Copyright (C) 2022 Trevor Karn +# (C) 2022 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/ +#***************************************************************************** + from sage.libs.gmp.mpz cimport mpz_sizeinbase, mpz_setbit, mpz_tstbit, mpz_cmp_si, mpz_sgn -from sage.data_structures.bitset_base cimport bitset_t, bitset_init, bitset_first, bitset_next, bitset_set_to +from sage.data_structures.bitset_base cimport (bitset_t, bitset_init, bitset_first, + bitset_next, bitset_set_to, bitset_len) from sage.structure.parent cimport Parent cdef inline Integer bitset_to_int(FrozenBitset X): @@ -23,7 +40,7 @@ cdef inline FrozenBitset int_to_bitset(Integer n): """ Convert a nonnegative integer ``n`` to a :class:`FrozenBitset`. """ - cdef unsigned long i + cdef Py_ssize_t i if mpz_sgn(n.value) == 0: return FrozenBitset() @@ -36,20 +53,15 @@ cdef inline FrozenBitset int_to_bitset(Integer n): return ret -cdef inline unsigned long degree(FrozenBitset X): +cdef inline long degree(FrozenBitset X): """ Compute the degree of ``X``. """ - cdef unsigned long ret = 0 - cdef long elt = bitset_first(X._bitset) - while elt >= 0: - ret += 1 - elt = bitset_next(X._bitset, elt + 1) - return ret + return bitset_len(X._bitset) #TODO: Bring the exterior algebra elements as a cdef class and make f know its type! -cdef inline FrozenBitset leading_supp(f): +cdef inline FrozenBitset leading_supp(CliffordAlgebraElement f): """ Return the leading support of the exterior algebra element ``f``. """ @@ -70,16 +82,17 @@ cpdef tuple get_leading_supports(tuple I): - ``I`` -- a tuple of elements of an exterior algebra """ # We filter out any elements that are 0 + cdef CliffordAlgebraElement f return tuple(set([leading_supp(f) for f in I if f._monomial_coefficients])) -cdef inline build_monomial(E, supp): +cdef inline build_monomial(Parent E, FrozenBitset supp): """ Helper function for the fastest way to build a monomial. """ - return E.element_class(E, {supp: ( E)._base.one()}) + return E.element_class(E, {supp: E._base.one()}) -cdef inline partial_S_poly(f, g, E, int side): +cdef inline partial_S_poly(CliffordAlgebraElement f, CliffordAlgebraElement g, Parent E, int side): """ Compute one half of the `S`-polynomial for ``f`` and ``g``. @@ -98,11 +111,12 @@ cdef inline partial_S_poly(f, g, E, int side): ret = f * build_monomial(E, D) return ret * (~ret[lmf._union(lmg)]) -cdef inline set preprocessing(list P, list G, E, int side): +cdef inline set preprocessing(list P, list G, Parent E, int side): """ Perform the preprocessing step. """ #print("Start preprocessing:", P) + cdef CliffordAlgebraElement f cdef set L = set(partial_S_poly(f0, f1, E, side) for f0,f1 in P) L.update(partial_S_poly(f1, f0, E, side) for f0,f1 in P) if side == 2: @@ -123,26 +137,28 @@ cdef inline set preprocessing(list P, list G, E, int side): for g in G: lm = leading_supp(g) if lm <= m: - f = build_monomial(E, m.difference(lm)) * g + f = build_monomial(E, m.difference(lm)) * g if f in L: break - monL.update(set(f.support()) - done) + monL.update(set(f._monomial_coefficients) - done) L.add(f) break #print("preprocessing:", L) return L -cdef inline list reduction(list P, list G, E, int side): +cdef inline list reduction(list P, list G, Parent E, int side): """ Perform the reduction of ``P`` mod ``G`` in ``E``. """ cdef set L = preprocessing(P, G, E, side) cdef Py_ssize_t i from sage.matrix.constructor import matrix - M = matrix({(i, bitset_to_int( m)): c for i,f in enumerate(L) for m,c in f._monomial_coefficients.items()}, + M = matrix({(i, bitset_to_int( m)): c + for i,f in enumerate(L) + for m,c in ( f)._monomial_coefficients.items()}, sparse=True) M.echelonize() # Do this in place - lead_supports = set(leading_supp(f) for f in L) + lead_supports = set(leading_supp( f) for f in L) return [E.element_class(E, {int_to_bitset(Integer(j)): c for j,c in M[i].iteritems()}) for i,p in enumerate(M.pivots()) if int_to_bitset(Integer(p)) not in lead_supports] @@ -157,9 +173,9 @@ def compute_groebner(I, side): - ``side`` -- integer; the side of the ideal: ``0`` for left, ``1`` for right, and ``2`` for two-sided """ - E = I.ring() + cdef Parent E = I.ring() cdef FrozenBitset p0, p1 - cdef unsigned long deg + cdef long deg cdef Py_ssize_t i, j, k cdef list G = [f for f in I.gens() if f] # Remove 0s TODO: We should make this unnecessary here From 3a9d790c122cf90a3efd9bf86a0db04d2d3d3395 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 13 Jul 2022 16:38:32 +0900 Subject: [PATCH 159/591] Initial version of GB strategy file for exterior algebra. --- src/sage/algebras/clifford_algebra.py | 9 +- .../algebras/exterior_algebra_groebner.pxd | 26 +- .../algebras/exterior_algebra_groebner.pyx | 434 +++++++++--------- 3 files changed, 245 insertions(+), 224 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 38508538ef9..bb3387bc88f 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2960,11 +2960,6 @@ def groebner_basis(self): -a*b*d + a*b*e - a*d*e + b*d*e, -a*b*c + a*b*e - a*c*e + b*c*e) """ - from sage.algebras.exterior_algebra_groebner import compute_groebner - side = 2 - if self.side() == "left": - side = 0 - elif self.side() == "right": - side = 1 - return compute_groebner(self, side) + from sage.algebras.exterior_algebra_groebner import GroebnerStrategy + return GroebnerStrategy(self).compute_groebner() diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd index 60916f57e0f..a35f22ae36a 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pxd +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -6,16 +6,26 @@ from sage.data_structures.bitset cimport FrozenBitset from sage.rings.integer cimport Integer from sage.algebras.clifford_algebra_element cimport CliffordAlgebraElement from sage.structure.parent cimport Parent +from sage.structure.element cimport MonoidElement -cdef Integer bitset_to_int(FrozenBitset X) -cdef FrozenBitset int_to_bitset(Integer n) cdef long degree(FrozenBitset X) -cdef FrozenBitset leading_supp(CliffordAlgebraElement f) -cpdef tuple get_leading_supports(tuple I) +cdef CliffordAlgebraElement build_monomial(Parent E, FrozenBitset supp) # Grobner basis functions -cdef build_monomial(Parent E, FrozenBitset supp) -cdef partial_S_poly(CliffordAlgebraElement f, CliffordAlgebraElement g, Parent E, int side) -cdef set preprocessing(list P, list G, Parent E, int side) -cdef list reduction(list P, list G, Parent E, int side) +cdef class GroebnerStrategy: + cdef Parent E # the exterior algebra + cdef int side + cdef MonoidElement ideal + + cdef inline FrozenBitset leading_supp(self, CliffordAlgebraElement f) + cdef inline partial_S_poly_left(self, CliffordAlgebraElement f, CliffordAlgebraElement g) + cdef inline partial_S_poly_right(self, CliffordAlgebraElement f, CliffordAlgebraElement g) + cdef set preprocessing(self, list P, list G) + cdef list reduction(self, list P, list G) + + # These are the methods that determine the ordering of the monomials. + # Override these for other orderings. + # TODO: Make them abstract methods that must be implemented in subclasses + cdef inline Integer bitset_to_int(self, FrozenBitset X) + cdef inline FrozenBitset int_to_bitset(self, Integer n) diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index d0d9ecda1ad..df13f4f30b4 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -25,34 +25,6 @@ from sage.data_structures.bitset_base cimport (bitset_t, bitset_init, bitset_fir bitset_next, bitset_set_to, bitset_len) from sage.structure.parent cimport Parent -cdef inline Integer bitset_to_int(FrozenBitset X): - """ - Convert ``X`` to an :class:`Integer`. - """ - cdef Integer ret = Integer(0) - cdef long elt = bitset_first(X._bitset) - while elt >= 0: - mpz_setbit(ret.value, elt) - elt = bitset_next(X._bitset, elt + 1) - return ret - -cdef inline FrozenBitset int_to_bitset(Integer n): - """ - Convert a nonnegative integer ``n`` to a :class:`FrozenBitset`. - """ - cdef Py_ssize_t i - - if mpz_sgn(n.value) == 0: - return FrozenBitset() - - cdef FrozenBitset ret = FrozenBitset() - cdef size_t s = mpz_sizeinbase(n.value, 2) - bitset_init(ret._bitset, s) - for i in range(s): - bitset_set_to(ret._bitset, i, mpz_tstbit(n.value, i)) - return ret - - cdef inline long degree(FrozenBitset X): """ Compute the degree of ``X``. @@ -60,202 +32,246 @@ cdef inline long degree(FrozenBitset X): return bitset_len(X._bitset) -#TODO: Bring the exterior algebra elements as a cdef class and make f know its type! -cdef inline FrozenBitset leading_supp(CliffordAlgebraElement f): - """ - Return the leading support of the exterior algebra element ``f``. - """ - cdef dict mc = f._monomial_coefficients - return int_to_bitset(min(bitset_to_int(k) for k in mc)) - -def leading_support(f): - return leading_supp(f) - -cpdef tuple get_leading_supports(tuple I): - """ - Return the leading supports of the elements in ``I``. - - Used for testing mostly - - INPUT: - - - ``I`` -- a tuple of elements of an exterior algebra - """ - # We filter out any elements that are 0 - cdef CliffordAlgebraElement f - return tuple(set([leading_supp(f) for f in I if f._monomial_coefficients])) - - -cdef inline build_monomial(Parent E, FrozenBitset supp): +cdef inline CliffordAlgebraElement build_monomial(Parent E, FrozenBitset supp): """ Helper function for the fastest way to build a monomial. """ - return E.element_class(E, {supp: E._base.one()}) + return E.element_class(E, {supp: E._base.one()}) -cdef inline partial_S_poly(CliffordAlgebraElement f, CliffordAlgebraElement g, Parent E, int side): +cdef class GroebnerStrategy: """ - Compute one half of the `S`-polynomial for ``f`` and ``g``. - - This computes: + A strategy for computing a Gröbner basis. - .. MATH:: + INPUT: - LCM(LM(f), LM(g)) / LT(f) \cdot f. + - ``I`` -- the ideal """ - cdef FrozenBitset lmf = leading_supp(f) - cdef FrozenBitset lmg = leading_supp(g) - cdef FrozenBitset D = lmg.difference(lmf) - if side == 0: - ret = build_monomial(E, D) * f + def __init__(self, I): + """ + Initialize ``self``. + """ + self.ideal = I + self.E = I.ring() + if I.side() == "left": + self.side = 0 + elif I.side() == "right": + self.side = 1 + else: + self.side = 2 + + cdef inline FrozenBitset leading_supp(self, CliffordAlgebraElement f): + """ + Return the leading support of the exterior algebra element ``f``. + """ + cdef dict mc = f._monomial_coefficients + return self.int_to_bitset(min(self.bitset_to_int(k) for k in mc)) + + cdef inline partial_S_poly_left(self, CliffordAlgebraElement f, CliffordAlgebraElement g): + """ + Compute one half of the `S`-polynomial for ``f`` and ``g``. + + This computes: + + .. MATH:: + + LCM(LM(f), LM(g)) / LT(f) \cdot f. + """ + cdef FrozenBitset lmf = self.leading_supp(f) + cdef FrozenBitset lmg = self.leading_supp(g) + cdef FrozenBitset D = lmg.difference(lmf) + ret = build_monomial(self.E, D) * f return (~ret[lmf._union(lmg)]) * ret - ret = f * build_monomial(E, D) - return ret * (~ret[lmf._union(lmg)]) -cdef inline set preprocessing(list P, list G, Parent E, int side): - """ - Perform the preprocessing step. - """ - #print("Start preprocessing:", P) - cdef CliffordAlgebraElement f - cdef set L = set(partial_S_poly(f0, f1, E, side) for f0,f1 in P) - L.update(partial_S_poly(f1, f0, E, side) for f0,f1 in P) - if side == 2: - # in partial_S_poly, side == 2 gets treated like right (== 1) - L.update(partial_S_poly(f0, f1, E, 0) for f0,f1 in P) - L.update(partial_S_poly(f1, f0, E, 0) for f0,f1 in P) - - cdef set done = set(leading_supp(f) for f in L) - cdef set monL = set() - for f in L: - monL.update(f.support()) - monL.difference_update(done) - - while monL: - m = int_to_bitset(max(bitset_to_int(k) for k in monL)) - done.add(m) - monL.remove(m) - for g in G: - lm = leading_supp(g) - if lm <= m: - f = build_monomial(E, m.difference(lm)) * g - if f in L: + cdef inline partial_S_poly_right(self, CliffordAlgebraElement f, CliffordAlgebraElement g): + """ + Compute one half of the `S`-polynomial for ``f`` and ``g``. + + This computes: + + .. MATH:: + + f \cdot LCM(LM(f), LM(g)) / LT(f). + """ + cdef FrozenBitset lmf = self.leading_supp(f) + cdef FrozenBitset lmg = self.leading_supp(g) + cdef FrozenBitset D = lmg.difference(lmf) + ret = f * build_monomial(self.E, D) + return ret * (~ret[lmf._union(lmg)]) + + cdef inline set preprocessing(self, list P, list G): + """ + Perform the preprocessing step. + """ + #print("Start preprocessing:", P) + cdef CliffordAlgebraElement f, g + + cdef set L = set() + if self.side == 0: + L.update(self.partial_S_poly_left(f0, f1) for f0,f1 in P) + L.update(self.partial_S_poly_left(f1, f0) for f0,f1 in P) + elif self.side == 1: + L.update(self.partial_S_poly_right(f0, f1) for f0,f1 in P) + L.update(self.partial_S_poly_right(f1, f0) for f0,f1 in P) + if self.side == 2: + L.update(self.partial_S_poly_left(f0, f1) for f0,f1 in P) + L.update(self.partial_S_poly_left(f1, f0) for f0,f1 in P) + L.update(self.partial_S_poly_right(f0, f1) for f0,f1 in P) + L.update(self.partial_S_poly_right(f1, f0) for f0,f1 in P) + + cdef set done = set(self.leading_supp(f) for f in L) + cdef set monL = set() + for f in L: + monL.update(f._monomial_coefficients) + monL.difference_update(done) + + while monL: + m = self.int_to_bitset(max(self.bitset_to_int(k) for k in monL)) + done.add(m) + monL.remove(m) + for g in G: + lm = self.leading_supp(g) + if lm <= m: + f = build_monomial(self.E, m.difference(lm)) * g + if f in L: + break + monL.update(set(f._monomial_coefficients) - done) + L.add(f) break - monL.update(set(f._monomial_coefficients) - done) - L.add(f) - break - #print("preprocessing:", L) - return L - -cdef inline list reduction(list P, list G, Parent E, int side): - """ - Perform the reduction of ``P`` mod ``G`` in ``E``. - """ - cdef set L = preprocessing(P, G, E, side) - cdef Py_ssize_t i - from sage.matrix.constructor import matrix - M = matrix({(i, bitset_to_int( m)): c - for i,f in enumerate(L) - for m,c in ( f)._monomial_coefficients.items()}, - sparse=True) - M.echelonize() # Do this in place - lead_supports = set(leading_supp( f) for f in L) - return [E.element_class(E, {int_to_bitset(Integer(j)): c for j,c in M[i].iteritems()}) - for i,p in enumerate(M.pivots()) - if int_to_bitset(Integer(p)) not in lead_supports] - -def compute_groebner(I, side): - """ - Compute the reduced ``side`` Gröbner basis for the ideal ``I``. - - INPUT: - - - ``I`` -- the ideal - - ``side`` -- integer; the side of the ideal: ``0`` for left, ``1`` for - right, and ``2`` for two-sided - """ - cdef Parent E = I.ring() - cdef FrozenBitset p0, p1 - cdef long deg - cdef Py_ssize_t i, j, k - - cdef list G = [f for f in I.gens() if f] # Remove 0s TODO: We should make this unnecessary here - cdef Py_ssize_t n = len(G) - cdef dict P = {} - cdef list Gp - - # for ideals generated by homogeneous (wrt Z_2-grading) polynomials, we can just consider it as a left ideal - # TODO: We can reduce the number of S-poly computations for Z_2-graded homogeneous - # ideals by throwing out those such that LCM(LM(f), LM(g)) == LM(f) * LM(g). - if all(f.is_super_homogeneous() for f in G): - side = 0 - - for i in range(n): - f0 = G[i] - p0 = leading_supp(f0) - for j in range(i+1, n): - f1 = G[j] - p1 = leading_supp(f1) - deg = degree( (p0._union(p1))) - if deg in P: - P[deg].append((f0, f1)) - else: - P[deg] = [(f0, f1)] - - while P: - #print("Cur G:", G) - Pp = P.pop(min(P)) # The selection: lowest lcm degree - Gp = reduction(Pp, G, E, side) - #print("Reduction yielded:", Gp) - G.extend(Gp) - for j in range(n, len(G)): - f1 = G[j] - p1 = leading_supp(f1) - for i in range(j): - f0 = G[i] - p0 = leading_supp(f0) + #print("preprocessing:", L) + return L + + cdef inline list reduction(self, list P, list G): + """ + Perform the reduction of ``P`` mod ``G`` in ``E``. + """ + cdef set L = self.preprocessing(P, G) + cdef Py_ssize_t i + from sage.matrix.constructor import matrix + M = matrix({(i, self.bitset_to_int( m)): c + for i,f in enumerate(L) + for m,c in ( f)._monomial_coefficients.items()}, + sparse=True) + M.echelonize() # Do this in place + lead_supports = set(self.leading_supp( f) for f in L) + return [self.E.element_class(self.E, {self.int_to_bitset(Integer(j)): c for j,c in M[i].iteritems()}) + for i,p in enumerate(M.pivots()) + if self.int_to_bitset(Integer(p)) not in lead_supports] + + def compute_groebner(self): + """ + Compute the reduced ``side`` Gröbner basis for the ideal ``I``. + """ + cdef FrozenBitset p0, p1 + cdef long deg + cdef Py_ssize_t i, j, k + cdef list G = [f for f in self.ideal.gens() if f] # Remove 0s TODO: We should make this unnecessary here + + cdef Py_ssize_t n = len(G) + cdef dict P = {} + cdef list Gp + + # for ideals generated by homogeneous (wrt Z_2-grading) polynomials, we can just consider it as a left ideal + # TODO: We can reduce the number of S-poly computations for Z_2-graded homogeneous + # ideals by throwing out those such that LCM(LM(f), LM(g)) == LM(f) * LM(g). + if all(f.is_super_homogeneous() for f in G): + side = 0 + + for i in range(n): + f0 = G[i] + p0 = self.leading_supp(f0) + for j in range(i+1, n): + f1 = G[j] + p1 = self.leading_supp(f1) deg = degree( (p0._union(p1))) if deg in P: P[deg].append((f0, f1)) else: P[deg] = [(f0, f1)] - n = len(G) - - #print(G) - - # Now that we have a Gröbner basis, we make this into a reduced Gröbner basis - cdef set pairs = set((i, j) for i in range(n) for j in range(n) if i != j) - cdef list supp - cdef bint did_reduction - cdef FrozenBitset lm, s - while pairs: - i,j = pairs.pop() - # We perform the classical reduction algorithm here on each pair - # TODO: Make this faster by using the previous technique - f = G[i] - g = G[j] - lm = leading_supp(g) - did_reduction = True - while did_reduction: - supp = f.support() - did_reduction = False - for s in supp: - if lm <= s: - did_reduction = True - mon = E.monomial(s - lm) - if side == 0: - gp = mon * g - f = f - f[s] / gp[s] * gp + + while P: + #print("Cur G:", G) + Pp = P.pop(min(P)) # The selection: lowest lcm degree + Gp = self.reduction(Pp, G) + #print("Reduction yielded:", Gp) + G.extend(Gp) + for j in range(n, len(G)): + f1 = G[j] + p1 = self.leading_supp(f1) + for i in range(j): + f0 = G[i] + p0 = self.leading_supp(f0) + deg = degree( (p0._union(p1))) + if deg in P: + P[deg].append((f0, f1)) else: - gp = g * mon - f = f - f[s] / gp[s] * gp - break - if G[i] != f: - G[i] = f - #print("reduction:", G) - if not f: - pairs.difference_update((k, i) for k in range(n)) - else: - pairs.update((k, i) for k in range(n) if k != i) - - return tuple([f for f in G if f]) + P[deg] = [(f0, f1)] + n = len(G) + + #print(G) + + # Now that we have a Gröbner basis, we make this into a reduced Gröbner basis + cdef set pairs = set((i, j) for i in range(n) for j in range(n) if i != j) + cdef list supp + cdef bint did_reduction + cdef FrozenBitset lm, s + while pairs: + i,j = pairs.pop() + # We perform the classical reduction algorithm here on each pair + # TODO: Make this faster by using the previous technique + f = G[i] + g = G[j] + lm = self.leading_supp(g) + did_reduction = True + while did_reduction: + supp = f.support() + did_reduction = False + for s in supp: + if lm <= s: + did_reduction = True + mon = self.E.monomial(s - lm) + if side == 0: + gp = mon * g + f = f - f[s] / gp[s] * gp + else: + gp = g * mon + f = f - f[s] / gp[s] * gp + break + if G[i] != f: + G[i] = f + #print("reduction:", G) + if not f: + pairs.difference_update((k, i) for k in range(n)) + else: + pairs.update((k, i) for k in range(n) if k != i) + + return tuple([f for f in G if f]) + + + cdef inline Integer bitset_to_int(self, FrozenBitset X): + """ + Convert ``X`` to an :class:`Integer`. + """ + cdef Integer ret = Integer(0) + cdef long elt = bitset_first(X._bitset) + while elt >= 0: + mpz_setbit(ret.value, elt) + elt = bitset_next(X._bitset, elt + 1) + return ret + + cdef inline FrozenBitset int_to_bitset(self, Integer n): + """ + Convert a nonnegative integer ``n`` to a :class:`FrozenBitset`. + """ + cdef Py_ssize_t i + + if mpz_sgn(n.value) == 0: + return FrozenBitset() + + cdef FrozenBitset ret = FrozenBitset() + cdef size_t s = mpz_sizeinbase(n.value, 2) + bitset_init(ret._bitset, s) + for i in range(s): + bitset_set_to(ret._bitset, i, mpz_tstbit(n.value, i)) + return ret + From 368491cc191b499916b48b38ae58e44432b7f4a0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 14 Jul 2022 12:03:52 +0900 Subject: [PATCH 160/591] Implementing different term orders for GB. --- src/sage/algebras/clifford_algebra.py | 53 +- .../algebras/clifford_algebra_element.pxd | 12 + .../algebras/clifford_algebra_element.pyx | 595 ++++++++++++++++++ .../algebras/exterior_algebra_groebner.pxd | 19 +- .../algebras/exterior_algebra_groebner.pyx | 235 ++++++- 5 files changed, 886 insertions(+), 28 deletions(-) create mode 100644 src/sage/algebras/clifford_algebra_element.pxd create mode 100644 src/sage/algebras/clifford_algebra_element.pyx diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index bb3387bc88f..e4f211c5512 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -18,6 +18,7 @@ #***************************************************************************** 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 import Parent from sage.structure.element import Element @@ -2932,17 +2933,36 @@ class ExteriorAlgebraIdeal(Ideal_nc): """ An ideal of the exterior algebra. """ + def __init__(self, ring, gens, coerce=True, side="twosided"): + """ + Initialize ``self``. + """ + self._groebner_basis = None + self._groebner_strategy = None + self._homogeneous = all(x.is_super_homogeneous() for x in gens) + if self._homogeneous: + side = "twosided" + Ideal_nc.__init__(self, ring, gens, coerce, side) + def reduce(self, f): """ Reduce ``f`` modulo ``self``. """ return f.reduce(self) - @cached_method - def groebner_basis(self): + def groebner_basis(self, term_order="negrevlex"): r""" Return the reduced Gröbner basis of ``self``. + INPUT: + + - ``term_order`` -- the term order used to compute the Gröbner basis; + must be one of the following: + + * ``"negrevlex"`` -- (default) negative reverse lex order + * ``"degrevlex"`` -- degree reverse lex order + * ``"deglex"`` -- degree lex order + EXAMPLES: We compute an example that was checked against Macaulay2:: @@ -2955,11 +2975,36 @@ def groebner_basis(self): ....: b*c*d - a*c*d + a*b*d - a*b*c] sage: I = E.ideal(rels) sage: I.groebner_basis() + (-a*c*d + a*c*e - a*d*e + c*d*e, + -a*b*c + a*b*d - a*c*d + b*c*d, + -a*b*d + a*b*e - a*d*e + b*d*e, + -a*b*c + a*b*e - a*c*e + b*c*e) + + With different term orders:: + + sage: I.groebner_basis("degrevlex") (-b*c*d + b*c*e - b*d*e + c*d*e, -a*c*d + a*c*e - a*d*e + c*d*e, -a*b*d + a*b*e - a*d*e + b*d*e, -a*b*c + a*b*e - a*c*e + b*c*e) + + sage: I.groebner_basis("deglex") + (-a*c*d + a*c*e - a*d*e + c*d*e, + -a*b*c + a*b*d - a*c*d + b*c*d, + -a*b*d + a*b*e - a*d*e + b*d*e, + -a*b*c + a*b*e - a*c*e + b*c*e) """ - from sage.algebras.exterior_algebra_groebner import GroebnerStrategy - return GroebnerStrategy(self).compute_groebner() + if term_order == "negrevlex": + from sage.algebras.exterior_algebra_groebner import GroebnerStrategyNegRevLex as strategy + elif term_order == "degrevlex": + from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegRevLex as strategy + elif term_order == "deglex": + from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegLex as strategy + else: + raise ValueError("invalid term order") + if strategy == self._groebner_strategy: + return self._groebner_basis + self._groebner_strategy = strategy + self._groebner_basis = self._groebner_strategy(self).compute_groebner() + return self._groebner_basis diff --git a/src/sage/algebras/clifford_algebra_element.pxd b/src/sage/algebras/clifford_algebra_element.pxd new file mode 100644 index 00000000000..f7a25582d54 --- /dev/null +++ b/src/sage/algebras/clifford_algebra_element.pxd @@ -0,0 +1,12 @@ +""" +Clifford algebra elements +""" + +from sage.modules.with_basis.indexed_element cimport IndexedFreeModuleElement + +cdef class CliffordAlgebraElement(IndexedFreeModuleElement): + pass + +cdef class ExteriorAlgebraElement(CliffordAlgebraElement): + pass + diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx new file mode 100644 index 00000000000..93568ebd1d1 --- /dev/null +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -0,0 +1,595 @@ +""" +Clifford algebra elements + +AUTHORS: + +- Travis Scrimshaw (2013-09-06): Initial version +- Trevor Karn (2022-07-10): Rewrite multiplication using bitsets +""" + +#***************************************************************************** +# Copyright (C) 2022 Trevor Karn +# (C) 2022 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/ +#***************************************************************************** + +from sage.structure.parent cimport Parent +from sage.data_structures.bitset cimport FrozenBitset, Bitset +from sage.algebras.weyl_algebra import repr_from_monomials +from copy import copy + +cdef class CliffordAlgebraElement(IndexedFreeModuleElement): + """ + An element in a Clifford algebra. + + TESTS:: + + sage: Q = QuadraticForm(ZZ, 3, [1, 2, 3, 4, 5, 6]) + sage: Cl. = CliffordAlgebra(Q) + sage: elt = ((x^3-z)*x + y)^2 + sage: TestSuite(elt).run() + """ + def _repr_(self): + """ + Return a string representation of ``self``. + + TESTS:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: ((x^3-z)*x + y)^2 + -2*x*y*z - x*z + 5*x - 4*y + 2*z + 2 + sage: Cl.zero() + 0 + """ + return repr_from_monomials(self.list(), self._parent._repr_term) + + def _latex_(self): + r""" + Return a `\LaTeX` representation of ``self``. + + TESTS:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: latex( ((x^3-z)*x + y)^2 ) + -2 x y z - x z + 5 x - 4 y + 2 z + 2 + sage: Cl. = CliffordAlgebra(Q) + sage: latex( (x1 - x2)*x0 + 5*x0*x1*x2 ) + 5 x_{0} x_{1} x_{2} - x_{0} x_{1} + x_{0} x_{2} - 1 + """ + return repr_from_monomials(self.list(), self._parent._latex_term, True) + + cdef _mul_(self, other): + """ + Return ``self`` multiplied by ``other``. + + INPUT: + + - ``other`` -- element of the same Clifford algebra as ``self`` + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: (x^3 - z*y)*x*(y*z + x*y*z) + x*y*z + y*z - 24*x + 12*y + 2*z - 24 + sage: y*x + -x*y + 2 + sage: z*x + -x*z + 3 + sage: z*z + 6 + sage: x*0 + 0 + sage: 0*x + 0 + """ + Q = self._parent._quadratic_form + zero = self._parent._base.zero() + cdef dict next_level, cur, d = {} + cdef FrozenBitset ml, mr, t + cdef Py_ssize_t i, j + + for ml,cl in self: + # Distribute the current term ``cl`` * ``ml`` over ``other``. + cur = copy(other._monomial_coefficients) # The current distribution of the term + for i in reversed(ml): + # Distribute the current factor ``e[i]`` (the ``i``-th + # element of the standard basis). + next_level = {} + # At the end of the following for-loop, ``next`` will be + # the dictionary describing the element + # ``e[i]`` * (the element described by the dictionary ``cur``) + # (where ``e[i]`` is the ``i``-th standard basis vector). + for mr,cr in cur.items(): + + # Commute the factor as necessary until we are in order + for j in mr: + if i <= j: + break + # Add the additional term from the commutation + # get a non-frozen bitset to manipulate + t = Bitset(mr) # a mutable copy + t.discard(j) + t = FrozenBitset(t) + next_level[t] = next_level.get(t, zero) + cr * Q[i,j] + # Note: ``Q[i,j] == Q(e[i]+e[j]) - Q(e[i]) - Q(e[j])`` for + # ``i != j``, where ``e[k]`` is the ``k``-th standard + # basis vector. + cr = -cr + if next_level[t] == zero: + del next_level[t] + + # Check to see if we have a squared term or not + mr = Bitset(mr) # temporarily mutable + if i in mr: + mr.discard(i) + cr *= Q[i,i] + # Note: ``Q[i,i] == Q(e[i])`` where ``e[i]`` is the + # ``i``-th standard basis vector. + else: + # mr is implicitly sorted + mr.add(i) + mr = FrozenBitset(mr) # refreeze it + next_level[mr] = next_level.get(mr, zero) + cr + if next_level[mr] == zero: + del next_level[mr] + cur = next_level + + # Add the distributed terms to the total + for index,coeff in cur.items(): + d[index] = d.get(index, zero) + cl * coeff + if d[index] == zero: + del d[index] + + return self.__class__(self.parent(), d) + + def list(self): + """ + Return the list of monomials and their coefficients in ``self`` + (as a list of `2`-tuples, each of which has the form + ``(monomial, coefficient)``). + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: elt = 5*x + y + sage: elt.list() + [(1, 5), (01, 1)] + """ + return sorted(self._monomial_coefficients.items(), key=lambda m: (-len(m[0]), list(m[0]))) + + def support(self): + """ + Return the support of ``self``. + + This is the list of all monomials which appear with nonzero + coefficient in ``self``. + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: elt = 5*x + y + sage: elt.support() + [1, 01] + """ + return sorted(self._monomial_coefficients, key=lambda x: (-len(x), list(x))) + + def reflection(self): + r""" + Return the image of the reflection automorphism on ``self``. + + The *reflection automorphism* of a Clifford algebra is defined + as the linear endomorphism of this algebra which maps + + .. MATH:: + + x_1 \wedge x_2 \wedge \cdots \wedge x_m \mapsto + (-1)^m x_1 \wedge x_2 \wedge \cdots \wedge x_m. + + It is an algebra automorphism of the Clifford algebra. + + :meth:`degree_negation` is an alias for :meth:`reflection`. + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: elt = 5*x + y + x*z + sage: r = elt.reflection(); r + x*z - 5*x - y + sage: r.reflection() == elt + True + + TESTS: + + We check that the reflection is an involution:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: all(x.reflection().reflection() == x for x in Cl.basis()) + True + """ + return self.__class__(self._parent, {m: (-1)**len(m) * c for m,c in self}) + + degree_negation = reflection + + def transpose(self): + r""" + Return the transpose of ``self``. + + The transpose is an anti-algebra involution of a Clifford algebra + and is defined (using linearity) by + + .. MATH:: + + x_1 \wedge x_2 \wedge \cdots \wedge x_m \mapsto + x_m \wedge \cdots \wedge x_2 \wedge x_1. + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: elt = 5*x + y + x*z + sage: t = elt.transpose(); t + -x*z + 5*x + y + 3 + sage: t.transpose() == elt + True + sage: Cl.one().transpose() + 1 + + TESTS: + + We check that the transpose is an involution:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: all(x.transpose().transpose() == x for x in Cl.basis()) + True + + Zero is sent to zero:: + + sage: Cl.zero().transpose() == Cl.zero() + True + """ + P = self._parent + if not self._monomial_coefficients: + return P.zero() + g = P.gens() + return P.sum(c * P.prod(g[i] for i in reversed(m)) for m,c in self) + + def conjugate(self): + r""" + Return the Clifford conjugate of ``self``. + + The Clifford conjugate of an element `x` of a Clifford algebra is + defined as + + .. MATH:: + + \bar{x} := \alpha(x^t) = \alpha(x)^t + + where `\alpha` denotes the :meth:`reflection ` + automorphism and `t` the :meth:`transposition `. + + EXAMPLES:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: elt = 5*x + y + x*z + sage: c = elt.conjugate(); c + -x*z - 5*x - y + 3 + sage: c.conjugate() == elt + True + + TESTS: + + We check that the conjugate is an involution:: + + sage: Q = QuadraticForm(ZZ, 3, [1,2,3,4,5,6]) + sage: Cl. = CliffordAlgebra(Q) + sage: all(x.conjugate().conjugate() == x for x in Cl.basis()) + True + """ + return self.reflection().transpose() + + clifford_conjugate = conjugate + + +cdef class ExteriorAlgebraElement(CliffordAlgebraElement): + """ + An element of an exterior algebra. + """ + cdef _mul_(self, other): + """ + Return ``self`` multiplied by ``other``. + + INPUT: + + - ``other`` -- element of the same exterior algebra as ``self`` + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: x*y + x*y + sage: y*x + -x*y + sage: z*y*x + -x*y*z + sage: (x*z)*y + -x*y*z + sage: (3*x + y)^2 + 0 + sage: (x - 3*y + z/3)^2 + 0 + sage: (x+y) * (y+z) + x*y + x*z + y*z + + sage: E. = ExteriorAlgebra(QQ) + sage: (x * y) * (w * z) + -x*y*z*w + sage: x * y * w * z + -x*y*z*w + sage: (z * w) * (x * y) + x*y*z*w + """ + cdef Parent P = self._parent + zero = P._base.zero() + cdef dict d = {} + cdef Py_ssize_t n = P.ngens() + cdef ExteriorAlgebraElement rhs = other + + cdef FrozenBitset ml, mr, t + cdef Py_ssize_t num_cross, tot_cross, i, j + + for ml,cl in self._monomial_coefficients.items(): # ml for "monomial on the left" + for mr,cr in rhs._monomial_coefficients.items(): # mr for "monomial on the right" + if ml.intersection(mr): + # if they intersect nontrivially, move along. + continue + + if not mr: + t = ml + else: + t = ml._union(mr) + it = iter(mr) + j = next(it) + + num_cross = 0 # keep track of the number of signs + tot_cross = 0 + for i in ml: + while i > j: + num_cross += 1 + try: + j = next(it) + except StopIteration: + j = n + 1 + tot_cross += num_cross + if tot_cross % 2: + cr = -cr + + d[t] = d.get(t, zero) + cl * cr + if not d[t]: + del d[t] + + return self.__class__(P, d) + + def reduce(self, I, left=True): + r""" + Reduce ``self`` with respect to the elements in ``I``. + + INPUT: + + - ``I`` -- a list of exterior algebra elements or an ideal + - ``side`` -- the side, ignored if ``I`` is an ideal + """ + from sage.algebras.clifford_algebra import ExteriorAlgebraIdeal + if isinstance(I, ExteriorAlgebraIdeal): + left = (I.side() == "left") + I = I.groebner_basis() + + f = self + E = self._parent + from sage.algebras.exterior_algebra_cython import leading_support + for g in I: + lm = leading_support(g) + reduction = True + while reduction: + supp = f.support() + reduction = False + for s in supp: + if lm <= s: + reduction = True + mon = E.monomial(s - lm) + if left: + gp = mon * g + f = f - f[s] / gp[s] * gp + else: + gp = g * mon + f = f - f[s] / gp[s] * gp + break + return f + + def interior_product(self, x): + r""" + Return the interior product (also known as antiderivation) of + ``self`` with respect to ``x`` (that is, the element + `\iota_{x}(\text{self})` of the exterior algebra). + + If `V` is an `R`-module, and if `\alpha` is a fixed element of + `V^*`, then the *interior product* with respect to `\alpha` is + an `R`-linear map + `i_{\alpha} \colon \Lambda(V) \to \Lambda(V)`, determined by + the following requirements: + + - `i_{\alpha}(v) = \alpha(v)` for all `v \in V = \Lambda^1(V)`, + - it is a graded derivation of degree `-1`: all `x` and `y` + in `\Lambda(V)` satisfy + + .. MATH:: + + i_{\alpha}(x \wedge y) = (i_{\alpha} x) \wedge y + + (-1)^{\deg x} x \wedge (i_{\alpha} y). + + It can be shown that this map `i_{\alpha}` is graded of + degree `-1` (that is, sends `\Lambda^k(V)` into + `\Lambda^{k-1}(V)` for every `k`). + + When `V` is a finite free `R`-module, the interior product can + also be defined by + + .. MATH:: + + (i_{\alpha} \omega)(u_1, \ldots, u_k) + = \omega(\alpha, u_1, \ldots, u_k), + + where `\omega \in \Lambda^k(V)` is thought of as an + alternating multilinear mapping from + `V^* \times \cdots \times V^*` to `R`. + + Since Sage is only dealing with exterior powers of modules + of the form `R^d` for some nonnegative integer `d`, the + element `\alpha \in V^*` can be thought of as an element of + `V` (by identifying the standard basis of `V = R^d` with its + dual basis). This is how `\alpha` should be passed to this + method. + + We then extend the interior product to all + `\alpha \in \Lambda (V^*)` by + + .. MATH:: + + i_{\beta \wedge \gamma} = i_{\gamma} \circ i_{\beta}. + + INPUT: + + - ``x`` -- element of (or coercing into) `\Lambda^1(V)` + (for example, an element of `V`); this plays the role of + `\alpha` in the above definition + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: x.interior_product(x) + 1 + sage: (x + x*y).interior_product(2*y) + -2*x + sage: (x*z + x*y*z).interior_product(2*y - x) + -2*x*z - y*z - z + sage: x.interior_product(E.one()) + x + sage: E.one().interior_product(x) + 0 + sage: x.interior_product(E.zero()) + 0 + sage: E.zero().interior_product(x) + 0 + + REFERENCES: + + - :wikipedia:`Exterior_algebra#Interior_product` + """ + P = self._parent + return P.sum([c * cx * P.interior_product_on_basis(m, mx) + for m,c in self for mx,cx in x]) + + antiderivation = interior_product + + def hodge_dual(self): + r""" + Return the Hodge dual of ``self``. + + The Hodge dual of an element `\alpha` of the exterior algebra is + defined as `i_{\alpha} \sigma`, where `\sigma` is the volume + form + (:meth:`~sage.algebras.clifford_algebra.ExteriorAlgebra.volume_form`) + and `i_{\alpha}` denotes the antiderivation function with + respect to `\alpha` (see :meth:`interior_product` for the + definition of this). + + .. NOTE:: + + The Hodge dual of the Hodge dual of a homogeneous element + `p` of `\Lambda(V)` equals `(-1)^{k(n-k)} p`, where + `n = \dim V` and `k = \deg(p) = |p|`. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: x.hodge_dual() + y*z + sage: (x*z).hodge_dual() + -y + sage: (x*y*z).hodge_dual() + 1 + sage: [a.hodge_dual().hodge_dual() for a in E.basis()] + [1, x, y, z, x*y, x*z, y*z, x*y*z] + sage: (x + x*y).hodge_dual() + y*z + z + sage: (x*z + x*y*z).hodge_dual() + -y + 1 + sage: E = ExteriorAlgebra(QQ, 'wxyz') + sage: [a.hodge_dual().hodge_dual() for a in E.basis()] + [1, -w, -x, -y, -z, w*x, w*y, w*z, x*y, x*z, y*z, + -w*x*y, -w*x*z, -w*y*z, -x*y*z, w*x*y*z] + """ + volume_form = self._parent.volume_form() + return volume_form.interior_product(self) + + def constant_coefficient(self): + """ + Return the constant coefficient of ``self``. + + .. TODO:: + + Define a similar method for general Clifford algebras once + the morphism to exterior algebras is implemented. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: elt = 5*x + y + x*z + 10 + sage: elt.constant_coefficient() + 10 + sage: x.constant_coefficient() + 0 + """ + return self._monomial_coefficients.get(self._parent.one_basis(), + self._parent._base.zero()) + + def scalar(self, other): + r""" + Return the standard scalar product of ``self`` with ``other``. + + The standard scalar product of `x, y \in \Lambda(V)` is + defined by `\langle x, y \rangle = \langle x^t y \rangle`, where + `\langle a \rangle` denotes the degree-0 term of `a`, and where + `x^t` denotes the transpose + (:meth:`~sage.algebras.clifford_algebra.CliffordAlgebraElement.transpose`) + of `x`. + + .. TODO:: + + Define a similar method for general Clifford algebras once + the morphism to exterior algebras is implemented. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: elt = 5*x + y + x*z + sage: elt.scalar(z + 2*x) + 0 + sage: elt.transpose() * (z + 2*x) + -2*x*y + 5*x*z + y*z + """ + return (self.transpose() * other).constant_coefficient() + diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd index a35f22ae36a..5d9430a1cce 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pxd +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -16,6 +16,9 @@ cdef class GroebnerStrategy: cdef Parent E # the exterior algebra cdef int side cdef MonoidElement ideal + cdef bint homogeneous + + cdef inline bint build_S_poly(self, CliffordAlgebraElement f, CliffordAlgebraElement g) cdef inline FrozenBitset leading_supp(self, CliffordAlgebraElement f) cdef inline partial_S_poly_left(self, CliffordAlgebraElement f, CliffordAlgebraElement g) @@ -24,8 +27,16 @@ cdef class GroebnerStrategy: cdef list reduction(self, list P, list G) # These are the methods that determine the ordering of the monomials. - # Override these for other orderings. - # TODO: Make them abstract methods that must be implemented in subclasses - cdef inline Integer bitset_to_int(self, FrozenBitset X) - cdef inline FrozenBitset int_to_bitset(self, Integer n) + # These must be implemented in subclasses. Declare them as "inline" there. + cdef Integer bitset_to_int(self, FrozenBitset X) + cdef FrozenBitset int_to_bitset(self, Integer n) + +cdef class GroebnerStrategyNegRevLex(GroebnerStrategy): + pass + +cdef class GroebnerStrategyDegRevLex(GroebnerStrategy): + cdef Integer rank + +cdef class GroebnerStrategyDegLex(GroebnerStrategy): + cdef Integer rank diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index df13f4f30b4..29998694656 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -52,7 +52,8 @@ cdef class GroebnerStrategy: """ self.ideal = I self.E = I.ring() - if I.side() == "left": + self.homogeneous = all(x.is_super_homogeneous() for x in I.gens()) + if self.homogeneous or I.side() == "left": self.side = 0 elif I.side() == "right": self.side = 1 @@ -64,7 +65,7 @@ cdef class GroebnerStrategy: Return the leading support of the exterior algebra element ``f``. """ cdef dict mc = f._monomial_coefficients - return self.int_to_bitset(min(self.bitset_to_int(k) for k in mc)) + return self.int_to_bitset(max(self.bitset_to_int(k) for k in mc)) cdef inline partial_S_poly_left(self, CliffordAlgebraElement f, CliffordAlgebraElement g): """ @@ -98,25 +99,46 @@ cdef class GroebnerStrategy: ret = f * build_monomial(self.E, D) return ret * (~ret[lmf._union(lmg)]) + cdef inline bint build_S_poly(self, CliffordAlgebraElement f, CliffordAlgebraElement g): + r""" + Check to see if we should build the `S`-polynomial. + + For homogeneous ideals, we throw out all those pairs `(f, g)` such that + + .. MATH:: + + LCM(LM(f), LM(g)) == LM(f) \cdot LM(g). + """ + if not self.homogeneous: + return True + + return ( self.leading_supp(f).intersection(self.leading_supp(g))).isempty() + cdef inline set preprocessing(self, list P, list G): """ Perform the preprocessing step. """ #print("Start preprocessing:", P) - cdef CliffordAlgebraElement f, g + cdef CliffordAlgebraElement f, g, f0, f1 cdef set L = set() if self.side == 0: - L.update(self.partial_S_poly_left(f0, f1) for f0,f1 in P) - L.update(self.partial_S_poly_left(f1, f0) for f0,f1 in P) + for f0, f1 in P: + if self.build_S_poly(f0, f1): + L.add(self.partial_S_poly_left(f0, f1)) + L.add(self.partial_S_poly_left(f1, f0)) elif self.side == 1: - L.update(self.partial_S_poly_right(f0, f1) for f0,f1 in P) - L.update(self.partial_S_poly_right(f1, f0) for f0,f1 in P) + for f0, f1 in P: + if self.build_S_poly(f0, f1): + L.add(self.partial_S_poly_right(f0, f1) for f0,f1 in P) + L.add(self.partial_S_poly_right(f1, f0) for f0,f1 in P) if self.side == 2: - L.update(self.partial_S_poly_left(f0, f1) for f0,f1 in P) - L.update(self.partial_S_poly_left(f1, f0) for f0,f1 in P) - L.update(self.partial_S_poly_right(f0, f1) for f0,f1 in P) - L.update(self.partial_S_poly_right(f1, f0) for f0,f1 in P) + for f0, f1 in P: + if self.build_S_poly(f0, f1): + L.add(self.partial_S_poly_left(f0, f1)) + L.add(self.partial_S_poly_left(f1, f0)) + L.add(self.partial_S_poly_right(f0, f1)) + L.add(self.partial_S_poly_right(f1, f0)) cdef set done = set(self.leading_supp(f) for f in L) cdef set monL = set() @@ -164,18 +186,12 @@ cdef class GroebnerStrategy: cdef FrozenBitset p0, p1 cdef long deg cdef Py_ssize_t i, j, k - cdef list G = [f for f in self.ideal.gens() if f] # Remove 0s TODO: We should make this unnecessary here + cdef list G = [f for f in self.ideal.gens() if f] # Remove 0s cdef Py_ssize_t n = len(G) cdef dict P = {} cdef list Gp - # for ideals generated by homogeneous (wrt Z_2-grading) polynomials, we can just consider it as a left ideal - # TODO: We can reduce the number of S-poly computations for Z_2-graded homogeneous - # ideals by throwing out those such that LCM(LM(f), LM(g)) == LM(f) * LM(g). - if all(f.is_super_homogeneous() for f in G): - side = 0 - for i in range(n): f0 = G[i] p0 = self.leading_supp(f0) @@ -229,7 +245,7 @@ cdef class GroebnerStrategy: if lm <= s: did_reduction = True mon = self.E.monomial(s - lm) - if side == 0: + if self.side == 0: gp = mon * g f = f - f[s] / gp[s] * gp else: @@ -246,7 +262,88 @@ cdef class GroebnerStrategy: return tuple([f for f in G if f]) + cdef Integer bitset_to_int(self, FrozenBitset X): + raise NotImplementedError + + cdef FrozenBitset int_to_bitset(self, Integer n): + raise NotImplementedError + def sorted_monomials(self, as_dict=False): + """ + Helper function to display the monomials in their term order + used by ``self``. + + EXAMPLES:: + + sage: from sage.algebras.exterior_algebra_groebner import * + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([x, y]) + sage: GroebnerStrategyNegRevLex(I).sorted_monomials() + [1, x, y, x*y, z, x*z, y*z, x*y*z] + sage: GroebnerStrategyDegLex(I).sorted_monomials() + [1, x, y, z, x*y, x*z, y*z, x*y*z] + sage: GroebnerStrategyDegRevLex(I).sorted_monomials() + [1, z, y, x, y*z, x*z, x*y, x*y*z] + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([a, b]) + sage: GroebnerStrategyNegRevLex(I).sorted_monomials() + [1, + a, + b, a*b, + c, a*c, b*c, a*b*c, + d, a*d, b*d, a*b*d, c*d, a*c*d, b*c*d, a*b*c*d] + sage: GroebnerStrategyDegLex(I).sorted_monomials() + [1, + a, b, c, d, + a*b, a*c, a*d, b*c, b*d, c*d, + a*b*c, a*b*d, a*c*d, b*c*d, + a*b*c*d] + sage: GroebnerStrategyDegRevLex(I).sorted_monomials() + [1, + d, c, b, a, + c*d, b*d, a*d, b*c, a*c, a*b, + b*c*d, a*c*d, a*b*d, a*b*c, + a*b*c*d] + """ + cdef FrozenBitset X + cdef Integer i + cdef list D = [self.bitset_to_int(X) for X in self.E._indices] + D.sort() + if as_dict: + return {i: build_monomial(self.E, self.int_to_bitset(i)) for i in D} + return [build_monomial(self.E, self.int_to_bitset(i)) for i in D] + + def monomial_to_int(self): + """ + Helper function to display the monomials in their term order + used by ``self``. + + EXAMPLES:: + + sage: from sage.algebras.exterior_algebra_groebner import * + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([a, b]) + sage: GroebnerStrategyDegLex(I).sorted_monomials() + {1: 0, + a: 1, b: 2, c: 3, d: 4, + a*b: 5, a*c: 6, a*d: 7, b*c: 8, b*d: 9, c*d: 10, + a*b*c: 11, a*b*d: 12, a*c*d: 13, b*c*d: 14, + a*b*c*d: 15} + sage: GroebnerStrategyDegRevLex(I).monomial_to_int() + {1: 0, + a: 4, b: 3, c: 2, d: 1, + a*b: 10, a*c: 9, a*d: 7, b*c: 8, b*d: 6, c*d: 5, + a*b*c: 14, a*b*d: 13, a*c*d: 12, b*c*d: 11, + a*b*c*d: 15} + """ + B = self.E.basis() + return {B[X]: self.bitset_to_int(X) for X in self.E._indices} + +cdef class GroebnerStrategyNegRevLex(GroebnerStrategy): + """ + Gröbner basis strategy implementing negrevlex ordering. + """ cdef inline Integer bitset_to_int(self, FrozenBitset X): """ Convert ``X`` to an :class:`Integer`. @@ -262,7 +359,7 @@ cdef class GroebnerStrategy: """ Convert a nonnegative integer ``n`` to a :class:`FrozenBitset`. """ - cdef Py_ssize_t i + cdef size_t i if mpz_sgn(n.value) == 0: return FrozenBitset() @@ -274,4 +371,102 @@ cdef class GroebnerStrategy: bitset_set_to(ret._bitset, i, mpz_tstbit(n.value, i)) return ret +cdef class GroebnerStrategyDegRevLex(GroebnerStrategy): + """ + Gröbner basis strategy implementing degree revlex ordering. + """ + def __init__(self, I): + """ + Initialize ``self``. + """ + GroebnerStrategy.__init__(self, I) + self.rank = Integer(self.E.ngens()) + + cdef inline Integer bitset_to_int(self, FrozenBitset X): + """ + Convert ``X`` to an :class:`Integer`. + """ + if X.isempty(): + return Integer(0) + + cdef Integer n = self.rank + cdef long i, deg = degree(X) + cdef long r = 1 + cdef Integer t = Integer(0) + + cdef long elt = bitset_first(X._bitset) + while elt >= 0: + t += Integer(elt).binomial(r) + r += 1 + elt = bitset_next(X._bitset, elt + 1) + return Integer(sum(n.binomial(i) for i in range(deg+1)) - t - 1) + + cdef inline FrozenBitset int_to_bitset(self, Integer n): + """ + Convert a nonnegative integer ``n`` to a :class:`FrozenBitset`. + """ + cdef size_t i + + if mpz_sgn(n.value) == 0: + return FrozenBitset() + + cdef Py_ssize_t deg = 0 + cdef Integer binom = Integer(1) + while n >= binom: + n -= binom + deg += 1 + binom = self.rank.binomial(deg) + + # TODO: Cythonize the from_rank + from sage.combinat.combination import from_rank + return FrozenBitset([self.rank - val - 1 for val in from_rank(n, self.rank, deg)]) + +cdef class GroebnerStrategyDegLex(GroebnerStrategy): + """ + Gröbner basis strategy implementing degree lex ordering. + """ + def __init__(self, I): + """ + Initialize ``self``. + """ + GroebnerStrategy.__init__(self, I) + self.rank = Integer(self.E.ngens()) + + cdef inline Integer bitset_to_int(self, FrozenBitset X): + """ + Convert ``X`` to an :class:`Integer`. + """ + if X.isempty(): + return Integer(0) + + cdef Integer n = self.rank + cdef long i, deg = degree(X) + cdef long r = deg + cdef Integer t = Integer(0) + + cdef long elt = bitset_first(X._bitset) + while elt >= 0: + t += Integer(n - 1 - elt).binomial(r) + r -= 1 + elt = bitset_next(X._bitset, elt + 1) + return Integer(sum(n.binomial(i) for i in range(deg+1)) - t - 1) + + cdef inline FrozenBitset int_to_bitset(self, Integer n): + """ + Convert a nonnegative integer ``n`` to a :class:`FrozenBitset`. + """ + cdef size_t i + + if mpz_sgn(n.value) == 0: + return FrozenBitset() + + cdef Py_ssize_t deg = 0 + cdef Integer binom = Integer(1) + while n >= binom: + n -= binom + deg += 1 + binom = self.rank.binomial(deg) + + from sage.combinat.combination import from_rank + return FrozenBitset(from_rank(n, self.rank, deg)) From f2a25e30e9d71a855d3321d1498825848331e353 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 14 Jul 2022 12:17:28 +0900 Subject: [PATCH 161/591] Fixing some things and tests. --- src/sage/algebras/clifford_algebra.py | 145 +++--------------- .../algebras/exterior_algebra_groebner.pxd | 2 +- .../algebras/exterior_algebra_groebner.pyx | 19 +-- 3 files changed, 30 insertions(+), 136 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index e4f211c5512..00f15bdbe12 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Clifford Algebras @@ -1850,118 +1849,6 @@ def lifted_form(x, y): codomain=self.base_ring(), name="Bilinear Form") - def exterior_bitset_f4(self, I): - r""" - Return a Groebner basis for an ideal `I` of the exterior algebra. - - EXAMPLES:: - - sage: E. = ExteriorAlgebra(QQ) - sage: rels = [c*d*e - b*d*e + b*c*e - b*c*d, - ....: c*d*e - a*d*e + a*c*e - a*c*d, - ....: b*d*e - a*d*e + a*b*e - a*b*d, - ....: b*c*e - a*c*e + a*b*e - a*b*c, - ....: b*c*d - a*c*d + a*b*d - a*b*c] - sage: I = E.ideal(rels); - sage: exterior_bitset_f4(I) - (b*c*d-b*c*e+b*d*e-c*d*e, - a*c*d-a*c*e+a*d*e-c*d*e, - a*b*d-a*b*e+a*d*e-b*d*e, - a*b*c-a*b*e+a*c*e-b*c*e) - - The example above was computed first using M2: - - E = QQ[a..e, SkewCommutative => true] - I = ideal( c*d*e - b*d*e + b*c*e - b*c*d, - c*d*e - a*d*e + a*c*e - a*c*d, - b*d*e - a*d*e + a*b*e - a*b*d, - b*c*e - a*c*e + a*b*e - a*b*c, - b*c*d - a*c*d + a*b*d - a*b*c) - groebnerBasis(I) - - returns: - o3 = | bcd-bce+bde-cde acd-ace+ade-cde abd-abe+ade-bde abc-abe+ace-bce | - """ - - # following https://pi.math.cornell.edu/~djp282/documents/math6140-2017a.pdf - - def get_pairs(pairs): - # this implements the `select` function of Peifer - - # change pairs in here so I don't have to do it after calling get_pairs. - return pairs.pop() # temporarily do Buchbergers - - def f4_sel(P): - # this is the function on page 13 of the original F4 paper. - - return P - - # P is a list of pairs - # TODO: implement the better choice. - - def symbolic_preprocessing(P, G): - # the first/second terms of the S polynomial might - # have to be adjusted a la Stokes' paper - left = set() # the first term of the S polynomial - right = set() # the second term of the S polynomial - L = left.union(right) - done = set(f.monomials()[0] for f in L) - - from itertools import chain - mon_L = set(chain.from_iterable(f.monomials() for f in L)) - - while done != mon_L: - m = sorted(mon_L.difference(done), key = lambda x: (-len(x.support_of_term()), tuple(x.support_of_term())))[0] - done = done.add(m) - for g in G: - if divides(g.monomials()[0], m): - L.add(m * g/g.monomials()[0]) - break - return L - - def f4_reduce(P, G): - # given a current set of pairs P and a - # current basis G, return G' of new basis - - L = symbolic_preprocessing(P, G) - lm_L = set(f.monomials()[0] for f in L) - - d = dict() - for i, f in enumerate(F): - d.update(((i,hash(m)),c) for m,c in f._monomial_coefficients.items()) - M = MatrixSpace(E.base_ring(), len(L), 2^self.ngens(), sparse=True) - poly_matrix = M(d).rref() - - Lprime = set(E._from_dict(dict((FrozenBitset(format(k,'b')[::-1]),v) for k,v in row.dict().items())) for row in poly_matrix) - - Gprime = set() - - for f in Lprime: - if f.monomials()[0] in lm_L: - continue - Gprime.add(f) - - return Gprime - - F = I.gens() - G = set(F) - k = I.ngens() - - from itertools import combinations - pairs = set(combinations(range(k), 2)) # this is Peifer's P - - while pairs: - P = f4_sel(pairs) # this is different from Buchbergers which would be pairs.pop() - Gtemp = f4_reduce(P, G) - pairs.difference_update(P) - - for h in Gtemp: - G.add(h) - k += 1 - pairs.update((i,k) for i in range(k)) - - return G - def _ideal_class_(self, n=0): """ Return the class that is used to implement ideals of ``self``. @@ -2950,7 +2837,7 @@ def reduce(self, f): """ return f.reduce(self) - def groebner_basis(self, term_order="negrevlex"): + def groebner_basis(self, term_order="neglex"): r""" Return the reduced Gröbner basis of ``self``. @@ -2959,13 +2846,13 @@ def groebner_basis(self, term_order="negrevlex"): - ``term_order`` -- the term order used to compute the Gröbner basis; must be one of the following: - * ``"negrevlex"`` -- (default) negative reverse lex order + * ``"neglex"`` -- (default) negative (read right-to-left) lex order * ``"degrevlex"`` -- degree reverse lex order * ``"deglex"`` -- degree lex order EXAMPLES: - We compute an example that was checked against Macaulay2:: + We compute an example:: sage: E. = ExteriorAlgebra(QQ) sage: rels = [c*d*e - b*d*e + b*c*e - b*c*d, @@ -2983,19 +2870,33 @@ def groebner_basis(self, term_order="negrevlex"): With different term orders:: sage: I.groebner_basis("degrevlex") - (-b*c*d + b*c*e - b*d*e + c*d*e, - -a*c*d + a*c*e - a*d*e + c*d*e, - -a*b*d + a*b*e - a*d*e + b*d*e, - -a*b*c + a*b*e - a*c*e + b*c*e) + (b*c*d - b*c*e + b*d*e - c*d*e, + a*c*d - a*c*e + a*d*e - c*d*e, + a*b*d - a*b*e + a*d*e - b*d*e, + a*b*c - a*b*e + a*c*e - b*c*e) sage: I.groebner_basis("deglex") (-a*c*d + a*c*e - a*d*e + c*d*e, -a*b*c + a*b*d - a*c*d + b*c*d, -a*b*d + a*b*e - a*d*e + b*d*e, -a*b*c + a*b*e - a*c*e + b*c*e) + + The example above was computed first using M2, which agrees with + the ``"degrevlex"`` ordering:: + + E = QQ[a..e, SkewCommutative => true] + I = ideal( c*d*e - b*d*e + b*c*e - b*c*d, + c*d*e - a*d*e + a*c*e - a*c*d, + b*d*e - a*d*e + a*b*e - a*b*d, + b*c*e - a*c*e + a*b*e - a*b*c, + b*c*d - a*c*d + a*b*d - a*b*c) + groebnerBasis(I) + + returns: + o3 = | bcd-bce+bde-cde acd-ace+ade-cde abd-abe+ade-bde abc-abe+ace-bce | """ - if term_order == "negrevlex": - from sage.algebras.exterior_algebra_groebner import GroebnerStrategyNegRevLex as strategy + if term_order == "neglex": + from sage.algebras.exterior_algebra_groebner import GroebnerStrategyNegLex as strategy elif term_order == "degrevlex": from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegRevLex as strategy elif term_order == "deglex": diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd index 5d9430a1cce..664d70202fe 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pxd +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -31,7 +31,7 @@ cdef class GroebnerStrategy: cdef Integer bitset_to_int(self, FrozenBitset X) cdef FrozenBitset int_to_bitset(self, Integer n) -cdef class GroebnerStrategyNegRevLex(GroebnerStrategy): +cdef class GroebnerStrategyNegLex(GroebnerStrategy): pass cdef class GroebnerStrategyDegRevLex(GroebnerStrategy): diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 29998694656..be35add50f7 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -118,7 +118,6 @@ cdef class GroebnerStrategy: """ Perform the preprocessing step. """ - #print("Start preprocessing:", P) cdef CliffordAlgebraElement f, g, f0, f1 cdef set L = set() @@ -159,7 +158,6 @@ cdef class GroebnerStrategy: monL.update(set(f._monomial_coefficients) - done) L.add(f) break - #print("preprocessing:", L) return L cdef inline list reduction(self, list P, list G): @@ -205,10 +203,8 @@ cdef class GroebnerStrategy: P[deg] = [(f0, f1)] while P: - #print("Cur G:", G) Pp = P.pop(min(P)) # The selection: lowest lcm degree Gp = self.reduction(Pp, G) - #print("Reduction yielded:", Gp) G.extend(Gp) for j in range(n, len(G)): f1 = G[j] @@ -223,8 +219,6 @@ cdef class GroebnerStrategy: P[deg] = [(f0, f1)] n = len(G) - #print(G) - # Now that we have a Gröbner basis, we make this into a reduced Gröbner basis cdef set pairs = set((i, j) for i in range(n) for j in range(n) if i != j) cdef list supp @@ -254,13 +248,12 @@ cdef class GroebnerStrategy: break if G[i] != f: G[i] = f - #print("reduction:", G) if not f: pairs.difference_update((k, i) for k in range(n)) else: pairs.update((k, i) for k in range(n) if k != i) - return tuple([f for f in G if f]) + return tuple([~f[self.leading_supp(f)] * f for f in G if f]) cdef Integer bitset_to_int(self, FrozenBitset X): raise NotImplementedError @@ -278,7 +271,7 @@ cdef class GroebnerStrategy: sage: from sage.algebras.exterior_algebra_groebner import * sage: E. = ExteriorAlgebra(QQ) sage: I = E.ideal([x, y]) - sage: GroebnerStrategyNegRevLex(I).sorted_monomials() + sage: GroebnerStrategyNegLex(I).sorted_monomials() [1, x, y, x*y, z, x*z, y*z, x*y*z] sage: GroebnerStrategyDegLex(I).sorted_monomials() [1, x, y, z, x*y, x*z, y*z, x*y*z] @@ -287,7 +280,7 @@ cdef class GroebnerStrategy: sage: E. = ExteriorAlgebra(QQ) sage: I = E.ideal([a, b]) - sage: GroebnerStrategyNegRevLex(I).sorted_monomials() + sage: GroebnerStrategyNegLex(I).sorted_monomials() [1, a, b, a*b, @@ -324,7 +317,7 @@ cdef class GroebnerStrategy: sage: from sage.algebras.exterior_algebra_groebner import * sage: E. = ExteriorAlgebra(QQ) sage: I = E.ideal([a, b]) - sage: GroebnerStrategyDegLex(I).sorted_monomials() + sage: GroebnerStrategyDegLex(I).monomial_to_int() {1: 0, a: 1, b: 2, c: 3, d: 4, a*b: 5, a*c: 6, a*d: 7, b*c: 8, b*d: 9, c*d: 10, @@ -340,9 +333,9 @@ cdef class GroebnerStrategy: B = self.E.basis() return {B[X]: self.bitset_to_int(X) for X in self.E._indices} -cdef class GroebnerStrategyNegRevLex(GroebnerStrategy): +cdef class GroebnerStrategyNegLex(GroebnerStrategy): """ - Gröbner basis strategy implementing negrevlex ordering. + Gröbner basis strategy implementing neglex ordering. """ cdef inline Integer bitset_to_int(self, FrozenBitset X): """ From dba5089f1517642d8654f31d415e42feb6f00f56 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 14 Jul 2022 13:15:36 +0900 Subject: [PATCH 162/591] Bringing more to the GB strategy classes. --- src/sage/algebras/clifford_algebra.py | 30 +++++++-- .../algebras/clifford_algebra_element.pyx | 11 ++-- .../algebras/exterior_algebra_groebner.pxd | 4 ++ .../algebras/exterior_algebra_groebner.pyx | 64 +++++++++++++------ 4 files changed, 76 insertions(+), 33 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 00f15bdbe12..78d3e212c2e 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2824,7 +2824,6 @@ def __init__(self, ring, gens, coerce=True, side="twosided"): """ Initialize ``self``. """ - self._groebner_basis = None self._groebner_strategy = None self._homogeneous = all(x.is_super_homogeneous() for x in gens) if self._homogeneous: @@ -2835,7 +2834,24 @@ def reduce(self, f): """ Reduce ``f`` modulo ``self``. """ - return f.reduce(self) + if self._groebner_strategy is None: + self.groebner_basis() + R = self.ring() + return self._groebner_strategy.reduce(R(f)) + + def _contains_(self, f): + r""" + Return ``True`` if ``f`` is in this ideal, + ``False`` otherwise. + + EXAMPLES:: + + .. NOTE:: + + Requires computation of a Groebner basis, which can be a very + expensive operation. + """ + return self.reduce(f).is_zero() def groebner_basis(self, term_order="neglex"): r""" @@ -2903,9 +2919,9 @@ def groebner_basis(self, term_order="neglex"): from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegLex as strategy else: raise ValueError("invalid term order") - if strategy == self._groebner_strategy: - return self._groebner_basis - self._groebner_strategy = strategy - self._groebner_basis = self._groebner_strategy(self).compute_groebner() - return self._groebner_basis + if strategy == type(self._groebner_strategy): + return self._groebner_strategy.groebner_basis + self._groebner_strategy = strategy(self) + self._groebner_strategy.compute_groebner() + return self._groebner_strategy.groebner_basis diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index 93568ebd1d1..0c35b57d983 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -390,18 +390,19 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): INPUT: - ``I`` -- a list of exterior algebra elements or an ideal - - ``side`` -- the side, ignored if ``I`` is an ideal + - ``left`` -- boolean; if reduce as a left ideal (``True``) + or right ideal (``False``), ignored if ``I`` is an ideal """ from sage.algebras.clifford_algebra import ExteriorAlgebraIdeal if isinstance(I, ExteriorAlgebraIdeal): - left = (I.side() == "left") - I = I.groebner_basis() + return I.reduce(self) f = self E = self._parent - from sage.algebras.exterior_algebra_cython import leading_support + + cdef FrozenBitset lm, s for g in I: - lm = leading_support(g) + lm = g.leading_support() reduction = True while reduction: supp = f.support() diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd index 664d70202fe..4e235dae6ef 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pxd +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -17,6 +17,7 @@ cdef class GroebnerStrategy: cdef int side cdef MonoidElement ideal cdef bint homogeneous + cdef public tuple groebner_basis cdef inline bint build_S_poly(self, CliffordAlgebraElement f, CliffordAlgebraElement g) @@ -26,6 +27,9 @@ cdef class GroebnerStrategy: cdef set preprocessing(self, list P, list G) cdef list reduction(self, list P, list G) + cpdef CliffordAlgebraElement reduce(self, CliffordAlgebraElement f) + cdef CliffordAlgebraElement reduce_single(self, CliffordAlgebraElement f, CliffordAlgebraElement g) + # These are the methods that determine the ordering of the monomials. # These must be implemented in subclasses. Declare them as "inline" there. cdef Integer bitset_to_int(self, FrozenBitset X) diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index be35add50f7..cb2dc49c8bf 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -51,6 +51,7 @@ cdef class GroebnerStrategy: Initialize ``self``. """ self.ideal = I + self.groebner_basis = (None,) self.E = I.ring() self.homogeneous = all(x.is_super_homogeneous() for x in I.gens()) if self.homogeneous or I.side() == "left": @@ -221,31 +222,14 @@ cdef class GroebnerStrategy: # Now that we have a Gröbner basis, we make this into a reduced Gröbner basis cdef set pairs = set((i, j) for i in range(n) for j in range(n) if i != j) - cdef list supp + cdef tuple supp cdef bint did_reduction cdef FrozenBitset lm, s while pairs: i,j = pairs.pop() # We perform the classical reduction algorithm here on each pair - # TODO: Make this faster by using the previous technique - f = G[i] - g = G[j] - lm = self.leading_supp(g) - did_reduction = True - while did_reduction: - supp = f.support() - did_reduction = False - for s in supp: - if lm <= s: - did_reduction = True - mon = self.E.monomial(s - lm) - if self.side == 0: - gp = mon * g - f = f - f[s] / gp[s] * gp - else: - gp = g * mon - f = f - f[s] / gp[s] * gp - break + # TODO: Make this faster by using the previous technique? + f = self.reduce_single(G[i], G[j]) if G[i] != f: G[i] = f if not f: @@ -253,7 +237,45 @@ cdef class GroebnerStrategy: else: pairs.update((k, i) for k in range(n) if k != i) - return tuple([~f[self.leading_supp(f)] * f for f in G if f]) + self.groebner_basis = tuple([~f[self.leading_supp(f)] * f for f in G if f]) + + cpdef CliffordAlgebraElement reduce(self, CliffordAlgebraElement f): + """ + Reduce ``f`` modulo the ideal with Gröbner basis ``G``. + """ + for g in self.groebner_basis: + f = self.reduce_single(f, g) + return f + + cdef CliffordAlgebraElement reduce_single(self, CliffordAlgebraElement f, CliffordAlgebraElement g): + """ + Reduce ``f`` by ``g``. + + .. TODO:: + + Optimize this by doing it in-place and changing the underlying dict of ``f``. + """ + cdef FrozenBitset lm, s + cdef tuple supp + + lm = self.leading_supp(g) + did_reduction = True + while did_reduction: + supp = tuple(f._monomial_coefficients) + did_reduction = False + for s in supp: + if lm <= s: + did_reduction = True + mon = self.E.monomial(s - lm) + if self.side == 0: + gp = mon * g + f -= f[s] / gp[s] * gp + else: + gp = g * mon + f -= f[s] / gp[s] * gp + break + return f + cdef Integer bitset_to_int(self, FrozenBitset X): raise NotImplementedError From 2362a631cf4d34b278f378424d375d2fe3e237c9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 14 Jul 2022 13:34:41 +0900 Subject: [PATCH 163/591] Implementing containment of ideals, mostly. --- src/sage/algebras/clifford_algebra.py | 92 ++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 78d3e212c2e..73d461cfbad 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -21,6 +21,8 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element +from sage.structure.richcmp import (richcmp_method, op_EQ, op_NE, + op_LT, op_GT, op_LE, op_GE, rich_to_bool) from sage.data_structures.bitset import Bitset, FrozenBitset from sage.algebras.clifford_algebra_element import CliffordAlgebraElement, ExteriorAlgebraElement @@ -2816,6 +2818,7 @@ def chain_complex(self, R=None): return ChainComplex(data, degree=1) +@richcmp_method class ExteriorAlgebraIdeal(Ideal_nc): """ An ideal of the exterior algebra. @@ -2846,12 +2849,99 @@ def _contains_(self, f): EXAMPLES:: + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([x, x*y*z + 2*x*z + 3*y*z]) + sage: I.groebner_basis() + (x, y*z) + sage: x in I + True + sage: y*z in I + True + sage: x + 3*y*z in I + True + sage: x + 3*y in I + False + .. NOTE:: Requires computation of a Groebner basis, which can be a very expensive operation. """ - return self.reduce(f).is_zero() + return not self.reduce(f) + + def __richcmp__(self, other, op): + """ + Compare ``self`` and ``other``. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([x, x*y*z + 2*x*z + 3*y*z]) + sage: I == I + True + sage: Ip = E.ideal([x, y*z]) + sage: Ip == I + True + sage: Ip <= I + True + sage: Ip < I + False + sage: Ip >= I + True + sage: Ip > I + False + sage: E.ideal([x]) < I + True + sage: E.ideal([x]) <= I + True + sage: I <= E.ideal([x]) + False + """ + if not isinstance(other, ExteriorAlgebraIdeal): + if op == op_EQ: + return False + if op == op_NE: + return True + return NotImplemented + + if self is other: + return rich_to_bool(op, 0) + + # comparison for >= and > : swap the arguments + if op == op_GE: + return other.__richcmp__(self, op_LE) + elif op == op_GT: + return other.__richcmp__(self, op_LT) + + if self.side() == other.side(): + s_gens = set(g for g in self.gens() if g) + o_gens = set(g for g in other.gens() if g) + if set(s_gens) == set(o_gens): + return rich_to_bool(op, 0) + + contained = all(f in other for f in s_gens) + if op == op_LE: + return contained + + contains = all(f in self for f in o_gens) + if op == op_EQ: + return contained and contains + if op == op_NE: + return not (contained and contains) + # remaining case < + return contained and not contains + + + if op in [op_LT, op_LE] and other.side() == "twosided": + if not all(f in other for f in set(self.gens()) if f): + return False + if op == op_LE: + return True + return self.__richcmp__(other, op_NE) + + # Otherwise we will fallback to linear algebra containment + # TODO: Implement this + return NotImplemented def groebner_basis(self, term_order="neglex"): r""" From 6480faaad4f3be343fd55e620e6292b9a177e450 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 26 Jul 2022 10:28:12 -0500 Subject: [PATCH 164/591] Rebase off of 9.7.beta6 and fix merge conflicts --- src/sage/algebras/clifford_algebra.py | 292 +------------------------- 1 file changed, 1 insertion(+), 291 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 73d461cfbad..900a796881c 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1628,11 +1628,7 @@ def coproduct_on_basis(self, a): one = self.base_ring().one() L = unshuffle_iterator(tuple(a), one) return self.tensor_square()._from_dict( -<<<<<<< HEAD {tuple(FrozenBitset(e) if e else FrozenBitset('0') for e in t): c for t, c in L if c}, -======= - {tuple(FrozenBitset(e) if e else FrozenBitset() for e in t): c for t,c in L if c}, ->>>>>>> b0f66e328e (Cythonizing the element classes.) coerce=False, remove_zeros=False) @@ -1863,294 +1859,8 @@ def _ideal_class_(self, n=0): """ return ExteriorAlgebraIdeal -<<<<<<< HEAD - class Element(CliffordAlgebraElement): - """ - An element of an exterior algebra. - """ - def _mul_(self, other): - """ - Return ``self`` multiplied by ``other``. - - INPUT: - - - ``other`` -- element of the same exterior algebra as ``self`` - - EXAMPLES:: - - sage: E. = ExteriorAlgebra(QQ) - sage: x*y - x*y - sage: y*x - -x*y - sage: z*y*x - -x*y*z - sage: (x*z)*y - -x*y*z - sage: (3*x + y)^2 - 0 - sage: (x - 3*y + z/3)^2 - 0 - sage: (x+y) * (y+z) - x*y + x*z + y*z - - sage: E. = ExteriorAlgebra(QQ) - sage: (x * y) * (w * z) - -x*y*z*w - sage: x * y * w * z - -x*y*z*w - sage: (z * w) * (x * y) - x*y*z*w - """ - P = self.parent() - zero = P.base_ring().zero() - d = {} - n = P.ngens() - - for ml, cl in self: # ml for "monomial on the left" - for mr, cr in other: # mr for "monomial on the right" - if ml.intersection(mr): - # if they intersect nontrivially, move along. - continue - - if not mr: - t = ml - else: - t = ml.union(mr) - it = iter(mr) - j = next(it) - - num_cross = 0 # keep track of the number of signs - tot_cross = 0 - for i in ml: - num_cross_new = 0 - while i > j: - num_cross_new += 1 - try: - j = next(it) - except StopIteration: - j = n + 1 - tot_cross += num_cross - if tot_cross % 2: - cr = -cr - - d[t] = d.get(t, zero) + cl * cr - if d[t] == zero: - del d[t] - - return self.__class__(P, d) - - def reduce(self, I, left=True): - r""" - Reduce ``self`` with respect to the elements in ``I``. - - INPUT: - - - ``I`` -- a list of exterior algebra elements or an ideal - - ``side`` -- the side, ignored if ``I`` is an ideal - """ - if isinstance(I, ExteriorAlgebraIdeal): - left = (I.side() == "left") - I = I.groebner_basis() - - E = self.parent() - f = self - from sage.algebras.exterior_algebra_cython import leading_support - for g in I: - lm = leading_support(g) - reduction = True - while reduction: - supp = f.support() - reduction = False - for s in supp: - if lm <= s: - reduction = True - mon = E.monomial(s - lm) - if left: - gp = mon * g - f = f - f[s] / gp[s] * gp - else: - gp = g * mon - f = f - f[s] / gp[s] * gp - break - return f - - def interior_product(self, x): - r""" - Return the interior product (also known as antiderivation) of - ``self`` with respect to ``x`` (that is, the element - `\iota_{x}(\text{self})` of the exterior algebra). - - If `V` is an `R`-module, and if `\alpha` is a fixed element of - `V^*`, then the *interior product* with respect to `\alpha` is - an `R`-linear map - `i_{\alpha} \colon \Lambda(V) \to \Lambda(V)`, determined by - the following requirements: - - - `i_{\alpha}(v) = \alpha(v)` for all `v \in V = \Lambda^1(V)`, - - it is a graded derivation of degree `-1`: all `x` and `y` - in `\Lambda(V)` satisfy - - .. MATH:: - - i_{\alpha}(x \wedge y) = (i_{\alpha} x) \wedge y - + (-1)^{\deg x} x \wedge (i_{\alpha} y). - - It can be shown that this map `i_{\alpha}` is graded of - degree `-1` (that is, sends `\Lambda^k(V)` into - `\Lambda^{k-1}(V)` for every `k`). - - When `V` is a finite free `R`-module, the interior product can - also be defined by - - .. MATH:: - - (i_{\alpha} \omega)(u_1, \ldots, u_k) - = \omega(\alpha, u_1, \ldots, u_k), - - where `\omega \in \Lambda^k(V)` is thought of as an - alternating multilinear mapping from - `V^* \times \cdots \times V^*` to `R`. - - Since Sage is only dealing with exterior powers of modules - of the form `R^d` for some nonnegative integer `d`, the - element `\alpha \in V^*` can be thought of as an element of - `V` (by identifying the standard basis of `V = R^d` with its - dual basis). This is how `\alpha` should be passed to this - method. - - We then extend the interior product to all - `\alpha \in \Lambda (V^*)` by - - .. MATH:: - - i_{\beta \wedge \gamma} = i_{\gamma} \circ i_{\beta}. - - INPUT: - - - ``x`` -- element of (or coercing into) `\Lambda^1(V)` - (for example, an element of `V`); this plays the role of - `\alpha` in the above definition - - EXAMPLES:: - - sage: E. = ExteriorAlgebra(QQ) - sage: x.interior_product(x) - 1 - sage: (x + x*y).interior_product(2*y) - -2*x - sage: (x*z + x*y*z).interior_product(2*y - x) - -2*x*z - y*z - z - sage: x.interior_product(E.one()) - x - sage: E.one().interior_product(x) - 0 - sage: x.interior_product(E.zero()) - 0 - sage: E.zero().interior_product(x) - 0 - - REFERENCES: - - - :wikipedia:`Exterior_algebra#Interior_product` - """ - P = self.parent() - return P.sum([c * cx * P.interior_product_on_basis(m, mx) - for m, c in self for mx, cx in x]) - - antiderivation = interior_product - - def hodge_dual(self): - r""" - Return the Hodge dual of ``self``. - - The Hodge dual of an element `\alpha` of the exterior algebra is - defined as `i_{\alpha} \sigma`, where `\sigma` is the volume - form - (:meth:`~sage.algebras.clifford_algebra.ExteriorAlgebra.volume_form`) - and `i_{\alpha}` denotes the antiderivation function with - respect to `\alpha` (see :meth:`interior_product` for the - definition of this). - - .. NOTE:: - - The Hodge dual of the Hodge dual of a homogeneous element - `p` of `\Lambda(V)` equals `(-1)^{k(n-k)} p`, where - `n = \dim V` and `k = \deg(p) = |p|`. - - EXAMPLES:: - - sage: E. = ExteriorAlgebra(QQ) - sage: x.hodge_dual() - y*z - sage: (x*z).hodge_dual() - -y - sage: (x*y*z).hodge_dual() - 1 - sage: [a.hodge_dual().hodge_dual() for a in E.basis()] - [1, x, y, z, x*y, x*z, y*z, x*y*z] - sage: (x + x*y).hodge_dual() - y*z + z - sage: (x*z + x*y*z).hodge_dual() - -y + 1 - sage: E = ExteriorAlgebra(QQ, 'wxyz') - sage: [a.hodge_dual().hodge_dual() for a in E.basis()] - [1, -w, -x, -y, -z, w*x, w*y, w*z, x*y, x*z, y*z, - -w*x*y, -w*x*z, -w*y*z, -x*y*z, w*x*y*z] - """ - volume_form = self.parent().volume_form() - return volume_form.interior_product(self) - - def constant_coefficient(self): - """ - Return the constant coefficient of ``self``. - - .. TODO:: - - Define a similar method for general Clifford algebras once - the morphism to exterior algebras is implemented. - - EXAMPLES:: - - sage: E. = ExteriorAlgebra(QQ) - sage: elt = 5*x + y + x*z + 10 - sage: elt.constant_coefficient() - 10 - sage: x.constant_coefficient() - 0 - """ - return self._monomial_coefficients.get(self.parent().one_basis(), - self.base_ring().zero()) - - def scalar(self, other): - r""" - Return the standard scalar product of ``self`` with ``other``. - - The standard scalar product of `x, y \in \Lambda(V)` is - defined by `\langle x, y \rangle = \langle x^t y \rangle`, where - `\langle a \rangle` denotes the degree-0 term of `a`, and where - `x^t` denotes the transpose - (:meth:`~sage.algebras.clifford_algebra.CliffordAlgebraElement.transpose`) - of `x`. - - .. TODO:: - - Define a similar method for general Clifford algebras once - the morphism to exterior algebras is implemented. - - EXAMPLES:: - - sage: E. = ExteriorAlgebra(QQ) - sage: elt = 5*x + y + x*z - sage: elt.scalar(z + 2*x) - 0 - sage: elt.transpose() * (z + 2*x) - -2*x*y + 5*x*z + y*z - """ - return (self.transpose() * other).constant_coefficient() -======= Element = ExteriorAlgebraElement ->>>>>>> b0f66e328e (Cythonizing the element classes.) + ##################################################################### # Differentials From e7bf85306d1ef42b59908d9805f9bf2fb315a7f6 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 27 Jul 2022 18:50:34 +0530 Subject: [PATCH 165/591] cleanup user interface of LazySymmetricFunctions --- src/sage/data_structures/stream.py | 1 + src/sage/rings/lazy_series.py | 38 ++++++++--- src/sage/rings/lazy_series_ring.py | 104 ++++++++++++++++------------- 3 files changed, 85 insertions(+), 58 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index e606f25579b..f83eeff0b89 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -837,6 +837,7 @@ def __init__(self, is_sparse, approximate_order): sage: TestSuite(C).run(skip="_test_pickling") """ self._target = None + assert approximate_order is not None, "calling Stream_uninitialized with None as approximate order" super().__init__(is_sparse, approximate_order) def get_coefficient(self, n): diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 9ce78477eb6..73e5a81cf16 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -691,6 +691,17 @@ def define(self, s): sage: [F[i] for i in range(1, 16)] [1, 1, 1, 3, 1, 5, 1, 10, 3, 5, 1, 24, 1, 5, 5] + We can compute the Frobenius character of unlabeled trees:: + + sage: m = SymmetricFunctions(QQ).m() + sage: s = SymmetricFunctions(QQ).s() + sage: L = LazySymmetricFunctions(m) + sage: E = L(lambda n: s[n], valuation=0) + sage: X = L(s[1]) + sage: A = L(None); A.define(X*E(A)) + sage: A + m[1] + (2*m[1,1]+m[2]) + (9*m[1,1,1]+5*m[2,1]+2*m[3]) + (64*m[1,1,1,1]+34*m[2,1,1]+18*m[2,2]+13*m[3,1]+4*m[4]) + (625*m[1,1,1,1,1]+326*m[2,1,1,1]+171*m[2,2,1]+119*m[3,1,1]+63*m[3,2]+35*m[4,1]+9*m[5]) + (7776*m[1,1,1,1,1,1]+4016*m[2,1,1,1,1]+2078*m[2,2,1,1]+1077*m[2,2,2]+1433*m[3,1,1,1]+744*m[3,2,1]+268*m[3,3]+401*m[4,1,1]+209*m[4,2]+95*m[5,1]+20*m[6]) + O^7 + TESTS:: sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) @@ -3364,7 +3375,8 @@ class LazySymmetricFunction(LazyCauchyProductSeries): EXAMPLES:: - sage: L = LazySymmetricFunctions(ZZ, "x") + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(s) """ def __call__(self, *args): r""" @@ -3389,24 +3401,24 @@ def __call__(self, *args): sage: P. = QQ[] sage: s = SymmetricFunctions(P).s() - sage: L = LazySymmetricFunctions(P, "x") + sage: L = LazySymmetricFunctions(s) sage: f = s[2]; g = s[3] sage: L(f)(L(g)) - L(f(g)) - O(x)^7 + O^7 sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] sage: L(f)(L(g)) - L(f(g)) - O(x)^7 + O^7 sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] sage: L(f)(L(q*g)) - L(f(q*g)) - O(x)^7 + O^7 The Frobenius character of the permutation action on set partitions is a plethysm:: sage: s = SymmetricFunctions(QQ).s() - sage: S = LazySymmetricFunctions(QQ, "x") + sage: S = LazySymmetricFunctions(s) sage: E1 = S(lambda n: s[n], valuation=1) sage: E = 1 + E1 sage: P = E(E1) @@ -3414,7 +3426,7 @@ def __call__(self, *args): [s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]] """ - if len(args) != len(self.parent().variable_names()): + if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") from sage.combinat.sf.sfa import is_SymmetricFunction if not all(isinstance(g, LazySymmetricFunction) or is_SymmetricFunction(g) for g in args): @@ -3423,8 +3435,11 @@ def __call__(self, *args): if len(args) == 1: g = args[0] P = g.parent() - R = P._internal_poly_ring.base_ring() BR = P.base_ring() + if isinstance(g, LazySymmetricFunction): + R = P._laurent_poly_ring + else: + R = P p = R.realization_of().power() g_p = Stream_map_coefficients(g._coeff_stream, lambda c: c, p) try: @@ -3450,7 +3465,7 @@ def stretched_coefficient(k, n): return c def g_coeff_stream(k): return Stream_function(lambda n: stretched_coefficient(k, n), - R, P._sparse, 0) + R, P._sparse, 0) stretched = lazy_list(lambda k: g_coeff_stream(k)) f_p = Stream_map_coefficients(self._coeff_stream, lambda c: c, p) def coefficient(n): @@ -3473,7 +3488,8 @@ def _format_series(self, formatter, format_strings=False): TESTS:: - sage: L = LazySymmetricFunctions(QQ, "x, y") + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(tensor([s, s])) """ P = self.parent() cs = self._coeff_stream @@ -3492,7 +3508,7 @@ def _format_series(self, formatter, format_strings=False): if P._internal_poly_ring.base_ring() is P.base_ring(): bigO = ["O(%s)" % P._monomial(1, m)] else: - bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] + bigO = ["O^%s" % m] else: bigO = [] diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 1d05a5da0b8..be24c2a838b 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1288,6 +1288,8 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No raise ValueError("the valuation of a Taylor series must be positive") if len(self.variable_names()) > 1: raise ValueError(f"valuation must not be specified for multivariate Taylor series") + if len(self.variable_names()) > 1: + valuation = 0 R = self._laurent_poly_ring BR = self.base_ring() @@ -1425,29 +1427,39 @@ class LazySymmetricFunctions(UniqueRepresentation, Parent): INPUT: - - ``base_ring`` -- coefficient ring + - ``basis`` -- the ring of symmetric functions - ``names`` -- name(s) of the alphabets - ``sparse`` -- (default: ``True``) whether we use a sparse or a dense representation EXAMPLES:: - sage: LazySymmetricFunctions(ZZ, 'x') - Lazy Symmetric Functions Ring in x over Integer Ring + sage: s = SymmetricFunctions(ZZ).s() + sage: LazySymmetricFunctions(s) + Lazy Symmetric Functions over Integer Ring in the Schur basis - sage: L = LazySymmetricFunctions(QQ, "x, y"); L - Multialphabet Lazy Symmetric Functions Ring in x, y over Rational Field + sage: m = SymmetricFunctions(ZZ).m() + sage: LazySymmetricFunctions(tensor([s, m])) + Lazy Symmetric Functions over Integer Ring in the Schur basis # Symmetric Functions over Integer Ring in the monomial basis """ Element = LazySymmetricFunction - def __init__(self, base_ring, names, sparse=True, category=None): + def __init__(self, basis, sparse=True, category=None): """ Initialize ``self``. TESTS:: - sage: L = LazySymmetricFunctions(ZZ, 't') + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(s) sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) """ + base_ring = basis.base_ring() + if basis in Algebras.TensorProducts: + self._arity = len(basis._sets) + else: + if basis not in Algebras.Graded: + raise ValueError("basis should be a graded algebra") + self._arity = 1 category = Algebras(base_ring.category()) if base_ring in Fields(): category &= CompleteDiscreteValuationRings() @@ -1460,16 +1472,9 @@ def __init__(self, base_ring, names, sparse=True, category=None): category = category.Finite() else: category = category.Infinite() - Parent.__init__(self, base=base_ring, names=names, - category=category) + Parent.__init__(self, base=base_ring, category=category) self._sparse = sparse - n = len(self.variable_names()) - if n == 1: - self._laurent_poly_ring = SymmetricFunctions(base_ring).m() - else: - from sage.categories.tensor import tensor - m = SymmetricFunctions(base_ring).m() - self._laurent_poly_ring = tensor([m]*len(self.variable_names())) + self._laurent_poly_ring = basis self._internal_poly_ring = PolynomialRing(self._laurent_poly_ring, "DUMMY_VARIABLE") def _repr_(self): @@ -1478,13 +1483,11 @@ def _repr_(self): EXAMPLES:: - sage: LazySymmetricFunctions(GF(2), 'z') - Lazy Symmetric Functions Ring in z over Finite Field of size 2 + sage: s = SymmetricFunctions(GF(2)).s() + sage: LazySymmetricFunctions(s) + Lazy Symmetric Functions over Finite Field of size 2 in the Schur basis """ - if len(self.variable_names()) == 1: - return "Lazy Symmetric Functions Ring in {} over {}".format(self.variable_name(), self.base_ring()) - generators_rep = ", ".join(self.variable_names()) - return "Multialphabet Lazy Symmetric Functions Ring in {} over {}".format(generators_rep, self.base_ring()) + return "Lazy {}".format(self._laurent_poly_ring) def _latex_(self): r""" @@ -1492,13 +1495,13 @@ def _latex_(self): EXAMPLES:: - sage: L = LazySymmetricFunctions(GF(2), 'z') + sage: s = SymmetricFunctions(GF(2)).s() + sage: L = LazySymmetricFunctions(s) sage: latex(L) - \Lambda( \Bold{F}_{2} , z) + \text{\texttt{Symmetric{ }Functions{ }over{ }Finite{ }Field{ }of{ }size{ }2{ }in{ }the{ }Schur{ }basis}} """ from sage.misc.latex import latex - generators_rep = ", ".join(self.variable_names()) - return r"\Lambda(" + latex(self.base_ring()) + r", {})".format(generators_rep) + return latex(self._laurent_poly_ring) def _monomial(self, c, n): r""" @@ -1506,8 +1509,9 @@ def _monomial(self, c, n): EXAMPLES:: + sage: m = SymmetricFunctions(ZZ).m() sage: s = SymmetricFunctions(ZZ).s() - sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L = LazySymmetricFunctions(m) sage: L._monomial(s[2,1], 3) 2*m[1, 1, 1] + m[2, 1] @@ -1521,7 +1525,8 @@ def _coerce_map_from_(self, S): EXAMPLES:: - sage: L = LazySymmetricFunctions(GF(2), 'z') + sage: s = SymmetricFunctions(GF(2)).s() + sage: L = LazySymmetricFunctions(s) sage: L.has_coerce_map_from(ZZ) True sage: L.has_coerce_map_from(GF(2)) @@ -1549,21 +1554,22 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) INPUT: - - ``x`` -- data used to the define a Taylor series + - ``x`` -- data used to the define a symmetric function - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series - ``degree`` -- (optional) the degree when the symmetric function has finite support - ``check`` -- (optional) check that coefficients are homogeneous of the correct degree when they are retrieved EXAMPLES:: - sage: L = LazySymmetricFunctions(GF(2), 'z') + sage: m = SymmetricFunctions(GF(2)).m() + sage: L = LazySymmetricFunctions(m) sage: L(2) 0 sage: L(3) m[] sage: m = SymmetricFunctions(ZZ).m() - sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: L = LazySymmetricFunctions(m) sage: f = L(lambda i: m([i]), valuation=5, degree=10); f m[5] + m[6] + m[7] + m[8] + m[9] @@ -1585,21 +1591,24 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) Finally, ``x`` can be a symmetric function:: + sage: m = SymmetricFunctions(ZZ).m() sage: s = SymmetricFunctions(ZZ).s() - sage: L = LazySymmetricFunctions(ZZ, "x") + sage: L = LazySymmetricFunctions(m) sage: L(s.an_element()) 2*m[] + 2*m[1] + (3*m[1,1]+3*m[2]) TESTS:: - sage: L = LazySymmetricFunctions(ZZ, "x,y") + sage: s = SymmetricFunctions(ZZ).s() + sage: m = SymmetricFunctions(ZZ).m() + sage: L = LazySymmetricFunctions(tensor([s, m])) sage: L(lambda n: 0) - O(x,y)^7 + O^7 sage: L(lambda n: n)[3]; Traceback (most recent call last): ... - ValueError: coefficient 3*m[] # m[] at degree 3 is not a symmetric function of the correct homogeneous degree + ValueError: coefficient 3*s[] # m[] at degree 3 is not a symmetric function of the correct homogeneous degree sage: L([1, 2, 3]); Traceback (most recent call last): @@ -1612,9 +1621,11 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) ValueError: coefficients must be symmetric functions of the correct homogeneous degree """ - if valuation is not None: - if valuation < 0: - raise ValueError("the valuation of a lazy symmetric function must be nonnegative") + if valuation is None: + valuation = 0 + if valuation < 0: + raise ValueError("the valuation of a lazy symmetric function must be nonnegative") + R = self._laurent_poly_ring BR = self.base_ring() @@ -1632,7 +1643,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) coeff_stream = Stream_zero(self._sparse) else: p_dict = {} - if len(self.variable_names()) == 1: + if self._arity == 1: for f in x.terms(): d = f.degree() p_dict[d] = p_dict.get(d, 0) + f @@ -1656,7 +1667,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) # TODO: Implement a way to make a self._sparse copy raise NotImplementedError("cannot convert between sparse and dense") - if len(self.variable_names()) == 1: + if self._arity == 1: def is_homogeneous_of_degree(f, d): if not f: return True @@ -1673,8 +1684,6 @@ def is_homogeneous_of_degree(f, d): if sum(p.size() for p in t) != d: return False if isinstance(x, (tuple, list)): - if valuation is None: - valuation = 0 if degree is None: degree = valuation + len(x) p = [R(e) for e in x] @@ -1687,8 +1696,6 @@ def is_homogeneous_of_degree(f, d): degree=degree) return self.element_class(self, coeff_stream) if callable(x): - if valuation is None: - valuation = 0 if degree is not None: p = [R(x(i)) for i in range(valuation, degree)] if not all(is_homogeneous_of_degree(e, i) @@ -1718,7 +1725,8 @@ def _an_element_(self): EXAMPLES:: - sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: m = SymmetricFunctions(ZZ).m() + sage: L = LazySymmetricFunctions(m) sage: L.an_element() m[] """ @@ -1734,7 +1742,8 @@ def one(self): EXAMPLES:: - sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: m = SymmetricFunctions(ZZ).m() + sage: L = LazySymmetricFunctions(m) sage: L.one() m[] """ @@ -1749,7 +1758,8 @@ def zero(self): EXAMPLES:: - sage: L = LazySymmetricFunctions(ZZ, 'z') + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(s) sage: L.zero() 0 """ From e95c5466ea763c1cf969cce5efdc069497ba5e97 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 28 Jul 2022 12:24:21 -0500 Subject: [PATCH 166/591] Add examples --- src/sage/algebras/clifford_algebra.py | 32 +++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 900a796881c..4830c0969cb 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1851,6 +1851,12 @@ def _ideal_class_(self, n=0): """ Return the class that is used to implement ideals of ``self``. + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: type(E.ideal(x*y - z)) + + TESTS:: sage: E. = ExteriorAlgebra(QQ) @@ -2532,6 +2538,21 @@ def chain_complex(self, R=None): class ExteriorAlgebraIdeal(Ideal_nc): """ An ideal of the exterior algebra. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal(x*y); I + Twosided Ideal (x*y) of The exterior algebra of rank 3 over Rational Field + + We can also use it to build a quotient:: + + sage: Q = E.quotient(I); Q + Quotient of The exterior algebra of rank 3 over Rational Field by the ideal (x*y) + sage: Q.inject_variables() + Defining xbar, ybar, zbar + sage: xbar * ybar + 0 """ def __init__(self, ring, gens, coerce=True, side="twosided"): """ @@ -2546,6 +2567,17 @@ def __init__(self, ring, gens, coerce=True, side="twosided"): def reduce(self, f): """ Reduce ``f`` modulo ``self``. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal(x*y); + sage: I.reduce(x*y + x*y*z + z) + z + sage: I.reduce(x*y + x + y) + x + y + sage: I.reduce(x*y + x*y*z) + 0 """ if self._groebner_strategy is None: self.groebner_basis() From b3ef1f706a4acd9687099126b0d7e0a3d6970188 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 28 Jul 2022 14:43:06 -0500 Subject: [PATCH 167/591] Fix matrix indexing --- src/sage/algebras/exterior_algebra_groebner.pyx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index cb2dc49c8bf..d76f797bbe8 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -168,19 +168,30 @@ cdef class GroebnerStrategy: cdef set L = self.preprocessing(P, G) cdef Py_ssize_t i from sage.matrix.constructor import matrix - M = matrix({(i, self.bitset_to_int( m)): c + r = 2 ** self.E.ngens() - 1 # r for "rank" or "reverso" + M = matrix({(i, r - self.bitset_to_int( m)): c for i,f in enumerate(L) for m,c in ( f)._monomial_coefficients.items()}, sparse=True) M.echelonize() # Do this in place lead_supports = set(self.leading_supp( f) for f in L) - return [self.E.element_class(self.E, {self.int_to_bitset(Integer(j)): c for j,c in M[i].iteritems()}) + return [self.E.element_class(self.E, {self.int_to_bitset(r - Integer(j)): c for j,c in M[i].iteritems()}) for i,p in enumerate(M.pivots()) - if self.int_to_bitset(Integer(p)) not in lead_supports] + if self.int_to_bitset(r - Integer(p)) not in lead_supports] def compute_groebner(self): """ Compute the reduced ``side`` Gröbner basis for the ideal ``I``. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([x*y - x, x*y -1]) + sage: I.groebner_basis() + (1,) + sage: J = E.ideal([x*y - x, 2*x*y - 2]) + sage: J.groebner_basis() + (1,) """ cdef FrozenBitset p0, p1 cdef long deg From 31eba3db538c46a1bcbd5a285ee9d32d86b10a16 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 31 Jul 2022 11:13:02 -0700 Subject: [PATCH 168/591] docker/.gitpod.Dockerfile: Add docker client --- docker/.gitpod.Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docker/.gitpod.Dockerfile b/docker/.gitpod.Dockerfile index ff17d331515..40636cca678 100644 --- a/docker/.gitpod.Dockerfile +++ b/docker/.gitpod.Dockerfile @@ -1,5 +1,17 @@ # Use minimal Ubuntu installation that includes mamba FROM condaforge/mambaforge + +# Make Docker available, like the default gitpod image does +# from https://github.com/gitpod-io/workspace-images/blob/main/chunks/tool-docker/Dockerfile @ 3f0988f2d06768d22d0aa1454ef0e963b0db65f3 +# - removed unneccessary "sudo" +# - replaced use of "install-packages" (https://github.com/gitpod-io/workspace-images/blob/main/base/install-packages) +# https://docs.docker.com/engine/install/ubuntu/ +RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \ + && apt update \ + && apt-get install -yq --no-install-recommends docker-ce docker-ce-cli containerd.io + # Workaround so that vscode internals (such as git) find things installed in the conda env (notably ssh which is required to contribute to trac) ENV PATH $PATH:/workspace/sagetrac-mirror/venv/bin # Default to non-admin user From b35341ef94583e06e41843d40e9aa32a12872723 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 31 Jul 2022 11:17:53 -0700 Subject: [PATCH 169/591] docker/.gitpod.Dockerfile: Install some basic system package --- docker/.gitpod.Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/.gitpod.Dockerfile b/docker/.gitpod.Dockerfile index 40636cca678..0f08133af7e 100644 --- a/docker/.gitpod.Dockerfile +++ b/docker/.gitpod.Dockerfile @@ -1,6 +1,9 @@ # Use minimal Ubuntu installation that includes mamba FROM condaforge/mambaforge +# Some basic system packages +RUN apt update && apt-get install -yq --no-install-recommends sudo gpg curl + # Make Docker available, like the default gitpod image does # from https://github.com/gitpod-io/workspace-images/blob/main/chunks/tool-docker/Dockerfile @ 3f0988f2d06768d22d0aa1454ef0e963b0db65f3 # - removed unneccessary "sudo" From 72925f061eeaac49f54d7528650517d3944172da Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 31 Jul 2022 11:21:39 -0700 Subject: [PATCH 170/591] docker/.gitpod.Dockerfile: Install lsb-release --- docker/.gitpod.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/.gitpod.Dockerfile b/docker/.gitpod.Dockerfile index 0f08133af7e..3ff75298c77 100644 --- a/docker/.gitpod.Dockerfile +++ b/docker/.gitpod.Dockerfile @@ -2,7 +2,7 @@ FROM condaforge/mambaforge # Some basic system packages -RUN apt update && apt-get install -yq --no-install-recommends sudo gpg curl +RUN apt update && apt-get install -yq --no-install-recommends sudo gpg curl lsb-release # Make Docker available, like the default gitpod image does # from https://github.com/gitpod-io/workspace-images/blob/main/chunks/tool-docker/Dockerfile @ 3f0988f2d06768d22d0aa1454ef0e963b0db65f3 From a325339c682a94907230fce49207af5ac91309ef Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Aug 2022 14:01:56 +0900 Subject: [PATCH 171/591] Doing some reviewer changes. --- src/sage/algebras/clifford_algebra.py | 134 +++++++++++++++++--------- 1 file changed, 87 insertions(+), 47 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index dfdafc49a06..2039f24780c 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -5,10 +5,12 @@ AUTHORS: - Travis Scrimshaw (2013-09-06): Initial version +- Trevor K. Karn (2022-07-27): Rewrite basis indexing using FrozenBitset """ #***************************************************************************** -# Copyright (C) 2013 Travis Scrimshaw +# Copyright (C) 2013-2022 Travis Scrimshaw +# (C) 2022 Trevor Karn # # 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 @@ -35,7 +37,6 @@ from sage.matrix.args import MatrixArgs from sage.sets.family import Family from sage.combinat.free_module import CombinatorialFreeModule -from sage.combinat.subset import Subsets from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.algebras.weyl_algebra import repr_from_monomials from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass @@ -400,7 +401,6 @@ def __call__(self, el): sage: E = ExteriorAlgebra(QQ, 7) sage: B = E.basis() """ - if not isinstance(el, Element): return self._element_constructor_(el) else: @@ -408,6 +408,8 @@ def __call__(self, el): def __init__(self, Qdim): r""" + Initialize ``self``. + EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices @@ -416,8 +418,6 @@ def __init__(self, Qdim): 7 sage: idx._cardinality 128 - sage: idx._maximal_set - 1111111 sage: i = idx.an_element(); i 0 sage: type(i) @@ -426,12 +426,13 @@ def __init__(self, Qdim): self._nbits = Qdim self._cardinality = 2**Qdim # the if statement here is in case Qdim is 0. - self._maximal_set = FrozenBitset('1'*self._nbits) if self._nbits else FrozenBitset('0') category = FiniteEnumeratedSets().Facade() Parent.__init__(self, category=category, facade=True) def _element_constructor_(self, x): r""" + Construct an element of ``self``. + EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices @@ -457,43 +458,79 @@ def _element_constructor_(self, x): def cardinality(self): r""" + Return the cardinality of ``self``. + EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices sage: idx = CliffordAlgebraIndices(7) sage: idx.cardinality() == 2^7 True + sage: len(idx) == 2^7 + True """ return self._cardinality + __len__ = cardinality + def _repr_(self): r""" + Return a string representation of ``self``. + EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices - sage: idx = CliffordAlgebraIndices(7); idx - Subsets of {1,2,...,7} - """ - return f"Subsets of {{1,2,...,{self._nbits}}}" + sage: CliffordAlgebraIndices(7) + Subsets of {0,1,...,6} + sage: CliffordAlgebraIndices(0) + Subsets of {} + sage: CliffordAlgebraIndices(1) + Subsets of {0} + sage: CliffordAlgebraIndices(2) + Subsets of {0,1} + """ + if self._nbits == 0: + return "Subsets of {}" + if self._nbits == 1: + return "Subsets of {0}" + if self._nbits == 2: + return "Subsets of {0,1}" + return f"Subsets of {{0,1,...,{self._nbits-1}}}" - def __len__(self): + def _latex_(self): r""" + Return a latex representation of ``self``. + EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices - sage: idx = CliffordAlgebraIndices(7); - sage: len(idx) == 2^7 - True - """ - return self._cardinality + sage: latex(CliffordAlgebraIndices(7)) + \mathcal{P}({0,1,\ldots,6}) + sage: latex(CliffordAlgebraIndices(0)) + \mathcal{P}(\emptyset) + sage: latex(CliffordAlgebraIndices(1)) + \mathcal{P}({0}) + sage: latex(CliffordAlgebraIndices(2)) + \mathcal{P}({0,1}) + """ + if self._nbits == 0: + return "\\mathcal{P}(\\emptyset)" + if self._nbits == 1: + return "\\mathcal{P}({0})" + if self._nbits == 2: + return "\\mathcal{P}({0,1})" + return f"\\mathcal{{P}}({{0,1,\\ldots,{self._nbits-1}}})" def __iter__(self): r""" + Iterate over ``self``. + EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices - sage: idx = CliffordAlgebraIndices(3); - sage: for i in idx: print(i) + sage: idx = CliffordAlgebraIndices(3) + sage: for i in idx: + ....: print(i) 0 1 01 @@ -505,28 +542,35 @@ def __iter__(self): """ import itertools n = self._nbits - yield FrozenBitset('0') + yield FrozenBitset() k = 1 while k <= n: for C in itertools.combinations(range(n), k): yield FrozenBitset(C) k += 1 - def __contains__(self, other): + def __contains__(self, elt): r""" + Check containment of ``elt`` in ``self``. + EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices sage: idx = CliffordAlgebraIndices(3); - sage: int(8) in idx # representing the set {4} + sage: int(8) in idx # representing the set {4} False + sage: int(5) in idx # representing the set {1,3} + True sage: FrozenBitset('1') in idx True + sage: FrozenBitset('000001') in idx + False """ - - if isinstance(other, int): - return (other < self._cardinality) and (other >= 0) - return self._maximal_set.issuperset(other) + if isinstance(elt, int): + return elt < self._cardinality and elt >= 0 + if not isinstance(elt, FrozenBitset): + return False + return elt.capacity() <= self._nbits class CliffordAlgebra(CombinatorialFreeModule): @@ -885,9 +929,9 @@ def _element_constructor_(self, x): if x in self.free_module(): R = self.base_ring() if x.parent().base_ring() is R: - return self.element_class(self, {FrozenBitset((i, )): c for i, c in x.items()}) + return self.element_class(self, {FrozenBitset((i,)): c for i, c in x.items()}) # if the base ring is different, attempt to coerce it into R - return self.element_class(self, {FrozenBitset((i, )): R(c) for i, c in x.items() if R(c) != R.zero()}) + return self.element_class(self, {FrozenBitset((i,)): R(c) for i, c in x.items() if R(c) != R.zero()}) if (isinstance(x, CliffordAlgebraElement) and self.has_coerce_map_from(x.parent())): @@ -918,7 +962,7 @@ def gen(self, i): sage: [Cl.gen(i) for i in range(3)] [x, y, z] """ - return self._from_dict({FrozenBitset((i, )): self.base_ring().one()}, remove_zeros=False) + return self._from_dict({FrozenBitset((i,)): self.base_ring().one()}, remove_zeros=False) def algebra_generators(self): """ @@ -975,7 +1019,7 @@ def one_basis(self): sage: Cl.one_basis() 0 """ - return FrozenBitset('0') + return FrozenBitset() def is_commutative(self): """ @@ -1657,7 +1701,7 @@ def _ascii_art_term(self, m): if len(m) == 0: return ascii_art('1') wedge = '/\\' - return ascii_art(*[repr(self.basis()[FrozenBitset((i, ))]) for i in m], sep=wedge) + return ascii_art(*[repr(self.basis()[FrozenBitset((i,))]) for i in m], sep=wedge) def _unicode_art_term(self, m): """ @@ -1929,7 +1973,7 @@ def coproduct_on_basis(self, a): one = self.base_ring().one() L = unshuffle_iterator(tuple(a), one) return self.tensor_square()._from_dict( - {tuple(FrozenBitset(e) if e else FrozenBitset('0') for e in t): c for t, c in L if c}, + {tuple(FrozenBitset(e) if e else FrozenBitset() for e in t): c for t, c in L if c}, coerce=False, remove_zeros=False) @@ -2452,7 +2496,7 @@ def __classcall__(cls, E, s_coeff): if isinstance(v, dict): R = E.base_ring() - v = E._from_dict({FrozenBitset((i, )): R(c) for i, c in v.items()}) + v = E._from_dict({FrozenBitset((i,)): R(c) for i, c in v.items()}) else: # Make sure v is in ``E`` v = E(v) @@ -2660,7 +2704,7 @@ def _on_basis(self, m): sage: E. = ExteriorAlgebra(QQ) sage: par = E.boundary({(0,1): z, (1,2): x, (2,0): y}) - sage: par._on_basis(FrozenBitset('0')) + sage: par._on_basis(FrozenBitset()) 0 sage: par._on_basis((0,)) 0 @@ -2679,12 +2723,12 @@ def _on_basis(self, m): s = E.zero() for b, (i, j) in enumerate(combinations(m, 2)): - t = Bitset(m) if (i, j) not in keys: continue + t = Bitset(m) t.discard(i) t.discard(j) - s += (-1)**b * sc[(i, j)] * E.monomial(FrozenBitset(t)) + s += sc[i, j] * E.term(FrozenBitset(t), (-1)**b) return s @@ -2763,10 +2807,7 @@ def chain_complex(self, R=None): mat = [] for b in basis: ret = self._on_basis(b) - try: - mat.append([ret.coefficient(p) for p in prev_basis]) - except AttributeError: # if ret is in E.base_ring() - mat.append([E.base_ring()(ret)]) + mat.append([ret.coefficient(p) for p in prev_basis]) data[deg] = Matrix(mat).transpose().change_ring(R) prev_basis = basis @@ -2906,7 +2947,6 @@ def __init__(self, E, s_coeff): zero = E.zero() B = E.basis() for k, v in dict(s_coeff).items(): - if k[0] > k[1]: # k will have length 2 k = sorted(k) v = -v @@ -2955,27 +2995,26 @@ def _on_basis(self, m): """ E = self.domain() cc = self._cos_coeff - keys = cc.keys() tot = E.zero() for sgn, i in enumerate(m): k = FrozenBitset((i,)) - if k in keys: - below = tuple(j for j in m if j < i) - above = tuple(j for j in m if j > i) + if k in cc: + below = tuple([j for j in m if j < i]) + above = tuple([j for j in m if j > i]) # a hack to deal with empty bitsets - if len(below) == 0: + if not below: below = E.one() else: below = E.monomial(FrozenBitset(below)) - if len(above) == 0: + if not above: above = E.one() else: above = E.monomial(FrozenBitset(above)) - tot = tot + (-1)**sgn * below * cc[k] * above + tot += (-1)**sgn * below * cc[k] * above return tot @@ -3062,3 +3101,4 @@ def chain_complex(self, R=None): basis = next_basis return ChainComplex(data, degree=1) + From 692f2f54b95bac1d9694ae571e3f3d9bf8102600 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Aug 2022 15:40:13 +0900 Subject: [PATCH 172/591] Fixing containment and reduction of exterior algebra ideals. --- src/sage/algebras/clifford_algebra.py | 107 +++++++++++++----- .../algebras/clifford_algebra_element.pyx | 2 +- .../algebras/exterior_algebra_groebner.pxd | 5 +- .../algebras/exterior_algebra_groebner.pyx | 59 +++++----- 4 files changed, 110 insertions(+), 63 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index f9f2e929fe3..dda85132dc7 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -80,15 +80,13 @@ def __init__(self, Qdim): 7 sage: idx._cardinality 128 - sage: idx._maximal_set - 1111111 sage: i = idx.an_element(); i 0 sage: type(i) """ self._nbits = Qdim - self._cardinality = 2**Qdim + self._cardinality = 2 ** Qdim # the if statement here is in case Qdim is 0. category = FiniteEnumeratedSets().Facade() Parent.__init__(self, category=category, facade=True) @@ -2599,9 +2597,24 @@ class ExteriorAlgebraIdeal(Ideal_nc): def __init__(self, ring, gens, coerce=True, side="twosided"): """ Initialize ``self``. + + EXAMPLES: + + We skip the category test because the ideals are not a proper + element class of the monoid of all ideals:: + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([x*y - x, x*y - 1]) + sage: TestSuite(I).run(skip="_test_category") + + sage: I = E.ideal([x*y - 3, 0, 2*3]) + sage: TestSuite(I).run(skip="_test_category") + + sage: I = E.ideal([]) + sage: TestSuite(I).run(skip="_test_category") """ self._groebner_strategy = None - self._homogeneous = all(x.is_super_homogeneous() for x in gens) + self._homogeneous = all(x.is_super_homogeneous() for x in gens if x) if self._homogeneous: side = "twosided" Ideal_nc.__init__(self, ring, gens, coerce, side) @@ -2620,6 +2633,11 @@ def reduce(self, f): x + y sage: I.reduce(x*y + x*y*z) 0 + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([a+b*c]) + sage: I.reduce(I.gen(0) * d) + 0 """ if self._groebner_strategy is None: self.groebner_basis() @@ -2680,6 +2698,31 @@ def __richcmp__(self, other, op): True sage: I <= E.ideal([x]) False + + sage: E. = ExteriorAlgebra(QQ) + sage: p = a + b*c + sage: IT = E.ideal([p], side="twosided") + sage: IR = E.ideal([p], side="right") + sage: IL = E.ideal([p], side="left") + sage: IR == IL + False + sage: IR <= IL + False + sage: IR >= IL + False + sage: IL.reduce(p * d) + 2*a*d + sage: IR.reduce(d * p) + -2*a*d + + sage: IR <= IT + True + sage: IL <= IT + True + sage: IT <= IL + False + sage: IT <= IR + False """ if not isinstance(other, ExteriorAlgebraIdeal): if op == op_EQ: @@ -2697,35 +2740,41 @@ def __richcmp__(self, other, op): elif op == op_GT: return other.__richcmp__(self, op_LT) - if self.side() == other.side(): - s_gens = set(g for g in self.gens() if g) - o_gens = set(g for g in other.gens() if g) - if set(s_gens) == set(o_gens): - return rich_to_bool(op, 0) - - contained = all(f in other for f in s_gens) - if op == op_LE: - return contained + s_gens = set(g for g in self.gens() if g) + o_gens = set(g for g in other.gens() if g) - contains = all(f in self for f in o_gens) - if op == op_EQ: - return contained and contains - if op == op_NE: - return not (contained and contains) - # remaining case < - return contained and not contains + if self.side() != other.side(): + if other.side() == "right": + X = set(t * f for t in self.ring().basis() for f in s_gens) + s_gens.update(X) + elif other.side() == "left": + X = set(f * t for t in self.ring().basis() for f in s_gens) + s_gens.update(X) + if set(s_gens) == set(o_gens): + return rich_to_bool(op, 0) - if op in [op_LT, op_LE] and other.side() == "twosided": - if not all(f in other for f in set(self.gens()) if f): - return False - if op == op_LE: - return True - return self.__richcmp__(other, op_NE) + contained = all(f in other for f in s_gens) + if op == op_LE: + return contained + if op == op_NE and not contained: + return True - # Otherwise we will fallback to linear algebra containment - # TODO: Implement this - return NotImplemented + if self.side() != other.side(): + if self.side() == "right": + X = set(t * f for t in self.ring().basis() for f in o_gens) + s_gens.update(X) + elif self.side() == "left": + X = set(f * t for t in self.ring().basis() for f in o_gens) + s_gens.update(X) + + contains = all(f in self for f in o_gens) + if op == op_EQ: + return contained and contains + if op == op_NE: + return not (contained and contains) + # remaining case < + return contained and not contains def groebner_basis(self, term_order="neglex"): r""" diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index 0c35b57d983..ba2d89b880d 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -8,7 +8,7 @@ AUTHORS: """ #***************************************************************************** -# Copyright (C) 2022 Trevor Karn +# Copyright (C) 2022 Trevor K. Karn # (C) 2022 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd index 4e235dae6ef..37ac62d08cc 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pxd +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -17,6 +17,7 @@ cdef class GroebnerStrategy: cdef int side cdef MonoidElement ideal cdef bint homogeneous + cdef Integer rank cdef public tuple groebner_basis cdef inline bint build_S_poly(self, CliffordAlgebraElement f, CliffordAlgebraElement g) @@ -39,8 +40,8 @@ cdef class GroebnerStrategyNegLex(GroebnerStrategy): pass cdef class GroebnerStrategyDegRevLex(GroebnerStrategy): - cdef Integer rank + pass cdef class GroebnerStrategyDegLex(GroebnerStrategy): - cdef Integer rank + pass diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index d76f797bbe8..771af149931 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -6,11 +6,11 @@ of exterior algebra. AUTHORS: -- Trevor Karn, Travis Scrimshaw (July 2022): Initial implementation +- Trevor K. Karn, Travis Scrimshaw (July 2022): Initial implementation """ #***************************************************************************** -# Copyright (C) 2022 Trevor Karn +# Copyright (C) 2022 Trevor K. Karn # (C) 2022 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -53,7 +53,8 @@ cdef class GroebnerStrategy: self.ideal = I self.groebner_basis = (None,) self.E = I.ring() - self.homogeneous = all(x.is_super_homogeneous() for x in I.gens()) + self.homogeneous = I._homogeneous + self.rank = Integer(self.E.ngens()) if self.homogeneous or I.side() == "left": self.side = 0 elif I.side() == "right": @@ -120,25 +121,24 @@ cdef class GroebnerStrategy: Perform the preprocessing step. """ cdef CliffordAlgebraElement f, g, f0, f1 + cdef set additions cdef set L = set() - if self.side == 0: + if self.side == 1: for f0, f1 in P: if self.build_S_poly(f0, f1): - L.add(self.partial_S_poly_left(f0, f1)) - L.add(self.partial_S_poly_left(f1, f0)) - elif self.side == 1: - for f0, f1 in P: - if self.build_S_poly(f0, f1): - L.add(self.partial_S_poly_right(f0, f1) for f0,f1 in P) - L.add(self.partial_S_poly_right(f1, f0) for f0,f1 in P) - if self.side == 2: + L.add(self.partial_S_poly_right(f0, f1)) + L.add(self.partial_S_poly_right(f1, f0)) + else: # We compute a left Gröbner basis for two-sided ideals for f0, f1 in P: if self.build_S_poly(f0, f1): L.add(self.partial_S_poly_left(f0, f1)) L.add(self.partial_S_poly_left(f1, f0)) - L.add(self.partial_S_poly_right(f0, f1)) - L.add(self.partial_S_poly_right(f1, f0)) + + if self.side == 2 and not self.homogeneous: + # Add in all S-poly times positive degree monomials + additions = set(f * t for t in self.E.basis() for f in L) + L.update(f for f in additions if f) cdef set done = set(self.leading_supp(f) for f in L) cdef set monL = set() @@ -168,7 +168,7 @@ cdef class GroebnerStrategy: cdef set L = self.preprocessing(P, G) cdef Py_ssize_t i from sage.matrix.constructor import matrix - r = 2 ** self.E.ngens() - 1 # r for "rank" or "reverso" + cdef Integer r = Integer(2) ** self.rank - Integer(1) # r for "rank" or "reverso" M = matrix({(i, r - self.bitset_to_int( m)): c for i,f in enumerate(L) for m,c in ( f)._monomial_coefficients.items()}, @@ -186,18 +186,29 @@ cdef class GroebnerStrategy: EXAMPLES:: sage: E. = ExteriorAlgebra(QQ) - sage: I = E.ideal([x*y - x, x*y -1]) + sage: I = E.ideal([x*y - x, x*y - 1], side="left") sage: I.groebner_basis() (1,) - sage: J = E.ideal([x*y - x, 2*x*y - 2]) + sage: J = E.ideal([x*y - x, 2*x*y - 2], side="left") sage: J.groebner_basis() (1,) + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([a+b*c]) + sage: I.groebner_basis() + (b*c + a, a*c, a*b, a*d) """ cdef FrozenBitset p0, p1 cdef long deg cdef Py_ssize_t i, j, k + cdef set additions cdef list G = [f for f in self.ideal.gens() if f] # Remove 0s + if self.side == 2 and not self.homogeneous: + # Add in all S-poly times positive degree monomials + additions = set(f * t for t in self.E.basis() for f in G) + G.extend(f for f in additions if f) + cdef Py_ssize_t n = len(G) cdef dict P = {} cdef list Gp @@ -401,13 +412,6 @@ cdef class GroebnerStrategyDegRevLex(GroebnerStrategy): """ Gröbner basis strategy implementing degree revlex ordering. """ - def __init__(self, I): - """ - Initialize ``self``. - """ - GroebnerStrategy.__init__(self, I) - self.rank = Integer(self.E.ngens()) - cdef inline Integer bitset_to_int(self, FrozenBitset X): """ Convert ``X`` to an :class:`Integer`. @@ -451,13 +455,6 @@ cdef class GroebnerStrategyDegLex(GroebnerStrategy): """ Gröbner basis strategy implementing degree lex ordering. """ - def __init__(self, I): - """ - Initialize ``self``. - """ - GroebnerStrategy.__init__(self, I) - self.rank = Integer(self.E.ngens()) - cdef inline Integer bitset_to_int(self, FrozenBitset X): """ Convert ``X`` to an :class:`Integer`. From 20dd21c71db7e4ccea149e9caa89f36e831c24c4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Aug 2022 16:21:15 +0900 Subject: [PATCH 173/591] Allowing L * R nc ideals. --- src/sage/rings/noncommutative_ideals.pyx | 43 ++++++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/noncommutative_ideals.pyx b/src/sage/rings/noncommutative_ideals.pyx index af446f23663..70039b238c9 100644 --- a/src/sage/rings/noncommutative_ideals.pyx +++ b/src/sage/rings/noncommutative_ideals.pyx @@ -337,14 +337,26 @@ class Ideal_nc(Ideal_generic): return self.__side def __mul__(self, other): - """ + r""" + Multiply ``self`` with ``other``. + Multiplication of a one-sided ideal with its ring from the other side yields a two-sided ideal. + Let `L` (resp. `R`) be a left (resp. right) ideal, then the product + `LR` is a twosided ideal generated by `x y`, where `x` (resp. `y`) + is a generator of `L` (resp. `R`). + + .. TODO:: + + The product of left (resp. right) ideals is a left + (resp. right) ideal. However, these do not necessarily have + simple generating sets. + TESTS:: sage: MS = MatrixSpace(QQ,2,2) - sage: IL = MS*[2*MS.0,3*MS.1]; IL + sage: IL = MS * [2*MS.0,3*MS.1]; IL Left Ideal ( [2 0] @@ -361,7 +373,7 @@ class Ideal_nc(Ideal_generic): [0 1] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: IL*MS # indirect doctest + sage: IL * MS Twosided Ideal ( [2 0] @@ -371,12 +383,27 @@ class Ideal_nc(Ideal_generic): [0 0] ) of Full MatrixSpace of 2 by 2 dense matrices over Rational Field - sage: IR*IR + + sage: IL * IR + Twosided Ideal + ( + [0 3] + [0 0] + ) + of Full MatrixSpace of 2 by 2 dense matrices over Rational Field + + sage: IR * IR Traceback (most recent call last): ... - NotImplementedError: Cannot multiply non-commutative ideals. - + NotImplementedError: cannot multiply non-commutative ideals """ + if isinstance(other, Ideal_nc) and self.ring() == other.ring(): + if (self.side() == "left" and other.side() == "right" + or self.side() == other.side() == "twosided"): + gens = [z for z in (x * y for x in self.gens() for y in other.gens()) if z] + return self.ring().ideal(gens, side='twosided') + raise NotImplementedError("cannot multiply non-commutative ideals") + if not isinstance(other, Ideal_nc): # Perhaps other is a ring and thus has its own # multiplication. @@ -390,4 +417,6 @@ class Ideal_nc(Ideal_generic): if other.side() == 'left': return other return other.ring().ideal(other.gens(), side='twosided') - raise NotImplementedError("Cannot multiply non-commutative ideals.") + + raise NotImplementedError("cannot multiply non-commutative ideals") + From 6c92f180c49697fac6d2d85013cbc4da58b405e1 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Aug 2022 17:06:29 +0900 Subject: [PATCH 174/591] Implementing multiplication of exterior algebra ideals. --- src/sage/algebras/clifford_algebra.py | 72 +++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index dda85132dc7..88046a341a7 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2776,6 +2776,78 @@ def __richcmp__(self, other, op): # remaining case < return contained and not contains + def __mul__(self, other): + """ + Return the product of ``self`` with ``other``. + + .. WARNING:: + + If ``self`` is a right ideal and ``other`` is a left ideal, + this returns a submodule rather than an ideal. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + + sage: I = E.ideal([a + 1], side="left") + sage: J = I * I; J + Left Ideal (2*a + 1, a, b, c, d, a*b, a*c, a*d, 2*a*b*c + b*c, 2*a*b*d + b*d, + 2*a*c*d + c*d, a*b*c, a*b*d, a*c*d, b*c*d, a*b*c*d) + of The exterior algebra of rank 4 over Rational Field + sage: J.groebner_basis() + (1,) + sage: I.gen(0)^2 + 2*a + 1 + + sage: J = E.ideal([b+c]) + sage: I * J + Twosided Ideal (a*b + a*c + b + c) of The exterior algebra of rank 4 over Rational Field + sage: J * I + Left Ideal (-a*b - a*c + b + c) of The exterior algebra of rank 4 over Rational Field + + sage: K = J * I + sage: K + Left Ideal (-a*b - a*c + b + c) of The exterior algebra of rank 4 over Rational Field + sage: E.ideal([J.gen(0) * d * I.gen(0)], side="left") <= K + True + + sage: J = E.ideal([b + c*d], side="right") + sage: I * J + Twosided Ideal (a*c*d + a*b + c*d + b) of The exterior algebra of rank 4 over Rational Field + sage: X = J * I; X + Free module generated by {0, 1, 2, 3, 4, 5, 6, 7} over Rational Field + sage: [X.lift(b) for b in X.basis()] + [c*d + b, -a*c*d + a*b, b*c, b*d, a*b*c, a*b*d, b*c*d, a*b*c*d] + sage: p = X.lift(X.basis()[0]) + sage: p + c*d + b + sage: a * p # not a left ideal + a*c*d + a*b + + sage: I = E.ideal([a + 1], side="right") + sage: E.ideal([1]) * I + Twosided Ideal (a + 1) of The exterior algebra of rank 4 over Rational Field + sage: I * E.ideal([1]) + Right Ideal (a + 1) of The exterior algebra of rank 4 over Rational Field + """ + if not isinstance(other, ExteriorAlgebraIdeal) or self.ring() != other.ring(): + return super().__mul__(other) + + if self._homogeneous or other._homogeneous or (self.side() == "left" and other.side() == "right"): + gens = (x * y for x in self.gens() for y in other.gens()) + else: + gens = (x * t * y for t in self.ring().basis() for x in self.gens() for y in other.gens()) + gens = [z for z in gens if z] + + if self.side() == "right" and other.side() == "left": + return self.ring().submodule(gens) + + if self.side() == "left" or self.side() == "twosided": + if other.side() == "right" or other.side() == "twosided": + return self.ring().ideal(gens, side="twosided") + return self.ring().ideal(gens, side="left") + return self.ring().ideal(gens, side="right") + def groebner_basis(self, term_order="neglex"): r""" Return the reduced Gröbner basis of ``self``. From 698e051b3e7a8775a2146839110464ecb322d808 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 2 Aug 2022 17:22:21 +0900 Subject: [PATCH 175/591] Some last details for pyflakes and full coverage. --- src/sage/algebras/clifford_algebra.py | 13 ++++++- .../algebras/clifford_algebra_element.pyx | 13 +++++++ .../algebras/exterior_algebra_groebner.pyx | 34 +++++++++++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 88046a341a7..0969856f4c6 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -19,7 +19,6 @@ #***************************************************************************** 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 import Parent from sage.structure.element import Element @@ -30,6 +29,7 @@ from sage.algebras.clifford_algebra_element import CliffordAlgebraElement, ExteriorAlgebraElement from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis +from sage.categories.fields import Fields from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.modules.with_basis.morphism import ModuleMorphismByLinearity from sage.categories.poor_man_map import PoorManMap @@ -2905,7 +2905,18 @@ def groebner_basis(self, term_order="neglex"): returns: o3 = | bcd-bce+bde-cde acd-ace+ade-cde abd-abe+ade-bde abc-abe+ace-bce | + + TESTS:: + + sage: E. = ExteriorAlgebra(ZZ) + sage: I = E.ideal([a+1, b*c+d]) + sage: I.groebner_basis() + Traceback (most recent call last): + ... + NotImplementedError: only implemented over fields """ + if self.ring().base_ring() not in Fields(): + raise NotImplementedError("only implemented over fields") if term_order == "neglex": from sage.algebras.exterior_algebra_groebner import GroebnerStrategyNegLex as strategy elif term_order == "degrevlex": diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index ba2d89b880d..ac74f313f76 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -392,6 +392,19 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): - ``I`` -- a list of exterior algebra elements or an ideal - ``left`` -- boolean; if reduce as a left ideal (``True``) or right ideal (``False``), ignored if ``I`` is an ideal + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: f = (a + b*c) * d + sage: f.reduce([a + b*c], True) + 2*a*d + sage: f.reduce([a + b*c], False) + 0 + + sage: I = E.ideal([a + b*c]) + sage: f.reduce(I) + 0 """ from sage.algebras.clifford_algebra import ExteriorAlgebraIdeal if isinstance(I, ExteriorAlgebraIdeal): diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 771af149931..3cd7cf3911e 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -49,6 +49,14 @@ cdef class GroebnerStrategy: def __init__(self, I): """ Initialize ``self``. + + EXAMPLES:: + + sage: from sage.algebras.exterior_algebra_groebner import GroebnerStrategy + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([a + 1], side="left") + sage: G = GroebnerStrategy(I) + sage: TestSuite(G).run(skip="_test_pickling") """ self.ideal = I self.groebner_basis = (None,) @@ -187,15 +195,15 @@ cdef class GroebnerStrategy: sage: E. = ExteriorAlgebra(QQ) sage: I = E.ideal([x*y - x, x*y - 1], side="left") - sage: I.groebner_basis() + sage: I.groebner_basis() # indirect doctest (1,) sage: J = E.ideal([x*y - x, 2*x*y - 2], side="left") - sage: J.groebner_basis() + sage: J.groebner_basis() # indirect doctest (1,) sage: E. = ExteriorAlgebra(QQ) sage: I = E.ideal([a+b*c]) - sage: I.groebner_basis() + sage: I.groebner_basis() # indirect doctest (b*c + a, a*c, a*b, a*d) """ cdef FrozenBitset p0, p1 @@ -264,6 +272,26 @@ cdef class GroebnerStrategy: cpdef CliffordAlgebraElement reduce(self, CliffordAlgebraElement f): """ Reduce ``f`` modulo the ideal with Gröbner basis ``G``. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: rels = [c*d*e - b*d*e + b*c*e - b*c*d, + ....: c*d*e - a*d*e + a*c*e - a*c*d, + ....: b*d*e - a*d*e + a*b*e - a*b*d, + ....: b*c*e - a*c*e + a*b*e - a*b*c, + ....: b*c*d - a*c*d + a*b*d - a*b*c] + sage: I = E.ideal(rels) + sage: I.reduce(a*b*e) + a*b*e + sage: I.reduce(b*d*e) + a*b*d - a*b*e + a*d*e + sage: I.reduce(c*d*e) + a*c*d - a*c*e + a*d*e + sage: I.reduce(a*b*c*d*e) + 0 + sage: I.reduce(a*b*c*d) + 0 """ for g in self.groebner_basis: f = self.reduce_single(f, g) From 7261907e2bf1d83bf659972d3a2296a97fca720e Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Wed, 3 Aug 2022 02:06:34 -0600 Subject: [PATCH 176/591] added tests for algorithm='rho' --- src/sage/groups/generic.py | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 5972c8485f9..44987d6b3c7 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -791,6 +791,50 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: discrete_log(u,g) 123456789 + The above examples also work when the 'rho' algorithm is used:: + + sage: b = Mod(2,37); a = b^20 + sage: discrete_log(a, b, algorithm='rho') + 20 + sage: b = Mod(2,997); a = b^20 + sage: discrete_log(a, b, algorithm='rho') + 20 + + sage: K = GF(3^6,'b') + sage: b = K.gen() + sage: a = b^210 + sage: discrete_log(a, b, K.order()-1, algorithm='rho') + 210 + + sage: b = Mod(1,37); x = Mod(2,37) + sage: discrete_log(x, b, algorithm='rho') + Traceback (most recent call last): + ... + ValueError: no discrete log of 2 found to base 1 + sage: b = Mod(1,997); x = Mod(2,997) + sage: discrete_log(x, b, algorithm='rho') + Traceback (most recent call last): + ... + ValueError: no discrete log of 2 found to base 1 + + sage: F=GF(37^2,'a') + sage: E=EllipticCurve(F,[1,1]) + sage: F.=GF(37^2,'a') + sage: E=EllipticCurve(F,[1,1]) + sage: P=E(25*a + 16 , 15*a + 7 ) + sage: P.order() + 672 + sage: Q=39*P; Q + (36*a + 32 : 5*a + 12 : 1) + sage: discrete_log(Q,P,P.order(),operation='+',algorithm='rho') + 39 + + sage: F. = GF(2^63) + sage: g = F.gen() + sage: u = g**123456789 + sage: discrete_log(u,g,algorithm='rho') + 123456789 + AUTHORS: - William Stein and David Joyner (2005-01-05) From 0a33cf3eea05987efead158510b8bbd34d42c48c Mon Sep 17 00:00:00 2001 From: dcoudert Date: Wed, 3 Aug 2022 16:53:08 +0200 Subject: [PATCH 177/591] trac #34211: reduce verbosity of some doctests --- src/sage/graphs/isgci.py | 59 ++++++++-------------------------------- 1 file changed, 12 insertions(+), 47 deletions(-) diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index 2319df40fe2..294c905d225 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -55,30 +55,13 @@ ------------------------- id : gc_32 name : chordal - type : base - + ... Problems : ----------- 3-Colourability : Linear Clique : Polynomial Clique cover : Polynomial - Cliquewidth : Unbounded - Cliquewidth expression : NP-complete - Colourability : Linear - Cutwidth : NP-complete - Domination : NP-complete - Feedback vertex set : Polynomial - Hamiltonian cycle : NP-complete - Hamiltonian path : NP-complete - Independent set : Linear - Maximum bisection : Unknown - Maximum cut : NP-complete - Minimum bisection : Unknown - Recognition : Linear - Treewidth : Polynomial - Weighted clique : Polynomial - Weighted feedback vertex set : Unknown - Weighted independent set : Linear + ... It is possible to obtain the complete list of the classes stored in ISGCI by calling the :meth:`~GraphClasses.show_all` method (beware -- long output):: @@ -637,30 +620,15 @@ def description(self): ------------------------- id : gc_32 name : chordal - type : base - + ... Problems : ----------- 3-Colourability : Linear Clique : Polynomial Clique cover : Polynomial - Cliquewidth : Unbounded - Cliquewidth expression : NP-complete - Colourability : Linear - Cutwidth : NP-complete - Domination : NP-complete - Feedback vertex set : Polynomial - Hamiltonian cycle : NP-complete - Hamiltonian path : NP-complete - Independent set : Linear - Maximum bisection : Unknown - Maximum cut : NP-complete - Minimum bisection : Unknown + ... Recognition : Linear - Treewidth : Polynomial - Weighted clique : Polynomial - Weighted feedback vertex set : Unknown - Weighted independent set : Linear + ... """ classes = GraphClasses().classes() cls = classes[self._gc_id] @@ -737,7 +705,7 @@ def classes(self): sage: type(t) <... 'dict'> sage: sorted(t["gc_151"].keys()) - ['id', 'name', 'problem', 'type'] + ['id', 'name',... 'problem',... 'type'] sage: t["gc_151"]['name'] 'cograph' sage: t["gc_151"]['problem']['Clique'] @@ -780,16 +748,14 @@ def smallgraphs(self): EXAMPLES:: sage: t = graph_classes.smallgraphs() - sage: t - {'2C_4': Graph on 8 vertices, - '2K_2': Graph on 4 vertices, - '2K_3': Graph on 6 vertices, - '2K_3 + e': Graph on 6 vertices, - '2K_4': Graph on 8 vertices, - '2P_3': Graph on 6 vertices, - ... + sage: t['2C_4'] + Graph on 8 vertices + sage: t['2K_3 + e'] + Graph on 6 vertices sage: t['fish'] Graph on 6 vertices + sage: t['bull'] + Graph on 5 vertices """ self._get_ISGCI() return self.smallgraphs() @@ -1041,7 +1007,6 @@ def _XML_to_dict(root): ------------------------- id : gc_56 name : perfect - type : base ... """ ans = root.attrib.copy() From eb839d4775e208ab0ee64f5380cb80ed68664a8c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 3 Aug 2022 14:22:11 -0700 Subject: [PATCH 178/591] .gitpod.yml: Use $(pwd) to refer to the workspace dir --- .gitpod.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitpod.yml b/.gitpod.yml index 6017bd072e8..fcd6027c88d 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -9,8 +9,8 @@ tasks: # Create conda environment ./bootstrap-conda mamba env create --file src/environment-dev.yml --prefix venv - conda config --append envs_dirs /workspace/sagetrac-mirror - conda activate /workspace/sagetrac-mirror/venv + conda config --append envs_dirs $(pwd) + conda activate $(pwd)/venv # Build sage ./bootstrap @@ -20,8 +20,8 @@ tasks: command: | # Activate conda environment - conda config --append envs_dirs /workspace/sagetrac-mirror - conda activate /workspace/sagetrac-mirror/venv + conda config --append envs_dirs $(pwd) + conda activate $(pwd)/venv # RestructuredText extension recommends python extension, although we have already installed it ## So disable the recommendation dialog From de3e0f3d5d405ef0f255aaf6d9934f86c72fcca7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 3 Aug 2022 17:14:50 -0700 Subject: [PATCH 179/591] build/pkgs/openssl/distros/opensuse.txt: Use libopenssl-3-devel --- build/pkgs/openssl/distros/opensuse.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/openssl/distros/opensuse.txt b/build/pkgs/openssl/distros/opensuse.txt index 196ba2d1153..11344b31a10 100644 --- a/build/pkgs/openssl/distros/opensuse.txt +++ b/build/pkgs/openssl/distros/opensuse.txt @@ -1 +1 @@ -"pkgconfig(libssl)" +libopenssl-3-devel From d46f190b83388be070d53a105c0b8bd5ba31695f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 3 Aug 2022 17:32:51 -0700 Subject: [PATCH 180/591] build/pkgs/openssl/spkg-configure.m4: Add API check from python3 configure.ac --- build/pkgs/openssl/spkg-configure.m4 | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/build/pkgs/openssl/spkg-configure.m4 b/build/pkgs/openssl/spkg-configure.m4 index 2862d7ebec0..fd2d257d721 100644 --- a/build/pkgs/openssl/spkg-configure.m4 +++ b/build/pkgs/openssl/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([openssl], [ AX_CHECK_OPENSSL([ - AC_MSG_CHECKING([whether OpenSSL >= 1.1.1, as required by PEP 644]) + AC_MSG_CHECKING([whether OpenSSL >= 1.1.1, as required by PEP 644, and provides required APIs]) AC_COMPILE_IFELSE( dnl Trac #32580: Need OpenSSL >= 1.1.1 for PEP 644 dnl From https://www.openssl.org/docs/man3.0/man3/OPENSSL_VERSION_NUMBER.html: @@ -12,12 +12,33 @@ SAGE_SPKG_CONFIGURE([openssl], [ dnl FF is "fix" dnl S is "status" (f = release) dnl -> OPENSSL_VERSION_NUMBER is 0xMNNFFPPSL + dnl + dnl Trac #34273: Test program from ​https://github.com/python/cpython/blob/3.10/configure.ac#L5845 [AC_LANG_PROGRAM([[ + #include + #include #include #if OPENSSL_VERSION_NUMBER < 0x10101000L - # error OpenSSL >= 1.1.1 is required according to PEP 644 + #error OpenSSL >= 1.1.1 is required according to PEP 644 #endif - ]], [])], [ + static void keylog_cb(const SSL *ssl, const char *line) {} + ]], [[ + /* SSL APIs */ + SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); + SSL_CTX_set_keylog_callback(ctx, keylog_cb); + SSL *ssl = SSL_new(ctx); + X509_VERIFY_PARAM *param = SSL_get0_param(ssl); + X509_VERIFY_PARAM_set1_host(param, "python.org", 0); + SSL_free(ssl); + SSL_CTX_free(ctx); + /* hashlib APIs */ + OBJ_nid2sn(NID_md5); + OBJ_nid2sn(NID_sha1); + OBJ_nid2sn(NID_sha3_512); + OBJ_nid2sn(NID_blake2b512); + EVP_PBE_scrypt(NULL, 0, NULL, 0, 2, 8, 1, 0, NULL, 0); + ]]) + ], [ AC_MSG_RESULT([yes]) sage_spkg_install_openssl=no ], [ From 4fc0dd32deb00bc3823458400fb9ce3fb92098ac Mon Sep 17 00:00:00 2001 From: Amritanshu Prasad Date: Thu, 4 Aug 2022 14:04:35 +0530 Subject: [PATCH 181/591] fixed typo on line 346 --- src/sage/interfaces/r.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 565d6a1da93..f096002d0bb 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -343,7 +343,7 @@ def _setup_r_to_sage_converter(): sage: r.options(width="60").sage() # optional - rpy2 {'DATA': {'width': 60}, '_Names': 'width'} - The conversion can handle "not a number", infintiy, imaginary values and + The conversion can handle "not a number", infinity, imaginary values and missing values:: sage: r(-17).sqrt().sage() # optional - rpy2 From 736d44825f37dc0add60118e89da1964aaf89e1b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 4 Aug 2022 18:45:03 +0900 Subject: [PATCH 182/591] Moving the main computation to be done on demand. --- src/sage/homology/free_resolution.pyx | 286 +++++++++++++++--------- src/sage/homology/graded_resolution.pyx | 90 +++++--- 2 files changed, 232 insertions(+), 144 deletions(-) diff --git a/src/sage/homology/free_resolution.pyx b/src/sage/homology/free_resolution.pyx index be084842b45..dd29690ec6b 100644 --- a/src/sage/homology/free_resolution.pyx +++ b/src/sage/homology/free_resolution.pyx @@ -1,24 +1,24 @@ -""" +r""" Free resolutions The :class:`FreeResolution` implements a finite free resolution, which is a chain complex of free modules, terminating with a zero module at the end, whose homology groups are all zero. -The class is intended to be subclassed for finite free resolutions in different -subject areas. Thus :meth:`_repr_module` may be overrided by a subclass. See -Examples below. EXAMPLES:: - sage: from sage.homology.free_resolution import FreeResolution_generic + sage: from sage.homology.free_resolution import FreeResolution sage: S. = PolynomialRing(QQ) - sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) + sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) - sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: r = FreeResolution(m1, name='S') sage: r S^1 <-- S^3 <-- S^2 <-- 0 + sage: FreeResolution(m2, name='S') + S^2 <-- S^6 <-- S^5 <-- 0 + :: sage: from sage.homology.graded_resolution import GradedFreeResolution @@ -58,7 +58,6 @@ An example of a minimal free resolution from [CLO2005]_:: AUTHORS: - Kwankyu Lee (2022-05-13): initial version - """ # **************************************************************************** @@ -77,9 +76,11 @@ from sage.libs.singular.function cimport Resolution, new_sage_polynomial, access from sage.libs.singular.function import singular_function from sage.structure.sequence import Sequence, Sequence_generic from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.matrix.constructor import matrix as _matrix from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense from sage.modules.free_module_element import vector +from sage.modules.free_module import FreeModule from sage.modules.free_module import Module_free_ambient from sage.rings.integer_ring import ZZ from sage.rings.ideal import Ideal_generic @@ -88,14 +89,8 @@ from sage.structure.sage_object import SageObject class FreeResolution_generic(SageObject): - """ - Base class of free resolutions. - - INPUT: - - - ``base_ring`` -- a ring - - - ``maps`` -- list of matrices over the base ring + r""" + Abstract base class of finite free resolutions. The matrix at index `i` in the list defines the differential map from `(i+1)`-th free module to the `i`-th free module over the base ring by @@ -104,22 +99,10 @@ class FreeResolution_generic(SageObject): define the ranks of the free modules in the resolution. Note that the first matrix in the list defines the differential map at - homological index `1`. A subclass can define ``_initial_differential`` - attribute that contains the `0`-th differential map whose codomain is the - target of the free resolution. + homological index `1`. EXAMPLES:: - sage: from sage.homology.free_resolution import FreeResolution_generic - sage: S. = PolynomialRing(QQ) - sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) - sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) - sage: r = FreeResolution_generic(S, [m1, m2], name='S') - sage: r - S^1 <-- S^3 <-- S^2 <-- 0 - - :: - sage: from sage.homology.free_resolution import FreeResolution sage: P. = PolynomialRing(QQ) sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) @@ -135,25 +118,49 @@ class FreeResolution_generic(SageObject): [ y*z - x*w] [-y^2 + x*z] """ - def __init__(self, base_ring, maps, name='F'): + def __init__(self, base_ring, name='F'): """ Initialize. + Subclasses must provide a ``_maps`` attribute that contains the + maps defining the resolution. + + A subclass can define ``_initial_differential`` attribute that + contains the `0`-th differential map whose codomain is the target + of the free resolution. + + INPUT: + + - ``base_ring`` -- a ring + TESTS:: - sage: from sage.homology.free_resolution import FreeResolution_generic + sage: from sage.homology.free_resolution import FreeResolution sage: S. = PolynomialRing(QQ) sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) - sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) - sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: r = FreeResolution(m1, name='S') sage: TestSuite(r).run(skip=['_test_pickling']) """ - self.__base_ring = base_ring - self.__maps = maps - self.__name = name - self.__length = len(maps) + self._base_ring = base_ring + self._name = name + + @lazy_attribute + def _length(self): + """ + The length of ``self``. + + TESTS:: - def __repr__(self): + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r._length + 2 + """ + return len(self._maps) + + def _repr_(self): """ Return the string form of this resolution. @@ -171,13 +178,13 @@ class FreeResolution_generic(SageObject): S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 """ s = self._repr_module(0) - for i in range(1, self.__length + 1): + for i in range(1, self._length + 1): s += ' <-- ' + self._repr_module(i) s += ' <-- 0' return s def _repr_module(self, i): - """ + r""" Return the string form of the `i`-th free module. INPUT: @@ -186,30 +193,31 @@ class FreeResolution_generic(SageObject): EXAMPLES:: - sage: from sage.homology.free_resolution import FreeResolution_generic + sage: from sage.homology.free_resolution import FreeResolution sage: S. = PolynomialRing(QQ) - sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]) - sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) - sage: r = FreeResolution_generic(S, [m1, m2], name='S') + sage: m = matrix(S, 1, [y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(m.transpose(), name='S') + sage: r._repr_module(2) + 'S^2' sage: r # indirect doctest S^1 <-- S^3 <-- S^2 <-- 0 """ if i == 0: - r = self.__maps[0].nrows() - s = f'{self.__name}^{r}' + r = self._maps[0].nrows() + s = f'{self._name}^{r}' return s - elif i > self.__length: + elif i > self._length: s = '0' else: - r = self.__maps[i - 1].ncols() + r = self._maps[i - 1].ncols() if r > 0: - s = f'{self.__name}^{r}' + s = f'{self._name}^{r}' else: s = '0' return s def __len__(self): - """ + r""" Return the length of this resolution. The length of a free resolution is the index of the last nonzero free module. @@ -225,11 +233,11 @@ class FreeResolution_generic(SageObject): sage: len(r) 2 """ - return self.__length + return len(self._maps) def __getitem__(self, i): - """ - Return the `i`-th free module of this resolution. + r""" + Return the ``i``-th free module of this resolution. INPUT: @@ -253,17 +261,17 @@ class FreeResolution_generic(SageObject): """ if i < 0: raise IndexError('invalid index') - elif i > self.__length: - F = (self.__base_ring)**0 - elif i == self.__length: - F = (self.__base_ring)**(self.__maps[i - 1].ncols()) + elif i > self._length: + F = FreeModule(self._base_ring, 0) + elif i == self._length: + F = FreeModule(self._base_ring, self._maps[i - 1].ncols()) else: - F = (self.__base_ring)**(self.__maps[i].nrows()) + F = FreeModule(self._base_ring, self._maps[i].nrows()) return F def differential(self, i): - """ - Return the matrix representing the `i`-th differential map. + r""" + Return the matrix representing the ``i``-th differential map. INPUT: @@ -318,23 +326,23 @@ class FreeResolution_generic(SageObject): return self._initial_differential except AttributeError: raise ValueError('0th differential map undefined') - elif i == self.__length + 1: - s = (self.__base_ring)**0 - t = (self.__base_ring)**(self.__maps[i - 2].ncols()) + elif i == self._length + 1: + s = FreeModule(self._base_ring, 0) + t = FreeModule(self._base_ring, self._maps[i - 2].ncols()) m = s.hom(0, t) - elif i > self.__length + 1: - s = (self.__base_ring)**0 - t = (self.__base_ring)**0 + elif i > self._length + 1: + s = FreeModule(self._base_ring, 0) + t = FreeModule(self._base_ring, 0) m = s.hom(0, t) else: - s = (self.__base_ring)**(self.__maps[i - 1].ncols()) - t = (self.__base_ring)**(self.__maps[i - 1].nrows()) - m = s.hom(self.__maps[i - 1], t, side='right') + s = FreeModule(self._base_ring, self._maps[i - 1].ncols()) + t = FreeModule(self._base_ring, self._maps[i - 1].nrows()) + m = s.hom(self._maps[i - 1], t, side='right') return m def target(self): - """ - Return the codomain of the 0-th differential map. + r""" + Return the codomain of the ``0``-th differential map. EXAMPLES:: @@ -355,8 +363,8 @@ class FreeResolution_generic(SageObject): return self.differential(0).codomain() def matrix(self, i): - """ - Return the matrix representing the `i`-th differential map. + r""" + Return the matrix representing the ``i``-th differential map. INPUT: @@ -380,14 +388,14 @@ class FreeResolution_generic(SageObject): [z^2 - y*w y*z - x*w y^2 - x*z] """ if i <= 0: - raise IndexError(f'invalid index') - elif i <= self.__length: - return self.__maps[i - 1] + raise IndexError('invalid index') + elif i <= self._length: + return self._maps[i - 1] else: return self.differential(i).matrix() def chain_complex(self): - """ + r""" Return this resolution as a chain complex. A chain complex in Sage has its own useful methods. @@ -406,22 +414,20 @@ class FreeResolution_generic(SageObject): """ from sage.homology.chain_complex import ChainComplex mats = {} - for i in range(self.__length, 0, -1): + for i in range(self._length, 0, -1): mats[i] = self.matrix(i) return ChainComplex(mats, degree_of_differential=-1) class FreeResolution(FreeResolution_generic): - """ + r""" Minimal free resolutions of ideals of multivariate polynomial rings. INPUT: - ``ideal`` -- a homogeneous ideal of a multi-variate polynomial ring or a submodule of a free module `M` of rank `n` over `S` - - ``name`` -- a string; name of the base ring - - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` OUTPUT: a minimal free resolution of the ideal @@ -459,6 +465,23 @@ class FreeResolution(FreeResolution_generic): S^1 <-- S^3 <-- S^2 <-- 0 sage: FreeResolution(I, algorithm='heuristic') S^1 <-- S^3 <-- S^2 <-- 0 + + We can also construct a resolution by passing in a matrix defining + the initial differential:: + + sage: m = matrix(P, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: r = FreeResolution(m, name='S') + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + sage: r.matrix(1) + [z^2 - y*w y*z - x*w y^2 - x*z] + + An additional construction is using a submodule of a free module:: + + sage: M = m.image() + sage: r = FreeResolution(M, name='S') + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 """ def __init__(self, ideal, name='S', algorithm='heuristic'): """ @@ -471,60 +494,106 @@ class FreeResolution(FreeResolution_generic): sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) sage: TestSuite(r).run(skip=['_test_pickling']) + + sage: m = matrix(P, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: r = FreeResolution(m, name='S') + sage: TestSuite(r).run(skip=['_test_pickling']) + + sage: M = m.image() + sage: r = FreeResolution(M, name='S') + sage: TestSuite(r).run(skip=['_test_pickling']) """ if isinstance(ideal, Ideal_generic): S = ideal.ring() - m = ideal - rank = 1 elif isinstance(ideal, Module_free_ambient): S = ideal.base_ring() - m = ideal.matrix().transpose() - rank = m.nrows() elif isinstance(ideal, Matrix_mpolynomial_dense): S = ideal.base_ring() - m = ideal.transpose() - rank = ideal.ncols() else: raise TypeError('no ideal, module, or matrix') - nvars = S.ngens() + self._ideal = ideal + self._algorithm = algorithm + super().__init__(S, name=name) + + def _m(self): + """ + The attribute ``m``. + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r._m() + Ideal (-z^2 + y*w, y*z - x*w, -y^2 + x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field + + sage: m = matrix(P, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: r = FreeResolution(m, name='S') + sage: r._m() + [z^2 - y*w y*z - x*w y^2 - x*z] + sage: M = m.image() + sage: r = FreeResolution(M, name='S') + sage: r._m() + [z^2 - y*w y*z - x*w y^2 - x*z] + """ + if isinstance(self._ideal, Ideal_generic): + return self._ideal + if isinstance(self._ideal, Module_free_ambient): + return self._ideal.matrix().transpose() + if isinstance(self._ideal, Matrix_mpolynomial_dense): + return self._ideal.transpose() + + @lazy_attribute + def _maps(self): + """ + Return the maps that define ``self``. + + TESTS:: + + sage: from sage.homology.free_resolution import FreeResolution + sage: P. = PolynomialRing(QQ) + sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r._maps + [ + [-y x] + [ z -y] + [z^2 - y*w y*z - x*w y^2 - x*z], [-w z] + ] + """ # This ensures the first component of the Singular resolution to be a # module, like the later components. This is important when the # components are converted to Sage modules. module = singular_function("module") - mod = module(m) + mod = module(self._m()) - if algorithm == 'minimal': + if self._algorithm == 'minimal': mres = singular_function('mres') # syzygy method r = mres(mod, 0) - elif algorithm == 'shreyer': + elif self._algorithm == 'shreyer': std = singular_function('std') sres = singular_function('sres') # Shreyer method minres = singular_function('minres') r = minres(sres(std(mod), 0)) - elif algorithm == 'standard': + elif self._algorithm == 'standard': nres = singular_function('nres') # standard basis method minres = singular_function('minres') r = minres(nres(mod, 0)) - elif algorithm == 'heuristic': + elif self._algorithm == 'heuristic': std = singular_function('std') res = singular_function('res') # heuristic method minres = singular_function('minres') r = minres(res(std(mod), 0)) - res_mats = to_sage_resolution(r) + return to_sage_resolution(r) - super().__init__(S, res_mats, name=name) - - self._ideal = ideal - self._name = name - - @property - @cached_method + @lazy_attribute def _initial_differential(self): - """ - Defines the `0`-th differential map of this resolution. + r""" + Define the `0`-th differential map of this resolution. EXAMPLES:: @@ -546,7 +615,7 @@ class FreeResolution(FreeResolution_generic): ideal = self._ideal if isinstance(ideal, Ideal_generic): S = ideal.ring() - M = S**1 + M = FreeModule(S, 1) N = M.submodule([vector([g]) for g in ideal.gens()]) elif isinstance(ideal, Module_free_ambient): S = ideal.base_ring() @@ -561,7 +630,7 @@ class FreeResolution(FreeResolution_generic): cdef singular_monomial_exponents(poly *p, ring *r): - """ + r""" Return the list of exponents of monomial ``p``. """ cdef int v @@ -572,7 +641,7 @@ cdef singular_monomial_exponents(poly *p, ring *r): return ml cdef to_sage_resolution(Resolution res): - """ + r""" Pull the data from Singular resolution ``res`` to construct a Sage resolution. @@ -580,7 +649,7 @@ cdef to_sage_resolution(Resolution res): - ``res`` -- Singular resolution - The procedure is destructive, and ``res`` is not usable afterward. + The procedure is destructive and ``res`` is not usable afterward. """ cdef ring *singular_ring cdef syStrategy singular_res @@ -615,7 +684,7 @@ cdef to_sage_resolution(Resolution res): if mod == NULL: break rank = mod.rank - free_module = sage_ring ** rank + free_module = FreeModule(sage_ring, rank) nrows = rank ncols = mod.ncols # IDELEMS(mod) @@ -665,3 +734,4 @@ cdef to_sage_resolution(Resolution res): res_mats.append(mat) return res_mats + diff --git a/src/sage/homology/graded_resolution.pyx b/src/sage/homology/graded_resolution.pyx index 03620cdb195..2b424f495d1 100644 --- a/src/sage/homology/graded_resolution.pyx +++ b/src/sage/homology/graded_resolution.pyx @@ -91,6 +91,7 @@ from sage.libs.singular.function cimport Resolution, new_sage_polynomial, access from sage.libs.singular.function import singular_function from sage.structure.sequence import Sequence, Sequence_generic from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute from sage.matrix.constructor import matrix as _matrix from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense from sage.modules.free_module_element import vector @@ -163,28 +164,20 @@ class GradedFreeResolution(FreeResolution): sage: r = GradedFreeResolution(I) sage: TestSuite(r).run(skip=['_test_pickling']) """ - cdef int i, j, k, ncols, nrows - cdef list res_shifts, prev_shifts, new_shifts + super().__init__(ideal, name=name, algorithm=algorithm) + + nvars = self._base_ring.ngens() - if isinstance(ideal, Ideal_generic): - S = ideal.ring() - m = ideal + if isinstance(self._ideal, Ideal_generic): rank = 1 - elif isinstance(ideal, Module_free_ambient): - S = ideal.base_ring() + elif isinstance(self._ideal, Module_free_ambient): m = ideal.matrix().transpose() - rank = m.nrows() - elif isinstance(ideal, Matrix_mpolynomial_dense): - S = ideal.base_ring() - m = ideal.transpose() - rank = ideal.ncols() - else: - raise TypeError('no ideal, module, or matrix') - - nvars = S.ngens() + rank = self._m().nrows() + elif isinstance(self._ideal, Matrix_mpolynomial_dense): + rank = self._ideal.ncols() if degrees is None: - degrees = nvars*[1] # standard grading + degrees = nvars * [1] # standard grading if len(degrees) != nvars: raise ValueError('the length of degrees does not match the number of generators') @@ -197,38 +190,68 @@ class GradedFreeResolution(FreeResolution): zero_deg = degrees[0].parent().zero() multigrade = True + if shifts is None: + shifts = rank * [zero_deg] + + self._shifts = shifts + self._degrees = degrees + self._multigrade = multigrade + self._zero_deg = zero_deg + + @lazy_attribute + def _maps(self): + """ + The maps that define ``self``. + + This also sets the attribute ``_res_shifts``. + + TESTS:: + + sage: from sage.homology.graded_resolution import GradedFreeResolution + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = GradedFreeResolution(I) + sage: r._maps + [ + [-y x] + [ z -y] + [z^2 - y*w y*z - x*w y^2 - x*z], [-w z] + ] + """ + cdef int i, j, k, ncols, nrows + cdef list res_shifts, prev_shifts, new_shifts + + S = self._base_ring + # This ensures the first component of the Singular resolution to be a # module, like the later components. This is important when the # components are converted to Sage modules. module = singular_function("module") - mod = module(m) + mod = module(self._m()) - if shifts is None: - shifts = rank*[zero_deg] - - if algorithm == 'minimal': + if self._algorithm == 'minimal': mres = singular_function('mres') # syzygy method r = mres(mod, 0) - elif algorithm == 'shreyer': + elif self._algorithm == 'shreyer': std = singular_function('std') sres = singular_function('sres') # Shreyer method minres = singular_function('minres') r = minres(sres(std(mod), 0)) - elif algorithm == 'standard': + elif self._algorithm == 'standard': nres = singular_function('nres') # standard basis method minres = singular_function('minres') r = minres(nres(mod, 0)) - elif algorithm == 'heuristic': + elif self._algorithm == 'heuristic': std = singular_function('std') res = singular_function('res') # heuristic method minres = singular_function('minres') r = minres(res(std(mod), 0)) - res_mats, res_degs = to_sage_resolution_graded(r, degrees) + res_mats, res_degs = to_sage_resolution_graded(r, self._degrees) # compute shifts of free modules in the resolution res_shifts = [] - prev_shifts = list(shifts) + prev_shifts = list(self._shifts) for k in range(len(res_degs)): new_shifts = [] degs = res_degs[k] @@ -247,15 +270,8 @@ class GradedFreeResolution(FreeResolution): res_shifts.append(new_shifts) prev_shifts = new_shifts - super(FreeResolution, self).__init__(S, res_mats, name=name) - - self._ideal = ideal - self._shifts = shifts - self._degrees = degrees self._res_shifts = res_shifts - self._multigrade = multigrade - self._zero_deg = zero_deg - self._name = name + return res_mats def _repr_module(self, i): """ @@ -274,6 +290,7 @@ class GradedFreeResolution(FreeResolution): sage: r._repr_module(3) '0' """ + self._maps # to set _res_shifts if i > len(self): m = '0' else: @@ -319,6 +336,7 @@ class GradedFreeResolution(FreeResolution): elif i > len(self): shifts = [] else: + self._maps # to set _res_shifts shifts = self._res_shifts[i - 1] return shifts @@ -397,6 +415,7 @@ class GradedFreeResolution(FreeResolution): kpoly = 1 sign = -1 + self._maps # to set _res_shifts for j in range(len(self)): for v in self._res_shifts[j]: if self._multigrade: @@ -416,7 +435,6 @@ cdef to_sage_resolution_graded(Resolution res, degrees): INPUT: - ``res`` -- Singular resolution - - ``degrees`` -- list of integers or integer vectors The procedure is destructive, and ``res`` is not usable afterward. From 12d76e7aff60783f4c9099ff1b7319d540926409 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 4 Aug 2022 19:52:56 -0500 Subject: [PATCH 183/591] Revert change in morphisms --- src/sage/modules/with_basis/morphism.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 2efcc4f25e9..b8fe98111b2 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -404,10 +404,10 @@ def __call__(self, *args): if self._is_module_with_basis_over_same_base_ring: return self.codomain().linear_combination( (self._on_basis(*(before+(index,)+after)), coeff ) - for (index, coeff) in mc.items() if self._on_basis(index)) + for (index, coeff) in mc.items()) else: return sum((coeff * self._on_basis(*(before+(index,)+after)) - for (index, coeff) in mc.items() if self._on_basis(index)), self._zero) + for (index, coeff) in mc.items()), self._zero) # As per the specs of Map, we should in fact implement _call_. # However we currently need to abuse Map.__call__ (which strict From 6058fdfc5750fe3d9077016434f1aebdfe8d1e24 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Thu, 4 Aug 2022 22:15:01 -0600 Subject: [PATCH 184/591] use bounds better The previous code wouldn't shorten l before applying CRT. The new code also uses the bounds more efficiently. --- src/sage/groups/generic.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 44987d6b3c7..926b3c7c824 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -713,7 +713,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: discrete_log(a, b) 20 sage: b = Mod(2,997); a = b^20 - sage: discrete_log(a, b) + sage: discrete_log(a, b, bounds=(10, 100)) 20 sage: K = GF(3^6,'b') @@ -797,7 +797,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: discrete_log(a, b, algorithm='rho') 20 sage: b = Mod(2,997); a = b^20 - sage: discrete_log(a, b, algorithm='rho') + sage: discrete_log(a, b, algorithm='rho', bounds=(10, 100)) 20 sage: K = GF(3^6,'b') @@ -869,21 +869,35 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i raise ValueError f = ord.factor() l = [0] * len(f) + mods = [] running_mod = 1 + offset = 0 + bound = ord - 1 # to avoid putting extra if statements everywhere + if bounds: + a = mult(a, power(base, -lb)) + offset = lb + bound = ub - lb for i, (pi, ri) in enumerate(f): + running_bound = min(bound, pi ** ri) for j in range(ri): + temp_bound = min(running_bound, pi) gamma = power(base, ord // pi) h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) if algorithm == 'bsgs': - c = bsgs(gamma, h, (0, pi), inverse=inverse, identity=identity, op=op, operation=operation) + c = bsgs(gamma, h, (0, temp_bound), inverse=inverse, identity=identity, op=op, operation=operation) elif algorithm == 'rho': c = discrete_log_rho(h, gamma, ord=pi, inverse=inverse, identity=identity, op=op, operation=operation) l[i] += c * (pi**j) - running_mod*=pi**ri - if(bounds and running_mod>ub): - break # we have log%running_mod. if we know that log bound: + break + mods.append(pi ** (j+1)) + if running_mod > bound: + break # we have log%running_mod. if we know that log Date: Fri, 5 Aug 2022 13:25:39 +0800 Subject: [PATCH 185/591] defer primality and irreducibility testing to "real" constructor (so we skip it when fetching a field from the cache) --- .../finite_rings/finite_field_constructor.py | 69 ++++++++++--------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index e6129689ad5..685c385cf2e 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -494,19 +494,20 @@ def __init__(self, *args, **kwds): super().__init__(*args, **kwds) def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, - impl=None, proof=None, check_irreducible=True, + impl=None, proof=None, + check_prime=True, check_irreducible=True, prefix=None, repr=None, elem_cache=None, **kwds): """ EXAMPLES:: sage: GF.create_key_and_extra_args(9, 'a') - ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True), {}) + ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True, True, True), {}) The order `q` can also be given as a pair `(p,n)`:: sage: GF.create_key_and_extra_args((3, 2), 'a') - ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True), {}) + ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True, True, True), {}) We do not take invalid keyword arguments and raise a value error to better ensure uniqueness:: @@ -520,9 +521,9 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, using givaro:: sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', repr='poly') - ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None), {}) + ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None, True, True), {}) sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', elem_cache=False) - ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None), {}) + ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None, True, True), {}) sage: GF(16, impl='ntl') is GF(16, impl='ntl', repr='foo') True @@ -541,61 +542,56 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, but we ignore them as they are not used, see :trac:`21433`:: sage: GF.create_key_and_extra_args(9, 'a', structure=None) - ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True), {}) + ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True, True, True), {}) TESTS:: - sage: GF.create_key_and_extra_args((6, 1), 'a') + sage: GF((6, 1), 'a') # implicit doctest Traceback (most recent call last): ... ValueError: the order of a finite field must be a prime power - sage: GF.create_key_and_extra_args((9, 1), 'a') + sage: GF((9, 1), 'a') # implicit doctest Traceback (most recent call last): ... ValueError: the order of a finite field must be a prime power - sage: GF.create_key_and_extra_args((5, 0), 'a') + sage: GF((5, 0), 'a') # implicit doctest Traceback (most recent call last): ... ValueError: the order of a finite field must be a prime power - sage: GF.create_key_and_extra_args((3, 2, 1), 'a') + sage: GF((3, 2, 1), 'a') # implicit doctest Traceback (most recent call last): ... ValueError: wrong input for finite field constructor """ import sage.arith.all - from sage.structure.proof.all import WithProof, arithmetic - if proof is None: - proof = arithmetic() + for key, val in kwds.items(): if key not in ['structure', 'implementation', 'prec', 'embedding', 'latex_names']: raise TypeError("create_key_and_extra_args() got an unexpected keyword argument '%s'" % key) if not (val is None or isinstance(val, list) and all(c is None for c in val)): raise NotImplementedError("ring extension with prescribed %s is not implemented" % key) + + from sage.structure.proof.all import WithProof, arithmetic + if proof is None: + proof = arithmetic() with WithProof('arithmetic', proof): if isinstance(order, tuple): if len(order) != 2: raise ValueError('wrong input for finite field constructor') - p, n = order - p = Integer(p) - if not p.is_prime() or n < 1: + p, n = map(Integer, order) + if p < 2 or n < 1: raise ValueError("the order of a finite field must be a prime power") - n = Integer(n) order = p**n else: order = Integer(order) - if order <= 1: + if order < 2: raise ValueError("the order of a finite field must be at least 2") - if order.is_prime(): - p = order - n = Integer(1) - else: - p, n = order.is_prime_power(get_data=True) - if n == 0: - raise ValueError("the order of a finite field must be a prime power") + p, n = order.perfect_power() # at this point, order = p**n + # note that we haven't tested p for primality if n == 1: if impl is None: @@ -651,11 +647,11 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, if modulus.degree() != n: raise ValueError("the degree of the modulus does not equal the degree of the field") - if check_irreducible and not modulus.is_irreducible(): - raise ValueError("finite field modulus must be irreducible but it is not") # If modulus is x - 1 for impl="modn", set it to None - if impl == 'modn' and modulus[0] == -1: + if impl == 'modn' and modulus.list() == [-1,1]: modulus = None + if modulus is None: + check_irreducible = False # Check extra arguments for givaro and setup their defaults # TODO: ntl takes a repr, but ignores it @@ -669,7 +665,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, repr = None elem_cache = None - return (order, name, modulus, impl, p, n, proof, prefix, repr, elem_cache), {} + return (order, name, modulus, impl, p, n, proof, prefix, repr, elem_cache, check_prime, check_irreducible), {} def create_object(self, version, key, **kwds): """ @@ -734,6 +730,7 @@ def create_object(self, version, key, **kwds): # as they are otherwise ignored repr = 'poly' elem_cache = (order < 500) + check_prime = check_irreducible = False elif len(key) == 8: # For backward compatibility of pickles (see trac #21433) order, name, modulus, impl, _, p, n, proof = key @@ -742,8 +739,19 @@ def create_object(self, version, key, **kwds): # as they are otherwise ignored repr = kwds.get('repr', 'poly') elem_cache = kwds.get('elem_cache', (order < 500)) - else: + check_prime = check_irreducible = False + elif len(key) == 10: order, name, modulus, impl, p, n, proof, prefix, repr, elem_cache = key + check_prime = check_irreducible = False + else: + order, name, modulus, impl, p, n, proof, prefix, repr, elem_cache, check_prime, check_irreducible = key + + from sage.structure.proof.all import WithProof + with WithProof('arithmetic', proof): + if check_prime and not p.is_prime(): + raise ValueError("the order of a finite field must be a prime power") + if check_irreducible and not modulus.is_irreducible(): + raise ValueError("finite field modulus must be irreducible but it is not") if impl == 'modn': if n != 1: @@ -759,7 +767,6 @@ def create_object(self, version, key, **kwds): # passed in when checking for primality, factoring, etc. # Otherwise, we would have to complicate all of their # constructors with check options. - from sage.structure.proof.all import WithProof with WithProof('arithmetic', proof): if impl == 'givaro': K = FiniteField_givaro(order, name, modulus, repr, elem_cache) From d4cf504d86bf87a136ee6d34293bdfd7e8ed62a2 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Fri, 5 Aug 2022 09:17:02 +0200 Subject: [PATCH 186/591] 34283: initial --- src/sage/matrix/matrix_space.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index c29bcc64260..cebee45661f 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -36,9 +36,7 @@ import sys import operator -# Sage matrix imports -from . import matrix_generic_dense -from . import matrix_generic_sparse +# Sage matrix imports see :trac:`34283` # Sage imports import sage.structure.coerce @@ -189,6 +187,8 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if isinstance(implementation, type): return implementation + from sage.matrix.matrix_generic_dense import Matrix_generic_dense + from sage.matrix.matrix_generic_sparse import Matrix_generic_sparse if not sparse: if implementation is None: # Choose default implementation: @@ -303,7 +303,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): return matrix_mpolynomial_dense.Matrix_mpolynomial_dense # The fallback - return matrix_generic_dense.Matrix_generic_dense + return Matrix_generic_dense # Deal with request for a specific implementation if implementation == 'flint': @@ -360,7 +360,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): raise ValueError("'linbox-double' matrices can only deal with order < %s" % matrix_modn_dense_double.MAX_MODULUS) if implementation == 'generic': - return matrix_generic_dense.Matrix_generic_dense + return Matrix_generic_dense if implementation == 'gap': from .matrix_gap import Matrix_gap @@ -402,7 +402,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): return matrix_double_sparse.Matrix_double_sparse # the fallback - return matrix_generic_sparse.Matrix_generic_sparse + return Matrix_generic_sparse From 07615d374d66583a140251f4700a02f27c29f271 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Fri, 5 Aug 2022 03:12:17 -0600 Subject: [PATCH 187/591] added test to detect previously fixed bug --- src/sage/groups/generic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 926b3c7c824..7b6f822f198 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -712,7 +712,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: b = Mod(2,37); a = b^20 sage: discrete_log(a, b) 20 - sage: b = Mod(2,997); a = b^20 + sage: b = Mod(3,2017); a = b^20 sage: discrete_log(a, b, bounds=(10, 100)) 20 @@ -796,7 +796,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: b = Mod(2,37); a = b^20 sage: discrete_log(a, b, algorithm='rho') 20 - sage: b = Mod(2,997); a = b^20 + sage: b = Mod(3,2017); a = b^20 sage: discrete_log(a, b, algorithm='rho', bounds=(10, 100)) 20 From b5f2eac416f30607c1e72e32c2a4745101fd74c3 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 5 Aug 2022 17:25:27 +0800 Subject: [PATCH 188/591] update doctest outputs --- src/sage/structure/factory.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/structure/factory.pyx b/src/sage/structure/factory.pyx index 6ad42da8c2d..a4a13186973 100644 --- a/src/sage/structure/factory.pyx +++ b/src/sage/structure/factory.pyx @@ -467,7 +467,7 @@ cdef class UniqueFactory(SageObject): sage: test_factory.create_key_and_extra_args(1, 2, key=5) ((1, 2), {}) sage: GF.create_key_and_extra_args(3) - ((3, ('x',), None, 'modn', 3, 1, True, None, None, None), {}) + ((3, ('x',), None, 'modn', 3, 1, True, None, None, None, True, False), {}) """ return self.create_key(*args, **kwds), {} @@ -517,7 +517,7 @@ cdef class UniqueFactory(SageObject): method, but this was removed in :trac:`16934`:: sage: key, _ = GF.create_key_and_extra_args(27, 'k'); key - (27, ('k',), x^3 + 2*x + 1, 'givaro', 3, 3, True, None, 'poly', True) + (27, ('k',), x^3 + 2*x + 1, 'givaro', 3, 3, True, None, 'poly', True, True, True) sage: K = GF.create_object(0, key); K Finite Field in k of size 3^3 sage: GF.other_keys(key, K) From 42db8520b729407a55861162c684a1c9f21b3d0b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 16:44:40 -0700 Subject: [PATCH 189/591] src/sage/geometry/polyhedral_complex.py (exploded_rainbow_plot, PolyhedralComplex.plot): New --- src/sage/geometry/polyhedral_complex.py | 87 +++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 7ac453ea78e..ed767eb1707 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -723,6 +723,15 @@ def plot(self, **kwds): """ Return a plot of the polyhedral complex, if it is of dim at most 3. + INPUT: + + - ``explosion_factor`` -- (default: 0) if positive, separate the cells of + the complex by extra space. See :func:`exploded_rainbow_plot` for + additional keyword arguments that can be passed in this case. + + - other keyword arguments are passed on to + :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.plot`. + EXAMPLES:: sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) @@ -733,6 +742,8 @@ def plot(self, **kwds): """ if self.dimension() > 3: raise ValueError("cannot plot in high dimension") + if kwds.get('explosion_factor', 0): + return exploded_rainbow_plot(self.maximal_cell_iterator(), **kwds) return sum(cell.plot(**kwds) for cell in self.maximal_cell_iterator()) def is_pure(self): @@ -2433,3 +2444,79 @@ def cells_list_to_cells_dict(cells_list): else: cells_dict[d] = set([cell]) return cells_dict + + +def exploded_rainbow_plot(polyhedra, *, + center=None, explosion_factor=1, sticky_vertices=False, + sticky_center=True, point=None, **kwds): + r""" + Return a plot of several ``polyhedra`` in one figure with extra space between them. + + INPUT: + + - ``polyhedra`` -- an iterable of :class:`~sage.geometry.polyhedron.base.Polyhedron_base` objects + + - keyword arguments: see :meth:`~sage.geometry.polyhedral_complex.PolyhedralComplex.plot` + + EXAMPLES:: + + sage: from sage.geometry.polyhedral_complex import exploded_rainbow_plot + sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) + sage: p2 = Polyhedron(vertices=[(1, 2), (0, 0), (0, 2)]) + sage: p3 = Polyhedron(vertices=[(0, 0), (1, 1), (2, 0)]) + sage: exploded_rainbow_plot([p1, p2, p3]) + Graphics object consisting of 20 graphics primitives + sage: exploded_rainbow_plot([p1, p2, p3], center=(1, 1)) + Graphics object consisting of 19 graphics primitives + sage: exploded_rainbow_plot([p1, p2, p3], center=(1, 1), sticky_vertices=True) + Graphics object consisting of 23 graphics primitives + """ + from sage.plot.colors import rainbow + from sage.plot.graphics import Graphics + from sage.plot.line import line + from sage.plot.point import point as plot_point + import itertools + + polyhedra = list(polyhedra) + g = Graphics() + if not polyhedra: + return g + dim = polyhedra[0].ambient_dimension() + if center is None: + from sage.rings.rational_field import QQ + center = vector(QQ, dim) + else: + center = vector(center) + translations = [explosion_factor * (p.center() - center) + for p in polyhedra] + vertex_translations_dict = {} + for P, t in zip(polyhedra, translations): + for v in P.vertices(): + v = v.vector() + v.set_immutable() + vertex_translations_dict[v] = vertex_translations_dict.get(v, []) + vertex_translations_dict[v].append(v + t) + if sticky_vertices or sticky_center: + for vertex, vertex_translations in vertex_translations_dict.items(): + if vertex == center: + if sticky_center: + for vt in vertex_translations: + g += line((center, vt), color='gray') + else: + if sticky_vertices: + for vt1, vt2 in itertools.combinations(vertex_translations, 2): + g += line((vt1, vt2), color='gray') + + if point is None: + point = dict(size=1.5) + if point is not False: + vertex_colors_dict = {vertex: color + for vertex, color in zip(vertex_translations_dict.keys(), + rainbow(len(vertex_translations_dict.keys())))} + for vertex, vertex_translations in vertex_translations_dict.items(): + g += plot_point(vertex_translations, + color=vertex_colors_dict[vertex], + alpha=0.5, **point) + + return g + sum((p + t).plot(alpha=0.5, point=False, color=color, **kwds) + for p, t, color in zip(polyhedra, translations, rainbow(len(polyhedra)))) From 1028bb465c039a6182ab0764fc3e917fd2578c32 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 17:51:32 -0700 Subject: [PATCH 190/591] src/sage/geometry/polyhedral_complex.py: Add documentation --- src/sage/geometry/polyhedral_complex.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index ed767eb1707..d8d171e7a87 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -2456,7 +2456,18 @@ def exploded_rainbow_plot(polyhedra, *, - ``polyhedra`` -- an iterable of :class:`~sage.geometry.polyhedron.base.Polyhedron_base` objects - - keyword arguments: see :meth:`~sage.geometry.polyhedral_complex.PolyhedralComplex.plot` + - ``center`` -- (default: ``None``, denoting the origin) the center of explosion + + - ``explosion_factor`` -- (default: 1) a nonnegative number; translate polyhedra by this + factor of the distance from ``center`` to their center + + - ``sticky_vertices`` -- (default: ``False``) whether to draw line segments between shared + vertices of the given polyhedra + + - ``sticky_center`` -- (default: ``True``) whether to draw line segments between ``center`` + and the vertices of the given polyhedra + + - other keyword arguments are passed on to :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.plot`. EXAMPLES:: @@ -2464,11 +2475,11 @@ def exploded_rainbow_plot(polyhedra, *, sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) sage: p2 = Polyhedron(vertices=[(1, 2), (0, 0), (0, 2)]) sage: p3 = Polyhedron(vertices=[(0, 0), (1, 1), (2, 0)]) - sage: exploded_rainbow_plot([p1, p2, p3]) + sage: exploded_rainbow_plot([p1, p2, p3]) # optional - sage.plot Graphics object consisting of 20 graphics primitives - sage: exploded_rainbow_plot([p1, p2, p3], center=(1, 1)) + sage: exploded_rainbow_plot([p1, p2, p3], center=(1, 1)) # optional - sage.plot Graphics object consisting of 19 graphics primitives - sage: exploded_rainbow_plot([p1, p2, p3], center=(1, 1), sticky_vertices=True) + sage: exploded_rainbow_plot([p1, p2, p3], center=(1, 1), sticky_vertices=True) # optional - sage.plot Graphics object consisting of 23 graphics primitives """ from sage.plot.colors import rainbow From 65b7cfe7ecf3c1ce778ea274707ecb1e9b0871f0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 18:18:55 -0700 Subject: [PATCH 191/591] Triangulation.polyhedral_complex: New --- src/sage/geometry/triangulation/element.py | 42 +++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index cf58a76187b..772517a5aa7 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -572,8 +572,7 @@ def fan(self, origin=None): @cached_method def simplicial_complex(self): r""" - Return a simplicial complex from a triangulation of the point - configuration. + Return ``self`` as an (abstract) simplicial complex. OUTPUT: @@ -711,6 +710,42 @@ def interior_facets(self): in self._boundary_simplex_dictionary().items() if len(bounded_simplices) == 2) + def polyhedral_complex(self, **kwds): + """ + Return ``self`` as a :class:`~sage.geometry.polyhedral_complex.PolyhedralComplex`. + + OUTPUT: + + A :class:`~sage.geometry.polyhedral_complex.PolyhedralComplex` whose maximal cells + are the simplices of the triangulation. + + EXAMPLES:: + + sage: P = polytopes.cube() + sage: pc = PointConfiguration(P.vertices()) + sage: T = pc.placing_triangulation(); T + (<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>) + sage: C = T.polyhedral_complex(); C + Polyhedral complex with 6 maximal cells + sage: [P.vertices_list() for P in C.maximal_cells_sorted()] + [[[-1, -1, -1], [-1, -1, 1], [-1, 1, 1], [1, -1, -1]], + [[-1, -1, -1], [-1, 1, -1], [-1, 1, 1], [1, 1, -1]], + [[-1, -1, -1], [-1, 1, 1], [1, -1, -1], [1, 1, -1]], + [[-1, -1, 1], [-1, 1, 1], [1, -1, -1], [1, -1, 1]], + [[-1, 1, 1], [1, -1, -1], [1, -1, 1], [1, 1, 1]], + [[-1, 1, 1], [1, -1, -1], [1, 1, -1], [1, 1, 1]]] + """ + from sage.geometry.polyhedral_complex import PolyhedralComplex + from sage.geometry.polyhedron.constructor import Polyhedron + ambient_dim = self.point_configuration().ambient_dim() + points = self.point_configuration().points() + return PolyhedralComplex([Polyhedron(vertices=[points[i] for i in simplex]) + for simplex in self], + ambient_dim=ambient_dim, + maximality_check=False, + face_to_face_check=False, + **kwds) + @cached_method def normal_cone(self): r""" @@ -798,8 +833,7 @@ def normal_cone(self): def adjacency_graph(self): """ - Returns a graph showing which simplices are adjacent in the - triangulation + Return a graph showing which simplices are adjacent in the triangulation OUTPUT: From fff67c3d2f60db85f014b5291ab3f1746199c5e5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 18:55:49 -0700 Subject: [PATCH 192/591] Triangulation.boundary_{simplicial,polyhedral}_complex: New --- src/sage/geometry/triangulation/element.py | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index 772517a5aa7..4b6480ac4c8 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -674,6 +674,28 @@ def boundary(self): in self._boundary_simplex_dictionary().items() if len(bounded_simplices) == 1) + @cached_method + def boundary_simplicial_complex(self): + r""" + Return the boundary of ``self`` as an (abstract) simplicial complex. + + OUTPUT: + + A :class:`~sage.topology.simplicial_complex.SimplicialComplex`. + + EXAMPLES:: + + sage: p = polytopes.cuboctahedron() + sage: sc = p.triangulate(engine='internal').boundary_simplicial_complex() + sage: sc + Simplicial complex with 12 vertices and 20 facets + + The boundary of every convex set is a topological sphere:: + + """ + from sage.topology.simplicial_complex import SimplicialComplex + return SimplicialComplex(self.boundary(), maximality_check=False) + @cached_method def interior_facets(self): """ @@ -746,6 +768,48 @@ def polyhedral_complex(self, **kwds): face_to_face_check=False, **kwds) + def boundary_polyhedral_complex(self, **kwds): + r""" + Return the boundary of ``self`` as a :class:`~sage.geometry.polyhedral_complex.PolyhedralComplex`. + + OUTPUT: + + A :class:`~sage.geometry.polyhedral_complex.PolyhedralComplex` whose maximal cells + are the simplices of the boundary of ``self``. + + EXAMPLES:: + + sage: P = polytopes.cube() + sage: pc = PointConfiguration(P.vertices()) + sage: T = pc.placing_triangulation(); T + (<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>) + sage: C = T.boundary_polyhedral_complex(); C + Polyhedral complex with 12 maximal cells + sage: [P.vertices_list() for P in C.maximal_cells_sorted()] + [[[-1, -1, -1], [-1, -1, 1], [-1, 1, 1]], + [[-1, -1, -1], [-1, -1, 1], [1, -1, -1]], + [[-1, -1, -1], [-1, 1, -1], [-1, 1, 1]], + [[-1, -1, -1], [-1, 1, -1], [1, 1, -1]], + [[-1, -1, -1], [1, -1, -1], [1, 1, -1]], + [[-1, -1, 1], [-1, 1, 1], [1, -1, 1]], + [[-1, -1, 1], [1, -1, -1], [1, -1, 1]], + [[-1, 1, -1], [-1, 1, 1], [1, 1, -1]], + [[-1, 1, 1], [1, -1, 1], [1, 1, 1]], + [[-1, 1, 1], [1, 1, -1], [1, 1, 1]], + [[1, -1, -1], [1, -1, 1], [1, 1, 1]], + [[1, -1, -1], [1, 1, -1], [1, 1, 1]]] + """ + from sage.geometry.polyhedral_complex import PolyhedralComplex + from sage.geometry.polyhedron.constructor import Polyhedron + ambient_dim = self.point_configuration().ambient_dim() + points = self.point_configuration().points() + return PolyhedralComplex([Polyhedron(vertices=[points[i] for i in simplex]) + for simplex in self.boundary()], + ambient_dim=ambient_dim, + maximality_check=False, + face_to_face_check=False, + **kwds) + @cached_method def normal_cone(self): r""" From 0a09ca45dc4a579a1900b922b156b02836b3340f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 5 Aug 2022 19:11:21 -0700 Subject: [PATCH 193/591] src/sage/geometry/triangulation/element.py: Add missing example --- src/sage/geometry/triangulation/element.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index 4b6480ac4c8..ebb60a72584 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -690,8 +690,11 @@ def boundary_simplicial_complex(self): sage: sc Simplicial complex with 12 vertices and 20 facets - The boundary of every convex set is a topological sphere:: + The boundary of every convex set is a topological sphere, so it has + spherical homology:: + sage: sc.homology() + {0: 0, 1: 0, 2: Z} """ from sage.topology.simplicial_complex import SimplicialComplex return SimplicialComplex(self.boundary(), maximality_check=False) From ea9610d76ff08beca1b2916bdadf621cd61581be Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 6 Aug 2022 15:08:22 +0900 Subject: [PATCH 194/591] Caching the leading support FrozenBitset and Integer. --- .../algebras/exterior_algebra_groebner.pxd | 16 +- .../algebras/exterior_algebra_groebner.pyx | 161 ++++++++++++------ 2 files changed, 122 insertions(+), 55 deletions(-) diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd index 37ac62d08cc..7708930faa8 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pxd +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -11,6 +11,11 @@ from sage.structure.element cimport MonoidElement cdef long degree(FrozenBitset X) cdef CliffordAlgebraElement build_monomial(Parent E, FrozenBitset supp) +cdef class GBElement: + cdef CliffordAlgebraElement elt + cdef FrozenBitset ls # leading support as a bitset + cdef Integer lsi # leading support as an Integer + # Grobner basis functions cdef class GroebnerStrategy: cdef Parent E # the exterior algebra @@ -20,11 +25,14 @@ cdef class GroebnerStrategy: cdef Integer rank cdef public tuple groebner_basis - cdef inline bint build_S_poly(self, CliffordAlgebraElement f, CliffordAlgebraElement g) + cdef inline GBElement build_elt(self, CliffordAlgebraElement f) + cdef inline GBElement prod_GB_term(self, GBElement f, FrozenBitset t) + cdef inline GBElement prod_term_GB(self, FrozenBitset t, GBElement f) + cdef inline bint build_S_poly(self, GBElement f, GBElement g) - cdef inline FrozenBitset leading_supp(self, CliffordAlgebraElement f) - cdef inline partial_S_poly_left(self, CliffordAlgebraElement f, CliffordAlgebraElement g) - cdef inline partial_S_poly_right(self, CliffordAlgebraElement f, CliffordAlgebraElement g) + cdef inline FrozenBitset leading_support(self, CliffordAlgebraElement f) + cdef inline partial_S_poly_left(self, GBElement f, GBElement g) + cdef inline partial_S_poly_right(self, GBElement f, GBElement g) cdef set preprocessing(self, list P, list G) cdef list reduction(self, list P, list G) diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 3cd7cf3911e..5a1858b08e0 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -1,4 +1,5 @@ -""" +# cython: linetrace=True +r""" Exterior algebras Gröbner bases This contains the backend implementations in Cython for the Gröbner bases @@ -24,6 +25,7 @@ from sage.libs.gmp.mpz cimport mpz_sizeinbase, mpz_setbit, mpz_tstbit, mpz_cmp_s from sage.data_structures.bitset_base cimport (bitset_t, bitset_init, bitset_first, bitset_next, bitset_set_to, bitset_len) from sage.structure.parent cimport Parent +from sage.structure.richcmp cimport richcmp cdef inline long degree(FrozenBitset X): """ @@ -38,6 +40,18 @@ cdef inline CliffordAlgebraElement build_monomial(Parent E, FrozenBitset supp): """ return E.element_class(E, {supp: E._base.one()}) +cdef class GBElement: + def __init__(self, CliffordAlgebraElement x, FrozenBitset ls, Integer n): + self.elt = x + self.ls = ls + self.lsi = n + + def __hash__(self): + return int(self.lsi) + + def __richcmp__(self, other, int op): + return richcmp(self.elt, ( other).elt, op) + cdef class GroebnerStrategy: """ A strategy for computing a Gröbner basis. @@ -70,14 +84,14 @@ cdef class GroebnerStrategy: else: self.side = 2 - cdef inline FrozenBitset leading_supp(self, CliffordAlgebraElement f): + cdef inline FrozenBitset leading_support(self, CliffordAlgebraElement f): """ Return the leading support of the exterior algebra element ``f``. """ cdef dict mc = f._monomial_coefficients return self.int_to_bitset(max(self.bitset_to_int(k) for k in mc)) - cdef inline partial_S_poly_left(self, CliffordAlgebraElement f, CliffordAlgebraElement g): + cdef inline partial_S_poly_left(self, GBElement f, GBElement g): """ Compute one half of the `S`-polynomial for ``f`` and ``g``. @@ -87,13 +101,14 @@ cdef class GroebnerStrategy: LCM(LM(f), LM(g)) / LT(f) \cdot f. """ - cdef FrozenBitset lmf = self.leading_supp(f) - cdef FrozenBitset lmg = self.leading_supp(g) - cdef FrozenBitset D = lmg.difference(lmf) - ret = build_monomial(self.E, D) * f - return (~ret[lmf._union(lmg)]) * ret + cdef FrozenBitset D = g.ls.difference(f.ls) + cdef GBElement ret = self.prod_term_GB(D, f) + inv = ~ret.elt[ret.ls] + for k in ret.elt._monomial_coefficients: + ret.elt._monomial_coefficients[k] *= inv + return ret - cdef inline partial_S_poly_right(self, CliffordAlgebraElement f, CliffordAlgebraElement g): + cdef inline partial_S_poly_right(self, GBElement f, GBElement g): """ Compute one half of the `S`-polynomial for ``f`` and ``g``. @@ -103,13 +118,48 @@ cdef class GroebnerStrategy: f \cdot LCM(LM(f), LM(g)) / LT(f). """ - cdef FrozenBitset lmf = self.leading_supp(f) - cdef FrozenBitset lmg = self.leading_supp(g) - cdef FrozenBitset D = lmg.difference(lmf) - ret = f * build_monomial(self.E, D) - return ret * (~ret[lmf._union(lmg)]) + cdef FrozenBitset D = g.ls.difference(f.ls) + cdef GBElement ret = self.prod_GB_term(f, D) + inv = ~ret.elt[ret.ls] + for k in ret.elt._monomial_coefficients: + ret.elt._monomial_coefficients[k] *= inv + return ret + + cdef inline GBElement build_elt(self, CliffordAlgebraElement f): + """ + Convert ``f`` into a ``GBElement``. + """ + cdef dict mc = f._monomial_coefficients + #if not mc: + # return GBElement(f, FrozenBitset(), -1) + cdef Integer r = max(self.bitset_to_int(k) for k in mc) + return GBElement(f, self.int_to_bitset(r), r) + + cdef inline GBElement prod_GB_term(self, GBElement f, FrozenBitset t): + """ + Return the GBElement corresponding to ``f * t``. + + .. WARNING:: + + This assumes the leading support is ``f.ls._union(t)``. + """ + ret = f.elt * build_monomial(self.E, t) + cdef FrozenBitset ls = f.ls._union(t) + return GBElement(ret, ls, self.bitset_to_int(ls)) + + cdef inline GBElement prod_term_GB(self, FrozenBitset t, GBElement f): + """ + Return the GBElement corresponding to ``t * f``. + + .. WARNING:: + + This assumes the leading support is ``f.ls._union(t)``. + """ + ret = build_monomial(self.E, t) * f.elt + cdef FrozenBitset ls = f.ls._union(t) + return GBElement(ret, ls, self.bitset_to_int(ls)) - cdef inline bint build_S_poly(self, CliffordAlgebraElement f, CliffordAlgebraElement g): + cdef inline bint build_S_poly(self, GBElement f, GBElement g): r""" Check to see if we should build the `S`-polynomial. @@ -122,13 +172,13 @@ cdef class GroebnerStrategy: if not self.homogeneous: return True - return ( self.leading_supp(f).intersection(self.leading_supp(g))).isempty() + return ( f.ls.intersection(g.ls)).isempty() cdef inline set preprocessing(self, list P, list G): """ Perform the preprocessing step. """ - cdef CliffordAlgebraElement f, g, f0, f1 + cdef GBElement f, g, f0, f1 cdef set additions cdef set L = set() @@ -145,13 +195,13 @@ cdef class GroebnerStrategy: if self.side == 2 and not self.homogeneous: # Add in all S-poly times positive degree monomials - additions = set(f * t for t in self.E.basis() for f in L) - L.update(f for f in additions if f) + additions = set(( f).elt * t for t in self.E.basis() for f in L) + L.update(self.build_elt(f) for f in additions if f) - cdef set done = set(self.leading_supp(f) for f in L) + cdef set done = set(( f).ls for f in L) cdef set monL = set() for f in L: - monL.update(f._monomial_coefficients) + monL.update(f.elt._monomial_coefficients) monL.difference_update(done) while monL: @@ -159,12 +209,12 @@ cdef class GroebnerStrategy: done.add(m) monL.remove(m) for g in G: - lm = self.leading_supp(g) + lm = g.ls if lm <= m: - f = build_monomial(self.E, m.difference(lm)) * g + f = self.prod_term_GB( m.difference(lm), g) if f in L: break - monL.update(set(f._monomial_coefficients) - done) + monL.update(set(f.elt._monomial_coefficients) - done) L.add(f) break return L @@ -179,13 +229,15 @@ cdef class GroebnerStrategy: cdef Integer r = Integer(2) ** self.rank - Integer(1) # r for "rank" or "reverso" M = matrix({(i, r - self.bitset_to_int( m)): c for i,f in enumerate(L) - for m,c in ( f)._monomial_coefficients.items()}, + for m,c in ( f).elt._monomial_coefficients.items()}, sparse=True) M.echelonize() # Do this in place - lead_supports = set(self.leading_supp( f) for f in L) - return [self.E.element_class(self.E, {self.int_to_bitset(r - Integer(j)): c for j,c in M[i].iteritems()}) - for i,p in enumerate(M.pivots()) - if self.int_to_bitset(r - Integer(p)) not in lead_supports] + lead_supports = set(( f).lsi for f in L) + return [GBElement(self.E.element_class(self.E, {self.int_to_bitset(r - Integer(j)): c for j,c in M[i].iteritems()}), + self.int_to_bitset(Integer(r - p)), + Integer(r - p)) + for i, p in enumerate(M.pivots()) + if r - Integer(p) not in lead_supports] def compute_groebner(self): """ @@ -210,23 +262,24 @@ cdef class GroebnerStrategy: cdef long deg cdef Py_ssize_t i, j, k cdef set additions - cdef list G = [f for f in self.ideal.gens() if f] # Remove 0s + cdef GBElement f0, f1 + cdef list G = [self.build_elt(f) for f in self.ideal.gens() if f] # Remove 0s + cdef list Gp if self.side == 2 and not self.homogeneous: # Add in all S-poly times positive degree monomials - additions = set(f * t for t in self.E.basis() for f in G) - G.extend(f for f in additions if f) + additions = set(( f0).elt * t for t in self.E.basis() for f0 in G) + G.extend(self.build_elt(f) for f in additions if f) cdef Py_ssize_t n = len(G) cdef dict P = {} - cdef list Gp for i in range(n): - f0 = G[i] - p0 = self.leading_supp(f0) + f0 = G[i] + p0 = f0.ls for j in range(i+1, n): - f1 = G[j] - p1 = self.leading_supp(f1) + f1 = G[j] + p1 = f1.ls deg = degree( (p0._union(p1))) if deg in P: P[deg].append((f0, f1)) @@ -239,10 +292,10 @@ cdef class GroebnerStrategy: G.extend(Gp) for j in range(n, len(G)): f1 = G[j] - p1 = self.leading_supp(f1) + p1 = f1.ls for i in range(j): f0 = G[i] - p0 = self.leading_supp(f0) + p0 = f0.ls deg = degree( (p0._union(p1))) if deg in P: P[deg].append((f0, f1)) @@ -250,24 +303,31 @@ cdef class GroebnerStrategy: P[deg] = [(f0, f1)] n = len(G) + G.sort(key=lambda x: ( x).lsi) + + for i in range(len(G)): + G[i] = ( G[i]).elt + # Now that we have a Gröbner basis, we make this into a reduced Gröbner basis - cdef set pairs = set((i, j) for i in range(n) for j in range(n) if i != j) + cdef set pairs = set((i, j) for i in range(n) for j in range(i+1,n)) cdef tuple supp cdef bint did_reduction cdef FrozenBitset lm, s while pairs: i,j = pairs.pop() + f = G[i] + g = G[j] # We perform the classical reduction algorithm here on each pair # TODO: Make this faster by using the previous technique? - f = self.reduce_single(G[i], G[j]) - if G[i] != f: - G[i] = f - if not f: + fp = self.reduce_single(f, g) + if f != fp: + G[i] = fp + if not fp: pairs.difference_update((k, i) for k in range(n)) else: pairs.update((k, i) for k in range(n) if k != i) - self.groebner_basis = tuple([~f[self.leading_supp(f)] * f for f in G if f]) + self.groebner_basis = tuple([~f[self.leading_support(f)] * f for f in G if f]) cpdef CliffordAlgebraElement reduce(self, CliffordAlgebraElement f): """ @@ -294,7 +354,7 @@ cdef class GroebnerStrategy: 0 """ for g in self.groebner_basis: - f = self.reduce_single(f, g) + f = self.reduce_single(f, g) return f cdef CliffordAlgebraElement reduce_single(self, CliffordAlgebraElement f, CliffordAlgebraElement g): @@ -305,20 +365,19 @@ cdef class GroebnerStrategy: Optimize this by doing it in-place and changing the underlying dict of ``f``. """ - cdef FrozenBitset lm, s + cdef FrozenBitset lm = self.leading_support(g), s + cdef bint did_reduction = True cdef tuple supp - lm = self.leading_supp(g) - did_reduction = True while did_reduction: supp = tuple(f._monomial_coefficients) did_reduction = False for s in supp: if lm <= s: did_reduction = True - mon = self.E.monomial(s - lm) + mon = build_monomial(self.E, s - lm) if self.side == 0: - gp = mon * g + gp = mon * g.elt f -= f[s] / gp[s] * gp else: gp = g * mon From d21d2e82c724caf14234c964cb108ae0291041dc Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 6 Aug 2022 15:11:06 +0900 Subject: [PATCH 195/591] Forgot to remove the Cython profiling directive. --- src/sage/algebras/exterior_algebra_groebner.pyx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 5a1858b08e0..3a2e73de41c 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -1,4 +1,3 @@ -# cython: linetrace=True r""" Exterior algebras Gröbner bases From 85e6d0939ccd599ff13cc8f4a8732bdf7b756c05 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Sat, 6 Aug 2022 03:04:45 -0600 Subject: [PATCH 196/591] fixed local variable referenced before assignment bug --- src/sage/groups/generic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 7b6f822f198..280de319e34 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -877,6 +877,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i a = mult(a, power(base, -lb)) offset = lb bound = ub - lb + i = 0 # this corrects a bug in which the loop is never entered and i never gets assigned a value for i, (pi, ri) in enumerate(f): running_bound = min(bound, pi ** ri) for j in range(ri): From 5285e67cfe80b7f42343373c40f92131b5d48c68 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 6 Aug 2022 19:41:16 +0900 Subject: [PATCH 197/591] Moving Singular conversion code to libs/singular; converting resoltuion files to Python files. --- src/sage/homology/free_resolution.pxd | 3 - ...free_resolution.pyx => free_resolution.py} | 123 +--------- ...ed_resolution.pyx => graded_resolution.py} | 153 ++---------- src/sage/libs/singular/singular.pxd | 5 + src/sage/libs/singular/singular.pyx | 228 ++++++++++++++++++ 5 files changed, 253 insertions(+), 259 deletions(-) delete mode 100644 src/sage/homology/free_resolution.pxd rename src/sage/homology/{free_resolution.pyx => free_resolution.py} (85%) rename src/sage/homology/{graded_resolution.pyx => graded_resolution.py} (75%) diff --git a/src/sage/homology/free_resolution.pxd b/src/sage/homology/free_resolution.pxd deleted file mode 100644 index 4ad023387d8..00000000000 --- a/src/sage/homology/free_resolution.pxd +++ /dev/null @@ -1,3 +0,0 @@ -from sage.libs.singular.decl cimport * - -cdef singular_monomial_exponents(poly *p, ring *r) diff --git a/src/sage/homology/free_resolution.pyx b/src/sage/homology/free_resolution.py similarity index 85% rename from src/sage/homology/free_resolution.pyx rename to src/sage/homology/free_resolution.py index dd29690ec6b..771aa2cb59a 100644 --- a/src/sage/homology/free_resolution.pyx +++ b/src/sage/homology/free_resolution.py @@ -70,19 +70,13 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.libs.singular.decl cimport * -from sage.libs.singular.decl cimport ring -from sage.libs.singular.function cimport Resolution, new_sage_polynomial, access_singular_ring +from sage.libs.singular.singular import si2sa_resolution from sage.libs.singular.function import singular_function -from sage.structure.sequence import Sequence, Sequence_generic -from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.matrix.constructor import matrix as _matrix from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense from sage.modules.free_module_element import vector from sage.modules.free_module import FreeModule from sage.modules.free_module import Module_free_ambient -from sage.rings.integer_ring import ZZ from sage.rings.ideal import Ideal_generic from sage.structure.sage_object import SageObject @@ -517,8 +511,8 @@ def __init__(self, ideal, name='S', algorithm='heuristic'): super().__init__(S, name=name) def _m(self): - """ - The attribute ``m``. + r""" + The defining module of ``self``. TESTS:: @@ -548,7 +542,7 @@ def _m(self): @lazy_attribute def _maps(self): - """ + r""" Return the maps that define ``self``. TESTS:: @@ -588,7 +582,7 @@ def _maps(self): minres = singular_function('minres') r = minres(res(std(mod), 0)) - return to_sage_resolution(r) + return si2sa_resolution(r) @lazy_attribute def _initial_differential(self): @@ -628,110 +622,3 @@ def _initial_differential(self): Q = M.quotient(N) return Q.coerce_map_from(M) - -cdef singular_monomial_exponents(poly *p, ring *r): - r""" - Return the list of exponents of monomial ``p``. - """ - cdef int v - cdef list ml = list() - - for v in range(1, r.N + 1): - ml.append(p_GetExp(p, v, r)) - return ml - -cdef to_sage_resolution(Resolution res): - r""" - Pull the data from Singular resolution ``res`` to construct a Sage - resolution. - - INPUT: - - - ``res`` -- Singular resolution - - The procedure is destructive and ``res`` is not usable afterward. - """ - cdef ring *singular_ring - cdef syStrategy singular_res - cdef poly *p - cdef poly *p_iter - cdef poly *first - cdef poly *previous - cdef poly *acc - cdef resolvente mods - cdef ideal *mod - cdef int i, j, k, idx, rank, nrows, ncols - cdef bint zero_mat - - singular_res = res._resolution[0] - sage_ring = res.base_ring - singular_ring = access_singular_ring(res.base_ring) - - if singular_res.minres != NULL: - mods = singular_res.minres - elif singular_res.fullres != NULL: - mods = singular_res.fullres - else: - raise ValueError('Singular resolution is not usable') - - res_mats = [] - - # length is the length of fullres. The length of minres - # can be shorter. Hence we avoid SEGFAULT by stopping - # at NULL pointer. - for idx in range(singular_res.length): - mod = mods[idx] - if mod == NULL: - break - rank = mod.rank - free_module = FreeModule(sage_ring, rank) - - nrows = rank - ncols = mod.ncols # IDELEMS(mod) - - mat = _matrix(sage_ring, nrows, ncols) - matdegs = [] - zero_mat = True - for j in range(ncols): - p = mod.m[j] - degs = [] - # code below copied and modified from to_sage_vector_destructive - # in sage.libs.singular.function.Converter - for i in range(1, rank + 1): - previous = NULL - acc = NULL - first = NULL - p_iter = p - while p_iter != NULL: - if p_GetComp(p_iter, singular_ring) == i: - p_SetComp(p_iter, 0, singular_ring) - p_Setm(p_iter, singular_ring) - if acc == NULL: - first = p_iter - else: - acc.next = p_iter - acc = p_iter - if p_iter == p: - p = pNext(p_iter) - if previous != NULL: - previous.next = pNext(p_iter) - p_iter = pNext(p_iter) - acc.next = NULL - else: - previous = p_iter - p_iter = pNext(p_iter) - - if zero_mat: - zero_mat = first == NULL - - mat[i - 1, j] = new_sage_polynomial(sage_ring, first) - - # Singular sometimes leaves zero matrix in the resolution. We can stop - # when one is seen. - if zero_mat: - break - - res_mats.append(mat) - - return res_mats - diff --git a/src/sage/homology/graded_resolution.pyx b/src/sage/homology/graded_resolution.py similarity index 75% rename from src/sage/homology/graded_resolution.pyx rename to src/sage/homology/graded_resolution.py index 2b424f495d1..593ca98b36d 100644 --- a/src/sage/homology/graded_resolution.pyx +++ b/src/sage/homology/graded_resolution.py @@ -72,7 +72,6 @@ AUTHORS: - Kwankyu Lee (2022-05): initial version - """ # **************************************************************************** @@ -85,14 +84,9 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.libs.singular.decl cimport * -from sage.libs.singular.decl cimport ring -from sage.libs.singular.function cimport Resolution, new_sage_polynomial, access_singular_ring +from sage.libs.singular.singular import si2sa_resolution_graded from sage.libs.singular.function import singular_function -from sage.structure.sequence import Sequence, Sequence_generic -from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.matrix.constructor import matrix as _matrix from sage.matrix.matrix_mpolynomial_dense import Matrix_mpolynomial_dense from sage.modules.free_module_element import vector from sage.modules.free_module import Module_free_ambient @@ -101,7 +95,6 @@ from sage.rings.ideal import Ideal_generic from sage.homology.free_resolution import FreeResolution -from sage.homology.free_resolution cimport singular_monomial_exponents class GradedFreeResolution(FreeResolution): @@ -112,16 +105,12 @@ class GradedFreeResolution(FreeResolution): - ``ideal`` -- a homogeneous ideal of a multivariate polynomial ring `S`, or a homogeneous submodule of a free module `M` of rank `n` over `S` - - ``degree`` -- a list of integers or integer vectors giving degrees of variables of `S`; this is a list of 1s by default - - ``shifts`` -- a list of integers or integer vectors giving shifts of degrees of `n` summands of the free module `M`; this is a list of zero degrees of length `n` by default - - ``name`` -- a string; name of the base ring - - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` If ``ideal`` is an ideal of `S`, then `M = S`, a free module of rank `1` @@ -171,13 +160,12 @@ def __init__(self, ideal, degrees=None, shifts=None, name='S', algorithm='heuris if isinstance(self._ideal, Ideal_generic): rank = 1 elif isinstance(self._ideal, Module_free_ambient): - m = ideal.matrix().transpose() rank = self._m().nrows() elif isinstance(self._ideal, Matrix_mpolynomial_dense): rank = self._ideal.ncols() if degrees is None: - degrees = nvars * [1] # standard grading + degrees = nvars * (1,) # standard grading if len(degrees) != nvars: raise ValueError('the length of degrees does not match the number of generators') @@ -186,7 +174,7 @@ def __init__(self, ideal, degrees=None, shifts=None, name='S', algorithm='heuris zero_deg = 0 multigrade = False else: # degrees are integer vectors - degrees = [vector(v) for v in degrees] + degrees = tuple([vector(v) for v in degrees]) zero_deg = degrees[0].parent().zero() multigrade = True @@ -194,7 +182,7 @@ def __init__(self, ideal, degrees=None, shifts=None, name='S', algorithm='heuris shifts = rank * [zero_deg] self._shifts = shifts - self._degrees = degrees + self._degrees = tuple(degrees) self._multigrade = multigrade self._zero_deg = zero_deg @@ -217,11 +205,11 @@ def _maps(self): [ z -y] [z^2 - y*w y*z - x*w y^2 - x*z], [-w z] ] + sage: r._res_shifts + [[2, 2, 2], [3, 3]] """ - cdef int i, j, k, ncols, nrows - cdef list res_shifts, prev_shifts, new_shifts - - S = self._base_ring + #cdef int i, j, k, ncols, nrows + #cdef list res_shifts, prev_shifts, new_shifts # This ensures the first component of the Singular resolution to be a # module, like the later components. This is important when the @@ -247,7 +235,7 @@ def _maps(self): minres = singular_function('minres') r = minres(res(std(mod), 0)) - res_mats, res_degs = to_sage_resolution_graded(r, self._degrees) + res_mats, res_degs = si2sa_resolution_graded(r, self._degrees) # compute shifts of free modules in the resolution res_shifts = [] @@ -314,6 +302,8 @@ def _repr_module(self, i): def shifts(self, i): """ + Return the shifts of ``self``. + EXAMPLES:: sage: from sage.homology.graded_resolution import GradedFreeResolution @@ -342,7 +332,7 @@ def shifts(self, i): return shifts def betti(self, i, a=None): - """ + r""" Return the `i`-th Betti number in degree `a`. INPUT: @@ -387,12 +377,13 @@ def betti(self, i, a=None): return betti[a] if a in betti else 0 def K_polynomial(self, names=None): - """ + r""" Return the K-polynomial of this resolution. INPUT: - - ``names`` -- a string of names of the variables of the K-polynomial + - ``names`` -- (optional) a string of names of the variables + of the K-polynomial EXAMPLES:: @@ -426,117 +417,3 @@ def K_polynomial(self, names=None): return kpoly - -cdef to_sage_resolution_graded(Resolution res, degrees): - """ - Pull the data from Singular resolution ``res`` to construct a Sage - resolution. - - INPUT: - - - ``res`` -- Singular resolution - - ``degrees`` -- list of integers or integer vectors - - The procedure is destructive, and ``res`` is not usable afterward. - """ - cdef ring *singular_ring - cdef syStrategy singular_res - cdef poly *p - cdef poly *p_iter - cdef poly *first - cdef poly *previous - cdef poly *acc - cdef resolvente mods - cdef ideal *mod - cdef int i, j, k, idx, rank, nrows, ncols - cdef int ngens = len(degrees) - cdef bint zero_mat - - singular_res = res._resolution[0] - sage_ring = res.base_ring - singular_ring = access_singular_ring(res.base_ring) - - if singular_res.minres != NULL: - mods = singular_res.minres - elif singular_res.fullres != NULL: - mods = singular_res.fullres - else: - raise ValueError('Singular resolution is not usable') - - res_mats = [] - res_degs = [] - - # length is the length of fullres. The length of minres - # can be shorter. Hence we avoid SEGFAULT by stopping - # at NULL pointer. - for idx in range(singular_res.length): - mod = mods[idx] - if mod == NULL: - break - rank = mod.rank - free_module = sage_ring ** rank - - nrows = rank - ncols = mod.ncols # IDELEMS(mod) - - mat = _matrix(sage_ring, nrows, ncols) - matdegs = [] - zero_mat = True - for j in range(ncols): - p = mod.m[j] - degs = [] - # code below copied and modified from to_sage_vector_destructive - # in sage.libs.singular.function.Converter - for i in range(1, rank + 1): - previous = NULL - acc = NULL - first = NULL - p_iter = p - while p_iter != NULL: - if p_GetComp(p_iter, singular_ring) == i: - p_SetComp(p_iter, 0, singular_ring) - p_Setm(p_iter, singular_ring) - if acc == NULL: - first = p_iter - else: - acc.next = p_iter - acc = p_iter - if p_iter == p: - p = pNext(p_iter) - if previous != NULL: - previous.next = pNext(p_iter) - p_iter = pNext(p_iter) - acc.next = NULL - else: - previous = p_iter - p_iter = pNext(p_iter) - - if zero_mat: - zero_mat = first == NULL - - mat[i - 1, j] = new_sage_polynomial(sage_ring, first) - - # degree of a homogeneous polynomial can be computed from the - # first monomial - if first != NULL: - exps = singular_monomial_exponents(first, singular_ring) - deg = 0 - for k in range(ngens): - deg += exps[k] * degrees[k] - degs.append(deg) - else: - degs.append(None) - - matdegs.append(degs) # store degrees of the column - - # Singular sometimes leaves zero matrix in the resolution. We can stop - # when one is seen. - if zero_mat: - break - - res_mats.append(mat) - res_degs.append(matdegs) - - return res_mats, res_degs - - diff --git a/src/sage/libs/singular/singular.pxd b/src/sage/libs/singular/singular.pxd index e590126d546..e1a55fbcd84 100644 --- a/src/sage/libs/singular/singular.pxd +++ b/src/sage/libs/singular/singular.pxd @@ -1,4 +1,5 @@ from sage.libs.singular.decl cimport ring, poly, number, intvec +from sage.libs.singular.function cimport Resolution from sage.rings.rational cimport Rational from sage.structure.element cimport Element @@ -32,6 +33,10 @@ cdef object si2sa_intvec(intvec *v) # dispatches to all the above. cdef object si2sa(number *n, ring *_ring, object base) +cdef list singular_monomial_exponents(poly *p, ring *r) +cpdef list si2sa_resolution(Resolution res) +cpdef tuple si2sa_resolution_graded(Resolution res, tuple degrees) + # ====================================== # Conversion from Sage to Singular types # ====================================== diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index 63cb6a9e19e..2a08d698580 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -30,6 +30,7 @@ from libc.stdint cimport int64_t from sage.libs.singular.decl cimport * from sage.rings.polynomial.polydict import ETuple +from sage.libs.singular.function cimport new_sage_polynomial, access_singular_ring from sage.rings.rational_field import RationalField from sage.rings.integer_ring cimport IntegerRing_class @@ -630,6 +631,233 @@ cdef inline object si2sa_ZZmod(number *n, ring *_ring, object base): return base(_ring.cf.cfInt(n,_ring.cf)) + +cdef list singular_monomial_exponents(poly *p, ring *r): + r""" + Return the list of exponents of monomial ``p``. + """ + cdef int v + cdef list ml = [None] * r.N + + for v in range(1, r.N + 1): + ml[v-1] = p_GetExp(p, v, r) + return ml + +cpdef list si2sa_resolution(Resolution res): + r""" + Pull the data from Singular resolution ``res`` to construct a Sage + resolution. + + INPUT: + + - ``res`` -- Singular resolution + + The procedure is destructive and ``res`` is not usable afterward. + """ + cdef ring *singular_ring + cdef syStrategy singular_res + cdef poly *p + cdef poly *p_iter + cdef poly *first + cdef poly *previous + cdef poly *acc + cdef resolvente mods + cdef ideal *mod + cdef int i, j, k, idx, rank, nrows, ncols + cdef bint zero_mat + cdef list degs, matdegs + + from sage.modules.free_module import FreeModule + from sage.matrix.constructor import matrix as _matrix + + singular_res = res._resolution[0] + sage_ring = res.base_ring + singular_ring = access_singular_ring(res.base_ring) + + if singular_res.minres != NULL: + mods = singular_res.minres + elif singular_res.fullres != NULL: + mods = singular_res.fullres + else: + raise ValueError('Singular resolution is not usable') + + cdef list res_mats = [] + + # length is the length of fullres. The length of minres + # can be shorter. Hence we avoid SEGFAULT by stopping + # at NULL pointer. + for idx in range(singular_res.length): + mod = mods[idx] + if mod == NULL: + break + rank = mod.rank + free_module = FreeModule(sage_ring, rank) + + nrows = rank + ncols = mod.ncols # IDELEMS(mod) + + mat = _matrix(sage_ring, nrows, ncols) + matdegs = [] + zero_mat = True + for j in range(ncols): + p = mod.m[j] + degs = [] + # code below copied and modified from to_sage_vector_destructive + # in sage.libs.singular.function.Converter + for i in range(1, rank + 1): + previous = NULL + acc = NULL + first = NULL + p_iter = p + while p_iter != NULL: + if p_GetComp(p_iter, singular_ring) == i: + p_SetComp(p_iter, 0, singular_ring) + p_Setm(p_iter, singular_ring) + if acc == NULL: + first = p_iter + else: + acc.next = p_iter + acc = p_iter + if p_iter == p: + p = pNext(p_iter) + if previous != NULL: + previous.next = pNext(p_iter) + p_iter = pNext(p_iter) + acc.next = NULL + else: + previous = p_iter + p_iter = pNext(p_iter) + + if zero_mat: + zero_mat = first == NULL + + mat[i - 1, j] = new_sage_polynomial(sage_ring, first) + + # Singular sometimes leaves zero matrix in the resolution. We can stop + # when one is seen. + if zero_mat: + break + + res_mats.append(mat) + + return res_mats + +cpdef tuple si2sa_resolution_graded(Resolution res, tuple degrees): + """ + Pull the data from Singular resolution ``res`` to construct a Sage + resolution. + + INPUT: + + - ``res`` -- Singular resolution + - ``degrees`` -- list of integers or integer vectors + + The procedure is destructive, and ``res`` is not usable afterward. + """ + cdef ring *singular_ring + cdef syStrategy singular_res + cdef poly *p + cdef poly *p_iter + cdef poly *first + cdef poly *previous + cdef poly *acc + cdef resolvente mods + cdef ideal *mod + cdef int i, j, k, idx, rank, nrows, ncols + cdef int ngens = len(degrees) + cdef bint zero_mat + cdef list matdegs, exps + + from sage.matrix.constructor import matrix as _matrix + + singular_res = res._resolution[0] + sage_ring = res.base_ring + singular_ring = access_singular_ring(res.base_ring) + + if singular_res.minres != NULL: + mods = singular_res.minres + elif singular_res.fullres != NULL: + mods = singular_res.fullres + else: + raise ValueError('Singular resolution is not usable') + + cdef list res_mats = [] + cdef list res_degs = [] + + # length is the length of fullres. The length of minres + # can be shorter. Hence we avoid SEGFAULT by stopping + # at NULL pointer. + for idx in range(singular_res.length): + mod = mods[idx] + if mod == NULL: + break + rank = mod.rank + free_module = sage_ring ** rank + + nrows = rank + ncols = mod.ncols # IDELEMS(mod) + + mat = _matrix(sage_ring, nrows, ncols) + matdegs = [] + zero_mat = True + for j in range(ncols): + p = mod.m[j] + degs = [] + # code below copied and modified from to_sage_vector_destructive + # in sage.libs.singular.function.Converter + for i in range(1, rank + 1): + previous = NULL + acc = NULL + first = NULL + p_iter = p + while p_iter != NULL: + if p_GetComp(p_iter, singular_ring) == i: + p_SetComp(p_iter, 0, singular_ring) + p_Setm(p_iter, singular_ring) + if acc == NULL: + first = p_iter + else: + acc.next = p_iter + acc = p_iter + if p_iter == p: + p = pNext(p_iter) + if previous != NULL: + previous.next = pNext(p_iter) + p_iter = pNext(p_iter) + acc.next = NULL + else: + previous = p_iter + p_iter = pNext(p_iter) + + if zero_mat: + zero_mat = first == NULL + + mat[i - 1, j] = new_sage_polynomial(sage_ring, first) + + # degree of a homogeneous polynomial can be computed from the + # first monomial + if first != NULL: + exps = singular_monomial_exponents(first, singular_ring) + deg = 0 + for k in range(ngens): + deg += exps[k] * degrees[k] + degs.append(deg) + else: + degs.append(None) + + matdegs.append(degs) # store degrees of the column + + # Singular sometimes leaves zero matrix in the resolution. We can stop + # when one is seen. + if zero_mat: + break + + res_mats.append(mat) + res_degs.append(matdegs) + + return (res_mats, res_degs) + + cdef number *sa2si_QQ(Rational r, ring *_ring): """ Create a singular number from a sage rational. From 5917129241b4f214506fe27f6a04ed14ea8bbb22 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 6 Aug 2022 20:13:39 +0900 Subject: [PATCH 198/591] Changing the doc for clarity and to add some more descriptions. --- src/sage/homology/free_resolution.py | 118 ++++++++++++++----------- src/sage/homology/graded_resolution.py | 84 ++++++++++-------- 2 files changed, 114 insertions(+), 88 deletions(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 771aa2cb59a..82e7e91af28 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -1,10 +1,16 @@ r""" Free resolutions -The :class:`FreeResolution` implements a finite free resolution, which is a -chain complex of free modules, terminating with a zero module at the end, whose -homology groups are all zero. +Let `R` be a commutative ring. A finite free resolution of an `R`-module `M` +is a chain complex of free `R`-modules +.. MATH:: + + 0 \xleftarrow{d_0} R^{n_1} \xleftarrow{d_1} R^{n_1} \xleftarrow{d_2} + \cdots \xleftarrow{d_k} R^{n_k} \xleftarrow{d_{k+1}} 0 + +terminating with a zero module at the end that is exact (all homology groups +are zero) such that the image of `d_1` is `M`. EXAMPLES:: @@ -16,6 +22,11 @@ sage: r S^1 <-- S^3 <-- S^2 <-- 0 + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: r = FreeResolution(I) + sage: r + S^1 <-- S^3 <-- S^2 <-- 0 + sage: FreeResolution(m2, name='S') S^2 <-- S^6 <-- S^5 <-- 0 @@ -28,18 +39,6 @@ sage: r S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 -The :class:`FreeResolution` computes a minimal free resolution of modules -over a multivariate polynomial ring. - -EXAMPLES:: - - sage: from sage.homology.free_resolution import FreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) - sage: r = FreeResolution(I) - sage: r - S^1 <-- S^3 <-- S^2 <-- 0 - An example of a minimal free resolution from [CLO2005]_:: sage: R. = QQ[] @@ -98,8 +97,8 @@ class FreeResolution_generic(SageObject): EXAMPLES:: sage: from sage.homology.free_resolution import FreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) sage: r.differential(0) Coercion map: @@ -146,8 +145,8 @@ def _length(self): TESTS:: sage: from sage.homology.free_resolution import FreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) sage: r._length 2 @@ -415,17 +414,21 @@ def chain_complex(self): class FreeResolution(FreeResolution_generic): r""" - Minimal free resolutions of ideals of multivariate polynomial rings. + Minimal free resolutions of ideals or submodules of free modules + of multivariate polynomial rings. INPUT: - - ``ideal`` -- a homogeneous ideal of a multi-variate polynomial ring or - a submodule of a free module `M` of rank `n` over `S` + - ``module`` -- a submodule of a free module `M` of rank `n` over `S` or + an ideal of a multi-variate polynomial ring - ``name`` -- a string; name of the base ring - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` OUTPUT: a minimal free resolution of the ideal + If ``module`` is an ideal of `S`, it is considered as a submodule of a + free module of rank `1` over `S`. + The available algorithms and the corresponding Singular commands are shown below: @@ -441,8 +444,8 @@ class FreeResolution(FreeResolution_generic): EXAMPLES:: sage: from sage.homology.free_resolution import FreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) sage: r S^1 <-- S^3 <-- S^2 <-- 0 @@ -463,7 +466,7 @@ class FreeResolution(FreeResolution_generic): We can also construct a resolution by passing in a matrix defining the initial differential:: - sage: m = matrix(P, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() sage: r = FreeResolution(m, name='S') sage: r S^1 <-- S^3 <-- S^2 <-- 0 @@ -476,20 +479,35 @@ class FreeResolution(FreeResolution_generic): sage: r = FreeResolution(M, name='S') sage: r S^1 <-- S^3 <-- S^2 <-- 0 + + A nonhomogeneous ideal:: + + sage: I = S.ideal([z^2 - y*w, y*z - x*w, y^2 - x]) + sage: R = FreeResolution(I) + sage: R + S^1 <-- S^3 <-- S^3 <-- S^1 <-- 0 + sage: R.matrix(2) + [ y*z - x*w y^2 - x 0] + [-z^2 + y*w 0 y^2 - x] + [ 0 -z^2 + y*w -y*z + x*w] + sage: R.matrix(3) + [ y^2 - x] + [-y*z + x*w] + [ z^2 - y*w] """ - def __init__(self, ideal, name='S', algorithm='heuristic'): + def __init__(self, module, name='S', algorithm='heuristic'): """ Initialize. TESTS:: sage: from sage.homology.free_resolution import FreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) sage: TestSuite(r).run(skip=['_test_pickling']) - sage: m = matrix(P, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() sage: r = FreeResolution(m, name='S') sage: TestSuite(r).run(skip=['_test_pickling']) @@ -497,16 +515,16 @@ def __init__(self, ideal, name='S', algorithm='heuristic'): sage: r = FreeResolution(M, name='S') sage: TestSuite(r).run(skip=['_test_pickling']) """ - if isinstance(ideal, Ideal_generic): - S = ideal.ring() - elif isinstance(ideal, Module_free_ambient): - S = ideal.base_ring() - elif isinstance(ideal, Matrix_mpolynomial_dense): - S = ideal.base_ring() + if isinstance(module, Ideal_generic): + S = module.ring() + elif isinstance(module, Module_free_ambient): + S = module.base_ring() + elif isinstance(module, Matrix_mpolynomial_dense): + S = module.base_ring() else: raise TypeError('no ideal, module, or matrix') - self._ideal = ideal + self._module = module self._algorithm = algorithm super().__init__(S, name=name) @@ -517,13 +535,13 @@ def _m(self): TESTS:: sage: from sage.homology.free_resolution import FreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) sage: r._m() Ideal (-z^2 + y*w, y*z - x*w, -y^2 + x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field - sage: m = matrix(P, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() sage: r = FreeResolution(m, name='S') sage: r._m() [z^2 - y*w y*z - x*w y^2 - x*z] @@ -533,12 +551,12 @@ def _m(self): sage: r._m() [z^2 - y*w y*z - x*w y^2 - x*z] """ - if isinstance(self._ideal, Ideal_generic): - return self._ideal - if isinstance(self._ideal, Module_free_ambient): - return self._ideal.matrix().transpose() - if isinstance(self._ideal, Matrix_mpolynomial_dense): - return self._ideal.transpose() + if isinstance(self._module, Ideal_generic): + return self._module + if isinstance(self._module, Module_free_ambient): + return self._module.matrix().transpose() + if isinstance(self._module, Matrix_mpolynomial_dense): + return self._module.transpose() @lazy_attribute def _maps(self): @@ -548,8 +566,8 @@ def _maps(self): TESTS:: sage: from sage.homology.free_resolution import FreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) sage: r._maps [ @@ -592,8 +610,8 @@ def _initial_differential(self): EXAMPLES:: sage: from sage.homology.free_resolution import FreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = FreeResolution(I) sage: r._initial_differential Coercion map: @@ -606,7 +624,7 @@ def _initial_differential(self): [ y*z - x*w] [-y^2 + x*z] """ - ideal = self._ideal + ideal = self._module if isinstance(ideal, Ideal_generic): S = ideal.ring() M = FreeModule(S, 1) diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index 593ca98b36d..bfa9354ff4c 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -1,21 +1,9 @@ r""" Graded free resolutions -This module defines :class:`GradedFreeResolution` which computes a -graded free resolution of a homogeneous ideal `I` of a graded multivariate -polynomial ring `S`, or a homogeneous submodule of a graded free module `M` -over `S`. The output resolution is always minimal. - -The degrees given to the variables of `S` are integers or integer vectors of -the same length. In the latter case, `S` is said to be multigraded, and the -resolution is a multigraded free resolution. The standard grading where all -variables have degree `1` is used if the degrees are not specified. - -A summand of the graded free module `M` is a shifted (or twisted) module of -rank one over `S`, denoted `S(-d)` with shift `d`. - -The computation of the resolution is done by the libSingular behind. Different -Singular algorithms can be chosen for best performance. +Let `R` be a commutative ring. A graded free resolution of a graded +`R`-module `M` is a :mod:`free resolution ` +such that all maps are homogeneous module homomorphisms. EXAMPLES:: @@ -96,25 +84,35 @@ from sage.homology.free_resolution import FreeResolution - class GradedFreeResolution(FreeResolution): """ - Graded free resolutions of ideals of multi-variate polynomial rings. + Graded free resolutions of ideals of multivariate polynomial rings. INPUT: - - ``ideal`` -- a homogeneous ideal of a multivariate polynomial ring `S`, or - a homogeneous submodule of a free module `M` of rank `n` over `S` - - ``degree`` -- a list of integers or integer vectors giving degrees of - variables of `S`; this is a list of 1s by default + - ``module`` -- a homogeneous submodule of a free module `M` of rank `n` + over `S` or a homogeneous ideal of a multivariate polynomial ring `S` + - ``degrees`` -- (default: a list with all entries `1`) a list of integers + or integer vectors giving degrees of variables of `S` - ``shifts`` -- a list of integers or integer vectors giving shifts of degrees of `n` summands of the free module `M`; this is a list of zero degrees of length `n` by default - ``name`` -- a string; name of the base ring - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` - If ``ideal`` is an ideal of `S`, then `M = S`, a free module of rank `1` - over `S`. + If ``module`` is an ideal of `S`, it is considered as a submodule of a + free module of rank `1` over `S`. + + The degrees given to the variables of `S` are integers or integer vectors of + the same length. In the latter case, `S` is said to be multigraded, and the + resolution is a multigraded free resolution. The standard grading where all + variables have degree `1` is used if the degrees are not specified. + + A summand of the graded free module `M` is a shifted (or twisted) module of + rank one over `S`, denoted `S(-d)` with shift `d`. + + The computation of the resolution is done by using ``libSingular``. + Different Singular algorithms can be chosen for best performance. OUTPUT: a graded minimal free resolution of ``ideal`` @@ -130,6 +128,10 @@ class GradedFreeResolution(FreeResolution): ``heuristic`` ``minres(res(std(ideal)))`` ============= ============================ + .. WARNING:: + + This does not check that the module is homogeneous. + EXAMPLES:: sage: from sage.homology.graded_resolution import GradedFreeResolution @@ -140,8 +142,15 @@ class GradedFreeResolution(FreeResolution): S(0) <-- S(-2)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3) <-- 0 sage: len(r) 2 + + sage: I = S.ideal([z^2 - y*w, y*z - x*w, y - x]) + sage: I.is_homogeneous() + True + sage: R = GradedFreeResolution(I) + sage: R + S(0) <-- S(-1)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3)⊕S(-4) <-- S(-5) <-- 0 """ - def __init__(self, ideal, degrees=None, shifts=None, name='S', algorithm='heuristic'): + def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuristic'): """ Initialize. @@ -153,16 +162,16 @@ def __init__(self, ideal, degrees=None, shifts=None, name='S', algorithm='heuris sage: r = GradedFreeResolution(I) sage: TestSuite(r).run(skip=['_test_pickling']) """ - super().__init__(ideal, name=name, algorithm=algorithm) + super().__init__(module, name=name, algorithm=algorithm) nvars = self._base_ring.ngens() - if isinstance(self._ideal, Ideal_generic): + if isinstance(self._module, Ideal_generic): rank = 1 - elif isinstance(self._ideal, Module_free_ambient): + elif isinstance(self._module, Module_free_ambient): rank = self._m().nrows() - elif isinstance(self._ideal, Matrix_mpolynomial_dense): - rank = self._ideal.ncols() + elif isinstance(self._module, Matrix_mpolynomial_dense): + rank = self._module.ncols() if degrees is None: degrees = nvars * (1,) # standard grading @@ -266,8 +275,8 @@ def _repr_module(self, i): EXAMPLES:: sage: from sage.homology.graded_resolution import GradedFreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = GradedFreeResolution(I) sage: r._repr_module(0) 'S(0)' @@ -307,8 +316,8 @@ def shifts(self, i): EXAMPLES:: sage: from sage.homology.graded_resolution import GradedFreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = GradedFreeResolution(I) sage: r.shifts(0) [0] @@ -338,14 +347,13 @@ def betti(self, i, a=None): INPUT: - ``i`` -- nonnegative integer - - ``a`` -- a degree; if ``None``, return Betti numbers in all degrees EXAMPLES:: sage: from sage.homology.graded_resolution import GradedFreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = GradedFreeResolution(I) sage: r.betti(0) {0: 1} @@ -388,8 +396,8 @@ def K_polynomial(self, names=None): EXAMPLES:: sage: from sage.homology.graded_resolution import GradedFreeResolution - sage: P. = PolynomialRing(QQ) - sage: I = P.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) + sage: S. = PolynomialRing(QQ) + sage: I = S.ideal([y*w - z^2, -x*w + y*z, x*z - y^2]) sage: r = GradedFreeResolution(I) sage: r.K_polynomial() 2*t^3 - 3*t^2 + 1 From 32403e99d99b7ba0833a516da28f5d307c605f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 6 Aug 2022 18:05:55 +0200 Subject: [PATCH 199/591] a few rst fixes in pyx files --- src/sage/coding/codecan/codecan.pyx | 6 ++-- src/sage/graphs/distances_all_pairs.pyx | 5 ++-- .../vertex_separation.pyx | 2 +- src/sage/graphs/matchpoly.pyx | 2 +- .../perm_gps/partn_ref/data_structures.pyx | 5 ++-- .../perm_gps/partn_ref/refinement_binary.pyx | 28 +++++++++++-------- .../partn_ref2/refinement_generic.pyx | 2 +- .../groups/perm_gps/permgroup_element.pyx | 12 ++++---- 8 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/sage/coding/codecan/codecan.pyx b/src/sage/coding/codecan/codecan.pyx index e88b560fef4..5320a49b179 100644 --- a/src/sage/coding/codecan/codecan.pyx +++ b/src/sage/coding/codecan/codecan.pyx @@ -369,7 +369,7 @@ cdef class InnerGroup: return self.transporter def __repr__(self): - """ + r""" EXAMPLES:: sage: from sage.coding.codecan.codecan import InnerGroup @@ -378,7 +378,7 @@ cdef class InnerGroup: frobenius power = 1 and partition = 0 -> 0 1 -> 1 2 -> 2 3 -> 3 4 -> 4 5 -> 5 6 -> 6 7 -> 7 8 -> 8 9 -> 9 """ - return "Subgroup of (GL(k,q) times \GF{q}^n ) rtimes Aut(\GF{q}) " + \ + return r"Subgroup of (GL(k,q) times \GF{q}^n ) rtimes Aut(\GF{q}) " + \ "with rank = %s, frobenius power = %s and partition =%s" % (self.rank, self.frob_pow, OP_string(self.row_partition)) @@ -741,7 +741,7 @@ cdef class PartitionRefinementLinearCode(PartitionRefinement_generic): return self._inner_group_stabilizer_order cdef _init_point_hyperplane_incidence(self): - """ + r""" Compute a set of codewords `W` of `C` (generated by self) which is compatible with the group action, i.e. if we start with some other code `(g,\pi)C` the result should be `(g,\pi)W`. diff --git a/src/sage/graphs/distances_all_pairs.pyx b/src/sage/graphs/distances_all_pairs.pyx index 2b4955737dc..f33c9beebd2 100644 --- a/src/sage/graphs/distances_all_pairs.pyx +++ b/src/sage/graphs/distances_all_pairs.pyx @@ -2079,7 +2079,7 @@ def wiener_index(G): ################ cdef uint64_t c_szeged_index_low_memory(short_digraph sd): - """ + r""" Return the Szeged index of the graph. Let `G = (V, E)` be a connected simple graph, and for any `uv\in E`, let @@ -2185,8 +2185,9 @@ cdef uint64_t c_szeged_index_low_memory(short_digraph sd): return s + cdef uint64_t c_szeged_index_high_memory(short_digraph sd): - """ + r""" Return the Szeged index of the graph. Let `G = (V, E)` be a connected graph, and for any `uv\in E`, let `N_u(uv) = diff --git a/src/sage/graphs/graph_decompositions/vertex_separation.pyx b/src/sage/graphs/graph_decompositions/vertex_separation.pyx index 07ed7855558..9b0e2431045 100644 --- a/src/sage/graphs/graph_decompositions/vertex_separation.pyx +++ b/src/sage/graphs/graph_decompositions/vertex_separation.pyx @@ -475,7 +475,7 @@ def linear_ordering_to_path_decomposition(G, L): def pathwidth(self, k=None, certificate=False, algorithm="BAB", verbose=False, max_prefix_length=20, max_prefix_number=10**6): - """ + r""" Compute the pathwidth of ``self`` (and provides a decomposition) INPUT: diff --git a/src/sage/graphs/matchpoly.pyx b/src/sage/graphs/matchpoly.pyx index 36c6c8fb2c4..444d99ebee3 100644 --- a/src/sage/graphs/matchpoly.pyx +++ b/src/sage/graphs/matchpoly.pyx @@ -50,7 +50,7 @@ x = polygen(ZZ, 'x') def matching_polynomial(G, complement=True, name=None): - """ + r""" Computes the matching polynomial of the graph `G`. If `p(G, k)` denotes the number of `k`-matchings (matchings with `k` edges) diff --git a/src/sage/groups/perm_gps/partn_ref/data_structures.pyx b/src/sage/groups/perm_gps/partn_ref/data_structures.pyx index 90995722d64..74065fe1fec 100644 --- a/src/sage/groups/perm_gps/partn_ref/data_structures.pyx +++ b/src/sage/groups/perm_gps/partn_ref/data_structures.pyx @@ -828,11 +828,12 @@ cdef SC_print_level(StabilizerChain *SC, int level): print('| labels {}'.format([SC.labels [level][i] for i from 0 <= i < n])) print('|') print('| generators {}'.format([[SC.generators [level][n*i + j] for j from 0 <= j < n] for i from 0 <= i < SC.num_gens[level]])) - print('\ inverses {}'.format([[SC.gen_inverses[level][n*i + j] for j from 0 <= j < n] for i from 0 <= i < SC.num_gens[level]])) + print(r'\ inverses {}'.format([[SC.gen_inverses[level][n*i + j] for j from 0 <= j < n] for i from 0 <= i < SC.num_gens[level]])) else: print('/ level {}'.format(level)) print('|') - print('\ base_size {}'.format(SC.base_size)) + print(r'\ base_size {}'.format(SC.base_size)) + cdef StabilizerChain *SC_new_base(StabilizerChain *SC, int *base, int base_len): """ diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx index 5f54d4f8ac2..f13fccf891a 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx @@ -607,7 +607,7 @@ cdef int ith_word_nonlinear(BinaryCodeStruct self, int i, bitset_s *word): return 0 cdef int refine_by_bip_degree(PartitionStack *col_ps, void *S, int *cells_to_refine_by, int ctrb_len): - """ + r""" Refines the input partition by checking degrees of vertices to the given cells in the associated bipartite graph (vertices split into columns and words). @@ -731,11 +731,14 @@ cdef int refine_by_bip_degree(PartitionStack *col_ps, void *S, int *cells_to_ref return invariant cdef int compare_linear_codes(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree): - """ + r""" Compare gamma_1(S1) and gamma_2(S2). - Return return -1 if gamma_1(S1) < gamma_2(S2), 0 if gamma_1(S1) == gamma_2(S2), - 1 if gamma_1(S1) > gamma_2(S2). (Just like the python \code{cmp}) function. + This returns: + + - -1 if gamma_1(S1) < gamma_2(S2), + - 0 if gamma_1(S1) == gamma_2(S2), + - 1 if gamma_1(S1) > gamma_2(S2). Abstractly, what this function does is relabel the basis of B by gamma_1 and gamma_2, run a row reduction on each, and verify that the matrices are the @@ -745,9 +748,9 @@ cdef int compare_linear_codes(int *gamma_1, int *gamma_2, void *S1, void *S2, in code has a 1 in the entry in which they differ is reported as larger. INPUT: - gamma_1, gamma_2 -- list permutations (inverse) - S1, S2 -- binary code struct objects + - gamma_1, gamma_2 -- list permutations (inverse) + - S1, S2 -- binary code struct objects """ cdef int i, piv_loc_1, piv_loc_2, cur_col, cur_row=0 cdef bint is_pivot_1, is_pivot_2 @@ -804,16 +807,19 @@ cdef int compare_linear_codes(int *gamma_1, int *gamma_2, void *S1, void *S2, in return 0 cdef int compare_nonlinear_codes(int *gamma_1, int *gamma_2, void *S1, void *S2, int degree): - """ + r""" Compare gamma_1(S1) and gamma_2(S2). - Return return -1 if gamma_1(S1) < gamma_2(S2), 0 if gamma_1(S1) == gamma_2(S2), - 1 if gamma_1(S1) > gamma_2(S2). (Just like the python \code{cmp}) function. + This returns: + + - -1 if gamma_1(S1) < gamma_2(S2), + - 0 if gamma_1(S1) == gamma_2(S2), + - 1 if gamma_1(S1) > gamma_2(S2). INPUT: - gamma_1, gamma_2 -- list permutations (inverse) - S1, S2 -- a binary code struct object + - gamma_1, gamma_2 -- list permutations (inverse) + - S1, S2 -- a binary code struct object """ cdef int side=0, i, start, end, n_one_1, n_one_2, cur_col cdef int where_0, where_1 diff --git a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx index 2fcb0363a8b..71e6c1fc94d 100644 --- a/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx +++ b/src/sage/groups/perm_gps/partn_ref2/refinement_generic.pyx @@ -913,7 +913,7 @@ cdef class PartitionRefinement_generic: "\\begin{tikzpicture}\n" + "\\tikzset{level distance=3cm, edge from parent/.style=" + "{draw, edge from parent path={(\\tikzparentnode.south) -- (\\tikzchildnode.north)}}}\n" + - "\Tree") + "\\Tree") self._latex_debug_string += "[." self._latex_act_node() diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 037884f55da..99cf04054cf 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -1175,7 +1175,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return result cpdef _act_on_(self, x, bint self_on_left): - """ + r""" Return the result of the action of ``self`` on ``x``. For example, if ``x=f(z)`` is a polynomial, then this function returns @@ -1619,7 +1619,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return ~self def sign(self): - """ + r""" Returns the sign of self, which is `(-1)^{s}`, where `s` is the number of swaps. @@ -1857,12 +1857,12 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return _Partitions(cycle_type) def has_descent(self, i, side = "right", positive = False): - """ + r""" INPUT: - - ``i``: an element of the index set - - ``side``: "left" or "right" (default: "right") - - ``positive``: a boolean (default: False) + - ``i`` -- an element of the index set + - ``side`` -- "left" or "right" (default: "right") + - ``positive`` -- a boolean (default: False) Returns whether ``self`` has a left (resp. right) descent at position ``i``. If ``positive`` is True, then test for a non From b3ab217f4f610729b64738d5cc42053a85270d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 6 Aug 2022 18:33:37 +0200 Subject: [PATCH 200/591] minor tweaks in the doc/ --- src/doc/en/developer/coding_in_other.rst | 112 +++++++++--------- .../algebraic_combinatorics/n_cube.rst | 4 +- src/doc/en/thematic_tutorials/lie/affine.rst | 3 +- .../lie/branching_rules.rst | 35 +++--- .../numerical_sage/cvxopt.rst | 25 ++-- .../numerical_sage/numpy.rst | 50 ++++---- .../numerical_sage/scipy.rst | 4 +- .../steenrod_algebra_modules.rst | 3 +- 8 files changed, 118 insertions(+), 118 deletions(-) diff --git a/src/doc/en/developer/coding_in_other.rst b/src/doc/en/developer/coding_in_other.rst index 6693aed5b8b..e7891af92d7 100644 --- a/src/doc/en/developer/coding_in_other.rst +++ b/src/doc/en/developer/coding_in_other.rst @@ -106,8 +106,7 @@ convert output from PARI to Sage objects: def frobenius(self, flag=0, var='x'): """ - Return the Frobenius form (rational canonical form) of this - matrix. + Return the Frobenius form (rational canonical form) of this matrix. INPUT: @@ -125,7 +124,7 @@ convert output from PARI to Sage objects: - ``var`` -- a string (default: 'x') - ALGORITHM: uses PARI's matfrobenius() + ALGORITHM: uses PARI's :pari:`matfrobenius` EXAMPLES:: @@ -143,15 +142,15 @@ convert output from PARI to Sage objects: raise ArithmeticError("frobenius matrix of non-square matrix not defined.") v = self.__pari__().matfrobenius(flag) - if flag==0: + if flag == 0: return self.matrix_space()(v.python()) - elif flag==1: + elif flag == 1: r = PolynomialRing(self.base_ring(), names=var) retr = [] for f in v: retr.append(eval(str(f).replace("^","**"), {'x':r.gen()}, r.gens_dict())) return retr - elif flag==2: + elif flag == 2: F = matrix_space.MatrixSpace(QQ, self.nrows())(v[0].python()) B = matrix_space.MatrixSpace(QQ, self.nrows())(v[1].python()) return F, B @@ -212,11 +211,13 @@ object. Return the Cartan matrix of given Chevalley type and rank. INPUT: - type -- a Chevalley letter name, as a string, for - a family type of simple Lie algebras - rank -- an integer (legal for that type). - EXAMPLES: + - type -- a Chevalley letter name, as a string, for + a family type of simple Lie algebras + - rank -- an integer (legal for that type). + + EXAMPLES:: + sage: cartan_matrix("A",5) [ 2 -1 0 0 0] [-1 2 -1 0 0] @@ -227,12 +228,11 @@ object. [ 2 -1] [-3 2] """ - - L = gap.SimpleLieAlgebra('"%s"'%type, rank, 'Rationals') + L = gap.SimpleLieAlgebra('"%s"' % type, rank, 'Rationals') R = L.RootSystem() sM = R.CartanMatrix() ans = eval(str(sM)) - MS = MatrixSpace(QQ, rank) + MS = MatrixSpace(QQ, rank) return MS(ans) The output ``ans`` is a Python list. The last two lines convert that @@ -460,50 +460,51 @@ just that. .. CODE-BLOCK:: python - def points_parser(string_points,F): + def points_parser(string_points, F): """ This function will parse a string of points of X over a finite field F returned by Singular's NSplaces command into a Python list of points with entries from F. - EXAMPLES: + EXAMPLES:: + sage: F = GF(5) sage: points_parser(L,F) ((0, 1, 0), (3, 4, 1), (0, 0, 1), (2, 3, 1), (3, 1, 1), (2, 2, 1)) """ - Pts=[] - n=len(L) - #start block to compute a pt - L1=L - while len(L1)>32: - idx=L1.index(" ") - pt=[] - ## start block1 for compute pt - idx=L1.index(" ") - idx2=L1[idx:].index("\n") - L2=L1[idx:idx+idx2] + Pts = [] + n = len(L) + # start block to compute a pt + L1 = L + while len(L1) > 32: + idx =L1.index(" ") + pt = [] + # start block1 for compute pt + idx = L1.index(" ") + idx2 = L1[idx:].index("\n") + L2 = L1[idx:idx+idx2] pt.append(F(eval(L2))) # end block1 to compute pt - L1=L1[idx+8:] # repeat block 2 more times - ## start block2 for compute pt - idx=L1.index(" ") - idx2=L1[idx:].index("\n") - L2=L1[idx:idx+idx2] + L1 = L1[idx+8:] # repeat block 2 more times + # start block2 for compute pt + idx = L1.index(" ") + idx2 = L1[idx:].index("\n") + L2 = L1[idx:idx+idx2] pt.append(F(eval(L2))) # end block2 to compute pt L1=L1[idx+8:] # repeat block 1 more time - ## start block3 for compute pt + # start block3 for compute pt idx=L1.index(" ") if "\n" in L1[idx:]: - idx2=L1[idx:].index("\n") + idx2 = L1[idx:].index("\n") else: - idx2=len(L1[idx:]) - L2=L1[idx:idx+idx2] + idx2 = len(L1[idx:]) + L2 = L1[idx:idx+idx2] pt.append(F(eval(L2))) # end block3 to compute pt - #end block to compute a pt + # end block to compute a pt Pts.append(tuple(pt)) # repeat until no more pts - L1=L1[idx+8:] # repeat block 2 more times + L1 = L1[idx+8:] # repeat block 2 more times return tuple(Pts) Now it is an easy matter to put these ingredients together into a Sage @@ -519,20 +520,23 @@ ourselves to points of degree one. .. CODE-BLOCK:: python - def places_on_curve(f,F): + def places_on_curve(f, F): """ INPUT: - f -- element of F[x,y], defining X: f(x,y)=0 - F -- a finite field of *prime order* + + - f -- element of F[x,y], defining X: f(x,y)=0 + - F -- a finite field of *prime order* OUTPUT: - integer -- the number of places in X of degree d=1 over F - EXAMPLES: - sage: F=GF(5) - sage: R=PolynomialRing(F,2,names=["x","y"]) - sage: x,y=R.gens() - sage: f=y^2-x^9-x + integer -- the number of places in X of degree d=1 over F + + EXAMPLES:: + + sage: F = GF(5) + sage: R = PolynomialRing(F,2,names=["x","y"]) + sage: x,y = R.gens() + sage: f = y^2-x^9-x sage: places_on_curve(f,F) ((0, 1, 0), (3, 4, 1), (0, 0, 1), (2, 3, 1), (3, 1, 1), (2, 2, 1)) """ @@ -600,7 +604,7 @@ function is not required: .. CODE-BLOCK:: python - def places_on_curve(f,F): + def places_on_curve(f, F): p = F.characteristic() if F.degree() > 1: raise NotImplementedError @@ -677,7 +681,7 @@ This uses the class ``Expect`` to set up the Octave interface: """ Set the variable var to the given value. """ - cmd = '%s=%s;'%(var,value) + cmd = '%s=%s;' % (var,value) out = self.eval(cmd) if out.find("error") != -1: raise TypeError("Error executing code in Octave\nCODE:\n\t%s\nOctave ERROR:\n\t%s"%(cmd, out)) @@ -686,7 +690,7 @@ This uses the class ``Expect`` to set up the Octave interface: """ Get the value of the variable var. """ - s = self.eval('%s'%var) + s = self.eval('%s' % var) i = s.find('=') return s[i+1:] @@ -729,16 +733,16 @@ dumps the user into an Octave interactive shell: raise ValueError("dimensions of A and b must be compatible") from sage.matrix.all import MatrixSpace from sage.rings.all import QQ - MS = MatrixSpace(QQ,m,1) - b = MS(list(b)) # converted b to a "column vector" + MS = MatrixSpace(QQ, m, 1) + b = MS(list(b)) # converted b to a "column vector" sA = self.sage2octave_matrix_string(A) sb = self.sage2octave_matrix_string(b) self.eval("a = " + sA ) self.eval("b = " + sb ) soln = octave.eval("c = a \\ b") - soln = soln.replace("\n\n ","[") - soln = soln.replace("\n\n","]") - soln = soln.replace("\n",",") + soln = soln.replace("\n\n ", "[") + soln = soln.replace("\n\n", "]") + soln = soln.replace("\n", ",") sol = soln[3:] return eval(sol) diff --git a/src/doc/en/thematic_tutorials/algebraic_combinatorics/n_cube.rst b/src/doc/en/thematic_tutorials/algebraic_combinatorics/n_cube.rst index a31dff543a2..307291b10cc 100644 --- a/src/doc/en/thematic_tutorials/algebraic_combinatorics/n_cube.rst +++ b/src/doc/en/thematic_tutorials/algebraic_combinatorics/n_cube.rst @@ -19,8 +19,8 @@ The vertices of the `n`-cube can be described by vectors in The distance function measures in how many slots two vectors in `\mathbb{Z}_2^n` differ:: - sage: u=(1,0,1,1,1,0) - sage: v=(0,0,1,1,0,0) + sage: u = (1,0,1,1,1,0) + sage: v = (0,0,1,1,0,0) sage: dist(u,v) 2 diff --git a/src/doc/en/thematic_tutorials/lie/affine.rst b/src/doc/en/thematic_tutorials/lie/affine.rst index 124bf1f2e8d..320ff381783 100644 --- a/src/doc/en/thematic_tutorials/lie/affine.rst +++ b/src/doc/en/thematic_tutorials/lie/affine.rst @@ -381,7 +381,7 @@ The column vector `a` with these entries spans the nullspace of `A`:: sage: RS = RootSystem(['E',6,2]); RS Root system of type ['F', 4, 1]^* - sage: A=RS.cartan_matrix(); A + sage: A = RS.cartan_matrix(); A [ 2 -1 0 0 0] [-1 2 -1 0 0] [ 0 -1 2 -2 0] @@ -471,4 +471,3 @@ It may be constructed in Sage as follows:: See the documentation in :mod:`~sage.combinat.root_system.extended_affine_weyl_group` if you need this. - diff --git a/src/doc/en/thematic_tutorials/lie/branching_rules.rst b/src/doc/en/thematic_tutorials/lie/branching_rules.rst index 8ae0a9591ff..40eaf488f1d 100644 --- a/src/doc/en/thematic_tutorials/lie/branching_rules.rst +++ b/src/doc/en/thematic_tutorials/lie/branching_rules.rst @@ -50,7 +50,7 @@ Sage has a class ``BranchingRule`` for branching rules. The function the natural embedding of `Sp(4)` into `SL(4)` corresponds to the branching rule that we may create as follows:: - sage: b=branching_rule("A3","C2",rule="symmetric"); b + sage: b = branching_rule("A3","C2",rule="symmetric"); b symmetric branching rule A3 => C2 The name "symmetric" of this branching rule will be @@ -62,10 +62,10 @@ Here ``A3`` and ``C2`` are the Cartan types of the groups Now we may see how representations of `SL(4)` decompose into irreducibles when they are restricted to `Sp(4)`:: - sage: A3=WeylCharacterRing("A3",style="coroots") - sage: chi=A3(1,0,1); chi.degree() + sage: A3 = WeylCharacterRing("A3",style="coroots") + sage: chi = A3(1,0,1); chi.degree() 15 - sage: C2=WeylCharacterRing("C2",style="coroots") + sage: C2 = WeylCharacterRing("C2",style="coroots") sage: chi.branch(C2,rule=b) C2(0,1) + C2(2,0) @@ -95,13 +95,13 @@ Observe that we do not have to build the intermediate :: - sage: C4=WeylCharacterRing("C4",style="coroots") - sage: b1=branching_rule("C4","A3","levi")*branching_rule("A3","C2","symmetric"); b1 + sage: C4 = WeylCharacterRing("C4",style="coroots") + sage: b1 = branching_rule("C4","A3","levi")*branching_rule("A3","C2","symmetric"); b1 composite branching rule C4 => (levi) A3 => (symmetric) C2 - sage: b2=branching_rule("C4","C2xC2","orthogonal_sum")*branching_rule("C2xC2","C2","proj1"); b2 + sage: b2 = branching_rule("C4","C2xC2","orthogonal_sum")*branching_rule("C2xC2","C2","proj1"); b2 composite branching rule C4 => (orthogonal_sum) C2xC2 => (proj1) C2 - sage: C2=WeylCharacterRing("C2",style="coroots") - sage: C4=WeylCharacterRing("C4",style="coroots") + sage: C2 = WeylCharacterRing("C2",style="coroots") + sage: C4 = WeylCharacterRing("C4",style="coroots") sage: [C4(2,0,0,1).branch(C2, rule=br) for br in [b1,b2]] [4*C2(0,0) + 7*C2(0,1) + 15*C2(2,0) + 7*C2(0,2) + 11*C2(2,1) + C2(0,3) + 6*C2(4,0) + 3*C2(2,2), 10*C2(0,0) + 40*C2(1,0) + 50*C2(0,1) + 16*C2(2,0) + 20*C2(1,1) + 4*C2(3,0) + 5*C2(2,1)] @@ -187,7 +187,7 @@ Sage has a database of maximal subgroups for every simple Cartan type of rank `\le 8`. You may access this with the ``maximal_subgroups`` method of the Weyl character ring:: - sage: E7=WeylCharacterRing("E7",style="coroots") + sage: E7 = WeylCharacterRing("E7",style="coroots") sage: E7.maximal_subgroups() A7:branching_rule("E7","A7","extended") E6:branching_rule("E7","E6","levi") @@ -212,7 +212,7 @@ as follows:: sage: b = E7.maximal_subgroup("A2"); b miscellaneous branching rule E7 => A2 - sage: [E7,A2]=[WeylCharacterRing(x,style="coroots") for x in ["E7","A2"]] + sage: E7, A2 = [WeylCharacterRing(x,style="coroots") for x in ["E7","A2"]] sage: E7(1,0,0,0,0,0,0).branch(A2,rule=b) A2(1,1) + A2(4,4) @@ -236,8 +236,8 @@ complete up to inner automorphisms. For example, `E_6` has a nontrivial Dynkin diagram automorphism so it has an outer automorphism that is not inner:: - sage: [E6,A2xG2]=[WeylCharacterRing(x,style="coroots") for x in ["E6","A2xG2"]] - sage: b=E6.maximal_subgroup("A2xG2"); b + sage: E6, A2xG2 = [WeylCharacterRing(x,style="coroots") for x in ["E6","A2xG2"]] + sage: b = E6.maximal_subgroup("A2xG2"); b miscellaneous branching rule E6 => A2xG2 sage: E6(1,0,0,0,0,0).branch(A2xG2,rule=b) A2xG2(0,1,1,0) + A2xG2(2,0,0,0) @@ -250,7 +250,7 @@ the `A_2\times G_2` subgroup is changed to a different one by the outer automorphism. To obtain the second branching rule, we compose the given one with this automorphism:: - sage: b1=branching_rule("E6","E6","automorphic")*b; b1 + sage: b1 = branching_rule("E6","E6","automorphic")*b; b1 composite branching rule E6 => (automorphic) E6 => (miscellaneous) A2xG2 .. _levi_branch_rules: @@ -533,8 +533,8 @@ construct the branching rule to `A_5` we may proceed as follows:: sage: b = branching_rule("E6","A5xA1","extended")*branching_rule("A5xA1","A5","proj1"); b composite branching rule E6 => (extended) A5xA1 => (proj1) A5 - sage: E6=WeylCharacterRing("E6",style="coroots") - sage: A5=WeylCharacterRing("A5",style="coroots") + sage: E6 = WeylCharacterRing("E6",style="coroots") + sage: A5 = WeylCharacterRing("A5",style="coroots") sage: E6(0,1,0,0,0,0).branch(A5,rule=b) 3*A5(0,0,0,0,0) + 2*A5(0,0,1,0,0) + A5(1,0,0,0,1) sage: b.describe() @@ -1006,7 +1006,7 @@ representation of `SO(8)` and the two eight-dimensional spin representations. These are permuted by triality:: - sage: D4=WeylCharacterRing("D4",style="coroots") + sage: D4 = WeylCharacterRing("D4",style="coroots") sage: D4(0,0,0,1).branch(D4,rule="triality") D4(1,0,0,0) sage: D4(0,0,0,1).branch(D4,rule="triality").branch(D4,rule="triality") @@ -1021,4 +1021,3 @@ spin representations, as it always does in type `D`:: D4(0,0,1,0) sage: D4(0,0,1,0).branch(D4,rule="automorphic") D4(0,0,0,1) - diff --git a/src/doc/en/thematic_tutorials/numerical_sage/cvxopt.rst b/src/doc/en/thematic_tutorials/numerical_sage/cvxopt.rst index 7b365f60ba4..ba6cfb5fb86 100644 --- a/src/doc/en/thematic_tutorials/numerical_sage/cvxopt.rst +++ b/src/doc/en/thematic_tutorials/numerical_sage/cvxopt.rst @@ -1,11 +1,11 @@ Cvxopt ====== -Cvxopt provides many routines for solving convex optimization +``Cvxopt`` provides many routines for solving convex optimization problems such as linear and quadratic programming packages. It also has a very nice sparse matrix library that provides an interface to -umfpack (the same sparse matrix solver that matlab uses), it also -has a nice interface to lapack. For more details on cvxopt please +``umfpack`` (the same sparse matrix solver that ``matlab`` uses), it also +has a nice interface to ``lapack``. For more details on ``cvxopt`` please refer to its documentation at ``_ Sparse matrices are represented in triplet notation that is as a @@ -32,7 +32,7 @@ by sage: from cvxopt.base import spmatrix # optional - cvxopt sage: from cvxopt.base import matrix as m # optional - cvxopt sage: from cvxopt import umfpack # optional - cvxopt - sage: Integer=int # optional - cvxopt + sage: Integer = int # optional - cvxopt sage: V = [2,3, 3,-1,4, 4,-3,1,2, 2, 6,1] # optional - cvxopt sage: I = [0,1, 0, 2,4, 1, 2,3,4, 2, 1,4] # optional - cvxopt sage: J = [0,0, 1, 1,1, 2, 2,2,2, 3, 4,4] # optional - cvxopt @@ -61,7 +61,7 @@ we could do the following. [ 0 -1.00e+00 -3.00e+00 2.00e+00 0 ] [ 0 0 1.00e+00 0 0 ] [ 0 4.00e+00 2.00e+00 0 1.00e+00] - sage: C=m(B) # optional - cvxopt + sage: C = m(B) # optional - cvxopt sage: umfpack.linsolve(A,C) # optional - cvxopt sage: print(C) # optional - cvxopt [ 5.79e-01] @@ -71,7 +71,7 @@ we could do the following. [-7.89e-01] Note the solution is stored in :math:`B` afterward. also note the -m(B), this turns our numpy array into a format cvxopt understands. +m(B), this turns our numpy array into a format ``cvxopt`` understands. You can directly create a cvxopt matrix using cvxopt's own matrix command, but I personally find numpy arrays nicer. Also note we explicitly set the shape of the numpy array to make it clear it was @@ -81,12 +81,12 @@ We could compute the approximate minimum degree ordering by doing :: - sage: RealNumber=float # optional - cvxopt - sage: Integer=int # optional - cvxopt + sage: RealNumber = float # optional - cvxopt + sage: Integer = int # optional - cvxopt sage: from cvxopt.base import spmatrix # optional - cvxopt sage: from cvxopt import amd # optional - cvxopt - sage: A=spmatrix([10,3,5,-2,5,2],[0,2,1,2,2,3],[0,0,1,1,2,3]) # optional - cvxopt - sage: P=amd.order(A) # optional - cvxopt + sage: A = spmatrix([10,3,5,-2,5,2],[0,2,1,2,2,3],[0,0,1,1,2,3]) # optional - cvxopt + sage: P = amd.order(A) # optional - cvxopt sage: print(P) # optional - cvxopt [ 1] [ 0] @@ -108,8 +108,8 @@ For a simple linear programming example, if we want to solve :: - sage: RealNumber=float # optional - cvxopt - sage: Integer=int # optional - cvxopt + sage: RealNumber = float # optional - cvxopt + sage: Integer = int # optional - cvxopt sage: from cvxopt.base import matrix as m # optional - cvxopt sage: from cvxopt import solvers # optional - cvxopt sage: c = m([-4., -5.]) # optional - cvxopt @@ -130,4 +130,3 @@ For a simple linear programming example, if we want to solve sage: print(sol['x']) # optional - cvxopt # ... below since can get -00 or +00 depending on architecture [ 1.00e...00] [ 1.00e+00] - diff --git a/src/doc/en/thematic_tutorials/numerical_sage/numpy.rst b/src/doc/en/thematic_tutorials/numerical_sage/numpy.rst index 6e2bdbfb0c6..dbc2de71d42 100644 --- a/src/doc/en/thematic_tutorials/numerical_sage/numpy.rst +++ b/src/doc/en/thematic_tutorials/numerical_sage/numpy.rst @@ -15,7 +15,7 @@ create an array. :: - sage: l=numpy.array([1,2,3]) + sage: l = numpy.array([1,2,3]) sage: l array([1, 2, 3]) @@ -34,10 +34,10 @@ hardware float or int. :: - sage: l=numpy.array([2**40, 3**40, 4**40]) + sage: l = numpy.array([2**40, 3**40, 4**40]) sage: l array([1099511627776, 12157665459056928801, 1208925819614629174706176], dtype=object) - sage: a=2.0000000000000000001 + sage: a = 2.0000000000000000001 sage: a.prec() # higher precision than hardware floating point numbers 67 sage: numpy.array([a,2*a,3*a]) @@ -55,7 +55,7 @@ can be operated on much faster. :: - sage: l=numpy.array([1.0, 2.0, 3.0]) + sage: l = numpy.array([1.0, 2.0, 3.0]) sage: l.dtype dtype('float64') @@ -68,7 +68,7 @@ an array. :: - sage: l=numpy.array([1,2,3], dtype=float) + sage: l = numpy.array([1,2,3], dtype=float) sage: l.dtype dtype('float64') @@ -80,7 +80,7 @@ well as take slices :: - sage: l=numpy.array(range(10),dtype=float) + sage: l = numpy.array(range(10),dtype=float) sage: l[3] 3.0 sage: l[3:6] @@ -128,7 +128,7 @@ This is basically equivalent to the following :: - sage: m=numpy.matrix([[1,2],[3,4]]) + sage: m = numpy.matrix([[1,2],[3,4]]) sage: m matrix([[1, 2], [3, 4]]) @@ -184,8 +184,8 @@ NumPy arrays can be sliced as well :: - sage: n=numpy.array(range(25),dtype=float) - sage: n.shape=(5,5) + sage: n = numpy.array(range(25),dtype=float) + sage: n.shape = (5,5) sage: n[2:4,1:3] array([[11., 12.], [16., 17.]]) @@ -197,8 +197,8 @@ the original :: - sage: m=n[2:4,1:3] - sage: m[0,0]=100 + sage: m = n[2:4,1:3] + sage: m[0,0] = 100 sage: n array([[ 0., 1., 2., 3., 4.], [ 5., 6., 7., 8., 9.], @@ -222,7 +222,7 @@ Some particularly useful commands are :: - sage: x=numpy.arange(0,2,.1,dtype=float) + sage: x = numpy.arange(0,2,.1,dtype=float) sage: x array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9]) @@ -235,13 +235,13 @@ from 0 to 2. There is a useful command :meth:`numpy.r_` that is best explained b :: sage: from numpy import r_ - sage: j=complex(0,1) - sage: RealNumber=float - sage: Integer=int - sage: n=r_[0.0:5.0] + sage: j = complex(0,1) + sage: RealNumber = float + sage: Integer = int + sage: n = r_[0.0:5.0] sage: n array([0., 1., 2., 3., 4.]) - sage: n=r_[0.0:5.0, [0.0]*5] + sage: n = r_[0.0:5.0, [0.0]*5] sage: n array([0., 1., 2., 3., 4., 0., 0., 0., 0., 0.]) @@ -267,7 +267,7 @@ arrays. We can combine all of these techniques :: - sage: n=r_[0.0:5.0:11*j,int(5)*[0.0],-5.0:0.0] + sage: n = r_[0.0:5.0:11*j,int(5)*[0.0],-5.0:0.0] sage: n array([ 0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. , 0. , 0. , 0. , 0. , 0. , -5. , -4. , -3. , -2. , -1. ]) @@ -280,13 +280,13 @@ an equally spaced grid with `\Delta x = \Delta y = .25` for :: sage: import numpy - sage: j=complex(0,1) + sage: j = complex(0,1) sage: def f(x,y): ....: return x**2+y**2 sage: from numpy import meshgrid - sage: x=numpy.r_[0.0:1.0:5*j] - sage: y=numpy.r_[0.0:1.0:5*j] - sage: xx,yy= meshgrid(x,y) + sage: x = numpy.r_[0.0:1.0:5*j] + sage: y = numpy.r_[0.0:1.0:5*j] + sage: xx,yy = meshgrid(x,y) sage: xx array([[0. , 0.25, 0.5 , 0.75, 1. ], [0. , 0.25, 0.5 , 0.75, 1. ], @@ -321,9 +321,9 @@ equation `Ax=b` do sage: import numpy sage: from numpy import linalg - sage: A=numpy.random.randn(5,5) - sage: b=numpy.array(range(1,6)) - sage: x=linalg.solve(A,b) + sage: A = numpy.random.randn(5,5) + sage: b = numpy.array(range(1,6)) + sage: x = linalg.solve(A,b) sage: numpy.dot(A,x) array([1., 2., 3., 4., 5.]) diff --git a/src/doc/en/thematic_tutorials/numerical_sage/scipy.rst b/src/doc/en/thematic_tutorials/numerical_sage/scipy.rst index 8d3e788d87a..1cab99dda26 100644 --- a/src/doc/en/thematic_tutorials/numerical_sage/scipy.rst +++ b/src/doc/en/thematic_tutorials/numerical_sage/scipy.rst @@ -95,8 +95,8 @@ code. ....: return[y[1],-y[0]-10*y[1]*(y[0]**2-1)] sage: def j_1(y,t): ....: return [ [0, 1.0],[-2.0*10*y[0]*y[1]-1.0,-10*(y[0]*y[0]-1.0)] ] - sage: x= numpy.arange(0,100,.1) - sage: y=integrate.odeint(f_1,[1,0],x,Dfun=j_1) + sage: x = numpy.arange(0,100,.1) + sage: y = integrate.odeint(f_1,[1,0],x,Dfun=j_1) We could plot the solution if we wanted by doing diff --git a/src/doc/en/thematic_tutorials/steenrod_algebra_modules.rst b/src/doc/en/thematic_tutorials/steenrod_algebra_modules.rst index 6d6513af258..f038ff7acaa 100644 --- a/src/doc/en/thematic_tutorials/steenrod_algebra_modules.rst +++ b/src/doc/en/thematic_tutorials/steenrod_algebra_modules.rst @@ -92,7 +92,7 @@ The generators are themselves elements of the module:: One can produce an element from a given set of algebra coefficients:: - sage: coeffs=[Sq(15), Sq(10)*Sq(1,1), Sq(8)] + sage: coeffs = [Sq(15), Sq(10)*Sq(1,1), Sq(8)] sage: x = M(coeffs); x Sq(15)*g[0] + (Sq(4,1,1)+Sq(7,0,1)+Sq(11,1))*g[1] + Sq(8)*g[7] @@ -772,4 +772,3 @@ re-ordering of list elements), so the following comparison is reassuring:: True sage: flift[3] == lifts[1] True - From 489534142db0e4c0f6bced0ab7e989382d0741f9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 12:05:07 -0700 Subject: [PATCH 201/591] build/pkgs/rubiks/spkg-install.in: Remove obsolete workaround --- build/pkgs/rubiks/spkg-install.in | 8 -------- 1 file changed, 8 deletions(-) diff --git a/build/pkgs/rubiks/spkg-install.in b/build/pkgs/rubiks/spkg-install.in index e03c76e432a..c979824251a 100644 --- a/build/pkgs/rubiks/spkg-install.in +++ b/build/pkgs/rubiks/spkg-install.in @@ -2,14 +2,6 @@ ## rubiks ########################################### -# Work around a bug in gcc 4.6.0: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48702 -if [ "`testcc.sh $CC`" = GCC ] ; then - if $CC -dumpversion 2>/dev/null |grep >/dev/null '^4\.6\.[01]$' ; then - echo "Warning: Working around bug in gcc 4.6.0" - EXTRA_FLAG="-fno-ivopts" - fi -fi - # Most packages do not need all these set # But it is better to do them all each time, rather than ommit # a flag by mistake. From 6b9e1d7bed3809813968e46b6cfe853c534bdbcb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 12:06:24 -0700 Subject: [PATCH 202/591] build/pkgs/rubiks/spkg-install.in: Work around compiler hang with XCode --- build/pkgs/rubiks/spkg-install.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/pkgs/rubiks/spkg-install.in b/build/pkgs/rubiks/spkg-install.in index c979824251a..893485ea0bd 100644 --- a/build/pkgs/rubiks/spkg-install.in +++ b/build/pkgs/rubiks/spkg-install.in @@ -42,6 +42,11 @@ else INSTALL=install; export INSTALL fi +if [ $UNAME = "Darwin" ]; then + # #34293: Work around compiler hang + export CXXFLAGS="$CXXFLAGS -O1" +fi + cd src echo "Building Rubiks cube solvers" From 43bda8389306e2589e151e506ef7c3ab719a5c87 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 6 Aug 2022 13:52:18 -0700 Subject: [PATCH 203/591] trac 34291: downgrade some broken optional packages to experimental --- build/pkgs/barvinok/type | 2 +- build/pkgs/p_group_cohomology/type | 2 +- build/pkgs/polylib/type | 2 +- build/pkgs/r_jupyter/type | 2 +- build/pkgs/symengine_py/type | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/pkgs/barvinok/type b/build/pkgs/barvinok/type index 134d9bc32d5..af4d63af86d 100644 --- a/build/pkgs/barvinok/type +++ b/build/pkgs/barvinok/type @@ -1 +1 @@ -optional +experimental \ No newline at end of file diff --git a/build/pkgs/p_group_cohomology/type b/build/pkgs/p_group_cohomology/type index 134d9bc32d5..af4d63af86d 100644 --- a/build/pkgs/p_group_cohomology/type +++ b/build/pkgs/p_group_cohomology/type @@ -1 +1 @@ -optional +experimental \ No newline at end of file diff --git a/build/pkgs/polylib/type b/build/pkgs/polylib/type index 134d9bc32d5..af4d63af86d 100644 --- a/build/pkgs/polylib/type +++ b/build/pkgs/polylib/type @@ -1 +1 @@ -optional +experimental \ No newline at end of file diff --git a/build/pkgs/r_jupyter/type b/build/pkgs/r_jupyter/type index 134d9bc32d5..af4d63af86d 100644 --- a/build/pkgs/r_jupyter/type +++ b/build/pkgs/r_jupyter/type @@ -1 +1 @@ -optional +experimental \ No newline at end of file diff --git a/build/pkgs/symengine_py/type b/build/pkgs/symengine_py/type index 134d9bc32d5..af4d63af86d 100644 --- a/build/pkgs/symengine_py/type +++ b/build/pkgs/symengine_py/type @@ -1 +1 @@ -optional +experimental \ No newline at end of file From 0845f0381c559acfa648c9828099ca0c4d38ba8a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 14:23:29 -0700 Subject: [PATCH 204/591] Triangulation.boundary_simplicial_complex: Expand example --- src/sage/geometry/triangulation/element.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index ebb60a72584..48f16e8ed06 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -686,15 +686,22 @@ def boundary_simplicial_complex(self): EXAMPLES:: sage: p = polytopes.cuboctahedron() - sage: sc = p.triangulate(engine='internal').boundary_simplicial_complex() - sage: sc + sage: triangulation = p.triangulate(engine='internal') + sage: bd_sc = triangulation.boundary_simplicial_complex() + sage: bd_sc Simplicial complex with 12 vertices and 20 facets The boundary of every convex set is a topological sphere, so it has spherical homology:: - sage: sc.homology() + sage: bd_sc.homology() {0: 0, 1: 0, 2: Z} + + It is a subcomplex of ``self`` as a :meth:`simplicial_complex`:: + + sage: sc = triangulation.simplicial_complex() + sage: all(f in sc for f in bd_sc.maximal_faces()) + True """ from sage.topology.simplicial_complex import SimplicialComplex return SimplicialComplex(self.boundary(), maximality_check=False) From 80165ba864883114469c4dfd14c11796f8bab256 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 14:27:03 -0700 Subject: [PATCH 205/591] Triangulation.boundary_polyhedral_complex: Expand example --- src/sage/geometry/triangulation/element.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index 48f16e8ed06..a2572cf24d2 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -793,9 +793,9 @@ def boundary_polyhedral_complex(self, **kwds): sage: pc = PointConfiguration(P.vertices()) sage: T = pc.placing_triangulation(); T (<0,1,2,7>, <0,1,5,7>, <0,2,3,7>, <0,3,4,7>, <0,4,5,7>, <1,5,6,7>) - sage: C = T.boundary_polyhedral_complex(); C + sage: bd_C = T.boundary_polyhedral_complex(); bd_C Polyhedral complex with 12 maximal cells - sage: [P.vertices_list() for P in C.maximal_cells_sorted()] + sage: [P.vertices_list() for P in bd_C.maximal_cells_sorted()] [[[-1, -1, -1], [-1, -1, 1], [-1, 1, 1]], [[-1, -1, -1], [-1, -1, 1], [1, -1, -1]], [[-1, -1, -1], [-1, 1, -1], [-1, 1, 1]], @@ -808,6 +808,12 @@ def boundary_polyhedral_complex(self, **kwds): [[-1, 1, 1], [1, 1, -1], [1, 1, 1]], [[1, -1, -1], [1, -1, 1], [1, 1, 1]], [[1, -1, -1], [1, 1, -1], [1, 1, 1]]] + + It is a subcomplex of ``self`` as a :meth:`polyhedral_complex`:: + + sage: C = T.polyhedral_complex() + sage: bd_C.is_subcomplex(C) + True """ from sage.geometry.polyhedral_complex import PolyhedralComplex from sage.geometry.polyhedron.constructor import Polyhedron From f4cf82860877717562671f492a9400868cb54ee2 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 6 Aug 2022 14:55:46 -0700 Subject: [PATCH 206/591] trac 34295: remove sage-gdb-commands from Developer's Guide. --- src/doc/en/developer/doctesting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/developer/doctesting.rst b/src/doc/en/developer/doctesting.rst index f00e22042f4..9619460c30f 100644 --- a/src/doc/en/developer/doctesting.rst +++ b/src/doc/en/developer/doctesting.rst @@ -1070,7 +1070,7 @@ appear in real time use the ``--verbose`` flag). To have doctests run under the control of gdb, use the ``--gdb`` flag:: [roed@sage sage-6.0]$ sage -t --gdb src/sage/schemes/elliptic_curves/constructor.py - gdb -x /home/roed/sage-6.0.b5/local/bin/sage-gdb-commands --args python /home/roed/sage-6.0.b5/local/bin/sage-runtests --serial --nthreads 1 --timeout 1048576 --optional sagemath_doc_html,sage --stats_path /home/roed/.sage/timings2.json src/sage/schemes/elliptic_curves/constructor.py + exec gdb --eval-commands="run" --args /home/roed/sage-9.7/local/var/lib/sage/venv-python3.9/bin/python3 sage-runtests --serial --timeout=0 --stats_path=/home/roed/.sage/timings2.json --optional=pip,sage,sage_spkg src/sage/schemes/elliptic_curves/constructor.py GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later From c1e4a2ba3426160e0632cf1453efb5e4ae1e6b1b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 15:00:50 -0700 Subject: [PATCH 207/591] .github/workflows/dist.yml: Deploy wheels to PyPI --- .github/workflows/dist.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index 0e40644d0c5..5086ca60a7c 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -138,6 +138,8 @@ jobs: upload_wheels: needs: build_wheels runs-on: ubuntu-latest + env: + CAN_DEPLOY: ${{ secrets.SAGEMATH_PYPI_API_TOKEN != '' }} steps: - uses: actions/download-artifact@v2 From 65134f1606814d4b3e94e87d84c0b18576bfa180 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 15:23:25 -0700 Subject: [PATCH 208/591] src/sage/geometry/triangulation/element.py: Docstring improvements --- src/sage/geometry/triangulation/element.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index a2572cf24d2..a0e76c3bf54 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -227,8 +227,9 @@ class Triangulation(Element): """ def __init__(self, triangulation, parent, check=True): """ - The constructor of a ``Triangulation`` object. Note that an - internal reference to the underlying ``PointConfiguration`` is + The constructor of a ``Triangulation`` object. + + Note that an internal reference to the underlying ``PointConfiguration`` is kept. INPUT: @@ -236,12 +237,11 @@ def __init__(self, triangulation, parent, check=True): - ``parent`` -- a :class:`~sage.geometry.triangulation.point_configuration.PointConfiguration` - - ``triangulation`` -- an iterable of integers or iterable of - iterables (e.g. a list of lists). In the first case, the - integers specify simplices via - :meth:`PointConfiguration.simplex_to_int`. In the second - case, the point indices of the maximal simplices of the - triangulation. + - ``triangulation`` -- an iterable of integers or an iterable of + iterables (e.g. a list of lists), specifying the maximal simplices + of the triangulation. In the first case, each integer specifies a simplex + by the correspondence :meth:`PointConfiguration.simplex_to_int`. In the second + case, a simplex is specified by listing the indices of the included points. - ``check`` -- boolean. Whether to perform checks that the triangulation is, indeed, a triangulation of the point @@ -370,7 +370,7 @@ def __getitem__(self, i): def __len__(self): """ - Returns the length of the triangulation. + Return the length of the triangulation. TESTS:: @@ -597,7 +597,7 @@ def simplicial_complex(self): @cached_method def _boundary_simplex_dictionary(self): """ - Return facets and the simplices they bound + Return facets and the simplices they bound. TESTS:: @@ -913,7 +913,7 @@ def normal_cone(self): def adjacency_graph(self): """ - Return a graph showing which simplices are adjacent in the triangulation + Return a graph showing which simplices are adjacent in the triangulation. OUTPUT: From 9eebc328897247191872849222dddffc284d4d85 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 15:40:25 -0700 Subject: [PATCH 209/591] src/sage/geometry/polyhedral_complex.py: Expand example of plot method --- src/sage/geometry/polyhedral_complex.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index d8d171e7a87..8f447e96739 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -736,9 +736,13 @@ def plot(self, **kwds): sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) sage: p2 = Polyhedron(vertices=[(1, 2), (0, 0), (0, 2)]) - sage: pc = PolyhedralComplex([p1, p2]) - sage: pc.plot() # optional - sage.plot - Graphics object consisting of 10 graphics primitives + sage: p3 = Polyhedron(vertices=[(0, 0), (0, 2), (-1, 1)]) + sage: pc = PolyhedralComplex([p1, p2, p3]) + sage: bb = dict(xmin=-2, xmax=2, ymin=-0.5, ymax=3, axes=False) + sage: g0 = pc.plot(**bb) # optional - sage.plot + sage: g1 = pc.plot(explosion_factor=0.3, **bb) # optional - sage.plot + sage: g2 = pc.plot(explosion_factor=1, **bb) # optional - sage.plot + sage: graphics_array([g0, g1, g2]).show(axes=False) # not tested """ if self.dimension() > 3: raise ValueError("cannot plot in high dimension") From b0ed0a7b61b0b58ffd20c11e6cb4f1efb41d6dc9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 15:51:11 -0700 Subject: [PATCH 210/591] src/sage/geometry/polyhedral_complex.py (exploded_rainbow_plot): Accepts dicts for sticky_vertices, sticky_center --- src/sage/geometry/polyhedral_complex.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 8f447e96739..5aefb48cb1e 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -2465,11 +2465,11 @@ def exploded_rainbow_plot(polyhedra, *, - ``explosion_factor`` -- (default: 1) a nonnegative number; translate polyhedra by this factor of the distance from ``center`` to their center - - ``sticky_vertices`` -- (default: ``False``) whether to draw line segments between shared - vertices of the given polyhedra + - ``sticky_vertices`` -- (default: ``False``) boolean or dict. Whether to draw line segments between shared + vertices of the given polyhedra. A dict gives options for :func:`sage.plot.line`. - - ``sticky_center`` -- (default: ``True``) whether to draw line segments between ``center`` - and the vertices of the given polyhedra + - ``sticky_center`` -- (default: ``True``) boolean or dict. Whether to draw line segments between ``center`` + and the vertices of the given polyhedra. A dict gives options for :func:`sage.plot.line`. - other keyword arguments are passed on to :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.plot`. @@ -2512,15 +2512,19 @@ def exploded_rainbow_plot(polyhedra, *, vertex_translations_dict[v] = vertex_translations_dict.get(v, []) vertex_translations_dict[v].append(v + t) if sticky_vertices or sticky_center: + if sticky_vertices is True: + sticky_vertices = dict(color='gray') + if sticky_center is True: + sticky_center = dict(color='gray') for vertex, vertex_translations in vertex_translations_dict.items(): if vertex == center: if sticky_center: for vt in vertex_translations: - g += line((center, vt), color='gray') + g += line((center, vt), **sticky_center) else: if sticky_vertices: for vt1, vt2 in itertools.combinations(vertex_translations, 2): - g += line((vt1, vt2), color='gray') + g += line((vt1, vt2), **sticky_vertices) if point is None: point = dict(size=1.5) From e1d43a9bf24778e9eb43b1352c92adf2f40030d7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 15:58:14 -0700 Subject: [PATCH 211/591] src/sage/geometry/polyhedral_complex.py: Change to a centrally symmetric example --- src/sage/geometry/polyhedral_complex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 5aefb48cb1e..41c6fb0cdd3 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -737,8 +737,8 @@ def plot(self, **kwds): sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) sage: p2 = Polyhedron(vertices=[(1, 2), (0, 0), (0, 2)]) sage: p3 = Polyhedron(vertices=[(0, 0), (0, 2), (-1, 1)]) - sage: pc = PolyhedralComplex([p1, p2, p3]) - sage: bb = dict(xmin=-2, xmax=2, ymin=-0.5, ymax=3, axes=False) + sage: pc = PolyhedralComplex([p1, p2, p3, -p1, -p2, -p3]) + sage: bb = dict(xmin=-2, xmax=2, ymin=-3, ymax=3, axes=False) sage: g0 = pc.plot(**bb) # optional - sage.plot sage: g1 = pc.plot(explosion_factor=0.3, **bb) # optional - sage.plot sage: g2 = pc.plot(explosion_factor=1, **bb) # optional - sage.plot From 3d84635230dab2f2ff256547634b21b7aac857b9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 16:44:26 -0700 Subject: [PATCH 212/591] src/sage/geometry/polyhedral_complex.py (exploded_plot): Rename from exploded_rainbow_plot, handle color='rainbow' --- src/sage/geometry/polyhedral_complex.py | 50 +++++++++++++++---------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 41c6fb0cdd3..e406e24c516 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -726,7 +726,7 @@ def plot(self, **kwds): INPUT: - ``explosion_factor`` -- (default: 0) if positive, separate the cells of - the complex by extra space. See :func:`exploded_rainbow_plot` for + the complex by extra space. See :func:`exploded_plot` for additional keyword arguments that can be passed in this case. - other keyword arguments are passed on to @@ -740,14 +740,14 @@ def plot(self, **kwds): sage: pc = PolyhedralComplex([p1, p2, p3, -p1, -p2, -p3]) sage: bb = dict(xmin=-2, xmax=2, ymin=-3, ymax=3, axes=False) sage: g0 = pc.plot(**bb) # optional - sage.plot - sage: g1 = pc.plot(explosion_factor=0.3, **bb) # optional - sage.plot - sage: g2 = pc.plot(explosion_factor=1, **bb) # optional - sage.plot + sage: g1 = pc.plot(explosion_factor=0.5, **bb) # optional - sage.plot + sage: g2 = pc.plot(explosion_factor=1, color='rainbow', **bb) # optional - sage.plot sage: graphics_array([g0, g1, g2]).show(axes=False) # not tested """ if self.dimension() > 3: raise ValueError("cannot plot in high dimension") if kwds.get('explosion_factor', 0): - return exploded_rainbow_plot(self.maximal_cell_iterator(), **kwds) + return exploded_plot(self.maximal_cell_iterator(), **kwds) return sum(cell.plot(**kwds) for cell in self.maximal_cell_iterator()) def is_pure(self): @@ -2450,9 +2450,9 @@ def cells_list_to_cells_dict(cells_list): return cells_dict -def exploded_rainbow_plot(polyhedra, *, - center=None, explosion_factor=1, sticky_vertices=False, - sticky_center=True, point=None, **kwds): +def exploded_plot(polyhedra, *, + center=None, explosion_factor=1, sticky_vertices=False, + sticky_center=True, point=None, **kwds): r""" Return a plot of several ``polyhedra`` in one figure with extra space between them. @@ -2471,19 +2471,22 @@ def exploded_rainbow_plot(polyhedra, *, - ``sticky_center`` -- (default: ``True``) boolean or dict. Whether to draw line segments between ``center`` and the vertices of the given polyhedra. A dict gives options for :func:`sage.plot.line`. + - ``color`` -- (default: ``None``) if ``"rainbow"``, assign a different color to every maximal cell and + every vertex; otherwise, passed on to :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.plot`. + - other keyword arguments are passed on to :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.plot`. EXAMPLES:: - sage: from sage.geometry.polyhedral_complex import exploded_rainbow_plot + sage: from sage.geometry.polyhedral_complex import exploded_plot sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) sage: p2 = Polyhedron(vertices=[(1, 2), (0, 0), (0, 2)]) sage: p3 = Polyhedron(vertices=[(0, 0), (1, 1), (2, 0)]) - sage: exploded_rainbow_plot([p1, p2, p3]) # optional - sage.plot + sage: exploded_plot([p1, p2, p3]) # optional - sage.plot Graphics object consisting of 20 graphics primitives - sage: exploded_rainbow_plot([p1, p2, p3], center=(1, 1)) # optional - sage.plot + sage: exploded_plot([p1, p2, p3], center=(1, 1)) # optional - sage.plot Graphics object consisting of 19 graphics primitives - sage: exploded_rainbow_plot([p1, p2, p3], center=(1, 1), sticky_vertices=True) # optional - sage.plot + sage: exploded_plot([p1, p2, p3], center=(1, 1), sticky_vertices=True) # optional - sage.plot Graphics object consisting of 23 graphics primitives """ from sage.plot.colors import rainbow @@ -2526,16 +2529,25 @@ def exploded_rainbow_plot(polyhedra, *, for vt1, vt2 in itertools.combinations(vertex_translations, 2): g += line((vt1, vt2), **sticky_vertices) + color = kwds.get('color') if point is None: point = dict(size=1.5) if point is not False: - vertex_colors_dict = {vertex: color - for vertex, color in zip(vertex_translations_dict.keys(), - rainbow(len(vertex_translations_dict.keys())))} + if color == 'rainbow': + vertex_colors_dict = dict(zip(vertex_translations_dict.keys(), + rainbow(len(vertex_translations_dict.keys())))) for vertex, vertex_translations in vertex_translations_dict.items(): + options = copy(point) + if color == 'rainbow': + options['color'] = vertex_colors_dict[vertex] g += plot_point(vertex_translations, - color=vertex_colors_dict[vertex], - alpha=0.5, **point) - - return g + sum((p + t).plot(alpha=0.5, point=False, color=color, **kwds) - for p, t, color in zip(polyhedra, translations, rainbow(len(polyhedra)))) + alpha=0.5, **options) + if color == 'rainbow': + cell_colors_dict = dict(zip(polyhedra, + rainbow(len(polyhedra)))) + for p, t in zip(polyhedra, translations): + options = copy(kwds) + if color == 'rainbow': + options['color'] = cell_colors_dict[p] + g += (p + t).plot(alpha=0.5, point=False, **options) + return g From 85cb04ebc739813b84ac849595738b6b6f530edf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 16:47:39 -0700 Subject: [PATCH 213/591] src/sage/geometry/polyhedral_complex.py (exploded_plot): Do not set alpha=0.5 by default --- src/sage/geometry/polyhedral_complex.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index e406e24c516..810268c6b32 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -739,10 +739,10 @@ def plot(self, **kwds): sage: p3 = Polyhedron(vertices=[(0, 0), (0, 2), (-1, 1)]) sage: pc = PolyhedralComplex([p1, p2, p3, -p1, -p2, -p3]) sage: bb = dict(xmin=-2, xmax=2, ymin=-3, ymax=3, axes=False) - sage: g0 = pc.plot(**bb) # optional - sage.plot - sage: g1 = pc.plot(explosion_factor=0.5, **bb) # optional - sage.plot - sage: g2 = pc.plot(explosion_factor=1, color='rainbow', **bb) # optional - sage.plot - sage: graphics_array([g0, g1, g2]).show(axes=False) # not tested + sage: g0 = pc.plot(**bb) # optional - sage.plot + sage: g1 = pc.plot(explosion_factor=0.5, **bb) # optional - sage.plot + sage: g2 = pc.plot(explosion_factor=1, color='rainbow', alpha=0.5, **bb) # optional - sage.plot + sage: graphics_array([g0, g1, g2]).show(axes=False) # not tested """ if self.dimension() > 3: raise ValueError("cannot plot in high dimension") @@ -2540,8 +2540,7 @@ def exploded_plot(polyhedra, *, options = copy(point) if color == 'rainbow': options['color'] = vertex_colors_dict[vertex] - g += plot_point(vertex_translations, - alpha=0.5, **options) + g += plot_point(vertex_translations, **options) if color == 'rainbow': cell_colors_dict = dict(zip(polyhedra, rainbow(len(polyhedra)))) @@ -2549,5 +2548,5 @@ def exploded_plot(polyhedra, *, options = copy(kwds) if color == 'rainbow': options['color'] = cell_colors_dict[p] - g += (p + t).plot(alpha=0.5, point=False, **options) + g += (p + t).plot(point=False, **options) return g From a5974651c13d12cdc4f0d50e123d0a672ec27491 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 6 Aug 2022 16:48:37 -0700 Subject: [PATCH 214/591] trac 34294: is_subcomplex method for simplicial complexes --- src/sage/topology/simplicial_complex.py | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/sage/topology/simplicial_complex.py b/src/sage/topology/simplicial_complex.py index fc6f9c36f71..ee1c25a31ef 100644 --- a/src/sage/topology/simplicial_complex.py +++ b/src/sage/topology/simplicial_complex.py @@ -2785,6 +2785,35 @@ def remove_faces(self, faces, check=False): for f in faces: self.remove_face(f, check=check) + def is_subcomplex(self, other): + """ + Return ``True`` if this is a subcomplex of ``other``. + + :param other: another simplicial complex + + EXAMPLES:: + + sage: S1 = simplicial_complexes.Sphere(1) + sage: S1.is_subcomplex(S1) + True + sage: Empty = SimplicialComplex() + sage: Empty.is_subcomplex(S1) + True + sage: S1.is_subcomplex(Empty) + False + + sage: sorted(S1.facets()) + [(0, 1), (0, 2), (1, 2)] + sage: T = S1.product(S1) + sage: sorted(T.facets())[0] # typical facet in T + ('L0R0', 'L0R1', 'L1R1') + sage: S1.is_subcomplex(T) + False + sage: T._contractible_subcomplex().is_subcomplex(T) + True + """ + return all(f in other for f in self.facets()) + def connected_sum(self, other, is_mutable=True): """ The connected sum of this simplicial complex with another one. From 568b027de0562b11973b1d72a0531b5336e9a69e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 16:59:03 -0700 Subject: [PATCH 215/591] src/sage/geometry/polyhedral_complex.py (exploded_plot): Use same default for point size as Polyhedron.plot --- src/sage/geometry/polyhedral_complex.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 810268c6b32..bca5ecaa2a5 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -2531,7 +2531,8 @@ def exploded_plot(polyhedra, *, color = kwds.get('color') if point is None: - point = dict(size=1.5) + # default from sage.geometry.polyhedron.plot + point = dict(size=10) if point is not False: if color == 'rainbow': vertex_colors_dict = dict(zip(vertex_translations_dict.keys(), From efc94551c6df88a04c7cafeb48f7b069a525ea12 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 17:08:28 -0700 Subject: [PATCH 216/591] src/sage/geometry/polyhedral_complex.py (PolyhedralComplex.plot): Handle color='rainbow' in non-exploded plots too --- src/sage/geometry/polyhedral_complex.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index bca5ecaa2a5..cea55f28223 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -729,6 +729,10 @@ def plot(self, **kwds): the complex by extra space. See :func:`exploded_plot` for additional keyword arguments that can be passed in this case. + - ``color`` -- (default: ``None``) if ``"rainbow"``, assign a different color + to every maximal cell; otherwise, passed on to + :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.plot`. + - other keyword arguments are passed on to :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.plot`. @@ -739,7 +743,7 @@ def plot(self, **kwds): sage: p3 = Polyhedron(vertices=[(0, 0), (0, 2), (-1, 1)]) sage: pc = PolyhedralComplex([p1, p2, p3, -p1, -p2, -p3]) sage: bb = dict(xmin=-2, xmax=2, ymin=-3, ymax=3, axes=False) - sage: g0 = pc.plot(**bb) # optional - sage.plot + sage: g0 = pc.plot(color='rainbow', **bb) # optional - sage.plot sage: g1 = pc.plot(explosion_factor=0.5, **bb) # optional - sage.plot sage: g2 = pc.plot(explosion_factor=1, color='rainbow', alpha=0.5, **bb) # optional - sage.plot sage: graphics_array([g0, g1, g2]).show(axes=False) # not tested @@ -748,7 +752,23 @@ def plot(self, **kwds): raise ValueError("cannot plot in high dimension") if kwds.get('explosion_factor', 0): return exploded_plot(self.maximal_cell_iterator(), **kwds) - return sum(cell.plot(**kwds) for cell in self.maximal_cell_iterator()) + + from sage.plot.colors import rainbow + from sage.plot.graphics import Graphics + + color = kwds.get('color') + polyhedra = self.maximal_cell_iterator() + if color == 'rainbow': + polyhedra = list(polyhedra) + cell_colors_dict = dict(zip(polyhedra, + rainbow(len(polyhedra)))) + g = Graphics() + for cell in polyhedra: + options = copy(kwds) + if color == 'rainbow': + options['color'] = cell_colors_dict[cell] + g += cell.plot(**options) + return g def is_pure(self): """ From f0321e5219ca26502c72204434beb4a6c0760fda Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 21:15:31 -0700 Subject: [PATCH 217/591] src/sage/geometry/polyhedral_complex.py (exploded_plot): Handle unbounded case --- src/sage/geometry/polyhedral_complex.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index cea55f28223..42da369cb5b 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -2525,7 +2525,9 @@ def exploded_plot(polyhedra, *, center = vector(QQ, dim) else: center = vector(center) - translations = [explosion_factor * (p.center() - center) + translations = [explosion_factor * ((p.center() + + sum(r.vector() for r in p.rays())) + - center) for p in polyhedra] vertex_translations_dict = {} for P, t in zip(polyhedra, translations): From cc0a47e2686567c1a1616d11855231efd96d4658 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 6 Aug 2022 21:23:15 -0700 Subject: [PATCH 218/591] src/sage/geometry/polyhedral_complex.py (exploded_plot): Fix doc of sticky_center --- src/sage/geometry/polyhedral_complex.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 42da369cb5b..f354ee28622 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -2488,8 +2488,9 @@ def exploded_plot(polyhedra, *, - ``sticky_vertices`` -- (default: ``False``) boolean or dict. Whether to draw line segments between shared vertices of the given polyhedra. A dict gives options for :func:`sage.plot.line`. - - ``sticky_center`` -- (default: ``True``) boolean or dict. Whether to draw line segments between ``center`` - and the vertices of the given polyhedra. A dict gives options for :func:`sage.plot.line`. + - ``sticky_center`` -- (default: ``True``) boolean or dict. When ``center`` is a vertex of some + of the polyhedra, whether to draw line segments connecting the ``center`` to the shifted copies + of these vertices. A dict gives options for :func:`sage.plot.line`. - ``color`` -- (default: ``None``) if ``"rainbow"``, assign a different color to every maximal cell and every vertex; otherwise, passed on to :meth:`~sage.geometry.polyhedron.base.Polyhedron_base.plot`. From c5a8200a261d9d325ac844ef3c394c2e9c61b734 Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Sun, 7 Aug 2022 01:31:05 -0400 Subject: [PATCH 219/591] src/sage/geometry/polyhedral_complex.py (plot): Add 3d plot examples --- src/sage/geometry/polyhedral_complex.py | 30 ++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index f354ee28622..ed1ca74441c 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -741,12 +741,32 @@ def plot(self, **kwds): sage: p1 = Polyhedron(vertices=[(1, 1), (0, 0), (1, 2)]) sage: p2 = Polyhedron(vertices=[(1, 2), (0, 0), (0, 2)]) sage: p3 = Polyhedron(vertices=[(0, 0), (0, 2), (-1, 1)]) - sage: pc = PolyhedralComplex([p1, p2, p3, -p1, -p2, -p3]) + sage: pc1 = PolyhedralComplex([p1, p2, p3, -p1, -p2, -p3]) sage: bb = dict(xmin=-2, xmax=2, ymin=-3, ymax=3, axes=False) - sage: g0 = pc.plot(color='rainbow', **bb) # optional - sage.plot - sage: g1 = pc.plot(explosion_factor=0.5, **bb) # optional - sage.plot - sage: g2 = pc.plot(explosion_factor=1, color='rainbow', alpha=0.5, **bb) # optional - sage.plot - sage: graphics_array([g0, g1, g2]).show(axes=False) # not tested + sage: g0 = pc1.plot(color='rainbow', **bb) # optional - sage.plot + sage: g1 = pc1.plot(explosion_factor=0.5, **bb) # optional - sage.plot + sage: g2 = pc1.plot(explosion_factor=1, color='rainbow', alpha=0.5, **bb) # optional - sage.plot + sage: graphics_array([g0, g1, g2]).show(axes=False) # not tested + + sage: pc2 = PolyhedralComplex([polytopes.hypercube(3)]) + sage: pc3 = pc2.subdivide(new_vertices=[(0, 0, 0)]) + sage: g3 = pc3.plot(explosion_factor=1, color='rainbow', + ....: alpha=0.5, axes=False, online=True) # optional - sage.plot + sage: pc4 = pc2.subdivide(make_simplicial=True) + sage: g4 = pc4.plot(explosion_factor=1, center=(1, -1, 1), fill='blue', + ....: wireframe='white', point={'color':'red', 'size':10}, + ....: alpha=0.6, online=True) # optional - sage.plot + sage: pc5 = PolyhedralComplex([ + ....: Polyhedron(rays=[[1,0,0], [0,1,0], [0,0,-1]]), + ....: Polyhedron(rays=[[1,0,0], [0,-1,0], [0,0,-1]]), + ....: Polyhedron(rays=[[1,0,0], [0,-1,0], [0,0,1]]), + ....: Polyhedron(rays=[[-1,0,0], [0,-1,0], [0,0,-1]]), + ....: Polyhedron(rays=[[-1,0,0], [0,-1,0], [0,0,1]]), + ....: Polyhedron(rays=[[-1,0,0], [0,1,0], [0,0,-1]]), + ....: Polyhedron(rays=[[-1,0,0], [0,1,0], [0,0,1]])]) + sage: g5 = pc5.plot(explosion_factor=0.3, color='rainbow', alpha=0.8, + ....: point={'size': 20}, axes=False, online=True) # optional - sage.plot + """ if self.dimension() > 3: raise ValueError("cannot plot in high dimension") From 2b9decfa5969eadd25844d29ce14cb9e78da23ba Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Sun, 7 Aug 2022 02:03:11 -0400 Subject: [PATCH 220/591] src/sage/geometry/polyhedral_complex.py (plot): Describe exploded_plot keyword arguments in the docstring --- src/sage/geometry/polyhedral_complex.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index ed1ca74441c..020a0614927 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -726,8 +726,17 @@ def plot(self, **kwds): INPUT: - ``explosion_factor`` -- (default: 0) if positive, separate the cells of - the complex by extra space. See :func:`exploded_plot` for - additional keyword arguments that can be passed in this case. + the complex by extra space. In this case, the following keyword arguments + can be passed to :func:`exploded_plot`: + + - ``center`` -- (default: ``None``, denoting the origin) the center of explosion + - ``sticky_vertices`` -- (default: ``False``) boolean or dict. + Whether to draw line segments between shared vertices of the given polyhedra. + A dict gives options for :func:`sage.plot.line`. + - ``sticky_center`` -- (default: ``True``) boolean or dict. When ``center`` is + a vertex of some of the polyhedra, whether to draw line segments connecting the + ``center`` to the shifted copies of these vertices. + A dict gives options for :func:`sage.plot.line`. - ``color`` -- (default: ``None``) if ``"rainbow"``, assign a different color to every maximal cell; otherwise, passed on to From b0641464e852d52e0c80937d568302a575bf5b5f Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Sun, 7 Aug 2022 02:20:37 -0400 Subject: [PATCH 221/591] src/sage/geometry/polyhedral_complex.py (plot): Add 3d plot examples (fixup) --- src/sage/geometry/polyhedral_complex.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 020a0614927..af1af22a39a 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -759,12 +759,12 @@ def plot(self, **kwds): sage: pc2 = PolyhedralComplex([polytopes.hypercube(3)]) sage: pc3 = pc2.subdivide(new_vertices=[(0, 0, 0)]) - sage: g3 = pc3.plot(explosion_factor=1, color='rainbow', - ....: alpha=0.5, axes=False, online=True) # optional - sage.plot + sage: g3 = pc3.plot(explosion_factor=1, color='rainbow', # optional - sage.plot + ....: alpha=0.5, axes=False, online=True) sage: pc4 = pc2.subdivide(make_simplicial=True) - sage: g4 = pc4.plot(explosion_factor=1, center=(1, -1, 1), fill='blue', + sage: g4 = pc4.plot(explosion_factor=1, center=(1, -1, 1), fill='blue', # optional - sage.plot ....: wireframe='white', point={'color':'red', 'size':10}, - ....: alpha=0.6, online=True) # optional - sage.plot + ....: alpha=0.6, online=True) sage: pc5 = PolyhedralComplex([ ....: Polyhedron(rays=[[1,0,0], [0,1,0], [0,0,-1]]), ....: Polyhedron(rays=[[1,0,0], [0,-1,0], [0,0,-1]]), @@ -773,8 +773,8 @@ def plot(self, **kwds): ....: Polyhedron(rays=[[-1,0,0], [0,-1,0], [0,0,1]]), ....: Polyhedron(rays=[[-1,0,0], [0,1,0], [0,0,-1]]), ....: Polyhedron(rays=[[-1,0,0], [0,1,0], [0,0,1]])]) - sage: g5 = pc5.plot(explosion_factor=0.3, color='rainbow', alpha=0.8, - ....: point={'size': 20}, axes=False, online=True) # optional - sage.plot + sage: g5 = pc5.plot(explosion_factor=0.3, color='rainbow', alpha=0.8, # optional - sage.plot + ....: point={'size': 20}, axes=False, online=True) """ if self.dimension() > 3: From 40aab1e2536895fdef15623e136cf72a722edf6c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 7 Aug 2022 15:29:14 +0900 Subject: [PATCH 222/591] Added whitespace for E306. --- src/sage/algebras/quantum_clifford.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index 4e5570ce6bf..f646b0c2a52 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -696,6 +696,7 @@ def _repr_term(self, m): 5 """ p, v = m + def ppr(i): val = p[i] if val == -1: @@ -704,6 +705,7 @@ def ppr(i): return 'psi%s'%i elif val == 2: return 'psi%s*psid%s'%(i,i) + rp = '*'.join(ppr(i) for i in range(self._n) if p[i] != 0) gen_str = lambda e: '' if e == 1 else '^%s'%e rv = '*'.join('w%s'%i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) @@ -735,6 +737,7 @@ def _latex_term(self, m): 5 """ p, v = m + def ppr(i): val = p[i] if val == -1: @@ -742,7 +745,8 @@ def ppr(i): elif val == 1: return '\\psi_{%s}'%i elif val == 2: - return '\\psi_{%s}\\psi^{\\dagger}_{%s}'%(i,i) + return '\\psi_{%s}\\psi^{\\dagger}_{%s}' % (i, i) + rp = ''.join(ppr(i) for i in range(self._n) if p[i] != 0) gen_str = lambda e: '' if e == 1 else '^{%s}'%e rv = ''.join('\\omega_{%s}'%i + gen_str(v[i]) From e8ec0ebfc02341d0c216001d23b588d55c0ad3e8 Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Sun, 7 Aug 2022 02:51:43 -0400 Subject: [PATCH 223/591] src/sage/geometry/polyhedral_complex.py (exploded_plot): Plot polyhedra first, lines next and points last. --- src/sage/geometry/polyhedral_complex.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index af1af22a39a..1c298df5065 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -2566,6 +2566,17 @@ def exploded_plot(polyhedra, *, v.set_immutable() vertex_translations_dict[v] = vertex_translations_dict.get(v, []) vertex_translations_dict[v].append(v + t) + + color = kwds.get('color') + if color == 'rainbow': + cell_colors_dict = dict(zip(polyhedra, + rainbow(len(polyhedra)))) + for p, t in zip(polyhedra, translations): + options = copy(kwds) + if color == 'rainbow': + options['color'] = cell_colors_dict[p] + g += (p + t).plot(point=False, **options) + if sticky_vertices or sticky_center: if sticky_vertices is True: sticky_vertices = dict(color='gray') @@ -2580,8 +2591,6 @@ def exploded_plot(polyhedra, *, if sticky_vertices: for vt1, vt2 in itertools.combinations(vertex_translations, 2): g += line((vt1, vt2), **sticky_vertices) - - color = kwds.get('color') if point is None: # default from sage.geometry.polyhedron.plot point = dict(size=10) @@ -2594,12 +2603,4 @@ def exploded_plot(polyhedra, *, if color == 'rainbow': options['color'] = vertex_colors_dict[vertex] g += plot_point(vertex_translations, **options) - if color == 'rainbow': - cell_colors_dict = dict(zip(polyhedra, - rainbow(len(polyhedra)))) - for p, t in zip(polyhedra, translations): - options = copy(kwds) - if color == 'rainbow': - options['color'] = cell_colors_dict[p] - g += (p + t).plot(point=False, **options) return g From 68679e0611ac30751e259a77392af5dc449b0322 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Sun, 7 Aug 2022 00:58:40 -0600 Subject: [PATCH 224/591] added lambda algorithm to discrete_log --- src/sage/groups/generic.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 280de319e34..99cf0fb4f46 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -683,7 +683,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - ``identity`` - the group's identity - ``inverse()`` - function of 1 argument ``x`` returning inverse of ``x`` - ``op()`` - function of 2 arguments ``x``, ``y`` returning ``x*y`` in the group - - ``algorithm`` - string denoting what algorithm to use for prime-order logarithms: 'bsgs', 'rho' + - ``algorithm`` - string denoting what algorithm to use for prime-order logarithms: 'bsgs', 'rho', 'lambda' ``a`` and ``base`` must be elements of some group with identity given by identity, inverse of ``x`` by ``inverse(x)``, and group @@ -705,7 +705,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i than using this function. E.g., if ``x`` is an integer modulo `n`, use its log method instead! - ALGORITHM: Pohlig-Hellman, Baby step giant step, and Pollard's rho. + ALGORITHM: Pohlig-Hellman, Baby step giant step, Pollard's lambda/kangaroo, and Pollard's rho. EXAMPLES:: @@ -791,13 +791,13 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: discrete_log(u,g) 123456789 - The above examples also work when the 'rho' algorithm is used:: + The above examples also work when the 'rho' and 'lambda' algorithms are used:: sage: b = Mod(2,37); a = b^20 sage: discrete_log(a, b, algorithm='rho') 20 sage: b = Mod(3,2017); a = b^20 - sage: discrete_log(a, b, algorithm='rho', bounds=(10, 100)) + sage: discrete_log(a, b, algorithm='lambda', bounds=(10, 100)) 20 sage: K = GF(3^6,'b') @@ -807,7 +807,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i 210 sage: b = Mod(1,37); x = Mod(2,37) - sage: discrete_log(x, b, algorithm='rho') + sage: discrete_log(x, b, algorithm='lambda') Traceback (most recent call last): ... ValueError: no discrete log of 2 found to base 1 @@ -826,7 +826,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i 672 sage: Q=39*P; Q (36*a + 32 : 5*a + 12 : 1) - sage: discrete_log(Q,P,P.order(),operation='+',algorithm='rho') + sage: discrete_log(Q,P,P.order(),operation='+',algorithm='lambda') 39 sage: F. = GF(2^63) @@ -888,6 +888,8 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i c = bsgs(gamma, h, (0, temp_bound), inverse=inverse, identity=identity, op=op, operation=operation) elif algorithm == 'rho': c = discrete_log_rho(h, gamma, ord=pi, inverse=inverse, identity=identity, op=op, operation=operation) + elif algorithm == 'lambda': + c = discrete_log_lambda(h, gamma, (0, temp_bound), inverse=inverse, identity=identity, op=op, operation=operation) l[i] += c * (pi**j) running_bound //= pi running_mod *= pi @@ -910,7 +912,7 @@ def discrete_log_generic(a, base, ord=None, bounds=None, operation='*', identity return discrete_log(a, base, ord=ord, bounds=bounds, operation=operation, identity=identity, inverse=inverse, op=op, algorithm=algorithm) -def discrete_log_lambda(a, base, bounds, operation='*', hash_function=hash): +def discrete_log_lambda(a, base, bounds, operation='*', identity=None, inverse=None, op=None, hash_function=hash): """ Pollard Lambda algorithm for computing discrete logarithms. It uses only a logarithmic amount of memory. It's useful if you have @@ -923,6 +925,9 @@ def discrete_log_lambda(a, base, bounds, operation='*', hash_function=hash): - base -- a group element - bounds -- a couple (lb,ub) representing the range where we look for a logarithm - operation -- string: '+', '*' or 'other' + - identity -- the identity element of the group + - inverse() -- function of 1 argument ``x`` returning inverse of ``x`` + - op() -- function of 2 arguments ``x``, ``y`` returning ``x*y`` in the group - hash_function -- having an efficient hash function is critical for this algorithm OUTPUT: Returns an integer `n` such that `a=base^n` (or `a=n*base`) @@ -957,16 +962,14 @@ def discrete_log_lambda(a, base, bounds, operation='*', hash_function=hash): """ from sage.rings.integer import Integer - from operator import mul, add, pow + from operator import mul, add + mult = op if operation in addition_names: mult = add - power = mul elif operation in multiplication_names: mult = mul - power = pow - else: - raise ValueError("unknown operation") + power = lambda x, y: multiple(x, y, operation=operation, identity=identity, inverse=inverse, op=op) lb, ub = bounds if lb < 0 or ub < lb: From 7d70a031cb845e4c7d47f846f3f6fc95138569c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 7 Aug 2022 10:05:41 +0200 Subject: [PATCH 225/591] refresh Zariski-VanKampen file --- src/sage/schemes/curves/zariski_vankampen.py | 209 ++++++++++--------- 1 file changed, 106 insertions(+), 103 deletions(-) diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 71956e584e5..a8b71a2ac38 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -13,7 +13,7 @@ choose several base points and a system of paths joining them that generate all the necessary loops around the points of the discriminant. The group is generated by the free groups over these points, and -braids over this paths gives relations between these generators. +braids over these paths give relations between these generators. This big group presentation is simplified at the end. AUTHORS: @@ -37,27 +37,27 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +import itertools +from copy import copy +from sage.combinat.permutation import Permutation +from sage.geometry.voronoi_diagram import VoronoiDiagram +from sage.graphs.graph import Graph from sage.groups.braid import BraidGroup +from sage.groups.free_group import FreeGroup from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.rings.rational_field import QQ -from sage.rings.qqbar import QQbar -from sage.parallel.decorate import parallel +from sage.misc.cachefunc import cached_function from sage.misc.flatten import flatten -from sage.groups.free_group import FreeGroup from sage.misc.misc_c import prod +from sage.parallel.decorate import parallel +from sage.rings.complex_interval_field import ComplexIntervalField from sage.rings.complex_mpfr import ComplexField +from sage.rings.qqbar import QQbar +from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RealField -from sage.rings.complex_interval_field import ComplexIntervalField -from sage.combinat.permutation import Permutation -import itertools -from sage.geometry.voronoi_diagram import VoronoiDiagram -from sage.graphs.graph import Graph -from sage.misc.cachefunc import cached_function -from copy import copy -roots_interval_cache = dict() +roots_interval_cache = {} def braid_from_piecewise(strands): @@ -67,7 +67,8 @@ def braid_from_piecewise(strands): INPUT: - ``strands`` -- a list of lists of tuples ``(t, c1, c2)``, where ``t`` - is a number between 0 and 1, and ``c1`` and ``c2`` are rationals or algebraic reals. + is a number between 0 and 1, and ``c1`` and ``c2`` are rationals + or algebraic reals. OUTPUT: @@ -123,11 +124,13 @@ def sgn(x, y): l1 = [a[0] for a in M] l2 = [a[1] for a in M] cruces = [] - for j in range(len(l2)): + for j, l2j in enumerate(l2): + l1j = l1[j] for k in range(j): - if l2[j] < l2[k]: - t = (l1[j][0] - l1[k][0])/((l2[k][0]-l2[j][0]) + (l1[j][0] - l1[k][0])) - s = sgn(l1[k][1]*(1 - t) + t*l2[k][1], l1[j][1]*(1 - t) + t*l2[j][1]) + if l2j < l2[k]: + t = (l1j[0] - l1[k][0]) / ((l2[k][0] - l2j[0]) + (l1j[0] - l1[k][0])) + s = sgn(l1[k][1] * (1 - t) + t * l2[k][1], + l1j[1] * (1 - t) + t * l2j[1]) cruces.append([t, k, j, s]) if cruces: cruces.sort() @@ -141,10 +144,10 @@ def sgn(x, y): while crossesl: crossesl.sort() c = crossesl.pop(0) - braid.append(c[3]*min(map(P, [c[1] + 1, c[2] + 1]))) + braid.append(c[3] * min(map(P, [c[1] + 1, c[2] + 1]))) P = G(Permutation([(c[1] + 1, c[2] + 1)])) * P - crossesl = [(P(cr[2]+1) - P(cr[1]+1), cr[1], cr[2], cr[3]) - for cr in crossesl] + crossesl = [(P(cr[2] + 1) - P(cr[1] + 1), + cr[1], cr[2], cr[3]) for cr in crossesl] B = BraidGroup(len(L)) return B(braid) @@ -185,8 +188,9 @@ def discrim(f): @cached_function def corrected_voronoi_diagram(points): r""" - Compute a Voronoi diagram of a set of points with rational coordinates, such - that the given points are granted to lie one in each bounded region. + Compute a Voronoi diagram of a set of points with rational coordinates. + + The given points are granted to lie one in each bounded region. INPUT: @@ -215,18 +219,18 @@ def corrected_voronoi_diagram(points): P(1/1000000, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, P(2, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, P(7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays} - """ prec = 53 point_coordinates = [(p.real(), p.imag()) for p in points] while True: RF = RealField(prec) - apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))): p for p in point_coordinates} + apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))): p + for p in point_coordinates} added_points = 3 * max(map(abs, flatten(apprpoints))) + 1 - configuration = list(apprpoints.keys())+[(added_points, 0), - (-added_points, 0), - (0, added_points), - (0, -added_points)] + configuration = list(apprpoints.keys()) + [(added_points, 0), + (-added_points, 0), + (0, added_points), + (0, -added_points)] V = VoronoiDiagram(configuration) valid = True for r in V.regions().items(): @@ -277,19 +281,18 @@ def segments(points): (-5/2*I + 5/2, 5/2*I + 5/2), (5/2*I + 5/2, 144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326)] - """ V = corrected_voronoi_diagram(tuple(points)) - res = set([]) + res = set() for region in V.regions().values(): if region.rays(): continue - segments = region.facets() - for s in segments: + for s in region.facets(): t = tuple((tuple(v.vector()) for v in s.vertices())) if t not in res and not tuple(reversed(t)) in res: res.add(t) - return [(r[0]+QQbar.gen()*r[1], s[0]+QQbar.gen()*s[1]) for (r, s) in res] + return [(r[0] + QQbar.gen() * r[1], + s[0] + QQbar.gen() * s[1]) for r, s in res] def followstrand(f, factors, x0, x1, y0a, prec=53): @@ -336,7 +339,6 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): (0.5303300858899107, -1.0076747107983448, -0.17588022709184917), (0.7651655429449553, -1.015686131039112, -0.25243563967299404), (1.0, -1.026166099551513, -0.3276894025360433)] - """ if f.degree() == 1: CF = ComplexField(prec) @@ -349,7 +351,7 @@ def followstrand(f, factors, x0, x1, y0a, prec=53): CIF = ComplexIntervalField(prec) CC = ComplexField(prec) G = f.change_ring(QQbar).change_ring(CIF) - (x, y) = G.parent().gens() + x, y = G.parent().gens() g = G.subs({x: (1 - x) * CIF(x0) + x * CIF(x1)}) coefs = [] deg = g.total_degree() @@ -407,7 +409,6 @@ def newton(f, x0, i0): The interval `x_0-\frac{f(x_0)}{f'(I_0)}` - EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import newton @@ -422,9 +423,8 @@ def newton(f, x0, i0): (-0.0147727272727274, 0.00982142857142862) sage: n.imag().endpoints() (0.000000000000000, -0.000000000000000) - """ - return x0 - f(x0)/f.derivative()(i0) + return x0 - f(x0) / f.derivative()(i0) @parallel @@ -441,8 +441,9 @@ def roots_interval(f, x0): The intervals are taken as big as possible to be able to detect when two approximate roots of `f(x_0, y)` correspond to the same exact root. - The result is given as a dictionary, where the keys are approximations to the roots - with rational real and imaginary parts, and the values are intervals containing them. + The result is given as a dictionary, where the keys are + approximations to the roots with rational real and imaginary + parts, and the values are intervals containing them. EXAMPLES:: @@ -467,32 +468,32 @@ def roots_interval(f, x0): -0.0669872981077806 + 1.29903810567666*I, -0.933012701892219 + 1.29903810567666*I, -0.0669872981077806 + 0.433012701892219*I)] - """ x, y = f.parent().gens() I = QQbar.gen() - fx = QQbar[y](f.subs({x: QQ(x0.real())+I*QQ(x0.imag())})) + fx = QQbar[y](f.subs({x: QQ(x0.real()) + I * QQ(x0.imag())})) roots = fx.roots(QQbar, multiplicities=False) result = {} - for i in range(len(roots)): - r = roots[i] + for i, r in enumerate(roots): prec = 53 IF = ComplexIntervalField(prec) CF = ComplexField(prec) divisor = 4 - diam = min((CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]) / divisor - envelop = IF(diam)*IF((-1, 1), (-1, 1)) - while not newton(fx, r, r+envelop) in r+envelop: + diam = min((CF(r) - CF(r0)).abs() + for r0 in roots[:i] + roots[i + 1:]) / divisor + envelop = IF(diam) * IF((-1, 1), (-1, 1)) + while not newton(fx, r, r + envelop) in r + envelop: prec += 53 IF = ComplexIntervalField(prec) CF = ComplexField(prec) divisor *= 2 - diam = min([(CF(r)-CF(r0)).abs() for r0 in roots[:i]+roots[i+1:]])/divisor - envelop = IF(diam)*IF((-1, 1), (-1, 1)) - qapr = QQ(CF(r).real())+QQbar.gen()*QQ(CF(r).imag()) - if qapr not in r+envelop: + diam = min((CF(r) - CF(r0)).abs() + for r0 in roots[:i] + roots[i + 1:]) / divisor + envelop = IF(diam) * IF((-1, 1), (-1, 1)) + qapr = QQ(CF(r).real()) + QQbar.gen() * QQ(CF(r).imag()) + if qapr not in r + envelop: raise ValueError("Could not approximate roots with exact values") - result[qapr] = r+envelop + result[qapr] = r + envelop return result @@ -500,7 +501,6 @@ def roots_interval_cached(f, x0): r""" Cached version of :func:`roots_interval`. - TESTS:: sage: from sage.schemes.curves.zariski_vankampen import roots_interval, roots_interval_cached, roots_interval_cache @@ -515,7 +515,6 @@ def roots_interval_cached(f, x0): 1: 1.? + 0.?*I} sage: (f, 1) in roots_interval_cache True - """ global roots_interval_cache try: @@ -602,16 +601,15 @@ def braid_in_segment(g, x0, x1): sage: B = zvk.braid_in_segment(g.factor(),CC(p1),CC(p2)) # optional - sirocco sage: B # optional - sirocco s5*s3^-1 - """ - (x, y) = g.value().parent().gens() + _, y = g.value().parent().gens() I = QQbar.gen() X0 = QQ(x0.real()) + I * QQ(x0.imag()) X1 = QQ(x1.real()) + I * QQ(x1.imag()) intervals = {} precision = {} y0s = [] - for (f, naux) in g: + for f, _ in g: if f.variables() == (y,): F0 = QQbar[y](f.base_ring()[y](f)) else: @@ -633,8 +631,8 @@ def braid_in_segment(g, x0, x1): initialintervals = roots_interval_cached(g.value(), X0) finalintervals = roots_interval_cached(g.value(), X1) for cs in complexstrands: - ip = cs[0][1] + I*cs[0][2] - fp = cs[-1][1] + I*cs[-1][2] + ip = cs[0][1] + I * cs[0][2] + fp = cs[-1][1] + I * cs[-1][2] matched = 0 for center, interval in initialintervals.items(): if ip in interval: @@ -652,7 +650,7 @@ def braid_in_segment(g, x0, x1): if matched == 0: raise ValueError("unable to match braid endpoint with root") if matched > 1: - raise ValueError("braid endpoint mathes more than one root") + raise ValueError("braid endpoint matches more than one root") initialbraid = braid_from_piecewise(initialstrands) finalbraid = braid_from_piecewise(finalstrands) @@ -661,7 +659,7 @@ def braid_in_segment(g, x0, x1): def orient_circuit(circuit): r""" - Reverses a circuit if it goes clockwise; otherwise leaves it unchanged. + Reverse a circuit if it goes clockwise; otherwise leave it unchanged. INPUT: @@ -711,16 +709,16 @@ def orient_circuit(circuit): """ prec = 53 - vectors = [v[1].vector()-v[0].vector() for v in circuit] + vectors = [v[1].vector() - v[0].vector() for v in circuit] while True: CIF = ComplexIntervalField(prec) - totalangle = sum((CIF(*vectors[i])/CIF(*vectors[i-1])).argument() for i in range(len(vectors))) + totalangle = sum((CIF(*vectors[i]) / CIF(*vectors[i - 1])).argument() + for i in range(len(vectors))) if totalangle < 0: return list(reversed([(c[1], c[0]) + c[2:] for c in circuit])) - elif totalangle > 0: + if totalangle > 0: return circuit - else: - prec *= 2 + prec *= 2 def geometric_basis(G, E, p): @@ -731,15 +729,15 @@ def geometric_basis(G, E, p): - ``G`` -- the graph of the bounded regions of a Voronoi Diagram - - ``E`` -- the subgraph of ``G`` formed by the edges that touch an unbounded - region + - ``E`` -- the subgraph of ``G`` formed by the edges that touch + an unbounded region - ``p`` -- a vertex of ``E`` OUTPUT: A geometric basis. It is formed by a list of sequences of paths. Each path is a list of vertices, that form a closed path in `G`, based at - `p`, that goes to a region, surrounds it, and comes back by the same path it - came. The concatenation of all these paths is equivalent to `E`. + `p`, that goes to a region, surrounds it, and comes back by the same + path it came. The concatenation of all these paths is equivalent to `E`. EXAMPLES:: @@ -790,11 +788,10 @@ def geometric_basis(G, E, p): A vertex at (-1/2, 1/2), A vertex at (-2, 2), A vertex at (-2, -2)]] - """ EC = [v[0] for v in orient_circuit(E.eulerian_circuit())] i = EC.index(p) - EC = EC[i:]+EC[:i+1] # A counterclockwise eulerian circuit on the boundary, based at p + EC = EC[i:] + EC[:i + 1] # A counterclockwise eulerian circuit on the boundary, based at p if len(G.edges()) == len(E.edges()): if E.is_cycle(): return [EC] @@ -808,17 +805,19 @@ def geometric_basis(G, E, p): if len(E.neighbors(v)) > 2: I.add_vertex(v) - for i in range(len(EC)): # q and r are the points we will cut through + for i, ECi in enumerate(EC): # q and r are the points we will cut through - if EC[i] in I.vertices(): - q = EC[i] + if ECi in I.vertices(): + q = ECi connecting_path = EC[:i] break - elif EC[-i] in I.vertices(): + if EC[-i] in I.vertices(): q = EC[-i] connecting_path = list(reversed(EC[-i:])) break - distancequotients = [(E.distance(q, v)**2/I.distance(q, v), v) for v in E.vertices() if v in I.connected_component_containing_vertex(q) and not v == q] + distancequotients = [(E.distance(q, v)**2 / I.distance(q, v), v) + for v in E.vertices() + if v in I.connected_component_containing_vertex(q) and not v == q] r = max(distancequotients)[1] cutpath = I.shortest_path(q, r) Gcut = copy(G) @@ -834,21 +833,21 @@ def geometric_basis(G, E, p): for v in cutpath: neighs = G.neighbors(v) for n in neighs: - if n in G1.vertices()+cutpath: + if n in G1.vertices() + cutpath: G1.add_edge(v, n, None) - if n in G2.vertices()+cutpath: + if n in G2.vertices() + cutpath: G2.add_edge(v, n, None) - if EC[EC.index(q)+1] in G2.vertices(): + if EC[EC.index(q) + 1] in G2.vertices(): G1, G2 = G2, G1 E1, E2 = Ecut.connected_components_subgraphs() - if EC[EC.index(q)+1] in E2.vertices(): + if EC[EC.index(q) + 1] in E2.vertices(): E1, E2 = E2, E1 - for i in range(len(cutpath)-1): - E1.add_edge(cutpath[i], cutpath[i+1], None) - E2.add_edge(cutpath[i], cutpath[i+1], None) + for i in range(len(cutpath) - 1): + E1.add_edge(cutpath[i], cutpath[i + 1], None) + E2.add_edge(cutpath[i], cutpath[i + 1], None) for v in [q, r]: for n in E.neighbors(v): @@ -860,14 +859,16 @@ def geometric_basis(G, E, p): gb1 = geometric_basis(G1, E1, q) gb2 = geometric_basis(G2, E2, q) - resul = [connecting_path + path + list(reversed(connecting_path)) for path in gb1 + gb2] + reverse_connecting = list(reversed(connecting_path)) + resul = [connecting_path + path + reverse_connecting + for path in gb1 + gb2] for r in resul: i = 0 - while i < len(r)-2: - if r[i] == r[i+2]: + while i < len(r) - 2: + if r[i] == r[i + 2]: r.pop(i) r.pop(i) - if i > 0: + if i: i -= 1 else: i += 1 @@ -876,12 +877,12 @@ def geometric_basis(G, E, p): def braid_monodromy(f): r""" - Compute the braid monodromy of a projection of the curve defined by a polynomial + Compute the braid monodromy of a projection of the curve defined by a polynomial. INPUT: - - ``f`` -- a polynomial with two variables, over a number field with an embedding - in the complex numbers. + - ``f`` -- a polynomial with two variables, over a number field + with an embedding in the complex numbers OUTPUT: @@ -904,10 +905,9 @@ def braid_monodromy(f): s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1, s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1, s1*s0*s2*s0^-1*s2*s1^-1] - """ global roots_interval_cache - (x, y) = f.parent().gens() + x, y = f.parent().gens() F = f.base_ring() g = f.radical() d = g.degree(y) @@ -925,22 +925,24 @@ def braid_monodromy(f): E = E.union(reg.vertex_graph()) p = next(E.vertex_iterator()) geombasis = geometric_basis(G, E, p) - segs = set([]) + segs = set() for p in geombasis: for s in zip(p[:-1], p[1:]): if (s[1], s[0]) not in segs: segs.add((s[0], s[1])) I = QQbar.gen() - segs = [(a[0]+I*a[1], b[0]+I*b[1]) for (a, b) in segs] + segs = [(a[0] + I * a[1], b[0] + I * b[1]) for a, b in segs] vertices = list(set(flatten(segs))) tocacheverts = [(g, v) for v in vertices] populate_roots_interval_cache(tocacheverts) gfac = g.factor() try: - braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) + braidscomputed = (braid_in_segment([(gfac, seg[0], seg[1]) + for seg in segs])) except ChildProcessError: # hack to deal with random fails first time - braidscomputed = list(braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs])) - segsbraids = dict() + braidscomputed = (braid_in_segment([(gfac, seg[0], seg[1]) + for seg in segs])) + segsbraids = {} for braidcomputed in braidscomputed: seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) beginseg = (QQ(seg[0].real()), QQ(seg[0].imag())) @@ -952,9 +954,9 @@ def braid_monodromy(f): result = [] for path in geombasis: braidpath = B.one() - for i in range(len(path)-1): + for i in range(len(path) - 1): x0 = tuple(path[i].vector()) - x1 = tuple(path[i+1].vector()) + x1 = tuple(path[i + 1].vector()) braidpath = braidpath * segsbraids[(x0, x1)] result.append(braidpath) return result @@ -978,7 +980,8 @@ def fundamental_group(f, simplified=True, projective=False): of the curve will be computed, otherwise, the fundamental group of the complement in the affine plane will be computed - If ``simplified`` is ``False``, a Zariski-VanKampen presentation is returned. + If ``simplified`` is ``False``, a Zariski-VanKampen presentation + is returned. OUTPUT: @@ -1025,7 +1028,7 @@ def fundamental_group(f, simplified=True, projective=False): @parallel def relation(x, b): return x * b / x - relations = list(relation([(x, b) for x in F.gens() for b in bm])) + relations = (relation([(x, b) for x in F.gens() for b in bm])) R = [r[1] for r in relations] if projective: R.append(prod(F.gens())) From 6d6bc9d9ea8e811cffbd67a957fc8e3a15a7d9ca Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Sun, 7 Aug 2022 11:35:52 +0200 Subject: [PATCH 226/591] fix whitespace, (almost) fix coverage, multivariate tests, better error message for degree mismatch --- src/sage/rings/lazy_series.py | 89 +++++++++++++++++++++--------- src/sage/rings/lazy_series_ring.py | 64 +++++++++++---------- 2 files changed, 97 insertions(+), 56 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 73e5a81cf16..a35d41be998 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -349,7 +349,7 @@ def truncate(self, d): v = coeff_stream._approximate_order initial_coefficients = [coeff_stream[i] for i in range(v, d)] return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, - order=v)) + order=v)) def shift(self, n): r""" @@ -1009,16 +1009,19 @@ def _add_(self, other): and isinstance(right, Stream_exact)): approximate_order = min(left.order(), right.order()) degree = max(left._degree, right._degree) - initial_coefficients = [left[i] + right[i] for i in range(approximate_order, degree)] + initial_coefficients = [left[i] + right[i] + for i in range(approximate_order, degree)] constant = left._constant + right._constant if not any(initial_coefficients) and not constant: return P.zero() - coeff_stream = Stream_exact(initial_coefficients, P._sparse, - constant=constant, - degree=degree, - order=approximate_order) + coeff_stream = Stream_exact(initial_coefficients, + P._sparse, + constant=constant, + degree=degree, + order=approximate_order) return P.element_class(P, coeff_stream) - return P.element_class(P, Stream_add(self._coeff_stream, other._coeff_stream)) + return P.element_class(P, Stream_add(self._coeff_stream, + other._coeff_stream)) def _sub_(self, other): """ @@ -1089,10 +1092,11 @@ def _sub_(self, other): constant = left._constant - right._constant if not any(initial_coefficients) and not constant: return P.zero() - coeff_stream = Stream_exact(initial_coefficients, P._sparse, - constant=constant, - degree=degree, - order=approximate_order) + coeff_stream = Stream_exact(initial_coefficients, + P._sparse, + constant=constant, + degree=degree, + order=approximate_order) return P.element_class(P, coeff_stream) if left == right: return P.zero() @@ -1233,8 +1237,10 @@ def _acted_upon_(self, scalar, self_on_left): else: c = scalar * coeff_stream._constant initial_coefficients = [scalar * val for val in init_coeffs] - return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, - order=v, constant=c, + return P.element_class(P, Stream_exact(initial_coefficients, + P._sparse, + order=v, + constant=c, degree=coeff_stream._degree)) if self_on_left or R.is_commutative(): return P.element_class(P, Stream_lmul(coeff_stream, scalar)) @@ -1293,7 +1299,8 @@ def _neg_(self): if isinstance(coeff_stream, Stream_exact): initial_coefficients = [-v for v in coeff_stream._initial_coefficients] constant = -coeff_stream._constant - coeff_stream = Stream_exact(initial_coefficients, P._sparse, + coeff_stream = Stream_exact(initial_coefficients, + P._sparse, constant=constant, degree=coeff_stream._degree, order=coeff_stream.order()) @@ -1839,6 +1846,11 @@ def arcsinh(self): sage: asinh(z) z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8) + ``arcsinh`` is an alias:: + + sage: arcsinh(z) + z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8) + sage: L. = LazyTaylorSeriesRing(QQ) sage: asinh(x/(1-y)) x + x*y + (-1/6*x^3+x*y^2) + (-1/2*x^3*y+x*y^3) + (3/40*x^5-x^3*y^2+x*y^4) @@ -1872,6 +1884,11 @@ def arctanh(self): sage: atanh(z) z + 1/3*z^3 + 1/5*z^5 + 1/7*z^7 + O(z^8) + ``arctanh`` is an alias:: + + sage: arctanh(z) + z + 1/3*z^3 + 1/5*z^5 + 1/7*z^7 + O(z^8) + sage: L. = LazyTaylorSeriesRing(QQ) sage: atanh(x/(1-y)) x + x*y + (1/3*x^3+x*y^2) + (x^3*y+x*y^3) + (1/5*x^5+2*x^3*y^2+x*y^4) @@ -2156,8 +2173,10 @@ def _mul_(self, other): c += left._constant * ir[-1] else: c = left._constant # this is zero - coeff_stream = Stream_exact(initial_coefficients, P._sparse, - order=lv+rv, constant=c) + coeff_stream = Stream_exact(initial_coefficients, + P._sparse, + order=lv + rv, + constant=c) return P.element_class(P, coeff_stream) return P.element_class(P, Stream_cauchy_mul(left, right)) @@ -2235,9 +2254,11 @@ def __pow__(self, n): val = ret.valuation() deg = ret.degree() + 1 initial_coefficients = [ret[i] for i in range(val, deg)] - return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, + return P.element_class(P, Stream_exact(initial_coefficients, + P._sparse, constant=cs._constant, - degree=deg, order=val)) + degree=deg, + order=val)) return super().__pow__(n) @@ -2294,23 +2315,29 @@ def __invert__(self): i = ~coeff_stream._constant v = -coeff_stream.order() c = P._internal_poly_ring.base_ring().zero() - coeff_stream = Stream_exact((i, -i), P._sparse, - order=v, constant=c) + coeff_stream = Stream_exact((i, -i), + P._sparse, + order=v, + constant=c) return P.element_class(P, coeff_stream) if len(initial_coefficients) == 1 and not coeff_stream._constant: i = ~initial_coefficients[0] v = -coeff_stream.order() c = P._internal_poly_ring.base_ring().zero() - coeff_stream = Stream_exact((i,), P._sparse, - order=v, constant=c) + coeff_stream = Stream_exact((i,), + P._sparse, + order=v, + constant=c) return P.element_class(P, coeff_stream) if (len(initial_coefficients) == 2 and not (initial_coefficients[0] + initial_coefficients[1]) and not coeff_stream._constant): v = -coeff_stream.order() c = ~initial_coefficients[0] - coeff_stream = Stream_exact((), P._sparse, - order=v, constant=c) + coeff_stream = Stream_exact((), + P._sparse, + order=v, + constant=c) return P.element_class(P, coeff_stream) # (f^-1)^-1 = f @@ -2392,7 +2419,8 @@ def _div_(self, other): pass else: initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, + return P.element_class(P, Stream_exact(initial_coefficients, + P._sparse, order=ret.valuation(), constant=left._constant)) @@ -3410,6 +3438,9 @@ def __call__(self, *args): sage: L(f)(L(g)) - L(f(g)) O^7 + sage: L(f)(g) - L(f(g)) + O^7 + sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] sage: L(f)(L(q*g)) - L(f(q*g)) O^7 @@ -3488,8 +3519,12 @@ def _format_series(self, formatter, format_strings=False): TESTS:: - sage: s = SymmetricFunctions(ZZ).s() - sage: L = LazySymmetricFunctions(tensor([s, s])) + sage: h = SymmetricFunctions(ZZ).h() + sage: e = SymmetricFunctions(ZZ).e() + sage: L = LazySymmetricFunctions(tensor([h, e])) + sage: f = L(lambda n: sum(tensor([h[k], e[n-k]]) for k in range(n+1))) + sage: f._format_series(repr) + '(h[]#e[]) + (h[]#e[1]+h[1]#e[]) + (h[]#e[2]+h[1]#e[1]+h[2]#e[]) + (h[]#e[3]+h[1]#e[2]+h[2]#e[1]+h[3]#e[]) + (h[]#e[4]+h[1]#e[3]+h[2]#e[2]+h[3]#e[1]+h[4]#e[]) + (h[]#e[5]+h[1]#e[4]+h[2]#e[3]+h[3]#e[2]+h[4]#e[1]+h[5]#e[]) + (h[]#e[6]+h[1]#e[5]+h[2]#e[4]+h[3]#e[3]+h[4]#e[2]+h[5]#e[1]+h[6]#e[]) + O^7' """ P = self.parent() cs = self._coeff_stream diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index be24c2a838b..dbb010999ed 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1599,26 +1599,29 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) TESTS:: - sage: s = SymmetricFunctions(ZZ).s() - sage: m = SymmetricFunctions(ZZ).m() - sage: L = LazySymmetricFunctions(tensor([s, m])) + sage: e = SymmetricFunctions(ZZ).e() + sage: h = SymmetricFunctions(ZZ).h() + sage: L = LazySymmetricFunctions(tensor([h, e])) sage: L(lambda n: 0) O^7 + sage: L(lambda n: tensor([h[n], e([])]) + tensor([h([]), e[n]]), degree=3) + (2*h[]#e[]) + (h[]#e[1]+h[1]#e[]) + (h[]#e[2]+h[2]#e[]) + sage: L(lambda n: n)[3]; Traceback (most recent call last): ... - ValueError: coefficient 3*s[] # m[] at degree 3 is not a symmetric function of the correct homogeneous degree + ValueError: coefficient 3*h[] # e[] should be a symmetric function of homogeneous degree 3 but has degree 0 sage: L([1, 2, 3]); Traceback (most recent call last): ... - ValueError: coefficients must be symmetric functions of the correct homogeneous degree + ValueError: coefficient 2*h[] # e[] should be a symmetric function of homogeneous degree 1 but has degree 0 sage: L(lambda n: n, degree=3); Traceback (most recent call last): ... - ValueError: coefficients must be symmetric functions of the correct homogeneous degree + ValueError: coefficient h[] # e[] should be a symmetric function of homogeneous degree 1 but has degree 0 """ if valuation is None: @@ -1668,51 +1671,54 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) raise NotImplementedError("cannot convert between sparse and dense") if self._arity == 1: - def is_homogeneous_of_degree(f, d): + def check_homogeneous_of_degree(f, d): if not f: - return True + return try: - return f.homogeneous_degree() == d + d1 = f.homogeneous_degree() + if d1 == d: + return except ValueError: - return False + raise ValueError("coefficient %s should be a symmetric function of homogeneous degree %s" % (f, d)) + raise ValueError("coefficient %s should be a symmetric function of homogeneous degree %s but has degree %s" % (f, d, d1)) else: - def is_homogeneous_of_degree(f, d): + def check_homogeneous_of_degree(f, d): if not f: - return True + return for m in f.monomials(): for t in m.support(): - if sum(p.size() for p in t) != d: - return False + d1 = sum(p.size() for p in t) + if d1 != d: + raise ValueError("coefficient %s should be a symmetric function of homogeneous degree %s but has degree %s" % (f, d, d1)) + if isinstance(x, (tuple, list)): if degree is None: degree = valuation + len(x) p = [R(e) for e in x] - if not all(is_homogeneous_of_degree(e, i) - for i, e in enumerate(p, valuation)): - raise ValueError("coefficients must be symmetric functions of the correct homogeneous degree") + for i, e in enumerate(p, valuation): + check_homogeneous_of_degree(e, i) coeff_stream = Stream_exact(p, self._sparse, - order=valuation, - constant=0, - degree=degree) + order=valuation, + constant=0, + degree=degree) return self.element_class(self, coeff_stream) if callable(x): if degree is not None: p = [R(x(i)) for i in range(valuation, degree)] - if not all(is_homogeneous_of_degree(e, i) - for i, e in enumerate(p, valuation)): - raise ValueError("coefficients must be symmetric functions of the correct homogeneous degree") + for i, e in enumerate(p, valuation): + check_homogeneous_of_degree(e, i) coeff_stream = Stream_exact(p, self._sparse, - order=valuation, - constant=0, - degree=degree) + order=valuation, + constant=0, + degree=degree) return self.element_class(self, coeff_stream) coeff_ring = self._internal_poly_ring.base_ring() if check: def y(n): e = R(x(n)) - if is_homogeneous_of_degree(e, n): - return e - raise ValueError("coefficient %s at degree %s is not a symmetric function of the correct homogeneous degree" % (e, n)) + check_homogeneous_of_degree(e, n) + return e + coeff_stream = Stream_function(y, coeff_ring, self._sparse, valuation) else: coeff_stream = Stream_function(x, coeff_ring, self._sparse, valuation) From 57345553ed8801593ab22ea4842afbaa5579b4c8 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 7 Aug 2022 18:53:34 +0900 Subject: [PATCH 227/591] Fixing a number of small bugs and adding option for non-reduced GB. --- src/sage/algebras/clifford_algebra.py | 72 ++++++++++--- .../algebras/exterior_algebra_groebner.pxd | 1 + .../algebras/exterior_algebra_groebner.pyx | 101 +++++++++++++----- 3 files changed, 133 insertions(+), 41 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 0969856f4c6..55c3957ca3c 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2614,6 +2614,7 @@ def __init__(self, ring, gens, coerce=True, side="twosided"): sage: TestSuite(I).run(skip="_test_category") """ self._groebner_strategy = None + self._reduced = False self._homogeneous = all(x.is_super_homogeneous() for x in gens if x) if self._homogeneous: side = "twosided" @@ -2652,7 +2653,7 @@ def _contains_(self, f): EXAMPLES:: sage: E. = ExteriorAlgebra(QQ) - sage: I = E.ideal([x, x*y*z + 2*x*z + 3*y*z]) + sage: I = E.ideal([x, x*y*z + 2*x*z + 3*y*z], side="left") sage: I.groebner_basis() (x, y*z) sage: x in I @@ -2663,6 +2664,10 @@ def _contains_(self, f): True sage: x + 3*y in I False + sage: x*y in I + True + sage: x + x*y + y*z + x*z in I + True .. NOTE:: @@ -2848,9 +2853,9 @@ def __mul__(self, other): return self.ring().ideal(gens, side="left") return self.ring().ideal(gens, side="right") - def groebner_basis(self, term_order="neglex"): + def groebner_basis(self, term_order=None, reduced=True): r""" - Return the reduced Gröbner basis of ``self``. + Return the (reduced) Gröbner basis of ``self``. INPUT: @@ -2861,6 +2866,9 @@ def groebner_basis(self, term_order="neglex"): * ``"degrevlex"`` -- degree reverse lex order * ``"deglex"`` -- degree lex order + - ``reduced`` -- (default: ``True``) whether or not to return the + reduced Gröbner basis + EXAMPLES: We compute an example:: @@ -2873,10 +2881,10 @@ def groebner_basis(self, term_order="neglex"): ....: b*c*d - a*c*d + a*b*d - a*b*c] sage: I = E.ideal(rels) sage: I.groebner_basis() - (-a*c*d + a*c*e - a*d*e + c*d*e, - -a*b*c + a*b*d - a*c*d + b*c*d, + (-a*b*c + a*b*d - a*c*d + b*c*d, + -a*b*c + a*b*e - a*c*e + b*c*e, -a*b*d + a*b*e - a*d*e + b*d*e, - -a*b*c + a*b*e - a*c*e + b*c*e) + -a*c*d + a*c*e - a*d*e + c*d*e) With different term orders:: @@ -2887,10 +2895,10 @@ def groebner_basis(self, term_order="neglex"): a*b*c - a*b*e + a*c*e - b*c*e) sage: I.groebner_basis("deglex") - (-a*c*d + a*c*e - a*d*e + c*d*e, - -a*b*c + a*b*d - a*c*d + b*c*d, + (-a*b*c + a*b*d - a*c*d + b*c*d, + -a*b*c + a*b*e - a*c*e + b*c*e, -a*b*d + a*b*e - a*d*e + b*d*e, - -a*b*c + a*b*e - a*c*e + b*c*e) + -a*c*d + a*c*e - a*d*e + c*d*e) The example above was computed first using M2, which agrees with the ``"degrevlex"`` ordering:: @@ -2906,6 +2914,25 @@ def groebner_basis(self, term_order="neglex"): returns: o3 = | bcd-bce+bde-cde acd-ace+ade-cde abd-abe+ade-bde abc-abe+ace-bce | + By default, the Gröbner basis is reduced, but we can get non-reduced + Gröber bases (which are not unique):: + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([x+y*z]) + sage: I.groebner_basis(reduced=False) + (x*y, x*z, y*z + x, y*z + x, x*y*z) + sage: I.groebner_basis(reduced=True) + (x*y, x*z, y*z + x) + + However, if we have already computed a reduced Gröbner basis (with + a given term order), then we return that:: + + sage: I = E.ideal([x+y*z]) # A fresh ideal + sage: I.groebner_basis() + (x*y, x*z, y*z + x) + sage: I.groebner_basis(reduced=False) + (x*y, x*z, y*z + x) + TESTS:: sage: E. = ExteriorAlgebra(ZZ) @@ -2917,17 +2944,28 @@ def groebner_basis(self, term_order="neglex"): """ if self.ring().base_ring() not in Fields(): raise NotImplementedError("only implemented over fields") - if term_order == "neglex": - from sage.algebras.exterior_algebra_groebner import GroebnerStrategyNegLex as strategy - elif term_order == "degrevlex": - from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegRevLex as strategy - elif term_order == "deglex": - from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegLex as strategy + if term_order is None: + if self._groebner_strategy is not None: + strategy = type(self._groebner_strategy) + else: + from sage.algebras.exterior_algebra_groebner import GroebnerStrategyNegLex as strategy else: - raise ValueError("invalid term order") + if term_order == "neglex": + from sage.algebras.exterior_algebra_groebner import GroebnerStrategyNegLex as strategy + elif term_order == "degrevlex": + from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegRevLex as strategy + elif term_order == "deglex": + from sage.algebras.exterior_algebra_groebner import GroebnerStrategyDegLex as strategy + else: + raise ValueError("invalid term order") if strategy == type(self._groebner_strategy): + if self._reduced or not reduced: + return self._groebner_strategy.groebner_basis + self._reduced = reduced + self._groebner_strategy.reduce_computed_gb() return self._groebner_strategy.groebner_basis self._groebner_strategy = strategy(self) - self._groebner_strategy.compute_groebner() + self._groebner_strategy.compute_groebner(reduced=reduced) + self._reduced = reduced return self._groebner_strategy.groebner_basis diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd index 7708930faa8..0c001363130 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pxd +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -38,6 +38,7 @@ cdef class GroebnerStrategy: cpdef CliffordAlgebraElement reduce(self, CliffordAlgebraElement f) cdef CliffordAlgebraElement reduce_single(self, CliffordAlgebraElement f, CliffordAlgebraElement g) + cdef int reduced_gb(self, list G) except -1 # These are the methods that determine the ordering of the monomials. # These must be implemented in subclasses. Declare them as "inline" there. diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 3a2e73de41c..5a0ce6ccb6c 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -20,6 +20,7 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** +from cysignals.signals cimport sig_check from sage.libs.gmp.mpz cimport mpz_sizeinbase, mpz_setbit, mpz_tstbit, mpz_cmp_si, mpz_sgn from sage.data_structures.bitset_base cimport (bitset_t, bitset_init, bitset_first, bitset_next, bitset_set_to, bitset_len) @@ -238,9 +239,9 @@ cdef class GroebnerStrategy: for i, p in enumerate(M.pivots()) if r - Integer(p) not in lead_supports] - def compute_groebner(self): - """ - Compute the reduced ``side`` Gröbner basis for the ideal ``I``. + def compute_groebner(self, reduced=True): + r""" + Compute the (``reduced``) left/right Gröbner basis for the ideal ``I``. EXAMPLES:: @@ -253,9 +254,12 @@ cdef class GroebnerStrategy: (1,) sage: E. = ExteriorAlgebra(QQ) - sage: I = E.ideal([a+b*c]) + sage: I = E.ideal([a+b*c], side="left") + sage: I.groebner_basis() # indirect doctest + (b*c + a,) + sage: I = E.ideal([a+b*c], side="twosided") sage: I.groebner_basis() # indirect doctest - (b*c + a, a*c, a*b, a*d) + (a*b, a*c, b*c + a, a*d) """ cdef FrozenBitset p0, p1 cdef long deg @@ -264,6 +268,7 @@ cdef class GroebnerStrategy: cdef GBElement f0, f1 cdef list G = [self.build_elt(f) for f in self.ideal.gens() if f] # Remove 0s cdef list Gp + cdef CliffordAlgebraElement f if self.side == 2 and not self.homogeneous: # Add in all S-poly times positive degree monomials @@ -286,6 +291,7 @@ cdef class GroebnerStrategy: P[deg] = [(f0, f1)] while P: + sig_check() Pp = P.pop(min(P)) # The selection: lowest lcm degree Gp = self.reduction(Pp, G) G.extend(Gp) @@ -304,29 +310,71 @@ cdef class GroebnerStrategy: G.sort(key=lambda x: ( x).lsi) - for i in range(len(G)): - G[i] = ( G[i]).elt + if not reduced: + self.groebner_basis = tuple([( f0).elt for f0 in G if ( f0).elt]) + return + self.reduced_gb(G) + + cdef int reduced_gb(self, list G) except -1: + """ + Convert the Gröbner basis ``G`` into a reduced Gröbner basis. + """ + cdef Py_ssize_t i, j, k + cdef GBElement f0, f1 # Now that we have a Gröbner basis, we make this into a reduced Gröbner basis - cdef set pairs = set((i, j) for i in range(n) for j in range(i+1,n)) cdef tuple supp cdef bint did_reduction cdef FrozenBitset lm, s + cdef Integer r + cdef Py_ssize_t num_zeros = 0 + cdef Py_ssize_t n = len(G) + cdef set pairs = set((i, j) for i in range(n) for j in range(n) if i != j) + while pairs: + sig_check() i,j = pairs.pop() - f = G[i] - g = G[j] + f0 = G[i] + f1 = G[j] # We perform the classical reduction algorithm here on each pair # TODO: Make this faster by using the previous technique? - fp = self.reduce_single(f, g) - if f != fp: - G[i] = fp - if not fp: - pairs.difference_update((k, i) for k in range(n)) - else: + f = self.reduce_single(f0.elt, f1.elt) + if f0.elt != f: + if f: + G[i] = self.build_elt(f) pairs.update((k, i) for k in range(n) if k != i) + else: + G[i] = GBElement(f, FrozenBitset(), Integer(2)**self.rank + 1) + num_zeros += 1 + pairs.difference_update((k, i) for k in range(n) if k != i) + pairs.difference_update((i, k) for k in range(n) if k != i) + + G.sort(key=lambda x: ( x).lsi) + for i in range(len(G)-num_zeros): + f0 = G[i] + if f0.elt: + inv = ~f0.elt[f0.ls] + for key in f0.elt._monomial_coefficients: + f0.elt._monomial_coefficients[key] *= inv + self.groebner_basis = tuple([f0.elt for f0 in G[:len(G)-num_zeros]]) + return 0 - self.groebner_basis = tuple([~f[self.leading_support(f)] * f for f in G if f]) + def reduce_computed_gb(self): + """ + Convert the computed Gröbner basis to a reduced Gröbner basis. + + sage: E. = ExteriorAlgebra(QQ) + sage: I = E.ideal([x+y*z]) + sage: I.groebner_basis(reduced=False) + (x*y, x*z, y*z + x, y*z + x, x*y*z) + sage: I._groebner_strategy.reduce_computed_gb() + sage: I._groebner_strategy.groebner_basis + (x*y, x*z, y*z + x) + """ + if self.groebner_basis == [(None,)]: + raise ValueError("Gröbner basis not yet computed") + cdef list G = [self.build_elt(f) for f in self.groebner_basis] + self.reduced_gb(G) cpdef CliffordAlgebraElement reduce(self, CliffordAlgebraElement f): """ @@ -341,23 +389,28 @@ cdef class GroebnerStrategy: ....: b*c*e - a*c*e + a*b*e - a*b*c, ....: b*c*d - a*c*d + a*b*d - a*b*c] sage: I = E.ideal(rels) - sage: I.reduce(a*b*e) + sage: GB = I.groebner_basis() + sage: I._groebner_strategy.reduce(a*b*e) a*b*e - sage: I.reduce(b*d*e) + sage: I._groebner_strategy.reduce(b*d*e) a*b*d - a*b*e + a*d*e - sage: I.reduce(c*d*e) + sage: I._groebner_strategy.reduce(c*d*e) a*c*d - a*c*e + a*d*e - sage: I.reduce(a*b*c*d*e) + sage: I._groebner_strategy.reduce(a*b*c*d*e) + 0 + sage: I._groebner_strategy.reduce(a*b*c*d) 0 - sage: I.reduce(a*b*c*d) + sage: I._groebner_strategy.reduce(E.zero()) 0 """ + if not f: + return f for g in self.groebner_basis: f = self.reduce_single(f, g) return f cdef CliffordAlgebraElement reduce_single(self, CliffordAlgebraElement f, CliffordAlgebraElement g): - """ + r""" Reduce ``f`` by ``g``. .. TODO:: @@ -376,7 +429,7 @@ cdef class GroebnerStrategy: did_reduction = True mon = build_monomial(self.E, s - lm) if self.side == 0: - gp = mon * g.elt + gp = mon * g f -= f[s] / gp[s] * gp else: gp = g * mon From cc5a551ee786bf453bb1a879a09af50d8c781431 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sun, 7 Aug 2022 15:44:20 -0700 Subject: [PATCH 228/591] Update threejs-sage conda package name --- build/pkgs/threejs/distros/conda.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/threejs/distros/conda.txt b/build/pkgs/threejs/distros/conda.txt index 023a0678428..d1ffb850424 100644 --- a/build/pkgs/threejs/distros/conda.txt +++ b/build/pkgs/threejs/distros/conda.txt @@ -1 +1 @@ -three.js +threejs-sage=122.* From c01586d5b8b0c387b54775a065f2109614381193 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 8 Aug 2022 09:20:02 +0900 Subject: [PATCH 229/591] Revert with_basis/morphism.py. --- src/sage/modules/with_basis/morphism.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 2efcc4f25e9..b8fe98111b2 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -404,10 +404,10 @@ def __call__(self, *args): if self._is_module_with_basis_over_same_base_ring: return self.codomain().linear_combination( (self._on_basis(*(before+(index,)+after)), coeff ) - for (index, coeff) in mc.items() if self._on_basis(index)) + for (index, coeff) in mc.items()) else: return sum((coeff * self._on_basis(*(before+(index,)+after)) - for (index, coeff) in mc.items() if self._on_basis(index)), self._zero) + for (index, coeff) in mc.items()), self._zero) # As per the specs of Map, we should in fact implement _call_. # However we currently need to abuse Map.__call__ (which strict From 8b777a044a9f6559e608d0ae2dca24306abbfcf7 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 8 Aug 2022 09:50:38 +0900 Subject: [PATCH 230/591] Fixing up doctests and some other compatibility issues. --- src/sage/algebras/clifford_algebra.py | 66 +++++++++++++------ .../categories/filtered_modules_with_basis.py | 4 +- .../categories/graded_algebras_with_basis.py | 4 +- src/sage/modules/with_basis/invariant.py | 12 ++-- src/sage/modules/with_basis/representation.py | 6 +- 5 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 2039f24780c..b00c252a31a 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -385,27 +385,11 @@ def supercommutator(self, x): return ret -class CliffordAlgebraIndices(Parent): +class CliffordAlgebraIndices(UniqueRepresentation, Parent): r""" A facade parent for the indices of Clifford algebra. Users should not create instances of this class directly. """ - def __call__(self, el): - r""" - EXAMPLES:: - - sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices - sage: idx = CliffordAlgebraIndices(7) - sage: idx([1,3,6]) - 0101001 - sage: E = ExteriorAlgebra(QQ, 7) - sage: B = E.basis() - """ - if not isinstance(el, Element): - return self._element_constructor_(el) - else: - return Parent.__call__(self, el) - def __init__(self, Qdim): r""" Initialize ``self``. @@ -419,12 +403,12 @@ def __init__(self, Qdim): sage: idx._cardinality 128 sage: i = idx.an_element(); i - 0 + 1111 sage: type(i) """ self._nbits = Qdim - self._cardinality = 2**Qdim + self._cardinality = 2 ** Qdim # the if statement here is in case Qdim is 0. category = FiniteEnumeratedSets().Facade() Parent.__init__(self, category=category, facade=True) @@ -456,6 +440,22 @@ def _element_constructor_(self, x): if isinstance(x, int): return FrozenBitset((x,)) + def __call__(self, el): + r""" + EXAMPLES:: + + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(7) + sage: idx([1,3,6]) + 0101001 + sage: E = ExteriorAlgebra(QQ, 7) + sage: B = E.basis() + """ + if not isinstance(el, Element): + return self._element_constructor_(el) + else: + return Parent.__call__(self, el) + def cardinality(self): r""" Return the cardinality of ``self``. @@ -556,7 +556,7 @@ def __contains__(self, elt): EXAMPLES:: sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices - sage: idx = CliffordAlgebraIndices(3); + sage: idx = CliffordAlgebraIndices(3) sage: int(8) in idx # representing the set {4} False sage: int(5) in idx # representing the set {1,3} @@ -572,6 +572,32 @@ def __contains__(self, elt): return False return elt.capacity() <= self._nbits + def _an_element_(self): + """ + Returns an element of ``self``. + + EXAMPLES:: + + sage: from sage.algebras.clifford_algebra import CliffordAlgebraIndices + sage: idx = CliffordAlgebraIndices(0) + sage: idx._an_element_() + 0 + sage: idx = CliffordAlgebraIndices(1) + sage: idx._an_element_() + 1 + sage: idx = CliffordAlgebraIndices(2) + sage: idx._an_element_() + 01 + sage: idx = CliffordAlgebraIndices(3) + sage: idx._an_element_() + 11 + """ + if not self._nbits: + return FrozenBitset() + + from sage.combinat.subset import SubsetsSorted + X = SubsetsSorted(range(self._nbits)) + return FrozenBitset(X.an_element()) class CliffordAlgebra(CombinatorialFreeModule): r""" diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index bd75b8f8e8a..336c1c326c8 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -178,9 +178,9 @@ def basis(self, d=None): sage: E. = ExteriorAlgebra(QQ) sage: E.basis() - Lazy family (Term map from Subsets of {0, 1} to + Lazy family (Term map from Subsets of {0,1} to The exterior algebra of rank 2 over Rational Field(i))_{i in - Subsets of {0, 1}} + Subsets of {0,1}} """ if d is None: from sage.sets.family import Family diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index e80c1b00bf4..abece323a5c 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -168,10 +168,10 @@ def one_basis(self): sage: A. = ExteriorAlgebra(QQ) sage: A.one_basis() - () + 0 sage: B = tensor((A, A, A)) sage: B.one_basis() - ((), (), ()) + (0, 0, 0) sage: B.one() 1 # 1 # 1 """ diff --git a/src/sage/modules/with_basis/invariant.py b/src/sage/modules/with_basis/invariant.py index e44c1ece287..f180f442c19 100644 --- a/src/sage/modules/with_basis/invariant.py +++ b/src/sage/modules/with_basis/invariant.py @@ -109,7 +109,7 @@ class FiniteDimensionalInvariantModule(SubmoduleWithBasis): sage: M = algebras.Exterior(QQ, 'x', 3) sage: def cyclic_ext_action(g, m): ....: # cyclically permute generators - ....: return M.prod([M.monomial((g(j+1)-1,)) for j in m]) + ....: return M.prod([M.monomial(FrozenBitset([g(j+1)-1])) for j in m]) If you care about being able to exploit the algebra structure of the exterior algebra (i.e. if you want to multiply elements together), you @@ -398,7 +398,7 @@ def _mul_(self, other): sage: G = CyclicPermutationGroup(3); G.rename('G') sage: M = algebras.Exterior(QQ, 'x', 3) - sage: def on_basis(g,m): return M.prod([M.monomial((g(j+1)-1,)) for j in m]) # cyclically permute generators + sage: def on_basis(g,m): return M.prod([M.monomial(FrozenBitset([g(j+1)-1])) for j in m]) # cyclically permute generators sage: R = Representation(G, M, on_basis, category=Algebras(QQ).WithBasis().FiniteDimensional(), side='right') sage: I = R.invariant_module(); I.rename('I') sage: B = I.basis() @@ -466,7 +466,6 @@ def _acted_upon_(self, scalar, self_on_left=False): sage: g = G.an_element(); g (1,2,3) sage: M = CombinatorialFreeModule(QQ, [1,2,3]) - sage: E = algebras.Exterior(QQ, 'x', 3) sage: from sage.modules.with_basis.representation import Representation sage: R = Representation(G, M, lambda g,x: M.monomial(g(x))) sage: I = R.invariant_module() @@ -480,7 +479,8 @@ def _acted_upon_(self, scalar, self_on_left=False): [2*B[0], 2*B[0], 2*B[0]] - sage: def on_basis(g,m): return E.prod([E.monomial((g(j+1)-1,)) for j in m]) # cyclically permute generators + sage: E = algebras.Exterior(QQ, 'x', 3) + sage: def on_basis(g,m): return E.prod([E.monomial(FrozenBitset([g(j+1)-1])) for j in m]) # cyclically permute generators sage: R = Representation(G, E, on_basis, category=Algebras(QQ).WithBasis().FiniteDimensional()) sage: I = R.invariant_module() sage: B = I.basis() @@ -528,7 +528,7 @@ def _acted_upon_(self, scalar, self_on_left=False): sage: [b._acted_upon_(G((1,3,2)), self_on_left=True) for b in I.basis()] [B[0]] - sage: def on_basis(g,m): return E.prod([E.monomial((g(j+1)-1,)) for j in m]) # cyclically permute generators + sage: def on_basis(g,m): return E.prod([E.monomial(FrozenBitset([g(j+1)-1])) for j in m]) # cyclically permute generators sage: R = Representation(G, E, on_basis, category=Algebras(QQ).WithBasis().FiniteDimensional(), side='right') sage: I = R.invariant_module() sage: B = I.basis() @@ -687,7 +687,7 @@ class FiniteDimensionalTwistedInvariantModule(SubmoduleWithBasis): sage: G = SymmetricGroup(3); G.rename('S3') sage: E = algebras.Exterior(QQ, 'x', 3); E.rename('E') - sage: def action(g,m): return E.prod([E.monomial((g(j+1)-1,)) for j in m]) + sage: def action(g,m): return E.prod([E.monomial(FrozenBitset([g(j+1)-1])) for j in m]) sage: from sage.modules.with_basis.representation import Representation sage: EA = Representation(G, E, action, category=Algebras(QQ).WithBasis().FiniteDimensional()) sage: T = EA.twisted_invariant_module([2,0,-1]) diff --git a/src/sage/modules/with_basis/representation.py b/src/sage/modules/with_basis/representation.py index 89721adffae..815871e038d 100644 --- a/src/sage/modules/with_basis/representation.py +++ b/src/sage/modules/with_basis/representation.py @@ -276,7 +276,7 @@ def __init__(self, semigroup, module, on_basis, side="left", **kwargs): sage: G = CyclicPermutationGroup(3) sage: M = algebras.Exterior(QQ, 'x', 3) sage: from sage.modules.with_basis.representation import Representation - sage: on_basis = lambda g,m: M.prod([M.monomial((g(j+1)-1,)) for j in m]) #cyclically permute generators + sage: on_basis = lambda g,m: M.prod([M.monomial(FrozenBitset([g(j+1)-1])) for j in m]) #cyclically permute generators sage: from sage.categories.algebras import Algebras sage: R = Representation(G, M, on_basis, category=Algebras(QQ).WithBasis().FiniteDimensional()) sage: r = R.an_element(); r @@ -451,9 +451,9 @@ def product_by_coercion(self, left, right): ... TypeError: unsupported operand parent(s) for *: 'Representation of The Klein 4 group of order 4, as a permutation - group indexed by Subsets of {0, 1, 2, 3} over Rational Field' and + group indexed by Subsets of {0,1,...,3} over Rational Field' and 'Representation of The Klein 4 group of order 4, as a permutation - group indexed by Subsets of {0, 1, 2, 3} over Rational Field' + group indexed by Subsets of {0,1,...,3} over Rational Field' sage: from sage.categories.algebras import Algebras sage: category = Algebras(QQ).FiniteDimensional().WithBasis() From c6772ddbddf7ce66c9956aff3e0915f35507f33c Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 8 Aug 2022 11:40:38 +0800 Subject: [PATCH 231/591] remove incorrect(?) sig_on/sig_off The callee ._groebner_basis() is a Python function doing lots of Python things, but according to the cysignals documentation "the code inside sig_on() should be pure C or Cython code". --- src/sage/rings/polynomial/pbori/pbori.pyx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index 9e3723c5c4b..413a09656e6 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -182,7 +182,6 @@ and naturally the second option is faster. from cpython.object cimport Py_EQ, Py_NE from cython.operator cimport dereference as deref from cysignals.memory cimport sig_malloc, sig_free -from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr import operator @@ -5037,9 +5036,7 @@ class BooleanPolynomialIdeal(MPolynomialIdeal): else: if "redsb" not in kwds: kwds["redsb"]=True - sig_on() gb = self._groebner_basis(**kwds) - sig_off() if kwds.get("deg_bound", False) is False: g = GroebnerStrategy(gb[0].ring()) From ab725f2de9f18cd692b6828e8978842c4a4b98b0 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 8 Aug 2022 11:07:22 +0900 Subject: [PATCH 232/591] Fix spaces --- src/sage/homology/free_resolution.py | 29 +++++++++++++------------- src/sage/homology/graded_resolution.py | 6 ++++++ src/sage/libs/singular/function.pyx | 7 +------ src/sage/libs/singular/singular.pyx | 13 ++---------- 4 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 82e7e91af28..4468585c4f6 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -16,9 +16,8 @@ sage: from sage.homology.free_resolution import FreeResolution sage: S. = PolynomialRing(QQ) - sage: m1 = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() - sage: m2 = matrix(S, 3, [-y, x, z, -y, -w, z]) - sage: r = FreeResolution(m1, name='S') + sage: m = matrix(S, 1, [z^2 - y*w, y*z - x*w, y^2 - x*z]).transpose() + sage: r = FreeResolution(m, name='S') sage: r S^1 <-- S^3 <-- S^2 <-- 0 @@ -27,9 +26,6 @@ sage: r S^1 <-- S^3 <-- S^2 <-- 0 - sage: FreeResolution(m2, name='S') - S^2 <-- S^6 <-- S^5 <-- 0 - :: sage: from sage.homology.graded_resolution import GradedFreeResolution @@ -57,6 +53,7 @@ AUTHORS: - Kwankyu Lee (2022-05-13): initial version + """ # **************************************************************************** @@ -83,10 +80,13 @@ class FreeResolution_generic(SageObject): r""" - Abstract base class of finite free resolutions. + Generic base class of finite free resolutions. + + A subclass must provide a ``_maps`` attribute that contains a list of the + maps defining the resolution. The matrix at index `i` in the list defines the differential map from - `(i+1)`-th free module to the `i`-th free module over the base ring by + `(i + 1)`-th free module to the `i`-th free module over the base ring by multiplication on the left. The number of matrices in the list is the length of the resolution. The number of rows and columns of the matrices define the ranks of the free modules in the resolution. @@ -94,6 +94,10 @@ class FreeResolution_generic(SageObject): Note that the first matrix in the list defines the differential map at homological index `1`. + A subclass can define ``_initial_differential`` attribute that + contains the `0`-th differential map whose codomain is the target + of the free resolution. + EXAMPLES:: sage: from sage.homology.free_resolution import FreeResolution @@ -115,13 +119,6 @@ def __init__(self, base_ring, name='F'): """ Initialize. - Subclasses must provide a ``_maps`` attribute that contains the - maps defining the resolution. - - A subclass can define ``_initial_differential`` attribute that - contains the `0`-th differential map whose codomain is the target - of the free resolution. - INPUT: - ``base_ring`` -- a ring @@ -421,7 +418,9 @@ class FreeResolution(FreeResolution_generic): - ``module`` -- a submodule of a free module `M` of rank `n` over `S` or an ideal of a multi-variate polynomial ring + - ``name`` -- a string; name of the base ring + - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` OUTPUT: a minimal free resolution of the ideal diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index bfa9354ff4c..a73aa7f5c9f 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -60,6 +60,7 @@ AUTHORS: - Kwankyu Lee (2022-05): initial version + """ # **************************************************************************** @@ -92,12 +93,16 @@ class GradedFreeResolution(FreeResolution): - ``module`` -- a homogeneous submodule of a free module `M` of rank `n` over `S` or a homogeneous ideal of a multivariate polynomial ring `S` + - ``degrees`` -- (default: a list with all entries `1`) a list of integers or integer vectors giving degrees of variables of `S` + - ``shifts`` -- a list of integers or integer vectors giving shifts of degrees of `n` summands of the free module `M`; this is a list of zero degrees of length `n` by default + - ``name`` -- a string; name of the base ring + - ``algorithm`` -- Singular algorithm to compute a resolution of ``ideal`` If ``module`` is an ideal of `S`, it is considered as a submodule of a @@ -347,6 +352,7 @@ def betti(self, i, a=None): INPUT: - ``i`` -- nonnegative integer + - ``a`` -- a degree; if ``None``, return Betti numbers in all degrees EXAMPLES:: diff --git a/src/sage/libs/singular/function.pyx b/src/sage/libs/singular/function.pyx index 7557f6ee026..d7255b34440 100644 --- a/src/sage/libs/singular/function.pyx +++ b/src/sage/libs/singular/function.pyx @@ -56,15 +56,10 @@ TESTS:: AUTHORS: - Michael Brickenstein (2009-07): initial implementation, overall design - - Martin Albrecht (2009-07): clean up, enhancements, etc - - Michael Brickenstein (2009-10): extension to more Singular types - - Martin Albrecht (2010-01): clean up, support for attributes - - Simon King (2011-04): include the documentation provided by Singular as a code block - - Burcin Erocal, Michael Brickenstein, Oleksandr Motsak, Alexander Dreyer, Simon King (2011-09): plural support """ @@ -757,7 +752,7 @@ cdef class Converter(SageObject): for j from 0 <= j < IDELEMS(i): p = self.to_sage_vector_destructive(i.m[j], free_module) - i.m[j]=NULL # save it from getting freed + i.m[j] = NULL # save it from getting freed l.append( p ) return Sequence(l, check=False, immutable=True) diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index 2a08d698580..82d83e01212 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -750,6 +750,7 @@ cpdef tuple si2sa_resolution_graded(Resolution res, tuple degrees): INPUT: - ``res`` -- Singular resolution + - ``degrees`` -- list of integers or integer vectors The procedure is destructive, and ``res`` is not usable afterward. @@ -868,7 +869,6 @@ cdef number *sa2si_QQ(Rational r, ring *_ring): - ``_ ring`` - a (pointer to) a singular ring, where the resul will live - OUTPUT: - A (pointer to) a singular number @@ -899,7 +899,6 @@ cdef number *sa2si_GFqGivaro(int quo, ring *_ring): - ``_ ring`` - a (pointer to) a singular ring, where the resul will live - OUTPUT: - A (pointer to) a singular number @@ -908,7 +907,6 @@ cdef number *sa2si_GFqGivaro(int quo, ring *_ring): generator. In this case, ``quo`` is the integer resulting from evaluating that polynomial in the characteristic of the field. - TESTS:: sage: F = FiniteField(5^2) @@ -969,7 +967,6 @@ cdef number *sa2si_GFqNTLGF2E(FFgf2eE elem, ring *_ring): - ``_ ring`` - a (pointer to) a singular ring, where the resul will live - OUTPUT: - A (pointer to) a singular number @@ -1035,7 +1032,6 @@ cdef number *sa2si_GFq_generic(object elem, ring *_ring): - ``_ ring`` - a (pointer to) a singular ring, where the resul will live - OUTPUT: - A (pointer to) a singular number @@ -1102,7 +1098,6 @@ cdef number *sa2si_transext_QQ(object elem, ring *_ring): - ``_ ring`` - a (pointer to) a singular ring, where the resul will live - OUTPUT: - A (pointer to) a singular number @@ -1150,7 +1145,6 @@ cdef number *sa2si_transext_QQ(object elem, ring *_ring): sage: R(f) x + y + 1 """ - cdef int j cdef number *n1 cdef number *a @@ -1255,7 +1249,6 @@ cdef number *sa2si_transext_FF(object elem, ring *_ring): - ``_ ring`` - a (pointer to) a singular ring, where the resul will live - OUTPUT: - A (pointer to) a singular number @@ -1357,7 +1350,6 @@ cdef number *sa2si_NF(object elem, ring *_ring): - ``_ ring`` - a (pointer to) a singular ring, where the resul will live - OUTPUT: - A (pointer to) a singular number @@ -1449,7 +1441,6 @@ cdef number *sa2si_ZZ(Integer d, ring *_ring): - ``_ ring`` - a (pointer to) a singular ring, where the resul will live - OUTPUT: - A (pointer to) a singular number @@ -1659,7 +1650,7 @@ cdef object si2sa_intvec(intvec *v): INPUT: - - ``v`` - a (pointer to) a singular intvec + - ``v`` -- a (pointer to) a singular intvec OUTPUT: From c4cbb1faf3f7aa4f4530aed16bd59a1377464649 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Sun, 7 Aug 2022 22:54:26 -0600 Subject: [PATCH 233/591] fix all dlog bounds to be inclusive --- src/sage/groups/generic.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 99cf0fb4f46..48a726eb6b2 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -879,11 +879,12 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i bound = ub - lb i = 0 # this corrects a bug in which the loop is never entered and i never gets assigned a value for i, (pi, ri) in enumerate(f): - running_bound = min(bound, pi ** ri) + running_bound = min(bound, pi**ri - 1) for j in range(ri): - temp_bound = min(running_bound, pi) + temp_bound = min(running_bound, pi - 1) gamma = power(base, ord // pi) h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) + print(l[i]) if algorithm == 'bsgs': c = bsgs(gamma, h, (0, temp_bound), inverse=inverse, identity=identity, op=op, operation=operation) elif algorithm == 'rho': @@ -1007,7 +1008,7 @@ def discrete_log_lambda(a, base, bounds, operation='*', identity=None, inverse=N while c - d >= lb: if mut: H.set_immutable() - if ub > c - d and H in mem: + if ub >= c - d and H in mem: return c - d r, e = M[hash_function(H) % k] H = mult(H, e) From 0eb4c5222ff5b9fd983e5de9db1842fc703b73ee Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Sun, 7 Aug 2022 23:03:37 -0600 Subject: [PATCH 234/591] workaround in case user provides bad order --- src/sage/groups/generic.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 48a726eb6b2..6fb864a8ec1 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -872,19 +872,24 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i mods = [] running_mod = 1 offset = 0 - bound = ord - 1 # to avoid putting extra if statements everywhere if bounds: a = mult(a, power(base, -lb)) offset = lb bound = ub - lb i = 0 # this corrects a bug in which the loop is never entered and i never gets assigned a value for i, (pi, ri) in enumerate(f): + gamma = power(base, ord // pi) + # pohlig-hellman doesn't work with an incorrect order, and the user might have provided a bad parameter + while gamma == power(gamma, 0): # identity might be None + gamma = mult(gamma, power(base, -1)) + ri -= 1 + ord //= pi + if not bounds: + bound = ord - 1 running_bound = min(bound, pi**ri - 1) for j in range(ri): temp_bound = min(running_bound, pi - 1) - gamma = power(base, ord // pi) h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) - print(l[i]) if algorithm == 'bsgs': c = bsgs(gamma, h, (0, temp_bound), inverse=inverse, identity=identity, op=op, operation=operation) elif algorithm == 'rho': From fe1b932988bdfa21384bc0286915e052e3a6eec0 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Sun, 7 Aug 2022 23:08:51 -0600 Subject: [PATCH 235/591] added random testing --- src/sage/groups/generic.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 6fb864a8ec1..48542bfcc4e 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -835,6 +835,28 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: discrete_log(u,g,algorithm='rho') 123456789 + TESTS: + + Random testing:: + + sage: G = Zmod(randrange(1, 1000)) + sage: base = G.random_element() + sage: order = base.additive_order() + sage: assert order.divides(G.cardinality()) + sage: sol = randrange(order) + sage: elem = sol * base + sage: args = (elem, base, order) + sage: kwargs = {'operation': '+'} + sage: kwargs['algorithm'] = choice(['bsgs', 'rho', 'lambda']) + sage: if randrange(2): + ....: lo = randrange(-order, sol+1) + ....: hi = randrange(sol+1, 2*order) + ....: assert lo <= sol <= hi + ....: kwargs['bounds'] = (lo, hi) + sage: res = discrete_log(*args, **kwargs) + sage: res == sol + True + AUTHORS: - William Stein and David Joyner (2005-01-05) From 263775068531d6d9083d7f81bdbda560e28d72d7 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 8 Aug 2022 14:21:39 +0900 Subject: [PATCH 236/591] Small doc tweak. --- src/sage/algebras/clifford_algebra.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index b00c252a31a..d40e330819f 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -573,8 +573,8 @@ def __contains__(self, elt): return elt.capacity() <= self._nbits def _an_element_(self): - """ - Returns an element of ``self``. + r""" + Return an element of ``self``. EXAMPLES:: From 20ae1d81b04a1d455164c416e2e07d988181d704 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Sun, 7 Aug 2022 23:22:55 -0600 Subject: [PATCH 237/591] fixed previous workaround when base == identity --- src/sage/groups/generic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 48542bfcc4e..856c4cbafe6 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -902,13 +902,14 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i for i, (pi, ri) in enumerate(f): gamma = power(base, ord // pi) # pohlig-hellman doesn't work with an incorrect order, and the user might have provided a bad parameter - while gamma == power(gamma, 0): # identity might be None + while gamma == power(gamma, 0) and ord > 1: # identity might be None gamma = mult(gamma, power(base, -1)) ri -= 1 ord //= pi if not bounds: bound = ord - 1 running_bound = min(bound, pi**ri - 1) + j = 0 for j in range(ri): temp_bound = min(running_bound, pi - 1) h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) From 140ac6c9b2fced6e9ff87336040d3a906a248a61 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 8 Aug 2022 14:45:26 +0900 Subject: [PATCH 238/591] Migration of RAAG cohomology to Cython. --- .../algebras/clifford_algebra_element.pxd | 3 + .../algebras/clifford_algebra_element.pyx | 60 +++++++++++++++++++ src/sage/groups/raag.py | 50 +--------------- 3 files changed, 65 insertions(+), 48 deletions(-) diff --git a/src/sage/algebras/clifford_algebra_element.pxd b/src/sage/algebras/clifford_algebra_element.pxd index f7a25582d54..a274f65205a 100644 --- a/src/sage/algebras/clifford_algebra_element.pxd +++ b/src/sage/algebras/clifford_algebra_element.pxd @@ -10,3 +10,6 @@ cdef class CliffordAlgebraElement(IndexedFreeModuleElement): cdef class ExteriorAlgebraElement(CliffordAlgebraElement): pass +cdef class CohomologyRAAGElement(CliffordAlgebraElement): + pass + diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index ac74f313f76..dc24c92ae03 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -607,3 +607,63 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): """ return (self.transpose() * other).constant_coefficient() +cdef class CohomologyRAAGElement(CliffordAlgebraElement): + """ + An element in the cohomology of a right-angled Artin group. + + .. SEEALSO:: + + :class:`~sage.groups.raag.CohomologyRAAG` + """ + cdef _mul_(self, other): + """ + Return ``self`` multiplied by ``other``. + + EXAMPLES:: + + sage: C4 = graphs.CycleGraph(4) + sage: A = groups.misc.RightAngledArtin(C4) + sage: H = A.cohomology() + sage: b = sum(H.basis()) + sage: b * b + 2*e0*e2 + 2*e1*e3 + 2*e0 + 2*e1 + 2*e2 + 2*e3 + 1 + """ + zero = self._parent._base.zero() + cdef frozenset I = frozenset(self._parent._indices) + cdef dict d = {} + cdef list t + cdef tuple tp + cdef tuple ml, mr + cdef Py_ssize_t pos, i, j + cdef bint negate + + for ml, cl in self._monomial_coefficients.items(): + for mr, cr in other._monomial_coefficients.items(): + # Create the next term + tp = tuple(sorted(mr + ml)) + if any(tp[i] == tp[i+1] for i in range(len(tp)-1)): # e_i ^ e_i = 0 + continue + if tp not in I: # not an independent set, so this term is also 0 + continue + + t = list(mr) + negate = False + for i in reversed(ml): + pos = 0 + for j in t: + assert i != j + if i < j: + break + pos += 1 + negate = not negate + t.insert(pos, i) + + if negate: + cr = -cr + + d[tp] = d.get(tp, zero) + cl * cr + if d[tp] == zero: + del d[tp] + + return self.__class__(self._parent, d) + diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index 7e0dffe4419..ecb36fc8b18 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -39,7 +39,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.categories.fields import Fields from sage.categories.algebras_with_basis import AlgebrasWithBasis -from sage.algebras.clifford_algebra import CliffordAlgebraElement +from sage.algebras.clifford_algebra_element import CohomologyRAAGElement from sage.typeset.ascii_art import ascii_art from sage.typeset.unicode_art import unicode_art @@ -853,54 +853,8 @@ def degree_on_basis(self, I): """ return len(I) - class Element(CliffordAlgebraElement): + class Element(CohomologyRAAGElement): """ An element in the cohomology ring of a right-angled Artin group. """ - def _mul_(self, other): - """ - Return ``self`` multiplied by ``other``. - - EXAMPLES:: - - sage: C4 = graphs.CycleGraph(4) - sage: A = groups.misc.RightAngledArtin(C4) - sage: H = A.cohomology() - sage: b = sum(H.basis()) - sage: b * b - 2*e0*e2 + 2*e1*e3 + 2*e0 + 2*e1 + 2*e2 + 2*e3 + 1 - """ - zero = self.parent().base_ring().zero() - I = self.parent()._indices - d = {} - - for ml,cl in self: - for mr,cr in other: - # Create the next term - t = list(mr) - for i in reversed(ml): - pos = 0 - for j in t: - if i == j: - pos = None - break - if i < j: - break - pos += 1 - cr = -cr - if pos is None: - t = None - break - t.insert(pos, i) - - if t is None: # The next term is 0, move along - continue - - t = tuple(t) - if t not in I: # not an independent set, so this term is also 0 - continue - d[t] = d.get(t, zero) + cl * cr - if d[t] == zero: - del d[t] - return self.__class__(self.parent(), d) From 7f9cdb647a460aa7902f2a90097f40d9e249a429 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Mon, 8 Aug 2022 00:03:31 -0600 Subject: [PATCH 239/591] map bounds and ord to ZZ in discrete_log these parameters may be python ints for which the methods isqrt and factor are not available. --- src/sage/groups/generic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 856c4cbafe6..30985cd47de 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -869,7 +869,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i mult = op power = lambda x, y: multiple(x, y, operation=operation, identity=identity, inverse=inverse, op=op) if bounds: - lb, ub = bounds + lb, ub = map(integer_ring.ZZ, bounds) if (op is None or identity is None or inverse is None or ord is None) and operation not in addition_names+multiplication_names: raise ValueError("ord, op, identity, and inverse must all be specified for this operation") if ord is None: @@ -883,6 +883,8 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i ord = base.additive_order() except Exception: ord = base.order() + else: + ord = integer_ring.ZZ(ord) try: from sage.rings.infinity import Infinity if ord == +Infinity: From 4b24a772b7115c97ed4d8c1727347e90aec4587a Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 8 Aug 2022 18:19:28 +0800 Subject: [PATCH 240/591] =?UTF-8?q?implement=20=E2=88=9A=C3=A9lu=20algorit?= =?UTF-8?q?hm=20for=20isogenies=20of=20elliptic=20curves?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../en/reference/arithmetic_curves/index.rst | 3 +- src/doc/en/reference/references/index.rst | 9 + .../elliptic_curves/ell_curve_isogeny.py | 4 +- src/sage/schemes/elliptic_curves/ell_field.py | 5 + src/sage/schemes/elliptic_curves/hom.py | 4 +- .../schemes/elliptic_curves/hom_composite.py | 4 +- .../schemes/elliptic_curves/hom_velusqrt.py | 1087 +++++++++++++++++ .../elliptic_curves/weierstrass_morphism.py | 2 +- 8 files changed, 1111 insertions(+), 7 deletions(-) create mode 100644 src/sage/schemes/elliptic_curves/hom_velusqrt.py diff --git a/src/doc/en/reference/arithmetic_curves/index.rst b/src/doc/en/reference/arithmetic_curves/index.rst index 9fbc0495854..73f6f602490 100644 --- a/src/doc/en/reference/arithmetic_curves/index.rst +++ b/src/doc/en/reference/arithmetic_curves/index.rst @@ -20,8 +20,9 @@ Maps between them sage/schemes/elliptic_curves/hom sage/schemes/elliptic_curves/weierstrass_morphism sage/schemes/elliptic_curves/ell_curve_isogeny - sage/schemes/elliptic_curves/isogeny_small_degree + sage/schemes/elliptic_curves/hom_velusqrt sage/schemes/elliptic_curves/hom_composite + sage/schemes/elliptic_curves/isogeny_small_degree Elliptic curves over number fields diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index e8f8640e1ae..ea98b84530d 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -591,6 +591,11 @@ REFERENCES: for Computing p-Adic Polylogarithms." Mathematics of Computation (2008): 1105-1134. +.. [BDLS2020] Daniel J. Bernstein, Luca De Feo, Antonin Leroux, and Benjamin + Smith: Faster computation of isogenies of large prime degree. + ANTS XIV, Open Book Series Vol. 4, No. 1, 2020. + :arxiv:`2003.10118` + .. [BD1989] \R. J. Bradford and J. H. Davenport, *Effective tests for cyclotomic polynomials*, Symbolic and Algebraic Computation (1989), pp. 244--251, @@ -4944,6 +4949,10 @@ REFERENCES: linear codes, and cryptography. STOC, pp. 84--93, ACM, 2005. +.. [Ren2018] Joost Renes: Computing Isogenies Between Montgomery Curves + Using the Action of `(0,0)`. PQCrypto 2018, pp. 229--247. + https://eprint.iacr.org/2017/1198.pdf + .. [Reu1993] \C. Reutenauer. *Free Lie Algebras*. Number 7 in London Math. Soc. Monogr. (N.S.). Oxford University Press. (1993). diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index b46fe3c7bdc..c8225c78121 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -1058,8 +1058,9 @@ def _eval(self, P): if self._domain.defining_polynomial()(*P): raise ValueError(f"{P} not on {self._domain}") + k = Sequence(P).universe() + if not P: - k = Sequence(tuple(P)).universe() return self._codomain(0).change_ring(k) Q = P.xy() @@ -1082,7 +1083,6 @@ def _eval(self, P): if self.__post_isomorphism is not None: Q = baseWI.__call__(self.__post_isomorphism, Q) - k = Sequence(tuple(P) + tuple(Q)).universe() return self._codomain.base_extend(k).point(Q) def _call_(self, P): diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 4d6bfe1c815..73f3358ebe8 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1873,6 +1873,8 @@ def compute_model(E, name): sage: E = EllipticCurve([12/7, 405/49, 0, -81/8, 135/64]) sage: compute_model(E, 'minimal') Elliptic Curve defined by y^2 = x^3 - x^2 - 7*x + 10 over Rational Field + sage: compute_model(E, 'short_weierstrass') + Elliptic Curve defined by y^2 = x^3 - 48114*x + 4035015 over Rational Field sage: compute_model(E, 'montgomery') Elliptic Curve defined by y^2 = x^3 + 5*x^2 + x over Rational Field """ @@ -1885,6 +1887,9 @@ def compute_model(E, name): raise ValueError('can only compute minimal model for curves over number fields') return E.global_minimal_model(semi_global=True) + if name == 'short_weierstrass': + return E.short_weierstrass_model() + if name == 'montgomery': return E.montgomery_model() diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index de40a534220..82ebdb8cefd 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -10,6 +10,7 @@ - :class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny` - :class:`~sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism` - :class:`~sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite` +- :class:`~sage.schemes.elliptic_curves.hom_velusqrt.EllipticCurveHom_velusqrt` AUTHORS: @@ -25,8 +26,6 @@ from sage.categories.morphism import Morphism -import sage.schemes.elliptic_curves.weierstrass_morphism as wm - class EllipticCurveHom(Morphism): """ @@ -587,6 +586,7 @@ def __neg__(self): sage: psi.rational_maps() == (f, -g) True """ + import sage.schemes.elliptic_curves.weierstrass_morphism as wm a1,_,a3,_,_ = self.codomain().a_invariants() return wm.WeierstrassIsomorphism(self.codomain(), (-1,0,-a1,-a3)) * self diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index 8184e86a7dc..5a163ca4479 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -428,10 +428,12 @@ def _eval(self, P): """ if self._domain.defining_polynomial()(*P): raise ValueError(f'{P} not on {self._domain}') + k = Sequence(P).universe() + Q = P for phi in self._phis: Q = phi._eval(Q) - k = Sequence(tuple(P) + tuple(Q)).universe() + return self._codomain.base_extend(k)(*Q) def _repr_(self): diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py new file mode 100644 index 00000000000..2b8b3c5699c --- /dev/null +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -0,0 +1,1087 @@ +r""" +√élu Formulas for Elliptic-Curve Isogenies + +The √élu formulas compute isogenies of elliptic curves in time +`\tilde O(\sqrt\ell)` rather than naïvely `O(\ell)`, where `\ell` +is the degree. + +The core idea is to reindex the points in the kernel subgroup in +a baby-step-giant-step manner, then use fast resultant computations +to evaluate "elliptic polynomials" +(see :class:`FastEllipticPolynomial`) +in essentially square-root time. + +Based on experiments with Sage version 9.7, +the isogeny degree where +:class:`EllipticCurveHom_velusqrt` +begins to outperform +:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny` +can be as low as `\approx 100`, +but is typically closer to `\approx 1000`, +depending on the exact situation. + +REFERENCES: [BDLS2020]_ + +EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + ... + sage: E = EllipticCurve(GF(6666679), [5,5]) + sage: K = E(9970, 1003793, 1) + sage: K.order() + 10009 + sage: phi = EllipticCurveHom_velusqrt(E, K) + sage: phi + Elliptic-curve isogeny (using √élu) of degree 10009: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 6666679 + To: Elliptic Curve defined by y^2 = x^3 + 227975*x + 3596133 over Finite Field of size 6666679 + sage: phi.codomain() + Elliptic Curve defined by y^2 = x^3 + 227975*x + 3596133 over Finite Field of size 6666679 + +Note that the isogeny is usually not identical to the one computed by +:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`:: + + sage: psi = EllipticCurveIsogeny(E, K) + sage: psi + Isogeny of degree 10009 + from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 6666679 + to Elliptic Curve defined by y^2 = x^3 + 5344836*x + 3950273 over Finite Field of size 6666679 + +However, they are certainly separable isogenies with the same kernel +and must therefore be equal *up to post-isomorphism*:: + + sage: sum(iso * psi == phi for iso in isos) # TODO: comparison is not implemented yet + 1 + sage: Q = E.gens()[0] + sage: phiQ, psiQ = phi(Q), psi(Q) + sage: isos = psi.codomain().isomorphisms(phi.codomain()) + sage: sum(iso(psiQ) == phiQ for iso in isos) + 1 + +Just like +:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`, +the constructor supports a ``model`` keyword argument:: + + sage: E = EllipticCurve(GF(6666679), [1,1]) + sage: K = E(9091, 517864) + sage: phi = EllipticCurveHom_velusqrt(E, K, model='montgomery') + sage: phi + Elliptic-curve isogeny (using √élu) of degree 2999: + From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 6666679 + To: Elliptic Curve defined by y^2 = x^3 + 1559358*x^2 + x over Finite Field of size 6666679 + +Internally, :class:`EllipticCurveHom_velusqrt` works on short +Weierstraß curves, but it performs the conversion automatically:: + + sage: E = EllipticCurve(GF(101), [1,2,3,4,5]) + sage: K = E(1, 2) + sage: K.order() + 37 + sage: EllipticCurveHom_velusqrt(E, K) + Elliptic-curve isogeny (using √élu) of degree 37: + From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 66*x + 86 over Finite Field of size 101 + +However, this does imply not all elliptic curves are supported:: + + sage: F. = GF(3^3) + sage: E = EllipticCurve(F, [1,1,1,1,1]) + sage: P = E(t^2+2, 1) + sage: P.order() + 19 + sage: EllipticCurveHom_velusqrt(E, P) + Traceback (most recent call last): + ... + NotImplementedError: only implemented for curves having a short Weierstrass model + +Furthermore, the implementation is restricted to finite fields, +since this is the most relevant application:: + + sage: E = EllipticCurve('26b1') + sage: P = E(1,0) + sage: P.order() + 7 + sage: EllipticCurveHom_velusqrt(E, P) + Traceback (most recent call last): + ... + NotImplementedError: only implemented for elliptic curves over finite fields + +.. NOTE:: + + Currently :class:`EllipticCurveHom_velusqrt` does not implement + all methods of :class:`EllipticCurveHom`. This will hopefully + change in the future. + +.. WARNING:: + + This module is currently considered experimental. + It may change in a future release without prior warning. + +AUTHORS: + +- Lorenz Panny (2022) +""" + +# **************************************************************************** +# Copyright (C) 2022 Lorenz Panny +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.structure.sequence import Sequence +from sage.structure.all import coercion_model as cm + +from sage.misc.misc_c import prod + +from sage.schemes.elliptic_curves.constructor import EllipticCurve +from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_finite_field +from sage.schemes.elliptic_curves.hom import EllipticCurveHom + +from sage.misc.superseded import experimental_warning +experimental_warning(34303, 'This module is experimental.') + + +#TODO: This is general. It should be elsewhere. +class ProductTree: + r""" + A simple product tree. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import ProductTree + sage: R. = GF(101)[] + sage: vs = [x - i for i in range(1,10)] + sage: tree = ProductTree(vs) + sage: tree.value() + x^9 + 56*x^8 + 62*x^7 + 44*x^6 + 47*x^5 + 42*x^4 + 15*x^3 + 11*x^2 + 12*x + 13 + sage: tree.remainders(x^7 + x + 1) + [3, 30, 70, 27, 58, 72, 98, 98, 23] + sage: tree.remainders(x^100) + [1, 1, 1, 1, 1, 1, 1, 1, 1] + + :: + + sage: vs = prime_range(100) + sage: tree = ProductTree(vs) + sage: tree.value().factor() + 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 * 31 * 37 * 41 * 43 * 47 * 53 * 59 * 61 * 67 * 71 * 73 * 79 * 83 * 89 * 97 + sage: tree.remainders(3599) + [1, 2, 4, 1, 2, 11, 12, 8, 11, 3, 3, 10, 32, 30, 27, 48, 0, 0, 48, 49, 22, 44, 30, 39, 10] + + We can access the individual layers of the tree:: + + sage: tree.layers + [(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97), + (6, 35, 143, 323, 667, 1147, 1763, 2491, 3599, 4757, 5767, 7387, 97), + (210, 46189, 765049, 4391633, 17120443, 42600829, 97), + (9699690, 3359814435017, 729345064647247, 97), + (32589158477190044730, 70746471270782959), + (2305567963945518424753102147331756070,)] + + .. NOTE:: + + Use this class if you need the :meth:`remainders` method. + To compute just the product, :func:`prod` is likely faster. + """ + def __init__(self, leaves): + r""" + Initialize a product tree having the given ring elements + as its leaves. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import ProductTree + sage: vs = prime_range(100) + sage: tree = ProductTree(vs) + """ + V = tuple(leaves) + self.layers = [V] + while len(V) > 1: + V = tuple(prod(V[i:i+2]) for i in range(0,len(V),2)) + self.layers.append(V) + + def __len__(self): + r""" + Return the number of leaves of this product tree. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import ProductTree + sage: R. = GF(101)[] + sage: vs = [x - i for i in range(1,10)] + sage: tree = ProductTree(vs) + sage: len(tree) + 9 + sage: len(tree) == len(vs) + True + sage: len(tree.remainders(x^2)) + 9 + """ + return len(self.layers[0]) + + def value(self): + r""" + Return the value represented by this product tree + (i.e., the product of all leaves). + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import ProductTree + sage: R. = GF(101)[] + sage: vs = [x - i for i in range(1,10)] + sage: tree = ProductTree(vs) + sage: tree.value() + x^9 + 56*x^8 + 62*x^7 + 44*x^6 + 47*x^5 + 42*x^4 + 15*x^3 + 11*x^2 + 12*x + 13 + sage: tree.value() == prod(vs) + True + """ + assert len(self.layers[-1]) == 1 + return self.layers[-1][0] + + def remainders(self, x): + r""" + Given a value `x`, return a list of all remainders of `x` + modulo the leaves of this product tree. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import ProductTree + sage: vs = prime_range(100) + sage: tree = ProductTree(vs) + sage: n = 1085749272377676749812331719267 + sage: tree.remainders(n) + [1, 1, 2, 1, 9, 1, 7, 15, 8, 20, 15, 6, 27, 11, 2, 6, 0, 25, 49, 5, 51, 4, 19, 74, 13] + sage: [n % v for v in vs] + [1, 1, 2, 1, 9, 1, 7, 15, 8, 20, 15, 6, 27, 11, 2, 6, 0, 25, 49, 5, 51, 4, 19, 74, 13] + """ + X = [x] + for V in reversed(self.layers): + X = [X[i//2] % V[i] for i in range(len(V))] + return X + +#TODO: This is general. It should be elsewhere. +def prod_with_derivative(pairs): + r""" + Given a list of pairs `(f, \partial f)` of ring elements, return + the pair `(\prod f, \partial \prod f)`, assuming `\partial` is an + operator obeying the standard product rule. + + ALGORITHM: + + This function wraps the given pairs in a thin helper class that + automatically applies the product rule whenever multiplication + is invoked, then calls :func:`prod` on the wrapped pairs. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import prod_with_derivative + sage: R. = ZZ[] + sage: fs = [x^2 + 2*x + 3, 4*x + 5, 6*x^7 + 8*x + 9] + sage: prod(fs) + 24*x^10 + 78*x^9 + 132*x^8 + 90*x^7 + 32*x^4 + 140*x^3 + 293*x^2 + 318*x + 135 + sage: prod(fs).derivative() + 240*x^9 + 702*x^8 + 1056*x^7 + 630*x^6 + 128*x^3 + 420*x^2 + 586*x + 318 + sage: F, dF = prod_with_derivative((f, f.derivative()) for f in fs) + sage: F + 24*x^10 + 78*x^9 + 132*x^8 + 90*x^7 + 32*x^4 + 140*x^3 + 293*x^2 + 318*x + 135 + sage: dF + 240*x^9 + 702*x^8 + 1056*x^7 + 630*x^6 + 128*x^3 + 420*x^2 + 586*x + 318 + + The main reason for this function to exist is that it allows us to + compute the *value* of the derivative at a point `\alpha` without + ever fully expanding the product *as a polynomial*:: + + sage: alpha = 42 + sage: F(alpha) + 442943981574522759 + sage: dF(alpha) + 104645261461514994 + sage: us = [f(alpha) for f in fs] + sage: vs = [f.derivative()(alpha) for f in fs] + sage: prod_with_derivative(zip(us, vs)) + (442943981574522759, 104645261461514994) + """ + class _aux: + def __init__(self, f, df): + self.f, self.df = f, df + def __mul__(self, other): + return _aux(self.f * other.f, self.df * other.f + self.f * other.df) + def __iter__(self): + yield self.f + yield self.df + return tuple(prod(_aux(*tup) for tup in pairs)) + + +def _choose_IJK(n): + r""" + Helper function to choose an "index system" for the set + `\{1,3,5,7,...,n-2\}` where `n \geq 5` is an odd integer. + + REFERENCES: [BDLS2020]_, Examples 4.7 and 4.12 + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import _choose_IJK + sage: IJK = _choose_IJK(101); IJK + (range(10, 91, 20), range(1, 10, 2), range(101, 101, 2)) + sage: I,J,K = IJK + sage: sorted([i + s*j for i in iter(I) for j in iter(J) for s in (+1,-1)] + list(iter(K))) + [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, + 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99] + + TESTS:: + + sage: for n in range(5,1000,2): + ....: I,J,K = _choose_IJK(ZZ(n)) + ....: assert sorted([i + s*j for i in iter(I) for j in iter(J) for s in (+1,-1)] + list(iter(K))) == sorted(range(1,n,2)) + """ + if n % 2 != 1 or n < 5: + raise ValueError('n must be odd and >= 5') + b = int((n-1).sqrt() / 2) + b_ = (n-1) // (4*b) + I = range(2*b, 2*b*(2*b_-1)+1, 4*b) + J = range(1, 2*b, 2) + K = range(4*b*b_+1, n, 2) + return I, J, K + +def _points_range(rr, P, Q=None): + r""" + Return an iterator yielding all points `Q + [i]P` where `i` runs + through the :class:`range` object ``rr``. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import _points_range + sage: E = EllipticCurve(GF(1123), [4,5]) + sage: P = E(1, 75) + sage: 2*P + (1038 : 498 : 1) + sage: 5*P + (236 : 598 : 1) + sage: 8*P + (717 : 530 : 1) + sage: list(_points_range(range(2,10,3), P)) + [(1038 : 498 : 1), (236 : 598 : 1), (717 : 530 : 1)] + sage: Q = E(7, 202) + sage: Q + 2*P + (65 : 717 : 1) + sage: Q + 5*P + (1119 : 788 : 1) + sage: Q + 8*P + (949 : 315 : 1) + sage: list(_points_range(range(2,10,3), P, Q)) + [(65 : 717 : 1), (1119 : 788 : 1), (949 : 315 : 1)] + """ + if not rr: + return + a,b,s = rr.start, rr.stop, rr.step + R = a*P if Q is None else Q + a*P + yield R + sP = s*P + for _ in range(a+s, b, s): + yield (R := R + sP) + +class FastEllipticPolynomial: + r""" + A class to represent and evaluate an *elliptic polynomial*, + and optionally its derivative, in essentially square-root time. + + The elliptic polynomials computed by this class are of the form + + .. MATH:: + + h_S(Z) = \prod_{i\in S} (Z - x(Q + [i]P)) + + where `P` is a point of odd order `n \geq 5` and `Q` is either ``None``, + in which case it is assumed to be `\infty`, or an arbitrary point which is + not a multiple of `P`. + + The index set `S` is chosen as follows: + + - If `Q` is given, then `S = \{0,1,2,3,...,n-1\}`. + + - If `Q` is omitted, then `S = \{1,3,5,...,n-2\}`. Note that in this case, + `h_{\{1,2,3,...,n-1\}}` can be computed as `h_S^2` since `n` is odd. + + ALGORITHM: [BDLS2020]_, Algorithm 2 + + .. NOTE:: + + Currently only implemented for short Weierstraß curves. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial + sage: E = EllipticCurve(GF(71), [5,5]) + sage: P = E(4, 35) + sage: hP = FastEllipticPolynomial(E, P.order(), P); hP + Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1) + sage: hP(7) + 19 + sage: prod(7 - (i*P).xy()[0] for i in range(1,P.order(),2)) + 19 + + Passing `Q` changes the index set:: + + sage: Q = E(0, 17) + sage: hPQ = FastEllipticPolynomial(E, P.order(), P, Q) + sage: hPQ(7) + 58 + sage: prod(7 - (Q+i*P).xy()[0] for i in range(P.order())) + 58 + + The call syntax has an optional keyword argument ``derivative``, which + will make the function return the pair `(h_S(\alpha), h_S'(\alpha))` + instead of just `h_S(\alpha)`:: + + sage: hP(7, derivative=True) + (19, 15) + sage: R. = E.base_field()[] + sage: HP = prod(Z - (i*P).xy()[0] for i in range(1,P.order(),2)) + sage: HP + Z^9 + 16*Z^8 + 57*Z^7 + 6*Z^6 + 45*Z^5 + 31*Z^4 + 46*Z^3 + 10*Z^2 + 28*Z + 41 + sage: HP(7) + 19 + sage: HP.derivative()(7) + 15 + + :: + + sage: hPQ(7, derivative=True) + (58, 62) + sage: R. = E.base_field()[] + sage: HPQ = prod(Z - (Q+i*P).xy()[0] for i in range(P.order())) + sage: HPQ + Z^19 + 53*Z^18 + 67*Z^17 + 39*Z^16 + 56*Z^15 + 32*Z^14 + 44*Z^13 + 6*Z^12 + 27*Z^11 + 29*Z^10 + 38*Z^9 + 48*Z^8 + 38*Z^7 + 43*Z^6 + 21*Z^5 + 25*Z^4 + 33*Z^3 + 49*Z^2 + 60*Z + sage: HPQ(7) + 58 + sage: HPQ.derivative()(7) + 62 + + The input can be an element of any algebra over the base ring:: + + sage: R. = GF(71)[] + sage: S. = R.quotient(T^2) + sage: hP(7 + t) + 15*t + 19 + """ + def __init__(self, E, n, P, Q=None): + r""" + Initialize this elliptic polynomial and precompute some + input-independent data required for evaluation. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial + sage: E = EllipticCurve(GF(71), [5,5]) + sage: P = E(0, 17) + sage: FastEllipticPolynomial(E, P.order(), P) + Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with n = 57, P = (0 : 17 : 1) + """ + if any(E.a_invariants()[:-2]): + raise NotImplementedError('only implemented for short Weierstrass curves') + + if Q is None: + IJK = _choose_IJK(n) # [1,3,5,7,...,n-4,n-2] + else: + IJK = _choose_IJK(2*n+1) # [1,3,5,7,...,2n-1] = [0,1,2,3,...,n-2,n-1] + + self.base = E.base_ring() + R, Z = self.base['x'].objgen() + + # Cassels, Lectures on Elliptic Curves, p.132 + A,B = E.a_invariants()[-2:] + Fs = lambda X,Y: ( + (X - Y)**2, + -2 * (X*Y + A) * (X + Y) - 4*B, + (X*Y - A)**2 - 4*B*(X+Y), + ) + + I, J, K = IJK + xI = (R.xy()[0] for R in _points_range(I, P, Q)) + xJ = [R.xy()[0] for R in _points_range(J, P )] + xK = (R.xy()[0] for R in _points_range(K, P, Q)) + + self.hItree = ProductTree(Z - xi for xi in xI) + + self.EJparts = [Fs(Z,xj) for xj in xJ] + + DJ = prod(F0j for F0j,_,_ in self.EJparts) + self.DeltaIJ = self._hI_resultant(DJ) + + self.hK = R(prod(Z - xk for xk in xK)) + self.dhK = self.hK.derivative() + + if Q is None: + self._repr = f"Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with {n = }, {P = }" + else: + self._repr = f"Fast elliptic polynomial prod(Z - x(Q+i*P)) for i in range(n)) with {n = }, {P = }, {Q = }" + + def __call__(self, alpha, *, derivative=False): + r""" + Evaluate this elliptic polynomial at a point `\alpha`, + and if ``derivative`` is set to ``True`` also return + the evaluation of the derivative at `\alpha`. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial + sage: E = EllipticCurve(GF(71), [5,5]) + sage: P = E(4, 35) + sage: hP = FastEllipticPolynomial(E, P.order(), P); hP + Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1) + sage: hP(7) + 19 + sage: hP(7, derivative=True) + (19, 15) + """ + base = cm.common_parent(self.base, alpha) + + EJparts = [tuple(F.base_extend(base) for F in part) for part in self.EJparts] + + EJfacs = [(F0j * alpha + F1j) * alpha + F2j for F0j,F1j,F2j in EJparts] + if not derivative: + EJ = prod(EJfacs) + else: + dEJfacs = [2 * F0j * alpha + F1j for F0j,F1j,_ in EJparts] + EJ, dEJ = prod_with_derivative(zip(EJfacs, dEJfacs)) + + EJrems = self.hItree.remainders(EJ) + R = self._hI_resultant(EJ, EJrems) + hK = self.hK(alpha) + res = hK * R / self.DeltaIJ + + if not derivative: + return res + + dEJrems = self.hItree.remainders(dEJ) + cnt = EJrems.count(0) + if cnt == 0: + dR = sum(R // EJrem * dEJrem for EJrem, dEJrem in zip(EJrems, dEJrems)) + elif cnt == 1: + dR = prod(EJrem or dEJrem for EJrem, dEJrem in zip(EJrems, dEJrems)) + else: + dR = 0 + dhK = self.dhK(alpha) + dres = (dhK * R + hK * dR) / self.DeltaIJ + + return res, dres + + def _hI_resultant(self, poly, rems=None): + r""" + Internal helper function to evaluate a resultant with `h_I` quickly, + using the product tree constructed in :meth:`__init__`. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial + sage: E = EllipticCurve(GF(71), [5,5]) + sage: P = E(4, 35) + sage: hP = FastEllipticPolynomial(E, P.order(), P) + sage: f = GF(71)['x']([5,4,3,2,1]) + sage: hP._hI_resultant(f) + 66 + sage: prod(f(r) for fi in hP.hItree.layers[0] + ....: for r in fi.roots(multiplicities=False)) + 66 + + :: + + sage: Q = E(0, 17) + sage: hPQ = FastEllipticPolynomial(E, P.order(), P, Q) + sage: f = GF(71)['x']([9,8,7,6,5,4,3,2,1]) + sage: hPQ._hI_resultant(f) + 36 + sage: prod(f(r) for fi in hPQ.hItree.layers[0] + ....: for r in fi.roots(multiplicities=False)) + 36 + """ + if rems is None: + rems = self.hItree.remainders(poly) + r = prod(rems) + s = -1 if len(self.hItree)%2 == 1 == poly.degree() else 1 + assert r.is_constant() + return s * r[0] + + def __repr__(self): + r""" + Return a string representation of this elliptic polynomial. + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial + sage: E = EllipticCurve(GF(71), [5,5]) + sage: P = E(4, 35) + sage: FastEllipticPolynomial(E, P.order(), P) + Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1) + sage: Q = E(0, 17) + sage: FastEllipticPolynomial(E, P.order(), P, Q) + Fast elliptic polynomial prod(Z - x(Q+i*P)) for i in range(n)) with n = 19, P = (4 : 35 : 1), Q = (0 : 17 : 1) + """ + return self._repr + + +def _point_outside_subgroup(P): + r""" + Simple helper function to return a point on an elliptic + curve `E` that is not a multiple of a given point `P`. + The base field is extended if (and only if) necessary. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import _point_outside_subgroup + sage: E = EllipticCurve(GF(71), [5,5]) + sage: P = E(4, 35) + sage: Q = _point_outside_subgroup(P); Q # random + (14 : 11 : 1) + sage: Q.curve()(P).discrete_log(Q) + Traceback (most recent call last): + ... + ValueError: ECDLog problem has no solution (...) + + An example where `P` generates `E(\mathbb F_q)`:: + + sage: E.

= EllipticCurve(GF(71), [5,5]) + sage: P.order() == E.cardinality() + True + sage: Q = _point_outside_subgroup(P); Q # random + (35*z2 + 7 : 24*z2 + 7 : 1) + sage: Q.curve()(P).discrete_log(Q) + Traceback (most recent call last): + ... + ValueError: ECDLog problem has no solution (...) + + An example where the group is non-cyclic: + + sage: E. = EllipticCurve(GF(71^2), [0,1]) + sage: E.abelian_group() + Additive abelian group isomorphic to Z/72 + Z/72 embedded in Abelian group of points on Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 71^2 + sage: P = E.random_point() + sage: Q = _point_outside_subgroup(P); Q # random + (18*z2 + 46 : 58*z2 + 61 : 1) + sage: Q in E + True + sage: P.discrete_log(Q) + Traceback (most recent call last): + ... + ValueError: ECDLog problem has no solution (...) + + .. NOTE:: + + The field extension is only needed when `P` generates the + entire rational subgroup of `E`. But in that case, the + isogeny defined by `P` is simply `\pi-1` (where `\pi` is + Frobenius). Thus, once `\pi-1` can be represented in Sage, + we may just return that in + :meth:`~sage.schemes.elliptic_curves.ell_field.EllipticCurve_field.isogeny` + rather than insisting on using Îlu. + """ + E = P.curve() + n = P.order() + if n == E.order(): + d = 2 + (n == 7 and E.base_field().cardinality() == 3) + F = E.base_field().extension(d) + E = E.base_extend(F) + P = E(P) +# assert E.cardinality() > n + for _ in range(1000): + Q = E.random_point() + if n*Q or not P.weil_pairing(Q,n).is_one(): + return Q + else: + raise NotImplementedError('could not find a point outside the kernel') + +class EllipticCurveHom_velusqrt(EllipticCurveHom): + r""" + This class implements separable odd-degree isogenies of elliptic + curves over finite fields using the Îlu formulas. + + The complexity is `\tilde O(\sqrt{\ell})` base-field operations, + where `\ell` is the degree. + + REFERENCES: [BDLS2020]_ + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + sage: F. = GF(10009^3) + sage: E = EllipticCurve(F, [t,t]) + sage: K = E(2154*t^2 + 5711*t + 2899, 7340*t^2 + 4653*t + 6935) + sage: phi = EllipticCurveHom_velusqrt(E, K); phi + Elliptic-curve isogeny (using Îlu) of degree 601: + From: Elliptic Curve defined by y^2 = x^3 + t*x + t over Finite Field in t of size 10009^3 + To: Elliptic Curve defined by y^2 = x^3 + (263*t^2+3173*t+4759)*x + (3898*t^2+6111*t+9443) over Finite Field in t of size 10009^3 + sage: phi(K) + (0 : 1 : 0) + sage: P = E(2, 3163*t^2 + 7293*t + 5999) + sage: phi(P) + (6085*t^2 + 855*t + 8720 : 8078*t^2 + 9889*t + 6030 : 1) + sage: Q = E(6, 5575*t^2 + 6607*t + 9991) + sage: phi(Q) + (626*t^2 + 9749*t + 1291 : 5931*t^2 + 8549*t + 3111 : 1) + sage: phi(P + Q) + (983*t^2 + 4894*t + 4072 : 5047*t^2 + 9325*t + 336 : 1) + sage: phi(P) + phi(Q) + (983*t^2 + 4894*t + 4072 : 5047*t^2 + 9325*t + 336 : 1) + + TESTS: + + Check on a random example that the isogeny is a well-defined + group homomorphism with the correct kernel:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import _random_example_for_testing + sage: E, K = _random_example_for_testing() + sage: phi = EllipticCurveHom_velusqrt(E, K) + sage: not phi(K) + True + sage: not phi(randrange(2^99) * K) + True + sage: P = E.random_point() + sage: phi(P) in phi.codomain() + True + sage: Q = E.random_point() + sage: phi(Q) in phi.codomain() + True + sage: phi(P + Q) == phi(P) + phi(Q) + True + + Check that the isogeny preserves the field of definition:: + + sage: Sequence(K).universe() == phi.domain().base_field() + True + sage: phi.codomain().base_field() == phi.domain().base_field() + True + + Check that the isogeny affects the Weil pairing in the correct way:: + + sage: m = lcm(P.order(), Q.order()) + sage: e1 = P.weil_pairing(Q, m) + sage: e2 = phi(P).weil_pairing(phi(Q), m) + sage: e2 == e1^phi.degree() + True + + Check that the isogeny matches (up to isomorphism) the one from + :class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`:: + + sage: psi = EllipticCurveIsogeny(E, K) + sage: check = lambda iso: all(iso(psi(Q)) == phi(Q) for Q in E.gens()) + sage: any(map(check, psi.codomain().isomorphisms(phi.codomain()))) + True + + .. SEEALSO:: + + :class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny` + """ + def __init__(self, E, P, *, model=None, Q=None): + r""" + Initialize this Îlu isogeny from a kernel point of odd order. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + sage: E = EllipticCurve(GF(71), [5,5]) + sage: P = E(-2, 22) + sage: EllipticCurveHom_velusqrt(E, P) + Elliptic-curve isogeny (using Îlu) of degree 19: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 71 + To: Elliptic Curve defined by y^2 = x^3 + 13*x + 11 over Finite Field of size 71 + """ + if not isinstance(E, EllipticCurve_finite_field): + raise NotImplementedError('only implemented for elliptic curves over finite fields') + + try: + self._raw_domain = E.short_weierstrass_model() + except ValueError: + raise NotImplementedError('only implemented for curves having a short Weierstrass model') + self._pre_iso = E.isomorphism_to(self._raw_domain) + + try: + P = E(P) + except TypeError: + raise ValueError('given kernel point P does not lie on E') + self._P = self._pre_iso(P) + + self._degree = self._P.order() + if self._degree % 2 != 1 or self._degree < 5: + raise NotImplementedError('only implemented for odd degrees >= 5') + + if Q is not None: + self._Q = E(Q) + EE = E + else: + self._Q = _point_outside_subgroup(self._P) # may extend base field + EE = self._Q.curve() + self._P = EE(self._P) + + self._base_ring = EE.base_ring() + + self._h0 = FastEllipticPolynomial(EE, self._degree, self._P) + self._h1 = FastEllipticPolynomial(EE, self._degree, self._P, self._Q) + + self._domain = E + self._compute_codomain(model=model) + + super().__init__(self._domain, self._codomain) + + def _raw_eval(self, x, y=None): + r""" + Evaluate the "inner" Îlu isogeny (i.e., without applying + pre- and post-isomorphism) at either just an `x`-coordinate + or a pair `(x,y)` of coordinates. + + If the given point lies in the kernel, the empty tuple + ``()`` is returned. + + No checking of the input coordinates is performed. + + ALGORITHM: + + - [Ren2018]_, Theorem 1 + - :class:`FastEllipticPolynomial` + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + sage: E = EllipticCurve(GF(65537), [1,1]) + sage: P = E(2112, 803) + sage: phi = EllipticCurveHom_velusqrt(E, P, Q=(32924,0)) + sage: phi._raw_domain is E + True + sage: phi._raw_codomain + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 65537 + sage: Q = E(42, 15860) + sage: phi._raw_eval(Q.xy()[0]) + 11958 + sage: phi._raw_eval(*Q.xy()) + (11958, 42770) + sage: phi._raw_codomain.defining_polynomial()(*phi._raw_eval(*Q.xy()), 1) + 0 + + No checking is performed:: + + sage: E.defining_polynomial()(123, 456, 1) + 50907 + sage: phi._raw_eval(123, 456) + (3805, 29941) + """ + if y is None: + h0 = self._h0(x) + h1 = self._h1(x) + else: + h0, h0d = self._h0(x, derivative=True) + h1, h1d = self._h1(x, derivative=True) + +# assert h0 == prod(x - ( i*self._P).xy()[0] for i in range(1,self._P.order(),2)) +# assert h1 == prod(x - (self._Q+i*self._P).xy()[0] for i in range( self._P.order() )) + + if not h0: + return () + + xx = h1 / h0**2 + + if y is None: + return xx + +# assert h0d == sum(prod(x - ( i*self._P).xy()[0] for i in range(1,self._P.order(),2) if i!=j) for j in range(1,self._P.order(),2)) +# assert h1d == sum(prod(x - (self._Q+i*self._P).xy()[0] for i in range( self._P.order() ) if i!=j) for j in range( self._P.order() )) + + yy = y * (h1d - 2 * h1 / h0 * h0d) / h0**2 + + return xx, yy + + def _compute_codomain(self, model=None): + r""" + Helper method to compute the codomain of this Îlu isogeny + once the data for :meth:`_raw_eval` has been initialized. + Called by the constructor. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + sage: E = EllipticCurve(GF(71), [0,5,0,1,0]) + sage: P = E(4, 19) + sage: phi = EllipticCurveHom_velusqrt(E, P) + sage: phi._raw_codomain + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field of size 71 + sage: phi._codomain + Elliptic Curve defined by y^2 = x^3 + 8*x + 34 over Finite Field of size 71 + sage: phi.codomain() + Elliptic Curve defined by y^2 = x^3 + 8*x + 34 over Finite Field of size 71 + + Passing a ``model`` parameter is supported:: + + sage: phi._compute_codomain('montgomery') + sage: phi + Elliptic-curve isogeny (using Îlu) of degree 19: + From: Elliptic Curve defined by y^2 = x^3 + 5*x^2 + x over Finite Field of size 71 + To: Elliptic Curve defined by y^2 = x^3 + 40*x^2 + x over Finite Field of size 71 + """ + poly = self._raw_domain.two_division_polynomial().monic() + R, Z = poly.parent().objgen() + + f = 1 + for g,_ in poly.factor(): + if g.degree() == 1: + f *= Z - self._raw_eval(-g[0]) + else: + K, X0 = self._base_ring.extension(g,'T').objgen() + imX0 = self._raw_eval(X0) + try: + imX0 = imX0.polynomial()(Z) # K is a FiniteField + except AttributeError: + imX0 = imX0.lift() # K is a PolynomialQuotientRing + V = R['V'].gen() + f *= (Z - imX0(V)).resultant(g(V)) + + a6,a4,a2,_ = f.monic().list() + + self._raw_codomain = EllipticCurve(self._domain.base_ring(), [0,a2,0,a4,a6]) + + if model is None: + model = 'short_weierstrass' + + from sage.schemes.elliptic_curves.ell_field import compute_model + self._codomain = compute_model(self._raw_codomain, model) + self._post_iso = self._raw_codomain.isomorphism_to(self._codomain) + + def _eval(self, P): + r""" + Evaluate this Îlu isogeny at a point. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + sage: E = EllipticCurve(GF(71), [0,5,0,1,0]) + sage: K = E(4, 19) + sage: phi = EllipticCurveHom_velusqrt(E, K, model='montgomery') + sage: phi + Elliptic-curve isogeny (using Îlu) of degree 19: + From: Elliptic Curve defined by y^2 = x^3 + 5*x^2 + x over Finite Field of size 71 + To: Elliptic Curve defined by y^2 = x^3 + 40*x^2 + x over Finite Field of size 71 + sage: phi(K) + (0 : 1 : 0) + sage: phi(5*K) + (0 : 1 : 0) + sage: phi(E(0)) + (0 : 1 : 0) + sage: phi(E(0,0)) + (0 : 0 : 1) + sage: phi(E(7,13)) + (70 : 31 : 1) + + TESTS:: + + sage: P,Q = (E.random_point() for _ in 'PQ') + sage: assert phi(P) in phi.codomain() + sage: assert phi(Q) in phi.codomain() + sage: assert phi(P + Q) == phi(P) + phi(Q) + + Randomized testing:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + sage: from sage.schemes.elliptic_curves.hom_velusqrt import _random_example_for_testing + sage: E, K = _random_example_for_testing() + sage: phi = EllipticCurveHom_velusqrt(E, K) + sage: phi.degree() == K.order() + True + sage: P = E.random_point() + sage: phi(P) in phi.codomain() + True + sage: Q = E.random_point() + sage: phi(Q) in phi.codomain() + True + sage: phi(P + Q) == phi(P) + phi(Q) + True + """ + if self._domain.defining_polynomial()(*P): + raise ValueError(f'{P} not on {self._domain}') + + k = Sequence(P).universe() + + if not P: + return self._codomain(0).change_ring(k) + + P = self._pre_iso._eval(P) + + xy = self._raw_eval(*P.xy()) + + if xy == (): + return self._codomain(0).change_ring(k) + + return self._post_iso._eval(Sequence(xy, k) + [1]) + + _call_ = _eval + + def _repr_(self): + r""" + Return basic information about this Îlu isogeny as a string. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + sage: E.

= EllipticCurve(GF(71), [5,5]) + sage: phi = EllipticCurveHom_velusqrt(E, P) + sage: phi # indirect doctest + Elliptic-curve isogeny (using √élu) of degree 57: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 71 + To: Elliptic Curve defined by y^2 = x^3 + 19*x + 45 over Finite Field of size 71 + """ + return f'Elliptic-curve isogeny (using √élu) of degree {self._degree}:' \ + f'\n From: {self._domain}' \ + f'\n To: {self._codomain}' + + +def _random_example_for_testing(): + r""" + Function to generate somewhat random valid √élu inputs + for testing purposes. + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import _random_example_for_testing + sage: E, K = _random_example_for_testing() + sage: E # random + Elliptic Curve defined by y^2 + (t^3+6*t^2)*x*y + (t^3+3*t^2+2*t+2)*y = x^3 + (6*t^3+2*t^2+t)*x^2 + (3*t^3+2*t^2+6*t+1)*x + (t^3+2*t^2+2) over Finite Field in t of size 7^4 + sage: E.short_weierstrass_model() + Elliptic Curve defined by y^2 = x^3 + ...*x... over Finite Field ... + sage: K # random + (3*t^3 + 4*t^2 + 4*t + 3 : 6*t^3 + 5*t^2 + 5*t : 1) + sage: K.order() # random + 101 + sage: K in E + True + sage: K.order() % 2 + 1 + sage: 5 <= K.order() + True + """ + from sage.all import prime_range, choice, randrange, GF, gcd + p = choice(prime_range(3, 100)) + e = randrange(1,5) + F,t = GF((p,e),'t').objgen() + while True: + try: + E = EllipticCurve([F.random_element() for _ in range(5)]) + except ArithmeticError: + continue + try: + E.short_weierstrass_model() + except ValueError: + continue + A = E.abelian_group() + ds = max(A.invariants()).prime_to_m_part(2).divisors() + ds = [d for d in ds if 5 <= d < 1000] + if ds: + deg = choice(ds) + break + G = A.torsion_subgroup(deg) + while True: + v = [randrange(deg) for _ in range(G.ngens())] + if gcd([deg] + v) == 1: + break + K = G(v).element() + assert K.order() == deg + return E, K + diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index 13617317e4b..ca5931fbd62 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -604,9 +604,9 @@ def _eval(self, P): """ if self._domain.defining_polynomial()(*P): raise ValueError(f'{P} not on {self._domain}') + k = Sequence(P).universe() Q = baseWI.__call__(self, P) - k = Sequence(tuple(P) + tuple(Q)).universe() return self._codomain.base_extend(k).point(Q) def __call__(self, P): From 3af0dd2265aacfa26d77d3c0a645898ebd3905a7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Jul 2022 17:20:36 -0700 Subject: [PATCH 241/591] build/pkgs/ninja_build/type: Change to standard --- build/pkgs/ninja_build/type | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/ninja_build/type b/build/pkgs/ninja_build/type index 134d9bc32d5..a6a7b9cd726 100644 --- a/build/pkgs/ninja_build/type +++ b/build/pkgs/ninja_build/type @@ -1 +1 @@ -optional +standard From 18bbc58f7f6b826d6f9733ede2b470663ef33f94 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 27 Jul 2022 15:20:43 -0700 Subject: [PATCH 242/591] build/pkgs/ninja_build: Update to 1.11.0 --- build/pkgs/ninja_build/checksums.ini | 7 ++++--- build/pkgs/ninja_build/package-version.txt | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/build/pkgs/ninja_build/checksums.ini b/build/pkgs/ninja_build/checksums.ini index cd1733990c7..d3914da794a 100644 --- a/build/pkgs/ninja_build/checksums.ini +++ b/build/pkgs/ninja_build/checksums.ini @@ -1,4 +1,5 @@ tarball=ninja_build-VERSION.tar.gz -sha1=17219deb34dd816363e37470f77ff7231509143a -md5=5fdb04461cc7f5d02536b3bfc0300166 -cksum=28253504 +sha1=f8c9279bdd4efc63b1a6be3b8c5a5031699af9ac +md5=7d1a1a2f5cdc06795b3054df5c17d5ef +cksum=3142198237 +upstream_url=https://github.com/ninja-build/ninja/archive/refs/tags/vVERSION.tar.gz diff --git a/build/pkgs/ninja_build/package-version.txt b/build/pkgs/ninja_build/package-version.txt index 53adb84c822..1cac385c6cb 100644 --- a/build/pkgs/ninja_build/package-version.txt +++ b/build/pkgs/ninja_build/package-version.txt @@ -1 +1 @@ -1.8.2 +1.11.0 From 66af9c2fe49efe3302ac7ee49ae2f9d2492dc764 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 27 Jul 2022 15:24:16 -0700 Subject: [PATCH 243/591] build/pkgs/ninja_build/spkg-configure.m4: Set lower version bound to 1.8.2 --- build/pkgs/ninja_build/spkg-configure.m4 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/pkgs/ninja_build/spkg-configure.m4 b/build/pkgs/ninja_build/spkg-configure.m4 index d9661574a13..fb6c4f00985 100644 --- a/build/pkgs/ninja_build/spkg-configure.m4 +++ b/build/pkgs/ninja_build/spkg-configure.m4 @@ -1,11 +1,12 @@ SAGE_SPKG_CONFIGURE( [ninja_build], [ - AC_CACHE_CHECK([for ninja >= 1.7.2], [ac_cv_path_NINJA], [ + dnl meson_python needs 1.8.2 or later + AC_CACHE_CHECK([for ninja >= 1.8.2], [ac_cv_path_NINJA], [ AC_PATH_PROGS_FEATURE_CHECK([NINJA], [ninja], [ ninja_version=`$ac_path_NINJA --version 2>&1 \ | $SED -n -e 's/\([[0-9]]*\.[[0-9]]*\.[[0-9]]*\).*/\1/p'` AS_IF([test -n "$ninja_version"], [ - AX_COMPARE_VERSION([$ninja_version], [ge], [1.7.2], [ + AX_COMPARE_VERSION([$ninja_version], [ge], [1.8.2], [ ac_cv_path_NINJA="$ac_path_NINJA" ac_path_NINJA_found=: ]) From 0a8bdc9664242614778324f7b6ce6bbeb2b73654 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 25 Jul 2022 15:14:19 -0700 Subject: [PATCH 244/591] build/pkgs/polymake: Upgrade to 4.7 --- build/pkgs/polymake/checksums.ini | 6 +++--- build/pkgs/polymake/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/polymake/checksums.ini b/build/pkgs/polymake/checksums.ini index 4c893d90f1c..2727d96238b 100644 --- a/build/pkgs/polymake/checksums.ini +++ b/build/pkgs/polymake/checksums.ini @@ -1,5 +1,5 @@ tarball=polymake-VERSION-minimal.tar.bz2 -sha1=fe54e1e099e7e87a12d771c7ea5dd011d12ec8f8 -md5=732deb4a3cb83363448c59ec72b0e2cf -cksum=1021474111 +sha1=a3903ef9438388e56a76cb04918c1fe9b2e2b563 +md5=9a451d56cfe8c6138b91558d6d369dbe +cksum=1195315956 upstream_url=https://polymake.org/lib/exe/fetch.php/download/polymake-VERSION-minimal.tar.bz2 diff --git a/build/pkgs/polymake/package-version.txt b/build/pkgs/polymake/package-version.txt index b3d791d7525..4f8c639658e 100644 --- a/build/pkgs/polymake/package-version.txt +++ b/build/pkgs/polymake/package-version.txt @@ -1 +1 @@ -4.6 +4.7 From 2302af6f35af2260bc72244d646dea2a3627dd08 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 8 Aug 2022 16:57:43 +0200 Subject: [PATCH 245/591] trac #34211: indicate optional doctests --- src/sage/graphs/isgci.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index 62057603404..2ea1adce781 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -793,7 +793,7 @@ def _download_db(self): EXAMPLES:: - sage: graph_classes._download_db() # Not tested -- requires internet + sage: graph_classes._download_db() # optional - internet """ import tempfile u = urlopen('https://www.graphclasses.org/data.zip', @@ -868,7 +868,7 @@ def update_db(self): EXAMPLES:: - sage: graph_classes.update_db() # Not tested -- requires internet + sage: graph_classes.update_db() # optional - internet """ self._download_db() @@ -1002,7 +1002,7 @@ def _XML_to_dict(root): EXAMPLES:: - sage: graph_classes.Perfect.description() # indirect doctest + sage: graph_classes.Perfect.description() # indirect doctest Class of graphs : Perfect ------------------------- id : gc_56 From fe6f742de077ff0b4173e8310250e5e394fb6b18 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 8 Aug 2022 17:30:39 +0200 Subject: [PATCH 246/591] trac #34306: better use of graphs in src/sage/geometry/hyperplane_arrangement/library.py --- .../hyperplane_arrangement/library.py | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index 0c5f67b546e..cfa2fbeb083 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -152,9 +152,10 @@ def bigraphical(self, G, A=None, K=QQ, names=None): H = make_parent(K, n, names) x = H.gens() hyperplanes = [] - for e in G.edges(sort=True): - i = G.vertices(sort=True).index(e[0]) - j = G.vertices(sort=True).index(e[1]) + vertex_to_int = {u: i for i, u in enumerate(G)} + for u, v in G.edge_iterator(labels=False, sort_vertices=False): + i = vertex_to_int[u] + j = vertex_to_int[v] hyperplanes.append( x[i] - x[j] - A[i][j]) hyperplanes.append(-x[i] + x[j] - A[j][i]) return H(*hyperplanes) @@ -264,9 +265,10 @@ def G_semiorder(self, G, K=QQ, names=None): H = make_parent(K, n, names) x = H.gens() hyperplanes = [] - for e in G.edges(sort=True): - i = G.vertices(sort=True).index(e[0]) - j = G.vertices(sort=True).index(e[1]) + vertex_to_int = {u: i for i, u in enumerate(G.vertices(sort=True))} + for u, v in G.edge_iterator(labels=False): + i = vertex_to_int[u] + j = vertex_to_int[v] hyperplanes.append(x[i] - x[j] - 1) hyperplanes.append(x[i] - x[j] + 1) return H(*hyperplanes) @@ -303,9 +305,10 @@ def G_Shi(self, G, K=QQ, names=None): H = make_parent(K, n, names) x = H.gens() hyperplanes = [] - for e in G.edges(sort=True): - i = G.vertices(sort=True).index(e[0]) - j = G.vertices(sort=True).index(e[1]) + vertex_to_int = {u: i for i, u in enumerate(G.vertices(sort=True))} + for u, v in G.edge_iterator(labels=False): + i = vertex_to_int[u] + j = vertex_to_int[v] hyperplanes.append(x[i] - x[j]) hyperplanes.append(x[i] - x[j] - 1) return H(*hyperplanes) @@ -351,9 +354,10 @@ def graphical(self, G, K=QQ, names=None): H = make_parent(K, n, names) x = H.gens() hyperplanes = [] - for e in G.edges(sort=True): - i = G.vertices(sort=True).index(e[0]) - j = G.vertices(sort=True).index(e[1]) + vertex_to_int = {u: i for i, u in enumerate(G.vertices(sort=True))} + for u, v in G.edge_iterator(labels=False): + i = vertex_to_int[u] + j = vertex_to_int[v] hyperplanes.append(x[i] - x[j]) A = H(*hyperplanes) charpoly = G.chromatic_polynomial() From bde3fe0d0fabe6d90dc24907aff2a4bd69585adc Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 8 Aug 2022 17:43:20 +0200 Subject: [PATCH 247/591] trac #34306: small improvement in src/sage/geometry/fan.py --- src/sage/geometry/fan.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index af3935741b8..c0e0644be4c 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -646,7 +646,8 @@ def result(): rays = new_rays else: rays = tuple(sorted(ray_set)) - cones = (tuple(sorted(rays.index(ray) for ray in cone.rays())) + ray_to_index = {ray: i for i, ray in enumerate(rays)} + cones = (tuple(sorted(ray_to_index[ray] for ray in cone.rays())) for cone in cones) return result() # Construct the fan from rays and "tuple cones" @@ -1925,7 +1926,8 @@ def _subdivide_stellar(self, new_rays, verbose): new_fan_rays = list(self.rays()) new_fan_rays.extend(ray for ray in new_rays if ray not in self.rays().set()) - cones = tuple(tuple(sorted(new_fan_rays.index(ray) for ray in cone)) + ray_to_index = {ray: i for i, ray in enumerate(new_fan_rays)} + cones = tuple(tuple(sorted(ray_to_index[ray] for ray in cone)) for cone in cones) fan = Fan(cones, new_fan_rays, check=False, normalize=False) return fan From e351e422d8c76a801f9facd5786e4a55fa3cb324 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 8 Aug 2022 17:53:07 +0200 Subject: [PATCH 248/591] trac #34306: small improvement in src/sage/geometry/latice_polytope.py --- src/sage/geometry/lattice_polytope.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index c7c53a65045..48758580ec6 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -1566,7 +1566,8 @@ def ambient_point_indices(self): if self._ambient is self: return tuple(range(self.npoints())) points = self._ambient.points() - return tuple(points.index(p) for p in self.points()) + point_to_index = {p: i for i, p in enumerate(points)} + return tuple(point_to_index[p] for p in self.points()) @cached_method def ambient_ordered_point_indices(self): @@ -1600,7 +1601,8 @@ def ambient_ordered_point_indices(self): if self._ambient is self: return tuple(range(self.npoints())) points = self._ambient.points() - return tuple(points.index(p) for p in sorted(self.points())) + point_to_index = {p: i for i, p in enumerate(points)} + return tuple(point_to_index[p] for p in sorted(self.points())) def ambient_vertex_indices(self): r""" @@ -3614,8 +3616,9 @@ def plot3d(self, elif dim == 3: if facet_colors is None: facet_colors = [facet_color] * self.nfacets() + vertex_to_index = {v: i for i, v in enumerate(self.vertices())} for f, c in zip(self.facets(), facet_colors): - pplot += IndexFaceSet([[self.vertices().index(v) for v in f.vertices(f.traverse_boundary())]], + pplot += IndexFaceSet([[vertex_to_index[v] for v in f.vertices(f.traverse_boundary())]], vertices, opacity=facet_opacity, rgbcolor=c) if show_edges: if dim == 1: @@ -4081,7 +4084,8 @@ def traverse_boundary(self): if next == l[-2]: next = prev l.append(next) - return [self.vertices().index(v.vertex(0)) for v in l] + vertex_to_index = {v: i for i, v in enumerate(self.vertices())} + return [vertex_to_index[v.vertex(0)] for v in l] def vertex(self, i): r""" From da3bc668ff45372804e4af885757abb6c3584577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 8 Aug 2022 17:24:49 +0200 Subject: [PATCH 249/591] refactor abelian subgroup with libgap --- src/sage/groups/abelian_gps/abelian_group.py | 66 ++++++-------------- 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index cc94e2b568e..8a6afa76bbb 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -1170,7 +1170,7 @@ def random_element(self): result = self.one() for g in self.gens(): order = g.order() - if order not in ZZ: + if order is infinity: order = 42 # infinite order; randomly chosen maximum result *= g**(randint(0,order)) return result @@ -1683,56 +1683,26 @@ def __init__(self, ambient, gens, names="f", category=None): sage: G.subgroup([prod(g^k for g,k in zip(G.gens(),[1,-2,3,-4,5]))]) Multiplicative Abelian subgroup isomorphic to Z generated by {f0*f1^-2*f2^3*f3^-4*f4} """ - from sage.interfaces.gap import gap + from sage.libs.gap.libgap import libgap if not isinstance(ambient, AbelianGroup_class): - raise TypeError("ambient (=%s) must be an abelian group."%ambient) + raise TypeError("ambient (=%s) must be an abelian group" % ambient) if not isinstance(gens, tuple): - raise TypeError("gens (=%s) must be a tuple"%gens) + raise TypeError("gens (=%s) must be a tuple" % gens) self._ambient_group = ambient - Hgens = tuple(x for x in gens if x != ambient.one()) ## in case someone puts 1 in the list of generators - self._gens = Hgens - ambient_invs = ambient.gens_orders() - invsf = [x for x in ambient_invs if x > 0] ## fixes the problem with - invs0 = [x for x in ambient_invs if x == 0] ## the infinite parts - Ggens = list(ambient.variable_names()) - if invs0!=[]: - Gfgens = [x for x in ambient.variable_names() if - ambient_invs[Ggens.index(x)] != 0] - Gf = AbelianGroup(invsf, names=Gfgens) - s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%Gf._gap_init_() - gap.eval(s1) - Hgens0 = [ - x for x in Hgens if - any(e!=0 and (g.order() not in ZZ) for e,g in zip(x.exponents(),ambient.gens())) - ] - Hgensf = [x for x in Hgens if x not in Hgens0] - # the "infinite" generators of H - for i in range(len(Gfgens)): - cmd = ("%s := gens["+str(i+1)+"]")%Gfgens[i] - gap.eval(cmd) - else: # invs0==[]: - Hgensf = Hgens - Hgens0 = [] # added for consistency - G = ambient - s1 = "G:= %s; gens := GeneratorsOfGroup(G)"%G._gap_init_() - gap.eval(s1) - for i in range(len(Ggens)): - cmd = '%s := gens[%s]'%(Ggens[i], i+1) - gap.eval(cmd) - s2 = "gensH:=%s"%list(Hgensf) #### remove from this the ones <--> 0 invar - gap.eval(s2) - s3 = 'H:=Subgroup(G,gensH)' - gap.eval(s3) - # a GAP command which returns the "invariants" of the - # subgroup as an AbelianPcpGroup, RelativeOrdersOfPcp(Pcp(G)), - # works if G is the subgroup declared as a AbelianPcpGroup - self._abinvs = eval(gap.eval("AbelianInvariants(H)")) - invs = self._abinvs - if Hgens0 != []: - for x in Hgens0: - invs.append(0) + H_gens = tuple(x for x in gens if x != ambient.one()) # clean entry + self._gens = H_gens + + H = libgap(ambient).Subgroup(H_gens) + + invs = H.TorsionSubgroup().AbelianInvariants().sage() + rank = len([1 for g in H.GeneratorsOfGroup() + if g.Order().sage() is infinity]) + invs += [0] * rank + + self._abinvs = invs invs = tuple(ZZ(i) for i in invs) + if category is None: category = Groups().Commutative().Subobjects() AbelianGroup_class.__init__(self, invs, names, category=category) @@ -1778,7 +1748,7 @@ def __contains__(self, x): return False if x.parent() is self: return True - elif x in self.ambient_group(): + if x in self.ambient_group(): amb_inv = self.ambient_group().gens_orders() inv_basis = diagonal_matrix(ZZ, amb_inv) gens_basis = matrix( @@ -1870,7 +1840,7 @@ def _repr_(self): sage: A._repr_() 'Multiplicative Abelian subgroup isomorphic to Z generated by {a}' """ - eldv = self.gens_orders() + eldv = self._abinvs if self.is_trivial(): return "Trivial Abelian subgroup" s = 'Multiplicative Abelian subgroup isomorphic to ' From b19f265553f835d7aa73824219bdf3de454f1312 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 8 Aug 2022 18:02:51 +0200 Subject: [PATCH 250/591] trac #34306: small improvements in src/sage/geometry/polyhedron/ --- src/sage/geometry/polyhedron/plot.py | 3 ++- src/sage/geometry/polyhedron/ppl_lattice_polytope.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index df157066c43..2c959b61195 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -1816,9 +1816,10 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, # Draw the facets in the front by going in cycles for every facet. tikz_pic += '%%\n%%\n%% Drawing the facets\n%%\n' + vertex_to_index = {v: i for i, v in enumerate(vertices)} for index_facet in front_facets: cyclic_vert = cyclic_sort_vertices_2d(list(facets[index_facet].incident())) - cyclic_indices = [vertices.index(v) for v in cyclic_vert] + cyclic_indices = [vertex_to_index[v] for v in cyclic_vert] tikz_pic += '\\fill[facet] ' for v in cyclic_indices: if v in dict_drawing: diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py index 5698d71a045..d45f8a3991a 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py @@ -671,7 +671,8 @@ def pointsets_mod_automorphism(self, pointsets): points = tuple(sorted(points)) Aut = self.lattice_automorphism_group(points, point_labels=tuple(range(len(points)))) - indexsets = set(frozenset(points.index(p) for p in ps) + point_to_index = {p: i for i, p in enumerate(points)} + indexsets = set(frozenset(point_to_index[p] for p in ps) for ps in pointsets) orbits = [] while indexsets: From 8708ba96a8b5879dbd912c7f1d2ae5d5b8ca9a5c Mon Sep 17 00:00:00 2001 From: dcoudert Date: Mon, 8 Aug 2022 20:09:33 +0200 Subject: [PATCH 251/591] trac #34309: pycodestyle cleanup in graphs/generators/families.py --- src/sage/graphs/generators/families.py | 407 +++++++++++++------------ 1 file changed, 215 insertions(+), 192 deletions(-) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index f4a59dea38e..9837fe3a5fa 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -37,13 +37,13 @@ def JohnsonGraph(n, k): EXAMPLES: - The Johnson graph is a Hamiltonian graph. :: + The Johnson graph is a Hamiltonian graph:: sage: g = graphs.JohnsonGraph(7, 3) sage: g.is_hamiltonian() True - Every Johnson graph is vertex transitive. :: + Every Johnson graph is vertex transitive:: sage: g = graphs.JohnsonGraph(6, 4) sage: g.is_vertex_transitive() @@ -51,7 +51,7 @@ def JohnsonGraph(n, k): The complement of the Johnson graph `J(n,2)` is isomorphic to the Kneser Graph `K(n,2)`. In particular the complement of `J(5,2)` is isomorphic to - the Petersen graph. :: + the Petersen graph.:: sage: g = graphs.JohnsonGraph(5,2) sage: g.complement().is_isomorphic(graphs.PetersenGraph()) @@ -70,12 +70,12 @@ def JohnsonGraph(n, k): for j in elem_left: if j <= i: continue - g.add_edge(sub+Set([i]),sub+Set([j])) + g.add_edge(sub + Set([i]), sub + Set([j])) return g -def KneserGraph(n,k): +def KneserGraph(n, k): r""" Returns the Kneser Graph with parameters `n, k`. @@ -109,22 +109,22 @@ def KneserGraph(n,k): ValueError: Parameter k should be a strictly positive integer inferior to n """ - if not n>0: + if n <= 0: raise ValueError("Parameter n should be a strictly positive integer") - if not (k>0 and k<=n): + if k <= 0 or k > n: raise ValueError("Parameter k should be a strictly positive integer inferior to n") - g = Graph(name="Kneser graph with parameters {},{}".format(n,k)) + g = Graph(name="Kneser graph with parameters {},{}".format(n, k)) from sage.combinat.subset import Subsets - S = Subsets(n,k) + S = Subsets(n, k) if 2 * k > n: g.add_vertices(S) s0 = S.underlying_set() # {1,2,...,n} for s in S: for t in Subsets(s0.difference(s), k): - g.add_edge(s,t) + g.add_edge(s, t) return g @@ -212,18 +212,18 @@ def FurerGadget(k, prefix=None): V_b = list(zip(rep(prefix, k), V_b)) G.add_vertices(V_a) G.add_vertices(V_b) - powerset = list(chain.from_iterable(combinations(range(k), r) for r in range(0,k+1,2))) + powerset = list(chain.from_iterable(combinations(range(k), r) for r in range(0, k + 1, 2))) if prefix is not None: - G.add_edges(chain.from_iterable([((prefix,s),(prefix,(i,'a'))) for i in s] for s in powerset)) - G.add_edges(chain.from_iterable([((prefix,s),(prefix,(i,'b'))) for i in range(k) if i not in s] for s in powerset)) + G.add_edges(chain.from_iterable([((prefix, s), (prefix, (i, 'a'))) for i in s] for s in powerset)) + G.add_edges(chain.from_iterable([((prefix, s), (prefix, (i, 'b'))) for i in range(k) if i not in s] for s in powerset)) else: - G.add_edges(chain.from_iterable([(s,(i,'a')) for i in s] for s in powerset)) - G.add_edges(chain.from_iterable([(s,(i,'b')) for i in range(k) if i not in s] for s in powerset)) + G.add_edges(chain.from_iterable([(s, (i, 'a')) for i in s] for s in powerset)) + G.add_edges(chain.from_iterable([(s, (i, 'b')) for i in range(k) if i not in s] for s in powerset)) partition = [] for i in range(k): partition.append([V_a[i], V_b[i]]) if prefix is not None: - powerset = [(prefix,s) for s in powerset] + powerset = [(prefix, s) for s in powerset] partition.append(powerset) return G, partition @@ -317,9 +317,9 @@ def CaiFurerImmermanGraph(G, twisted=False): for v in G: Fk, p = FurerGadget(G.degree(v), v) total_partition += p - newG=newG.union(Fk) + newG = newG.union(Fk) edge_index[v] = 0 - for v,u in G.edge_iterator(labels=False): + for v, u in G.edge_iterator(labels=False): i = edge_index[v] edge_index[v] += 1 j = edge_index[u] @@ -394,22 +394,22 @@ def EgawaGraph(p, s): g = Graph(name="Egawa Graph with parameters " + str(p) + "," + str(s), multiedges=False) X = CompleteGraph(4) Y = Graph('O?Wse@UgqqT_LUebWkbT_') - g.add_vertices(product(*chain(repeat(Y, p), repeat(X,s)))) + g.add_vertices(product(*chain(repeat(Y, p), repeat(X, s)))) for v in g: for i in range(p): prefix = v[:i] suffix = v[i+1:] for el in Y.neighbor_iterator(v[i]): u = prefix + (el,) + suffix - g.add_edge(v,u) - for i in range(p, s+p): + g.add_edge(v, u) + for i in range(p, s + p): prefix = v[:i] suffix = v[i+1:] for el in X: if el == v[i]: continue u = prefix + (el,) + suffix - g.add_edge(v,u) + g.add_edge(v, u) return g @@ -491,9 +491,10 @@ def HammingGraph(n, q, X=None): if el == v[i]: continue u = prefix + (el,) + suffix - g.add_edge(v,u) + g.add_edge(v, u) return g + def BalancedTree(r, h): r""" Returns the perfectly balanced tree of height `h \geq 1`, @@ -680,7 +681,7 @@ def BarbellGraph(n1, n2): G = Graph(name="Barbell graph") G.add_clique(list(range(n1))) - G.add_path(list(range(n1 - 1 , n1 + n2 + 1))) + G.add_path(list(range(n1 - 1, n1 + n2 + 1))) G.add_clique(list(range(n1 + n2, n1 + n2 + n1))) G._circle_embedding(list(range(n1)), shift=1, angle=pi/4) @@ -755,7 +756,7 @@ def LollipopGraph(n1, n2): if n1 * n2 > 0: G.add_edge(n1 - 1, n1) if n1 == 1: - G.set_pos({0:(0, 0)}) + G.set_pos({0: (0, 0)}) else: G._circle_embedding(list(range(n1)), shift=1, angle=pi/4) G._line_embedding(list(range(n1, n1 + n2)), first=(2, 2), last=(n2 + 1, n2 + 1)) @@ -860,7 +861,6 @@ def AztecDiamondGraph(n): return H - def DipoleGraph(n): r""" Returns a dipole graph with n edges. @@ -900,7 +900,7 @@ def DipoleGraph(n): if n < 0: raise ValueError("invalid graph description, n should be >= 0") - return Graph([[0,1], [(0,1)]*n], name="Dipole graph", multiedges=True) + return Graph([[0, 1], [(0, 1)]*n], name="Dipole graph", multiedges=True) def BubbleSortGraph(n): @@ -976,26 +976,27 @@ def BubbleSortGraph(n): from sage.graphs.generators.basic import CompleteGraph return Graph(CompleteGraph(n), name="Bubble sort") from sage.combinat.permutation import Permutations - #create set from which to permute + # create set from which to permute label_set = [str(i) for i in range(1, n + 1)] d = {} - #iterate through all vertices + # iterate through all vertices for v in Permutations(label_set): - v = list(v) # So we can easily mutate it + v = list(v) # So we can easily mutate it tmp_dict = {} - #add all adjacencies + # add all adjacencies for i in range(n - 1): - #swap entries + # swap entries v[i], v[i + 1] = v[i + 1], v[i] - #add new vertex + # add new vertex new_vert = ''.join(v) tmp_dict[new_vert] = None - #swap back + # swap back v[i], v[i + 1] = v[i + 1], v[i] - #add adjacency dict + # add adjacency dict d[''.join(v)] = tmp_dict return Graph(d, name="Bubble sort") + def chang_graphs(): r""" Return the three Chang graphs. @@ -1040,7 +1041,8 @@ def chang_graphs(): loops=False, multiedges=False) g3 = Graph(r"[~~vVMWdKFpV`^UGIaIERQ`\DBxpA@g`CbGRI`AxICNaFM[?fM\?Ytj@CxrGGlYt", loops=False, multiedges=False) - return [g1,g2,g3] + return [g1, g2, g3] + def CirculantGraph(n, adjacency): r""" @@ -1139,14 +1141,15 @@ def CirculantGraph(n, adjacency): if not isinstance(adjacency, list): adjacency = [adjacency] - G = Graph(n, name="Circulant graph ("+str(adjacency)+")") + G = Graph(n, name="Circulant graph (" + str(adjacency) + ")") G._circle_embedding(list(range(n))) for v in G: - G.add_edges([(v,(v+j)%n) for j in adjacency]) + G.add_edges([(v, (v + j) % n) for j in adjacency]) return G + def CubeGraph(n, embedding=1): r""" Return the `n`-cube graph, also called the hypercube in `n` dimensions. @@ -1232,14 +1235,14 @@ def CubeGraph(n, embedding=1): l1.append(m + '1') dn[v0] = l0 dn[v1] = l1 - x,y = p[v] + x, y = p[v] pn[v0] = (x, y) pn[v1] = (x + ci, y + si) d, dn = dn, {} p, pn = pn, {} # construct the graph - G = Graph(d, format='dict_of_lists', pos=p, name="%d-Cube"%n) + G = Graph(d, format='dict_of_lists', pos=p, name="%d-Cube" % n) else: # construct recursively the adjacency dict @@ -1260,7 +1263,7 @@ def CubeGraph(n, embedding=1): d, dn = dn, {} # construct the graph - G = Graph(d, name="%d-Cube"%n, format='dict_of_lists') + G = Graph(d, name="%d-Cube" % n, format='dict_of_lists') if embedding == 2: # Orthogonal projection @@ -1276,7 +1279,8 @@ def CubeGraph(n, embedding=1): return G -def GoethalsSeidelGraph(k,r): + +def GoethalsSeidelGraph(k, r): r""" Returns the graph `\text{Goethals-Seidel}(k,r)`. @@ -1306,23 +1310,22 @@ def GoethalsSeidelGraph(k,r): Graph on 28 vertices sage: graphs.GoethalsSeidelGraph(3,3).is_strongly_regular(parameters=True) (28, 15, 6, 10) - """ from sage.combinat.designs.bibd import balanced_incomplete_block_design from sage.combinat.matrices.hadamard_matrix import hadamard_matrix from sage.matrix.constructor import Matrix from sage.matrix.constructor import block_matrix - v = (k-1)*r+1 - n = v*(r+1) + v = (k-1)*r + 1 + n = v*(r + 1) # N is the (v times b) incidence matrix of a bibd - N = balanced_incomplete_block_design(v,k).incidence_matrix() + N = balanced_incomplete_block_design(v, k).incidence_matrix() # L is a (r+1 times r) matrix, where r is the row sum of N - L = hadamard_matrix(r+1).submatrix(0,1) + L = hadamard_matrix(r + 1).submatrix(0, 1) L = [Matrix(C).transpose() for C in L.columns()] - zero = Matrix(r+1,1,[0]*(r+1)) + zero = Matrix(r + 1, 1, [0]*(r + 1)) # For every row of N, we replace the 0s with a column of zeros, and we # replace the ith 1 with the ith column of L. The result is P. @@ -1337,11 +1340,12 @@ def GoethalsSeidelGraph(k,r): # The final graph PP = P*P.transpose() for i in range(n): - PP[i,i] = 0 + PP[i, i] = 0 G = Graph(PP, format="seidel_adjacency_matrix") return G + def DorogovtsevGoltsevMendesGraph(n): """ Construct the n-th generation of the Dorogovtsev-Goltsev-Mendes @@ -1360,8 +1364,9 @@ def DorogovtsevGoltsevMendesGraph(n): (2002). """ import networkx - return Graph(networkx.dorogovtsev_goltsev_mendes_graph(n),\ - name="Dorogovtsev-Goltsev-Mendes Graph, %d-th generation"%n) + return Graph(networkx.dorogovtsev_goltsev_mendes_graph(n), + name="Dorogovtsev-Goltsev-Mendes Graph, %d-th generation" % n) + def FoldedCubeGraph(n): r""" @@ -1384,23 +1389,22 @@ def FoldedCubeGraph(n): sage: fc.is_isomorphic(clebsch) True """ - if n < 1: raise ValueError("The value of n must be at least 2") - g = CubeGraph(n-1) + g = CubeGraph(n - 1) g.name("Folded Cube Graph") # Complementing the binary word def complement(x): - x = x.replace('0','a') - x = x.replace('1','0') - x = x.replace('a','1') + x = x.replace('0', 'a') + x = x.replace('1', '0') + x = x.replace('a', '1') return x for x in g: if x[0] == '0': - g.add_edge(x,complement(x)) + g.add_edge(x, complement(x)) return g @@ -1509,11 +1513,12 @@ def FriendshipGraph(n): center = 2 * n G = Graph(N, name="Friendship graph") for i in range(0, N - 1, 2): - G.add_cycle([center, i, i+1]) - G.set_pos({center:(0, 0)}) + G.add_cycle([center, i, i + 1]) + G.set_pos({center: (0, 0)}) G._circle_embedding(list(range(N - 1)), radius=1) return G + def FuzzyBallGraph(partition, q): r""" Construct a Fuzzy Ball graph with the integer partition @@ -1554,14 +1559,14 @@ def FuzzyBallGraph(partition, q): {x^8 - 8*x^7 + 4079/150*x^6 - 68689/1350*x^5 + 610783/10800*x^4 - 120877/3240*x^3 + 1351/100*x^2 - 931/450*x} """ from sage.graphs.generators.basic import CompleteGraph - if len(partition)<1: + if len(partition) < 1: raise ValueError("partition must be a nonempty list of positive integers") - n=q+sum(partition) - g=CompleteGraph(n) - curr_vertex=0 - for e,p in enumerate(partition): - g.add_edges([(curr_vertex+i, 'a{0}'.format(e+1)) for i in range(p)]) - curr_vertex+=p + n = q + sum(partition) + g = CompleteGraph(n) + curr_vertex = 0 + for e, p in enumerate(partition): + g.add_edges([(curr_vertex + i, 'a{0}'.format(e + 1)) for i in range(p)]) + curr_vertex += p return g @@ -1613,7 +1618,7 @@ def fib(level, node, y): y -= s diff = F[level] T.add_edge(node, node - diff) - if level == 1: # only one child + if level == 1: # only one child pos[node - diff] = (node, y) return T.add_edge(node, node + diff) @@ -1673,9 +1678,9 @@ def GeneralizedPetersenGraph(n, k): - Anders Jonsson (2009-10-15) """ if n < 3: - raise ValueError("n must be larger than 2") + raise ValueError("n must be larger than 2") if k < 1 or k > (n - 1) // 2: - raise ValueError("k must be in 1<= k <=floor((n-1)/2)") + raise ValueError("k must be in 1<= k <=floor((n-1)/2)") G = Graph(2 * n, name="Generalized Petersen graph (n="+str(n)+",k="+str(k)+")") for i in range(n): G.add_edge(i, (i+1) % n) @@ -1685,6 +1690,7 @@ def GeneralizedPetersenGraph(n, k): G._circle_embedding(list(range(n, 2*n)), radius=.5, angle=pi/2) return G + def IGraph(n, j, k): r""" Return an I-graph with `2n` nodes. @@ -1769,6 +1775,7 @@ def IGraph(n, j, k): G._circle_embedding(list(range(n, 2 * n)), radius=.5, angle=pi/2) return G + def DoubleGeneralizedPetersenGraph(n, k): r""" Return a double generalized Petersen graph with `4n` nodes. @@ -1821,9 +1828,9 @@ def DoubleGeneralizedPetersenGraph(n, k): ValueError: k must be in 1 <= k <= floor((n - 1) / 2) """ if n < 3: - raise ValueError("n must be larger than 2") + raise ValueError("n must be larger than 2") if k < 1 or k > (n - 1) // 2: - raise ValueError("k must be in 1 <= k <= floor((n - 1) / 2)") + raise ValueError("k must be in 1 <= k <= floor((n - 1) / 2)") G = Graph(4 * n, name="Double generalized Petersen graph (n={}, k={})".format(n, k)) for i in range(n): @@ -1832,13 +1839,14 @@ def DoubleGeneralizedPetersenGraph(n, k): G.add_edge(i, i + n) G.add_edge(i + 2 * n, i + 3 * n) G.add_edge(i + n, (i + k) % n + 2 * n) - G.add_edge(i+ 2 * n, (i + k) % n + n) + G.add_edge(i + 2 * n, (i + k) % n + n) G._circle_embedding(list(range(n)), radius=3, angle=pi/2) G._circle_embedding(list(range(n, 2 * n)), radius=2, angle=pi/2) G._circle_embedding(list(range(2 * n, 3 * n)), radius=1.5, angle=pi/2) G._circle_embedding(list(range(3 * n, 4 * n)), radius=0.5, angle=pi/2) return G + def RoseWindowGraph(n, a, r): r""" Return a rose window graph with `2n` nodes. @@ -1927,6 +1935,7 @@ def RoseWindowGraph(n, a, r): G._circle_embedding(list(range(n, 2 * n)), radius=0.5, angle=pi/2) return G + def TabacjnGraph(n, a, b, r): r""" Return a Tabačjn graph with `2n` nodes. @@ -2036,7 +2045,7 @@ def TabacjnGraph(n, a, b, r): return G -def HararyGraph( k, n ): +def HararyGraph(k, n): r""" Returns the Harary graph on `n` vertices and connectivity `k`, where `2 \leq k < n`. @@ -2079,20 +2088,21 @@ def HararyGraph( k, n ): if k >= n: raise ValueError("Number of vertices n should be greater than k.") - if k%2 == 0: - G = CirculantGraph( n, list(range(1,k//2+1)) ) + if k % 2 == 0: + G = CirculantGraph(n, list(range(1, k//2 + 1))) else: - if n%2 == 0: - G = CirculantGraph( n, list(range(1,(k-1)//2+1)) ) + if n % 2 == 0: + G = CirculantGraph(n, list(range(1, (k - 1)//2 + 1))) for i in range(n): - G.add_edge( i, (i + n//2)%n ) + G.add_edge(i, (i + n//2) % n) else: - G = HararyGraph( k-1, n ) - for i in range((n-1)//2 + 1): - G.add_edge( i, (i + (n-1)//2)%n ) - G.name('Harary graph {0}, {1}'.format(k,n)) + G = HararyGraph(k - 1, n) + for i in range((n - 1)//2 + 1): + G.add_edge(i, (i + (n - 1)//2) % n) + G.name('Harary graph {0}, {1}'.format(k, n)) return G + def HyperStarGraph(n, k): r""" Return the hyper-star graph `HS(n, k)`. @@ -2163,7 +2173,8 @@ def HyperStarGraph(n, k): c[i] = one adj[u] = L - return Graph(adj, format='dict_of_lists', name="HS(%d,%d)"%(n,k)) + return Graph(adj, format='dict_of_lists', name="HS(%d,%d)" % (n, k)) + def LCFGraph(n, shift_list, repeats): r""" @@ -2240,6 +2251,7 @@ def LCFGraph(n, shift_list, repeats): G._circle_embedding(list(range(n)), radius=1, angle=pi/2) return G + def MycielskiGraph(k=1, relabel=True): r""" Returns the `k`-th Mycielski Graph. @@ -2296,7 +2308,7 @@ def MycielskiGraph(k=1, relabel=True): g = Graph() g.name("Mycielski Graph " + str(k)) - if k<0: + if k < 0: raise ValueError("parameter k must be a nonnegative integer") if k == 0: @@ -2307,10 +2319,10 @@ def MycielskiGraph(k=1, relabel=True): return g if k == 2: - g.add_edge(0,1) + g.add_edge(0, 1) return g - g0 = MycielskiGraph(k-1) + g0 = MycielskiGraph(k - 1) g = MycielskiStep(g0) g.name("Mycielski Graph " + str(k)) if relabel: @@ -2318,6 +2330,7 @@ def MycielskiGraph(k=1, relabel=True): return g + def MycielskiStep(g): r""" Perform one iteration of the Mycielski construction. @@ -2334,7 +2347,6 @@ def MycielskiStep(g): sage: h.is_isomorphic(graphs.GrotzschGraph()) True """ - # Make a copy of the input graph g gg = copy(g) @@ -2347,18 +2359,19 @@ def MycielskiStep(g): gg.add_vertices(wlist) # add the z vertex as (0,0) - gg.add_vertex((0,0)) + gg.add_vertex((0, 0)) # add the edges from z to w_i - gg.add_edges([((0, 0), (2, v)) for v in g] ) + gg.add_edges([((0, 0), (2, v)) for v in g]) # make the v_i w_j edges for v in g: - gg.add_edges([((1,v),(2,vv)) for vv in g.neighbors(v)]) + gg.add_edges([((1, v), (2, vv)) for vv in g.neighbors(v)]) return gg -def NKStarGraph(n,k): + +def NKStarGraph(n, k): r""" Returns the (n,k)-star graph. @@ -2393,34 +2406,35 @@ def NKStarGraph(n,k): - Michael Yurko (2009-09-01) """ from sage.combinat.permutation import Arrangements - #set from which to permute - set = [str(i) for i in range(1,n+1)] - #create dict + # set from which to permute + set = [str(i) for i in range(1, n + 1)] + # create dict d = {} - for v in Arrangements(set,k): - v = list(v) # So we can easily mutate it + for v in Arrangements(set, k): + v = list(v) # So we can easily mutate it tmp_dict = {} - #add edges of dimension i - for i in range(1,k): - #swap 0th and ith element + # add edges of dimension i + for i in range(1, k): + # swap 0th and ith element v[0], v[i] = v[i], v[0] - #convert to str and add to list + # convert to str and add to list vert = "".join(v) tmp_dict[vert] = None - #swap back + # swap back v[0], v[i] = v[i], v[0] - #add other edges + # add other edges tmp_bit = v[0] for i in set: - #check if external - if not (i in v): + # check if external + if i not in v: v[0] = i - #add edge + # add edge vert = "".join(v) tmp_dict[vert] = None v[0] = tmp_bit d["".join(v)] = tmp_dict - return Graph(d, name="(%d,%d)-star"%(n,k)) + return Graph(d, name="(%d,%d)-star" % (n, k)) + def NStarGraph(n): r""" @@ -2451,26 +2465,26 @@ def NStarGraph(n): - Michael Yurko (2009-09-01) """ from sage.combinat.permutation import Permutations - #set from which to permute - set = [str(i) for i in range(1,n+1)] - #create dictionary of lists - #vertices are adjacent if the first element - #is swapped with the ith element + # set from which to permute + set = [str(i) for i in range(1, n + 1)] + # create dictionary of lists + # vertices are adjacent if the first element is swapped with the ith element d = {} for v in Permutations(set): - v = list(v) # So we can easily mutate it + v = list(v) # So we can easily mutate it tmp_dict = {} - for i in range(1,n): + for i in range(1, n): if v[0] != v[i]: - #swap 0th and ith element + # swap 0th and ith element v[0], v[i] = v[i], v[0] - #convert to str and add to list + # convert to str and add to list vert = "".join(v) tmp_dict[vert] = None - #swap back + # swap back v[0], v[i] = v[i], v[0] d["".join(v)] = tmp_dict - return Graph(d, name = "%d-star"%n) + return Graph(d, name="%d-star" % n) + def OddGraph(n): r""" @@ -2503,13 +2517,13 @@ def OddGraph(n): ... ValueError: Parameter n should be an integer strictly greater than 1 """ - - if not n>1: + if n <= 1: raise ValueError("Parameter n should be an integer strictly greater than 1") - g = KneserGraph(2*n-1,n-1) + g = KneserGraph(2*n - 1, n - 1) g.name("Odd Graph with parameter %s" % n) return g + def PaleyGraph(q): r""" Paley graph with `q` vertices @@ -2549,10 +2563,11 @@ def PaleyGraph(q): raise ValueError("parameter q must be a prime power") if not mod(q, 4) == 1: raise ValueError("parameter q must be congruent to 1 mod 4") - g = Graph([FiniteField(q,'a'), lambda i,j: (i-j).is_square()], - loops=False, name="Paley graph with parameter {}".format(q)) + g = Graph([FiniteField(q, 'a'), lambda i, j: (i - j).is_square()], + loops=False, name="Paley graph with parameter {}".format(q)) return g + def PasechnikGraph(n): r""" Pasechnik strongly regular graph on `(4n-1)^2` vertices @@ -2638,6 +2653,7 @@ def SquaredSkewHadamardMatrixGraph(n): G.name("skewhad^2_{}".format(n)) return G + def SwitchedSquaredSkewHadamardMatrixGraph(n): r""" A strongly regular graph in Seidel switching class of @@ -2824,7 +2840,6 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True): - Rob Beezer, (2009-12-26), with assistance from Su Doree """ - # sanitize input from sage.rings.integer import Integer pegs = Integer(pegs) @@ -2843,7 +2858,7 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True): # the number of pegs, and low-order digits to the right # complete graph on number of pegs when just a single disk - edges = [[i,j] for i in range(pegs) for j in range(i+1,pegs)] + edges = [[i, j] for i in range(pegs) for j in range(i + 1, pegs)] nverts = 1 for d in range(2, disks+1): @@ -2857,7 +2872,7 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True): for p in range(pegs): largedisk = p*nverts for anedge in prevedges: - edges.append([anedge[0]+largedisk, anedge[1]+largedisk]) + edges.append([anedge[0] + largedisk, anedge[1] + largedisk]) # Two new states may only differ in the large disk # being the only disk on two different pegs, thus @@ -2873,12 +2888,11 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True): emptypegs.remove(apeg) reduced_state = reduced_state//pegs for freea, freeb in Subsets(emptypegs, 2): - edges.append([freea*nverts+state,freeb*nverts+state]) + edges.append([freea*nverts + state, freeb*nverts + state]) H = Graph({}, loops=False, multiedges=False) H.add_edges(edges) - # Making labels and/or computing positions can take a long time, # relative to just constructing the edges on integer vertices. # We try to minimize coercion overhead, but need Sage @@ -2923,7 +2937,7 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True): locy_temp = parity*sine[p]*locx + cosine[p]*locy - radius*parity*sine[p] locx = locx_temp locy = locy_temp - pos[i] = (locx,locy) + pos[i] = (locx, locy) # set positions, then relabel (not vice versa) if positions: H.set_pos(pos) @@ -2932,6 +2946,7 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True): return H + def line_graph_forbidden_subgraphs(): r""" Returns the 9 forbidden subgraphs of a line graph. @@ -3204,6 +3219,7 @@ def next_step(triangle_list): dg.relabel() return dg + def GeneralizedSierpinskiGraph(G, k, stretch=None): r""" Return the generalized Sierpinski graph of `G` of dimension `k`. @@ -3354,6 +3370,7 @@ def rec(H, kk): for u in H}) return H + def WheelGraph(n): """ Returns a Wheel graph with n nodes. @@ -3428,6 +3445,7 @@ def WheelGraph(n): G.name("Wheel graph") return G + def WindmillGraph(k, n): r""" Return the Windmill graph `Wd(k, n)`. @@ -3499,18 +3517,18 @@ def WindmillGraph(k, n): slide = 1/sin(sector/4) pos_dict = {} - for i in range(0,k): + for i in range(0, k): x = float(cos(i*pi/(k-2))) y = float(sin(i*pi/(k-2))) + slide - pos_dict[i] = (x,y) + pos_dict[i] = (x, y) G = Graph() pos = {0: [0, 0]} for i in range(n): - V = list( range(i*(k-1)+1, (i+1)*(k-1)+1) ) + V = list(range(i*(k - 1) + 1, (i + 1)*(k - 1) + 1)) G.add_clique([0]+V) - for j,v in enumerate(V): - x,y = pos_dict[j] + for j, v in enumerate(V): + x, y = pos_dict[j] xv = x*cos(i*sector) - y*sin(i*sector) yv = x*sin(i*sector) + y*cos(i*sector) pos[v] = [xv, yv] @@ -3569,6 +3587,7 @@ def trees(vertices): from sage.graphs.trees import TreeIterator return iter(TreeIterator(vertices)) + def nauty_gentreeg(options="", debug=False): r""" Return a generator which creates non-isomorphic trees from nauty's gentreeg @@ -3692,7 +3711,8 @@ def nauty_gentreeg(options="", debug=False): G = Graph(s[:-1], format='sparse6', loops=False, multiedges=False) yield G -def RingedTree(k, vertex_labels = True): + +def RingedTree(k, vertex_labels=True): r""" Return the ringed tree on k-levels. @@ -3735,43 +3755,44 @@ def RingedTree(k, vertex_labels = True): [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] """ - if k<1: + if k < 1: raise ValueError('The number of levels must be >= 1.') # Creating the Balanced tree, which contains most edges already - g = BalancedTree(2,k-1) - g.name('Ringed Tree on '+str(k)+' levels') + g = BalancedTree(2, k - 1) + g.name('Ringed Tree on ' + str(k) + ' levels') # We consider edges layer by layer - for i in range(1,k): - vertices = list(range(2**(i)-1,2**(i+1)-1)) + for i in range(1, k): + vertices = list(range(2**(i) - 1, 2**(i + 1) - 1)) # Add the missing edges g.add_cycle(vertices) # And set the vertices' positions radius = i if i <= 1 else 1.5**i - shift = -2**(i-2)+.5 if i > 1 else 0 - g._circle_embedding(vertices, radius = radius, shift = shift) + shift = -2**(i - 2) + .5 if i > 1 else 0 + g._circle_embedding(vertices, radius=radius, shift=shift) # Specific position for the central vertex - g._pos[0] = (0,0.2) + g._pos[0] = (0, 0.2) # Relabel vertices as binary words if not vertex_labels: return g vertices = [''] - for i in range(k-1): - for j in range(2**(i)-1,2**(i+1)-1): + for i in range(k - 1): + for j in range(2**(i) - 1, 2**(i + 1) - 1): v = vertices[j] - vertices.append(v+'0') - vertices.append(v+'1') + vertices.append(v + '0') + vertices.append(v + '1') g.relabel(vertices) return g + def MathonPseudocyclicMergingGraph(M, t): r""" Mathon's merging of classes in a pseudo-cyclic 3-class association scheme @@ -3824,6 +3845,7 @@ def MathonPseudocyclicMergingGraph(M, t): A += sum(M[0].tensor_product(x) for x in M[1:]) return Graph(A) + def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): r""" Return a strongly regular graph on `(4t+1)(4t-1)^2` vertices from @@ -3912,24 +3934,24 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None): from sage.matrix.constructor import matrix, block_matrix, \ ones_matrix, identity_matrix from sage.arith.all import two_squares - p = 4*t+1 + p = 4*t + 1 try: x = two_squares(p) except ValueError: raise ValueError(str(p)+" must be a sum of two squares!") if G is None: from sage.graphs.strongly_regular_db import strongly_regular_graph as SRG - G = SRG(p, 2*t, t-1) + G = SRG(p, 2*t, t - 1) G.relabel(range(p)) if L is None: from sage.matrix.constructor import circulant - L = circulant(list(range(2 * t + 1))+list(range(-2 * t, 0))) - q = 4*t -1 - K = GF(q,prefix='x') - K_pairs = set(frozenset([x,-x]) for x in K) + L = circulant(list(range(2 * t + 1)) + list(range(-2 * t, 0))) + q = 4*t - 1 + K = GF(q, prefix='x') + K_pairs = set(frozenset([x, -x]) for x in K) K_pairs.discard(frozenset([0])) a = [None]*(q-1) # order the non-0 elements of K as required - for i,(x,y) in enumerate(K_pairs): + for i, (x, y) in enumerate(K_pairs): a[i] = x a[-i-1] = y a.append(K(0)) # and append the 0 of K at the end @@ -3946,36 +3968,37 @@ def B(m): def f(i, j): if i == j: return 0 * I - elif (a[j]-a[i]).is_square(): + elif (a[j] - a[i]).is_square(): return I + F else: return J - F elif m < 2*t: def f(i, j): - return F * P[a.index(g**(2*m) * (a[i]+a[j]))] + return F * P[a.index(g**(2*m) * (a[i] + a[j]))] elif m == 2*t: def f(i, j): return E * P[i] - return block_matrix(q,q, [f(i, j) for i in range(q) for j in range(q)]) + return block_matrix(q, q, [f(i, j) for i in range(q) for j in range(q)]) def Acon(i, j): J = ones_matrix(q**2) - if i==j: - return B(0) - if L[i,j]>0: - if G.has_edge(i,j): - return B(L[i,j]) - return J-B(L[i,j]) - if G.has_edge(i,j): - return B(-L[i,j]).T - return J-B(-L[i,j]).T - - A = Graph(block_matrix(p, p, [Acon(i,j) for i in range(p) for j in range(p)])) - A.name("Mathon's PC SRG on "+str(p*q**2)+" vertices") + if i == j: + return B(0) + if L[i, j] > 0: + if G.has_edge(i, j): + return B(L[i, j]) + return J - B(L[i, j]) + if G.has_edge(i, j): + return B(-L[i, j]).T + return J - B(-L[i, j]).T + + A = Graph(block_matrix(p, p, [Acon(i, j) for i in range(p) for j in range(p)])) + A.name("Mathon's PC SRG on " + str(p*q**2) + " vertices") A.relabel() return A -def TuranGraph(n,r): + +def TuranGraph(n, r): r""" Returns the Turan graph with parameters `n, r`. @@ -4038,6 +4061,7 @@ def TuranGraph(n,r): return g + def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): r""" Return a strongly regular graph of S6 type from [Muz2007]_ on @@ -4128,8 +4152,8 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): ... ValueError: Sigma must be 'random' or 'fixed' """ - ### TO DO: optimise - ### add option to return phi, sigma? generate phi, sigma from seed? (int say?) + # TO DO: optimise + # add option to return phi, sigma? generate phi, sigma from seed? (int say?) from sage.combinat.designs.block_design import ProjectiveGeometryDesign from sage.misc.prandom import randrange @@ -4149,7 +4173,7 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): t = time() # build L, L_i and the design - m = int((n**d-1)/(n-1) + 1) #from m = p + 1, p = (n^d-1) / (n-1) + m = int((n**d - 1)/(n - 1) + 1) # from m = p + 1, p = (n^d-1) / (n-1) L = CompleteGraph(m) L.delete_edges([(2 * x, 2 * x + 1) for x in range(m // 2)]) L_i = [L.edges_incident(x, labels=False) for x in range(m)] @@ -4166,7 +4190,7 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): while ParClasses[0]: nextHyp = ParClasses[0].pop() for C in ParClasses[1:]: - listC = sum(C,[]) + listC = sum(C, []) for x in nextHyp: if x in listC: break @@ -4189,8 +4213,8 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): for C in ParClasses: EC = matrix(QQ, v) for line in C: - for i,j in combinations(line, 2): - EC[i,j] = EC[j,i] = 1/k + for i, j in combinations(line, 2): + EC[i, j] = EC[j, i] = 1/k EC -= ones_v E[tuple(C[0])] = EC if verbose: @@ -4206,21 +4230,19 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): rand = randrange(0, len(temp)) Phi[(x, line)] = temp.pop(rand) elif Phi == 'fixed': - Phi = {(x,line):val for x in range(m) for val,line in enumerate(L_i[x])} + Phi = {(x, line): val for x in range(m) for val, line in enumerate(L_i[x])} else: assert isinstance(Phi, dict), \ - "Phi must be a dictionary or 'random' or 'fixed'" - assert set(Phi.keys()) == \ - set([(x, line) for x in range(m) for line in L_i[x]]), \ - 'each Phi_i must have domain L_i' + "Phi must be a dictionary or 'random' or 'fixed'" + assert set(Phi.keys()) == set([(x, line) for x in range(m) for line in L_i[x]]), \ + 'each Phi_i must have domain L_i' for x in range(m): - assert m - 2 == len(set([val - for (key, val) in Phi.items() if key[0] == x])), \ - 'each phi_i must be injective' + assert m - 2 == len(set([val for (key, val) in Phi.items() if key[0] == x])), \ + 'each phi_i must be injective' for val in Phi.values(): - assert val in range(m-1), \ - 'codomain should be {0,..., (n^d - 1)/(n - 1) - 1}' - phi = {(x, line):ParClasses[Phi[(x, line)]] for x in range(m) for line in L_i[x]} + assert val in range(m - 1), \ + 'codomain should be {0,..., (n^d - 1)/(n - 1) - 1}' + phi = {(x, line): ParClasses[Phi[(x, line)]] for x in range(m) for line in L_i[x]} if verbose: print('finished phi at %f (+%f)' % (time() - t, time() - t1)) t1 = time() @@ -4253,7 +4275,7 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): t1 = time() # build V - edges = [] ###how many? *m^2*n^2 + edges = [] # how many? *m^2*n^2 for (i, j) in L.edges(sort=True, labels=False): for hyp in phi[(i, (i, j))]: for x in hyp: @@ -4275,8 +4297,8 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): F_i = [1 - D_i[x] - ones_v for x in range(m)] # as the sum of (1/v)*J_\Omega_i, D_i, F_i is identity A_i = [(v-k)*ones_v - k*F_i[x] for x in range(m)] - # we know A_i = k''*(1/v)*J_\Omega_i + r''*D_i + s''*F_i, - # and (k'', s'', r'') = (v - k, 0, -k) + # we know A_i = k''*(1/v)*J_\Omega_i + r''*D_i + s''*F_i, + # and (k'', s'', r'') = (v - k, 0, -k) if verbose: print('finished D, F and A at %f (+%f)' % (time() - t, time() - t1)) t1 = time() @@ -4291,6 +4313,7 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False): print('finished at %f (+%f)' % ((time() - t), time() - t1)) return V + def CubeConnectedCycle(d): r""" Return the cube-connected cycle of dimension `d`. @@ -4352,7 +4375,7 @@ def CubeConnectedCycle(d): if d == 1: G.allow_loops(True) # only d = 1 requires loops - G.add_edges([((0,0),(0,1)), ((0,0),(0,0)), ((0,1),(0,1))]) + G.add_edges([((0, 0), (0, 1)), ((0, 0), (0, 0)), ((0, 1), (0, 1))]) return G if d == 2: @@ -4364,10 +4387,10 @@ def CubeConnectedCycle(d): ((2, 0), (3, 0)), ((3, 0), (3, 1)), ((3, 0), (3, 1))]) return G - for x in range(1< Date: Wed, 22 Jun 2022 14:30:15 -0500 Subject: [PATCH 252/591] Add documentation of Integer index --- src/sage/sets/family.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/sets/family.py b/src/sage/sets/family.py index 996eb106de6..453d427a220 100644 --- a/src/sage/sets/family.py +++ b/src/sage/sets/family.py @@ -1346,7 +1346,7 @@ def __setstate__(self, state): class EnumeratedFamily(LazyFamily): r""" :class:`EnumeratedFamily` turns an enumerated set ``c`` into a family - indexed by the set `\{0,\dots, |c|-1\}`. + indexed by the set `\{0,\dots, |c|-1\}` or ``ZZ``. Instances should be created via the :func:`Family` factory. See its documentation for examples and tests. @@ -1374,6 +1374,8 @@ def __init__(self, enumset): True sage: Family(Permutations()).keys() Non negative integers + sage: type(Family(ZZ)) + """ if enumset.cardinality() == Infinity: baseset = NonNegativeIntegers() From ef18836e3b979903ef8e49618033186e62c1e82c Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 16 Nov 2021 19:26:18 +0000 Subject: [PATCH 253/591] update sagetex to version 3.6 --- build/pkgs/sagetex/checksums.ini | 6 +++--- build/pkgs/sagetex/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sagetex/checksums.ini b/build/pkgs/sagetex/checksums.ini index bbb0fdadd37..5f572db0d49 100644 --- a/build/pkgs/sagetex/checksums.ini +++ b/build/pkgs/sagetex/checksums.ini @@ -1,5 +1,5 @@ tarball=sagetex-VERSION.tar.gz -sha1=f92518caf6e355cc8046847c73446679c3a1c1bc -md5=46dcd30b18c107cc6f6dca1d47685f51 -cksum=1068602151 +sha1=01b829991631679dfd176068d2d235d70b737d40 +md5=2195f448817093648a9d7ad86890088b +cksum=3871373557 upstream_url=https://github.com/sagemath/sagetex/releases/download/vVERSION/sagetex-VERSION.tar.gz diff --git a/build/pkgs/sagetex/package-version.txt b/build/pkgs/sagetex/package-version.txt index 5a958026daa..d70c8f8d89f 100644 --- a/build/pkgs/sagetex/package-version.txt +++ b/build/pkgs/sagetex/package-version.txt @@ -1 +1 @@ -3.5 +3.6 From 89b2af86d21085223bcf4c221646cbbc09fc9b0b Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 17 Nov 2021 09:42:02 +0000 Subject: [PATCH 254/591] correct version in setup.py, and deps --- build/pkgs/sagetex/checksums.ini | 6 +++--- build/pkgs/sagetex/dependencies | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sagetex/checksums.ini b/build/pkgs/sagetex/checksums.ini index 5f572db0d49..3e35ffd5a94 100644 --- a/build/pkgs/sagetex/checksums.ini +++ b/build/pkgs/sagetex/checksums.ini @@ -1,5 +1,5 @@ tarball=sagetex-VERSION.tar.gz -sha1=01b829991631679dfd176068d2d235d70b737d40 -md5=2195f448817093648a9d7ad86890088b -cksum=3871373557 +sha1=693b0e0624c468717484758f9e42d0c6fd4d1a56 +md5=3af3a403fc01021176044ee838775502 +cksum=2482351308 upstream_url=https://github.com/sagemath/sagetex/releases/download/vVERSION/sagetex-VERSION.tar.gz diff --git a/build/pkgs/sagetex/dependencies b/build/pkgs/sagetex/dependencies index 29f49d5c215..2a21dc572ef 100644 --- a/build/pkgs/sagetex/dependencies +++ b/build/pkgs/sagetex/dependencies @@ -1,4 +1,6 @@ -$(PYTHON) maxima scipy matplotlib pillow tachyon +$(PYTHON) maxima scipy matplotlib pillow tachyon pyparsing ninja | $(and $(filter-out no,$(SAGE_CHECK_sagetex)), $(SAGERUNTIME) sympy elliptic_curves jmol) +To build SageTeX, you just need Python and pyparsing, but to test (SAGE_CHECK=yes) +SageTeX, you actually need to run Sage, produce plots,... ---------- All lines of this file are ignored except the first. From 26eca99822f0d423250aa2279023b85d22826b15 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 6 Dec 2021 15:16:34 -0800 Subject: [PATCH 255/591] trac 32887: change location of sagetex to venv/share/texmf/... --- build/pkgs/sagetex/SPKG.rst | 4 ++-- src/doc/de/tutorial/introduction.rst | 2 +- src/doc/de/tutorial/sagetex.rst | 4 ++-- src/doc/en/tutorial/introduction.rst | 2 +- src/doc/en/tutorial/sagetex.rst | 16 ++++++++-------- src/doc/es/tutorial/introduction.rst | 2 +- src/doc/fr/tutorial/introduction.rst | 2 +- src/doc/fr/tutorial/sagetex.rst | 4 ++-- src/doc/ja/tutorial/introduction.rst | 2 +- src/doc/ja/tutorial/sagetex.rst | 16 ++++++++-------- src/doc/pt/tutorial/introduction.rst | 2 +- src/doc/pt/tutorial/sagetex.rst | 4 ++-- src/doc/ru/tutorial/introduction.rst | 2 +- src/doc/ru/tutorial/sagetex.rst | 4 ++-- 14 files changed, 33 insertions(+), 33 deletions(-) diff --git a/build/pkgs/sagetex/SPKG.rst b/build/pkgs/sagetex/SPKG.rst index 1a3de2a92b4..b2e3bd85b18 100644 --- a/build/pkgs/sagetex/SPKG.rst +++ b/build/pkgs/sagetex/SPKG.rst @@ -55,9 +55,9 @@ needs. Full details are in the Sage installation guide at http://doc.sagemath.org/html/en/installation/ and http://doc.sagemath.org/html/en/tutorial/sagetex.html . -The directory ``$SAGE_ROOT/local/share/doc/sagetex`` contains +The directory ``$SAGE_ROOT/venv/share/doc/sagetex`` contains documentation and an example file. See -``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex`` for the source code +``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex`` for the source code and some possibly useful scripts. If you have problems or suggestions see `the sage-support group `__. diff --git a/src/doc/de/tutorial/introduction.rst b/src/doc/de/tutorial/introduction.rst index ea3bf00cf34..ac4f353571b 100644 --- a/src/doc/de/tutorial/introduction.rst +++ b/src/doc/de/tutorial/introduction.rst @@ -98,7 +98,7 @@ Hier geben wir nur ein paar Kommentare ab. einzige Datei in ein Verzeichnis kopieren, welches TeX durchsucht. Die Dokumentation für SageTeX befindet sich in - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, wobei + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, wobei "``$SAGE_ROOT``" auf das Verzeichnis zeigt, in welches Sie Sage installiert haben, zum Beispiel ``/opt/sage-4.2.1``. diff --git a/src/doc/de/tutorial/sagetex.rst b/src/doc/de/tutorial/sagetex.rst index 8f58e812a78..37780eb6cf2 100644 --- a/src/doc/de/tutorial/sagetex.rst +++ b/src/doc/de/tutorial/sagetex.rst @@ -15,7 +15,7 @@ Tutorial und den Abschnitt "Make SageTeX known to TeX" des `Sage installation gu Installationsanleitung führen) um weitere Informationen zu erhalten. Hier stellen wir ein sehr kurzes Beispiel vor wie man SageTeX nutzt. -Die komplette Dokumentation finden Sie unter ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``, +Die komplette Dokumentation finden Sie unter ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``, wobei ``SAGE_ROOT`` das Installationsverzeichnis von Sage ist. Dieses Verzeichnis enthält die Dokumentation, eine Beispieldatei und einige nützliche Python Skripte. @@ -103,4 +103,4 @@ an den Sage Befehlen in Ihrem Dokument vorgenommen haben. Es gibt noch viel mehr über SageTeX zu sagen, aber da sowohl Sage alsauch LaTeX komplexe und mächtige Werkzeuge sind, sollten Sie die Dokumentation -über SageTeX in ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex`` lesen. +über SageTeX in ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex`` lesen. diff --git a/src/doc/en/tutorial/introduction.rst b/src/doc/en/tutorial/introduction.rst index c9683df4d78..3112aec0ecd 100644 --- a/src/doc/en/tutorial/introduction.rst +++ b/src/doc/en/tutorial/introduction.rst @@ -89,7 +89,7 @@ computer. Here we merely make a few comments. will search. The documentation for using SageTeX is located in - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, where + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, where "``$SAGE_ROOT``" refers to the directory where you installed Sage -- for example, ``/opt/sage-4.2.1``. diff --git a/src/doc/en/tutorial/sagetex.rst b/src/doc/en/tutorial/sagetex.rst index 0fdc74b0640..17460be0b49 100644 --- a/src/doc/en/tutorial/sagetex.rst +++ b/src/doc/en/tutorial/sagetex.rst @@ -12,10 +12,10 @@ An example ---------- Here is a very brief example of using SageTeX. The full documentation -can be found in ``SAGE_ROOT/local/share/doc/sagetex``, +can be found in ``SAGE_ROOT/venv/share/doc/sagetex``, where ``SAGE_ROOT`` is the directory where your Sage installation is located. That directory contains the documentation and an example file. -See ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex`` for +See ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex`` for some possibly useful Python scripts. To see how SageTeX works, follow the directions for installing SageTeX (in @@ -105,7 +105,7 @@ commands in your document. There's a lot more to SageTeX, and since both Sage and LaTeX are complex, powerful tools, it's a good idea to read the documentation for SageTeX, which is in -``SAGE_ROOT/local/share/doc/sagetex``. +``SAGE_ROOT/venv/share/doc/sagetex``. .. _sec-sagetex_install: @@ -122,7 +122,7 @@ installation aware of it before it will work. The key to this is that TeX needs to be able to find ``sagetex.sty``, which can be found in -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, where +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, where ``SAGE_ROOT`` is the directory where you built or installed Sage. If TeX can find ``sagetex.sty``, then SageTeX will work. There are several ways to accomplish this. @@ -142,7 +142,7 @@ ways to accomplish this. .. CODE-BLOCK:: shell-session - $ export TEXINPUTS="SAGE_ROOT/local/share/texmf//:" + $ export TEXINPUTS="SAGE_ROOT/venv/share/texmf//:" where ``SAGE_ROOT`` is the location of your Sage installation. Note that the double slash and colon at the end of that line are important. @@ -173,12 +173,12 @@ ways to accomplish this. which will print out a directory, such as ``/home/drake/texmf`` or ``/Users/drake/Library/texmf``. Copy the ``tex/`` directory from - ``SAGE_ROOT/local/share/texmf/`` into your home ``texmf`` directory + ``SAGE_ROOT/venv/share/texmf/`` into your home ``texmf`` directory with a command like .. CODE-BLOCK:: shell-session - $ cp -R SAGE_ROOT/local/share/texmf/tex TEXMFHOME + $ cp -R SAGE_ROOT/venv/share/texmf/tex TEXMFHOME where ``SAGE_ROOT`` is, as usual, replaced with the location of your Sage installation and ``TEXMFHOME`` is the result of the @@ -229,7 +229,7 @@ SageTeX documentation While not strictly part of installation, it bears mentioning here that the documentation for SageTeX is maintained in -``SAGE_ROOT/local/share/doc/sagetex/sagetex.pdf``. There is also an +``SAGE_ROOT/venv/share/doc/sagetex/sagetex.pdf``. There is also an example file in the same directory -- see ``example.tex`` and ``example.pdf``, the pre-built result of typesetting that file with LaTeX and Sage. You can also get those files from the `SageTeX page `_. diff --git a/src/doc/es/tutorial/introduction.rst b/src/doc/es/tutorial/introduction.rst index 7eb55a8d740..9c3077cdef6 100644 --- a/src/doc/es/tutorial/introduction.rst +++ b/src/doc/es/tutorial/introduction.rst @@ -90,7 +90,7 @@ Sage en tu computador. Aquí hacemos simplemente dos comentarios: en un directorio en el que TeX va a buscar. La documentación para usar SageTeX se encuentra en - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, donde + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, donde "``$SAGE_ROOT``" se refiere al directorio donde Sage está instalado -- por ejemplo, ``/opt/sage-4.2.1``. diff --git a/src/doc/fr/tutorial/introduction.rst b/src/doc/fr/tutorial/introduction.rst index 875fefbeaa1..c3f3adc8da5 100644 --- a/src/doc/fr/tutorial/introduction.rst +++ b/src/doc/fr/tutorial/introduction.rst @@ -96,7 +96,7 @@ Nous nous limiterons ici à quelques remarques. d'environnement. La documentation de SageTeX se trouve dans le répertoire - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, où + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, où "``$SAGE_ROOT``" est le répertoire où vous avez installé Sage, par exemple ``/opt/sage-4.3.4``. diff --git a/src/doc/fr/tutorial/sagetex.rst b/src/doc/fr/tutorial/sagetex.rst index 9aa52f3759a..b17f0ad56f7 100644 --- a/src/doc/fr/tutorial/sagetex.rst +++ b/src/doc/fr/tutorial/sagetex.rst @@ -16,7 +16,7 @@ locale) pour plus de détails. Voici un bref exemple d'utilisation de SageTeX. La documentation complète se trouve dans -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``, où ``SAGE_ROOT`` +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``, où ``SAGE_ROOT`` désigne le répertoire racine de votre installation Sage. Elle est accompagnée d'un fichier exemple et de scripts Python potentiellement utiles. @@ -114,4 +114,4 @@ compilation précédente.) SageTeX offre bien d'autres possibilités. Puisque Sage comme LaTeX sont des outils complexes et puissants, le mieux est sans doute de consulter la documentation complète de SageTeX, qui se trouve -dans ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``. +dans ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``. diff --git a/src/doc/ja/tutorial/introduction.rst b/src/doc/ja/tutorial/introduction.rst index 2c4ce235f6a..dda2e673bd1 100644 --- a/src/doc/ja/tutorial/introduction.rst +++ b/src/doc/ja/tutorial/introduction.rst @@ -73,7 +73,7 @@ Sageを自分のコンピュータへインストールする手順について SageTeXの利用に関する解説は -``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/`` にある. +``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/`` にある. ``$SAGE_ROOT`` はSageがインストールされているディレクトリで,例えば ``/opt/sage-4.2.1`` などとなっているはずだ. diff --git a/src/doc/ja/tutorial/sagetex.rst b/src/doc/ja/tutorial/sagetex.rst index a6e2b40b5b2..dbbdc3ff7bd 100644 --- a/src/doc/ja/tutorial/sagetex.rst +++ b/src/doc/ja/tutorial/sagetex.rst @@ -12,8 +12,8 @@ SageTeXパッケージを使うと,Sageによる処理結果をLaTeX文書に ======= ここでは,ごく簡単な例題を通してSageTeXの利用手順を紹介する. -完全な解説ドキュメントと例題ファイルは,ディレクトリ ``SAGE_ROOT/local/share/doc/sagetex`` に置いてある. -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex`` にあるPythonスクリプトは何か役に立つ場面があるはずだ. +完全な解説ドキュメントと例題ファイルは,ディレクトリ ``SAGE_ROOT/venv/share/doc/sagetex`` に置いてある. +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex`` にあるPythonスクリプトは何か役に立つ場面があるはずだ. 以上の ``SAGE_ROOT`` は,Sageをインストールしたディレクトリである. @@ -98,7 +98,7 @@ SageTeXの動作を体験するために,まずSageTeXのインストール手 SageTeXは到底以上で語り尽せるものでなく,SageとLaTeXは共に複雑で強力なツールだ. -``SAGE_ROOT/local/share/doc/sagetex`` にあるSageTeXのドキュメントを読むことを強くお勧めする. +``SAGE_ROOT/venv/share/doc/sagetex`` にあるSageTeXのドキュメントを読むことを強くお勧めする. .. _sec-sagetex_install: @@ -118,7 +118,7 @@ SageTeXはデフォルトでSageにインストールされるが,LaTeX文書 鍵になるのは, TeXが ``sagetex.sty`` を発見できるかどうかである. この ``sagetex.sty`` は, ``SAGE_ROOT`` をSageがビルトあるいはインストールされたディレクトリとすると, -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex/`` に置かれているはずだ. +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/`` に置かれているはずだ. TeXが ``sagetex.sty`` を読めるようにしてやらなければ,SageTeXも動作できないのである. これを実現するには何通りかのやり方がある. @@ -137,7 +137,7 @@ TeXが ``sagetex.sty`` を読めるようにしてやらなければ,SageTeX :: - export TEXINPUTS="SAGE_ROOT/local/share/texmf//:" + export TEXINPUTS="SAGE_ROOT/venv/share/texmf//:" と実行すればよい.ただし ``SAGE_ROOT`` はSageのインストール先ディレクトリである. 上の実行例では,行末にスラッシュ2個とコロンを付け忘れないでいただきたい. @@ -163,11 +163,11 @@ TeXが ``sagetex.sty`` を読めるようにしてやらなければ,SageTeX kpsewhich -var-value=TEXMFHOME - を実行する.すると ``/home/drake/texmf`` や ``/Users/drake/Library/texmf`` などと表示されるはずだから, ``SAGE_ROOT/local/share/texmf/`` 内の ``tex/`` ディレクトリをホームディレクトリの ``texmf`` にコピーするには + を実行する.すると ``/home/drake/texmf`` や ``/Users/drake/Library/texmf`` などと表示されるはずだから, ``SAGE_ROOT/venv/share/texmf/`` 内の ``tex/`` ディレクトリをホームディレクトリの ``texmf`` にコピーするには :: - cp -R SAGE_ROOT/local/share/texmf/tex TEXMFHOME + cp -R SAGE_ROOT/venv/share/texmf/tex TEXMFHOME などとする. もちろん, ``SAGE_ROOT`` を実際にSageをインストールしたディレクトリとするのはこれまでと同じことで, ``TEXMFHOME`` は上で見た ``kpsewhich`` コマンドの結果で置き換える. @@ -210,7 +210,7 @@ SageTeXドキュメント --------------------- 厳密にはSageのインストール一式には含まれないものの,ここで -SageTeXのドキュメントが ``SAGE_ROOT/local/share/doc/sagetex/sagetex.pdf`` に配置されていることに触れておきたい. +SageTeXのドキュメントが ``SAGE_ROOT/venv/share/doc/sagetex/sagetex.pdf`` に配置されていることに触れておきたい. 同じディレクトリには例題ファイルと,これをLaTeXとSageTeXによってすでに組版処理した結果も用意されている(``example.tex`` と ``example.pdf`` を参照). これらのファイルは `SageTeX ページ `_ からダンロードすることもできる. diff --git a/src/doc/pt/tutorial/introduction.rst b/src/doc/pt/tutorial/introduction.rst index 0a821b3c099..676855f7172 100644 --- a/src/doc/pt/tutorial/introduction.rst +++ b/src/doc/pt/tutorial/introduction.rst @@ -90,7 +90,7 @@ computador. Aqui faremos apenas alguns comentários. encontrá-lo. A documentação para usar o SageTex está disponível em - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, onde + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, onde ``$SAGE_ROOT`` refere-se ao diretório onde você instalou o Sage -- por exemplo, ``/opt/sage-4.2.1``. diff --git a/src/doc/pt/tutorial/sagetex.rst b/src/doc/pt/tutorial/sagetex.rst index 949b9b3e6db..8b0c47b6891 100644 --- a/src/doc/pt/tutorial/sagetex.rst +++ b/src/doc/pt/tutorial/sagetex.rst @@ -14,7 +14,7 @@ instalação do Sage `_ Aqui vai um breve exemplo de como usar o SageTeX. A documentação completa pode ser encontrada em -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``, onde +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``, onde ``SAGE_ROOT`` é o diretório onde se encontra a sua instalação. Esse diretório contém a documentação, um arquivo de exemplo, e alguns scripts em Python possivelmente úteis. @@ -107,4 +107,4 @@ os comandos em Sage em seu documento. Há muito mais sobre o SageTeX, e como tanto o Sage como o LaTeX são ferramentas complexas e poderosas, é uma boa idéia ler a documentação para o SageTeX que se encontra em -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``. +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``. diff --git a/src/doc/ru/tutorial/introduction.rst b/src/doc/ru/tutorial/introduction.rst index 3f62905cee9..f60e2954803 100644 --- a/src/doc/ru/tutorial/introduction.rst +++ b/src/doc/ru/tutorial/introduction.rst @@ -88,7 +88,7 @@ Sage в разделе документации: [SA]_ Здесь мы прив всего лишь скопировать один файл в директорию поиска TeX. Документация по использованию SageTeX находится в - ``$SAGE_ROOT/local/share/texmf/tex/latex/sagetex/``, где + ``$SAGE_ROOT/venv/share/texmf/tex/latex/sagetex/``, где "``$SAGE_ROOT``" соответствует директории, где установлен сам Sage, например, ``/opt/sage-4.2.1``. diff --git a/src/doc/ru/tutorial/sagetex.rst b/src/doc/ru/tutorial/sagetex.rst index d23ebc7fb31..8c930e2de2a 100644 --- a/src/doc/ru/tutorial/sagetex.rst +++ b/src/doc/ru/tutorial/sagetex.rst @@ -12,7 +12,7 @@ SageTeX known to TeX" `Руководства по установке Sage по установке). В этом уроке показан небольшой пример использования SageTeX. Полная документация -находится в ``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``, где +находится в ``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``, где ``SAGE_ROOT`` - это директория, в которой установлен Sage. Эта папка содержит документацию, файл с примером и полезные скрипты Python. @@ -89,4 +89,4 @@ SageTeX known to TeX" `Руководства по установке Sage SageTeX предлагает много возможностей, и так как Sage и LaTeX являются мощными инструментами, то стоит изучить -``SAGE_ROOT/local/share/texmf/tex/latex/sagetex``. +``SAGE_ROOT/venv/share/texmf/tex/latex/sagetex``. From 15675e5fa5343d6b0c1edecb6aa9dc123d1930cb Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 7 Dec 2021 17:29:00 +0000 Subject: [PATCH 256/591] fixed sagetex v3.6 --- build/pkgs/sagetex/checksums.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/sagetex/checksums.ini b/build/pkgs/sagetex/checksums.ini index 3e35ffd5a94..8d53b030a72 100644 --- a/build/pkgs/sagetex/checksums.ini +++ b/build/pkgs/sagetex/checksums.ini @@ -1,5 +1,5 @@ tarball=sagetex-VERSION.tar.gz -sha1=693b0e0624c468717484758f9e42d0c6fd4d1a56 -md5=3af3a403fc01021176044ee838775502 -cksum=2482351308 +sha1=3f2a907d14bfff5243c9803c57bf9d46685291a0 +md5=a013fdbeaa4b9ba33a687a51ee390094 +cksum=3706582539 upstream_url=https://github.com/sagemath/sagetex/releases/download/vVERSION/sagetex-VERSION.tar.gz From 858e982549d2e2457bd63600e6d565675b5d8582 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Aug 2022 16:48:41 -0700 Subject: [PATCH 257/591] src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx: Reformat algorithm, avoid unicode symbols --- .../face_iterator.pyx | 118 ++++++++++-------- 1 file changed, 67 insertions(+), 51 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index cc36509a47e..4fe24c3d45b 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -1464,84 +1464,100 @@ cdef class FaceIterator(FaceIterator_base): ALGORITHM: - For the special case that the all intervals of the lattice not containing zero are boolean - (e.g. when the polyhedron is simple) the algorithm is modified. See below. - - - A (slightly generalized) description of the algorithm can be found in [KS2019]_. - The algorithm to visit all proper faces exactly once is roughly - equivalent to:: + equivalent to the following. A (slightly generalized) description of the + algorithm can be found in [KS2019]_. + + Initialization:: faces = [set(facet) for facet in P.facets()] face_iterator(faces, []) + The function ``face_iterator`` is defined recursively. It visits all faces of + the polyhedron `P`, except those contained in any of ``visited_all``. + It assumes ``faces`` to be exactly those facets of `P` + that are not contained in any of the ``visited_all``. + It assumes ``visited_all`` to be some list of faces of + a polyhedron `P_2`, which contains `P` as one of its faces:: + def face_iterator(faces, visited_all): - # Visit all faces of a polyhedron `P`, except those contained in - # any of the visited all. + while facets: + one_face = faces.pop() + maybe_new_faces = [one_face.intersection(face) for face in faces] + ... - # Assumes ``faces`` to be exactly those facets of `P` - # that are not contained in any of the ``visited_all``. + At this point we claim that ``maybe_new_faces`` contains all facets of ``one_face``, + which we have not visited before. - # Assumes ``visited_all`` to be some list of faces of - # a polyhedron `P_2`, which contains `P` as one of its faces. + Proof: Let `F` be a facet of ``one_face``. We have a chain: - while facets: - one_face = faces.pop() - new_faces = [one_face.intersection(face) for face in faces] - - # ``maybe_new_faces`` contains all facets of ``one_face``, - # which we have not visited before. - # Proof: Let `F` be a facet of ``one_face``. - # We have a chain: - # `P` ⊃ ``one_face`` ⊃ `F`. - # By diamond property there exists ``second_face`` with: - # `P` ⊃ ``second_face`` ⊃ `F`. - - # Either ``second_face`` is not an element of ``faces``: - # Hence ``second_face`` is contained in one of ``visited_all``. - # In particular, `F` is contained in ``visited_all``. - # Or ``second_face`` is an element of ``faces``: - # Then, intersecting ``one_face`` with ``second_face`` gives - # ``F``. ∎ - - # If an element in ``maybe_new_faces`` is inclusion maximal - # and not contained in any of the ``visited_all``, - # it is a facet of ``one_face``. - # Any facet in ``maybe_new_faces`` of ``one_face`` - # is inclusion maximal. + .. MATH:: + + P \supset \texttt{one_face} \supset F. + + By the diamond property, there exists a ``second_face`` with: + + .. MATH:: + + P \supset \texttt{second_face} \supset F. + + Now either ``second_face`` is not an element of ``faces``: + Hence ``second_face`` is contained in one of ``visited_all``. + In particular, `F` is contained in ``visited_all``. + + Or ``second_face`` is an element of ``faces``: + Then, intersecting ``one_face`` with ``second_face`` gives ``F``. + + This concludes the proof. + + Moreover, if an element in ``maybe_new_faces`` is inclusion-maximal + and not contained in any of the ``visited_all``, it is a facet of ``one_face``. + Any facet in ``maybe_new_faces`` of ``one_face`` is inclusion-maximal. + + Hence, in the following loop, an element ``face1`` in ``maybe_new_faces`` + is a facet of ``one_face`` if and only if it is not contained in another facet:: + + ... maybe_new_faces2 = [] for i, face1 in enumerate(maybe_new_faces): - # ``face1`` is a facet of ``one_face``, - # iff it is not contained in another facet. if (all(not face1 < face2 for face2 in maybe_new_faces[:i]) and all(not face1 <= face2 for face2 in maybe_new_faces[i+1:])): maybe_new_faces2.append(face1) + ... + + Now ``maybe_new_faces2`` contains only facets of ``one_face`` + and some faces contained in any of ``visited_all``. + It also contains all the facets not contained in any of ``visited_all``. + + We construct ``new_faces`` as the list of all facets of ``one_face`` + not contained in any of ``visited_all``:: - # ``maybe_new_faces2`` contains only facets of ``one_face`` - # and some faces contained in any of ``visited_all``. - # It also contains all the facets not contained in any of ``visited_all``. - # Let ``new_faces`` be the list of all facets of ``one_face`` - # not contained in any of ``visited_all``. + ... new_faces = [] for face1 in maybe_new_faces2: if all(not face1 < face2 for face2 in visited_all): new_faces.append(face1) + ... - # By induction we can apply the algorithm, to visit all - # faces of ``one_face`` not contained in ``visited_all``: + By induction we can apply the algorithm, to visit all + faces of ``one_face`` not contained in ``visited_all``:: + + ... face_iterator(new_faces, visited_all) + ... + + Finally we visit ``one_face`` and add it to ``visited_all``:: - # Finally visit ``one_face`` and add it to ``visited_all``: + ... visit(one_face) visited_all.append(one_face) - # Note: At this point, we have visited exactly those faces, - # contained in any of the ``visited_all``. + Note: At this point, we have visited exactly those faces, + contained in any of the ``visited_all``. The function ends here. - For the special case that the all intervals of the lattice not containing zero are boolean - (e.g. when the polyhedron is simple), the algorithm can be modified. + ALGORITHM for the special case that all intervals of the lattice not + containing zero are boolean (e.g. when the polyhedron is simple): We do not assume any other properties of our lattice in this case. Note that intervals of length 2 not containing zero, have exactly 2 elements now. From b2279734577506e0e4983e07dd7488c7106573dc Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Aug 2022 09:19:42 +0900 Subject: [PATCH 258/591] Speeding up multiplication even further. --- .../algebras/clifford_algebra_element.pyx | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index dc24c92ae03..f2a6e09ad86 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -341,25 +341,50 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): -x*y*z*w sage: (z * w) * (x * y) x*y*z*w + + sage: E. = ExteriorAlgebra(QQ) + sage: r = sum(E.basis()) + sage: r*r + 4*a*b*c*d + 4*a*b*c + 4*a*b*d + 4*a*c*d + 4*b*c*d + + 2*a*b + 2*a*c + 2*a*d + 2*b*c + 2*b*d + 2*c*d + + 2*a + 2*b + 2*c + 2*d + 1 """ cdef Parent P = self._parent zero = P._base.zero() - cdef dict d = {} + cdef dict d cdef Py_ssize_t n = P.ngens() cdef ExteriorAlgebraElement rhs = other + cdef list to_remove cdef FrozenBitset ml, mr, t cdef Py_ssize_t num_cross, tot_cross, i, j + ml = FrozenBitset() + + if ml in self._monomial_coefficients: + const_coeff = self._monomial_coefficients[ml] + d = dict(rhs._monomial_coefficients) # Make a shallow copy + to_remove = [] + if const_coeff != P._base.one(): + for k in d: + d[k] *= const_coeff + if not d[k]: # there might be zero divisors + to_remove.append(k) + for k in to_remove: + del d[k] + else: + d = {} + for ml,cl in self._monomial_coefficients.items(): # ml for "monomial on the left" + if not ml: # We already handled the trivial element + continue for mr,cr in rhs._monomial_coefficients.items(): # mr for "monomial on the right" - if ml.intersection(mr): - # if they intersect nontrivially, move along. - continue - if not mr: t = ml else: + if not ml.isdisjoint(mr): + # if they intersect nontrivially, move along. + continue t = ml._union(mr) it = iter(mr) j = next(it) From 50216044e804c7dd8c5eed8050598adb45cbfe9a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Aug 2022 18:31:16 -0700 Subject: [PATCH 259/591] src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx: Reformat algorithm, avoid unicode symbols (fixup) --- .../combinatorial_polyhedron/face_iterator.pyx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 4fe24c3d45b..f1885cb4873 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -1484,7 +1484,7 @@ cdef class FaceIterator(FaceIterator_base): while facets: one_face = faces.pop() maybe_new_faces = [one_face.intersection(face) for face in faces] - ... + ... At this point we claim that ``maybe_new_faces`` contains all facets of ``one_face``, which we have not visited before. @@ -1517,13 +1517,13 @@ cdef class FaceIterator(FaceIterator_base): Hence, in the following loop, an element ``face1`` in ``maybe_new_faces`` is a facet of ``one_face`` if and only if it is not contained in another facet:: - ... + ... maybe_new_faces2 = [] for i, face1 in enumerate(maybe_new_faces): if (all(not face1 < face2 for face2 in maybe_new_faces[:i]) and all(not face1 <= face2 for face2 in maybe_new_faces[i+1:])): maybe_new_faces2.append(face1) - ... + ... Now ``maybe_new_faces2`` contains only facets of ``one_face`` and some faces contained in any of ``visited_all``. @@ -1532,23 +1532,23 @@ cdef class FaceIterator(FaceIterator_base): We construct ``new_faces`` as the list of all facets of ``one_face`` not contained in any of ``visited_all``:: - ... + ... new_faces = [] for face1 in maybe_new_faces2: if all(not face1 < face2 for face2 in visited_all): new_faces.append(face1) - ... + ... By induction we can apply the algorithm, to visit all faces of ``one_face`` not contained in ``visited_all``:: - ... + ... face_iterator(new_faces, visited_all) - ... + ... Finally we visit ``one_face`` and add it to ``visited_all``:: - ... + ... visit(one_face) visited_all.append(one_face) From feec89bd1bf78ae083db9798845a95916a94a5c1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Aug 2022 18:54:02 -0700 Subject: [PATCH 260/591] src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx: Reformat algorithm, avoid unicode symbols (fixup 2) --- .../polyhedron/combinatorial_polyhedron/face_iterator.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index f1885cb4873..77cd4c79ca0 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -1493,13 +1493,13 @@ cdef class FaceIterator(FaceIterator_base): .. MATH:: - P \supset \texttt{one_face} \supset F. + P \supset \texttt{one\_face} \supset F. By the diamond property, there exists a ``second_face`` with: .. MATH:: - P \supset \texttt{second_face} \supset F. + P \supset \texttt{second\_face} \supset F. Now either ``second_face`` is not an element of ``faces``: Hence ``second_face`` is contained in one of ``visited_all``. From 3082afef02adb97c5cf46f3c96508e980d1ffe44 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Aug 2022 19:09:18 -0700 Subject: [PATCH 261/591] src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx: Reformat algorithm, avoid unicode symbols (fixup 3) --- .../combinatorial_polyhedron/face_iterator.pyx | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index 77cd4c79ca0..b8f9f0a27b0 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -1490,16 +1490,9 @@ cdef class FaceIterator(FaceIterator_base): which we have not visited before. Proof: Let `F` be a facet of ``one_face``. We have a chain: - - .. MATH:: - - P \supset \texttt{one\_face} \supset F. - - By the diamond property, there exists a ``second_face`` with: - - .. MATH:: - - P \supset \texttt{second\_face} \supset F. + `P \supset{}` ``one_face`` `{}\supset F`. + By the diamond property, there exists a ``second_face`` with + `P \supset{}` ``second_face`` `{}\supset F`. Now either ``second_face`` is not an element of ``faces``: Hence ``second_face`` is contained in one of ``visited_all``. From e7e84b73a87aac57620190aa776448f422f0c6cd Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Aug 2022 11:05:26 +0900 Subject: [PATCH 262/591] Special casing multiplication by a term. --- .../algebras/clifford_algebra_element.pxd | 4 +- .../algebras/clifford_algebra_element.pyx | 311 +++++++++++++++++- .../algebras/exterior_algebra_groebner.pyx | 29 +- 3 files changed, 322 insertions(+), 22 deletions(-) diff --git a/src/sage/algebras/clifford_algebra_element.pxd b/src/sage/algebras/clifford_algebra_element.pxd index a274f65205a..64ac7253351 100644 --- a/src/sage/algebras/clifford_algebra_element.pxd +++ b/src/sage/algebras/clifford_algebra_element.pxd @@ -3,9 +3,11 @@ Clifford algebra elements """ from sage.modules.with_basis.indexed_element cimport IndexedFreeModuleElement +from sage.data_structures.bitset cimport FrozenBitset cdef class CliffordAlgebraElement(IndexedFreeModuleElement): - pass + cdef CliffordAlgebraElement _mul_self_term(self, FrozenBitset supp, coeff) + cdef CliffordAlgebraElement _mul_term_self(self, FrozenBitset supp, coeff) cdef class ExteriorAlgebraElement(CliffordAlgebraElement): pass diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index f2a6e09ad86..e065b6b70b9 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -19,8 +19,9 @@ AUTHORS: #***************************************************************************** from sage.structure.parent cimport Parent -from sage.data_structures.bitset cimport FrozenBitset, Bitset +from sage.data_structures.bitset cimport Bitset from sage.algebras.weyl_algebra import repr_from_monomials +from sage.data_structures.blas_dict cimport scal from copy import copy cdef class CliffordAlgebraElement(IndexedFreeModuleElement): @@ -95,8 +96,25 @@ cdef class CliffordAlgebraElement(IndexedFreeModuleElement): cdef dict next_level, cur, d = {} cdef FrozenBitset ml, mr, t cdef Py_ssize_t i, j + cdef CliffordAlgebraElement rhs = other - for ml,cl in self: + # Special case when multiplying by 0 + if not self._monomial_coefficients: + return self + if not rhs._monomial_coefficients: + return rhs + + # Special case when multiplying by an element of the base ring + if len(self._monomial_coefficients) == 1: + ml, cl = next(iter(self._monomial_coefficients.items())) + if ml.isempty(): + return rhs._mul_term_self(ml, cl) + if len(rhs._monomial_coefficients) == 1: + mr, cr = next(iter(self._monomial_coefficients.items())) + if mr.isempty(): + return self._mul_self_term(mr, cr) + + for ml, cl in self: # Distribute the current term ``cl`` * ``ml`` over ``other``. cur = copy(other._monomial_coefficients) # The current distribution of the term for i in reversed(ml): @@ -150,6 +168,76 @@ cdef class CliffordAlgebraElement(IndexedFreeModuleElement): return self.__class__(self.parent(), d) + cdef CliffordAlgebraElement _mul_self_term(self, FrozenBitset supp, coeff): + r""" + Multiply ``self * term`` with the ``term`` having support ``supp`` + and coefficient ``coeff``. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: r = sum(E.basis()) + sage: x * y # indirect doctest + x*y + sage: y * x # indirect doctest + -x*y + sage: r * x # indirect doctest + x*y*z - x*y - x*z + x + sage: r * -x # indirect doctest + -x*y*z + x*y + x*z - x + sage: r * (2*x) # indirect doctest + 2*x*y*z - 2*x*y - 2*x*z + 2*x + sage: r * y # indirect doctest + -x*y*z + x*y - y*z + y + sage: r * z # indirect doctest + x*y*z + x*z + y*z + z + sage: r * (x*y) # indirect doctest + x*y*z + x*y + sage: r * (-x*y) # indirect doctest + -x*y*z - x*y + sage: r * (x*y*z) # indirect doctest + x*y*z + sage: r * 1 == r # indirect doctest + True + sage: r * -1 == -r # indirect doctest + True + sage: r * 2 # indirect doctest + 2*x*y*z + 2*x*y + 2*x*z + 2*y*z + 2*x + 2*y + 2*z + 2 + """ + cdef dict d + cdef list to_remove + cdef Py_ssize_t num_cross, tot_cross, i, j + cdef FrozenBitset ml + + if supp.isempty(): # Multiplication by a base ring element + if coeff == self._parent._base.one(): + return self + if coeff == -self._parent._base.one(): + return self._neg_() + + return type(self)(self._parent, + scal(coeff, self._monomial_coefficients, + factor_on_left=False)) + + return type(self)(self._parent, {supp: coeff}) * self + + cdef CliffordAlgebraElement _mul_term_self(self, FrozenBitset supp, coeff): + r""" + Multiply ``term * self`` with the ``term`` having support ``supp`` + and coefficient ``coeff``. + """ + if supp.isempty(): # Multiplication by a base ring element + if coeff == self._parent._base.one(): + return self + if coeff == -self._parent._base.one(): + return self._neg_() + + return type(self)(self._parent, + scal(coeff, self._monomial_coefficients, + factor_on_left=True)) + + return type(self)(self._parent, {supp: coeff}) * self + def list(self): """ Return the list of monomials and their coefficients in ``self`` @@ -352,15 +440,30 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): cdef Parent P = self._parent zero = P._base.zero() cdef dict d - cdef Py_ssize_t n = P.ngens() cdef ExteriorAlgebraElement rhs = other cdef list to_remove cdef FrozenBitset ml, mr, t - cdef Py_ssize_t num_cross, tot_cross, i, j + cdef Py_ssize_t n, num_cross, tot_cross, i, j - ml = FrozenBitset() + # Special case: one of them is zero + if not self._monomial_coefficients: + return self + if not rhs._monomial_coefficients: + return rhs + + # Special case: other is a single term + if len(rhs._monomial_coefficients) == 1: + mr, cr = next(iter(rhs._monomial_coefficients.items())) + return self._mul_self_term(mr, cr) + # Special case: self is a single term + if len(self._monomial_coefficients) == 1: + ml, cl = next(iter(self._monomial_coefficients.items())) + return rhs._mul_term_self(ml, cl) + + # Do some special processing for the constant monomial in ml + ml = FrozenBitset() if ml in self._monomial_coefficients: const_coeff = self._monomial_coefficients[ml] d = dict(rhs._monomial_coefficients) # Make a shallow copy @@ -375,11 +478,12 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): else: d = {} - for ml,cl in self._monomial_coefficients.items(): # ml for "monomial on the left" - if not ml: # We already handled the trivial element + n = P.ngens() + for ml, cl in self._monomial_coefficients.items(): # ml for "monomial on the left" + if ml.isempty(): # We already handled the trivial element continue for mr,cr in rhs._monomial_coefficients.items(): # mr for "monomial on the right" - if not mr: + if mr.isempty(): t = ml else: if not ml.isdisjoint(mr): @@ -402,12 +506,199 @@ cdef class ExteriorAlgebraElement(CliffordAlgebraElement): if tot_cross % 2: cr = -cr - d[t] = d.get(t, zero) + cl * cr - if not d[t]: + val = d.get(t, zero) + cl * cr + if not val: del d[t] + else: + d[t] = val return self.__class__(P, d) + cdef CliffordAlgebraElement _mul_self_term(self, FrozenBitset supp, coeff): + r""" + Multiply ``self * term`` with the ``term`` having support ``supp`` + and coefficient ``coeff``. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: r = sum(E.basis()) + sage: x * y # indirect doctest + x*y + sage: y * x # indirect doctest + -x*y + sage: r * x # indirect doctest + x*y*z - x*y - x*z + x + sage: r * -x # indirect doctest + -x*y*z + x*y + x*z - x + sage: r * (2*x) # indirect doctest + 2*x*y*z - 2*x*y - 2*x*z + 2*x + sage: r * y # indirect doctest + -x*y*z + x*y - y*z + y + sage: r * z # indirect doctest + x*y*z + x*z + y*z + z + sage: r * (x*y) # indirect doctest + x*y*z + x*y + sage: r * (-x*y) # indirect doctest + -x*y*z - x*y + sage: r * (x*y*z) # indirect doctest + x*y*z + sage: r * 1 == r # indirect doctest + True + sage: r * -1 == -r # indirect doctest + True + sage: r * 2 # indirect doctest + 2*x*y*z + 2*x*y + 2*x*z + 2*y*z + 2*x + 2*y + 2*z + 2 + """ + cdef dict d + cdef list to_remove + cdef Py_ssize_t num_cross, tot_cross, i, j + cdef FrozenBitset ml + + if supp.isempty(): # Multiplication by a base ring element + if coeff == self._parent._base.one(): + return self + if coeff == -self._parent._base.one(): + return self._neg_() + + return type(self)(self._parent, + scal(coeff, self._monomial_coefficients, + factor_on_left=False)) + + n = self._parent.ngens() + d = {} + for ml, cl in self._monomial_coefficients.items(): # ml for "monomial on the left" + if not ml.isdisjoint(supp): + # if they intersect nontrivially, move along. + continue + t = ml._union(supp) + it = iter(supp) + j = next(it) + + num_cross = 0 # keep track of the number of signs + tot_cross = 0 + for i in ml: + while i > j: + num_cross += 1 + try: + j = next(it) + except StopIteration: + j = n + 1 + tot_cross += num_cross + if tot_cross % 2: + d[t] = -cl + else: + d[t] = cl + + if coeff == -self._parent._base.one(): + for k in d: + d[k] = -d[k] + elif coeff != self._parent._base.one(): + to_remove = [] + for k in d: + d[k] *= coeff + if not d[k]: # there might be zero divisors + to_remove.append(k) + for k in to_remove: + del d[k] + return type(self)(self._parent, d) + + cdef CliffordAlgebraElement _mul_term_self(self, FrozenBitset supp, coeff): + r""" + Multiply ``term * self`` with the ``term`` having support ``supp`` + and coefficient ``coeff``. + + EXAMPLES:: + + sage: E. = ExteriorAlgebra(QQ) + sage: r = sum(E.basis()) + sage: x * r # indirect doctest + x*y*z + x*y + x*z + x + sage: (-x) * r # indirect doctest + -x*y*z - x*y - x*z - x + sage: (2*x) * r # indirect doctest + 2*x*y*z + 2*x*y + 2*x*z + 2*x + sage: y * r # indirect doctest + -x*y*z - x*y + y*z + y + sage: z * r # indirect doctest + x*y*z - x*z - y*z + z + sage: (x*y) * r # indirect doctest + x*y*z + x*y + sage: (-x*y) * r # indirect doctest + -x*y*z - x*y + sage: (x*y*z) * r # indirect doctest + x*y*z + sage: 1 * r == r # indirect doctest + True + sage: -1 * r == -r # indirect doctest + True + sage: 2 * r # indirect doctest + 2*x*y*z + 2*x*y + 2*x*z + 2*y*z + 2*x + 2*y + 2*z + 2 + """ + cdef dict d + cdef list to_remove + cdef Py_ssize_t n, num_cross, tot_cross, i, j + cdef FrozenBitset mr, t + + if supp.isempty(): # Multiplication by a base ring element + if coeff == self._parent._base.one(): + return self + if coeff == -self._parent._base.one(): + return self._neg_() + + return type(self)(self._parent, + scal(coeff, self._monomial_coefficients, + factor_on_left=True)) + + n = self._parent.ngens() + d = {} + mr = FrozenBitset() + # We need to special case the constant coefficient + const_coeff = None + if mr in self._monomial_coefficients: + const_coeff = self._monomial_coefficients.pop(mr) + d[supp] = const_coeff + + for mr, cr in self._monomial_coefficients.items(): # mr for "monomial on the right" + if not supp.isdisjoint(mr): + # if they intersect nontrivially, move along. + continue + t = supp._union(mr) + it = iter(mr) + j = next(it) # We assume mr is non-empty here + + num_cross = 0 # keep track of the number of signs + tot_cross = 0 + for i in supp: + while i > j: + num_cross += 1 + try: + j = next(it) + except StopIteration: + j = n + 1 + tot_cross += num_cross + if tot_cross % 2: + d[t] = -cr + else: + d[t] = cr + + if coeff == -self._parent._base.one(): + for k in d: + d[k] = -d[k] + elif coeff != self._parent._base.one(): + to_remove = [] + for k in d: + d[k] = coeff * d[k] # This will work for non-commutative base rings + if not d[k]: # there might be zero divisors + to_remove.append(k) + for k in to_remove: + del d[k] + + # Add back the constant coefficient since we removed it for the special case + if const_coeff is not None: + self._monomial_coefficients[FrozenBitset()] = const_coeff + return type(self)(self._parent, d) + def reduce(self, I, left=True): r""" Reduce ``self`` with respect to the elements in ``I``. diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 5a0ce6ccb6c..ad514216abb 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -26,6 +26,7 @@ from sage.data_structures.bitset_base cimport (bitset_t, bitset_init, bitset_fir bitset_next, bitset_set_to, bitset_len) from sage.structure.parent cimport Parent from sage.structure.richcmp cimport richcmp +from sage.data_structures.blas_dict cimport iaxpy, remove_zeros cdef inline long degree(FrozenBitset X): """ @@ -143,9 +144,9 @@ cdef class GroebnerStrategy: This assumes the leading support is ``f.ls._union(t)``. """ - ret = f.elt * build_monomial(self.E, t) + ret = f.elt._mul_self_term(self.E, self.E._base.one()) cdef FrozenBitset ls = f.ls._union(t) - return GBElement(ret, ls, self.bitset_to_int(ls)) + return GBElement( ret, ls, self.bitset_to_int(ls)) cdef inline GBElement prod_term_GB(self, FrozenBitset t, GBElement f): """ @@ -155,9 +156,9 @@ cdef class GroebnerStrategy: This assumes the leading support is ``f.ls._union(t)``. """ - ret = build_monomial(self.E, t) * f.elt + ret = f.elt._mul_term_self(t, self.E._base.one()) cdef FrozenBitset ls = f.ls._union(t) - return GBElement(ret, ls, self.bitset_to_int(ls)) + return GBElement( ret, ls, self.bitset_to_int(ls)) cdef inline bint build_S_poly(self, GBElement f, GBElement g): r""" @@ -195,7 +196,8 @@ cdef class GroebnerStrategy: if self.side == 2 and not self.homogeneous: # Add in all S-poly times positive degree monomials - additions = set(( f).elt * t for t in self.E.basis() for f in L) + one = self.E._base.one() + additions = set(( f).elt._mul_self_term(t, one) for t in self.E._indices for f in L) L.update(self.build_elt(f) for f in additions if f) cdef set done = set(( f).ls for f in L) @@ -272,7 +274,8 @@ cdef class GroebnerStrategy: if self.side == 2 and not self.homogeneous: # Add in all S-poly times positive degree monomials - additions = set(( f0).elt * t for t in self.E.basis() for f0 in G) + one = self.E._base.one() + additions = set(( f0).elt._mul_self_term(t, one) for t in self.E._indices for f0 in G) G.extend(self.build_elt(f) for f in additions if f) cdef Py_ssize_t n = len(G) @@ -420,20 +423,24 @@ cdef class GroebnerStrategy: cdef FrozenBitset lm = self.leading_support(g), s cdef bint did_reduction = True cdef tuple supp + cdef CliffordAlgebraElement gp + one = self.E._base.one() while did_reduction: supp = tuple(f._monomial_coefficients) did_reduction = False for s in supp: if lm <= s: did_reduction = True - mon = build_monomial(self.E, s - lm) if self.side == 0: - gp = mon * g - f -= f[s] / gp[s] * gp + gp = g._mul_term_self(s - lm, one) else: - gp = g * mon - f -= f[s] / gp[s] * gp + gp = g._mul_self_term(s - lm, one) + coeff = f[s] / gp._monomial_coefficients[s] + for k in gp._monomial_coefficients: + gp._monomial_coefficients[k] *= coeff + remove_zeros(gp._monomial_coefficients) + f -= gp break return f From 36b6b201b9be9350b284653cd21dcac55d461b71 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 9 Aug 2022 12:18:51 +0900 Subject: [PATCH 263/591] Doing reduction in place; being careful about duplicates. --- src/sage/algebras/clifford_algebra.py | 2 +- .../algebras/exterior_algebra_groebner.pxd | 2 +- .../algebras/exterior_algebra_groebner.pyx | 143 ++++++++++++++---- 3 files changed, 112 insertions(+), 35 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 85b6e902f0d..0def7ae087b 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -2946,7 +2946,7 @@ def groebner_basis(self, term_order=None, reduced=True): sage: E. = ExteriorAlgebra(QQ) sage: I = E.ideal([x+y*z]) sage: I.groebner_basis(reduced=False) - (x*y, x*z, y*z + x, y*z + x, x*y*z) + (x*y, x*z, y*z + x, x*y*z) sage: I.groebner_basis(reduced=True) (x*y, x*z, y*z + x) diff --git a/src/sage/algebras/exterior_algebra_groebner.pxd b/src/sage/algebras/exterior_algebra_groebner.pxd index 0c001363130..d00fb2e8560 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pxd +++ b/src/sage/algebras/exterior_algebra_groebner.pxd @@ -37,7 +37,7 @@ cdef class GroebnerStrategy: cdef list reduction(self, list P, list G) cpdef CliffordAlgebraElement reduce(self, CliffordAlgebraElement f) - cdef CliffordAlgebraElement reduce_single(self, CliffordAlgebraElement f, CliffordAlgebraElement g) + cdef bint reduce_single(self, CliffordAlgebraElement f, CliffordAlgebraElement g) except -1 cdef int reduced_gb(self, list G) except -1 # These are the methods that determine the ordering of the monomials. diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index ad514216abb..98e338d3468 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -25,8 +25,9 @@ from sage.libs.gmp.mpz cimport mpz_sizeinbase, mpz_setbit, mpz_tstbit, mpz_cmp_s from sage.data_structures.bitset_base cimport (bitset_t, bitset_init, bitset_first, bitset_next, bitset_set_to, bitset_len) from sage.structure.parent cimport Parent -from sage.structure.richcmp cimport richcmp -from sage.data_structures.blas_dict cimport iaxpy, remove_zeros +from sage.structure.richcmp cimport richcmp, rich_to_bool +from sage.data_structures.blas_dict cimport iaxpy +from copy import copy cdef inline long degree(FrozenBitset X): """ @@ -42,16 +43,59 @@ cdef inline CliffordAlgebraElement build_monomial(Parent E, FrozenBitset supp): return E.element_class(E, {supp: E._base.one()}) cdef class GBElement: + """ + Helper class for storing an element with its leading support both as + a :class:`FrozenBitset` and an :class:`Integer`. + """ def __init__(self, CliffordAlgebraElement x, FrozenBitset ls, Integer n): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.algebras.exterior_algebra_groebner import GBElement + sage: E. = ExteriorAlgebra(QQ) + sage: X = GBElement(a, a.leading_support(), 1) + sage: TestSuite(X).run(skip="_test_pickling") + """ self.elt = x self.ls = ls self.lsi = n def __hash__(self): + """ + Return the hash of ``self``. + + EXAMPLES:: + + sage: from sage.algebras.exterior_algebra_groebner import GBElement + sage: E. = ExteriorAlgebra(QQ) + sage: X = GBElement(a, a.leading_support(), 1) + sage: hash(X) == 1 + True + """ return int(self.lsi) def __richcmp__(self, other, int op): - return richcmp(self.elt, ( other).elt, op) + """ + Rich compare ``self`` with ``other`` by ``op``. + + EXAMPLES:: + + sage: from sage.algebras.exterior_algebra_groebner import GBElement + sage: E. = ExteriorAlgebra(QQ) + sage: X = GBElement(a, a.leading_support(), 1) + sage: Y = GBElement(a*b, (a*b).leading_support(), 3) + sage: X == X + True + sage: X == Y + False + sage: X != Y + True + """ + if self is other: + return rich_to_bool(op, 0) + return richcmp(self.elt, ( other).elt, op) cdef class GroebnerStrategy: """ @@ -268,15 +312,38 @@ cdef class GroebnerStrategy: cdef Py_ssize_t i, j, k cdef set additions cdef GBElement f0, f1 - cdef list G = [self.build_elt(f) for f in self.ideal.gens() if f] # Remove 0s - cdef list Gp + cdef list G = [], Gp + cdef dict constructed = {} cdef CliffordAlgebraElement f + for f in self.ideal.gens(): + if not f: # Remove 0s + continue + f0 = self.build_elt(f) + if f0.lsi in constructed: + if f0 in constructed[f0.lsi]: # Already there + continue + constructed[f0.lsi].add(f0) + else: + constructed[f0.lsi] = set([f0]) + G.append(f0) + if self.side == 2 and not self.homogeneous: # Add in all S-poly times positive degree monomials one = self.E._base.one() - additions = set(( f0).elt._mul_self_term(t, one) for t in self.E._indices for f0 in G) - G.extend(self.build_elt(f) for f in additions if f) + for t in self.E._indices: + for f0 in G: + f = f0.elt._mul_self_term(t, one) + if not f: + continue + f1 = self.build_elt(f) + if f1.lsi in constructed: + if f1 in constructed[f1.lsi]: # Already there + continue + constructed[f1.lsi].add(f1) + else: + constructed[f1.lsi] = set([f1]) + G.append(f1) cdef Py_ssize_t n = len(G) cdef dict P = {} @@ -297,7 +364,16 @@ cdef class GroebnerStrategy: sig_check() Pp = P.pop(min(P)) # The selection: lowest lcm degree Gp = self.reduction(Pp, G) - G.extend(Gp) + # Add the elements Gp to G when a new element is found + for f0 in Gp: + if f0.lsi in constructed: + if f0 in constructed[f0.lsi]: # Already there + continue + constructed[f0.lsi].add(f0) + else: + constructed[f0.lsi] = set([f0]) + G.append(f0) + # Find the degress of the new pairs for j in range(n, len(G)): f1 = G[j] p1 = f1.ls @@ -339,15 +415,15 @@ cdef class GroebnerStrategy: i,j = pairs.pop() f0 = G[i] f1 = G[j] + assert f0.elt._monomial_coefficients is not f1.elt._monomial_coefficients, (i,j) # We perform the classical reduction algorithm here on each pair # TODO: Make this faster by using the previous technique? - f = self.reduce_single(f0.elt, f1.elt) - if f0.elt != f: - if f: - G[i] = self.build_elt(f) + if self.reduce_single(f0.elt, f1.elt): + if f0.elt: + G[i] = self.build_elt(f0.elt) pairs.update((k, i) for k in range(n) if k != i) else: - G[i] = GBElement(f, FrozenBitset(), Integer(2)**self.rank + 1) + G[i] = GBElement(f0.elt, FrozenBitset(), Integer(2)**self.rank + 1) num_zeros += 1 pairs.difference_update((k, i) for k in range(n) if k != i) pairs.difference_update((i, k) for k in range(n) if k != i) @@ -369,7 +445,7 @@ cdef class GroebnerStrategy: sage: E. = ExteriorAlgebra(QQ) sage: I = E.ideal([x+y*z]) sage: I.groebner_basis(reduced=False) - (x*y, x*z, y*z + x, y*z + x, x*y*z) + (x*y, x*z, y*z + x, x*y*z) sage: I._groebner_strategy.reduce_computed_gb() sage: I._groebner_strategy.groebner_basis (x*y, x*z, y*z + x) @@ -408,41 +484,42 @@ cdef class GroebnerStrategy: """ if not f: return f + # Make a copy to mutate + f = type(f)(f._parent, copy(f._monomial_coefficients)) for g in self.groebner_basis: - f = self.reduce_single(f, g) + self.reduce_single(f, g) return f - cdef CliffordAlgebraElement reduce_single(self, CliffordAlgebraElement f, CliffordAlgebraElement g): + cdef bint reduce_single(self, CliffordAlgebraElement f, CliffordAlgebraElement g) except -1: r""" Reduce ``f`` by ``g``. - .. TODO:: + .. WARNING:: - Optimize this by doing it in-place and changing the underlying dict of ``f``. + This modifies the element ``f``. """ - cdef FrozenBitset lm = self.leading_support(g), s - cdef bint did_reduction = True + cdef FrozenBitset lm = self.leading_support(g), s, t + cdef bint did_reduction = True, was_reduced=False cdef tuple supp cdef CliffordAlgebraElement gp one = self.E._base.one() while did_reduction: - supp = tuple(f._monomial_coefficients) did_reduction = False - for s in supp: - if lm <= s: + for s in f._monomial_coefficients: + if lm.issubset(s): + t = s did_reduction = True - if self.side == 0: - gp = g._mul_term_self(s - lm, one) - else: - gp = g._mul_self_term(s - lm, one) - coeff = f[s] / gp._monomial_coefficients[s] - for k in gp._monomial_coefficients: - gp._monomial_coefficients[k] *= coeff - remove_zeros(gp._monomial_coefficients) - f -= gp + was_reduced = True break - return f + if did_reduction: + if self.side == 0: + gp = g._mul_term_self(t - lm, one) + else: + gp = g._mul_self_term(t - lm, one) + coeff = f[t] / gp._monomial_coefficients[t] + iaxpy(-coeff, gp._monomial_coefficients, f._monomial_coefficients) + return was_reduced cdef Integer bitset_to_int(self, FrozenBitset X): From b2f1e2d7ed02408226bbb90a1545ef36348130dd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 6 Mar 2022 22:41:10 -0800 Subject: [PATCH 264/591] build/pkgs/modular_resolution: New, split from p_group_cohomology --- build/pkgs/modular_resolution/SPKG.rst | 115 ++++++++++++++++++ build/pkgs/modular_resolution/checksums.ini | 1 + .../modular_resolution/package-version.txt | 1 + build/pkgs/modular_resolution/spkg-install.in | 7 ++ build/pkgs/modular_resolution/type | 1 + 5 files changed, 125 insertions(+) create mode 100644 build/pkgs/modular_resolution/SPKG.rst create mode 120000 build/pkgs/modular_resolution/checksums.ini create mode 120000 build/pkgs/modular_resolution/package-version.txt create mode 100644 build/pkgs/modular_resolution/spkg-install.in create mode 100644 build/pkgs/modular_resolution/type diff --git a/build/pkgs/modular_resolution/SPKG.rst b/build/pkgs/modular_resolution/SPKG.rst new file mode 100644 index 00000000000..22c3f90f0fe --- /dev/null +++ b/build/pkgs/modular_resolution/SPKG.rst @@ -0,0 +1,115 @@ +p_group_cohomology: Modular cohomology rings of finite groups +============================================================= + +Description +----------- + +Modular Cohomology Rings of Finite Groups + +The package is located at http://users.fmi.uni-jena.de/cohomology/, +that's to say the tarball p_group_cohomology-x.y.tar.xz can be found +there and the documentation of the package is provided at +http://users.fmi.uni-jena.de/cohomology/documentation/ + +License +------- + +Copyright (C) 2018 Simon A. King Copyright (C) +2011 Simon A. King Copyright (C) 2009 Simon A. +King and + + David J. Green + +Distributed under the terms of the GNU General Public License (GPL), +version 2 or later (at your choice). + + 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/ + +The package includes a data base of cohomology rings of the groups of +order 64 and provides access to a data base of cohomology rings of the +groups of order 128 and 243, located at + + http://cohomology.uni-jena.de/db/ + +These data bases are distributed under the Creative Commons +Attribution-Share Alike 3.0 License. The full text of this licence is +available at + + http://creativecommons.org/licenses/by-sa/3.0/ + + +SPKG Maintainers +---------------- + +Simon A. King + + +Upstream Contact +---------------- + +Simon A. King David J. Green + + +Acknowledgements +---------------- + +The development of the initial version of this SPKG was funded by the +German Science Foundation, DFG project GR 1585/4.1, and was accomplished +at the Friedrich Schiller University Jena. + +Since version 1.0.1, the further work on this SPKG was funded by Marie +Curie grant MTKD-CT-2006-042685 and was pursued at the National +University of Ireland, Galway. Since Novermber 2010, it is moved back to +Jena. + +We thank William Stein for giving us access to various computers on +which we could build test the SPKG and on which some huge computations +could be completed, and acknowledge the support by National Science +Foundation Grant No. DMS-0821725. + +We thank Mathieu Dutour Sikirić for hints on how to use GAP more +efficiently. + +We owe Peter Symonds the idea of using the Poincaré series in a rather +efficient completeness criterion. + +We are greatful to John Palmieri for his help on making +p_group_cohomology work with python-3. + +Dependencies +------------ + +- The SharedMeatAxe needs to be installed, as a build time dependency. + + This can be met by installing the meataxe spkg + +Testing +------- + +Our package provides a very short test suite for David Green's routines +for the computation of minimal projective resolutions. The majority of +this package's tests is formed by doc tests in the Cython code. In fact, +any class, method and function is covered by tests. + +Note that internet access is required for these tests, as it is +attempted to download cohomology rings from a public data base in the +web. + +The script ``spkg-check`` calls ``sage -t --force_lib`` on the files +in ``pGroupCohomology``. + +Documentation +------------- + +The documentation of this package is automatically built, if the +environment variable SAGE_SPKG_INSTALL_DOCS is yes (do "export +SAGE_SPKG_INSTALL_DOCS=yes" on the command line before installation). +The documents are put into +SAGE_ROOT/local/share/doc/p_group_cohomology/. diff --git a/build/pkgs/modular_resolution/checksums.ini b/build/pkgs/modular_resolution/checksums.ini new file mode 120000 index 00000000000..c94028a71ef --- /dev/null +++ b/build/pkgs/modular_resolution/checksums.ini @@ -0,0 +1 @@ +../p_group_cohomology/checksums.ini \ No newline at end of file diff --git a/build/pkgs/modular_resolution/package-version.txt b/build/pkgs/modular_resolution/package-version.txt new file mode 120000 index 00000000000..819a4a33206 --- /dev/null +++ b/build/pkgs/modular_resolution/package-version.txt @@ -0,0 +1 @@ +../p_group_cohomology/package-version.txt \ No newline at end of file diff --git a/build/pkgs/modular_resolution/spkg-install.in b/build/pkgs/modular_resolution/spkg-install.in new file mode 100644 index 00000000000..7642045ed5e --- /dev/null +++ b/build/pkgs/modular_resolution/spkg-install.in @@ -0,0 +1,7 @@ +cd src + +# build and install modular_resolution +cd `ls -d modular_resolution*` +sdh_configure || sdh_die "Error configuring modular_resolution" +# sdh_make install got broken by trac ticket #24106 +$MAKE install || sdh_die "Error installing modular_resolution" diff --git a/build/pkgs/modular_resolution/type b/build/pkgs/modular_resolution/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/modular_resolution/type @@ -0,0 +1 @@ +optional From 6852530e1db69f47b532022e28de64bb29085ad8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 6 Mar 2022 23:09:42 -0800 Subject: [PATCH 265/591] build/pkgs/{p_group_cohomology,modular_resolution}: First attempt at dependencies --- build/pkgs/p_group_cohomology/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/p_group_cohomology/dependencies b/build/pkgs/p_group_cohomology/dependencies index 9492937c0f8..a9d113183c5 100644 --- a/build/pkgs/p_group_cohomology/dependencies +++ b/build/pkgs/p_group_cohomology/dependencies @@ -1 +1 @@ -$(PYTHON) cython cysignals singular meataxe $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/structure/element.pxd $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/matrix/matrix0.pxd $(SAGE_SRC)/sage/libs/meataxe.pxd $(SAGE_SRC)/sage/rings/morphism.pxd | $(PYTHON_TOOLCHAIN) matplotlib gap xz $(SAGERUNTIME) ipywidgets +$(PYTHON) cython cysignals singular meataxe modular_resolution $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/structure/element.pxd $(SAGE_SRC)/sage/matrix/matrix_gfpn_dense.pxd $(SAGE_SRC)/sage/matrix/matrix0.pxd $(SAGE_SRC)/sage/libs/meataxe.pxd $(SAGE_SRC)/sage/rings/morphism.pxd | $(PYTHON_TOOLCHAIN) matplotlib gap xz $(SAGERUNTIME) ipywidgets From 78b64f63b8f597c3f48387ab3ed6d6ce2408eee3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 6 Mar 2022 23:16:04 -0800 Subject: [PATCH 266/591] build/pkgs/p_group_cohomology/spkg-install.in: Remove installation of modular_resolution --- build/pkgs/p_group_cohomology/spkg-install.in | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/build/pkgs/p_group_cohomology/spkg-install.in b/build/pkgs/p_group_cohomology/spkg-install.in index dc312069886..5b785e4ba6d 100644 --- a/build/pkgs/p_group_cohomology/spkg-install.in +++ b/build/pkgs/p_group_cohomology/spkg-install.in @@ -1,15 +1,5 @@ -# Check if meataxe was properly installed -sage -c "import sage.libs.meataxe" || sdh_die "sage.libs.meataxe cannot be imported. To solve this, it is enough to retry installation of p_group_cohomology" - cd src -# build and install modular_resolution -cd `ls -d modular_resolution*` -sdh_configure || sdh_die "Error configuring modular_resolution" -# sdh_make install got broken by trac ticket #24106 -$MAKE install || sdh_die "Error installing modular_resolution" -cd .. - # install helper modules sdh_install gap_helper "$SAGE_SHARE/gap/pkg/p_group_cohomology_helper" || sdh_die "Error installing GAP helper module" sdh_install singular_helper/dickson.lib "$SAGE_SHARE/singular/LIB/" || sdh_die "Error installing Singular helper module" From b92d9cab4db235f0282ba65adabd7f3fed441485 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 7 Mar 2022 13:13:12 +0000 Subject: [PATCH 267/591] move installing GAP and Singular files to spkg-postinstall apparently spkg_pip_install does not mix well in one script with spkg_install --- build/pkgs/p_group_cohomology/spkg-install.in | 8 +------- build/pkgs/p_group_cohomology/spkg-postinst.in | 9 ++++++++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/build/pkgs/p_group_cohomology/spkg-install.in b/build/pkgs/p_group_cohomology/spkg-install.in index 5b785e4ba6d..359015fd37c 100644 --- a/build/pkgs/p_group_cohomology/spkg-install.in +++ b/build/pkgs/p_group_cohomology/spkg-install.in @@ -1,9 +1,3 @@ -cd src - -# install helper modules -sdh_install gap_helper "$SAGE_SHARE/gap/pkg/p_group_cohomology_helper" || sdh_die "Error installing GAP helper module" -sdh_install singular_helper/dickson.lib "$SAGE_SHARE/singular/LIB/" || sdh_die "Error installing Singular helper module" - # building pGroupCohomology -cd `ls -d pGroupCohomology*` +cd `ls -d src/pGroupCohomology*` sdh_pip_install . diff --git a/build/pkgs/p_group_cohomology/spkg-postinst.in b/build/pkgs/p_group_cohomology/spkg-postinst.in index 34bd835ef85..bb0ada84357 100644 --- a/build/pkgs/p_group_cohomology/spkg-postinst.in +++ b/build/pkgs/p_group_cohomology/spkg-postinst.in @@ -1,7 +1,14 @@ +cd src + +# install helper modules +mv gap_helper p_group_cohomology_helper +sdh_install p_group_cohomology_helper "$SAGE_SHARE/gap/pkg" || sdh_die "Error installing GAP helper module" +sdh_install singular_helper/dickson.lib "$SAGE_SHARE/singular/LIB/" || sdh_die "Error installing Singular helper module" + # building pGroupCohomology's documentation if [ "x$SAGE_SPKG_INSTALL_DOCS" = xyes ] ; then - cd `ls -d src/pGroupCohomology*/doc` + cd `ls -d pGroupCohomology*/doc` $MAKE html || sdh_die "Error building documentation" sdh_install build/html/* "$SAGE_SHARE/doc/p_group_cohomology/" || sdh_die "Error moving documentation to $SAGE_SHARE/doc/p_group_cohomology" fi From ebc976f6fbf33e82a2d7ceb8a79530e54d5bc5d6 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 7 Mar 2022 13:48:20 +0000 Subject: [PATCH 268/591] patch to change poly.lib -> polylib.lib --- .../p_group_cohomology/package-version.txt | 2 +- .../p_group_cohomology/patches/polylib.patch | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 build/pkgs/p_group_cohomology/patches/polylib.patch diff --git a/build/pkgs/p_group_cohomology/package-version.txt b/build/pkgs/p_group_cohomology/package-version.txt index 47725433179..e5691ee639c 100644 --- a/build/pkgs/p_group_cohomology/package-version.txt +++ b/build/pkgs/p_group_cohomology/package-version.txt @@ -1 +1 @@ -3.3.2 +3.3.2.p0 diff --git a/build/pkgs/p_group_cohomology/patches/polylib.patch b/build/pkgs/p_group_cohomology/patches/polylib.patch new file mode 100644 index 00000000000..00b46afbe1b --- /dev/null +++ b/build/pkgs/p_group_cohomology/patches/polylib.patch @@ -0,0 +1,57 @@ +diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/cohomology.pyx b/pGroupCohomology-3.3.2/pGroupCohomology/cohomology.pyx +index 8e37be9..828b6a2 100644 +--- a/pGroupCohomology-3.3.2/pGroupCohomology/cohomology.pyx ++++ b/pGroupCohomology-3.3.2/pGroupCohomology/cohomology.pyx +@@ -3108,7 +3108,7 @@ class COHO(Ring): + if self.Resl.coef()!=2: # non-commutative case + singular.LIB('ncall.lib') + singular.LIB('general.lib') +- singular.LIB('poly.lib') ++ singular.LIB('polylib.lib') + singular.LIB('dickson.lib') + singular.eval('option(redSB)'); + singular.eval('int i') +@@ -3877,7 +3877,7 @@ class COHO(Ring): + if p!=2: + singular.LIB("ncall.lib") + singular.LIB('general.lib') +- singular.LIB('poly.lib') ++ singular.LIB('polylib.lib') + singular.LIB('dickson.lib') + if singular.eval('defined(i)')=='0': + singular.eval('int i') +@@ -10062,7 +10062,7 @@ is an error. Please inform the author!""") + if p!=2: + singular.LIB("ncall.lib") + singular.LIB('general.lib') +- singular.LIB('poly.lib') ++ singular.LIB('polylib.lib') + singular.LIB('dickson.lib') + from pGroupCohomology.cochain import MODCOCH + if singular.eval('defined(i)')=='0': +diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/isomorphism_test.py b/pGroupCohomology-3.3.2/pGroupCohomology/isomorphism_test.py +index 37627c4..dd2bb85 100644 +--- a/pGroupCohomology-3.3.2/pGroupCohomology/isomorphism_test.py ++++ b/pGroupCohomology-3.3.2/pGroupCohomology/isomorphism_test.py +@@ -218,7 +218,7 @@ class IsomorphismTest: + i = self.singular._next_var_name() + self.singular.eval('for (int %s=1; %s<=size(%s[2]); %s++){%s[2][%s]="@"+%s[2][%s];} kill %s;'%(i,i,L.name(),i,L.name(), i,L.name(),i,i)) + if self._domain.base_ring().characteristic()%2: +- self.singular.LIB("poly.lib") ++ self.singular.LIB("polylib.lib") + self._dim_command = 'GKdim' + #self._R_elim = self.singular('gcRingSum(ring(%s))+%s'%(L.name(),self._SD.name())) + else: +diff --git a/singular_helper/dickson.lib b/singular_helper/dickson.lib +index 3284920..dc1c69f 100644 +--- a/singular_helper/dickson.lib ++++ b/singular_helper/dickson.lib +@@ -21,7 +21,7 @@ + //***************************************************************************** + + LIB "general.lib"; +-LIB "poly.lib"; ++LIB "polylib.lib"; + //LIB "ring.lib"; // for changeord + + // Auxiliar procedure, since NF in non-commutative rings now removes zeroes from ideals: From b1d6c339f76f9be5473d8db26bdfb8193860da14 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 7 Mar 2022 15:10:25 -0800 Subject: [PATCH 269/591] build/pkgs/modular_resolution/dependencies: New --- build/pkgs/modular_resolution/dependencies | 1 + 1 file changed, 1 insertion(+) create mode 100644 build/pkgs/modular_resolution/dependencies diff --git a/build/pkgs/modular_resolution/dependencies b/build/pkgs/modular_resolution/dependencies new file mode 100644 index 00000000000..d3ad6d2cbbc --- /dev/null +++ b/build/pkgs/modular_resolution/dependencies @@ -0,0 +1 @@ +singular meataxe From ddaa6cfc6b353022ea08c9561133d0692f7ac485 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 8 Mar 2022 08:27:40 +0000 Subject: [PATCH 270/591] split spkg-check between corresponding packages --- build/pkgs/modular_resolution/spkg-check.in | 4 ++++ build/pkgs/p_group_cohomology/spkg-check.in | 6 ------ 2 files changed, 4 insertions(+), 6 deletions(-) create mode 100644 build/pkgs/modular_resolution/spkg-check.in diff --git a/build/pkgs/modular_resolution/spkg-check.in b/build/pkgs/modular_resolution/spkg-check.in new file mode 100644 index 00000000000..bdd7bb89496 --- /dev/null +++ b/build/pkgs/modular_resolution/spkg-check.in @@ -0,0 +1,4 @@ +cd src + +cd `ls -d modular_resolution*` +$MAKE check || sdh_die "Error testing modular_resolution" diff --git a/build/pkgs/p_group_cohomology/spkg-check.in b/build/pkgs/p_group_cohomology/spkg-check.in index 47b086b61df..ce0d8990676 100644 --- a/build/pkgs/p_group_cohomology/spkg-check.in +++ b/build/pkgs/p_group_cohomology/spkg-check.in @@ -1,9 +1,3 @@ cd src -# testing modular_resolution-1.1 -cd `ls -d modular_resolution*` -$MAKE check || sdh_die "Error testing modular_resolution-1.1" -cd .. - -# testing pGroupCohomology sage -tp 0 --long --force_lib --warn-long 80 --timeout=0 `ls -d pGroupCohomology*`/pGroupCohomology/ || sdh_die "Error testing pGroupCohomology" From a0962f687fd74b4ab9becdcc4f257ba423cf450c Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Tue, 8 Mar 2022 11:03:48 +0000 Subject: [PATCH 271/591] doctest patches --- .../patches/set_default_prec.patch | 32 ++++++++ .../patches/trivial_doctests.patch | 77 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 build/pkgs/p_group_cohomology/patches/set_default_prec.patch create mode 100644 build/pkgs/p_group_cohomology/patches/trivial_doctests.patch diff --git a/build/pkgs/p_group_cohomology/patches/set_default_prec.patch b/build/pkgs/p_group_cohomology/patches/set_default_prec.patch new file mode 100644 index 00000000000..ddcb2148598 --- /dev/null +++ b/build/pkgs/p_group_cohomology/patches/set_default_prec.patch @@ -0,0 +1,32 @@ +diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/barcode.py b/pGroupCohomology-3.3.2/pGroupCohomology/barcode.py +index 635aed0..291df0b 100644 +--- a/pGroupCohomology-3.3.2/pGroupCohomology/barcode.py ++++ b/pGroupCohomology-3.3.2/pGroupCohomology/barcode.py +@@ -534,7 +534,6 @@ class BarCode(object): + [ 0 0 16] + + """ +- _PSRing = PowerSeriesRing(QQ, names=['t']) + def __init__(self, L, **MetaData): + r""" + NOTE: +@@ -708,16 +707,16 @@ class BarCode(object): + [0 0 4] + + """ +- self._PSRing.set_default_prec(d+3) ++ _PSRing = PowerSeriesRing(QQ, names=['t'], default_prec=d+3) + D = {} + l = self._length + for i in range(-l,l+1): + for j in range(i,l+1): + if (i,j) in self._L: + if hasattr(self._L[i,j],'numerator'): +- D[i,j] = (self._PSRing(self._L[i,j].numerator())/self._PSRing(self._L[i,j].denominator()))[d] ++ D[i,j] = (_PSRing(self._L[i,j].numerator())/_PSRing(self._L[i,j].denominator()))[d] + else: +- D[i,j] = (self._PSRing(self._L[i,j]))[d] ++ D[i,j] = (_PSRing(self._L[i,j]))[d] + else: + D[i,j] = 0 + OUT = BarCode2d(D, **(self._Meta)) diff --git a/build/pkgs/p_group_cohomology/patches/trivial_doctests.patch b/build/pkgs/p_group_cohomology/patches/trivial_doctests.patch new file mode 100644 index 00000000000..5a5b6809247 --- /dev/null +++ b/build/pkgs/p_group_cohomology/patches/trivial_doctests.patch @@ -0,0 +1,77 @@ +diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/cochain.pyx b/pGroupCohomology-3.3.2/pGroupCohomology/cochain.pyx +index 881d59f..87174c9 100644 +--- a/pGroupCohomology-3.3.2/pGroupCohomology/cochain.pyx ++++ b/pGroupCohomology-3.3.2/pGroupCohomology/cochain.pyx +@@ -115,7 +115,7 @@ Note that the generators of ``HD`` are :class:`COCH`, while those of + formed by :class:`MODCOCH`:: + + sage: type(HD.1) +- ++ + sage: type(HS.1) + + sage: type(resS_D(HS.1)) +@@ -185,7 +185,7 @@ class COCH_unpickle_class: + sage: H.make() + sage: C=H.2 + sage: type(C) +- ++ + sage: D = loads(dumps(C)) #indirect doctest + sage: print(C) + 1-Cocycle in H^*(D8; GF(2)), +@@ -633,7 +633,7 @@ cdef class COCH(RingElement): + sage: c = H.1+H.3*H.4; c + c_2_1+(a_1_0)*(a_1_1): 2-Cocycle in H^*(SmallGroup(32,4); GF(2)) + sage: type(c) +- ++ + sage: C = c._MODCOCH_() + sage: type(C) + +@@ -1274,7 +1274,7 @@ cdef class COCH(RingElement): + sage: X = CohomologyRing(720,763,prime=2) + sage: X.make() + sage: type(X.sylow_cohomology()('c_2_5*b_1_0')) +- ++ + sage: type(X.3.as_cocycle_in_sylow()) + + sage: print(X.sylow_cohomology()('c_2_5*b_1_0')+X.3.as_cocycle_in_sylow()) +@@ -2020,7 +2020,7 @@ class MODCOCH(RingElement): + sage: H.1 + c_2_2: 2-Cocycle in H^*(D8; GF(2)) + sage: type(H.1) +- ++ + sage: from pGroupCohomology.cochain import MODCOCH + sage: c = MODCOCH(H, singular(H.1), name='foo') # indirect doctest + sage: c +diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/resolution.pyx b/pGroupCohomology-3.3.2/pGroupCohomology/resolution.pyx +index 9c07f2b..b1a4822 100644 +--- a/pGroupCohomology-3.3.2/pGroupCohomology/resolution.pyx ++++ b/pGroupCohomology-3.3.2/pGroupCohomology/resolution.pyx +@@ -1075,7 +1075,6 @@ cdef class RESL: + sage: gstem='8gp3' + sage: gps_folder=os.path.join(tmp_root,gstem) + sage: res_folder=os.path.join(gps_folder,'dat') +- sage: m=get_memory_usage() + sage: R=RESL(gstem,gps_folder,res_folder) + sage: R.nextDiff() + sage: R.nextDiff() +@@ -1108,7 +1107,6 @@ cdef class RESL: + sage: gstem='8gp3' + sage: gps_folder=os.path.join(tmp_root,gstem) + sage: res_folder=os.path.join(gps_folder,'dat') +- sage: m=get_memory_usage() + sage: R=RESL(gstem,gps_folder,res_folder) + sage: R.nextDiff() + sage: R.nextDiff() +@@ -1155,7 +1153,6 @@ cdef class RESL: + sage: gstem='8gp3' + sage: gps_folder=os.path.join(tmp_root,gstem) + sage: res_folder=os.path.join(gps_folder,'dat') +- sage: m=get_memory_usage() + sage: R=RESL(gstem,gps_folder,res_folder) + sage: R.nextDiff() + sage: R.nextDiff() From 97cbfd9fd9c69debce95b46d2a87280b74748d94 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 8 Mar 2022 10:39:46 -0800 Subject: [PATCH 272/591] build/pkgs/modular_resolution/spkg-install.in: Use sdh_make_install, remove redundant error handling --- build/pkgs/modular_resolution/spkg-install.in | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/pkgs/modular_resolution/spkg-install.in b/build/pkgs/modular_resolution/spkg-install.in index 7642045ed5e..b9fb854adec 100644 --- a/build/pkgs/modular_resolution/spkg-install.in +++ b/build/pkgs/modular_resolution/spkg-install.in @@ -2,6 +2,5 @@ cd src # build and install modular_resolution cd `ls -d modular_resolution*` -sdh_configure || sdh_die "Error configuring modular_resolution" -# sdh_make install got broken by trac ticket #24106 -$MAKE install || sdh_die "Error installing modular_resolution" +sdh_configure +sdh_make_install From 242c14754ff66e78037b3591a61abcd37d72cfa0 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Tue, 8 Mar 2022 13:57:09 -0800 Subject: [PATCH 273/591] trac 30787: fix docbuilding. Mainly use Sage's conf.py. --- .../patches/docbuild_conf.patch | 509 ++++++++++++++++++ 1 file changed, 509 insertions(+) create mode 100644 build/pkgs/p_group_cohomology/patches/docbuild_conf.patch diff --git a/build/pkgs/p_group_cohomology/patches/docbuild_conf.patch b/build/pkgs/p_group_cohomology/patches/docbuild_conf.patch new file mode 100644 index 00000000000..5fea52dddc1 --- /dev/null +++ b/build/pkgs/p_group_cohomology/patches/docbuild_conf.patch @@ -0,0 +1,509 @@ +diff --git a/pGroupCohomology-3.3.2/doc/source/conf.py.orig b/pGroupCohomology-3.3.2/doc/source/conf.py +index e24ceb6..49d8a0d 100644 +--- a/pGroupCohomology-3.3.2/doc/source/conf.py.orig ++++ b/pGroupCohomology-3.3.2/doc/source/conf.py +@@ -1,52 +1,7 @@ + # -*- coding: utf-8 -*- +-# +-# "p_group_cohomology" documentation build configuration file, created by +-# sphinx-quickstart on Wed Jan 3 00:48:45 2018. +-# +-# This file is execfile()d with the current directory set to its +-# containing dir. +-# +-# Note that not all possible configuration values are present in this +-# autogenerated file. +-# +-# All configuration values have a default; values that are commented out +-# serve to show the default. +- +-# If extensions (or modules to document with autodoc) are in another directory, +-# add these directories to sys.path here. If the directory is relative to the +-# documentation root, use os.path.abspath to make it absolute, like shown here. +-# +-import os +-import sys +-from sage.env import SAGE_DOC_SRC, SAGE_DOC, SAGE_SRC, THEBE_DIR, SAGE_SHARE +-COHO_DOC_SRC = os.path.abspath('../pGroupCohomology') ++# Mainly use Sage's conf.py. + +-sys.path.insert(0, COHO_DOC_SRC) +-sys.path.append(os.path.join(SAGE_SRC, "sage_setup", "docbuild", "ext")) +- +- +-# -- General configuration ------------------------------------------------ +- +-# If your documentation needs a minimal Sphinx version, state it here. +-# +-# needs_sphinx = '1.0' +- +-# Add any Sphinx extension module names here, as strings. They can be +-# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +-# ones. +-extensions = ['inventory_builder', +- 'sage_autodoc', +- 'sphinx.ext.intersphinx', +- 'sphinx.ext.todo'] +- +-# The suffix(es) of source filenames. +-# You can specify multiple suffix as a list of string: +-# +-# source_suffix = ['.rst', '.md'] +-source_suffix = '.rst' +- +-# The master toctree document. +-master_doc = 'index' ++from sage.docs.conf import * + + # General information about the project. + project = u'"p_group_cohomology"' +@@ -62,449 +17,9 @@ version = u'3.3.2' + # The full version, including alpha/beta/rc tags. + release = u'3.3.2' + +-# The language for content autogenerated by Sphinx. Refer to documentation +-# for a list of supported languages. +-# +-# This is also used if you do content translation via gettext catalogs. +-# Usually you set "language" from the command line for these cases. +-language = None +- +-# List of patterns, relative to source directory, that match files and +-# directories to ignore when looking for source files. +-# This patterns also effect to html_static_path and html_extra_path +-exclude_patterns = [] +- +-default_role = 'math' +- +-add_function_parentheses = True +- +-add_module_names = True +- +-# syntax highlighting +-from sphinx import highlighting +-from IPython.lib.lexers import IPythonConsoleLexer, IPyLexer +- +-pygments_style = 'sphinx' +-highlighting.lexers['ipycon'] = IPythonConsoleLexer(in1_regex=r'sage: ', in2_regex=r'[.][.][.][.]: ') +-highlighting.lexers['ipython'] = IPyLexer() +-highlight_language = 'ipycon' +- +- +-# If true, `todo` and `todoList` produce output, else they produce nothing. +-todo_include_todos = True +- +-# Cross-links to other project's online documentation. +-intersphinx_mapping = { +- 'python' : ('https://docs.python.org/', +- os.path.join(SAGE_DOC_SRC, "common", "python2.inv")), +- 'sagemath': ('http://doc.sagemath.org/', +- os.path.join(SAGE_SHARE, "doc", "sage", "html", "en", "reference", "objects.inv")) +- } +- +-## TODO: Automaticall generated inventory +- +-pythonversion = sys.version.split(' ')[0] +-# Python and Sage trac ticket shortcuts. For example, :trac:`7549` . +- +-# Sage trac ticket shortcuts. For example, :trac:`7549` . +-extlinks = { +- 'python': ('https://docs.python.org/release/'+pythonversion+'/%s', ''), +- 'trac': ('https://trac.sagemath.org/%s', 'trac ticket #'), +- 'wikipedia': ('https://en.wikipedia.org/wiki/%s', 'Wikipedia article '), +- 'arxiv': ('http://arxiv.org/abs/%s', 'Arxiv '), +- 'oeis': ('https://oeis.org/%s', 'OEIS sequence '), +- 'doi': ('https://dx.doi.org/%s', 'doi:'), +- 'pari': ('http://pari.math.u-bordeaux.fr/dochtml/help/%s', 'pari:'), +- 'mathscinet': ('http://www.ams.org/mathscinet-getitem?mr=%s', 'MathSciNet ') +- } +- +- + # -- Options for HTML output ---------------------------------------------- + + # The theme to use for HTML and HTML Help pages. See the documentation for + # a list of builtin themes. + # + html_theme = 'classic' +- +-# Theme options are theme-specific and customize the look and feel of a theme +-# further. For a list of options available for each theme, see the +-# documentation. +-# +-html_theme_options = {} +- +-# Add any paths that contain custom static files (such as style sheets) here, +-# relative to this directory. They are copied after the builtin static files, +-# so a file named "default.css" will overwrite the builtin "default.css". +-html_static_path = ['_static', THEBE_DIR] +-html_theme_path = [os.path.join(SAGE_DOC_SRC, 'common', 'themes')] +- +-# Custom sidebar templates, must be a dictionary that maps document names +-# to template names. +-# +-# This is required for the alabaster theme +-# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars +-#~ html_sidebars = { +- #~ '**': [ +- #~ 'about.html', +- #~ 'navigation.html', +- #~ 'relations.html', # needs 'show_related': True theme option to display +- #~ 'searchbox.html', +- #~ 'donate.html', +- #~ ] +-#~ } +- +-extensions.append('sphinx.ext.mathjax') +-mathjax_path = 'MathJax.js?config=TeX-AMS_HTML-full,../mathjax_sage.js' +- +-from sage.misc.latex_macros import sage_mathjax_macros +-#~ html_theme_options['mathjax_macros'] = sage_mathjax_macros() +- +-mathjax_relative = 'mathjax' +- +-# It would be really nice if sphinx would copy the entire mathjax directory, +-# (so we could have a _static/mathjax directory), rather than the contents of the directory +- +-mathjax_static = os.path.join(SAGE_SHARE, mathjax_relative) +-html_static_path.append(mathjax_static) +-exclude_patterns += ['**/'+os.path.join(mathjax_relative, i) +- for i in ('docs', 'README*', 'test', +- 'unpacked', 'LICENSE')] +- +-# Add any paths that contain templates here, relative to this directory. +-templates_path = [os.path.join(SAGE_DOC_SRC, 'common', 'templates'), '_templates'] +- +-##################### +- +-modindex_common_prefix = ['pGroupCohomology.'] +- +-# By default document are not master. +-multidocs_is_master = True +- +-# -- Options for HTMLHelp output ------------------------------------------ +- +-# Output file base name for HTML help builder. +-htmlhelp_basename = 'mod-pgroupcohomologydoc' +- +- +-# -- Options for LaTeX output --------------------------------------------- +- +-latex_elements = { +- # The paper size ('letterpaper' or 'a4paper'). +- # +- # 'papersize': 'letterpaper', +- +- # The font size ('10pt', '11pt' or '12pt'). +- # +- # 'pointsize': '10pt', +- +- # Additional stuff for the LaTeX preamble. +- # +- # 'preamble': '', +- +- # Latex figure (float) alignment +- # +- # 'figure_align': 'htbp', +-} +- +-# Grouping the document tree into LaTeX files. List of tuples +-# (source start file, target name, title, +-# author, documentclass [howto, manual, or own class]). +-latex_documents = [ +- (master_doc, 'mod-pgroupcohomology.tex', u'"mod-p group cohomology" Documentation', +- u'"Simon King"', 'manual'), +-] +- +-latex_elements['preamble'] = r""" +-\usepackage{amsmath} +-\usepackage{amssymb} +-\usepackage{textcomp} +-\usepackage{mathrsfs} +-\usepackage{iftex} +- +-% Only declare unicode characters when compiling with pdftex; E.g. japanese +-% tutorial does not use pdftex +-\ifPDFTeX +- \DeclareUnicodeCharacter{01CE}{\capitalcaron a} +- \DeclareUnicodeCharacter{0428}{cyrillic Sha} +- \DeclareUnicodeCharacter{250C}{+} +- \DeclareUnicodeCharacter{2510}{+} +- \DeclareUnicodeCharacter{2514}{+} +- \DeclareUnicodeCharacter{2518}{+} +- \DeclareUnicodeCharacter{253C}{+} +- +- \DeclareUnicodeCharacter{03B1}{\ensuremath{\alpha}} +- \DeclareUnicodeCharacter{03B2}{\ensuremath{\beta}} +- \DeclareUnicodeCharacter{03B3}{\ensuremath{\gamma}} +- \DeclareUnicodeCharacter{0393}{\ensuremath{\Gamma}} +- \DeclareUnicodeCharacter{03B4}{\ensuremath{\delta}} +- \DeclareUnicodeCharacter{0394}{\ensuremath{\Delta}} +- \DeclareUnicodeCharacter{03B5}{\ensuremath{\varepsilon}} +- \DeclareUnicodeCharacter{03B6}{\ensuremath{\zeta}} +- \DeclareUnicodeCharacter{03B7}{\ensuremath{\eta}} +- \DeclareUnicodeCharacter{03B8}{\ensuremath{\vartheta}} +- \DeclareUnicodeCharacter{0398}{\ensuremath{\Theta}} +- \DeclareUnicodeCharacter{03BA}{\ensuremath{\kappa}} +- \DeclareUnicodeCharacter{03BB}{\ensuremath{\lambda}} +- \DeclareUnicodeCharacter{039B}{\ensuremath{\Lambda}} +- \DeclareUnicodeCharacter{00B5}{\ensuremath{\mu}} % micron sign +- \DeclareUnicodeCharacter{03BC}{\ensuremath{\mu}} +- \DeclareUnicodeCharacter{03BD}{\ensuremath{\nu}} +- \DeclareUnicodeCharacter{03BE}{\ensuremath{\xi}} +- \DeclareUnicodeCharacter{039E}{\ensuremath{\Xi}} +- \DeclareUnicodeCharacter{03B9}{\ensuremath{\iota}} +- \DeclareUnicodeCharacter{03C0}{\ensuremath{\pi}} +- \DeclareUnicodeCharacter{03A0}{\ensuremath{\Pi}} +- \DeclareUnicodeCharacter{03C1}{\ensuremath{\rho}} +- \DeclareUnicodeCharacter{03C3}{\ensuremath{\sigma}} +- \DeclareUnicodeCharacter{03A3}{\ensuremath{\Sigma}} +- \DeclareUnicodeCharacter{03C4}{\ensuremath{\tau}} +- \DeclareUnicodeCharacter{03C6}{\ensuremath{\varphi}} +- \DeclareUnicodeCharacter{03A6}{\ensuremath{\Phi}} +- \DeclareUnicodeCharacter{03C7}{\ensuremath{\chi}} +- \DeclareUnicodeCharacter{03C8}{\ensuremath{\psi}} +- \DeclareUnicodeCharacter{03A8}{\ensuremath{\Psi}} +- \DeclareUnicodeCharacter{03C9}{\ensuremath{\omega}} +- \DeclareUnicodeCharacter{03A9}{\ensuremath{\Omega}} +- \DeclareUnicodeCharacter{03C5}{\ensuremath{\upsilon}} +- \DeclareUnicodeCharacter{03A5}{\ensuremath{\Upsilon}} +- \DeclareUnicodeCharacter{2113}{\ell} +- +- \DeclareUnicodeCharacter{221A}{\ensuremath{\sqrt{}}} +- \DeclareUnicodeCharacter{2264}{\leq} +- \DeclareUnicodeCharacter{2265}{\geq} +- \DeclareUnicodeCharacter{221E}{\infty} +- \DeclareUnicodeCharacter{2211}{\sum} +- \DeclareUnicodeCharacter{2208}{\in} +- \DeclareUnicodeCharacter{2209}{\notin} +- \DeclareUnicodeCharacter{2202}{\partial} +- \DeclareUnicodeCharacter{222B}{\ensuremath{\int}} +- \DeclareUnicodeCharacter{2148}{\id} +- \DeclareUnicodeCharacter{2248}{\approx} +- \DeclareUnicodeCharacter{2260}{\neq} +- \DeclareUnicodeCharacter{00B1}{\pm} +- \DeclareUnicodeCharacter{2A02}{\otimes} +- \DeclareUnicodeCharacter{2A01}{\oplus} +- \DeclareUnicodeCharacter{00BD}{\nicefrac{1}{2}} +- \DeclareUnicodeCharacter{00D7}{\times} +- \DeclareUnicodeCharacter{00B7}{\cdot} +- \DeclareUnicodeCharacter{230A}{\lfloor} +- \DeclareUnicodeCharacter{230B}{\rfloor} +- \DeclareUnicodeCharacter{2308}{\lceil} +- \DeclareUnicodeCharacter{2309}{\rceil} +- \DeclareUnicodeCharacter{22C5}{\ensuremath{\cdot}} +- +- \newcommand{\sageMexSymbol}[1] +- {{\fontencoding{OMX}\fontfamily{cmex}\selectfont\raisebox{0.75em}{\symbol{#1}}}} +- \DeclareUnicodeCharacter{239B}{\sageMexSymbol{"30}} % parenlefttp +- \DeclareUnicodeCharacter{239C}{\sageMexSymbol{"42}} % parenleftex +- \DeclareUnicodeCharacter{239D}{\sageMexSymbol{"40}} % parenleftbt +- \DeclareUnicodeCharacter{239E}{\sageMexSymbol{"31}} % parenrighttp +- \DeclareUnicodeCharacter{239F}{\sageMexSymbol{"43}} % parenrightex +- \DeclareUnicodeCharacter{23A0}{\sageMexSymbol{"41}} % parenrightbt +- \DeclareUnicodeCharacter{23A1}{\sageMexSymbol{"32}} % bracketlefttp +- \DeclareUnicodeCharacter{23A2}{\sageMexSymbol{"36}} % bracketleftex +- \DeclareUnicodeCharacter{23A3}{\sageMexSymbol{"34}} % bracketleftbt +- \DeclareUnicodeCharacter{23A4}{\sageMexSymbol{"33}} % bracketrighttp +- \DeclareUnicodeCharacter{23A5}{\sageMexSymbol{"37}} % bracketrightex +- \DeclareUnicodeCharacter{23A6}{\sageMexSymbol{"35}} % bracketrightbt +- +- \DeclareUnicodeCharacter{23A7}{\sageMexSymbol{"38}} % curly brace left top +- \DeclareUnicodeCharacter{23A8}{\sageMexSymbol{"3C}} % curly brace left middle +- \DeclareUnicodeCharacter{23A9}{\sageMexSymbol{"3A}} % curly brace left bottom +- \DeclareUnicodeCharacter{23AA}{\sageMexSymbol{"3E}} % curly brace extension +- \DeclareUnicodeCharacter{23AB}{\sageMexSymbol{"39}} % curly brace right top +- \DeclareUnicodeCharacter{23AC}{\sageMexSymbol{"3D}} % curly brace right middle +- \DeclareUnicodeCharacter{23AD}{\sageMexSymbol{"3B}} % curly brace right bottom +- \DeclareUnicodeCharacter{23B0}{\{} % 2-line curly brace left top half (not in cmex) +- \DeclareUnicodeCharacter{23B1}{\}} % 2-line curly brace right top half (not in cmex) +- +- \DeclareUnicodeCharacter{2320}{\ensuremath{\int}} % top half integral +- \DeclareUnicodeCharacter{2321}{\ensuremath{\int}} % bottom half integral +- \DeclareUnicodeCharacter{23AE}{\ensuremath{\|}} % integral extenison +- +- \DeclareUnicodeCharacter{2571}{/} % Box drawings light diagonal upper right to lower left +-\fi +- +-\let\textLaTeX\LaTeX +-\renewcommand*{\LaTeX}{\hbox{\textLaTeX}} +-""" +- +-#################################################### +-# add LaTeX macros for Sage +- +-from sage.misc.latex_macros import sage_latex_macros +- +-try: +- pngmath_latex_preamble # check whether this is already defined +-except NameError: +- pngmath_latex_preamble = "" +- +-for macro in sage_latex_macros(): +- # used when building latex and pdf versions +- latex_elements['preamble'] += macro + '\n' +- # used when building html version +- pngmath_latex_preamble += macro + '\n' +- +-# -- Options for manual page output --------------------------------------- +- +-# One entry per manual page. List of tuples +-# (source start file, name, description, authors, manual section). +-man_pages = [ +- (master_doc, 'mod-pgroupcohomology', u'"mod-p group cohomology" Documentation', +- [author], 1) +-] +- +- +-# -- Options for Texinfo output ------------------------------------------- +- +-# Grouping the document tree into Texinfo files. List of tuples +-# (source start file, target name, title, author, +-# dir menu entry, description, category) +-texinfo_documents = [ +- (master_doc, 'mod-pgroupcohomology', u'"mod-p group cohomology" Documentation', +- author, 'mod-pgroupcohomology', 'One line description of project.', +- 'Miscellaneous'), +-] +- +-############### +-## Doc processing +- +-##################################################### +- +-def process_docstring_aliases(app, what, name, obj, options, docstringlines): +- """ +- Change the docstrings for aliases to point to the original object. +- """ +- basename = name.rpartition('.')[2] +- if hasattr(obj, '__name__') and obj.__name__ != basename: +- docstringlines[:] = ['See :obj:`%s`.' % name] +- +-def process_directives(app, what, name, obj, options, docstringlines): +- """ +- Remove 'nodetex' and other directives from the first line of any +- docstring where they appear. +- """ +- if len(docstringlines) == 0: +- return +- first_line = docstringlines[0] +- directives = [ d.lower() for d in first_line.split(',') ] +- if 'nodetex' in directives: +- docstringlines.pop(0) +- +-def process_docstring_cython(app, what, name, obj, options, docstringlines): +- """ +- Remove Cython's filename, location and argspec embedding. +- """ +- if len(docstringlines) <= 1: +- return +- if what == 'function': +- embedded_name = '.'.join(name.split('.')[-1:]) +- else: +- embedded_name = '.'.join(name.split('.')[-2:]) +- #~ print embedded_name, name,what +- while len(docstringlines) > 1: +- first_line = docstringlines[0].strip() +- # Filename/location +- if first_line.startswith('File:') and '(starting at' in first_line: +- #Remove the first two lines +- docstringlines.pop(0) +- docstringlines.pop(0) +- elif first_line.startswith(embedded_name): +- args = first_line.split(embedded_name,1)[1] +- if args.startswith('(') and args.endswith(')'): +- #Remove the first line +- docstringlines.pop(0) +- else: +- return +- else: +- return +- +-def process_docstring_module_title(app, what, name, obj, options, docstringlines): +- """ +- Removes the first line from the beginning of the module's docstring. This +- corresponds to the title of the module's documentation page. +- """ +- if what != "module": +- return +- +- #Remove any additional blank lines at the beginning +- title_removed = False +- while len(docstringlines) > 1 and not title_removed: +- if docstringlines[0].strip() != "": +- title_removed = True +- docstringlines.pop(0) +- +- #Remove any additional blank lines at the beginning +- while len(docstringlines) > 1: +- if docstringlines[0].strip() == "": +- docstringlines.pop(0) +- else: +- break +- +-def process_dollars(app, what, name, obj, options, docstringlines): +- r""" +- Replace dollar signs with backticks. +- +- See sage.misc.sagedoc.process_dollars for more information. +- """ +- if len(docstringlines) and name.find("process_dollars") == -1: +- from six.moves import range +- from sage.misc.sagedoc import process_dollars as sagedoc_dollars +- s = sagedoc_dollars("\n".join(docstringlines)) +- lines = s.split("\n") +- for i in range(len(lines)): +- docstringlines[i] = lines[i] +- +-def process_inherited(app, what, name, obj, options, docstringlines): +- """ +- If we're including inherited members, omit their docstrings. +- """ +- if not options.get('inherited-members'): +- return +- +- if what in ['class', 'data', 'exception', 'function', 'module']: +- return +- +- name = name.split('.')[-1] +- +- if what == 'method' and hasattr(obj, 'im_class'): +- if name in obj.im_class.__dict__.keys(): +- return +- +- if what == 'attribute' and hasattr(obj, '__objclass__'): +- if name in obj.__objclass__.__dict__.keys(): +- return +- +- for i in range(len(docstringlines)): +- docstringlines.pop() +- +-########################################## +-# +-# Connecting with app +- +-from sage.misc.sageinspect import sage_getargspec +-autodoc_builtin_argspec = sage_getargspec +- +-def setup(app): +- app.connect('autodoc-process-docstring', process_docstring_cython) +- app.connect('autodoc-process-docstring', process_directives) +- app.connect('autodoc-process-docstring', process_docstring_module_title) +- app.connect('autodoc-process-docstring', process_dollars) +- app.connect('autodoc-process-docstring', process_inherited) +- #~ app.connect('autodoc-skip-member', skip_member) +- +- #~ # When building the standard docs, app.srcdir is set to COHO_DOC_SRC + +- #~ # 'LANGUAGE/DOCNAME', but when doing introspection, app.srcdir is +- #~ # set to a temporary directory. We don't want to use intersphinx, +- #~ # etc., when doing introspection. +- #~ if app.srcdir.startswith(COHO_DOC_SRC): +- #~ app.add_config_value('intersphinx_mapping', {}, False) +- #~ app.add_config_value('intersphinx_cache_limit', 5, False) +- #~ # We do *not* fully initialize intersphinx since we call it by hand +- #~ # in find_sage_dangling_links. +- #~ # app.connect('missing-reference', missing_reference) +- #~ app.connect('missing-reference', find_sage_dangling_links) +- #~ import sphinx.ext.intersphinx +- #~ app.connect('builder-inited', set_intersphinx_mappings) +- #~ app.connect('builder-inited', sphinx.ext.intersphinx.load_mappings) +- #~ app.connect('builder-inited', nitpick_patch_config) From 9a7479772abe4461a589be92696e7ab5ac534a85 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 9 Mar 2022 12:10:19 +0000 Subject: [PATCH 274/591] a separate repo and a tarball for modular_resolution --- build/pkgs/modular_resolution/checksums.ini | 6 +++++- build/pkgs/modular_resolution/package-version.txt | 2 +- build/pkgs/modular_resolution/spkg-check.in | 1 - build/pkgs/modular_resolution/spkg-install.in | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) mode change 120000 => 100644 build/pkgs/modular_resolution/checksums.ini mode change 120000 => 100644 build/pkgs/modular_resolution/package-version.txt diff --git a/build/pkgs/modular_resolution/checksums.ini b/build/pkgs/modular_resolution/checksums.ini deleted file mode 120000 index c94028a71ef..00000000000 --- a/build/pkgs/modular_resolution/checksums.ini +++ /dev/null @@ -1 +0,0 @@ -../p_group_cohomology/checksums.ini \ No newline at end of file diff --git a/build/pkgs/modular_resolution/checksums.ini b/build/pkgs/modular_resolution/checksums.ini new file mode 100644 index 00000000000..5d1d465cead --- /dev/null +++ b/build/pkgs/modular_resolution/checksums.ini @@ -0,0 +1,5 @@ +tarball=modular_resolution-VERSION.tar.gz +sha1=09ee61b1f9a33fb3e9bf0b658f81d3ede5748328 +md5=0e59e69a46014b8935c5e081d3bfc57a +cksum=2981185519 +upstream_url=https://github.com/sagemath/modular_resolution/releases/download/VERSION/modular_resolution-VERSION.tar.gz diff --git a/build/pkgs/modular_resolution/package-version.txt b/build/pkgs/modular_resolution/package-version.txt deleted file mode 120000 index 819a4a33206..00000000000 --- a/build/pkgs/modular_resolution/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -../p_group_cohomology/package-version.txt \ No newline at end of file diff --git a/build/pkgs/modular_resolution/package-version.txt b/build/pkgs/modular_resolution/package-version.txt new file mode 100644 index 00000000000..9459d4ba2a0 --- /dev/null +++ b/build/pkgs/modular_resolution/package-version.txt @@ -0,0 +1 @@ +1.1 diff --git a/build/pkgs/modular_resolution/spkg-check.in b/build/pkgs/modular_resolution/spkg-check.in index bdd7bb89496..39b12d01df6 100644 --- a/build/pkgs/modular_resolution/spkg-check.in +++ b/build/pkgs/modular_resolution/spkg-check.in @@ -1,4 +1,3 @@ cd src -cd `ls -d modular_resolution*` $MAKE check || sdh_die "Error testing modular_resolution" diff --git a/build/pkgs/modular_resolution/spkg-install.in b/build/pkgs/modular_resolution/spkg-install.in index b9fb854adec..ee5610a4c14 100644 --- a/build/pkgs/modular_resolution/spkg-install.in +++ b/build/pkgs/modular_resolution/spkg-install.in @@ -1,6 +1,5 @@ cd src # build and install modular_resolution -cd `ls -d modular_resolution*` sdh_configure sdh_make_install From 6c4c9012a16390a99d588651587e0281b7450c3c Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 9 Mar 2022 14:46:14 +0000 Subject: [PATCH 275/591] upstream patches, new version --- build/pkgs/p_group_cohomology/checksums.ini | 6 +- .../p_group_cohomology/package-version.txt | 2 +- .../patches/docbuild_conf.patch | 509 ------------------ .../p_group_cohomology/patches/polylib.patch | 57 -- .../patches/set_default_prec.patch | 32 -- .../patches/trivial_doctests.patch | 77 --- .../pkgs/p_group_cohomology/spkg-postinst.in | 5 - 7 files changed, 4 insertions(+), 684 deletions(-) delete mode 100644 build/pkgs/p_group_cohomology/patches/docbuild_conf.patch delete mode 100644 build/pkgs/p_group_cohomology/patches/polylib.patch delete mode 100644 build/pkgs/p_group_cohomology/patches/set_default_prec.patch delete mode 100644 build/pkgs/p_group_cohomology/patches/trivial_doctests.patch diff --git a/build/pkgs/p_group_cohomology/checksums.ini b/build/pkgs/p_group_cohomology/checksums.ini index a7dd222a72f..037adebe13b 100644 --- a/build/pkgs/p_group_cohomology/checksums.ini +++ b/build/pkgs/p_group_cohomology/checksums.ini @@ -1,5 +1,5 @@ tarball=p_group_cohomology-VERSION.tar.xz -sha1=110a6dbe26ae6d7aa1227e1ff2338d7c8b38daa9 -md5=d4fad2cde21c275aed753ccbd467616a -cksum=1676569830 +sha1=219ff8c28408d2457b9e929af6d59ffceb4d3191 +md5=7bf803ae191a27b881f148d2ac350650 +cksum=163652230 upstream_url=https://github.com/sagemath/p_group_cohomology/releases/download/vVERSION/p_group_cohomology-VERSION.tar.xz diff --git a/build/pkgs/p_group_cohomology/package-version.txt b/build/pkgs/p_group_cohomology/package-version.txt index e5691ee639c..619b5376684 100644 --- a/build/pkgs/p_group_cohomology/package-version.txt +++ b/build/pkgs/p_group_cohomology/package-version.txt @@ -1 +1 @@ -3.3.2.p0 +3.3.3 diff --git a/build/pkgs/p_group_cohomology/patches/docbuild_conf.patch b/build/pkgs/p_group_cohomology/patches/docbuild_conf.patch deleted file mode 100644 index 5fea52dddc1..00000000000 --- a/build/pkgs/p_group_cohomology/patches/docbuild_conf.patch +++ /dev/null @@ -1,509 +0,0 @@ -diff --git a/pGroupCohomology-3.3.2/doc/source/conf.py.orig b/pGroupCohomology-3.3.2/doc/source/conf.py -index e24ceb6..49d8a0d 100644 ---- a/pGroupCohomology-3.3.2/doc/source/conf.py.orig -+++ b/pGroupCohomology-3.3.2/doc/source/conf.py -@@ -1,52 +1,7 @@ - # -*- coding: utf-8 -*- --# --# "p_group_cohomology" documentation build configuration file, created by --# sphinx-quickstart on Wed Jan 3 00:48:45 2018. --# --# This file is execfile()d with the current directory set to its --# containing dir. --# --# Note that not all possible configuration values are present in this --# autogenerated file. --# --# All configuration values have a default; values that are commented out --# serve to show the default. -- --# If extensions (or modules to document with autodoc) are in another directory, --# add these directories to sys.path here. If the directory is relative to the --# documentation root, use os.path.abspath to make it absolute, like shown here. --# --import os --import sys --from sage.env import SAGE_DOC_SRC, SAGE_DOC, SAGE_SRC, THEBE_DIR, SAGE_SHARE --COHO_DOC_SRC = os.path.abspath('../pGroupCohomology') -+# Mainly use Sage's conf.py. - --sys.path.insert(0, COHO_DOC_SRC) --sys.path.append(os.path.join(SAGE_SRC, "sage_setup", "docbuild", "ext")) -- -- --# -- General configuration ------------------------------------------------ -- --# If your documentation needs a minimal Sphinx version, state it here. --# --# needs_sphinx = '1.0' -- --# Add any Sphinx extension module names here, as strings. They can be --# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom --# ones. --extensions = ['inventory_builder', -- 'sage_autodoc', -- 'sphinx.ext.intersphinx', -- 'sphinx.ext.todo'] -- --# The suffix(es) of source filenames. --# You can specify multiple suffix as a list of string: --# --# source_suffix = ['.rst', '.md'] --source_suffix = '.rst' -- --# The master toctree document. --master_doc = 'index' -+from sage.docs.conf import * - - # General information about the project. - project = u'"p_group_cohomology"' -@@ -62,449 +17,9 @@ version = u'3.3.2' - # The full version, including alpha/beta/rc tags. - release = u'3.3.2' - --# The language for content autogenerated by Sphinx. Refer to documentation --# for a list of supported languages. --# --# This is also used if you do content translation via gettext catalogs. --# Usually you set "language" from the command line for these cases. --language = None -- --# List of patterns, relative to source directory, that match files and --# directories to ignore when looking for source files. --# This patterns also effect to html_static_path and html_extra_path --exclude_patterns = [] -- --default_role = 'math' -- --add_function_parentheses = True -- --add_module_names = True -- --# syntax highlighting --from sphinx import highlighting --from IPython.lib.lexers import IPythonConsoleLexer, IPyLexer -- --pygments_style = 'sphinx' --highlighting.lexers['ipycon'] = IPythonConsoleLexer(in1_regex=r'sage: ', in2_regex=r'[.][.][.][.]: ') --highlighting.lexers['ipython'] = IPyLexer() --highlight_language = 'ipycon' -- -- --# If true, `todo` and `todoList` produce output, else they produce nothing. --todo_include_todos = True -- --# Cross-links to other project's online documentation. --intersphinx_mapping = { -- 'python' : ('https://docs.python.org/', -- os.path.join(SAGE_DOC_SRC, "common", "python2.inv")), -- 'sagemath': ('http://doc.sagemath.org/', -- os.path.join(SAGE_SHARE, "doc", "sage", "html", "en", "reference", "objects.inv")) -- } -- --## TODO: Automaticall generated inventory -- --pythonversion = sys.version.split(' ')[0] --# Python and Sage trac ticket shortcuts. For example, :trac:`7549` . -- --# Sage trac ticket shortcuts. For example, :trac:`7549` . --extlinks = { -- 'python': ('https://docs.python.org/release/'+pythonversion+'/%s', ''), -- 'trac': ('https://trac.sagemath.org/%s', 'trac ticket #'), -- 'wikipedia': ('https://en.wikipedia.org/wiki/%s', 'Wikipedia article '), -- 'arxiv': ('http://arxiv.org/abs/%s', 'Arxiv '), -- 'oeis': ('https://oeis.org/%s', 'OEIS sequence '), -- 'doi': ('https://dx.doi.org/%s', 'doi:'), -- 'pari': ('http://pari.math.u-bordeaux.fr/dochtml/help/%s', 'pari:'), -- 'mathscinet': ('http://www.ams.org/mathscinet-getitem?mr=%s', 'MathSciNet ') -- } -- -- - # -- Options for HTML output ---------------------------------------------- - - # The theme to use for HTML and HTML Help pages. See the documentation for - # a list of builtin themes. - # - html_theme = 'classic' -- --# Theme options are theme-specific and customize the look and feel of a theme --# further. For a list of options available for each theme, see the --# documentation. --# --html_theme_options = {} -- --# Add any paths that contain custom static files (such as style sheets) here, --# relative to this directory. They are copied after the builtin static files, --# so a file named "default.css" will overwrite the builtin "default.css". --html_static_path = ['_static', THEBE_DIR] --html_theme_path = [os.path.join(SAGE_DOC_SRC, 'common', 'themes')] -- --# Custom sidebar templates, must be a dictionary that maps document names --# to template names. --# --# This is required for the alabaster theme --# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars --#~ html_sidebars = { -- #~ '**': [ -- #~ 'about.html', -- #~ 'navigation.html', -- #~ 'relations.html', # needs 'show_related': True theme option to display -- #~ 'searchbox.html', -- #~ 'donate.html', -- #~ ] --#~ } -- --extensions.append('sphinx.ext.mathjax') --mathjax_path = 'MathJax.js?config=TeX-AMS_HTML-full,../mathjax_sage.js' -- --from sage.misc.latex_macros import sage_mathjax_macros --#~ html_theme_options['mathjax_macros'] = sage_mathjax_macros() -- --mathjax_relative = 'mathjax' -- --# It would be really nice if sphinx would copy the entire mathjax directory, --# (so we could have a _static/mathjax directory), rather than the contents of the directory -- --mathjax_static = os.path.join(SAGE_SHARE, mathjax_relative) --html_static_path.append(mathjax_static) --exclude_patterns += ['**/'+os.path.join(mathjax_relative, i) -- for i in ('docs', 'README*', 'test', -- 'unpacked', 'LICENSE')] -- --# Add any paths that contain templates here, relative to this directory. --templates_path = [os.path.join(SAGE_DOC_SRC, 'common', 'templates'), '_templates'] -- --##################### -- --modindex_common_prefix = ['pGroupCohomology.'] -- --# By default document are not master. --multidocs_is_master = True -- --# -- Options for HTMLHelp output ------------------------------------------ -- --# Output file base name for HTML help builder. --htmlhelp_basename = 'mod-pgroupcohomologydoc' -- -- --# -- Options for LaTeX output --------------------------------------------- -- --latex_elements = { -- # The paper size ('letterpaper' or 'a4paper'). -- # -- # 'papersize': 'letterpaper', -- -- # The font size ('10pt', '11pt' or '12pt'). -- # -- # 'pointsize': '10pt', -- -- # Additional stuff for the LaTeX preamble. -- # -- # 'preamble': '', -- -- # Latex figure (float) alignment -- # -- # 'figure_align': 'htbp', --} -- --# Grouping the document tree into LaTeX files. List of tuples --# (source start file, target name, title, --# author, documentclass [howto, manual, or own class]). --latex_documents = [ -- (master_doc, 'mod-pgroupcohomology.tex', u'"mod-p group cohomology" Documentation', -- u'"Simon King"', 'manual'), --] -- --latex_elements['preamble'] = r""" --\usepackage{amsmath} --\usepackage{amssymb} --\usepackage{textcomp} --\usepackage{mathrsfs} --\usepackage{iftex} -- --% Only declare unicode characters when compiling with pdftex; E.g. japanese --% tutorial does not use pdftex --\ifPDFTeX -- \DeclareUnicodeCharacter{01CE}{\capitalcaron a} -- \DeclareUnicodeCharacter{0428}{cyrillic Sha} -- \DeclareUnicodeCharacter{250C}{+} -- \DeclareUnicodeCharacter{2510}{+} -- \DeclareUnicodeCharacter{2514}{+} -- \DeclareUnicodeCharacter{2518}{+} -- \DeclareUnicodeCharacter{253C}{+} -- -- \DeclareUnicodeCharacter{03B1}{\ensuremath{\alpha}} -- \DeclareUnicodeCharacter{03B2}{\ensuremath{\beta}} -- \DeclareUnicodeCharacter{03B3}{\ensuremath{\gamma}} -- \DeclareUnicodeCharacter{0393}{\ensuremath{\Gamma}} -- \DeclareUnicodeCharacter{03B4}{\ensuremath{\delta}} -- \DeclareUnicodeCharacter{0394}{\ensuremath{\Delta}} -- \DeclareUnicodeCharacter{03B5}{\ensuremath{\varepsilon}} -- \DeclareUnicodeCharacter{03B6}{\ensuremath{\zeta}} -- \DeclareUnicodeCharacter{03B7}{\ensuremath{\eta}} -- \DeclareUnicodeCharacter{03B8}{\ensuremath{\vartheta}} -- \DeclareUnicodeCharacter{0398}{\ensuremath{\Theta}} -- \DeclareUnicodeCharacter{03BA}{\ensuremath{\kappa}} -- \DeclareUnicodeCharacter{03BB}{\ensuremath{\lambda}} -- \DeclareUnicodeCharacter{039B}{\ensuremath{\Lambda}} -- \DeclareUnicodeCharacter{00B5}{\ensuremath{\mu}} % micron sign -- \DeclareUnicodeCharacter{03BC}{\ensuremath{\mu}} -- \DeclareUnicodeCharacter{03BD}{\ensuremath{\nu}} -- \DeclareUnicodeCharacter{03BE}{\ensuremath{\xi}} -- \DeclareUnicodeCharacter{039E}{\ensuremath{\Xi}} -- \DeclareUnicodeCharacter{03B9}{\ensuremath{\iota}} -- \DeclareUnicodeCharacter{03C0}{\ensuremath{\pi}} -- \DeclareUnicodeCharacter{03A0}{\ensuremath{\Pi}} -- \DeclareUnicodeCharacter{03C1}{\ensuremath{\rho}} -- \DeclareUnicodeCharacter{03C3}{\ensuremath{\sigma}} -- \DeclareUnicodeCharacter{03A3}{\ensuremath{\Sigma}} -- \DeclareUnicodeCharacter{03C4}{\ensuremath{\tau}} -- \DeclareUnicodeCharacter{03C6}{\ensuremath{\varphi}} -- \DeclareUnicodeCharacter{03A6}{\ensuremath{\Phi}} -- \DeclareUnicodeCharacter{03C7}{\ensuremath{\chi}} -- \DeclareUnicodeCharacter{03C8}{\ensuremath{\psi}} -- \DeclareUnicodeCharacter{03A8}{\ensuremath{\Psi}} -- \DeclareUnicodeCharacter{03C9}{\ensuremath{\omega}} -- \DeclareUnicodeCharacter{03A9}{\ensuremath{\Omega}} -- \DeclareUnicodeCharacter{03C5}{\ensuremath{\upsilon}} -- \DeclareUnicodeCharacter{03A5}{\ensuremath{\Upsilon}} -- \DeclareUnicodeCharacter{2113}{\ell} -- -- \DeclareUnicodeCharacter{221A}{\ensuremath{\sqrt{}}} -- \DeclareUnicodeCharacter{2264}{\leq} -- \DeclareUnicodeCharacter{2265}{\geq} -- \DeclareUnicodeCharacter{221E}{\infty} -- \DeclareUnicodeCharacter{2211}{\sum} -- \DeclareUnicodeCharacter{2208}{\in} -- \DeclareUnicodeCharacter{2209}{\notin} -- \DeclareUnicodeCharacter{2202}{\partial} -- \DeclareUnicodeCharacter{222B}{\ensuremath{\int}} -- \DeclareUnicodeCharacter{2148}{\id} -- \DeclareUnicodeCharacter{2248}{\approx} -- \DeclareUnicodeCharacter{2260}{\neq} -- \DeclareUnicodeCharacter{00B1}{\pm} -- \DeclareUnicodeCharacter{2A02}{\otimes} -- \DeclareUnicodeCharacter{2A01}{\oplus} -- \DeclareUnicodeCharacter{00BD}{\nicefrac{1}{2}} -- \DeclareUnicodeCharacter{00D7}{\times} -- \DeclareUnicodeCharacter{00B7}{\cdot} -- \DeclareUnicodeCharacter{230A}{\lfloor} -- \DeclareUnicodeCharacter{230B}{\rfloor} -- \DeclareUnicodeCharacter{2308}{\lceil} -- \DeclareUnicodeCharacter{2309}{\rceil} -- \DeclareUnicodeCharacter{22C5}{\ensuremath{\cdot}} -- -- \newcommand{\sageMexSymbol}[1] -- {{\fontencoding{OMX}\fontfamily{cmex}\selectfont\raisebox{0.75em}{\symbol{#1}}}} -- \DeclareUnicodeCharacter{239B}{\sageMexSymbol{"30}} % parenlefttp -- \DeclareUnicodeCharacter{239C}{\sageMexSymbol{"42}} % parenleftex -- \DeclareUnicodeCharacter{239D}{\sageMexSymbol{"40}} % parenleftbt -- \DeclareUnicodeCharacter{239E}{\sageMexSymbol{"31}} % parenrighttp -- \DeclareUnicodeCharacter{239F}{\sageMexSymbol{"43}} % parenrightex -- \DeclareUnicodeCharacter{23A0}{\sageMexSymbol{"41}} % parenrightbt -- \DeclareUnicodeCharacter{23A1}{\sageMexSymbol{"32}} % bracketlefttp -- \DeclareUnicodeCharacter{23A2}{\sageMexSymbol{"36}} % bracketleftex -- \DeclareUnicodeCharacter{23A3}{\sageMexSymbol{"34}} % bracketleftbt -- \DeclareUnicodeCharacter{23A4}{\sageMexSymbol{"33}} % bracketrighttp -- \DeclareUnicodeCharacter{23A5}{\sageMexSymbol{"37}} % bracketrightex -- \DeclareUnicodeCharacter{23A6}{\sageMexSymbol{"35}} % bracketrightbt -- -- \DeclareUnicodeCharacter{23A7}{\sageMexSymbol{"38}} % curly brace left top -- \DeclareUnicodeCharacter{23A8}{\sageMexSymbol{"3C}} % curly brace left middle -- \DeclareUnicodeCharacter{23A9}{\sageMexSymbol{"3A}} % curly brace left bottom -- \DeclareUnicodeCharacter{23AA}{\sageMexSymbol{"3E}} % curly brace extension -- \DeclareUnicodeCharacter{23AB}{\sageMexSymbol{"39}} % curly brace right top -- \DeclareUnicodeCharacter{23AC}{\sageMexSymbol{"3D}} % curly brace right middle -- \DeclareUnicodeCharacter{23AD}{\sageMexSymbol{"3B}} % curly brace right bottom -- \DeclareUnicodeCharacter{23B0}{\{} % 2-line curly brace left top half (not in cmex) -- \DeclareUnicodeCharacter{23B1}{\}} % 2-line curly brace right top half (not in cmex) -- -- \DeclareUnicodeCharacter{2320}{\ensuremath{\int}} % top half integral -- \DeclareUnicodeCharacter{2321}{\ensuremath{\int}} % bottom half integral -- \DeclareUnicodeCharacter{23AE}{\ensuremath{\|}} % integral extenison -- -- \DeclareUnicodeCharacter{2571}{/} % Box drawings light diagonal upper right to lower left --\fi -- --\let\textLaTeX\LaTeX --\renewcommand*{\LaTeX}{\hbox{\textLaTeX}} --""" -- --#################################################### --# add LaTeX macros for Sage -- --from sage.misc.latex_macros import sage_latex_macros -- --try: -- pngmath_latex_preamble # check whether this is already defined --except NameError: -- pngmath_latex_preamble = "" -- --for macro in sage_latex_macros(): -- # used when building latex and pdf versions -- latex_elements['preamble'] += macro + '\n' -- # used when building html version -- pngmath_latex_preamble += macro + '\n' -- --# -- Options for manual page output --------------------------------------- -- --# One entry per manual page. List of tuples --# (source start file, name, description, authors, manual section). --man_pages = [ -- (master_doc, 'mod-pgroupcohomology', u'"mod-p group cohomology" Documentation', -- [author], 1) --] -- -- --# -- Options for Texinfo output ------------------------------------------- -- --# Grouping the document tree into Texinfo files. List of tuples --# (source start file, target name, title, author, --# dir menu entry, description, category) --texinfo_documents = [ -- (master_doc, 'mod-pgroupcohomology', u'"mod-p group cohomology" Documentation', -- author, 'mod-pgroupcohomology', 'One line description of project.', -- 'Miscellaneous'), --] -- --############### --## Doc processing -- --##################################################### -- --def process_docstring_aliases(app, what, name, obj, options, docstringlines): -- """ -- Change the docstrings for aliases to point to the original object. -- """ -- basename = name.rpartition('.')[2] -- if hasattr(obj, '__name__') and obj.__name__ != basename: -- docstringlines[:] = ['See :obj:`%s`.' % name] -- --def process_directives(app, what, name, obj, options, docstringlines): -- """ -- Remove 'nodetex' and other directives from the first line of any -- docstring where they appear. -- """ -- if len(docstringlines) == 0: -- return -- first_line = docstringlines[0] -- directives = [ d.lower() for d in first_line.split(',') ] -- if 'nodetex' in directives: -- docstringlines.pop(0) -- --def process_docstring_cython(app, what, name, obj, options, docstringlines): -- """ -- Remove Cython's filename, location and argspec embedding. -- """ -- if len(docstringlines) <= 1: -- return -- if what == 'function': -- embedded_name = '.'.join(name.split('.')[-1:]) -- else: -- embedded_name = '.'.join(name.split('.')[-2:]) -- #~ print embedded_name, name,what -- while len(docstringlines) > 1: -- first_line = docstringlines[0].strip() -- # Filename/location -- if first_line.startswith('File:') and '(starting at' in first_line: -- #Remove the first two lines -- docstringlines.pop(0) -- docstringlines.pop(0) -- elif first_line.startswith(embedded_name): -- args = first_line.split(embedded_name,1)[1] -- if args.startswith('(') and args.endswith(')'): -- #Remove the first line -- docstringlines.pop(0) -- else: -- return -- else: -- return -- --def process_docstring_module_title(app, what, name, obj, options, docstringlines): -- """ -- Removes the first line from the beginning of the module's docstring. This -- corresponds to the title of the module's documentation page. -- """ -- if what != "module": -- return -- -- #Remove any additional blank lines at the beginning -- title_removed = False -- while len(docstringlines) > 1 and not title_removed: -- if docstringlines[0].strip() != "": -- title_removed = True -- docstringlines.pop(0) -- -- #Remove any additional blank lines at the beginning -- while len(docstringlines) > 1: -- if docstringlines[0].strip() == "": -- docstringlines.pop(0) -- else: -- break -- --def process_dollars(app, what, name, obj, options, docstringlines): -- r""" -- Replace dollar signs with backticks. -- -- See sage.misc.sagedoc.process_dollars for more information. -- """ -- if len(docstringlines) and name.find("process_dollars") == -1: -- from six.moves import range -- from sage.misc.sagedoc import process_dollars as sagedoc_dollars -- s = sagedoc_dollars("\n".join(docstringlines)) -- lines = s.split("\n") -- for i in range(len(lines)): -- docstringlines[i] = lines[i] -- --def process_inherited(app, what, name, obj, options, docstringlines): -- """ -- If we're including inherited members, omit their docstrings. -- """ -- if not options.get('inherited-members'): -- return -- -- if what in ['class', 'data', 'exception', 'function', 'module']: -- return -- -- name = name.split('.')[-1] -- -- if what == 'method' and hasattr(obj, 'im_class'): -- if name in obj.im_class.__dict__.keys(): -- return -- -- if what == 'attribute' and hasattr(obj, '__objclass__'): -- if name in obj.__objclass__.__dict__.keys(): -- return -- -- for i in range(len(docstringlines)): -- docstringlines.pop() -- --########################################## --# --# Connecting with app -- --from sage.misc.sageinspect import sage_getargspec --autodoc_builtin_argspec = sage_getargspec -- --def setup(app): -- app.connect('autodoc-process-docstring', process_docstring_cython) -- app.connect('autodoc-process-docstring', process_directives) -- app.connect('autodoc-process-docstring', process_docstring_module_title) -- app.connect('autodoc-process-docstring', process_dollars) -- app.connect('autodoc-process-docstring', process_inherited) -- #~ app.connect('autodoc-skip-member', skip_member) -- -- #~ # When building the standard docs, app.srcdir is set to COHO_DOC_SRC + -- #~ # 'LANGUAGE/DOCNAME', but when doing introspection, app.srcdir is -- #~ # set to a temporary directory. We don't want to use intersphinx, -- #~ # etc., when doing introspection. -- #~ if app.srcdir.startswith(COHO_DOC_SRC): -- #~ app.add_config_value('intersphinx_mapping', {}, False) -- #~ app.add_config_value('intersphinx_cache_limit', 5, False) -- #~ # We do *not* fully initialize intersphinx since we call it by hand -- #~ # in find_sage_dangling_links. -- #~ # app.connect('missing-reference', missing_reference) -- #~ app.connect('missing-reference', find_sage_dangling_links) -- #~ import sphinx.ext.intersphinx -- #~ app.connect('builder-inited', set_intersphinx_mappings) -- #~ app.connect('builder-inited', sphinx.ext.intersphinx.load_mappings) -- #~ app.connect('builder-inited', nitpick_patch_config) diff --git a/build/pkgs/p_group_cohomology/patches/polylib.patch b/build/pkgs/p_group_cohomology/patches/polylib.patch deleted file mode 100644 index 00b46afbe1b..00000000000 --- a/build/pkgs/p_group_cohomology/patches/polylib.patch +++ /dev/null @@ -1,57 +0,0 @@ -diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/cohomology.pyx b/pGroupCohomology-3.3.2/pGroupCohomology/cohomology.pyx -index 8e37be9..828b6a2 100644 ---- a/pGroupCohomology-3.3.2/pGroupCohomology/cohomology.pyx -+++ b/pGroupCohomology-3.3.2/pGroupCohomology/cohomology.pyx -@@ -3108,7 +3108,7 @@ class COHO(Ring): - if self.Resl.coef()!=2: # non-commutative case - singular.LIB('ncall.lib') - singular.LIB('general.lib') -- singular.LIB('poly.lib') -+ singular.LIB('polylib.lib') - singular.LIB('dickson.lib') - singular.eval('option(redSB)'); - singular.eval('int i') -@@ -3877,7 +3877,7 @@ class COHO(Ring): - if p!=2: - singular.LIB("ncall.lib") - singular.LIB('general.lib') -- singular.LIB('poly.lib') -+ singular.LIB('polylib.lib') - singular.LIB('dickson.lib') - if singular.eval('defined(i)')=='0': - singular.eval('int i') -@@ -10062,7 +10062,7 @@ is an error. Please inform the author!""") - if p!=2: - singular.LIB("ncall.lib") - singular.LIB('general.lib') -- singular.LIB('poly.lib') -+ singular.LIB('polylib.lib') - singular.LIB('dickson.lib') - from pGroupCohomology.cochain import MODCOCH - if singular.eval('defined(i)')=='0': -diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/isomorphism_test.py b/pGroupCohomology-3.3.2/pGroupCohomology/isomorphism_test.py -index 37627c4..dd2bb85 100644 ---- a/pGroupCohomology-3.3.2/pGroupCohomology/isomorphism_test.py -+++ b/pGroupCohomology-3.3.2/pGroupCohomology/isomorphism_test.py -@@ -218,7 +218,7 @@ class IsomorphismTest: - i = self.singular._next_var_name() - self.singular.eval('for (int %s=1; %s<=size(%s[2]); %s++){%s[2][%s]="@"+%s[2][%s];} kill %s;'%(i,i,L.name(),i,L.name(), i,L.name(),i,i)) - if self._domain.base_ring().characteristic()%2: -- self.singular.LIB("poly.lib") -+ self.singular.LIB("polylib.lib") - self._dim_command = 'GKdim' - #self._R_elim = self.singular('gcRingSum(ring(%s))+%s'%(L.name(),self._SD.name())) - else: -diff --git a/singular_helper/dickson.lib b/singular_helper/dickson.lib -index 3284920..dc1c69f 100644 ---- a/singular_helper/dickson.lib -+++ b/singular_helper/dickson.lib -@@ -21,7 +21,7 @@ - //***************************************************************************** - - LIB "general.lib"; --LIB "poly.lib"; -+LIB "polylib.lib"; - //LIB "ring.lib"; // for changeord - - // Auxiliar procedure, since NF in non-commutative rings now removes zeroes from ideals: diff --git a/build/pkgs/p_group_cohomology/patches/set_default_prec.patch b/build/pkgs/p_group_cohomology/patches/set_default_prec.patch deleted file mode 100644 index ddcb2148598..00000000000 --- a/build/pkgs/p_group_cohomology/patches/set_default_prec.patch +++ /dev/null @@ -1,32 +0,0 @@ -diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/barcode.py b/pGroupCohomology-3.3.2/pGroupCohomology/barcode.py -index 635aed0..291df0b 100644 ---- a/pGroupCohomology-3.3.2/pGroupCohomology/barcode.py -+++ b/pGroupCohomology-3.3.2/pGroupCohomology/barcode.py -@@ -534,7 +534,6 @@ class BarCode(object): - [ 0 0 16] - - """ -- _PSRing = PowerSeriesRing(QQ, names=['t']) - def __init__(self, L, **MetaData): - r""" - NOTE: -@@ -708,16 +707,16 @@ class BarCode(object): - [0 0 4] - - """ -- self._PSRing.set_default_prec(d+3) -+ _PSRing = PowerSeriesRing(QQ, names=['t'], default_prec=d+3) - D = {} - l = self._length - for i in range(-l,l+1): - for j in range(i,l+1): - if (i,j) in self._L: - if hasattr(self._L[i,j],'numerator'): -- D[i,j] = (self._PSRing(self._L[i,j].numerator())/self._PSRing(self._L[i,j].denominator()))[d] -+ D[i,j] = (_PSRing(self._L[i,j].numerator())/_PSRing(self._L[i,j].denominator()))[d] - else: -- D[i,j] = (self._PSRing(self._L[i,j]))[d] -+ D[i,j] = (_PSRing(self._L[i,j]))[d] - else: - D[i,j] = 0 - OUT = BarCode2d(D, **(self._Meta)) diff --git a/build/pkgs/p_group_cohomology/patches/trivial_doctests.patch b/build/pkgs/p_group_cohomology/patches/trivial_doctests.patch deleted file mode 100644 index 5a5b6809247..00000000000 --- a/build/pkgs/p_group_cohomology/patches/trivial_doctests.patch +++ /dev/null @@ -1,77 +0,0 @@ -diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/cochain.pyx b/pGroupCohomology-3.3.2/pGroupCohomology/cochain.pyx -index 881d59f..87174c9 100644 ---- a/pGroupCohomology-3.3.2/pGroupCohomology/cochain.pyx -+++ b/pGroupCohomology-3.3.2/pGroupCohomology/cochain.pyx -@@ -115,7 +115,7 @@ Note that the generators of ``HD`` are :class:`COCH`, while those of - formed by :class:`MODCOCH`:: - - sage: type(HD.1) -- -+ - sage: type(HS.1) - - sage: type(resS_D(HS.1)) -@@ -185,7 +185,7 @@ class COCH_unpickle_class: - sage: H.make() - sage: C=H.2 - sage: type(C) -- -+ - sage: D = loads(dumps(C)) #indirect doctest - sage: print(C) - 1-Cocycle in H^*(D8; GF(2)), -@@ -633,7 +633,7 @@ cdef class COCH(RingElement): - sage: c = H.1+H.3*H.4; c - c_2_1+(a_1_0)*(a_1_1): 2-Cocycle in H^*(SmallGroup(32,4); GF(2)) - sage: type(c) -- -+ - sage: C = c._MODCOCH_() - sage: type(C) - -@@ -1274,7 +1274,7 @@ cdef class COCH(RingElement): - sage: X = CohomologyRing(720,763,prime=2) - sage: X.make() - sage: type(X.sylow_cohomology()('c_2_5*b_1_0')) -- -+ - sage: type(X.3.as_cocycle_in_sylow()) - - sage: print(X.sylow_cohomology()('c_2_5*b_1_0')+X.3.as_cocycle_in_sylow()) -@@ -2020,7 +2020,7 @@ class MODCOCH(RingElement): - sage: H.1 - c_2_2: 2-Cocycle in H^*(D8; GF(2)) - sage: type(H.1) -- -+ - sage: from pGroupCohomology.cochain import MODCOCH - sage: c = MODCOCH(H, singular(H.1), name='foo') # indirect doctest - sage: c -diff --git a/pGroupCohomology-3.3.2/pGroupCohomology/resolution.pyx b/pGroupCohomology-3.3.2/pGroupCohomology/resolution.pyx -index 9c07f2b..b1a4822 100644 ---- a/pGroupCohomology-3.3.2/pGroupCohomology/resolution.pyx -+++ b/pGroupCohomology-3.3.2/pGroupCohomology/resolution.pyx -@@ -1075,7 +1075,6 @@ cdef class RESL: - sage: gstem='8gp3' - sage: gps_folder=os.path.join(tmp_root,gstem) - sage: res_folder=os.path.join(gps_folder,'dat') -- sage: m=get_memory_usage() - sage: R=RESL(gstem,gps_folder,res_folder) - sage: R.nextDiff() - sage: R.nextDiff() -@@ -1108,7 +1107,6 @@ cdef class RESL: - sage: gstem='8gp3' - sage: gps_folder=os.path.join(tmp_root,gstem) - sage: res_folder=os.path.join(gps_folder,'dat') -- sage: m=get_memory_usage() - sage: R=RESL(gstem,gps_folder,res_folder) - sage: R.nextDiff() - sage: R.nextDiff() -@@ -1155,7 +1153,6 @@ cdef class RESL: - sage: gstem='8gp3' - sage: gps_folder=os.path.join(tmp_root,gstem) - sage: res_folder=os.path.join(gps_folder,'dat') -- sage: m=get_memory_usage() - sage: R=RESL(gstem,gps_folder,res_folder) - sage: R.nextDiff() - sage: R.nextDiff() diff --git a/build/pkgs/p_group_cohomology/spkg-postinst.in b/build/pkgs/p_group_cohomology/spkg-postinst.in index bb0ada84357..cd0ece5ab37 100644 --- a/build/pkgs/p_group_cohomology/spkg-postinst.in +++ b/build/pkgs/p_group_cohomology/spkg-postinst.in @@ -1,10 +1,5 @@ cd src -# install helper modules -mv gap_helper p_group_cohomology_helper -sdh_install p_group_cohomology_helper "$SAGE_SHARE/gap/pkg" || sdh_die "Error installing GAP helper module" -sdh_install singular_helper/dickson.lib "$SAGE_SHARE/singular/LIB/" || sdh_die "Error installing Singular helper module" - # building pGroupCohomology's documentation if [ "x$SAGE_SPKG_INSTALL_DOCS" = xyes ] ; then From 5898668196fef35f4741f8bb640f2d27819ea8b2 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 9 Mar 2022 19:44:09 +0000 Subject: [PATCH 276/591] package update - to use __file__ --- build/pkgs/p_group_cohomology/checksums.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/p_group_cohomology/checksums.ini b/build/pkgs/p_group_cohomology/checksums.ini index 037adebe13b..7bd24c14471 100644 --- a/build/pkgs/p_group_cohomology/checksums.ini +++ b/build/pkgs/p_group_cohomology/checksums.ini @@ -1,5 +1,5 @@ tarball=p_group_cohomology-VERSION.tar.xz -sha1=219ff8c28408d2457b9e929af6d59ffceb4d3191 -md5=7bf803ae191a27b881f148d2ac350650 -cksum=163652230 +sha1=20df3a5e672fd60b1179d7e6bd0d741734c1a3a6 +md5=152b6a3af871d9d4cc9930b75544479e +cksum=218472909 upstream_url=https://github.com/sagemath/p_group_cohomology/releases/download/vVERSION/p_group_cohomology-VERSION.tar.xz From 31edb848da843125a0230f1752c0607710d400c3 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 9 Mar 2022 22:51:55 +0000 Subject: [PATCH 277/591] package update to fix path to GAP package --- build/pkgs/p_group_cohomology/checksums.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/p_group_cohomology/checksums.ini b/build/pkgs/p_group_cohomology/checksums.ini index 7bd24c14471..2f5d6e8f3b5 100644 --- a/build/pkgs/p_group_cohomology/checksums.ini +++ b/build/pkgs/p_group_cohomology/checksums.ini @@ -1,5 +1,5 @@ tarball=p_group_cohomology-VERSION.tar.xz -sha1=20df3a5e672fd60b1179d7e6bd0d741734c1a3a6 -md5=152b6a3af871d9d4cc9930b75544479e -cksum=218472909 +sha1=d1d9a54f212a6de7d6a7e3afff80ffc3475264ad +md5=9a57cd7dd045dfd5e014473d543060c2 +cksum=2489285741 upstream_url=https://github.com/sagemath/p_group_cohomology/releases/download/vVERSION/p_group_cohomology-VERSION.tar.xz From 0b9db49a459b78c018f610f23ec9c79562e56b62 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 9 Aug 2022 13:21:07 +0800 Subject: [PATCH 278/591] avoid failing code path by passing tuple to GF constructor This seems to fix the crashes (see #34281). It's obviously an ugly hack to get things to work properly. At some point, someone should really find the root cause of the issue and resolve it properly. --- src/sage/rings/polynomial/pbori/pbori.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index 413a09656e6..e369473c3c4 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -411,7 +411,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): pbnames = tuple(names) names = [name.replace('(', '').replace(')', '') for name in pbnames] - MPolynomialRing_base.__init__(self, GF(2), n, names, order) + MPolynomialRing_base.__init__(self, GF((2,1)), n, names, order) counter = 0 for i in range(len(order.blocks()) - 1): @@ -1928,7 +1928,7 @@ class BooleanMonomialMonoid(UniqueRepresentation, Monoid_class): cdef BooleanMonomial m self._ring = polring from sage.categories.monoids import Monoids - Parent.__init__(self, GF(2), names=polring._names, category=Monoids().Commutative()) + Parent.__init__(self, GF((2,1)), names=polring._names, category=Monoids().Commutative()) m = new_BM(self, polring) m._pbmonom = PBMonom(polring._pbring) From c5bd05276b5901e047cc247094673953c20a8d30 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Aug 2022 23:04:36 -0700 Subject: [PATCH 279/591] src/sage/interfaces/polymake.py: Remove deprecated Polymake_expect --- src/sage/interfaces/polymake.py | 696 +------------------------------- 1 file changed, 3 insertions(+), 693 deletions(-) diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index e335f33ae0a..c34e72a21c7 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -114,34 +114,11 @@ class PolymakeAbstract(ExtraTabCompletion, Interface): EXAMPLES:: - sage: from sage.interfaces.polymake import PolymakeAbstract, polymake_expect, polymake_jupymake + sage: from sage.interfaces.polymake import PolymakeAbstract, polymake_jupymake We test the verbosity management with very early doctests because messages will not be repeated. - Testing the deprecated pexpect-based interface:: - - sage: type(polymake_expect) - <...sage.interfaces.polymake.PolymakeExpect... - sage: isinstance(polymake_expect, PolymakeAbstract) - True - sage: p = polymake_expect.rand_sphere(4, 20, seed=5) # optional - polymake_expect - doctest...: DeprecationWarning: the pexpect-based interface to - polymake is deprecated. - Install package jupymake so that Sage can use the more robust - jupymake-based interface to polymake - See https://trac.sagemath.org/27745 for details. - sage: p # optional - polymake_expect - Random spherical polytope of dimension 4; seed=5... - sage: set_verbose(3) - sage: p.H_VECTOR # optional - polymake_expect - used package ppl - The Parma Polyhedra Library ... - 1 16 40 16 1 - sage: set_verbose(0) - sage: p.F_VECTOR # optional - polymake_expect - 20 94 148 74 - Testing the JuPyMake interface:: sage: isinstance(polymake_jupymake, PolymakeAbstract) @@ -180,15 +157,6 @@ def version(self): sage: polymake.version() # optional - polymake # random '4...' - - TESTS:: - - sage: from sage.interfaces.polymake import Polymake - sage: Polymake(command='foobar').version() - Traceback (most recent call last): - ... - RuntimeError: runtime error with deprecated pexpect-based interface to polymake; please install jupymake - """ return self.get('$Polymake::Version') @@ -1080,8 +1048,6 @@ def __bool__(self): cmd = '{} {} {};'.format(self._name, P._equality_symbol(), t) return P.get(cmd) == t - - def known_properties(self): """ List the names of properties that have been computed so far on this element. @@ -1827,655 +1793,6 @@ def _sage_doc_(self): return P.help(self._name.split("->")[-1], pager=False) -class PolymakeExpect(PolymakeAbstract, Expect): - r""" - Interface to the polymake interpreter using pexpect. - - In order to use this interface, you need to either install the - optional polymake package for Sage, or install polymake system-wide - on your computer; it is available from https://polymake.org. - - Type ``polymake.[tab]`` for a list of most functions - available from your polymake install. Type - ``polymake.Function?`` for polymake's help about a given ``Function``. - Type ``polymake(...)`` to create a new polymake - object, and ``polymake.eval(...)`` to run a string using - polymake and get the result back as a string. - - EXAMPLES:: - - sage: from sage.interfaces.polymake import polymake_expect as polymake - sage: type(polymake) - <...sage.interfaces.polymake.PolymakeExpect... - sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - polymake_expect - sage: p # optional - polymake_expect - Random spherical polytope of dimension 4; seed=5... - sage: set_verbose(3) - sage: p.H_VECTOR; # optional - polymake_expect # random - used package ppl - The Parma Polyhedra Library ... - sage: p.H_VECTOR # optional - polymake_expect - 1 16 40 16 1 - sage: set_verbose(0) - sage: p.F_VECTOR # optional - polymake_expect - 20 94 148 74 - sage: print(p.F_VECTOR._sage_doc_()) # optional - polymake_expect # random - property_types/Algebraic Types/Vector: - A type for vectors with entries of type Element. - - You can perform algebraic operations such as addition or scalar multiplication. - - You can create a new Vector by entering its elements, e.g.: - $v = new Vector(1,2,3); - or - $v = new Vector([1,2,3]); - - .. automethod:: _eval_line - """ - - def __init__(self, script_subdirectory=None, - logfile=None, server=None, server_tmpdir=None, - seed=None, command=None): - """ - TESTS:: - - sage: from sage.interfaces.polymake import PolymakeExpect - sage: PolymakeExpect() - Polymake - sage: PolymakeExpect().is_running() - False - - """ - if command is None: - command = "env TERM=dumb {}".format(os.getenv('SAGE_POLYMAKE_COMMAND') or 'polymake') - PolymakeAbstract.__init__(self, seed=seed) - Expect.__init__(self, - name="polymake", - command=command, - prompt="polytope > ", - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - logfile=logfile, - eval_using_file_cutoff=1024) # > 1024 causes hangs - - def _start(self, alt_message=None): - """ - Start the polymake interface in the application "polytope". - - .. NOTE:: - - There should be no need to call this explicitly. - - TESTS:: - - sage: from sage.interfaces.polymake import polymake_expect as polymake - sage: polymake.application('fan') # optional - polymake_expect - sage: 'normal_fan' in dir(polymake) # optional - polymake_expect - True - sage: polymake.quit() # optional - polymake_expect - sage: polymake._start() # optional - polymake_expect - doctest...: DeprecationWarning: the pexpect-based interface to - polymake is deprecated. - Install package jupymake so that Sage can use the more robust - jupymake-based interface to polymake - See https://trac.sagemath.org/27745 for details. - - Since 'normal_fan' is not defined in the polymake application 'polytope', - we now get:: - - sage: 'normal_fan' in dir(polymake) # optional - polymake_expect - False - - """ - from sage.misc.superseded import deprecation - if not self.is_running(): - try: - self._change_prompt("polytope > ") - Expect._start(self, alt_message=None) - except RuntimeError: - raise RuntimeError("runtime error with deprecated pexpect-based interface to polymake; please install jupymake") - deprecation(27745, "the pexpect-based interface to polymake is deprecated. Install package jupymake so that Sage can use the more robust jupymake-based interface to polymake") - PolymakeAbstract._start(self) - self.eval('use File::Slurp;') - - def _quit_string(self): - """ - TESTS:: - - sage: from sage.interfaces.polymake import polymake_expect as polymake - sage: polymake._quit_string() - 'exit;' - """ - return "exit;" - - def _keyboard_interrupt(self): - r""" - Interrupt a computation with . - - TESTS: - - For reasons that are not clear to the author, the following test - is very flaky. Therefore, this test is marked as "not tested". :: - - sage: from sage.interfaces.polymake import polymake_expect as polymake - sage: c = polymake.cube(15) # optional - polymake_expect - sage: alarm(1) # not tested - sage: try: # not tested # indirect doctest - ....: c.F_VECTOR - ....: except KeyboardInterrupt: - ....: pass - Interrupting Polymake... - doctest:warning - ... - RuntimeWarning: We ignore that Polymake issues warning during keyboard interrupt - doctest:warning - ... - RuntimeWarning: We ignore that Polymake raises error during keyboard interrupt - - Afterwards, the interface should still be running. :: - - sage: c.N_FACETS # optional - polymake_expect - 30 - - """ - if not self.is_running(): - raise KeyboardInterrupt - print("Interrupting %s..." % self) - while True: - try: - self._expect.send(chr(3)) - except pexpect.ExceptionPexpect as msg: - raise pexpect.ExceptionPexpect("THIS IS A BUG -- PLEASE REPORT. This should never happen.\n" + msg) - sleep(0.1) - i = self._expect.expect_list(self._prompt, timeout=1) - if i == 0: - break - elif i == 7: # EOF - warnings.warn("Polymake {} during keyboard interrupt".format(_available_polymake_answers[i]), RuntimeWarning) - self._crash_msg() - self.quit() - elif i == 8: # Timeout - self.quit() - raise RuntimeError("{} interface is not responding. We closed it".format(self)) - elif i != 3: # Anything but a "computation killed" - warnings.warn("We ignore that {} {} during keyboard interrupt".format(self, _available_polymake_answers[i]), RuntimeWarning) - raise KeyboardInterrupt("Ctrl-c pressed while running {}".format(self)) - - def _synchronize(self): - """ - TESTS:: - - sage: from sage.interfaces.polymake import polymake_expect as polymake - sage: Q = polymake.cube(4) # optional - polymake_expect - sage: polymake('"ok"') # optional - polymake_expect - ok - sage: polymake._expect.sendline() # optional - polymake_expect - 1 - - Now the interface is badly out of sync:: - - sage: polymake('"foobar"') # optional - polymake_expect - ) failed: - ...PolymakeError: Can't locate object method "description" via package "1" - (perhaps you forgot to load "1"?)...> - sage: Q.typeof() # optional - polymake_expect # random - ('foobar...', 'Polymake::polytope::Polytope__Rational') - sage: Q.typeof.clear_cache() # optional - polymake_expect - - After synchronisation, things work again as expected:: - - sage: polymake._synchronize() # optional - polymake_expect - doctest:warning - ... - UserWarning: Polymake seems out of sync: - The expected output did not appear before reaching the next prompt. - sage: polymake('"back to normal"') # optional - polymake_expect - back to normal - sage: Q.typeof() # optional - polymake_expect - ('Polymake::polytope::Polytope__Rational', 'ARRAY') - - """ - if not self.is_running(): - return - rnd = randrange(2147483647) - res = str(rnd+1) - cmd = 'print 1+{};' + os.linesep - self._sendstr(cmd.format(rnd)) - pat = self._expect.expect(self._prompt, timeout=0.5) - # 0: normal prompt - # 1: continuation prompt - # 2: user input expected when requestion "help" - # 3: what we are looking for when interrupting a computation - # 4: error - # 5: warning - # 6: anything but an error or warning, thus, an information - # 7: unexpected end of the stream - # 8: (expected) timeout - if pat == 8: # timeout - warnings.warn("{} unexpectedly {} during synchronisation.".format(self, _available_polymake_answers[pat]), RuntimeWarning) - self.interrupt() - # ... but we continue, as that probably means we currently are at the end of the buffer - elif pat == 7: # EOF - self._crash_msg() - self.quit() - elif pat == 0: - # We got the right prompt, but perhaps in a wrong position in the stream - # The result of the addition should appear *before* our prompt - if res not in bytes_to_str(self._expect.before): - try: - warnings.warn("{} seems out of sync: The expected output did not appear before reaching the next prompt.".format(self)) - while True: - i = self._expect.expect_list(self._prompt, timeout=0.1) - if i == 8: # This time, we do expect a timeout - return - elif i > 0: - raise RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[i])) - except pexpect.TIMEOUT: - warnings.warn("A timeout has occurred when synchronising {}.".format(self), RuntimeWarning) - self._interrupt() - except pexpect.EOF: - self._crash_msg() - self.quit() - else: - return - else: - raise RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[pat])) - - def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=True, **kwds): - r""" - Evaluate a command. - - INPUT: - - - ``line`` -- string; a command to be evaluated - - ``allow_use_file`` -- (default: ``True``) bool; whether or not - to use a file if the line is very long - - ``wait_for_prompt`` -- (default: ``True``) bool; whether or not - to wait before polymake returns a prompt. If it is a string, it is - considered as alternative prompt to be waited for - - ``restart_if_needed`` (default: ``True``) bool; whether or - not to restart polymake in case something goes wrong - - further optional arguments (e.g., timeout) that will be passed to - :meth:`pexpect.pty_spawn.spawn.expect`. Note that they are ignored - if the line is too long and thus is evaluated via a file. So, - if a timeout is defined, it should be accompanied by - ``allow_use_file=False``. - - Different reaction types of polymake, including warnings, comments, - errors, request for user interaction, and yielding a continuation prompt, - are taken into account. - - Usually, this method is indirectly called via - :meth:`~sage.interfaces.expect.Expect.eval`. - - EXAMPLES:: - - sage: from sage.interfaces.polymake import polymake_expect as polymake # optional - polymake_expect - sage: p = polymake.cube(3) # optional - polymake_expect # indirect doctest - - Here we see that remarks printed by polymake are displayed if - the verbosity is positive:: - - sage: set_verbose(1) - sage: p.N_LATTICE_POINTS # optional - polymake_expect # random - used package latte - LattE (Lattice point Enumeration) is a computer software dedicated to the - problems of counting lattice points and integration inside convex polytopes. - Copyright by Matthias Koeppe, Jesus A. De Loera and others. - http://www.math.ucdavis.edu/~latte/ - 27 - sage: set_verbose(0) - - If polymake raises an error, the polymake *interface* raises - a :class:`PolymakeError`:: - - sage: polymake.eval('FOOBAR(3);') # optional - polymake_expect - Traceback (most recent call last): - ... - PolymakeError: Undefined subroutine &Polymake::User::FOOBAR called... - - If a command is incomplete, then polymake returns a continuation - prompt. In that case, we raise an error:: - - sage: polymake.eval('print 3') # optional - polymake_expect - Traceback (most recent call last): - ... - SyntaxError: Incomplete polymake command 'print 3' - sage: polymake.eval('print 3;') # optional - polymake_expect - '3' - - However, if the command contains line breaks but eventually is complete, - no error is raised:: - - sage: print(polymake.eval('$tmp="abc";\nprint $tmp;')) # optional - polymake_expect - abc - - When requesting help, polymake sometimes expect the user to choose - from a list. In that situation, we abort with a warning, and show - the list from which the user can choose; we could demonstrate this using - the :meth:`help` method, but here we use an explicit code evaluation:: - - sage: print(polymake.eval('help "TRIANGULATION";')) # optional - polymake_expect # random - doctest:warning - ... - UserWarning: Polymake expects user interaction. We abort and return - the options that Polymake provides. - There are 5 help topics matching 'TRIANGULATION': - 1: objects/Cone/properties/Triangulation and volume/TRIANGULATION - 2: objects/Polytope/properties/Triangulation and volume/TRIANGULATION - 3: objects/Visualization/Visual::PointConfiguration/methods/TRIANGULATION - 4: objects/Visualization/Visual::Polytope/methods/TRIANGULATION - 5: objects/PointConfiguration/properties/Triangulation and volume/TRIANGULATION - - By default, we just wait until polymake returns a result. However, - it is possible to explicitly set a timeout. The following usually does - work in an interactive session and often in doc tests, too. However, - sometimes it hangs, and therefore we remove it from the tests, for now:: - - sage: c = polymake.cube(15) # optional - polymake_expect - sage: polymake.eval('print {}->F_VECTOR;'.format(c.name()), timeout=1) # not tested # optional - polymake_expect - Traceback (most recent call last): - ... - RuntimeError: Polymake fails to respond timely - - We verify that after the timeout, polymake is still able to give answers:: - - sage: c # optional - polymake_expect - cube of dimension 15 - sage: c.N_VERTICES # optional - polymake_expect - 32768 - - Note, however, that the recovery after a timeout is not perfect. - It may happen that in some situation the interface collapses and - thus polymake would automatically be restarted, thereby losing all - data that have been computed before. - - """ - line = line.strip() - if allow_use_file and wait_for_prompt and self._eval_using_file_cutoff and len(line) > self._eval_using_file_cutoff: - return self._eval_line_using_file(line) - try: - if not self.is_running(): - self._start() - E = self._expect - try: - if len(line) >= 4096: - raise RuntimeError("Sending more than 4096 characters with {} on a line may cause a hang and you're sending {} characters".format(self, len(line))) - E.sendline(line) - if not wait_for_prompt: - return '' - - except OSError as msg: - if restart_if_needed: - # The subprocess most likely crashed. - # If it's really still alive, we fall through - # and raise RuntimeError. - if sys.platform.startswith('sunos'): - # On (Open)Solaris, we might need to wait a - # while because the process might not die - # immediately. See Trac #14371. - for t in [0.5, 1.0, 2.0]: - if E.isalive(): - time.sleep(t) - else: - break - if not E.isalive(): - try: - self._synchronize() - except (TypeError, RuntimeError): - pass - return self._eval_line(line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False, **kwds) - raise RuntimeError("{}\nError evaluating {} in {}".format(msg, line, self)) - - p_warnings = [] - p_errors = [] - have_warning = False - have_error = False - have_log = False - if len(line) > 0: - first = True - while True: - try: - if isinstance(wait_for_prompt, str): - pat = E.expect(wait_for_prompt, **kwds) - else: - pat = E.expect_list(self._prompt, **kwds) - except pexpect.EOF as msg: - try: - if self.is_local(): - tmp_to_use = self._local_tmpfile() - else: - tmp_to_use = self._remote_tmpfile() - if self._read_in_file_command(tmp_to_use) in line: - raise pexpect.EOF(msg) - except NotImplementedError: - pass - if self._quit_string() in line: - # we expect to get an EOF if we're quitting. - return '' - elif restart_if_needed: # the subprocess might have crashed - try: - self._synchronize() - return self._eval_line(line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt, restart_if_needed=False, **kwds) - except (TypeError, RuntimeError): - pass - raise RuntimeError("{}\n{} crashed executing {}".format(msg, self, line)) - if self._terminal_echo: - out = E.before - else: - out = E.before.rstrip(b'\n\r') - if self._terminal_echo and first: - i = out.find(b"\n") - j = out.rfind(b"\r") - out = out[i + 1:j].replace(b'\r\n', b'\n') - else: - out = out.strip().replace(b'\r\n', b'\n') - first = False - if have_error: - p_errors.append(out) - have_error = False - out = b"" - elif have_warning: - p_warnings.append(out) - have_warning = False - out = b"" - elif have_log: - if get_verbose() > 0: - print(bytes_to_str(out)) - have_log = False - out = b"" - # 0: normal prompt - # 1: continuation prompt - # 2: user input expected when requestion "help" - # 3: what we are looking for when interrupting a computation - # 4: error - # 5: warning - # 6: anything but an error or warning, thus, an information - # 7: unexpected end of the stream - # 8: (expected) timeout - if pat == 0: - have_log = False - have_error = False - have_warning = False - if E.buffer: - if not E.buffer.strip(): - E.send(chr(3)) - sleep(0.1) - pat = E.expect_list(self._prompt) - if E.buffer or pat: - raise RuntimeError("Couldn't return to prompt after command '{}'".format(line)) - break - elif pat == 1: # unexpected continuation prompt - # Return to normal prompt - i = pat - E.send(chr(3)) - sleep(0.1) - i = E.expect_list(self._prompt) - assert i == 0, "Command '{}': Couldn't return to normal prompt after polymake {}. Instead, polymake {}".format(line, _available_polymake_answers[pat], _available_polymake_answers[i]) - raise SyntaxError("Incomplete polymake command '{}'".format(line)) - elif pat == 2: # request for user interaction - # Return to normal prompt - warnings.warn("{} expects user interaction. We abort and return the options that {} provides.".format(self, self)) - i = pat - while i: - self._expect.sendline(chr(3)) - sleep(0.1) - i = self._expect.expect(self._prompt, timeout=0.1) - # User interaction is expected to happen when requesting help - if line.startswith('help'): - out = str_to_bytes(os.linesep).join(out.split(str_to_bytes(os.linesep))[:-1]) - break - else: - RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[pat])) - elif pat == 3: # killed by signal - i = pat - while pat != 0: - E.send(chr(3)) - sleep(0.1) - i = E.expect_list(self._prompt) - RuntimeError("Polymake unexpectedly {}".format(_available_polymake_answers[pat])) - elif pat == 4: # polymake error - have_error = True - elif pat == 5: # polymake warning - have_warning = True - elif pat == 6: # apparently polymake prints a comment - have_log = True - elif pat == 7: # we have reached the end of the buffer - warnings.warn("Polymake unexpectedly {}".format(_available_polymake_answers[pat]), RuntimeWarning) - E.buffer = E.before + E.after + E.buffer - break - else: # timeout or some other problem - # Polymake would still continue with the computation. Thus, we send an interrupt - E.send(chr(3)) - sleep(0.1) - while E.expect_list(self._prompt, timeout=0.1): - # ... and since a single Ctrl-c just interrupts *one* of polymake's - # rule chains, we repeat until polymake is running out of rules. - E.send(chr(3)) - sleep(0.1) - raise RuntimeError("Polymake {}".format(_available_polymake_answers[pat])) - else: - out = b'' - except KeyboardInterrupt: - self._keyboard_interrupt() - raise KeyboardInterrupt("Ctrl-c pressed while running {}".format(self)) - for w in p_warnings: - warnings.warn(bytes_to_str(w), RuntimeWarning) - for e in p_errors: - raise PolymakeError(bytes_to_str(e)) - return bytes_to_str(out) - - def application(self, app): - """ - Change to a given polymake application. - - INPUT: - - - ``app``, a string, one of "common", "fulton", "group", "matroid", "topaz", - "fan", "graph", "ideal", "polytope", "tropical" - - EXAMPLES: - - We expose a computation that uses both the 'polytope' and the 'fan' - application of polymake. Let us start by defining a polytope `q` in - terms of inequalities. Polymake knows to compute the f- and h-vector - and finds that the polytope is very ample:: - - sage: from sage.interfaces.polymake import polymake_expect as polymake - sage: q = polymake.new_object("Polytope", INEQUALITIES=[[5,-4,0,1],[-3,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1],[1,0,-1,0],[3,-1,0,0]]) # optional - polymake_expect - sage: q.H_VECTOR # optional - polymake_expect - 1 5 5 1 - sage: q.F_VECTOR # optional - polymake_expect - 8 14 8 - sage: q.VERY_AMPLE # optional - polymake_expect - true - - In the application 'fan', polymake can now compute the normal fan - of `q` and its (primitive) rays:: - - sage: polymake.application('fan') # optional - polymake_expect - sage: g = q.normal_fan() # optional - polymake_expect - sage: g.RAYS # optional - polymake_expect - -1 0 1/4 - 0 -1 1/4 - 1 0 0 - 1 1 -1/4 - 0 1 0 - 0 0 -1 - 0 -1 0 - -1 0 0 - sage: g.RAYS.primitive() # optional - polymake_expect - -4 0 1 - 0 -4 1 - 1 0 0 - 4 4 -1 - 0 1 0 - 0 0 -1 - 0 -1 0 - -1 0 0 - - Note that the list of functions available by tab completion depends - on the application. - - TESTS: - - Since 'trop_witness' is not defined in the polymake application 'polytope' - but only in 'tropical', the following shows the effect of changing - the application. :: - - sage: polymake.application('polytope') # optional - polymake_expect - sage: 'trop_witness' in dir(polymake) # optional - polymake_expect - False - sage: polymake.application('tropical') # optional - polymake_expect - sage: 'trop_witness' in dir(polymake) # optional - polymake_expect - True - sage: polymake.application('polytope') # optional - polymake_expect - sage: 'trop_witness' in dir(polymake) # optional - polymake_expect - False - - For completeness, we show what happens when asking for an application - that doesn't exist:: - - sage: polymake.application('killerapp') # optional - polymake_expect - Traceback (most recent call last): - ... - ValueError: Unknown polymake application 'killerapp' - - Of course, a different error results when we send an explicit - command in polymake to change to an unknown application:: - - sage: polymake.eval('application "killerapp";') # optional - polymake_expect - Traceback (most recent call last): - ... - PolymakeError: Unknown application killerapp - - """ - if not self.is_running(): - self._start() - if app not in ["common", "fulton", "group", "matroid", "topaz", "fan", "graph", "ideal", "polytope", "tropical"]: - raise ValueError("Unknown polymake application '{}'".format(app)) - self._application = app - patterns = ["{} > ".format(app), # 0: normal prompt - r"{} \([0-9]+\)> ".format(app), # 1: continuation prompt - "Please choose ", # 2: user input expected when requesting "help" - "killed by signal", # 3: what we are looking for when interrupting a computation - "polymake: +ERROR: +", # 4: error - "polymake: +WARNING: +", # 5: warning - "polymake: +", # 6: anything but an error or warning, thus, an information - pexpect.EOF, # 7: unexpected end of the stream - pexpect.TIMEOUT] # 8: timeout - self._change_prompt(self._expect.compile_pattern_list(patterns)) - self._sendstr('application "{}";{}'.format(app, os.linesep)) - pat = self._expect.expect_list(self._prompt) - if pat: - raise RuntimeError("When changing the application, polymake unexpectedly {}".format(_available_polymake_answers[pat])) - - -Polymake = PolymakeExpect - - class PolymakeJuPyMake(PolymakeAbstract): r""" Interface to the polymake interpreter using JuPyMake. @@ -2730,13 +2047,6 @@ def reduce_load_Polymake(): return polymake -polymake_expect = PolymakeExpect() - -polymake_jupymake = PolymakeJuPyMake() - -from sage.features import PythonModule -if PythonModule("JuPyMake").is_present(): - polymake = polymake_jupymake -else: - polymake = polymake_expect +Polymake = PolymakeJuPyMake +polymake = polymake_jupymake = PolymakeJuPyMake() From 1927882c2a7ead8743e6a5179d073b1b391d106c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Aug 2022 23:13:45 -0700 Subject: [PATCH 280/591] Replace '# optional - polymake' with '# optional - jupymake' --- .../geometry/polyhedra_tutorial.rst | 4 +- .../combinat/root_system/associahedron.py | 2 +- .../geometry/polyhedron/backend_polymake.py | 194 ++++----- src/sage/geometry/polyhedron/base.py | 36 +- src/sage/geometry/polyhedron/base0.py | 4 +- src/sage/geometry/polyhedron/face.py | 2 +- src/sage/geometry/polyhedron/parent.py | 2 +- src/sage/interfaces/polymake.py | 400 +++++++++--------- src/sage/matrix/matrix1.pyx | 4 +- src/sage/matrix/matrix_space.py | 4 +- src/sage/rings/integer_ring.pyx | 2 +- src/sage/rings/number_field/number_field.py | 2 +- .../number_field_element_quadratic.pyx | 10 +- src/sage/rings/rational_field.py | 2 +- src/sage/rings/real_double.pyx | 2 +- 15 files changed, 335 insertions(+), 335 deletions(-) diff --git a/src/doc/en/thematic_tutorials/geometry/polyhedra_tutorial.rst b/src/doc/en/thematic_tutorials/geometry/polyhedra_tutorial.rst index cb4ad1faa2e..b7d689e5ca3 100644 --- a/src/doc/en/thematic_tutorials/geometry/polyhedra_tutorial.rst +++ b/src/doc/en/thematic_tutorials/geometry/polyhedra_tutorial.rst @@ -646,7 +646,7 @@ for sage is installed. :: - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - polymake + sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - jupymake ....: rays=[(1,1)], lines=[], ....: backend='polymake', base_ring=QQ) @@ -657,7 +657,7 @@ An example with quadratic field: :: sage: V = polytopes.dodecahedron().vertices_list() # optional - sage.rings.number_field - sage: Polyhedron(vertices=V, backend='polymake') # optional - polymake # optional - sage.rings.number_field + sage: Polyhedron(vertices=V, backend='polymake') # optional - jupymake # optional - sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 diff --git a/src/sage/combinat/root_system/associahedron.py b/src/sage/combinat/root_system/associahedron.py index 66b134a35e7..c6765e71eb9 100644 --- a/src/sage/combinat/root_system/associahedron.py +++ b/src/sage/combinat/root_system/associahedron.py @@ -288,7 +288,7 @@ def Associahedra(base_ring, ambient_dim, backend='ppl'): sage: Associahedra(QQ, 4, 'normaliz').parent() # optional - pynormaliz - sage: Associahedra(QQ, 4, 'polymake').parent() # optional - polymake + sage: Associahedra(QQ, 4, 'polymake').parent() # optional - jupymake sage: Associahedra(QQ, 4, 'field').parent() diff --git a/src/sage/geometry/polyhedron/backend_polymake.py b/src/sage/geometry/polyhedron/backend_polymake.py index 97dfdc2c63e..36ccc33c39f 100644 --- a/src/sage/geometry/polyhedron/backend_polymake.py +++ b/src/sage/geometry/polyhedron/backend_polymake.py @@ -56,48 +56,48 @@ class Polyhedron_polymake(Polyhedron_base): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], rays=[(1,1)], # optional - polymake + sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], rays=[(1,1)], # optional - jupymake ....: lines=[], backend='polymake') - sage: TestSuite(p).run() # optional - polymake + sage: TestSuite(p).run() # optional - jupymake A lower-dimensional affine cone; we test that there are no mysterious inequalities coming in from the homogenization:: - sage: P = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], # optional - polymake + sage: P = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], # optional - jupymake ....: backend='polymake') - sage: P.n_inequalities() # optional - polymake + sage: P.n_inequalities() # optional - jupymake 1 - sage: P.equations() # optional - polymake + sage: P.equations() # optional - jupymake (An equation (1, 0) x - 1 == 0,) The empty polyhedron:: - sage: Polyhedron(eqns=[[1, 0, 0]], backend='polymake') # optional - polymake + sage: Polyhedron(eqns=[[1, 0, 0]], backend='polymake') # optional - jupymake The empty polyhedron in QQ^2 It can also be obtained differently:: - sage: P=Polyhedron(ieqs=[[-2, 1, 1], [-3, -1, -1], [-4, 1, -2]], # optional - polymake + sage: P=Polyhedron(ieqs=[[-2, 1, 1], [-3, -1, -1], [-4, 1, -2]], # optional - jupymake ....: backend='polymake') - sage: P # optional - polymake + sage: P # optional - jupymake The empty polyhedron in QQ^2 - sage: P.Vrepresentation() # optional - polymake + sage: P.Vrepresentation() # optional - jupymake () - sage: P.Hrepresentation() # optional - polymake + sage: P.Hrepresentation() # optional - jupymake (An equation -1 == 0,) The full polyhedron:: - sage: Polyhedron(eqns=[[0, 0, 0]], backend='polymake') # optional - polymake + sage: Polyhedron(eqns=[[0, 0, 0]], backend='polymake') # optional - jupymake A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines - sage: Polyhedron(ieqs=[[0, 0, 0]], backend='polymake') # optional - polymake + sage: Polyhedron(ieqs=[[0, 0, 0]], backend='polymake') # optional - jupymake A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 lines Quadratic fields work:: sage: V = polytopes.dodecahedron().vertices_list() # optional - sage.rings.number_field - sage: Polyhedron(vertices=V, backend='polymake') # optional - polymake # optional - sage.rings.number_field + sage: Polyhedron(vertices=V, backend='polymake') # optional - jupymake # optional - sage.rings.number_field A 3-dimensional polyhedron in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 @@ -107,31 +107,31 @@ class Polyhedron_polymake(Polyhedron_base): Tests copied from various methods in :mod:`sage.geometry.polyhedron.base`:: - sage: p = Polyhedron(vertices = [[1,0,0], [0,1,0], [0,0,1]], # optional - polymake + sage: p = Polyhedron(vertices = [[1,0,0], [0,1,0], [0,0,1]], # optional - jupymake ....: backend='polymake') - sage: p.n_equations() # optional - polymake + sage: p.n_equations() # optional - jupymake 1 - sage: p.n_inequalities() # optional - polymake + sage: p.n_inequalities() # optional - jupymake 3 - sage: p = Polyhedron(vertices = [[t,t^2,t^3] for t in range(6)], # optional - polymake + sage: p = Polyhedron(vertices = [[t,t^2,t^3] for t in range(6)], # optional - jupymake ....: backend='polymake') - sage: p.n_facets() # optional - polymake + sage: p.n_facets() # optional - jupymake 8 - sage: p = Polyhedron(vertices = [[1,0],[0,1],[1,1]], rays=[[1,1]], # optional - polymake + sage: p = Polyhedron(vertices = [[1,0],[0,1],[1,1]], rays=[[1,1]], # optional - jupymake ....: backend='polymake') - sage: p.n_vertices() # optional - polymake + sage: p.n_vertices() # optional - jupymake 2 - sage: p = Polyhedron(vertices = [[1,0],[0,1]], rays=[[1,1]], # optional - polymake + sage: p = Polyhedron(vertices = [[1,0],[0,1]], rays=[[1,1]], # optional - jupymake ....: backend='polymake') - sage: p.n_rays() # optional - polymake + sage: p.n_rays() # optional - jupymake 1 - sage: p = Polyhedron(vertices = [[0,0]], rays=[[0,1],[0,-1]], # optional - polymake + sage: p = Polyhedron(vertices = [[0,0]], rays=[[0,1],[0,-1]], # optional - jupymake ....: backend='polymake') - sage: p.n_lines() # optional - polymake + sage: p.n_lines() # optional - jupymake 1 """ @@ -150,10 +150,10 @@ def _is_zero(self, x): EXAMPLES:: - sage: p = Polyhedron([(0,0)], backend='polymake') # optional - polymake - sage: p._is_zero(0) # optional - polymake + sage: p = Polyhedron([(0,0)], backend='polymake') # optional - jupymake + sage: p._is_zero(0) # optional - jupymake True - sage: p._is_zero(1/100000) # optional - polymake + sage: p._is_zero(1/100000) # optional - jupymake False """ return x == 0 @@ -172,10 +172,10 @@ def _is_nonneg(self, x): EXAMPLES:: - sage: p = Polyhedron([(0,0)], backend='polymake') # optional - polymake - sage: p._is_nonneg(1) # optional - polymake + sage: p = Polyhedron([(0,0)], backend='polymake') # optional - jupymake + sage: p._is_nonneg(1) # optional - jupymake True - sage: p._is_nonneg(-1/100000) # optional - polymake + sage: p._is_nonneg(-1/100000) # optional - jupymake False """ return x >= 0 @@ -194,10 +194,10 @@ def _is_positive(self, x): EXAMPLES:: - sage: p = Polyhedron([(0,0)], backend='polymake') # optional - polymake - sage: p._is_positive(1) # optional - polymake + sage: p = Polyhedron([(0,0)], backend='polymake') # optional - jupymake + sage: p._is_positive(1) # optional - jupymake True - sage: p._is_positive(0) # optional - polymake + sage: p._is_positive(0) # optional - jupymake False """ return x > 0 @@ -211,29 +211,29 @@ def __init__(self, parent, Vrep, Hrep, polymake_polytope=None, **kwds): TESTS: - sage: p = Polyhedron(backend='polymake') # optional - polymake - sage: TestSuite(p).run() # optional - polymake - sage: p = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], # optional - polymake + sage: p = Polyhedron(backend='polymake') # optional - jupymake + sage: TestSuite(p).run() # optional - jupymake + sage: p = Polyhedron(vertices=[(1, 1)], rays=[(0, 1)], # optional - jupymake ....: backend='polymake') - sage: TestSuite(p).run() # optional - polymake + sage: TestSuite(p).run() # optional - jupymake We skip the Lawrence test because it involves numerically unstable floating point arithmetic:: - sage: p = Polyhedron(vertices=[(-1,-1), (1,0), (1,1), (0,1)], # optional - polymake + sage: p = Polyhedron(vertices=[(-1,-1), (1,0), (1,1), (0,1)], # optional - jupymake ....: backend='polymake') - sage: TestSuite(p).run(skip='_test_lawrence') # optional - polymake + sage: TestSuite(p).run(skip='_test_lawrence') # optional - jupymake :: - sage: p = Polyhedron(rays=[[1,1]], backend='polymake') # optional - polymake - sage: TestSuite(p).run() # optional - polymake - sage: p = Polyhedron(rays=[[1]], backend='polymake') # optional - polymake - sage: TestSuite(p).run() # optional - polymake - sage: p = Polyhedron(rays=[[1,1,1]], lines=[[1,0,0]], backend='polymake') # optional - polymake - sage: TestSuite(p).run() # optional - polymake - sage: p = Polyhedron(vertices=[[]], backend='polymake') # optional - polymake - sage: TestSuite(p).run() # optional - polymake + sage: p = Polyhedron(rays=[[1,1]], backend='polymake') # optional - jupymake + sage: TestSuite(p).run() # optional - jupymake + sage: p = Polyhedron(rays=[[1]], backend='polymake') # optional - jupymake + sage: TestSuite(p).run() # optional - jupymake + sage: p = Polyhedron(rays=[[1,1,1]], lines=[[1,0,0]], backend='polymake') # optional - jupymake + sage: TestSuite(p).run() # optional - jupymake + sage: p = Polyhedron(vertices=[[]], backend='polymake') # optional - jupymake + sage: TestSuite(p).run() # optional - jupymake """ if polymake_polytope is not None: if Hrep is not None or Vrep is not None: @@ -249,9 +249,9 @@ def _init_from_polymake_polytope(self, polymake_polytope): TESTS:: - sage: p = Polyhedron(backend='polymake') # optional - polymake - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - polymake - sage: Polyhedron_polymake._init_from_Hrepresentation(p, [], []) # indirect doctest # optional - polymake + sage: p = Polyhedron(backend='polymake') # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: Polyhedron_polymake._init_from_Hrepresentation(p, [], []) # indirect doctest # optional - jupymake """ self._polymake_polytope = polymake_polytope self._init_Vrepresentation_from_polymake() @@ -280,9 +280,9 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbo EXAMPLES:: - sage: p = Polyhedron(backend='polymake') # optional - polymake - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - polymake - sage: Polyhedron_polymake._init_from_Vrepresentation(p, [], [], []) # optional - polymake + sage: p = Polyhedron(backend='polymake') # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: Polyhedron_polymake._init_from_Vrepresentation(p, [], [], []) # optional - jupymake """ from sage.interfaces.polymake import polymake data = self._polymake_Vrepresentation_data(vertices, rays, lines) @@ -347,9 +347,9 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): EXAMPLES:: - sage: p = Polyhedron(backend='polymake') # optional - polymake - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - polymake - sage: Polyhedron_polymake._init_from_Hrepresentation(p, [], []) # optional - polymake + sage: p = Polyhedron(backend='polymake') # optional - jupymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: Polyhedron_polymake._init_from_Hrepresentation(p, [], []) # optional - jupymake """ from sage.interfaces.polymake import polymake data = self._polymake_Hrepresentation_data(ieqs, eqns) @@ -420,9 +420,9 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep): sage: parent = Polyhedra_polymake(ZZ, 1, 'polymake') sage: Vrep = [[[0], [1]], [], []] sage: Hrep = [[[0, 1], [1, -1]], []] - sage: p = Polyhedron_polymake(parent, Vrep, Hrep, # indirect doctest # optional - polymake + sage: p = Polyhedron_polymake(parent, Vrep, Hrep, # indirect doctest # optional - jupymake ....: Vrep_minimal=True, Hrep_minimal=True) - sage: p # optional - polymake + sage: p # optional - jupymake A 1-dimensional polyhedron in ZZ^1 defined as the convex hull of 2 vertices """ Vrep = [list(x) for x in Vrep] @@ -482,13 +482,13 @@ def _init_Vrepresentation_from_polymake(self): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], # indirect doctest # optional - polymake + sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], # indirect doctest # optional - jupymake ....: backend='polymake') - sage: set(p.Hrepresentation()) # optional - polymake + sage: set(p.Hrepresentation()) # optional - jupymake {An inequality (1, 4) x - 2 >= 0, An inequality (1, -12) x + 6 >= 0, An inequality (-5, 12) x + 10 >= 0} - sage: set(p.Vrepresentation()) # optional - polymake + sage: set(p.Vrepresentation()) # optional - jupymake {A vertex at (0, 1/2), A vertex at (2, 0), A vertex at (4, 5/6)} """ @@ -517,13 +517,13 @@ def _init_Hrepresentation_from_polymake(self): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], # indirect doctest # optional - polymake + sage: p = Polyhedron(vertices=[(0,1/2), (2,0), (4,5/6)], # indirect doctest # optional - jupymake ....: backend='polymake') - sage: set(p.Hrepresentation()) # optional - polymake + sage: set(p.Hrepresentation()) # optional - jupymake {An inequality (1, 4) x - 2 >= 0, An inequality (1, -12) x + 6 >= 0, An inequality (-5, 12) x + 10 >= 0} - sage: set(p.Vrepresentation()) # optional - polymake + sage: set(p.Vrepresentation()) # optional - jupymake {A vertex at (0, 1/2), A vertex at (2, 0), A vertex at (4, 5/6)} """ @@ -553,9 +553,9 @@ def _from_polymake_polytope(cls, parent, polymake_polytope): sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake sage: from sage.geometry.polyhedron.parent import Polyhedra sage: P=Polyhedron(ieqs=[[1, 0, 2], [3, 0, -2], [3, 2, -2]]) - sage: PP = polymake(P) # optional - polymake - sage: parent = Polyhedra(QQ, 2, backend='polymake') # optional - polymake - sage: Q=Polyhedron_polymake._from_polymake_polytope(parent, PP) # optional - polymake + sage: PP = polymake(P) # optional - jupymake + sage: parent = Polyhedra(QQ, 2, backend='polymake') # optional - jupymake + sage: Q=Polyhedron_polymake._from_polymake_polytope(parent, PP) # optional - jupymake """ if parent is None: from .parent import Polyhedra @@ -584,9 +584,9 @@ def _polymake_(self, polymake): EXAMPLES:: - sage: P = Polyhedron(vertices=[[1, 0], [0, 1], [0, 0]], backend='polymake') # optional - polymake - sage: PP = polymake(P) # optional - polymake - sage: PP.N_VERTICES # optional - polymake + sage: P = Polyhedron(vertices=[[1, 0], [0, 1], [0, 0]], backend='polymake') # optional - jupymake + sage: PP = polymake(P) # optional - jupymake + sage: PP.N_VERTICES # optional - jupymake 3 """ if self._polymake_polytope.parent() is polymake: @@ -600,8 +600,8 @@ def __getstate__(self): TESTS:: - sage: P = polytopes.simplex(backend='polymake') # optional - polymake - sage: P.__getstate__() # optional - polymake + sage: P = polytopes.simplex(backend='polymake') # optional - jupymake + sage: P.__getstate__() # optional - jupymake (Polyhedra in QQ^4, {'_Hrepresentation': (An inequality (0, -1, -1, -1) x + 1 >= 0, An inequality (0, 1, 0, 0) x + 0 >= 0, @@ -644,31 +644,31 @@ def __setstate__(self, state): Test that the obtained cone is valid:: - sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - polymake - sage: P = polytopes.permutahedron(4, backend='polymake') # optional - polymake - sage: P1 = loads(dumps(P)) # optional - polymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - polymake - sage: P._test_polymake_pickling(other=P2) # optional - polymake + sage: from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake # optional - jupymake + sage: P = polytopes.permutahedron(4, backend='polymake') # optional - jupymake + sage: P1 = loads(dumps(P)) # optional - jupymake + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake + sage: P._test_polymake_pickling(other=P2) # optional - jupymake - sage: P = Polyhedron(lines=[[1,0], [0,1]], backend='polymake') # optional - polymake - sage: P1 = loads(dumps(P)) # optional - polymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - polymake - sage: P._test_polymake_pickling(other=P2) # optional - polymake + sage: P = Polyhedron(lines=[[1,0], [0,1]], backend='polymake') # optional - jupymake + sage: P1 = loads(dumps(P)) # optional - jupymake + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake + sage: P._test_polymake_pickling(other=P2) # optional - jupymake - sage: P = Polyhedron(backend='polymake') # optional - polymake - sage: P1 = loads(dumps(P)) # optional - polymake - sage: P._test_polymake_pickling(other=P1) # optional - polymake + sage: P = Polyhedron(backend='polymake') # optional - jupymake + sage: P1 = loads(dumps(P)) # optional - jupymake + sage: P._test_polymake_pickling(other=P1) # optional - jupymake - sage: P = polytopes.permutahedron(4, backend='polymake') * Polyhedron(lines=[[1]], backend='polymake') # optional - polymake - sage: P1 = loads(dumps(P)) # optional - polymake - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - polymake - sage: P._test_polymake_pickling(other=P2) # optional - polymake + sage: P = polytopes.permutahedron(4, backend='polymake') * Polyhedron(lines=[[1]], backend='polymake') # optional - jupymake + sage: P1 = loads(dumps(P)) # optional - jupymake + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake + sage: P._test_polymake_pickling(other=P2) # optional - jupymake - sage: print("Possible output"); P = polytopes.dodecahedron(backend='polymake') # optional - polymake # optional - sage.rings.number_field + sage: print("Possible output"); P = polytopes.dodecahedron(backend='polymake') # optional - jupymake # optional - sage.rings.number_field Possible output... - sage: P1 = loads(dumps(P)) # optional - polymake # optional - sage.rings.number_field - sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - polymake # optional - sage.rings.number_field - sage: P._test_polymake_pickling(other=P2) # optional - polymake # optional - sage.rings.number_field + sage: P1 = loads(dumps(P)) # optional - jupymake # optional - sage.rings.number_field + sage: P2 = Polyhedron_polymake(P1.parent(), None, None, P1._polymake_polytope) # optional - jupymake # optional - sage.rings.number_field + sage: P._test_polymake_pickling(other=P2) # optional - jupymake # optional - sage.rings.number_field """ if "_pickle_vertices" in state[1]: vertices = state[1].pop("_pickle_vertices") @@ -703,7 +703,7 @@ def _test_polymake_pickling(self, tester=None, other=None, **options): TESTS:: - sage: polytopes.cross_polytope(3, backend='polymake')._test_polymake_pickling() # optional - polymake + sage: polytopes.cross_polytope(3, backend='polymake')._test_polymake_pickling() # optional - jupymake """ if tester is None: tester = self._tester(**options) @@ -739,10 +739,10 @@ class Polyhedron_QQ_polymake(Polyhedron_polymake, Polyhedron_QQ): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - polymake + sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - jupymake ....: rays=[(1,1)], lines=[], ....: backend='polymake', base_ring=QQ) - sage: TestSuite(p).run() # optional - polymake + sage: TestSuite(p).run() # optional - jupymake """ pass @@ -759,9 +759,9 @@ class Polyhedron_ZZ_polymake(Polyhedron_polymake, Polyhedron_ZZ): EXAMPLES:: - sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - polymake + sage: p = Polyhedron(vertices=[(0,0),(1,0),(0,1)], # optional - jupymake ....: rays=[(1,1)], lines=[], ....: backend='polymake', base_ring=ZZ) - sage: TestSuite(p).run() # optional - polymake + sage: TestSuite(p).run() # optional - jupymake """ pass diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 576e073a825..9a21159f322 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1116,35 +1116,35 @@ def _polymake_init_(self): EXAMPLES:: sage: P = polytopes.cube() - sage: PP = polymake(P) # optional - polymake - sage: PP.N_VERTICES # optional - polymake + sage: PP = polymake(P) # optional - jupymake + sage: PP.N_VERTICES # optional - jupymake 8 Lower-dimensional polyhedron:: sage: P = Polyhedron(vertices=[[1, 0], [0, 1]]) - sage: PP = polymake(P) # optional - polymake - sage: PP.COMBINATORIAL_DIM # optional - polymake + sage: PP = polymake(P) # optional - jupymake + sage: PP.COMBINATORIAL_DIM # optional - jupymake 1 - sage: PP.AFFINE_HULL # optional - polymake + sage: PP.AFFINE_HULL # optional - jupymake -1 1 1 Empty polyhedron:: sage: P = Polyhedron(ambient_dim=2, vertices=[]) - sage: PP = polymake(P) # optional - polymake - sage: PP.COMBINATORIAL_DIM # optional - polymake + sage: PP = polymake(P) # optional - jupymake + sage: PP.COMBINATORIAL_DIM # optional - jupymake -1 Pointed unbounded polyhedron:: sage: P = Polyhedron(vertices=[[1, 0], [0, 1]], rays=[[1, 0]]) - sage: PP = polymake(P) # optional - polymake - sage: PP.VERTICES # optional - polymake + sage: PP = polymake(P) # optional - jupymake + sage: PP.VERTICES # optional - jupymake 1 0 1 1 1 0 0 1 0 - sage: PP.FACETS # optional - polymake + sage: PP.FACETS # optional - jupymake 1 0 -1 -1 1 1 0 0 1 @@ -1152,14 +1152,14 @@ def _polymake_init_(self): Non-pointed polyhedron:: sage: P = Polyhedron(vertices=[[1, 0], [0, 1]], lines=[[1, 0]]) - sage: PP = polymake(P) # optional - polymake - sage: PP.VERTICES # optional - polymake + sage: PP = polymake(P) # optional - jupymake + sage: PP.VERTICES # optional - jupymake 1 0 1 1 0 0 - sage: PP.FACETS # optional - polymake + sage: PP.FACETS # optional - jupymake 1 0 -1 0 0 1 - sage: PP.LINEALITY_SPACE # optional - polymake + sage: PP.LINEALITY_SPACE # optional - jupymake 0 1 0 Algebraic polyhedron:: @@ -1169,20 +1169,20 @@ def _polymake_init_(self): in (Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?)^3 defined as the convex hull of 20 vertices - sage: print("There may be a recompilation warning"); PP = polymake(P); PP # optional - polymake # optional - sage.rings.number_field + sage: print("There may be a recompilation warning"); PP = polymake(P); PP # optional - jupymake # optional - sage.rings.number_field There may be a recompilation warning... Polytope>[...] - sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - polymake # optional - sage.rings.number_field + sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake # optional - sage.rings.number_field 1 -1+1r5 -4+2r5 0 Floating-point polyhedron:: sage: P = polytopes.dodecahedron(exact=False); P A 3-dimensional polyhedron in RDF^3 defined as the convex hull of 20 vertices - sage: print("There may be a recompilation warning"); PP = polymake(P); PP # optional - polymake + sage: print("There may be a recompilation warning"); PP = polymake(P); PP # optional - jupymake There may be a recompilation warning... Polytope[...] - sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - polymake + sage: sorted(PP.VERTICES[:], key=repr)[0] # optional - jupymake 1 -0.472135955 0 -1.236067978 """ diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py index 2e0f6a716cf..44182e0f9e4 100644 --- a/src/sage/geometry/polyhedron/base0.py +++ b/src/sage/geometry/polyhedron/base0.py @@ -315,8 +315,8 @@ def _sage_input_(self, sib, coerced): sage: P = Polyhedron(vertices = [[1, 0], [0, 1]], rays = [[1, 1]], backend='normaliz') # optional - pynormaliz sage: sage_input(P) # optional - pynormaliz Polyhedron(backend='normaliz', base_ring=QQ, rays=[(QQ(1), QQ(1))], vertices=[(QQ(0), QQ(1)), (QQ(1), QQ(0))]) - sage: P = Polyhedron(vertices = [[1, 0], [0, 1]], rays = [[1, 1]], backend='polymake') # optional - polymake - sage: sage_input(P) # optional - polymake + sage: P = Polyhedron(vertices = [[1, 0], [0, 1]], rays = [[1, 1]], backend='polymake') # optional - jupymake + sage: sage_input(P) # optional - jupymake Polyhedron(backend='polymake', base_ring=QQ, rays=[(QQ(1), QQ(1))], vertices=[(QQ(1), QQ(0)), (QQ(0), QQ(1))]) """ kwds = dict() diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index 52304d08d75..d9dd5a6c4d6 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -1056,7 +1056,7 @@ def combinatorial_face_to_polyhedral_face(polyhedron, combinatorial_face): 4 sage: polytopes.simplex(backend='normaliz').equations()[0].index() # optional - pynormaliz 4 - sage: polytopes.simplex(backend='polymake').equations()[0].index() # optional - polymake + sage: polytopes.simplex(backend='polymake').equations()[0].index() # optional - jupymake 4 """ V_indices = combinatorial_face.ambient_V_indices() diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 881c614238a..3eee9514560 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -109,7 +109,7 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * Traceback (most recent call last): ... ValueError: invalid base ring: Number Field in I with defining polynomial x^2 + 1 with I = 1*I cannot be coerced to a real field - sage: Polyhedra(AA, 3, backend='polymake') # optional - polymake + sage: Polyhedra(AA, 3, backend='polymake') # optional - jupymake Traceback (most recent call last): ... ValueError: the 'polymake' backend for polyhedron cannot be used with Algebraic Real Field diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index c34e72a21c7..c459a7268e6 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -65,7 +65,7 @@ class PolymakeError(RuntimeError): TESTS:: - sage: polymake.eval('print foo;') # optional polymake + sage: polymake.eval('print foo;') # optional - jupymake Traceback (most recent call last): ... PolymakeError: Unquoted string "foo" may clash with future reserved word... @@ -155,7 +155,7 @@ def version(self): EXAMPLES:: - sage: polymake.version() # optional - polymake # random + sage: polymake.version() # optional - jupymake # random '4...' """ return self.get('$Polymake::Version') @@ -178,10 +178,10 @@ def _object_class(self): TESTS:: - sage: C = polymake('cube(3)') # indirect doctest # optional - polymake - sage: C # optional - polymake + sage: C = polymake('cube(3)') # indirect doctest # optional - jupymake + sage: C # optional - jupymake cube of dimension 3 - sage: type(C) # optional - polymake + sage: type(C) # optional - jupymake """ @@ -196,10 +196,10 @@ def _function_element_class(self): We use ellipses in the tests, to make it more robust against future changes in polymake:: - sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - polymake - sage: p.get_schedule # optional - polymake # indirect doctest + sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - jupymake + sage: p.get_schedule # optional - jupymake # indirect doctest Member function 'get_schedule' of Polymake::polytope::Polytope__Rational object - sage: p.get_schedule('"F_VECTOR"') # optional - polymake # random + sage: p.get_schedule('"F_VECTOR"') # optional - jupymake # random CONE_DIM : RAYS | INPUT_RAYS precondition : BOUNDED ( POINTED : ) POINTED : @@ -229,7 +229,7 @@ def function_call(self, function, args=None, kwds=None): """ EXAMPLES:: - sage: polymake.rand_sphere(4, 30, seed=15) # optional - polymake # indirect doctest + sage: polymake.rand_sphere(4, 30, seed=15) # optional - jupymake # indirect doctest Random spherical polytope of dimension 4; seed=15... """ @@ -246,15 +246,15 @@ def _function_call_string(self, function, args, kwds): EXAMPLES:: - sage: polymake._function_call_string('cube', ['2','7','3'], ['group=>1']) # optional - polymake + sage: polymake._function_call_string('cube', ['2','7','3'], ['group=>1']) # optional - jupymake 'cube(2,7,3, group=>1);' - sage: c = polymake('cube(2,7,3, group=>1)') # optional - polymake - sage: c.VERTICES # optional - polymake + sage: c = polymake('cube(2,7,3, group=>1)') # optional - jupymake + sage: c.VERTICES # optional - jupymake 1 3 3 1 7 3 1 3 7 1 7 7 - sage: c.GROUP # optional - polymake + sage: c.GROUP # optional - jupymake full combinatorial group """ @@ -273,10 +273,10 @@ def _coerce_impl(self, x, use_special=True): Test that dictionaries are converted to hashes:: - sage: h = polymake({'"a"': 1, '"b"': 2}) # optional - polymake - sage: h # optional - polymake + sage: h = polymake({'"a"': 1, '"b"': 2}) # optional - jupymake + sage: h # optional - jupymake HASH(0x...) - sage: h['"a"'] # optional - polymake + sage: h['"a"'] # optional - jupymake 1 """ if isinstance(x, dict): @@ -384,13 +384,13 @@ def _start(self): TESTS:: - sage: polymake._start() # optional - polymake + sage: polymake._start() # optional - jupymake Since 'normal_fan' is not defined in the polymake application 'polytope', we now get :: - sage: 'normal_fan' in dir(polymake) # optional - polymake + sage: 'normal_fan' in dir(polymake) # optional - jupymake False """ @@ -425,14 +425,14 @@ def _read_in_file_command(self, filename): Force use of file:: - sage: L = polymake([42] * 400) # optional - polymake - sage: len(L) # optional - polymake + sage: L = polymake([42] * 400) # optional - jupymake + sage: len(L) # optional - jupymake 400 Just below standard file cutoff of 1024:: - sage: L = polymake([42] * 84) # optional - polymake - sage: len(L) # optional - polymake + sage: L = polymake([42] * 84) # optional - jupymake + sage: len(L) # optional - jupymake 84 """ return 'eval read_file "{}";\n'.format(filename) @@ -464,13 +464,13 @@ def clear(self, var): TESTS:: - sage: c = polymake.cube(15) # optional - polymake - sage: polymake._available_vars = [] # optional - polymake - sage: old = c._name # optional - polymake - sage: del c # optional - polymake # indirect doctest - sage: len(polymake._available_vars) # optional - polymake + sage: c = polymake.cube(15) # optional - jupymake + sage: polymake._available_vars = [] # optional - jupymake + sage: old = c._name # optional - jupymake + sage: del c # optional - jupymake # indirect doctest + sage: len(polymake._available_vars) # optional - jupymake 1 - sage: polymake._next_var_name() in old # optional - polymake + sage: polymake._next_var_name() in old # optional - jupymake True """ @@ -503,13 +503,13 @@ def _create(self, value, name=None): EXAMPLES:: - sage: polymake._create("('foo', 'bar')", name="my_array") # optional - polymake + sage: polymake._create("('foo', 'bar')", name="my_array") # optional - jupymake '@my_array' - sage: print(polymake.eval('print join(", ", @my_array);')) # optional - polymake + sage: print(polymake.eval('print join(", ", @my_array);')) # optional - jupymake foo, bar - sage: polymake._create('"foobar"', name="my_string") # optional - polymake + sage: polymake._create('"foobar"', name="my_string") # optional - jupymake '$my_string[0]' - sage: print(polymake.eval('print $my_string[0];')) # optional - polymake + sage: print(polymake.eval('print $my_string[0];')) # optional - jupymake foobar """ @@ -551,18 +551,18 @@ def set(self, var, value): EXAMPLES:: - sage: c = polymake('cube(3)') # optional - polymake # indirect doctest - sage: d = polymake.cube(3) # optional - polymake + sage: c = polymake('cube(3)') # optional - jupymake # indirect doctest + sage: d = polymake.cube(3) # optional - jupymake Equality is, for "big" objects such as polytopes, comparison by identity:: - sage: c == d # optional - polymake + sage: c == d # optional - jupymake False However, the list of vertices is equal:: - sage: c.VERTICES == d.VERTICES # optional - polymake + sage: c.VERTICES == d.VERTICES # optional - jupymake True TESTS: @@ -571,13 +571,13 @@ def set(self, var, value): It should, however, **never** be needed to do the following *explicitly*:: - sage: polymake.set('myvar', 'cube(3)') # optional - polymake - sage: polymake.get('$myvar[0]') # optional - polymake + sage: polymake.set('myvar', 'cube(3)') # optional - jupymake + sage: polymake.get('$myvar[0]') # optional - jupymake 'Polymake::polytope::Polytope__Rational=ARRAY(...)' The following tests against :trac:`22658`:: - sage: P = polymake.new_object("Polytope", FACETS=[[12, -2, -3, -5, -8, -13, -21, -34, -55], # optional - polymake + sage: P = polymake.new_object("Polytope", FACETS=[[12, -2, -3, -5, -8, -13, -21, -34, -55], # optional - jupymake ....: [0, 1, 0, 0, 0, 0, 0, 0, 0], ....: [0, 0, 0, 0, 0, 0, 0, 0, 1], ....: [0, 0, 0, 0, 0, 0, 0, 1, 0], @@ -586,7 +586,7 @@ def set(self, var, value): ....: [0, 0, 0, 0, 1, 0, 0, 0, 0], ....: [0, 0, 0, 1, 0, 0, 0, 0, 0], ....: [0, 0, 1, 0, 0, 0, 0, 0, 0]]) - sage: P.VERTICES # optional - polymake + sage: P.VERTICES # optional - jupymake 1 6 0 0 0 0 0 0 0 1 0 4 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 @@ -596,7 +596,7 @@ def set(self, var, value): 1 0 0 0 0 0 4/7 0 0 1 0 0 0 0 12/13 0 0 0 1 0 0 0 3/2 0 0 0 0 - sage: P.F_VECTOR # optional - polymake + sage: P.F_VECTOR # optional - jupymake 9 36 84 126 126 84 36 9 """ @@ -611,13 +611,13 @@ def get(self, cmd): EXAMPLES:: - sage: polymake.get('cube(3)') # optional - polymake + sage: polymake.get('cube(3)') # optional - jupymake 'Polymake::polytope::Polytope__Rational=ARRAY(...)' Note that the above string representation is what polymake provides. In our interface, we use what polymake calls a "description":: - sage: polymake('cube(3)') # optional - polymake + sage: polymake('cube(3)') # optional - jupymake cube of dimension 3 @@ -635,7 +635,7 @@ def help(self, topic, pager=True): EXAMPLES:: - sage: print(polymake.help('Polytope', pager=False)) # optional - polymake # random + sage: print(polymake.help('Polytope', pager=False)) # optional - jupymake # random objects/Polytope: Not necessarily bounded or unbounded polyhedron. Nonetheless, the name "Polytope" is used for two reasons: @@ -650,7 +650,7 @@ def help(self, topic, pager=True): and the available help topics are displayed resp. printed, without user interaction:: - sage: polymake.help('TRIANGULATION') # optional - polymake # random + sage: polymake.help('TRIANGULATION') # optional - jupymake # random doctest:warning ... UserWarning: Polymake expects user interaction. We abort and return the options that Polymake provides. @@ -664,7 +664,7 @@ def help(self, topic, pager=True): If an unknown help topic is requested, a :class:`PolymakeError` results:: - sage: polymake.help('Triangulation') # optional - polymake + sage: polymake.help('Triangulation') # optional - jupymake Traceback (most recent call last): ... PolymakeError: unknown help topic 'Triangulation' @@ -691,25 +691,25 @@ def _tab_completion(self): TESTS:: - sage: polymake.application('fan') # optional - polymake - sage: 'normal_fan' in dir(polymake) # optional - polymake # indirect doctest + sage: polymake.application('fan') # optional - jupymake + sage: 'normal_fan' in dir(polymake) # optional - jupymake # indirect doctest True - sage: polymake.application('polytope') # optional - polymake + sage: polymake.application('polytope') # optional - jupymake Since ``'normal_fan'`` is not defined in the polymake application ``'polytope'``, we now get:: - sage: 'normal_fan' in dir(polymake) # optional - polymake + sage: 'normal_fan' in dir(polymake) # optional - jupymake False Global functions from ``'core'`` are available:: - sage: 'show_credits' in dir(polymake) # optional - polymake + sage: 'show_credits' in dir(polymake) # optional - jupymake True Global functions from ``'common'`` are available:: - sage: 'lex_ordered' in dir(polymake) # optional - polymake + sage: 'lex_ordered' in dir(polymake) # optional - jupymake True """ if not self.is_running(): @@ -746,20 +746,20 @@ def application(self, app): terms of inequalities. Polymake knows to compute the f- and h-vector and finds that the polytope is very ample:: - sage: q = polymake.new_object("Polytope", INEQUALITIES=[[5,-4,0,1],[-3,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1],[1,0,-1,0],[3,-1,0,0]]) # optional - polymake - sage: q.H_VECTOR # optional - polymake + sage: q = polymake.new_object("Polytope", INEQUALITIES=[[5,-4,0,1],[-3,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1],[1,0,-1,0],[3,-1,0,0]]) # optional - jupymake + sage: q.H_VECTOR # optional - jupymake 1 5 5 1 - sage: q.F_VECTOR # optional - polymake + sage: q.F_VECTOR # optional - jupymake 8 14 8 - sage: q.VERY_AMPLE # optional - polymake + sage: q.VERY_AMPLE # optional - jupymake true In the application 'fan', polymake can now compute the normal fan of `q` and its (primitive) rays:: - sage: polymake.application('fan') # optional - polymake - sage: g = q.normal_fan() # optional - polymake - sage: g.RAYS # optional - polymake + sage: polymake.application('fan') # optional - jupymake + sage: g = q.normal_fan() # optional - jupymake + sage: g.RAYS # optional - jupymake -1 0 1/4 0 -1 1/4 1 0 0 @@ -768,7 +768,7 @@ def application(self, app): 0 0 -1 0 -1 0 -1 0 0 - sage: g.RAYS.primitive() # optional - polymake + sage: g.RAYS.primitive() # optional - jupymake -4 0 1 0 -4 1 1 0 0 @@ -787,20 +787,20 @@ def application(self, app): but only in 'tropical', the following shows the effect of changing the application. :: - sage: polymake.application('polytope') # optional - polymake - sage: 'trop_witness' in dir(polymake) # optional - polymake + sage: polymake.application('polytope') # optional - jupymake + sage: 'trop_witness' in dir(polymake) # optional - jupymake False - sage: polymake.application('tropical') # optional - polymake - sage: 'trop_witness' in dir(polymake) # optional - polymake + sage: polymake.application('tropical') # optional - jupymake + sage: 'trop_witness' in dir(polymake) # optional - jupymake True - sage: polymake.application('polytope') # optional - polymake - sage: 'trop_witness' in dir(polymake) # optional - polymake + sage: polymake.application('polytope') # optional - jupymake + sage: 'trop_witness' in dir(polymake) # optional - jupymake False For completeness, we show what happens when asking for an application that doesn't exist:: - sage: polymake.application('killerapp') # optional - polymake + sage: polymake.application('killerapp') # optional - jupymake Traceback (most recent call last): ... ValueError: Unknown polymake application 'killerapp' @@ -808,7 +808,7 @@ def application(self, app): Of course, a different error results when we send an explicit command in polymake to change to an unknown application:: - sage: polymake.eval('application "killerapp";') # optional - polymake + sage: polymake.eval('application "killerapp";') # optional - jupymake Traceback (most recent call last): ... PolymakeError: Unknown application killerapp @@ -830,17 +830,17 @@ def new_object(self, name, *args, **kwds): EXAMPLES:: - sage: q = polymake.new_object("Polytope", INEQUALITIES=[[4,-4,0,1],[-4,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1]]) # optional - polymake - sage: q.N_VERTICES # optional - polymake + sage: q = polymake.new_object("Polytope", INEQUALITIES=[[4,-4,0,1],[-4,0,-4,1],[-2,1,0,0],[-4,4,4,-1],[0,0,1,0],[8,0,0,-1]]) # optional - jupymake + sage: q.N_VERTICES # optional - jupymake 4 - sage: q.BOUNDED # optional - polymake + sage: q.BOUNDED # optional - jupymake true - sage: q.VERTICES # optional - polymake + sage: q.VERTICES # optional - jupymake 1 2 0 4 1 3 0 8 1 2 1 8 1 3 1 8 - sage: q.full_typename() # optional - polymake + sage: q.full_typename() # optional - jupymake 'Polytope' """ @@ -866,15 +866,15 @@ class PolymakeElement(ExtraTabCompletion, InterfaceElement): We support all "big" polymake types, Perl arrays of length different from one, and Perl scalars:: - sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - polymake - sage: p.typename() # optional - polymake + sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - jupymake + sage: p.typename() # optional - jupymake 'Polytope' - sage: p # optional - polymake + sage: p # optional - jupymake Random spherical polytope of dimension 4; seed=5... Now, one can work with that element in Python syntax, for example:: - sage: p.VERTICES[2][2] # optional - polymake + sage: p.VERTICES[2][2] # optional - jupymake 1450479926727001/2251799813685248 """ @@ -888,21 +888,21 @@ def _repr_(self): of the object that is not longer than single line, it is used for printing:: - sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - polymake - sage: p # optional - polymake + sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - jupymake + sage: p # optional - jupymake Random spherical polytope of dimension 3; seed=15... - sage: c = polymake.cube(4) # optional - polymake - sage: c # optional - polymake + sage: c = polymake.cube(4) # optional - jupymake + sage: c # optional - jupymake cube of dimension 4 We use the print representation of scalars to display scalars:: - sage: p.N_VERTICES # optional - polymake + sage: p.N_VERTICES # optional - jupymake 12 The items of a Perl arrays are shown separated by commas:: - sage: p.get_member('list_properties') # optional - polymake # random + sage: p.get_member('list_properties') # optional - jupymake # random POINTS, CONE_AMBIENT_DIM, BOUNDED, FEASIBLE, N_POINTS, POINTED, CONE_DIM, FULL_DIM, LINEALITY_DIM, LINEALITY_SPACE, COMBINATORIAL_DIM, AFFINE_HULL, VERTICES, N_VERTICES @@ -910,8 +910,8 @@ def _repr_(self): We chose to print rule chains explicitly, so that the user doesn't need to know how to list the rules using polymake commands:: - sage: r = p.get_schedule('"H_VECTOR"') # optional - polymake - sage: r # optional - polymake # random + sage: r = p.get_schedule('"H_VECTOR"') # optional - jupymake + sage: r # optional - jupymake # random precondition : N_RAYS | N_INPUT_RAYS ( ppl.convex_hull.primal: FACETS, LINEAR_SPAN : RAYS | INPUT_RAYS ) sensitivity check for FacetPerm ppl.convex_hull.primal: FACETS, LINEAR_SPAN : RAYS | INPUT_RAYS @@ -922,16 +922,16 @@ def _repr_(self): F_VECTOR : N_FACETS, N_RAYS, COMBINATORIAL_DIM precondition : SIMPLICIAL ( H_VECTOR : F_VECTOR ) H_VECTOR : F_VECTOR - sage: r.typeof() # optional - polymake + sage: r.typeof() # optional - jupymake ('Polymake::Core::Scheduler::RuleChain', 'ARRAY') Similarly, polymake matrices and vectors are explicitly listed:: - sage: c.VERTICES.typename() # optional - polymake + sage: c.VERTICES.typename() # optional - jupymake 'Matrix' - sage: c.VERTICES[0].typename() # optional - polymake + sage: c.VERTICES[0].typename() # optional - jupymake 'Vector' - sage: c.VERTICES # optional - polymake # random + sage: c.VERTICES # optional - jupymake # random 1 -1 -1 -1 -1 1 1 -1 -1 -1 1 -1 1 -1 -1 @@ -948,15 +948,15 @@ def _repr_(self): 1 1 -1 1 1 1 -1 1 1 1 1 1 1 1 1 - sage: c.VERTICES[0] # optional - polymake + sage: c.VERTICES[0] # optional - jupymake 1 -1 -1 -1 -1 For other types, we simply use the print representation offered by polymake:: - sage: p.TWO_FACE_SIZES.typename() # optional - polymake + sage: p.TWO_FACE_SIZES.typename() # optional - jupymake 'Map' - sage: p.TWO_FACE_SIZES # optional - polymake + sage: p.TWO_FACE_SIZES # optional - jupymake {(3 20)} """ @@ -999,25 +999,25 @@ def _richcmp_(self, other, op): The default for comparing equality for polytopes is *identity*:: - sage: p1 = polymake.rand_sphere(3, 12, seed=15) # optional - polymake - sage: p2 = polymake.rand_sphere(3, 12, seed=15) # optional - polymake - sage: p1 == p2 # optional - polymake + sage: p1 = polymake.rand_sphere(3, 12, seed=15) # optional - jupymake + sage: p2 = polymake.rand_sphere(3, 12, seed=15) # optional - jupymake + sage: p1 == p2 # optional - jupymake False However, other data types are compared by equality, not identity:: - sage: p1.VERTICES == p2.VERTICES # optional - polymake + sage: p1.VERTICES == p2.VERTICES # optional - jupymake True A computation applied to a polytope can change the available properties, and thus we have :: - sage: p1.get_member('list_properties') == p2.get_member('list_properties') # optional - polymake + sage: p1.get_member('list_properties') == p2.get_member('list_properties') # optional - jupymake True - sage: p1.F_VECTOR # optional - polymake + sage: p1.F_VECTOR # optional - jupymake 12 30 20 - sage: p1.get_member('list_properties') == p2.get_member('list_properties') # optional - polymake + sage: p1.get_member('list_properties') == p2.get_member('list_properties') # optional - jupymake False """ @@ -1037,9 +1037,9 @@ def __bool__(self): EXAMPLES:: sage: from sage.interfaces.polymake import polymake - sage: bool(polymake(0)) # optional polymake + sage: bool(polymake(0)) # optional - jupymake False - sage: bool(polymake(1)) # optional polymake + sage: bool(polymake(1)) # optional - jupymake True """ @@ -1061,23 +1061,23 @@ def known_properties(self): EXAMPLES:: - sage: c = polymake.cube(4) # optional - polymake - sage: c.known_properties() # optional - polymake + sage: c = polymake.cube(4) # optional - jupymake + sage: c.known_properties() # optional - jupymake ['AFFINE_HULL', 'BOUNDED', 'CONE_AMBIENT_DIM', 'CONE_DIM', ... 'VERTICES_IN_FACETS'] - sage: c.list_properties() # optional - polymake + sage: c.list_properties() # optional - jupymake CONE_AMBIENT_DIM, CONE_DIM, FACETS, AFFINE_HULL, VERTICES_IN_FACETS, BOUNDED... A computation can change the list of known properties:: - sage: c.F_VECTOR # optional - polymake + sage: c.F_VECTOR # optional - jupymake 16 32 24 8 - sage: c.known_properties() # optional - polymake + sage: c.known_properties() # optional - jupymake ['AFFINE_HULL', 'BOUNDED', 'COMBINATORIAL_DIM', @@ -1102,8 +1102,8 @@ def _member_list(self): TESTS:: - sage: c = polymake.cube(4) # optional - polymake - sage: c._member_list() # optional - polymake + sage: c = polymake.cube(4) # optional - jupymake + sage: c._member_list() # optional - jupymake ['AFFINE_HULL', ... 'WEAKLY_CENTERED', @@ -1130,10 +1130,10 @@ def typename(self): EXAMPLES:: - sage: c = polymake.cube(4) # optional - polymake - sage: c.typename() # optional - polymake + sage: c = polymake.cube(4) # optional - jupymake + sage: c.typename() # optional - jupymake 'Polytope' - sage: c.VERTICES.typename() # optional - polymake + sage: c.VERTICES.typename() # optional - jupymake 'Matrix' """ @@ -1149,10 +1149,10 @@ def full_typename(self): EXAMPLES:: - sage: c = polymake.cube(4) # optional - polymake - sage: c.full_typename() # optional - polymake + sage: c = polymake.cube(4) # optional - jupymake + sage: c.full_typename() # optional - jupymake 'Polytope' - sage: c.VERTICES.full_typename() # optional - polymake + sage: c.VERTICES.full_typename() # optional - jupymake 'Matrix' """ @@ -1168,10 +1168,10 @@ def qualified_typename(self): EXAMPLES:: - sage: c = polymake.cube(4) # optional - polymake - sage: c.qualified_typename() # optional - polymake + sage: c = polymake.cube(4) # optional - jupymake + sage: c.qualified_typename() # optional - jupymake 'polytope::Polytope' - sage: c.VERTICES.qualified_typename() # optional - polymake + sage: c.VERTICES.qualified_typename() # optional - jupymake 'common::Matrix' """ @@ -1196,8 +1196,8 @@ def _tab_completion(self): EXAMPLES:: - sage: c = polymake.cube(4) # optional - polymake - sage: c._tab_completion() # optional - polymake + sage: c = polymake.cube(4) # optional - jupymake + sage: c._tab_completion() # optional - jupymake ['AFFINE_HULL', ... 'zero_vector', @@ -1228,34 +1228,34 @@ def __getattr__(self, attrname): A property:: - sage: c = polymake.cube(3) # optional - polymake - sage: c.H_VECTOR # optional - polymake + sage: c = polymake.cube(3) # optional - jupymake + sage: c.H_VECTOR # optional - jupymake 1 5 5 1 - sage: c.N_VERTICES # optional - polymake + sage: c.N_VERTICES # optional - jupymake 8 - sage: d = polymake.cross(3) # optional - polymake - sage: d.N_VERTICES # optional - polymake + sage: d = polymake.cross(3) # optional - jupymake + sage: d.N_VERTICES # optional - jupymake 6 A function:: - sage: c.minkowski_sum_fukuda # optional - polymake + sage: c.minkowski_sum_fukuda # optional - jupymake minkowski_sum_fukuda (bound to Polymake::polytope::Polytope__Rational object) - sage: s = c.minkowski_sum_fukuda(d) # optional - polymake - sage: s.N_VERTICES # optional - polymake + sage: s = c.minkowski_sum_fukuda(d) # optional - jupymake + sage: s.N_VERTICES # optional - jupymake 24 - sage: s # optional - polymake + sage: s # optional - jupymake Polytope[SAGE...] A member function:: - sage: c = polymake.cube(2) # optional - polymake - sage: V = polymake.new_object('Vector', [1,0,0]) # optional - polymake - sage: V # optional - polymake + sage: c = polymake.cube(2) # optional - jupymake + sage: V = polymake.new_object('Vector', [1,0,0]) # optional - jupymake + sage: V # optional - jupymake 1 0 0 - sage: c.contains # optional - polymake + sage: c.contains # optional - jupymake Member function 'contains' of Polymake::polytope::Polytope__Rational object - sage: c.contains(V) # optional - polymake + sage: c.contains(V) # optional - jupymake true """ @@ -1284,21 +1284,21 @@ def get_member_function(self, attrname): EXAMPLES:: - sage: c = polymake.cube(2) # optional - polymake - sage: c.contains # optional - polymake + sage: c = polymake.cube(2) # optional - jupymake + sage: c.contains # optional - jupymake Member function 'contains' of Polymake::polytope::Polytope__Rational object - sage: V = polymake.new_object('Vector', [1,0,0]) # optional - polymake - sage: V # optional - polymake + sage: V = polymake.new_object('Vector', [1,0,0]) # optional - jupymake + sage: V # optional - jupymake 1 0 0 - sage: c.contains(V) # optional - polymake + sage: c.contains(V) # optional - jupymake true Whether a member function of the given name actually exists for that object will only be clear when calling it:: - sage: c.get_member_function("foo") # optional - polymake + sage: c.get_member_function("foo") # optional - jupymake Member function 'foo' of Polymake::polytope::Polytope__Rational object - sage: c.get_member_function("foo")() # optional - polymake + sage: c.get_member_function("foo")() # optional - jupymake Traceback (most recent call last): ... TypeError: Can't locate object method "foo" via package "Polymake::polytope::Polytope__Rational" @@ -1318,31 +1318,31 @@ def get_member(self, attrname): EXAMPLES:: - sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - polymake + sage: p = polymake.rand_sphere(4, 20, seed=5) # optional - jupymake Normally, a property would be accessed as follows:: - sage: p.F_VECTOR # optional - polymake + sage: p.F_VECTOR # optional - jupymake 20 94 148 74 However, explicit access is possible as well:: - sage: p.get_member('F_VECTOR') # optional - polymake + sage: p.get_member('F_VECTOR') # optional - jupymake 20 94 148 74 In some cases, the explicit access works better:: - sage: p.type # optional - polymake + sage: p.type # optional - jupymake Member function 'type' of Polymake::polytope::Polytope__Rational object - sage: p.get_member('type') # optional - polymake + sage: p.get_member('type') # optional - jupymake Polytope[SAGE...] - sage: p.get_member('type').get_member('name') # optional - polymake + sage: p.get_member('type').get_member('name') # optional - jupymake Polytope Note that in the last example calling the erroneously constructed member function ``type`` still works:: - sage: p.type() # optional - polymake + sage: p.type() # optional - jupymake Polytope[SAGE...] """ @@ -1357,19 +1357,19 @@ def __getitem__(self, key): EXAMPLES:: - sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - polymake - sage: p.VERTICES[3] # optional - polymake + sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - jupymake + sage: p.VERTICES[3] # optional - jupymake 1 7977905618560809/18014398509481984 -1671539598851959/144115188075855872 8075083879632623/9007199254740992 - sage: p.list_properties()[2] # optional - polymake + sage: p.list_properties()[2] # optional - jupymake BOUNDED Slicing:: - sage: p.F_VECTOR[:] # optional - polymake + sage: p.F_VECTOR[:] # optional - jupymake [12, 30, 20] - sage: p.F_VECTOR[0:1] # optional - polymake + sage: p.F_VECTOR[0:1] # optional - jupymake [12] - sage: p.F_VECTOR[0:3:2] # optional - polymake + sage: p.F_VECTOR[0:3:2] # optional - jupymake [12, 20] """ P = self._check_valid() @@ -1400,8 +1400,8 @@ def __iter__(self): EXAMPLES:: - sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - polymake - sage: [ x for x in p.VERTICES[3] ] # optional - polymake + sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - jupymake + sage: [ x for x in p.VERTICES[3] ] # optional - jupymake [1, 7977905618560809/18014398509481984, -1671539598851959/144115188075855872, 8075083879632623/9007199254740992] """ for i in range(len(self)): @@ -1411,10 +1411,10 @@ def __len__(self): """ EXAMPLES:: - sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - polymake - sage: len(p.FACETS) # optional - polymake + sage: p = polymake.rand_sphere(3, 12, seed=15) # optional - jupymake + sage: len(p.FACETS) # optional - jupymake 20 - sage: len(p.list_properties()) >= 12 # optional - polymake + sage: len(p.list_properties()) >= 12 # optional - jupymake True """ @@ -1441,19 +1441,19 @@ def typeof(self): EXAMPLES:: - sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake - sage: p.typeof() # optional - polymake + sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - jupymake + sage: p.typeof() # optional - jupymake ('Polymake::polytope::Polytope__Rational', 'ARRAY') - sage: p.VERTICES.typeof() # optional - polymake + sage: p.VERTICES.typeof() # optional - jupymake ('Polymake::common::Matrix_A_Rational_I_NonSymmetric_Z', 'ARRAY') - sage: p.get_schedule('"F_VECTOR"').typeof() # optional - polymake + sage: p.get_schedule('"F_VECTOR"').typeof() # optional - jupymake ('Polymake::Core::Scheduler::RuleChain', 'ARRAY') On "small" objects, it just returns empty strings:: - sage: p.N_VERTICES.typeof() # optional - polymake + sage: p.N_VERTICES.typeof() # optional - jupymake ('', '') - sage: p.list_properties().typeof() # optional - polymake + sage: p.list_properties().typeof() # optional - jupymake ('', '') """ P = self._check_valid() @@ -1469,50 +1469,50 @@ def _sage_(self): EXAMPLES:: - sage: a = polymake(1/2); a # optional - polymake + sage: a = polymake(1/2); a # optional - jupymake 1/2 - sage: a.sage() # optional - polymake + sage: a.sage() # optional - jupymake 1/2 - sage: _.parent() # optional - polymake + sage: _.parent() # optional - jupymake Rational Field Quadratic extensions:: sage: K. = QuadraticField(5) - sage: polymake(K(0)).sage() # optional - polymake + sage: polymake(K(0)).sage() # optional - jupymake 0 - sage: _.parent() # optional - polymake + sage: _.parent() # optional - jupymake Rational Field - sage: polymake(sqrt5).sage() # optional - polymake + sage: polymake(sqrt5).sage() # optional - jupymake a - sage: polymake(-sqrt5).sage() # optional - polymake + sage: polymake(-sqrt5).sage() # optional - jupymake -a - sage: polymake(1/3-1/2*sqrt5).sage() # optional - polymake + sage: polymake(1/3-1/2*sqrt5).sage() # optional - jupymake -1/2*a + 1/3 - sage: polymake(-1+sqrt5).sage() # optional - polymake + sage: polymake(-1+sqrt5).sage() # optional - jupymake a - 1 Vectors:: - sage: PP = polymake.cube(3) # optional - polymake - sage: PP.F_VECTOR.sage() # optional - polymake + sage: PP = polymake.cube(3) # optional - jupymake + sage: PP.F_VECTOR.sage() # optional - jupymake (8, 12, 6) - sage: _.parent() # optional - polymake + sage: _.parent() # optional - jupymake Ambient free module of rank 3 over the principal ideal domain Integer Ring Matrices:: - sage: polymake.unit_matrix(2).sage() # optional - polymake + sage: polymake.unit_matrix(2).sage() # optional - jupymake [1 0] [0 1] - sage: _.parent() # optional - polymake + sage: _.parent() # optional - jupymake Full MatrixSpace of 2 by 2 dense matrices over Integer Ring Polytopes:: - sage: polymake.cube(3).sage() # optional - polymake + sage: polymake.cube(3).sage() # optional - jupymake A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices - sage: polymake.icosahedron().sage() # optional - polymake + sage: polymake.icosahedron().sage() # optional - jupymake A 3-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^3 defined as the convex hull of 12 vertices @@ -1596,8 +1596,8 @@ def _sage_doc_(self): """ EXAMPLES:: - sage: c = polymake.cube(3) # optional - polymake - sage: print(c._sage_doc_()) # optional - polymake # random + sage: c = polymake.cube(3) # optional - jupymake + sage: print(c._sage_doc_()) # optional - jupymake # random objects/Polytope: Not necessarily bounded or unbounded polyhedron. Nonetheless, the name "Polytope" is used for two reasons: @@ -1609,7 +1609,7 @@ def _sage_doc_(self): objects/Polytope/specializations/Polytope: A rational polyhedron realized in Q^d - sage: print(c.FACETS._sage_doc_()) # optional - polymake # random + sage: print(c.FACETS._sage_doc_()) # optional - jupymake # random property_types/Algebraic Types/SparseMatrix: A SparseMatrix is a two-dimensional associative array with row and column indices as keys; elements equal to the default value (ElementType(), which is 0 for most numerical types) are not stored, but implicitly encoded by the gaps in the key set. Each row and column is organized as an AVL-tree. @@ -1669,13 +1669,13 @@ class PolymakeFunctionElement(InterfaceFunctionElement): EXAMPLES:: - sage: c = polymake.cube(2) # optional - polymake - sage: V = polymake.new_object('Vector', [1,0,0]) # optional - polymake - sage: V # optional - polymake + sage: c = polymake.cube(2) # optional - jupymake + sage: V = polymake.new_object('Vector', [1,0,0]) # optional - jupymake + sage: V # optional - jupymake 1 0 0 - sage: c.contains # optional - polymake + sage: c.contains # optional - jupymake Member function 'contains' of Polymake::polytope::Polytope__Rational object - sage: c.contains(V) # optional - polymake + sage: c.contains(V) # optional - jupymake true """ @@ -1691,10 +1691,10 @@ def __init__(self, obj, name, memberfunction=False): EXAMPLES:: - sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake - sage: p.minkowski_sum_fukuda # optional - polymake + sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - jupymake + sage: p.minkowski_sum_fukuda # optional - jupymake minkowski_sum_fukuda (bound to Polymake::polytope::Polytope__Rational object) - sage: p.get_schedule # optional - polymake + sage: p.get_schedule # optional - jupymake Member function 'get_schedule' of Polymake::polytope::Polytope__Rational object """ @@ -1706,10 +1706,10 @@ def _repr_(self): """ EXAMPLES:: - sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake - sage: p.minkowski_sum_fukuda # optional - polymake + sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - jupymake + sage: p.minkowski_sum_fukuda # optional - jupymake minkowski_sum_fukuda (bound to Polymake::polytope::Polytope__Rational object) - sage: p.contains # optional - polymake + sage: p.contains # optional - jupymake Member function 'contains' of Polymake::polytope::Polytope__Rational object """ @@ -1724,11 +1724,11 @@ def __call__(self, *args, **kwds): We consider both member functions of an element and global functions bound to an element:: - sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake - sage: p.get_schedule('"VERTICES"') # optional - polymake # random + sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - jupymake + sage: p.get_schedule('"VERTICES"') # optional - jupymake # random sensitivity check for VertexPerm cdd.convex_hull.canon: POINTED, RAYS, LINEALITY_SPACE : INPUT_RAYS - sage: p.minkowski_sum_fukuda(p).F_VECTOR # optional - polymake # not tested + sage: p.minkowski_sum_fukuda(p).F_VECTOR # optional - jupymake # not tested 13 33 22 """ @@ -1747,8 +1747,8 @@ def _sage_doc_(self): EXAMPLES:: - sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - polymake - sage: print(p.get_schedule._sage_doc_()) # optional - polymake # random + sage: p = polymake.rand_sphere(3, 13, seed=12) # optional - jupymake + sage: print(p.get_schedule._sage_doc_()) # optional - jupymake # random objects/Core::Object/methods/get_schedule: get_schedule(request; ... ) -> Core::RuleChain @@ -1764,7 +1764,7 @@ def _sage_doc_(self): Several requests may be listed. Returns Core::RuleChain - sage: print(p.minkowski_sum_fukuda._sage_doc_()) # optional - polymake # random + sage: print(p.minkowski_sum_fukuda._sage_doc_()) # optional - jupymake # random functions/Producing a polytope from polytopes/minkowski_sum_fukuda: minkowski_sum_fukuda(summands) -> Polytope diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index 287d58886d4..1f109a2e3cc 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -404,12 +404,12 @@ cdef class Matrix(Matrix0): EXAMPLES:: sage: M = matrix(ZZ,2,range(4)) - sage: polymake(M) # optional - polymake + sage: polymake(M) # optional - jupymake 0 1 2 3 sage: K. = QuadraticField(5) sage: M = matrix(K, [[1, 2], [sqrt5, 3]]) - sage: polymake(M) # optional - polymake + sage: polymake(M) # optional - jupymake 1 2 0+1r5 3 """ diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index c29bcc64260..0a76510a895 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -2338,9 +2338,9 @@ def _polymake_init_(self): EXAMPLES:: - sage: polymake(MatrixSpace(QQ,3)) # optional - polymake + sage: polymake(MatrixSpace(QQ,3)) # optional - jupymake Matrix - sage: polymake(MatrixSpace(QuadraticField(5),3)) # optional - polymake + sage: polymake(MatrixSpace(QuadraticField(5),3)) # optional - jupymake Matrix """ from sage.interfaces.polymake import polymake diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 889a16295a7..7ba77ca2aa2 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -1506,7 +1506,7 @@ cdef class IntegerRing_class(PrincipalIdealDomain): EXAMPLES:: - sage: polymake(ZZ) # optional - polymake # indirect doctest + sage: polymake(ZZ) # optional - jupymake # indirect doctest Integer """ diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 66dddb5597e..330afb77af5 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -11957,7 +11957,7 @@ def _polymake_init_(self): EXAMPLES:: sage: Z = QuadraticField(7) - sage: polymake(Z) # optional - polymake # indirect doctest + sage: polymake(Z) # optional - jupymake # indirect doctest QuadraticExtension """ diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 0cea74a50eb..24fc7db909e 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -314,12 +314,12 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): EXAMPLES:: sage: K. = QuadraticField(5) - sage: polymake(3+2*sqrt5) # optional - polymake + sage: polymake(3+2*sqrt5) # optional - jupymake 3+2r5 - sage: polymake(2**100/7 - 2*sqrt5/3**50) # optional - polymake + sage: polymake(2**100/7 - 2*sqrt5/3**50) # optional - jupymake 1267650600228229401496703205376/7-2/717897987691852588770249r5 sage: K. = QuadraticField(-1) - sage: polymake(i) # optional - polymake + sage: polymake(i) # optional - jupymake Traceback (most recent call last): ... TypeError: Negative values for the root of the extension ... Bad Thing... @@ -331,9 +331,9 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: x = polygen(QQ, 'x') sage: K = NumberField(x^2 - x -1, 'a', embedding=(1-AA(5).sqrt())/2) sage: L = NumberField(x^2 - x -1, 'a', embedding=(1+AA(5).sqrt())/2) - sage: polymake(K.gen()) # optional - polymake + sage: polymake(K.gen()) # optional - jupymake 1/2-1/2r5 - sage: polymake(L.gen()) # optional - polymake + sage: polymake(L.gen()) # optional - jupymake 1/2+1/2r5 """ cdef Integer a = Integer.__new__(Integer) diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index ca84b20e165..55e7a46319d 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -1575,7 +1575,7 @@ def _polymake_init_(self): EXAMPLES:: - sage: polymake(QQ) #optional - polymake # indirect doctest + sage: polymake(QQ) #optional - jupymake # indirect doctest Rational """ diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index c641eb3f710..fa121ddf547 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -421,7 +421,7 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): EXAMPLES:: - sage: polymake(RDF) #optional - polymake # indirect doctest + sage: polymake(RDF) #optional - jupymake # indirect doctest Float """ return '"Float"' From cfe01083f6180c3393322f5b609bd3b502b459dc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 8 Aug 2022 23:16:53 -0700 Subject: [PATCH 281/591] build/pkgs/polymake/SPKG.rst: Update info on jupymake --- build/pkgs/polymake/SPKG.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/build/pkgs/polymake/SPKG.rst b/build/pkgs/polymake/SPKG.rst index 2f38f212b5c..6cccfcc2fa5 100644 --- a/build/pkgs/polymake/SPKG.rst +++ b/build/pkgs/polymake/SPKG.rst @@ -65,13 +65,10 @@ Information on missing Polymake prerequisites after installing polymake:: (sage-sh) $ polymake polytope> show_unconfigured; -It is strongly recommended to also install JuPyMake:: +In order to Polymake from Sage, you will need the JuPyMake:: sage -i jupymake -When JuPyMake is present, Sage is able to use a more robust interface -to Polymake. - Debugging polymake install problems ----------------------------------- From 53d8d11c02dae01a3dc0748304ec5d61a7c9a155 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 9 Aug 2022 09:43:38 +0200 Subject: [PATCH 282/591] 34283: fix according to review --- src/sage/matrix/matrix_space.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index cebee45661f..998bb99d8a0 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -187,8 +187,6 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if isinstance(implementation, type): return implementation - from sage.matrix.matrix_generic_dense import Matrix_generic_dense - from sage.matrix.matrix_generic_sparse import Matrix_generic_sparse if not sparse: if implementation is None: # Choose default implementation: @@ -303,6 +301,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): return matrix_mpolynomial_dense.Matrix_mpolynomial_dense # The fallback + from sage.matrix.matrix_generic_dense import Matrix_generic_dense return Matrix_generic_dense # Deal with request for a specific implementation @@ -360,6 +359,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): raise ValueError("'linbox-double' matrices can only deal with order < %s" % matrix_modn_dense_double.MAX_MODULUS) if implementation == 'generic': + from sage.matrix.matrix_generic_dense import Matrix_generic_dense return Matrix_generic_dense if implementation == 'gap': @@ -402,6 +402,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): return matrix_double_sparse.Matrix_double_sparse # the fallback + from sage.matrix.matrix_generic_sparse import Matrix_generic_sparse return Matrix_generic_sparse From 99775382d28bc97c2378bf0850fea82d01f0ad5d Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 10:34:49 +0200 Subject: [PATCH 283/591] trac #34310: clean src/sage/graphs/generators/distance_regular.pyx --- .../graphs/generators/distance_regular.pyx | 146 +++++++++++------- 1 file changed, 87 insertions(+), 59 deletions(-) diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx index 29e101f9473..7be8e02741c 100644 --- a/src/sage/graphs/generators/distance_regular.pyx +++ b/src/sage/graphs/generators/distance_regular.pyx @@ -86,6 +86,7 @@ def cocliques_HoffmannSingleton(): G = Graph(edges, format="list_of_edges") return G + def locally_GQ42_distance_transitive_graph(): r""" Return the unique amply regular graph with `\mu = 6` which is locally @@ -141,10 +142,10 @@ def ConwaySmith_for_3S7(): F = CyclotomicField(3) w = F.gen() - V= VectorSpace(GF(4), 6) - z2 = GF(4)('z2') # GF(4) = {0, 1, z2, z2+1} + V = VectorSpace(GF(4), 6) + z2 = GF(4)('z2') # GF(4) = {0, 1, z2, z2+1} - W = V.span([(0,0,1,1,1,1), (0,1,0,1,z2,z2+1), (1,0,0,1,z2+1,z2)]) + W = V.span([(0, 0, 1, 1, 1, 1), (0, 1, 0, 1, z2, z2 + 1), (1, 0, 0, 1, z2 + 1, z2)]) # we only need the 45 vectors with 2 zero entries # we also embed everything into CC @@ -199,6 +200,7 @@ def ConwaySmith_for_3S7(): G.name("Conway-Smith graph for 3S7") return G + def graph_3O73(): r""" Return the graph related to the group `3 O(7,3)`. @@ -225,6 +227,7 @@ def graph_3O73(): G.name("Distance transitive graph with automorphism group 3.O_7(3)") return G + def FosterGraph3S6(): r""" Return the Foster graph for `3.Sym(6)`. @@ -245,7 +248,6 @@ def FosterGraph3S6(): A description and construction of this graph can be found in [BCN1989]_ p. 397. """ - a = libgap.eval(("(2,6)(3,5)(4,11)(7,17)(8,16)(9,14)(13,22)(15,25)" "(18,29)(19,28)(20,21)(24,30)(26,35)(27,33)(31,39)" "(34,38)(36,43)(37,40)(42,44)")) @@ -253,12 +255,13 @@ def FosterGraph3S6(): "(14,23,28,31,24)(16,22,29,36,27)(25,32,35,42,34)" "(30,37,39,44,38)(33,40,43,45,41)")) - group = libgap.Group(a,b) + group = libgap.Group(a, b) G = Graph(group.Orbit([1, 7], libgap.OnSets), format='list_of_edges') G.name("Foster graph for 3.Sym(6) graph") return G + def J2Graph(): r""" Return the distance-transitive graph with automorphism group `J_2`. @@ -279,6 +282,7 @@ def J2Graph(): G.name("J_2 graph") return G + def IvanovIvanovFaradjevGraph(): r""" Return the IvanovIvanovFaradjev graph. @@ -303,6 +307,7 @@ def IvanovIvanovFaradjevGraph(): graph.name("Ivanov-Ivanov-Faradjev Graph") return graph + def LargeWittGraph(): r""" Return the large Witt graph. @@ -337,6 +342,7 @@ def LargeWittGraph(): W.name("Large Witt graph") return W + def TruncatedWittGraph(): r""" Return the truncated Witt graph. @@ -360,11 +366,12 @@ def TruncatedWittGraph(): """ # get large witt graph and remove all vertices which start with a 1 G = LargeWittGraph() - G.delete_vertices(filter(lambda x : x[0] == 1, G.vertices(sort=False))) + G.delete_vertices(filter(lambda x: x[0] == 1, G.vertices(sort=False))) G.name("Truncated Witt graph") return G + def DoublyTruncatedWittGraph(): r""" Return the doubly truncated Witt graph. @@ -386,13 +393,13 @@ def DoublyTruncatedWittGraph(): A description and construction of this graph can be found in [BCN1989]_ p. 368. """ - G = TruncatedWittGraph() - G.delete_vertices(filter(lambda x : x[1] == 1, G.vertices(sort=False))) + G.delete_vertices(filter(lambda x: x[1] == 1, G.vertices(sort=False))) G.name("Doubly Truncated Witt graph") return G + def distance_3_doubly_truncated_Golay_code_graph(): r""" Return a distance-regular graph with intersection array @@ -416,17 +423,18 @@ def distance_3_doubly_truncated_Golay_code_graph(): Description and construction of this graph are taken from [BCN1989]_ p. 364. """ - G = codes.GolayCode(GF(2),extended=False).punctured([0,1]).cosetGraph() + G = codes.GolayCode(GF(2), extended=False).punctured([0, 1]).cosetGraph() v = G.vertices(sort=False)[0] it = G.breadth_first_search(v, distance=3, report_distance=True) - vertices = [w for (w,d) in it if d == 3] + vertices = [w for (w, d) in it if d == 3] - edges =[(a ,b) for a, b in itertools.combinations(vertices, 2) - if G.has_edge((a, b))] + edges = [(a, b) for a, b in itertools.combinations(vertices, 2) + if G.has_edge((a, b))] H = Graph(edges, format='list_of_edges') return H + def shortened_00_11_binary_Golay_code_graph(): r""" Return a distance-regular graph with intersection array @@ -454,7 +462,7 @@ def shortened_00_11_binary_Golay_code_graph(): C_basis = code.basis() # Now special shortening - v = C_basis[0] + C_basis[1] # v has 11 at the start + v = C_basis[0] + C_basis[1] # v has 11 at the start C_basis = C_basis[2:] C_basis.append(v) C_basis = list(map(lambda x: x[2:], C_basis)) @@ -465,6 +473,7 @@ def shortened_00_11_binary_Golay_code_graph(): G.name("Shortened 00 11 binary Golay code") return G + def shortened_000_111_extended_binary_Golay_code_graph(): r""" Return a distance-regular graph with intersection array @@ -492,7 +501,7 @@ def shortened_000_111_extended_binary_Golay_code_graph(): C_basis = code.basis() # now special shortening - v = C_basis[0] + C_basis[1] + C_basis[2] # v has 111 at the start + v = C_basis[0] + C_basis[1] + C_basis[2] # v has 111 at the start C_basis = C_basis[3:] C_basis.append(v) C_basis = list(map(lambda x: x[3:], C_basis)) @@ -503,6 +512,7 @@ def shortened_000_111_extended_binary_Golay_code_graph(): G.name("Shortened 000 111 extended binary Golay code") return G + def vanLintSchrijverGraph(): r""" Return the van Lint-Schrijver graph. @@ -533,6 +543,7 @@ def vanLintSchrijverGraph(): H.name("Linst-Schrijver graph") return H + def LeonardGraph(): r""" Return the Leonard graph. @@ -567,6 +578,7 @@ def LeonardGraph(): G = Graph(edges, format="list_of_edges") return G + def UstimenkoGraph(const int m, const int q): r""" Return the Ustimenko graph with parameters `(m, q)`. @@ -617,6 +629,7 @@ def UstimenkoGraph(const int m, const int q): G.name(f"Ustimenko graph ({m}, {q})") return G + def BilinearFormsGraph(const int d, const int e, const int q): r""" Return a bilinear forms graph with the given parameters. @@ -704,9 +717,10 @@ def BilinearFormsGraph(const int d, const int e, const int q): edges.append((intM1, intM3)) G = Graph(edges, format='list_of_edges') - G.name("Bilinear forms graphs over F_%d with parameters (%d, %d)"%(q, d, e)) + G.name("Bilinear forms graphs over F_%d with parameters (%d, %d)" % (q, d, e)) return G + def AlternatingFormsGraph(const int n, const int q): r""" Return the alternating forms graph with the given parameters. @@ -800,9 +814,10 @@ def AlternatingFormsGraph(const int n, const int q): edges.append((t1, t3)) G = Graph(edges, format='list_of_edges') - G.name("Alternating forms graph on (F_%d)^%d"%(q, n)) + G.name("Alternating forms graph on (F_%d)^%d" % (q, n)) return G + def HermitianFormsGraph(const int n, const int r): r""" Return the Hermitian forms graph with the given parameters. @@ -905,6 +920,7 @@ def HermitianFormsGraph(const int n, const int r): G.name(f"Hermitian forms graph on (F_{q})^{n}") return G + def DoubleOddGraph(const int n): r""" Return the double odd graph on `2n+1` points. @@ -967,9 +983,10 @@ def DoubleOddGraph(const int n): edges.append((tuple(s1), tuple(s2))) G = Graph(edges, format='list_of_edges') - G.name("Bipartite double of Odd graph on a set of %d elements"%(2*n + 1)) + G.name("Bipartite double of Odd graph on a set of %d elements" % (2*n + 1)) return G + def HalfCube(const int n): r""" Return the halved cube in `n` dimensions. @@ -1035,9 +1052,10 @@ def HalfCube(const int n): G = Graph([range(2**(n - 1)), E], format='vertices_and_edges') G.set_pos(pos) - G.name("Half %d Cube"%n) + G.name("Half %d Cube" % n) return G + def GrassmannGraph(const int q, const int n, const int input_e): r""" Return the Grassmann graph with parameters `(q, n, e)`. @@ -1086,11 +1104,12 @@ def GrassmannGraph(const int q, const int n, const int input_e): PG = designs.ProjectiveGeometryDesign(n - 1, e - 1, q) # we want the intersection graph # the size of the intersection must be (q^{e-1} - 1) / (q-1) - size = (q**(e-1) - 1) // (q - 1) + size = (q**(e - 1) - 1) // (q - 1) G = PG.intersection_graph([size]) - G.name("Grassmann graph J_%d(%d, %d)"%(q, n, e)) + G.name("Grassmann graph J_%d(%d, %d)" % (q, n, e)) return G + def DoubleGrassmannGraph(const int q, const int e): r""" Return the bipartite double of the distance-`e` graph of the Grassmann graph `J_q(n,e)`. @@ -1145,7 +1164,7 @@ def DoubleGrassmannGraph(const int q, const int e): edges.append((Wbasis, Ubasis)) G = Graph(edges, format='list_of_edges') - G.name("Double Grassmann graph (%d, %d, %d)"%(n, e, q)) + G.name("Double Grassmann graph (%d, %d, %d)" % (n, e, q)) return G @@ -1216,7 +1235,8 @@ def is_from_GQ_spread(list arr): is not True: return False - return (s,t) + return (s, t) + def graph_from_GQ_spread(const int s, const int t): r""" @@ -1269,6 +1289,7 @@ def graph_from_GQ_spread(const int s, const int t): G = Graph(edges, format="list_of_edges") return G + def GeneralisedDodecagonGraph(const int s, const int t): r""" Return the point-graph of a generalised dodecagon of order `(s,t)`. @@ -1363,16 +1384,17 @@ def GeneralisedDodecagonGraph(const int s, const int t): edges.append((p, l)) G = Graph(edges, format='list_of_edges') - G.name("Generalised dodecagon of order (1, %d)"%q) + G.name("Generalised dodecagon of order (1, %d)" % q) return G else: # orderType == 1 # dual H = GeneralisedDodecagonGraph(t, s) G = _line_graph_generalised_polygon(H) - G.name("Generalised dodecagon of order (%s, %d)"%(s, t)) + G.name("Generalised dodecagon of order (%s, %d)" % (s, t)) return G + def GeneralisedOctagonGraph(const int s, const int t): r""" Return the point-graph of a generalised octagon of order `(s,t)`. @@ -1427,7 +1449,7 @@ def GeneralisedOctagonGraph(const int s, const int t): elif t == 1: # (q, 1) q = s orderType = 1 - elif s**2 == t: # (q, q^2) + elif s**2 == t: # (q, q^2) q = s (p, k) = is_prime_power(q, get_data=True) @@ -1463,14 +1485,14 @@ def GeneralisedOctagonGraph(const int s, const int t): edges.append((p, l)) G = Graph(edges, format='list_of_edges') - G.name("Generalised octagon of order (1, %d)"%q) + G.name("Generalised octagon of order (1, %d)" % q) return G elif orderType == 1: # dual H = GeneralisedOctagonGraph(t, s) G = _line_graph_generalised_polygon(H) - G.name("Generalised octagon of order(%d, %d)"%(s, t)) + G.name("Generalised octagon of order(%d, %d)" % (s, t)) return G else: if q == 2: @@ -1570,14 +1592,14 @@ def GeneralisedHexagonGraph(const int s, const int t): edges.append((p, tuple(l))) G = Graph(edges, format='list_of_edges') - G.name("Generalised hexagon of order (1, %d)"%q) + G.name("Generalised hexagon of order (1, %d)" % q) return G elif orderType == 1: # dual graph H = GeneralisedHexagonGraph(t, s) G = _line_graph_generalised_polygon(H) - G.name("Generalised hexagon of order(%d, %d)"%(s, t)) + G.name("Generalised hexagon of order(%d, %d)" % (s, t)) return G elif orderType == 2: @@ -1587,7 +1609,7 @@ def GeneralisedHexagonGraph(const int s, const int t): group = libgap.AtlasGroup("U3(3).2", libgap.NrMovedPoints, 63) G = Graph(libgap.Orbit(group, [1, 19], libgap.OnSets), format='list_of_edges') - G.name("Generalised hexagon of order (%d, %d)"%(q, q)) + G.name("Generalised hexagon of order (%d, %d)" % (q, q)) return G elif q == 3: # we don't have permutation representation; so we build it @@ -1599,17 +1621,17 @@ def GeneralisedHexagonGraph(const int s, const int t): # now group is our permutation representation G = Graph(libgap.Orbit(group, [1, 52], libgap.OnSets), format='list_of_edges') - G.name("Generalised hexagon of order (%d, %d)"%(q, q)) + G.name("Generalised hexagon of order (%d, %d)" % (q, q)) return G elif q <= 5: n = 1365 if q == 4 else 3906 p = 43 if q == 4 else 185 - group = libgap.AtlasGroup("G2(%d)"%q, libgap.NrMovedPoints, n) + group = libgap.AtlasGroup("G2(%d)" % q, libgap.NrMovedPoints, n) G = Graph(libgap.Orbit(group, [1, p], libgap.OnSets), format='list_of_edges') - G.name("Generalised hexagon of order (%d, %d)"%(q, q)) + G.name("Generalised hexagon of order (%d, %d)" % (q, q)) return G else: @@ -1619,14 +1641,15 @@ def GeneralisedHexagonGraph(const int s, const int t): if q > 3: raise NotImplementedError("Graph would be too big") - movedPoints = 819 if q==2 else 26572 - group = libgap.AtlasGroup("3D4(%d)"%q, libgap.NrMovedPoints, movedPoints) + movedPoints = 819 if q == 2 else 26572 + group = libgap.AtlasGroup("3D4(%d)" % q, libgap.NrMovedPoints, movedPoints) G = Graph(libgap.Orbit(group, [1, 2], libgap.OnSets), format='list_of_edges') - G.name("Generalised hexagon of order (%d, %d)"%(q, q**3)) + G.name("Generalised hexagon of order (%d, %d)" % (q, q**3)) return G + def _extract_lines(G): r""" Return the set of lines from the point-graph of a generalised polygon. @@ -1666,14 +1689,13 @@ def _extract_lines(G): generalised polygons. See also [BCN1989]_ pp. 28, 29 for some theory about singular lines. """ - lines = [] edges = set(G.edges(labels=False, sort=False)) while edges: (x, y) = edges.pop() - #compute line + # compute line botX = set(G.neighbors(x, closed=True)) botY = set(G.neighbors(y, closed=True)) bot1 = botX.intersection(botY) @@ -1699,6 +1721,7 @@ def _extract_lines(G): return lines + def _line_graph_generalised_polygon(H): r""" Return the line-graph of the generalised polygon whose point-graph is `H`. @@ -1752,6 +1775,7 @@ def _line_graph_generalised_polygon(H): G = Graph(edges, format="list_of_edges") return G + def _intersection_array_from_graph(G): r""" Return the intersection array of the graph `G`. @@ -1816,6 +1840,7 @@ cdef enum ClassicalParametersGraph: LieE77, AffineE6 + def is_classical_parameters_graph(list array): r""" Return a tuple of parameters representing the array given. If such no tuple @@ -1889,7 +1914,7 @@ def is_classical_parameters_graph(list array): return -1 def check_parameters(int d, int b, int alpha, int beta, list arr): - bs = [(q_binomial(d, 1, b) - q_binomial(i, 1, b)) * \ + bs = [(q_binomial(d, 1, b) - q_binomial(i, 1, b)) * (beta - alpha * q_binomial(i, 1, b)) for i in range(d)] cs = [q_binomial(i, 1, b) * (1 + alpha*q_binomial(i-1, 1, b)) for i in range(1, d+1)] @@ -1908,7 +1933,7 @@ def is_classical_parameters_graph(list array): def a_(i): return b_(0) - b_(i) - c_(i) - if len(array) % 2 != 0 : + if len(array) % 2: return False d = len(array) // 2 @@ -1961,7 +1986,7 @@ def is_classical_parameters_graph(list array): gamma = ClassicalParametersGraph.NonExisting - if b == 1 : + if b == 1: if alpha == 1 and beta >= d: # since beta+d = n >= 2*d # Johnson Graph gamma = ClassicalParametersGraph.Johnson @@ -1971,18 +1996,18 @@ def is_classical_parameters_graph(list array): elif alpha == 2 and (beta == 2*d + 1 or beta == 2*d - 1): # Halved cube graph gamma = ClassicalParametersGraph.HalvedCube - else : + else: return False # no other (unbounbded) drg exists with b = 1 elif b < 0 and is_prime_power(-b): - if alpha + 1 == (1 + b*b) / (1 + b) and \ - beta + 1 == (1 - b**(d+1)) / (1 + b): + if (alpha + 1 == (1 + b*b) / (1 + b) and + beta + 1 == (1 - b**(d + 1)) / (1 + b)): # U(2d,r) gamma = ClassicalParametersGraph.UnitaryDualPolar1 elif alpha + 1 == b and beta + 1 == - (b**d): gamma = ClassicalParametersGraph.HermitianForms - elif d == 3 and alpha + 1 == 1 / (1+b) and \ - beta + 1 == q_binomial(3, 1, -b): + elif (d == 3 and alpha + 1 == 1 / (1+b) and + beta + 1 == q_binomial(3, 1, -b)): gamma = ClassicalParametersGraph.GeneralisedHexagon else: return False @@ -2001,7 +2026,7 @@ def is_classical_parameters_graph(list array): # Grassmann graph gamma = ClassicalParametersGraph.Grassmann - elif alpha == 0 and beta * beta in {1, b, b * b, b**3, b**4}: + elif alpha == 0 and beta * beta in {1, b, b * b, b**3, b**4}: # checked beta in {b^0, b^(0.5), b, b^(1.5), b^2} # dual polar graphs if beta == 1: @@ -2018,20 +2043,20 @@ def is_classical_parameters_graph(list array): elif beta == r: gamma = ClassicalParametersGraph.UnitaryDualPolar2 - elif k % 2 == 0 and alpha + 1 == q_binomial(3, 1, r) and \ - beta + 1 in {q_binomial(2*d + 2, 1, r), - q_binomial(2*d + 1, 1, r)}: + elif (k % 2 == 0 and alpha + 1 == q_binomial(3, 1, r) and + beta + 1 in {q_binomial(2*d + 2, 1, r), + q_binomial(2*d + 1, 1, r)}): gamma = ClassicalParametersGraph.Ustimenko elif alpha + 1 == b and integral_log(beta + 1, b) >= d: gamma = ClassicalParametersGraph.BilinearForms - elif k % 2 == 0 and alpha + 1 == b and \ - beta + 1 in {r**(2*d - 1),r**(2*d + 1)}: + elif (k % 2 == 0 and alpha + 1 == b and + beta + 1 in {r**(2*d - 1), r**(2*d + 1)}): gamma = ClassicalParametersGraph.AlternatingForms - elif d == 3 and k % 4 == 0 and alpha + 1 == q_binomial(5, 1, p**(k//4)) and \ - beta + 1 == q_binomial(10, 1, p**(k//4)): + elif (d == 3 and k % 4 == 0 and alpha + 1 == q_binomial(5, 1, p**(k//4)) and + beta + 1 == q_binomial(10, 1, p**(k//4))): gamma = ClassicalParametersGraph.LieE77 elif d == 3 and k % 4 == 0 and alpha + 1 == b and beta + 1 == (p**(k//4))**9: @@ -2041,6 +2066,7 @@ def is_classical_parameters_graph(list array): return False return (d, b, alpha, beta, gamma) + def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): r""" Return the graph with the classical parameters given. @@ -2134,14 +2160,14 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): return UnitaryDualPolarGraph(2 * d, -b) elif gamma == ClassicalParametersGraph.HermitianForms: - return HermitianFormsGraph(d,(-b)**2) + return HermitianFormsGraph(d, (-b)**2) elif gamma == ClassicalParametersGraph.GeneralisedHexagon: q = -b return GeneralisedHexagonGraph(q, q**3) elif gamma == ClassicalParametersGraph.Grassmann: - n = int(log((beta+1) * (b-1) + 1, b)) + d -1 + n = int(log((beta + 1) * (b - 1) + 1, b)) + d - 1 return GrassmannGraph(b, n, d) elif gamma == ClassicalParametersGraph.OrthogonalDualPolar1: @@ -2175,12 +2201,13 @@ def graph_with_classical_parameters(int d, int b, alpha_in, beta_in, int gamma): a = 0 if beta + 1 == q**(2*d - 1) else 1 return AlternatingFormsGraph(2*d + a, q) - elif gamma == ClassicalParametersGraph.LieE77 or \ - gamma == ClassicalParametersGraph.AffineE6: + elif (gamma == ClassicalParametersGraph.LieE77 or + gamma == ClassicalParametersGraph.AffineE6): raise NotImplementedError("Graph would be too big") raise ValueError("Incorrect family of graphs") + def is_pseudo_partition_graph(list arr): r""" Return `(m, a)` if the intersection array given satisfies: @@ -2235,7 +2262,7 @@ def is_pseudo_partition_graph(list arr): d = d // 2 - if d < 3 : + if d < 3: return False # c_2 = 2 (1+a) @@ -2265,6 +2292,7 @@ def is_pseudo_partition_graph(list arr): return False + def pseudo_partition_graph(int m, int a): r""" Return a pseudo partition graph with the given parameters. From d629def1d9354131b9b468e7a6406529833cea6c Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 12:03:04 +0200 Subject: [PATCH 284/591] trac #34311: clean strongly_regular_db.pyx - part 1 --- src/sage/graphs/strongly_regular_db.pyx | 176 +++++++++++++----------- 1 file changed, 94 insertions(+), 82 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index a98c5662b35..ea868e095c7 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -2210,6 +2210,7 @@ def SRG_220_84_38_28(): G.name('Tonchev: quasisymmetric 2-(45,9,8)') return G + def SRG_276_140_58_84(): r""" Return a `(276, 140, 58, 84)`-strongly regular graph. @@ -2237,11 +2238,12 @@ def SRG_276_140_58_84(): [20, 75, 98, 239, 267], [21, 33, 56, 113, 240], [23, 127, 152, 164, 172], [25, 101, 128, 183, 264], [27, 129, 154, 160, 201], [28, 126, 144, 161, 228], [29, 100, 133, 204, 266], [30, 108, 146, 200, 219]] g.add_vertex(-1) - g.seidel_switching(sum(C,[])) + g.seidel_switching(sum(C, [])) g.relabel() g.name('Haemers-Tonchev') return g + def SRG_280_135_70_60(): r""" Return a strongly regular graph with parameters `(280, 135, 70, 60)`. @@ -2260,14 +2262,15 @@ def SRG_280_135_70_60(): libgap.load_package("AtlasRep") # A representation of J2 acting on a 3.PGL(2,9) it contains. - J2 = libgap.AtlasGroup("J2", libgap.NrMovedPoints, 280) - edges = J2.Orbit([1,2], libgap.OnSets) - g = Graph() + J2 = libgap.AtlasGroup("J2", libgap.NrMovedPoints, 280) + edges = J2.Orbit([1, 2], libgap.OnSets) + g = Graph() g.add_edges(edges) g.relabel() g.name('J_2 on cosets of 3.PGL(2,9)') return g + def SRG_280_117_44_52(): r""" Return a strongly regular graph with parameters `(280, 117, 44, 52)`. @@ -2292,19 +2295,20 @@ def SRG_280_117_44_52(): from sage.graphs.hypergraph_generators import hypergraphs # V is the set of partitions {{a,b,c},{d,e,f},{g,h,i}} of {0,...,8} - H = hypergraphs.CompleteUniform(9,3) + H = hypergraphs.CompleteUniform(9, 3) g = H.intersection_graph() V = g.complement().cliques_maximal() V = [frozenset(u) for u in V] # G is the graph defined on V in which two vertices are adjacent when they # corresponding partitions cross-intersect on 7 nonempty sets - G = Graph([V, lambda x,y: + G = Graph([V, lambda x, y: sum(any(xxx in yy for xxx in xx) for xx in x for yy in y) != 7], loops=False) G.name('Mathon-Rosa') return G + def strongly_regular_from_two_weight_code(L): r""" Return a strongly regular graph from a two-weight code. @@ -2337,12 +2341,13 @@ def strongly_regular_from_two_weight_code(L): if is_Matrix(L): L = LinearCode(L) V = [tuple(l) for l in L] - w1, w2 = sorted(set(sum(map(bool,x)) for x in V).difference([0])) - G = Graph([V,lambda u,v: sum(uu!=vv for uu,vv in zip(u,v)) == w1]) + w1, w2 = sorted(set(sum(map(bool, x)) for x in V).difference([0])) + G = Graph([V, lambda u, v: sum(uu!=vv for uu, vv in zip(u, v)) == w1]) G.relabel() G.name('two-weight code: '+str(L)) return G + def SRG_416_100_36_20(): r""" Return a `(416,100,36,20)`-strongly regular graph. @@ -2362,13 +2367,14 @@ def SRG_416_100_36_20(): """ from sage.libs.gap.libgap import libgap libgap.load_package("AtlasRep") - g=libgap.AtlasGroup("G2(4)",libgap.NrMovedPoints,416) + g=libgap.AtlasGroup("G2(4)", libgap.NrMovedPoints, 416) h = Graph() - h.add_edges(g.Orbit([1,5],libgap.OnSets)) + h.add_edges(g.Orbit([1, 5],libgap.OnSets)) h.relabel() h.name('G_2(4) on cosets of HS') return h + def SRG_560_208_72_80(): r""" Return a `(560,208,72,80)`-strongly regular graph @@ -2385,17 +2391,18 @@ def SRG_560_208_72_80(): """ from sage.libs.gap.libgap import libgap libgap.load_package("AtlasRep") - g=libgap.AtlasGroup("Sz8",libgap.NrMovedPoints,560) + g=libgap.AtlasGroup("Sz8", libgap.NrMovedPoints, 560) h = Graph() - h.add_edges(g.Orbit([1,2],libgap.OnSets)) - h.add_edges(g.Orbit([1,4],libgap.OnSets)) - h.add_edges(g.Orbit([1,8],libgap.OnSets)) - h.add_edges(g.Orbit([1,27],libgap.OnSets)) + h.add_edges(g.Orbit([1, 2],libgap.OnSets)) + h.add_edges(g.Orbit([1, 4],libgap.OnSets)) + h.add_edges(g.Orbit([1, 8],libgap.OnSets)) + h.add_edges(g.Orbit([1, 27],libgap.OnSets)) h.relabel() h.name('Sz(8)-graph') return h + def strongly_regular_from_two_intersection_set(M): r""" Return a strongly regular graph from a 2-intersection set. @@ -2447,14 +2454,15 @@ def strongly_regular_from_two_intersection_set(M): # For every v point of M for v in M: # u is adjacent with all vertices on a uv line. - g.add_edges([[u,tuple([u[i]+qq*v[i] for i in range(k)])] \ - for qq in K if not qq==K.zero()]) + g.add_edges([[u, tuple([u[i] + qq*v[i] for i in range(k)])] + for qq in K if not qq==K.zero()]) g.relabel() e = QQ((1,k)) qq = g.num_verts()**e g.name('two-intersection set in PG('+str(k)+','+str(qq)+')') return g + def SRG_120_63_30_36(): r""" Return a `(120,63,30,36)`-strongly regular graph @@ -2470,7 +2478,8 @@ def SRG_120_63_30_36(): (120, 63, 30, 36) """ from sage.graphs.generators.families import JohnsonGraph - return JohnsonGraph(10,3).distance_graph([2]) + return JohnsonGraph(10, 3).distance_graph([2]) + def SRG_126_25_8_4(): r""" @@ -2487,7 +2496,8 @@ def SRG_126_25_8_4(): (126, 25, 8, 4) """ from sage.graphs.generators.families import JohnsonGraph - return JohnsonGraph(9,4).distance_graph([1,4]) + return JohnsonGraph(9, 4).distance_graph([1, 4]) + def SRG_175_72_20_36(): r""" @@ -2509,6 +2519,7 @@ def SRG_175_72_20_36(): from sage.graphs.generators.smallgraphs import HoffmanSingletonGraph return HoffmanSingletonGraph().line_graph().distance_graph([2]) + def SRG_176_90_38_54(): r""" Return a `(176,90,38,54)`-strongly regular graph @@ -2533,11 +2544,12 @@ def SRG_176_90_38_54(): g.relabel(range(175)) # c=filter(lambda x: len(x)==5, g.cliques_maximal()) # r=flatten(Hypergraph(c).packing()[:18]) # takes 3s, so we put the answer here - r = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23, - 24,25,28,29,32,38,39,41,42,43,47,49,50,51,52,53,55,57,61,63,65, - 67,69,72,75,77,79,81,84,87,88,89,92,95,96,97,99,101,102,104, - 105,107,112,114,117,118,123,125,129,132,139,140,141,144,146, - 147,153,154,162,165,166,167,170,172,173,174] + r = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 28, 29, 32, 38, 39, 41, 42, 43, 47, 49, 50, 51, + 52, 53, 55, 57, 61, 63, 65, 67, 69, 72, 75, 77, 79, 81, 84, 87, 88, 89, + 92, 95, 96, 97, 99, 101, 102, 104, 105, 107, 112, 114, 117, 118, 123, + 125, 129, 132, 139, 140, 141, 144, 146, 147, 153, 154, 162, 165, 166, + 167, 170, 172, 173, 174] g.add_vertex() g.seidel_switching(r) g.name('a Seidel switching of ' + g.name()) @@ -2592,13 +2604,12 @@ def SRG_126_50_13_24(): from sage.graphs.strongly_regular_db import SRG_175_72_20_36 from sage.graphs.generators.smallgraphs import HoffmanSingletonGraph hs = HoffmanSingletonGraph() - s = set(hs.vertices(sort=False)).difference(hs.neighbors(0)+[0]) - g = SRG_175_72_20_36().subgraph(hs.edge_boundary(s,s)) + s = set(hs.vertices(sort=False)).difference(hs.neighbors(0) + [0]) + g = SRG_175_72_20_36().subgraph(hs.edge_boundary(s, s)) g.name('Goethals graph') return g - def SRG_1288_792_476_504(): r""" Return a `(1288, 792, 476, 504)`-strongly regular graph. @@ -2626,11 +2637,12 @@ def SRG_1288_792_476_504(): for c in C] C = [s for s in C if len(s) == 12] G = Graph([[frozenset(c) for c in C], - lambda x,y: len(x.symmetric_difference(y)) == 12]) + lambda x, y: len(x.symmetric_difference(y)) == 12]) G.relabel() G.name('binary Golay code') return G + cdef bint seems_feasible(int v, int k, int l, int mu): r""" Check if the set of parameters seems feasible. @@ -2649,25 +2661,25 @@ cdef bint seems_feasible(int v, int k, int l, int mu): """ cdef uint_fast32_t tmp[2] - if (v<0 or k<=0 or l<0 or mu<0 or - k>=v-1 or l>=k or mu>k or - v-2*k+mu-2 < 0 or # lambda of complement graph >=0 - v-2*k+l < 0 or # μ of complement graph >= 0 - mu*(v-k-1) != k*(k-l-1)): + if (v < 0 or k <= 0 or l < 0 or mu < 0 or + k >= v - 1 or l >= k or mu > k or + v - 2*k + mu - 2 < 0 or # lambda of complement graph >=0 + v - 2*k + l < 0 or # μ of complement graph >= 0 + mu*(v - k - 1) != k*(k - l - 1)): return False - if mu == k: # complete multipartite graph - r = v//(v-k) # number of parts (of size v-k each) + if mu == k: # complete multipartite graph + r = v//(v-k) # number of parts (of size v-k each) return (l == (v-k)*(r-2) and v == r*(v-k)) - if mu == 0: # the complement of a complete multipartite graph - r = v//(k+1) # number of parts (of size k+1 each) + if mu == 0: # the complement of a complete multipartite graph + r = v//(k+1) # number of parts (of size k+1 each) return (l == k-1 and v == r*(k+1)) # Conference graphs. Only possible if 'v' is a sum of two squares (3.A of # [BL1984]_) if (v-1)*(mu-l)-2*k == 0: - return two_squares_c(v,tmp) + return two_squares_c(v, tmp) rr, ss = eigenvalues(v, k, l, mu) if rr is None: @@ -2682,45 +2694,43 @@ cdef bint seems_feasible(int v, int k, int l, int mu): # Theorem 21.3 of [WilsonACourse] or # 3.B of [BL1984]_ # (Krein conditions) - if ((r+1)*(k+r+2*r*s) > (k+r)*(s+1)**2 or - (s+1)*(k+s+2*r*s) > (k+s)*(r+1)**2): + if (r+1)*(k+r+2*r*s) > (k+r)*(s+1)**2 or (s+1)*(k+s+2*r*s) > (k+s)*(r+1)**2: return False # multiplicity of eigenvalues 'r,s' (f=lambda_r, g=lambda_s) # # They are integers (checked by the 'integrality condition'). f = -k*(s+1)*(k-s)//(mu*(r-s)) - g = k*(r+1)*(k-r)//(mu*(r-s)) - if 1+f+g != v: # the only other eigenvalue, k, has multiplicity 1 + g = k*(r+1)*(k-r)//(mu*(r-s)) + if 1 + f + g != v: # the only other eigenvalue, k, has multiplicity 1 return False # 3.C of [BL1984]_ # (Absolute bound) - if (2*v > f*(f+3) or - 2*v > g*(g+3)): + if 2*v > f*(f+3) or 2*v > g*(g+3): return False # 3.D of [BL1984]_ # (Claw bound) - if (mu != s**2 and - mu != s*(s+1) and - 2*(r+1) > s*(s+1)*(mu+1)): + if (mu != s**2 and + mu != s*(s+1) and + 2*(r+1) > s*(s+1)*(mu+1)): return False # 3.E of [BL1984]_ # (the Case μ=1) if mu == 1: - if ( k % (l+1) or - (v*k) % ((l+1)*(l+2))): + if k % (l+1) or (v*k) % ((l+1)*(l+2)): return False # 3.F of [BL1984]_ # (the Case μ=2) - if mu == 2 and 2*k < l*(l+3) and k%(l+1): + if mu == 2 and 2*k < l*(l + 3) and k % (l + 1): return False return True + def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, bint check=True): r""" Return a `(v,k,\lambda,\mu)`-strongly regular graph. @@ -2847,7 +2857,7 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, Multipartite Graph with set sizes [3, 3]: Graph on 6 vertices """ if mu == -1: - mu = k*(k-l-1)//(v-k-1) + mu = k*(k - l - 1)//(v - k - 1) g = strongly_regular_graph_lazy(v, k, l, mu=mu, existence=existence) if existence is True: return g @@ -2857,6 +2867,7 @@ def strongly_regular_graph(int v, int k, int l, int mu=-1, bint existence=False, raise RuntimeError(f"Sage built an incorrect {params}-SRG.") return G + def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=False): r""" return a promise to build an `(v,k,l,mu)`-srg @@ -2893,10 +2904,10 @@ def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=F """ load_brouwer_database() if mu == -1: - mu = k*(k-l-1)//(v-k-1) + mu = k*(k - l - 1)//(v - k - 1) params = (v, k, l, mu) - params_complement = (v,v-k-1,v-2*k+mu-2,v-2*k+l) + params_complement = (v, v - k - 1, v - 2*k + mu - 2, v - 2*k + l) if not seems_feasible(v, k, l, mu): if existence: @@ -2913,7 +2924,7 @@ def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=F val = _small_srg_database[params_complement] return True if existence else (lambda *t: val[0](*t).complement(), *val[1:]) - test_functions = [is_complete_multipartite, # must be 1st, to prevent 0-divisions + test_functions = [is_complete_multipartite, # must be 1st, to prevent 0-divisions is_paley, is_johnson, is_orthogonal_array_block_graph, is_steiner, is_affine_polar, @@ -2940,7 +2951,7 @@ def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=F if existence: return True ans = f(*params) - return (ans[0],*ans[1:]) + return (ans[0], *ans[1:]) if f(*params_complement): if existence: return True @@ -2952,7 +2963,7 @@ def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=F # We try to return the most appropriate error message. global _brouwer_database - brouwer_data = _brouwer_database.get(params,None) + brouwer_data = _brouwer_database.get(params, None) if brouwer_data is not None: comments = brouwer_data['comments'] @@ -2986,6 +2997,7 @@ def strongly_regular_graph_lazy(int v, int k, int l, int mu=-1, bint existence=F f"Sage cannot figure out if a {params}-strongly " f"regular graph exists.") + def apparently_feasible_parameters(int n): r""" Return a list of a priori feasible parameters `(v,k,\lambda,\mu)`, with `0<\mu 0 and mu < k and seems_feasible(v, k, l, mu): feasible.add((v, k, l, mu)) return feasible + def _build_small_srg_database(): r""" Build the database of small strongly regular graphs. @@ -3106,7 +3118,6 @@ def _build_small_srg_database(): sage: graphs.strongly_regular_graph(1024, 825, 668, 650)# not tested (too long) complement(two-intersection set in PG(10,2)): Graph on 1024 vertices """ - from sage.graphs.generators.smallgraphs import McLaughlinGraph from sage.graphs.generators.smallgraphs import CameronGraph from sage.graphs.generators.smallgraphs import GritsenkoGraph @@ -3125,8 +3136,9 @@ def _build_small_srg_database(): global _small_srg_database _small_srg_database = { - ( 36, 14, 4, 6): [Graph,('c~rLDEOcKTPO`U`HOIj@MWFLQFAaRIT`HIWqPsQQJ'+ - 'DXGLqYM@gRLAWLdkEW@RQYQIErcgesClhKefC_ygSGkZ`OyHETdK[?lWStCapVgKK')], + ( 36, 14, 4, 6): [Graph, ('c~rLDEOcKTPO`U`HOIj@MWFLQFAaRIT`HIWqPsQQJ' + 'DXGLqYM@gRLAWLdkEW@RQYQIErcgesClhKefC_ygS' + 'GkZ`OyHETdK[?lWStCapVgKK')], ( 50, 7, 0, 1): [HoffmanSingletonGraph], ( 56, 10, 0, 2): [SimsGewirtzGraph], ( 65, 32, 15, 16): [GritsenkoGraph], @@ -3172,30 +3184,30 @@ def _build_small_srg_database(): # Turns the known two-weight codes into SRG constructors # - cdef int n,q,k,w1,w2,K,N,l,m,K_O,l_O,m_O + cdef int n, q, k, w1, w2, K, N, l, m, K_O, l_O, m_O import sage.coding.two_weight_db from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ - cinv = matrix(ZZ, [[1,0,0],[0,0,1],[0,1,0]]) + cinv = matrix(ZZ, [[1, 0, 0], [0, 0, 1], [0, 1, 0]]) for code in sage.coding.two_weight_db.data: - n,q,k,w1,w2 = code['n'], code['K'].cardinality(), code['k'], code['w1'], code['w2'] + n, q, k, w1, w2 = code['n'], code['K'].cardinality(), code['k'], code['w1'], code['w2'] N = q**k - K_O = n*(q-1) - l_O = K_O**2+3*K_O-q*(w1+w2)-K_O*q*(w1+w2)+w1*w2*q**2 + K_O = n*(q - 1) + l_O = K_O**2 + 3*K_O - q*(w1 + w2) - K_O*q*(w1 + w2) + w1*w2*q**2 m_O = (w1*w2*q**2)//N - em = eigenmatrix(N,K_O,l_O,m_O) # 1st eigenmatrix - assert((not em is None) and (em.det() != 0)) - emi = N*em.inverse() # 2nd eigenmatrix + em = eigenmatrix(N, K_O, l_O, m_O) # 1st eigenmatrix + assert((em is not None) and (em.det() != 0)) + emi = N*em.inverse() # 2nd eigenmatrix # 1st and 2nd eigenmatrices equal up to renumbering graphs? - selfdual = em==cinv*emi*cinv - _small_srg_database[N,K_O,l_O,m_O] = \ + selfdual = em == cinv*emi*cinv + _small_srg_database[N, K_O, l_O, m_O] = \ [lambda x: strongly_regular_from_two_intersection_set(x.transpose()), code['M']] - if not selfdual: # we can build two graphs (not complements to each other!) - K, s, r = emi[0,1], emi[1,1], emi[2,1] # by Thm 5.7 in [CK1986]_. - l = K+r*s+r+s - m = K+r*s - _small_srg_database[N,K,l,m] = [strongly_regular_from_two_weight_code, code['M']] + if not selfdual: # we can build two graphs (not complements to each other!) + K, s, r = emi[0, 1], emi[1, 1], emi[2, 1] # by Thm 5.7 in [CK1986]_. + l = K + r*s + r + s + m = K + r*s + _small_srg_database[N, K, l, m] = [strongly_regular_from_two_weight_code, code['M']] cdef load_brouwer_database(): @@ -3257,8 +3269,8 @@ def _check_database(): _brouwer_database, saved_database = {}, _brouwer_database cdef int missed = 0 - for params,dic in sorted(saved_database.items()): - sage_answer = strongly_regular_graph(*params,existence=True) + for params, dic in sorted(saved_database.items()): + sage_answer = strongly_regular_graph(*params, existence=True) if dic['status'] == 'open': if sage_answer is True: print("Sage can build a {}, Brouwer's database cannot".format(params)) @@ -3267,13 +3279,13 @@ def _check_database(): if sage_answer is not True: print(("Sage cannot build a ({:<4} {:<4} {:<4} {:<4}) that exists. " + "Comment from Brouwer's database: ").format(*params) - + dic['comments']) + + dic['comments']) missed += 1 assert sage_answer is not False elif dic['status'] == 'impossible': assert sage_answer is not True else: - assert False # must not happen + assert False # must not happen status = [x['status'] for x in saved_database.values()] print("\nIn Andries Brouwer's database:") From 7ef0a024dce461c2574d5813d995968bec225212 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 12:50:36 +0200 Subject: [PATCH 285/591] trac #34312: clean strongly_regular_db.pyx - part 2 --- src/sage/graphs/strongly_regular_db.pyx | 141 +++++++++++++----------- 1 file changed, 78 insertions(+), 63 deletions(-) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index ea868e095c7..027011ac677 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1300,6 +1300,7 @@ def is_unitary_polar(int v, int k, int l, int mu): from sage.graphs.generators.classical_geometries import UnitaryPolarGraph return (UnitaryPolarGraph, 2*d, p**t) + @cached_function def is_unitary_dual_polar(int v, int k, int l, int mu): r""" @@ -1339,19 +1340,20 @@ def is_unitary_dual_polar(int v, int k, int l, int mu): q = mu - 1 if q < 2: return - p,t = is_prime_power(q, get_data=True) + p, t = is_prime_power(q, get_data=True) if p**t != q or t % 2: return if (r < 0 and q != -r - 1) or (s < 0 and q != -s - 1): return t //= 2 # we have correct mu, negative eigenvalue, and q=p^(2t) - if (v == (q**2*p**t + 1)*(q*p**t + 1) and - k == q*p**t*(q + 1) and - l == k - 1 - q**2*p**t): + if (v == (q**2*p**t + 1)*(q*p**t + 1) and + k == q*p**t*(q + 1) and + l == k - 1 - q**2*p**t): from sage.graphs.generators.classical_geometries import UnitaryDualPolarGraph return (UnitaryDualPolarGraph, 5, p**t) + @cached_function def is_GQqmqp(int v, int k, int l, int mu): r""" @@ -1410,25 +1412,26 @@ def is_GQqmqp(int v, int k, int l, int mu): """ # do we have GQ(s,t)? we must have mu=t+1, s=l+1, # v=(s+1)(st+1), k=s(t+1) - S=l+1 - T=mu-1 + S = l + 1 + T = mu - 1 q = (S+T)//2 p, w = is_prime_power(q, get_data=True) - if (v == (S+1)*(S*T+1) and - k == S*(T+1) and - q == p**w and - (S+T)//2 == q): + if (v == (S+1)*(S*T+1) and + k == S*(T+1) and + q == p**w and + (S+T)//2 == q): if p % 2 == 0: from sage.graphs.generators.classical_geometries\ import T2starGeneralizedQuadrangleGraph as F else: from sage.graphs.generators.classical_geometries\ import AhrensSzekeresGeneralizedQuadrangleGraph as F - if (S,T) == (q-1, q+1): + if (S, T) == (q-1, q+1): return (F, q, False) - elif (S,T) == (q+1, q-1): + elif (S, T) == (q+1, q-1): return (F, q, True) + @cached_function def is_twograph_descendant_of_srg(int v, int k0, int l, int mu): r""" @@ -1475,23 +1478,23 @@ def is_twograph_descendant_of_srg(int v, int k0, int l, int mu): (279, 150, 85, 75) """ cdef int b, k, s - if k0 != 2*mu or v % 2 == 0: + if k0 != 2*mu or not v % 2: return b = v+1+4*mu D = sqrt(b**2-16*v*mu) - if int(D)==D: + if int(D) == D: for kf in [(-D+b)//4, (D+b)//4]: k = int(kf) - if k == kf and \ - strongly_regular_graph(v+1, k, l - 2*mu + k , k - mu, existence=True) is True: + if (k == kf and + strongly_regular_graph(v+1, k, l - 2*mu + k, k - mu, existence=True) is True): try: - g = strongly_regular_graph_lazy(v+1, k, l - 2*mu + k) # Sage might not know how to build g + g = strongly_regular_graph_lazy(v+1, k, l - 2*mu + k) # Sage might not know how to build g def la(*gr): from sage.combinat.designs.twographs import twograph_descendant gg = g[0](*gr) if (gg.name() is None) or (gg.name() == ''): - gg = Graph(gg, name=str((v+1, k, l - 2*mu + k , k - mu))+"-strongly regular graph") + gg = Graph(gg, name=str((v+1, k, l - 2*mu + k, k - mu))+"-strongly regular graph") return twograph_descendant(gg, next(gg.vertex_iterator()), name=True) return (la, *g[1:]) @@ -1538,7 +1541,7 @@ def is_taylor_twograph_srg(int v, int k, int l, int mu): r, s = eigenvalues(v, k, l, mu) if r is None: return - p,t = is_prime_power(v-1, get_data=True) + p, t = is_prime_power(v-1, get_data=True) if p**t+1 != v or t % 3 != 0 or p % 2 == 0: return q = p**(t//3) @@ -1547,6 +1550,7 @@ def is_taylor_twograph_srg(int v, int k, int l, int mu): return (TaylorTwographSRG, q) return + def is_switch_skewhad(int v, int k, int l, int mu): r""" Test whether some ``switch skewhad^2+*`` is `(v,k,\lambda,\mu)`-strongly regular. @@ -1584,14 +1588,15 @@ def is_switch_skewhad(int v, int k, int l, int mu): r, s = eigenvalues(v, k, l, mu) if r is None: return - if r.switch_OA_srg at ..., 12, 25) sage: is_switch_OA_srg(842, 406, 195, 196) (.switch_OA_srg at ..., 14, 29) - """ cdef int n_2_p_1 = v - cdef int n = floor(sqrt(n_2_p_1-1)) + cdef int n = floor(sqrt(n_2_p_1 - 1)) if n*n != n_2_p_1-1: # is it a square? return None cdef int c = k//n - if (k % n or - l != c*c-1 or - k != 1+(c-1)*(c+1)+(n-c)*(n-c-1) or - not orthogonal_array(c+1,n,existence=True,resolvable=True) is True): + if (k % n or l != c*c-1 or k != 1+(c-1)*(c+1)+(n-c)*(n-c-1) or + orthogonal_array(c+1, n, existence=True, resolvable=True) is not True): return None def switch_OA_srg(c, n): OA = [tuple(x) for x in orthogonal_array(c+1, n, resolvable=True)] - g = Graph([OA, lambda x,y: any(xx==yy for xx,yy in zip(x,y))], + g = Graph([OA, lambda x, y: any(xx == yy for xx, yy in zip(x, y))], loops=False) g.add_vertex(0) g.seidel_switching(OA[:c*n]) @@ -1692,15 +1694,16 @@ def is_nowhere0_twoweight(int v, int k, int l, int mu): r, s = eigenvalues(v, k, l, mu) if r is None: return - if r 4 and is_prime_power(q) and 0==r%2 and \ - v == r*(q-1)**2 and \ - 4*k == q*(q-2)*(q-3) and \ - 8*mu == q*(q-3)*(q-4): + if (q > 4 and is_prime_power(q) and not r % 2 and + v == r*(q-1)**2 and + 4*k == q*(q-2)*(q-3) and + 8*mu == q*(q-3)*(q-4)): return (Nowhere0WordsTwoWeightCodeGraph, q) + cdef eigenvalues(int v, int k, int l, int mu): r""" Return the eigenvalues of a (v,k,l,mu)-strongly regular graph. @@ -1719,7 +1722,7 @@ cdef eigenvalues(int v, int k, int l, int mu): c = (mu-k) D = b**2-4*c if not is_square(D): - return [None,None] + return [None, None] return [(-b+sqrt(D))/2.0, (-b-sqrt(D))/2.0] @@ -1807,9 +1810,10 @@ def eigenmatrix(int v, int k, int l, int mu): from sage.rings.integer_ring import ZZ r, s = eigenvalues(v, k, l, mu) if r is not None: - return Matrix(ZZ, [[1,k,v-k-1],[1,r,-r-1],[1,s,-s-1]]) + return Matrix(ZZ, [[1, k, v-k-1], [1, r, -r-1], [1, s, -s-1]]) -cpdef latin_squares_graph_parameters(int v,int k, int l,int mu): + +cpdef latin_squares_graph_parameters(int v, int k, int l,int mu): r""" Check whether (v,k,l,mu)-strongly regular graph has parameters of an `L_g(n)` s.r.g. @@ -1839,10 +1843,11 @@ cpdef latin_squares_graph_parameters(int v,int k, int l,int mu): r, s = s, r g = -s n = r+g - if v==n**2 and k==g*(n-1) and l==(g-1)*(g-2)+n-2 and mu==g*(g-1): + if v == n**2 and k == g*(n-1) and l == (g-1)*(g-2)+n-2 and mu == g*(g-1): return g, n return + def _H_3_cayley_graph(L): r""" return the `L`-Cayley graph of the group `H_3` from Prop. 12 in [JK2003]_. @@ -1861,16 +1866,17 @@ def _H_3_cayley_graph(L): from sage.groups.free_group import FreeGroup from sage.groups.finitely_presented import FinitelyPresentedGroup G = FreeGroup('x,y,z') - x,y,z = G.gens() - rels = (x**5,y**5,z**4,x*y*x**(-1)*y**(-1),z*x*z**(-1)*x**(-2),z*y*z**(-1)*y**(-2)) - G = FinitelyPresentedGroup(G,rels) - x,y,z = G.gens() + x, y, z = G.gens() + rels = (x**5, y**5, z**4, x*y*x**(-1)*y**(-1), z*x*z**(-1)*x**(-2), z*y*z**(-1)*y**(-2)) + G = FinitelyPresentedGroup(G, rels) + x, y, z = G.gens() H = G.as_permutation_group() L = [[int(u) for u in x] for x in L] x, y, z = (H.gen(0), H.gen(1), H.gen(2)) L = [H(x**xx*y**yy*z**zz) for xx, yy, zz in L] return Graph(H.cayley_graph(generators=L, simple=True)) + def SRG_100_44_18_20(): r""" Return a `(100, 44, 18, 20)`-strongly regular graph. @@ -1885,11 +1891,13 @@ def SRG_100_44_18_20(): sage: G.is_strongly_regular(parameters=True) # long time (100, 44, 18, 20) """ - return _H_3_cayley_graph(["100","110","130","140","200","230","240","300", - "310","320","400","410","420","440","041","111","221","231","241", - "321","331","401","421","441","002","042","112","122","142","212", - "232","242","322","342","033","113","143","223","303","333","343", - "413","433","443"]) + L = ['100', '110', '130', '140', '200', '230', '240', '300', '310', '320', + '400', '410', '420', '440', '041', '111', '221', '231', '241', '321', + '331', '401', '421', '441', '002', '042', '112', '122', '142', '212', + '232', '242', '322', '342', '033', '113', '143', '223', '303', '333', + '343', '413', '433', '443'] + return _H_3_cayley_graph(L) + def SRG_100_45_20_20(): r""" @@ -1905,11 +1913,12 @@ def SRG_100_45_20_20(): sage: G.is_strongly_regular(parameters=True) # long time (100, 45, 20, 20) """ - return _H_3_cayley_graph(["120","140","200","210","201","401","411","321", - "002","012","022","042","303","403","013","413","240","031","102", - "323","300","231","132","133","310","141","142","233","340","241", - "202","333","410","341","222","433","430","441","242","302","312", - "322","332","442","143"]) + L = ['120', '140', '200', '210', '201', '401', '411', '321', '002', '012', + '022', '042', '303', '403', '013', '413', '240', '031', '102', '323', + '300', '231', '132', '133', '310', '141', '142', '233', '340', '241', + '202', '333', '410', '341', '222', '433', '430', '441', '242', '302', + '312', '322', '332', '442', '143'] + return _H_3_cayley_graph(L) def SRG_105_32_4_12(): @@ -1966,6 +1975,7 @@ def SRG_120_77_52_44(): g.name('PG(2,2)s in PG(2,4)') return g + def SRG_144_39_6_12(): r""" Return a `(144,39,6,12)`-strongly regular graph. @@ -1990,12 +2000,13 @@ def SRG_144_39_6_12(): if len(o) != 39: continue h = Graph() - h.add_edges(G.Orbit([1,o[0]],libgap.OnSets)) + h.add_edges(G.Orbit([1, o[0]], libgap.OnSets)) if h.is_strongly_regular(): h.relabel() h.name('PGL_3(3) on cosets of 13:3') return h + def SRG_176_49_12_14(): r""" Return a `(176,49,12,14)`-strongly regular graph. @@ -2017,7 +2028,7 @@ def SRG_176_49_12_14(): from sage.combinat.designs.database import HigmanSimsDesign d = HigmanSimsDesign() g = d.incidence_graph(labels=True) - ag=g.automorphism_group().conjugacy_classes_representatives() + ag = g.automorphism_group().conjugacy_classes_representatives() # Looking for an involution that maps a point of the design to one of the # blocks that contains it. It is called a polarity with only absolute @@ -2030,10 +2041,11 @@ def SRG_176_49_12_14(): if (aut.order() == 2 and all(i in aut(i) for i in d.ground_set())): g = Graph() - g.add_edges(((u,v) for u in d.ground_set() for v in aut(u)), loops=False) + g.add_edges(((u, v) for u in d.ground_set() for v in aut(u)), loops=False) g.name('Higman symmetric 2-design') return g + def SRG_176_105_68_54(): r""" Return a `(176, 105, 68, 54)`-strongly regular graph. @@ -2058,6 +2070,7 @@ def SRG_176_105_68_54(): g.name('Witt 3-(22,7,4)') return g + def SRG_210_99_48_45(): r""" Return a strongly regular graph with parameters `(210, 99, 48, 45)` @@ -2091,12 +2104,12 @@ def SRG_210_99_48_45(): (7, 3, 1, 4, 5, 6), (7, 2, 4, 3, 5, 6), (7, 3, 2, 4, 5, 1), (7, 2, 4, 3, 5, 1)])) s = libgap.SymmetricGroup(7) - O = s.Orbit(kd[0],libgap.OnSetsTuples) - sa = s.Action(O,libgap.OnSetsTuples) + O = s.Orbit(kd[0], libgap.OnSetsTuples) + sa = s.Action(O, libgap.OnSetsTuples) G = Graph() for g in kd[1:]: - G.add_edges(libgap.Orbit(sa,[libgap.Position(O,kd[0]),\ - libgap.Position(O,g)],libgap.OnSets)) + G.add_edges(libgap.Orbit(sa, [libgap.Position(O, kd[0]), + libgap.Position(O, g)], libgap.OnSets)) G.name('merging of S_7 on Circulant(6,[1,4])s') return G @@ -2126,10 +2139,11 @@ def SRG_243_110_37_60(): from sage.coding.golay_code import GolayCode M = GolayCode(GF(3), False).generator_matrix() V = list(M.right_kernel()) - g = Graph([list(xrange(len(V))), lambda x,y:(V[x]-V[y]).hamming_weight() == 9 ]) + g = Graph([list(xrange(len(V))), lambda x, y: (V[x] - V[y]).hamming_weight() == 9]) g.name('Ternary Golay code') return g + def SRG_253_140_87_65(): r""" Return a `(253, 140, 87, 65)`-strongly regular graph. @@ -2153,6 +2167,7 @@ def SRG_253_140_87_65(): g.name('Witt 4-(23,7,1)') return g + def SRG_196_91_42_42(): r""" Return a `(196,91,42,42)`-strongly regular graph. From 93d51ce84cbdba50b385599e2264bce5285b3f1b Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 14:59:12 +0200 Subject: [PATCH 286/591] trac #34315: clean src/sage/graphs/graph.py - part 1 --- src/sage/graphs/graph.py | 96 +++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 50 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 96f4f8c6e75..1add28d7a81 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -6333,11 +6333,11 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose # Exactly one representative per vertex of H for h in H: - p.add_constraint(p.sum(v_repr[h,g] for g in G), min=1, max=1) + p.add_constraint(p.sum(v_repr[h, g] for g in G), min=1, max=1) # A vertex of G can only represent one vertex of H for g in G: - p.add_constraint(p.sum(v_repr[h,g] for h in H), max=1) + p.add_constraint(p.sum(v_repr[h, g] for h in H), max=1) ################### # Is representent # @@ -6349,7 +6349,7 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose for g in G: for h in H: - p.add_constraint(v_repr[h,g] - is_repr[g], max=0) + p.add_constraint(v_repr[h, g] - is_repr[g], max=0) ################################### # paths between the representents # @@ -6368,21 +6368,21 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose # These functions return the balance of flow corresponding to # commodity C at vertex v def flow_in(C, v): - return p.sum(flow[C,(v,u)] for u in G.neighbor_iterator(v)) + return p.sum(flow[C, (v, u)] for u in G.neighbor_iterator(v)) def flow_out(C, v): - return p.sum(flow[C,(u,v)] for u in G.neighbor_iterator(v)) + return p.sum(flow[C, (u, v)] for u in G.neighbor_iterator(v)) def flow_balance(C, v): - return flow_in(C,v) - flow_out(C,v) + return flow_in(C, v) - flow_out(C, v) - for h1,h2 in H.edge_iterator(labels=False): + for h1, h2 in H.edge_iterator(labels=False): for v in G: # The flow balance depends on whether the vertex v is a # representative of h1 or h2 in G, or a representative of none - p.add_constraint(flow_balance((h1,h2),v) == v_repr[h1,v] - v_repr[h2,v]) + p.add_constraint(flow_balance((h1, h2), v) == v_repr[h1, v] - v_repr[h2, v]) ############################# # Internal vertex of a path # @@ -6396,7 +6396,7 @@ def flow_balance(C, v): # When is a vertex internal for a commodity ? for C in H.edge_iterator(labels=False): for g in G: - p.add_constraint(flow_in(C,g) + flow_out(C,g) - is_internal[C,g], max=1) + p.add_constraint(flow_in(C, g) + flow_out(C, g) - is_internal[C, g], max=1) ############################ # Two paths do not cross ! # @@ -6406,8 +6406,8 @@ def flow_balance(C, v): # the vertex is a representent for g in G: - p.add_constraint(p.sum(is_internal[C,g] for C in H.edge_iterator(labels=False)) - + is_repr[g], max=1) + p.add_constraint(p.sum(is_internal[C, g] for C in H.edge_iterator(labels=False)) + + is_repr[g], max=1) # (The following inequalities are not necessary, but they seem to be of # help (the solvers find the answer quicker when they are added) @@ -6415,33 +6415,29 @@ def flow_balance(C, v): # The flow on one edge can go in only one direction. Besides, it can # belong to at most one commodity and has a maximum intensity of 1. - for g1,g2 in G.edge_iterator(labels=None): - - p.add_constraint( p.sum(flow[C,(g1,g2)] for C in H.edge_iterator(labels=False)) - + p.sum(flow[C,(g2,g1)] for C in H.edge_iterator(labels=False)), - max=1) - + for g1, g2 in G.edge_iterator(labels=None): + p.add_constraint(p.sum(flow[C, (g1, g2)] for C in H.edge_iterator(labels=False)) + + p.sum(flow[C, (g2, g1)] for C in H.edge_iterator(labels=False)), + max=1) # Now we can solve the problem itself ! try: p.solve(log=verbose) - except MIPSolverException: return False - minor = G.subgraph(immutable=False) is_repr = p.get_values(is_repr, convert=bool, tolerance=integrality_tolerance) v_repr = p.get_values(v_repr, convert=bool, tolerance=integrality_tolerance) flow = p.get_values(flow, convert=bool, tolerance=integrality_tolerance) - for u,v in minor.edge_iterator(labels=False): + for u, v in minor.edge_iterator(labels=False): used = False for C in H.edge_iterator(labels=False): - if flow[C,(u,v)] or flow[C,(v,u)]: + if flow[C, (u, v)] or flow[C, (v, u)]: used = True minor.set_edge_label(u, v, C) break @@ -6453,13 +6449,13 @@ def flow_balance(C, v): for g in minor: if is_repr[g]: for h in H: - if v_repr[h,v]: + if v_repr[h, v]: minor.set_vertex(g, h) break return minor - ### Cliques + # Cliques @doc_index("Clique-related methods") def cliques_maximal(self, algorithm="native"): @@ -6911,9 +6907,9 @@ def independent_set(self, algorithm="Cliquer", value_only=False, reduction_rules sphinx_plot(g.plot(partition=[g.independent_set()])) """ my_cover = self.vertex_cover(algorithm=algorithm, value_only=value_only, - reduction_rules=reduction_rules, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + reduction_rules=reduction_rules, + solver=solver, verbose=verbose, + integrality_tolerance=integrality_tolerance) if value_only: return self.order() - my_cover else: @@ -7081,7 +7077,7 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, # We first take a copy of the graph without multiple edges, if any. g = Graph(data=self.edges(sort=False), format='list_of_edges', - multiedges=self.allows_multiple_edges()) + multiedges=self.allows_multiple_edges()) g.allow_multiple_edges(False) degree_at_most_two = {u for u in g if g.degree(u) <= 2} @@ -7115,7 +7111,7 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, degree_at_most_two.discard(v) elif du == 2: - v,w = g.neighbors(u) + v, w = g.neighbors(u) if g.has_edge(v, w): # RULE 3: If the neighbors v and w of a degree 2 vertex @@ -7142,7 +7138,7 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, g.delete_vertex(v) g.delete_vertex(w) for z in neigh: - g.add_edge(u,z) + g.add_edge(u, z) folded_vertices.append((u, v, w)) @@ -7152,11 +7148,9 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, degree_at_most_two.discard(v) degree_at_most_two.discard(w) - # RULE 5: # TODO: add extra reduction rules - ################## # Main Algorithm # ################## @@ -7187,7 +7181,7 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, p.set_objective(p.sum(b[v] for v in g)) # an edge contains at least one vertex of the minimum vertex cover - for u,v in g.edge_iterator(labels=None): + for u, v in g.edge_iterator(labels=None): p.add_constraint(b[u] + b[v], min=1) p.solve(log=verbose) @@ -7211,7 +7205,7 @@ def vertex_cover(self, algorithm="Cliquer", value_only=False, cover_g.update(ppset) # RULE 4: folded_vertices.reverse() - for u,v,w in folded_vertices: + for u, v, w in folded_vertices: if u in cover_g: cover_g.discard(u) cover_g.add(v) @@ -7366,9 +7360,9 @@ def traverse(start, pointer): # Perform ear decomposition on each connected component of input graph. for v in self: if v not in seen: - # Start the depth first search from first vertex + # Start the depth first search from first vertex DFS(v) - value = {u:i for i,u in enumerate(dfs_order)} + value = {u: i for i, u in enumerate(dfs_order)} # Traverse all the non Tree edges, according to DFS order for u in dfs_order: @@ -7557,9 +7551,9 @@ def clique_polynomial(self, t=None): number_of = [0]*(self.order() + 1) for x in IndependentSets(self, complement=True): number_of[len(x)] += 1 - return sum(coeff*t**i for i,coeff in enumerate(number_of) if coeff) + return sum(coeff*t**i for i, coeff in enumerate(number_of) if coeff) - ### Miscellaneous + # Miscellaneous @doc_index("Leftovers") def cores(self, k=None, with_labels=False): @@ -7724,11 +7718,11 @@ def cores(self, k=None, with_labels=False): return verts, [] bin_boundaries = [0] curr_degree = 0 - for i,v in enumerate(verts): + for i, v in enumerate(verts): if degrees[v] > curr_degree: bin_boundaries.extend([i] * (degrees[v] - curr_degree)) curr_degree = degrees[v] - vert_pos = {v: pos for pos,v in enumerate(verts)} + vert_pos = {v: pos for pos, v in enumerate(verts)} # Lists of neighbors. nbrs = {v: set(self.neighbors(v)) for v in self} # form vertex core building up from smallest @@ -7752,7 +7746,7 @@ def cores(self, k=None, with_labels=False): bin_start = bin_boundaries[core[u]] vert_pos[u] = bin_start vert_pos[verts[bin_start]] = pos - verts[bin_start],verts[pos] = verts[pos],verts[bin_start] + verts[bin_start], verts[pos] = verts[pos], verts[bin_start] bin_boundaries[core[u]] += 1 core[u] -= 1 @@ -8287,15 +8281,16 @@ def _gomory_hu_tree(self, vertices, algorithm=None): # Take any two vertices (u,v) it = iter(vertices) - u,v = next(it),next(it) + u, v = next(it), next(it) # Compute a uv min-edge-cut. # # The graph is split into U,V with u \in U and v\in V. - flow,edges,[U,V] = self.edge_cut(u, v, use_edge_labels=True, vertices=True, algorithm=algorithm) + flow, edges, [U, V] = self.edge_cut(u, v, use_edge_labels=True, + vertices=True, algorithm=algorithm) # One graph for each part of the previous one - gU,gV = self.subgraph(U, immutable=False), self.subgraph(V, immutable=False) + gU, gV = self.subgraph(U, immutable=False), self.subgraph(V, immutable=False) # A fake vertex fU (resp. fV) to represent U (resp. V) fU = frozenset(U) @@ -8308,12 +8303,12 @@ def _gomory_hu_tree(self, vertices, algorithm=None): # If the same edge is added several times their capacities add up. from sage.rings.real_mpfr import RR - for uu,vv,capacity in edges: + for uu, vv, capacity in edges: capacity = capacity if capacity in RR else 1 # Assume uu is in gU if uu in V: - uu,vv = vv,uu + uu, vv = vv, uu # Create the new edges if necessary if not gU.has_edge(uu, fV): @@ -8513,7 +8508,7 @@ def two_factor_petersen(self, solver=None, verbose=0, *, integrality_tolerance=1 # and have to be translated back to (u,v) classes_b = [] for c in classes: - classes_b.append([(u,v) for ((uu,u),(vv,v)) in c]) + classes_b.append([(u, v) for ((uu, u), (vv, v)) in c]) return classes_b @@ -9078,7 +9073,7 @@ def effective_resistance(self, i, j, *, base_ring=None): if base_ring is None: base_ring = ZZ - if i == j : + if i == j: return base_ring(0) self._scream_if_not_simple() @@ -9086,7 +9081,7 @@ def effective_resistance(self, i, j, *, base_ring=None): connected_i = self.connected_component_containing_vertex(i) if j in connected_i: component = self.subgraph(connected_i) - return component.effective_resistance(i,j) + return component.effective_resistance(i, j) else: from sage.rings.infinity import Infinity return Infinity @@ -9935,7 +9930,7 @@ def bipartite_double(self, extended=False): G.add_edges(((v, 0), (v, 1)) for v in self) prefix = "Extended " if extended else "" - G.name("%sBipartite Double of %s"%(prefix, self.name())) + G.name("%sBipartite Double of %s" % (prefix, self.name())) return G # Aliases to functions defined in other modules @@ -9976,6 +9971,7 @@ def bipartite_double(self, extended=False): from sage.graphs.graph_coloring import fractional_chromatic_index from sage.graphs.hyperbolicity import hyperbolicity + _additional_categories = { "is_long_hole_free" : "Graph properties", "is_long_antihole_free" : "Graph properties", @@ -10024,4 +10020,4 @@ def bipartite_double(self, extended=False): "hyperbolicity" : "Distances", } -__doc__ = __doc__.replace("{INDEX_OF_METHODS}",gen_thematic_rest_table_index(Graph,_additional_categories)) +__doc__ = __doc__.replace("{INDEX_OF_METHODS}", gen_thematic_rest_table_index(Graph, _additional_categories)) From fed43ea1b6c26a5e37bd109c2ef5ddb486c7ef9a Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 15:54:07 +0200 Subject: [PATCH 287/591] trac #34316: clean src/sage/graphs/graph.py - part 2 --- src/sage/graphs/graph.py | 107 +++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 54 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 1add28d7a81..c563dd1377f 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4304,7 +4304,7 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve Bipartite graphs are not factor-critical:: - sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) + sage: G = graphs.RandomBipartite(randint(1, 10), randint(1, 10), .5) sage: G.is_factor_critical() False @@ -4351,7 +4351,7 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve # The graph must have an odd number of vertices, be 2-edge connected, so # without bridges, and not bipartite if (not self.order() % 2 or not self.is_connected() or - list(self.bridges()) or self.is_bipartite()): + list(self.bridges()) or self.is_bipartite()): return False if matching: @@ -4416,7 +4416,7 @@ def is_factor_critical(self, matching=None, algorithm='Edmonds', solver=None, ve even.add(a) odd.discard(a) Q.put(a) - else: # y has not been visited yet + else: # y has not been visited yet z = next(M.neighbor_iterator(y)) odd.add(y) even.add(z) @@ -4509,18 +4509,18 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, # Each vertex has an image for ug in self: - p.add_constraint(p.sum(b[ug,uh] for uh in H) == 1) + p.add_constraint(p.sum(b[ug, uh] for uh in H) == 1) nonedges = H.complement().edges(sort=False, labels=False) - for ug,vg in self.edges(sort=False, labels=False): + for ug, vg in self.edges(sort=False, labels=False): # Two adjacent vertices cannot be mapped to the same element for uh in H: - p.add_constraint(b[ug,uh] + b[vg,uh] <= 1) + p.add_constraint(b[ug, uh] + b[vg, uh] <= 1) # Two adjacent vertices cannot be mapped to no adjacent vertices - for uh,vh in nonedges: - p.add_constraint(b[ug,uh] + b[vg,vh] <= 1) - p.add_constraint(b[ug,vh] + b[vg,uh] <= 1) + for uh, vh in nonedges: + p.add_constraint(b[ug, uh] + b[vg, vh] <= 1) + p.add_constraint(b[ug, vh] + b[vg, uh] <= 1) # Minimize the mapping's size if core: @@ -4529,7 +4529,7 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, m = p.new_variable(nonnegative=True) for uh in H: for ug in self: - p.add_constraint(b[ug,uh] <= m[uh]) + p.add_constraint(b[ug, uh] <= m[uh]) p.set_objective(p.sum(m[vh] for vh in H)) @@ -4542,7 +4542,6 @@ def has_homomorphism_to(self, H, core=False, solver=None, verbose=0, mapping = dict(x[0] for x in b.items() if x[1]) return mapping - @doc_index("Clique-related methods") def fractional_clique_number(self, solver='PPL', verbose=0, check_components=True, check_bipartite=True): @@ -4672,7 +4671,7 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0): d = p.new_variable(nonnegative=True) one = p.new_variable(nonnegative=True) - for u,v in g.edge_iterator(labels=False): + for u, v in g.edge_iterator(labels=False): fuv = frozenset((u, v)) p.add_constraint(one[fuv] - 2 * d[u], max=0) p.add_constraint(one[fuv] - 2 * d[v], max=0) @@ -4692,9 +4691,9 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0): # setting the minimum to 1/(10 * size of the whole graph ) # should be safe :-) - m = 1/(10 *Integer(g.order())) + m = 1/(10 * Integer(g.order())) d_val = p.get_values(d) - g_mad = g.subgraph(v for v,l in d_val.items() if l > m) + g_mad = g.subgraph(v for v, l in d_val.items() if l > m) if value_only: return g_mad.average_degree() @@ -4787,21 +4786,21 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, # Associates to the vertices the classes to which they belong lists = {v: [] for v in self} - for i,f in enumerate(family): + for i, f in enumerate(family): for v in f: lists[v].append(i) # a classss has exactly one representative - p.add_constraint(p.sum(classss[v,i] for v in f), max=1, min=1) + p.add_constraint(p.sum(classss[v, i] for v in f), max=1, min=1) # A vertex represents at most one classss (vertex_taken is binary), and # vertex_taken[v]==1 if v is the representative of some classss for v in self: - p.add_constraint(p.sum(classss[v,i] for i in lists[v]) - vertex_taken[v], max=0) + p.add_constraint(p.sum(classss[v, i] for i in lists[v]) - vertex_taken[v], max=0) # Two adjacent vertices can not both be representatives of a set - for u,v in self.edge_iterator(labels=None): + for u, v in self.edge_iterator(labels=None): p.add_constraint(vertex_taken[u] + vertex_taken[v], max=1) p.set_objective(None) @@ -4814,9 +4813,9 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, classss = p.get_values(classss, convert=bool, tolerance=integrality_tolerance) repr = [] - for i,f in enumerate(family): + for i, f in enumerate(family): for v in f: - if classss[v,i]: + if classss[v, i]: repr.append(v) break @@ -4924,7 +4923,7 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): rs = p.new_variable(binary=True) for v in self: - p.add_constraint(p.sum(rs[h,v] for h in H), max=1) + p.add_constraint(p.sum(rs[h, v] for h in H), max=1) # We ensure that the set of representatives of a # vertex h contains a tree, and thus is connected @@ -4934,29 +4933,29 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): # there can be a edge for h between two vertices # only if those vertices represent h - for u,v in self.edge_iterator(labels=None): + for u, v in self.edge_iterator(labels=None): fuv = frozenset((u, v)) for h in H: - p.add_constraint(edges[h,fuv] - rs[h,u], max=0) - p.add_constraint(edges[h,fuv] - rs[h,v], max=0) + p.add_constraint(edges[h, fuv] - rs[h, u], max=0) + p.add_constraint(edges[h, fuv] - rs[h, v], max=0) # The number of edges of the tree in h is exactly the cardinal # of its representative set minus 1 for h in H: - p.add_constraint( p.sum(edges[h,frozenset(e)] for e in self.edge_iterator(labels=None)) - - p.sum(rs[h,v] for v in self), min=-1, max=-1) + p.add_constraint(p.sum(edges[h, frozenset(e)] for e in self.edge_iterator(labels=None)) + - p.sum(rs[h, v] for v in self), min=-1, max=-1) # a tree has no cycle epsilon = 1/(5*Integer(self.order())) r_edges = p.new_variable(nonnegative=True) for h in H: - for u,v in self.edge_iterator(labels=None): - p.add_constraint(r_edges[h,(u,v)] + r_edges[h,(v,u)] - edges[h,frozenset((u,v))], min=0) + for u, v in self.edge_iterator(labels=None): + p.add_constraint(r_edges[h, (u, v)] + r_edges[h, (v, u)] - edges[h, frozenset((u, v))], min=0) for v in self: - p.add_constraint(p.sum(r_edges[h,(u,v)] for u in self.neighbor_iterator(v)), max=1-epsilon) + p.add_constraint(p.sum(r_edges[h, (u, v)] for u in self.neighbor_iterator(v)), max=1-epsilon) # Once the representative sets are described, we must ensure # there are arcs corresponding to those of H between them @@ -4966,14 +4965,14 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): for v1, v2 in self.edge_iterator(labels=None): fv1v2 = frozenset((v1, v2)) - p.add_constraint(h_edges[(h1,h2),fv1v2] - rs[h2,v2], max=0) - p.add_constraint(h_edges[(h1,h2),fv1v2] - rs[h1,v1], max=0) + p.add_constraint(h_edges[(h1, h2), fv1v2] - rs[h2, v2], max=0) + p.add_constraint(h_edges[(h1, h2), fv1v2] - rs[h1, v1], max=0) - p.add_constraint(h_edges[(h2,h1),fv1v2] - rs[h1,v2], max=0) - p.add_constraint(h_edges[(h2,h1),fv1v2] - rs[h2,v1], max=0) + p.add_constraint(h_edges[(h2, h1), fv1v2] - rs[h1, v2], max=0) + p.add_constraint(h_edges[(h2, h1), fv1v2] - rs[h2, v1], max=0) - p.add_constraint(p.sum(h_edges[(h1,h2),frozenset(e)] + h_edges[(h2,h1),frozenset(e)] - for e in self.edge_iterator(labels=None)), min=1) + p.add_constraint(p.sum(h_edges[(h1, h2), frozenset(e)] + h_edges[(h2, h1), frozenset(e)] + for e in self.edge_iterator(labels=None)), min=1) p.set_objective(None) @@ -4986,11 +4985,11 @@ def minor(self, H, solver=None, verbose=0, *, integrality_tolerance=1e-3): rs_dict = {} for h in H: - rs_dict[h] = [v for v in self if rs[h,v]] + rs_dict[h] = [v for v in self if rs[h, v]] return rs_dict - ### Convexity + # Convexity @doc_index("Algorithmically hard stuff") def convexity_properties(self): @@ -5080,7 +5079,7 @@ def centrality_degree(self, v=None): else: return self.degree(v)/n_minus_one - ### Distances + # Distances @doc_index("Distances") def eccentricity(self, v=None, by_weight=False, algorithm=None, @@ -5278,7 +5277,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, if with_labels: return dict(zip(v, eccentricity(self, algorithm=algo, vertex_list=v))) else: - return eccentricity(self, algorithm=algo,vertex_list=v) + return eccentricity(self, algorithm=algo, vertex_list=v) if algorithm == 'DHV': if by_weight: @@ -5305,7 +5304,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, check_weight)[0] algorithm = 'From_Dictionary' - elif algorithm in ['Floyd-Warshall-Python', 'Floyd-Warshall-Cython', 'Johnson_Boost','DHV']: + elif algorithm in ['Floyd-Warshall-Python', 'Floyd-Warshall-Cython', 'Johnson_Boost', 'DHV']: raise ValueError("algorithm '" + algorithm + "' works only if all" + " eccentricities are needed") @@ -5866,7 +5865,7 @@ def distance_graph(self, dist): D.add_edges((u, u) for u in self) return D - ### Constructors + # Constructors @doc_index("Basic methods") def to_directed(self, data_structure=None, sparse=None): @@ -5938,18 +5937,18 @@ def to_directed(self, data_structure=None, sparse=None): else: data_structure = "static_sparse" from sage.graphs.digraph import DiGraph - D = DiGraph(name = self.name(), - pos = self.get_pos(), - multiedges = self.allows_multiple_edges(), - loops = self.allows_loops(), - data_structure = (data_structure if data_structure!="static_sparse" - else "sparse")) # we need a mutable copy + D = DiGraph(name=self.name(), + pos=self.get_pos(), + multiedges=self.allows_multiple_edges(), + loops=self.allows_loops(), + data_structure=(data_structure if data_structure != "static_sparse" + else "sparse")) # we need a mutable copy D.add_vertices(self.vertex_iterator()) D.set_vertices(self.get_vertices()) - for u,v,l in self.edge_iterator(): - D.add_edge(u,v,l) - D.add_edge(v,u,l) + for u, v, l in self.edge_iterator(): + D.add_edge(u, v, l) + D.add_edge(v, u, l) if hasattr(self, '_embedding'): D._embedding = copy(self._embedding) D._weighted = self._weighted @@ -6031,7 +6030,7 @@ def join(self, other, labels="pairs", immutable=None): else: G.add_edges(((0, u), (1, v)) for u in self for v in other) - G.name('%s join %s'%(self.name(), other.name())) + G.name('%s join %s' % (self.name(), other.name())) if immutable is None: immutable = self.is_immutable() and other.is_immutable() @@ -6190,11 +6189,11 @@ def twograph(self): T.append([x, y, z]) T = TwoGraph(T) - T.relabel({i: v for i,v in enumerate(self.vertices(sort=False))}) + T.relabel({i: v for i, v in enumerate(self)}) return T - ### Visualization + # Visualization @doc_index("Basic methods") def write_to_eps(self, filename, **options): @@ -6226,7 +6225,7 @@ def write_to_eps(self, filename, **options): if filename[-4:] != '.eps': filename += '.eps' f = open(filename, 'w') - f.write( print_graph_eps(self.vertices(sort=False), self.edge_iterator(), pos) ) + f.write(print_graph_eps(self, self.edge_iterator(), pos)) f.close() @doc_index("Algorithmically hard stuff") From 258eb979406e3d1fa6a249835d644525f4e8ecce Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 16:27:11 +0200 Subject: [PATCH 288/591] trac #34317: clean src/sage/graphs/graph.py - part 3 --- src/sage/graphs/graph.py | 153 ++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 74 deletions(-) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index c563dd1377f..af93c60a7a2 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1072,19 +1072,19 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if format is None and isinstance(data, DiGraph): data = data.to_undirected() format = 'Graph' - if (format is None and - isinstance(data, list) and - len(data) >= 2 and - callable(data[1])): + if (format is None and + isinstance(data, list) and + len(data) >= 2 and + callable(data[1])): format = 'rule' - if (format is None and - isinstance(data, list) and - len(data) == 2 and - isinstance(data[0], list) and # a list of two lists, the second of - ((isinstance(data[1], list) and # which contains iterables (the edges) - (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or - (isinstance(data[1], EdgesView)))): + if (format is None and + isinstance(data, list) and + len(data) == 2 and + isinstance(data[0], list) and # a list of two lists, the second of + ((isinstance(data[1], list) and # which contains iterables (the edges) + (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or + isinstance(data[1], EdgesView))): format = "vertices_and_edges" if format is None and isinstance(data, dict): @@ -1100,14 +1100,14 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # the input is a networkx (Multi)(Di)Graph format = 'NX' - if (format is None and - hasattr(data, 'vcount') and - hasattr(data, 'get_edgelist')): + if (format is None and + hasattr(data, 'vcount') and + hasattr(data, 'get_edgelist')): try: import igraph except ImportError: - raise ImportError("The data seems to be a igraph object, but "+ - "igraph is not installed in Sage. To install "+ + raise ImportError("The data seems to be a igraph object, but " + "igraph is not installed in Sage. To install " "it, run 'sage -i python_igraph'") if format is None and isinstance(data, igraph.Graph): format = 'igraph' @@ -1192,8 +1192,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif format == 'igraph': if data.is_directed(): - raise ValueError("An *undirected* igraph graph was expected. "+ - "To build an directed graph, call the DiGraph "+ + raise ValueError("An *undirected* igraph graph was expected. " + "To build an directed graph, call the DiGraph " "constructor.") self.add_vertices(range(data.vcount())) @@ -1201,21 +1201,21 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if vertex_labels and 'name' in data.vertex_attributes(): vs = data.vs() - self.relabel({v:vs[v]['name'] for v in self}) + self.relabel({v: vs[v]['name'] for v in self}) elif format == 'rule': f = data[1] verts = data[0] if loops is None: - loops = any(f(v,v) for v in verts) + loops = any(f(v, v) for v in verts) if weighted is None: weighted = False self.allow_loops(loops, check=False) self.allow_multiple_edges(True if multiedges else False, check=False) self.add_vertices(verts) - self.add_edges(e for e in itertools.combinations(verts,2) if f(*e)) + self.add_edges(e for e in itertools.combinations(verts, 2) if f(*e)) if loops: - self.add_edges((v,v) for v in verts if f(v,v)) + self.add_edges((v, v) for v in verts if f(v, v)) elif format == "vertices_and_edges": self.allow_multiple_edges(bool(multiedges), check=False) @@ -1226,7 +1226,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif format == 'dict_of_dicts': from .graph_input import from_dict_of_dicts from_dict_of_dicts(self, data, loops=loops, multiedges=multiedges, weighted=weighted, - convert_empty_dict_labels_to_None = False if convert_empty_dict_labels_to_None is None else convert_empty_dict_labels_to_None) + convert_empty_dict_labels_to_None=(False if convert_empty_dict_labels_to_None is None + else convert_empty_dict_labels_to_None)) elif format == 'dict_of_lists': from .graph_input import from_dict_of_lists @@ -1260,12 +1261,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if data_structure == "static_sparse": from sage.graphs.base.static_sparse_backend import StaticSparseBackend ib = StaticSparseBackend(self, - loops = self.allows_loops(), - multiedges = self.allows_multiple_edges()) + loops=self.allows_loops(), + multiedges=self.allows_multiple_edges()) self._backend = ib self._immutable = True - ### Formats + # Formats @doc_index("Basic methods") def graph6_string(self): @@ -1395,9 +1396,9 @@ def sparse6_string(self): V = sorted(self) except TypeError: V = self - v_to_int = {v:i for i,v in enumerate(V)} - edges = [sorted((v_to_int[u], v_to_int[v])) for u,v in self.edge_iterator(labels=False)] - edges.sort(key=lambda e: (e[1], e[0])) # reverse lexicographic order + v_to_int = {v: i for i, v in enumerate(V)} + edges = [sorted((v_to_int[u], v_to_int[v])) for u, v in self.edge_iterator(labels=False)] + edges.sort(key=lambda e: (e[1], e[0])) # reverse lexicographic order # encode bit vector k = int((ZZ(n) - 1).nbits()) @@ -1425,15 +1426,15 @@ def sparse6_string(self): # encode s as a 6-string, as in R(x), but padding with 1's # pad on the right to make a multiple of 6 - s = s + ( '1' * ((6 - len(s))%6) ) + s = s + ('1' * ((6 - len(s)) % 6)) # split into groups of 6, and convert numbers to decimal, adding 63 six_bits = '' for i in range(0, len(s), 6): - six_bits += chr( int( s[i:i+6], 2) + 63 ) + six_bits += chr(int(s[i:i+6], 2) + 63) return ':' + generic_graph_pyx.small_integer_to_graph6(n) + six_bits - ### Attributes + # Attributes @doc_index("Basic methods") def is_directed(self): @@ -1447,7 +1448,8 @@ def is_directed(self): """ return False - ### Properties + # Properties + @doc_index("Graph properties") def is_tree(self, certificate=False, output='vertex'): r""" @@ -1787,7 +1789,7 @@ def is_block_graph(self): if self.is_clique(): return True - B,C = self.blocks_and_cut_vertices() + B, C = self.blocks_and_cut_vertices() return all(self.is_clique(vertices=block) for block in B) @doc_index("Graph properties") @@ -1898,7 +1900,7 @@ def is_apex(self): True """ # Easy cases: null graph, subgraphs of K_5 and K_3,3 - if self.order() <= 5 or ( self.order() <= 6 and self.is_bipartite() ): + if self.order() <= 5 or (self.order() <= 6 and self.is_bipartite()): return True return len(self.apex_vertices(k=1)) > 0 @@ -2024,7 +2026,6 @@ def apex_vertices(self, k=None): it = self.vertex_iterator() return [next(it) for _ in range(k)] - if not self.is_connected(): # We search for its non planar connected components. If it has more # than one such component, the graph is not apex. It is apex if @@ -2032,7 +2033,7 @@ def apex_vertices(self, k=None): # planar, or if its unique non planar component is apex. P = [H for H in self.connected_components_subgraphs() if not H.is_planar()] - if not P: # The graph is planar + if not P: # The graph is planar it = self.vertex_iterator() return [next(it) for _ in range(k)] elif len(P) > 1: @@ -2053,7 +2054,6 @@ def apex_vertices(self, k=None): # We make a basic copy of the graph since we will modify it H = Graph(self.edges(labels=0, sort=False), immutable=False, loops=False, multiedges=False) - # General case: basic implementation # # Test for each vertex if its removal makes the graph planar. @@ -2071,7 +2071,7 @@ def apex_vertices(self, k=None): apex = set() for deg in sorted(V): for u in V[deg]: - if u in apex: # True if neighbor of an apex of degree 2 + if u in apex: # True if neighbor of an apex of degree 2 if deg == 2: # We ensure that its neighbors are known apex apex.update(H.neighbor_iterator(u)) @@ -2484,7 +2484,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False): return (self.adjacency_matrix()**3).trace() == 0 else: - raise ValueError("Algorithm '%s' not yet implemented. Please contribute." %(algorithm)) + raise ValueError("Algorithm '%s' not yet implemented. Please contribute." % (algorithm)) @doc_index("Graph properties") def is_split(self): @@ -2753,7 +2753,7 @@ def is_arc_transitive(self): e = next(self.edge_iterator(labels=False)) e = [A._domain_to_gap[e[0]], A._domain_to_gap[e[1]]] - return libgap(A).OrbitLength(e,libgap.OnTuples) == 2*self.size() + return libgap(A).OrbitLength(e, libgap.OnTuples) == 2*self.size() @doc_index("Graph properties") def is_half_transitive(self): @@ -2957,24 +2957,29 @@ def degree_constrained_subgraph(self, bounds, solver=None, verbose=0, p = MixedIntegerLinearProgram(maximization=False, solver=solver) b = p.new_variable(binary=True) - if isinstance(bounds,dict): - f_bounds = lambda x: bounds[x] + if isinstance(bounds, dict): + def f_bounds(x): + return bounds[x] else: f_bounds = bounds - if self.weighted(): from sage.rings.real_mpfr import RR - weight = lambda x: x if x in RR else 1 + + def weight(x): + return x if x in RR else 1 else: - weight = lambda x: 1 + def weight(x): + return 1 for v in self: - minimum,maximum = f_bounds(v) - p.add_constraint(p.sum(b[frozenset((x,y))]*weight(l) for x,y,l in self.edges_incident(v)), - min=minimum, max=maximum) + minimum, maximum = f_bounds(v) + p.add_constraint(p.sum(b[frozenset((x, y))]*weight(l) + for x, y, l in self.edges_incident(v)), + min=minimum, max=maximum) - p.set_objective(p.sum(b[frozenset((x,y))]*weight(l) for x,y,l in self.edge_iterator())) + p.set_objective(p.sum(b[frozenset((x, y))]*weight(l) + for x, y, l in self.edge_iterator())) try: p.solve(log=verbose) @@ -2986,7 +2991,7 @@ def degree_constrained_subgraph(self, bounds, solver=None, verbose=0, g.delete_edges(e for e in g.edge_iterator(labels=False) if not b[frozenset(e)]) return g - ### Orientations + # Orientations @doc_index("Connectivity, orientations, trees") def strong_orientation(self): @@ -3081,7 +3086,7 @@ def strong_orientation(self): if seen.get(e[1], False) is False: d.add_edge(e) next_.extend(ee for ee in self.edges_incident(e[1]) - if ((e[0],e[1]) != (ee[0],ee[1])) and ((e[0],e[1]) != (ee[1],ee[0]))) + if ((e[0], e[1]) != (ee[0], ee[1])) and ((e[0], e[1]) != (ee[1], ee[0]))) i += 1 seen[e[1]] = i @@ -3154,8 +3159,8 @@ def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verb """ self._scream_if_not_simple() if self.is_directed(): - raise ValueError("Cannot compute an orientation of a DiGraph. "+\ - "Please convert it to a Graph if you really mean it.") + raise ValueError("Cannot compute an orientation of a DiGraph. " + "Please convert it to a Graph if you really mean it.") if use_edge_labels: from sage.rings.real_mpfr import RR @@ -3188,8 +3193,8 @@ def outgoing(u, e, variable): for u in self: p.add_constraint(p.sum(weight(e) * outgoing(u, e, orientation[frozenset(e)]) - for e in self.edge_iterator(vertices=[u], labels=False)) - - degree['max'], max=0) + for e in self.edge_iterator(vertices=[u], labels=False)) + - degree['max'], max=0) p.set_objective(degree['max']) @@ -3329,7 +3334,7 @@ def bounded_outdegree_orientation(self, bound, solver=None, verbose=False, return DiGraph() vertices = list(self) - vertices_id = {y: x for x,y in enumerate(vertices)} + vertices_id = {y: x for x, y in enumerate(vertices)} b = {} @@ -3338,7 +3343,7 @@ def bounded_outdegree_orientation(self, bound, solver=None, verbose=False, b = bound else: try: - b = dict(zip(vertices,map(bound, vertices))) + b = dict(zip(vertices, map(bound, vertices))) except TypeError: b = dict(zip(vertices, [bound]*n)) @@ -3349,17 +3354,17 @@ def bounded_outdegree_orientation(self, bound, solver=None, verbose=False, d.add_edges(('s', vertices_id[v], b[v]) for v in vertices) d.add_edges(((vertices_id[u], vertices_id[v]), 't', 1) - for u,v in self.edges(sort=False, labels=None) ) + for u, v in self.edges(sort=False, labels=None)) # each v is linked to its incident edges - for u,v in self.edge_iterator(labels=None): - u,v = vertices_id[u], vertices_id[v] - d.add_edge(u, (u,v), 1) - d.add_edge(v, (u,v), 1) + for u, v in self.edge_iterator(labels=None): + u, v = vertices_id[u], vertices_id[v] + d.add_edge(u, (u, v), 1) + d.add_edge(v, (u, v), 1) # Solving the maximum flow - value, flow = d.flow('s','t', value_only=False, integer=True, + value, flow = d.flow('s', 't', value_only=False, integer=True, use_edge_labels=True, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) @@ -3374,7 +3379,7 @@ def bounded_outdegree_orientation(self, bound, solver=None, verbose=False, for u in [x for x in range(n) if x in flow]: - for uu,vv in flow.neighbors_out(u): + for uu, vv in flow.neighbors_out(u): v = vv if vv != u else uu D.add_edge(vertices[u], vertices[v]) @@ -3494,8 +3499,8 @@ def orientations(self, data_structure=None, sparse=None): yield D return - E = [[(u,v,label), (v,u,label)] if u != v else [(u,v,label)] - for u,v,label in self.edge_iterator()] + E = [[(u, v, label), (v, u, label)] if u != v else [(u, v, label)] + for u, v, label in self.edge_iterator()] verts = self.vertices(sort=False) for edges in itertools.product(*E): D = DiGraph(data=[verts, edges], @@ -3509,7 +3514,7 @@ def orientations(self, data_structure=None, sparse=None): D._embedding = copy(self._embedding) yield D - ### Coloring + # Coloring @doc_index("Basic methods") def bipartite_color(self): @@ -3561,7 +3566,7 @@ def bipartite_sets(self): left = set() right = set() - for u,s in color.items(): + for u, s in color.items(): if s: left.add(u) else: @@ -4170,11 +4175,11 @@ def weight(x): W = {} L = {} - for u,v,l in self.edge_iterator(): + for u, v, l in self.edge_iterator(): if u is v: continue fuv = frozenset((u, v)) - if fuv not in L or ( use_edge_labels and W[fuv] < weight(l) ): + if fuv not in L or (use_edge_labels and W[fuv] < weight(l)): L[fuv] = l if use_edge_labels: W[fuv] = weight(l) @@ -4183,7 +4188,7 @@ def weight(x): import networkx g = networkx.Graph() if use_edge_labels: - for (u, v),w in W.items(): + for (u, v), w in W.items(): g.add_edge(u, v, weight=w) else: for u, v in L: @@ -4205,14 +4210,14 @@ def weight(x): p = MixedIntegerLinearProgram(maximization=True, solver=solver) b = p.new_variable(binary=True) if use_edge_labels: - p.set_objective(p.sum(w * b[fe] for fe,w in W.items())) + p.set_objective(p.sum(w * b[fe] for fe, w in W.items())) else: p.set_objective(p.sum(b[fe] for fe in L)) # for any vertex v, there is at most one edge incident to v in # the maximum matching for v in g: p.add_constraint(p.sum(b[frozenset(e)] for e in self.edge_iterator(vertices=[v], labels=False) - if e[0] != e[1]), max=1) + if e[0] != e[1]), max=1) p.solve(log=verbose) b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) From 444a55a47bd764f564535371816c03d3fab17811 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 17:01:26 +0200 Subject: [PATCH 289/591] trac #34318: clean src/sage/graphs/generic_graph.py - part 1 --- src/sage/graphs/generic_graph.py | 135 ++++++++++++++++++------------- 1 file changed, 78 insertions(+), 57 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b8a2a920dab..4f4f57c5484 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -22965,17 +22965,18 @@ def is_hamiltonian(self, solver=None, constraint_generation=None, except EmptySetError: return False + def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False): r""" Tests for isomorphism between self and other. INPUT: - - ``certificate`` -- if True, then output is `(a, b)`, where `a` - is a boolean and `b` is either a map or ``None``. + - ``certificate`` -- if True, then output is `(a, b)`, where `a` + is a boolean and `b` is either a map or ``None`` - - ``edge_labels`` -- boolean (default: ``False``); if ``True`` allows - only permutations respecting edge labels. + - ``edge_labels`` -- boolean (default: ``False``); if ``True`` allows + only permutations respecting edge labels OUTPUT: @@ -23200,10 +23201,12 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False if not self.order() and not other.order(): return (True, None) if certificate else True - if (self.is_directed() != other.is_directed() or self.order() != other.order() or - self.size() != other.size() or self.degree_sequence() != other.degree_sequence()): + if (self.is_directed() != other.is_directed() or + self.order() != other.order() or + self.size() != other.size() or + self.degree_sequence() != other.degree_sequence()): if certificate: - return False,None + return False, None else: return False @@ -23215,36 +23218,53 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False if edge_labels and sorted(self.edge_labels(), key=str) != sorted(other.edge_labels(), key=str): return (False, None) if certificate else False else: - G, partition, relabeling, G_edge_labels = graph_isom_equivalent_non_edge_labeled_graph(self, return_relabeling=True, ignore_edge_labels=(not edge_labels), return_edge_labels=True) - self_vertices = sum(partition,[]) - G2, partition2, relabeling2, G2_edge_labels = graph_isom_equivalent_non_edge_labeled_graph(other, return_relabeling=True, ignore_edge_labels=(not edge_labels), return_edge_labels=True) + ret = graph_isom_equivalent_non_edge_labeled_graph(self, return_relabeling=True, + ignore_edge_labels=(not edge_labels), + return_edge_labels=True) + G, partition, relabeling, G_edge_labels = ret + self_vertices = sum(partition, []) + ret = graph_isom_equivalent_non_edge_labeled_graph(other, return_relabeling=True, + ignore_edge_labels=(not edge_labels), + return_edge_labels=True) + G2, partition2, relabeling2, G2_edge_labels = ret + if [len(_) for _ in partition] != [len(_) for _ in partition2]: return (False, None) if certificate else False - multilabel = (lambda e:e) if edge_labels else (lambda e:[[None, el[1]] for el in e]) + + if edge_labels: + def multilabel(e): + return e + else: + def multilabel(e): + return [[None, el[1]] for el in e] + if [multilabel(_) for _ in G_edge_labels] != [multilabel(_) for _ in G2_edge_labels]: return (False, None) if certificate else False - partition2 = sum(partition2,[]) + partition2 = sum(partition2, []) other_vertices = partition2 else: G = self partition = [self_vertices] G2 = other partition2 = other_vertices - G_to = {u: i for i,u in enumerate(self_vertices)} - from sage.graphs.graph import Graph - from sage.graphs.digraph import DiGraph - DoDG = DiGraph if self._directed else Graph + G_to = {u: i for i, u in enumerate(self_vertices)} + if self._directed: + from sage.graphs.digraph import DiGraph + DoDG = DiGraph + else: + from sage.graphs.graph import Graph + DoDG = Graph H = DoDG(len(self_vertices), loops=G.allows_loops()) HB = H._backend - for u,v in G.edge_iterator(labels=False): + for u, v in G.edge_iterator(labels=False): HB.add_edge(G_to[u], G_to[v], None, G._directed) G = HB.c_graph()[0] partition = [[G_to[vv] for vv in cell] for cell in partition] GC = G - G2_to = {u: i for i,u in enumerate(other_vertices)} + G2_to = {u: i for i, u in enumerate(other_vertices)} H2 = DoDG(len(other_vertices), loops=G2.allows_loops()) H2B = H2._backend - for u,v in G2.edge_iterator(labels=False): + for u, v in G2.edge_iterator(labels=False): H2B.add_edge(G2_to[u], G2_to[v], None, G2._directed) G2 = H2B.c_graph()[0] partition2 = [G2_to[vv] for vv in partition2] @@ -23448,7 +23468,6 @@ class by some canonization function `c`. If `G` and `H` are graphs, ....: assert gcan0 == gcan1, (edges, labels, part, pp) ....: assert gcan0 == gcan2, (edges, labels, part, pp) """ - # Check parameter combinations if algorithm not in [None, 'sage', 'bliss']: raise ValueError("'algorithm' must be equal to 'bliss', 'sage', or None") @@ -23492,21 +23511,21 @@ class by some canonization function `c`. If `G` and `H` are graphs, if edge_labels or self.has_multiple_edges(): G, partition, relabeling = graph_isom_equivalent_non_edge_labeled_graph(self, partition, return_relabeling=True) G_vertices = list(chain(*partition)) - G_to = {u: i for i,u in enumerate(G_vertices)} + G_to = {u: i for i, u in enumerate(G_vertices)} DoDG = DiGraph if self._directed else Graph H = DoDG(len(G_vertices), loops=G.allows_loops()) HB = H._backend - for u,v in G.edge_iterator(labels=False): + for u, v in G.edge_iterator(labels=False): HB.add_edge(G_to[u], G_to[v], None, G._directed) GC = HB.c_graph()[0] partition = [[G_to[vv] for vv in cell] for cell in partition] - a,b,c = search_tree(GC, partition, certificate=True, dig=dig) + a, b, c = search_tree(GC, partition, certificate=True, dig=dig) # c is a permutation to the canonical label of G, which depends only on isomorphism class of self. H = copy(self) c_new = {v: c[G_to[relabeling[v]]] for v in self} else: G_vertices = list(chain(*partition)) - G_to = {u: i for i,u in enumerate(G_vertices)} + G_to = {u: i for i, u in enumerate(G_vertices)} DoDG = DiGraph if self._directed else Graph H = DoDG(len(G_vertices), loops=self.allows_loops()) HB = H._backend @@ -23514,7 +23533,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, HB.add_edge(G_to[u], G_to[v], None, self._directed) GC = HB.c_graph()[0] partition = [[G_to[vv] for vv in cell] for cell in partition] - a,b,c = search_tree(GC, partition, certificate=True, dig=dig) + a, b, c = search_tree(GC, partition, certificate=True, dig=dig) H = copy(self) c_new = {v: c[G_to[v]] for v in G_to} H.relabel(c_new) @@ -23523,8 +23542,8 @@ class by some canonization function `c`. If `G` and `H` are graphs, else: return H - def is_cayley(self, return_group = False, mapping = False, - generators = False, allow_disconnected = False): + def is_cayley(self, return_group=False, mapping=False, + generators=False, allow_disconnected=False): r""" Check whether the graph is a Cayley graph. @@ -23629,11 +23648,11 @@ def is_cayley(self, return_group = False, mapping = False, ....: generators = True) (False, False, False) """ - if self.order() == 0: + if not self: n = return_group + mapping + generators - if n == 0: + if not n: return False - return tuple([False] * (n+1)) + return tuple([False] * (n + 1)) compute_map = mapping or generators certificate = return_group or compute_map @@ -23642,7 +23661,7 @@ def is_cayley(self, return_group = False, mapping = False, if allow_disconnected and self.is_vertex_transitive(): C = self.connected_components_subgraphs() if certificate: - c, CG = C[0].is_cayley(return_group = True) + c, CG = C[0].is_cayley(return_group=True) if c: from sage.groups.perm_gps.permgroup import PermutationGroup I = [C[0].is_isomorphic(g, certificate=True)[1] for g in C] @@ -23652,24 +23671,24 @@ def is_cayley(self, return_group = False, mapping = False, for h in CG.gens()] + \ [[tuple([M[v] for M in I]) for v in C[0].vertices(sort=False)]] - G = PermutationGroup(gens, domain = self.vertices(sort=False)) + G = PermutationGroup(gens, domain=self.vertices(sort=False)) else: - c = C[0].is_cayley(return_group = False) - elif not self.allows_loops() and not self.allows_multiple_edges() and \ - self.density() > Rational(1)/Rational(2): + c = C[0].is_cayley(return_group=False) + elif (not self.allows_loops() and not self.allows_multiple_edges() and + self.density() > Rational(1)/Rational(2)): if certificate: - c, G = self.complement().is_cayley(return_group = True, - allow_disconnected = True) + c, G = self.complement().is_cayley(return_group=True, + allow_disconnected=True) else: - c = self.complement().is_cayley(return_group = False, - allow_disconnected = True) + c = self.complement().is_cayley(return_group=False, + allow_disconnected=True) else: A = self.automorphism_group() if certificate: - G = A.has_regular_subgroup(return_group = True) + G = A.has_regular_subgroup(return_group=True) c = G is not None else: - c = A.has_regular_subgroup(return_group = False) + c = A.has_regular_subgroup(return_group=False) if c and compute_map: v = next(self.vertex_iterator()) map = {(f**-1)(v): f for f in G} @@ -23912,7 +23931,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): raise ValueError('the parameter alpha must be strictly positive') n = self.order() - if n == 0 : + if not n: raise ValueError('graph is empty') if vertices is None: vertices = self.vertices(sort=True) @@ -23930,7 +23949,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): raise ValueError('the parameter alpha must be less than the reciprocal of the spectral radius of the graph') In = matrix.identity(n) - K = (In - alpha * A.transpose()).inverse() - In + K = (In - alpha * A.transpose()).inverse() - In if nonedgesonly: onesmat = matrix(QQ, n, n, lambda i, j: 1) Missing = onesmat - A - In @@ -23938,7 +23957,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): else: return K - def katz_centrality(self, alpha , u=None): + def katz_centrality(self, alpha, u=None): r""" Return the Katz centrality of vertex `u`. @@ -24118,7 +24137,7 @@ def edge_polytope(self, backend=None): dim = self.num_verts() e = identity_matrix(dim).rows() dic = {v: e[i] for i, v in enumerate(self)} - vertices = ((dic[i] + dic[j]) for i,j in self.edge_iterator(sort_vertices=False, labels=False)) + vertices = ((dic[i] + dic[j]) for i, j in self.edge_iterator(sort_vertices=False, labels=False)) parent = Polyhedra(ZZ, dim, backend=backend) return parent([vertices, [], []], None) @@ -24249,13 +24268,13 @@ def symmetric_edge_polytope(self, backend=None): dim = self.num_verts() e = identity_matrix(dim).rows() dic = {v: e[i] for i, v in enumerate(self)} - vertices = chain(((dic[i] - dic[j]) for i,j in self.edge_iterator(sort_vertices=False, labels=False)), - ((dic[j] - dic[i]) for i,j in self.edge_iterator(sort_vertices=False, labels=False))) + vertices = chain(((dic[i] - dic[j]) for i, j in self.edge_iterator(sort_vertices=False, labels=False)), + ((dic[j] - dic[i]) for i, j in self.edge_iterator(sort_vertices=False, labels=False))) parent = Polyhedra(ZZ, dim, backend=backend) return parent([vertices, [], []], None) -def tachyon_vertex_plot(g, bgcolor=(1,1,1), +def tachyon_vertex_plot(g, bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, pos3d=None, @@ -24286,12 +24305,12 @@ def tachyon_vertex_plot(g, bgcolor=(1,1,1), from math import sqrt from sage.plot.plot3d.tachyon import Tachyon - c = [0,0,0] + c = [0, 0, 0] r = [] verts = list(g) if vertex_colors is None: - vertex_colors = {(1,0,0): verts} + vertex_colors = {(1, 0, 0): verts} try: for v in verts: c[0] += pos3d[v][0] @@ -24324,14 +24343,17 @@ def tachyon_vertex_plot(g, bgcolor=(1,1,1), i = 0 for color in vertex_colors: i += 1 - TT.texture('node_color_%d'%i, ambient=0.1, diffuse=0.9, + TT.texture('node_color_%d' % i, ambient=0.1, diffuse=0.9, specular=0.03, opacity=1.0, color=color) for v in vertex_colors[color]: - TT.sphere((pos3d[v][0], pos3d[v][1], pos3d[v][2]), vertex_size, 'node_color_%d'%i) + TT.sphere((pos3d[v][0], pos3d[v][1], pos3d[v][2]), vertex_size, 'node_color_%d' % i) return TT, pos3d -def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_label=None, return_relabeling=False, return_edge_labels=False, inplace=False, ignore_edge_labels=False): + +def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_label=None, + return_relabeling=False, return_edge_labels=False, + inplace=False, ignore_edge_labels=False): r""" Helper function for canonical labeling of edge labeled (di)graphs. @@ -24549,13 +24571,12 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab # We build the list of distinct edge labels edge_labels = [] - for _,_,label in G.edge_iterator(): + for _, _, label in G.edge_iterator(): if label != standard_label and label not in edge_labels: edge_labels.append(label) edge_labels = sorted(edge_labels, key=str) - # We now add to G, for each edge (u, v, l), a new vertex i in [n..n + m] and # arcs (u, i, None) and (i, v, None). We record for each distinct label l # the list of added vertices. @@ -24571,7 +24592,7 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab edges = list(G._backend.iterator_edges(G, True)) i = G_order - for u,v,l in edges: + for u, v, l in edges: if l != standard_label: for el, part in edge_partition: if el == l: @@ -24621,7 +24642,7 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab else: # Flatten edge_partition to [list of edges, list of edges, ...] - edge_partition = [part for _,part in edge_partition] + edge_partition = [part for _, part in edge_partition] new_partition = [part for part in chain(partition, edge_partition) if part] From b62e29e0664e821f00bca31054f0e95142ceade0 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 9 Aug 2022 17:44:47 +0200 Subject: [PATCH 290/591] trac #34319: clean src/sage/graphs/generic_graph.py - part 2 --- src/sage/graphs/generic_graph.py | 116 +++++++++++++++++++------------ 1 file changed, 70 insertions(+), 46 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 4f4f57c5484..0727b945e93 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -21809,23 +21809,47 @@ def eigenvectors(self, laplacian=False): sage: C = graphs.CycleGraph(8) sage: C.eigenvectors() - [(2, [ - (1, 1, 1, 1, 1, 1, 1, 1) - ], 1), (-2, [ - (1, -1, 1, -1, 1, -1, 1, -1) - ], 1), (0, [ - (1, 0, -1, 0, 1, 0, -1, 0), - (0, 1, 0, -1, 0, 1, 0, -1) - ], 2), (-1.4142135623..., [(1, 0, -1, 1.4142135623..., -1, 0, 1, -1.4142135623...), (0, 1, -1.4142135623..., 1, 0, -1, 1.4142135623..., -1)], 2), (1.4142135623..., [(1, 0, -1, -1.4142135623..., -1, 0, 1, 1.4142135623...), (0, 1, 1.4142135623..., 1, 0, -1, -1.4142135623..., -1)], 2)] + [(2, + [ + (1, 1, 1, 1, 1, 1, 1, 1) + ], + 1), + (-2, + [ + (1, -1, 1, -1, 1, -1, 1, -1) + ], + 1), + (0, + [ + (1, 0, -1, 0, 1, 0, -1, 0), + (0, 1, 0, -1, 0, 1, 0, -1) + ], + 2), + (-1.4142135623..., + [(1, 0, -1, 1.4142135623..., -1, 0, 1, -1.4142135623...), + (0, 1, -1.4142135623..., 1, 0, -1, 1.4142135623..., -1)], + 2), + (1.4142135623..., + [(1, 0, -1, -1.4142135623..., -1, 0, 1, 1.4142135623...), + (0, 1, 1.4142135623..., 1, 0, -1, -1.4142135623..., -1)], + 2)] A digraph may have complex eigenvalues. Previously, the complex parts of graph eigenvalues were being dropped. For a 3-cycle, we have:: sage: T = DiGraph({0:[1], 1:[2], 2:[0]}) sage: T.eigenvectors() - [(1, [ - (1, 1, 1) - ], 1), (-0.5000000000... - 0.8660254037...*I, [(1, -0.5000000000... - 0.8660254037...*I, -0.5000000000... + 0.8660254037...*I)], 1), (-0.5000000000... + 0.8660254037...*I, [(1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...*I)], 1)] + [(1, + [ + (1, 1, 1) + ], + 1), + (-0.5000000000... - 0.8660254037...*I, + [(1, -0.5000000000... - 0.8660254037...*I, -0.5000000000... + 0.8660254037...*I)], + 1), + (-0.5000000000... + 0.8660254037...*I, + [(1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...*I)], + 1)] """ if laplacian: M = self.kirchhoff_matrix(vertices=list(self)) @@ -21944,7 +21968,7 @@ def eigenspaces(self, laplacian=False): # which would be a change in default behavior return M.right_eigenspaces(format='galois', algebraic_multiplicity=False) - ### Automorphism and isomorphism + # Automorphism and isomorphism def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, complete_partial_function=True, immutable=None): r""" @@ -22170,14 +22194,14 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, c if not inplace: G = copy(self) perm2 = G.relabel(perm, - return_map= return_map, - check_input = check_input, - complete_partial_function = complete_partial_function) + return_map=return_map, + check_input=check_input, + complete_partial_function=complete_partial_function) if immutable is None: immutable = self.is_immutable() if immutable: - G = self.__class__(G, immutable = True) + G = self.__class__(G, immutable=True) if return_map: return G, perm2 @@ -22290,8 +22314,8 @@ def degree_to_cell(self, vertex, cell): (0, 2) """ if self._directed: - in_neighbors_in_cell = set([a for a,_,_ in self.incoming_edges(vertex)]) & set(cell) - out_neighbors_in_cell = set([a for _,a,_ in self.outgoing_edges(vertex)]) & set(cell) + in_neighbors_in_cell = set([a for a, _, _ in self.incoming_edges(vertex)]) & set(cell) + out_neighbors_in_cell = set([a for _, a, _ in self.outgoing_edges(vertex)]) & set(cell) return (len(in_neighbors_in_cell), len(out_neighbors_in_cell)) else: neighbors_in_cell = set(self.neighbors(vertex)) & set(cell) @@ -22351,9 +22375,9 @@ def is_equitable(self, partition, quotient_matrix=False): """ from sage.misc.flatten import flatten if sorted(flatten(partition, max_level=1)) != self.vertices(sort=True): - raise TypeError("Partition (%s) is not valid for this graph: vertices are incorrect."%partition) - if any(len(cell)==0 for cell in partition): - raise TypeError("Partition (%s) is not valid for this graph: there is a cell of length 0."%partition) + raise TypeError("Partition (%s) is not valid for this graph: vertices are incorrect." % partition) + if any(not cell for cell in partition): + raise TypeError("Partition (%s) is not valid for this graph: there is a cell of length 0." % partition) if quotient_matrix: from sage.matrix.constructor import Matrix from sage.rings.integer_ring import IntegerRing @@ -22439,9 +22463,9 @@ def coarsest_equitable_refinement(self, partition, sparse=True): """ from sage.misc.flatten import flatten if set(flatten(partition, max_level=1)) != set(self): - raise TypeError("partition (%s) is not valid for this graph: vertices are incorrect"%partition) + raise TypeError("partition (%s) is not valid for this graph: vertices are incorrect" % partition) if any(len(cell) == 0 for cell in partition): - raise TypeError("partition (%s) is not valid for this graph: there is a cell of length 0"%partition) + raise TypeError("partition (%s) is not valid for this graph: there is a cell of length 0" % partition) if self.has_multiple_edges(): raise TypeError("refinement function does not support multiple edges") G = copy(self) @@ -22697,8 +22721,8 @@ def automorphism_group(self, partition=None, verbosity=0, raise NotImplementedError("algorithm 'bliss' cannot be used for graph with multiedges") have_bliss = False - if (algorithm == 'bliss' or # explicit choice from the user; or - (algorithm is None and # by default + if (algorithm == 'bliss' or # explicit choice from the user; or + (algorithm is None and # by default have_bliss)): Bliss().require() @@ -22723,8 +22747,7 @@ def automorphism_group(self, partition=None, verbosity=0, return ret[0] return ret - if (algorithm is not None and - algorithm != "sage"): + if algorithm is not None and algorithm != "sage": raise ValueError("'algorithm' must be equal to 'bliss', 'sage', or None") from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree @@ -22738,21 +22761,24 @@ def automorphism_group(self, partition=None, verbosity=0, partition = [list(self)] if edge_labels or self.has_multiple_edges(): - G, partition, relabeling = graph_isom_equivalent_non_edge_labeled_graph(self, partition, return_relabeling=True, ignore_edge_labels=(not edge_labels)) + ret = graph_isom_equivalent_non_edge_labeled_graph(self, partition, + return_relabeling=True, + ignore_edge_labels=(not edge_labels)) + G, partition, relabeling = ret G_vertices = list(chain(*partition)) - G_to = {u: i for i,u in enumerate(G_vertices)} + G_to = {u: i for i, u in enumerate(G_vertices)} DoDG = DiGraph if self._directed else Graph H = DoDG(len(G_vertices), loops=G.allows_loops()) HB = H._backend - for u,v in G.edge_iterator(labels=False): + for u, v in G.edge_iterator(labels=False): HB.add_edge(G_to[u], G_to[v], None, G._directed) GC = HB.c_graph()[0] partition = [[G_to[vv] for vv in cell] for cell in partition] A = search_tree(GC, partition, lab=False, dict_rep=True, dig=dig, verbosity=verbosity, order=order) if order: - a,b,c = A + a, b, c = A else: - a,b = A + a, b = A b_new = {v: b[G_to[v]] for v in G_to} b = b_new # b is a translation of the labellings @@ -22781,11 +22807,11 @@ def automorphism_group(self, partition=None, verbosity=0, b = translation_d else: G_vertices = list(chain(*partition)) - G_to = {u: i for i,u in enumerate(G_vertices)} + G_to = {u: i for i, u in enumerate(G_vertices)} DoDG = DiGraph if self._directed else Graph H = DoDG(len(G_vertices), loops=self.allows_loops()) HB = H._backend - for u,v in self.edge_iterator(labels=False): + for u, v in self.edge_iterator(labels=False): HB.add_edge(G_to[u], G_to[v], None, self._directed) GC = HB.c_graph()[0] partition = [[G_to[vv] for vv in cell] for cell in partition] @@ -22793,15 +22819,15 @@ def automorphism_group(self, partition=None, verbosity=0, if return_group: A = search_tree(GC, partition, dict_rep=True, lab=False, dig=dig, verbosity=verbosity, order=order) if order: - a,b,c = A + a, b, c = A else: - a,b = A + a, b = A b_new = {v: b[G_to[v]] for v in G_to} b = b_new else: a = search_tree(GC, partition, dict_rep=False, lab=False, dig=dig, verbosity=verbosity, order=order) if order: - a,c = a + a, c = a output = [] if return_group: @@ -22825,17 +22851,15 @@ def automorphism_group(self, partition=None, verbosity=0, from sage.groups.perm_gps.partn_ref.refinement_graphs import get_orbits output.append([[G_from[v] for v in W] for W in get_orbits(a, self.num_verts())]) - # A Python switch statement! - return { 0: None, - 1: output[0], - 2: tuple(output), - 3: tuple(output), - 4: tuple(output) - }[len(output)] + if len(output) == 1: + return output[0] + elif len(output) > 1: + return tuple(output) + return None def is_vertex_transitive(self, partition=None, verbosity=0, - edge_labels=False, order=False, - return_group=True, orbits=False): + edge_labels=False, order=False, + return_group=True, orbits=False): """ Returns whether the automorphism group of self is transitive within the partition provided, by default the unit partition of the From 6a26dcb8ae316ef562ee2caf6269629ac513ecff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 9 Aug 2022 18:37:19 +0200 Subject: [PATCH 291/591] fix E251 in combinat/sf --- src/sage/combinat/crystals/letters.pyx | 8 +++-- src/sage/combinat/sf/dual.py | 9 +++--- src/sage/combinat/sf/elementary.py | 2 +- src/sage/combinat/sf/hall_littlewood.py | 39 +++++++++++++---------- src/sage/combinat/sf/jack.py | 42 +++++++++++++++---------- src/sage/combinat/sf/k_dual.py | 8 ++--- src/sage/combinat/sf/llt.py | 16 +++++----- src/sage/combinat/sf/macdonald.py | 33 +++++++++++-------- src/sage/combinat/sf/orthotriang.py | 11 ++++--- src/sage/combinat/sf/sf.py | 9 +++--- src/sage/combinat/sf/sfa.py | 24 +++++++------- src/sage/combinat/sf/witt.py | 20 ++++++------ 12 files changed, 124 insertions(+), 97 deletions(-) diff --git a/src/sage/combinat/crystals/letters.pyx b/src/sage/combinat/crystals/letters.pyx index 8a06939ce07..6ca78aed640 100644 --- a/src/sage/combinat/crystals/letters.pyx +++ b/src/sage/combinat/crystals/letters.pyx @@ -104,7 +104,7 @@ def CrystalOfLetters(cartan_type, element_print_style=None, dual=None): else: return ClassicalCrystalOfLetters(ct, Crystal_of_letters_type_E6_element_dual, - element_print_style, dual = True) + element_print_style, dual=True) elif ct.letter == 'E' and ct.rank() == 7: return ClassicalCrystalOfLetters(ct, Crystal_of_letters_type_E7_element) elif ct.letter == 'E' and ct.rank() == 8 or ct.letter == 'F': @@ -116,6 +116,7 @@ def CrystalOfLetters(cartan_type, element_print_style=None, dual=None): else: raise NotImplementedError + class ClassicalCrystalOfLetters(UniqueRepresentation, Parent): r""" A generic class for classical crystals of letters. @@ -136,7 +137,8 @@ class ClassicalCrystalOfLetters(UniqueRepresentation, Parent): time: ``list``, ``cmp``, (todo: ``phi``, ``epsilon``, ``e``, and ``f`` with caching) """ - def __init__(self, cartan_type, element_class, element_print_style = None, dual = None): + def __init__(self, cartan_type, element_class, + element_print_style=None, dual=None): """ EXAMPLES:: @@ -146,7 +148,7 @@ class ClassicalCrystalOfLetters(UniqueRepresentation, Parent): sage: TestSuite(C).run() """ self.Element = element_class - Parent.__init__(self, category = ClassicalCrystals()) + Parent.__init__(self, category=ClassicalCrystals()) self._cartan_type = CartanType(cartan_type) self.rename("The crystal of letters for type %s" % self._cartan_type) if cartan_type.type() == 'E': diff --git a/src/sage/combinat/sf/dual.py b/src/sage/combinat/sf/dual.py index 4ec49461f59..445521e4193 100644 --- a/src/sage/combinat/sf/dual.py +++ b/src/sage/combinat/sf/dual.py @@ -148,15 +148,14 @@ def __init__(self, dual_basis, scalar, scalar_name="", basis_name=None, prefix=N prefix = 'd_'+dual_basis.prefix() classical.SymmetricFunctionAlgebra_classical.__init__(self, self._sym, - basis_name = basis_name, - prefix = prefix) + basis_name=basis_name, + prefix=prefix) # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = sage.categories.all.ModulesWithBasis(self.base_ring()) - self .register_coercion(SetMorphism(Hom(self._dual_basis, self, category), self._dual_to_self)) + self.register_coercion(SetMorphism(Hom(self._dual_basis, self, category), self._dual_to_self)) self._dual_basis.register_coercion(SetMorphism(Hom(self, self._dual_basis, category), self._self_to_dual)) - def _dual_to_self(self, x): """ Coerce an element of the dual of ``self`` canonically into ``self``. @@ -193,7 +192,7 @@ def _dual_to_self(self, x): sage: h(m([2,1]) + 3*m[1,1,1]) d_m[1, 1, 1] - d_m[2, 1] """ - return self._element_class(self, dual = x) + return self._element_class(self, dual=x) def _self_to_dual(self, x): """ diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index 5081f4760fe..446acbf23a3 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -67,7 +67,7 @@ def _dual_basis_default(self): sage: e._dual_basis_default() is e.dual_basis() True """ - return self.dual_basis(scalar = None, prefix="f", basis_name = "forgotten") + return self.dual_basis(scalar=None, prefix="f", basis_name="forgotten") def coproduct_on_generators(self, i): r""" diff --git a/src/sage/combinat/sf/hall_littlewood.py b/src/sage/combinat/sf/hall_littlewood.py index 930d3c2b73e..507112d9311 100644 --- a/src/sage/combinat/sf/hall_littlewood.py +++ b/src/sage/combinat/sf/hall_littlewood.py @@ -73,7 +73,7 @@ def __repr__(self): """ return self._name + " over %s" % self._sym.base_ring() - def __init__(self, Sym, t = 't'): + def __init__(self, Sym, t='t'): """ Initialize ``self``. @@ -365,8 +365,8 @@ def __init__(self, hall_littlewood): s = self.__class__.__name__[15:].capitalize() sfa.SymmetricFunctionAlgebra_generic.__init__( self, hall_littlewood._sym, - basis_name = "Hall-Littlewood " + s + hall_littlewood._name_suffix, - prefix = "HL"+s) + basis_name="Hall-Littlewood " + s + hall_littlewood._name_suffix, + prefix="HL" +s) self.t = hall_littlewood.t self._sym = hall_littlewood._sym self._hall_littlewood = hall_littlewood @@ -407,7 +407,8 @@ def _s_to_self(self, x): sage: P(s[2,1]) 6*HLP[1, 1, 1] + HLP[2, 1] """ - return self._from_cache(x, self._s_cache, self._s_to_self_cache, t = self.t) + return self._from_cache(x, self._s_cache, self._s_to_self_cache, + t=self.t) def _self_to_s(self, x): r""" @@ -435,7 +436,8 @@ def _self_to_s(self, x): sage: s(P[2,1]) -6*s[1, 1, 1] + s[2, 1] """ - return self._s._from_cache(x, self._s_cache, self._self_to_s_cache, t = self.t) + return self._s._from_cache(x, self._s_cache, self._self_to_s_cache, + t=self.t) def transition_matrix(self, basis, n): r""" @@ -545,7 +547,7 @@ class Element(sfa.SymmetricFunctionAlgebra_generic.Element): Methods for elements of a Hall-Littlewood basis that are common to all bases. """ - def expand(self, n, alphabet = 'x'): + def expand(self, n, alphabet='x'): r""" Expands the symmetric function as a symmetric polynomial in ``n`` variables. @@ -577,7 +579,7 @@ def expand(self, n, alphabet = 'x'): x^2 """ s = self.parent().realization_of().schur() - return s(self).expand(n, alphabet = alphabet) + return s(self).expand(n, alphabet=alphabet) def scalar(self, x, zee=None): r""" @@ -618,7 +620,7 @@ def scalar(self, x, zee=None): s_x = s(x) return s_self.scalar(s_x, zee) - def scalar_hl(self, x, t = None): + def scalar_hl(self, x, t=None): r""" Returns the Hall-Littlewood (with parameter ``t``) scalar product of ``self`` and ``x``. @@ -661,8 +663,9 @@ def scalar_hl(self, x, t = None): if t is None: t = parent.t p = parent.realization_of().power() - f = lambda part1, part2: part1.centralizer_size(t = t) - return parent._apply_multi_module_morphism(p(self),p(x),f,orthogonal=True) + f = lambda part1, part2: part1.centralizer_size(t=t) + return parent._apply_multi_module_morphism(p(self), p(x), f, + orthogonal=True) ########### @@ -794,12 +797,11 @@ def _s_cache(self, n): sage: l(HLP._s_to_self_cache[2]) [([1, 1], [([1, 1], 1)]), ([2], [([1, 1], t), ([2], 1)])] """ - self._invert_morphism(n, QQt, self._self_to_s_cache, \ - self._s_to_self_cache, to_self_function = self._s_to_self_base, \ + self._invert_morphism(n, QQt, self._self_to_s_cache, + self._s_to_self_cache, to_self_function=self._s_to_self_base, upper_triangular=True, ones_on_diagonal=True) - ########### # Q basis # ########### @@ -844,9 +846,10 @@ def __init__(self, hall_littlewood): # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = sage.categories.all.ModulesWithBasis(self.base_ring()) - phi = self.module_morphism(diagonal = self._P._q_to_p_normalization, codomain = self._P, category = category) + phi = self.module_morphism(diagonal=self._P._q_to_p_normalization, + codomain=self._P, category=category) self._P.register_coercion(phi) - self .register_coercion(~phi) + self.register_coercion(~phi) def _p_to_q_normalization(self, m): r""" @@ -996,10 +999,12 @@ def _s_cache(self, n): sage: l(HLQp._self_to_s_cache[2]) [([1, 1], [([1, 1], 1), ([2], t)]), ([2], [([2], 1)])] """ - self._invert_morphism(n, QQt, self._self_to_s_cache, \ - self._s_to_self_cache, to_other_function = self._to_s, \ + self._invert_morphism(n, QQt, self._self_to_s_cache, + self._s_to_self_cache, + to_other_function=self._to_s, lower_triangular=True, ones_on_diagonal=True) + # Unpickling backward compatibility sage.misc.persist.register_unpickle_override('sage.combinat.sf.hall_littlewood', 'HallLittlewoodElement_p', HallLittlewood_p.Element) sage.misc.persist.register_unpickle_override('sage.combinat.sf.hall_littlewood', 'HallLittlewoodElement_q', HallLittlewood_q.Element) diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py index 5231e113686..c46c78afefe 100644 --- a/src/sage/combinat/sf/jack.py +++ b/src/sage/combinat/sf/jack.py @@ -503,8 +503,8 @@ def __init__(self, jack): s = self.__class__.__name__[16:].capitalize() sfa.SymmetricFunctionAlgebra_generic.__init__( self, jack._sym, - basis_name = "Jack " + s + jack._name_suffix, - prefix = "Jack"+s) + basis_name="Jack " + s + jack._name_suffix, + prefix="Jack" + s) self.t = jack.t self._sym = jack._sym self._jack = jack @@ -550,7 +550,8 @@ def _m_to_self(self, x): sage: JP(m[2,1]) -3/2*JackP[1, 1, 1] + JackP[2, 1] """ - return self._from_cache(x, self._m_cache, self._m_to_self_cache, t = self.t) + return self._from_cache(x, self._m_cache, self._m_to_self_cache, + t=self.t) def _self_to_m(self, x): r""" @@ -578,7 +579,8 @@ def _self_to_m(self, x): sage: m(JP[2,1]) 3/2*m[1, 1, 1] + m[2, 1] """ - return self._m._from_cache(x, self._m_cache, self._self_to_m_cache, t = self.t) + return self._m._from_cache(x, self._m_cache, self._self_to_m_cache, + t=self.t) def c1(self, part): r""" @@ -897,15 +899,14 @@ def _m_cache(self, n): """ if n in self._self_to_m_cache: return - else: - self._self_to_m_cache[n] = {} + self._self_to_m_cache[n] = {} t = QQt.gen() monomial = sage.combinat.sf.sf.SymmetricFunctions(QQt).monomial() JP = sage.combinat.sf.sf.SymmetricFunctions(QQt).jack().P() - JP._gram_schmidt(n, monomial, lambda p: part_scalar_jack(p,p,t), \ - self._self_to_m_cache[n], upper_triangular=True) - JP._invert_morphism(n, QQt, self._self_to_m_cache, \ - self._m_to_self_cache, to_other_function = self._to_m) + JP._gram_schmidt(n, monomial, lambda p: part_scalar_jack(p, p, t), + self._self_to_m_cache[n], upper_triangular=True) + JP._invert_morphism(n, QQt, self._self_to_m_cache, + self._m_to_self_cache, to_other_function=self._to_m) def _to_m(self, part): r""" @@ -1071,7 +1072,8 @@ def __init__(self, jack): self._P = self._jack.P() # temporary until Hom(GradedHopfAlgebrasWithBasis) works better category = sage.categories.all.ModulesWithBasis(self.base_ring()) - phi = self.module_morphism(diagonal = self.c1, codomain = self._P, category = category) + phi = self.module_morphism(diagonal=self.c1, + codomain=self._P, category=category) # should use module_morphism(on_coeffs = ...) once it exists self._P.register_coercion(self._P._normalize_morphism(category) * phi) self .register_coercion(self ._normalize_morphism(category) *~phi) @@ -1107,15 +1109,19 @@ def __init__(self, jack): self._P = self._jack.P() # temporary until Hom(GradedHopfAlgebrasWithBasis) works better category = sage.categories.all.ModulesWithBasis(self.base_ring()) - phi = self._P.module_morphism(diagonal = self._P.scalar_jack_basis, codomain = self, category = category) - self .register_coercion(self ._normalize_morphism(category) * phi) + phi = self._P.module_morphism(diagonal=self._P.scalar_jack_basis, + codomain=self, category=category) + self.register_coercion(self._normalize_morphism(category) * phi) self._P.register_coercion(self._P._normalize_morphism(category) * ~phi) class Element(JackPolynomials_generic.Element): pass + qp_to_h_cache = {} h_to_qp_cache = {} + + class JackPolynomials_qp(JackPolynomials_generic): def __init__(self, jack): r""" @@ -1247,9 +1253,10 @@ def _self_to_h( self, x ): sage: h(JQp[2,1]) h[2, 1] - 3/5*h[3] """ - return self._h._from_cache(x, self._h_cache, self._self_to_h_cache, t = self.t) + return self._h._from_cache(x, self._h_cache, self._self_to_h_cache, + t=self.t) - def _h_to_self( self, x ): + def _h_to_self(self, x): r""" Isomorphism from the homogeneous basis into ``self`` @@ -1275,9 +1282,10 @@ def _h_to_self( self, x ): sage: JQp(h[2,1]) JackQp[2, 1] + 3/5*JackQp[3] """ - return self._from_cache(x, self._h_cache, self._h_to_self_cache, t = self.t) + return self._from_cache(x, self._h_cache, self._h_to_self_cache, + t=self.t) - def coproduct_by_coercion( self, elt ): + def coproduct_by_coercion(self, elt): r""" Returns the coproduct of the element ``elt`` by coercion to the Schur basis. diff --git a/src/sage/combinat/sf/k_dual.py b/src/sage/combinat/sf/k_dual.py index 7b557b25104..425af1bc96f 100644 --- a/src/sage/combinat/sf/k_dual.py +++ b/src/sage/combinat/sf/k_dual.py @@ -131,7 +131,7 @@ def __init__(self, Sym, k, t='t'): self._quotient_basis = Sym.m() else: self._quotient_basis = Sym.hall_littlewood(t=self.t).P() - Parent.__init__(self, category = GradedHopfAlgebras(R).Quotients().WithRealizations()) + Parent.__init__(self, category=GradedHopfAlgebras(R).Quotients().WithRealizations()) self.indices = ConstantFunction(Partitions_all_bounded(k)) def ambient(self): @@ -282,11 +282,11 @@ def _G_to_km_on_basis_single_level(self, w, m): if m < w.length(): return 0 ans = self.zero() - for la in Partitions(m, max_part = self.k): - ans += g.homogeneous_basis_noncommutative_variables_zero_Hecke((la)).coefficient(w)*mon(la) + for la in Partitions(m, max_part=self.k): + ans += g.homogeneous_basis_noncommutative_variables_zero_Hecke((la)).coefficient(w) * mon(la) return ans - def _AffineGrothendieck(self, w,m): + def _AffineGrothendieck(self, w, m): r""" Returns the affine Grothendieck polynomial indexed by the affine permutation ``w``. Because this belongs to the completion of the algebra, and hence is an diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index 3c854f342ed..b6b19659a3e 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -432,8 +432,8 @@ def __init__(self, llt, prefix): s = self.__class__.__name__[4:] sfa.SymmetricFunctionAlgebra_generic.__init__( self, llt._sym, - basis_name = "level %s LLT "%llt.level() + s + llt._name_suffix, - prefix = prefix) + basis_name="level %s LLT " % llt.level() + s + llt._name_suffix, + prefix=prefix) self.t = llt.t self._sym = llt._sym @@ -474,7 +474,8 @@ def _m_to_self(self, x): sage: HSp3(m[2,1]) -2*HSp3[1, 1, 1] + (2*t^2+2*t+1)*HSp3[2, 1] + (-2*t^2-t)*HSp3[3] """ - return self._from_cache(x, self._m_cache, self._m_to_self_cache, t = self.t) + return self._from_cache(x, self._m_cache, self._m_to_self_cache, + t=self.t) def _self_to_m(self, x): r""" @@ -502,8 +503,8 @@ def _self_to_m(self, x): sage: m(HSp3[2,1]) (t+2)*m[1, 1, 1] + (t+1)*m[2, 1] + t*m[3] """ - return self._m._from_cache(x, self._m_cache, self._self_to_m_cache, t = self.t) - + return self._m._from_cache(x, self._m_cache, self._self_to_m_cache, + t=self.t) def level(self): r""" @@ -598,8 +599,9 @@ def _m_cache(self, n): [([1, 1], [([1, 1], 1/t), ([2], -1/t)]), ([2], [([1, 1], -1/t), ([2], (t + 1)/t)])] """ - self._invert_morphism(n, QQt, self._self_to_m_cache, \ - self._m_to_self_cache, to_other_function = self._to_m) + self._invert_morphism(n, QQt, self._self_to_m_cache, + self._m_to_self_cache, + to_other_function=self._to_m) class Element(sfa.SymmetricFunctionAlgebra_generic.Element): pass diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 3bc4bdbfd5f..3671ae2de8a 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -746,8 +746,8 @@ def __init__(self, macdonald): s = self.__class__.__name__[21:].capitalize() sfa.SymmetricFunctionAlgebra_generic.__init__( self, macdonald._sym, - basis_name = "Macdonald " + s + macdonald._name_suffix, - prefix = "Mcd"+s) + basis_name="Macdonald " + s + macdonald._name_suffix, + prefix="Mcd" + s) self.q = macdonald.q self.t = macdonald.t self._macdonald = macdonald @@ -787,7 +787,8 @@ def _s_to_self(self, x): sage: J(s[2,1]) ((-1/28*q+1/14)/(q-1/4))*McdJ[1, 1, 1] - (1/4/(q-1/4))*McdJ[2, 1] """ - return self._from_cache(x, self._s_cache, self._s_to_self_cache, q = self.q, t = self.t) + return self._from_cache(x, self._s_cache, self._s_to_self_cache, + q=self.q, t=self.t) def _self_to_s(self, x): r""" @@ -815,7 +816,8 @@ def _self_to_s(self, x): sage: s(J[2,1]) (3*q-6)*s[1, 1, 1] + (-4*q+1)*s[2, 1] """ - return self._s._from_cache(x, self._s_cache, self._self_to_s_cache, q = self.q, t = self.t) + return self._s._from_cache(x, self._s_cache, self._self_to_s_cache, + q=self.q, t=self.t) def c1(self, part): r""" @@ -1006,11 +1008,12 @@ def __init__(self, macdonald): self._J = macdonald.J() # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = ModulesWithBasis(self.base_ring()) - phi = self._J.module_morphism(diagonal = self.c2, codomain = self, category = category) + phi = self._J.module_morphism(diagonal=self.c2, + codomain=self, category=category) self.register_coercion( phi) self._J.register_coercion(~phi) - def scalar_qt_basis(self, part1, part2 = None): + def scalar_qt_basis(self, part1, part2=None): r""" Returns the scalar product of `P(part1)` and `P(part2)` This scalar product formula is given in equation (4.11) p.323 @@ -1077,8 +1080,9 @@ def __init__(self, macdonald): # temporary until Hom(GradedHopfAlgebrasWithBasis) works better category = ModulesWithBasis(self.base_ring()) - phi = self._P.module_morphism(diagonal = self._P.scalar_qt_basis, codomain = self, category = category) - self .register_coercion( phi) + phi = self._P.module_morphism(diagonal=self._P.scalar_qt_basis, + codomain=self, category=category) + self.register_coercion( phi) self._P.register_coercion(~phi) class Element(MacdonaldPolynomials_generic.Element): @@ -1134,15 +1138,17 @@ def _s_cache(self, n): [([1, 1], [([1, 1], t^3 - t^2 - t + 1)]), ([2], [([1, 1], -q*t + t^2 + q - t), ([2], q*t^2 - q*t - t + 1)])] """ - self._invert_morphism(n, QQqt, self._self_to_s_cache, \ - self._s_to_self_cache, to_other_function = self._to_s, \ + self._invert_morphism(n, QQqt, self._self_to_s_cache, + self._s_to_self_cache, + to_other_function=self._to_s, upper_triangular=False) def _to_s(self, part): r""" Returns a function which gives the coefficient of a partition in the Schur expansion of self(part). - these computations are completed with coefficients in fraction + + These computations are completed with coefficients in fraction field of polynomials in `q` and `t` INPUT: @@ -1811,8 +1817,9 @@ def _s_cache(self, n): sage: l( S._self_to_s_cache[2] ) [([1, 1], [([1, 1], (-q*t^2 + q*t + t - 1)/(-q^3 + q^2 + q - 1)), ([2], (q*t - t^2 - q + t)/(-q^3 + q^2 + q - 1))]), ([2], [([1, 1], (q*t - t^2 - q + t)/(-q^3 + q^2 + q - 1)), ([2], (-q*t^2 + q*t + t - 1)/(-q^3 + q^2 + q - 1))])] """ - self._invert_morphism(n, QQqt, self._self_to_s_cache, \ - self._s_to_self_cache, to_other_function = self._to_s) + self._invert_morphism(n, QQqt, self._self_to_s_cache, + self._s_to_self_cache, + to_other_function=self._to_s) class Element(MacdonaldPolynomials_generic.Element): diff --git a/src/sage/combinat/sf/orthotriang.py b/src/sage/combinat/sf/orthotriang.py index a0790e4855d..6905cbfd3d9 100644 --- a/src/sage/combinat/sf/orthotriang.py +++ b/src/sage/combinat/sf/orthotriang.py @@ -181,10 +181,13 @@ def _base_cache(self, n): else: self._self_to_base_cache[n] = {} - self._gram_schmidt(n, self._sf_base, self._scalar, self._self_to_base_cache,\ - leading_coeff=self._leading_coeff, upper_triangular=True) - self._invert_morphism(n, self.base_ring(), self._self_to_base_cache, \ - self._base_to_self_cache, to_other_function = self._to_base) + self._gram_schmidt(n, self._sf_base, self._scalar, + self._self_to_base_cache, + leading_coeff=self._leading_coeff, + upper_triangular=True) + self._invert_morphism(n, self.base_ring(), self._self_to_base_cache, + self._base_to_self_cache, + to_other_function=self._to_base) def _to_base(self, part): r""" diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index b4418a40606..f18f6fb75a2 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -1441,15 +1441,16 @@ def __init_extra__(self): for (basis1_name, basis2_name) in conversion_functions: basis1 = getattr(self, basis1_name)() basis2 = getattr(self, basis2_name)() - on_basis = SymmetricaConversionOnBasis(t = conversion_functions[basis1_name,basis2_name], domain = basis1, codomain = basis2) + on_basis = SymmetricaConversionOnBasis(t=conversion_functions[basis1_name,basis2_name], domain=basis1, codomain=basis2) from sage.rings.rational_field import RationalField if basis2_name != "powersum" or self._base.has_coerce_map_from(RationalField()): - iso(basis1._module_morphism(on_basis, codomain = basis2)) + iso(basis1._module_morphism(on_basis, codomain=basis2)) else: # Don't register conversions to powersums as coercions, # unless the base ring is a `\QQ`-algebra # (otherwise the coercion graph loses commutativity). - iso(basis1._module_morphism(on_basis, codomain = basis2), only_conversion = True) + iso(basis1._module_morphism(on_basis, codomain=basis2), + only_conversion=True) # Todo: fill in with other conversion functions on the classical bases @@ -1612,4 +1613,4 @@ def __call__(self, partition): # TODO: use self._codomain.sum_of_monomials, when the later # will have an optional optimization for the case when there # is no repetition in the support - return self._codomain._from_dict(dict(self._t(self.fake_sym.monomial(partition))), coerce = True) + return self._codomain._from_dict(dict(self._t(self.fake_sym.monomial(partition))), coerce=True) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index d1fd77e8c69..03ea31525b0 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -2690,8 +2690,7 @@ def _dual_basis_default(self): sage: Sym.f()._dual_basis_default() Symmetric Functions over Rational Field in the elementary basis """ - return self.dual_basis(scalar=zee, scalar_name = "Hall scalar product") - + return self.dual_basis(scalar=zee, scalar_name="Hall scalar product") def dual_basis(self, scalar=None, scalar_name="", basis_name=None, prefix=None): r""" @@ -2750,8 +2749,8 @@ def dual_basis(self, scalar=None, scalar_name="", basis_name=None, prefix=None): scalar = zee scalar_name = "Hall scalar product" return dual.SymmetricFunctionAlgebra_dual(self, scalar, scalar_name, - basis_name = basis_name, - prefix = prefix) + basis_name=basis_name, + prefix=prefix) def basis_name(self): r""" @@ -4579,7 +4578,7 @@ def scalar(self, x, zee=None): p_x = p(x) return sum(zee(mu)*p_x.coefficient(mu)*p_self.coefficient(mu) for mu in p_self.support()) - def scalar_qt(self, x, q = None, t = None): + def scalar_qt(self, x, q=None, t=None): r""" Return the `q,t`-deformed standard Hall-Littlewood scalar product of ``self`` and ``x``. @@ -4633,10 +4632,10 @@ def scalar_qt(self, x, q = None, t = None): q = parent.q else: q = QQ['q','t'].gens()[0] - f = lambda part1, part2: part1.centralizer_size(t = t, q = q) + f = lambda part1, part2: part1.centralizer_size(t=t, q=q) return p._apply_multi_module_morphism(p(self), p(x), f, orthogonal=True) - def scalar_t(self, x, t = None): + def scalar_t(self, x, t=None): r""" Return the `t`-deformed standard Hall-Littlewood scalar product of ``self`` and ``x``. @@ -5155,7 +5154,7 @@ def bernstein_creation_operator(self, n): break return parent(res) - def _expand(self, condition, n, alphabet = 'x'): + def _expand(self, condition, n, alphabet='x'): r""" Expand the symmetric function as a symmetric polynomial in ``n`` variables. @@ -5338,7 +5337,7 @@ def restrict_degree(self, d, exact=True): res = dict(x for x in self._monomial_coefficients.items() if sum(x[0]) <= d) return self.parent()._from_dict(res) - def restrict_partition_lengths(self, l, exact = True): + def restrict_partition_lengths(self, l, exact=True): r""" Return the terms of ``self`` labelled by partitions of length ``l``. @@ -5390,10 +5389,11 @@ def restrict_parts(self, n): sage: z.restrict_parts(1) s[1] + s[1, 1, 1] """ - res = dict(x for x in self._monomial_coefficients.items() if _lmax(x[0]) <= n) + res = dict(x for x in self._monomial_coefficients.items() + if _lmax(x[0]) <= n) return self.parent()._from_dict(res) - def expand(self, n, alphabet = 'x'): + def expand(self, n, alphabet='x'): r""" Expand the symmetric function ``self`` as a symmetric polynomial in ``n`` variables. @@ -5493,7 +5493,7 @@ def skew_by(self, x): if p1.contains(p2)) return parent(s.element_class(s, ret)) - def hl_creation_operator(self, nu, t = None): + def hl_creation_operator(self, nu, t=None): r""" This is the vertex operator that generalizes Jing's operator. diff --git a/src/sage/combinat/sf/witt.py b/src/sage/combinat/sf/witt.py index 169fea1c370..1dadb90ffdf 100644 --- a/src/sage/combinat/sf/witt.py +++ b/src/sage/combinat/sf/witt.py @@ -1022,14 +1022,14 @@ def __init_extra__(self): # the elements of the Witt basis with respect to the powersum basis self._p_inverse_transition_matrices = {} - self .register_coercion(self._p._module_morphism(self._p_to_w_on_basis, codomain = self)) + self .register_coercion(self._p._module_morphism(self._p_to_w_on_basis, codomain=self)) from sage.rings.rational_field import RationalField if self.base_ring().has_coerce_map_from(RationalField): - self._p.register_coercion(self._module_morphism(self._w_to_p_on_basis, codomain = self._p)) + self._p.register_coercion(self._module_morphism(self._w_to_p_on_basis, codomain=self._p)) self._friendly = self._p else: # self._w_to_p_on_basis is a partial map at best - self._p.register_conversion(self._module_morphism(self._w_to_p_on_basis, codomain = self._p)) + self._p.register_conversion(self._module_morphism(self._w_to_p_on_basis, codomain=self._p)) if (not self._coerce_e) and (not self._coerce_h): # ensure that self has coercion at least to one other basis, # or else coercion-based computations will fail @@ -1054,8 +1054,8 @@ def __init_extra__(self): # cache for transition matrices which contain the coordinates of # the elements of the Witt basis with respect to the homogeneous basis self._h_inverse_transition_matrices = {} - self .register_coercion(self._h._module_morphism(self._h_to_w_on_basis, codomain = self)) - self._h.register_coercion(self._module_morphism(self._w_to_h_on_basis, codomain = self._h)) + self .register_coercion(self._h._module_morphism(self._h_to_w_on_basis, codomain=self)) + self._h.register_coercion(self._module_morphism(self._w_to_h_on_basis, codomain=self._h)) if self._friendly is None: self._friendly = self._h @@ -1076,8 +1076,8 @@ def __init_extra__(self): # cache for transition matrices which contain the coordinates of # the elements of the Witt basis with respect to the elementary basis self._e_inverse_transition_matrices = {} - self .register_coercion(self._e._module_morphism(self._e_to_w_on_basis, codomain = self)) - self._e.register_coercion(self._module_morphism(self._w_to_e_on_basis, codomain = self._e)) + self .register_coercion(self._e._module_morphism(self._e_to_w_on_basis, codomain=self)) + self._e.register_coercion(self._module_morphism(self._w_to_e_on_basis, codomain=self._e)) if self._friendly is None: self._friendly = self._e @@ -1337,7 +1337,7 @@ def verschiebung(self, n): w_coords_of_self = self.monomial_coefficients().items() from sage.combinat.partition import Partition dct = {Partition([i // n for i in lam]): coeff - for (lam, coeff) in w_coords_of_self - if all( i % n == 0 for i in lam )} + for lam, coeff in w_coords_of_self + if all(i % n == 0 for i in lam)} result_in_w_basis = parent._from_dict(dct) - return parent(result_in_w_basis) + return result_in_w_basis From 4103a7114f751a30eba115a542218b6fbf76de96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 9 Aug 2022 18:47:39 +0200 Subject: [PATCH 292/591] fix E251 in algebras --- src/sage/algebras/affine_nil_temperley_lieb.py | 4 ++-- src/sage/algebras/free_algebra.py | 3 ++- .../algebras/letterplace/letterplace_ideal.pyx | 2 +- .../freely_generated_lie_conformal_algebra.py | 6 +++--- .../lie_conformal_algebra_element.py | 6 +++--- .../virasoro_lie_conformal_algebra.py | 9 +++++---- src/sage/algebras/nil_coxeter_algebra.py | 2 +- .../algebras/steenrod/steenrod_algebra_bases.py | 14 +++++--------- 8 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/sage/algebras/affine_nil_temperley_lieb.py b/src/sage/algebras/affine_nil_temperley_lieb.py index 0a35c89d753..492043ddf7d 100644 --- a/src/sage/algebras/affine_nil_temperley_lieb.py +++ b/src/sage/algebras/affine_nil_temperley_lieb.py @@ -41,9 +41,9 @@ class AffineNilTemperleyLiebTypeA(CombinatorialFreeModule): 2*a0 + 1 + 3*a1 + a0*a1*a2*a3 """ - def __init__(self, n, R = ZZ, prefix = 'a'): + def __init__(self, n, R=ZZ, prefix='a'): """ - Initiates the affine nilTemperley Lieb algebra over the ring `R`. + Initiate the affine nilTemperley Lieb algebra over the ring `R`. EXAMPLES:: diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index c53ab5da0e2..7286f62ce27 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -880,7 +880,8 @@ def g_algebra(self, relations, names=None, order='degrevlex', check=True): if d_poly: dmat[v2_ind,v1_ind] = d_poly from sage.rings.polynomial.plural import g_Algebra - return g_Algebra(base_ring, cmat, dmat, names = names or self.variable_names(), + return g_Algebra(base_ring, cmat, dmat, + names=names or self.variable_names(), order=order, check=check) def poincare_birkhoff_witt_basis(self): diff --git a/src/sage/algebras/letterplace/letterplace_ideal.pyx b/src/sage/algebras/letterplace/letterplace_ideal.pyx index c16803280b2..56ec1c3d399 100644 --- a/src/sage/algebras/letterplace/letterplace_ideal.pyx +++ b/src/sage/algebras/letterplace/letterplace_ideal.pyx @@ -161,7 +161,7 @@ class LetterplaceIdeal(Ideal_nc): -y*x*z + z*z """ - def __init__(self, ring, gens, coerce=True, side = "twosided"): + def __init__(self, ring, gens, coerce=True, side="twosided"): """ INPUT: diff --git a/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py index f462a933a38..8fa5460d29a 100644 --- a/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py @@ -80,7 +80,7 @@ def lie_conformal_algebra_generators(self): """ F = Family(self._generators, lambda i: self.monomial((i,Integer(0))), - name = "generator map") + name="generator map") from sage.categories.sets_cat import Sets if F in Sets().Finite(): return tuple(F) @@ -100,5 +100,5 @@ def central_elements(self): (B['K'],) """ return Family(self._central_elements, - lambda i: self.monomial((i,Integer(0))), - name = "central_element map") + lambda i: self.monomial((i, Integer(0))), + name="central_element map") diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py index 55d9e3dab67..b11c912f36d 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py @@ -227,11 +227,11 @@ def _latex_(self): else("T{}".format(names[p._index_to_pos[k[0]]]),v)\ if k[1] == 1\ else ("{}".format(names[p._index_to_pos[k[0]]]),v)\ - for k,v in self.monomial_coefficients().items()] + for k, v in self.monomial_coefficients().items()] else: terms = [("T^{{({0})}}{1}".format(k[1], latex(k[0])),v) if k[1] > 1 \ else("T{}".format(latex(k[0])),v) if k[1] == 1 \ else ("{}".format(latex(k[0])),v)\ - for k,v in self.monomial_coefficients().items()] + for k, v in self.monomial_coefficients().items()] - return repr_lincomb(terms, is_latex=True, strip_one = True) + return repr_lincomb(terms, is_latex=True, strip_one=True) diff --git a/src/sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py index 26ac0951167..cc11ec06a0a 100644 --- a/src/sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py @@ -59,10 +59,11 @@ def __init__(self, R): sage: V = lie_conformal_algebras.Virasoro(QQ) sage: TestSuite(V).run() """ - virdict = {('L','L'):{0:{('L',1):1}, 1:{('L',0): 2}, - 3:{('C', 0):R(2).inverse_of_unit()}}} - GradedLieConformalAlgebra.__init__(self,R, virdict, - names = ('L',), central_elements = ('C',), weights = (2,)) + virdict = {('L', 'L'): {0: {('L', 1): 1}, + 1: {('L', 0): 2}, + 3: {('C', 0): R(2).inverse_of_unit()}}} + GradedLieConformalAlgebra.__init__(self, R, virdict, + names=('L',), central_elements=('C',), weights=(2,)) def _repr_(self): """ diff --git a/src/sage/algebras/nil_coxeter_algebra.py b/src/sage/algebras/nil_coxeter_algebra.py index f44039253ac..5d255b9786d 100644 --- a/src/sage/algebras/nil_coxeter_algebra.py +++ b/src/sage/algebras/nil_coxeter_algebra.py @@ -44,7 +44,7 @@ class NilCoxeterAlgebra(IwahoriHeckeAlgebra.T): u[0,1,2,3] + 2*u[0] + 3*u[1] + 1 """ - def __init__(self, W, base_ring = QQ, prefix='u'): + def __init__(self, W, base_ring=QQ, prefix='u'): r""" Initiate the affine nil-Coxeter algebra corresponding to the Weyl group `W` over the base ring. diff --git a/src/sage/algebras/steenrod/steenrod_algebra_bases.py b/src/sage/algebras/steenrod/steenrod_algebra_bases.py index 34be27e2d58..4cfbe2f83e4 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_bases.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_bases.py @@ -629,7 +629,7 @@ def milnor_basis(n, p=2, **kwds): # with distinct parts. for sigma in restricted_partitions(deg, q_degrees_decrease, - no_repeats = True): + no_repeats=True): index = 0 q_mono = [] for q in q_degrees: @@ -713,7 +713,7 @@ def serre_cartan_basis(n, p=2, bound=1, **kwds): # This means that 2 last <= n - last, or 3 last <= n. result = [(n,)] for last in range(bound, 1+n//3): - for vec in serre_cartan_basis(n - last, bound = 2*last): + for vec in serre_cartan_basis(n - last, bound=2 * last): new = vec + (last,) result.append(new) else: # p odd @@ -1057,13 +1057,9 @@ def sorting_pair(s,t,basis): # pair used for sorting the basis # with distinct parts. for sigma in restricted_partitions(deg, q_degrees_decrease, - no_repeats = True): - index = 0 - q_mono = [] - for q in q_degrees: - if q in sigma: - q_mono.append(index) - index += 1 + no_repeats=True): + q_mono = [index for index, q in enumerate(q_degrees) + if q in sigma] # check profile: okay = True if profile is not None and profile != ((), ()): From 3d7f800ee1b8aa5a32f33ceb32d0722be8be4bf8 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 9 Aug 2022 11:17:27 -0600 Subject: [PATCH 293/591] fixed order correction --- src/sage/groups/generic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 30985cd47de..279ccc06d11 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -904,10 +904,10 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i for i, (pi, ri) in enumerate(f): gamma = power(base, ord // pi) # pohlig-hellman doesn't work with an incorrect order, and the user might have provided a bad parameter - while gamma == power(gamma, 0) and ord > 1: # identity might be None - gamma = mult(gamma, power(base, -1)) - ri -= 1 + while gamma == power(gamma, 0) and ri > 0: # identity might be None ord //= pi + ri -= 1 + gamma = power(base, ord // pi) if not bounds: bound = ord - 1 running_bound = min(bound, pi**ri - 1) From 9579fb4325bc2779dc7d2b16c5d939260d01b7c3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 10:31:51 -0700 Subject: [PATCH 294/591] build/pkgs/p_group_cohomology/patches: Add https://github.com/sagemath/p_group_cohomology/pull/7 --- .../p_group_cohomology/package-version.txt | 2 +- build/pkgs/p_group_cohomology/patches/7.patch | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 build/pkgs/p_group_cohomology/patches/7.patch diff --git a/build/pkgs/p_group_cohomology/package-version.txt b/build/pkgs/p_group_cohomology/package-version.txt index 619b5376684..b0360883a51 100644 --- a/build/pkgs/p_group_cohomology/package-version.txt +++ b/build/pkgs/p_group_cohomology/package-version.txt @@ -1 +1 @@ -3.3.3 +3.3.3.p1 diff --git a/build/pkgs/p_group_cohomology/patches/7.patch b/build/pkgs/p_group_cohomology/patches/7.patch new file mode 100644 index 00000000000..89a8b1e7294 --- /dev/null +++ b/build/pkgs/p_group_cohomology/patches/7.patch @@ -0,0 +1,23 @@ +From dde5d18ff0a0b8d1f9e88806bb9bb4b694b4666c Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Tue, 9 Aug 2022 10:09:22 -0700 +Subject: [PATCH] pGroupCohomology-3.3.3/pGroupCohomology/cohomology.pyx: Update import of + instancedoc for Sage 9.7 + +--- + pGroupCohomology-3.3.3/pGroupCohomology/cohomology.pyx | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/pGroupCohomology-3.3.3/pGroupCohomology/cohomology.pyx b/pGroupCohomology-3.3.3/pGroupCohomology/cohomology.pyx +index 3a7dc77..ae1458d 100644 +--- a/pGroupCohomology-3.3.3/pGroupCohomology/cohomology.pyx ++++ b/pGroupCohomology-3.3.3/pGroupCohomology/cohomology.pyx +@@ -68,7 +68,7 @@ from sage.all import mul + from sage.env import DOT_SAGE, SAGE_ROOT + from sage.misc.sageinspect import sage_getargspec + from sage.misc.lazy_attribute import lazy_attribute +-from sage.docs.instancedoc import instancedoc ++from sage.misc.instancedoc import instancedoc + from sage.structure.richcmp import richcmp, richcmp_method, op_LT, op_NE, op_GT + + # Sage rings etc. From 0a648f1ab588fb860421157a30e80d791a72c079 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 9 Aug 2022 11:46:27 -0600 Subject: [PATCH 295/591] randomly test group order instead of just base order --- src/sage/groups/generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 279ccc06d11..e9055561bb0 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -841,7 +841,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: G = Zmod(randrange(1, 1000)) sage: base = G.random_element() - sage: order = base.additive_order() + sage: order = choice([base.additive_order(), G.order()]) sage: assert order.divides(G.cardinality()) sage: sol = randrange(order) sage: elem = sol * base From eb28739862dcf078bff976eeb071c41219c56210 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 9 Aug 2022 12:03:17 -0600 Subject: [PATCH 296/591] fix silent failure issue when base == identity the code to reduce the order provided to the order of the base allowed the dlog function to silently produce a wrong answer when base == identity, a != base, and ord>1 --- src/sage/groups/generic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index e9055561bb0..455e05abd2e 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -854,8 +854,8 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i ....: assert lo <= sol <= hi ....: kwargs['bounds'] = (lo, hi) sage: res = discrete_log(*args, **kwargs) - sage: res == sol - True + sage: if not res == sol: + ....: print(args, kwargs, G, res, sol) AUTHORS: @@ -889,7 +889,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i from sage.rings.infinity import Infinity if ord == +Infinity: return bsgs(base, a, bounds, identity=identity, inverse=inverse, op=op, operation=operation) - if ord == 1 and a != base: + if base == power(base, 0) and a != base: raise ValueError f = ord.factor() l = [0] * len(f) From 17fd21ac63a7ee0dc2f6a15a1f2503aa035a8d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 9 Aug 2022 20:03:58 +0200 Subject: [PATCH 297/591] fix E251 in categories --- src/sage/categories/algebras_with_basis.py | 2 +- src/sage/categories/category.py | 22 ++++++------- src/sage/categories/category_cy_helper.pyx | 3 +- src/sage/categories/category_with_axiom.py | 4 +-- src/sage/categories/classical_crystals.py | 2 +- src/sage/categories/coalgebras_with_basis.py | 9 +++--- .../covariant_functorial_construction.py | 2 +- src/sage/categories/crystals.py | 15 ++++----- .../examples/algebras_with_basis.py | 6 ++-- .../examples/commutative_additive_monoids.py | 2 +- .../commutative_additive_semigroups.py | 3 +- src/sage/categories/examples/crystals.py | 14 ++++----- src/sage/categories/examples/facade_sets.py | 9 ++---- .../examples/finite_coxeter_groups.py | 9 +++--- .../categories/examples/finite_monoids.py | 4 +-- .../categories/examples/finite_semigroups.py | 3 +- .../categories/examples/finite_weyl_groups.py | 2 +- .../examples/hopf_algebras_with_basis.py | 3 +- .../examples/infinite_enumerated_sets.py | 2 +- src/sage/categories/examples/monoids.py | 2 +- src/sage/categories/examples/posets.py | 4 +-- src/sage/categories/examples/semigroups.py | 16 +++++----- .../categories/examples/semigroups_cython.pyx | 4 +-- src/sage/categories/examples/sets_cat.py | 8 ++--- .../categories/examples/with_realizations.py | 2 +- src/sage/categories/finite_coxeter_groups.py | 11 ++++--- src/sage/categories/finite_crystals.py | 2 +- ...ite_dimensional_lie_algebras_with_basis.py | 2 +- .../categories/finite_permutation_groups.py | 5 ++- src/sage/categories/finite_posets.py | 31 ++++++++++--------- src/sage/categories/groupoid.py | 3 +- src/sage/categories/groups.py | 4 +-- src/sage/categories/hecke_modules.py | 2 +- .../categories/highest_weight_crystals.py | 4 +-- src/sage/categories/homset.py | 12 ++++--- .../categories/hopf_algebras_with_basis.py | 5 +-- src/sage/categories/loop_crystals.py | 2 +- src/sage/categories/magmatic_algebras.py | 2 +- src/sage/categories/modules_with_basis.py | 6 ++-- src/sage/categories/poor_man_map.py | 2 +- src/sage/categories/posets.py | 10 +++--- src/sage/categories/regular_crystals.py | 6 ++-- src/sage/categories/rings.py | 4 +-- src/sage/categories/schemes.py | 2 +- src/sage/categories/semigroups.py | 5 +-- src/sage/categories/sets_cat.py | 11 ++++--- .../super_hopf_algebras_with_basis.py | 3 +- src/sage/categories/unital_algebras.py | 2 +- src/sage/categories/vector_spaces.py | 2 +- src/sage/categories/weyl_groups.py | 8 ++--- 50 files changed, 151 insertions(+), 147 deletions(-) diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index 459dc7f53be..dbd7a9a43a1 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -104,7 +104,7 @@ class AlgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: TestSuite(AlgebrasWithBasis(QQ)).run() """ - def example(self, alphabet = ('a','b','c')): + def example(self, alphabet=('a','b','c')): """ Return an example of algebra with basis. diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 60e45a11260..eef5e7acc70 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -474,7 +474,7 @@ def __init__(self, s=None): assert s is None self.__class__ = dynamic_class("{}_with_category".format(self.__class__.__name__), (self.__class__, self.subcategory_class, ), - cache = False, reduction = None, + cache=False, reduction=None, doccls=self.__class__) @lazy_attribute @@ -870,7 +870,7 @@ def _all_super_categories(self): for cat in self._super_categories] + [self._super_categories], category_sort_key) - if not sorted(result, key = category_sort_key, reverse=True) == result: + if not sorted(result, key=category_sort_key, reverse=True) == result: warn("Inconsistent sorting results for all super categories of {}".format( self.__class__)) self._super_categories_for_classes = bases @@ -1009,7 +1009,7 @@ def _super_categories(self): sage: Rings()._super_categories [Category of rngs, Category of semirings] """ - return sorted(_flatten_categories(self.super_categories(),JoinCategory), key = category_sort_key, reverse=True) + return sorted(_flatten_categories(self.super_categories(), JoinCategory), key=category_sort_key, reverse=True) @lazy_attribute def _super_categories_for_classes(self): @@ -1597,10 +1597,9 @@ def _make_named_class(self, name, method_provider, cache=False, picklable=True): else: reduction = None return dynamic_class(class_name, - tuple(getattr(cat,name) for cat in self._super_categories_for_classes), - method_provider_cls, prepend_cls_bases = False, doccls = doccls, - reduction = reduction, cache = cache) - + tuple(getattr(cat, name) for cat in self._super_categories_for_classes), + method_provider_cls, prepend_cls_bases=False, + doccls=doccls, reduction=reduction, cache=cache) @lazy_attribute def subcategory_class(self): @@ -1822,7 +1821,7 @@ def is_subcategory(self, c): return c in self._set_of_super_categories return subcat_hook - def or_subcategory(self, category = None, join = False): + def or_subcategory(self, category=None, join=False): """ Return ``category`` or ``self`` if ``category`` is ``None``. @@ -2618,7 +2617,8 @@ def category_sample(): for cls in sage.categories.all.__dict__.values() if isinstance(cls, type) and issubclass(cls, Category) and cls not in abstract_classes_for_categories) -def category_graph(categories = None): + +def category_graph(categories=None): """ Return the graph of the categories in Sage. @@ -2707,7 +2707,7 @@ class CategoryWithParameters(Category): .. automethod:: Category._make_named_class """ - def _make_named_class(self, name, method_provider, cache = False, **options): + def _make_named_class(self, name, method_provider, cache=False, **options): """ Return the parent/element/... class of ``self``. @@ -3215,7 +3215,7 @@ def _repr_object_names(self): from sage.categories.category_with_axiom import CategoryWithAxiom return CategoryWithAxiom._repr_object_names_static(self._without_axioms(named=True), self.axioms()) - def _repr_(self, as_join = False): + def _repr_(self, as_join=False): """ Print representation. diff --git a/src/sage/categories/category_cy_helper.pyx b/src/sage/categories/category_cy_helper.pyx index 804db9cce89..135b015fc1c 100644 --- a/src/sage/categories/category_cy_helper.pyx +++ b/src/sage/categories/category_cy_helper.pyx @@ -318,6 +318,5 @@ cpdef tuple canonicalize_axioms(AxiomContainer all_axioms, axioms): ('Finite', 'Connected', 'WithBasis', 'Commutative') """ cdef list L = list(set(axioms)) - L.sort(key = (all_axioms).__getitem__) + L.sort(key=(all_axioms).__getitem__) return tuple(L) - diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index e9faa85ab57..e8811e9f25e 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -2177,8 +2177,8 @@ def super_categories(self): for category in base_category._super_categories for cat in category._with_axiom_as_tuple(axiom)) + tuple(self.extra_super_categories()), - ignore_axioms = ((base_category, axiom),), - as_list = True) + ignore_axioms=((base_category, axiom),), + as_list=True) def additional_structure(self): r""" diff --git a/src/sage/categories/classical_crystals.py b/src/sage/categories/classical_crystals.py index 5bb4b5c4a1b..490337d0bda 100644 --- a/src/sage/categories/classical_crystals.py +++ b/src/sage/categories/classical_crystals.py @@ -110,7 +110,7 @@ def additional_structure(self): class ParentMethods: - def demazure_character(self, w, f = None): + def demazure_character(self, w, f=None): r""" Return the Demazure character associated to ``w``. diff --git a/src/sage/categories/coalgebras_with_basis.py b/src/sage/categories/coalgebras_with_basis.py index 5f781613944..b672c37dd27 100644 --- a/src/sage/categories/coalgebras_with_basis.py +++ b/src/sage/categories/coalgebras_with_basis.py @@ -17,6 +17,7 @@ from sage.categories.super_modules import SuperModulesCategory from sage.categories.filtered_modules import FilteredModulesCategory + class CoalgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ The category of coalgebras with a distinguished basis. @@ -43,7 +44,7 @@ class Filtered(FilteredModulesCategory): class ParentMethods: - @abstract_method(optional = True) + @abstract_method(optional=True) def coproduct_on_basis(self, i): """ The coproduct of the algebra on the basis (optional). @@ -86,14 +87,14 @@ def coproduct(self): """ if self.coproduct_on_basis is not NotImplemented: - # TODO: if self is a hopf algebra, then one would want + # TODO: if self is a Hopf algebra, then one would want # to create a morphism of algebras with basis instead # should there be a method self.coproduct_homset_category? - return Hom(self, tensor([self, self]), ModulesWithBasis(self.base_ring()))(on_basis = self.coproduct_on_basis) + return Hom(self, tensor([self, self]), ModulesWithBasis(self.base_ring()))(on_basis=self.coproduct_on_basis) elif hasattr(self, "coproduct_by_coercion"): return self.coproduct_by_coercion - @abstract_method(optional = True) + @abstract_method(optional=True) def counit_on_basis(self, i): """ The counit of the algebra on the basis (optional). diff --git a/src/sage/categories/covariant_functorial_construction.py b/src/sage/categories/covariant_functorial_construction.py index 96dbf891bc9..4ed3a678986 100644 --- a/src/sage/categories/covariant_functorial_construction.py +++ b/src/sage/categories/covariant_functorial_construction.py @@ -480,7 +480,7 @@ def super_categories(self): """ return Category.join([self.__class__.default_super_categories(self.base_category(), *self._args)] + self.extra_super_categories(), - as_list = True) + as_list=True) def _repr_object_names(self): """ diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 995dd7e63e6..efd995d70f0 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -1515,9 +1515,10 @@ def s(self, i): b = b.e(i) return b - def is_highest_weight(self, index_set = None): + def is_highest_weight(self, index_set=None): r""" - Returns ``True`` if ``self`` is a highest weight. + Return ``True`` if ``self`` is a highest weight. + Specifying the option ``index_set`` to be a subset `I` of the index set of the underlying crystal, finds all highest weight vectors for arrows in `I`. @@ -1536,7 +1537,7 @@ def is_highest_weight(self, index_set = None): index_set = self.index_set() return all(self.e(i) is None for i in index_set) - def is_lowest_weight(self, index_set = None): + def is_lowest_weight(self, index_set=None): r""" Returns ``True`` if ``self`` is a lowest weight. Specifying the option ``index_set`` to be a subset `I` of the @@ -1557,7 +1558,7 @@ def is_lowest_weight(self, index_set = None): index_set = self.index_set() return all(self.f(i) is None for i in index_set) - def to_highest_weight(self, index_set = None): + def to_highest_weight(self, index_set=None): r""" Return the highest weight element `u` and a list `[i_1,...,i_k]` such that `self = f_{i_1} ... f_{i_k} u`, where `i_1,...,i_k` are @@ -1592,11 +1593,11 @@ def to_highest_weight(self, index_set = None): for i in index_set: next = self.e(i) if next is not None: - hw = next.to_highest_weight(index_set = index_set) + hw = next.to_highest_weight(index_set=index_set) return [hw[0], [i] + hw[1]] return [self, []] - def to_lowest_weight(self, index_set = None): + def to_lowest_weight(self, index_set=None): r""" Return the lowest weight element `u` and a list `[i_1,...,i_k]` such that `self = e_{i_1} ... e_{i_k} u`, where `i_1,...,i_k` are @@ -1633,7 +1634,7 @@ def to_lowest_weight(self, index_set = None): for i in index_set: next = self.f(i) if next is not None: - lw = next.to_lowest_weight(index_set = index_set) + lw = next.to_lowest_weight(index_set=index_set) return [lw[0], [i] + lw[1]] return [self, []] diff --git a/src/sage/categories/examples/algebras_with_basis.py b/src/sage/categories/examples/algebras_with_basis.py index 066c72aee4f..7ad85cb82ed 100644 --- a/src/sage/categories/examples/algebras_with_basis.py +++ b/src/sage/categories/examples/algebras_with_basis.py @@ -21,7 +21,7 @@ class FreeAlgebra(CombinatorialFreeModule): This class illustrates a minimal implementation of an algebra with basis. """ - def __init__(self, R, alphabet = ("a", "b", "c")): + def __init__(self, R, alphabet=("a", "b", "c")): """ EXAMPLES:: @@ -31,7 +31,9 @@ def __init__(self, R, alphabet = ("a", "b", "c")): """ self._alphabet = alphabet - CombinatorialFreeModule.__init__(self, R, Words(alphabet, infinite=False), category = AlgebrasWithBasis(R)) + CombinatorialFreeModule.__init__(self, R, + Words(alphabet, infinite=False), + category=AlgebrasWithBasis(R)) def _repr_(self): """ diff --git a/src/sage/categories/examples/commutative_additive_monoids.py b/src/sage/categories/examples/commutative_additive_monoids.py index 229f66ae7e0..c0930bec5d5 100644 --- a/src/sage/categories/examples/commutative_additive_monoids.py +++ b/src/sage/categories/examples/commutative_additive_monoids.py @@ -84,7 +84,7 @@ def __init__(self, alphabet=('a','b','c','d')): """ self.alphabet = alphabet - Parent.__init__(self, category = CommutativeAdditiveMonoids()) + Parent.__init__(self, category=CommutativeAdditiveMonoids()) def _repr_(self): r""" diff --git a/src/sage/categories/examples/commutative_additive_semigroups.py b/src/sage/categories/examples/commutative_additive_semigroups.py index 88cdeeee55d..ea2fde99bb4 100644 --- a/src/sage/categories/examples/commutative_additive_semigroups.py +++ b/src/sage/categories/examples/commutative_additive_semigroups.py @@ -81,10 +81,9 @@ def __init__(self, alphabet=('a','b','c','d')): TESTS:: sage: TestSuite(M).run() - """ self.alphabet = alphabet - Parent.__init__(self, category = CommutativeAdditiveSemigroups()) + Parent.__init__(self, category=CommutativeAdditiveSemigroups()) def _repr_(self): r""" diff --git a/src/sage/categories/examples/crystals.py b/src/sage/categories/examples/crystals.py index 0e5fd353d9b..02121cd3c02 100644 --- a/src/sage/categories/examples/crystals.py +++ b/src/sage/categories/examples/crystals.py @@ -96,7 +96,7 @@ class HighestWeightCrystalOfTypeA(UniqueRepresentation, Parent): running ._test_stembridge_local_axioms() . . . pass """ - def __init__(self, n = 3): + def __init__(self, n=3): """ EXAMPLES:: @@ -104,10 +104,10 @@ def __init__(self, n = 3): sage: C == Crystals().example(n=4) True """ - Parent.__init__(self, category = ClassicalCrystals()) + Parent.__init__(self, category=ClassicalCrystals()) self.n = n - self._cartan_type = CartanType(['A',n]) - self.module_generators = [ self(1) ] + self._cartan_type = CartanType(['A', n]) + self.module_generators = [self(1)] def _repr_(self): """ @@ -183,12 +183,12 @@ def __init__(self): sage: C == Crystals().example(choice='naive') True """ - Parent.__init__(self, category = ClassicalCrystals()) + Parent.__init__(self, category=ClassicalCrystals()) self.n = 2 - self._cartan_type = CartanType(['A',2]) + self._cartan_type = CartanType(['A', 2]) self.G = DiGraph(5) self.G.add_edges([ [0,1,1], [1,2,1], [2,3,1], [3,5,1], [0,4,2], [4,5,2] ]) - self.module_generators = [ self(0) ] + self.module_generators = [self(0)] def __repr__(self): """ diff --git a/src/sage/categories/examples/facade_sets.py b/src/sage/categories/examples/facade_sets.py index 5eed585c62c..bff442e2c5c 100644 --- a/src/sage/categories/examples/facade_sets.py +++ b/src/sage/categories/examples/facade_sets.py @@ -70,9 +70,8 @@ def __init__(self): TESTS:: sage: TestSuite(S).run() - """ - Parent.__init__(self, facade = ZZ, category = Monoids()) + Parent.__init__(self, facade=ZZ, category=Monoids()) def _repr_(self): r""" @@ -170,12 +169,11 @@ def __init__(self): TESTS:: sage: TestSuite(S).run() - """ # We can't use InfinityRing, because this ring contains 3 - # elements besides +-infinity. We can't use Set either for the + # elements besides +-infinity. We can not use Set either for the # moment, because Set([1,2])(1) raises an error - Parent.__init__(self, facade = (ZZ, FiniteEnumeratedSet([-infinity, +infinity])), category = Sets()) + Parent.__init__(self, facade=(ZZ, FiniteEnumeratedSet([-infinity, +infinity])), category=Sets()) def _repr_(self): r""" @@ -183,6 +181,5 @@ def _repr_(self): EXAMPLES:: sage: S = Sets().Facade().example() # indirect doctest - """ return "An example of a facade set: the integers completed by +-infinity" diff --git a/src/sage/categories/examples/finite_coxeter_groups.py b/src/sage/categories/examples/finite_coxeter_groups.py index 83b60ea6d1c..c135c877b70 100644 --- a/src/sage/categories/examples/finite_coxeter_groups.py +++ b/src/sage/categories/examples/finite_coxeter_groups.py @@ -85,7 +85,7 @@ class DihedralGroup(UniqueRepresentation, Parent): ((2, 1), (2,), 1)] """ - def __init__(self, n = 5): + def __init__(self, n=5): r""" INPUT: - ``n`` - an integer with `n>=2` @@ -97,10 +97,9 @@ def __init__(self, n = 5): sage: from sage.categories.examples.finite_coxeter_groups import DihedralGroup sage: DihedralGroup(3) The 3-th dihedral group of order 6 - """ assert n >= 2 - Parent.__init__(self, category = FiniteCoxeterGroups()) + Parent.__init__(self, category=FiniteCoxeterGroups()) self.n = n def _repr_(self): @@ -112,7 +111,7 @@ def _repr_(self): sage: FiniteCoxeterGroups().example(6) The 6-th dihedral group of order 12 """ - return "The %s-th dihedral group of order %s"%(self.n, 2*self.n) + return "The %s-th dihedral group of order %s" % (self.n, 2 * self.n) def __contains__(self, x): r""" @@ -184,7 +183,7 @@ class Element(ElementWrapper): wrapped_class = tuple __lt__ = ElementWrapper._lt_by_value - def has_right_descent(self, i, positive = False, side = "right"): + def has_right_descent(self, i, positive=False, side="right"): r""" Implements :meth:`SemiGroups.ElementMethods.has_right_descent`. diff --git a/src/sage/categories/examples/finite_monoids.py b/src/sage/categories/examples/finite_monoids.py index 52e473ee6a1..f61c28a4032 100644 --- a/src/sage/categories/examples/finite_monoids.py +++ b/src/sage/categories/examples/finite_monoids.py @@ -17,6 +17,7 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ + class IntegerModMonoid(UniqueRepresentation, Parent): r""" An example of a finite monoid: the integers mod `n` @@ -63,7 +64,7 @@ class IntegerModMonoid(UniqueRepresentation, Parent): running ._test_some_elements() . . . pass """ - def __init__(self, n = 12): + def __init__(self, n=12): r""" EXAMPLES:: @@ -73,7 +74,6 @@ def __init__(self, n = 12): TESTS:: sage: TestSuite(M).run() - """ self.n = n Parent.__init__(self, category=Monoids().Finite().FinitelyGenerated()) diff --git a/src/sage/categories/examples/finite_semigroups.py b/src/sage/categories/examples/finite_semigroups.py index 25ffa464bd3..e21a9713815 100644 --- a/src/sage/categories/examples/finite_semigroups.py +++ b/src/sage/categories/examples/finite_semigroups.py @@ -117,7 +117,8 @@ def __init__(self, alphabet=('a','b','c','d')): sage: TestSuite(S).run() """ self.alphabet = alphabet - Parent.__init__(self, category = Semigroups().Finite().FinitelyGenerated()) + Parent.__init__(self, + category=Semigroups().Finite().FinitelyGenerated()) def _repr_(self): r""" diff --git a/src/sage/categories/examples/finite_weyl_groups.py b/src/sage/categories/examples/finite_weyl_groups.py index d3d50c9af89..a17a48c142e 100644 --- a/src/sage/categories/examples/finite_weyl_groups.py +++ b/src/sage/categories/examples/finite_weyl_groups.py @@ -72,7 +72,7 @@ class SymmetricGroup(UniqueRepresentation, Parent): sage: TestSuite(S).run() """ - def __init__(self, n = 4): + def __init__(self, n=4): """ EXAMPLES:: diff --git a/src/sage/categories/examples/hopf_algebras_with_basis.py b/src/sage/categories/examples/hopf_algebras_with_basis.py index fc3ef19d914..16bd866c9c6 100644 --- a/src/sage/categories/examples/hopf_algebras_with_basis.py +++ b/src/sage/categories/examples/hopf_algebras_with_basis.py @@ -32,7 +32,8 @@ def __init__(self, R, G): sage: TestSuite(A).run() """ self._group = G - CombinatorialFreeModule.__init__(self, R, G, category = HopfAlgebrasWithBasis(R)) + CombinatorialFreeModule.__init__(self, R, G, + category=HopfAlgebrasWithBasis(R)) def _repr_(self): """ diff --git a/src/sage/categories/examples/infinite_enumerated_sets.py b/src/sage/categories/examples/infinite_enumerated_sets.py index d606c9274da..c4bb3d8e55d 100644 --- a/src/sage/categories/examples/infinite_enumerated_sets.py +++ b/src/sage/categories/examples/infinite_enumerated_sets.py @@ -89,7 +89,7 @@ def __init__(self): Category of infinite enumerated sets sage: TestSuite(NN).run() """ - Parent.__init__(self, category = InfiniteEnumeratedSets()) + Parent.__init__(self, category=InfiniteEnumeratedSets()) def _repr_(self): """ diff --git a/src/sage/categories/examples/monoids.py b/src/sage/categories/examples/monoids.py index 9de0d2f06e1..c2919a8cc28 100644 --- a/src/sage/categories/examples/monoids.py +++ b/src/sage/categories/examples/monoids.py @@ -93,7 +93,7 @@ def __init__(self, alphabet=('a','b','c','d')): """ self.alphabet = alphabet - Parent.__init__(self, category = Monoids()) + Parent.__init__(self, category=Monoids()) def _repr_(self): r""" diff --git a/src/sage/categories/examples/posets.py b/src/sage/categories/examples/posets.py index 4d864c9cef5..5041df19835 100644 --- a/src/sage/categories/examples/posets.py +++ b/src/sage/categories/examples/posets.py @@ -64,7 +64,7 @@ def __init__(self): sage: TestSuite(P).run() """ - Parent.__init__(self, category = Posets()) + Parent.__init__(self, category=Posets()) def _repr_(self): r""" @@ -146,7 +146,7 @@ def __init__(self): sage: TestSuite(P).run() """ - Parent.__init__(self, facade = (PositiveIntegers(),), category = Posets()) + Parent.__init__(self, facade=(PositiveIntegers(),), category=Posets()) def _repr_(self): r""" diff --git a/src/sage/categories/examples/semigroups.py b/src/sage/categories/examples/semigroups.py index 4d7767a3c51..4c4d9a1f4df 100644 --- a/src/sage/categories/examples/semigroups.py +++ b/src/sage/categories/examples/semigroups.py @@ -78,9 +78,8 @@ def __init__(self): TESTS:: sage: TestSuite(S).run() - """ - Parent.__init__(self, category = Semigroups()) + Parent.__init__(self, category=Semigroups()) def _repr_(self): r""" @@ -197,10 +196,9 @@ def __init__(self, alphabet=('a','b','c','d')): sage: F == loads(dumps(F)) True - """ self.alphabet = alphabet - Parent.__init__(self, category = Semigroups().FinitelyGenerated()) + Parent.__init__(self, category=Semigroups().FinitelyGenerated()) def _repr_(self): r""" @@ -372,7 +370,7 @@ def _element_constructor_(self, x): """ return self.retract(self.ambient()(x)) - def __init__(self, category = None): + def __init__(self, category=None): r""" This quotient of the left zero semigroup of integers obtained by setting `x=42` for any `x\geq 42`. @@ -396,7 +394,7 @@ def __init__(self, category = None): """ if category is None: category = Semigroups().Quotients() - Parent.__init__(self, category = category) + Parent.__init__(self, category=category) def _repr_(self): r""" @@ -526,14 +524,14 @@ def retract(self, x): assert x in self.ambient() and x.value in ZZ if x.value > 42: return self.the_answer() - else: - return self.element_class(self, x) + return self.element_class(self, x) class Element(ElementWrapper): pass + class IncompleteSubquotientSemigroup(UniqueRepresentation,Parent): - def __init__(self, category = None): + def __init__(self, category=None): r""" An incompletely implemented subquotient semigroup, for testing purposes diff --git a/src/sage/categories/examples/semigroups_cython.pyx b/src/sage/categories/examples/semigroups_cython.pyx index ffd8dad8342..ee7a03ddc82 100644 --- a/src/sage/categories/examples/semigroups_cython.pyx +++ b/src/sage/categories/examples/semigroups_cython.pyx @@ -57,7 +57,7 @@ cdef class LeftZeroSemigroupElement(Element): sage: x = S(3) sage: TestSuite(x).run() """ - Element.__init__(self, parent = parent) + Element.__init__(self, parent=parent) self._value = value def _repr_(self): @@ -214,6 +214,6 @@ class LeftZeroSemigroup(LeftZeroSemigroupPython): Category of idempotent semigroups sage: TestSuite(S).run() """ - Parent.__init__(self, category = IdempotentSemigroups()) + Parent.__init__(self, category=IdempotentSemigroups()) Element = LeftZeroSemigroupElement diff --git a/src/sage/categories/examples/sets_cat.py b/src/sage/categories/examples/sets_cat.py index a9e8933901d..eee40b1bfbe 100644 --- a/src/sage/categories/examples/sets_cat.py +++ b/src/sage/categories/examples/sets_cat.py @@ -91,7 +91,7 @@ def __init__(self): sage: P is Sets().example() True """ - Parent.__init__(self, facade = IntegerRing(), category = Sets()) + Parent.__init__(self, facade=IntegerRing(), category=Sets()) def _repr_(self): """ @@ -172,7 +172,7 @@ def __init__(self): sage: P = Sets().example("inherits") """ - Parent.__init__(self, category = Sets()) + Parent.__init__(self, category=Sets()) def _repr_(self): """ @@ -496,7 +496,7 @@ def __init__(self): sage: P(13) + 1 == 14 True """ - Parent.__init__(self, category = Sets()) + Parent.__init__(self, category=Sets()) from sage.rings.integer_ring import IntegerRing from sage.categories.homset import Hom self.mor = Hom(self, IntegerRing())(lambda z: z.value) @@ -665,7 +665,7 @@ def __init__(self): sage: P = Sets().example("inherits") """ - Parent.__init__(self, facade = IntegerRing(), category = Sets()) + Parent.__init__(self, facade=IntegerRing(), category=Sets()) def _repr_(self): """ diff --git a/src/sage/categories/examples/with_realizations.py b/src/sage/categories/examples/with_realizations.py index d322aba065a..e72b2f5b3d0 100644 --- a/src/sage/categories/examples/with_realizations.py +++ b/src/sage/categories/examples/with_realizations.py @@ -169,7 +169,7 @@ def __init__(self, R, S): assert(R in Rings()) self._base = R # Won't be needed when CategoryObject won't override anymore base_ring self._S = S - Parent.__init__(self, category = Algebras(R).Commutative().WithRealizations()) + Parent.__init__(self, category=Algebras(R).Commutative().WithRealizations()) # Initializes the bases and change of bases of ``self`` diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 1cf0d84a1e7..22b324d850c 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -474,11 +474,12 @@ def weak_poset(self, side="right", facade=False): from sage.combinat.posets.posets import Poset from sage.combinat.posets.lattices import LatticePoset if side == "twosided": - covers = tuple([u, v] for u in self for v in u.upper_covers(side="left")+u.upper_covers(side="right") ) - return Poset((self, covers), cover_relations = True, facade = facade) - else: - covers = tuple([u, v] for u in self for v in u.upper_covers(side=side) ) - return LatticePoset((self, covers), cover_relations = True, facade = facade) + covers = tuple([u, v] for u in self for v in u.upper_covers(side="left") + u.upper_covers(side="right")) + return Poset((self, covers), cover_relations=True, + facade=facade) + covers = tuple([u, v] for u in self for v in u.upper_covers(side=side)) + return LatticePoset((self, covers), cover_relations=True, + facade=facade) weak_lattice = weak_poset diff --git a/src/sage/categories/finite_crystals.py b/src/sage/categories/finite_crystals.py index cf78401065d..072df1f9c53 100644 --- a/src/sage/categories/finite_crystals.py +++ b/src/sage/categories/finite_crystals.py @@ -71,7 +71,7 @@ def extra_super_categories(self): """ return [FiniteEnumeratedSets()] - def example(self, n = 3): + def example(self, n=3): """ Returns an example of highest weight crystals, as per :meth:`Category.example`. diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index ab72f20f970..2edc78c26e3 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -971,7 +971,7 @@ def lower_central_series(self, submodule=False): else: L = [self] while L[-1].dimension() > 0: - s = self.product_space(L[-1], submodule = submodule) + s = self.product_space(L[-1], submodule=submodule) if L[-1].dimension() == s.dimension(): break L.append(s) diff --git a/src/sage/categories/finite_permutation_groups.py b/src/sage/categories/finite_permutation_groups.py index 3f5fcfd1fe7..9269bc8ac1c 100644 --- a/src/sage/categories/finite_permutation_groups.py +++ b/src/sage/categories/finite_permutation_groups.py @@ -104,7 +104,7 @@ class ParentMethods: # - Port features from MuPAD-Combinat, lib/DOMAINS/CATEGORIES/PermutationGroup.mu # - Move here generic code from sage/groups/perm_gps/permgroup.py - def cycle_index(self, parent = None): + def cycle_index(self, parent=None): r""" Return the *cycle index* of ``self``. @@ -274,14 +274,13 @@ def profile_series(self, variable='z'): sage: u = var('u') # optional - sage.symbolic sage: D8.profile_series(u).parent() # optional - sage.symbolic Symbolic Ring - """ from sage.rings.integer_ring import ZZ if isinstance(variable, str): variable = ZZ[variable].gen() cycle_poly = self.cycle_index() - return cycle_poly.expand(2).subs(x0 = 1, x1 = variable) + return cycle_poly.expand(2).subs(x0=1, x1=variable) profile_polynomial = profile_series diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index 1f6b49d2e15..caf76e44893 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -419,7 +419,7 @@ def order_ideal_complement_generators(self, antichain, direction='up'): else: I = self.order_filter(antichain) I_comp = set(self).difference(I) - return set(self.order_ideal_generators(I_comp, direction = direction)) + return set(self.order_ideal_generators(I_comp, direction=direction)) panyushev_complement = order_ideal_complement_generators @@ -1314,7 +1314,7 @@ def birational_rowmotion(self, labelling): l = self.birational_toggle(v, l) return l - def panyushev_orbits(self, element_constructor = set): + def panyushev_orbits(self, element_constructor=set): r""" Return the Panyushev orbits of antichains in ``self``. @@ -1362,21 +1362,21 @@ def panyushev_orbits(self, element_constructor = set): """ # TODO: implement a generic function taking a set and # bijections on this set, and returning the orbits. - AC = set(self.antichains(element_constructor = frozenset)) + AC = set(self.antichains(element_constructor=frozenset)) orbits = [] while AC: A = AC.pop() - orbit = [ A ] + orbit = [A] while True: A = frozenset(self.order_ideal_complement_generators(A)) if A not in AC: break - orbit.append( A ) - AC.remove( A ) - orbits.append([element_constructor(_) for _ in orbit]) + orbit.append(A) + AC.remove(A) + orbits.append([element_constructor(elt) for elt in orbit]) return orbits - def rowmotion_orbits(self, element_constructor = set): + def rowmotion_orbits(self, element_constructor=set): r""" Return the rowmotion orbits of order ideals in ``self``. @@ -1415,8 +1415,9 @@ def rowmotion_orbits(self, element_constructor = set): sage: P.rowmotion_orbits(element_constructor=tuple) [[()]] """ - pan_orbits = self.panyushev_orbits(element_constructor = list) - return [[element_constructor(self.order_ideal(oideal)) for oideal in orbit] for orbit in pan_orbits] + pan_orbits = self.panyushev_orbits(element_constructor=list) + return [[element_constructor(self.order_ideal(oideal)) + for oideal in orbit] for orbit in pan_orbits] def rowmotion_orbits_plots(self): r""" @@ -1446,10 +1447,9 @@ def rowmotion_orbits_plots(self): oiplot = self.order_ideal_plot(oi) orb_plots.append(oiplot) plot_of_orb_plots.append(orb_plots) - return graphics_array(plot_of_orb_plots, ncols = max_orbit_size) - + return graphics_array(plot_of_orb_plots, ncols=max_orbit_size) - def toggling_orbits(self, vs, element_constructor = set): + def toggling_orbits(self, vs, element_constructor=set): r""" Return the orbits of order ideals in ``self`` under the operation of toggling the vertices ``vs[0], vs[1], ...`` @@ -1533,9 +1533,10 @@ def toggling_orbits_plots(self, vs): oiplot = self.order_ideal_plot(oi) orb_plots.append(oiplot) plot_of_orb_plots.append(orb_plots) - return graphics_array(plot_of_orb_plots, ncols = max_orbit_size) + return graphics_array(plot_of_orb_plots, ncols=max_orbit_size) - def panyushev_orbit_iter(self, antichain, element_constructor=set, stop=True, check=True): + def panyushev_orbit_iter(self, antichain, element_constructor=set, + stop=True, check=True): r""" Iterate over the Panyushev orbit of an antichain ``antichain`` of ``self``. diff --git a/src/sage/categories/groupoid.py b/src/sage/categories/groupoid.py index d9a26227995..4c6e3ae6042 100644 --- a/src/sage/categories/groupoid.py +++ b/src/sage/categories/groupoid.py @@ -27,10 +27,9 @@ class Groupoid(CategoryWithParameters): sage: Groupoid(DihedralGroup(3)) Groupoid with underlying set Dihedral group of order 6 as a permutation group - """ - def __init__(self, G = None): + def __init__(self, G=None): """ TESTS:: diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 809ef93e3e1..b921570a63c 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -150,7 +150,7 @@ def _test_inverse(self, **options): tester.assertEqual(x * ~x, self.one()) tester.assertEqual(~x * x, self.one()) - def semidirect_product(self, N, mapping, check = True): + def semidirect_product(self, N, mapping, check=True): r""" The semi-direct product of two groups @@ -162,7 +162,7 @@ def semidirect_product(self, N, mapping, check = True): ... NotImplementedError: semidirect product of General Linear Group of degree 4 over Rational Field and General Linear Group of degree 4 over Rational Field not yet implemented """ - raise NotImplementedError("semidirect product of %s and %s not yet implemented"%(self, N)) + raise NotImplementedError("semidirect product of %s and %s not yet implemented" % (self, N)) def holomorph(self): r""" diff --git a/src/sage/categories/hecke_modules.py b/src/sage/categories/hecke_modules.py index aa2ce2aea7b..88331973496 100644 --- a/src/sage/categories/hecke_modules.py +++ b/src/sage/categories/hecke_modules.py @@ -149,7 +149,7 @@ def _Hom_(self, Y, category): if category is not None and not category.is_subcategory(HeckeModules(self.base_ring())): raise TypeError("%s is not a subcategory of %s"%(category, HeckeModules(self.base_ring()))) from sage.modular.hecke.homspace import HeckeModuleHomspace - return HeckeModuleHomspace(self, Y, category = category) + return HeckeModuleHomspace(self, Y, category=category) class Homsets(HomsetsCategory): """ diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index 266a1cab6fb..e063e388998 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -180,9 +180,9 @@ def lowest_weight_vectors(self): """ return tuple(g for g in self if g.is_lowest_weight()) - def __iter__(self, index_set=None, max_depth = float("inf")): + def __iter__(self, index_set=None, max_depth=float("inf")): """ - Returns the iterator of ``self``. + Return the iterator of ``self``. INPUT: diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index bfd78e8d8a5..1c8cdcd9383 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -580,7 +580,7 @@ class Homset(Set_generic): sage: loads(dumps(H)) == H True """ - def __init__(self, X, Y, category=None, base = None, check=True): + def __init__(self, X, Y, category=None, base=None, check=True): r""" TESTS:: @@ -649,8 +649,8 @@ def __init__(self, X, Y, category=None, base = None, check=True): # See also #15801. base = X.base_ring() - Parent.__init__(self, base = base, - category = category.Endsets() if X is Y else category.Homsets()) + Parent.__init__(self, base=base, + category=category.Endsets() if X is Y else category.Homsets()) def __reduce__(self): """ @@ -1224,7 +1224,8 @@ def reversed(self): sage: type(H.reversed()) """ - return Hom(self.codomain(), self.domain(), category = self.homset_category()) + return Hom(self.codomain(), self.domain(), + category=self.homset_category()) # Really needed??? @@ -1249,7 +1250,8 @@ def __init__(self, X, Y, category=None, check=True, base=None): """ if base is None: base = X.base_ring() - Homset.__init__(self, X, Y, check=check, category=category, base = base) + Homset.__init__(self, X, Y, check=check, category=category, base=base) + def is_Homset(x): """ diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index 161ea71f2b9..79a0b69ce14 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -115,7 +115,7 @@ class HopfAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: TestSuite(C).run() """ - def example(self, G = None): + def example(self, G=None): """ Returns an example of algebra with basis:: @@ -212,7 +212,8 @@ def antipode(self): """ if self.antipode_on_basis is not NotImplemented: # Should give the information that this is an anti-morphism of algebra - return self._module_morphism(self.antipode_on_basis, codomain = self) + return self._module_morphism(self.antipode_on_basis, + codomain=self) elif hasattr(self, "antipode_by_coercion"): return self.antipode_by_coercion diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index 00bdf0a911d..aa96f2b5594 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -59,7 +59,7 @@ def super_categories(self): """ return [Crystals()] - def example(self, n = 3): + def example(self, n=3): """ Return an example of Kirillov-Reshetikhin crystals, as per :meth:`Category.example`. diff --git a/src/sage/categories/magmatic_algebras.py b/src/sage/categories/magmatic_algebras.py index 0a7cd2755a3..ef82ba4319b 100644 --- a/src/sage/categories/magmatic_algebras.py +++ b/src/sage/categories/magmatic_algebras.py @@ -144,7 +144,7 @@ def algebra_generators(self): """ return self.basis() - @abstract_method(optional = True) + @abstract_method(optional=True) def product_on_basis(self, i, j): """ The product of the algebra on the basis (optional). diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 49d91c17049..22f5a6d8f07 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1064,7 +1064,7 @@ def sum_of_monomials(self): A map to Free module generated by {'a', 'b', 'c'} over Rational Field """ # domain = iterables of basis indices of self. - return PoorManMap(self._sum_of_monomials, codomain = self) + return PoorManMap(self._sum_of_monomials, codomain=self) def monomial_or_zero_if_none(self, i): """ @@ -2186,7 +2186,7 @@ def __call_on_basis__(self, **options): sage: H.zero().category_for() Category of finite dimensional vector spaces with basis over Rational Field """ - return self.domain().module_morphism(codomain = self.codomain(), + return self.domain().module_morphism(codomain=self.codomain(), **options) class MorphismMethods: @@ -2307,7 +2307,7 @@ class ElementMethods: with basis. """ - def apply_multilinear_morphism(self, f, codomain = None): + def apply_multilinear_morphism(self, f, codomain=None): r""" Return the result of applying the morphism induced by ``f`` to ``self``. diff --git a/src/sage/categories/poor_man_map.py b/src/sage/categories/poor_man_map.py index 73c8032f065..507705fb9f9 100644 --- a/src/sage/categories/poor_man_map.py +++ b/src/sage/categories/poor_man_map.py @@ -57,7 +57,7 @@ class PoorManMap(sage.structure.sage_object.SageObject): True """ - def __init__(self, function, domain = None, codomain = None, name = None): + def __init__(self, function, domain=None, codomain=None, name=None): """ TESTS:: diff --git a/src/sage/categories/posets.py b/src/sage/categories/posets.py index 6ab5657e929..b09d920c863 100644 --- a/src/sage/categories/posets.py +++ b/src/sage/categories/posets.py @@ -100,7 +100,7 @@ def super_categories(self): """ return [Sets()] - def example(self, choice = None): + def example(self, choice=None): r""" Return examples of objects of ``Posets()``, as per :meth:`Category.example() @@ -241,7 +241,7 @@ def gt(self, x, y): """ return self.lt(y,x) - @abstract_method(optional = True) + @abstract_method(optional=True) def upper_covers(self, x): r""" Return the upper covers of `x`, that is, the elements `y` @@ -254,7 +254,7 @@ def upper_covers(self, x): [6, 15] """ - @abstract_method(optional = True) + @abstract_method(optional=True) def lower_covers(self, x): r""" Return the lower covers of `x`, that is, the elements `y` @@ -267,7 +267,7 @@ def lower_covers(self, x): [3, 5] """ - @abstract_method(optional = True) + @abstract_method(optional=True) def order_ideal(self, elements): r""" Return the order ideal in ``self`` generated by the elements @@ -285,7 +285,7 @@ def order_ideal(self, elements): [0, 1, 2, 3, 4, 5, 6, 7, 8, 10] """ - @abstract_method(optional = True) + @abstract_method(optional=True) def order_filter(self, elements): r""" Return the order filter generated by a list of elements. diff --git a/src/sage/categories/regular_crystals.py b/src/sage/categories/regular_crystals.py index 26cb0540dbc..f5412fe6ab1 100644 --- a/src/sage/categories/regular_crystals.py +++ b/src/sage/categories/regular_crystals.py @@ -93,7 +93,7 @@ def super_categories(self): """ return [Crystals()] - def example(self, n = 3): + def example(self, n=3): """ Returns an example of highest weight crystals, as per :meth:`Category.example`. @@ -493,7 +493,7 @@ def phi(self, i): phi = 0 while x is not None: x = x.f(i) - phi = phi + 1 + phi += 1 return phi def weight(self): @@ -508,7 +508,7 @@ def weight(self): """ return self.Phi() - self.Epsilon() - def demazure_operator_simple(self, i, ring = None): + def demazure_operator_simple(self, i, ring=None): r""" Return the Demazure operator `D_i` applied to ``self``. diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index efac793478e..fc1df0de372 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -417,9 +417,9 @@ def _Hom_(self, Y, category): if category is not None and not category.is_subcategory(Rings()): raise TypeError("%s is not a subcategory of Rings()"%category) if Y not in Rings(): - raise TypeError("%s is not a ring"%Y) + raise TypeError("%s is not a ring" % Y) from sage.rings.homset import RingHomset - return RingHomset(self, Y, category = category) + return RingHomset(self, Y, category=category) # this is already in sage.rings.ring.Ring, # but not all rings descend from that class, diff --git a/src/sage/categories/schemes.py b/src/sage/categories/schemes.py index 45ef3943239..bfd7eb4369b 100644 --- a/src/sage/categories/schemes.py +++ b/src/sage/categories/schemes.py @@ -52,7 +52,7 @@ class Schemes(Category): """ @staticmethod - def __classcall_private__(cls, X = None): + def __classcall_private__(cls, X=None): """ Implement the dispatching ``Schemes(ZZ)`` -> ``Schemes_over_base``. diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index fb8ae29f30f..007401e5474 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -171,7 +171,8 @@ def prod(self, args): assert len(args) > 0, "Cannot compute an empty product in a semigroup" return prod(args[1:], args[0]) - def cayley_graph(self, side="right", simple=False, elements = None, generators = None, connecting_set = None): + def cayley_graph(self, side="right", simple=False, elements=None, + generators=None, connecting_set=None): r""" Return the Cayley graph for this finite semigroup. @@ -791,7 +792,7 @@ def example(self): An example of a (sub)quotient semigroup: a quotient of the left zero semigroup """ from sage.categories.examples.semigroups import QuotientOfLeftZeroSemigroup - return QuotientOfLeftZeroSemigroup(category = self.Subquotients()) + return QuotientOfLeftZeroSemigroup(category=self.Subquotients()) class Quotients(QuotientsCategory): diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 09a57770a3b..4de601e210c 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1162,16 +1162,17 @@ def _test_elements(self, tester=None, **options): # The intention is to raise an exception only if this is # run as a sub-testsuite of a larger testsuite. is_sub_testsuite = (tester is not None) - tester = self._tester(tester = tester, **options) + tester = self._tester(tester=tester, **options) # Or do we want to run the test on some_elements? try: an_element = self.an_element() except EmptySetError: return tester.info("\n Running the test suite of self.an_element()") - TestSuite(an_element).run(verbose = tester._verbose, prefix = tester._prefix+" ", - raise_on_failure = is_sub_testsuite) - tester.info(tester._prefix+" ", newline = False) + TestSuite(an_element).run(verbose=tester._verbose, + prefix=tester._prefix + " ", + raise_on_failure=is_sub_testsuite) + tester.info(tester._prefix + " ", newline=False) def _test_elements_eq_reflexive(self, **options): """ @@ -2682,7 +2683,7 @@ def extra_super_categories(self): """ return [Sets().Facade()] - def example(self, base_ring = None, set = None): + def example(self, base_ring=None, set=None): r""" Return an example of set with multiple realizations, as per :meth:`Category.example`. diff --git a/src/sage/categories/super_hopf_algebras_with_basis.py b/src/sage/categories/super_hopf_algebras_with_basis.py index c0716ed2fc1..4fd09867b45 100644 --- a/src/sage/categories/super_hopf_algebras_with_basis.py +++ b/src/sage/categories/super_hopf_algebras_with_basis.py @@ -55,7 +55,8 @@ def antipode(self): """ if self.antipode_on_basis is not NotImplemented: # Should give the information that this is an anti-morphism of algebra - return self._module_morphism(self.antipode_on_basis, codomain = self) + return self._module_morphism(self.antipode_on_basis, + codomain=self) elif hasattr(self, "antipode_by_coercion"): return self.antipode_by_coercion diff --git a/src/sage/categories/unital_algebras.py b/src/sage/categories/unital_algebras.py index 8d28187d97f..43ffa76d47c 100644 --- a/src/sage/categories/unital_algebras.py +++ b/src/sage/categories/unital_algebras.py @@ -263,7 +263,7 @@ class WithBasis(CategoryWithAxiom_over_base_ring): class ParentMethods: - @abstract_method(optional = True) + @abstract_method(optional=True) def one_basis(self): """ When the one of an algebra with basis is an element of diff --git a/src/sage/categories/vector_spaces.py b/src/sage/categories/vector_spaces.py index 7568c705326..66534879b5a 100644 --- a/src/sage/categories/vector_spaces.py +++ b/src/sage/categories/vector_spaces.py @@ -134,7 +134,7 @@ def super_categories(self): [Category of modules over Rational Field] """ R = self.base_field() - return [Modules(R, dispatch = False)] + return [Modules(R, dispatch=False)] def additional_structure(self): r""" diff --git a/src/sage/categories/weyl_groups.py b/src/sage/categories/weyl_groups.py index 683729405b1..47ca72306f0 100644 --- a/src/sage/categories/weyl_groups.py +++ b/src/sage/categories/weyl_groups.py @@ -495,7 +495,7 @@ def stanley_symmetric_function_as_polynomial(self, max_length=None): if self.is_one(): return R.one() - return R(sum(2**(pieri_factors.stanley_symm_poly_weight(u))*x[u.length()-1] * v.stanley_symmetric_function_as_polynomial(max_length = u.length()) + return R(sum(2**(pieri_factors.stanley_symm_poly_weight(u))*x[u.length()-1] * v.stanley_symmetric_function_as_polynomial(max_length=u.length()) for (u,v) in self.left_pieri_factorizations(max_length) if u != W.one())) @@ -629,14 +629,14 @@ def reflection_to_coroot(self): raise ValueError("{} is not a reflection".format(self)) return rsi.apply_simple_reflection(i, side='left').reflection_to_coroot().simple_reflection(i) - def inversions(self, side = 'right', inversion_type = 'reflections'): + def inversions(self, side='right', inversion_type='reflections'): """ - Returns the set of inversions of ``self``. + Return the set of inversions of ``self``. INPUT: - ``side`` -- 'right' (default) or 'left' - - ``inversion_type`` -- 'reflections' (default), 'roots', or 'coroots'. + - ``inversion_type`` -- 'reflections' (default), 'roots', or 'coroots' OUTPUT: From 0de2c986e8b8252e996b6905348ac64ae268fe20 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 11:35:41 -0700 Subject: [PATCH 298/591] build/pkgs/p_group_cohomology/type: Back to optional --- build/pkgs/p_group_cohomology/type | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/p_group_cohomology/type b/build/pkgs/p_group_cohomology/type index af4d63af86d..134d9bc32d5 100644 --- a/build/pkgs/p_group_cohomology/type +++ b/build/pkgs/p_group_cohomology/type @@ -1 +1 @@ -experimental \ No newline at end of file +optional From d2a9e32565017f43d2476e784fa546d810423ee9 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 9 Aug 2022 13:11:18 -0600 Subject: [PATCH 299/591] i, j initialized off by one this caused an issue where a correct but not minimal log was sometimes returned --- src/sage/groups/generic.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 455e05abd2e..81a8639953e 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -843,7 +843,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i sage: base = G.random_element() sage: order = choice([base.additive_order(), G.order()]) sage: assert order.divides(G.cardinality()) - sage: sol = randrange(order) + sage: sol = randrange(base.additive_order()) sage: elem = sol * base sage: args = (elem, base, order) sage: kwargs = {'operation': '+'} @@ -854,8 +854,8 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i ....: assert lo <= sol <= hi ....: kwargs['bounds'] = (lo, hi) sage: res = discrete_log(*args, **kwargs) - sage: if not res == sol: - ....: print(args, kwargs, G, res, sol) + sage: res == sol + True AUTHORS: @@ -900,7 +900,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i a = mult(a, power(base, -lb)) offset = lb bound = ub - lb - i = 0 # this corrects a bug in which the loop is never entered and i never gets assigned a value + i = -1 # this corrects a bug in which the loop is never entered and i never gets assigned a value for i, (pi, ri) in enumerate(f): gamma = power(base, ord // pi) # pohlig-hellman doesn't work with an incorrect order, and the user might have provided a bad parameter @@ -911,7 +911,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i if not bounds: bound = ord - 1 running_bound = min(bound, pi**ri - 1) - j = 0 + j = -1 for j in range(ri): temp_bound = min(running_bound, pi - 1) h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) From 6fed145aadb0c81a1e1637f2a9081da818d1d8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 9 Aug 2022 21:22:30 +0200 Subject: [PATCH 300/591] details in sf/ --- src/sage/combinat/sf/macdonald.py | 7 ++++--- src/sage/combinat/sf/witt.py | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 3671ae2de8a..d30339bc82d 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -758,7 +758,7 @@ def __init__(self, macdonald): if hasattr(self, "_s_cache"): # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = ModulesWithBasis(self.base_ring()) - self .register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) + self.register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) self._s.register_coercion(SetMorphism(Hom(self, self._s, category), self._self_to_s)) def _s_to_self(self, x): @@ -1010,7 +1010,7 @@ def __init__(self, macdonald): category = ModulesWithBasis(self.base_ring()) phi = self._J.module_morphism(diagonal=self.c2, codomain=self, category=category) - self.register_coercion( phi) + self.register_coercion(phi) self._J.register_coercion(~phi) def scalar_qt_basis(self, part1, part2=None): @@ -1082,7 +1082,7 @@ def __init__(self, macdonald): category = ModulesWithBasis(self.base_ring()) phi = self._P.module_morphism(diagonal=self._P.scalar_qt_basis, codomain=self, category=category) - self.register_coercion( phi) + self.register_coercion(phi) self._P.register_coercion(~phi) class Element(MacdonaldPolynomials_generic.Element): @@ -2027,6 +2027,7 @@ def qt_kostka(lam, mu): return _qt_kostka_cache[(lam,mu)] + # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.combinat.sf.macdonald', 'MacdonaldPolynomial_h', MacdonaldPolynomials_h.Element) diff --git a/src/sage/combinat/sf/witt.py b/src/sage/combinat/sf/witt.py index 1dadb90ffdf..2f942af97f3 100644 --- a/src/sage/combinat/sf/witt.py +++ b/src/sage/combinat/sf/witt.py @@ -1022,7 +1022,7 @@ def __init_extra__(self): # the elements of the Witt basis with respect to the powersum basis self._p_inverse_transition_matrices = {} - self .register_coercion(self._p._module_morphism(self._p_to_w_on_basis, codomain=self)) + self.register_coercion(self._p._module_morphism(self._p_to_w_on_basis, codomain=self)) from sage.rings.rational_field import RationalField if self.base_ring().has_coerce_map_from(RationalField): self._p.register_coercion(self._module_morphism(self._w_to_p_on_basis, codomain=self._p)) @@ -1054,7 +1054,7 @@ def __init_extra__(self): # cache for transition matrices which contain the coordinates of # the elements of the Witt basis with respect to the homogeneous basis self._h_inverse_transition_matrices = {} - self .register_coercion(self._h._module_morphism(self._h_to_w_on_basis, codomain=self)) + self.register_coercion(self._h._module_morphism(self._h_to_w_on_basis, codomain=self)) self._h.register_coercion(self._module_morphism(self._w_to_h_on_basis, codomain=self._h)) if self._friendly is None: self._friendly = self._h @@ -1076,7 +1076,7 @@ def __init_extra__(self): # cache for transition matrices which contain the coordinates of # the elements of the Witt basis with respect to the elementary basis self._e_inverse_transition_matrices = {} - self .register_coercion(self._e._module_morphism(self._e_to_w_on_basis, codomain=self)) + self.register_coercion(self._e._module_morphism(self._e_to_w_on_basis, codomain=self)) self._e.register_coercion(self._module_morphism(self._w_to_e_on_basis, codomain=self._e)) if self._friendly is None: self._friendly = self._e From 4417ed23303f82b2a872361a26b7defe7ad92bc1 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Sat, 6 Aug 2022 15:02:27 -0700 Subject: [PATCH 301/591] Fix trac 34292 --- src/sage/algebras/group_algebra.py | 10 ++++++++++ src/sage/structure/coerce.pyx | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/group_algebra.py b/src/sage/algebras/group_algebra.py index 2a903447f3d..2ee63cd6f8a 100644 --- a/src/sage/algebras/group_algebra.py +++ b/src/sage/algebras/group_algebra.py @@ -172,6 +172,14 @@ def _coerce_map_from_(self, S): From: Algebra of Cyclic group of order 3 as a permutation group over Integer Ring To: Algebra of Dihedral group of order 6 as a permutation group over Rational Field + sage: H = PermutationGroup([ [(1,2), (3,4)], [(5,6,7),(12,14,18)] ]) + sage: kH = H.algebra(GF(2)) + sage: [a, b] = kH.gens() + sage: x = kH(a) + kH(b) + kH.one(); print(x) + () + (5,6,7)(12,14,18) + (1,2)(3,4) + sage: x*x #checks :trac:34292 + (5,7,6)(12,18,14) + As expected, there is no coercion when restricting the field:: @@ -184,6 +192,8 @@ def _coerce_map_from_(self, S): sage: ZG = G.algebra(ZZ, category=AdditiveMagmas()) sage: ZG.has_coerce_map_from(G) False + + """ G = self.basis().keys() K = self.base_ring() diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 6cf8ec78bae..9f12c6b0ec9 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -1326,9 +1326,10 @@ cdef class CoercionModel: return x_elt,y_elt elif x_elt._parent == y_elt._parent: # TODO: Non-uniqueness of parents strikes again! - y_elt = parent(x_elt)(y_elt) + x_elt = parent(y_elt)(x_elt) if x_elt._parent is y_elt._parent: return x_elt,y_elt + self._coercion_error(x, x_map, x_elt, y, y_map, y_elt) cdef bint x_numeric = isinstance(x, (int, long, float, complex)) From e19ec8e7c8ba530e56a49b33c98cc58b54ab9441 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 9 Aug 2022 15:25:33 -0700 Subject: [PATCH 302/591] Revert changes --- src/sage/structure/coerce.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 9f12c6b0ec9..417923dad9a 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -1326,7 +1326,7 @@ cdef class CoercionModel: return x_elt,y_elt elif x_elt._parent == y_elt._parent: # TODO: Non-uniqueness of parents strikes again! - x_elt = parent(y_elt)(x_elt) + y_elt = parent(x_elt)(y_elt) if x_elt._parent is y_elt._parent: return x_elt,y_elt From f8ad044f4197e4b5087d54bc7a917eff9fda5979 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 15:35:10 -0700 Subject: [PATCH 303/591] ConvexSet_base.representative_point: New --- src/sage/geometry/convex_set.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index 604df756af0..74eabb91bf6 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -622,6 +622,24 @@ def relative_interior(self): return self raise NotImplementedError + @cached_method + def representative_point(self): + """ + Return a "generic" point of ``self``. + + OUTPUT: + + A point in the relative interior of ``self`` as a coordinate vector. + + EXAMPLES:: + + sage: C = Cone([[1, 2, 0], [2, 1, 0]]) + sage: C.representative_point() + (1, 1, 0) + """ + affine_basis = self.an_affine_basis() + return sum(affine_basis) / len(affine_basis) + def _test_convex_set(self, tester=None, **options): """ Run some tests on the methods of :class:`ConvexSet_base`. From 8ba6fcd652cc84a5d22777f5781f1d02f33b243a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 15:36:02 -0700 Subject: [PATCH 304/591] Polyhedron_base1.an_affine_basis: Implement for the unbounded pointed case --- src/sage/geometry/cone.py | 14 ++++------- src/sage/geometry/polyhedron/base1.py | 34 +++++++++++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index d9d57b3b12a..bbdfe3e3f3b 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -3533,21 +3533,17 @@ def an_affine_basis(self): sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.an_affine_basis() - Traceback (most recent call last): - ... - NotImplementedError: this function is not implemented for unbounded polyhedra + [(0, 0), (1, 0), (0, 1)] sage: ray = Cone([(1, 1)]) sage: ray.an_affine_basis() - Traceback (most recent call last): - ... - NotImplementedError: this function is not implemented for unbounded polyhedra + [(0, 0), (1, 1)] sage: line = Cone([(1,0), (-1,0)]) - sage: line.an_affine_basis() + sage: line.an_affine_basis() # FIXME Traceback (most recent call last): ... - NotImplementedError: this function is not implemented for unbounded polyhedra + NameError: free variable 'vertex' referenced before assignment in enclosing scope """ - return self.polyhedron().an_affine_basis() + return [vector(v) for v in self.polyhedron().an_affine_basis()] @cached_method def strict_quotient(self): diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index e36867647f5..3cf14d9ad88 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -455,16 +455,23 @@ def an_affine_basis(self): A vertex at (4, 1, 3, 5, 2), A vertex at (4, 2, 5, 3, 1)] - The method is not implemented for unbounded polyhedra:: + For unbounded polyhedra, the result may contain arbitrary points of ``self``, + not just vertices:: - sage: p = Polyhedron(vertices=[(0,0)],rays=[(1,0),(0,1)]) + sage: p = Polyhedron(vertices=[(0, 0)], rays=[(1,0), (0,1)]) sage: p.an_affine_basis() + [A vertex at (0, 0), (1, 0), (0, 1)] + sage: p = Polyhedron(vertices=[(2, 1)], rays=[(1,0), (0,1)]) + sage: p.an_affine_basis() + [A vertex at (2, 1), (3, 1), (2, 2)] + sage: p = Polyhedron(vertices=[(2, 1)], rays=[(1,0)], lines=[(0,1)]) + sage: p.an_affine_basis() # FIXME Traceback (most recent call last): ... - NotImplementedError: this function is not implemented for unbounded polyhedra + NameError: free variable 'vertex' referenced before assignment in enclosing scope """ - if not self.is_compact(): - raise NotImplementedError("this function is not implemented for unbounded polyhedra") + ## if not self.is_compact(): + ## raise NotImplementedError("this function is not implemented for unbounded polyhedra") chain = self.a_maximal_chain()[1:] # we exclude the empty face chain_indices = [face.ambient_V_indices() for face in chain] @@ -472,25 +479,32 @@ def an_affine_basis(self): # We use in the following that elements in ``chain_indices`` are sorted lists # of V-indices. - # Thus for each two faces we can easily find the first vertex that differs. + # Thus for each two faces we can easily find the first Vrep that differs. for dim, face in enumerate(chain_indices): if dim == 0: - # Append the vertex. + # Append the V-index. basis_indices.append(face[0]) continue prev_face = chain_indices[dim-1] for i in range(len(prev_face)): if prev_face[i] != face[i]: - # We found a vertex that ``face`` has, but its facet does not. + # We found a Vrep that ``face`` has, but its facet does not. basis_indices.append(face[i]) break else: # no break # ``prev_face`` contains all the same vertices as ``face`` until now. - # But ``face`` is guaranteed to contain one more vertex (at least). + # But ``face`` is guaranteed to contain one more Vrep (at least). basis_indices.append(face[len(prev_face)]) - return [self.Vrepresentation()[i] for i in basis_indices] + Vreps = [self.Vrepresentation()[i] for i in basis_indices] + if all(vrep.is_vertex() for vrep in Vreps): + return Vreps + for vrep in Vreps: + if vrep.is_vertex(): + vertex = vrep + return [vrep if vrep.is_vertex() else vertex.vector() + vrep.vector() + for vrep in Vreps] @abstract_method def a_maximal_chain(self): From f0708e787786d25316b623a0f06d6b5b869c523b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 15:45:45 -0700 Subject: [PATCH 305/591] RelativeInterior.representative_point: New --- src/sage/geometry/relative_interior.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sage/geometry/relative_interior.py b/src/sage/geometry/relative_interior.py index 8f463170aad..262c927a08a 100644 --- a/src/sage/geometry/relative_interior.py +++ b/src/sage/geometry/relative_interior.py @@ -276,6 +276,22 @@ def _some_elements_(self): if p in self: yield p + def representative_point(self): + """ + Return a "generic" point of ``self``. + + OUTPUT: + + A point in ``self`` (thus, in the relative interior of ``self``) as a coordinate vector. + + EXAMPLES:: + + sage: C = Cone([[1, 2, 0], [2, 1, 0]]) + sage: C.relative_interior().representative_point() + (1, 1, 0) + """ + return self._polyhedron.representative_point() + def _repr_(self): r""" Return a description of ``self``. From 5f3a8ed7d40a6d22beb1212e7ade912856f4d394 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 15:46:08 -0700 Subject: [PATCH 306/591] ConvexSet_base._some_elements_: Provide a default implementation --- src/sage/geometry/convex_set.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index 74eabb91bf6..695f118311b 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -764,7 +764,6 @@ def some_elements(self): raise NotImplementedError return list(self._some_elements_()) - @abstract_method(optional=True) def _some_elements_(self): r""" Generate some points of ``self``. @@ -775,11 +774,12 @@ def _some_elements_(self): sage: from sage.geometry.convex_set import ConvexSet_base sage: C = ConvexSet_base() - sage: C._some_elements_(C) + sage: list(C._some_elements_()) Traceback (most recent call last): ... TypeError: 'NotImplementedType' object is not callable """ + yield self.representative_point() @abstract_method(optional=True) def cartesian_product(self, other): From 383d2733753c531d29005ba331548a0fdede4ca3 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 9 Aug 2022 15:52:16 -0700 Subject: [PATCH 307/591] Change copy and fix _coerce_map_from --- src/sage/algebras/group_algebra.py | 20 +++++++++++++++----- src/sage/groups/perm_gps/permgroup.py | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/sage/algebras/group_algebra.py b/src/sage/algebras/group_algebra.py index 2ee63cd6f8a..6821a64f68f 100644 --- a/src/sage/algebras/group_algebra.py +++ b/src/sage/algebras/group_algebra.py @@ -156,9 +156,16 @@ def _coerce_map_from_(self, S): sage: QG = G.algebra(QQ) sage: ZG = G.algebra(ZZ) sage: ZG.coerce_map_from(H) - Coercion map: + Composite map: From: Cyclic group of order 3 as a permutation group To: Algebra of Dihedral group of order 6 as a permutation group over Integer Ring + Defn: Coercion map: + From: Cyclic group of order 3 as a permutation group + To: Dihedral group of order 6 as a permutation group + then + Coercion map: + From: Dihedral group of order 6 as a permutation group + To: Algebra of Dihedral group of order 6 as a permutation group over Integer Ring sage: QG.coerce_map_from(ZG) Generic morphism: From: Algebra of Dihedral group of order 6 as a permutation group over Integer Ring @@ -192,17 +199,20 @@ def _coerce_map_from_(self, S): sage: ZG = G.algebra(ZZ, category=AdditiveMagmas()) sage: ZG.has_coerce_map_from(G) False - - """ G = self.basis().keys() K = self.base_ring() - if G.has_coerce_map_from(S): + G_coercion = G.coerce_map_from(S) + if G_coercion is not None: from sage.categories.groups import Groups # No coercion for additive groups because of ambiguity of + # being the group action or addition of a new term. - return self.category().is_subcategory(Groups().Algebras(K)) + if not self.category().is_subcategory(Groups().Algebras(K)): + return None + if S is G: + return True + return self.coerce_map_from(G) * G_coercion if S in Sets.Algebras: S_K = S.base_ring() diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 49089346995..459129c4ac8 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -532,6 +532,20 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, _libgap = None + def __copy__(self): + r""" + Return a "copy" of ``self`` by returning ``self``. + + EXAMPLES:: + + sage: G = PermutationGroup(((1,2), (4,5))) + sage: copy(G) is G + True + """ + return self + + __deepcopy__ = __copy__ + def construction(self): """ Return the construction of ``self``. From bfe56c6c6675444d5c767772220b94649163ca1e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 9 Aug 2022 16:02:01 -0700 Subject: [PATCH 308/591] Polyhedron_base1.an_affine_basis: Implement for the non-pointed case --- src/sage/geometry/cone.py | 6 ++---- src/sage/geometry/polyhedron/base1.py | 13 ++++--------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index bbdfe3e3f3b..09b0f3cd1c3 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -3538,10 +3538,8 @@ def an_affine_basis(self): sage: ray.an_affine_basis() [(0, 0), (1, 1)] sage: line = Cone([(1,0), (-1,0)]) - sage: line.an_affine_basis() # FIXME - Traceback (most recent call last): - ... - NameError: free variable 'vertex' referenced before assignment in enclosing scope + sage: line.an_affine_basis() + [(1, 0), (0, 0)] """ return [vector(v) for v in self.polyhedron().an_affine_basis()] diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index 3cf14d9ad88..7a404a5097f 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -465,14 +465,9 @@ def an_affine_basis(self): sage: p.an_affine_basis() [A vertex at (2, 1), (3, 1), (2, 2)] sage: p = Polyhedron(vertices=[(2, 1)], rays=[(1,0)], lines=[(0,1)]) - sage: p.an_affine_basis() # FIXME - Traceback (most recent call last): - ... - NameError: free variable 'vertex' referenced before assignment in enclosing scope + sage: p.an_affine_basis() + [(2, 1), A vertex at (2, 0), (3, 0)] """ - ## if not self.is_compact(): - ## raise NotImplementedError("this function is not implemented for unbounded polyhedra") - chain = self.a_maximal_chain()[1:] # we exclude the empty face chain_indices = [face.ambient_V_indices() for face in chain] basis_indices = [] @@ -482,8 +477,8 @@ def an_affine_basis(self): # Thus for each two faces we can easily find the first Vrep that differs. for dim, face in enumerate(chain_indices): if dim == 0: - # Append the V-index. - basis_indices.append(face[0]) + # Append the V-indices of the minimal face. + basis_indices.extend(face[:]) continue prev_face = chain_indices[dim-1] From f11c1a3bcb10ff99fd4ddc46f33140c3ed775c93 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Tue, 9 Aug 2022 17:55:27 -0700 Subject: [PATCH 309/591] Add check for positivity of rank --- src/sage/categories/enumerated_sets.py | 10 ++++++++++ src/sage/sets/family.py | 5 +++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 563a8025e6d..d85d175c818 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -650,11 +650,21 @@ def _unrank_from_iterator(self, r): sage: C = FiniteEnumeratedSets().example() sage: C.unrank(2) # indirect doctest 3 + + TESTS:: + + sage: ZZ._unrank_from_iterator(-1) + Traceback (most recent call last): + ... + ValueError: the value must be greater than or equal to 0 sage: C._unrank_from_iterator(5) Traceback (most recent call last): ... ValueError: the value must be between 0 and 2 inclusive + """ + if r < 0: + raise ValueError("the value must be greater than or equal to 0") counter = 0 for u in self: if counter == r: diff --git a/src/sage/sets/family.py b/src/sage/sets/family.py index 453d427a220..7ba1d9edf7e 100644 --- a/src/sage/sets/family.py +++ b/src/sage/sets/family.py @@ -1346,7 +1346,8 @@ def __setstate__(self, state): class EnumeratedFamily(LazyFamily): r""" :class:`EnumeratedFamily` turns an enumerated set ``c`` into a family - indexed by the set `\{0,\dots, |c|-1\}` or ``ZZ``. + indexed by the set `\{0,\dots, |c|-1\}` (or ``NN`` if `|c|` is + countably infinite). Instances should be created via the :func:`Family` factory. See its documentation for examples and tests. @@ -1374,7 +1375,7 @@ def __init__(self, enumset): True sage: Family(Permutations()).keys() Non negative integers - sage: type(Family(ZZ)) + sage: type(Family(NN)) """ if enumset.cardinality() == Infinity: From dc2e766576a5a536682abf3168eac8e6603a6e98 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Wed, 10 Aug 2022 11:23:51 +0900 Subject: [PATCH 310/591] Replace lazy_import with normal import --- src/sage/docs/{instancedoc.pyx => instancedoc.py} | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) rename src/sage/docs/{instancedoc.pyx => instancedoc.py} (95%) diff --git a/src/sage/docs/instancedoc.pyx b/src/sage/docs/instancedoc.py similarity index 95% rename from src/sage/docs/instancedoc.pyx rename to src/sage/docs/instancedoc.py index 681fbf767bd..e24368e4943 100644 --- a/src/sage/docs/instancedoc.pyx +++ b/src/sage/docs/instancedoc.py @@ -116,5 +116,7 @@ # https://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.lazy_import import lazy_import -lazy_import('sage.misc.instancedoc', 'instancedoc', deprecation=33763) +from sage.misc.superseded import deprecation +deprecation(33763, 'This module is deprecated. Use "sage.misc.instancedoc" instead.') + +from sage.misc.instancedoc import instancedoc From 07682a6c737d8d6b024bb646520901db1bab2c96 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 9 Aug 2022 22:23:22 -0600 Subject: [PATCH 311/591] made lambda test not randomly fail --- src/sage/groups/generic.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 81a8639953e..40fb7cc6fe5 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -853,9 +853,13 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i ....: hi = randrange(sol+1, 2*order) ....: assert lo <= sol <= hi ....: kwargs['bounds'] = (lo, hi) - sage: res = discrete_log(*args, **kwargs) - sage: res == sol - True + sage: try: + ....: res = discrete_log(*args, **kwargs) + ....: except ValueError: + ....: # lambda can fail randomly + ....: assert kwargs['algorithm'] == 'lambda' + ....: else: + ....: assert res == sol AUTHORS: From 63684ec39f0ef606c18ec49c45c9242b8eb2b303 Mon Sep 17 00:00:00 2001 From: Julien Grijalva Date: Tue, 9 Aug 2022 22:25:13 -0600 Subject: [PATCH 312/591] added to authors list --- src/sage/groups/generic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 40fb7cc6fe5..cb2da5d597b 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -865,6 +865,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i - William Stein and David Joyner (2005-01-05) - John Cremona (2008-02-29) rewrite using ``dict()`` and make generic + - Julien Grijalva (2022-08-09) rewrite to make more generic, more algorithm options, and more effective use of bounds """ from operator import mul, add, pow power = mul if operation in addition_names else pow From 80e34789a1507c32f0cd71d35e49ed3b23440354 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 10 Aug 2022 13:11:39 +0200 Subject: [PATCH 313/591] fix offset of remainder --- .../rings/polynomial/laurent_polynomial.pyx | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index ae56110610d..eb603944563 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1341,8 +1341,8 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): @coerce_binop def quo_rem(self, right_r): """ - Attempts to divide ``self`` by ``right`` and returns a quotient and - a remainder. + Attempts to divide ``self`` by ``right`` and returns a quotient ``q``and + a remainder ``r`` such that ``self = q*other + r``. EXAMPLES:: @@ -1351,11 +1351,24 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): (t^-2 + 1 + t^2, 0) sage: (t^-2 + 3 + t).quo_rem(t^-4) (t^2 + 3*t^4 + t^5, 0) - sage: (t^-2 + 3 + t).quo_rem(t^-4 + t) - (0, 1 + 3*t^2 + t^3) + + sage: num, den = t^-2 + t, t^-2 + 1 + sage: q, r = num.quo_rem(den) + sage: num == q * den + r + True + + TESTS: + + Check that :trac:`34330` is fixed:: + + sage: num, den = t^-2 + 3 + t, t^-4 + t + sage: q, r = num.quo_rem(den); q, r + (0, t^-2 + 3 + t) + sage: num == q * den + r + True """ cdef LaurentPolynomial_univariate right = right_r - q,r = self.__u.quo_rem(right.__u) + q, r = self.__u.quo_rem(right.__u) cdef LaurentPolynomial_univariate ql, qr ql = self._new_c() ql.__u = q @@ -1363,9 +1376,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ql.__normalize() qr = self._new_c() qr.__u = r - qr.__n = 0 + qr.__n = self.__n qr.__normalize() - return (ql, qr) + return ql, qr cpdef _richcmp_(self, right_r, int op): r""" @@ -3726,4 +3739,3 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): if new_ring is not None: return new_ring(ans) return ans - From 67c7a1804bd1354773b7ac5c1f249a8267545edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 10 Aug 2022 13:18:03 +0200 Subject: [PATCH 314/591] E251 in geometry/ and manifolds/ --- src/sage/geometry/cone.py | 4 ++-- .../geometry/hyperplane_arrangement/plot.py | 6 +++--- src/sage/geometry/lattice_polytope.py | 4 ++-- src/sage/geometry/polyhedron/base.py | 17 +++++++++-------- src/sage/geometry/polyhedron/base3.py | 2 +- src/sage/geometry/pseudolines.py | 5 ++--- src/sage/geometry/triangulation/element.py | 18 +++++++----------- .../triangulation/point_configuration.py | 5 ++--- src/sage/manifolds/differentiable/curve.py | 4 +--- .../differentiable/degenerate_submanifold.py | 8 ++++---- src/sage/manifolds/differentiable/metric.py | 4 +--- 11 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index d9d57b3b12a..18e20e4d841 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -2602,7 +2602,7 @@ def ConeFace(atoms, facets): self._face_lattice = lattice_from_incidences( atom_to_facets, facet_to_atoms, ConeFace, - key = id(self)) + key=id(self)) else: # Get face lattice as a sublattice of the ambient one allowed_indices = frozenset(self._ambient_ray_indices) @@ -2642,7 +2642,7 @@ def ConeFace(atoms, facets): L.add_edge(face_to_index[face], next_index) D = {i:f for i,f in enumerate(faces)} L.relabel(D) - self._face_lattice = FinitePoset(L, faces, key = id(self)) + self._face_lattice = FinitePoset(L, faces, key=id(self)) return self._face_lattice # Internally we use this name for a uniform behaviour of cones and fans. diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index 02028e13297..bf2455a0ceb 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -406,13 +406,13 @@ def plot_hyperplane(hyperplane, **kwds): ranges_set = True ranges = kwds.pop('ranges') else: - ranges_set = False # give default values below + ranges_set = False # give default values below # the extra keywords have now been handled # now create the plot - if hyperplane.dimension() == 0: # a point on a line + if hyperplane.dimension() == 0: # a point on a line x, = hyperplane.A() d = hyperplane.b() - p = point((d/x,0), size = pt_size, **kwds) + p = point((d/x,0), size=pt_size, **kwds) if has_hyp_label: if not has_offset: label_offset = 0.1 diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index c7c53a65045..e08bc09a835 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -2020,7 +2020,7 @@ def LPFace(vertices, facets): ambient_facet_indices=facets) return lattice_from_incidences( - vertex_to_facets, facet_to_vertices, LPFace, key = id(self)) + vertex_to_facets, facet_to_vertices, LPFace, key=id(self)) else: # Get face lattice as a sublattice of the ambient one allowed_indices = frozenset(self._ambient_vertex_indices) @@ -2059,7 +2059,7 @@ def LPFace(vertices, facets): L.add_edge(face_to_index[face], next_index) D = {i:f for i,f in enumerate(faces)} L.relabel(D) - return FinitePoset(L, faces, key = id(self)) + return FinitePoset(L, faces, key=id(self)) def faces(self, dim=None, codim=None): r""" diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 576e073a825..d001cccab06 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -1191,15 +1191,16 @@ def _polymake_init_(self): polymake_class = "Polytope<{}>".format(polymake_field) if self.is_empty(): # Polymake 3.1 cannot enter an empty polyhedron using - # FACETS and AFFINE_HULL. Use corresponding input properties instead. + # FACETS and AFFINE_HULL. + # Use corresponding input properties instead. # https://forum.polymake.org/viewtopic.php?f=8&t=545 return polymake.new_object(polymake_class, INEQUALITIES=self.inequalities_list(), EQUATIONS=self.equations_list()) - else: - return polymake.new_object(polymake_class, - FACETS=self.inequalities_list(), - AFFINE_HULL=self.equations_list(), - VERTICES= [ [1] + v for v in self.vertices_list() ] \ - + [ [0] + r for r in self.rays_list() ], - LINEALITY_SPACE=[ [0] + l for l in self.lines_list() ]) + + return polymake.new_object(polymake_class, + FACETS=self.inequalities_list(), + AFFINE_HULL=self.equations_list(), + VERTICES=[[1] + v for v in self.vertices_list()] \ + + [[0] + r for r in self.rays_list()], + LINEALITY_SPACE=[[0] + l for l in self.lines_list()]) diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index 0b85c4f944c..f0bc13bb116 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -369,7 +369,7 @@ def _test_combinatorial_polyhedron(self, tester=None, **options): tester.info("\n Running the test suite of self.combinatorial_polyhedron()") TestSuite(self.combinatorial_polyhedron()).run(verbose=tester._verbose, prefix=tester._prefix+" ") - tester.info(tester._prefix+" ", newline = False) + tester.info(tester._prefix + " ", newline=False) def face_generator(self, face_dimension=None, algorithm=None, **kwds): r""" diff --git a/src/sage/geometry/pseudolines.py b/src/sage/geometry/pseudolines.py index 642a5c4b8aa..c579637da41 100644 --- a/src/sage/geometry/pseudolines.py +++ b/src/sage/geometry/pseudolines.py @@ -168,7 +168,7 @@ class PseudolineArrangement: - def __init__(self, seq, encoding = "auto"): + def __init__(self, seq, encoding "auto"): r""" Creates an arrangement of pseudolines. @@ -463,8 +463,7 @@ def show(self, **args): L += text(str(i), (0, l[0][1]+.3), horizontal_alignment="right") L += text(str(i), (x+2, l[-1][1]+.3), horizontal_alignment="left") - return L.show(axes = False, **args) - + return L.show(axes=False, **args) def __repr__(self): r""" diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index cf58a76187b..ddb3b254163 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -193,23 +193,19 @@ def triangulation_render_3d(triangulation, **kwds): exterior_triangs = [l for l in all_triangs if l not in interior_triangs] plot_interior_triangs = \ - sum([ polygon3d([coord[t[0]], coord[t[1]], coord[t[2]]], - texture = triang_int, **kwds) - for t in interior_triangs ]) + sum([polygon3d([coord[t[0]], coord[t[1]], coord[t[2]]], + texture=triang_int, **kwds) + for t in interior_triangs]) plot_exterior_triangs = \ - sum([ polygon3d([coord[t[0]], coord[t[1]], coord[t[2]]], - texture = triang_ext, **kwds) - for t in exterior_triangs ]) + sum([polygon3d([coord[t[0]], coord[t[1]], coord[t[2]]], + texture=triang_ext, **kwds) + for t in exterior_triangs]) - return \ - plot_points + \ + return plot_points + \ plot_interior_lines + plot_exterior_lines + \ plot_interior_triangs + plot_exterior_triangs - - - ######################################################################## class Triangulation(Element): """ diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index 0efde128726..8d05c3bcb19 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -1377,8 +1377,7 @@ def secondary_polytope(self): #change the next line to only take the regular triangulations, #since they are the vertices of the secondary polytope anyway. l = self.triangulations_list() - return Polyhedron(vertices = [x.gkz_phi() for x in l]) - + return Polyhedron(vertices=[x.gkz_phi() for x in l]) def circuits_support(self): r""" @@ -2019,7 +2018,7 @@ def facets_of_simplex(simplex): # construct the initial simplex if point_order_is_given: - simplices = [frozenset(self.contained_simplex(large=False, point_order = point_order))] + simplices = [frozenset(self.contained_simplex(large=False, point_order=point_order))] else: simplices = [frozenset(self.contained_simplex(large=True))] for s in simplices[0]: diff --git a/src/sage/manifolds/differentiable/curve.py b/src/sage/manifolds/differentiable/curve.py index cf5f5fd754b..ca7cef3f626 100644 --- a/src/sage/manifolds/differentiable/curve.py +++ b/src/sage/manifolds/differentiable/curve.py @@ -965,11 +965,9 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, return self._graphics(plot_curve, ambient_coords, thickness=thickness, - aspect_ratio=aspect_ratio, color= color, + aspect_ratio=aspect_ratio, color=color, style=style, label_axes=label_axes) - - def _graphics(self, plot_curve, ambient_coords, thickness=1, aspect_ratio='automatic', color='red', style='-', label_axes=True): diff --git a/src/sage/manifolds/differentiable/degenerate_submanifold.py b/src/sage/manifolds/differentiable/degenerate_submanifold.py index 1a8db5f8aa9..5d5ebb3de0f 100644 --- a/src/sage/manifolds/differentiable/degenerate_submanifold.py +++ b/src/sage/manifolds/differentiable/degenerate_submanifold.py @@ -1200,14 +1200,14 @@ def shape_operator(self, screen=None): T = T.along(im) except ValueError: pass - T.set_name("A^*", latex_name = r'A^\ast') + T.set_name("A^*", latex_name=r'A^\ast') A = TangentTensor(T, im) self._shape_operator[screen._name] = A return A def gauss_curvature(self, screen=None): r""" - Gauss curvature is the product of all eigenfunctions of the shape operator. + Gauss curvature is the product of all eigenfunctions of the shape operator. INPUT: @@ -1245,8 +1245,8 @@ def gauss_curvature(self, screen=None): """ if self._ambient._dim-self._dim != 1: - raise ValueError("'gauss_curvature' is defined"+ - " only for hypersurfaces.") + raise ValueError("'gauss_curvature' is defined" + " only for hypersurfaces.") if screen is None: screen = self.default_screen() if screen._name not in self._gauss_curvature: diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 686af0d3505..f2e6478d07c 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -1220,15 +1220,13 @@ def weyl(self, name=None, latex_name=None): 3-dimensional differentiable manifold H^3 sage: C == 0 True - """ if self._weyl is None: n = self._ambient_domain.dimension() if n < 3: raise ValueError("the Weyl tensor is not defined for a " + "manifold of dimension n <= 2") - delta = self._domain.tangent_identity_field(dest_map= - self._vmodule._dest_map) + delta = self._domain.tangent_identity_field(dest_map=self._vmodule._dest_map) riem = self.riemann() ric = self.ricci() rscal = self.ricci_scalar() From e4479ed6b72f2e4391559877abd283eb3633556f Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 10 Aug 2022 13:56:54 +0200 Subject: [PATCH 315/591] fix missing space --- src/sage/rings/polynomial/laurent_polynomial.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index eb603944563..67650c76158 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1341,8 +1341,8 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): @coerce_binop def quo_rem(self, right_r): """ - Attempts to divide ``self`` by ``right`` and returns a quotient ``q``and - a remainder ``r`` such that ``self = q*other + r``. + Attempts to divide ``self`` by ``right`` and returns a quotient + ``q`` and a remainder ``r`` such that ``self = q*other + r``. EXAMPLES:: From 250ee345fc32f6d1ad9590027d2563ee862630de Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Wed, 10 Aug 2022 08:13:32 -0700 Subject: [PATCH 316/591] Remove TESTS block --- src/sage/categories/enumerated_sets.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index d85d175c818..a556c4f3d2b 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -650,17 +650,14 @@ def _unrank_from_iterator(self, r): sage: C = FiniteEnumeratedSets().example() sage: C.unrank(2) # indirect doctest 3 - - TESTS:: - - sage: ZZ._unrank_from_iterator(-1) - Traceback (most recent call last): - ... - ValueError: the value must be greater than or equal to 0 sage: C._unrank_from_iterator(5) Traceback (most recent call last): ... ValueError: the value must be between 0 and 2 inclusive + sage: ZZ._unrank_from_iterator(-1) + Traceback (most recent call last): + ... + ValueError: the value must be greater than or equal to 0 """ if r < 0: From e6f16a7a60867a855752fe17cde5f2526bd980f2 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Wed, 10 Aug 2022 08:47:38 -0700 Subject: [PATCH 317/591] Remove blankline --- src/sage/structure/coerce.pyx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 417923dad9a..6cf8ec78bae 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -1329,7 +1329,6 @@ cdef class CoercionModel: y_elt = parent(x_elt)(y_elt) if x_elt._parent is y_elt._parent: return x_elt,y_elt - self._coercion_error(x, x_map, x_elt, y, y_map, y_elt) cdef bint x_numeric = isinstance(x, (int, long, float, complex)) From 573ff69471b3939d3fe6c8edc2239f39a76db34e Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Wed, 10 Aug 2022 17:50:54 +0200 Subject: [PATCH 318/591] redesign LazyCauchyProductSeries._div_ for the exact case --- src/sage/rings/lazy_series.py | 129 ++++++++++++------ .../rings/polynomial/laurent_polynomial.pyx | 28 ++-- 2 files changed, 111 insertions(+), 46 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index a35d41be998..d99ca3f777d 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -r""" -Lazy Series +r"""Lazy Series A lazy series is a series whose coefficients are computed on demand. Therefore, unlike the usual Laurent/power/etc. series in Sage, @@ -57,6 +56,13 @@ sage: g = (f + f^-1)*(f - f^-1); g 4*z + 6*z^2 + 8*z^3 + 19*z^4 + 38*z^5 + 71*z^6 + O(z^7) +We call lazy power series whose coefficients are known to be +eventually constant 'exact'. In some cases, computations with such +series are much faster. Moreover, these are the series where +equality can be decided. For example:: + + sage: f = 1/(1 - z) + We can change the base ring:: sage: h = g.change_ring(QQ) @@ -319,12 +325,12 @@ def truncate(self, d): sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: alpha = 1/(1-z) sage: alpha - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + 1 + z + z^2 + O(z^3) sage: beta = alpha.truncate(5) sage: beta 1 + z + z^2 + z^3 + z^4 sage: alpha - beta - z^5 + z^6 + O(z^7) + z^5 + z^6 + z^7 + O(z^8) sage: M = L(lambda n: n, valuation=0); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: M.truncate(4) @@ -2021,14 +2027,14 @@ class LazyCauchyProductSeries(LazyModuleElement): sage: L. = LazyLaurentSeriesRing(ZZ) sage: f = 1 / (1 - z) sage: f - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + 1 + z + z^2 + O(z^3) sage: f * (1 - z) - 1 + O(z^7) + 1 sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) sage: f = 1 / (1 - z) sage: f - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + 1 + z + z^2 + O(z^3) """ def valuation(self): r""" @@ -2358,8 +2364,11 @@ def _div_(self, other): Lazy Laurent series that have a dense implementation can be divided:: sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: z/(1 - z) - z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + O(z^8) + sage: z / (1 - z) + z + z^2 + z^3 + O(z^4) + sage: 1 / (z*(1-z)) + z^-1 + 1 + z + O(z^2) + sage: M = L(lambda n: n, 0); M z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: N = L(lambda n: 1, 0); N @@ -2380,8 +2389,9 @@ def _div_(self, other): If the division of exact Lazy Laurent series yields a Laurent polynomial, it is represented as an exact series:: - sage: 1/z - z^-1 + sage: L. = LazyLaurentSeriesRing(QQ) + sage: (3*z^-3 + 3*z^-2 + 2*z^2 + 2*z^3) / (6*z + 4*z^6) + 1/2*z^-4 + 1/2*z^-3 sage: m = z^2 + 2*z + 1 sage: n = z + 1 @@ -2396,6 +2406,15 @@ def _div_(self, other): e[] + e[1]*z + e[1, 1]*z^2 + e[1, 1, 1]*z^3 + e[1, 1, 1, 1]*z^4 + e[1, 1, 1, 1, 1]*z^5 + e[1, 1, 1, 1, 1, 1]*z^6 + O(e[]*z^7) + An example for multivariate Taylor series:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: 1 / (1 - y) # should be exact, but isn't + 1 + y + y^2 + y^3 + y^4 + y^5 + y^6 + O(x,y)^7 + + sage: (x + y) / (1 - y) + (x+y) + (x*y+y^2) + (x*y^2+y^3) + (x*y^3+y^4) + (x*y^4+y^5) + (x*y^5+y^6) + (x*y^6+y^7) + O(x,y)^8 + """ if isinstance(other._coeff_stream, Stream_zero): raise ZeroDivisionError("cannot divide by 0") @@ -2405,24 +2424,58 @@ def _div_(self, other): if isinstance(left, Stream_zero): return P.zero() right = other._coeff_stream + R = P._internal_poly_ring if (isinstance(left, Stream_exact) - and isinstance(right, Stream_exact)): - if not left._constant and not right._constant: - R = P._internal_poly_ring - pl = left._polynomial_part(R) - pr = right._polynomial_part(R) - try: - ret = pl / pr - ret = R(ret) - except (TypeError, ValueError, NotImplementedError): - # We cannot divide the polynomials, so the result must be a series - pass - else: - initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)] - return P.element_class(P, Stream_exact(initial_coefficients, + and isinstance(right, Stream_exact) + and hasattr(R, "_gcd_univariate_polynomial")): + z = R.gen() + num = left._polynomial_part(R) * (1-z) + left._constant * z**left._degree + den = right._polynomial_part(R) * (1-z) + right._constant * z**right._degree + # num / den is not necessarily reduced, but gcd and // seems to work: + # sage: a = var("a"); R. = SR[] + # sage: (a*z - a)/(z - 1) + # (a*z - a)/(z - 1) + # sage: gcd((a*z - a), (z - 1)) + # z - 1 + g = num.gcd(den) + # apparently, the gcd is chosen so that den // g is is + # actually a polynomial, but we do not rely on this + num = num // g + den = den // g + exponents = den.exponents() + if len(exponents) == 1: + d = den[exponents[0]] + initial_coefficients = [c / d for c in num] + order = num.valuation() - den.valuation() + return P.element_class(P, Stream_exact(initial_coefficients, + P._sparse, + order=order, + constant=0)) + + if (len(exponents) == 2 + and exponents[0] + 1 == exponents[1] + and den[exponents[0]] == -den[exponents[1]]): + quo, rem = num.quo_rem(den) + # rem is a unit, i.e., in the Laurent case c*z^v + c, v_rem = rem.polynomial_construction() + constant = P.base_ring()(c / den[exponents[0]]) + v = v_rem - exponents[0] + if quo: + d = quo.degree() + m = d - v + 1 + if m > 0: + quo += R([constant]*m).shift(v) + v = d + 1 + return P.element_class(P, Stream_exact(list(quo), P._sparse, - order=ret.valuation(), - constant=left._constant)) + order=quo.valuation(), + degree=v, + constant=constant)) + return P.element_class(P, Stream_exact([], + P._sparse, + order=v, + degree=v, + constant=constant)) return P.element_class(P, Stream_cauchy_mul(left, Stream_cauchy_invert(right))) @@ -2675,19 +2728,19 @@ def __call__(self, g): sage: f = z^-2 + 1 + z sage: g = 1/(y*(1-y)); g - y^-1 + 1 + y + y^2 + y^3 + y^4 + y^5 + O(y^6) + y^-1 + 1 + y + O(y^2) sage: f(g) - y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + O(y^6) - sage: g^-2 + 1 + g - y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + O(y^6) + y^-1 + 2 + y + 2*y^2 - y^3 + 2*y^4 + y^5 + y^6 + y^7 + O(y^8) + sage: g^-2 + 1 + g == f(g) + True sage: f = z^-3 + z^-2 + 1 sage: g = 1/(y^2*(1-y)); g - y^-2 + y^-1 + 1 + y + y^2 + y^3 + y^4 + O(y^5) + y^-2 + y^-1 + 1 + O(y) sage: f(g) - 1 + y^4 - 2*y^5 + 2*y^6 + O(y^7) - sage: g^-3 + g^-2 + 1 - 1 + y^4 - 2*y^5 + 2*y^6 + O(y^7) + 1 + y^4 - 2*y^5 + 2*y^6 - 3*y^7 + 3*y^8 - y^9 + sage: g^-3 + g^-2 + 1 == f(g) + True sage: z(y) y @@ -3068,7 +3121,7 @@ def polynomial(self, degree=None, name=None): sage: z = L.gen() sage: f = (1 + z)/(z^3 - z^5) sage: f - z^-3 + z^-2 + z^-1 + 1 + z + z^2 + z^3 + O(z^4) + z^-3 + z^-2 + z^-1 + O(1) sage: f.polynomial(5) z^-3 + z^-2 + z^-1 + 1 + z + z^2 + z^3 + z^4 + z^5 sage: f.polynomial(0) @@ -3855,9 +3908,9 @@ def _format_series(self, formatter, format_strings=False): sage: L. = LazyLaurentSeriesRing(QQ) sage: D = LazyDirichletSeriesRing(L, "s") sage: f = D([2, 0, 1/(1-z), 3]); f - (2)/1^s + ((1+z+z^2+z^3+z^4+z^5+z^6+O(z^7))/3^s) + (3)/4^s + (2)/1^s + ((1+z+z^2+O(z^3))/3^s) + (3)/4^s sage: f._format_series(ascii_art) - ((2)/1^s) + ((1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7))/3^s) + ((3)/4^s) + ((2)/1^s) + ((1 + z + z^2 + O(z^3))/3^s) + ((3)/4^s) """ P = self.parent() cs = self._coeff_stream diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index ae56110610d..67650c76158 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1341,8 +1341,8 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): @coerce_binop def quo_rem(self, right_r): """ - Attempts to divide ``self`` by ``right`` and returns a quotient and - a remainder. + Attempts to divide ``self`` by ``right`` and returns a quotient + ``q`` and a remainder ``r`` such that ``self = q*other + r``. EXAMPLES:: @@ -1351,11 +1351,24 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): (t^-2 + 1 + t^2, 0) sage: (t^-2 + 3 + t).quo_rem(t^-4) (t^2 + 3*t^4 + t^5, 0) - sage: (t^-2 + 3 + t).quo_rem(t^-4 + t) - (0, 1 + 3*t^2 + t^3) + + sage: num, den = t^-2 + t, t^-2 + 1 + sage: q, r = num.quo_rem(den) + sage: num == q * den + r + True + + TESTS: + + Check that :trac:`34330` is fixed:: + + sage: num, den = t^-2 + 3 + t, t^-4 + t + sage: q, r = num.quo_rem(den); q, r + (0, t^-2 + 3 + t) + sage: num == q * den + r + True """ cdef LaurentPolynomial_univariate right = right_r - q,r = self.__u.quo_rem(right.__u) + q, r = self.__u.quo_rem(right.__u) cdef LaurentPolynomial_univariate ql, qr ql = self._new_c() ql.__u = q @@ -1363,9 +1376,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ql.__normalize() qr = self._new_c() qr.__u = r - qr.__n = 0 + qr.__n = self.__n qr.__normalize() - return (ql, qr) + return ql, qr cpdef _richcmp_(self, right_r, int op): r""" @@ -3726,4 +3739,3 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): if new_ring is not None: return new_ring(ans) return ans - From acde46531121606176bd66bfdd9ae699a1b1f7b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 10 Aug 2022 11:15:01 +0200 Subject: [PATCH 319/591] E251 in interfaces and interacts --- src/sage/calculus/calculus.py | 24 ++++++++++----------- src/sage/functions/bessel.py | 27 ++++++++++++------------ src/sage/functions/jacobi.py | 25 +++++++--------------- src/sage/game_theory/normal_form_game.py | 2 +- src/sage/games/sudoku.py | 2 +- src/sage/homology/tests.py | 3 ++- src/sage/interacts/library.py | 22 ++++++++++--------- src/sage/interfaces/axiom.py | 16 +++++++------- src/sage/interfaces/frobby.py | 4 ++-- src/sage/interfaces/jmoldata.py | 2 +- src/sage/interfaces/lisp.py | 12 +++++------ src/sage/interfaces/macaulay2.py | 16 +++++++------- src/sage/interfaces/matlab.py | 18 ++++++++-------- src/sage/interfaces/maxima.py | 20 +++++++++--------- src/sage/interfaces/mupad.py | 21 ++++++++---------- src/sage/interfaces/mwrank.py | 14 ++++++------ src/sage/interfaces/octave.py | 20 +++++++++--------- src/sage/interfaces/r.py | 5 ++--- src/sage/interfaces/scilab.py | 18 ++++++++-------- src/sage/interfaces/singular.py | 20 +++++++++--------- src/sage/interfaces/tides.py | 7 +++--- src/sage/matrix/benchmark.py | 3 ++- src/sage/media/wav.py | 19 ++++++++--------- src/sage/symbolic/units.py | 3 ++- 24 files changed, 157 insertions(+), 166 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index b1c9d1f81d7..f4a821996b3 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -2519,10 +2519,10 @@ def _find_func(name, create_when_missing=True): parser_make_var = LookupNameMaker({}, fallback=_find_var) parser_make_function = LookupNameMaker({}, fallback=_find_func) -SR_parser = Parser(make_int = lambda x: SR(Integer(x)), - make_float = lambda x: SR(create_RealNumber(x)), - make_var = parser_make_var, - make_function = parser_make_function) +SR_parser = Parser(make_int=lambda x: SR(Integer(x)), + make_float=lambda x: SR(create_RealNumber(x)), + make_var=parser_make_var, + make_function=parser_make_function) def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, parser=None): @@ -2581,12 +2581,12 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars parser_make_Mvar = LookupNameMaker({}, fallback=lambda x: _find_var(x, interface='maxima')) -SRM_parser = Parser(make_int = lambda x: SR(Integer(x)), - make_float = lambda x: SR(RealDoubleElement(x)), - make_var = parser_make_Mvar, - make_function = parser_make_function) +SRM_parser = Parser(make_int=lambda x: SR(Integer(x)), + make_float=lambda x: SR(RealDoubleElement(x)), + make_var=parser_make_Mvar, + make_function=parser_make_function) -SR_parser_giac = Parser(make_int = lambda x: SR(Integer(x)), - make_float = lambda x: SR(create_RealNumber(x)), - make_var = LookupNameMaker({}, fallback=lambda x: _find_var(x, interface='giac')), - make_function = parser_make_function) +SR_parser_giac = Parser(make_int=lambda x: SR(Integer(x)), + make_float=lambda x: SR(create_RealNumber(x)), + make_var=LookupNameMaker({}, fallback=lambda x: _find_var(x, interface='giac')), + make_function=parser_make_function) diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index 718bd20cd52..34375e849b6 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -1661,11 +1661,11 @@ def __init__(self): sage: spherical_bessel_J(3, x)._sympy_() jn(3, x) """ + conversions = dict(mathematica='SphericalBesselJ', + maxima='spherical_bessel_j', + sympy='jn') BuiltinFunction.__init__(self, 'spherical_bessel_J', nargs=2, - conversions=dict(mathematica= - 'SphericalBesselJ', - maxima='spherical_bessel_j', - sympy='jn')) + conversions=conversions) def _evalf_(self, n, z, parent, algorithm=None): r""" @@ -1759,11 +1759,11 @@ def __init__(self): sage: spherical_bessel_Y(3, x)._sympy_() yn(3, x) """ + conversions = dict(mathematica='SphericalBesselY', + maxima='spherical_bessel_y', + sympy='yn') BuiltinFunction.__init__(self, 'spherical_bessel_Y', nargs=2, - conversions=dict(mathematica= - 'SphericalBesselY', - maxima='spherical_bessel_y', - sympy='yn')) + conversions=conversions) def _evalf_(self, n, z, parent, algorithm=None): r""" @@ -1857,10 +1857,10 @@ def __init__(self): sage: spherical_hankel1 spherical_hankel1 """ + conversions = dict(mathematica='SphericalHankelH1', + maxima='spherical_hankel1') BuiltinFunction.__init__(self, 'spherical_hankel1', nargs=2, - conversions=dict(mathematica= - 'SphericalHankelH1', - maxima='spherical_hankel1')) + conversions=conversions) def _evalf_(self, n, z, parent, algorithm=None): r""" @@ -1959,9 +1959,8 @@ def __init__(self): spherical_hankel2 """ BuiltinFunction.__init__(self, 'spherical_hankel2', nargs=2, - conversions=dict(mathematica= - 'SphericalHankelH2', - maxima='spherical_hankel2')) + conversions=dict(mathematica='SphericalHankelH2', + maxima='spherical_hankel2')) def _evalf_(self, n, z, parent, algorithm=None): r""" diff --git a/src/sage/functions/jacobi.py b/src/sage/functions/jacobi.py index 19a1981136d..af67d857f27 100644 --- a/src/sage/functions/jacobi.py +++ b/src/sage/functions/jacobi.py @@ -196,8 +196,7 @@ def __init__(self, kind): "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") self.kind = kind BuiltinFunction.__init__(self, - name='jacobi_{}'.format(kind), - nargs=2, evalf_params_first=False, + name=f'jacobi_{kind}', nargs=2, evalf_params_first=False, conversions=dict(maple=('Jacobi{}'.format(kind.upper())), mathematica=('Jacobi{}'.format(kind.upper())), fricas=('jacobi{}'.format(kind.capitalize())), @@ -550,17 +549,10 @@ def __init__(self, kind): "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") self.kind = kind BuiltinFunction.__init__(self, - name='inverse_jacobi_{}'.format(kind), - nargs=2, evalf_params_first=False, - conversions=dict(maple= - ('InverseJacobi{}' - .format(kind.upper())), - mathematica= - ('InverseJacobi{}' - .format(kind.upper())), - maxima= - ('inverse_jacobi_{}' - .format(kind)))) + name=f'inverse_jacobi_{kind}', nargs=2, evalf_params_first=False, + conversions=dict(maple=('InverseJacobi{}'.format(kind.upper())), + mathematica=f'InverseJacobi{kind.upper()}', + maxima=(f'inverse_jacobi_{kind}'))) def _eval_(self, x, m): r""" @@ -1073,10 +1065,9 @@ def __init__(self): jacobi_am """ BuiltinFunction.__init__(self, name='jacobi_am', nargs=2, - conversions=dict(maple='JacobiAM', - mathematica= - 'JacobiAmplitude'), - evalf_params_first=False) + conversions=dict(maple='JacobiAM', + mathematica='JacobiAmplitude'), + evalf_params_first=False) def _eval_(self, x, m): r""" diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index f0d58a98aec..67047f42363 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -1805,7 +1805,7 @@ def _solve_gambit_LP(self, maximization=True): """ if Game is None: raise NotImplementedError("gambit is not installed") - g = self._gambit_(maximization = maximization) + g = self._gambit_(maximization=maximization) output = ExternalLPSolver().solve(g) nasheq = Parser(output).format_gambit(g) return sorted(nasheq) diff --git a/src/sage/games/sudoku.py b/src/sage/games/sudoku.py index 3e2de73ef98..eb311b4bc05 100644 --- a/src/sage/games/sudoku.py +++ b/src/sage/games/sudoku.py @@ -131,7 +131,7 @@ class Sudoku(SageObject): |4 9 1|8 5 6|7 2 3| +-----+-----+-----+ """ - def __init__(self, puzzle, verify_input = True): + def __init__(self, puzzle, verify_input=True): r""" Initialize a Sudoku puzzle, determine its size, sanity-check the inputs. diff --git a/src/sage/homology/tests.py b/src/sage/homology/tests.py index e49d0cc8373..89c86857d44 100644 --- a/src/sage/homology/tests.py +++ b/src/sage/homology/tests.py @@ -61,7 +61,8 @@ def random_chain_complex(level=1): mat = random_matrix(ZZ, nrows, ncols, sparse=sparseness) dim = randint(-bound, bound) deg = 2 * randint(0, 1) - 1 # -1 or 1 - return ChainComplex({dim: mat}, degree = deg) + return ChainComplex({dim: mat}, degree=deg) + @random_testing def test_random_chain_complex(level=1, trials=1, verbose=False): diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index 8166014739d..06d680109a0 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -226,7 +226,7 @@ def taylor_polynomial(title, f, order: int): html(r'$f(x)\;=\;%s$' % latex(f)) html(r'$\hat{f}(x;%s)\;=\;%s+\mathcal{O}(x^{%s})$' % (x0, latex(ft), order + 1)) - show(dot + p + pt, ymin = -.5, ymax = 1) + show(dot + p + pt, ymin=-.5, ymax=1) @library_interact( @@ -1176,14 +1176,15 @@ def trapezoid_integration( for i in range(n): xi = interval[0] + i*h yi = f(xi) - trapezoids += line([[xi, 0], [xi, yi], [xi + h, f(xi + h)],[xi + h, 0],[xi, 0]], rgbcolor = (1,0,0)) + trapezoids += line([[xi, 0], [xi, yi], [xi + h, f(xi + h)],[xi + h, 0],[xi, 0]], rgbcolor=(1, 0, 0)) xs.append(xi) ys.append(yi) xs.append(xi + h) ys.append(f(xi + h)) html(r'Function $f(x)=%s$'%latex(f(x))) - show(plot(f, interval[0], interval[1]) + trapezoids, xmin = interval[0], xmax = interval[1]) + show(plot(f, interval[0], interval[1]) + trapezoids, + xmin=interval[0], xmax=interval[1]) numeric_value = integral_numerical(f, interval[0], interval[1])[0] approx = h *(ys[0]/2 + sum([ys[i] for i in range(1,n)]) + ys[n]/2) @@ -1326,7 +1327,8 @@ def parabola(a, b, c): html(r'Function $f(x)=%s$'%latex(f(x))) - show(plot(f(x),x,interval[0],interval[1]) + parabolas + lines, xmin = interval[0], xmax = interval[1]) + show(plot(f(x), x, interval[0], interval[1]) + parabolas + lines, + xmin=interval[0], xmax=interval[1]) numeric_value = integral_numerical(f,interval[0],interval[1])[0] approx = dx/3 *(ys[0] + sum([4*ys[i] for i in range(1,n,2)]) + sum([2*ys[i] for i in range(2,n,2)]) + ys[n]) @@ -1467,9 +1469,9 @@ def riemann_sum( color_rect='green' else: color_rect='red' - rects = rects +polygon2d(body, rgbcolor = color_rect,alpha=0.1)\ - + point((xs[i],ys[i]), rgbcolor = (1,0,0))\ - + line(body,rgbcolor='black',zorder=-1) + rects = rects + polygon2d(body, rgbcolor=color_rect, alpha=0.1)\ + + point((xs[i], ys[i]), rgbcolor=(1, 0, 0))\ + + line(body, rgbcolor='black', zorder=-1) html('Adjust your data and click Update button. Click repeatedly for another random values.') show(plot(func(x),(x,a,b),zorder=5) + rects) @@ -1870,7 +1872,7 @@ def polar_prime_spiral(interval, show_factors, highlight_primes, show_curves, n, list = [] list2 = [] if not show_factors: - for i in srange(start, end, include_endpoint = True): + for i in srange(start, end, include_endpoint=True): if Integer(i).is_pseudoprime(): list.append(f(i-start+1)) # primes list else: @@ -1878,7 +1880,7 @@ def polar_prime_spiral(interval, show_factors, highlight_primes, show_curves, n, P = points(list) R = points(list2, alpha=.1) # faded composites else: - for i in srange(start, end, include_endpoint = True): + for i in srange(start, end, include_endpoint=True): # Resize each of the dots depending of the number of factors of each number list.append(disk((f(i-start+1)),0.05*pow(2,len(factor(i))-1), (0,2*pi))) if Integer(i).is_pseudoprime() and highlight_primes: @@ -1889,7 +1891,7 @@ def polar_prime_spiral(interval, show_factors, highlight_primes, show_curves, n, p_size = 5 # the orange dot size of the prime markers if not highlight_primes: list2 = [(f(n-start+1))] - R = points(list2, hue = .1, pointsize = p_size) + R = points(list2, hue=.1, pointsize=p_size) if n > 0: html('$n = %s$' % factor(n)) diff --git a/src/sage/interfaces/axiom.py b/src/sage/interfaces/axiom.py index c6ef330ae63..499592bae6a 100644 --- a/src/sage/interfaces/axiom.py +++ b/src/sage/interfaces/axiom.py @@ -214,16 +214,16 @@ def __init__(self, name='axiom', command='axiom -nox -noclef', self.__eval_using_file_cutoff = eval_using_file_cutoff self._COMMANDS_CACHE = '%s/%s_commandlist_cache.sobj' % (DOT_SAGE, name) Expect.__init__(self, - name = name, - prompt = r'\([0-9]+\) -> ', - command = command, - script_subdirectory = script_subdirectory, + name=name, + prompt=r'\([0-9]+\) -> ', + command=command, + script_subdirectory=script_subdirectory, server=server, server_tmpdir=server_tmpdir, - restart_on_ctrlc = False, - verbose_start = False, - init_code = init_code, - logfile = logfile, + restart_on_ctrlc=False, + verbose_start=False, + init_code=init_code, + logfile=logfile, eval_using_file_cutoff=eval_using_file_cutoff) self._prompt_wait = self._prompt diff --git a/src/sage/interfaces/frobby.py b/src/sage/interfaces/frobby.py index 7680704d291..9f514422528 100644 --- a/src/sage/interfaces/frobby.py +++ b/src/sage/interfaces/frobby.py @@ -78,12 +78,12 @@ def __call__(self, action, input=None, options=[], verbose=False): print("Frobby command: ", repr(command)) print("Frobby input:\n", input) - process = Popen(command, stdin = PIPE, stdout = PIPE, stderr = PIPE) + process = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE) if input: frinput = str_to_bytes(input) else: frinput = None - output, err = process.communicate(input = frinput) + output, err = process.communicate(input=frinput) output = bytes_to_str(output) err = bytes_to_str(err) diff --git a/src/sage/interfaces/jmoldata.py b/src/sage/interfaces/jmoldata.py index b94f168c6cf..6660a14e1cc 100644 --- a/src/sage/interfaces/jmoldata.py +++ b/src/sage/interfaces/jmoldata.py @@ -75,7 +75,7 @@ def export_image(self, targetfile, datafile, #name (path) of data file Jmol can read or script file telling it what to read or load datafile_cmd='script', #"script" or "load" - image_type ='PNG', #PNG, JPG, GIF + image_type='PNG', #PNG, JPG, GIF figsize=5, **kwds): r""" diff --git a/src/sage/interfaces/lisp.py b/src/sage/interfaces/lisp.py index 668b35640df..0f9d09605bf 100644 --- a/src/sage/interfaces/lisp.py +++ b/src/sage/interfaces/lisp.py @@ -74,28 +74,28 @@ def __init__(self, Expect.__init__(self, # The capitalized version of this is used for printing. - name = 'Lisp', + name='Lisp', # This is regexp of the input prompt. If you can change # it to be very obfuscated that would be better. Even # better is to use sequence numbers. - prompt = '> ', + prompt='> ', # This is the command that starts up your program - command = "ecl", + command="ecl", server=server, server_tmpdir=server_tmpdir, - script_subdirectory = script_subdirectory, + script_subdirectory=script_subdirectory, # If this is true, then whenever the user presses Control-C to # interrupt a calculation, the whole interface is restarted. - restart_on_ctrlc = False, + restart_on_ctrlc=False, # If true, print out a message when starting # up the command when you first send a command # to this interface. - verbose_start = False, + verbose_start=False, logfile=logfile, diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index 4c7a8ae9851..91e4da97ea0 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -216,14 +216,14 @@ def __init__(self, maxread=None, script_subdirectory=None, ) command = "%s --no-debug --no-readline --silent -e '%s'" % (command, init_str) Expect.__init__(self, - name = 'macaulay2', - prompt = PROMPT, - command = command, - server = server, - server_tmpdir = server_tmpdir, - script_subdirectory = script_subdirectory, - verbose_start = False, - logfile = logfile, + name='macaulay2', + prompt=PROMPT, + command=command, + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + verbose_start=False, + logfile=logfile, eval_using_file_cutoff=500) # Macaulay2 provides no "clear" function. However, Macaulay2 does provide diff --git a/src/sage/interfaces/matlab.py b/src/sage/interfaces/matlab.py index 0f930905656..d3701a553b8 100644 --- a/src/sage/interfaces/matlab.py +++ b/src/sage/interfaces/matlab.py @@ -170,15 +170,15 @@ class Matlab(Expect): def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None,server_tmpdir=None): Expect.__init__(self, - name = 'matlab', - prompt = '>> ', - command = "matlab -nodisplay", - server = server, - server_tmpdir = server_tmpdir, - script_subdirectory = script_subdirectory, - restart_on_ctrlc = False, - verbose_start = False, - logfile = logfile, + name='matlab', + prompt='>> ', + command="matlab -nodisplay", + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + restart_on_ctrlc=False, + verbose_start=False, + logfile=logfile, eval_using_file_cutoff=100) def __reduce__(self): diff --git a/src/sage/interfaces/maxima.py b/src/sage/interfaces/maxima.py index a05b4995cac..8950adfdea1 100644 --- a/src/sage/interfaces/maxima.py +++ b/src/sage/interfaces/maxima.py @@ -566,14 +566,14 @@ def __init__(self, script_subdirectory=None, logfile=None, server=None, MaximaAbstract.__init__(self,"maxima") Expect.__init__(self, - name = 'maxima', - prompt = r'\(\%i[0-9]+\) ', - command = '{0} -p {1}'.format(MAXIMA, shlex.quote(STARTUP)), - script_subdirectory = script_subdirectory, - restart_on_ctrlc = False, - verbose_start = False, - init_code = init_code, - logfile = logfile, + name='maxima', + prompt=r'\(\%i[0-9]+\) ', + command='{0} -p {1}'.format(MAXIMA, shlex.quote(STARTUP)), + script_subdirectory=script_subdirectory, + restart_on_ctrlc=False, + verbose_start=False, + init_code=init_code, + logfile=logfile, eval_using_file_cutoff=eval_using_file_cutoff) # Must match what is in the file sage-maxima.lisp self._display_prompt = '' @@ -1253,8 +1253,8 @@ def __init__(self, parent, name, defn, args, latex): # An instance -maxima = Maxima(init_code = ['display2d : false', - 'domain : complex', 'keepfloat : true'], +maxima = Maxima(init_code=['display2d : false', + 'domain : complex', 'keepfloat : true'], script_subdirectory=None) diff --git a/src/sage/interfaces/mupad.py b/src/sage/interfaces/mupad.py index 077ef21e70d..ada87034c0c 100644 --- a/src/sage/interfaces/mupad.py +++ b/src/sage/interfaces/mupad.py @@ -118,19 +118,16 @@ def __init__(self, maxread=None, script_subdirectory=None, server=None, server_t True """ Expect.__init__(self, - name = 'MuPAD', - prompt = PROMPT, + name='MuPAD', + prompt=PROMPT, # the -U SAGE=TRUE allows for MuPAD programs to test whether they are run from Sage - command = "mupkern -P e -U SAGE=TRUE", - script_subdirectory = script_subdirectory, - server = server, - server_tmpdir = server_tmpdir, - restart_on_ctrlc = False, - verbose_start = False, - logfile = None) - - - + command="mupkern -P e -U SAGE=TRUE", + script_subdirectory=script_subdirectory, + server=server, + server_tmpdir=server_tmpdir, + restart_on_ctrlc=False, + verbose_start=False, + logfile=None) def _function_class(self): """ diff --git a/src/sage/interfaces/mwrank.py b/src/sage/interfaces/mwrank.py index 636b7d6d961..dd4663ab802 100644 --- a/src/sage/interfaces/mwrank.py +++ b/src/sage/interfaces/mwrank.py @@ -185,13 +185,13 @@ def __init__(self, options="", server=None,server_tmpdir=None): sage: TestSuite(Mwrank_class).run() """ Expect.__init__(self, - name = 'mwrank', - prompt = 'Enter curve: ', - command = "mwrank %s" % options, - server = server, - server_tmpdir = server_tmpdir, - restart_on_ctrlc = True, - verbose_start = False) + name='mwrank', + prompt='Enter curve: ', + command="mwrank %s" % options, + server=server, + server_tmpdir=server_tmpdir, + restart_on_ctrlc=True, + verbose_start=False) def __getattr__(self, attrname): """ diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index 8f12f515ce4..4923aec71da 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -187,18 +187,18 @@ def __init__(self, maxread=None, script_subdirectory=None, logfile=None, if server is None: server = os.getenv('SAGE_OCTAVE_SERVER') or None Expect.__init__(self, - name = 'octave', + name='octave', # We want the prompt sequence to be unique to avoid confusion with syntax error messages containing >>> - prompt = r'octave\:\d+> ', + prompt=r'octave\:\d+> ', # We don't want any pagination of output - command = command + " --no-line-editing --silent --eval 'PS2(PS1());more off' --persist", - maxread = maxread, - server = server, - server_tmpdir = server_tmpdir, - script_subdirectory = script_subdirectory, - restart_on_ctrlc = False, - verbose_start = False, - logfile = logfile, + command=command + " --no-line-editing --silent --eval 'PS2(PS1());more off' --persist", + maxread=maxread, + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + restart_on_ctrlc=False, + verbose_start=False, + logfile=logfile, eval_using_file_cutoff=100) self._seed = seed diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 565d6a1da93..7c13b153469 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -476,13 +476,12 @@ def __init__(self, sage: r == loads(dumps(r)) # optional - rpy2 True """ - Interface.__init__( self, - name = 'r', # The capitalized version of this is used for printing. + name='r', # The capitalized version of this is used for printing. ) self._seed = seed - self._initialized = False # done lazily + self._initialized = False # done lazily def _lazy_init(self): """ diff --git a/src/sage/interfaces/scilab.py b/src/sage/interfaces/scilab.py index c1144d40ab0..692c6b0b3b4 100644 --- a/src/sage/interfaces/scilab.py +++ b/src/sage/interfaces/scilab.py @@ -220,15 +220,15 @@ def __init__(self, maxread=None, script_subdirectory=None, sage: del sci_obj """ Expect.__init__(self, - name = 'scilab', - prompt = '-->', - command = "scilab -nw", - server = server, - server_tmpdir = server_tmpdir, - script_subdirectory = script_subdirectory, - restart_on_ctrlc = False, - verbose_start = False, - logfile = logfile, + name='scilab', + prompt='-->', + command="scilab -nw", + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + restart_on_ctrlc=False, + verbose_start=False, + logfile=logfile, eval_using_file_cutoff=100) self._seed = seed diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 41e9c9ff251..ff25f8d7b6c 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -396,19 +396,19 @@ def __init__(self, maxread=None, script_subdirectory=None, prompt = '> ' Expect.__init__(self, terminal_echo=False, - name = 'singular', - prompt = prompt, + name='singular', + prompt=prompt, # no tty, fine grained cputime() # and do not display CTRL-C prompt - command = "{} -t --ticks-per-sec 1000 --cntrlc=a".format( + command="{} -t --ticks-per-sec 1000 --cntrlc=a".format( shlex.quote(sage.features.singular.Singular().absolute_filename())), - server = server, - server_tmpdir = server_tmpdir, - script_subdirectory = script_subdirectory, - restart_on_ctrlc = True, - verbose_start = False, - logfile = logfile, - eval_using_file_cutoff=100 if os.uname()[0]=="SunOS" else 1000) + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + restart_on_ctrlc=True, + verbose_start=False, + logfile=logfile, + eval_using_file_cutoff=100 if os.uname()[0] == "SunOS" else 1000) self.__libs = [] self._prompt_wait = prompt self.__to_clear = [] # list of variable names that need to be cleared. diff --git a/src/sage/interfaces/tides.py b/src/sage/interfaces/tides.py index 6f29de666cc..906f95396e5 100644 --- a/src/sage/interfaces/tides.py +++ b/src/sage/interfaces/tides.py @@ -378,7 +378,7 @@ def remove_constants(l1,l2): def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, - tolrel=1e-16, tolabs=1e-16, output = ''): + tolrel=1e-16, tolabs=1e-16, output=''): r""" Generate the needed files for the min_tides library. @@ -637,9 +637,10 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, outfile.write('\treturn 0; \n }') outfile.close() + def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, - parameters = None , parameter_values = None, dig = 20, tolrel=1e-16, - tolabs=1e-16, output = ''): + parameters=None, parameter_values=None, dig=20, tolrel=1e-16, + tolabs=1e-16, output=''): r""" Generate the needed files for the mpfr module of the tides library. diff --git a/src/sage/matrix/benchmark.py b/src/sage/matrix/benchmark.py index 5058798da1a..86d09a63a49 100644 --- a/src/sage/matrix/benchmark.py +++ b/src/sage/matrix/benchmark.py @@ -30,7 +30,8 @@ timeout = 60 -def report(F, title, systems = ['sage', 'magma'], **kwds): + +def report(F, title, systems=['sage', 'magma'], **kwds): """ Run benchmarks with default arguments for each function in the list F. diff --git a/src/sage/media/wav.py b/src/sage/media/wav.py index 7be09afdf41..2c35cb9320a 100644 --- a/src/sage/media/wav.py +++ b/src/sage/media/wav.py @@ -297,9 +297,8 @@ def plot(self, npoints=None, channel=0, plotjoined=True, **kwds): a plot object that can be shown. """ - - domain = self.domain(npoints = npoints) - values = self.values(npoints=npoints, channel = channel) + domain = self.domain(npoints=npoints) + values = self.values(npoints=npoints, channel=channel) points = zip(domain, values) L = list_plot(points, plotjoined=plotjoined, **kwds) @@ -373,13 +372,13 @@ def _copy(self, start, stop): channels_sliced = [self._channel_data[i][start:stop] for i in range(self._nchannels)] print(stop - start) - return Wave(nchannels = self._nchannels, - width = self._width, - framerate = self._framerate, - bytes = self._bytes[start:stop], - nframes = stop - start, - channel_data = channels_sliced, - name = self._name) + return Wave(nchannels=self._nchannels, + width=self._width, + framerate=self._framerate, + bytes=self._bytes[start:stop], + nframes=stop - start, + channel_data=channels_sliced, + name=self._name) def __copy__(self): return self._copy(0, self._nframes) diff --git a/src/sage/symbolic/units.py b/src/sage/symbolic/units.py index 9618739f6ba..9b5407786e1 100644 --- a/src/sage/symbolic/units.py +++ b/src/sage/symbolic/units.py @@ -1456,7 +1456,8 @@ def convert_temperature(expr, target): coeff = expr/expr_temp if target is not None: target_temp = target.variables()[0] - a = sage_eval(unitdict['temperature'][str(expr_temp)], locals = {'x':coeff}) + a = sage_eval(unitdict['temperature'][str(expr_temp)], + locals={'x': coeff}) if target is None or target_temp == units.temperature.kelvin: return a[0]*units.temperature.kelvin elif target_temp == units.temperature.celsius or target_temp == units.temperature.centigrade: From c6485477c54c1d40dd0f58cd9745a61e5c6b75d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 10 Aug 2022 21:48:16 +0200 Subject: [PATCH 320/591] fix mistake --- src/sage/geometry/pseudolines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/pseudolines.py b/src/sage/geometry/pseudolines.py index c579637da41..5b7897f376f 100644 --- a/src/sage/geometry/pseudolines.py +++ b/src/sage/geometry/pseudolines.py @@ -168,7 +168,7 @@ class PseudolineArrangement: - def __init__(self, seq, encoding "auto"): + def __init__(self, seq, encoding="auto"): r""" Creates an arrangement of pseudolines. From 3da6b3deb53c37dab9676cf60c9aaff6e9e43e14 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 11 Aug 2022 00:01:29 +0200 Subject: [PATCH 321/591] better docstring --- src/sage/rings/polynomial/laurent_polynomial.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 67650c76158..0fc936f4bba 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1339,10 +1339,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): return ret @coerce_binop - def quo_rem(self, right_r): + def quo_rem(self, other): """ - Attempts to divide ``self`` by ``right`` and returns a quotient - ``q`` and a remainder ``r`` such that ``self = q*other + r``. + Divide ``self`` by ``other`` and return a quotient ``q`` + and a remainder ``r`` such that ``self == q * other + r``. EXAMPLES:: @@ -1367,7 +1367,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: num == q * den + r True """ - cdef LaurentPolynomial_univariate right = right_r + cdef LaurentPolynomial_univariate right = other q, r = self.__u.quo_rem(right.__u) cdef LaurentPolynomial_univariate ql, qr ql = self._new_c() From 3ccea325086deba234c4a9865b1f7efb5e646fae Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 11 Aug 2022 00:50:35 +0200 Subject: [PATCH 322/591] fix _div_ for univariate Taylor series, add documentation --- src/sage/rings/lazy_series.py | 39 ++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index d99ca3f777d..30bf0c61cdf 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -61,7 +61,25 @@ series are much faster. Moreover, these are the series where equality can be decided. For example:: - sage: f = 1/(1 - z) + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: f = 1 + 2*z^2 / (1 - z) + sage: f - 2 / (1 - z) + 1 + 2*z + 0 + +However, multivariate Taylor series are actually represented as +streams of multivariate polynomials. Therefore, the only exact +series in this case are polynomials:: + + sage: L. = LazyTaylorSeriesRing(ZZ) + sage: 1 / (1-x) + 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + O(x,y)^7 + +A similar statement is true for lazy symmetric functions:: + + sage: h = SymmetricFunctions(QQ).h() + sage: L = LazySymmetricFunctions(h) + sage: 1 / (1-L(h[1])) + h[] + h[1] + (h[1,1]) + (h[1,1,1]) + (h[1,1,1,1]) + (h[1,1,1,1,1]) + (h[1,1,1,1,1,1]) + O^7 We can change the base ring:: @@ -2406,13 +2424,13 @@ def _div_(self, other): e[] + e[1]*z + e[1, 1]*z^2 + e[1, 1, 1]*z^3 + e[1, 1, 1, 1]*z^4 + e[1, 1, 1, 1, 1]*z^5 + e[1, 1, 1, 1, 1, 1]*z^6 + O(e[]*z^7) - An example for multivariate Taylor series:: + Examples for multivariate Taylor series:: sage: L. = LazyTaylorSeriesRing(QQ) - sage: 1 / (1 - y) # should be exact, but isn't + sage: 1 / (1 - y) 1 + y + y^2 + y^3 + y^4 + y^5 + y^6 + O(x,y)^7 - sage: (x + y) / (1 - y) + sage: (x + y) / (1 - y) (x+y) + (x*y+y^2) + (x*y^2+y^3) + (x*y^3+y^4) + (x*y^4+y^5) + (x*y^5+y^6) + (x*y^6+y^7) + O(x,y)^8 """ @@ -2457,7 +2475,8 @@ def _div_(self, other): and den[exponents[0]] == -den[exponents[1]]): quo, rem = num.quo_rem(den) # rem is a unit, i.e., in the Laurent case c*z^v - c, v_rem = rem.polynomial_construction() + v_rem = rem.exponents()[0] + c = rem[v_rem] constant = P.base_ring()(c / den[exponents[0]]) v = v_rem - exponents[0] if quo: @@ -2466,9 +2485,13 @@ def _div_(self, other): if m > 0: quo += R([constant]*m).shift(v) v = d + 1 + if quo: + order = quo.valuation() + else: + order = 0 return P.element_class(P, Stream_exact(list(quo), P._sparse, - order=quo.valuation(), + order=order, degree=v, constant=constant)) return P.element_class(P, Stream_exact([], @@ -3075,12 +3098,12 @@ def approximate_series(self, prec, name=None): name = S.variable_name() if self.valuation() < 0: - from sage.rings.all import LaurentSeriesRing + from sage.rings.laurent_series_ring import LaurentSeriesRing R = LaurentSeriesRing(S.base_ring(), name=name) n = self.valuation() return R([self[i] for i in range(n, prec)], n).add_bigoh(prec) else: - from sage.rings.all import PowerSeriesRing + from sage.rings.power_series_ring import PowerSeriesRing R = PowerSeriesRing(S.base_ring(), name=name) return R([self[i] for i in range(prec)]).add_bigoh(prec) From 3641be4f8312f00193f810ed0c076783bb9ffc6c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 11 Aug 2022 09:18:28 +0900 Subject: [PATCH 323/591] Marking failing test as "# known bug". --- src/sage/tests/modular_group_cohomology.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tests/modular_group_cohomology.py b/src/sage/tests/modular_group_cohomology.py index 868d35e14be..69783f8020a 100644 --- a/src/sage/tests/modular_group_cohomology.py +++ b/src/sage/tests/modular_group_cohomology.py @@ -52,7 +52,7 @@ sage: H.essential_ideal() # optional - p_group_cohomology a_1_0*a_1_1, a_1_1*a_3_1 - sage: ascii_art(H.bar_code('LowerCentralSeries')[2])# optional - p_group_cohomology + sage: ascii_art(H.bar_code('LowerCentralSeries')[2]) # known bug # optional - p_group_cohomology * *-* *-* From 6522eff7f2d98703a6aa3f7ee72a42d60c6aa63d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 17:45:25 -0700 Subject: [PATCH 324/591] Polyhedron_base1.an_affine_basis: Update documentation --- src/sage/geometry/polyhedron/base1.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index 7a404a5097f..42a87ecb173 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -426,7 +426,7 @@ def ambient_dim(self): def an_affine_basis(self): """ - Return points in ``self`` that are a basis for the affine span of the polytope. + Return points in ``self`` that form a basis for the affine span of ``self``. This implementation of the method :meth:`ConvexSet_base.an_affine_basis` for polytopes guarantees the following: @@ -438,6 +438,9 @@ def an_affine_basis(self): one vertex that is in the difference. Thus this method is independent of the concrete realization of the polytope. + For unbounded polyhedra, the result may contain arbitrary points of ``self``, + not just vertices. + EXAMPLES:: sage: P = polytopes.cube() @@ -455,8 +458,7 @@ def an_affine_basis(self): A vertex at (4, 1, 3, 5, 2), A vertex at (4, 2, 5, 3, 1)] - For unbounded polyhedra, the result may contain arbitrary points of ``self``, - not just vertices:: + Unbounded polyhedra:: sage: p = Polyhedron(vertices=[(0, 0)], rays=[(1,0), (0,1)]) sage: p.an_affine_basis() From c7108e9a8f0ccf4fbc19f6cbfa799b5d6f347439 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 11 Aug 2022 10:01:03 +0900 Subject: [PATCH 325/591] Updating "# known bug" description. --- src/sage/tests/modular_group_cohomology.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tests/modular_group_cohomology.py b/src/sage/tests/modular_group_cohomology.py index 69783f8020a..be00146dc6f 100644 --- a/src/sage/tests/modular_group_cohomology.py +++ b/src/sage/tests/modular_group_cohomology.py @@ -52,7 +52,7 @@ sage: H.essential_ideal() # optional - p_group_cohomology a_1_0*a_1_1, a_1_1*a_3_1 - sage: ascii_art(H.bar_code('LowerCentralSeries')[2]) # known bug # optional - p_group_cohomology + sage: ascii_art(H.bar_code('LowerCentralSeries')[2]) # known bug (possibly, the output might be correct) # optional - p_group_cohomology * *-* *-* From 393808c0af1b16e9a702f2d282957589d782f16e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 18:22:51 -0700 Subject: [PATCH 326/591] src/doc/en/installation/binary.rst: No more cygwin binaries --- src/doc/en/installation/binary.rst | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/doc/en/installation/binary.rst b/src/doc/en/installation/binary.rst index db9c4d3e69a..5fcce7d5943 100644 --- a/src/doc/en/installation/binary.rst +++ b/src/doc/en/installation/binary.rst @@ -25,12 +25,9 @@ This has been discontinued, and the old binaries that are still available there are no longer supported. -Microsoft Windows (Cygwin) --------------------------- +Microsoft Windows +----------------- -SageMath on Windows requires a 64-bit Windows (which is likely to be the case -on a modern computer). If you happen to have a 32-bit Windows, you can consider -the alternatives mentioned at the end of :ref:`installation-guide`. - -To install SageMath on Windows, just download the installer (see the above -"Download Guide" section) and run it. +SageMath used to provide pre-built binaries for Windows based on Cygwin. +This has been discontinued, and the old binaries that can be found +are no longer supported. Use Windows Subsystem for Linux instead. From fe98ca11bb48fd3155a8741f395eb0ade7147a90 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 19:34:02 -0700 Subject: [PATCH 327/591] README.md, src/doc/en/installation: Move all Cygwin instructions to one section of the installation manual --- README.md | 67 +--------- src/doc/en/installation/source.rst | 206 ++++++++++++++++++----------- 2 files changed, 133 insertions(+), 140 deletions(-) diff --git a/README.md b/README.md index fd467aa85f8..cf92b803b16 100644 --- a/README.md +++ b/README.md @@ -67,57 +67,6 @@ your Windows. Then all instructions for installation in Linux apply. As an alternative, you can also run Linux on Windows using Docker (see above) or other virtualization solutions. -Finally, Sage also works on the 64-bit version of `Cygwin -`_. If you wish to use Cygwin, use the following -instructions to get started. - -1. Download [cygwin64](https://cygwin.com/install.html) (do not get - the 32-bit version; it is not supported by Sage). - -2. Run the `setup-x86_64.exe` graphical installer. Pick the default - options in most cases. At the package selection screen, use the - search bar to find and select at least the following packages: - `bzip2`, `coreutils`, `curl`, `gawk`, `gzip`, `tar`, `wget`, `git`. - -3. Start the Cygwin terminal and ensure you get a working bash prompt. - -4. Make sure the path of your Cygwin home directory does not contain - space characters. - - By default, your username in Cygwin is the same as your username in - Windows. This might contain spaces and other traditionally - non-UNIX-friendly characters, e.g., if it is your full name. You - can check this as follows: - - $ whoami - Erik M. Bray - - This means your default home directory on Cygwin contains this - username verbatim; in the above example, `/home/Erik M. Bray`. - It will save some potential trouble if you change your Cygwin home - directory to contain only alphanumeric characters, for example, - `/home/embray`. The easiest way to do this is to first create - the home directory you want to use instead, then create an - `/etc/passwd` file specifying that directory as your home, as follows: - - $ whocanibe=embray - $ mkdir /home/$whocanibe - $ mkpasswd.exe -l -u "$(whoami)" | sed -r 's,/home/[^:]+,/home/'$whocanibe, > /etc/passwd - - After this, close all Cygwin terminals (ensure nothing in - `C:\cygwin64` is running), then start a new Cygwin terminal and - your home directory should have moved. - - There are [other ways to do - this](https://stackoverflow.com/questions/1494658/how-can-i-change-my-cygwin-home-folder-after-installation), - but the above seems to be the simplest that's still supported. - -5. Install the package manager `apt-cyg`: - - $ curl -OL https://rawgit.com/transcode-open/apt-cyg/master/apt-cyg - $ install apt-cyg /usr/local/bin - $ rm -f apt-cyg - [macOS] Preparing the Platform ------------------------------ @@ -162,7 +111,7 @@ Like many other software packages, Sage is built from source using `./configure`, followed by `make`. However, we strongly recommend to read the following step-by-step instructions for building Sage. -The instructions cover all of Linux, macOS, and Cygwin. +The instructions cover all of Linux, macOS, and WSL. More details, providing a background for these instructions, can be found in the [section "Install from Source Code"](https://doc.sagemath.org/html/en/installation/source.html). @@ -193,9 +142,6 @@ in the Installation Guide. capitalization when changing into :envvar:`SAGE_ROOT` can lead to build errors for dependencies requiring exact capitalization in path names. - - [Cygwin] Avoid building in home directories of Windows domain - users or in paths with capital letters. - 2. Download/unpack or clone the sources. - Go to https://www.sagemath.org/download-source.html, select a mirror, @@ -236,12 +182,12 @@ in the Installation Guide. line endings are used. Therefore it is crucial that you unpack the source tree from the - Cygwin (or WSL) `bash` using the Cygwin (or WSL) `tar` utility - and not using other Windows tools (including mingw). Likewise, - when using `git`, it is recommended (but not necessary) to use - the Cygwin (or WSL) version of `git`. + WSL `bash` using the WSL `tar` utility and not using other + Windows tools (including mingw). Likewise, when using `git`, it + is recommended (but not necessary) to use the WSL version of + `git`. -3. [Linux, Cygwin] Install the required minimal build prerequisites. +3. [Linux, WSL] Install the required minimal build prerequisites. - Compilers: `gcc`, `gfortran`, `g++` (GCC 6.3 to 12.x and recent versions of Clang (LLVM) are supported). @@ -259,7 +205,6 @@ in the Installation Guide. [build/pkgs/_prereq/distros](build/pkgs/_prereq/distros), the files [arch.txt](build/pkgs/_prereq/distros/arch.txt), - [cygwin.txt](build/pkgs/_prereq/distros/cygwin.txt), [debian.txt](build/pkgs/_prereq/distros/debian.txt) (also for Ubuntu, Linux Mint, etc.), [fedora.txt](build/pkgs/_prereq/distros/fedora.txt) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index f670cd925b9..be70b69b5e2 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -168,8 +168,6 @@ On Redhat-derived systems not all perl components are installed by default and you might have to install the ``perl-ExtUtils-MakeMaker`` package. -On Cygwin, the ``lapack`` and ``liblapack-devel`` packages are required. - Installing prerequisites ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -307,43 +305,6 @@ Some additional optional packages are taken care of by: .. literalinclude:: homebrew-optional.txt -.. _section_cygwinprereqs: - -Cygwin prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Sage can be built only on the 64-bit version of Cygwin. See -the file `README.md `_ -in ``SAGE_ROOT`` for the most up-to-date instructions for building Sage -on Cygwin. - -Although it is possible to install Sage's dependencies using the Cygwin -graphical installer, it is recommended to install the `apt-cyg -`_ command-line package -installer, which is used for the remainder of these instructions. To -run ``apt-cyg``, you must have already installed (using the graphical -installer) the following packages at a minimum:: - - bzip2 coreutils gawk gzip tar wget - -With the exception of ``wget`` most of these are included in the default -package selection when you install Cygwin. Then, to install ``apt-cyg`` -run:: - - $ curl -OL https://rawgit.com/transcode-open/apt-cyg/master/apt-cyg - $ install apt-cyg /usr/local/bin - $ rm -f apt-cyg - -To install the current set of system packages known to work for building -Sage, run: - -.. literalinclude:: cygwin.txt - -Optional packages that are also known to be installable via system packages -include: - -.. literalinclude:: cygwin-optional.txt - Ubuntu on Windows Subsystem for Linux (WSL) prerequisite installation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,6 +337,133 @@ Also see the `related Github issue `_. + +As of Sage 9.7, we no longer recommend attempting to build Sage on +Cygwin and instead suggest that users on Windows 10 and 11 switch to +installing Sage using Windows Subsystem for Linux (WSL), which gives a +better performance and user/developer experience than Cygwin. + +Users on hardware configurations that do not support running WSL, as +well as users on legacy versions of Windows such as Windows 8 may find +it necessary to build Sage on Cygwin. + +.. WARNING:: + + As of Sage 9.7, `known issues with several packages + _ + will prevent a successful installation. Users need to be prepared + to contribute to Sage by fixing these issues. + +Use the following instructions to get started. + +1. Download `the 64-bit version of Cygwin `_ + (do not get the 32-bit version; it is not supported by Sage). + +2. Run the ``setup-x86_64.exe`` graphical installer. Pick the default + options in most cases. At the package selection screen, use the + search bar to find and select at least the following packages: + ``bzip2``, ``coreutils``, ``curl``, ``gawk``, ``gzip``, ``tar``, ``wget``, ``git``. + +3. Start the Cygwin terminal and ensure you get a working bash prompt. + +4. Make sure the path of your Cygwin home directory does not contain + space characters. Also avoid building in home directories of Windows domain + users or in paths with capital letters. + + By default, your username in Cygwin is the same as your username in + Windows. This might contain spaces and other traditionally + non-UNIX-friendly characters, e.g., if it is your full name. You + can check this as follows: + + $ whoami + Erik M. Bray + + This means your default home directory on Cygwin contains this + username verbatim; in the above example, `/home/Erik M. Bray`. + It will save some potential trouble if you change your Cygwin home + directory to contain only alphanumeric characters, for example, + `/home/embray`. The easiest way to do this is to first create + the home directory you want to use instead, then create an + `/etc/passwd` file specifying that directory as your home, as follows: + + $ whocanibe=embray + $ mkdir /home/$whocanibe + $ mkpasswd.exe -l -u "$(whoami)" | sed -r 's,/home/[^:]+,/home/'$whocanibe, > /etc/passwd + + After this, close all Cygwin terminals (ensure nothing in + `C:\cygwin64` is running), then start a new Cygwin terminal and + your home directory should have moved. + + There are [other ways to do + this](https://stackoverflow.com/questions/1494658/how-can-i-change-my-cygwin-home-folder-after-installation), + but the above seems to be the simplest that's still supported. + +5. (Optional) Although it is possible to install Sage's dependencies using the + Cygwin graphical installer, it is recommended to install the + `apt-cyg `_ + command-line package installer, which is used for the remainder of + these instructions. To install ``apt-cyg``, run:: + + $ curl -OL https://rawgit.com/transcode-open/apt-cyg/master/apt-cyg + $ install apt-cyg /usr/local/bin + $ rm -f apt-cyg + +6. Then, to install the current set of system packages known to work for building + Sage, run the following command (or use the graphical installer to + select and install these packages): + + .. literalinclude:: cygwin.txt + + Optional packages that are also known to be installable via system packages + include: + + .. literalinclude:: cygwin-optional.txt + +.. NOTE:: + + On Cygwin, at any point in time after building/installing software, + it may be required to "rebase" ``dll`` files. + Sage provides some scripts, located in :file:`$SAGE_LOCAL/bin`, to do so: + + - ``sage-rebaseall.sh``, a shell script which calls Cygwin's + ``rebaseall`` program. It must be run within a ``dash`` shell + from the :envvar:`SAGE_ROOT` directory after all other Cygwin + processes have been shut down and needs write-access to the + system-wide rebase database located at + :file:`/etc/rebase.db.i386`, which usually means administrator + privileges. It updates the system-wide database and adds Sage + dlls to it, so that subsequent calls to ``rebaseall`` will take + them into account. + + - ``sage-rebase.sh``, a shell script which calls Cygwin's ``rebase`` program + together with the ``-O/--oblivious`` option. + It must be run within a shell from :envvar:`SAGE_ROOT` directory. + Contrary to the ``sage-rebaseall.sh`` script, it neither updates the + system-wide database, nor adds Sage dlls to it. + Therefore, subsequent calls to ``rebaseall`` will not take them into account. + + - ``sage-rebaseall.bat`` (respectively ``sage-rebase.bat``), an MS-DOS batch + file which calls the ``sage-rebaseall.sh`` (respectively ``sage-rebase.sh``) + script. + It must be run from a Windows command prompt, after adjusting + :envvar:`SAGE_ROOT` to the Windows location of Sage's home directory, and, if + Cygwin is installed in a non-standard location, adjusting + :envvar:`CYGWIN_ROOT` as well. + + Some systems may encounter this problem frequently enough to make building or + testing difficult. + If executing the above scripts or directly calling ``rebaseall`` does not solve + rebasing issues, deleting the system-wide database and then regenerating it + from scratch, e.g., by executing ``sage-rebaseall.sh``, might help. + + Other platforms ^^^^^^^^^^^^^^^ @@ -735,46 +823,6 @@ General procedure #. Have fun! Discover some amazing conjectures! -Rebasing issues on Cygwin -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Building on Cygwin will occasionally require "rebasing" ``dll`` files. -Sage provides some scripts, located in :file:`$SAGE_LOCAL/bin`, to do so: - -- ``sage-rebaseall.sh``, a shell script which calls Cygwin's ``rebaseall`` - program. - It must be run within a ``dash`` shell from the :envvar:`SAGE_ROOT` directory - after all other Cygwin processes have been shut down and needs write-access - to the system-wide rebase database located at :file:`/etc/rebase.db.i386`, - which usually means administrator privileges. - It updates the system-wide database and adds Sage dlls to it, so that - subsequent calls to ``rebaseall`` will take them into account. -- ``sage-rebase.sh``, a shell script which calls Cygwin's ``rebase`` program - together with the ``-O/--oblivious`` option. - It must be run within a shell from :envvar:`SAGE_ROOT` directory. - Contrary to the ``sage-rebaseall.sh`` script, it neither updates the - system-wide database, nor adds Sage dlls to it. - Therefore, subsequent calls to ``rebaseall`` will not take them into account. -- ``sage-rebaseall.bat`` (respectively ``sage-rebase.bat``), an MS-DOS batch - file which calls the ``sage-rebaseall.sh`` (respectively ``sage-rebase.sh``) - script. - It must be run from a Windows command prompt, after adjusting - :envvar:`SAGE_ROOT` to the Windows location of Sage's home directory, and, if - Cygwin is installed in a non-standard location, adjusting - :envvar:`CYGWIN_ROOT` as well. - -Some systems may encounter this problem frequently enough to make building or -testing difficult. -If executing the above scripts or directly calling ``rebaseall`` does not solve -rebasing issues, deleting the system-wide database and then regenerating it -from scratch, e.g., by executing ``sage-rebaseall.sh``, might help. - -Finally, on Cygwin, one should also avoid the following: - -- building in home directories of Windows domain users; -- building in paths with capital letters - (see :trac:`13343`, although there has been some success doing so). - .. _section_make: From 550b3374a87aab5c8949e058f4d3d27f84bd6e79 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 19:34:30 -0700 Subject: [PATCH 328/591] README.md, src/doc/en/installation/index.rst: Remove mention of Cygwin --- README.md | 2 +- src/doc/en/installation/index.rst | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index cf92b803b16..7df0d64900f 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Supported Platforms ------------------- Sage attempts to support all major Linux distributions, recent versions of -macOS, and Windows (using Windows Subsystem for Linux, Cygwin, or +macOS, and Windows (using Windows Subsystem for Linux or virtualization). Detailed information on supported platforms for a specific version of Sage diff --git a/src/doc/en/installation/index.rst b/src/doc/en/installation/index.rst index 6a0b439ac66..8ec84509af2 100644 --- a/src/doc/en/installation/index.rst +++ b/src/doc/en/installation/index.rst @@ -80,10 +80,6 @@ Windows can use any of the installation methods described below for Linux. - - Alternatively, in particular if you cannot use WSL, install - `Cygwin `_ and then build SageMath from source - as described in section :ref:`sec-installation-from-sources`. - Linux ===== From 6ccd9e4203f2f6364f279e6d180a32da2c8a0012 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 11 Aug 2022 11:22:40 +0900 Subject: [PATCH 329/591] Optimization of add_*_border_strip() and doctest update. --- src/sage/combinat/partition.py | 118 ++++++++++++++++++---------- src/sage/combinat/superpartition.py | 54 ++++++------- src/sage/combinat/tableau.py | 20 ++--- 3 files changed, 113 insertions(+), 79 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 811679ede16..6b8b2f669e4 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -318,8 +318,8 @@ from . import permutation from . import composition from sage.combinat.partitions import ZS1_iterator, ZS1_iterator_nk -from sage.combinat.integer_vector import IntegerVectors from sage.combinat.integer_lists import IntegerListsLex +from sage.combinat.integer_lists.invlex import IntegerListsBackend_invlex from sage.combinat.integer_vector_weighted import iterator_fast as weighted_iterator_fast from sage.combinat.combinat_cython import conjugate from sage.combinat.root_system.weyl_group import WeylGroup @@ -4655,6 +4655,8 @@ def add_vertical_border_strip(self, k): sage: Partition([]).add_vertical_border_strip(0) [[]] + sage: Partition([3,2,1]).add_vertical_border_strip(0) + [[3, 2, 1]] sage: Partition([]).add_vertical_border_strip(2) [[1, 1]] sage: Partition([2,2]).add_vertical_border_strip(2) @@ -4662,60 +4664,92 @@ def add_vertical_border_strip(self, k): sage: Partition([3,2,2]).add_vertical_border_strip(2) [[4, 3, 2], [4, 2, 2, 1], [3, 3, 3], [3, 3, 2, 1], [3, 2, 2, 1, 1]] """ - return [p.conjugate() for p in self.conjugate().add_horizontal_border_strip(k)] + if k == 0: + return [self] - def add_horizontal_border_strip(self, k): - """ - Return a list of all the partitions that can be obtained by adding - a horizontal border strip of length ``k`` to ``self``. - - EXAMPLES:: - - sage: Partition([]).add_horizontal_border_strip(0) - [[]] - sage: Partition([]).add_horizontal_border_strip(2) - [[2]] - sage: Partition([2,2]).add_horizontal_border_strip(2) - [[2, 2, 2], [3, 2, 1], [4, 2]] - sage: Partition([3,2,2]).add_horizontal_border_strip(2) - [[3, 2, 2, 2], [3, 3, 2, 1], [4, 2, 2, 1], [4, 3, 2], [5, 2, 2]] - - .. TODO:: - - Reimplement like ``remove_horizontal_border_strip`` using - :class:`IntegerListsLex` - """ - conj = self.conjugate().to_list() shelf = [] res = [] i = 0 - while i < len(conj): + ell = len(self._list) + while i < ell: tmp = 1 - while i+1 < len(conj) and conj[i] == conj[i+1]: + while i+1 < ell and self._list[i] == self._list[i+1]: tmp += 1 i += 1 - if i == len(conj)-1 and i > 0 and conj[i] != conj[i-1]: + if i == ell-1 and i > 0 and self._list[i] != self._list[i-1]: tmp = 1 shelf.append(tmp) i += 1 - #added the last shelf on the right side of - #the first line + # added the last shelf on the right side of + # the first line shelf.append(k) - #list all of the positions for cells - #filling each self from the left to the right - for iv in IntegerVectors(k, len(shelf), outer=shelf): - iv = list(iv) # Make a mutable list - tmp = conj + [0]*k + # list all of the positions for cells + # filling each self from the left to the right + for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter(): + tmp = self._list + [0]*k j = 0 for t in range(len(iv)): - while iv[t] > 0: + for _ in range(iv[t]): tmp[j] += 1 - iv[t] -= 1 j += 1 j = sum(shelf[:t+1]) - res.append(Partition([u for u in tmp if u != 0]).conjugate()) + # This should never return the empty partition. + # So tmp should never be [0, ..., 0]. + while not tmp[-1]: + tmp.pop() + res.append(_Partitions(tmp)) + return res + + def add_horizontal_border_strip(self, k): + """ + Return a list of all the partitions that can be obtained by adding + a horizontal border strip of length ``k`` to ``self``. + + EXAMPLES:: + + sage: Partition([]).add_horizontal_border_strip(0) + [[]] + sage: Partition([3,2,1]).add_horizontal_border_strip(0) + [[3, 2, 1]] + sage: Partition([]).add_horizontal_border_strip(2) + [[2]] + sage: Partition([2,2]).add_horizontal_border_strip(2) + [[4, 2], [3, 2, 1], [2, 2, 2]] + sage: Partition([3,2,2]).add_horizontal_border_strip(2) + [[5, 2, 2], [4, 3, 2], [4, 2, 2, 1], [3, 3, 2, 1], [3, 2, 2, 2]] + """ + if k == 0: + return [self] + + L = self._list + res = [] + mapping = [0] + shelf = [k] + for i in range(len(L)-1): + val = L[i] - L[i+1] + if not val: + continue + mapping.append(i+1) + shelf.append(val) + + # add the last shelf + if L: + mapping.append(len(L)) + shelf.append(L[-1]) + + # list all of the positions for cells + # filling each self from the top to bottom + for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter(): + tmp = self._list + [0] + for i, val in enumerate(iv): + if val: + tmp[mapping[i]] += val + # Only the last row is possibly empty + if not tmp[-1]: + tmp.pop() + res.append(_Partitions(tmp)) return res def remove_horizontal_border_strip(self, k): @@ -4839,7 +4873,7 @@ def atom(self): return res def k_atom(self, k): - """ + r""" Return a list of the standard tableaux of size ``self.size()`` whose ``k``-atom is equal to ``self``. @@ -4849,12 +4883,12 @@ def k_atom(self, k): sage: p.k_atom(1) [] sage: p.k_atom(3) - [[[1, 1, 1], [2, 2], [3]], - [[1, 1, 1, 2], [2], [3]], + [[[1, 1, 1, 2, 3], [2]], [[1, 1, 1, 3], [2, 2]], - [[1, 1, 1, 2, 3], [2]]] + [[1, 1, 1, 2], [2], [3]], + [[1, 1, 1], [2, 2], [3]]] sage: Partition([3,2,1]).k_atom(4) - [[[1, 1, 1], [2, 2], [3]], [[1, 1, 1, 3], [2, 2]]] + [[[1, 1, 1, 3], [2, 2]], [[1, 1, 1], [2, 2], [3]]] TESTS:: diff --git a/src/sage/combinat/superpartition.py b/src/sage/combinat/superpartition.py index ced73e8dadd..1981b6bae0e 100644 --- a/src/sage/combinat/superpartition.py +++ b/src/sage/combinat/superpartition.py @@ -678,19 +678,19 @@ def add_horizontal_border_strip_star(self, h) -> list: EXAMPLES:: sage: SuperPartition([[4,1],[3]]).add_horizontal_border_strip_star(3) - [[4, 1; 3, 3], - [4, 1; 4, 2], - [3, 1; 5, 2], - [4, 1; 5, 1], + [[3, 1; 7], + [4, 1; 6], + [3, 0; 6, 2], [3, 1; 6, 1], - [4, 0; 4, 3], - [3, 0; 5, 3], [4, 0; 5, 2], - [3, 0; 6, 2], - [4, 1; 6], - [3, 1; 7]] + [4, 1; 5, 1], + [3, 0; 5, 3], + [3, 1; 5, 2], + [4, 0; 4, 3], + [4, 1; 4, 2], + [4, 1; 3, 3]] sage: SuperPartition([[2,1],[3]]).add_horizontal_border_strip_star(2) - [[2, 1; 3, 2], [2, 1; 4, 1], [2, 0; 3, 3], [2, 0; 4, 2], [2, 1; 5]] + [[2, 1; 5], [2, 0; 4, 2], [2, 1; 4, 1], [2, 0; 3, 3], [2, 1; 3, 2]] """ sp1, circ_list = self.to_circled_diagram() nsp = [list(la) + [0] for la in sp1.add_horizontal_border_strip(h)] @@ -726,29 +726,29 @@ def add_horizontal_border_strip_star_bar(self, h) -> list: EXAMPLES:: sage: SuperPartition([[4,1],[5,4]]).add_horizontal_border_strip_star_bar(3) - [[4, 3; 5, 4, 1], - [4, 1; 5, 4, 3], - [4, 2; 5, 5, 1], - [4, 1; 5, 5, 2], + [[4, 1; 8, 4], + [4, 1; 7, 5], + [4, 2; 7, 4], + [4, 1; 7, 4, 1], + [4, 2; 6, 5], + [4, 1; 6, 5, 1], + [4, 3; 6, 4], [4, 2; 6, 4, 1], [4, 1; 6, 4, 2], - [4, 1; 6, 5, 1], - [4, 1; 7, 4, 1], [4, 3; 5, 5], - [4, 3; 6, 4], - [4, 2; 6, 5], - [4, 2; 7, 4], - [4, 1; 7, 5], - [4, 1; 8, 4]] + [4, 2; 5, 5, 1], + [4, 1; 5, 5, 2], + [4, 3; 5, 4, 1], + [4, 1; 5, 4, 3]] sage: SuperPartition([[3,1],[5]]).add_horizontal_border_strip_star_bar(2) - [[3, 2; 5, 1], - [3, 1; 5, 2], - [4, 1; 5, 1], + [[3, 1; 7], + [4, 1; 6], + [3, 2; 6], [3, 1; 6, 1], [4, 2; 5], - [3, 2; 6], - [4, 1; 6], - [3, 1; 7]] + [4, 1; 5, 1], + [3, 2; 5, 1], + [3, 1; 5, 2]] """ sp1, circ_list = self.to_circled_diagram() nsp = [list(la) + [0] for la in sp1.add_horizontal_border_strip(h)] diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index c45fb0f2e87..f5652f86733 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -3239,26 +3239,26 @@ def promotion_operator(self, i): sage: t = Tableau([[1,2],[3]]) sage: t.promotion_operator(1) - [[[1, 2], [3], [4]], [[1, 2], [3, 4]], [[1, 2, 4], [3]]] + [[[1, 2, 4], [3]], [[1, 2], [3, 4]], [[1, 2], [3], [4]]] sage: t.promotion_operator(2) - [[[1, 1], [2, 3], [4]], - [[1, 1, 2], [3], [4]], + [[[1, 1, 2, 4], [3]], [[1, 1, 4], [2, 3]], - [[1, 1, 2, 4], [3]]] + [[1, 1, 2], [3], [4]], + [[1, 1], [2, 3], [4]]] sage: Tableau([[1]]).promotion_operator(2) - [[[1, 1], [2]], [[1, 1, 2]]] + [[[1, 1, 2]], [[1, 1], [2]]] sage: Tableau([[1,1],[2]]).promotion_operator(3) - [[[1, 1, 1], [2, 2], [3]], - [[1, 1, 1, 2], [2], [3]], + [[[1, 1, 1, 2, 3], [2]], [[1, 1, 1, 3], [2, 2]], - [[1, 1, 1, 2, 3], [2]]] + [[1, 1, 1, 2], [2], [3]], + [[1, 1, 1], [2, 2], [3]]] The example from [LLM2003]_ p. 12:: sage: Tableau([[1,1],[2,2]]).promotion_operator(3) - [[[1, 1, 1], [2, 2], [3, 3]], + [[[1, 1, 1, 3, 3], [2, 2]], [[1, 1, 1, 3], [2, 2], [3]], - [[1, 1, 1, 3, 3], [2, 2]]] + [[1, 1, 1], [2, 2], [3, 3]]] TESTS:: From 503ba263b9f6b8b3355e2999bca99b9ea1418b5c Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 11 Aug 2022 12:35:36 +0900 Subject: [PATCH 330/591] Updating doctests and making sure valuation() returns a Sage Integer or oo. --- src/sage/rings/lazy_series.py | 9 ++++--- src/sage/rings/lazy_series_ring.py | 25 +++++++++++-------- .../rings/polynomial/laurent_polynomial.pyx | 14 ++++++++--- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 30bf0c61cdf..f2727605a4e 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -2076,9 +2076,10 @@ def valuation(self): 1 sage: (M - M).valuation() +Infinity - """ - return self._coeff_stream.order() + if isinstance(self._coeff_stream, Stream_zero): + return self._coeff_stream.order() + return ZZ(self._coeff_stream.order()) def _mul_(self, other): """ @@ -3697,8 +3698,10 @@ def valuation(self): sage: (g*g).valuation() 2*log(2) """ + if isinstance(self._coeff_stream, Stream_zero): + return self._coeff_stream.order() from sage.functions.log import log - return log(self._coeff_stream.order()) + return log(ZZ(self._coeff_stream.order())) def _mul_(self, other): """ diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index dbb010999ed..9a66e2cd39c 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -236,14 +236,14 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L(L(1), valuation=-4) z^-4 sage: L(1/(1-z), valuation=-4) - z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) + z^-4 + z^-3 + z^-2 + O(z^-1) sage: L(z^-3/(1-z), valuation=-4) - z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) + z^-4 + z^-3 + z^-2 + O(z^-1) sage: L(z^3/(1-z), valuation=-4) - z^-4 + z^-3 + z^-2 + z^-1 + 1 + z + z^2 + O(z^3) + z^-4 + z^-3 + z^-2 + O(z^-1) sage: L(z^3/(1-z), valuation=0) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + 1 + z + z^2 + O(z^3) sage: L = LazyLaurentSeriesRing(ZZ, 'z') sage: L(lambda n: 1/(n+1), degree=3) @@ -449,7 +449,7 @@ class LazyLaurentSeriesRing(LazySeriesRing): sage: L. = LazyLaurentSeriesRing(QQ) sage: 1 / (1 - z) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + 1 + z + z^2 + O(z^3) sage: 1 / (1 - z) == 1 / (1 - z) True sage: L in Fields @@ -732,7 +732,7 @@ def gens(self): sage: L.gens() (z,) sage: 1/(1 - z) - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + 1 + z + z^2 + O(z^3) """ return tuple([self.gen(n) for n in range(self.ngens())]) @@ -816,7 +816,7 @@ def some_elements(self): [0, 1, z, z^-3 + z^-1 + 2 + z + z^2 + z^3, z^2 + z^3 + z^4 + z^5 + O(z^6), - z^-3 + z^-2 + z^-1 + 2 + 2*z + 2*z^2 + 2*z^3 + O(z^4), + z^-3 + z^-2 + z^-1 + 2 + 2*z + 2*z^2 + O(z^3), z^-2 + z^-1 + z + z^2 + z^4 + O(z^5)] """ z = self.gen() @@ -870,18 +870,23 @@ class options(GlobalOptions): sage: LLS. = LazyLaurentSeriesRing(QQ) sage: LLS.options.display_length 7 - sage: f = 1/(1-z) + sage: f = 1 / (1 + z) sage: f - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + 1 - z + z^2 - z^3 + z^4 - z^5 + z^6 + O(z^7) sage: LLS.options.display_length = 10 sage: f - 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + z^8 + z^9 + O(z^10) + 1 - z + z^2 - z^3 + z^4 - z^5 + z^6 - z^7 + z^8 - z^9 + O(z^10) sage: g = LLS(lambda n: n^2, valuation=-2, degree=5, constant=42) sage: g 4*z^-2 + z^-1 + z + 4*z^2 + 9*z^3 + 16*z^4 + 42*z^5 + 42*z^6 + 42*z^7 + O(z^8) + sage: h = 1 / (1 - z) # This is exact + sage: h + 1 + z + z^2 + O(z^3) sage: LLS.options.constant_length = 1 sage: g 4*z^-2 + z^-1 + z + 4*z^2 + 9*z^3 + 16*z^4 + 42*z^5 + O(z^6) + sage: h + 1 + O(z) sage: LazyLaurentSeriesRing.options._reset() sage: LazyLaurentSeriesRing.options.display_length 7 diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 67650c76158..0bd8dd593b4 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1340,7 +1340,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): @coerce_binop def quo_rem(self, right_r): - """ + r""" Attempts to divide ``self`` by ``right`` and returns a quotient ``q`` and a remainder ``r`` such that ``self = q*other + r``. @@ -1352,7 +1352,8 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: (t^-2 + 3 + t).quo_rem(t^-4) (t^2 + 3*t^4 + t^5, 0) - sage: num, den = t^-2 + t, t^-2 + 1 + sage: num = t^-2 + t + sage: den = t^-2 + 1 sage: q, r = num.quo_rem(den) sage: num == q * den + r True @@ -1361,11 +1362,18 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Check that :trac:`34330` is fixed:: - sage: num, den = t^-2 + 3 + t, t^-4 + t + sage: num = t^-2 + 3 + t + sage: den = t^-4 + t sage: q, r = num.quo_rem(den); q, r (0, t^-2 + 3 + t) sage: num == q * den + r True + + sage: num = 2*t^-4 + t^-3 + t^-2 + 2*t + 2*t^2 + sage: q, r = num.quo_rem(den); q, r + (2 + 2*t, -t^-3 + t^-2) + sage: num == q * den + r + True """ cdef LaurentPolynomial_univariate right = right_r q, r = self.__u.quo_rem(right.__u) From 87981391d758ccad3db3e5945ccff74dfb383ad9 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 11 Aug 2022 12:41:32 +0900 Subject: [PATCH 331/591] Adding a slightly more complicated doctest and other small tweaks. --- src/sage/rings/polynomial/laurent_polynomial.pyx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 0fc936f4bba..da9b447f879 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1340,7 +1340,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): @coerce_binop def quo_rem(self, other): - """ + r""" Divide ``self`` by ``other`` and return a quotient ``q`` and a remainder ``r`` such that ``self == q * other + r``. @@ -1352,7 +1352,8 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: (t^-2 + 3 + t).quo_rem(t^-4) (t^2 + 3*t^4 + t^5, 0) - sage: num, den = t^-2 + t, t^-2 + 1 + sage: num = t^-2 + t + sage: den = t^-2 + 1 sage: q, r = num.quo_rem(den) sage: num == q * den + r True @@ -1361,11 +1362,18 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Check that :trac:`34330` is fixed:: - sage: num, den = t^-2 + 3 + t, t^-4 + t + sage: num = t^-2 + 3 + t + sage: den = t^-4 + t sage: q, r = num.quo_rem(den); q, r (0, t^-2 + 3 + t) sage: num == q * den + r True + + sage: num = 2*t^-4 + t^-3 + t^-2 + 2*t + 2*t^2 + sage: q, r = num.quo_rem(den); q, r + (2 + 2*t, -t^-3 + t^-2) + sage: num == q * den + r + True """ cdef LaurentPolynomial_univariate right = other q, r = self.__u.quo_rem(right.__u) From e3af6c9bc6816f5a7daab8fe188032736bb6d993 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 21:22:46 -0700 Subject: [PATCH 332/591] src/doc/en/installation/index.rst: Fix markup --- src/doc/en/installation/source.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index be70b69b5e2..39ccff55e52 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -356,8 +356,8 @@ it necessary to build Sage on Cygwin. .. WARNING:: - As of Sage 9.7, `known issues with several packages - _ + As of Sage 9.7, :trac:`known issues with several packages + ` will prevent a successful installation. Users need to be prepared to contribute to Sage by fixing these issues. From 132083f3450318a09d23352f9fce9d7c75333612 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 22:51:53 -0700 Subject: [PATCH 333/591] src/doc/en/developer/portability_testing.rst: Explain the downstream-... devcontainers --- src/doc/en/developer/portability_testing.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 65846a1bb43..70e945d50a5 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1179,3 +1179,17 @@ the `VS Code devcontainer.json reference and the `GitHub introduction to dev containers `_ for more information. + +In addition to the ``.devcontainer/portability-.../devcontainer.json`` files, Sage also +provides several other sample ``devcontainer.json`` configuration files: + +- `.devcontainer/downstream-archlinux-latest/devcontainer.json + `_ + configures a container with an installation of `Arch Linux ` + and its SageMath package. (Arch Linux packaging is downstream from the Sage project, + hence the prefix ``downstream-...``; the suffix ``latest`` indicates + the most recent version of Arch Linux as available on Docker Hub.) + +- `.devcontainer/downstream-conda-forge-latest/devcontainer.json + `_ + similarly configures a container with an installation of conda-forge and its SageMath package. From d0790b4b33b427493dd99c1b29cc4cb27e56f6f7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 23:07:50 -0700 Subject: [PATCH 334/591] src/doc/en/developer/portability_testing.rst: Explain more about devcontainers --- src/doc/en/developer/portability_testing.rst | 25 +++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 70e945d50a5..8dc671fd502 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1185,7 +1185,7 @@ provides several other sample ``devcontainer.json`` configuration files: - `.devcontainer/downstream-archlinux-latest/devcontainer.json `_ - configures a container with an installation of `Arch Linux ` + configures a container with an installation of `Arch Linux `_ and its SageMath package. (Arch Linux packaging is downstream from the Sage project, hence the prefix ``downstream-...``; the suffix ``latest`` indicates the most recent version of Arch Linux as available on Docker Hub.) @@ -1193,3 +1193,26 @@ provides several other sample ``devcontainer.json`` configuration files: - `.devcontainer/downstream-conda-forge-latest/devcontainer.json `_ similarly configures a container with an installation of conda-forge and its SageMath package. + +- `.devcontainer/cocalc/devcontainer.json + `_ + configures a container with `the CoCalc Docker image `_. + It then updates the installation of SageMath in this container by building from + the current source tree. + +- `.devcontainer/computop-sage/devcontainer.json + `_ + configures a container with the `Docker image from the 3-manifolds + project `_, providing + SnapPy, Regina, PHCPack, etc. It then updates the installation of + SageMath in this container by building from the current source tree. + +- `.devcontainer/sagemath-sagemath/devcontainer.json + `_ + configures a container with `SageMath's official Docker image `_. + It then updates the installation of SageMath in this container by building from + the current source tree. + +These ``devcontainer.json`` configuration files are useful for testing +user scripts on these deployments of SageMath. You may also find it +useful to copy these configurations into your own projects or to adapt them to your needs. From a9f37fa8f1ecaf7b3181c71a6da75197905b3e92 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 23:24:31 -0700 Subject: [PATCH 335/591] .devcontainer/Dockerfile: Add comment --- .devcontainer/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 22465185f5e..52ca0bc6c75 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,3 +1,5 @@ +# This Dockerfile is used by all portability-.../devcontainer.json files, +# which provide the actual values for the 4 arguments defined below. ARG SYSTEM_FACTOR="ubuntu-jammy" ARG PACKAGE_FACTOR="standard" ARG DOCKER_TARGET="with-system-packages" From 97ae98d43829256ae7b7cfa509c2aa569bcd648d Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 11 Aug 2022 16:05:16 +0800 Subject: [PATCH 336/591] 33972 final version --- .../arithmetic_dynamics/projective_ds.py | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index c814b81987a..8e4e3ad7aa4 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -2104,36 +2104,31 @@ def height_difference_bound(self, prec=None): EXAMPLES:: - sage: P. = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2+y^2, x*y]) + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^2 + y^2, x*y]) sage: f.height_difference_bound() 1.38629436111989 - This function does not automatically normalize. :: - - sage: P. = ProjectiveSpace(ZZ,2) - sage: f = DynamicalSystem_projective([4*x^2+100*y^2, 210*x*y, 10000*z^2]) - sage: f.height_difference_bound() - 12.1007121298723 - sage: f.normalize_coordinates() + sage: P. = ProjectiveSpace(ZZ, 2) + sage: f = DynamicalSystem_projective([4*x^2 + 100*y^2, 210*x*y, 10000*z^2]) sage: f.height_difference_bound() - 11.4075649493124 + 10.3089526606443 - A number field example:: + A number field example:: sage: R. = QQ[] sage: K. = NumberField(x^3 - 2) - sage: P. = ProjectiveSpace(K,2) - sage: f = DynamicalSystem_projective([1/(c+1)*x^2+c*y^2, 210*x*y, 10000*z^2]) + sage: P. = ProjectiveSpace(K, 2) + sage: f = DynamicalSystem_projective([1/(c+1)*x^2 + c*y^2, 210*x*y, 10000*z^2]) sage: f.height_difference_bound() - 12.1007121298723 + 11.3683039374269 :: - sage: P. = ProjectiveSpace(QQbar,2) + sage: P. = ProjectiveSpace(QQbar, 2) sage: f = DynamicalSystem_projective([x^2, QQbar(sqrt(-1))*y^2, QQbar(sqrt(3))*z^2]) sage: f.height_difference_bound() - 3.43967790223022 + 2.89037175789616 :: @@ -2167,7 +2162,7 @@ def height_difference_bound(self, prec=None): maxh = 0 for k in range(N + 1): CoeffPolys = (CR.gen(k) ** D).lift(I) - h = max([c.global_height(prec) for g in CoeffPolys for c in (g).coefficients()]) + h = max([g.global_height(prec) for g in CoeffPolys]) maxh = max(maxh, h) L = R((N + 1) * binomial(N + D - d, D - d)).log() + maxh C = max(U, L) #height difference dh(P) - L <= h(f(P)) <= dh(P) +U From c74fd7105cc842367cef01807efce41d3c95b70f Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 11 Aug 2022 12:48:50 +0200 Subject: [PATCH 337/591] improve documentation, move options to abstract base class --- src/sage/rings/lazy_series.py | 24 +++-- src/sage/rings/lazy_series_ring.py | 156 +++++++++++++++++------------ 2 files changed, 104 insertions(+), 76 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index f2727605a4e..46c8c305f29 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -1,9 +1,16 @@ # -*- coding: utf-8 -*- -r"""Lazy Series +r""" +Lazy Series -A lazy series is a series whose coefficients are computed on demand. -Therefore, unlike the usual Laurent/power/etc. series in Sage, -lazy series have infinite precision. +Coefficients of lazy series are computed on demand. They have +infinite precision, although equality can only be decided in special +cases. + +AUTHORS: + +- Kwankyu Lee (2019-02-24): initial version +- Tejasvi Chebrolu, Martin Rubey, Travis Scrimshaw (2021-08): + refactored and expanded functionality EXAMPLES: @@ -93,12 +100,6 @@ sage: hinv.valuation() -1 -AUTHORS: - -- Kwankyu Lee (2019-02-24): initial version -- Tejasvi Chebrolu, Martin Rubey, Travis Scrimshaw (2021-08): - refactored and expanded functionality - """ # **************************************************************************** @@ -758,6 +759,9 @@ def define(self, s): raise ValueError("series already defined") self._coeff_stream._target = s._coeff_stream + # an alias for compatibility with padics + set = define + def _repr_(self): r""" Return a string representation of ``self``. diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 9a66e2cd39c..68dac09b15e 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1,6 +1,18 @@ r""" Lazy Series Rings +We provide lazy implementations for various `\NN`-graded rings. + +.. csv-table:: + :class: contentstable + :widths: 30, 70 + :delim: | + + :class:`LazyLaurentSeriesRing` | The ring of lazy Laurent series. + :class:`LazyTaylorSeriesRing` | The ring of (possibly multivariate) lazy Taylor series. + :class:`LazySymmetricFunctions` | The ring of (possibly multivariate) lazy symmetric functions. + :class:`LazyDirichletSeriesRing` | The ring of lazy Dirichlet series. + AUTHORS: - Kwankyu Lee (2019-02-24): initial version @@ -34,7 +46,6 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.combinat.sf.sf import SymmetricFunctions from sage.rings.lazy_series import (LazyModuleElement, LazyLaurentSeries, LazyTaylorSeries, @@ -430,6 +441,74 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No raise ValueError(f"unable to convert {x} into {self}") + def unknown(self, valuation=None): + """ + Return an uninitialized series. + + INPUT: + + - ``valuation`` -- integer; a lower bound for the valuation of the series + + Power series can be defined recursively (see + :meth:`sage.rings.lazy_series.LazyModuleElement.define()` for + more examples):: + + EXAMPLES:: + + sage: L. = LazyTaylorSeriesRing(QQ) + sage: s = L.unknown(1) + sage: s.define(z + (s^2+s(z^2))/2) + sage: s + z + z^2 + z^3 + 2*z^4 + 3*z^5 + 6*z^6 + 11*z^7 + O(z^8) + """ + return self(None, valuation=valuation) + + class options(GlobalOptions): + r""" + Set and display the options for Lazy Laurent series. + + If no parameters are set, then the function returns a copy of + the options dictionary. + + The ``options`` to Lazy Laurent series can be accessed as using + :class:`LazyLaurentSeriesRing.options` of :class:`LazyLaurentSeriesRing`. + + @OPTIONS@ + + EXAMPLES:: + + sage: LLS. = LazyLaurentSeriesRing(QQ) + sage: LLS.options.display_length + 7 + sage: f = 1 / (1 + z) + sage: f + 1 - z + z^2 - z^3 + z^4 - z^5 + z^6 + O(z^7) + sage: LLS.options.display_length = 10 + sage: f + 1 - z + z^2 - z^3 + z^4 - z^5 + z^6 - z^7 + z^8 - z^9 + O(z^10) + sage: g = LLS(lambda n: n^2, valuation=-2, degree=5, constant=42) + sage: g + 4*z^-2 + z^-1 + z + 4*z^2 + 9*z^3 + 16*z^4 + 42*z^5 + 42*z^6 + 42*z^7 + O(z^8) + sage: h = 1 / (1 - z) # This is exact + sage: h + 1 + z + z^2 + O(z^3) + sage: LLS.options.constant_length = 1 + sage: g + 4*z^-2 + z^-1 + z + 4*z^2 + 9*z^3 + 16*z^4 + 42*z^5 + O(z^6) + sage: h + 1 + O(z) + sage: LazyLaurentSeriesRing.options._reset() + sage: LazyLaurentSeriesRing.options.display_length + 7 + """ +# NAME = 'LazyLaurentSeriesRing' + module = 'sage.rings.lazy_series_ring' + display_length = dict(default=7, + description='the number of coefficients to display from the valuation', + checker=lambda x: x in ZZ and x > 0) + constant_length = dict(default=3, + description='the number of coefficients to display for nonzero constant series', + checker=lambda x: x in ZZ and x > 0) class LazyLaurentSeriesRing(LazySeriesRing): """ @@ -537,7 +616,8 @@ class LazyLaurentSeriesRing(LazySeriesRing): sage: L(f, valuation=1, degree=4, constant=5) z - z^2 + z^3 + 5*z^4 + 5*z^5 + 5*z^6 + O(z^7) - Power series can be defined recursively (see :meth:`define()` for + Power series can be defined recursively (see + :meth:`sage.rings.lazy_series.LazyModuleElement.define()` for more examples):: sage: L. = LazyLaurentSeriesRing(ZZ) @@ -576,6 +656,7 @@ class LazyLaurentSeriesRing(LazySeriesRing): sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: L.is_sparse() False + """ Element = LazyLaurentSeries @@ -852,54 +933,6 @@ def zero(self): """ return self.element_class(self, Stream_zero(self._sparse)) - # add options to class - class options(GlobalOptions): - r""" - Set and display the options for Lazy Laurent series. - - If no parameters are set, then the function returns a copy of - the options dictionary. - - The ``options`` to Lazy Laurent series can be accessed as using - :class:`LazyLaurentSeriesRing.options` of :class:`LazyLaurentSeriesRing`. - - @OPTIONS@ - - EXAMPLES:: - - sage: LLS. = LazyLaurentSeriesRing(QQ) - sage: LLS.options.display_length - 7 - sage: f = 1 / (1 + z) - sage: f - 1 - z + z^2 - z^3 + z^4 - z^5 + z^6 + O(z^7) - sage: LLS.options.display_length = 10 - sage: f - 1 - z + z^2 - z^3 + z^4 - z^5 + z^6 - z^7 + z^8 - z^9 + O(z^10) - sage: g = LLS(lambda n: n^2, valuation=-2, degree=5, constant=42) - sage: g - 4*z^-2 + z^-1 + z + 4*z^2 + 9*z^3 + 16*z^4 + 42*z^5 + 42*z^6 + 42*z^7 + O(z^8) - sage: h = 1 / (1 - z) # This is exact - sage: h - 1 + z + z^2 + O(z^3) - sage: LLS.options.constant_length = 1 - sage: g - 4*z^-2 + z^-1 + z + 4*z^2 + 9*z^3 + 16*z^4 + 42*z^5 + O(z^6) - sage: h - 1 + O(z) - sage: LazyLaurentSeriesRing.options._reset() - sage: LazyLaurentSeriesRing.options.display_length - 7 - """ - NAME = 'LazyLaurentSeriesRing' - module = 'sage.rings.lazy_series_ring' - display_length = dict(default=7, - description='the number of coefficients to display from the valuation', - checker=lambda x: x in ZZ and x > 0) - constant_length = dict(default=3, - description='the number of coefficients to display for nonzero constant series', - checker=lambda x: x in ZZ and x > 0) - def series(self, coefficient, valuation, degree=None, constant=None): r""" Return a lazy Laurent series. @@ -1003,9 +1036,9 @@ def _monomial(self, c, n): ###################################################################### -class LazyTaylorSeriesRing(UniqueRepresentation, Parent): +class LazyTaylorSeriesRing(LazySeriesRing): """ - Lazy Taylor series ring. + The ring of (possibly multivariate) lazy Taylor series. INPUT: @@ -1292,7 +1325,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if valuation < 0: raise ValueError("the valuation of a Taylor series must be positive") if len(self.variable_names()) > 1: - raise ValueError(f"valuation must not be specified for multivariate Taylor series") + raise ValueError("valuation must not be specified for multivariate Taylor series") if len(self.variable_names()) > 1: valuation = 0 @@ -1311,7 +1344,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No constant, degree = constant if constant is not None: if len(self.variable_names()) > 1 and constant: - raise ValueError(f"constant must be zero for multivariate Taylor series") + raise ValueError("constant must be zero for multivariate Taylor series") constant = BR(constant) if x in R: if not x and not constant: @@ -1353,7 +1386,6 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if degree is not None: if constant is None: constant = ZZ.zero() - z = R.gen() if len(self.variable_names()) == 1: p = [BR(x(i)) for i in range(valuation, degree)] else: @@ -1422,13 +1454,11 @@ def zero(self): """ return self.element_class(self, Stream_zero(self._sparse)) - options = LazyLaurentSeriesRing.options - ###################################################################### -class LazySymmetricFunctions(UniqueRepresentation, Parent): +class LazySymmetricFunctions(LazySeriesRing): """ - Lazy symmetric functions. + The ring of lazy symmetric functions. INPUT: @@ -1636,7 +1666,6 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) R = self._laurent_poly_ring - BR = self.base_ring() if x is None: assert degree is None coeff_stream = Stream_uninitialized(self._sparse, valuation) @@ -1741,7 +1770,6 @@ def _an_element_(self): sage: L.an_element() m[] """ - c = self.base_ring()(1) R = self._laurent_poly_ring coeff_stream = Stream_exact([R.one()], self._sparse, order=1, constant=0) return self.element_class(self, coeff_stream) @@ -1776,13 +1804,11 @@ def zero(self): """ return self.element_class(self, Stream_zero(self._sparse)) - options = LazyLaurentSeriesRing.options - ###################################################################### class LazyDirichletSeriesRing(LazySeriesRing): """ - Lazy Dirichlet series ring. + The ring of lazy Dirichlet series. INPUT: @@ -2055,5 +2081,3 @@ def _monomial(self, c, n): return L(c) * L(n) ** -L(self.variable_name()) except (ValueError, TypeError): return '({})/{}^{}'.format(self.base_ring()(c), n, self.variable_name()) - - options = LazyLaurentSeriesRing.options From feba6b8997b7d11a11f252b1ee957e68cfdf1bc5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 11 Aug 2022 20:22:58 +0900 Subject: [PATCH 338/591] Working more on __call__ for LazySymFunc. --- src/sage/data_structures/stream.py | 1 + src/sage/rings/lazy_series.py | 159 +++++++++++++++++++++++++---- src/sage/rings/lazy_series_ring.py | 1 + 3 files changed, 140 insertions(+), 21 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index f83eeff0b89..4a08ac29ef8 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -2195,3 +2195,4 @@ def is_nonzero(self): True """ return self._series.is_nonzero() + diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index f2727605a4e..043290a333b 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -722,9 +722,13 @@ def define(self, s): sage: L = LazySymmetricFunctions(m) sage: E = L(lambda n: s[n], valuation=0) sage: X = L(s[1]) - sage: A = L(None); A.define(X*E(A)) + sage: A = L(None, valuation=1); A.define(X*E(A)) sage: A - m[1] + (2*m[1,1]+m[2]) + (9*m[1,1,1]+5*m[2,1]+2*m[3]) + (64*m[1,1,1,1]+34*m[2,1,1]+18*m[2,2]+13*m[3,1]+4*m[4]) + (625*m[1,1,1,1,1]+326*m[2,1,1,1]+171*m[2,2,1]+119*m[3,1,1]+63*m[3,2]+35*m[4,1]+9*m[5]) + (7776*m[1,1,1,1,1,1]+4016*m[2,1,1,1,1]+2078*m[2,2,1,1]+1077*m[2,2,2]+1433*m[3,1,1,1]+744*m[3,2,1]+268*m[3,3]+401*m[4,1,1]+209*m[4,2]+95*m[5,1]+20*m[6]) + O^7 + m[1] + (2*m[1,1]+m[2]) + (9*m[1,1,1]+5*m[2,1]+2*m[3]) + + (64*m[1,1,1,1]+34*m[2,1,1]+18*m[2,2]+13*m[3,1]+4*m[4]) + + (625*m[1,1,1,1,1]+326*m[2,1,1,1]+171*m[2,2,1]+119*m[3,1,1]+63*m[3,2]+35*m[4,1]+9*m[5]) + + (7776*m[1,1,1,1,1,1]+4016*m[2,1,1,1,1]+2078*m[2,2,1,1]+1077*m[2,2,2]+1433*m[3,1,1,1]+744*m[3,2,1]+268*m[3,3]+401*m[4,1,1]+209*m[4,2]+95*m[5,1]+20*m[6]) + + O^7 TESTS:: @@ -3170,11 +3174,12 @@ def polynomial(self, degree=None, name=None): """ S = self.parent() + if isinstance(self._coeff_stream, Stream_zero): + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(S.base_ring(), name=name).zero() + if degree is None: - if isinstance(self._coeff_stream, Stream_zero): - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - return PolynomialRing(S.base_ring(), name=name).zero() - elif isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: m = self._coeff_stream._degree else: raise ValueError("not a polynomial") @@ -3327,13 +3332,13 @@ def __call__(self, *g): if len(g) == 1: # we assume that the valuation of self[i](g) is at least i def coefficient(n): - r = R(0) + r = R.zero() for i in range(n+1): r += self[i]*(g0 ** i)[n] return r else: def coefficient(n): - r = R(0) + r = R.zero() for i in range(n+1): r += self[i](g)[n] return r @@ -3456,11 +3461,11 @@ def polynomial(self, degree=None, names=None): if names is None: names = S.variable_names() R = PolynomialRing(S.base_ring(), names=names) + if isinstance(self._coeff_stream, Stream_zero): + return R.zero() if degree is None: - if isinstance(self._coeff_stream, Stream_zero): - return R.zero() - elif (isinstance(self._coeff_stream, Stream_exact) + if (isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant): m = self._coeff_stream._degree else: @@ -3507,20 +3512,23 @@ def __call__(self, *args): sage: P. = QQ[] sage: s = SymmetricFunctions(P).s() sage: L = LazySymmetricFunctions(s) - sage: f = s[2]; g = s[3] + sage: f = s[2] + sage: g = s[3] sage: L(f)(L(g)) - L(f(g)) - O^7 + 0 - sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] + sage: f = s[2] + s[2,1] + sage: g = s[1] + s[2,2] sage: L(f)(L(g)) - L(f(g)) - O^7 + 0 sage: L(f)(g) - L(f(g)) - O^7 + 0 - sage: f = s[2] + s[2,1]; g = s[1] + s[2,2] + sage: f = s[2] + s[2,1] + sage: g = s[1] + s[2,2] sage: L(f)(L(q*g)) - L(f(q*g)) - O^7 + 0 The Frobenius character of the permutation action on set partitions is a plethysm:: @@ -3533,21 +3541,63 @@ def __call__(self, *args): sage: [s(x) for x in P[:5]] [s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]] + TESTS:: + + sage: s = SymmetricFunctions(QQ).s() + sage: S = LazySymmetricFunctions(s) + sage: f = 1 / (1 - S(s[2])) + sage: g = f(s[2]); g + s[] + (s[2,2]+s[4]) + O^7 + sage: S(sum(f[i](s[2]) for i in range(5))).truncate(10) == g.truncate(10) + True + sage: f(0) + 1 + sage: f(s(1)) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series """ if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") from sage.combinat.sf.sfa import is_SymmetricFunction - if not all(isinstance(g, LazySymmetricFunction) or is_SymmetricFunction(g) for g in args): + if not all(isinstance(g, LazySymmetricFunction) or is_SymmetricFunction(g) or not g for g in args): raise ValueError("all arguments must be (possibly lazy) symmetric functions") - from sage.misc.lazy_list import lazy_list + + if isinstance(self._coeff_stream, Stream_zero): + return self + if len(args) == 1: g = args[0] P = g.parent() + + # Handle other types of 0s + if not isinstance(g, LazySymmetricFunction) and not g: + return P(self[0].leading_coefficient()) + + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: + f = self.symmetric_function() + if is_SymmetricFunction(g): + return f(g) + # g must be a LazySymmetricFunction + if isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant: + gs = g.symmetric_function() + return P(f(gs)) + BR = P.base_ring() if isinstance(g, LazySymmetricFunction): R = P._laurent_poly_ring else: - R = P + from sage.rings.lazy_series_ring import LazySymmetricFunctions + R = g.parent() + P = LazySymmetricFunctions(R) + g = P(g) + + # self has (potentially) infinitely many terms + if g._coeff_stream._approximate_order == 0: + if g[0]: + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_order = 1 + p = R.realization_of().power() g_p = Stream_map_coefficients(g._coeff_stream, lambda c: c, p) try: @@ -3574,6 +3624,7 @@ def stretched_coefficient(k, n): def g_coeff_stream(k): return Stream_function(lambda n: stretched_coefficient(k, n), R, P._sparse, 0) + from sage.misc.lazy_list import lazy_list stretched = lazy_list(lambda k: g_coeff_stream(k)) f_p = Stream_map_coefficients(self._coeff_stream, lambda c: c, p) def coefficient(n): @@ -3657,6 +3708,71 @@ def parenthesize(m): return poly + def symmetric_function(self, degree=None): + r""" + Return ``self`` as a symmetric function if ``self`` is actually so. + + INPUT: + + - ``degree`` -- ``None`` or an integer + + OUTPUT: + + If ``degree`` is not ``None``, the terms of the series of degree greater + than ``degree`` are truncated first. If ``degree`` is ``None`` and the + series is not a polynomial polynomial, a ``ValueError`` is raised. + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).s() + sage: S = LazySymmetricFunctions(s) + sage: elt = S(s[2]) + sage: elt.symmetric_function() + s[2] + + TESTS:: + + sage: s = SymmetricFunctions(QQ).s() + sage: S = LazySymmetricFunctions(s) + sage: elt = S(s[2]) + sage: elt.symmetric_function() + s[2] + sage: f = 1 / (1 - elt) + sage: f + s[] + s[2] + (s[2,2]+s[3,1]+s[4]) + (s[2,2,2]+2*s[3,2,1]+s[3,3]+s[4,1,1]+3*s[4,2]+2*s[5,1]+s[6]) + O^7 + sage: f.symmetric_function() + Traceback (most recent call last): + ... + ValueError: not a symmetric function + + sage: f4 = f.truncate(5); f4 + s[] + s[2] + (s[2,2]+s[3,1]+s[4]) + sage: f4.symmetric_function() + s[] + s[2] + s[2, 2] + s[3, 1] + s[4] + sage: f4.symmetric_function() == f.symmetric_function(4) + True + sage: S.zero().symmetric_function() + 0 + sage: f4.symmetric_function(0) + s[] + """ + S = self.parent() + R = S._laurent_poly_ring + + if isinstance(self._coeff_stream, Stream_zero): + return R.zero() + + if degree is None: + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): + m = self._coeff_stream._degree + else: + raise ValueError("not a symmetric function") + else: + m = degree + 1 + + return R.sum(self[:m]) + class LazyDirichletSeries(LazyModuleElement): r""" A Dirichlet series where the coefficients are computed lazily. @@ -3985,3 +4101,4 @@ def parenthesize(m): poly = formatter(*([parenthesize(mo) for mo in mons] + bigO), sep=" + ") return poly + diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 9a66e2cd39c..a8076af2e74 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -2057,3 +2057,4 @@ def _monomial(self, c, n): return '({})/{}^{}'.format(self.base_ring()(c), n, self.variable_name()) options = LazyLaurentSeriesRing.options + From 0fdd5a2a55741c0688bb5a6abc5502349463a613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 11 Aug 2022 16:11:15 +0200 Subject: [PATCH 339/591] some details in polyhedron/base --- src/sage/geometry/polyhedron/base.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index d001cccab06..cf01ade0fab 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -311,11 +311,11 @@ def to_linear_program(self, solver=None, return_variable=False, base_ring=None): for ineqn in self.inequalities_list(): b = -ineqn.pop(0) - p.add_constraint(p.sum([x[i]*ineqn[i] for i in range(len(ineqn))]) >= b) + p.add_constraint(p.sum([x[i] * ineqn[i] for i in range(len(ineqn))]) >= b) for eqn in self.equations_list(): b = -eqn.pop(0) - p.add_constraint(p.sum([x[i]*eqn[i] for i in range(len(eqn))]) == b) + p.add_constraint(p.sum([x[i] * eqn[i] for i in range(len(eqn))]) == b) if return_variable: return p, x @@ -402,7 +402,7 @@ def center(self): if self.dim() == 0: return self.vertices()[0].vector() else: - vertex_sum = vector(self.base_ring(), [0]*self.ambient_dim()) + vertex_sum = vector(self.base_ring(), [0] * self.ambient_dim()) for v in self.vertex_generator(): vertex_sum += v.vector() vertex_sum.set_immutable() @@ -1198,9 +1198,10 @@ def _polymake_init_(self): INEQUALITIES=self.inequalities_list(), EQUATIONS=self.equations_list()) + verts_and_rays = [[1] + v for v in self.vertices_list()] + verts_and_rays += [[0] + r for r in self.rays_list()] return polymake.new_object(polymake_class, FACETS=self.inequalities_list(), AFFINE_HULL=self.equations_list(), - VERTICES=[[1] + v for v in self.vertices_list()] \ - + [[0] + r for r in self.rays_list()], + VERTICES=verts_and_rays, LINEALITY_SPACE=[[0] + l for l in self.lines_list()]) From 9d6579ba5e4545140d9d74b3cb9f70f232109872 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Thu, 11 Aug 2022 16:51:29 +0200 Subject: [PATCH 340/591] improve documentation, move zero, one, characteristic, etc. to ABC --- src/sage/data_structures/stream.py | 2 +- src/sage/rings/lazy_series.py | 2 +- src/sage/rings/lazy_series_ring.py | 452 +++++++++++------------------ 3 files changed, 179 insertions(+), 277 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index f83eeff0b89..1feca8f712c 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -505,7 +505,7 @@ class Stream_exact(Stream): """ def __init__(self, initial_coefficients, is_sparse, constant=None, degree=None, order=None): """ - Initialize a series that is known to be eventually geometric. + Initialize a stream with eventually constant coefficients. TESTS:: diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 46c8c305f29..d124d63c65e 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -723,7 +723,7 @@ def define(self, s): sage: L = LazySymmetricFunctions(m) sage: E = L(lambda n: s[n], valuation=0) sage: X = L(s[1]) - sage: A = L(None); A.define(X*E(A)) + sage: A = L(None); A.define(X*E(A, check=False)) sage: A m[1] + (2*m[1,1]+m[2]) + (9*m[1,1,1]+5*m[2,1]+2*m[3]) + (64*m[1,1,1,1]+34*m[2,1,1]+18*m[2,2]+13*m[3,1]+4*m[4]) + (625*m[1,1,1,1,1]+326*m[2,1,1,1]+171*m[2,2,1]+119*m[3,1,1]+63*m[3,2]+35*m[4,1]+9*m[5]) + (7776*m[1,1,1,1,1,1]+4016*m[2,1,1,1,1]+2078*m[2,2,1,1]+1077*m[2,2,2]+1433*m[3,1,1,1]+744*m[3,2,1]+268*m[3,3]+401*m[4,1,1]+209*m[4,2]+95*m[5,1]+20*m[6]) + O^7 diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 68dac09b15e..daabae17744 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -441,7 +441,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No raise ValueError(f"unable to convert {x} into {self}") - def unknown(self, valuation=None): + def undefined(self, valuation=None): """ Return an uninitialized series. @@ -456,13 +456,15 @@ def unknown(self, valuation=None): EXAMPLES:: sage: L. = LazyTaylorSeriesRing(QQ) - sage: s = L.unknown(1) + sage: s = L.undefined(1) sage: s.define(z + (s^2+s(z^2))/2) sage: s z + z^2 + z^3 + 2*z^4 + 3*z^5 + 6*z^6 + 11*z^7 + O(z^8) """ return self(None, valuation=valuation) + unknown = undefined + class options(GlobalOptions): r""" Set and display the options for Lazy Laurent series. @@ -478,6 +480,11 @@ class options(GlobalOptions): EXAMPLES:: sage: LLS. = LazyLaurentSeriesRing(QQ) + sage: LLS.options + Current options for lazy series rings + - constant_length: 3 + - display_length: 7 + sage: LLS.options.display_length 7 sage: f = 1 / (1 + z) @@ -501,7 +508,7 @@ class options(GlobalOptions): sage: LazyLaurentSeriesRing.options.display_length 7 """ -# NAME = 'LazyLaurentSeriesRing' + NAME = 'lazy series rings' module = 'sage.rings.lazy_series_ring' display_length = dict(default=7, description='the number of coefficients to display from the valuation', @@ -510,6 +517,161 @@ class options(GlobalOptions): description='the number of coefficients to display for nonzero constant series', checker=lambda x: x in ZZ and x > 0) + @cached_method + def one(self): + r""" + Return the constant series `1`. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L.one() + 1 + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.one() + 1 + + sage: m = SymmetricFunctions(ZZ).m() + sage: L = LazySymmetricFunctions(m) + sage: L.one() + m[] + + """ + R = self.base_ring() + coeff_stream = Stream_exact([R.one()], self._sparse, constant=R.zero(), order=0) + return self.element_class(self, coeff_stream) + + @cached_method + def zero(self): + r""" + Return the zero series. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L.zero() + 0 + + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(s) + sage: L.zero() + 0 + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.zero() + 0 + + sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L.zero() + 0 + """ + return self.element_class(self, Stream_zero(self._sparse)) + + def characteristic(self): + """ + Return the characteristic of this lazy power series ring, which + is the same as the characteristic of its base ring. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L.characteristic() + 0 + + sage: R. = LazyLaurentSeriesRing(GF(11)); R + Lazy Laurent Series Ring in w over Finite Field of size 11 + sage: R.characteristic() + 11 + + sage: R. = LazyTaylorSeriesRing(GF(7)); R + Multivariate Lazy Taylor Series Ring in x, y over Finite Field of size 7 + sage: R.characteristic() + 7 + + sage: L = LazyDirichletSeriesRing(ZZ, "s") + sage: L.characteristic() + 0 + """ + return self.base_ring().characteristic() + + def _coerce_map_from_(self, S): + """ + Return ``True`` if a coercion from ``S`` exists. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(GF(2), 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(GF(2)) + True + + sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(GF(2)) + True + + sage: s = SymmetricFunctions(GF(2)).s() + sage: L = LazySymmetricFunctions(s) + sage: L.has_coerce_map_from(ZZ) + True + sage: L.has_coerce_map_from(GF(2)) + True + """ + if self.base_ring().has_coerce_map_from(S): + return True + + R = self._laurent_poly_ring + return R.has_coerce_map_from(S) + + def _coerce_map_from_base_ring(self): + """ + Return a coercion map from the base ring of ``self``. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: phi = L._coerce_map_from_base_ring() + sage: phi(2) + 2 + sage: phi(2, valuation=-2) + 2*z^-2 + sage: phi(2, valuation=-2, constant=3, degree=1) + 2*z^-2 + 3*z + 3*z^2 + 3*z^3 + O(z^4) + + sage: L = LazyDirichletSeriesRing(QQ, 'z') + sage: phi = L._coerce_map_from_base_ring() + sage: phi(2) + 2 + sage: phi(2, valuation=2) + 2/2^z + sage: phi(2, valuation=2, constant=4) + 2/2^z + 4/3^z + 4/4^z + 4/5^z + O(1/(6^z)) + """ + # Return a DefaultConvertMap_unique; this can pass additional + # arguments to _element_constructor_, unlike the map returned + # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. + return self._generic_coerce_map(self.base_ring()) + + def is_sparse(self): + """ + Return whether ``self`` is sparse or not. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z', sparse=False) + sage: L.is_sparse() + False + + sage: L = LazyLaurentSeriesRing(ZZ, 'z', sparse=True) + sage: L.is_sparse() + True + """ + return self._sparse + + class LazyLaurentSeriesRing(LazySeriesRing): """ The ring of lazy Laurent series. @@ -732,40 +894,6 @@ def _latex_(self): from sage.misc.latex import latex return latex(self.base_ring()) + r"(\!({})\!)".format(self.variable_name()) - def characteristic(self): - """ - Return the characteristic of this lazy power series ring, which - is the same as the characteristic of its base ring. - - EXAMPLES:: - - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L.characteristic() - 0 - sage: R. = LazyLaurentSeriesRing(GF(11)); R - Lazy Laurent Series Ring in w over Finite Field of size 11 - sage: R.characteristic() - 11 - - """ - return self.base_ring().characteristic() - - def is_sparse(self): - """ - Return whether ``self`` is sparse or not. - - EXAMPLES:: - - sage: L = LazyLaurentSeriesRing(ZZ, 'z', sparse=False) - sage: L.is_sparse() - False - - sage: L = LazyLaurentSeriesRing(ZZ, 'z', sparse=True) - sage: L.is_sparse() - True - """ - return self._sparse - @cached_method def gen(self, n=0): r""" @@ -817,44 +945,6 @@ def gens(self): """ return tuple([self.gen(n) for n in range(self.ngens())]) - def _coerce_map_from_(self, S): - """ - Return ``True`` if a coercion from ``S`` exists. - - EXAMPLES:: - - sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: L.has_coerce_map_from(ZZ) - True - sage: L.has_coerce_map_from(GF(2)) - True - """ - if self.base_ring().has_coerce_map_from(S): - return True - - R = self._laurent_poly_ring - return R.has_coerce_map_from(S) - - def _coerce_map_from_base_ring(self): - """ - Return a coercion map from the base ring of ``self``. - - EXAMPLES:: - - sage: L = LazyLaurentSeriesRing(QQ, 'z') - sage: phi = L._coerce_map_from_base_ring() - sage: phi(2) - 2 - sage: phi(2, valuation=-2) - 2*z^-2 - sage: phi(2, valuation=-2, constant=3, degree=1) - 2*z^-2 + 3*z + 3*z^2 + 3*z^3 + O(z^4) - """ - # Return a DefaultConvertMap_unique; this can pass additional - # arguments to _element_constructor_, unlike the map returned - # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. - return self._generic_coerce_map(self.base_ring()) - def _an_element_(self): """ Return a Laurent series in ``self``. @@ -905,34 +995,6 @@ def some_elements(self): (1 - 2*z**-3)/(1 - z + 3*z**2), self(lambda n: n**2, valuation=-2)] return elts - @cached_method - def one(self): - r""" - Return the constant series `1`. - - EXAMPLES:: - - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L.one() - 1 - """ - R = self.base_ring() - coeff_stream = Stream_exact([R.one()], self._sparse, constant=R.zero(), degree=1) - return self.element_class(self, coeff_stream) - - @cached_method - def zero(self): - r""" - Return the zero series. - - EXAMPLES:: - - sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L.zero() - 0 - """ - return self.element_class(self, Stream_zero(self._sparse)) - def series(self, coefficient, valuation, degree=None, constant=None): r""" Return a lazy Laurent series. @@ -1188,34 +1250,6 @@ def gens(self): """ return tuple([self.gen(n) for n in range(self.ngens())]) - def _coerce_map_from_(self, S): - """ - Return ``True`` if a coercion from ``S`` exists. - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(GF(2), 'z') - sage: L.has_coerce_map_from(ZZ) - True - sage: L.has_coerce_map_from(GF(2)) - True - """ - if self.base_ring().has_coerce_map_from(S): - return True - - R = self._laurent_poly_ring - return R.has_coerce_map_from(S) - - def _coerce_map_from_base_ring(self): - """ - Return a coercion map from the base ring of ``self``. - - """ - # Return a DefaultConvertMap_unique; this can pass additional - # arguments to _element_constructor_, unlike the map returned - # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. - return self._generic_coerce_map(self.base_ring()) - def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None, check=True): """ Construct a Taylor series from ``x``. @@ -1426,33 +1460,6 @@ def _an_element_(self): coeff_stream = Stream_exact([R.one()], self._sparse, order=1, constant=c) return self.element_class(self, coeff_stream) - @cached_method - def one(self): - r""" - Return the constant series `1`. - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(ZZ, 'z') - sage: L.one() - 1 - """ - R = self._laurent_poly_ring - coeff_stream = Stream_exact([R.one()], self._sparse, constant=ZZ.zero(), degree=1) - return self.element_class(self, coeff_stream) - - @cached_method - def zero(self): - r""" - Return the zero series. - - EXAMPLES:: - - sage: L = LazyTaylorSeriesRing(ZZ, 'z') - sage: L.zero() - 0 - """ - return self.element_class(self, Stream_zero(self._sparse)) ###################################################################### @@ -1554,35 +1561,6 @@ def _monomial(self, c, n): L = self._laurent_poly_ring return L(c) - def _coerce_map_from_(self, S): - """ - Return ``True`` if a coercion from ``S`` exists. - - EXAMPLES:: - - sage: s = SymmetricFunctions(GF(2)).s() - sage: L = LazySymmetricFunctions(s) - sage: L.has_coerce_map_from(ZZ) - True - sage: L.has_coerce_map_from(GF(2)) - True - """ - if self.base_ring().has_coerce_map_from(S): - return True - - R = self._laurent_poly_ring - return R.has_coerce_map_from(S) - - def _coerce_map_from_base_ring(self): - """ - Return a coercion map from the base ring of ``self``. - - """ - # Return a DefaultConvertMap_unique; this can pass additional - # arguments to _element_constructor_, unlike the map returned - # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. - return self._generic_coerce_map(self.base_ring()) - def _element_constructor_(self, x=None, valuation=None, degree=None, check=True): """ Construct a lazy symmetric function from ``x``. @@ -1774,36 +1752,6 @@ def _an_element_(self): coeff_stream = Stream_exact([R.one()], self._sparse, order=1, constant=0) return self.element_class(self, coeff_stream) - @cached_method - def one(self): - r""" - Return the constant `1`. - - EXAMPLES:: - - sage: m = SymmetricFunctions(ZZ).m() - sage: L = LazySymmetricFunctions(m) - sage: L.one() - m[] - """ - R = self._laurent_poly_ring - coeff_stream = Stream_exact([R.one()], self._sparse, constant=ZZ.zero(), degree=1) - return self.element_class(self, coeff_stream) - - @cached_method - def zero(self): - r""" - Return the zero series. - - EXAMPLES:: - - sage: s = SymmetricFunctions(ZZ).s() - sage: L = LazySymmetricFunctions(s) - sage: L.zero() - 0 - """ - return self.element_class(self, Stream_zero(self._sparse)) - ###################################################################### class LazyDirichletSeriesRing(LazySeriesRing): @@ -1860,18 +1808,22 @@ def _repr_(self): """ return "Lazy Dirichlet Series Ring in {} over {}".format(self.variable_name(), self.base_ring()) - def characteristic(self): - """ - Return the characteristic of this lazy power series ring, which - is the same as the characteristic of its base ring. + @cached_method + def one(self): + r""" + Return the constant series `1`. EXAMPLES:: - sage: L = LazyDirichletSeriesRing(ZZ, "s") - sage: L.characteristic() - 0 + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.one() + 1 + sage: ~L.one() + 1 + O(1/(8^z)) """ - return self.base_ring().characteristic() + R = self.base_ring() + coeff_stream = Stream_exact([R.one()], self._sparse, constant=R.zero(), order=1) + return self.element_class(self, coeff_stream) def _coerce_map_from_(self, S): """ @@ -1887,29 +1839,8 @@ def _coerce_map_from_(self, S): """ if self.base_ring().has_coerce_map_from(S): return True - return False - def _coerce_map_from_base_ring(self): - r""" - Return a coercion map from the base ring of ``self``. - - EXAMPLES:: - - sage: L = LazyDirichletSeriesRing(QQ, 'z') - sage: phi = L._coerce_map_from_base_ring() - sage: phi(2) - 2 - sage: phi(2, valuation=2) - 2/2^z - sage: phi(2, valuation=2, constant=4) - 2/2^z + 4/3^z + 4/4^z + 4/5^z + O(1/(6^z)) - """ - # Return a DefaultConvertMap_unique; this can pass additional - # arguments to _element_constructor_, unlike the map returned - # by UnitalAlgebras.ParentMethods._coerce_map_from_base_ring. - return self._generic_coerce_map(self.base_ring()) - def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, coefficients=None): r""" Construct a Dirichlet series from ``x``. @@ -2037,35 +1968,6 @@ def _an_element_(self): c = self.base_ring().an_element() return self.element_class(self, Stream_exact([], self._sparse, constant=c, order=4)) - @cached_method - def one(self): - """ - Return the constant series `1`. - - EXAMPLES:: - - sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.one() - 1 - sage: ~L.one() - 1 + O(1/(8^z)) - """ - R = self.base_ring() - return self.element_class(self, Stream_exact([R.one()], self._sparse, order=1)) - - @cached_method - def zero(self): - """ - Return the zero series. - - EXAMPLES:: - - sage: L = LazyDirichletSeriesRing(ZZ, 'z') - sage: L.zero() - 0 - """ - return self.element_class(self, Stream_zero(self._sparse)) - def _monomial(self, c, n): r""" Return the interpretation of the coefficient ``c`` at index ``n``. From 5ca40a8096bc599cc7c9274c02fe9151139f7e27 Mon Sep 17 00:00:00 2001 From: Thierry Monteil Date: Thu, 11 Aug 2022 17:51:42 +0200 Subject: [PATCH 341/591] #34341 : fix bool(x^2 + 2*x + 1 != (x + 1)^2) --- src/sage/symbolic/expression.pyx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index cc68b28bb90..4df4cfb562b 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -3456,6 +3456,11 @@ cdef class Expression(Expression_abc): sage: val = pi - 2286635172367940241408/1029347477390786609545*sqrt(2) sage: bool(val>0) False + + Check that :trac:`34341` is fixed:: + + sage: bool(x^2 + 2*x + 1 != (x + 1)^2) + False """ if self.is_relational(): # constants are wrappers around Sage objects, compare directly @@ -3499,8 +3504,8 @@ cdef class Expression(Expression_abc): # Use interval fields to try and falsify the relation if not need_assumptions: - if pynac_result == relational_notimplemented and self.operator()==operator.ne: - return not (self.lhs()-self.rhs()).is_trivial_zero() + if pynac_result == relational_notimplemented and self.operator() == operator.ne: + return not (self.lhs()-self.rhs()).is_zero() res = self.test_relation() if res in (True, False): return res From 0e1542b3a43d155565519dd0d3b08cbcf40b648b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 10 Aug 2022 23:29:02 -0700 Subject: [PATCH 342/591] .devcontainer/: Add two more portability-... configurations --- .../devcontainer.json | 23 +++++++++++++++++++ .../devcontainer.json | 23 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 .devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json create mode 100644 .devcontainer/portability-debian-buster-i386-standard/devcontainer.json diff --git a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json new file mode 100644 index 00000000000..91ea05d2d11 --- /dev/null +++ b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json @@ -0,0 +1,23 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "Centos 7", + "build": { + "dockerfile": "Dockerfile", + // See tox.ini for definitions + "args": { "SYSTEM_FACTOR": "centos-7-devtoolset-gcc_11", + "PACKAGE_FACTOR": "standard", + "DOCKER_TARGET": "with-targets", + "DOCKER_TAG": "dev" + } + }, + "containerEnv": { + "MAKE": "make -j12" + }, + // Run commands after the container is created: + "postCreateCommand": ".devcontainer/post_create.sh", + // Run commands after the container is started. + "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", + "extensions": [ + "ms-python.python" + ] +} diff --git a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json new file mode 100644 index 00000000000..7d50d30b496 --- /dev/null +++ b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json @@ -0,0 +1,23 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "Debian buster 32-bit", + "build": { + "dockerfile": "Dockerfile", + // See tox.ini for definitions + "args": { "SYSTEM_FACTOR": "debian-buster-i386", + "PACKAGE_FACTOR": "standard", + "DOCKER_TARGET": "with-targets", + "DOCKER_TAG": "dev" + } + }, + "containerEnv": { + "MAKE": "make -j12" + }, + // Run commands after the container is created: + "postCreateCommand": ".devcontainer/post_create.sh", + // Run commands after the container is started. + "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", + "extensions": [ + "ms-python.python" + ] +} From 8a8eb96727e0f4810032362cf31ceff1bb15ea5e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 11 Aug 2022 09:17:02 -0700 Subject: [PATCH 343/591] src/doc/en/developer/portability_testing.rst: Expand on using the VS Code remote containers extension --- src/doc/en/developer/portability_testing.rst | 51 ++++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 8dc671fd502..8ae23ad20d9 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1158,23 +1158,44 @@ Sage provides sample ``devcontainer.json`` configuration files `_ for this purpose. -To get started, copy (or symlink) the sample file +To get started, symlink (or copy) the sample file `.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json `_ -to ``devcontainer.json`` in the directory ``.devcontainer``. It uses -``ubuntu-jammy-standard`` and the most recent development version Sage -(``dev`` tag). You can edit a copy of the configuration file to -change to a different platform or another version. - -Then, opening the Sage repository in the configured devcontainer pulls the -image from ghcr.io, installs additional system packages for -development, and builds Sage from -source, reusing the installation (:envvar:`SAGE_LOCAL`, -:envvar:`SAGE_VENV`) from the image. - -After editing the configuration file (or changing the symlink), run -"Remote-Containers: Rebuild Container" from the Command Palette. See -the `VS Code devcontainer.json reference +to ``devcontainer.json`` in the directory ``.devcontainer``. For +example, in macOS using the shell:: + + [mkoeppe@sage sage] $ (cd .devcontainer && ln -s portability-ubuntu-jammy-standard/devcontainer.json .) + +Then, start VS Code:: + + [mkoeppe@sage sage] $ code . + +In VS Code, click the "Extension" icon on the left (or press +:kbd:`Ctrl` + :kbd:`Shift` + :kbd:`X`; on macOS, :kbd:`Command` + +:kbd:`Shift` + :kbd:`X`) to open a list of extensions. Search for +"Remote - Containers" and install it if it is not already installed. + +With the extension installed, VS Code may prompt you whether you would +like to open the current directory in the devcontainer (yes). If it +does not, use the command palette (:kbd:`Ctrl` + :kbd:`Shift` + +:kbd:`P`) to run the command "Remote-Containers: Reopen Folder in +Container". By clicking on "Show Log", you can see what it does: + +- It pulls the prebuilt image from ghcr.io; note that these + are multi-gigabyte images, so it may take a while. + +- As part of the "postCreateCommand", it installs additional system packages to + support VS Code and for development. Then it bootstraps and configures + the source tree and starts to build Sage from + source, reusing the installation (:envvar:`SAGE_LOCAL`, + :envvar:`SAGE_VENV`) from the prebuilt image. + +This sample file uses ``ubuntu-jammy-standard`` and the most recent +development version of Sage (``dev`` tag). You can edit a copy of the +configuration file to change to a different platform or another +version. After editing the configuration file (or changing the +symlink), run "Remote-Containers: Rebuild Container" from the Command +Palette. See the `VS Code devcontainer.json reference `_ and the `GitHub introduction to dev containers `_ From b78da73aec667a6f405ad7747fec30a02852a01b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 11 Aug 2022 09:26:18 -0700 Subject: [PATCH 344/591] .devcontainer/portability-Dockerfile: Rename from Dockerfile --- .devcontainer/{Dockerfile => portability-Dockerfile} | 0 .../devcontainer.json | 2 +- .../portability-debian-buster-i386-standard/devcontainer.json | 2 +- .../portability-ubuntu-jammy-standard/devcontainer.json | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename .devcontainer/{Dockerfile => portability-Dockerfile} (100%) diff --git a/.devcontainer/Dockerfile b/.devcontainer/portability-Dockerfile similarity index 100% rename from .devcontainer/Dockerfile rename to .devcontainer/portability-Dockerfile diff --git a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json index 91ea05d2d11..b1eaf54015c 100644 --- a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json +++ b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json @@ -2,7 +2,7 @@ { "name": "Centos 7", "build": { - "dockerfile": "Dockerfile", + "dockerfile": "portability-Dockerfile", // See tox.ini for definitions "args": { "SYSTEM_FACTOR": "centos-7-devtoolset-gcc_11", "PACKAGE_FACTOR": "standard", diff --git a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json index 7d50d30b496..fc3b9d5db47 100644 --- a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json +++ b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json @@ -2,7 +2,7 @@ { "name": "Debian buster 32-bit", "build": { - "dockerfile": "Dockerfile", + "dockerfile": "portability-Dockerfile", // See tox.ini for definitions "args": { "SYSTEM_FACTOR": "debian-buster-i386", "PACKAGE_FACTOR": "standard", diff --git a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json index e544f561a17..a5554b4d452 100644 --- a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +++ b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json @@ -2,7 +2,7 @@ { "name": "Ubuntu jammy", "build": { - "dockerfile": "Dockerfile", + "dockerfile": "portability-Dockerfile", // See tox.ini for definitions "args": { "SYSTEM_FACTOR": "ubuntu-jammy", "PACKAGE_FACTOR": "standard", From 5cde5fe8c2b58d7d914318dccfdbf06385c77481 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 11 Aug 2022 09:32:07 -0700 Subject: [PATCH 345/591] src/doc/en/developer/portability_testing.rst: Expand on the devcontainer build --- src/doc/en/developer/portability_testing.rst | 27 ++++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 8ae23ad20d9..a1e6aa2b24c 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1181,19 +1181,24 @@ does not, use the command palette (:kbd:`Ctrl` + :kbd:`Shift` + :kbd:`P`) to run the command "Remote-Containers: Reopen Folder in Container". By clicking on "Show Log", you can see what it does: -- It pulls the prebuilt image from ghcr.io; note that these - are multi-gigabyte images, so it may take a while. +- It pulls the prebuilt image from ghcr.io (via + `.devcontainer/portability-Dockerfile + `_); + note that these are multi-gigabyte images, so it may take a while. - As part of the "postCreateCommand", it installs additional system packages to - support VS Code and for development. Then it bootstraps and configures - the source tree and starts to build Sage from - source, reusing the installation (:envvar:`SAGE_LOCAL`, - :envvar:`SAGE_VENV`) from the prebuilt image. - -This sample file uses ``ubuntu-jammy-standard`` and the most recent -development version of Sage (``dev`` tag). You can edit a copy of the -configuration file to change to a different platform or another -version. After editing the configuration file (or changing the + support VS Code and for development. + +- Then, as part of the "postStartCommand", it bootstraps and + configures the source tree and starts to build Sage from source, + reusing the installation (:envvar:`SAGE_LOCAL`, :envvar:`SAGE_VENV`) + from the prebuilt image. + +This sample file uses ``ubuntu-jammy-standard``, the most recent +development version of Sage (``dev`` tag), and a full installation of +the Sage distribution (``with-targets``). You can edit a copy of the +configuration file to change to a different platform, another +version, or build stage. After editing the configuration file (or changing the symlink), run "Remote-Containers: Rebuild Container" from the Command Palette. See the `VS Code devcontainer.json reference `_ From bc0198af8d65b2d72c6ca7e9d2b70202e945e516 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 11 Aug 2022 09:49:53 -0700 Subject: [PATCH 346/591] .devcontainer/portability-post_start.sh: New, use it to simplify portability-.../devcontainer.json --- .../devcontainer.json | 2 +- .../devcontainer.json | 2 +- .devcontainer/portability-post_start.sh | 18 ++++++++++++++++++ .../devcontainer.json | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100755 .devcontainer/portability-post_start.sh diff --git a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json index b1eaf54015c..7b94ae1e906 100644 --- a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json +++ b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json @@ -16,7 +16,7 @@ // Run commands after the container is created: "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. - "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", + "postStartCommand": ".devcontainer/portability-post_start.sh", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json index fc3b9d5db47..9f4d6cb1cef 100644 --- a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json +++ b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json @@ -16,7 +16,7 @@ // Run commands after the container is created: "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. - "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", + "postStartCommand": ".devcontainer/portability-post_start.sh", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/portability-post_start.sh b/.devcontainer/portability-post_start.sh new file mode 100755 index 00000000000..2945504f1c5 --- /dev/null +++ b/.devcontainer/portability-post_start.sh @@ -0,0 +1,18 @@ +#! /bin/sh +# The portability-.../devcontainer.json configurations run this script after the container is started. +# +# The script assumes that it is run from SAGE_ROOT. +# +# If "config.log" or "logs" are symlinks (for example, created by 'tox -e local-...', +# or after https://trac.sagemath.org/ticket/33262), remove them. +for f in config.log logs; do + if [ -L $f ]; then + rm -f $f + fi +done +# Bootstrap, configure, and build the Sage distribution, reusing the Sage installation from the prebuilt image. +set -e +set -x +make configure +./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv +make build V=0 diff --git a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json index a5554b4d452..0d6c1bcf22d 100644 --- a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +++ b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json @@ -16,7 +16,7 @@ // Run commands after the container is created: "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. - "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv && make build V=0", + "postStartCommand": ".devcontainer/portability-post_start.sh", "extensions": [ "ms-python.python" ] From 869f6e2eec454da74899394e5feb0f5222311a5c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 11 Aug 2022 10:36:19 -0700 Subject: [PATCH 347/591] .devcontainer/portability-post_start.sh: If upstream is a symlink, remove it; keep logs in container if possible --- .devcontainer/portability-post_start.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.devcontainer/portability-post_start.sh b/.devcontainer/portability-post_start.sh index 2945504f1c5..d19e37002c8 100755 --- a/.devcontainer/portability-post_start.sh +++ b/.devcontainer/portability-post_start.sh @@ -4,12 +4,17 @@ # The script assumes that it is run from SAGE_ROOT. # # If "config.log" or "logs" are symlinks (for example, created by 'tox -e local-...', -# or after https://trac.sagemath.org/ticket/33262), remove them. -for f in config.log logs; do +# or after https://trac.sagemath.org/ticket/33262), they might point outside of +# the devcontainer, so remove them. Likewise for upstream. +for f in config.log logs upstream; do if [ -L $f ]; then rm -f $f fi done +# If possible (ensured after https://trac.sagemath.org/ticket/33262), keep the logs in the container. +if [ ! -f logs ]; then + ln -s /sage/logs logs +fi # Bootstrap, configure, and build the Sage distribution, reusing the Sage installation from the prebuilt image. set -e set -x From 434071a5f28bd8ec8b57dfb52a7d3302a598164f Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Thu, 11 Aug 2022 12:14:15 -0700 Subject: [PATCH 348/591] Rewrite loop computing outside corners --- src/sage/combinat/partition.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 811679ede16..f8001a3476c 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -4030,12 +4030,9 @@ def outside_corners(self): p = self if p.is_empty(): return [(0,0)] - res = [ (0, p[0]) ] - for i in range(1, len(p)): - if p[i-1] != p[i]: - res.append((i,p[i])) + res = [(0, p[0])] + res.extend((n, j) for n, (i, j) in enumerate(zip(p[:-1], p[1:]), start=1) if i != j) res.append((len(p), 0)) - return res addable_cells = outside_corners # for compatibility with partition tuples From 8bd20238d836a14dfde9a3a49d28abfe44768f21 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 11 Aug 2022 21:18:00 +0900 Subject: [PATCH 349/591] Some edits --- .devcontainer/cocalc/devcontainer.json | 2 +- .devcontainer/computop-sage/devcontainer.json | 2 +- .../devcontainer.json | 2 +- .../devcontainer.json | 2 +- .../devcontainer.json | 2 +- .../devcontainer.json | 2 +- .../devcontainer.json | 2 +- .../sagemath-sagemath/devcontainer.json | 2 +- src/doc/en/developer/portability_testing.rst | 95 ++++++++++--------- 9 files changed, 58 insertions(+), 53 deletions(-) diff --git a/.devcontainer/cocalc/devcontainer.json b/.devcontainer/cocalc/devcontainer.json index 5a51894682c..7752a065bd3 100644 --- a/.devcontainer/cocalc/devcontainer.json +++ b/.devcontainer/cocalc/devcontainer.json @@ -1,4 +1,4 @@ -// For format details, see https://aka.ms/devcontainer.json. +// See https://aka.ms/devcontainer.json for format details. { "name": "CoCalc Docker", "image": "sagemathinc/cocalc" diff --git a/.devcontainer/computop-sage/devcontainer.json b/.devcontainer/computop-sage/devcontainer.json index 2228c6699f8..a852d04a6dd 100644 --- a/.devcontainer/computop-sage/devcontainer.json +++ b/.devcontainer/computop-sage/devcontainer.json @@ -1,4 +1,4 @@ -// For format details, see https://aka.ms/devcontainer.json. +// See https://aka.ms/devcontainer.json for format details. { "name": "computop/sage Docker", "image": "computop/sage" diff --git a/.devcontainer/downstream-archlinux-latest/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json index df959894af8..5f1a9d94543 100644 --- a/.devcontainer/downstream-archlinux-latest/devcontainer.json +++ b/.devcontainer/downstream-archlinux-latest/devcontainer.json @@ -1,4 +1,4 @@ -// For format details, see https://aka.ms/devcontainer.json. +// See https://aka.ms/devcontainer.json for format details. { "name": "archlinux:latest downstream Sage", "image": "archlinux:latest", diff --git a/.devcontainer/downstream-conda-forge-latest/devcontainer.json b/.devcontainer/downstream-conda-forge-latest/devcontainer.json index 22463c2dd29..d7528beee72 100644 --- a/.devcontainer/downstream-conda-forge-latest/devcontainer.json +++ b/.devcontainer/downstream-conda-forge-latest/devcontainer.json @@ -1,4 +1,4 @@ -// For format details, see https://aka.ms/devcontainer.json. +// See https://aka.ms/devcontainer.json for format details. { "name": "condaforge/mambaforge:latest downstream Sage", "image": "condaforge/mambaforge:latest", diff --git a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json index 7b94ae1e906..67408930a2f 100644 --- a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json +++ b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json @@ -1,4 +1,4 @@ -// For format details, see https://aka.ms/devcontainer.json. +// See https://aka.ms/devcontainer.json for format details. { "name": "Centos 7", "build": { diff --git a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json index 9f4d6cb1cef..9e002922051 100644 --- a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json +++ b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json @@ -1,4 +1,4 @@ -// For format details, see https://aka.ms/devcontainer.json. +// See https://aka.ms/devcontainer.json for format details. { "name": "Debian buster 32-bit", "build": { diff --git a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json index 0d6c1bcf22d..cd3e8d86909 100644 --- a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +++ b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json @@ -1,4 +1,4 @@ -// For format details, see https://aka.ms/devcontainer.json. +// See https://aka.ms/devcontainer.json for format details. { "name": "Ubuntu jammy", "build": { diff --git a/.devcontainer/sagemath-sagemath/devcontainer.json b/.devcontainer/sagemath-sagemath/devcontainer.json index 214491aef31..501bc46702e 100644 --- a/.devcontainer/sagemath-sagemath/devcontainer.json +++ b/.devcontainer/sagemath-sagemath/devcontainer.json @@ -1,4 +1,4 @@ -// For format details, see https://aka.ms/devcontainer.json. +// See https://aka.ms/devcontainer.json for format details. { "name": "sagemath/sagemath Docker", // sagemath/sagemath-dev as of 9.5 is broken? diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index a1e6aa2b24c..2d59dad71c7 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -70,7 +70,7 @@ example, to run the current stable (LTS) version of Ubuntu interactively, you can use the shell command:: [mkoeppe@sage sage]$ docker run -it ubuntu:latest - root@9f3398da43c2:/# + root@9f3398da43c2:/# Here ``ubuntu`` is referred to as the "image (name)" and ``latest`` as the "tag". Other releases of Ubuntu are available under different @@ -118,9 +118,9 @@ this time let's mount the current directory into it:: root@39d693b2a75d:/# cd sage root@39d693b2a75d:/sage# ls COPYING.txt ... Makefile ... config configure configure.ac ... src tox.ini - + Typical Docker images provide minimal installations of packages only:: - + root@39d693b2a75d:/sage# command -v python root@39d693b2a75d:/sage# command -v gcc root@39d693b2a75d:/sage# @@ -128,7 +128,7 @@ Typical Docker images provide minimal installations of packages only:: As you can see above, the image ``ubuntu:latest`` has neither a Python nor a GCC installed, which are among the build prerequisites of Sage. We need to install them using the distribution's package manager first. - + Sage facilitates testing various distributions on Docker as follows. Discovering the system's package system @@ -136,7 +136,7 @@ Discovering the system's package system :: - root@39d693b2a75d:/sage# build/bin/sage-guess-package-system + root@39d693b2a75d:/sage# build/bin/sage-guess-package-system debian Let's install gcc, hoping that the Ubuntu package providing it is @@ -191,7 +191,7 @@ on our container to install the necessary build prerequisites:: root@39d693b2a75d:/sage# apt-get install binutils make m4 perl python3 tar bc gcc g++ ca-certificates Reading package lists... Done - Building dependency tree + Building dependency tree Reading state information... Done tar is already the newest version (1.29b-2ubuntu0.1). The following additional packages will be installed: @@ -204,7 +204,7 @@ automatically generated from the database of package names.) Now we can start the build:: - root@39d693b2a75d:/sage# ./configure + root@39d693b2a75d:/sage# ./configure checking for a BSD-compatible install... /usr/bin/install -c checking for root user... yes configure: error: You cannot build Sage as root, switch to an unprivileged user. (If building in a container, use --enable-build-as-root.) @@ -236,7 +236,7 @@ packages. For example:: root@39d693b2a75d:/sage# ls build/pkgs/arb/distros/ arch.txt conda.txt debian.txt gentoo.txt - root@39d693b2a75d:/sage# cat build/pkgs/arb/distros/debian.txt + root@39d693b2a75d:/sage# cat build/pkgs/arb/distros/debian.txt libflint-arb-dev Note that these package equivalencies are based on a current stable or @@ -258,7 +258,7 @@ Let us install a subset of these packages:: Setting up zlib1g-dev:amd64 (1:1.2.11.dfsg-0ubuntu2) ... root@39d693b2a75d:/sage# - + Committing a container to disk ------------------------------ @@ -324,7 +324,7 @@ The ``Dockerfile`` instructs the command ``docker build`` to build a new Docker image. Let us take a quick look at the generated file; this is slightly simplified:: - [mkoeppe@sage sage]$ cat Dockerfile + [mkoeppe@sage sage]$ cat Dockerfile # Automatically generated by SAGE_ROOT/build/bin/write-dockerfile.sh # the :comments: separate the generated file into sections # to simplify writing scripts that customize this file @@ -419,7 +419,7 @@ We can now start a container using the image id shown in the last step:: -rw-r--r-- 1 root root 6025 Mar 26 22:27 ratpoints-2.1.3.p5.log root@fab59e09a641:/sage# ls -l local/lib/*rat* -rw-r--r-- 1 root root 177256 Mar 26 22:27 local/lib/libratpoints.a - + You can customize the image build process further by editing the ``Dockerfile``. For example, by default, the generated ``Dockerfile`` configures, builds, and tests Sage. By deleting or commenting out the @@ -545,13 +545,13 @@ create an image from the container:: Note: SAGE_ROOT=/sage (sage-buildsh) root@2d9ac65f4572:surf-1.0.6-gcc6$ ls /usr/lib/libfl* /usr/lib/libflint-2.5.2.so /usr/lib/libflint-2.5.2.so.13.5.2 /usr/lib/libflint.a /usr/lib/libflint.so - (sage-buildsh) root@2d9ac65f4572:surf-1.0.6-gcc6$ apt-get update && apt-get install apt-file + (sage-buildsh) root@2d9ac65f4572:surf-1.0.6-gcc6$ apt-get update && apt-get install apt-file (sage-buildsh) root@2d9ac65f4572:surf-1.0.6-gcc6$ apt-file update (sage-buildsh) root@2d9ac65f4572:surf-1.0.6-gcc6$ apt-file search "/usr/lib/libfl.a" flex-old: /usr/lib/libfl.a freebsd-buildutils: /usr/lib/libfl.a (sage-buildsh) root@2d9ac65f4572:surf-1.0.6-gcc6$ apt-get install flex-old - (sage-buildsh) root@2d9ac65f4572:surf-1.0.6-gcc6$ ./spkg-install + (sage-buildsh) root@2d9ac65f4572:surf-1.0.6-gcc6$ ./spkg-install checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes ... @@ -564,7 +564,7 @@ create an image from the container:: [mkoeppe@sage sage]$ A standard case of bitrot. - + Automatic Docker-based build testing using tox ---------------------------------------------- @@ -633,11 +633,11 @@ To run an environment:: [mkoeppe@sage sage]$ tox -e docker-slackware-14.2-minimal [mkoeppe@sage sage]$ tox -e docker-ubuntu-bionic-standard - + Arbitrary extra arguments to ``docker build`` can be supplied through the environment variable ``EXTRA_DOCKER_BUILD_ARGS``. For example, for a non-silent build (``make V=1``), use:: - + [mkoeppe@sage sage]$ EXTRA_DOCKER_BUILD_ARGS="--build-arg USE_MAKEFLAGS=\"V=1\"" \ tox -e docker-ubuntu-bionic-standard @@ -867,7 +867,7 @@ an isolated copy of Homebrew with all prerequisites for bootstrapping:: ... local-homebrew-macos-minimal: commands succeeded congratulations :) - + The tox environment uses the subdirectory ``homebrew`` of the environment directory ``.tox/local-homebrew-macos-minimal`` as the Homebrew prefix. This installation does not interact in any way with @@ -985,7 +985,7 @@ system configurations. For more information, see the `GitHub documentation `_. -Alternatively, you can create and push a custom tag in order to trigger a run of tests as follows. +Alternatively, you can create and push a custom tag in order to trigger a run of tests as follows. Let's assume that ``github`` is the name of the remote corresponding to your GitHub fork of the Sage repository:: @@ -1107,19 +1107,19 @@ for example, the following command will work:: $ docker run -it ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional:dev bash Unable to find image 'ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional:dev' locally dev: Pulling from sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional - d5fd17ec1767: Already exists - 67586203f0c7: Pull complete + d5fd17ec1767: Already exists + 67586203f0c7: Pull complete b63c529f4777: Pull complete ... - 159775d1a3d2: Pull complete + 159775d1a3d2: Pull complete Digest: sha256:e6ba5e12f59c6c4668692ef4cfe4ae5f242556482664fb347bf260f32bf8e698 Status: Downloaded newer image for ghcr.io/sagemath/sage/sage-docker-ubuntu-focal-standard-with-targets-optional:dev - root@8055a7ba0607:/sage# ./sage + root@8055a7ba0607:/sage# ./sage ┌────────────────────────────────────────────────────────────────────┐ │ SageMath version 9.6, Release Date: 2022-05-15 │ │ Using Python 3.8.10. Type "help()" for help. │ └────────────────────────────────────────────────────────────────────┘ - sage: + sage: Images whose names end with the suffix ``-with-targets-optional`` are the results of full builds and a run of ``make ptest``. They also @@ -1145,11 +1145,11 @@ are available: ptest`` has not been run yet. -Developing with our pre-built Docker images as devcontainers in VS Code -======================================================================= +Using our pre-built Docker images for development in VS Code +============================================================ -`VS Code ` is very -convenient for working with Docker containers thanks to the `Visual +`VS Code `_ is very +convenient for developing with Docker containers thanks to the `Visual Studio Code Remote - Containers `_ extension. @@ -1158,11 +1158,15 @@ Sage provides sample ``devcontainer.json`` configuration files `_ for this purpose. -To get started, symlink (or copy) the sample file -`.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json -`_ -to ``devcontainer.json`` in the directory ``.devcontainer``. For -example, in macOS using the shell:: +To get started, symlink (or copy) one of the sample files to +``$SAGE_ROOT/.devcontainer/devcontainer.json``. For example, choose +`$SAGE_ROOT/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +`_, which uses the Docker image based on ``ubuntu-jammy-standard``, +the most recent +development version of Sage (``dev`` tag), and a full installation of +the Sage distribution (``with-targets``). + +For example, in macOS, you can do this using the shell as follows:: [mkoeppe@sage sage] $ (cd .devcontainer && ln -s portability-ubuntu-jammy-standard/devcontainer.json .) @@ -1178,8 +1182,9 @@ In VS Code, click the "Extension" icon on the left (or press With the extension installed, VS Code may prompt you whether you would like to open the current directory in the devcontainer (yes). If it does not, use the command palette (:kbd:`Ctrl` + :kbd:`Shift` + -:kbd:`P`) to run the command "Remote-Containers: Reopen Folder in -Container". By clicking on "Show Log", you can see what it does: +:kbd:`P`), enter the command "Remote-Containers: Reopen Folder in +Container" , and hit :kbd:`Enter`. +By clicking on "Show Log", you can see what it does: - It pulls the prebuilt image from ghcr.io (via `.devcontainer/portability-Dockerfile @@ -1194,10 +1199,7 @@ Container". By clicking on "Show Log", you can see what it does: reusing the installation (:envvar:`SAGE_LOCAL`, :envvar:`SAGE_VENV`) from the prebuilt image. -This sample file uses ``ubuntu-jammy-standard``, the most recent -development version of Sage (``dev`` tag), and a full installation of -the Sage distribution (``with-targets``). You can edit a copy of the -configuration file to change to a different platform, another +You can edit a copy of the configuration file to change to a different platform, another version, or build stage. After editing the configuration file (or changing the symlink), run "Remote-Containers: Rebuild Container" from the Command Palette. See the `VS Code devcontainer.json reference @@ -1206,34 +1208,36 @@ and the `GitHub introduction to dev containers `_ for more information. -In addition to the ``.devcontainer/portability-.../devcontainer.json`` files, Sage also -provides several other sample ``devcontainer.json`` configuration files: +In addition to the +``$SAGE_ROOT/.devcontainer/portability-.../devcontainer.json`` files, Sage also +provides several other sample ``devcontainer.json`` configuration files in the +directory ``$SAGE_ROOT/.devcontainer``: -- `.devcontainer/downstream-archlinux-latest/devcontainer.json +- `downstream-archlinux-latest/devcontainer.json `_ configures a container with an installation of `Arch Linux `_ and its SageMath package. (Arch Linux packaging is downstream from the Sage project, hence the prefix ``downstream-...``; the suffix ``latest`` indicates the most recent version of Arch Linux as available on Docker Hub.) -- `.devcontainer/downstream-conda-forge-latest/devcontainer.json +- `downstream-conda-forge-latest/devcontainer.json `_ similarly configures a container with an installation of conda-forge and its SageMath package. -- `.devcontainer/cocalc/devcontainer.json +- `cocalc/devcontainer.json `_ configures a container with `the CoCalc Docker image `_. It then updates the installation of SageMath in this container by building from the current source tree. -- `.devcontainer/computop-sage/devcontainer.json +- `computop-sage/devcontainer.json `_ configures a container with the `Docker image from the 3-manifolds project `_, providing SnapPy, Regina, PHCPack, etc. It then updates the installation of SageMath in this container by building from the current source tree. -- `.devcontainer/sagemath-sagemath/devcontainer.json +- `sagemath-sagemath/devcontainer.json `_ configures a container with `SageMath's official Docker image `_. It then updates the installation of SageMath in this container by building from @@ -1242,3 +1246,4 @@ provides several other sample ``devcontainer.json`` configuration files: These ``devcontainer.json`` configuration files are useful for testing user scripts on these deployments of SageMath. You may also find it useful to copy these configurations into your own projects or to adapt them to your needs. + From 9439ce6966629e20ac118fa92649dcf13d7c8f14 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 12 Aug 2022 10:18:07 +0900 Subject: [PATCH 350/591] More edits --- .devcontainer/cocalc/devcontainer.json | 2 +- .devcontainer/computop-sage/devcontainer.json | 2 +- .devcontainer/portability-post_start.sh | 9 ++-- .../sagemath-sagemath/devcontainer.json | 2 +- src/doc/en/developer/portability_testing.rst | 42 +++++++++++-------- 5 files changed, 33 insertions(+), 24 deletions(-) diff --git a/.devcontainer/cocalc/devcontainer.json b/.devcontainer/cocalc/devcontainer.json index 7752a065bd3..303d77bd51e 100644 --- a/.devcontainer/cocalc/devcontainer.json +++ b/.devcontainer/cocalc/devcontainer.json @@ -1,7 +1,7 @@ // See https://aka.ms/devcontainer.json for format details. { "name": "CoCalc Docker", - "image": "sagemathinc/cocalc" + "image": "sagemathinc/cocalc", "containerEnv": { "MAKE": "make -j12" }, diff --git a/.devcontainer/computop-sage/devcontainer.json b/.devcontainer/computop-sage/devcontainer.json index a852d04a6dd..c73ae9a564e 100644 --- a/.devcontainer/computop-sage/devcontainer.json +++ b/.devcontainer/computop-sage/devcontainer.json @@ -1,7 +1,7 @@ // See https://aka.ms/devcontainer.json for format details. { "name": "computop/sage Docker", - "image": "computop/sage" + "image": "computop/sage", "containerEnv": { "MAKE": "make -j12" }, diff --git a/.devcontainer/portability-post_start.sh b/.devcontainer/portability-post_start.sh index d19e37002c8..95a49473e2b 100755 --- a/.devcontainer/portability-post_start.sh +++ b/.devcontainer/portability-post_start.sh @@ -1,5 +1,6 @@ #! /bin/sh -# The portability-.../devcontainer.json configurations run this script after the container is started. +# The portability-.../devcontainer.json configurations run this script after +# the container is started. # # The script assumes that it is run from SAGE_ROOT. # @@ -11,11 +12,13 @@ for f in config.log logs upstream; do rm -f $f fi done -# If possible (ensured after https://trac.sagemath.org/ticket/33262), keep the logs in the container. +# If possible (ensured after https://trac.sagemath.org/ticket/33262), keep the +# logs in the container. if [ ! -f logs ]; then ln -s /sage/logs logs fi -# Bootstrap, configure, and build the Sage distribution, reusing the Sage installation from the prebuilt image. +# Bootstrap, configure, and build the Sage distribution, reusing the Sage +# installation from the prebuilt image. set -e set -x make configure diff --git a/.devcontainer/sagemath-sagemath/devcontainer.json b/.devcontainer/sagemath-sagemath/devcontainer.json index 501bc46702e..58112128e4a 100644 --- a/.devcontainer/sagemath-sagemath/devcontainer.json +++ b/.devcontainer/sagemath-sagemath/devcontainer.json @@ -2,7 +2,7 @@ { "name": "sagemath/sagemath Docker", // sagemath/sagemath-dev as of 9.5 is broken? - "image": "sagemath/sagemath:develop" + "image": "sagemath/sagemath:develop", "containerEnv": { "MAKE": "make -j12" }, diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 2d59dad71c7..e443b926e9f 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1153,10 +1153,16 @@ convenient for developing with Docker containers thanks to the `Visual Studio Code Remote - Containers `_ extension. -Sage provides sample ``devcontainer.json`` configuration files +If the extension is not already installed, then in VS Code, click the +"Extension" icon on the left (or press :kbd:`Ctrl` + :kbd:`Shift` + :kbd:`X`; +on macOS, :kbd:`Command` + :kbd:`Shift` + :kbd:`X`) to open a list of +extensions. Search for "Remote - Containers" and install it. + +The extension needs a ``devcontainer.json`` configuration file to work. Sage +provides sample ``devcontainer.json`` configuration files `$SAGE_ROOT/.devcontainer/*/devcontainer.json -`_ -for this purpose. +`_ for this +purpose. To get started, symlink (or copy) one of the sample files to ``$SAGE_ROOT/.devcontainer/devcontainer.json``. For example, choose @@ -1166,28 +1172,28 @@ the most recent development version of Sage (``dev`` tag), and a full installation of the Sage distribution (``with-targets``). -For example, in macOS, you can do this using the shell as follows:: +In macOS for example, you can do this using the shell as follows:: [mkoeppe@sage sage] $ (cd .devcontainer && ln -s portability-ubuntu-jammy-standard/devcontainer.json .) -Then, start VS Code:: +Now start VS Code:: [mkoeppe@sage sage] $ code . -In VS Code, click the "Extension" icon on the left (or press -:kbd:`Ctrl` + :kbd:`Shift` + :kbd:`X`; on macOS, :kbd:`Command` + -:kbd:`Shift` + :kbd:`X`) to open a list of extensions. Search for -"Remote - Containers" and install it if it is not already installed. +Then VS Code may prompt you whether you would like to open the current +directory in the configured devcontainer (yes). If it does not, use the command palette +(:kbd:`Ctrl` + :kbd:`Shift` + :kbd:`P`), enter the command "Remote-Containers: +Reopen Folder in Container" , and hit :kbd:`Enter`. + +If the above ``code .`` command does not work, start VS Code as a regular application, then in the +command palette of VS Code, enter "Remote-Containers: Open Folder Container", +and hit :kbd:`Enter`, and choose the Sage repository ``$SAGE_ROOT``. -With the extension installed, VS Code may prompt you whether you would -like to open the current directory in the devcontainer (yes). If it -does not, use the command palette (:kbd:`Ctrl` + :kbd:`Shift` + -:kbd:`P`), enter the command "Remote-Containers: Reopen Folder in -Container" , and hit :kbd:`Enter`. -By clicking on "Show Log", you can see what it does: +Once VS Code starts running the configured devcontainer, by clicking on "Show Log", +you can see what it does: - It pulls the prebuilt image from ghcr.io (via - `.devcontainer/portability-Dockerfile + `$SAGE_ROOT/.devcontainer/portability-Dockerfile `_); note that these are multi-gigabyte images, so it may take a while. @@ -1201,8 +1207,8 @@ By clicking on "Show Log", you can see what it does: You can edit a copy of the configuration file to change to a different platform, another version, or build stage. After editing the configuration file (or changing the -symlink), run "Remote-Containers: Rebuild Container" from the Command -Palette. See the `VS Code devcontainer.json reference +symlink), run "Remote-Containers: Rebuild Container" from the command +palette. See the `VS Code devcontainer.json reference `_ and the `GitHub introduction to dev containers `_ From 4bd8169eb26349b8a0f64cb03c983e0adfe8f8ff Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 12 Aug 2022 10:21:37 +0900 Subject: [PATCH 351/591] A typo --- src/doc/en/developer/portability_testing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index e443b926e9f..600086f46c2 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1186,7 +1186,7 @@ directory in the configured devcontainer (yes). If it does not, use the command Reopen Folder in Container" , and hit :kbd:`Enter`. If the above ``code .`` command does not work, start VS Code as a regular application, then in the -command palette of VS Code, enter "Remote-Containers: Open Folder Container", +command palette of VS Code, enter "Remote-Containers: Open Folder in Container", and hit :kbd:`Enter`, and choose the Sage repository ``$SAGE_ROOT``. Once VS Code starts running the configured devcontainer, by clicking on "Show Log", From 028796d47eedb24a730258ae18e89b95bda24639 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 12 Aug 2022 13:35:14 +0900 Subject: [PATCH 352/591] Fixing numerous issues with __call__ and expanding its functionality. Moving plethysm to a Stream_plethysm. --- src/sage/data_structures/stream.py | 129 +++++++++++++- src/sage/rings/lazy_series.py | 269 ++++++++++++++++++++++------- src/sage/rings/lazy_series_ring.py | 14 ++ 3 files changed, 351 insertions(+), 61 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 0a5219ba5b3..37ca2302ac6 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -96,6 +96,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.arith.misc import divisors +from sage.combinat.integer_vector_weighted import iterator_fast as wt_int_vec_iter class Stream(): """ @@ -1599,7 +1600,7 @@ def __init__(self, f, g): sage: g = Stream_function(lambda n: n^2, ZZ, True, 1) sage: h = Stream_cauchy_compose(f, g) """ - assert g._approximate_order > 0 + #assert g._approximate_order > 0 self._fv = f._approximate_order self._gv = g._approximate_order if self._fv < 0: @@ -1644,6 +1645,132 @@ def get_coefficient(self, n): return ret + sum(self._left[i] * self._pos_powers[i][n] for i in range(1, n // self._gv+1)) +class Stream_plethysm(Stream_binary): + r""" + Return the plethysm of ``f`` composed by ``g``. + + This is the plethysm `f \circ g = f(g)` when `g` is an element of + the ring of symmetric functions. + + INPUT: + + - ``f`` -- a :class:`Stream` + - ``g`` -- a :class:`Stream` with positive order + - ``p`` -- the powersum symmetric functions + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_plethysm + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: f = Stream_function(lambda n: s[n], s, True, 1) + sage: g = Stream_function(lambda n: s[[1]*n], s, True, 1) + sage: h = Stream_plethysm(f, g, p) + sage: [s(h[i]) for i in range(5)] + [0, + s[1], + s[1, 1] + s[2], + 2*s[1, 1, 1] + s[2, 1] + s[3], + 3*s[1, 1, 1, 1] + 2*s[2, 1, 1] + s[2, 2] + s[3, 1] + s[4]] + sage: u = Stream_plethysm(g, f, p) + sage: [s(u[i]) for i in range(5)] + [0, + s[1], + s[1, 1] + s[2], + s[1, 1, 1] + s[2, 1] + 2*s[3], + s[1, 1, 1, 1] + s[2, 1, 1] + 3*s[3, 1] + 2*s[4]] + """ + def __init__(self, f, g, p): + r""" + Initialize ``self``. + + TESTS:: + + sage: from sage.data_structures.stream import Stream_function, Stream_plethysm + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: f = Stream_function(lambda n: s[n], s, True, 1) + sage: g = Stream_function(lambda n: s[n-1,1], s, True, 2) + sage: h = Stream_plethysm(f, g, p) + """ + #assert g._approximate_order > 0 + self._fv = f._approximate_order + self._gv = g._approximate_order + self._p = p + val = self._fv * self._gv + super().__init__(f, g, f._is_sparse, val) + + def get_coefficient(self, n): + r""" + Return the ``n``-th coefficient of ``self``. + + INPUT: + + - ``n`` -- integer; the degree for the coefficient + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_plethysm + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: f = Stream_function(lambda n: s[n], s, True, 1) + sage: g = Stream_function(lambda n: s[[1]*n], s, True, 1) + sage: h = Stream_plethysm(f, g, p) + sage: s(h.get_coefficient(5)) + 4*s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 2*s[2, 2, 1] + 2*s[3, 1, 1] + s[3, 2] + s[4, 1] + s[5] + sage: [s(h.get_coefficient(i)) for i in range(6)] + [0, + s[1], + s[1, 1] + s[2], + 2*s[1, 1, 1] + s[2, 1] + s[3], + 3*s[1, 1, 1, 1] + 2*s[2, 1, 1] + s[2, 2] + s[3, 1] + s[4], + 4*s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 2*s[2, 2, 1] + 2*s[3, 1, 1] + s[3, 2] + s[4, 1] + s[5]] + """ + if not n: # special case of 0 + return self._left[0] + + # We assume n > 0 + p = self._p + ret = p.zero() + for k in range(n+1): + temp = p(self._left[k]) + for la, c in temp: + inner = self._compute_product(n, la, c) + if inner is not None: + ret += inner + return ret + + def _compute_product(self, n, la, c): + """ + Compute the product ``c * p[la](self._right)`` in degree ``n``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: f = Stream_function(lambda n: s[n], s, True, 1) + sage: g = Stream_exact([s[2], s[3]], False, 0, 4, 2) + sage: h = Stream_plethysm(f, g, p) + sage: ret = h._compute_product(7, [2, 1], 1); ret + 1/12*p[2, 2, 1, 1, 1] + 1/4*p[2, 2, 2, 1] + 1/6*p[3, 2, 2] + + 1/12*p[4, 1, 1, 1] + 1/4*p[4, 2, 1] + 1/6*p[4, 3] + sage: ret == p[2,1](s[2] + s[3]).homogeneous_component(7) + True + """ + p = self._p + ret = p.zero() + for mu in wt_int_vec_iter(n, la): + temp = c + for i, j in zip(la, mu): + gs = self._right[j] + if not gs: + temp = p.zero() + break + temp *= p[i](gs) + ret += temp + return ret + ##################################################################### # Unary operations diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 9b23aaf2dd0..68c5afb2c25 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -136,7 +136,8 @@ Stream_shift, Stream_function, Stream_dirichlet_convolve, - Stream_dirichlet_invert + Stream_dirichlet_invert, + Stream_plethysm ) class LazyModuleElement(Element): @@ -723,13 +724,14 @@ def define(self, s): sage: L = LazySymmetricFunctions(m) sage: E = L(lambda n: s[n], valuation=0) sage: X = L(s[1]) - sage: A = L(None, valuation=1); A.define(X*E(A)) - sage: A - m[1] + (2*m[1,1]+m[2]) + (9*m[1,1,1]+5*m[2,1]+2*m[3]) - + (64*m[1,1,1,1]+34*m[2,1,1]+18*m[2,2]+13*m[3,1]+4*m[4]) - + (625*m[1,1,1,1,1]+326*m[2,1,1,1]+171*m[2,2,1]+119*m[3,1,1]+63*m[3,2]+35*m[4,1]+9*m[5]) - + (7776*m[1,1,1,1,1,1]+4016*m[2,1,1,1,1]+2078*m[2,2,1,1]+1077*m[2,2,2]+1433*m[3,1,1,1]+744*m[3,2,1]+268*m[3,3]+401*m[4,1,1]+209*m[4,2]+95*m[5,1]+20*m[6]) - + O^7 + sage: A = L(None); A.define(X*E(A, check=False)) + sage: A[:6] + [0, + m[1], + 2*m[1, 1] + m[2], + 9*m[1, 1, 1] + 5*m[2, 1] + 2*m[3], + 64*m[1, 1, 1, 1] + 34*m[2, 1, 1] + 18*m[2, 2] + 13*m[3, 1] + 4*m[4], + 625*m[1, 1, 1, 1, 1] + 326*m[2, 1, 1, 1] + 171*m[2, 2, 1] + 119*m[3, 1, 1] + 63*m[3, 2] + 35*m[4, 1] + 9*m[5]] TESTS:: @@ -2584,7 +2586,7 @@ class LazyLaurentSeries(LazyCauchyProductSeries): sage: TestSuite(f).run() """ - def __call__(self, g): + def __call__(self, g, *, check=True): r""" Return the composition of ``self`` with ``g``. @@ -2954,16 +2956,18 @@ def __call__(self, g): raise NotImplementedError("can only compose with a lazy series") # Perhaps we just don't yet know if the valuation is positive - if g._coeff_stream._approximate_order <= 0: - if any(g._coeff_stream[i] for i in range(g._coeff_stream._approximate_order, 1)): - raise ValueError("can only compose with a positive valuation series") - g._coeff_stream._approximate_order = 1 + if check: + if g._coeff_stream._approximate_order <= 0: + if any(g._coeff_stream[i] for i in range(g._coeff_stream._approximate_order, 1)): + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_order = 1 if isinstance(g, LazyDirichletSeries): - if g._coeff_stream._approximate_order == 1: - if g._coeff_stream[1] != 0: - raise ValueError("can only compose with a positive valuation series") - g._coeff_stream._approximate_order = 2 + if check: + if g._coeff_stream._approximate_order == 1: + if g._coeff_stream[1] != 0: + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_order = 2 # we assume that the valuation of self[i](g) is at least i def coefficient(n): @@ -3261,7 +3265,7 @@ class LazyTaylorSeries(LazyCauchyProductSeries): sage: g == f True """ - def __call__(self, *g): + def __call__(self, *g, check=True): r""" Return the composition of ``self`` with ``g``. @@ -3283,17 +3287,16 @@ def __call__(self, *g): sage: L. = LazyTaylorSeriesRing(QQ) sage: M. = LazyTaylorSeriesRing(ZZ) - sage: g1 = 1/(1-x); g2 = x+y^2 + sage: g1 = 1 / (1 - x) + sage: g2 = x + y^2 sage: p = a^2 + b + 1 sage: p(g1, g2) - g1^2 - g2 - 1 O(x,y,z)^7 - sage: L. = LazyTaylorSeriesRing(QQ) - sage: M. = LazyTaylorSeriesRing(QQ) - The number of mappings from a set with `m` elements to a set with `n` elements:: + sage: M. = LazyTaylorSeriesRing(QQ) sage: Ea = M(lambda n: 1/factorial(n)) sage: Ex = L(lambda n: 1/factorial(n)*x^n) sage: Ea(Ex*y)[5] @@ -3305,50 +3308,176 @@ def __call__(self, *g): We perform the composition with a lazy Laurent series:: sage: N. = LazyLaurentSeriesRing(QQ) - sage: f1 = 1/(1-w); f2 = cot(w/(1-w)) + sage: f1 = 1 / (1 - w) + sage: f2 = cot(w / (1 - w)) sage: p(f1, f2) w^-1 + 1 + 5/3*w + 8/3*w^2 + 164/45*w^3 + 23/5*w^4 + 5227/945*w^5 + O(w^6) + We perform the composition with a lazy Dirichlet series:: + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: g = D(constant=1)-1; g + 1/(2^s) + 1/(3^s) + 1/(4^s) + O(1/(5^s)) + sage: f = 1 / (1 - x - y*z); f + 1 + x + (x^2+y*z) + (x^3+2*x*y*z) + (x^4+3*x^2*y*z+y^2*z^2) + + (x^5+4*x^3*y*z+3*x*y^2*z^2) + + (x^6+5*x^4*y*z+6*x^2*y^2*z^2+y^3*z^3) + + O(x,y,z)^7 + sage: fog = f(g, g, g); fog + 1 + 1/(2^s) + 1/(3^s) + 3/4^s + 1/(5^s) + 5/6^s + O(1/(7^s)) + sage: fg = 1 / (1 - g - g*g); fg + 1 + 1/(2^s) + 1/(3^s) + 3/4^s + 1/(5^s) + 5/6^s + 1/(7^s) + O(1/(8^s)) + sage: fog - fg + O(1/(7^s)) + + sage: f = 1 / (1 - 2*a) + sage: f(g) + 1 + 2/2^s + 2/3^s + 6/4^s + 2/5^s + 10/6^s + 2/7^s + O(1/(8^s)) + sage: 1 / (1 - 2*g) + 1 + 2/2^s + 2/3^s + 6/4^s + 2/5^s + 10/6^s + 2/7^s + O(1/(8^s)) + + The output parent is always the common parent between the base ring + of `f` and the parent of `g` or extended to the corresponding + lazy series:: + + sage: T. = LazyTaylorSeriesRing(QQ) + sage: R. = ZZ[] + sage: S. = R[] + sage: L. = LaurentPolynomialRing(ZZ) + sage: parent(x(a, b)) + Multivariate Polynomial Ring in a, b, c over Rational Field + sage: parent(x(CC(2), a)) + Multivariate Polynomial Ring in a, b, c over Complex Field with 53 bits of precision + sage: parent(x(0, 0)) + Rational Field + sage: f = 1 / (1 - x - y); f + 1 + (x+y) + (x^2+2*x*y+y^2) + (x^3+3*x^2*y+3*x*y^2+y^3) + + (x^4+4*x^3*y+6*x^2*y^2+4*x*y^3+y^4) + + (x^5+5*x^4*y+10*x^3*y^2+10*x^2*y^3+5*x*y^4+y^5) + + (x^6+6*x^5*y+15*x^4*y^2+20*x^3*y^3+15*x^2*y^4+6*x*y^5+y^6) + + O(x,y)^7 + sage: f(a^2, b*c) + 1 + (a^2+b*c) + (a^4+2*a^2*b*c+b^2*c^2) + (a^6+3*a^4*b*c+3*a^2*b^2*c^2+b^3*c^3) + O(a,b,c)^7 + sage: f(v, v^2) + 1 + v + 2*v^2 + 3*v^3 + 5*v^4 + 8*v^5 + 13*v^6 + O(v^7) + sage: f(z, z^2 + z) + 1 + 2*z + 5*z^2 + 12*z^3 + 29*z^4 + 70*z^5 + 169*z^6 + O(z^7) + sage: three = T(3)(a^2, b); three + 3 + sage: parent(three) + Multivariate Polynomial Ring in a, b, c over Rational Field + TESTS:: sage: L. = LazyTaylorSeriesRing(ZZ) - sage: f = 1/(1-x-y) + sage: f = 1 / (1 - x - y) sage: f(f) Traceback (most recent call last): ... ValueError: arity of must be equal to the number of arguments provided + sage: f(1, x*y) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + This test will pass once pushouts are implemented:: + + sage: R. = QQ[] + sage: f(1/2*a, x) + Traceback (most recent call last): + ... + TypeError: no common canonical parent for objects with parents: ... + """ if len(g) != len(self.parent().variable_names()): raise ValueError("arity of must be equal to the number of arguments provided") + # Find a good parent for the result + from sage.structure.element import get_coercion_model + cm = get_coercion_model() + P = cm.common_parent(self.base_ring(), *[parent(h) for h in g]) + # f has finite length if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: # constant polynomial poly = self.polynomial() if poly.is_constant(): - return poly - return poly(g) - - g0 = g[0] - P = g0.parent() + return P(poly) + return P(poly(g)) + + # f now has (potentially) infinitely many terms + # Lift the resulting parent to a lazy series (if possible) + # Also make sure each element of g is a LazyModuleElement + from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_univariate + from sage.rings.lazy_series_ring import LazySeriesRing + if not isinstance(P, LazySeriesRing): + fP = parent(self) + if fP._laurent_poly_ring.has_coerce_map_from(P): + S = fP._laurent_poly_ring + P = fP + if isinstance(P, (PolynomialRing_general, MPolynomialRing_base)): + from sage.rings.lazy_series_ring import LazyTaylorSeriesRing + S = P + try: + sparse = S.is_sparse() + except AttributeError: + sparse = fP.is_sparse() + P = LazyTaylorSeriesRing(S.base_ring(), S.variable_names(), sparse) + elif isinstance(P, LaurentPolynomialRing_univariate): + from sage.rings.lazy_series_ring import LazyLaurentSeriesRing + S = P + P = LazyLaurentSeriesRing(S.base_ring(), S.variable_names(), fP.is_sparse()) + else: + raise ValueError("unable to evaluate the series at {}".format(g)) + g = [P(S(h)) for h in g] + else: + g = [P(h) for h in g] R = P._internal_poly_ring.base_ring() + + if check: + for h in g: + if h._coeff_stream._approximate_order == 0: + if h[0]: + raise ValueError("can only compose with a positive valuation series") + h._coeff_stream._approximate_order = 1 + + if isinstance(h, LazyDirichletSeries): + if h._coeff_stream._approximate_order == 1: + if h._coeff_stream[1] != 0: + raise ValueError("can only compose with a positive valuation series") + h._coeff_stream._approximate_order = 2 + + + # We now ahave that every element of g has a _coeff_stream + sorder = self._coeff_stream._approximate_order if len(g) == 1: - # we assume that the valuation of self[i](g) is at least i - def coefficient(n): - r = R.zero() - for i in range(n+1): - r += self[i]*(g0 ** i)[n] - return r - else: - def coefficient(n): - r = R.zero() - for i in range(n+1): - r += self[i](g)[n] - return r - coeff_stream = Stream_function(coefficient, R, P._sparse, 0) + g0 = g[0] + if isinstance(g0, LazyDirichletSeries): + # we assume that the valuation of self[i](g) is at least i + def coefficient(n): + return sum(self[i] * (g0**i)[n] for i in range(n+1)) + coeff_stream = Stream_function(coefficient, R, P._sparse, 1) + return P.element_class(P, coeff_stream) + + coeff_stream = Stream_cauchy_compose(self._coeff_stream, g0._coeff_stream) + return P.element_class(P, coeff_stream) + + # The arity is at least 2 + gv = min(h._coeff_stream._approximate_order for h in g) + def coefficient(n): + r = R.zero() + for i in range(n//gv+1): + # Make sure the element returned from the composition is in P + r += P(self[i](g))[n] + return r + coeff_stream = Stream_function(coefficient, R, P._sparse, sorder * gv) return P.element_class(P, coeff_stream) + compose = __call__ + def _format_series(self, formatter, format_strings=False): """ Return nonzero ``self`` formatted by ``formatter``. @@ -3492,7 +3621,7 @@ class LazySymmetricFunction(LazyCauchyProductSeries): sage: s = SymmetricFunctions(ZZ).s() sage: L = LazySymmetricFunctions(s) """ - def __call__(self, *args): + def __call__(self, *args, check=True): r""" Return the composition of ``self`` with ``args``. @@ -3554,6 +3683,15 @@ def __call__(self, *args): s[] + (s[2,2]+s[4]) + O^7 sage: S(sum(f[i](s[2]) for i in range(5))).truncate(10) == g.truncate(10) True + sage: f = 1 / (1 - S(s[2])) + sage: g = S(s[1]) / (1 - S(s[1])) + sage: h = f(g) + sage: h + s[] + s[2] + (s[1,1,1]+2*s[2,1]+s[3]) + + (2*s[1,1,1,1]+4*s[2,1,1]+5*s[2,2]+5*s[3,1]+3*s[4]) + + (2*s[1,1,1,1,1]+10*s[2,1,1,1]+14*s[2,2,1]+18*s[3,1,1]+16*s[3,2]+14*s[4,1]+4*s[5]) + + (3*s[1,1,1,1,1,1]+22*s[2,1,1,1,1]+38*s[2,2,1,1]+28*s[2,2,2]+48*s[3,1,1,1]+82*s[3,2,1]+25*s[3,3]+51*s[4,1,1]+56*s[4,2]+31*s[5,1]+9*s[6]) + + O^7 sage: f(0) 1 sage: f(s(1)) @@ -3597,13 +3735,15 @@ def __call__(self, *args): g = P(g) # self has (potentially) infinitely many terms - if g._coeff_stream._approximate_order == 0: - if g[0]: - raise ValueError("can only compose with a positive valuation series") - g._coeff_stream._approximate_order = 1 - - p = R.realization_of().power() - g_p = Stream_map_coefficients(g._coeff_stream, lambda c: c, p) + if check: + if g._coeff_stream._approximate_order == 0: + if g[0]: + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_order = 1 + + ps = P._laurent_poly_ring.realization_of().p() + coeff_stream = Stream_plethysm(self._coeff_stream, g._coeff_stream, ps) + g_p = Stream_map_coefficients(g._coeff_stream, lambda c: c, ps) try: degree_one = [BR(x) for x in BR.variable_names_recursive()] except AttributeError: @@ -3630,23 +3770,25 @@ def g_coeff_stream(k): R, P._sparse, 0) from sage.misc.lazy_list import lazy_list stretched = lazy_list(lambda k: g_coeff_stream(k)) - f_p = Stream_map_coefficients(self._coeff_stream, lambda c: c, p) + f_p = Stream_map_coefficients(self._coeff_stream, lambda c: c, ps) def coefficient(n): r = R(0) for i in range(n+1): - r += p._apply_module_morphism(f_p[i], - lambda part: p.prod(sum(stretched[j][h] for h in range(n+1)) - for j in part), - codomain=p).homogeneous_component(n) + r += ps._apply_module_morphism(f_p[i], + lambda part: ps.prod(sum(stretched[j][h] for h in range(n+1)) + for j in part), + codomain=ps).homogeneous_component(n) return r + #coeff_stream = Stream_function(coefficient, P._internal_poly_ring.base_ring(), P._sparse, 0) else: - raise NotImplementedError + raise NotImplementedError("only implemented for arity 1") - coeff_stream = Stream_function(coefficient, P._internal_poly_ring.base_ring(), P._sparse, 0) return P.element_class(P, coeff_stream) + plethysm = __call__ + def _format_series(self, formatter, format_strings=False): - """ + r""" Return nonzero ``self`` formatted by ``formatter``. TESTS:: @@ -3656,7 +3798,14 @@ def _format_series(self, formatter, format_strings=False): sage: L = LazySymmetricFunctions(tensor([h, e])) sage: f = L(lambda n: sum(tensor([h[k], e[n-k]]) for k in range(n+1))) sage: f._format_series(repr) - '(h[]#e[]) + (h[]#e[1]+h[1]#e[]) + (h[]#e[2]+h[1]#e[1]+h[2]#e[]) + (h[]#e[3]+h[1]#e[2]+h[2]#e[1]+h[3]#e[]) + (h[]#e[4]+h[1]#e[3]+h[2]#e[2]+h[3]#e[1]+h[4]#e[]) + (h[]#e[5]+h[1]#e[4]+h[2]#e[3]+h[3]#e[2]+h[4]#e[1]+h[5]#e[]) + (h[]#e[6]+h[1]#e[5]+h[2]#e[4]+h[3]#e[3]+h[4]#e[2]+h[5]#e[1]+h[6]#e[]) + O^7' + '(h[]#e[]) + + (h[]#e[1]+h[1]#e[]) + + (h[]#e[2]+h[1]#e[1]+h[2]#e[]) + + (h[]#e[3]+h[1]#e[2]+h[2]#e[1]+h[3]#e[]) + + (h[]#e[4]+h[1]#e[3]+h[2]#e[2]+h[3]#e[1]+h[4]#e[]) + + (h[]#e[5]+h[1]#e[4]+h[2]#e[3]+h[3]#e[2]+h[4]#e[1]+h[5]#e[]) + + (h[]#e[6]+h[1]#e[5]+h[2]#e[4]+h[3]#e[3]+h[4]#e[2]+h[5]#e[1]+h[6]#e[]) + + O^7' """ P = self.parent() cs = self._coeff_stream @@ -3920,7 +4069,7 @@ def __invert__(self): P = self.parent() return P.element_class(P, Stream_dirichlet_invert(self._coeff_stream)) - def __call__(self, p): + def __call__(self, p, *, check=True): r""" Return the composition of ``self`` with a linear polynomial ``p``. diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 0ef1f1888c3..b0cc8172d07 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -671,6 +671,20 @@ def is_sparse(self): """ return self._sparse + def is_exact(self): + """ + Return if ``self`` is exact or not. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(ZZ, 'z') + sage: L.is_exact() + True + sage: L = LazyLaurentSeriesRing(RR, 'z') + sage: L.is_exact() + False + """ + return self.base_ring().is_exact() class LazyLaurentSeriesRing(LazySeriesRing): """ From 9fb155f4502d54f0ea8dc2b15745804b000d694a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 12 Aug 2022 13:42:42 +0900 Subject: [PATCH 353/591] Removing unused code from previous version. --- src/sage/rings/lazy_series.py | 37 ----------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 68c5afb2c25..2ba1388d6a3 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3743,43 +3743,6 @@ def __call__(self, *args, check=True): ps = P._laurent_poly_ring.realization_of().p() coeff_stream = Stream_plethysm(self._coeff_stream, g._coeff_stream, ps) - g_p = Stream_map_coefficients(g._coeff_stream, lambda c: c, ps) - try: - degree_one = [BR(x) for x in BR.variable_names_recursive()] - except AttributeError: - try: - degree_one = BR.gens() - except NotImplementedError: - degree_one = [] - def raise_c(n): - return lambda c: c.subs(**{str(x): x ** n for x in degree_one}) - def scale_part(n): - return lambda m: m.__class__(m.parent(), [i * n for i in m]) - def pn_pleth(f, n): - return f.map_support(scale_part(n)) - def stretched_coefficient(k, n): - q, r = ZZ(n).quo_rem(k) - if r: - return 0 - c = g_p[q] - if c: - return pn_pleth(c.map_coefficients(raise_c(k)), k) - return c - def g_coeff_stream(k): - return Stream_function(lambda n: stretched_coefficient(k, n), - R, P._sparse, 0) - from sage.misc.lazy_list import lazy_list - stretched = lazy_list(lambda k: g_coeff_stream(k)) - f_p = Stream_map_coefficients(self._coeff_stream, lambda c: c, ps) - def coefficient(n): - r = R(0) - for i in range(n+1): - r += ps._apply_module_morphism(f_p[i], - lambda part: ps.prod(sum(stretched[j][h] for h in range(n+1)) - for j in part), - codomain=ps).homogeneous_component(n) - return r - #coeff_stream = Stream_function(coefficient, P._internal_poly_ring.base_ring(), P._sparse, 0) else: raise NotImplementedError("only implemented for arity 1") From 5e528328e21c312483374adfc26967e95530063d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 12 Aug 2022 14:44:39 +0900 Subject: [PATCH 354/591] Fixing order of k_atoms in k-Schur book. --- src/sage/tests/book_schilling_zabrocki_kschur_primer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py index fe79941c39e..b0d56792851 100644 --- a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py +++ b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py @@ -542,7 +542,7 @@ sage: la = Partition([3,2,1,1]) sage: la.k_atom(4) - [[[1, 1, 1], [2, 2], [3], [4]], [[1, 1, 1, 4], [2, 2], [3]]] + [[[1, 1, 1, 4], [2, 2], [3]], [[1, 1, 1], [2, 2], [3], [4]]] Sage example in ./kschurnotes/notes-mike-anne.tex, line 3639:: From c41575e223d8481e172f1a9ec0a59f247cdc429b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 12 Aug 2022 14:47:25 +0900 Subject: [PATCH 355/591] Cannot specify a generating set when multiplying two-sided ideals. --- src/sage/rings/noncommutative_ideals.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/rings/noncommutative_ideals.pyx b/src/sage/rings/noncommutative_ideals.pyx index 70039b238c9..29599c2ac0f 100644 --- a/src/sage/rings/noncommutative_ideals.pyx +++ b/src/sage/rings/noncommutative_ideals.pyx @@ -398,8 +398,7 @@ class Ideal_nc(Ideal_generic): NotImplementedError: cannot multiply non-commutative ideals """ if isinstance(other, Ideal_nc) and self.ring() == other.ring(): - if (self.side() == "left" and other.side() == "right" - or self.side() == other.side() == "twosided"): + if self.side() == "left" and other.side() == "right": gens = [z for z in (x * y for x in self.gens() for y in other.gens()) if z] return self.ring().ideal(gens, side='twosided') raise NotImplementedError("cannot multiply non-commutative ideals") From c092e87889f97dc5a6f503deacb645dc90f4621c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 12 Aug 2022 17:40:34 +0900 Subject: [PATCH 356/591] Add section of disputed styles --- src/doc/en/developer/coding_basics.rst | 43 +++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 5f27ccd05c2..4f208b8e357 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -179,7 +179,6 @@ the section ``options.package_data`` of the file file of another distribution). - Learn by copy/paste =================== @@ -685,6 +684,48 @@ You are strongly encouraged to: of Sage that break something else might not go seen until much later when someone uses the system, which is unacceptable. +Fine points on styles +--------------------- + +A Sage developer, in writing code and docstrings, should follow the styles +suggested in this manual, except special cases with good reasons. However, there +are some details where we as a community did not reach to an agreement on +the official style. These are + +- one space:: + + This is the first sentence. This is the second sentence. + + vs two spaces:: + + This is the first sentence. This is the second sentence. + + between sentences. + +- tight list:: + + - first item + - second item + - third item + + vs spaced list:: + + - first item + + - second item + + - third item + +There are different opinions on each of these, and in reality, we find +instances in each style in our codebase. Then what should we do? Do we decide +on one style by voting? There are different opinions even on what to do! + +We can at least do this to prevent any dispute about these style conflicts: + +- Acknowledge different authors may have different preferences on these. + +- Respect the style choice of the author who first wrote the code or the docstrings. + Private functions ^^^^^^^^^^^^^^^^^ From 7f9dbb186459922ba90b5a9326ebf6b5dcaa1ba8 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 12 Aug 2022 17:45:50 +0900 Subject: [PATCH 357/591] Some last doc fixes and tweaks. --- src/sage/data_structures/stream.py | 24 +++++++++++++----------- src/sage/rings/lazy_series.py | 8 +++++--- src/sage/rings/lazy_series_ring.py | 12 +++++++----- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 37ca2302ac6..e54a90b8b88 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -4,7 +4,7 @@ This module provides lazy implementations of basic operators on streams. The classes implemented in this module can be used to build up more complex streams for different kinds of series (Laurent, -Dirichlet, etc). +Dirichlet, etc.). EXAMPLES: @@ -85,6 +85,8 @@ # **************************************************************************** # Copyright (C) 2019 Kwankyu Lee +# 2022 Martin Rubey +# 2022 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 @@ -1025,7 +1027,7 @@ def __eq__(self, other): INPUT: - - ``other`` -- a stream of coefficients + - ``other`` -- a :class:`Stream` of coefficients EXAMPLES:: @@ -1088,7 +1090,7 @@ def __eq__(self, other): INPUT: - - ``other`` -- a stream of coefficients + - ``other`` -- a :class:`Stream` of coefficients EXAMPLES:: @@ -1213,8 +1215,8 @@ class Stream_add(Stream_binaryCommutative): INPUT: - - ``left`` -- stream of coefficients on the left side of the operator - - ``right`` -- stream of coefficients on the right side of the operator + - ``left`` -- :class:`Stream` of coefficients on the left side of the operator + - ``right`` -- :class:`Stream` of coefficients on the right side of the operator EXAMPLES:: @@ -1273,8 +1275,8 @@ class Stream_sub(Stream_binary): INPUT: - - ``left`` -- stream of coefficients on the left side of the operator - - ``right`` -- stream of coefficients on the right side of the operator + - ``left`` -- :class:`Stream` of coefficients on the left side of the operator + - ``right`` -- :class:`Stream` of coefficients on the right side of the operator EXAMPLES:: @@ -1338,8 +1340,8 @@ class Stream_cauchy_mul(Stream_binary): INPUT: - - ``left`` -- stream of coefficients on the left side of the operator - - ``right`` -- stream of coefficients on the right side of the operator + - ``left`` -- :class:`Stream` of coefficients on the left side of the operator + - ``right`` -- :class:`Stream` of coefficients on the right side of the operator EXAMPLES:: @@ -1424,8 +1426,8 @@ class Stream_dirichlet_convolve(Stream_binary): INPUT: - - ``left`` -- stream of coefficients on the left side of the operator - - ``right`` -- stream of coefficients on the right side of the operator + - ``left`` -- :class:`Stream` of coefficients on the left side of the operator + - ``right`` -- :class:`Stream` of coefficients on the right side of the operator The coefficient of `n^{-s}` in the convolution of `l` and `r` equals `\sum_{k | n} l_k r_{n/k}`. diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 2ba1388d6a3..f580ed47191 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -104,6 +104,8 @@ # **************************************************************************** # Copyright (C) 2019 Kwankyu Lee +# 2022 Martin Rubey +# 2022 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 @@ -1474,7 +1476,7 @@ def tan(self): r""" Return the tangent of ``self``. - EXAMPLES: + EXAMPLES:: sage: L. = LazyLaurentSeriesRing(QQ) sage: tan(z) @@ -3281,7 +3283,7 @@ def __call__(self, *g, check=True): INPUT: - - ``g`` -- other series, all of the same parent. + - ``g`` -- other series, all can be coerced into the same parent EXAMPLES:: @@ -3638,7 +3640,7 @@ def __call__(self, *args, check=True): INPUT: - - ``args`` -- other (lazy) symmetric functions. + - ``args`` -- other (lazy) symmetric functions EXAMPLES:: diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index b0cc8172d07..2626384097c 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -22,6 +22,8 @@ # **************************************************************************** # Copyright (C) 2019 Kwankyu Lee +# 2022 Martin Rubey +# 2022 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 @@ -442,7 +444,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No raise ValueError(f"unable to convert {x} into {self}") def undefined(self, valuation=None): - """ + r""" Return an uninitialized series. INPUT: @@ -451,7 +453,7 @@ def undefined(self, valuation=None): Power series can be defined recursively (see :meth:`sage.rings.lazy_series.LazyModuleElement.define()` for - more examples):: + more examples). EXAMPLES:: @@ -467,13 +469,13 @@ def undefined(self, valuation=None): class options(GlobalOptions): r""" - Set and display the options for Lazy Laurent series. + Set and display the options for lazy series. If no parameters are set, then the function returns a copy of the options dictionary. - The ``options`` to Lazy Laurent series can be accessed as using - :class:`LazyLaurentSeriesRing.options` of :class:`LazyLaurentSeriesRing`. + The ``options`` to lazy series can be accessed as using + :class:`LazySeriesRing.options`. @OPTIONS@ From 1bad4cab778c109dfe3c89130804d6429a366431 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 12 Aug 2022 20:26:47 +0900 Subject: [PATCH 358/591] Some tiny edits --- .devcontainer/cocalc/devcontainer.json | 2 +- .devcontainer/computop-sage/devcontainer.json | 2 +- .devcontainer/downstream-archlinux-latest/devcontainer.json | 2 +- .devcontainer/downstream-conda-forge-latest/devcontainer.json | 2 +- .devcontainer/portability-Dockerfile | 3 ++- .../devcontainer.json | 2 +- .../portability-debian-buster-i386-standard/devcontainer.json | 2 +- .devcontainer/portability-post_start.sh | 2 +- .../portability-ubuntu-jammy-standard/devcontainer.json | 2 +- .devcontainer/sagemath-sagemath/devcontainer.json | 4 ++-- src/doc/en/developer/portability_testing.rst | 4 ++-- 11 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.devcontainer/cocalc/devcontainer.json b/.devcontainer/cocalc/devcontainer.json index 303d77bd51e..c62375d75e0 100644 --- a/.devcontainer/cocalc/devcontainer.json +++ b/.devcontainer/cocalc/devcontainer.json @@ -5,7 +5,7 @@ "containerEnv": { "MAKE": "make -j12" }, - // Run commands after the container is created: + // Run commands after the container is created. "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv && make build V=0", diff --git a/.devcontainer/computop-sage/devcontainer.json b/.devcontainer/computop-sage/devcontainer.json index c73ae9a564e..244ebf0e750 100644 --- a/.devcontainer/computop-sage/devcontainer.json +++ b/.devcontainer/computop-sage/devcontainer.json @@ -5,7 +5,7 @@ "containerEnv": { "MAKE": "make -j12" }, - // Run commands after the container is created: + // Run commands after the container is created. // Install build tools, get rid of sourcing /sage/activate in non-login shells. "postCreateCommand": ".devcontainer/post_create.sh --sudo && sed -i.bak '/sage.*activate/d' ~/.bashrc", // Run commands after the container is started. diff --git a/.devcontainer/downstream-archlinux-latest/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json index 5f1a9d94543..8f0b1480700 100644 --- a/.devcontainer/downstream-archlinux-latest/devcontainer.json +++ b/.devcontainer/downstream-archlinux-latest/devcontainer.json @@ -2,7 +2,7 @@ { "name": "archlinux:latest downstream Sage", "image": "archlinux:latest", - // Run commands after the container is created: + // Run commands after the container is created. "postCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh", // Run commands after the container is started. "postStartCommand": "make configure && ln -sf /usr venv", diff --git a/.devcontainer/downstream-conda-forge-latest/devcontainer.json b/.devcontainer/downstream-conda-forge-latest/devcontainer.json index d7528beee72..a38b23f880a 100644 --- a/.devcontainer/downstream-conda-forge-latest/devcontainer.json +++ b/.devcontainer/downstream-conda-forge-latest/devcontainer.json @@ -2,7 +2,7 @@ { "name": "condaforge/mambaforge:latest downstream Sage", "image": "condaforge/mambaforge:latest", - // Run commands after the container is created: + // Run commands after the container is created. "postCreateCommand": ".devcontainer/post_create.sh && mamba install --yes sage", // Run commands after the container is started. "postStartCommand": "make configure && ln -sf $CONDA_PREFIX venv", diff --git a/.devcontainer/portability-Dockerfile b/.devcontainer/portability-Dockerfile index 52ca0bc6c75..532a1854258 100644 --- a/.devcontainer/portability-Dockerfile +++ b/.devcontainer/portability-Dockerfile @@ -1,5 +1,6 @@ # This Dockerfile is used by all portability-.../devcontainer.json files, -# which provide the actual values for the 4 arguments defined below. +# which provide the actual values for the 4 arguments defined below, which +# feed into the FROM statement that determines the base Docker image. ARG SYSTEM_FACTOR="ubuntu-jammy" ARG PACKAGE_FACTOR="standard" ARG DOCKER_TARGET="with-system-packages" diff --git a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json index 67408930a2f..f6f53ebc87b 100644 --- a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json +++ b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json @@ -13,7 +13,7 @@ "containerEnv": { "MAKE": "make -j12" }, - // Run commands after the container is created: + // Run commands after the container is created. "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. "postStartCommand": ".devcontainer/portability-post_start.sh", diff --git a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json index 9e002922051..c7ea829b269 100644 --- a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json +++ b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json @@ -13,7 +13,7 @@ "containerEnv": { "MAKE": "make -j12" }, - // Run commands after the container is created: + // Run commands after the container is created. "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. "postStartCommand": ".devcontainer/portability-post_start.sh", diff --git a/.devcontainer/portability-post_start.sh b/.devcontainer/portability-post_start.sh index 95a49473e2b..45d0cfb5555 100755 --- a/.devcontainer/portability-post_start.sh +++ b/.devcontainer/portability-post_start.sh @@ -6,7 +6,7 @@ # # If "config.log" or "logs" are symlinks (for example, created by 'tox -e local-...', # or after https://trac.sagemath.org/ticket/33262), they might point outside of -# the devcontainer, so remove them. Likewise for upstream. +# the dev container, so remove them. Likewise for upstream. for f in config.log logs upstream; do if [ -L $f ]; then rm -f $f diff --git a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json index cd3e8d86909..1ce79588c26 100644 --- a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +++ b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json @@ -13,7 +13,7 @@ "containerEnv": { "MAKE": "make -j12" }, - // Run commands after the container is created: + // Run commands after the container is created. "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. "postStartCommand": ".devcontainer/portability-post_start.sh", diff --git a/.devcontainer/sagemath-sagemath/devcontainer.json b/.devcontainer/sagemath-sagemath/devcontainer.json index 58112128e4a..02d5c9fa8db 100644 --- a/.devcontainer/sagemath-sagemath/devcontainer.json +++ b/.devcontainer/sagemath-sagemath/devcontainer.json @@ -6,8 +6,8 @@ "containerEnv": { "MAKE": "make -j12" }, - // Run commands after the container is created: - // Install build tools + // Run commands after the container is created. + // Install build tools. "postCreateCommand": ".devcontainer/post_create.sh --sudo" // Run commands after the container is started. // Do not run configure within a sage-env (see #29485). diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 600086f46c2..68873a51781 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1181,7 +1181,7 @@ Now start VS Code:: [mkoeppe@sage sage] $ code . Then VS Code may prompt you whether you would like to open the current -directory in the configured devcontainer (yes). If it does not, use the command palette +directory in the dev container (yes). If it does not, use the command palette (:kbd:`Ctrl` + :kbd:`Shift` + :kbd:`P`), enter the command "Remote-Containers: Reopen Folder in Container" , and hit :kbd:`Enter`. @@ -1189,7 +1189,7 @@ If the above ``code .`` command does not work, start VS Code as a regular applic command palette of VS Code, enter "Remote-Containers: Open Folder in Container", and hit :kbd:`Enter`, and choose the Sage repository ``$SAGE_ROOT``. -Once VS Code starts running the configured devcontainer, by clicking on "Show Log", +Once VS Code starts running the dev container, by clicking on "show log", you can see what it does: - It pulls the prebuilt image from ghcr.io (via From dc976ec621e58c35db1edff375a71fdbb3b2bf37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 5 Jul 2022 16:53:54 +0200 Subject: [PATCH 359/591] add floordiv for power series for exact division by one coefficient --- src/sage/rings/power_series_poly.pyx | 37 +++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 198c8e99438..dc0c599a2c0 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -4,7 +4,6 @@ Power Series Methods The class ``PowerSeries_poly`` provides additional methods for univariate power series. """ - from .power_series_ring_element cimport PowerSeries from sage.structure.element cimport Element, ModuleElement, RingElement from .infinity import infinity, is_Infinite @@ -540,8 +539,8 @@ cdef class PowerSeries_poly(PowerSeries): prec = self._mul_prec(right_r) return PowerSeries_poly(self._parent, self.__f * (right_r).__f, - prec = prec, - check = True) # check, since truncation may be needed + prec=prec, + check=True) # check, since truncation may be needed cpdef _rmul_(self, Element c): """ @@ -721,6 +720,38 @@ cdef class PowerSeries_poly(PowerSeries): return self._parent(self.truncate().inverse_series_trunc(prec), prec=prec) + def _floordiv_(self, c): + """ + Perform the exact division of ``self`` by a coefficient ``c``. + + .. WARNING:: + + This is not intended to be used with another power series. + + EXAMPLES:: + + sage: A = ZZ[['t']] + sage: f = A([3*2**n for n in range(6)]).O(6) + sage: g = f//3; g + 1 + 2*t + 4*t^2 + 8*t^3 + 16*t^4 + 32*t^5 + O(t^6) + sage: g.parent() + Power Series Ring in t over Integer Ring + + sage: s = polygen(QQ,'s') + sage: A = s.parent()[['t']] + sage: f = A([(s+2)*(s+n) for n in range(5)]).O(5) + sage: g = f//(s+2); g + s + (s + 1)*t + (s + 2)*t^2 + (s + 3)*t^3 + (s + 4)*t^4 + O(t^5) + sage: g.parent() + Power Series Ring in t over Univariate Polynomial Ring in s + over Rational Field + """ + prec = self.prec() + return PowerSeries_poly(self._parent, + self.__f // (c).__f[0], + prec=prec, + check=False) + def truncate(self, prec=infinity): """ The polynomial obtained from power series by truncation at From 4e03fee27f1ebff2741eb57fb0de4d7d80043636 Mon Sep 17 00:00:00 2001 From: Martin Rubey Date: Fri, 12 Aug 2022 15:59:53 +0200 Subject: [PATCH 360/591] remove unused local variable --- src/sage/rings/lazy_series.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index f580ed47191..5bc647340c1 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3727,7 +3727,6 @@ def __call__(self, *args, check=True): gs = g.symmetric_function() return P(f(gs)) - BR = P.base_ring() if isinstance(g, LazySymmetricFunction): R = P._laurent_poly_ring else: @@ -4219,4 +4218,3 @@ def parenthesize(m): poly = formatter(*([parenthesize(mo) for mo in mons] + bigO), sep=" + ") return poly - From 8fd289716dd3e3b02b618bc3a170b6a2351dbd2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 12 Aug 2022 17:09:23 +0200 Subject: [PATCH 361/591] add an example : nice triangulated surface of genus 6 --- .../topology/simplicial_complex_catalog.py | 3 +- .../topology/simplicial_complex_examples.py | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/sage/topology/simplicial_complex_catalog.py b/src/sage/topology/simplicial_complex_catalog.py index 01ade2e3667..cbb84e0892e 100644 --- a/src/sage/topology/simplicial_complex_catalog.py +++ b/src/sage/topology/simplicial_complex_catalog.py @@ -27,6 +27,7 @@ - :meth:`~sage.topology.examples.ComplexProjectivePlane` - :meth:`~sage.topology.examples.DunceHat` - :meth:`~sage.topology.examples.FareyMap` +- :meth:`~sage.topology.examples.GenusSix` - :meth:`~sage.topology.examples.K3Surface` - :meth:`~sage.topology.examples.KleinBottle` - :meth:`~sage.topology.examples.MatchingComplex` @@ -66,7 +67,7 @@ from sage.topology.simplicial_complex_examples import (Sphere, Simplex, Torus, ProjectivePlane, - RealProjectivePlane, KleinBottle, FareyMap, SurfaceOfGenus, + RealProjectivePlane, KleinBottle, FareyMap, GenusSix, SurfaceOfGenus, MooreSpace, ComplexProjectivePlane, PseudoQuaternionicProjectivePlane, PoincareHomologyThreeSphere, RealProjectiveSpace, K3Surface, diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index e9068b7713d..99c67a60cef 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -27,6 +27,7 @@ - :func:`ComplexProjectivePlane` - :func:`DunceHat` - :func:`FareyMap` +- :func:`GenusSix` - :func:`K3Surface` - :func:`KleinBottle` - :func:`MatchingComplex` @@ -1615,3 +1616,42 @@ def normalise(pair): triangle = libgap.Set(triangle) triangles = libgap.Orbit(group, triangle, libgap.OnSets).sage() return SimplicialComplex(triangles) + + +def GenusSix(): + """ + Return a triangulated surface of genus 6. + + This is triangulated with 12 vertices, 66 edges and 44 faces. Each + vertex is neighbour to all other vertices. + + It appears as number `58` in the classification of Altshuler, + Bokowski and Schuchert in [ABS96]_, where it is the unique surface + with the largest symmetry group, of order 12. This article refers + for this surface to Ringel. + + EXAMPLES:: + + sage: S = simplicial_complexes.GenusSix() + sage: S.automorphism_group().cardinality() + 12 + sage: S.betti() + {0: 1, 1: 12, 2: 1} + sage: S.f_vector() + [1, 12, 66, 44] + + REFERENCES: + + - [ABS96] Amos Altshule, Jürgen Bokowski and Peter Schuchert, + *Neighborly 2-Manifolds with 12 Vertices*, Journal of Combinatorial + Theory, Series A 75, 148-162 (1996), :doi:`10.1006/jcta.1996.0069` + """ + L = ["014", "018", "023", "027", "036", "049", + "056", "05b", "07a", "08a", "09b", + "125", "126", "137", "139", "147", "15a", + "16b", "18b", "19a", "23b", "248", + "24a", "258", "269", "279", "2ab", "345", + "34b", "35a", "367", "389", "38a", + "459", "46a", "46b", "478", "568", "579", + "57b", "67a", "689", "78b", "9ab"] + return SimplicialComplex([list(w) for w in L]) From b18aef6be0848a4e5e4eee7fb4ea93bf9b097d2d Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Fri, 12 Aug 2022 17:58:03 +0200 Subject: [PATCH 362/591] 29717: compatibility with 9.7.beta8 --- build/pkgs/database_cubic_hecke/dependencies | 2 +- build/pkgs/database_cubic_hecke/dependencies_check | 1 + src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 build/pkgs/database_cubic_hecke/dependencies_check diff --git a/build/pkgs/database_cubic_hecke/dependencies b/build/pkgs/database_cubic_hecke/dependencies index b3002bde029..0738c2d7777 100644 --- a/build/pkgs/database_cubic_hecke/dependencies +++ b/build/pkgs/database_cubic_hecke/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) $(and $(filter-out no,$(SAGE_CHECK_database_cubic_hecke)), $(SAGERUNTIME) conway_polynomials ipywidgets sympy singular gap libhomfly libbraiding matplotlib) +$(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/database_cubic_hecke/dependencies_check b/build/pkgs/database_cubic_hecke/dependencies_check new file mode 100644 index 00000000000..1e1a85bb91a --- /dev/null +++ b/build/pkgs/database_cubic_hecke/dependencies_check @@ -0,0 +1 @@ +$(SAGERUNTIME) conway_polynomials ipywidgets sympy singular gap libhomfly libbraiding matplotlib diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py index ae20c0f8b6a..aa2476d06a6 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -403,6 +403,10 @@ class CubicHeckeMatrixRep(Matrix_generic_dense): [ 0 w 0] sage: len(_.block_diagonal_list()) 1 + + TEST: + + sage: TestSuite(m1).run(skip='_test_minpoly') """ @cached_method @@ -611,7 +615,7 @@ def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, su sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA2. = algebras.CubicHecke(2) sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) - sage: TestSuite(MS).run() + sage: TestSuite(MS).run(skip='_test_elements') """ from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra From bde6bb5e919836e7d7412288d51d78833f1976f6 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Fri, 12 Aug 2022 10:33:41 -0700 Subject: [PATCH 363/591] Change to list --- src/sage/combinat/partition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index f8001a3476c..f3d7b7f19bc 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -4027,8 +4027,8 @@ def outside_corners(self): sage: Partition([]).outside_corners() [(0, 0)] """ - p = self - if p.is_empty(): + p = self._list + if not p: return [(0,0)] res = [(0, p[0])] res.extend((n, j) for n, (i, j) in enumerate(zip(p[:-1], p[1:]), start=1) if i != j) From 3a58015943a8b7497e0cf1143c3dc6e51de03867 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Fri, 12 Aug 2022 13:58:28 -0400 Subject: [PATCH 364/591] settings.json: add missing comma --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index cb06559edea..25005ebbfbb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,7 +24,7 @@ "python.linting.pycodestyleEnabled": true, "python.linting.enabled": true, "cSpell.words": [ - "furo" + "furo", "Conda", "Cython" ], From 85fa6ad0653a7c37b4861be80f25d1550a75f5b5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 12 Aug 2022 12:05:48 -0700 Subject: [PATCH 365/591] .devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json: Enable the devtoolset --- .../devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json index f6f53ebc87b..273a5deabab 100644 --- a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json +++ b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json @@ -16,7 +16,7 @@ // Run commands after the container is created. "postCreateCommand": ".devcontainer/post_create.sh", // Run commands after the container is started. - "postStartCommand": ".devcontainer/portability-post_start.sh", + "postStartCommand": ". /opt/rh/devtoolset-11/enable && .devcontainer/portability-post_start.sh", "extensions": [ "ms-python.python" ] From 7f9ba982ba3e35e88c0bec99df4eefa348cf42b0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 12 Aug 2022 12:06:52 -0700 Subject: [PATCH 366/591] .devcontainer/portability-post_start.sh: Fix up logs symlinkery --- .devcontainer/portability-post_start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/portability-post_start.sh b/.devcontainer/portability-post_start.sh index 45d0cfb5555..03e1605b0aa 100755 --- a/.devcontainer/portability-post_start.sh +++ b/.devcontainer/portability-post_start.sh @@ -14,7 +14,7 @@ for f in config.log logs upstream; do done # If possible (ensured after https://trac.sagemath.org/ticket/33262), keep the # logs in the container. -if [ ! -f logs ]; then +if [ ! -d logs ]; then ln -s /sage/logs logs fi # Bootstrap, configure, and build the Sage distribution, reusing the Sage From c06132dd7c7d7af1cdf1146fd189424c9bb7006e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 12 Aug 2022 12:07:16 -0700 Subject: [PATCH 367/591] .devcontainer/portability-post_start.sh: Pick up configuration from image --- .devcontainer/portability-post_start.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.devcontainer/portability-post_start.sh b/.devcontainer/portability-post_start.sh index 03e1605b0aa..a923fc0d106 100755 --- a/.devcontainer/portability-post_start.sh +++ b/.devcontainer/portability-post_start.sh @@ -22,5 +22,9 @@ fi set -e set -x make configure -./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv +if [ -x /sage/config.status ]; then + eval ./configure $(/sage/config.status --config) --enable-build-as-root --prefix=/sage/local --with-sage-venv +else + ./configure --enable-build-as-root --prefix=/sage/local --with-sage-venv +fi make build V=0 From ca7b0f1ed3f47d8c88daa1212d9ed08171c59ab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Fri, 12 Aug 2022 21:22:17 +0200 Subject: [PATCH 368/591] Fix 4ti2 links and formatting --- build/pkgs/4ti2/SPKG.rst | 2 +- src/sage/interfaces/four_ti_2.py | 113 +++++++++++++++++-------------- 2 files changed, 64 insertions(+), 51 deletions(-) diff --git a/build/pkgs/4ti2/SPKG.rst b/build/pkgs/4ti2/SPKG.rst index 1a3a5e5c9c4..f3bd67741e9 100644 --- a/build/pkgs/4ti2/SPKG.rst +++ b/build/pkgs/4ti2/SPKG.rst @@ -5,7 +5,7 @@ Description ----------- A software package for algebraic, geometric and combinatorial problems -on linear spaces. Available at www.4ti2.de. +on linear spaces. Available at https://4ti2.github.io/. License ------- diff --git a/src/sage/interfaces/four_ti_2.py b/src/sage/interfaces/four_ti_2.py index 92de8d2d478..79a07dcdad4 100644 --- a/src/sage/interfaces/four_ti_2.py +++ b/src/sage/interfaces/four_ti_2.py @@ -1,7 +1,7 @@ r""" Interface to 4ti2 -http://www.4ti2.de +https://4ti2.github.io/ You must have the 4ti2 Sage package installed on your computer for this interface to work. @@ -43,8 +43,9 @@ class FourTi2(): r""" - This object defines an interface to the program 4ti2. Each command - 4ti2 has is exposed as one method. + An interface to the program 4ti2. + + Each 4ti2 command is exposed as a method of this class. """ def __init__(self, directory=None): r""" @@ -155,10 +156,11 @@ def write_single_row(self, row, filename): def write_array(self, array, nrows, ncols, filename): r""" - Write the matrix ``array`` of integers (can be represented as - a list of lists) to the file ``filename`` in directory - ``directory()`` in 4ti2 format. The matrix must have ``nrows`` - rows and ``ncols`` columns. + Write the integer matrix ``array`` to the file ``filename`` + in directory ``directory()`` in 4ti2 format. + + The matrix must have ``nrows`` rows and ``ncols`` columns. + It can be provided as a list of lists. INPUT: @@ -216,9 +218,10 @@ def read_matrix(self, filename): def _process_input(self, kwds): r""" - kwds is a dict, and the values are written to files with - extension given by the keys, except for the keys ``self`` - and ``project``. + Process the input in the dictionary ``kwds``. + + The values are written to files with extensions given + by the keys, except for the keys ``self`` and ``project``. This interesting method is intended to be called as the first thing going on in a method implementing some action of 4ti2, @@ -227,13 +230,13 @@ def _process_input(self, kwds): just by giving the parameters of the method names that are the extension of the corresponding files. - Nothing is written if the value is None. Otherwise the value + Nothing is written if the value is ``None``. Otherwise the value is written as a matrix to the file given by the value of the key ``'project'`` with extension given by the key. INPUT: - - kwds -- A dict controlling what data is written to what files. + - ``kwds`` -- A dict controlling what data is written to what files. OUTPUT: @@ -280,17 +283,17 @@ def call(self, command, project, verbose=True, *, options=()): INPUT: - - command -- The 4ti2 program to run. - - project -- The file name of the project to run on. - - verbose -- Display the output of 4ti2 if ``True``. - - options -- A list of strings to pass to the program. + - ``command`` -- The 4ti2 program to run. + - ``project`` -- The file name of the project to run on. + - ``verbose`` -- Display the output of 4ti2 if ``True``. + - ``options`` -- A list of strings to pass to the program. EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 sage: four_ti_2.write_matrix([[6,10,15]], "test_file") - sage: four_ti_2.call("groebner", "test_file", False) # optional - 4ti2 - sage: four_ti_2.read_matrix("test_file.gro") # optional - 4ti2 + sage: four_ti_2.call("groebner", "test_file", False) # optional - 4ti2 + sage: four_ti_2.read_matrix("test_file.gro") # optional - 4ti2 [-5 0 2] [-5 3 0] """ @@ -306,8 +309,9 @@ def call(self, command, project, verbose=True, *, options=()): def zsolve(self, mat=None, rel=None, rhs=None, sign=None, lat=None, project=None): r""" - Run the 4ti2 program ``zsolve`` on the parameters. See - ``http://www.4ti2.de/`` for details. + Run the 4ti2 program ``zsolve`` on the parameters. + + See `4ti2 website `_ for details. EXAMPLES:: @@ -316,7 +320,7 @@ def zsolve(self, mat=None, rel=None, rhs=None, sign=None, lat=None, project=None sage: rel = ['<', '<'] sage: rhs = [2, 3] sage: sign = [1,0,1] - sage: four_ti_2.zsolve(A, rel, rhs, sign) # optional - 4ti2 + sage: four_ti_2.zsolve(A, rel, rhs, sign) # optional - 4ti2 [ [ 1 -1 0] [ 0 -1 0] @@ -324,7 +328,7 @@ def zsolve(self, mat=None, rel=None, rhs=None, sign=None, lat=None, project=None [1 1 0] [ 1 -2 1] [0 1 0], [ 0 -2 1], [] ] - sage: four_ti_2.zsolve(lat=[[1,2,3],[1,1,1]]) # optional - 4ti2 + sage: four_ti_2.zsolve(lat=[[1,2,3],[1,1,1]]) # optional - 4ti2 [ [1 2 3] [0 0 0], [], [1 1 1] @@ -338,14 +342,15 @@ def zsolve(self, mat=None, rel=None, rhs=None, sign=None, lat=None, project=None def qsolve(self, mat=None, rel=None, sign=None, project=None): r""" - Run the 4ti2 program ``qsolve`` on the parameters. See - ``http://www.4ti2.de/`` for details. + Run the 4ti2 program ``qsolve`` on the parameters. + + See `4ti2 website `_ for details. EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 sage: A = [[1,1,1],[1,2,3]] - sage: four_ti_2.qsolve(A) # optional - 4ti2 + sage: four_ti_2.qsolve(A) # optional - 4ti2 [[], [ 1 -2 1]] """ project = self._process_input(locals()) @@ -355,13 +360,14 @@ def qsolve(self, mat=None, rel=None, sign=None, project=None): def rays(self, mat=None, project=None): r""" - Run the 4ti2 program ``rays`` on the parameters. See - ``http://www.4ti2.de/`` for details. + Run the 4ti2 program ``rays`` on the parameters. + + See `4ti2 website `_ for details. EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 - sage: four_ti_2.rays(four_ti_2._magic3x3()) # optional - 4ti2 + sage: four_ti_2.rays(four_ti_2._magic3x3()) # optional - 4ti2 [0 2 1 2 1 0 1 0 2] [1 0 2 2 1 0 0 2 1] [1 2 0 0 1 2 2 0 1] @@ -373,19 +379,20 @@ def rays(self, mat=None, project=None): def hilbert(self, mat=None, lat=None, project=None): r""" - Run the 4ti2 program ``hilbert`` on the parameters. See - ``http://www.4ti2.de/`` for details. + Run the 4ti2 program ``hilbert`` on the parameters. + + See `4ti2 website `_ for details. EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 - sage: four_ti_2.hilbert(four_ti_2._magic3x3()) # optional - 4ti2 + sage: four_ti_2.hilbert(four_ti_2._magic3x3()) # optional - 4ti2 [2 0 1 0 1 2 1 2 0] [1 0 2 2 1 0 0 2 1] [0 2 1 2 1 0 1 0 2] [1 2 0 0 1 2 2 0 1] [1 1 1 1 1 1 1 1 1] - sage: four_ti_2.hilbert(lat=[[1,2,3],[1,1,1]]) # optional - 4ti2 + sage: four_ti_2.hilbert(lat=[[1,2,3],[1,1,1]]) # optional - 4ti2 [2 1 0] [0 1 2] [1 1 1] @@ -396,13 +403,14 @@ def hilbert(self, mat=None, lat=None, project=None): def graver(self, mat=None, lat=None, project=None): r""" - Run the 4ti2 program ``graver`` on the parameters. See - ``http://www.4ti2.de/`` for details. + Run the 4ti2 program ``graver`` on the parameters. + + See `4ti2 website `_ for details. EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 - sage: four_ti_2.graver([1,2,3]) # optional - 4ti2 + sage: four_ti_2.graver([1,2,3]) # optional - 4ti2 [ 2 -1 0] [ 3 0 -1] [ 1 1 -1] @@ -420,13 +428,14 @@ def graver(self, mat=None, lat=None, project=None): def ppi(self, n): r""" - Run the 4ti2 program ``ppi`` on the parameters. See - ``http://www.4ti2.de/`` for details. + Run the 4ti2 program ``ppi`` on the parameters. + + See `4ti2 website `_ for details. EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 - sage: four_ti_2.ppi(3) # optional - 4ti2 + sage: four_ti_2.ppi(3) # optional - 4ti2 [-2 1 0] [ 0 -3 2] [-1 -1 1] @@ -439,13 +448,14 @@ def ppi(self, n): def circuits(self, mat=None, project=None): r""" - Run the 4ti2 program ``circuits`` on the parameters. See - ``http://www.4ti2.de/`` for details. + Run the 4ti2 program ``circuits`` on the parameters. + + See `4ti2 website `_ for details. EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 - sage: four_ti_2.circuits([1,2,3]) # optional - 4ti2 + sage: four_ti_2.circuits([1,2,3]) # optional - 4ti2 [ 0 3 -2] [ 2 -1 0] [ 3 0 -1] @@ -456,13 +466,14 @@ def circuits(self, mat=None, project=None): def minimize(self, mat=None, lat=None): r""" - Run the 4ti2 program ``minimize`` on the parameters. See - ``http://www.4ti2.de/`` for details. + Run the 4ti2 program ``minimize`` on the parameters. + + See `4ti2 website `_ for details. EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 - sage: four_ti_2.minimize() # optional - 4ti2 + sage: four_ti_2.minimize() # optional - 4ti2 Traceback (most recent call last): ... NotImplementedError: 4ti2 command 'minimize' not implemented in Sage. @@ -472,18 +483,20 @@ def minimize(self, mat=None, lat=None): def groebner(self, mat=None, lat=None, project=None): r""" - Run the 4ti2 program ``groebner`` on the parameters. This - computes a Toric Groebner basis of a matrix. See - ``http://www.4ti2.de/`` for details. + Run the 4ti2 program ``groebner`` on the parameters. + + This computes a toric Groebner basis of a matrix. + + See `4ti2 website `_ for details. EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 sage: A = [6,10,15] - sage: four_ti_2.groebner(A) # optional - 4ti2 + sage: four_ti_2.groebner(A) # optional - 4ti2 [-5 0 2] [-5 3 0] - sage: four_ti_2.groebner(lat=[[1,2,3],[1,1,1]]) # optional - 4ti2 + sage: four_ti_2.groebner(lat=[[1,2,3],[1,1,1]]) # optional - 4ti2 [-1 0 1] [ 2 1 0] """ @@ -498,7 +511,7 @@ def _magic3x3(self): EXAMPLES:: sage: from sage.interfaces.four_ti_2 import four_ti_2 - sage: four_ti_2._magic3x3() # optional - 4ti2 + sage: four_ti_2._magic3x3() # optional - 4ti2 [ 1 1 1 -1 -1 -1 0 0 0] [ 1 1 1 0 0 0 -1 -1 -1] [ 0 1 1 -1 0 0 -1 0 0] From 64bb118c2fc3acac522ffec05680dbaabb4793ed Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Fri, 12 Aug 2022 22:22:06 +0200 Subject: [PATCH 369/591] rough draft on how to use coercion for exact division of power series by coefficient --- src/sage/rings/power_series_poly.pyx | 8 ++++++-- src/sage/rings/power_series_ring.py | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index dc0c599a2c0..42c4a5602ce 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -720,7 +720,7 @@ cdef class PowerSeries_poly(PowerSeries): return self._parent(self.truncate().inverse_series_trunc(prec), prec=prec) - def _floordiv_(self, c): + def _floor_division_by_coefficient_(self, c): """ Perform the exact division of ``self`` by a coefficient ``c``. @@ -748,10 +748,14 @@ cdef class PowerSeries_poly(PowerSeries): """ prec = self.prec() return PowerSeries_poly(self._parent, - self.__f // (c).__f[0], + self.__f // c, prec=prec, check=False) + cpdef _acted_upon_(self, other, bint self_on_left): + if self_on_left and other in self.base_ring(): + return self._floor_division_by_coefficient_(other) + def truncate(self, prec=infinity): """ The polynomial obtained from power series by truncation at diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 0000a2daa38..88b60ebbe02 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -1288,6 +1288,12 @@ def fraction_field(self): laurent = self.laurent_series_ring() return laurent.change_ring(self.base_ring().fraction_field()) + def _get_action_(self, other, op, self_is_left): + import operator + from sage.structure.coerce_actions import ActedUponAction + if op is operator.floordiv and self_is_left and other is self.base_ring(): + # Floor division by coefficient. + return ActedUponAction(other, self, not self_is_left) class PowerSeriesRing_over_field(PowerSeriesRing_domain): _default_category = CompleteDiscreteValuationRings() From 1355787df880d72dfaae58f3c62ace0cbdb82a9f Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sat, 13 Aug 2022 09:21:00 +0900 Subject: [PATCH 370/591] Add note --- .../devcontainer.json | 2 +- .../devcontainer.json | 2 +- src/doc/en/developer/portability_testing.rst | 20 +++++++++++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json index 273a5deabab..4a97fb3cb2c 100644 --- a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json +++ b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json @@ -3,7 +3,7 @@ "name": "Centos 7", "build": { "dockerfile": "portability-Dockerfile", - // See tox.ini for definitions + // See tox.ini for definitions. "args": { "SYSTEM_FACTOR": "centos-7-devtoolset-gcc_11", "PACKAGE_FACTOR": "standard", "DOCKER_TARGET": "with-targets", diff --git a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json index c7ea829b269..0e6bc8d88e0 100644 --- a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json +++ b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json @@ -3,7 +3,7 @@ "name": "Debian buster 32-bit", "build": { "dockerfile": "portability-Dockerfile", - // See tox.ini for definitions + // See tox.ini for definitions. "args": { "SYSTEM_FACTOR": "debian-buster-i386", "PACKAGE_FACTOR": "standard", "DOCKER_TARGET": "with-targets", diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 68873a51781..dd8b7ea4df1 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -986,7 +986,7 @@ system configurations. For more information, see the `GitHub documentation `_. Alternatively, you can create and push a custom tag in order to trigger a run of tests as follows. -Let's assume that ``github`` is the name of +Let's assume that ``my-github`` is the name of the remote corresponding to your GitHub fork of the Sage repository:: $ git remote -v | grep /my-github @@ -1185,9 +1185,10 @@ directory in the dev container (yes). If it does not, use the command palette (:kbd:`Ctrl` + :kbd:`Shift` + :kbd:`P`), enter the command "Remote-Containers: Reopen Folder in Container" , and hit :kbd:`Enter`. -If the above ``code .`` command does not work, start VS Code as a regular application, then in the -command palette of VS Code, enter "Remote-Containers: Open Folder in Container", -and hit :kbd:`Enter`, and choose the Sage repository ``$SAGE_ROOT``. +If the above ``code .`` command does not work, start VS Code as a regular +application, then in the command palette of VS Code, enter "Remote-Containers: +Open Folder in Container", and hit :kbd:`Enter`, and choose the directory +``$SAGE_ROOT`` of your local Sage repository. Once VS Code starts running the dev container, by clicking on "show log", you can see what it does: @@ -1205,6 +1206,17 @@ you can see what it does: reusing the installation (:envvar:`SAGE_LOCAL`, :envvar:`SAGE_VENV`) from the prebuilt image. +After VS Code finished configuring the dev container, your local Sage +repository at ``$SAGE_ROOT`` is available in the container at the directory +``/workspaces/``. You may need to open a new Terminal to start +working from the directory. + +.. NOTE:: + + Your Sage at ``$SAGE_ROOT`` was configured and rebuilt inside the dev + container. Hence after working with VS Code, you may want to rebuild the Sage + for your local platform. + You can edit a copy of the configuration file to change to a different platform, another version, or build stage. After editing the configuration file (or changing the symlink), run "Remote-Containers: Rebuild Container" from the command From a9ba6d276336fbded0ee6fc9bb25893c141a0a8c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 12 Aug 2022 18:07:51 -0700 Subject: [PATCH 371/591] .devcontainer/portability-debian-buster-i386-standard: Remove (does not work) --- .../devcontainer.json | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 .devcontainer/portability-debian-buster-i386-standard/devcontainer.json diff --git a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json b/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json deleted file mode 100644 index 0e6bc8d88e0..00000000000 --- a/.devcontainer/portability-debian-buster-i386-standard/devcontainer.json +++ /dev/null @@ -1,23 +0,0 @@ -// See https://aka.ms/devcontainer.json for format details. -{ - "name": "Debian buster 32-bit", - "build": { - "dockerfile": "portability-Dockerfile", - // See tox.ini for definitions. - "args": { "SYSTEM_FACTOR": "debian-buster-i386", - "PACKAGE_FACTOR": "standard", - "DOCKER_TARGET": "with-targets", - "DOCKER_TAG": "dev" - } - }, - "containerEnv": { - "MAKE": "make -j12" - }, - // Run commands after the container is created. - "postCreateCommand": ".devcontainer/post_create.sh", - // Run commands after the container is started. - "postStartCommand": ".devcontainer/portability-post_start.sh", - "extensions": [ - "ms-python.python" - ] -} From afe62c2902db425e494b55f474ba70f11e14e300 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 12 Aug 2022 18:19:30 -0700 Subject: [PATCH 372/591] src/doc/en/developer/portability_testing.rst: Expand note on going back to local --- src/doc/en/developer/portability_testing.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index dd8b7ea4df1..22b9c01c0b6 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1214,8 +1214,12 @@ working from the directory. .. NOTE:: Your Sage at ``$SAGE_ROOT`` was configured and rebuilt inside the dev - container. Hence after working with VS Code, you may want to rebuild the Sage - for your local platform. + container. In particular, ``$SAGE_ROOT/venv``, ``$SAGE_ROOT/prefix``, and + (possibly) ``$SAGE_ROOT/logs`` will be symbolic links that work inside the dev + container, but not in your local file system; and also the script + ``$SAGE_ROOT/sage`` will not work. Hence after working with the dev container, + you will want to remove ``logs`` if it is a symbolic link, and to re-run the + ``configure`` script. You can edit a copy of the configuration file to change to a different platform, another version, or build stage. After editing the configuration file (or changing the From 86876262faffac5f3fed12e08b0cf0b45e3e216c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 12 Aug 2022 23:14:26 -0700 Subject: [PATCH 373/591] .devcontainer/cocalc/devcontainer.json: Fix ecm build --- .devcontainer/cocalc/devcontainer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/cocalc/devcontainer.json b/.devcontainer/cocalc/devcontainer.json index c62375d75e0..47a5a682dff 100644 --- a/.devcontainer/cocalc/devcontainer.json +++ b/.devcontainer/cocalc/devcontainer.json @@ -6,7 +6,8 @@ "MAKE": "make -j12" }, // Run commands after the container is created. - "postCreateCommand": ".devcontainer/post_create.sh", + // libgmp.a is broken and leads to a build failure of ecm. + "postCreateCommand": ".devcontainer/post_create.sh && rm -f /usr/local/sage/local/lib/libgmp.a", // Run commands after the container is started. "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv && make build V=0", "extensions": [ From e78047258774176c6e8271e29c9b5825cc12aa11 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sat, 13 Aug 2022 19:14:55 +0900 Subject: [PATCH 374/591] Addressing the linter complaint. --- src/sage/rings/lazy_series.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 5bc647340c1..50a8577504e 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3469,6 +3469,7 @@ def coefficient(n): # The arity is at least 2 gv = min(h._coeff_stream._approximate_order for h in g) + def coefficient(n): r = R.zero() for i in range(n//gv+1): From 1196685d58d134e7a7f88e9b5c1fe76c1312821d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 13 Aug 2022 13:07:45 +0200 Subject: [PATCH 375/591] tweak the reference --- src/sage/topology/simplicial_complex_examples.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index 99c67a60cef..c9901e45907 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -1642,9 +1642,10 @@ def GenusSix(): REFERENCES: - - [ABS96] Amos Altshule, Jürgen Bokowski and Peter Schuchert, - *Neighborly 2-Manifolds with 12 Vertices*, Journal of Combinatorial - Theory, Series A 75, 148-162 (1996), :doi:`10.1006/jcta.1996.0069` + .. [ABS96] Amos Altshule, Jürgen Bokowski and Peter Schuchert, + *Neighborly 2-Manifolds with 12 Vertices*, + Journal of Combinatorial Theory, Series A, 75, 148-162 (1996), + :doi:`10.1006/jcta.1996.0069` """ L = ["014", "018", "023", "027", "036", "049", "056", "05b", "07a", "08a", "09b", From fbfb7dd14f2009e0781b284071a9be0a5c3621d0 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Sat, 13 Aug 2022 14:42:52 +0200 Subject: [PATCH 376/591] 29717: missing fix for log test added --- src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py index aa2476d06a6..d7dbaabc65d 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -654,7 +654,7 @@ def __init__(self, base_ring, dimension, cols, sparse=True, sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA3. = algebras.CubicHecke(3) sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) - sage: TestSuite(MS).run() # long time + sage: TestSuite(MS).run(skip='_test_elements') # long time """ from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra From dc80c09d6adf734c7594c1b289e356949f978726 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 13 Aug 2022 15:20:27 +0200 Subject: [PATCH 377/591] trac #34354: clean src/sage/graphs/graph_database.py --- src/sage/graphs/graph_database.py | 60 +++++++++++++++++-------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index 9db59191da7..f416d7c04ee 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -36,13 +36,13 @@ Available: http://artsci.drake.edu/grout/graphs/ """ -################################################################################ +# ############################################################################## # Copyright (C) 2007 Emily A. Kirkman # # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -################################################################################ +# https://www.gnu.org/licenses/ +# ############################################################################## from . import graph import os @@ -51,7 +51,7 @@ from sage.databases.sql_db import SQLDatabase, SQLQuery from sage.env import GRAPHS_DATA_DIR from sage.graphs.graph import Graph -dblocation = os.path.join(GRAPHS_DATA_DIR,'graphs.db') +dblocation = os.path.join(GRAPHS_DATA_DIR, 'graphs.db') def degseq_to_data(degree_sequence): @@ -105,6 +105,7 @@ def data_to_degseq(data, graph6=None): else: return degseq + def graph6_to_plot(graph6): """ Return a ``Graphics`` object from a ``graph6`` string. @@ -126,6 +127,7 @@ def graph6_to_plot(graph6): g = Graph(str(graph6)) return g.plot(layout='circular', vertex_size=30, vertex_labels=False, graph_border=False) + def subgraphs_to_query(subgraphs, db): """ Return a GraphQuery object required for the induced_subgraphs parameter. @@ -175,6 +177,7 @@ def subgraphs_to_query(subgraphs, db): raise KeyError('unable to initiate query: illegal input format for induced_subgraphs') return q + # tables columns input data type sqlite data type # ----------------------------------------------------------------------------- aut_grp = ['aut_grp_size', # Integer INTEGER @@ -218,6 +221,7 @@ def subgraphs_to_query(subgraphs, db): valid_kwds = aut_grp + degrees + misc + spectrum + graph_data + def graph_db_info(tablename=None): """ Return a dictionary of allowed table and column names. @@ -254,6 +258,7 @@ def graph_db_info(tablename=None): info = info[tablename] return info + class GenericGraphQuery(SQLQuery): def __init__(self, query_string, database=None, param_tuple=None): @@ -311,7 +316,7 @@ def __init__(self, query_string, database=None, param_tuple=None): if database is None: database = GraphDatabase() if not isinstance(database, GraphDatabase): - raise TypeError('%s is not a valid GraphDatabase'%database) + raise TypeError('%s is not a valid GraphDatabase' % database) SQLQuery.__init__(self, database, query_string, param_tuple) @@ -431,12 +436,11 @@ class located in :mod:`sage.databases.sql_db` to make the query for key in kwds: # check validity if key not in valid_kwds: - raise KeyError('%s is not a valid key for this database.'%str(key)) + raise KeyError('%s is not a valid key for this database.' % str(key)) - # designate a query_dict - qdict = {'display_cols': None} # reserve display cols until end - # (database.py currently concatenates - # them including repeats) + # designate a query_dict and reserve display_cols until end + # (database.py currently concatenates them including repeats) + qdict = {'display_cols': None} # set table name if key in graph_data: @@ -453,7 +457,8 @@ class located in :mod:`sage.databases.sql_db` to make the query # set expression if not isinstance(kwds[key], list): if key == 'induced_subgraphs': - qdict['expression'] = [key, 'regexp', '.*%s.*'%(graph.Graph(kwds[key]).canonical_label()).graph6_string()] + s6 = (graph.Graph(kwds[key]).canonical_label()).graph6_string() + qdict['expression'] = [key, 'regexp', '.*%s.*' % s6] else: qdict['expression'] = [key, '=', kwds[key]] elif key == 'degree_sequence': @@ -465,9 +470,10 @@ class located in :mod:`sage.databases.sql_db` to make the query join_dict = {qdict['table_name']: ('graph_id', 'graph_id')} if key == 'induced_subgraphs' and isinstance(kwds[key], list): self.intersect(subgraphs_to_query(kwds[key], graph_db), - 'graph_data', join_dict, in_place=True) + 'graph_data', join_dict, in_place=True) else: - self.intersect(SQLQuery(graph_db, qdict), 'graph_data', join_dict,in_place=True) + self.intersect(SQLQuery(graph_db, qdict), 'graph_data', + join_dict, in_place=True) # include search params (keys) in join clause # again, we exclude graph_data because it is the base table @@ -482,7 +488,7 @@ class located in :mod:`sage.databases.sql_db` to make the query graph_data_disp = ['graph_data'] disp_tables = [aut_grp_disp, degrees_disp, misc_disp, spectrum_disp] - # graph_data intentionally left out because it is always called + # graph_data intentionally left out because it is always called # organize display if display_cols is not None: @@ -506,27 +512,28 @@ class located in :mod:`sage.databases.sql_db` to make the query # join clause for display tables join_str = 'FROM graph_data ' for tab in master_join: - join_str += 'INNER JOIN %s ON graph_data.graph_id=%s.graph_id '%(tab, tab) + join_str += 'INNER JOIN %s ON graph_data.graph_id=%s.graph_id ' % (tab, tab) # construct sql syntax substring for display cols disp_list = ['SELECT graph_data.graph6, '] for col in graph_data_disp[1:]: if col != 'graph6': - disp_list.append('graph_data.%s, '%col) + disp_list.append('graph_data.%s, ' % col) for col in aut_grp_disp[1:]: - disp_list.append('aut_grp.%s, '%col) + disp_list.append('aut_grp.%s, ' % col) for col in degrees_disp[1:]: - disp_list.append('degrees.%s, '%col) + disp_list.append('degrees.%s, ' % col) for col in misc_disp[1:]: - disp_list.append('misc.%s, '%col) + disp_list.append('misc.%s, ' % col) for col in spectrum_disp[1:]: - disp_list.append('spectrum.%s, '%col) + disp_list.append('spectrum.%s, ' % col) disp_list[-1] = disp_list[-1].rstrip(', ') + ' ' disp_str = ''.join(disp_list) # substitute disp_str and join_str back into self's query string - self.__query_string__ = re.sub('SELECT.*WHERE ', disp_str + join_str + \ - 'WHERE ', self.__query_string__) + self.__query_string__ = re.sub('SELECT.*WHERE ', + disp_str + join_str + 'WHERE ', + self.__query_string__) self.__query_string__ += ' ORDER BY graph_data.graph6' def query_iterator(self): @@ -717,6 +724,7 @@ def number_of(self): q = GenericGraphQuery(s, self.__database__, self.__param_tuple__) return len(q.query_results()) + class GraphDatabase(SQLDatabase): def __init__(self): @@ -942,15 +950,15 @@ def _gen_interact_func(self, display, **kwds): not be called directly. """ function_name = '__temporary_interact_function' - arg = ['%s=%s'%(word, kwds[word]) for word in kwds] - boxes = ["%s=input_grid(1,2,['=',%s])"%(word, kwds[word]) for word in kwds] - params = ['%s=%s[0]'%tuple(2 * [arg[i].split('=')[0]]) for i in range(len(arg))] + arg = ['%s=%s' % (word, kwds[word]) for word in kwds] + boxes = ["%s=input_grid(1,2,['=',%s])" % (word, kwds[word]) for word in kwds] + params = ['%s=%s[0]' % tuple(2 * [arg[i].split('=')[0]]) for i in range(len(arg))] s = 'def %s(%s):' % (function_name, ','.join(boxes)) t = """ print('

Query Results:

') GraphQuery(display_cols=%s,%s).show(with_picture=True) - """%tuple([display, ','.join(params)]) + """ % tuple([display, ','.join(params)]) s += '\t' + '\n\t'.join(t.split('\n')) + '\n' exec(s) return locals()[function_name] From 91d364579ceb00f801a1eab0d8bce980bd35758d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Oudompheng?= <> Date: Sat, 13 Aug 2022 22:32:08 +0800 Subject: [PATCH 378/591] avoid constructing list of all base-field elements --- src/sage/algebras/quatalg/quaternion_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index 3bde7b21536..3e12785e143 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -1232,7 +1232,7 @@ def modp_splitting_data(self, p): raise NotImplementedError("algorithm for computing local splittings not implemented in general (currently require the first invariant to be coprime to p)") i2inv = ~i2 a = None - for b in list(F): + for b in F: if not b: continue c = j2 + i2inv * b*b From 0ea8654bbd60b4bae5f1dc63c1494466d53473f1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 09:31:32 -0700 Subject: [PATCH 379/591] .devcontainer/computop-sage/devcontainer.json: Fix ecm build --- .devcontainer/computop-sage/devcontainer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.devcontainer/computop-sage/devcontainer.json b/.devcontainer/computop-sage/devcontainer.json index 244ebf0e750..639fc9543a4 100644 --- a/.devcontainer/computop-sage/devcontainer.json +++ b/.devcontainer/computop-sage/devcontainer.json @@ -7,11 +7,13 @@ }, // Run commands after the container is created. // Install build tools, get rid of sourcing /sage/activate in non-login shells. - "postCreateCommand": ".devcontainer/post_create.sh --sudo && sed -i.bak '/sage.*activate/d' ~/.bashrc", + // libgmp.a is broken and leads to a build failure of ecm. + "postCreateCommand": ".devcontainer/post_create.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", // Run commands after the container is started. // Do not run configure within a sage-env (see #29485). // The pari package is broken in the computop/sage 9.5 image, need to reinstall. // Also libnauty is broken. + "postStartCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv) && make pari-clean nauty-clean build V=0", "extensions": [ "ms-python.python" From 658c959049b3d0f2570dca579334dbe17d6e01c4 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 14 Aug 2022 00:32:28 +0800 Subject: [PATCH 380/591] move .base_ring() up from SchemeMorphism_polynomial to SchemeMorphism --- src/sage/schemes/generic/morphism.py | 70 +++++++++++++++++----------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 4fdeb0e84b1..b1409f05ba1 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -479,6 +479,48 @@ def is_endomorphism(self) -> bool: """ return self.parent().is_endomorphism_set() + def base_ring(self): + r""" + Return the base ring of ``self``, that is, the ring over which + the coefficients of ``self`` are given as polynomials. + + OUTPUT: + + - ring + + EXAMPLES:: + + sage: P.=ProjectiveSpace(QQ,1) + sage: H=Hom(P,P) + sage: f=H([3/5*x^2,6*y^2]) + sage: f.base_ring() + Rational Field + + :: + + sage: R.=PolynomialRing(ZZ,1) + sage: P.=ProjectiveSpace(R,1) + sage: H=Hom(P,P) + sage: f=H([3*x^2,y^2]) + sage: f.base_ring() + Multivariate Polynomial Ring in t over Integer Ring + + Points have correct base rings too (:trac:`34336`):: + + sage: x = P(t,5); x + (t : 5) + sage: x.base_ring() + Multivariate Polynomial Ring in t over Integer Ring + + :: + + sage: E = EllipticCurve(GF(17^2), [1,2,3,4,5]) + sage: P = E.random_point() + sage: P.base_ring() + Finite Field in z2 of size 17^2 + """ + return self.domain().base_ring() + def _composition(self, right): """ A helper for multiplying maps by composition. @@ -1240,34 +1282,6 @@ def __copy__(self): """ return self.parent()(self._polys) - def base_ring(self): - r""" - Return the base ring of ``self``, that is, the ring over which the coefficients - of ``self`` is given as polynomials. - - OUTPUT: - - - ring - - EXAMPLES:: - - sage: P.=ProjectiveSpace(QQ,1) - sage: H=Hom(P,P) - sage: f=H([3/5*x^2,6*y^2]) - sage: f.base_ring() - Rational Field - - :: - - sage: R.=PolynomialRing(ZZ,1) - sage: P.=ProjectiveSpace(R,1) - sage: H=Hom(P,P) - sage: f=H([3*x^2,y^2]) - sage: f.base_ring() - Multivariate Polynomial Ring in t over Integer Ring - """ - return self.domain().base_ring() - def coordinate_ring(self): r""" Returns the coordinate ring of the ambient projective space From 598744e2b342c5704b2dc32cdac2727852bc060f Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sat, 13 Aug 2022 19:12:46 +0200 Subject: [PATCH 381/591] trac #34357: clean src/sage/graphs/generic_graph.py - part 3 --- src/sage/graphs/generic_graph.py | 112 +++++++++++++++++-------------- 1 file changed, 61 insertions(+), 51 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index b8a2a920dab..57cb366b90f 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -20570,11 +20570,11 @@ def show(self, method="matplotlib", **kwds): return self.graphplot(**plot_kwds).show(**kwds) - def plot3d(self, bgcolor=(1,1,1), - vertex_colors=None, vertex_size=0.06, vertex_labels=False, - edge_colors=None, edge_size=0.02, edge_size2=0.0325, - pos3d=None, color_by_label=False, - engine='threejs', **kwds): + def plot3d(self, bgcolor=(1, 1, 1), + vertex_colors=None, vertex_size=0.06, vertex_labels=False, + edge_colors=None, edge_size=0.02, edge_size2=0.0325, + pos3d=None, color_by_label=False, + engine='threejs', **kwds): r""" Plot a graph in three dimensions. @@ -20671,7 +20671,11 @@ def plot3d(self, bgcolor=(1,1,1), :: - sage: D = DiGraph({0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19], 19: []}) + sage: D = DiGraph({0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], + ....: 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], + ....: 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], + ....: 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], + ....: 17: [18], 18: [19], 19: []}) sage: D.plot3d().show() # long time :: @@ -20739,14 +20743,14 @@ def plot3d(self, bgcolor=(1,1,1), R = rainbow(l) vertex_colors = {R[i]: partition[i] for i in range(l)} else: - vertex_colors = {(1,0,0) : list(self)} + vertex_colors = {(1, 0, 0) : list(self)} if color_by_label: if edge_colors is None: - # do the coloring - edge_colors = self._color_by_label(format=color_by_label) + # do the coloring + edge_colors = self._color_by_label(format=color_by_label) elif edge_colors is None: - edge_colors = {(0,0,0) : self.edges(sort=False)} + edge_colors = {(0, 0, 0) : self.edges(sort=False)} # by default turn off the frame if 'frame' not in kwds: @@ -20789,35 +20793,39 @@ def plot3d(self, bgcolor=(1,1,1), edge_colors = self._color_by_label(format=color_by_label) if edge_colors is None: - edge_colors = {(0,0,0) : self.edges(sort=False)} + edge_colors = {(0, 0, 0) : self.edges(sort=False)} i = 0 for color in edge_colors: i += 1 - TT.texture('edge_color_%d'%i, ambient=0.1, diffuse=0.9, specular=0.03, opacity=1.0, color=color) + TT.texture('edge_color_%d' % i, ambient=0.1, diffuse=0.9, + specular=0.03, opacity=1.0, color=color) if self._directed: for u,v,l in edge_colors[color]: TT.fcylinder((pos3d[u][0], pos3d[u][1], pos3d[u][2]), - (pos3d[v][0], pos3d[v][1], pos3d[v][2]), edge_size, 'edge_color_%d'%i) + (pos3d[v][0], pos3d[v][1], pos3d[v][2]), + edge_size, 'edge_color_%d' % i) TT.fcylinder((0.25 * pos3d[u][0] + 0.75 * pos3d[v][0], 0.25 * pos3d[u][1] + 0.75 * pos3d[v][1], 0.25 * pos3d[u][2] + 0.75 * pos3d[v][2]), - (pos3d[v][0], pos3d[v][1], pos3d[v][2]), edge_size2,'edge_color_%d'%i) + (pos3d[v][0], pos3d[v][1], pos3d[v][2]), + edge_size2, 'edge_color_%d' % i) else: for u, v, l in edge_colors[color]: TT.fcylinder((pos3d[u][0], pos3d[u][1], pos3d[u][2]), - (pos3d[v][0], pos3d[v][1], pos3d[v][2]), edge_size,'edge_color_%d'%i) + (pos3d[v][0], pos3d[v][1], pos3d[v][2]), + edge_size, 'edge_color_%d' % i) return TT else: - raise TypeError("rendering engine (%s) not implemented"%engine) + raise TypeError("rendering engine (%s) not implemented" % engine) - def show3d(self, bgcolor=(1,1,1), vertex_colors=None, vertex_size=0.06, - edge_colors=None, edge_size=0.02, edge_size2=0.0325, - pos3d=None, color_by_label=False, - engine='threejs', **kwds): + def show3d(self, bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, + edge_colors=None, edge_size=0.02, edge_size2=0.0325, + pos3d=None, color_by_label=False, + engine='threejs', **kwds): """ Plot the graph and show the resulting plot. @@ -20882,7 +20890,9 @@ def show3d(self, bgcolor=(1,1,1), vertex_colors=None, vertex_size=0.06, sage: A5 = AlternatingGroup(5); A5 Alternating group of order 5!/2 as a permutation group sage: G = A5.cayley_graph() - sage: G.show3d(vertex_size=0.03, edge_size=0.01, edge_size2=0.02, vertex_colors={(1,1,1): list(G)}, bgcolor=(0,0,0), color_by_label=True, iterations=200) # long time + sage: G.show3d(vertex_size=0.03, edge_size=0.01, edge_size2=0.02, + ....: vertex_colors={(1,1,1): list(G)}, bgcolor=(0,0,0), + ....: color_by_label=True, iterations=200) # long time Some :class:`~sage.plot.plot3d.tachyon.Tachyon` examples:: @@ -20937,15 +20947,14 @@ def get_label(vertex): return label[vertex] return get_label - ### String representation to be used by other programs + # String representation to be used by other programs @options(labels="string", - vertex_labels=True, edge_labels=False, - edge_color=None, edge_colors=None, - edge_options=(), - color_by_label=False, - rankdir='down', - subgraph_clusters=[], - ) + vertex_labels=True, edge_labels=False, + edge_color=None, edge_colors=None, + edge_options=(), + color_by_label=False, + rankdir='down', + subgraph_clusters=[]) def graphviz_string(self, **options): r""" Return a representation in the ``dot`` language. @@ -21470,10 +21479,10 @@ def graphviz_string(self, **options): for color in options['edge_colors'].keys(): for edge in options['edge_colors'][color]: assert isinstance(edge, (list, tuple)) and len(edge) >= 2 and len(edge) <= 3,\ - "%s is not a valid format for edge"%(edge) + "%s is not a valid format for edge" % (edge) u = edge[0] v = edge[1] - assert self.has_edge(*edge), "%s is not an edge"%(edge) + assert self.has_edge(*edge), "%s is not an edge" % (edge) if len(edge) == 2: if self.has_multiple_edges(): for label in self.edge_label(u, v): @@ -21492,10 +21501,10 @@ def graphviz_string(self, **options): if options['rankdir'] != "down": directions = {'up': 'BT', 'down': 'TB', 'left': 'RL', 'right': 'LR'} if options['rankdir'] not in directions: - raise ValueError("rankdir should be one of %s"%directions.keys()) - s += ' rankdir=%s\n'%(directions[options['rankdir']]) + raise ValueError("rankdir should be one of %s" % directions.keys()) + s += ' rankdir=%s\n' % (directions[options['rankdir']]) if (options['vertex_labels'] and - options['labels'] == "latex"): # not a perfect option name + options['labels'] == "latex"): # not a perfect option name # TODO: why do we set this only for latex labels? s += ' node [shape="plaintext"];\n' @@ -21504,11 +21513,11 @@ def graphviz_string(self, **options): if not options['vertex_labels']: node_options = "" elif options['labels'] == "latex": - node_options = " [label=\" \", texlbl=\"$%s$\"]"%quoted_latex(v) + node_options = " [label=\" \", texlbl=\"$%s$\"]" % quoted_latex(v) else: - node_options = " [label=\"%s\"]" %quoted_str(v) + node_options = " [label=\"%s\"]" % quoted_str(v) - s += ' %s %s;\n'%(key(v), node_options) + s += ' %s %s;\n' % (key(v), node_options) s += "\n" # subgraphs clusters for loop @@ -21522,7 +21531,7 @@ def graphviz_string(self, **options): s += '}\n\n' if default_color is not None: - s += 'edge [color="%s"];\n'%default_color + s += 'edge [color="%s"];\n' % default_color # edges for loop for u, v, label in self.edge_iterator(): @@ -21531,17 +21540,17 @@ def graphviz_string(self, **options): 'backward': False, 'dot': None, 'edge_string': default_edge_string, - 'color' : default_color, - 'label' : label, + 'color' : default_color, + 'label' : label, 'label_style': options['labels'] if options['edge_labels'] else None } for f in edge_option_functions: - edge_options.update(f((u, v,label))) + edge_options.update(f((u, v, label))) if not edge_options['edge_string'] in ['--', '->']: - raise ValueError("edge_string(='{}') in edge_options dict for the " - "edge ({}, {}) should be '--' " - "or '->'".format(edge_options['edge_string'], u, v)) + raise ValueError("edge_string(='{}') in edge_options dict for " + "the edge ({}, {}) should be '--' or '->'" + .format(edge_options['edge_string'], u, v)) dot_options = [] @@ -21552,9 +21561,9 @@ def graphviz_string(self, **options): label = edge_options['label'] if label is not None and edge_options['label_style'] is not None: if edge_options['label_style'] == 'latex': - dot_options.append('label=" ", texlbl="$%s$"'%quoted_latex(label)) + dot_options.append('label=" ", texlbl="$%s$"' % quoted_latex(label)) else: - dot_options.append('label="%s"'% label) + dot_options.append('label="%s"' % label) if edge_options['color'] != default_color: col = edge_options['color'] @@ -21577,13 +21586,14 @@ def graphviz_string(self, **options): dot_options.append('dir={}'.format(edge_options['dir'])) else: raise ValueError("dir(='{}') in edge_options dict for the" - " edge ({}, {}) should be 'forward', 'back', 'both'," - " or 'none'".format(edge_options['dir'], u, v)) + " edge ({}, {}) should be 'forward', 'back'," + " 'both', or 'none'" + .format(edge_options['dir'], u, v)) - s+= ' %s %s %s' % (key(u), edge_options['edge_string'], key(v)) + s += ' %s %s %s' % (key(u), edge_options['edge_string'], key(v)) if dot_options: s += " [" + ", ".join(dot_options)+"]" - s+= ";\n" + s += ";\n" s += "}" return s @@ -21623,7 +21633,7 @@ def graphviz_to_file_named(self, filename, **options): with open(filename, 'wt') as file: file.write(self.graphviz_string(**options)) - ### Spectrum + # Spectrum def spectrum(self, laplacian=False): r""" From 822d9d1e4ad254ab7284828655747c177eeac1cb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 10:54:57 -0700 Subject: [PATCH 382/591] .devcontainer/develop-docker-{cocalc,computop}/, .devcontainer/downstream-docker-{cocalc,computop,sagemath}: Rename/specialize from cocalc, computop-sage, sagemath-sagemath --- .../devcontainer.json | 0 .../devcontainer.json | 0 .../devcontainer.json | 16 +++++++++++ .../devcontainer.json | 21 ++++++++++++++ .../devcontainer.json | 0 src/doc/en/developer/portability_testing.rst | 28 ++++++++++++------- 6 files changed, 55 insertions(+), 10 deletions(-) rename .devcontainer/{cocalc => develop-docker-cocalc}/devcontainer.json (100%) rename .devcontainer/{computop-sage => develop-docker-computop}/devcontainer.json (100%) create mode 100644 .devcontainer/downstream-docker-cocalc/devcontainer.json create mode 100644 .devcontainer/downstream-docker-computop/devcontainer.json rename .devcontainer/{sagemath-sagemath => downstream-docker-sagemath}/devcontainer.json (100%) diff --git a/.devcontainer/cocalc/devcontainer.json b/.devcontainer/develop-docker-cocalc/devcontainer.json similarity index 100% rename from .devcontainer/cocalc/devcontainer.json rename to .devcontainer/develop-docker-cocalc/devcontainer.json diff --git a/.devcontainer/computop-sage/devcontainer.json b/.devcontainer/develop-docker-computop/devcontainer.json similarity index 100% rename from .devcontainer/computop-sage/devcontainer.json rename to .devcontainer/develop-docker-computop/devcontainer.json diff --git a/.devcontainer/downstream-docker-cocalc/devcontainer.json b/.devcontainer/downstream-docker-cocalc/devcontainer.json new file mode 100644 index 00000000000..bc97538c63b --- /dev/null +++ b/.devcontainer/downstream-docker-cocalc/devcontainer.json @@ -0,0 +1,16 @@ +// See https://aka.ms/devcontainer.json for format details. +{ + "name": "CoCalc Docker", + "image": "sagemathinc/cocalc", + "containerEnv": { + "MAKE": "make -j12" + }, + // Run commands after the container is created. + // libgmp.a is broken and leads to a build failure of ecm. + "postCreateCommand": ".devcontainer/post_create.sh && rm -f /usr/local/sage/local/lib/libgmp.a", + // Run commands after the container is started. + "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv", + "extensions": [ + "ms-python.python" + ] +} diff --git a/.devcontainer/downstream-docker-computop/devcontainer.json b/.devcontainer/downstream-docker-computop/devcontainer.json new file mode 100644 index 00000000000..0f9ba0b8841 --- /dev/null +++ b/.devcontainer/downstream-docker-computop/devcontainer.json @@ -0,0 +1,21 @@ +// See https://aka.ms/devcontainer.json for format details. +{ + "name": "computop/sage Docker", + "image": "computop/sage", + "containerEnv": { + "MAKE": "make -j12" + }, + // Run commands after the container is created. + // Install build tools, get rid of sourcing /sage/activate in non-login shells. + // libgmp.a is broken and leads to a build failure of ecm. + "postCreateCommand": ".devcontainer/post_create.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", + // Run commands after the container is started. + // Do not run configure within a sage-env (see #29485). + // The pari package is broken in the computop/sage 9.5 image, need to reinstall. + // Also libnauty is broken. + + "postStartCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv)", + "extensions": [ + "ms-python.python" + ] +} diff --git a/.devcontainer/sagemath-sagemath/devcontainer.json b/.devcontainer/downstream-docker-sagemath/devcontainer.json similarity index 100% rename from .devcontainer/sagemath-sagemath/devcontainer.json rename to .devcontainer/downstream-docker-sagemath/devcontainer.json diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 22b9c01c0b6..b4599a457fd 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1246,25 +1246,33 @@ directory ``$SAGE_ROOT/.devcontainer``: `_ similarly configures a container with an installation of conda-forge and its SageMath package. -- `cocalc/devcontainer.json - `_ +- `downstream-docker-sagemath/devcontainer.json + `_ + configures a container with `SageMath's official Docker image `_. + +- `downstream-docker-cocalc/devcontainer.json + `_ + configures a container with `the CoCalc Docker image `_. + +- `develop-docker-cocalc/devcontainer.json + `_ configures a container with `the CoCalc Docker image `_. It then updates the installation of SageMath in this container by building from the current source tree. -- `computop-sage/devcontainer.json - `_ +- `downstream-docker-computop/devcontainer.json + `_ + configures a container with the `Docker image from the 3-manifolds + project `_, providing + SnapPy, Regina, PHCPack, etc. + +- `develop-docker-computop/devcontainer.json + `_ configures a container with the `Docker image from the 3-manifolds project `_, providing SnapPy, Regina, PHCPack, etc. It then updates the installation of SageMath in this container by building from the current source tree. -- `sagemath-sagemath/devcontainer.json - `_ - configures a container with `SageMath's official Docker image `_. - It then updates the installation of SageMath in this container by building from - the current source tree. - These ``devcontainer.json`` configuration files are useful for testing user scripts on these deployments of SageMath. You may also find it useful to copy these configurations into your own projects or to adapt them to your needs. From cf27a5ecf82f203ba92e0bc4d84f4ff48d627ea9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 11:50:26 -0700 Subject: [PATCH 383/591] .devcontainer/downstream-docker-cocalc/devcontainer.json: Only run Sage config when in a Sage source tree --- .../downstream-docker-cocalc/devcontainer.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.devcontainer/downstream-docker-cocalc/devcontainer.json b/.devcontainer/downstream-docker-cocalc/devcontainer.json index bc97538c63b..161c562d04d 100644 --- a/.devcontainer/downstream-docker-cocalc/devcontainer.json +++ b/.devcontainer/downstream-docker-cocalc/devcontainer.json @@ -9,7 +9,15 @@ // libgmp.a is broken and leads to a build failure of ecm. "postCreateCommand": ".devcontainer/post_create.sh && rm -f /usr/local/sage/local/lib/libgmp.a", // Run commands after the container is started. - "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv", + // * If the workspace directory looks like a copy of the Sage source tree (SAGE_ROOT): + // - it bootstraps and configures the Sage distribution, + // - thus, the script ``./sage`` and the symlinks ``prefix``, ``venv`` are set as expected, + // - the source tree is prepared for rebuilding Sage based from the source tree on + // top of the existing installation from the Docker image. + // - however, do not start the build. + // * Otherwise, do nothing. This is so that users can copy this devcontainer.json file as is + // into their projects. + "postStartCommand": "if [ -d pkgs/sagemath-standard ]; then make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv; else echo 'Edit .devcontainer/devcontainer.json (postStartCommand) to run project-specific startup commands'; fi", "extensions": [ "ms-python.python" ] From 7ea06b3cecc6b841b6f20a56626efc7ae80dd654 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 12:13:20 -0700 Subject: [PATCH 384/591] src/doc/en/developer/portability_testing.rst: Expand on devcontainer directory prefixes --- src/doc/en/developer/portability_testing.rst | 31 ++++++++++++-------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index b4599a457fd..23e1da8108b 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1233,7 +1233,15 @@ for more information. In addition to the ``$SAGE_ROOT/.devcontainer/portability-.../devcontainer.json`` files, Sage also provides several other sample ``devcontainer.json`` configuration files in the -directory ``$SAGE_ROOT/.devcontainer``: +directory ``$SAGE_ROOT/.devcontainer``. + +Files named ``$SAGE_ROOT/.devcontainer/downstream-.../devcontainer.json`` configure +containers with an installation of downstream packages providing SageMath from a +package manager, or from a public Docker image that provides SageMath. +These ``devcontainer.json`` configuration files are useful for testing +user scripts on these deployments of SageMath. You may also find it +useful to copy these configurations into your own projects (they should +work without change) or to adapt them to your needs. - `downstream-archlinux-latest/devcontainer.json `_ @@ -1254,26 +1262,25 @@ directory ``$SAGE_ROOT/.devcontainer``: `_ configures a container with `the CoCalc Docker image `_. -- `develop-docker-cocalc/devcontainer.json - `_ - configures a container with `the CoCalc Docker image `_. - It then updates the installation of SageMath in this container by building from - the current source tree. - - `downstream-docker-computop/devcontainer.json `_ configures a container with the `Docker image from the 3-manifolds project `_, providing SnapPy, Regina, PHCPack, etc. +Files named ``$SAGE_ROOT/.devcontainer/develop-.../devcontainer.json`` configure +containers from a public Docker image that provides SageMath and then updates the +installation of SageMath in this container by building from the current source tree. + +- `develop-docker-cocalc/devcontainer.json + `_ + configures a container with `the CoCalc Docker image `_. + It then updates the installation of SageMath in this container by building from + the current source tree. + - `develop-docker-computop/devcontainer.json `_ configures a container with the `Docker image from the 3-manifolds project `_, providing SnapPy, Regina, PHCPack, etc. It then updates the installation of SageMath in this container by building from the current source tree. - -These ``devcontainer.json`` configuration files are useful for testing -user scripts on these deployments of SageMath. You may also find it -useful to copy these configurations into your own projects or to adapt them to your needs. - From c8b59ec134be569bdb4453f7c408d440219489f8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 12:23:30 -0700 Subject: [PATCH 385/591] .devcontainer/downstream-conda-forge-latest/devcontainer.json: Only run Sage config when in a Sage source tree --- .../downstream-conda-forge-latest/devcontainer.json | 10 +++++++++- .../downstream-docker-cocalc/devcontainer.json | 9 +++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.devcontainer/downstream-conda-forge-latest/devcontainer.json b/.devcontainer/downstream-conda-forge-latest/devcontainer.json index a38b23f880a..cf64cfc3d25 100644 --- a/.devcontainer/downstream-conda-forge-latest/devcontainer.json +++ b/.devcontainer/downstream-conda-forge-latest/devcontainer.json @@ -5,7 +5,15 @@ // Run commands after the container is created. "postCreateCommand": ".devcontainer/post_create.sh && mamba install --yes sage", // Run commands after the container is started. - "postStartCommand": "make configure && ln -sf $CONDA_PREFIX venv", + // * If the workspace directory looks like a copy of the Sage source tree (SAGE_ROOT): + // - it bootstraps and configures the Sage distribution, + // - thus, the script ``./sage`` and the symlinks ``prefix``, ``venv`` are set as expected, + // - the source tree is prepared for rebuilding Sage based from the source tree on + // top of the existing installation from the Docker image. + // - however, it does not start the build. + // * Otherwise, it does nothing. This is so that users can copy this devcontainer.json file as is + // into their projects. + "postStartCommand": "if [ -d pkgs/sagemath-standard ]; then make configure && ln -sf $CONDA_PREFIX venv; else echo 'Edit .devcontainer/devcontainer.json (postStartCommand) to run project-specific startup commands'; fi", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/downstream-docker-cocalc/devcontainer.json b/.devcontainer/downstream-docker-cocalc/devcontainer.json index 161c562d04d..d77f5f71df5 100644 --- a/.devcontainer/downstream-docker-cocalc/devcontainer.json +++ b/.devcontainer/downstream-docker-cocalc/devcontainer.json @@ -10,12 +10,9 @@ "postCreateCommand": ".devcontainer/post_create.sh && rm -f /usr/local/sage/local/lib/libgmp.a", // Run commands after the container is started. // * If the workspace directory looks like a copy of the Sage source tree (SAGE_ROOT): - // - it bootstraps and configures the Sage distribution, - // - thus, the script ``./sage`` and the symlinks ``prefix``, ``venv`` are set as expected, - // - the source tree is prepared for rebuilding Sage based from the source tree on - // top of the existing installation from the Docker image. - // - however, do not start the build. - // * Otherwise, do nothing. This is so that users can copy this devcontainer.json file as is + // - it bootstraps the Sage distribution, + // - sets the symlink ``venv`` as expected, + // * Otherwise, it does nothing. This is so that users can copy this devcontainer.json file as is // into their projects. "postStartCommand": "if [ -d pkgs/sagemath-standard ]; then make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv; else echo 'Edit .devcontainer/devcontainer.json (postStartCommand) to run project-specific startup commands'; fi", "extensions": [ From cb64abccfbb7e19e498d932fb7b17d5e7c675371 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 12:36:44 -0700 Subject: [PATCH 386/591] .devcontainer/downstream-docker-sagemath/devcontainer.json: Do not try to bootstrap/configure/build; only set synlinks when in a Sage source tree --- .devcontainer/downstream-docker-sagemath/devcontainer.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.devcontainer/downstream-docker-sagemath/devcontainer.json b/.devcontainer/downstream-docker-sagemath/devcontainer.json index 02d5c9fa8db..fd805860d99 100644 --- a/.devcontainer/downstream-docker-sagemath/devcontainer.json +++ b/.devcontainer/downstream-docker-sagemath/devcontainer.json @@ -1,17 +1,13 @@ // See https://aka.ms/devcontainer.json for format details. { "name": "sagemath/sagemath Docker", - // sagemath/sagemath-dev as of 9.5 is broken? "image": "sagemath/sagemath:develop", - "containerEnv": { - "MAKE": "make -j12" - }, // Run commands after the container is created. // Install build tools. "postCreateCommand": ".devcontainer/post_create.sh --sudo" // Run commands after the container is started. // Do not run configure within a sage-env (see #29485). - "postStartCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/home/sage/sage/local --with-sage-venv) && make build V=0", + "postStartCommand": "if [ -d pkgs/sagemath-standard ]; then ln -s /home/sage/sage/venv venv && ln -s /home/sage/sage/local prefix; else echo 'Edit .devcontainer/devcontainer.json (postStartCommand) to run project-specific startup commands'; fi", "extensions": [ "ms-python.python" ] From bb9ff58f60af07a4e15e8d667428ada9793237c9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 12:44:20 -0700 Subject: [PATCH 387/591] src/doc/en/developer/portability_testing.rst: Add link to _sagemath dummy package --- src/doc/en/developer/portability_testing.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 23e1da8108b..c951136a23b 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1237,7 +1237,8 @@ directory ``$SAGE_ROOT/.devcontainer``. Files named ``$SAGE_ROOT/.devcontainer/downstream-.../devcontainer.json`` configure containers with an installation of downstream packages providing SageMath from a -package manager, or from a public Docker image that provides SageMath. +package manager (see `the _sagemath dummy package <../reference/spkg/_sagemath.html>`_), +or from a public Docker image that provides SageMath. These ``devcontainer.json`` configuration files are useful for testing user scripts on these deployments of SageMath. You may also find it useful to copy these configurations into your own projects (they should From 6592b7d635fea77e407632b2060c02577cab36be Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 12:45:20 -0700 Subject: [PATCH 388/591] .devcontainer/downstream-docker-sagemath/devcontainer.json: Fixup --- .devcontainer/downstream-docker-sagemath/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/downstream-docker-sagemath/devcontainer.json b/.devcontainer/downstream-docker-sagemath/devcontainer.json index fd805860d99..a235bab1f2f 100644 --- a/.devcontainer/downstream-docker-sagemath/devcontainer.json +++ b/.devcontainer/downstream-docker-sagemath/devcontainer.json @@ -7,7 +7,7 @@ "postCreateCommand": ".devcontainer/post_create.sh --sudo" // Run commands after the container is started. // Do not run configure within a sage-env (see #29485). - "postStartCommand": "if [ -d pkgs/sagemath-standard ]; then ln -s /home/sage/sage/venv venv && ln -s /home/sage/sage/local prefix; else echo 'Edit .devcontainer/devcontainer.json (postStartCommand) to run project-specific startup commands'; fi", + "postStartCommand": "if [ -d pkgs/sagemath-standard ]; then ln -sf /home/sage/sage/venv venv && ln -sf /home/sage/sage/local prefix; else echo 'Edit .devcontainer/devcontainer.json (postStartCommand) to run project-specific startup commands'; fi", "extensions": [ "ms-python.python" ] From c5d883c7e24f0c7eef4f49bf2adf645248fb392b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 13:11:52 -0700 Subject: [PATCH 389/591] src/doc/en/developer/portability_testing.rst: Explain the devcontainer name prefix downstream-docker-... --- src/doc/en/developer/portability_testing.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index c951136a23b..a46d4f88eed 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1237,8 +1237,10 @@ directory ``$SAGE_ROOT/.devcontainer``. Files named ``$SAGE_ROOT/.devcontainer/downstream-.../devcontainer.json`` configure containers with an installation of downstream packages providing SageMath from a -package manager (see `the _sagemath dummy package <../reference/spkg/_sagemath.html>`_), -or from a public Docker image that provides SageMath. +package manager (``downstream-archlinux-...``, ``downstream-conda-forge``; +see also `the _sagemath dummy package <../reference/spkg/_sagemath.html>`_), +or from a public Docker image that provides SageMath (``docker-sagemath``, +``docker-cocalc``, ``docker-computop``). These ``devcontainer.json`` configuration files are useful for testing user scripts on these deployments of SageMath. You may also find it useful to copy these configurations into your own projects (they should From 6dc2131f96b49162974f7e9c71511d89c96de117 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 14 Aug 2022 06:14:20 +0800 Subject: [PATCH 390/591] automatically determine SchemeMorphism base ring if none is given --- src/sage/schemes/generic/homset.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index a1aa946614e..4115f163b48 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -105,12 +105,12 @@ class SchemeHomsetFactory(UniqueFactory): TESTS:: sage: Hom.base() - Integer Ring + Rational Field sage: Hom.base_ring() - Integer Ring + Rational Field """ - def create_key_and_extra_args(self, X, Y, category=None, base=ZZ, + def create_key_and_extra_args(self, X, Y, category=None, base=None, check=True, as_point_homset=False): """ Create a key that uniquely determines the Hom-set. @@ -142,17 +142,20 @@ def create_key_and_extra_args(self, X, Y, category=None, base=ZZ, sage: SHOMfactory = SchemeHomsetFactory('test') sage: key, extra = SHOMfactory.create_key_and_extra_args(A3,A2,check=False) sage: key - (..., ..., Category of schemes over Integer Ring, False) + (..., ..., Category of schemes over Rational Field, False) sage: extra {'X': Affine Space of dimension 3 over Rational Field, 'Y': Affine Space of dimension 2 over Rational Field, - 'base_ring': Integer Ring, + 'base_ring': Rational Field, 'check': False} """ if isinstance(X, CommutativeRing): X = AffineScheme(X) if isinstance(Y, CommutativeRing): Y = AffineScheme(Y) + if base is None: + from sage.structure.all import coercion_model + base = coercion_model.common_parent(X.base_ring(), Y.base_ring()) if is_AffineScheme(base): base_spec = base base_ring = base.coordinate_ring() From 3016ce985bd8b51fa3cb8f1438d751a7b7895a98 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 18:32:23 -0700 Subject: [PATCH 391/591] build/bin/sage-print-system-package-command (conda): Actually include options in command --- build/bin/sage-print-system-package-command | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/bin/sage-print-system-package-command b/build/bin/sage-print-system-package-command index 4ee33ab0e65..b493ebd0ffb 100755 --- a/build/bin/sage-print-system-package-command +++ b/build/bin/sage-print-system-package-command @@ -142,7 +142,7 @@ case $system:$command in ;; *conda*:install) [ "$YES" = yes ] && options="$options --yes" - [ -n "$system_packages" ] && print_shell_command "conda install $system_packages" + [ -n "$system_packages" ] && print_shell_command "conda install $options $system_packages" ;; homebrew*:install) [ -n "$system_packages" ] && print_shell_command "brew install $system_packages" From 84a5e13bd2d17cfb27ac93ab0177193d5a0917db Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 18:32:48 -0700 Subject: [PATCH 392/591] .devcontainer/downstream-conda-forge-latest/devcontainer.json: Do not use .devcontainer/post_create.sh --- .devcontainer/downstream-conda-forge-latest/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/downstream-conda-forge-latest/devcontainer.json b/.devcontainer/downstream-conda-forge-latest/devcontainer.json index cf64cfc3d25..d6799692c0a 100644 --- a/.devcontainer/downstream-conda-forge-latest/devcontainer.json +++ b/.devcontainer/downstream-conda-forge-latest/devcontainer.json @@ -3,7 +3,7 @@ "name": "condaforge/mambaforge:latest downstream Sage", "image": "condaforge/mambaforge:latest", // Run commands after the container is created. - "postCreateCommand": ".devcontainer/post_create.sh && mamba install --yes sage", + "postCreateCommand": "mamba install --yes sage", // Run commands after the container is started. // * If the workspace directory looks like a copy of the Sage source tree (SAGE_ROOT): // - it bootstraps and configures the Sage distribution, From cad694ca6f8c8433b43ceda874282b441bf9d2c4 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 14 Aug 2022 14:26:36 +0900 Subject: [PATCH 393/591] Some edits and import from sage.structure.element --- src/sage/schemes/generic/homset.py | 2 +- src/sage/schemes/generic/morphism.py | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index 4115f163b48..5a67c614efd 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -154,7 +154,7 @@ def create_key_and_extra_args(self, X, Y, category=None, base=None, if isinstance(Y, CommutativeRing): Y = AffineScheme(Y) if base is None: - from sage.structure.all import coercion_model + from sage.structure.element import coercion_model base = coercion_model.common_parent(X.base_ring(), Y.base_ring()) if is_AffineScheme(base): base_spec = base diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index b1409f05ba1..4c75777c1d1 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -482,7 +482,7 @@ def is_endomorphism(self) -> bool: def base_ring(self): r""" Return the base ring of ``self``, that is, the ring over which - the coefficients of ``self`` are given as polynomials. + the defining polynomials of ``self`` are defined. OUTPUT: @@ -490,31 +490,31 @@ def base_ring(self): EXAMPLES:: - sage: P.=ProjectiveSpace(QQ,1) - sage: H=Hom(P,P) - sage: f=H([3/5*x^2,6*y^2]) + sage: P. = ProjectiveSpace(QQ, 1) + sage: H = Hom(P,P) + sage: f = H([3/5*x^2, 6*y^2]) sage: f.base_ring() Rational Field :: - sage: R.=PolynomialRing(ZZ,1) - sage: P.=ProjectiveSpace(R,1) - sage: H=Hom(P,P) - sage: f=H([3*x^2,y^2]) + sage: R. = PolynomialRing(ZZ, 1) + sage: P. = ProjectiveSpace(R, 1) + sage: H = Hom(P, P) + sage: f = H([3*x^2, y^2]) sage: f.base_ring() Multivariate Polynomial Ring in t over Integer Ring Points have correct base rings too (:trac:`34336`):: - sage: x = P(t,5); x + sage: x = P(t, 5); x (t : 5) sage: x.base_ring() Multivariate Polynomial Ring in t over Integer Ring :: - sage: E = EllipticCurve(GF(17^2), [1,2,3,4,5]) + sage: E = EllipticCurve(GF((17,2)), [1,2,3,4,5]) sage: P = E.random_point() sage: P.base_ring() Finite Field in z2 of size 17^2 From 1626caf2b18735742316701d47018a38952f4988 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 14 Aug 2022 17:44:49 +0900 Subject: [PATCH 394/591] Fix a doctest --- src/sage/schemes/projective/projective_homset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/schemes/projective/projective_homset.py b/src/sage/schemes/projective/projective_homset.py index cb6420d80f1..0f7b6abce52 100644 --- a/src/sage/schemes/projective/projective_homset.py +++ b/src/sage/schemes/projective/projective_homset.py @@ -104,7 +104,7 @@ def points(self, **kwds): - a list of rational points of a projective scheme .. WARNING:: - + For numerically inexact fields such as ComplexField or RealField the list of points returned is very likely to be incomplete. It may also contain repeated points due to tolerances. @@ -643,7 +643,7 @@ def base_extend(self, R): Abelian group of points on Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field sage: Hom.base_ring() - Integer Ring + Rational Field sage: Hom.base_extend(QQ) Traceback (most recent call last): ... From c42eef0aae9a6242616dd97e836bd5a9204309da Mon Sep 17 00:00:00 2001 From: Robert Figura Date: Sun, 14 Aug 2022 12:22:33 +0200 Subject: [PATCH 395/591] fix #34360: curl configure --without-libmetalink no longer works --- build/pkgs/curl/spkg-install.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/curl/spkg-install.in b/build/pkgs/curl/spkg-install.in index bc09f074780..a123a4972c4 100644 --- a/build/pkgs/curl/spkg-install.in +++ b/build/pkgs/curl/spkg-install.in @@ -3,7 +3,7 @@ cd src if [ "$SAGE_FAT_BINARY" = yes ]; then # Let's disable a bunch of stuff which might get linked. # SSL/TLS still depends on the compilation environment. - CURL_CONFIGURE="--disable-ldap --disable-ldaps --disable-rtsp --disable-ares --disable-crypto-auth --without-libpsl --without-libmetalink --without-libssh2 --without-librtmp --without-libidn --without-nghttp2 --without-gssapi $CURL_CONFIGURE" + CURL_CONFIGURE="--disable-ldap --disable-ldaps --disable-rtsp --disable-ares --disable-crypto-auth --without-libpsl --without-libssh2 --without-librtmp --without-libidn --without-nghttp2 --without-gssapi $CURL_CONFIGURE" fi if [ "$UNAME" = "Darwin" ]; then From d324476216141a5e0c6f4047166140e649d94aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 14 Aug 2022 13:41:50 +0200 Subject: [PATCH 396/591] a few details in riemann_surface.py --- .../riemann_surfaces/riemann_surface.py | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index d71f608fb9d..e80b88c1bed 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -252,7 +252,7 @@ class ConvergenceError(ValueError): def differential_basis_baker(f): r""" - Compute a differential bases for a curve that is nonsingular outside (1:0:0),(0:1:0),(0:0:1) + Compute a differential basis for a curve that is nonsingular outside (1:0:0),(0:1:0),(0:0:1) Baker's theorem tells us that if a curve has its singularities at the coordinate vertices and meets some further easily tested genericity criteria, @@ -336,18 +336,19 @@ class RiemannSurface(): - ``prec`` -- the desired precision of computations on the surface in bits (default: 53) - - ``certification`` -- a boolean (default: True) value indicating whether - homotopy continuation is certified or not. Uncertified homotopy - continuation can be faster. + - ``certification`` -- a boolean (default: ``True``) value indicating + whether homotopy continuation is certified or not. Uncertified + homotopy continuation can be faster. - - ``differentials`` -- (default: None). If specified, provides a list of - polynomials `h` such that `h/(df/dw) dz` is a regular differential on the - Riemann surface. This is taken as a basis of the regular differentials, so - the genus is assumed to be equal to the length of this list. The results - from the homology basis computation are checked against this value. - Providing this parameter makes the computation independent from Singular. - For a nonsingular plane curve of degree `d`, an appropriate set is given - by the monomials of degree up to `d-3`. + - ``differentials`` -- (default: ``None``). If specified, provides a list + of polynomials `h` such that `h/(df/dw) dz` is a regular + differential on the Riemann surface. This is taken as a basis of + the regular differentials, so the genus is assumed to be equal + to the length of this list. The results from the homology basis + computation are checked against this value. Providing this + parameter makes the computation independent from Singular. For + a nonsingular plane curve of degree `d`, an appropriate set is + given by the monomials of degree up to `d-3`. - ``integration_method`` -- (default: ``'rigorous'``). String specifying the integration method to use when calculating the integrals of differentials. @@ -465,9 +466,9 @@ def __init__(self, f, prec=53, certification=True, differentials=None, integrati self._integration_method = integration_method self._R = f.parent() if len(self._R.gens()) != 2: - raise ValueError('only bivariate polynomials supported.') + raise ValueError('only bivariate polynomials supported') if f.degree() <= 1: - raise ValueError('equation must be of degree at least 2.') + raise ValueError('equation must be of degree at least 2') z, w = self._R.gen(0), self._R.gen(1) self._CC = ComplexField(self._prec) self._RR = RealField(self._prec) @@ -587,12 +588,12 @@ def downstairs_edges(self): """ # Because of how we constructed the Voronoi diagram, the first n points # correspond to the branch locus points. - # The regions of these points are all of the edges which don't go off + # The regions of these points are all of the edges which do not go off # to infinity, which are exactly the ones we want. n = len(self.branch_locus) desired_edges = [self.voronoi_diagram.regions[self.voronoi_diagram.point_region[i]] for i in range(n)] # First construct the edges as a set because the regions will overlap - # and we don't want to have two of the same edge. + # and we do not want to have two of the same edge. edges1 = set() for c in desired_edges: for j in range(len(c)-1): @@ -603,7 +604,7 @@ def downstairs_edges(self): # MUCH easier. # We orient all the edges so that we go from lower to higher # numbered vertex for the continuation. - edges = [(i0,i1) if (i0 < i1) else (i1,i0) for (i0,i1) in edges1] + edges = [(i0, i1) if (i0 < i1) else (i1, i0) for (i0, i1) in edges1] edges.sort() return edges @@ -875,8 +876,8 @@ def _determine_new_w(self, z0, oldw, epsilon): Nnew_delta = new_delta.norm() # If we found the root exactly, or if delta only affects half the digits and # stops getting smaller, we decide that we have converged. - if (new_delta == 0) or (Nnew_delta >= Ndelta and - Ndelta.sign_mantissa_exponent()[2]+prec < wi.norm().sign_mantissa_exponent()[2]): + if new_delta == 0 or (Nnew_delta >= Ndelta and + Ndelta.sign_mantissa_exponent()[2] + prec < wi.norm().sign_mantissa_exponent()[2]): neww.append(wi) break delta = new_delta @@ -955,12 +956,12 @@ def _newton_iteration(self, z0, oldw, epsilon): Nnew_delta = new_delta.norm() # If we found the root exactly, or if delta only affects half the digits and # stops getting smaller, we decide that we have converged. - if (new_delta == 0) or (Nnew_delta>=Ndelta and - Ndelta.sign_mantissa_exponent()[2]+prec < neww.norm().sign_mantissa_exponent()[2]): + if new_delta == 0 or (Nnew_delta >= Ndelta and + Ndelta.sign_mantissa_exponent()[2] + prec < neww.norm().sign_mantissa_exponent()[2]): return neww delta = new_delta Ndelta = Nnew_delta - neww-=delta + neww -= delta raise ConvergenceError("Newton iteration fails to converge") @cached_method @@ -1804,7 +1805,7 @@ def local_N(ct, rt): ball_stack.append((ncts[1], nrt, nNs[1])) continue - if lN % 2 and not lN==3: + if lN % 2 and not lN == 3: lN += 1 ct_minus_rt = ct-rt @@ -1882,7 +1883,7 @@ def normalize_pairs(L): bd = self._bounding_data(differentials) line_int = lambda edge: self.rigorous_line_integral(edge, fcd, bd) else: - raise ValueError("Invalid integration method") + raise ValueError("invalid integration method") integral_dict = {edge: line_int(edge) for edge in occurring_edges} @@ -1958,7 +1959,7 @@ def riemann_matrix(self): sage: S = RiemannSurface(f, prec=60) sage: M = S.riemann_matrix() - The Klein quartic has a Riemann matrix with values is a quadratic + The Klein quartic has a Riemann matrix with values in a quadratic field:: sage: x = polygen(QQ) @@ -2241,7 +2242,7 @@ def algebraize_element(alpha): rt = tup[0] if (alpha - CC(rt)).abs() < epscomp: return rt - raise AssertionError('No close root found while algebraizing') + raise AssertionError('no close root found while algebraizing') def algebraize_matrices(Ts): nr = Ts[0].nrows() @@ -2288,8 +2289,8 @@ def standard_symplectic_matrix(n): zero = Matrix.zero(n) return Matrix.block([[zero, -one], [one, zero]]) g = self.genus - if not(R.nrows() == 2 * g == R.ncols()): - raise AssertionError("Matrix is not the homology representation of an endomorphism") + if not (R.nrows() == 2 * g == R.ncols()): + raise AssertionError("matrix is not the homology representation of an endomorphism") J = standard_symplectic_matrix(g) return -J * R.transpose() * J @@ -2467,7 +2468,7 @@ def integer_matrix_relations(M1, M2, b=None, r=None): sage: [((m[:,:2]^(-1)*m)[:,2:]-M2).norm() < 1e-13 for m in M1t] [True, True] """ - if not(M1.is_square() and M2.is_square()): + if not (M1.is_square() and M2.is_square()): raise ValueError("matrices need to be square") prec = min(M1.base_ring().precision(),M2.base_ring().precision()) H = max(max(abs(m.real_part()) for m in M1.list() + M2.list()), @@ -2491,9 +2492,10 @@ def integer_matrix_relations(M1, M2, b=None, r=None): D = Matrix(R, g1, g2, vars[3*g1*g2:4*g1*g2]) W = ((M1*A+B) - (M1*C+D)*M2).list() vars = R.gens() - mt = Matrix(ZZ,[[1 if i == j else 0 for j in range(4*g1*g2)] + - [(S*w.monomial_coefficient(vars[i]).real_part()).round() for w in W] + - [(S*w.monomial_coefficient(vars[i]).imag_part()).round() for w in W] for i in range(len(vars))]) + mt = Matrix(ZZ, [[1 if i == j else 0 for j in range(4 * g1 * g2)] + + [(S * w.monomial_coefficient(vi).real_part()).round() for w in W] + + [(S * w.monomial_coefficient(vi).imag_part()).round() for w in W] + for i, vi in enumerate(vars)]) # we compute an LLL-reduced basis of this lattice: mtL = mt.LLL() From 07f08d5572f1908cdb6ec8aa5cc908858116e7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 14 Aug 2022 17:06:55 +0200 Subject: [PATCH 397/591] fix some whitespace E275 --- src/sage/calculus/transforms/dft.py | 2 +- src/sage/combinat/interval_posets.py | 4 ++-- .../dynamics/arithmetic_dynamics/affine_ds.py | 8 +++---- .../arithmetic_dynamics/berkovich_ds.py | 4 ++-- .../endPN_automorphism_group.py | 17 ++++++++------ .../endPN_minimal_model.py | 4 ++-- .../product_projective_ds.py | 10 ++++----- .../arithmetic_dynamics/projective_ds.py | 4 ++-- src/sage/game_theory/normal_form_game.py | 8 +++---- src/sage/games/sudoku.py | 10 ++++----- src/sage/geometry/fan.py | 4 ++-- .../hyperbolic_space/hyperbolic_geodesic.py | 2 +- .../hyperbolic_space/hyperbolic_point.py | 4 ++-- src/sage/geometry/polyhedron/base3.py | 6 ++--- src/sage/geometry/pseudolines.py | 2 +- .../abelian_gps/abelian_group_morphism.py | 22 +++++++++---------- .../groups/abelian_gps/dual_abelian_group.py | 4 ++-- src/sage/groups/cubic_braid.py | 2 +- src/sage/groups/free_group.py | 5 +++-- src/sage/groups/matrix_gps/matrix_group.py | 2 +- src/sage/groups/perm_gps/permgroup.py | 2 +- src/sage/groups/perm_gps/permgroup_named.py | 4 ++-- src/sage/homology/chain_complex.py | 2 +- src/sage/interfaces/fricas.py | 2 +- src/sage/interfaces/latte.py | 2 +- src/sage/interfaces/maxima_lib.py | 20 ++++++++--------- src/sage/interfaces/povray.py | 2 +- src/sage/interfaces/qepcad.py | 12 +++++----- src/sage/knots/link.py | 2 +- src/sage/symbolic/subring.py | 2 +- 30 files changed, 89 insertions(+), 85 deletions(-) diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index c71eedb23b3..9fd396f1915 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -330,7 +330,7 @@ def dft(self, chi=lambda x: x): N = len(J) S = self.list() F = self.base_ring() # elements must be coercible into QQ(zeta_N) - if not(J[0] in ZZ): + if J[0] not in ZZ: G = J[0].parent() # if J is not a range it is a group G if J[0] in ZZ and F.base_ring().fraction_field() == QQ: # assumes J is range(N) diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 3882bf26436..cd0846e3d6e 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -1482,8 +1482,8 @@ def _richcmp_(self, other, op) -> bool: return (self.size() == other.size() and self._cover_relations == other._cover_relations) if op == op_NE: - return not(self.size() == other.size() and - self._cover_relations == other._cover_relations) + return not (self.size() == other.size() and + self._cover_relations == other._cover_relations) return richcmp((self.size(), self.cubical_coordinates()), (other.size(), other.cubical_coordinates()), op) diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index 3bab02718c3..ccf1de6115d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -661,11 +661,11 @@ def nth_iterate(self, P, n): """ n = int(n) if n == 0: - return(P) + return P Q = P for i in range(n): Q = self(Q) - return(Q) + return Q def orbit(self, P, n): r""" @@ -728,7 +728,7 @@ def orbit(self, P, n): for i in range(bounds[0]+1, bounds[1]+1): Q = self(Q) orb.append(Q) - return(orb) + return orb def multiplier(self, P, n, check=True): r""" @@ -1014,7 +1014,7 @@ def orbit_structure(self, P): Q = self(Q) index += 1 I = orbit.index(Q) - return([I, index - I - 1]) + return [I, index - I - 1] def cyclegraph(self): r""" diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index 0301d68b8c9..92f10c05a9a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -329,7 +329,7 @@ def __neq__(self, other): sage: f != g True """ - return not(self == other) + return not (self == other) def domain(self): """ @@ -863,7 +863,7 @@ def __call__(self, x, type_3_pole_check=True): g = DynamicalSystem_Berkovich(f) return g(self.domain()(QQ(0), QQ(1))).involution_map() # if the reduction is not constant, the image is the Gauss point - if not(num.is_constant() and dem.is_constant()): + if not (num.is_constant() and dem.is_constant()): return self.domain()(QQ(0), QQ(1)) if self.domain().is_padic_base(): reduced_value = field(num * dem.inverse_of_unit()).lift_to_precision(field.precision_cap()) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index 91af87e49dd..8424b2fc505 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -275,8 +275,9 @@ def automorphism_group_QQ_fixedpoints(rational_function, return_functions=False, elements.append(matrix(F, 2, [a,b, 1, d])) if iso_type: - return(elements, which_group(elements)) - return(elements) + return elements, which_group(elements) + return elements + def height_bound(polynomial): r""" @@ -611,7 +612,8 @@ def remove_redundant_automorphisms(automorphisms, order_elts, moduli, integral_a del automorphisms[i][j] del order_elts[i][j] - return(automorphisms) + return automorphisms + def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_functions=True, iso_type=False): r""" @@ -755,7 +757,7 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun (gcd(orderaut + [24]) == 24 and \ (len(elements) == 12 or len(elements) == 8)): if iso_type: - return(elements, which_group(elements)) + return elements, which_group(elements) return elements else: N = gcd(orderaut + [12]) # all orders of elements divide N @@ -784,7 +786,7 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun if (len(elements) == gcd(orderaut + [24])): #found enough automorphisms if iso_type: - return(elements, which_group(elements)) + return elements, which_group(elements) return elements elif numelts <= (len(temp)): badorders.append(order) @@ -819,8 +821,9 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun p = primes.next(p) if iso_type: - return(elements, which_group(elements)) - return(elements) + return elements, which_group(elements) + return elements + def automorphism_group_FF(rational_function, absolute=False, iso_type=False, return_functions=False): r""" diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py index 9c6d5a2dd52..65c6671ce59 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py @@ -1083,8 +1083,8 @@ def coshdelta(z): gn = g.nth_iterate_map(n) pts_poly = y*gn[0] - x*gn[1] d = ZZ(pts_poly.degree()) - max_mult = max([ex for p,ex in pts_poly.factor()]) - assert(n<=4), "n > 4, failed to find usable poly" + max_mult = max([ex for _, ex in pts_poly.factor()]) + assert (n <= 4), "n > 4, failed to find usable poly" R = get_bound_dynamical(pts_poly, g, m=n, dynatomic=dynatomic, prec=prec, emb=emb) # search starts in fundamental domain diff --git a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py index 867d571db0d..caf82a3b00d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py @@ -111,7 +111,7 @@ def _call_with_args(self, P, check=True): A = self.domain() Q = list(P) newP = [f(Q) for f in self.defining_polynomials()] - return(A.point(newP, check)) + return A.point(newP, check) def nth_iterate(self, P, n, normalize=False): r""" @@ -154,7 +154,7 @@ def nth_iterate(self, P, n, normalize=False): if n < 0: raise TypeError("must be a forward orbit") if n == 0: - return(self) + return self else: Q = self(P) if normalize: @@ -163,7 +163,7 @@ def nth_iterate(self, P, n, normalize=False): Q = self(Q) if normalize: Q.normalize_coordinates() - return(Q) + return Q def orbit(self, P, N, **kwds): r""" @@ -219,7 +219,7 @@ def orbit(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 = copy(P) check = kwds.pop("check", True) @@ -237,7 +237,7 @@ def orbit(self, P, N, **kwds): if normalize: Q.normalize_coordinates() orb.append(Q) - return(orb) + return orb def nth_iterate_map(self, n): r""" diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index c814b81987a..f6fd1c0b01f 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -5726,7 +5726,7 @@ def reduced_form(self, **kwds): pp_d = pts_poly.degree() pts_poly_CF = pts_poly_CF.subs({pts_poly_CF.parent().gen(1):1}).univariate_polynomial() max_mult = max([pp_d - pts_poly_CF.degree()] + [ex for p,ex in pts_poly_CF.roots()]) - assert(n<=4), "n > 4, failed to find usable poly" + assert (n<=4), "n > 4, failed to find usable poly" G,m = pts_poly.reduced_form(prec=prec, emb=emb, smallest_coeffs=False) sm_f = self.conjugate(m) @@ -5913,7 +5913,7 @@ def postcritical_set(self, check=True): post_critical_list = [] for point in critical_points: next_point = f(point) - while not(next_point in post_critical_list): + while next_point not in post_critical_list: post_critical_list.append(next_point) next_point = f(next_point) return post_critical_list diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index f0d58a98aec..fdbf18d1960 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -2205,11 +2205,11 @@ 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 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)) + all(b[j] == 0 for j in range(len(b)) if j not in p2_support)): return False diff --git a/src/sage/games/sudoku.py b/src/sage/games/sudoku.py index 3e2de73ef98..44bc13fd287 100644 --- a/src/sage/games/sudoku.py +++ b/src/sage/games/sudoku.py @@ -177,7 +177,7 @@ def __init__(self, puzzle, verify_input = True): self.puzzle = tuple(puzzle) elif is_Matrix(puzzle): puzzle_size = puzzle.ncols() - if verify_input and not(puzzle.is_square()): + if verify_input and not puzzle.is_square(): raise ValueError('Sudoku puzzle must be a square matrix') self.puzzle = tuple([int(x) for x in puzzle.list()]) elif isinstance(puzzle, str): @@ -312,7 +312,7 @@ def _matrix_(self, R=None): ValueError: Sudoku puzzles only convert to matrices over Integer Ring, not Rational Field """ from sage.rings.integer_ring import ZZ, IntegerRing_class - if R and not(isinstance(R, IntegerRing_class)): + if R and not isinstance(R, IntegerRing_class): raise ValueError('Sudoku puzzles only convert to matrices over %s, not %s' % (ZZ, R)) return self.to_matrix() @@ -880,11 +880,11 @@ def make_row(row, col, entry): # These rows will represent the original hints, plus a single entry in every other location, # consistent with the requirements imposed on a solution to a Sudoku puzzle for cover in DLXCPP(ones): - if not(count_only): - solution = [0]*nfour + if not count_only: + solution = [0] * nfour for r in cover: row, col, entry = rowinfo[r] - solution[row*nsquare+col] = entry+1 + solution[row * nsquare + col] = entry + 1 yield solution else: yield None diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index af3935741b8..c28d84aebcc 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -3184,10 +3184,10 @@ def primitive_collections(self): pass def is_not_facet(I): - return all(not(I <= f) for f in facets) + return all(not (I <= f) for f in facets) def is_in_SR(I): - return all(not(I >= sr) for sr in SR) + return all(not (I >= sr) for sr in SR) # Generators of SR are index sets I = {i1, ..., ik} # called "primitive collections" such that diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index 6168e033670..45c8efb11ed 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -1474,7 +1474,7 @@ def intersection(self, other): UHP = self.model() # Both geodesic need to be UHP geodesics for this to work - if(other.model() != UHP): + if other.model() != UHP: other = other.to_model(UHP) # Get endpoints and ideal endpoints i_start_1, i_end_1 = sorted(self.ideal_endpoints(), key=str) diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py index 0d3446d0efa..6ae2e260aac 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py @@ -299,8 +299,8 @@ def _richcmp_(self, other, op): sage: p1 == p2 True """ - if not(isinstance(other, HyperbolicPoint) - or self.parent() is other.parent()): + if not (isinstance(other, HyperbolicPoint) + or self.parent() is other.parent()): return op == op_NE # bool is required to convert symbolic (in)equalities return bool(richcmp(self._coordinates, other._coordinates, op)) diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index 0b85c4f944c..d2d46bb41fc 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -1170,7 +1170,7 @@ def simplicity(self): ... NotImplementedError: this function is implemented for polytopes only """ - if not(self.is_compact()): + if not self.is_compact(): raise NotImplementedError("this function is implemented for polytopes only") return self.combinatorial_polyhedron().simplicity() @@ -1221,7 +1221,7 @@ def simpliciality(self): ... NotImplementedError: this function is implemented for polytopes only """ - if not(self.is_compact()): + if not self.is_compact(): raise NotImplementedError("this function is implemented for polytopes only") return self.combinatorial_polyhedron().simpliciality() @@ -1260,7 +1260,7 @@ def is_simplicial(self): ... NotImplementedError: this function is implemented for polytopes only """ - if not(self.is_compact()): + if not self.is_compact(): raise NotImplementedError("this function is implemented for polytopes only") return self.combinatorial_polyhedron().is_simplicial() diff --git a/src/sage/geometry/pseudolines.py b/src/sage/geometry/pseudolines.py index 642a5c4b8aa..ed27f598a9e 100644 --- a/src/sage/geometry/pseudolines.py +++ b/src/sage/geometry/pseudolines.py @@ -510,4 +510,4 @@ def __ne__(self, other): sage: p1 != p2 False """ - return not(self == other) + return not (self == other) diff --git a/src/sage/groups/abelian_gps/abelian_group_morphism.py b/src/sage/groups/abelian_gps/abelian_group_morphism.py index 400283827b1..718a0d50f57 100644 --- a/src/sage/groups/abelian_gps/abelian_group_morphism.py +++ b/src/sage/groups/abelian_gps/abelian_group_morphism.py @@ -81,38 +81,38 @@ class AbelianGroupMorphism(Morphism): #Traceback (most recent call last): # File "", line 1, in ? # File ".abeliangp_hom.sage.py", line 737, in __init__ -# raise TypeError, "Sorry, the orders of the corresponding elements in %s, %s must be equal."%(genss,imgss) -#TypeError: Sorry, the orders of the corresponding elements in [a*b, a*c], [x, y] must be equal. +# raise TypeError("the orders of the corresponding elements in %s, %s must be equal" % (genss,imgss)) +#TypeError: the orders of the corresponding elements in [a*b, a*c], [x, y] must be equal # # sage: phi = AbelianGroupMorphism_im_gens(G,H,[a*b,(a*c)^2],[x*y,y]) #------------------------------------------------------------ #Traceback (most recent call last): # File "", line 1, in ? # File ".abeliangp_hom.sage.py", line 730, in __init__ -# raise TypeError, "Sorry, the list %s must generate G."%genss -#TypeError: Sorry, the list [a*b, c^2] must generate G. +# raise TypeError("the list %s must generate G" % genss) +#TypeError: the list [a*b, c^2] must generate G def __init__(self, G, H, genss, imgss): from sage.categories.homset import Hom Morphism.__init__(self, Hom(G, H)) if len(genss) != len(imgss): - raise TypeError("Sorry, the lengths of %s, %s must be equal." % (genss, imgss)) + raise TypeError("the lengths of %s, %s must be equal" % (genss, imgss)) self._domain = G self._codomain = H - if not(G.is_abelian()): - raise TypeError("Sorry, the groups must be abelian groups.") - if not(H.is_abelian()): - raise TypeError("Sorry, the groups must be abelian groups.") + if not G.is_abelian(): + raise TypeError("the groups must be abelian groups") + if not H.is_abelian(): + raise TypeError("the groups must be abelian groups") G_domain = G.subgroup(genss) if G_domain.order() != G.order(): - raise TypeError("Sorry, the list %s must generate G." % genss) + raise TypeError("the list %s must generate G" % genss) # self.domain_invs = G.gens_orders() # self.codomaininvs = H.gens_orders() self.domaingens = genss self.codomaingens = imgss for i in range(len(self.domaingens)): if (self.domaingens[i]).order() != (self.codomaingens[i]).order(): - raise TypeError("Sorry, the orders of the corresponding elements in %s, %s must be equal." % (genss, imgss)) + raise TypeError("the orders of the corresponding elements in %s, %s must be equal" % (genss, imgss)) def _libgap_(self): """ diff --git a/src/sage/groups/abelian_gps/dual_abelian_group.py b/src/sage/groups/abelian_gps/dual_abelian_group.py index df2b51e0d57..46e151e7fd2 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group.py @@ -380,8 +380,8 @@ def list(self): sage: Gd.list() (1, B, B^2, A, A*B, A*B^2) """ - if not(self.is_finite()): - raise NotImplementedError("Group must be finite") + if not self.is_finite(): + raise NotImplementedError("the group must be finite") invs = self.gens_orders() return tuple(self(t) for t in mrange(invs)) diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index 295d43aa1d2..8f9a15bbecf 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -487,7 +487,7 @@ def burau_matrix(self, root_bur = None, domain = None, characteristic = None, va def find_root(domain): min_pol = min_pol_root_bur.change_ring(domain) root_list = min_pol.roots() - if not(root_list): + if not root_list: domain = min_pol.splitting_field(min_pol_root_bur.variable_name()) min_pol = min_pol_root_bur.change_ring(domain) root_list = min_pol.roots() diff --git a/src/sage/groups/free_group.py b/src/sage/groups/free_group.py index 2846028b5e7..0c51deafc64 100644 --- a/src/sage/groups/free_group.py +++ b/src/sage/groups/free_group.py @@ -149,13 +149,14 @@ def _lexi_gen(zeroes=False): count = Integer(0) while True: mwrap, ind = count.quo_rem(26) - if mwrap == 0 and not(zeroes): + if mwrap == 0 and not zeroes: name = '' else: name = str(mwrap) name = chr(ord('a') + ind) + name yield name - count = count + 1 + count += 1 + class FreeGroupElement(ElementLibGAP): """ diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index b3e3d491620..8cea6a6ef66 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -541,7 +541,7 @@ def __richcmp__(self, other, op): except (AttributeError, NotImplementedError): return richcmp(id(self), id(other), op) - assert(n_self == n_other) + assert n_self == n_other for g, h in zip(self_gens, other_gens): lx = g.matrix() rx = h.matrix() diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 49089346995..c065ebd6d3d 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -4190,7 +4190,7 @@ def is_normal(self, other): sage: H.is_normal(G) False """ - if not(self.is_subgroup(other)): + if not self.is_subgroup(other): raise TypeError("%s must be a subgroup of %s" % (self, other)) return bool(other._libgap_().IsNormal(self)) diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 43e47f7574e..d5078f03b40 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -1745,7 +1745,7 @@ def __init__(self, n): """ n = Integer(n) self._n = n - if not(n in [9, 10, 11, 12, 21, 22, 23, 24]): + if n not in [9, 10, 11, 12, 21, 22, 23, 24]: raise ValueError("argument must belong to {9, 10, 11, 12, 21, 22, 23, 24}") id = 'MathieuGroup(%s)' % n PermutationGroup_generic.__init__(self, gap_group=id) @@ -2702,7 +2702,7 @@ def __init__(self, n, q, name='a'): if q in FiniteFields(): name = q.gen() q = q.cardinality() - if not(q in NonNegativeIntegers()): + if q not in NonNegativeIntegers(): raise ValueError('q must be a prime power or a finite field') if n == 1: id = 'Group([()])' diff --git a/src/sage/homology/chain_complex.py b/src/sage/homology/chain_complex.py index 99fa87c9751..b879ac9c7eb 100644 --- a/src/sage/homology/chain_complex.py +++ b/src/sage/homology/chain_complex.py @@ -1154,7 +1154,7 @@ def _homology_chomp(self, deg, base_ring, verbose, generators): # one has to complete the answer of chomp result = H for idx in self.nonzero_degrees(): - if not(idx in H): + if idx not in H: result[idx] = HomologyGroup(0, base_ring) return result if deg in H: diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index dee071c736b..5658983af40 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -1092,7 +1092,7 @@ def __getitem__(self, n): raise else: n += l - if not(0 <= n < l): + if not (0 <= n < l): raise IndexError("index out of range") # use "elt" instead of "." here because then the error # message is clearer diff --git a/src/sage/interfaces/latte.py b/src/sage/interfaces/latte.py index ecb59e9ac77..4c6d8e9f061 100644 --- a/src/sage/interfaces/latte.py +++ b/src/sage/interfaces/latte.py @@ -409,7 +409,7 @@ def integrate(arg, polynomial=None, algorithm='triangulate', raw_output=False, v ans = bytes_to_str(ans) ans = ans.splitlines() ans = ans[-5].split() - assert(ans[0]=='Answer:') + assert ans[0] == 'Answer:' ans = ans[1] tempd.cleanup() diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index ecfa7af38b4..e772ede1101 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -1691,29 +1691,29 @@ def max_to_sr(expr): op_max=caar(expr) if op_max in special_max_to_sage: return special_max_to_sage[op_max](expr) - if not(op_max in max_op_dict): + if op_max not in max_op_dict: op_max_str = maxprint(op_max).python()[1:-1] if op_max_str in max_to_pynac_table: # nargs ? op = max_to_pynac_table[op_max_str] else: # This could be unsafe if the conversion to SR # changes the structure of expr - sage_expr=SR(maxima(expr)) - op=sage_expr.operator() + sage_expr = SR(maxima(expr)) + op = sage_expr.operator() if op in sage_op_dict: raise RuntimeError("Encountered operator mismatch in maxima-to-sr translation") max_op_dict[op_max]=op sage_op_dict[op]=op_max else: - op=max_op_dict[op_max] - max_args=cdr(expr) - args=[max_to_sr(a) for a in max_args] + op = max_op_dict[op_max] + max_args = cdr(expr) + args = [max_to_sr(a) for a in max_args] return op(*args) elif expr.symbolp(): - if not(expr in max_sym_dict): - sage_symbol=SR(maxima(expr)) - sage_sym_dict[sage_symbol]=expr - max_sym_dict[expr]=sage_symbol + if expr not in max_sym_dict: + sage_symbol = SR(maxima(expr)) + sage_sym_dict[sage_symbol] = expr + max_sym_dict[expr] = sage_symbol return max_sym_dict[expr] else: e = expr.python() diff --git a/src/sage/interfaces/povray.py b/src/sage/interfaces/povray.py index 880c5fecbcd..b892cb112cd 100644 --- a/src/sage/interfaces/povray.py +++ b/src/sage/interfaces/povray.py @@ -37,7 +37,7 @@ def __call__(self, pov_file, outfile='sage.ppm', block=True, **kwargs): outfile = os.path.abspath(os.path.expanduser(outfile)) - if not('W' in kwargs and 'H' in kwargs): + if not ('W' in kwargs and 'H' in kwargs): return "You must specify a width and height." cmd = "povray -D +FP +I%s +O%s " % (pov_file, outfile) diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index 549877b392d..934b396e162 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -687,7 +687,7 @@ def _update_command_info(): cache = {} with open(os.path.join(SAGE_LOCAL, 'share/qepcad', 'qepcad.help')) as help: - assert(help.readline().strip() == '@') + assert help.readline().strip() == '@' while True: cmd_line = help.readline() @@ -698,7 +698,7 @@ def _update_command_info(): break (cmd, id, phases, kind) = cmd_line.split() - assert(help.readline().strip() == '@') + assert help.readline().strip() == '@' help_text = '' help_line = help.readline() @@ -2451,8 +2451,8 @@ def __init__(self, parent, lines): saw_signs = True if saw_signs and 'Level' in line: (lev, n, colon, signs) = line.split() - assert(lev == 'Level' and colon == ':') - assert(int(n) == len(all_signs) + 1) + assert lev == 'Level' and colon == ':' + assert int(n) == len(all_signs) + 1 signs = signs.replace('+','1').replace('-','-1').replace(')',',)') all_signs.append(sage_eval(signs)) if 'PRIMITIVE' in line: @@ -2465,13 +2465,13 @@ def __init__(self, parent, lines): if 'Coordinate ' in line: (coord_n, val) = line.split('=') n = int(coord_n.split()[1]) - assert(n == len(all_coordinates) + 1) + assert n == len(all_coordinates) + 1 if n == self._level and saw_extended: grab_extended = True else: all_coordinates.append(val) elif grab_extended: - assert('=' in line) + assert '=' in line grab_extended = False all_coordinates.append(line.split('=')[1]) diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index 72ecdb80473..10035f729ef 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -3759,7 +3759,7 @@ def _knotinfo_matching_list(self): # note that KnotInfo pd_notation works counter clockwise. Therefore, # to compensate this we compare with the mirrored pd_code. See also, # docstring of :meth:`link` of :class:`~sage.knots.knotinfo.KnotInfoBase`. - return[L], True # pd_notation is unique in the KnotInfo database + return [L], True # pd_notation is unique in the KnotInfo database if L.braid_index() <= br_ind: if self._markov_move_cmp(L.braid()): diff --git a/src/sage/symbolic/subring.py b/src/sage/symbolic/subring.py index 0bf7a182587..e962c88ce2c 100644 --- a/src/sage/symbolic/subring.py +++ b/src/sage/symbolic/subring.py @@ -356,7 +356,7 @@ def _element_constructor_(self, x): TypeError: x is not contained in Symbolic Subring accepting the variable a """ expression = super()._element_constructor_(x) - assert(expression.parent() is self) + assert expression.parent() is self if not all(self.has_valid_variable(var) for var in expression.variables()): raise TypeError('%s is not contained in %s' % (x, self)) From 945de29b5be9c7bb3da86b306e36f284bae11103 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 14 Aug 2022 18:25:08 -0700 Subject: [PATCH 398/591] .devcontainer: Reduce parallelism to 4 --- .devcontainer/develop-docker-cocalc/devcontainer.json | 2 +- .devcontainer/develop-docker-computop/devcontainer.json | 2 +- .devcontainer/downstream-docker-cocalc/devcontainer.json | 2 +- .devcontainer/downstream-docker-computop/devcontainer.json | 2 +- .../devcontainer.json | 2 +- .../portability-ubuntu-jammy-standard/devcontainer.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.devcontainer/develop-docker-cocalc/devcontainer.json b/.devcontainer/develop-docker-cocalc/devcontainer.json index 47a5a682dff..20455fcebe1 100644 --- a/.devcontainer/develop-docker-cocalc/devcontainer.json +++ b/.devcontainer/develop-docker-cocalc/devcontainer.json @@ -3,7 +3,7 @@ "name": "CoCalc Docker", "image": "sagemathinc/cocalc", "containerEnv": { - "MAKE": "make -j12" + "MAKE": "make -j4" }, // Run commands after the container is created. // libgmp.a is broken and leads to a build failure of ecm. diff --git a/.devcontainer/develop-docker-computop/devcontainer.json b/.devcontainer/develop-docker-computop/devcontainer.json index 639fc9543a4..9754febbc22 100644 --- a/.devcontainer/develop-docker-computop/devcontainer.json +++ b/.devcontainer/develop-docker-computop/devcontainer.json @@ -3,7 +3,7 @@ "name": "computop/sage Docker", "image": "computop/sage", "containerEnv": { - "MAKE": "make -j12" + "MAKE": "make -j4" }, // Run commands after the container is created. // Install build tools, get rid of sourcing /sage/activate in non-login shells. diff --git a/.devcontainer/downstream-docker-cocalc/devcontainer.json b/.devcontainer/downstream-docker-cocalc/devcontainer.json index d77f5f71df5..a7ec23682a8 100644 --- a/.devcontainer/downstream-docker-cocalc/devcontainer.json +++ b/.devcontainer/downstream-docker-cocalc/devcontainer.json @@ -3,7 +3,7 @@ "name": "CoCalc Docker", "image": "sagemathinc/cocalc", "containerEnv": { - "MAKE": "make -j12" + "MAKE": "make -j4" }, // Run commands after the container is created. // libgmp.a is broken and leads to a build failure of ecm. diff --git a/.devcontainer/downstream-docker-computop/devcontainer.json b/.devcontainer/downstream-docker-computop/devcontainer.json index 0f9ba0b8841..bcf7f2e3cfe 100644 --- a/.devcontainer/downstream-docker-computop/devcontainer.json +++ b/.devcontainer/downstream-docker-computop/devcontainer.json @@ -3,7 +3,7 @@ "name": "computop/sage Docker", "image": "computop/sage", "containerEnv": { - "MAKE": "make -j12" + "MAKE": "make -j4" }, // Run commands after the container is created. // Install build tools, get rid of sourcing /sage/activate in non-login shells. diff --git a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json index 4a97fb3cb2c..eb416d68c85 100644 --- a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json +++ b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json @@ -11,7 +11,7 @@ } }, "containerEnv": { - "MAKE": "make -j12" + "MAKE": "make -j4" }, // Run commands after the container is created. "postCreateCommand": ".devcontainer/post_create.sh", diff --git a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json index 1ce79588c26..80fdc0de1b3 100644 --- a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +++ b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json @@ -11,7 +11,7 @@ } }, "containerEnv": { - "MAKE": "make -j12" + "MAKE": "make -j4" }, // Run commands after the container is created. "postCreateCommand": ".devcontainer/post_create.sh", From a98ef7d0328f51e0421bc8ef5f8972839f14340a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 15 Aug 2022 08:21:43 +0200 Subject: [PATCH 399/591] modernize super in numerical,plot,repl,topology --- src/sage/numerical/interactive_simplex_method.py | 12 ++++++------ src/sage/numerical/linear_functions.pyx | 2 +- src/sage/numerical/linear_tensor_constraints.py | 2 +- src/sage/numerical/sdp.pyx | 2 +- src/sage/plot/arrow.py | 2 +- src/sage/plot/colors.py | 4 ++-- src/sage/repl/display/formatter.py | 4 ++-- src/sage/repl/display/pretty_print.py | 4 ++-- src/sage/repl/interpreter.py | 8 ++++---- src/sage/repl/ipython_kernel/interact.py | 8 ++++---- src/sage/repl/ipython_kernel/kernel.py | 2 +- src/sage/repl/ipython_kernel/widgets.py | 4 ++-- src/sage/repl/rich_output/preferences.py | 4 ++-- src/sage/topology/simplicial_complex_examples.py | 4 +--- 14 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index 3bbc044ccab..0210d9aea87 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -641,7 +641,7 @@ def __init__(self, A, b, c, x="x", sage: P = InteractiveLPProblem(A, b, c, ["C", "B"], variable_type=">=") sage: TestSuite(P).run() """ - super(InteractiveLPProblem, self).__init__() + super().__init__() A = matrix(A) b = vector(b) c = vector(c) @@ -1973,7 +1973,7 @@ def __init__(self, A, b, c, x="x", problem_type="max", if problem_type not in ("max", "-max"): raise ValueError("problems in standard form must be of (negative) " "maximization type") - super(InteractiveLPProblemStandardForm, self).__init__( + super().__init__( A, b, c, x, problem_type=problem_type, constraint_type="<=", @@ -2733,7 +2733,7 @@ def __init__(self): sage: P = InteractiveLPProblemStandardForm(A, b, c) sage: D = P.initial_dictionary() # indirect doctest """ - super(LPAbstractDictionary, self).__init__() + super().__init__() self._entering = None self._leaving = None @@ -3892,7 +3892,7 @@ def __init__(self, A, b, c, objective_value, sage: D = LPDictionary(A, b, c, 0, R.gens()[2:], R.gens()[:2], "z") sage: TestSuite(D).run() """ - super(LPDictionary, self).__init__() + super().__init__() # We are going to change stuff while InteractiveLPProblem has immutable data. A = copy(A) b = copy(b) @@ -4503,7 +4503,7 @@ def __init__(self, problem, basic_variables): if problem.auxiliary_variable() == problem.decision_variables()[0]: raise ValueError("revised dictionaries should not be constructed " "for auxiliary problems") - super(LPRevisedDictionary, self).__init__() + super().__init__() self._problem = problem R = problem.coordinate_ring() self._x_B = vector(R, [variable(R, v) for v in basic_variables]) @@ -4706,7 +4706,7 @@ def _preupdate_output(self, direction): \end{equation*} """ return HtmlFragment("\n".join([ - super(LPRevisedDictionary, self)._preupdate_output(direction), + super()._preupdate_output(direction), r"\begin{equation*}", r"B_\mathrm{new}^{-1} = E^{-1} B_\mathrm{old}^{-1} = ", latex(self.E_inverse()), diff --git a/src/sage/numerical/linear_functions.pyx b/src/sage/numerical/linear_functions.pyx index d35272b6f3f..a5c0c0336d0 100644 --- a/src/sage/numerical/linear_functions.pyx +++ b/src/sage/numerical/linear_functions.pyx @@ -1427,7 +1427,7 @@ cdef class LinearConstraint(LinearFunctionOrConstraint): x_0 + 2*x_1 <= -5 + x_2 """ assert len(terms) > 0 - super(LinearConstraint, self).__init__(parent) + super().__init__(parent) self.equality = equality LF = parent.linear_functions_parent() self.constraints = [ LF(term) for term in terms ] diff --git a/src/sage/numerical/linear_tensor_constraints.py b/src/sage/numerical/linear_tensor_constraints.py index fb44e669637..ce09731cc6e 100644 --- a/src/sage/numerical/linear_tensor_constraints.py +++ b/src/sage/numerical/linear_tensor_constraints.py @@ -160,7 +160,7 @@ def __init__(self, parent, lhs, rhs, equality): sage: b[2] * vector([1,2]) + 2*b[3] <= 0 (1.0, 2.0)*x_0 + (2.0, 2.0)*x_1 <= (0.0, 0.0) """ - super(LinearTensorConstraint, self).__init__(parent) + super().__init__(parent) self._lhs = lhs self._rhs = rhs self._equality = equality diff --git a/src/sage/numerical/sdp.pyx b/src/sage/numerical/sdp.pyx index dc04e26a06b..207298d7ece 100644 --- a/src/sage/numerical/sdp.pyx +++ b/src/sage/numerical/sdp.pyx @@ -1237,7 +1237,7 @@ cdef class SDPVariable(Element): sage: p.new_variable() SDPVariable """ - super(SDPVariable, self).__init__(parent) + super().__init__(parent) self._dict = {} self._p = sdp self._name = name diff --git a/src/sage/plot/arrow.py b/src/sage/plot/arrow.py index a332b0578c5..13b3b07d241 100644 --- a/src/sage/plot/arrow.py +++ b/src/sage/plot/arrow.py @@ -426,7 +426,7 @@ def __init__(self, condition_func, pe_list): path effect that is only applied when the condition_func returns True. """ - super(ConditionalStroke, self).__init__() + super().__init__() self._pe_list = pe_list self._condition_func = condition_func diff --git a/src/sage/plot/colors.py b/src/sage/plot/colors.py index e3f54f53277..bc89be406ea 100644 --- a/src/sage/plot/colors.py +++ b/src/sage/plot/colors.py @@ -1123,7 +1123,7 @@ def __dir__(self): True """ methods = ['__dir__', '__getattr__'] - return dir(super(ColorsDict, self)) + methods + sorted(self) + return dir(super()) + methods + sorted(self) colors = ColorsDict() @@ -1482,7 +1482,7 @@ def __dir__(self): methods = ['load_maps', '__dir__', '__len__', '__iter__', '__contains__', '__getitem__', '__getattr__', '__setitem__', '__delitem__'] - return dir(super(Colormaps, self)) + methods + sorted(self) + return dir(super()) + methods + sorted(self) def __len__(self): """ diff --git a/src/sage/repl/display/formatter.py b/src/sage/repl/display/formatter.py index adde08d27d2..2910fb8ee19 100644 --- a/src/sage/repl/display/formatter.py +++ b/src/sage/repl/display/formatter.py @@ -100,7 +100,7 @@ def __init__(self, *args, **kwds): ... RuntimeError: check failed: current backend is invalid """ - super(SageDisplayFormatter, self).__init__(*args, **kwds) + super().__init__(*args, **kwds) from sage.repl.rich_output.display_manager import get_display_manager self.dm = get_display_manager() from sage.repl.rich_output.backend_ipython import BackendIPython @@ -277,7 +277,7 @@ def __init__(self, *args, **kwds): sage: shell.quit() """ - super(SagePlainTextFormatter, self).__init__(*args, **kwds) + super().__init__(*args, **kwds) def __call__(self, obj): r""" diff --git a/src/sage/repl/display/pretty_print.py b/src/sage/repl/display/pretty_print.py index 804115051ed..ec2aefbd7ad 100644 --- a/src/sage/repl/display/pretty_print.py +++ b/src/sage/repl/display/pretty_print.py @@ -105,8 +105,8 @@ def __init__(self, output, max_width, newline, max_seq_length=None): sage: foo """ - super(SagePrettyPrinter, self).__init__( - output, max_width, newline, max_seq_length=max_seq_length) + super().__init__(output, max_width, newline, + max_seq_length=max_seq_length) self.stack = [] def pretty(self, obj): diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index d7ba014361d..fe4cff3add5 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -229,7 +229,7 @@ def system_raw(self, cmd): 0 sage: shell.quit() """ - return super(SageShellOverride, self).system_raw(cmd) + return super().system_raw(cmd) class SageNotebookInteractiveShell(SageShellOverride, InteractiveShell): @@ -387,7 +387,7 @@ def run_cell(self, *args, **kwds): True sage: shell.quit() """ - super(SageTestShell, self).run_cell(*args, **kwds) + super().run_cell(*args, **kwds) ################################################################### @@ -480,7 +480,7 @@ def __init__(self, *args, **kwds): sage: ift._sage_import_re.findall('sage(a) + maxima(b)') ['sage(', 'maxima('] """ - super(InterfaceShellTransformer, self).__init__(*args, **kwds) + super().__init__(*args, **kwds) self.temporary_objects = set() self._sage_import_re = re.compile(r'(?:sage|%s)\(' % self.shell.interface.name()) @@ -739,7 +739,7 @@ def load_config_file(self, *args, **kwds): sage: SageTerminalApp().load_config_file() sage: os.environ['IPYTHONDIR'] = IPYTHONDIR """ - super(SageTerminalApp, self).load_config_file(*args, **kwds) + super().load_config_file(*args, **kwds) newconfig = sage_ipython_config.default() # merge in the config loaded from file newconfig.merge(self.config) diff --git a/src/sage/repl/ipython_kernel/interact.py b/src/sage/repl/ipython_kernel/interact.py index 9b94bc4d9b3..4a6960ece3a 100644 --- a/src/sage/repl/ipython_kernel/interact.py +++ b/src/sage/repl/ipython_kernel/interact.py @@ -123,7 +123,7 @@ def __init__(self, *args, **kwds): options["manual"] = (p_auto_update.default is False) self.__signature = sig.replace(parameters=params.values()) - super(sage_interactive, self).__init__(f, options, **kwds) + super().__init__(f, options, **kwds) if self.manual: # In Sage, manual interacts are always run once self.on_displayed(self.update) @@ -197,7 +197,7 @@ def widget_from_single_value(cls, abbrev, *args, **kwds): if isinstance(abbrev, Color): return SageColorPicker(value=abbrev.html_color()) # Get widget from IPython if possible - widget = super(sage_interactive, cls).widget_from_single_value(abbrev, *args, **kwds) + widget = super().widget_from_single_value(abbrev, *args, **kwds) if widget is not None or isinstance(abbrev, Iterable): return widget # If IPython didn't construct a widget and the abbrev is not an @@ -255,7 +255,7 @@ def n(x): else: return x abbrev = tuple(n(x) for x in abbrev) - return super(sage_interactive, cls).widget_from_tuple(abbrev, *args, **kwds) + return super().widget_from_tuple(abbrev, *args, **kwds) @classmethod # Behaves like a staticmethod, but we need super() def widget_from_iterable(cls, abbrev, *args, **kwds): @@ -283,7 +283,7 @@ def widget_from_iterable(cls, abbrev, *args, **kwds): """ if isinstance(abbrev, Iterator): return SelectionSlider(options=list(abbrev)) - return super(sage_interactive, cls).widget_from_iterable(abbrev, *args, **kwds) + return super().widget_from_iterable(abbrev, *args, **kwds) # @interact decorator diff --git a/src/sage/repl/ipython_kernel/kernel.py b/src/sage/repl/ipython_kernel/kernel.py index e38fc522a72..a4642014e90 100644 --- a/src/sage/repl/ipython_kernel/kernel.py +++ b/src/sage/repl/ipython_kernel/kernel.py @@ -48,7 +48,7 @@ def __init__(self, **kwds): sage: SageKernel.__new__(SageKernel) """ - super(SageKernel, self).__init__(**kwds) + super().__init__(**kwds) SageJupyterCustomizations(self.shell) @property diff --git a/src/sage/repl/ipython_kernel/widgets.py b/src/sage/repl/ipython_kernel/widgets.py index dfe126a2760..3ba45df9b04 100644 --- a/src/sage/repl/ipython_kernel/widgets.py +++ b/src/sage/repl/ipython_kernel/widgets.py @@ -118,7 +118,7 @@ def __init__(self, *args, **kwds): <... 'dict'> """ self.__transform = kwds.pop("transform", None) - return super(TransformWidget, self).__init__(*args, **kwds) + return super().__init__(*args, **kwds) def get_value(self): """ @@ -412,7 +412,7 @@ def __init__(self, nrows, ncols, make_widget, description=u"", transform=None): """ if nrows < 1 or ncols < 1: raise ValueError("Grid requires a positive number of rows and columns") - super(Grid, self).__init__(transform=transform) + super().__init__(transform=transform) label = Label(description) link((label, "value"), (self, "description")) diff --git a/src/sage/repl/rich_output/preferences.py b/src/sage/repl/rich_output/preferences.py index 410ee7322da..f26962dc29b 100644 --- a/src/sage/repl/rich_output/preferences.py +++ b/src/sage/repl/rich_output/preferences.py @@ -106,8 +106,8 @@ def __init__(self, name, allowed_values, doc=None): self.underscore_name = '_{0}'.format(name) self.allowed_values = tuple(allowed_values) self.__doc__ = doc = self._make_doc(doc) - super(Property, self).__init__( - fget=self.getter, fset=self.setter, fdel=self.deleter, doc=doc) + super().__init__(fget=self.getter, fset=self.setter, + fdel=self.deleter, doc=doc) def _make_doc(self, doc): """ diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index e9068b7713d..037a8b5b89d 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -242,9 +242,7 @@ def __classcall__(self, maximal_faces=None, name=None, **kwds): maximal_faces = C.facets() # Now convert maximal_faces to a tuple of tuples, so that it is hashable. maximal_faces = tuple(tuple(mf) for mf in maximal_faces) - return super(UniqueSimplicialComplex, self).__classcall__(self, maximal_faces, - name=name, - **kwds) + return super().__classcall__(self, maximal_faces, name=name, **kwds) def __init__(self, maximal_faces=None, name=None, **kwds): """ From 16b8c4d5dd038d69455f0f2567c26195ceac7f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 15 Aug 2022 09:12:18 +0200 Subject: [PATCH 400/591] remove inheritance of object in sage_docbuild --- src/sage_docbuild/builders.py | 8 ++++---- src/sage_docbuild/ext/sage_autodoc.py | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index c5be38600ad..fcb49cbb167 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -182,7 +182,7 @@ def f(self, *args, **kwds): return f -class DocBuilder(object): +class DocBuilder(): def __init__(self, name, lang='en'): """ INPUT: @@ -345,7 +345,7 @@ def build_other_doc(args): getattr(get_builder(document), name)(*args, **kwds) -class AllBuilder(object): +class AllBuilder(): """ A class used to build all of the documentation. """ @@ -863,10 +863,10 @@ def get_sphinx_environment(self): """ Return the Sphinx environment for this project. """ - class FakeConfig(object): + class FakeConfig(): values = tuple() - class FakeApp(object): + class FakeApp(): def __init__(self, dir): self.srcdir = dir self.config = FakeConfig() diff --git a/src/sage_docbuild/ext/sage_autodoc.py b/src/sage_docbuild/ext/sage_autodoc.py index 39a198e88a6..5b97b272718 100644 --- a/src/sage_docbuild/ext/sage_autodoc.py +++ b/src/sage_docbuild/ext/sage_autodoc.py @@ -130,7 +130,7 @@ def formatargspec(function, args, varargs=None, varkw=None, defaults=None, annotations=annotations) -class AutodocReporter(object): +class AutodocReporter(): """ A reporter replacement that assigns the correct source name and line number to a system message, as recorded in a ViewList. @@ -246,9 +246,7 @@ def process(app, what_, name, obj, options, lines): return process - - -class Documenter(object): +class Documenter(): """ A Documenter knows how to autodocument a single object type. When registered with the AutoDirective, it will be used to document objects @@ -988,7 +986,7 @@ def resolve_name(self, modname, parents, path, base): return modname, parents + [base] -class DocstringSignatureMixin(object): +class DocstringSignatureMixin(): """ Mixin for FunctionDocumenter and MethodDocumenter to provide the feature of reading the signature from the docstring. @@ -1175,7 +1173,7 @@ def import_object(self): # __name__ of the nested class. For example, in # # class A(metaclass=NestedMetaclass): - # class B(object): + # class B(): # pass # # the class B get its name changed to 'A.B'. Such dots '.' in names From b29dfa784916838ec3f21ad26db340bf5602b190 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 15 Aug 2022 07:37:06 -0700 Subject: [PATCH 401/591] .devcontainer/downstream-docker-sagemath: Remove --- .../downstream-docker-sagemath/devcontainer.json | 14 -------------- src/doc/en/developer/portability_testing.rst | 7 +------ 2 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 .devcontainer/downstream-docker-sagemath/devcontainer.json diff --git a/.devcontainer/downstream-docker-sagemath/devcontainer.json b/.devcontainer/downstream-docker-sagemath/devcontainer.json deleted file mode 100644 index a235bab1f2f..00000000000 --- a/.devcontainer/downstream-docker-sagemath/devcontainer.json +++ /dev/null @@ -1,14 +0,0 @@ -// See https://aka.ms/devcontainer.json for format details. -{ - "name": "sagemath/sagemath Docker", - "image": "sagemath/sagemath:develop", - // Run commands after the container is created. - // Install build tools. - "postCreateCommand": ".devcontainer/post_create.sh --sudo" - // Run commands after the container is started. - // Do not run configure within a sage-env (see #29485). - "postStartCommand": "if [ -d pkgs/sagemath-standard ]; then ln -sf /home/sage/sage/venv venv && ln -sf /home/sage/sage/local prefix; else echo 'Edit .devcontainer/devcontainer.json (postStartCommand) to run project-specific startup commands'; fi", - "extensions": [ - "ms-python.python" - ] -} diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index a46d4f88eed..23eb5b1bdf9 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1239,8 +1239,7 @@ Files named ``$SAGE_ROOT/.devcontainer/downstream-.../devcontainer.json`` config containers with an installation of downstream packages providing SageMath from a package manager (``downstream-archlinux-...``, ``downstream-conda-forge``; see also `the _sagemath dummy package <../reference/spkg/_sagemath.html>`_), -or from a public Docker image that provides SageMath (``docker-sagemath``, -``docker-cocalc``, ``docker-computop``). +or from a public Docker image that provides SageMath (``docker-cocalc``, ``docker-computop``). These ``devcontainer.json`` configuration files are useful for testing user scripts on these deployments of SageMath. You may also find it useful to copy these configurations into your own projects (they should @@ -1257,10 +1256,6 @@ work without change) or to adapt them to your needs. `_ similarly configures a container with an installation of conda-forge and its SageMath package. -- `downstream-docker-sagemath/devcontainer.json - `_ - configures a container with `SageMath's official Docker image `_. - - `downstream-docker-cocalc/devcontainer.json `_ configures a container with `the CoCalc Docker image `_. From 4aaedd72d4d5eea9cc98c2aa8754cb666334a4c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 15 Aug 2022 08:02:58 -0700 Subject: [PATCH 402/591] README.md, src/doc/en/installation/index.rst: Mention sagemathinc/cocalc instead of sagemath/sagemath --- README.md | 6 +----- src/doc/en/installation/index.rst | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fd467aa85f8..539a73d1c05 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,7 @@ mailing list](https://groups.google.com/group/sage-devel). Docker Images ------------- -You can also have a look at our Docker images to run Sage. -To use these images, -[install Docker](https://www.docker.com/community-edition#/download) -and follow the instructions on -[our Docker Hub page](https://hub.docker.com/r/sagemath/sagemath/). +SageMath is also available through the [Docker image sagemathinc/cocalc](https://hub.docker.com/r/sagemathinc/cocalc). [Windows] Preparing the Platform -------------------------------- diff --git a/src/doc/en/installation/index.rst b/src/doc/en/installation/index.rst index 6a0b439ac66..e630ae38be3 100644 --- a/src/doc/en/installation/index.rst +++ b/src/doc/en/installation/index.rst @@ -131,7 +131,7 @@ In the cloud many other tools. - On any system that allows you to bring your own Docker images to run in - a container: Use the `Docker image sagemath/sagemath `_. + a container: Use the `Docker image sagemathinc/cocalc `_. - `Sage Cell Server `_: an online service for elementary SageMath computations. From 34252a9f939c715ae7b01092eebc2a0775876327 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Mon, 15 Aug 2022 14:25:07 -0400 Subject: [PATCH 403/591] sage/modular/modform/element.py: apply pycodestyle coding conventions --- src/sage/modular/modform/element.py | 151 +++++++++++++--------------- 1 file changed, 72 insertions(+), 79 deletions(-) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 90043b2bb12..26d4a053fda 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -129,7 +129,6 @@ def delta_lseries(prec=53, max_imaginary_part=0, raise ValueError('algorithm must be "gp" or "pari"') - class ModularForm_abstract(ModuleElement): """ Constructor for generic class of a modular form. This @@ -186,7 +185,7 @@ def is_homogeneous(self): True """ return True - is_modular_form = is_homogeneous #alias + is_modular_form = is_homogeneous # alias def _repr_(self): """ @@ -333,23 +332,23 @@ def coefficients(self, X): sage: f = EisensteinForms(e, 3).eisenstein_series()[0] sage: f.coefficients([0,1]) [15/11*zeta10^3 - 9/11*zeta10^2 - 26/11*zeta10 - 10/11, - 1] + 1] sage: f.coefficients([0,1,2,3]) [15/11*zeta10^3 - 9/11*zeta10^2 - 26/11*zeta10 - 10/11, - 1, - 4*zeta10 + 1, - -9*zeta10^3 + 1] + 1, + 4*zeta10 + 1, + -9*zeta10^3 + 1] sage: f.coefficients([2,3]) [4*zeta10 + 1, - -9*zeta10^3 + 1] + -9*zeta10^3 + 1] Running this twice once revealed a bug, so we test it:: sage: f.coefficients([0,1,2,3]) [15/11*zeta10^3 - 9/11*zeta10^2 - 26/11*zeta10 - 10/11, - 1, - 4*zeta10 + 1, - -9*zeta10^3 + 1] + 1, + 4*zeta10 + 1, + -9*zeta10^3 + 1] """ try: self.__coefficients @@ -357,11 +356,11 @@ def coefficients(self, X): self.__coefficients = {} if isinstance(X, Integer): X = list(range(1, X + 1)) - Y = [n for n in X if n not in self.__coefficients] + Y = [n for n in X if n not in self.__coefficients] v = self._compute(Y) for i in range(len(v)): self.__coefficients[Y[i]] = v[i] - return [ self.__coefficients[x] for x in X ] + return [self.__coefficients[x] for x in X] def __getitem__(self, n): """ @@ -425,11 +424,12 @@ def padded_list(self, n): EXAMPLES:: sage: CuspForms(1,12).0.padded_list(20) - [0, 1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, -115920, 534612, -370944, -577738, 401856, 1217160, 987136, -6905934, 2727432, 10661420] + [0, 1, -24, 252, -1472, 4830, -6048, -16744, 84480, -113643, + -115920, 534612, -370944, -577738, 401856, 1217160, 987136, + -6905934, 2727432, 10661420] """ return self.q_expansion(n).padded_list(n) - def _latex_(self): """ Return the LaTeX expression of self. @@ -468,8 +468,8 @@ def character(self, compute=True): chi = self.parent().character() if (chi is not None) or (not compute): return chi - else: # do the expensive computation - G = DirichletGroup(self.parent().level(), base_ring = self.parent().base_ring()) + else: # do the expensive computation + G = DirichletGroup(self.parent().level(), base_ring=self.parent().base_ring()) gens = G.unit_gens() i = self.valuation() vals = [] @@ -663,10 +663,9 @@ def atkin_lehner_eigenvalue(self, d=None, embedding=None): sage: CuspForms(2, 8).0.atkin_lehner_eigenvalue() Traceback (most recent call last): ... - NotImplementedError: Don't know how to compute Atkin-Lehner matrix acting on this space (try using a newform constructor instead) + NotImplementedError: don't know how to compute Atkin-Lehner matrix acting on this space (try using a newform constructor instead) """ - raise NotImplementedError("Don't know how to compute Atkin-Lehner matrix acting on this space" \ - + " (try using a newform constructor instead)") + raise NotImplementedError("don't know how to compute Atkin-Lehner matrix acting on this space (try using a newform constructor instead)") # The methods period() and lseries() below currently live # in ModularForm_abstract so they are inherited by Newform (which @@ -781,7 +780,7 @@ def period(self, M, prec=53): sage: E.period(gamma) Traceback (most recent call last): ... - NotImplementedError: Don't know how to compute Atkin-Lehner matrix acting on this space (try using a newform constructor instead) + NotImplementedError: don't know how to compute Atkin-Lehner matrix acting on this space (try using a newform constructor instead) sage: E = EllipticCurve('19a1') sage: M = Gamma0(19)([10, 1, 19, 2]) @@ -829,13 +828,12 @@ def period(self, M, prec=53): coeff = self.coefficients(numterms) return sum((coeff[n - 1] / n) - *((eps - 1) * mu_N ** n - + mu_dN ** n * (mu_d ** (n * b) - eps * mu_d ** (n * c))) + * ((eps - 1) * mu_N ** n + + mu_dN ** n * (mu_d ** (n * b) - eps * mu_d ** (n * c))) for n in range(1, numterms + 1)) - def lseries(self, embedding=0, prec=53, - max_imaginary_part=0, - max_asymp_coeffs=40): + def lseries(self, embedding=0, prec=53, max_imaginary_part=0, + max_asymp_coeffs=40): r""" Return the L-series of the weight k cusp form `f` on `\Gamma_0(N)`. @@ -991,14 +989,10 @@ def lseries(self, embedding=0, prec=53, if self.is_cuspidal(): poles = [] # cuspidal else: - poles = [l] # non-cuspidal - - L = Dokchitser(conductor = N, - gammaV = [0, 1], - weight = l, - eps = e, - poles = poles, - prec = prec) + poles = [l] # non-cuspidal + + L = Dokchitser(conductor=N, gammaV=[0, 1], weight=l, eps=e, poles=poles, + prec=prec) # Find out how many coefficients of the Dirichlet series are needed # in order to compute to the required precision num_coeffs = L.num_coeffs() @@ -1017,10 +1011,10 @@ def lseries(self, embedding=0, prec=53, max_asymp_coeffs=max_asymp_coeffs) L.check_functional_equation() if K == QQ: - L.rename('L-series associated to the cusp form %s'%self) + L.rename('L-series associated to the cusp form %s' % self) else: - L.rename('L-series associated to the cusp form %s, %s=%s' \ - % (self, K.variable_name(), emb(K.gen()))) + L.rename('L-series associated to the cusp form %s, %s=%s' + % (self, K.variable_name(), emb(K.gen()))) return L def symsquare_lseries(self, chi=None, embedding=0, prec=53): @@ -1102,7 +1096,7 @@ def symsquare_lseries(self, chi=None, embedding=0, prec=53): else: assert chi.is_primitive() chi = chi.change_ring(C) - eps = chi.gauss_sum()**3 / chi.base_ring()(chi.conductor())**QQ( (3, 2) ) + eps = chi.gauss_sum()**3 / chi.base_ring()(chi.conductor())**QQ((3, 2)) N = chi.conductor()**3 if (chi is None) or chi.is_even(): @@ -1120,13 +1114,13 @@ def symsquare_lseries(self, chi=None, embedding=0, prec=53): # utility function for Dirichlet convolution of series def dirichlet_convolution(A, B): return [sum(A[d-1] * B[n/d - 1] for d in divisors(n)) - for n in range(1, 1 + min(len(A), len(B)))] + for n in range(1, 1 + min(len(A), len(B)))] # The Dirichlet series for \zeta(2 s - 2 k + 2) - riemann_series = [ n**(weight - 1) if n.is_square() else 0 - for n in xsrange(1, lcoeffs_prec + 1) ] + riemann_series = [n**(weight - 1) if n.is_square() else 0 + for n in xsrange(1, lcoeffs_prec + 1)] # The Dirichlet series for 1 / \zeta(s - k + 1) - mu_series = [ moebius(n) * n**(weight - 1) for n in xsrange(1, lcoeffs_prec + 1) ] + mu_series = [moebius(n) * n**(weight - 1) for n in xsrange(1, lcoeffs_prec + 1)] conv_series = dirichlet_convolution(mu_series, riemann_series) dirichlet_series = dirichlet_convolution(conv_series, F_series) @@ -1143,8 +1137,8 @@ def dirichlet_convolution(A, B): pari_precode = "hhh(n) = " + str(dirichlet_series) + "[n] * " + pari_precode_chi - L.init_coeffs( "hhh(k)", w="conj(hhh(k))", - pari_precode=pari_precode) + L.init_coeffs("hhh(k)", w="conj(hhh(k))", + pari_precode=pari_precode) return L @@ -1363,6 +1357,7 @@ def cm_discriminant(self): raise ValueError("Not a CM form") return -self.__cm_char.conductor() + class Newform(ModularForm_abstract): # The reasons why Newform does not inherit from ModularFormElement # should really be documented somewhere. @@ -1406,8 +1401,8 @@ def __init__(self, parent, component, names, check=True): raise ValueError("component must be cuspidal") if not component.is_simple(): raise ValueError("component must be simple") - extension_field = component.eigenvalue(1,name=names).parent() - if extension_field != parent.base_ring(): # .degree() != 1 and rings.is_NumberField(extension_field): + extension_field = component.eigenvalue(1, name=names).parent() + if extension_field != parent.base_ring(): # .degree() != 1 and rings.is_NumberField(extension_field): assert extension_field.base_field() == parent.base_ring() extension_field = parent.base_ring().extension(extension_field.relative_polynomial(), names=names) self.__name = names @@ -1471,12 +1466,10 @@ def __eq__(self, other): True """ - if (not isinstance(other, ModularForm_abstract) - or self.weight() != other.weight()): + if (not isinstance(other, ModularForm_abstract) or self.weight() != other.weight()): return False if isinstance(other, Newform): - if (self.level() != other.level() or - self.character() != other.character()): + if (self.level() != other.level() or self.character() != other.character()): return False # The two parents may have different Sturm bounds in case # one of them is a space of cusp forms with character @@ -1803,9 +1796,9 @@ def _atkin_lehner_eigenvalue_from_qexp(self, Q): l = ZZ(1) M = self.character().conductor() for p, e in Q.factor(): - if p.divides(M): # principal series at p + if p.divides(M): # principal series at p l *= (p**(self.weight() - 2) / self[p])**e - else: # special at p + else: # special at p l *= -self[p] return l @@ -1845,15 +1838,15 @@ def _atkin_lehner_eigenvalue_from_modsym(self, Q): W = self.group().atkin_lehner_matrix(Q) if Q0 == 1: - L = [ W ] + L = [W] else: L = [] for a in xsrange(Q0): if a.gcd(Q0) > 1: continue aa = crt(a, 1, Q, N.prime_to_m_part(Q)) - diam = matrix(ZZ, 2, lift_to_sl2z(0,aa,N) ) - L.append( (W * diam * matrix(QQ, 2, [1,a/Q0,0,1]) ).change_ring(ZZ) ) + diam = matrix(ZZ, 2, lift_to_sl2z(0, aa, N)) + L.append((W * diam * matrix(QQ, 2, [1, a/Q0, 0, 1])).change_ring(ZZ)) W = A._matrix_of_operator_on_modular_symbols(A, [x.list() for x in L]) e = S.dual_eigenvector(names=self._name()) @@ -2152,7 +2145,7 @@ def atkin_lehner_eigenvalue(self, d=None, normalization='analytic', embedding=No G = R(1) if not R(d**(self.weight()-2)).is_square(): raise ValueError("Unable to compute square root. Try specifying an embedding into a larger ring") - ratio = R(d**(self.weight()-2)).sqrt() * embedding(self.character()( crt(1, d//d0, d, N//d) )) / G + ratio = R(d**(self.weight()-2)).sqrt() * embedding(self.character()(crt(1, d//d0, d, N//d))) / G return embedding(w) / ratio def twist(self, chi, level=None, check=True): @@ -2344,7 +2337,7 @@ def minimal_twist(self, p=None): continue try: g = self.twist(chi, level=N//p**(r-c)) - candidates.append( (g, chi) ) + candidates.append((g, chi)) except ValueError: continue @@ -2353,7 +2346,7 @@ def minimal_twist(self, p=None): l = l.next_prime() if l == p: continue - candidates = [(h, chi) for (h, chi) in candidates if h[l] == chi(l)*self[l] ] + candidates = [(h, chi) for (h, chi) in candidates if h[l] == chi(l)*self[l]] if l > 10000 or len(candidates) == 0: raise RuntimeError("bug finding minimal twist") return candidates[0] @@ -2403,6 +2396,7 @@ def local_component(self, p, twist_factor=None): from sage.modular.local_comp.local_comp import LocalComponent return LocalComponent(self, p, twist_factor) + class ModularFormElement(ModularForm_abstract, element.HeckeModuleElement): def __init__(self, parent, x, check=True): r""" @@ -2446,7 +2440,7 @@ def _compute_q_expansion(self, prec): sage: f._compute_q_expansion(10) q - 2*q^2 - 3*q^3 + 2*q^4 - 2*q^5 + 6*q^6 - q^7 + 6*q^9 + O(q^10) """ - return self.parent()._q_expansion(element = self.element(), prec=prec) + return self.parent()._q_expansion(element=self.element(), prec=prec) def _add_(self, other): """ @@ -2588,15 +2582,14 @@ def atkin_lehner_eigenvalue(self, d=None, embedding=None): sage: CuspForms(2, 8).0.atkin_lehner_eigenvalue() Traceback (most recent call last): ... - NotImplementedError: Don't know how to compute Atkin-Lehner matrix acting on this space (try using a newform constructor instead) + NotImplementedError: don't know how to compute Atkin-Lehner matrix acting on this space (try using a newform constructor instead) """ if d is None: d = self.level() try: f = self.parent().atkin_lehner_operator(d)(self) except NotImplementedError: - raise NotImplementedError("Don't know how to compute Atkin-Lehner matrix acting on this space" \ - + " (try using a newform constructor instead)") + raise NotImplementedError("don't know how to compute Atkin-Lehner matrix acting on this space (try using a newform constructor instead)") w = self.element().nonzero_positions()[0] t = f.element()[w] / self.element()[w] if f.element() == self.element() * t: @@ -2830,7 +2823,7 @@ def atkin_lehner_eigenvalue(self, d=None, embedding=None): else: # The space of modular symbols attached to E is # one-dimensional. - w = self.__E.modular_symbol_space().atkin_lehner_operator(d).matrix()[0,0] + w = self.__E.modular_symbol_space().atkin_lehner_operator(d).matrix()[0, 0] return w @@ -2895,13 +2888,12 @@ def __init__(self, parent, vector, t, chi, psi): if chi.parent().base_ring() != K or psi.parent().base_ring() != K: raise ArithmeticError("Incompatible base rings") t = int(t) - if parent.weight() == 2 and chi.is_trivial() \ - and psi.is_trivial() and t==1: + if parent.weight() == 2 and chi.is_trivial() and psi.is_trivial() and t == 1: raise ArithmeticError("If chi and psi are trivial and k=2, then t must be >1.") ModularFormElement.__init__(self, parent, vector) self.__chi = chi self.__psi = psi - self.__t = t + self.__t = t def _compute_q_expansion(self, prec=None): """ @@ -2936,7 +2928,7 @@ def _compute(self, X): """ if self.weight() == 2 and (self.__chi.is_trivial() and self.__psi.is_trivial()): return self.__compute_weight2_trivial_character(X) - else: # general case + else: # general case return self.__compute_general_case(X) def __compute_weight2_trivial_character(self, X): @@ -3150,6 +3142,7 @@ def new_level(self): return factor(self.__t)[0][0] return self.L() * self.M() + class GradedModularFormElement(ModuleElement): r""" The element class for ``ModularFormsRing``. A ``GradedModularFormElement`` is basically a @@ -3250,13 +3243,13 @@ def __init__(self, parent, forms_datum): if parent.group().is_subgroup(f.group()) and parent.base_ring().has_coerce_map_from(f.base_ring()): forms_dictionary[k] = f else: - raise ValueError('the group and/or the base ring of at least one modular form (%s) is not consistant with the base space'%(f)) + raise ValueError('the group and/or the base ring of at least one modular form (%s) is not consistant with the base space' % (f)) else: - raise ValueError('at least one key (%s) of the defining dictionary does not correspond to the weight of its value (%s). Real weight: %s'%(k, f, f.weight())) + raise ValueError('at least one key (%s) of the defining dictionary does not correspond to the weight of its value (%s). Real weight: %s' % (k, f, f.weight())) else: - raise ValueError('at least one value (%s) of the defining dictionary is not a `ModularFormElement`'%(f)) + raise ValueError('at least one value (%s) of the defining dictionary is not a `ModularFormElement`' % (f)) else: - raise ValueError('at least one key (%s) of the defining dictionary is not an integer'%(k)) + raise ValueError('at least one key (%s) of the defining dictionary is not an integer' % (k)) elif isinstance(forms_datum, list): for f in forms_datum: if is_ModularFormElement(f): @@ -3266,12 +3259,12 @@ def __init__(self, parent, forms_datum): if parent.group().is_subgroup(f.group()) and parent.base_ring().has_coerce_map_from(f.base_ring()): forms_dictionary[f.weight()] = forms_dictionary.get(f.weight(), 0) + f else: - raise ValueError('the group and/or the base ring of at least one modular form (%s) is not consistant with the base space'%(f)) + raise ValueError('the group and/or the base ring of at least one modular form (%s) is not consistant with the base space' % (f)) else: forms_dictionary[ZZ(0)] = parent.base_ring().coerce(f) else: raise TypeError('the defining data structure should be a list or a dictionary') - self._forms_dictionary = {k:f for k,f in forms_dictionary.items() if not f.is_zero()} #remove the zero values + self._forms_dictionary = {k: f for k, f in forms_dictionary.items() if not f.is_zero()} # remove the zero values Element.__init__(self, parent) def __bool__(self): @@ -3371,7 +3364,7 @@ def q_expansion(self, prec=None): Pow = PowerSeriesRing(self.base_ring(), name=defaults.DEFAULT_VARIABLE) return Pow(self._forms_dictionary.get(0, Pow.zero())) + sum(f.q_expansion(prec) for k, f in self._forms_dictionary.items() if k != 0) - qexp = q_expansion #alias + qexp = q_expansion # alias def _repr_(self): r""" @@ -3431,7 +3424,7 @@ def __getitem__(self, weight): if weight < 0: raise ValueError("the weight must be non-negative") return self._forms_dictionary.get(weight, self.parent().zero()) - homogeneous_component = __getitem__ #alias + homogeneous_component = __getitem__ # alias def __call__(self, x, prec=None): r""" @@ -3478,7 +3471,7 @@ def _add_(self, other): GM = self.__class__ f_self = self._forms_dictionary f_other = other._forms_dictionary - f_sum = { k : f_self.get(k, 0) + f_other.get(k, 0) for k in set(f_self) | set(f_other)} + f_sum = {k: f_self.get(k, 0) + f_other.get(k, 0) for k in set(f_self) | set(f_other)} return GM(self.parent(), f_sum) def __neg__(self): @@ -3496,7 +3489,7 @@ def __neg__(self): """ GM = self.__class__ f_self = self._forms_dictionary - minus_self = {k:-f for k,f in f_self.items()} + minus_self = {k: -f for k, f in f_self.items()} return GM(self.parent(), minus_self) def _mul_(self, other): @@ -3553,7 +3546,7 @@ def _lmul_(self, c): """ GM = self.__class__ f_self = self._forms_dictionary - f_mul = {k:c*f for k,f in f_self.items()} + f_mul = {k: c*f for k, f in f_self.items()} return GM(self.parent(), f_mul) def _richcmp_(self, other, op): @@ -3653,7 +3646,7 @@ def is_homogeneous(self): False """ return len(self._forms_dictionary) <= 1 - is_modular_form = is_homogeneous #alias + is_modular_form = is_homogeneous # alias def _homogeneous_to_polynomial(self, names, gens): r""" @@ -3697,7 +3690,7 @@ def _homogeneous_to_polynomial(self, names, gens): if not self.base_ring() == QQ: raise NotImplementedError("conversion to polynomial are not implemented if the base ring is not Q") M = self.parent() - k = self.weight() #only if self is homogeneous + k = self.weight() # only if self is homogeneous poly_parent = M.polynomial_ring(names, gens) if k == 0: return poly_parent(self[k]) From 9cfeebebdc4618a1f2f9f2285908d233debb6545 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 15 Aug 2022 12:07:28 -0700 Subject: [PATCH 404/591] README.md: Be clearer that README only contains build-from-source instructions; remove section on Docker --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 539a73d1c05..e2ad81da670 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,14 @@ Getting Started The [Sage Installation Guide](https://doc.sagemath.org/html/en/installation/index.html) provides a decision tree that guides you to the type of installation -that will work best for you. +that will work best for you. This includes building from source, +obtaining Sage from a package manager, using a container image, or using +Sage in the cloud. -If you have already cloned the git repository or downloaded the +**This README contains self-contained instructions for building Sage from source.** +It assumes that you have already cloned the git repository or downloaded the [sources](https://www.sagemath.org/download-source.html) in the form -of a tarball, please read the self-contained instructions below on how -to build Sage and work around common issues. +of a tarball. If you have questions or encounter problems, please do not hesitate to email the [sage-support mailing list](https://groups.google.com/group/sage-support) @@ -47,11 +49,6 @@ We highly appreciate contributions to Sage that fix portability bugs and help port Sage to new platforms; let us know at the [sage-devel mailing list](https://groups.google.com/group/sage-devel). -Docker Images -------------- - -SageMath is also available through the [Docker image sagemathinc/cocalc](https://hub.docker.com/r/sagemathinc/cocalc). - [Windows] Preparing the Platform -------------------------------- From 19018bbdc9b25397bc59eb21fa6f641921703000 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 16 Aug 2022 03:14:58 +0800 Subject: [PATCH 405/591] implement polynomial factorization modulo prime powers (by calling the implementation for p-adics) --- .../polynomial/polynomial_zmod_flint.pyx | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx index 748d8ce37c7..1e5bcc6e9a4 100644 --- a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx @@ -736,8 +736,15 @@ cdef class Polynomial_zmod_flint(Polynomial_template): sage: (x^2 + 1).factor() (x + 2) * (x + 3) + It also works for prime-power moduli:: + + sage: R. = Zmod(23^5)[] + sage: (x^3 + 1).factor() + (x + 1) * (x^2 + 6436342*x + 1) + TESTS:: + sage: R. = GF(5)[] sage: (2*x^2 + 2).factor() (2) * (x + 2) * (x + 3) sage: P. = Zmod(10)[] @@ -745,10 +752,20 @@ cdef class Polynomial_zmod_flint(Polynomial_template): Traceback (most recent call last): ... NotImplementedError: factorization of polynomials over rings with composite characteristic is not implemented - """ - if not self.base_ring().is_field(): - raise NotImplementedError("factorization of polynomials over rings with composite characteristic is not implemented") + R = self.base_ring() + + if not R.is_field(): + p,e = R.characteristic().is_prime_power(get_data=True) + if not e: + raise NotImplementedError("factorization of polynomials over rings with composite characteristic is not implemented") + + # Factoring is well-defined for prime-power moduli. + # For simplicity we reuse the implementation for p-adics; + # presumably this can be done faster. + from sage.rings.padics.factory import Zp + f = self.change_ring(Zp(p, prec=e)) + return f.factor().base_change(self.parent()) return factor_helper(self) From 6212abfde09ee4191dd668f84e8e7d7f3e769ee9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 15 Aug 2022 12:16:26 -0700 Subject: [PATCH 406/591] src/doc/en/installation/index.rst: Also link to https://trac.sagemath.org/wiki/Distribution\#Dockerimages --- src/doc/en/installation/index.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/doc/en/installation/index.rst b/src/doc/en/installation/index.rst index e630ae38be3..22e538d7705 100644 --- a/src/doc/en/installation/index.rst +++ b/src/doc/en/installation/index.rst @@ -130,8 +130,11 @@ In the cloud - `CoCalc `_: an online service that provides SageMath and many other tools. -- On any system that allows you to bring your own Docker images to run in - a container: Use the `Docker image sagemathinc/cocalc `_. +- On any system that allows you to bring your own Docker images to run + in a container: Use the `Docker image sagemathinc/cocalc + `_ or `another Docker + image providing SageMath + `_. - `Sage Cell Server `_: an online service for elementary SageMath computations. From c2adcea5f3faabaf7d0daa3a540eed8bdd003696 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 15 Aug 2022 13:29:53 -0700 Subject: [PATCH 407/591] Add examples to SchubertPolynomials --- src/sage/combinat/schubert_polynomial.py | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/sage/combinat/schubert_polynomial.py b/src/sage/combinat/schubert_polynomial.py index b939754716c..3f31abe2f4d 100644 --- a/src/sage/combinat/schubert_polynomial.py +++ b/src/sage/combinat/schubert_polynomial.py @@ -1,5 +1,67 @@ r""" Schubert Polynomials + + +See :wikipedia:`Schubert_polynomial` and +`SymmetricFunctions.com `_. +Schubert polynomials are representatives of cohomology classes in flag varieties. +In `n` variables, they are indexed by permutations `w \in S_n`. They also form +a basis for the coinvariant ring of the `S_n` action on +`\\Bold{Z}[x_1, x_2, \ldots, x_n]`. + +In Sage, they are modeled in the :class:`SchubertPolynomial_class`. Instances of +this class can be created by creating an instance ``X`` of a Schubert polynomial +ring using the constructor :func:`SchubertPolynomialRing`. + +EXAMPLES:: + + sage: X = SchubertPolynomialRing(ZZ) + sage: w = [1,2,5,4,3]; # a list representing an element of `S_5` + sage: X(w) + X[1, 2, 5, 4, 3] + +This can be expanded in terms of polynomial variables:: + + sage: X(w).expand() + x0^2*x1 + x0*x1^2 + x0^2*x2 + 2*x0*x1*x2 + x1^2*x2 + + x0*x2^2 + x1*x2^2 + x0^2*x3 + x0*x1*x3 + x1^2*x3 + + x0*x2*x3 + x1*x2*x3 + x2^2*x3 + +We can also convert back from polynomial variables. For example, +the longest permutation is a single term. In `S_5`, this is the +element (in one line notation) `w_0 = 54321`:: + + sage: w0 = [5,4,3,2,1] + sage: R. = PolynomialRing(ZZ) + sage: Sw0 = X(x0^4*x1^3*x2^2*x3); Sw0 + X[5, 4, 3, 2, 1] + +The polynomials also have the property that if the indexing permutation `w` is +multiplied by a simple transposition `s_i = (i, i+1)` such that the length of +`w` is more than the length of `ws_i`, then the Schubert +polynomial of the permutation `ws_i` is computed by applying the divided +difference operator :meth:`~SchubertPolynomial_class.divided_difference` to +the polynomial indexed by `w`. For example, applying the divided difference +operator `\partial_2` to the Schubert polynomial `\mathfrak{S}_{w_0}`:: + + sage: Sw0.divided_difference(2) + X[5, 3, 4, 2, 1] + +We can also check the properties listed in :wikipedia:`Schubert_polynomial`:: + + sage: X([1,2,3,4,5]) # the identity in one-line notation + X[1] + sage: X([1,3,2,4,5]).expand() # the transposition swapping 2 and 3 + x0 + x1 + sage: X([2,4,5,3,1]).expand() + x0^2*x1^2*x2*x3 + x0^2*x1*x2^2*x3 + x0*x1^2*x2^2*x3 + + sage: w = [4,5,1,2,3] # r = 2 + sage: s = SymmetricFunctions(QQ).schur() + sage: s[3,3].expand(2) + x0^3*x1^3 + sage: X(w).expand() + x0^3*x1^3 """ # **************************************************************************** # Copyright (C) 2007 Mike Hansen , From 5861650d753e148d1f54e6df67b60201292eb098 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Mon, 15 Aug 2022 13:44:04 -0700 Subject: [PATCH 408/591] Fix typo --- src/sage/combinat/schubert_polynomial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/schubert_polynomial.py b/src/sage/combinat/schubert_polynomial.py index 3f31abe2f4d..22cbc410ea7 100644 --- a/src/sage/combinat/schubert_polynomial.py +++ b/src/sage/combinat/schubert_polynomial.py @@ -56,7 +56,7 @@ sage: X([2,4,5,3,1]).expand() x0^2*x1^2*x2*x3 + x0^2*x1*x2^2*x3 + x0*x1^2*x2^2*x3 - sage: w = [4,5,1,2,3] # r = 2 + sage: w = [4,5,1,2,3] sage: s = SymmetricFunctions(QQ).schur() sage: s[3,3].expand(2) x0^3*x1^3 From ae8cfa3610b600b0d7f27f27599aca5cb86cdd44 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 16 Aug 2022 14:54:57 +0900 Subject: [PATCH 409/591] Make is_integral_domain() always take a proof keyword arugment. --- src/sage/categories/integral_domains.py | 15 +++++++++++---- src/sage/rings/tate_algebra.py | 13 +++++++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 9daa68ff25e..8cf87ffe94f 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -96,17 +96,23 @@ def _contains_helper(cls): return Category_contains_method_by_parent_class(cls()) class ParentMethods: - def is_integral_domain(self): - """ - Return True, since this in an object of the category of integral domains. + def is_integral_domain(self, proof=True): + r""" + Return ``True``, since this in an object of the category + of integral domains. EXAMPLES:: sage: QQ.is_integral_domain() True - sage: Parent(QQ,category=IntegralDomains()).is_integral_domain() + sage: Parent(QQ, category=IntegralDomains()).is_integral_domain() True + sage: L. = LazyLaurentSeriesRing(QQ) + sage: L.is_integral_domain() + True + sage: L.is_integral_domain(proof=True) + True """ return True @@ -138,3 +144,4 @@ def _test_fraction_field(self, **options): class ElementMethods: pass + diff --git a/src/sage/rings/tate_algebra.py b/src/sage/rings/tate_algebra.py index fd0147eaf88..9097b2a4e07 100644 --- a/src/sage/rings/tate_algebra.py +++ b/src/sage/rings/tate_algebra.py @@ -1275,8 +1275,8 @@ def random_element(self, degree=2, terms=5, integral=False, prec=None): gens = [ self.element_class(self, g) for g in self._integer_ring._gens ] return self.element_class(self, polring.random_element(degree, terms)(*gens), prec) - def is_integral_domain(self): - """ + def is_integral_domain(self, proof=True): + r""" Return ``True`` since any Tate algebra is an integral domain. EXAMPLES:: @@ -1285,5 +1285,14 @@ def is_integral_domain(self): sage: A.is_integral_domain() True + TESTS: + + Check that :trac:`34372` is fixed:: + + sage: A. = TateAlgebra(Zp(3)) + sage: R. = PolynomialRing(A) + sage: R.is_integral_domain(proof=True) + True """ return True + From 551df02bbefdbe671dfd7d7c62b7e6acf6520b16 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 15 Aug 2022 23:19:30 -0700 Subject: [PATCH 410/591] src/doc/en/installation/index.rst: Fix markup of trac wiki link --- src/doc/en/installation/index.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/doc/en/installation/index.rst b/src/doc/en/installation/index.rst index 22e538d7705..c1ec9cd500c 100644 --- a/src/doc/en/installation/index.rst +++ b/src/doc/en/installation/index.rst @@ -132,9 +132,8 @@ In the cloud - On any system that allows you to bring your own Docker images to run in a container: Use the `Docker image sagemathinc/cocalc - `_ or `another Docker - image providing SageMath - `_. + `_ or :trac:`another Docker + image providing SageMath `. - `Sage Cell Server `_: an online service for elementary SageMath computations. From ebab2fd6d72cb95d380f3a2175c9f5cf044580ac Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 16 Aug 2022 17:31:00 +0900 Subject: [PATCH 411/591] Initial round of reviewer changes. --- .../hecke_algebras/cubic_hecke_algebra.py | 712 +++++++++--------- .../hecke_algebras/cubic_hecke_base_ring.py | 232 +++--- .../hecke_algebras/cubic_hecke_matrix_rep.py | 183 +++-- src/sage/databases/cubic_hecke_db.py | 236 +++--- 4 files changed, 672 insertions(+), 691 deletions(-) diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 66e554c85df..1c8a8f24b1b 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -2,12 +2,12 @@ r""" Cubic Hecke Algebras -This module is devoted to factors of the group algebra of the Artin braid groups, +We consider the factors of the group algebra of the Artin braid groups such that the images `s_i` of the braid generators satisfy a cubic equation: .. MATH:: - s_i^3 = u s_i^2 - v s_i + w + s_i^3 = u s_i^2 - v s_i + w. Here `u, v, w` are elements in an arbitrary integral domain and `i` is a positive integer less than `n`, the number of the braid group's strands. By the analogue @@ -17,8 +17,8 @@ .. MATH:: - s_i s_{i+1} s_i = s_{i+1} s_i s_{i+1} \mbox{ where } 1\leq i < n-1 \mbox{ and } - s_i s_j = s_j s_i \mbox{ where } 1 \leq i < j - 1 < n - 1. + s_i s_{i+1} s_i = s_{i+1} s_i s_{i+1} \text{ for } 1 \leq i < n - 1 + \mbox{ and } s_i s_j = s_j s_i \text{ for } 1 \leq i < j - 1 < n - 1. The algebra epimorphism from the braid group algebra over the same base ring is realized inside the element constructor of the present class, for example in the @@ -36,20 +36,20 @@ If the ring elements `u, v, w` (which will be called the *cubic equation parameters* in the sequel) are taken to be `u = v = 0, w = 1` the cubic Hecke algebra specializes to the group algebra of the *cubic braid group*, which is -the factor group of the Artin braid group under setting the generators order to -be three. A sage-class to handle these groups is attached and can be obtained by +the factor group of the Artin braid group under setting the generators order +to be three. These groups can be obtained by :meth:`CubicHeckeAlgebra.cubic_braid_group`. It is well known, that these algebras are free of finite rank as long as the number of braid generators is less than six and infinite dimensional else wise. In the former (non trivial) cases they are also known as *cyclotomic Hecke algebras* corresponding to the complex reflection groups having Shepard-Todd -number `4, 25` and `32`. +number `4`, `25` and `32`. -Since the *Broué, Malle, Rouquiere* conjecture has been proved in all these cases -(for references see [Mar2012]_) there exists a finite free basis of the cubic Hecke -algebra which is in bijection to the cubic braid group and compatible with the -specialization to the cubic braid group algebra as explained above. +Since the *Broué, Malle, Rouquiere* conjecture has been proved (for references +of these cases see [Mar2012]_) there exists a finite free basis of the cubic +Hecke algebra which is in bijection to the cubic braid group and compatible +with the specialization to the cubic braid group algebra as explained above. For the algebras corresponding to braid groups of less than five strands such a basis has been calculated by Ivan Marin. This one is used here. In the case of 5 @@ -64,10 +64,10 @@ EXAMPLES: -1. Consider the obstruction ``b`` of the *triple quadratic algebra* from section -2.6 of [Mar2018]_. We verify that the third power of it is a scalar multiple of -itself (explicitly ``2*w^2`` times the *Schur element* of the three dimensional -irreducible representation):: +1. Consider the obstruction ``b`` of the *triple quadratic algebra* from Section + 2.6 of [Mar2018]_. We verify that the third power of it is a scalar multiple + of itself (explicitly ``2*w^2`` times the *Schur element* of the three + dimensional irreducible representation):: sage: CHA3 = algebras.CubicHecke(3) sage: c1, c2 = CHA3.gens() @@ -81,7 +81,7 @@ sage: f = BR(b3.coefficients()[0]/w) sage: try: ....: sh = CHA3.schur_element(CHA3.irred_repr.W3_111) - ....: except NotImplementedError: # for the case GAP3 / CHEVIE not available + ....: except NotImplementedError: # for the case GAP3 / CHEVIE not available ....: sh = ER(f/(2*w^2)) sage: ER(f/(2*w^2)) == sh True @@ -89,8 +89,8 @@ True 2. Defining the cubic Hecke algebra on 6 strands will need some seconds for -initializing. But than you can do calculations inside the infinite algebra as -well:: + initializing. But than you can do calculations inside the infinite algebra + as well:: sage: CHA6 = algebras.CubicHecke(6) # optional - database_cubic_hecke sage: CHA6.inject_variables() # optional - database_cubic_hecke @@ -144,14 +144,9 @@ ############################################################################## class CubicHeckeElement(CombinatorialFreeModule.Element): r""" - Element class of :class:`CubicHeckeAlgebra`. + An element of a :class:`CubicHeckeAlgebra`. - It is inherited from :class:`CombinatorialFreeModule.Element` according to - the parent class being inherited from :class:`CombinatorialFreeModule`. The - construction of the elements is realized via - :meth:`CubicHeckeAlgebra._element_constructor_` of the parent class. - - For more information see the parent class. + For more information see :class:`CubicHeckeAlgebra`. EXAMPLES:: @@ -175,16 +170,19 @@ def __invert__(self): c0*c1^-1*c0 sage: ~ele1 # indirect doctest c0^-1*c1*c0^-1 - sage: ele2 = CHA3.an_element() - sage: ~ele2 # indirect doctest + + sage: CHA2 = algebras.CubicHecke(2) + sage: x = CHA2.an_element(); x + v*c + ((-v*w+u)/w) + sage: ~x Traceback (most recent call last): ... - NotImplementedError: inversion of non basis elements is not implemented, yet + ValueError: cannot invert self (= v*c + ((-v*w+u)/w)) """ self_Tietze = self.Tietze() if self_Tietze is None: - raise NotImplementedError('inversion of non basis elements is not implemented, yet') + return super().__invert__() inverse_Tietze = () len_self = len(self_Tietze) @@ -196,7 +194,7 @@ def __invert__(self): def Tietze(self): r""" Return the Tietze presentation of ``self`` if ``self`` belongs to the - basis of its parent and ``None`` else. + basis of its parent and ``None`` otherwise. OUTPUT: @@ -213,18 +211,17 @@ def Tietze(self): sage: [CHA3(sp).Tietze() for sp in ele.support()] [(), (1,), (1, -2), (2,)] """ - vecd = self.to_vector().dict() + vecd = self._monomial_coefficients if len(vecd) != 1: return None - ind = list(vecd.keys())[0] - if vecd[ind].is_one(): - P = self.parent() - return P.get_order()[ind].Tietze() + ind, coeff = next(iter(vecd.items())) + if coeff.is_one(): + return ind.Tietze() def max_len(self): r""" - Return the maximum of the length of Tietze expressions among the support - of ``self``. + Return the maximum of the length of Tietze expressions among the + support of ``self``. EXAMPLES:: @@ -238,7 +235,7 @@ def max_len(self): def braid_group_algebra_pre_image(self): r""" - Return a pre image of ``self`` in the group algebra of the braid_group + Return a pre image of ``self`` in the group algebra of the braid group (with respect to the basis given by Ivan Marin). OUTPUT: @@ -308,18 +305,19 @@ def matrix(self, subdivide=False, representation_type=None, original=False): Return certain types of matrix representations of ``self``. The absolutely irreducible representations of the cubic Hecke algebra - are constructed using the *GAP3*-Interface and the *CHEVIE* package if - GAP3 and CHEVIE are installed on the system. Furthermore, the - representations given on `Ivan Marin's homepage `__ + are constructed using the ``GAP3`` interface and the ``CHEVIE`` package + if ``GAP3`` and ``CHEVIE`` are installed on the system. Furthermore, + the representations given on `Ivan Marin's homepage + `__ are used: INPUT: - - ``subdivide`` -- boolean (default = False): this boolean is passed + - ``subdivide`` -- boolean (default: ``False``): this boolean is passed to the block_matrix function - - ``representation_type`` -- instance of enum :class:`RepresentationType`. - This can be obtained by the attribute :attr:`CubicHeckeAlgebra.repr_type` - of ``self``. The following values are possible: + - ``representation_type`` -- instance of enum :class:`RepresentationType`; + this can be obtained by the attribute :attr:`CubicHeckeAlgebra.repr_type` + of ``self``; the following values are possible: - ``RegularLeft`` -- (regular left repr. from the above URL) - ``RegularRight`` -- (regular right repr. from the above URL) @@ -327,18 +325,20 @@ def matrix(self, subdivide=False, representation_type=None, original=False): - ``SplitIrredMarin`` -- (split irred. repr. from the above URL) - default: ``SplitIrredChevie`` taken if GAP3 and CHEVIE are installed on the system, otherwise the default will be ``SplitIrredMarin`` - - ``original`` -- boolean (default = False): if set to true the base + + - ``original`` -- boolean (default: ``False``): if set to true the base ring of the matrix will be the generic base_ring resp. generic extension ring (for the split versions) of the parent of ``self`` OUTPUT: - An instance of the class :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.CubicHeckeMatrixRep` + An instance of :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.CubicHeckeMatrixRep`, which is inherited from :class:`~sage.matrix.matrix_generic_dense.Matrix_generic_dense`. In the case of the irreducible representations the matrix is given as a block matrix. Each single irreducible can be obtained as item indexed by the members of the enum :class:`AbsIrreducibeRep` available via - :attr:`CubicHeckeAlgebra.irred_repr`. For details type: ``CubicHeckeAlgebra.irred_repr?``. + :attr:`CubicHeckeAlgebra.irred_repr`. + For details type: ``CubicHeckeAlgebra.irred_repr?``. EXAMPLES:: @@ -391,9 +391,9 @@ def matrix(self, subdivide=False, representation_type=None, original=False): (9, 9) sage: em_irr24[3,2] # optional database_cubic_hecke -131*E3 - 393/7 - sage: emg = e.matrix(representation_type=chevie) # optional gap3 - sage: emg_irr24 = emg[23] # optional gap3 - sage: emg_irr24[3,2] # optional gap3 + sage: emg = e.matrix(representation_type=chevie) # optional gap3 database_cubic_hecke + sage: emg_irr24 = emg[23] # optional gap3 database_cubic_hecke + sage: emg_irr24[3,2] # optional gap3 database_cubic_hecke -131*E3 - 393/7 """ parent = self.parent() @@ -403,7 +403,10 @@ def matrix(self, subdivide=False, representation_type=None, original=False): def revert_garside(self): r""" Return the image of ``self`` under the Garside involution. - See also :meth:`CubicHeckeAlgebra.garside_involution` of the parent class. + + .. SEEALSO:: + + :meth:`CubicHeckeAlgebra.garside_involution` EXAMPLES:: @@ -421,7 +424,10 @@ def revert_garside(self): def revert_mirror(self): r""" Return the image of ``self`` under the mirror isomorphism. - See also :meth:`CubicHeckeAlgebra.mirror_isomorphism` of the parent class. + + .. SEEALSO:: + + :meth:`CubicHeckeAlgebra.mirror_isomorphism` EXAMPLES:: @@ -437,8 +443,11 @@ def revert_mirror(self): def revert_orientation(self): r""" Return the image of ``self`` under the anti involution reverting the - orientation of braids. See also :meth:`CubicHeckeAlgebra.orientation_antiinvolution` - of the parent class. + orientation of braids. + + .. SEEALSO:: + + :meth:`CubicHeckeAlgebra.orientation_antiinvolution` EXAMPLES:: @@ -454,29 +463,30 @@ def revert_orientation(self): def formal_markov_trace(self, extended=False, field_embedding=False): r""" Return a formal expression which can be specialized to Markov traces - which factor through the cubic Hecke algebra. This covers Markov traces - corresponding to the + which factor through the cubic Hecke algebra. - - HOMFLY-PT polynomial - - Kauffman polynomial - - Links-Gould polynomial + This covers Markov traces corresponding to the + + - HOMFLY-PT polynomial, + - Kauffman polynomial, + - Links-Gould polynomial. These expressions are elements of a sub-module of the module of linear forms on ``self`` the base ring of which is an extension of the - generic base ring of ``self`` by an additional variable ``s`` representing - the writhe factor. All variables of this base ring extension are - invertible. + generic base ring of ``self`` by an additional variable ``s`` + representing the writhe factor. All variables of this base ring + extension are invertible. - A Markov trace is a family of class functions `tr_n` on the family of - braid groups `B_n` into some commutative ring `R` depending on a - unit `s \in R` such that for all `b \in B_n` the following two + A Markov trace is a family of class functions `tr_n` on the family + of braid groups `B_n` into some commutative ring `R` depending on + a unit `s \in R` such that for all `b \in B_n` the following two conditions are satisfied (see [Kau1991]_, section 7): .. MATH:: \begin{array}{lll} - tr_{n+1}(b g_n) & = & s tr_n(b)\\ - tr_{n+1}(b g^{-1}_n) & = & s^{-1} tr_n(b) + tr_{n+1}(b g_n) & = & s tr_n(b), \\ + tr_{n+1}(b g^{-1}_n) & = & s^{-1} tr_n(b). \end{array} The unit `s` is often called the writhe factor and corresponds to the @@ -487,25 +497,18 @@ def formal_markov_trace(self, extended=False, field_embedding=False): Currently it is not known if all linear forms of this sub-module belong to a Markov trace, i.e. can be extended to the full tower of cubic Hecke algebras. Anyway, at least the four basis elements - (``U1, U2, U3`` and ``K4``) can be reconstructed form the HOMFLY-PT - and Kauffman polynomial. + (``U1``, ``U2, ``U3`` and ``K4``) can be reconstructed form + the HOMFLY-PT and Kauffman polynomial. INPUT: - - ``extended`` -- boolean (``False``) if set to ``True`` the base ring - of the Markov trace module is constructed as an extension of generic - extension ring of ``self``. Per default it is constructed upon the - generic base ring. - - - ``field_embedding`` -- boolean (default ``False``) if set to ``True` + - ``extended`` -- boolean (default: ``False``); if set to ``True`` the + base ring of the Markov trace module is constructed as an extension + of generic extension ring of ``self``; per default it is constructed + upon the generic base ring + - ``field_embedding`` -- boolean (default: ``False``); if set to ``True`` the base ring of the module is the smallest field containing the - generic extension ring of ``self``. The keyword is meaningless if - ``extended=False``. - - - OUTPUT: - - An instance of :class:`~sage.combinat.free_module.CombinatorialFreeModule_with_category.element_class`. + generic extension ring of ``self``; ignored if ``extended=False`` EXAMPLES:: @@ -520,18 +523,18 @@ def formal_markov_trace(self, extended=False, field_embedding=False): over Multivariate Polynomial Ring in u, v, w, s over Integer Ring localized at (s, w, v, u) - sage: b3_1.formal_markov_trace(extended=True) + sage: f = b3_1.formal_markov_trace(extended=True); f (a^2*b*c*s^-1+a*b^2*c*s^-1+a*b*c^2*s^-1+a^2*s+a*b*s+b^2*s+a*c*s+b*c*s+c^2*s)*B[U1] + (-a^2*b-a*b^2-a^2*c+(-2)*a*b*c-b^2*c-a*c^2-b*c^2)*B[U2] - sage: _.parent().base_ring() + sage: f.parent().base_ring() Multivariate Laurent Polynomial Ring in a, b, c, s over Splitting Algebra of x^2 + x + 1 with roots [e3, -e3 - 1] over Integer Ring - sage: b3_1.formal_markov_trace(extended=True, field_embedding=True) + sage: f = b3_1.formal_markov_trace(extended=True, field_embedding=True); f ((a^2*b*c+a*b^2*c+a*b*c^2+a^2*s^2+a*b*s^2+b^2*s^2+a*c*s^2+b*c*s^2+c^2*s^2)/s)*B[U1] + (-a^2*b-a*b^2-a^2*c-2*a*b*c-b^2*c-a*c^2-b*c^2)*B[U2] - sage: _.parent().base_ring() + sage: f.parent().base_ring() Fraction Field of Multivariate Polynomial Ring in a, b, c, s over Cyclotomic Field of order 3 and degree 2 @@ -542,15 +545,15 @@ def formal_markov_trace(self, extended=False, field_embedding=False): sage: u, v, w, s = mt3_1.base_ring().gens() sage: LK3_1 = mt3_1*s**-3 # since the writhe of K3_1 is 3 sage: f = MT.specialize_homfly() - sage: sum(f(LK3_1.coefficient(b)) * b.regular_homfly_polynomial() for b in sup) + sage: g = sum(f(LK3_1.coefficient(b)) * b.regular_homfly_polynomial() for b in sup); g L^-2*M^2 - 2*L^-2 - L^-4 - sage: _ == K3_1.link().homfly_polynomial() + sage: g == K3_1.link().homfly_polynomial() True sage: f = MT.specialize_kauffman() - sage: sum(f(LK3_1.coefficient(b)) * b.regular_kauffman_polynomial() for b in sup) + sage: g = sum(f(LK3_1.coefficient(b)) * b.regular_kauffman_polynomial() for b in sup); g a^-2*z^2 - 2*a^-2 + a^-3*z + a^-4*z^2 - a^-4 + a^-5*z - sage: _ == K3_1.kauffman_polynomial() + sage: g == K3_1.kauffman_polynomial() True sage: f = MT.specialize_links_gould() @@ -569,9 +572,9 @@ def formal_markov_trace(self, extended=False, field_embedding=False): RI = MI.base_ring() mtcf = [MI.from_vector(cf.to_vector()) for cf in mtcf] vs = vs.change_ring(RI) - mtcf = [M.from_vector(cf.to_vector()) for cf in mtcf] - return sum(vs[i]*mtcf[i] for i in range(len(vs))) + + return sum(vs[i] * mtcf[i] for i in range(len(vs))) class CubicHeckeAlgebra(CombinatorialFreeModule): @@ -581,30 +584,30 @@ class CubicHeckeAlgebra(CombinatorialFreeModule): This is a quotient of the group algebra of the Artin braid group, such that the images `s_i` (`1 \leq i < n`) of the braid generators satisfy a cubic - equation (see module header :mod:`~sage.algebras.hecke_algebras.cubic_hecke_algebra` + equation (see :mod:`~sage.algebras.hecke_algebras.cubic_hecke_algebra` for more information, in a session type ``sage.algebras.hecke_algebras.cubic_hecke_algebra?``): .. MATH:: - s_i^3 = u s_i^2 - v s_i + w + s_i^3 = u s_i^2 - v s_i + w. The base ring of this algebra can be specified by giving optional keywords - described below. If no keywords are given the base ring will be an instance - of the special class :class:`CubicHeckeRingOfDefinition` which is constructed - as the polynomial ring in `u, v, w` over the integers localized at `w`. + described below. If no keywords are given, the base ring will be a + :class:`CubicHeckeRingOfDefinition`, which is constructed as the + polynomial ring in `u, v, w` over the integers localized at `w`. This ring will be called the *ring of definition* or sometimes for short - *generic base ring*. But note, that in this context the word *generic* + *generic base ring*. However note, that in this context the word *generic* should not remind in a generic point of the corresponding scheme. - In addition to the base ring another ring containing the roots (`a, b` and - `c`) of the cubic equation will be needed to handle the split irreducible - representations. This ring will be called *extension ring*. Generically, the - extension ring will be an instance of the special class - :class:`~sage.algebras.hecke_algebras.cubic_hecke_base_ring.CubicHeckeExtensionRing` + In addition to the base ring, another ring containing the roots (`a`, `b` + and `c`) of the cubic equation will be needed to handle the split + irreducible representations. This ring will be called the *extension ring*. + Generically, the extension ring will be a + :class:`~sage.algebras.hecke_algebras.cubic_hecke_base_ring.CubicHeckeExtensionRing`, which is constructed as the Laurent polynomial ring in `a, b` and `c` over the integers adjoined with a primitive third root of unity. A special form - of this *generic extension ring* is constructed as an instance of + of this *generic extension ring* is constructed as a :class:`~sage.algebras.splitting_algebra.SplittingAlgebra` for the roots of the cubic equation and a primitive third root of unity over the ring of definition. This ring will be called the *default extension ring*. @@ -617,8 +620,8 @@ class CubicHeckeAlgebra(CombinatorialFreeModule): and have been imported from his corresponding `web page `__. - But note that just the data for the cubic Hecke algebras on less than four - strands is available in Sage per default. To deal with four strands and + Note that just the data for the cubic Hecke algebras on less than four + strands is available in Sage by default. To deal with four strands and more you need to install the optional package `database_cubic_hecke `__ by typing @@ -632,10 +635,13 @@ class CubicHeckeAlgebra(CombinatorialFreeModule): around Ivan Marin's data to the Sage library. For more installation hints see the documentation of this wrapper. - Furthermore, representation matrices can be obtained from the *CHEVIE* package - of *GAP3* via the GAP3 interface if GAP3 is installed inside sage. For more - information on how to obtain representation matrices to elements of this - class see the documentation of the matrix-method of the element class: + Furthermore, representation matrices can be obtained from the ``CHEVIE`` + package of ``GAP3`` via the ``GAP3`` interface if ``GAP3`` is installed + inside Sage. For more information on how to obtain representation matrices + to elements of this class, see the documentation of the element class + :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeElement` + or its method + :meth:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeElement.matrix`: ``algebras.CubicHecke.Element?`` or ``algebras.CubicHecke.Element.matrix?`` @@ -666,7 +672,7 @@ class see the documentation of the matrix-method of the element class: EXAMPLES: - 1. cubic Hecke algebra over the ring of definition:: + Cubic Hecke algebra over the ring of definition:: sage: CHA3 = algebras.CubicHecke('s1, s2'); CHA3 Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring @@ -686,7 +692,7 @@ class see the documentation of the matrix-method of the element class: over Multivariate Polynomial Ring in u, v, w over Integer Ring localized at (w,) - 2. element construction:: + Element construction:: sage: ele = CHA3.an_element(); ele (-w)*s1*s2^-1 + v*s1 + u*s2 + ((-v*w+u)/w) @@ -709,8 +715,8 @@ class see the documentation of the matrix-method of the element class: sage: ele4 = CHA4(ele3); ele4 # optional database_cubic_hecke c0*c1*c0^-1*c1 + u*c0^-1*c1*c0 + (-v)*c0*c1^-1 + v*c1^-1*c0 + (-u)*c0*c1*c0^-1 - 3. cubic Hecke algebra over the ring of definition using different variable - names:: + Cubic Hecke algebra over the ring of definition using different variable + names:: sage: algebras.CubicHecke(3, cubic_equation_parameters='u, v, w', cubic_equation_roots='p, q, r') Cubic Hecke algebra on 3 strands over Multivariate Polynomial Ring @@ -724,8 +730,8 @@ class see the documentation of the matrix-method of the element class: over Multivariate Polynomial Ring in u, v, w over Integer Ring localized at (w,) - 4. cubic Hecke algebra over a special base ring with respect to a special - cubic equation:: + Cubic Hecke algebra over a special base ring with respect to a special + cubic equation:: sage: algebras.CubicHecke('s1, s2', cubic_equation_parameters=(QQ(1),3,1)) Cubic Hecke algebra on 3 strands over Rational Field @@ -752,8 +758,8 @@ class see the documentation of the matrix-method of the element class: [2*S^3 + 2*S^2 + 2*S + 1, 2*S^3 + 3*S^2 + 3*S + 2, S^3 + 3] - 5. cubic Hecke algebra over a special extension ring with respect to special - roots of the cubic equation:: + Cubic Hecke algebra over a special extension ring with respect to special + roots of the cubic equation:: sage: UCF = UniversalCyclotomicField() sage: e3=UCF.gen(3); e5=UCF.gen(5) @@ -784,17 +790,6 @@ def __classcall_private__(cls, n=None, names='c', cubic_equation_parameters=None r""" Normalize input to ensure a unique representation. - INPUT: - - - ``n`` -- integer or None (default). The number of strands. If not - specified the "names" are counted and the algebra is assumed to have - one more strand than generators - - - ``names`` -- string or list/tuple/iterable of strings (default:'c'). - The generator names or name prefix. The entry can be either a string - with the names of the generators, or the number of generators and the - prefix - EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2, 'd', cubic_equation_roots=(3,5,7)); CHA2 @@ -815,7 +810,7 @@ def __classcall_private__(cls, n=None, names='c', cubic_equation_parameters=None # Support Freegroup('a,b') syntax if n is not None: try: - n = ZZ(n)-1 + n = ZZ(n) - 1 except TypeError: names = n n = None @@ -1044,7 +1039,6 @@ def check_base_ring_embedding(base_ring_embedding): # ---------------------------------------------------------------------- # registering variables # ---------------------------------------------------------------------- - self._base_ring = base_ring self._extension_ring = extension_ring self._base_ring_embedding = base_ring_embedding self._ring_of_definition_map = base_ring.convert_map_from(ring_of_definition) @@ -1088,7 +1082,7 @@ def check_base_ring_embedding(base_ring_embedding): # is initialized with Marin's list and is extended on demand. # ---------------------------------------------------------------------- db = self._database - ns = min(self.strands(), 4) + ns = min(self._nstrands, 4) self._basis_static = db.read(db.section.basis, nstrands=ns) # ---------------------------------------------------------------------- @@ -1143,44 +1137,42 @@ def _repr_(self): with cubic equation: h^3 - u*h^2 + v*h - w = 0 """ s = 'Cubic Hecke algebra on %s strands over %s with cubic equation: %s = 0' - return s % (self.strands(), self.base_ring(), self.cubic_equation()) + return s % (self._nstrands, self.base_ring(), self.cubic_equation()) def _element_constructor_(self, x): r""" Extensions to the element constructor of class :class:`CombinatorialFreeModule`. + New functionalities are: - -- constructing element from a braid (group homomorphism) - -- constructing element from a braid giving in Tietze form - -- constructing element from an element of the braid group algebra - (algebra homomorphism) - -- constructing element from an element of the cubic braid group - algebra (module homomorphism) - -- constructing element from an element of an other cubic Hecke - algebra over an other base ring or with less strands - -- constructing element from an element of the mirror image of - ``self`` (see method mirror_image) + - constructing element from a braid (group homomorphism) + - constructing element from a braid giving in Tietze form + - constructing element from an element of the braid group algebra + (algebra homomorphism) + - constructing element from an element of the cubic braid group + algebra (module homomorphism) + - constructing element from an element of an other cubic Hecke + algebra over an other base ring or with less strands + - constructing element from an element of the mirror image of + ``self`` (see method mirror_image) INPUT: - ``x`` -- can be one of the following: - -- an instance of the element class of ``self`` (but possible - to a different parent) - -- an instance of the element class of the braid group - -- an instance of the element class of the braid group algebra - over the base ring of ``self`` - -- an instance of the element class of the cubic braid group - -- an instance of the element class of the cubic braid group - algebra over the base ring of ``self`` - -- an instance of the element class of the mirror image of - ``self`` - -- a tuple representing a braid in Tietze form - -- any other object which works for the element constructor - of :class:`CombinatorialFreeModule` - - OUTPUT: - Instance of the element class of ``self``. + * an instance of the element class of ``self`` (but possible + to a different parent) + * an instance of the element class of the braid group + * an instance of the element class of the braid group algebra + over the base ring of ``self`` + * an instance of the element class of the cubic braid group + * an instance of the element class of the cubic braid group + algebra over the base ring of ``self`` + * an instance of the element class of the mirror image of + ``self`` + * a tuple representing a braid in Tietze form + * any other object which works for the element constructor + of :class:`CombinatorialFreeModule` EXAMPLES:: @@ -1264,7 +1256,6 @@ def _element_constructor_(self, x): return self(sub_alg(xb)) elif other_ngens < ngens and other_params == params: - cbraid_preimg = xb.cubic_braid_group_algebra_pre_image() other_cbga = other_cha.cubic_braid_group_algebra() @@ -1292,8 +1283,7 @@ def fb(ele): return result from sage.groups.braid import Braid - if isinstance(xb, Braid) and xb.strands() == self.strands(): - + if isinstance(xb, Braid) and xb.strands() == self._nstrands: result = braid_img(xb) verbose('end from braid_group %s: %s' % (xb, result), level=2) return result @@ -1303,14 +1293,12 @@ def fb(ele): # the same base ring xb the module morphism self._braid_image is applied # ---------------------------------------------------------------------- if isinstance(xb, cbraid_grp_alg.element_class) and xb in cbraid_grp_alg: - result = cbraid_grp_alg._apply_module_morphism(xb, cbraid_img, codomain=self) verbose('end from cubic braid_group algebra %s: %s' % (xb, result), level=2) return result from sage.groups.cubic_braid import CubicBraidElement - if isinstance(xb, CubicBraidElement) and xb.parent().strands() == self.strands(): - + if isinstance(xb, CubicBraidElement) and xb.parent().strands() == self._nstrands: result = cbraid_img(xb) verbose('end from cubic braid_group %s: %s' % (xb, result), level=2) return result @@ -1324,13 +1312,7 @@ def fb(ele): def get_order(self): r""" - Overwrites the corresponding method of :class:`CombinatorialFreeModule`. - The reason is that we have to care about the dynamical growth of the - finite sub basis used for the calculation in case of more than 4 strands. - - To see the documentation of the original method type: - - ``CombinatorialFreeModule.get_order?`` + Return an ordering of the basis of ``self``. EXAMPLES:: @@ -1338,33 +1320,35 @@ def get_order(self): sage: len(CHA3.get_order()) 24 """ - if self.strands() < 5: - return self._order - else: - # detect change of order of sub algebra - cbg = self.cubic_braid_group() - sub_alg = self.cubic_hecke_subalgebra() - former_len_sub = len(sub_alg._order) - sub_order = [cbg(cb) for cb in sub_alg.get_order()] - if former_len_sub == len(sub_order): - if len(self._order) == former_len_sub + len(self._basis_extension): - return self._order - # order has changed! re-calculation necessary: - self._order = sub_order + [cbg(tup) for tup in self._basis_extension] + # The reason we have overriden this is that we have to care about + # the dynamical growth of thefinite sub basis used for the + # calculation in case of more than 4 strands. + + if self._nstrands < 5: return self._order + # detect change of order of sub algebra + cbg = self.cubic_braid_group() + sub_alg = self.cubic_hecke_subalgebra() + former_len_sub = len(sub_alg._order) + sub_order = [cbg(cb) for cb in sub_alg.get_order()] + if former_len_sub == len(sub_order): + if len(self._order) == former_len_sub + len(self._basis_extension): + return self._order + # order has changed! re-calculation necessary: + self._order = sub_order + [cbg(tup) for tup in self._basis_extension] + return self._order + def _dense_free_module(self, base_ring=None): r""" - Overwrites the corresponding method of :class:`CombinatorialFreeModule`. + Return a dense free module with the same dimension as ``self``. + + This overwrites the corresponding method of :class:`CombinatorialFreeModule`. The only difference is, that the dimension is not the dimension of ``self`` but the dimension of the sub-module generated by the dynamically growing basis given by the :meth:`get_order`. In particular there is no difference if the number of strands is less than 5. - To see the documentation of the original method type: - - ``CombinatorialFreeModule._dense_free_module?`` - EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2) @@ -1388,7 +1372,7 @@ def ngens(self): sage: CHA2.ngens() 1 """ - return self.strands() - 1 + return self._nstrands - 1 def algebra_generators(self): r""" @@ -1429,8 +1413,8 @@ def gen(self, i): def one_basis(self): r""" - Return the identity element in the cubic braid group, as per - :meth:`~sage.categories.algebras_with_basis.AlgebrasWithBasis.ParentMethods.one_basis`. + Return the index of the basis element for the identity element + in the cubic braid group. EXAMPLES:: @@ -1454,7 +1438,7 @@ def _an_element_(self): n = self.ngens() + 1 base_ring = self.base_ring() u, v, w = [base_ring(para) for para in self._cubic_equation_parameters] - const = (u*~w - v)*self.one() + const = (u*~w - v) * self.one() gens = self.gens() first_gens = [gen for gen in gens if gens.index(gen) < 3] @@ -1471,8 +1455,8 @@ def _an_element_(self): @cached_method def chevie(self): r""" - Return the *GAP3-CHEVIE* realization of the corresponding *cyclotomic - Hecke algebra* in the finite-dimensional case. + Return the ``GAP3``-``CHEVIE`` realization of the corresponding + cyclotomic Hecke algebra in the finite-dimensional case. EXAMPLES:: @@ -1480,7 +1464,6 @@ def chevie(self): sage: CHA3.chevie() # optional gap3 Hecke(G4,[[a,b,c]]) """ - from sage.combinat.root_system.reflection_group_real import is_chevie_available if not is_chevie_available(): raise NotImplementedError('this functionality needs GAP3 with package CHEVIE') @@ -1514,8 +1497,7 @@ def chevie(self): @cached_method def product_on_basis(self, g1, g2): r""" - Return product on basis elements, as per - :meth:`~sage.categories.magmatic_algebras.MagmaticAlgebras.WithBasis.ParentMethods.product_on_basis` + Return product on basis elements indexed by ``g1`` and ``g2``. EXAMPLES:: @@ -1572,7 +1554,7 @@ def _basis_tietze(self): sage: CHA2._basis_tietze() [[], [1], [-1]] """ - if self.strands() > 4: + if self._nstrands > 4: self_sub = self.cubic_hecke_subalgebra() result_list = self_sub._basis_tietze() + self._basis_extension else: @@ -1582,7 +1564,7 @@ def _basis_tietze(self): def _tietze_to_finite_sub_basis_monomial(self, tietze_tup): r""" Return the monomial corresponding to a Tietze tuple - if it is in the finite sub basis. Else return None. + if it is in the finite sub basis, otherwise return ``None``. EXAMPLES:: @@ -1596,7 +1578,7 @@ def _tietze_to_finite_sub_basis_monomial(self, tietze_tup): in_basis = False if tietze_list in self._basis_tietze(): in_basis = True - elif self.strands() > 4: + elif self._nstrands > 4: fsb_dict = self._finite_sub_basis_tuples if tietze_list in list(fsb_dict.values()): in_basis = True @@ -1608,13 +1590,14 @@ def _tietze_to_finite_sub_basis_monomial(self, tietze_tup): B = self.basis() cb = self.cubic_braid_group()(tietze_tup) return B[cb] - else: - return None + + return None @cached_method def _create_matrix_list_for_one(self, representation_type): r""" - Return the matrix list for the given representation_type for ``self.one()`. + Return the matrix list for the given representation type + for ``self.one()`. EXAMPLES:: @@ -1628,7 +1611,7 @@ def _create_matrix_list_for_one(self, representation_type): [0 0 1] ] """ - n = self.strands() + n = self._nstrands if representation_type.is_split(): gen_base_ring = self.extension_ring(generic=True) rep_ind = [rep.internal_index() for rep in AbsIrreducibeRep if rep.number_gens() == n - 1] @@ -1648,7 +1631,7 @@ def _fetch_matrix_list_from_chevie(self, number): INPUT: - - ``number`` -- integer: number of the representation according to + - ``number`` -- integer; number of the representation according to *CHEVIE* OUTPUT: @@ -1754,14 +1737,16 @@ def _test_ring_constructions(self, **options): # -------------------------------------------------------------------------- def _test_matrix_constructions(self, **options): r""" - Method called by :class:`TestSuite`. + Test that the matrix constructions are valid. The following is checked: - - construction of matrices of the following types - -- ``RepresentationType.SplitIrredChevie`` - -- ``RepresentationType.SplitIrredMarin`` - -- ``RepresentationType.RegularLeft`` + - construction of matrices of the following types: + + * ``RepresentationType.SplitIrredChevie`` + * ``RepresentationType.SplitIrredMarin`` + * ``RepresentationType.RegularLeft`` + - multiplication of matrices and compare with the matrix of the corresponding product of elements - construction of maps between generic base and extension ring and @@ -1810,13 +1795,15 @@ def check_matrix(representation_type): # -------------------------------------------------------------------------- def _init_basis_extension(self): r""" - Return the extension of the basis for more than 4 strands hold in file - cache. The basis elements from the file are added to the elements of the - Marin basis. + Return the extension of the basis for more than 4 strands hold + in file cache. + + The basis elements from the file are added to the elements of + the Marin basis. EXAMPLES:: - sage: CHA5 = algebras.CubicHecke(5) # optional - database_cubic_hecke # indirect doctest + sage: CHA5 = algebras.CubicHecke(5) # optional - database_cubic_hecke # indirect doctest sage: fc = CHA5._filecache # optional - database_cubic_hecke sage: be = fc.section.basis_extensions # optional - database_cubic_hecke sage: CHA5.reset_filecache(be) # optional - database_cubic_hecke @@ -1825,7 +1812,7 @@ def _init_basis_extension(self): sage: ele = CHA5.an_element() # optional - database_cubic_hecke sage: CHA5.inject_variables() # optional - database_cubic_hecke Defining c0, c1, c2, c3 - sage: ele2 = ele*c3 # optional - database_cubic_hecke + sage: ele2 = ele * c3 # optional - database_cubic_hecke sage: bex = fc.read(be) # optional - database_cubic_hecke sage: bex.sort(); bex # optional - database_cubic_hecke [[-4], [1, -3, 4], [1, -2, 4], [3, 2, 4], [4]] @@ -1838,7 +1825,7 @@ def _init_basis_extension(self): self.set_order(order_list) verbose('finite sub basis length: %s' % (len(order_list)), level=2) - if self.strands() < 5: + if self._nstrands < 5: return # ---------------------------------------------------------------------- # loading the extension of the basis from data file @@ -1850,7 +1837,7 @@ def _init_basis_extension(self): # pre definition of additional basis elements # ---------------------------------------------------------------------- cub_braid_group = self.cubic_braid_group() - if len(former_bas_ext) == 0: + if not former_bas_ext: gens = cub_braid_group.gens() last_gen = gens[len(gens)-1] self._cubic_braid_image(last_gen, check=False) @@ -1884,8 +1871,8 @@ def _braid_image_from_filecache(self, braid): OUTPUT: - Image of braid as element of ``self``. None if the product has not been - stored. + Image of braid as element of ``self``. ``None`` if the product has + not been stored. EXAMPLES:: @@ -1898,7 +1885,7 @@ def _braid_image_from_filecache(self, braid): sage: CHA3F = algebras.CubicHecke(3, cubic_equation_parameters=par) sage: CHA3F._braid_image_from_filecache(br) 1/w*c0*c1*c0^-1*c1 + v/w*c1^-1*c0 + ((-u)/w)*c0*c1*c0^-1 - sage: section = CHA3.select_filecache_section().braid_images + sage: section = CHA3.filecache_section().braid_images sage: CHA3.reset_filecache(section) sage: CHA3._braid_image_from_filecache(br) """ @@ -1929,13 +1916,13 @@ def _braid_image_to_filecache(self, braid_tietze, braid_image_vect): sage: CHA2 = algebras.CubicHecke(2) sage: br, = CHA2.braid_group().gens(); br2 = br**2 - sage: section = CHA2.select_filecache_section().braid_images + sage: section = CHA2.filecache_section().braid_images sage: CHA2.is_filecache_empty(section) # note: 2-strand images are not automatically cached in file system True sage: CHA2._braid_image_to_filecache(br2.Tietze(), CHA2(br2).to_vector()) sage: CHA2._braid_image_from_filecache(br2) w*c^-1 + u*c + (-v) - sage: CHA2.reset_filecache(CHA2.select_filecache_section().braid_images) + sage: CHA2.reset_filecache(CHA2.filecache_section().braid_images) sage: CHA2._braid_image_from_filecache(br2) == None True """ @@ -1956,7 +1943,7 @@ def _braid_image(self, braid): INPUT: - - ``braid`` - instance of :class:`~sage.groups.braid.Braid`, whose image + - ``braid`` -- :class:`~sage.groups.braid.Braid` whose image in ``self`` should be calculated OUTPUT: @@ -1998,10 +1985,10 @@ def _braid_image_from_reduced_powers(self, braid_tietze): INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose image in - ``self`` should be computed. It is assumed that no successive - repetitions occur among the entries (i.e. (1,1) is not allowed - but (1, -2, 1) is) + - ``braid_tietze`` -- tuple representing the Braid whose image in + ``self`` should be computed; it is assumed that no successive + repetitions occur among the entries (i.e. ``(1, 1)`` is not allowed + but ``(1, -2, 1)`` is) OUTPUT: @@ -2099,9 +2086,9 @@ def _braid_image_from_former_calculations(self, braid_tietze): INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose image in - ``self`` should be computed. The generator exponents in the braid - word are assumed to be 1 or -1 + - ``braid_tietze`` -- tuple representing the braid whose image in + ``self`` should be computed; he generator exponents in the braid + word are assumed to be ``1`` or ``-1`` OUTPUT: @@ -2174,8 +2161,8 @@ def _braid_image_from_former_calculations(self, braid_tietze): if len(word_decomp_left_result) >= len(word_decomp_right_result): return result_left, ([braid_tietze[0]] + word_decomp_left_left, word_decomp_left_result, word_decomp_left_right) - else: - return result_right, (word_decomp_right_left, word_decomp_right_result, word_decomp_right_right + [braid_tietze[len_braid - 1]]) + + return result_right, (word_decomp_right_left, word_decomp_right_result, word_decomp_right_right + [braid_tietze[len_braid - 1]]) # -------------------------------------------------------------------------- # _braid_image_by_basis_expansion_ @@ -2189,9 +2176,9 @@ def _braid_image_by_basis_extension(self, braid_tietze): INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose image in - ``self`` should be computed. The generator exponents in the braid - word are assumed to be 1 or -1 + - ``braid_tietze`` -- tuple representing the braid whose image in + ``self`` should be computed; he generator exponents in the braid + word are assumed to be ``1`` or ``-1`` OUTPUT: @@ -2200,7 +2187,7 @@ def _braid_image_by_basis_extension(self, braid_tietze): EXAMPLES:: sage: CHA5 = algebras.CubicHecke(5) # optional - database_cubic_hecke - sage: be = CHA5.select_filecache_section().basis_extensions # optional - database_cubic_hecke + sage: be = CHA5.filecache_section().basis_extensions # optional - database_cubic_hecke sage: CHA5.reset_filecache(be) # optional - database_cubic_hecke sage: CHA5._basis_extension # optional - database_cubic_hecke [[4], [-4]] @@ -2223,7 +2210,6 @@ def _braid_image_by_basis_extension(self, braid_tietze): Traceback (most recent call last): ... NotImplementedError: no algorithm available to calculate braid image of (1, 1) - """ cubic_braid = self._cubic_braid_group(braid_tietze) tup = self._cubic_braid_basis_tuple(cubic_braid) @@ -2243,14 +2229,15 @@ def _braid_image_by_basis_extension(self, braid_tietze): @cached_method def _reduce_all_gen_powers(self, braid_tietze): r""" - Return a linear combination of braids that have no higher powers in the + Return a linear combination of braids that have no higher powers in the braid generators having the same image in ``self`` than the given braid. + This linear combination is returned as a pair of lists of braids and corresponding coefficients. INPUT: - - ``braid_tietze`` -- tuple representing the Braid whose powers should + - ``braid_tietze`` -- tuple representing the braid whose powers should be reduced given in Tietze form OUTPUT: @@ -2344,7 +2331,8 @@ def _reduce_all_gen_powers(self, braid_tietze): @cached_method def _reduce_gen_power(self, k): r""" - Return the ``k``-th power on an arbitrary generator, for example ``c0^k` . + Return the ``k``-th power on an arbitrary generator, + for example ``c0^k` . INPUT: @@ -2352,7 +2340,7 @@ def _reduce_gen_power(self, k): OUTPUT: - A list [coeff_one, coeff_gen, coeff_gen_inverse] of the three + A list ``[coeff_one, coeff_gen, coeff_gen_inverse]`` of the three coefficients of the generators power in the span of the generator. EXAMPLES:: @@ -2401,9 +2389,10 @@ def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preim r""" Return the product of an`element of ``self`` given as a coefficient vector with a sequence (tuple) of generators (that is a braid word) - using regular representation matrices. The multiplication will be - performed form left or right according to the given - ``representation_type``. + using regular representation matrices. + + The multiplication will be performed form left or right according + to the given ``representation_type``. INPUT: @@ -2483,13 +2472,15 @@ def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preim def _cubic_braid_append_to_basis(self, cubic_braid): r""" Append the given cubic braid to the finite sub basis which is used for - calculation of products and representation matrices. This only makes - sense if the ``cubic_braid`` is not in this finite sub basis, before. - This can happen if the number of strands is more than 4. + calculation of products and representation matrices. + + This only makes sense if the ``cubic_braid`` is not in this finite + sub-basis, before. This can happen if the number of strands is more + than 4. INPUT: - - ``cubic_braid`` -- instance of the :class:`~sage.groups.cubic_braid.CubicBraid` + - ``cubic_braid`` -- :class:`~sage.groups.cubic_braid.CubicBraid` whose image in ``self`` should be appended OUTPUT: @@ -2499,7 +2490,7 @@ def _cubic_braid_append_to_basis(self, cubic_braid): EXAMPLES:: sage: CHA5 = algebras.CubicHecke(5) # optional - database_cubic_hecke - sage: be = CHA5.select_filecache_section().basis_extensions # optional - database_cubic_hecke + sage: be = CHA5.filecache_section().basis_extensions # optional - database_cubic_hecke sage: CHA5.reset_filecache(be) # optional - database_cubic_hecke sage: CHA5._basis_extension # optional - database_cubic_hecke [[4], [-4]] @@ -2530,13 +2521,15 @@ def _cubic_braid_append_to_basis(self, cubic_braid): def _cubic_braid_basis_tuple(self, cubic_braid): r""" Return the Tietze tuple that represents the given cubic_braid in the - basis of ``self``. In the case ``self`` has more than 4 strands it may - happen that the given cubic braid is not contained in the finite sub - basis, so far. In this case it is automatically added to it. + basis of ``self``. + + In the case ``self`` has more than 4 strands it may happen that the + given cubic braid is not contained in the finite subbasis, so far. + In this case it is automatically added to it. INPUT: - - ``cubic_braid`` -- instance of the :class:`~sage.groups.cubic_braid.CubicBraid` + - ``cubic_braid`` -- :class:`~sage.groups.cubic_braid.CubicBraid` OUTPUT: @@ -2574,22 +2567,20 @@ def _cubic_braid_basis_tuple(self, cubic_braid): def _cubic_braid_image(self, cubic_braid, check=True): r""" Return the given cubic braid as monomial of ``self``, that is the image - under the map onto the basis. If the number of strands is larger than 4, - the corresponding basis element may not be contained in the order of - ``self``. In this case it will be appended here. + under the map onto the basis. + + If the number of strands is larger than 4, the corresponding basis + element may not be contained in the order of ``self``. In this + case it will be appended here. INPUT: - - ``cubic_braid`` -- instance of :class:`~sage.groups.cubic_braid.CubicBraid` + - ``cubic_braid`` -- :class:`~sage.groups.cubic_braid.CubicBraid` whose image in ``self`` should be returned - - ``check`` -- (optional) boolean (default=True) to check in the given - cubic braid is already registered in the finite sub basis. If set to + - ``check`` -- boolean (default: ``True``); check in the given cubic + braid is already registered in the finite sub basis; if set to ``False`` duplicate entries can occur. - OUTPUT: - - Instance of the element class of ``self``. - EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2) @@ -2614,13 +2605,13 @@ def _extend_braid_automorphism(self, element, braid_automorphism): INPUT: - - ``element`` -- instance of the element class of ``self`` + - ``element`` -- an element class of ``self`` - ``braid_automorphism`` -- braid group automorphism factoring through ``self`` OUTPUT: - Instance of the element class of ``self`` representing the image of element + Element class of ``self`` representing the image of element under the extension of the given braid group automorphism. EXAMPLES:: @@ -2648,18 +2639,18 @@ def _markov_trace_module(self, extended=False, field_embedding=False): INPUT: - - ``extended`` -- boolean (default ``False``) if set to ``True`` the + - ``extended`` -- boolean (default: ``False``); if set to ``True`` the base ring of the module is the Markov trace version of the generic extension ring of ``self``. - - ``field_embedding`` -- boolean (default ``False``) if set to ``True` + - ``field_embedding`` -- boolean (default: ``False``); if set to ``True` the base ring of the module is the smallest field containing the generic extension ring of ``self``. The keyword is meaningless if ``extended=False``. OUTPUT: - An instance of :class:`~sage.combinat.free_module.CombinatorialFreeModule`. + A :class:`~sage.combinat.free_module.CombinatorialFreeModule`. EXAMPLES:: @@ -2682,7 +2673,7 @@ def _markov_trace_module(self, extended=False, field_embedding=False): """ from sage.modules.free_module import FreeModule from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis - basis = [b for b in MarkovTraceModuleBasis if b.strands() <= self.strands()] + basis = [b for b in MarkovTraceModuleBasis if b.strands() <= self._nstrands] BRM = self.base_ring(generic=True).markov_trace_version() if extended: BRM = BRM.extension_ring() @@ -2719,7 +2710,7 @@ def _markov_trace_coeffs(self): Mbas = M.basis().keys() db = self._database sec = db.section.markov_tr_cfs - cfs = db.read(sec, variables=M.base_ring().gens(), nstrands=self.strands()) + cfs = db.read(sec, variables=M.base_ring().gens(), nstrands=self._nstrands) d = self.dimension() return [sum(cfs[bas_ele][i]*M(bas_ele) for bas_ele in Mbas) for i in range(d)] @@ -2728,14 +2719,14 @@ def _markov_trace_coeffs(self): # public methods # -------------------------------------------------------------------------- ############################################################################ - def select_filecache_section(self): + def filecache_section(self): r""" Return the ``enum`` to select a section in the file cache. EXAMPLES:: sage: CHA2 = algebras.CubicHecke(2) - sage: list(CHA2.select_filecache_section()) + sage: list(CHA2.filecache_section()) [, , , @@ -2751,9 +2742,9 @@ def is_filecache_empty(self, section=None): INPUT: - - ``section`` -- (default is ``None`` meaning all sections) instance - of enum :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` - which can be selected using :meth:`select_filecache_section` + - ``section`` -- (default: all sections) an element of enum + :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` + that can be selected using :meth:`filecache_section` EXAMPLES:: @@ -2770,17 +2761,16 @@ def reset_filecache(self, section=None, commit=True): INPUT: - - ``section`` -- (default is ``None`` meaning all sections) instance - of enum :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` - which can be selected using :meth:`select_filecache_section` - - - ``commit`` -- boolean (default is ``True``) if set to ``False`` the + - ``section`` -- (default: all sections) an element of enum + :class:`~sage.databases.cubic_hecke_db.CubicHeckeFileCache.section` + that can be selected using :meth:`filecache_section` + - ``commit`` -- boolean (default: ``True``); if set to ``False`` the reset is not written to the filesystem EXAMPLES:: sage: CHA5 = algebras.CubicHecke(5) # optional - database_cubic_hecke - sage: be = CHA5.select_filecache_section().basis_extensions # optional - database_cubic_hecke + sage: be = CHA5.filecache_section().basis_extensions # optional - database_cubic_hecke sage: CHA5.is_filecache_empty(be) # optional - database_cubic_hecke False sage: CHA5.reset_filecache(be) # optional - database_cubic_hecke @@ -2789,7 +2779,7 @@ def reset_filecache(self, section=None, commit=True): """ fc = self._filecache if section == fc.section.basis_extensions: - if self.strands() < 5: + if self._nstrands < 5: raise ValueError('not allowed for less than 5 strand') fc.reset_library(section=section) @@ -2803,13 +2793,11 @@ def strands(self): Return the number of strands of the braid group whose group algebra image is ``self``. - OUTPUT: Integer. - EXAMPLES:: - sage: CHA4 = algebras.CubicHecke(4) # optional - database_cubic_hecke - sage: CHA4.strands() # optional - database_cubic_hecke - 4 + sage: CHA4 = algebras.CubicHecke(2) + sage: CHA4.strands() + 2 """ return self._nstrands @@ -2924,7 +2912,7 @@ def mirror_isomorphism(self, element): sage: ele = CHA3.an_element() sage: ele_mirr = CHA3.mirror_isomorphism(ele); ele_mirr -1/w*c0^-1*c1 + u/w*c0^-1 + v/w*c1^-1 + ((v*w-u)/w) - sage: ele_mirr2 = ele.revert_mirror() # indirect doctest + sage: ele_mirr2 = ele.revert_mirror() # indirect doctest sage: ele_mirr == ele_mirr2 True sage: par_mirr = ele_mirr.parent() @@ -2955,9 +2943,9 @@ def cubic_equation(self, var='h', as_coefficients=False, generic=False): - ``var`` -- string (default ``h``) setting the indeterminate of the equation - - ``as_coefficients`` -- boolean (default ``False``) if set to ``True`` + - ``as_coefficients`` -- boolean (default: ``False``); if set to ``True`` the list of coefficients is returned - - ``generic`` -- boolean (default ``False``) if set to ``True`` the + - ``generic`` -- boolean (default: ``False``); if set to ``True`` the cubic equation will be given over the generic base ring OUTPUT: @@ -2968,7 +2956,7 @@ def cubic_equation(self, var='h', as_coefficients=False, generic=False): EXAMPLES:: - sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (E(3), ~E(3), 1)) + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(E(3), ~E(3), 1)) sage: CHA2.cubic_equation() h^3 - 1 sage: CHA2.cubic_equation(generic=True) @@ -2999,7 +2987,7 @@ def cubic_equation_roots(self, generic=False): INPUT: - - ``generic`` -- boolean (default ``False``) if set to ``True`` the + - ``generic`` -- boolean (default: ``False``); if set to ``True`` the roots are returned as elements of the generic extension ring OUTPUT: @@ -3008,7 +2996,7 @@ def cubic_equation_roots(self, generic=False): EXAMPLES:: - sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3, 4, 5)) sage: CHA2.cubic_equation() h^3 - 12*h^2 + 47*h - 60 sage: CHA2.cubic_equation_roots() @@ -3030,7 +3018,7 @@ def cubic_equation_parameters(self, generic=False): INPUT: - - ``generic`` -- boolean (default ``False``) if set to ``True`` the + - ``generic`` -- boolean (default: ``False``); if set to ``True`` the coefficients are returned as elements of the generic base ring OUTPUT: @@ -3039,7 +3027,7 @@ def cubic_equation_parameters(self, generic=False): EXAMPLES:: - sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3, 4, 5)) sage: CHA2.cubic_equation() h^3 - 12*h^2 + 47*h - 60 sage: CHA2.cubic_equation_parameters() @@ -3057,21 +3045,16 @@ def cubic_equation_parameters(self, generic=False): # -------------------------------------------------------------------------- def base_ring(self, generic=False): r""" - Return the base ring of the cubic Hecke algebra. + Return the base ring of ``self``. INPUT: - - ``generic`` -- boolean (default ``False``) if set to ``True`` the ring + - ``generic`` -- boolean (default: ``False``); if ``True`` the ring of definition (here often called the generic base ring) is returned - OUTPUT: - - An instance of :class:`Ring`. If ``generic`` is set ``True`` this will - be an instance of :class:`CubicHeckeRingOfDefinition`, as well. - EXAMMPLES:: - sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3, 4, 5)) sage: CHA2.base_ring() Integer Ring localized at (2, 3, 5) sage: CHA2.base_ring(generic=True) @@ -3081,30 +3064,27 @@ def base_ring(self, generic=False): if generic: return self._ring_of_definition else: - return self._base_ring + return super().base_ring() # -------------------------------------------------------------------------- # extension_ring # -------------------------------------------------------------------------- def extension_ring(self, generic=False): r""" - Return the extension ring of the cubic Hecke algebra. This is an - extension of its base ring containing the roots of the cubic equation. + Return the extension ring of ``self``. + + This is an extension of its base ring containing the roots + of the cubic equation. INPUT: - - ``generic`` -- boolean (default ``False``) if set to ``True`` the + - ``generic`` -- boolean (default: ``False``); if ``True`` the extension ring of definition (here often called the generic extension ring) is returned - OUTPUT: - - An instance of :class:`Ring`. If ``generic`` is set ``True`` this will - be an instance of :class:`CubicHeckeExtensionRing`, as well. - EXAMMPLES:: - sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3, 4, 5)) sage: CHA2.extension_ring() Splitting Algebra of T^2 + T + 1 with roots [E3, -E3 - 1] over Integer Ring localized at (2, 3, 5) @@ -3123,26 +3103,21 @@ def extension_ring(self, generic=False): # -------------------------------------------------------------------------- def cyclotomic_generator(self, generic=False): r""" - Return the third root of unity as element of the extension ring. The - only thing where this is needed is in the nine dimensional irreducible - representations of the cubic Hecke algebra on four strands (see the - examples of :meth:`CubicHeckeElement.matrix` for instance). + Return the third root of unity as element of the extension ring. + + The only thing where this is needed is in the nine dimensional + irreducible representations of the cubic Hecke algebra on four strands + (see the examples of :meth:`CubicHeckeElement.matrix` for instance). INPUT: - - ``generic`` -- boolean (default ``False``) if set to ``True`` the - cyclotomic_generator is returned as an element extension ring of + - ``generic`` -- boolean (default: ``False``); if ``True`` the + cyclotomic generator is returned as an element extension ring of definition - OUTPUT: - - An element with parent :class:`Ring`. If ``generic`` is set ``True`` - the parent will be an instance of :class:`CubicHeckeExtensionRing`, - as well. - EXAMMPLES:: - sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2 = algebras.CubicHecke(2, cubic_equation_roots=(3, 4, 5)) sage: CHA2.cyclotomic_generator() E3 sage: CHA2.cyclotomic_generator(generic=True) @@ -3225,13 +3200,13 @@ def cubic_braid_group_algebra(self): # -------------------------------------------------------------------------- def cubic_hecke_subalgebra(self, nstrands=None): r""" - Return an instance of :class:`CubicHeckeAlgebra` which realizes a - sub-algebra of ``self`` on the first ``n_strands`` strands. + Return a :class:`CubicHeckeAlgebra` that realizes a sub-algebra + of ``self`` on the first ``n_strands`` strands. INPUT: - - ``nstrands`` -- integer ``> 0`` and `` < self.strands()`` giving - the number of strands for the subgroup. The default is one strand + - ``nstrands`` -- integer at least 1 and at most :meth:`strands` giving + the number of strands for the subgroup; the default is one strand less than ``self`` has OUTPUT: @@ -3240,22 +3215,22 @@ def cubic_hecke_subalgebra(self, nstrands=None): EXAMPLES:: - sage: CHA3 = algebras.CubicHecke(3, cubic_equation_roots = (3, 4, 5)) + sage: CHA3 = algebras.CubicHecke(3, cubic_equation_roots=(3, 4, 5)) sage: CHA3.cubic_hecke_subalgebra() Cubic Hecke algebra on 2 strands over Integer Ring localized at (2, 3, 5) with cubic equation: h^3 - 12*h^2 + 47*h - 60 = 0 """ if nstrands is None: - nstrands = self.strands() - 1 - n = self.strands() + nstrands = self._nstrands - 1 + n = self._nstrands nstrands = ZZ(nstrands) if nstrands >= n or nstrands <= 0: - raise ValueError('nstrands must be positive and less than %s' % self.strands()) + raise ValueError('nstrands must be positive and less than %s' % self._nstrands) Gens = self.gens() - if nstrands == self.strands() - 1 and self._cubic_hecke_subalgebra is not None: + if nstrands == self._nstrands - 1 and self._cubic_hecke_subalgebra is not None: return self._cubic_hecke_subalgebra gen_range = range(nstrands - 1) @@ -3267,7 +3242,7 @@ def cubic_hecke_subalgebra(self, nstrands=None): cubic_equation_parameters=tuple(self._cubic_equation_parameters), cubic_equation_roots=tuple(self._cubic_equation_roots)) - if nstrands == self.strands() - 1: + if nstrands == self._nstrands - 1: self._cubic_hecke_subalgebra = SubHeckeAlg return SubHeckeAlg @@ -3276,18 +3251,20 @@ def cubic_hecke_subalgebra(self, nstrands=None): # -------------------------------------------------------------------------- def mirror_image(self): r""" - Return a copy of ``self`` with the mirrored cubic equation, that is: the - cubic equation has the inverse roots to the roots with respect to - ``self``. This is needed since the mirror involution of the braid group - does not factor through ``self`` (considered as an algebra over the base - ring, just considered as ``ZZ``-algebra). Therefore, the mirror involution - of an element of ``self`` belongs to ``mirror_image``. + Return a copy of ``self`` with the mirrored cubic equation, that is: + the cubic equation has the inverse roots to the roots with respect + to ``self``. + + This is needed since the mirror involution of the braid group does + not factor through ``self`` (considered as an algebra over the base + ring, just considered as `\ZZ`-algebra). Therefore, the mirror + involution of an element of ``self`` belongs to ``mirror_image``. OUTPUT: - An instance of the class of ``self`` over the same base and extension - ring, but whose cubic equation is transformed by the mirror involution - applied to its coefficients resp. roots. + A cubic Hecke algebra over the same base and extension ring, + but whose cubic equation is transformed by the mirror involution + applied to its coefficients and roots. EXAMPLES:: @@ -3306,7 +3283,7 @@ def mirror_image(self): sage: cem == cem.parent()([mi(cf) for cf in ce.coefficients()]) True - Note, that both cubic Hecke algebras have the same ring of definition + Note that both cubic Hecke algebras have the same ring of definition and identical generic cubic equation:: sage: cemg = CHA2m.cubic_equation(generic=True) @@ -3337,13 +3314,13 @@ def mirror_image(self): algebras if the specialization does not factor through the mirror involution on the ring if definition:: - sage: CHA2s = algebras.CubicHecke(2, cubic_equation_roots = (3, 4, 5)) + sage: CHA2s = algebras.CubicHecke(2, cubic_equation_roots=(3, 4, 5)) sage: CHA2s Cubic Hecke algebra on 2 strands over Integer Ring localized at (2, 3, 5) with cubic equation: h^3 - 12*h^2 + 47*h - 60 = 0 - In the next example it isn't clear what the mirror image of ``7`` + In the next example it is not clear what the mirror image of ``7`` should be:: sage: CHA2s.mirror_image() @@ -3384,7 +3361,7 @@ def mirror_image(self): mirr_paras = tuple([base_ring(par) for par in mirr_paras_gen]) mirr_roots = tuple([extension_ring(root) for root in mirr_roots_gen]) - n = self.strands() + n = self._nstrands mirror_image = CubicHeckeAlgebra(n, cubic_equation_parameters=mirr_paras, cubic_equation_roots=mirr_roots) @@ -3406,11 +3383,13 @@ def schur_elements(self, generic=False): Return the list of Schur elements of ``self`` as elements of the extension ring of ``self``. - This method needs *GAP3* installed with package *CHEVIE* + .. NOTE:: + + This method needs ``GAP3`` installed with package ``CHEVIE``. INPUT: - - ``generic`` -- boolean (default False). If set to ``True`` + - ``generic`` -- boolean (default: ``False``); if ``True``, the element is returned as element of the generic extension ring @@ -3438,14 +3417,16 @@ def schur_element(self, item, generic=False): Return a single Schur element of ``self`` as elements of the extension ring of ``self``. - This method needs *GAP3* installed with package *CHEVIE* + .. NOTE:: + + This method needs ``GAP3`` installed with package ``CHEVIE``. INPUT: - - ``item`` -- instance of Enum :class:`AbsIrreducibeRep` to give + - ``item`` -- an element of :class:`AbsIrreducibeRep` to give the irreducible representation of ``self`` to which the Schur element should be returned - - ``generic`` -- boolean (default False). If set to True + - ``generic`` -- boolean (default: ``False``); if ``True``, the element is returned as element of the generic extension ring @@ -3464,17 +3445,19 @@ def schur_element(self, item, generic=False): # -------------------------------------------------------------------------- def characters(self, irr=None, original=True): r""" - Return the irreducible characters of ``self``. By default the values - are given in the generic extension ring. Setting the keyword ``original`` - to ``False`` you can obtain the values in the (non generic) extension - ring (compare the same keyword for :meth:`matrix`). + Return the irreducible characters of ``self``. + + By default the values are given in the generic extension ring. + Setting the keyword ``original`` to ``False`` you can obtain + the values in the (non generic) extension ring (compare the + same keyword for :meth:`CubicHeckeElement.matrix`). INPUT: - ``irr`` -- (optional) instance of :class:`AbsIrreducibeRep` selecting the irreducible representation corresponding to the - character. If not given a list of all characters is returned - - ``original`` -- (default ``True``) see description above + character; if not given a list of all characters is returned + - ``original`` -- (default ``True``) see description above OUTPUT: @@ -3512,5 +3495,6 @@ def char_function(ele): return m[irr].trace() if irr: return char_function - irrs = [irr for irr in self.irred_repr if irr.number_gens() == self.strands() - 1] + irrs = [irr for irr in self.irred_repr if irr.number_gens() == self._nstrands - 1] return [self.characters(irrs[i], original=original) for i in range(len(irrs))] + diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py index 7015b438fb3..d30633cad55 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -1,11 +1,11 @@ -# -*- coding: utf-8 -*- r""" Cubic Hecke Base Rings This module contains special classes of polynomial rings -(:class:`CubicHeckeRingOfDefinition` and :class:`CubicHeckeExtensionRing`) used -in the context of cubic Hecke algebras -(:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra`). +(:class:`CubicHeckeRingOfDefinition` and :class:`CubicHeckeExtensionRing`) +used in the context of +:class:`cubic Hecke algebras +`. AUTHORS: @@ -41,14 +41,14 @@ def normalize_names_markov(names, markov_trace_version): r""" Return a tuple of strings of variable names of length 3 resp. 4 (if - ``markov_trace_version == True``) according to the given input names. + ``markov_trace_version`` is ``True``) according to the given input names. INPUT: - - `names` -- passed to :func:`~sage.structure.category_object.noramize_names` - - `markov_trace_version` -- boolean if set to ``True`` four names are - expected the last of which corresponds to the writhe factor of the - Markov trace + - ``names`` -- passed to :func:`~sage.structure.category_object.normalize_names` + - ``markov_trace_version`` -- boolean; if set to ``True`` four names are + expected the last of which corresponds to the writhe factor of the + Markov trace EXAMPLES:: @@ -72,8 +72,7 @@ def normalize_names_markov(names, markov_trace_version): def register_ring_hom(ring_hom): r""" - This function tries to register the given ring homomorphism as conversion - map. + Register the given ring homomorphism as conversion map. EXAMPLES:: @@ -133,7 +132,7 @@ class GaloisGroupAction(Action): """ def _act_(self, perm, pol): r""" - Application of the action + Application of the action. EXAMPLES:: @@ -151,9 +150,9 @@ def _act_(self, perm, pol): perm, pol = pol, perm pol_dict = {} for key, value in pol.dict().items(): - newkey = [0]*len(key) - for pos in range(len(key)): - newkey[perm(pos+1)-1] = key[pos] + newkey = [0] * len(key) + for pos, k in enumerate(key): + newkey[perm(pos+1)-1] = k pol_dict[tuple(newkey)] = value return self.domain()(pol_dict) @@ -169,12 +168,13 @@ def _act_(self, perm, pol): # ------------------------------------------------------------------------------ class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): r""" - This class implements the generic splitting algebra for the irreducible - representations of the cubic Hecke algebra. + The generic splitting algebra for the irreducible representations of + the cubic Hecke algebra. - This ring must contain three invertible indeterminates (representing the - roots of the cubic equation) together with a third root of unity (needed - for the 18-dimensional irreducibles of the cubic Hecke algebra on 4 strands). + This ring must contain three invertible indeterminates (representing + the roots of the cubic equation) together with a third root of unity + (needed for the 18-dimensional irreducibles of the cubic Hecke algebra + on 4 strands). Therefore this ring is constructed as a multivariate Laurent polynomial ring in three indeterminates over a polynomial quotient ring over the @@ -185,18 +185,17 @@ class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): INPUT: - - ``names`` -- string containing the names of the indeterminates separated - by ',' or a triple of strings each of which is the name of one of the - three indeterminates. The default is ``u, v, w`` - - ``order`` -- string (default='degrevlex') transferred to the - corresponding input of LaurentPolynomialRing_mpair - - ``ring_of_definition`` -- instance of CubicHeckeRingOfDefinition - (default=None) to specify the generic cubic Hecke base ring over which - self may be realized as splitting ring via the ``as_splitting_algebra`` - method - - ``third_unity_root_name`` -- string (default is ``e3``) for setting the + - ``names`` -- (default: ``'u,v,w'``) string containing the names of the + indeterminates separated by ``,`` or a triple of strings each of which + are the names of one of the three indeterminates + - ``order`` -- string (default: ``'degrevlex'``); the term order; see also + :class:`~sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_mpair` + - ``ring_of_definition`` -- (optional) a :class:`CubicHeckeRingOfDefinition` + to specify the generic cubic Hecke base ring over which ``self`` may be + realized as splitting ring via the ``as_splitting_algebra`` method + - ``third_unity_root_name`` -- string (default: ``'e3'``); for setting the name of the third root if unity of ``self`` - - ``markov_trace_version`` -- boolean (default is ``False``). If this is + - ``markov_trace_version`` -- boolean (default: ``False``) if this is set to ``True`` then ``self`` contains one invertible indeterminate in addition which is meant to represent the writhe factor of a Markov trace on the cubic Hecke algebra and which default name is ``s`` @@ -214,7 +213,7 @@ class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): """ def __init__(self, names, order='degrevlex', ring_of_definition=None, third_unity_root_name='e3', markov_trace_version=False): r""" - Python constructor. + Initialize ``self``. TESTS:: @@ -296,7 +295,7 @@ def __reduce__(self): def _element_constructor_(self, x, mon=None): r""" Inherited element constructor overloaded to allow construction from - *GAP3* *Mvp* expressions. + ``GAP3`` ``MVP`` expressions. EXAMPLES:: @@ -356,14 +355,12 @@ def _coerce_map_from_(self, R): def hom(self, im_gens, codomain=None, check=True, base_map=None): r""" - Custom version overloading the corresponding method of class - :class:`~sage.structure.parent_gens.ParentWithGens` because of special - effort with respect to the third root of unity. + Return a homomorphism of ``self``. - INPUT: according to the class :class:`~sage.structure.parent_gens.ParentWithGens`. - For more information type ``ParentWithGens.hom?`` + INPUT: - OUTPUT: according to the :class:`~sage.structure.parent_gens.ParentWithGens`. + - ``im_gens`` -- tuple for the image of the generators of ``self`` + - ``codomain`` -- (optional) the codomain of the homomorphism EXAMPLES:: @@ -396,8 +393,7 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): def _an_element_(self): r""" - Overwrite the original method to obtain a more interesting element for - ``TestSuite``. + Return an element of ``self``. EXAMPLES:: @@ -441,17 +437,13 @@ def _is_markov_trace_version(self): # -------------------------------------------------------------------------- def _convert_from_gap3_mvp(self, mvp_expression): r""" - Convert a string produced via *GAP3* interface and containing Jean - Michel's *MVP* (multivariate polynomials) to an element of ``self``. + Convert a string produced via ``GAP3`` interface and containing Jean + Michel's ``MVP`` (multivariate polynomials) to an element of ``self``. INPUT: - ``string`` -- string produced via GAP3 interface and containing - Jean Michel's *MVP* (multivariate polynomials) - - OUTPUT: - - An instance of the element class of ``self``. + Jean Michel's ``MVP`` (multivariate polynomials) EXAMPLES:: @@ -484,7 +476,8 @@ def _convert_from_gap3_mvp(self, mvp_expression): ############################################################################ def cyclotomic_generator(self): r""" - Return the third root of unity as generator of the base ring of ``self``. + Return the third root of unity as generator of the base ring + of ``self``. EXAMPLES:: @@ -499,8 +492,8 @@ def cyclotomic_generator(self): def conjugation(self): r""" - Return an involution that performs *complex conjugation* with respect to - base ring considered as order in the complex field. + Return an involution that performs *complex conjugation* with respect + to base ring considered as order in the complex field. EXAMPLES:: @@ -536,21 +529,21 @@ def cubic_equation_galois_group(self): ((1,3), a^-1*b^2 + e3*c), ((1,2), a^2*c^-1 + e3*b)] """ - return self._galois_group def mirror_involution(self): r""" Return the involution of ``self`` corresponding to the involution of - the cubic Hecke algebra (with the same name). This means that it maps - the generators of ``self`` to their inverses. + the cubic Hecke algebra (with the same name). + + This means that it maps the generators of ``self`` to their inverses. .. NOTE:: The mirror involution of the braid group does not factor through the - cubic hecke algebra over its base ring, but it does if it is - considered as `\ZZ`-algebra. The base ring elements are transformed by - this automorphism. + cubic Hecke algebra over its base ring, but it does if it is + considered as `\ZZ`-algebra. The base ring elements are transformed + by this automorphism. OUTPUT: @@ -598,7 +591,7 @@ def mirror_involution(self): def create_specialization(self, im_cubic_equation_roots, im_writhe_parameter=None, var='T', third_unity_root_name='E3'): r""" - Return an appropriate Ring containing the elements from the list + Return an appropriate ring containing the elements from the list ``im_cubic_equation_roots`` defining a conversion map from self mapping the cubic equation roots of ``self`` to ``im_cubic_equation_roots``. @@ -731,12 +724,11 @@ def create_specialization(self, im_cubic_equation_roots, im_writhe_parameter=Non def as_splitting_algebra(self): r""" - Return ``self`` as instance of class :class:`SplittingAlgebra` that is - as an extension ring of the corresponding cubic Hecke algebra base ring - (``self._ring_of_definition``, an instance of class - :class:`CubicHeckeRingOfDefinition`) splitting its cubic equation into - linear factors, such that the roots are images of the generators - of ``self``. + Return ``self`` as a :class:`SplittingAlgebra`; that is as an + extension ring of the corresponding cubic Hecke algebra base ring + (``self._ring_of_definition``, as a :class:`CubicHeckeRingOfDefinition`) + splitting its cubic equation into linear factors, such that the roots + are images of the generators of ``self``. EXAMPLES:: @@ -814,8 +806,8 @@ def field_embedding(self, characteristic=0): INPUT: - - ``characteristic`` -- integer (default 0) the characteristic of the - field. + - ``characteristic`` -- integer (default: ``0``); the characteristic + of the field EXAMPLES:: @@ -920,31 +912,36 @@ def markov_trace_version(self): # ------------------------------------------------------------------------------ class CubicHeckeRingOfDefinition(Localization): r""" - This class implements the *ring of definition* of the cubic Hecke algebra. + The *ring of definition* of the cubic Hecke algebra. It contains one invertible indeterminate (representing the product of the roots of the cubic equation) and two non invertible indeterminates. - With the name *ring of definition* we follow a suggestion by Ivan Marin. - We avoid alternative names like *generic* or *universal* base ring - as these have some issues. The first option could be misleading - in view of the term *generic point* used in algebraic geometry which would - mean the function field in ``u, v, w``, here. + .. NOTE:: + + We follow a suggestion by Ivan Marin in the name *ring of definition*. + We avoid alternative names like *generic* or *universal* base ring + as these have some issues. The first option could be misleading + in view of the term *generic point* used in algebraic geometry, which + would mean the function field in ``u, v, w``, here. - The second option is problematic since the base ring itself is not a - universal object. Rather, the universal object is the cubic Hecke algebra - considered as a `ZZ` algebra including ``u, v, w`` as pairwise commuting - indeterminates. From this point of view the base ring appears to be a - subalgebra of this universal object generated by ``u, v, w``. + The second option is problematic since the base ring itself is not a + universal object. Rather, the universal object is the cubic Hecke algebra + considered as a `\ZZ`-algebra including ``u, v, w`` as pairwise commuting + indeterminates. From this point of view the base ring appears to be a + subalgebra of this universal object generated by ``u, v, w``. INPUT: - - ``names`` -- string containing the names of the indeterminates separated - by ',' or a triple of strings each of which is the name of one of the - three indeterminates. The default is ``u, v, w``. - - ``order`` -- string (default='degrevlex') transferred to the corresponding - input of LaurentPolynomialRing_mpair - - ``markov_trace_version`` -- boolean (default is ``False``). If this is + - ``names`` -- (default: ``'u,v,w'``) string containing the names of the + indeterminates separated by ``,`` or a triple of strings each of which + are the names of one of the three indeterminates + - ``order`` -- string (default: ``'degrevlex'``); the term order; see also + :class:`~sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_mpair` + - ``ring_of_definition`` -- (optional) a :class:`CubicHeckeRingOfDefinition` + to specify the generic cubic Hecke base ring over which ``self`` may be + realized as splitting ring via the ``as_splitting_algebra`` method + - ``markov_trace_version`` -- boolean (default: ``False``) if this is set to ``True`` then ``self`` contains one invertible indeterminate in addition which is meant to represent the writhe factor of a Markov trace on the cubic Hecke algebra and which default name is ``s`` @@ -979,7 +976,7 @@ class CubicHeckeRingOfDefinition(Localization): """ def __init__(self, names=('u', 'v', 'w', 's'), order='degrevlex', markov_trace_version=False): r""" - Python constructor. + Initialize ``self``. TESTS:: @@ -1026,10 +1023,12 @@ def __init__(self, names=('u', 'v', 'w', 's'), order='degrevlex', markov_trace_v ############################################################################ def _defining_names(self): r""" - This method is cached in the parent class. This causes trouble if a - second instance of self is used for another cubic Hecke algebra in the - same session. To avoid this it is overloaded without ``cached_method`` - decorator. + Return the generators of ``self`` as the defining names. + + This method is cached in the parent class. + This causes trouble if a second instance of ``self`` is used for another + cubic Hecke algebra in the same session. To avoid this it is overloaded + without ``cached_method`` decorator. EXAMPLES:: @@ -1042,8 +1041,7 @@ def _defining_names(self): def _an_element_(self): r""" - Overwriting the original method to obtain an more interesting element - for ``TestSuite``. + Return an element of ``self``. EXAMPLES:: @@ -1110,28 +1108,30 @@ def cubic_equation(self, var='h', as_coefficients=False): def mirror_involution(self): r""" Return the involution of ``self`` corresponding to the involution of the - cubic Hecke algebra (with the same name). This means that it maps the - last generator of ``self`` to its inverse and both others to their - product with the image of the former. + cubic Hecke algebra (with the same name). + + This means that it maps the last generator of ``self`` to its inverse + and both others to their product with the image of the former. From the cubic equation for a braid generator `\beta_i`: .. MATH:: - \beta_i^3 - u \beta_i^2 + v\beta_i -w = 0 + \beta_i^3 - u \beta_i^2 + v\beta_i -w = 0. One deduces the following cubic equation for `\beta_i^{-1}`: .. MATH:: - \beta_i^{-3} -\frac{v}{w} \beta_i^{-2} + \frac{u}{w}\beta_i^{-1} -\frac{1}{w} = 0 + \beta_i^{-3} -\frac{v}{w} \beta_i^{-2} + \frac{u}{w}\beta_i^{-1} + - \frac{1}{w} = 0. .. NOTE:: - The mirror involution of the braid group does not factor through the - cubic Hecke algebra over its base ring, but it does if it is - considered as `\ZZ`-algebra. The base ring elements are transformed by - this automorphism. + The mirror involution of the braid group does not factor through + the cubic Hecke algebra over its base ring, but it does if it is + considered as `\ZZ`-algebra. The base ring elements are transformed + by this automorphism. OUTPUT: @@ -1185,9 +1185,8 @@ def create_specialization(self, im_cubic_equation_parameters, im_writhe_paramete OUTPUT: - A common parent containing the elements of - ``im_cubic_equation_parameters`` together with an inverse of the third - element. + A common parent containing the elements of ``im_cubic_equation_parameters`` + together with an inverse of the third element. EXAMPLES:: @@ -1311,8 +1310,10 @@ def extension_ring(self, names=('a', 'b', 'c', 's')): def markov_trace_version(self): r""" Return the extension of the ring of definition needed to treat the - formal Markov traces. This appends an additional variable ``s`` to - measure the writhe of knots and makes ``u`` and ``v`` invertible. + formal Markov traces. + + This appends an additional variable ``s`` to measure the writhe + of knots and makes ``u`` and ``v`` invertible. EXAMPLES:: @@ -1329,7 +1330,7 @@ def markov_trace_version(self): def specialize_homfly(self): r""" - Return a map to the two variable Laurent polynomial Ring which is + Return a map to the two variable Laurent polynomial ring that is the parent of the HOMFLY-PT polynomial. EXAMPLES:: @@ -1372,15 +1373,15 @@ def specialize_homfly(self): from sage.knots.link import Link H = Link([]).homfly_polynomial().parent() L, M = H.gens() - HL = H.localization(1-M) - u = HL(1-M) + HL = H.localization(1 - M) + u = HL(1 - M) phi = self.hom((u, u, HL.one(), HL(L))) inc = H.convert_map_from(HL) - return inc*phi + return inc * phi def specialize_kauffman(self): r""" - Return a map to the two variable Laurent polynomial Ring which is + Return a map to the two variable Laurent polynomial ring that is the parent of the Kauffman polynomial. EXAMPLES:: @@ -1426,15 +1427,15 @@ def specialize_kauffman(self): ku = z * a + 1 kv = z + a KL = K.localization((ku, kv)) - u = KL(ku/a) - v = KL(kv/a) + u = KL(ku / a) + v = KL(kv / a) phi = self.hom((u, v, KL(~a), KL(a))) inc = K.convert_map_from(KL) - return inc*phi + return inc * phi def specialize_links_gould(self): r""" - Return a map to the two variable Laurent polynomial Ring which is + Return a map to the two variable Laurent polynomial ring that is the parent of the Links-Gould polynomial. EXAMPLES:: @@ -1477,11 +1478,12 @@ def specialize_links_gould(self): t0, t1 = L.gens() lu = t0 + t1 - 1 lv = t0*t1 - t0 - t1 - lw = -t0*t1 + lw = -t0 * t1 LL = L.localization((lu, lv)) u = LL(lu) v = LL(lv) w = LL(lw) phi = self.hom((u, v, w, LL.one())) inc = L.convert_map_from(LL) - return inc*phi + return inc * phi + diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py index d7dbaabc65d..01c72e26098 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -67,7 +67,7 @@ class RepresentationType(Enum): - ``SplitIrredMarin`` -- split irreducible representations obtained from Ivan Marin's data - ``SplitIrredChevie`` -- the split irreducible representations obtained - from CHEVIE via the *GAP3*-interface + from CHEVIE via the ``GAP3`` interface EXAMPLES:: @@ -148,7 +148,7 @@ def number_of_representations(self, nstrands): class AbsIrreducibeRep(Enum): r""" Enum class to select an absolutely irreducible representation for the cubic - Hecke algebra (``CHAn``) on n-strands. + Hecke algebra (``CHAn``) on `n`-strands. The names are build as follows: Take the determinant of one of the generators of the ``CHAn``. This is a monomial in the generic extension @@ -158,12 +158,12 @@ class AbsIrreducibeRep(Enum): monomial might be looked as the weight of the representation. Therefore we use it as a name: - ``Wn_ijk`` + ``Wn_ijk`` The only ambiguity among the available irreducible representations occurs for the two nine-dimensional modules, which are conjugated to each other and distinguished by these names: - ``W4_333`` and ``W4_333bar`` + ``W4_333`` and ``W4_333bar`` Examples of names: @@ -173,8 +173,8 @@ class AbsIrreducibeRep(Enum): - ``W4_242`` -- eight dimensional irreducible representation of the cubic Hecke algebra on 4 strands having the second root of the cubic equation as weight of dimension 4 - - Alternative names are taken from [MW2012]_ and can be shown by :meth:`alternative_name`. + Alternative names are taken from [MW2012]_ and can be shown by + :meth:`alternative_name`. EXAMPLES:: @@ -191,12 +191,12 @@ class AbsIrreducibeRep(Enum): REFERENCES: - [MW2012]_ + - [MW2012]_ """ def alternative_name(self): r""" - Return the name of the split irreducible representation for cubic Hecke algebras for up to four strands - as given in [MW2012]_. + Return the name of the split irreducible representation for cubic Hecke + algebras for up to four strands as given in [MW2012]_. EXAMPLES:: @@ -249,8 +249,8 @@ def length_orbit(self): def gap_index(self): r""" - Return the array index of this representation for the access to the *GAP3* - package *CHEVIE*. + Return the array index of this representation for the access + to the ``GAP3`` package ``CHEVIE``. EXAMPLES:: @@ -372,8 +372,8 @@ def internal_index(self): # -------------------------------------------------------------------------------------------------------- class CubicHeckeMatrixRep(Matrix_generic_dense): r""" - Class to supervise the diagonal block matrix structure arising from cubic Hecke algebra-representations. - I is the element class of :class:`CubicHeckeMatrixSpace`. + Class to supervise the diagonal block matrix structure arising from + cubic Hecke algebra-representations. EXAMPLES:: @@ -404,7 +404,9 @@ class CubicHeckeMatrixRep(Matrix_generic_dense): sage: len(_.block_diagonal_list()) 1 - TEST: + TESTS: + + The minpoly does not work over more generic rings:: sage: TestSuite(m1).run(skip='_test_minpoly') """ @@ -412,15 +414,18 @@ class CubicHeckeMatrixRep(Matrix_generic_dense): @cached_method def _get_block(self, ind): r""" - Return the ``ind``-th sub-matrix block of ``self`` considered as block diagonal matrix. + Return the ``ind``-th sub-matrix block of ``self`` considered + as block diagonal matrix. INPUT: - - ``ind`` -- integer specifying the list index according to :meth:`internal_index` respectively :meth:`gap_index` + - ``ind`` -- integer specifying the list index according to + :meth:`internal_index` respectively :meth:`gap_index` OUTPUT: - An instance of :class:`Matrix_generic_dense` representing the specified block of ``self``. + An instance of :class:`Matrix_generic_dense` representing + the specified block of ``self``. EXAMPLES:: @@ -442,12 +447,13 @@ def _get_block(self, ind): @cached_method def _irr_to_ind(self, irr): r""" - Return the index if the given split irreducible representation of ``self``. + Return the index if the given split irreducible representation + of ``self``. INPUT: - - ``irr`` -- an instance of :class:`AbsIrreducibeRep` specifying an absolute irreducible - representation of the cubic Hecke algebra + - ``irr`` -- an instance of :class:`AbsIrreducibeRep` specifying an + absolute irreducible representation of the cubic Hecke algebra EXAMPLES:: @@ -476,19 +482,22 @@ def _irr_to_ind(self, irr): @cached_method def __getitem__(self, item): r""" - Return the sub-matrix block of ``self`` considered as block diagonal matrix specified by `item`. + Return the sub-matrix block of ``self`` considered as block diagonal + matrix specified by `item`. + Overloading builtin-method to select a list-item. INPUT: - - ``item`` -- an instance of :class:`AbsIrreducibeRep` specifying an absolute irreducible - representation of the cubic Hecke algebra. Alternatively, it can be specified by list index - (see :meth:`internal_index` repectively :meth:`gap_index`). + - ``item`` -- an :class:`AbsIrreducibeRep` specifying an + absolute irreducible representation of the cubic Hecke algebra; + alternatively, it can be specified by list index + (see :meth:`internal_index` repectively :meth:`gap_index`) OUTPUT: - An instance of :class:`Matrix_generic_dense` representing the specified block of ``self``. - + An instance of :class:`Matrix_generic_dense` representing + the specified block of ``self``. EXAMPLES:: @@ -509,11 +518,13 @@ def __getitem__(self, item): @cached_method def block_diagonal_list(self): r""" - Return the list of sub-matrix blocks of ``self`` considered as block diagonal matrix. + Return the list of sub-matrix blocks of ``self`` considered + as block diagonal matrix. OUTPUT: - A list of instances of :class:`Matrix_generic_dense` each of which represents a diagonal block of ``self``. + A list of instances of :class:`Matrix_generic_dense` each of + which represents a diagonal block of ``self``. EXAMPLES:: @@ -534,9 +545,9 @@ def reduce_to_irr_block(self, irr): INPUT: - - ``irr`` -- an instance of :class:`AbsIrreducibeRep` specifying an - absolute irreducible representation of the cubic Hecke algebra. - Alternatively, it can be specified by list index (see + - ``irr`` -- an :class:`AbsIrreducibeRep` specifying an + absolute irreducible representation of the cubic Hecke algebra; + alternatively, it can be specified by list index (see :meth:`internal_index` respectively :meth:`gap_index`) OUTPUT: @@ -572,20 +583,20 @@ def reduce_to_irr_block(self, irr): # -------------------------------------------------------------------------------------------------------- class CubicHeckeMatrixSpace(MatrixSpace): r""" - This class defines the matrix space of cubic Hecke algebra-representations. + The matrix space of cubic Hecke algebra representations. - INPUT (to the python constructor): + INPUT: - - ``cubic_hecke_algebra`` -- (default = None) instance of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.cubicHeckeAlgebra` must be given if - `element` fails to be an instance of its element class. + - ``cubic_hecke_algebra`` -- (optional) + :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra` + must be given if ``element`` fails to be an instance of its element class + - ``representation_type`` -- (default: ``RepresentationType.SplitIrredChevie``) + :class:`RepresentationType` specifying the type of the representation + - ``subdivide`` -- boolean (default: ``False``); whether or not to subdivide + the resulting matrices - - ``representation_type`` -- (default RepresentationType.SplitIrredChevie) instance of :class:`RepresentationType` - specifying the type of the representation. - - - ``subdivide`` -- boolean (default False) passed to :func:`~sage.matrix.special.block_diagonal_matrix`. - - - ``original`` -- boolean (default False) if set to True the matrix will coefficients in the generic - base / extension ring. + - ``original`` -- boolean (default: ``False``) if ``True``, the matrix + will have coefficients in the generic base / extension ring EXAMPLES:: @@ -615,7 +626,9 @@ def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, su sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA2. = algebras.CubicHecke(2) sage: MS = chmr.CubicHeckeMatrixSpace(CHA2) - sage: TestSuite(MS).run(skip='_test_elements') + sage: MS2 = chmr.CubicHeckeMatrixSpace(CHA2, representation_type=CHA2.repr_type.SplitIrredMarin, subdivide=False) + sage: MS is MS2 + True """ from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra @@ -635,25 +648,28 @@ def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, su if representation_type.is_split(): dimension = cubic_hecke_algebra._dim_irr_rep base_ring = cubic_hecke_algebra.extension_ring(generic=original) - return super(CubicHeckeMatrixSpace, cls).__classcall__(cls, base_ring, dimension, - cubic_hecke_algebra=cubic_hecke_algebra, - representation_type=representation_type, - subdivide=subdivide, sparse=True, - implementation=Matrix_generic_dense) - - def __init__(self, base_ring, dimension, cols, sparse=True, - implementation=Matrix_generic_dense, - cubic_hecke_algebra=None, - representation_type=RepresentationType.SplitIrredChevie, - subdivide=False): + # Bypass the MatrixSpace.__classcall__ + return super(MatrixSpace, cls).__classcall__(cls, base_ring, int(dimension), + cubic_hecke_algebra=cubic_hecke_algebra, + representation_type=representation_type, + subdivide=subdivide) + + def __init__(self, base_ring, + dimension, + cubic_hecke_algebra, + representation_type, + subdivide): r""" - Python constructor. + Initialize ``self``. TESTS:: sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA3. = algebras.CubicHecke(3) sage: MS = chmr.CubicHeckeMatrixSpace(CHA3, original=True) + + The minpoly does not work over more generic rings:: + sage: TestSuite(MS).run(skip='_test_elements') # long time """ from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra @@ -681,9 +697,7 @@ def __init__(self, base_ring, dimension, cols, sparse=True, self._original_base_ring = original_base_ring self._specialize = specialize - super(CubicHeckeMatrixSpace, self).__init__(base_ring, dimension, cols, sparse=sparse, implementation=implementation) - self.Element = CubicHeckeMatrixRep - return + super().__init__(base_ring, dimension, dimension, sparse=True, implementation=CubicHeckeMatrixRep) def construction(self): r""" @@ -715,8 +729,9 @@ def _element_constructor_(self, x): r""" INPUT: - - ``x`` -- instance of the element class of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra` or an instance - whose parent is in instance of :class:`MatrixSpace` + - ``x`` -- an element of a + :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra` + or an element whose parent is a :class:`MatrixSpace` EXAMLPES:: @@ -742,7 +757,7 @@ def _element_constructor_(self, x): ele_parent = x.parent() ori_base_ring = self._original_base_ring if isinstance(ele_parent, MatrixSpace): - # ToDo: - Find preimage in cubic hecke algebra + # TODO: Find preimage in cubic hecke algebra d1, d2 = x.dimensions() if d1 != self.ncols() or d2 != self.nrows(): raise ValueError('incompatible dimensions!') @@ -756,21 +771,21 @@ def _element_constructor_(self, x): matrix = block_diagonal_matrix(matrix_list, subdivide=self._subdivide, sparse=True) if matrix != x: raise TypeError('incompatible block structure') + return self.element_class(self, matrix) - elif ele_parent == ch_algebra: + if ele_parent == ch_algebra: mat = ch_algebra._apply_module_morphism(x, self._image_on_basis) return self(mat) - else: - raise TypeError('element must be an instance of CubicHeckeElement or a matrix') - - return self.element_class(self, matrix) + raise TypeError('element must be an instance of CubicHeckeElement or a matrix') @cached_method def __call__(self, entries=None, coerce=True, copy=None): r""" - Perform the instance call. This method needs to be overloaded here - since :class:`MatrixSpace` has an own implementation of it. + Construct an element of ``self``. + + This method needs to be overloaded here since + :class:`MatrixSpace` has an own implementation of it. EXAMLPES:: @@ -831,13 +846,15 @@ def _specialize_matrix(self, mat): @cached_method def _image_on_gen(self, gen_ind): r""" - Return the matrix list corresponding to the generator given by ``(gen_ind,)`` in Tietze form - under the representation_type of ``self`` from the data-file or via the *GAP3* interface + Return the matrix list corresponding to the generator given by + ``(gen_ind,)`` in Tietze form under the representation_type of + ``self`` from the data-file or via the ``GAP3`` interface INPUT: - - ``gen_ind`` -- integer, index of a generator of the cubic Hecke algebra attached to ``self`` + 1. - Negative values correspond to the according inverses. + - ``gen_ind`` -- integer; index of a generator of the cubic Hecke + algebra attached to ``self + 1``; negative values correspond to + the according inverses EXAMPLES:: @@ -863,7 +880,6 @@ def _image_on_gen(self, gen_ind): [ 1 0 v/w] ] """ - representation_type = self._representation_type original_base_ring = self._original_base_ring ch_algebra = self._cubic_hecke_algebra @@ -896,14 +912,12 @@ def invert_gen(matr): num_rep = representation_type.number_of_representations(n) if representation_type == RepresentationType.SplitIrredChevie: - rep_list = [ch_algebra._fetch_matrix_list_from_chevie(i+1) for i in range(num_rep)] if gen_ind > 0: matrix_list = [rep[gen_ind - 1] for rep in rep_list] else: matrix_list = [invert_gen(rep[-gen_ind - 1]) for rep in rep_list] else: - database = ch_algebra._database matrix_list = database.read_matrix_representation(representation_type, gen_ind, n, original_base_ring) return matrix_list @@ -916,9 +930,9 @@ def _image_on_basis(self, basis_element): INPUT: - - ``basis_element`` -- instance of + - ``basis_element`` -- a :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeElement` - which is a monomial + that is a monomial EXAMPLES:: @@ -1050,16 +1064,19 @@ def some_elements(self): EXAMPLES:: sage: CHA2. = algebras.CubicHecke(2, cubic_equation_roots=(2, 3, 5)) - sage: c1.matrix() + sage: M = c1.matrix(); M [2 0 0] [0 3 0] [0 0 5] - sage: list(_.parent().some_elements()) - [ + sage: MS = M.parent() + sage: MS.some_elements() + ( [ 94/3 0 0] [ 0 187/3 0] [ 0 0 373/3] - ] + ) + sage: MS.some_elements() == tuple(MS(x) for x in CHA2.some_elements()) + True """ - for x in self._cubic_hecke_algebra.some_elements(): - yield self(x) + return tuple([self(x) for x in self._cubic_hecke_algebra.some_elements()]) + diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 52ef0fdb585..6d2ddb4f086 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -3,38 +3,40 @@ Cubic Hecke Database This module contains the class :class:`CubicHeckeDataBase` which serves as an -interface to `Ivan Marin's data files `__ -with respect to the cubic Hecke algebras. The data is available via a Python wrapper as a -pip installable package `database_cubic_hecke `__. +interface to `Ivan Marin's data files +`__ +with respect to the cubic Hecke algebras. The data is available via a Python +wrapper as a pip installable package `database_cubic_hecke +`__. For installation hints please see the documentation there. -Anyway, all data needed for the cubic Hecke algebras on less than four strands is +All data needed for the cubic Hecke algebras on less than four strands is included in this module for demonstration purpose (see for example :func:`read_basis`, :func:`read_irr` , ... generated with the help of :func:`create_demo_data`). -In addition to Ivan Marin's data the package contains a function :func:`read_markov` -to obtain the coefficients of Markov traces on the cubic Hecke algebras. This -data has been precomputed with the help of ``create_markov_trace_data.py`` in the -`database_cubic_hecke repository `__. -Again, for less than four strands, this data is includes here for demonstration -purpose. - -Furthermore, this module contains the class :class:`CubicHeckeFileCache` which -enables :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebras.CubicHeckeAlgebra` +In addition to Ivan Marin's data the package contains a function +:func:`read_markov` to obtain the coefficients of Markov traces on the +cubic Hecke algebras. This data has been precomputed with the help of +``create_markov_trace_data.py`` in the `database_cubic_hecke repository +`__. +Again, for less than four strands, this data is includes here for +demonstration purposes. + +Furthermore, this module contains the class :class:`CubicHeckeFileCache` +that enables +:class:`~sage.algebras.hecke_algebras.cubic_hecke_algebras.CubicHeckeAlgebra` to keep intermediate results of calculations in the file system. -Finally, there is an enum :class:`MarkovTraceModuleBasis` serving -as basis for the sub-module of linear forms on the cubic Hecke algebra on four -and less strands satisfying the Markov trace condition for its cubic Hecke -sub-algebras. +The enum :class:`MarkovTraceModuleBasis` serves as basis for the submodule +of linear forms on the cubic Hecke algebra on at most four strands +satisfying the Markov trace condition for its cubic Hecke subalgebras. AUTHORS: -- Sebastian Oehms May 2020: initial version -- Sebastian Oehms March 2022: PyPi version and Markov trace functionality +- Sebastian Oehms (May 2020): initial version +- Sebastian Oehms (March 2022): PyPi version and Markov trace functionality """ - ############################################################################## # Copyright (C) 2020 Sebastian Oehms # @@ -45,7 +47,6 @@ # http://www.gnu.org/licenses/ ############################################################################## - import os from enum import Enum @@ -69,11 +70,11 @@ def simplify(mat): INPUT: - -- ``mat`` - matrix to be converted into python dictionary + - ``mat`` -- matrix to be converted into a ``dict`` OUTPUT: - A python dictionary from which ``mat`` can be reconstructed via + A ``dict`` from which ``mat`` can be reconstructed via element construction. The values of the dictionary may be dictionaries of tuples of integers or strings. @@ -111,8 +112,9 @@ def simplify(mat): class CubicHeckeDataSection(Enum): r""" - Enum for the different sections of the database. The following choices are - possible: + Enum for the different sections of the database. + + The following choices are possible: - ``basis`` -- list of basis elements - ``reg_left_reprs`` -- data for the left regular representation @@ -120,7 +122,7 @@ class CubicHeckeDataSection(Enum): - ``irr_reprs`` -- data for the split irreducible representations - ``markov_tr_cfs`` -- data for the coefficients of the formal Markov traces - Examples:: + EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeDataBase sage: cha_db = CubicHeckeDataBase() @@ -140,17 +142,18 @@ class CubicHeckeDataSection(Enum): # ------------------------------------------------------------------------------- class CubicHeckeDataBase(SageObject): r""" - Database interface needed for :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebras.CubicHeckeAlgebra` + Database interface for + :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebras.CubicHeckeAlgebra` - The original data are obtained from - `Ivan Marin's web page `__ + The original data are obtained from `Ivan Marin's web page + `__ The data needed to work with the cubic Hecke algebras on less than 4 strands is completely contained in this module. Data needed for the larger algebras - can be installed as an optional Sage package which comes as a *pip* installable + can be installed as an optional Sage package which comes as a ``pip`` installable `Python wrapper `__ of - Ivan Marin's data. For more information see the - `corresponding repository `__. + Ivan Marin's data. For more information see the `corresponding repository + `__. EXAMPLES:: @@ -159,12 +162,11 @@ class CubicHeckeDataBase(SageObject): sage: cha_db._feature Feature('database_cubic_hecke') """ - section = CubicHeckeDataSection def __init__(self): r""" - Python constructor. + Initialize ``self``. EXAMPLES:: @@ -180,7 +182,7 @@ def __init__(self): def version(self): r""" - Return the current version. + Return the current version of the database. EXAMPLES:: @@ -217,7 +219,7 @@ def demo_version(self): # -------------------------------------------------------------------------- def read(self, section, variables=None, nstrands=4): r""" - Access various static data library. + Access various static data libraries. INPUT: @@ -291,11 +293,10 @@ def read_matrix_representation(self, representation_type, gen_ind, nstrands, rin INPUT: - - ``representation_type`` -- instance of enum + - ``representation_type`` -- an element of :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.RepresentationType` specifying the type of the representation - OUTPUT: EXAMPLES:: @@ -339,11 +340,12 @@ def read_matrix_representation(self, representation_type, gen_ind, nstrands, rin class MarkovTraceModuleBasis(Enum): r""" - Enum for the basis elements for the Markov trace module. The choice of - the basis elements doesn't have a systematically background apart from - generating the sub-module of maximal rank in the module of linear forms - on the cubic Hecke algebra for which the Markov trace condition with - respect to its cubic Hecke sub-algebras hold. The number of crossings in + Enum for the basis elements for the Markov trace module. + + The choice of the basis elements doesn't have a systematically background + apart from generating the submodule of maximal rank in the module of linear + forms on the cubic Hecke algebra for which the Markov trace condition with + respect to its cubic Hecke subalgebras hold. The number of crossings in the corresponding links is chosen as minimal as possible. EXAMPLES:: @@ -382,8 +384,8 @@ def __gt__(self, other): def strands(self): r""" - Return the number of strands of the minimal braid representative of the - link corresponding to ``self``. + Return the number of strands of the minimal braid representative + of the link corresponding to ``self``. EXAMPLES:: @@ -401,7 +403,7 @@ def braid_tietze(self, strands_embed=None): INPUT: - ``strands_embed`` -- (optional) the number of strands of the braid - if strands should be added. + if strands should be added OUTPUT: @@ -421,8 +423,8 @@ def braid_tietze(self, strands_embed=None): if strands_embed > self.strands(): last_gen = strands_embed-1 return self.braid_tietze(strands_embed=last_gen) + (last_gen,) - else: - return self.value[2] + + return self.value[2] def writhe(self): r""" @@ -442,6 +444,7 @@ def writhe(self): def description(self): r""" Return a description of the link corresponding to this basis element. + In the case of knots it refers to the naming according to `KnotInfo `__. @@ -455,8 +458,7 @@ def description(self): def link(self): r""" - Return the link which represents this basis element as instance of - :class:`Link`. + Return the :class:`Link` that represents this basis element. EXAMPLES:: @@ -479,14 +481,11 @@ def link(self): def regular_homfly_polynomial(self): r""" - Return the regular variant of the KOMFLY-PT polynomial of the link which - represents this basis element. This is the HOMFLY-PT polynomial - renormalized by the writhe factor such that it is an invariant of - regular isotopy. + Return the regular variant of the KOMFLY-PT polynomial of the link that + represents this basis element. - OUTPUT: - - An instance of :class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`. + This is the HOMFLY-PT polynomial renormalized by the writhe factor + such that it is an invariant of regular isotopy. EXAMPLES:: @@ -502,18 +501,15 @@ def regular_homfly_polynomial(self): """ H = self.link().homfly_polynomial() L, M = H.parent().gens() - return H*L**self.writhe() + return H * L**self.writhe() def regular_kauffman_polynomial(self): r""" - Return the regular variant of the Kauffman polynomial of the link which - represents this basis element. This is the Kauffman polynomial - renormalized by the writhe factor such that it is an invariant of - regular isotopy. + Return the regular variant of the Kauffman polynomial of the link that + represents this basis element. - OUTPUT: - - An instance of :class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`. + This is the Kauffman polynomial renormalized by the writhe factor + such that it is an invariant of regular isotopy. EXAMPLES:: @@ -542,13 +538,9 @@ def regular_kauffman_polynomial(self): def links_gould_polynomial(self): r""" - Return the Links-Gould polynomial of the link which represents this + Return the Links-Gould polynomial of the link that represents this basis element. - OUTPUT: - - An instance of :class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`. - EXAMPLES:: sage: from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis @@ -645,7 +637,8 @@ def links_gould_polynomial(self): class CubicHeckeFileCache(SageObject): """ - A class to cache calculations of :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebras.CubicHeckeAlgebra` + A class to cache calculations of + :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebras.CubicHeckeAlgebra` in the local file system. """ @@ -664,7 +657,7 @@ class section(Enum): preboius attemps of calculation until the corresponding intermediate step - Examples:: + EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache sage: CHA2 = algebras.CubicHecke(2) @@ -672,7 +665,6 @@ class section(Enum): sage: cha_fc.section """ - def filename(self, nstrands=None): r""" Return the file name under which the data of this file cache section @@ -680,10 +672,10 @@ def filename(self, nstrands=None): INPUT: - - ``nstrands`` -- Integer, number of strands of the underlying braid - group if the data file depends on it. Otherwise use default ``None`` + - ``nstrands`` -- (optional) :class:`Integer`; number of strands of + the underlying braid group if the data file depends on it - Examples:: + EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache sage: CHA2 = algebras.CubicHecke(2) @@ -705,7 +697,7 @@ def filename(self, nstrands=None): def __init__(self, num_strands): r""" - Python constructor. + Initialize ``self``. INPUT: @@ -728,8 +720,8 @@ def __init__(self, num_strands): def _warn_incompatibility(self, fname): """ - Warn the user that he has an incomaptible file cache under `Sage_DOT` and - move it away to another file (marked with timestamp). + Warn the user that he has an incomaptible file cache under `Sage_DOT` + and move it away to another file (marked with timestamp). EXAMPLES:: @@ -757,7 +749,7 @@ def reset_library(self, section=None): INPUT: - - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + - ``section`` -- an element of :class:`CubicHeckeFileCache.section` to select the section of the file cache or ``None`` (default) meaning all sections @@ -798,11 +790,10 @@ def is_empty(self, section=None): INPUT: - - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + - ``section`` -- an element of :class:`CubicHeckeFileCache.section` to select the section of the file cache or ``None`` (default) meaning all sections - EXAMPLES:: sage: from sage.databases.cubic_hecke_db import CubicHeckeFileCache @@ -830,7 +821,7 @@ def is_empty(self, section=None): # the new generators and their inverses are not counted # since they are added during initialization return len(data_lib) <= 2*(self._nstrands - 4) - return len(data_lib) == 0 + return not data_lib # -------------------------------------------------------------------------- # save data file system @@ -841,9 +832,9 @@ def write(self, section=None): INPUT: - - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` - specifying the section where the corresponding cached data belong to. - If omitted data of all sections is written to the file system + - ``section`` -- an element of :class:`CubicHeckeFileCache.section` + specifying the section where the corresponding cached data belong to; + if omitted, the data of all sections is written to the file system EXAMPLES:: @@ -882,7 +873,7 @@ def read(self, section): INPUT: - - ``section`` -- instance of enum :class:`CubicHeckeFileCache.section` + - ``section`` -- an element of :class:`CubicHeckeFileCache.section` specifying the section where the corresponding cached data belong to OUTPUT: @@ -927,16 +918,13 @@ def read(self, section): def read_matrix_representation(self, representation_type, monomial_tietze, ring_of_definition): r""" Return the matrix representations of the given monomial (in Tietze form) - if it has been stored in the file cache before. Otherwise ``None`` is - returned. - + if it has been stored in the file cache before. INPUT: - - ``representation_type`` -- instance of enum :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.RepresentationType` + - ``representation_type`` -- an element of + :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.RepresentationType` specifying the type of the representation - - ``monomial_tietze`` -- tuple representing the braid in Tietze form - - ``ring_of_definition`` -- instance of :class:`~sage.algebras.hecke_algebras.cubic_hecke_base_ring.CubicHeckeRingOfDefinition` respectively @@ -945,8 +933,9 @@ def read_matrix_representation(self, representation_type, monomial_tietze, ring_ OUTPUT: - Dictionary containing all matrix representations of ``self`` of the given - ``representation_type`` which have been stored in the file cache. + Dictionary containing all matrix representations of ``self`` of the + given ``representation_type`` which have been stored in the file cache. + Otherwise ``None`` is returned. EXAMPLES:: @@ -988,12 +977,10 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr INPUT: - - ``representation_type`` -- instance of enum + - ``representation_type`` -- an element of :class:`~sage.algebras.hecke_algebras.cubic_hecke_matrix_rep.RepresentationType` specifying the type of the representation - - ``monomial_tietze`` -- tuple representing the braid in Tietze form - - ``matrix_list`` -- list of matrices corresponding to the irreducible representations @@ -1052,8 +1039,7 @@ def read_braid_image(self, braid_tietze, ring_of_definition): INPUT: - ``braid_tietze`` -- tuple representing the braid in Tietze form - - - ``ring_of_definition`` -- instance of + - ``ring_of_definition`` -- a :class:`~sage.algebras.hecke_algebras.cubic_hecke_base_ring.CubicHeckeRingOfDefinition` OUTPUT: @@ -1139,7 +1125,7 @@ def update_basis_extensions(self, new_basis_extensions): INPUT: - ``new_basis_extensions`` -- list of additional (to the static basis) - basis elements which should replace the former such list in the file. + basis elements which should replace the former such list in the file EXAMPLES:: @@ -1182,14 +1168,13 @@ def update_basis_extensions(self, new_basis_extensions): doc = r"""{} - Return precomputed data of Ivan Marin + Return precomputed data of Ivan Marin. - This code was generated by :func:`create_demo_data`, please don't edit. + This code was generated by :func:`create_demo_data`, please do not edit. INPUT: %s - - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra - in question + - ``num_strands`` -- integer; number of strands of the cubic Hecke algebra EXAMPLES:: @@ -1203,6 +1188,7 @@ def create_demo_data(filename='demo_data.py'): r""" Generate code for the functions inserted below to access the small cases of less than 4 strands as demonstration cases. + The code is written to a file with the given name from where it can be copied into this source file (in case a change is needed). @@ -1271,14 +1257,13 @@ def fl(s): def read_basis(num_strands=3): r""" - Return precomputed data of Ivan Marin + Return precomputed data of Ivan Marin. - This code was generated by :func:`create_demo_data`, please don't edit. + This code was generated by :func:`create_demo_data`, please do not edit. INPUT: - - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra - in question + - ``num_strands`` -- integer; number of strands of the cubic Hecke algebra EXAMPLES:: @@ -1286,7 +1271,6 @@ def read_basis(num_strands=3): sage: read_basis(2) [[], [1], [-1]] """ - data = {} data[2] = [[], [1], [-1]] data[3] = [[], [1], [-1], [2], [-2], [1, 2], [1, -2], [-1, 2], [-1, -2], [1, 2, @@ -1297,15 +1281,14 @@ def read_basis(num_strands=3): def read_irr(variables, num_strands=3): r""" - Return precomputed data of Ivan Marin + Return precomputed data of Ivan Marin. - This code was generated by :func:`create_demo_data`, please don't edit. + This code was generated by :func:`create_demo_data`, please do not edit. INPUT: - ``variables`` -- tuple containing the indeterminates of the representation - - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra - in question + - ``num_strands`` -- integer; number of strands of the cubic Hecke algebra EXAMPLES:: @@ -1316,7 +1299,6 @@ def read_irr(variables, num_strands=3): [[{(0, 0): a}], [{(0, 0): c}], [{(0, 0): b}]], [[{(0, 0): a^-1}], [{(0, 0): c^-1}], [{(0, 0): b^-1}]]) """ - (a, b, c, j) = variables data = {} data[2] = ([1, 1, 1], [[{(0, 0): a}], [{(0, 0): c}], [{(0, 0): b}]], [[{(0, 0): @@ -1342,15 +1324,14 @@ def read_irr(variables, num_strands=3): def read_regl(variables, num_strands=3): r""" - Return precomputed data of Ivan Marin + Return precomputed data of Ivan Marin. - This code was generated by :func:`create_demo_data`, please don't edit. + This code was generated by :func:`create_demo_data`, please do not edit. INPUT: - ``variables`` -- tuple containing the indeterminates of the representation - - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra - in question + - ``num_strands`` -- integer; number of strands of the cubic Hecke algebra EXAMPLES:: @@ -1361,7 +1342,6 @@ def read_regl(variables, num_strands=3): [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], [[{(0, 1): 1, (0, 2): -u*w^-1, (1, 2): w^-1, (2, 0): 1, (2, 2): v*w^-1}]]) """ - (u, v, w) = variables data = {} data[2] = ([3], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], @@ -1417,15 +1397,14 @@ def read_regl(variables, num_strands=3): def read_regr(variables, num_strands=3): r""" - Return precomputed data of Ivan Marin + Return precomputed data of Ivan Marin. - This code was generated by :func:`create_demo_data`, please don't edit. + This code was generated by :func:`create_demo_data`, please do not edit. INPUT: - ``variables`` -- tuple containing the indeterminates of the representation - - ``num_strands`` -- integer, number of strands of the cubic Hecke algebra - in question + - ``num_strands`` -- integer; number of strands of the cubic Hecke algebra EXAMPLES:: @@ -1436,7 +1415,6 @@ def read_regr(variables, num_strands=3): [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], [[{(0, 1): 1, (0, 2): -u*w^-1, (1, 2): w^-1, (2, 0): 1, (2, 2): v*w^-1}]]) """ - (u, v, w) = variables data = {} data[2] = ([3], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], @@ -1498,14 +1476,14 @@ def read_markov(bas_ele, variables, num_strands=4): Return precomputed Markov trace coefficients. This code was generated by ``create_markov_trace_data.py`` (from - the `database_cubic_heck` repository), please don't edit. + the ``database_cubic_heck`` repository), please do not edit. INPUT: - - ``bas_ele`` -- instance of enum :class:`MarkovTraceModuleBasis` + - ``bas_ele`` -- an element of :class:`MarkovTraceModuleBasis` - ``variables`` -- tuple consisting of the variables used in the coefficients - - ``num_strands`` -- integer indicating the number of strands (default 4) + - ``num_strands`` -- integer (default: 4); the number of strands OUTPUT: @@ -1523,7 +1501,6 @@ def read_markov(bas_ele, variables, num_strands=4): [0, s, 1/s, s, 1/s, 0, 0, 0, 0, -s*v, s, s, -s*u/w, -v/s, 1/s, 0, 0, 0, 0, 1/s, -u/(s*w), -v/s, 0, 0] """ - u, v, w, s = variables data = {} data[2] = {'U1': [0, s, 1/s], 'U2': [1, 0, 0]} @@ -1537,3 +1514,4 @@ def read_markov(bas_ele, variables, num_strands=4): 0, 1]} return data[num_strands][bas_ele] + From 328cc6a00c8023e903057cda86882b914dca827b Mon Sep 17 00:00:00 2001 From: dcoudert Date: Tue, 16 Aug 2022 11:33:48 +0200 Subject: [PATCH 412/591] trac #34318: fix pyflakes issue --- src/sage/graphs/generic_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 4f4f57c5484..b2b3b92179a 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -10871,7 +10871,7 @@ def set_vertex(self, vertex, object): except AttributeError: assoc = self._assoc = {} - self._assoc[vertex] = object + assoc[vertex] = object def get_vertex(self, vertex): """ From 27579d65c19b5b2a89eb94f8d23035b9d5be27e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Leli=C3=A8vre?= Date: Tue, 16 Aug 2022 15:29:10 +0200 Subject: [PATCH 413/591] 34128: Improve documentation of symbolic operators --- src/sage/symbolic/operators.py | 89 ++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/src/sage/symbolic/operators.py b/src/sage/symbolic/operators.py index 52351f0867b..a48b0e8e393 100644 --- a/src/sage/symbolic/operators.py +++ b/src/sage/symbolic/operators.py @@ -6,21 +6,22 @@ def add_vararg(first, *rest): r""" - Addition of a variable number of arguments. + Return the sum of all the arguments. INPUT: - - ``first``, ``rest`` -- arguments to add + - ``first``, ``*rest`` -- arguments to add - OUTPUT: sum of arguments + OUTPUT: sum of the arguments EXAMPLES:: sage: from sage.symbolic.operators import add_vararg - sage: add_vararg(1,2,3,4,5,6,7) + sage: add_vararg(1, 2, 3, 4, 5, 6, 7) 28 - sage: F = (1+x+x^2) - sage: bool(F.operator()(*F.operands()) == F) + sage: x = SR.var('x') + sage: s = 1 + x + x^2 # symbolic sum + sage: bool(s.operator()(*s.operands()) == s) True """ for r in rest: @@ -30,21 +31,22 @@ def add_vararg(first, *rest): def mul_vararg(first, *rest): r""" - Multiplication of a variable number of arguments. + Return the product of all the arguments. INPUT: - - ``args`` -- arguments to multiply + - ``first``, ``*rest`` -- arguments to multiply - OUTPUT: product of arguments + OUTPUT: product of the arguments EXAMPLES:: sage: from sage.symbolic.operators import mul_vararg - sage: mul_vararg(9,8,7,6,5,4) + sage: mul_vararg(9, 8, 7, 6, 5, 4) 60480 - sage: G = x*cos(x)*sin(x) - sage: bool(G.operator()(*G.operands())==G) + sage: x = SR.var('x') + sage: p = x * cos(x) * sin(x) # symbolic product + sage: bool(p.operator()(*p.operands()) == p) True """ for r in rest: @@ -69,13 +71,25 @@ def mul_vararg(first, *rest): operator.ge:'>='} class FDerivativeOperator(): + r""" + Function derivative operators. + + A function derivative operator represents a partial derivative + of a function with respect to some variables. + + The underlying data are the function, and the parameter set, + a list recording the indices of the variables with respect + to which the partial derivative is taken. + """ def __init__(self, function, parameter_set): - """ + r""" + Initialize this function derivative operator. + EXAMPLES:: sage: from sage.symbolic.operators import FDerivativeOperator sage: f = function('foo') - sage: op = FDerivativeOperator(f, [0,1]) + sage: op = FDerivativeOperator(f, [0, 1]) sage: loads(dumps(op)) D[0, 1](foo) """ @@ -83,16 +97,18 @@ def __init__(self, function, parameter_set): self._parameter_set = [int(_) for _ in parameter_set] def __call__(self, *args): - """ + r""" + Call this function derivative operator on these arguments. + EXAMPLES:: sage: from sage.symbolic.operators import FDerivativeOperator - sage: x,y = var('x,y') + sage: x, y = SR.var('x, y') sage: f = function('foo') - sage: op = FDerivativeOperator(f, [0,1]) - sage: op(x,y) + sage: op = FDerivativeOperator(f, [0, 1]) + sage: op(x, y) diff(foo(x, y), x, y) - sage: op(x,x^2) + sage: op(x, x^2) D[0, 1](foo)(x, x^2) TESTS: @@ -115,56 +131,65 @@ def __call__(self, *args): # temporary variable e.g. `t0` and then evaluate the # derivative f'(t0) symbolically at t0=1. See trac # #12796. - temp_args=SR.temp_var(n=len(args)) - vars=[temp_args[i] for i in self._parameter_set] + temp_args = SR.temp_var(n=len(args)) + vars = [temp_args[i] for i in self._parameter_set] return self._f(*temp_args).diff(*vars).function(*temp_args)(*args) vars = [args[i] for i in self._parameter_set] return self._f(*args).diff(*vars) def __repr__(self): - """ + r""" + Return the string representation of this function derivative operator. + EXAMPLES:: sage: from sage.symbolic.operators import FDerivativeOperator sage: f = function('foo') - sage: op = FDerivativeOperator(f, [0,1]); op + sage: op = FDerivativeOperator(f, [0, 1]); op D[0, 1](foo) """ - return "D[%s](%s)"%(", ".join(map(repr, self._parameter_set)), self._f) + return "D[%s](%s)" % (", ".join(map(repr, self._parameter_set)), self._f) def function(self): - """ + r""" + Return the function associated to this function derivative operator. + EXAMPLES:: sage: from sage.symbolic.operators import FDerivativeOperator sage: f = function('foo') - sage: op = FDerivativeOperator(f, [0,1]) + sage: op = FDerivativeOperator(f, [0, 1]) sage: op.function() foo """ return self._f def change_function(self, new): - """ - Returns a new FDerivativeOperator with the same parameter set - for a new function. + r""" + Return a new function derivative operator with the same + parameter set but for a new function. sage: from sage.symbolic.operators import FDerivativeOperator sage: f = function('foo') sage: b = function('bar') - sage: op = FDerivativeOperator(f, [0,1]) + sage: op = FDerivativeOperator(f, [0, 1]) sage: op.change_function(bar) D[0, 1](bar) """ return FDerivativeOperator(new, self._parameter_set) def parameter_set(self): - """ + r""" + Return the parameter set of this function derivative operator. + + This is the list of indices of variables with respect to which + the derivative is taken. + EXAMPLES:: sage: from sage.symbolic.operators import FDerivativeOperator sage: f = function('foo') - sage: op = FDerivativeOperator(f, [0,1]) + sage: op = FDerivativeOperator(f, [0, 1]) sage: op.parameter_set() [0, 1] """ From 2edbdbaf6548fb4416664ac624b092ac23e52212 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 11 Aug 2022 11:31:44 -0700 Subject: [PATCH 414/591] Sets.CartesianProducts.ParentMethods.__iter__: Use cantor_product if factors other than first are infinite --- src/sage/categories/sets_cat.py | 81 ++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 09a57770a3b..ae066366b3f 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -2217,7 +2217,14 @@ def example(self): class ParentMethods: def __iter__(self): r""" - Return a lexicographic iterator for the elements of this Cartesian product. + Return an iterator for the elements of this Cartesian product. + + If all factors (except possibly the first factor) are known to be finite, + it uses the lexicographic order. + + Otherwise, the iterator enumerates the elements in increasing + order of sum-of-ranks, refined by the lexicographic order + (see :func:`~sage.misc.mrange.cantor_product`). EXAMPLES: @@ -2260,29 +2267,38 @@ def __iter__(self): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]) - .. WARNING:: - - The elements are returned in lexicographic order, - which gives a valid enumeration only if all - factors, but possibly the first one, are - finite. So the following one is fine:: - - sage: it = iter(cartesian_product([ZZ, GF(2)])) - sage: [next(it) for _ in range(10)] - [(0, 0), (0, 1), (1, 0), (1, 1), - (-1, 0), (-1, 1), (2, 0), (2, 1), - (-2, 0), (-2, 1)] - - But this one is not:: - - sage: it = iter(cartesian_product([GF(2), ZZ])) - sage: [next(it) for _ in range(10)] - doctest:...: UserWarning: Sage is not able to determine - whether the factors of this Cartesian product are - finite. The lexicographic ordering might not go through - all elements. - [(0, 0), (0, 1), (0, -1), (0, 2), (0, -2), - (0, 3), (0, -3), (0, 4), (0, -4), (0, 5)] + When the first factor is infinite (or not known to be finite), it still + uses the lexicographic order:: + + sage: it = iter(cartesian_product([ZZ, GF(2)])) + sage: [next(it) for _ in range(10)] + [(0, 0), (0, 1), + (1, 0), (1, 1), + (-1, 0), (-1, 1), + (2, 0), (2, 1), + (-2, 0), (-2, 1)] + + When other factors are infinite (or not known to be finite), it enumerates + the elements in increasing order of sum-of-ranks:: + + sage: NN = NonNegativeIntegers() + sage: it = iter(cartesian_product([NN, NN])) + sage: [next(it) for _ in range(10)] + [(0, 0), + (1, 0), (0, 1), + (2, 0), (1, 1), (0, 2), + (3, 0), (2, 1), (1, 2), (0, 3)] + + An example with the first factor finite, the second infinite:: + + sage: it = iter(cartesian_product([GF(2), ZZ])) + sage: [next(it) for _ in range(11)] + [(0, 0), + (1, 0), (0, 1), + (1, 1), (0, -1), + (1, -1), (0, 2), + (1, 2), (0, -2), + (1, -2), (0, 3)] .. NOTE:: @@ -2292,17 +2308,18 @@ def __iter__(self): ALGORITHM: - Recipe 19.9 in the Python Cookbook by Alex Martelli - and David Ascher. + The lexicographic enumeration follows Recipe 19.9 in the Python Cookbook + by Alex Martelli and David Ascher. """ - if any(f not in Sets().Finite() for f in self.cartesian_factors()[1:]): - from warnings import warn - warn("Sage is not able to determine whether the factors of " - "this Cartesian product are finite. The lexicographic " - "ordering might not go through all elements.") + factors = list(self.cartesian_factors()) + if any(f not in Sets().Finite() for f in factors[1:]): + from sage.misc.mrange import cantor_product + for t in cantor_product(*factors): + yield self._cartesian_product_of_elements(t) + return + # Lexicographic enumeration: # visualize an odometer, with "wheels" displaying "digits"...: - factors = list(self.cartesian_factors()) wheels = [iter(f) for f in factors] try: digits = [next(it) for it in wheels] From 8890f1eede8d00eb29a7825eac005c9b68be3714 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 12 Aug 2022 21:56:34 -0700 Subject: [PATCH 415/591] src/sage/categories/sets_cat.py: Update documentation - cantor_product refines with revlex --- src/sage/categories/sets_cat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index ae066366b3f..bdc2e03078e 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -2223,7 +2223,7 @@ def __iter__(self): it uses the lexicographic order. Otherwise, the iterator enumerates the elements in increasing - order of sum-of-ranks, refined by the lexicographic order + order of sum-of-ranks, refined by the reverse lexicographic order (see :func:`~sage.misc.mrange.cantor_product`). EXAMPLES: From a20341ef50cd8fa46e08a3ebe38e3f2d40a1c492 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 13 Aug 2022 09:59:36 -0700 Subject: [PATCH 416/591] src/sage/categories/sets_cat.py: Rephrase cartesian product docstring --- src/sage/categories/sets_cat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index bdc2e03078e..e3d961c0873 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -2267,7 +2267,7 @@ def __iter__(self): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]) - When the first factor is infinite (or not known to be finite), it still + When all factors (except possibly the first factor) are known to be finite, it uses the lexicographic order:: sage: it = iter(cartesian_product([ZZ, GF(2)])) From 21a7d8d31051377d245c6ec0bc1dfae4897593d8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 15 Aug 2022 14:05:25 -0700 Subject: [PATCH 417/591] src/sage/sets/image_set.py: Handle is_injective='check' --- src/sage/sets/image_set.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/sage/sets/image_set.py b/src/sage/sets/image_set.py index 2de224762ba..ba0be21c685 100644 --- a/src/sage/sets/image_set.py +++ b/src/sage/sets/image_set.py @@ -18,14 +18,15 @@ from typing import Iterator -from sage.structure.parent import Parent, is_Parent from sage.categories.map import is_Map from sage.categories.poor_man_map import PoorManMap from sage.categories.sets_cat import Sets from sage.categories.enumerated_sets import EnumeratedSets +from sage.misc.cachefunc import cached_method from sage.rings.integer import Integer from sage.modules.free_module import FreeModule from sage.structure.element import Expression +from sage.structure.parent import Parent, is_Parent from .set import Set_base, Set_add_sub_operators, Set_boolean_operators @@ -39,6 +40,25 @@ class ImageSubobject(Parent): .. MATH:: \{ f(x) | x \in X \} \subseteq Y. + + INPUT: + + - ``is_injective``: whether the ``map`` is injective: + - ``None`` (default): infer from ``map`` or default to ``False`` + - ``False``: ``map`` is known to be non-injective + - ``True``: ``map`` is known to be injective + - ``"check"``: raise an error when ``map`` is not injective + + EXAMPLES:: + + sage: import itertools + sage: from sage.sets.image_set import ImageSubobject + sage: D = ZZ + sage: I = ImageSubobject(abs, ZZ, is_injective='check') + sage: list(itertools.islice(I, 10)) + Traceback (most recent call last): + ... + ValueError: The map from Integer Ring is not injective: 1 """ def __init__(self, map, domain_subset, *, category=None, is_injective=None): """ @@ -176,6 +196,7 @@ def _repr_(self) -> str: """ return f"Image of {self._domain_subset} by {self._map}" + @cached_method def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. @@ -186,7 +207,7 @@ def cardinality(self) -> Integer: sage: R.cardinality() 3628800 """ - if self._is_injective: + if self._is_injective and self._is_injective != 'check': return self._domain_subset.cardinality() return super().cardinality() @@ -204,7 +225,7 @@ def __iter__(self) -> Iterator: sage: [next(it) for _ in range(5)] [0, 1, 2, 3, 4] """ - if self._is_injective: + if self._is_injective and self._is_injective != 'check': for x in self._domain_subset: yield self._map(x) else: @@ -212,6 +233,8 @@ def __iter__(self) -> Iterator: for x in self._domain_subset: y = self._map(x) if y in visited: + if self._is_injective == 'check': + raise ValueError(f'{self._map} is not injective: {y}') continue visited.add(y) yield y From d41813574849b86313b47fa34b16d8ea7b5cf1a0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 15 Aug 2022 15:46:16 -0700 Subject: [PATCH 418/591] src/sage/sets/image_set.py: Handle keyword inverse, implement _element_constructor_ --- src/sage/sets/image_set.py | 39 +++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/sage/sets/image_set.py b/src/sage/sets/image_set.py index ba0be21c685..c70bd3f149b 100644 --- a/src/sage/sets/image_set.py +++ b/src/sage/sets/image_set.py @@ -60,7 +60,7 @@ class ImageSubobject(Parent): ... ValueError: The map from Integer Ring is not injective: 1 """ - def __init__(self, map, domain_subset, *, category=None, is_injective=None): + def __init__(self, map, domain_subset, *, category=None, is_injective=None, inverse=None): """ Initialize ``self``. @@ -119,9 +119,46 @@ def map(arg): Parent.__init__(self, category=category) self._map = map + self._inverse = inverse self._domain_subset = domain_subset self._is_injective = is_injective + def _element_constructor_(self, x): + """ + EXAMPLES:: + + sage: import itertools + sage: from sage.sets.image_set import ImageSubobject + sage: D = ZZ + sage: I = ImageSubobject(lambda x: 2 * x, ZZ, inverse=lambda x: x/2) + sage: I(8/2) + 4 + sage: _.parent() + Integer Ring + sage: I(10/2) + Traceback (most recent call last): + ... + ValueError: 5 is not in Image of Integer Ring by The map at ...> from Integer Ring + sage: 6 in I + True + sage: 7 in I + False + """ + # Same as ImageManifoldSubset.__contains__ + codomain = self._map.codomain() + if codomain is not None and x not in codomain: + raise ValueError(f"{x} is not in {self}") + if self._inverse is not None: + preimage = self._inverse(x) + if preimage not in self._domain_subset: + raise ValueError(f"{x} is not in {self}") + preimage = self._map.domain()(preimage) + y = self._map(preimage) + if y == x: + return y + raise ValueError(f"{x} is not in {self}") + raise NotImplementedError + def ambient(self): """ Return the ambient set of ``self``, which is the codomain of From 1b383b5c3c61ffcdc40e8ebd19b197add64372f2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 14:18:18 -0700 Subject: [PATCH 419/591] ImageSet.cardinality: Fix fallback, add examples --- src/sage/sets/image_set.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/sage/sets/image_set.py b/src/sage/sets/image_set.py index c70bd3f149b..decbdc513ea 100644 --- a/src/sage/sets/image_set.py +++ b/src/sage/sets/image_set.py @@ -238,15 +238,32 @@ def cardinality(self) -> Integer: r""" Return the cardinality of ``self``. - EXAMPLES:: + EXAMPLES: + + Injective case (note that + :meth:`~sage.categories.enumerated_sets.EnumeratedSets.ParentMethods.map` + defaults to ``is_injective=True``): sage: R = Permutations(10).map(attrcall('reduced_word')) sage: R.cardinality() 3628800 + + sage: Evens = ZZ.map(lambda x: 2 * x) + sage: Evens.cardinality() + +Infinity + + Non-injective case:: + + sage: Z4 = Set(range(4)) + sage: from sage.sets.image_set import ImageSet + sage: Z4711 = ImageSet(lambda x: x**7 % 11, Z4, is_injective=False) + sage: Z4711.cardinality() + 4 """ if self._is_injective and self._is_injective != 'check': return self._domain_subset.cardinality() - return super().cardinality() + # Fallback like EnumeratedSets.ParentMethods.__len__ + return Integer(len(list(self))) def __iter__(self) -> Iterator: r""" From 318cf6218a1678b71c413e2cd6a404a5e5c47062 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 14:27:38 -0700 Subject: [PATCH 420/591] src/sage/sets/image_set.py: Add documentation --- src/sage/sets/image_set.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/sets/image_set.py b/src/sage/sets/image_set.py index decbdc513ea..be37ea197b2 100644 --- a/src/sage/sets/image_set.py +++ b/src/sage/sets/image_set.py @@ -43,12 +43,18 @@ class ImageSubobject(Parent): INPUT: - - ``is_injective``: whether the ``map`` is injective: + - ``map`` -- a function + + - ``domain_subset`` -- the set `X`; optional if `f` has a domain + + - ``is_injective`` -- whether the ``map`` is injective: - ``None`` (default): infer from ``map`` or default to ``False`` - ``False``: ``map`` is known to be non-injective - ``True``: ``map`` is known to be injective - ``"check"``: raise an error when ``map`` is not injective + - ``inverse`` -- a function (optional); a map from `f(X)` to `X` + EXAMPLES:: sage: import itertools From 52f6ca6ca8ed4655442bf24d8918d7b721a900d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 14:37:00 -0700 Subject: [PATCH 421/591] src/sage/sets/image_set.py: Improve example --- src/sage/sets/image_set.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/sets/image_set.py b/src/sage/sets/image_set.py index be37ea197b2..375f95be548 100644 --- a/src/sage/sets/image_set.py +++ b/src/sage/sets/image_set.py @@ -260,11 +260,11 @@ def cardinality(self) -> Integer: Non-injective case:: - sage: Z4 = Set(range(4)) + sage: Z7 = Set(range(7)) sage: from sage.sets.image_set import ImageSet - sage: Z4711 = ImageSet(lambda x: x**7 % 11, Z4, is_injective=False) + sage: Z4711 = ImageSet(lambda x: x**4 % 11, Z7, is_injective=False) sage: Z4711.cardinality() - 4 + 6 """ if self._is_injective and self._is_injective != 'check': return self._domain_subset.cardinality() From bb5e329913d19baf42f9e49cd63529b2d62d1b67 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 17 Aug 2022 10:16:31 +0900 Subject: [PATCH 422/591] Refine the try-except block in FreeModuleFactoy to run subsequent tests as they might work even if one of the earlier ones fail. --- src/sage/modules/free_module.py | 46 +++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 9946a588c85..e68656ffb1b 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -191,6 +191,7 @@ import sage.rings.infinity import sage.rings.integer from sage.categories.principal_ideal_domains import PrincipalIdealDomains +from sage.categories.integral_domains import IntegralDomains from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.misc.randstate import current_randstate from sage.structure.factory import UniqueFactory @@ -236,6 +237,17 @@ def create_object(self, version, key): sage: TestSuite(ZZ^6).run() sage: TestSuite(RDF^3).run() + + Check that :trac:`34380` is fixed:: + + sage: R. = QQ[] + sage: Q = R.quo(R.ideal([x^2 - y^2 - 1])) + sage: Q.is_integral_domain() + True + sage: Q2 = FreeModule(Q, 2) + sage: from sage.modules.free_module import FreeModule_ambient_domain + sage: isinstance(Q2, FreeModule_ambient_domain) + True """ base_ring, rank, sparse, inner_product_matrix = key @@ -254,29 +266,29 @@ def create_object(self, version, key): "done from the right side.") #raise TypeError, "The base_ring must be a commutative ring." - try: - if not sparse and isinstance(base_ring, sage.rings.abc.RealDoubleField): - return RealDoubleVectorSpace_class(rank) + if not sparse and isinstance(base_ring, sage.rings.abc.RealDoubleField): + return RealDoubleVectorSpace_class(rank) - elif not sparse and isinstance(base_ring, sage.rings.abc.ComplexDoubleField): - return ComplexDoubleVectorSpace_class(rank) + if not sparse and isinstance(base_ring, sage.rings.abc.ComplexDoubleField): + return ComplexDoubleVectorSpace_class(rank) - elif base_ring.is_field(): + try: + if base_ring.is_field(): return FreeModule_ambient_field(base_ring, rank, sparse=sparse) + except NotImplementedError: + pass - elif base_ring in PrincipalIdealDomains(): - return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) + if base_ring in PrincipalIdealDomains(): + return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) - elif isinstance(base_ring, sage.rings.abc.Order) \ - and base_ring.is_maximal() and base_ring.class_number() == 1: - return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) + if (isinstance(base_ring, sage.rings.abc.Order) + and base_ring.is_maximal() and base_ring.class_number() == 1): + return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) - elif isinstance(base_ring, ring.IntegralDomain) or base_ring.is_integral_domain(): - return FreeModule_ambient_domain(base_ring, rank, sparse=sparse) - else: - return FreeModule_ambient(base_ring, rank, sparse=sparse) - except NotImplementedError: - return FreeModule_ambient(base_ring, rank, sparse=sparse) + if isinstance(base_ring, ring.IntegralDomain) or base_ring in IntegralDomains(): + return FreeModule_ambient_domain(base_ring, rank, sparse=sparse) + + return FreeModule_ambient(base_ring, rank, sparse=sparse) FreeModuleFactory_with_standard_basis = FreeModuleFactory("FreeModule") From 9e8d0234ce66ca99ad7350a9b9d8bab093923319 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 19:44:44 -0700 Subject: [PATCH 423/591] ImageSubobject.cardinality: Handle infinite cardinalities explicitly --- src/sage/sets/image_set.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/sage/sets/image_set.py b/src/sage/sets/image_set.py index 375f95be548..752ee4987bb 100644 --- a/src/sage/sets/image_set.py +++ b/src/sage/sets/image_set.py @@ -23,6 +23,7 @@ from sage.categories.sets_cat import Sets from sage.categories.enumerated_sets import EnumeratedSets from sage.misc.cachefunc import cached_method +from sage.rings.infinity import Infinity from sage.rings.integer import Integer from sage.modules.free_module import FreeModule from sage.structure.element import Expression @@ -265,11 +266,27 @@ def cardinality(self) -> Integer: sage: Z4711 = ImageSet(lambda x: x**4 % 11, Z7, is_injective=False) sage: Z4711.cardinality() 6 + + sage: Squares = ImageSet(lambda x: x^2, ZZ, is_injective=False, + ....: category=Sets().Infinite()) + sage: Squares.cardinality() + +Infinity + + sage: Mod2 = ZZ.map(lambda x: x % 2, is_injective=False) + sage: Mod2.cardinality() + Traceback (most recent call last): + ... + NotImplementedError: cannot determine cardinality of a non-injective image of an infinite set """ + domain_cardinality = self._domain_subset.cardinality() if self._is_injective and self._is_injective != 'check': - return self._domain_subset.cardinality() + return domain_cardinality + if self in Sets().Infinite(): + return Infinity + if domain_cardinality == Infinity: + raise NotImplementedError('cannot determine cardinality of a non-injective image of an infinite set') # Fallback like EnumeratedSets.ParentMethods.__len__ - return Integer(len(list(self))) + return Integer(len(list(iter(self)))) def __iter__(self) -> Iterator: r""" From b09e6d18bd5574f39b474ef5974eb1ab196d0723 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 21:21:08 -0700 Subject: [PATCH 424/591] .devcontainer/downstream-archlinux-latest/devcontainer.json: Remove a 'prefix' symlink if present --- .devcontainer/downstream-archlinux-latest/devcontainer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/downstream-archlinux-latest/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json index 8f0b1480700..3ce2e0fc60b 100644 --- a/.devcontainer/downstream-archlinux-latest/devcontainer.json +++ b/.devcontainer/downstream-archlinux-latest/devcontainer.json @@ -5,7 +5,8 @@ // Run commands after the container is created. "postCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh", // Run commands after the container is started. - "postStartCommand": "make configure && ln -sf /usr venv", + // There's no SAGE_LOCAL, so remove the symlink 'prefix'. + "postStartCommand": "make configure && rm -f prefix && ln -sf /usr venv", "extensions": [ "ms-python.python" ] From f99f09fe674666dfff47fd47326c2d216eec2047 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 21:45:46 -0700 Subject: [PATCH 425/591] .devcontainer/downstream-archlinux-latest/devcontainer.json: No need to bootstrap --- .devcontainer/downstream-archlinux-latest/devcontainer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/downstream-archlinux-latest/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json index 3ce2e0fc60b..be5613ffb40 100644 --- a/.devcontainer/downstream-archlinux-latest/devcontainer.json +++ b/.devcontainer/downstream-archlinux-latest/devcontainer.json @@ -6,7 +6,7 @@ "postCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh", // Run commands after the container is started. // There's no SAGE_LOCAL, so remove the symlink 'prefix'. - "postStartCommand": "make configure && rm -f prefix && ln -sf /usr venv", + "postStartCommand": "rm -f prefix && ln -sf /usr venv", "extensions": [ "ms-python.python" ] From b72ff17c346b2f64849a45400a226b74dc2f10f8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 22:00:48 -0700 Subject: [PATCH 426/591] Refinements for downstream-archlinux-latest --- .devcontainer/downstream-archlinux-latest/devcontainer.json | 3 ++- src/doc/en/developer/portability_testing.rst | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.devcontainer/downstream-archlinux-latest/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json index be5613ffb40..93966269922 100644 --- a/.devcontainer/downstream-archlinux-latest/devcontainer.json +++ b/.devcontainer/downstream-archlinux-latest/devcontainer.json @@ -3,7 +3,8 @@ "name": "archlinux:latest downstream Sage", "image": "archlinux:latest", // Run commands after the container is created. - "postCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh", + // Create an empty bashrc to avoid the error "No such file or directory" when opening a terminal. + "postCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh && touch ~/.bashrc", // Run commands after the container is started. // There's no SAGE_LOCAL, so remove the symlink 'prefix'. "postStartCommand": "rm -f prefix && ln -sf /usr venv", diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 23eb5b1bdf9..bc7662d6b06 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1252,6 +1252,12 @@ work without change) or to adapt them to your needs. hence the prefix ``downstream-...``; the suffix ``latest`` indicates the most recent version of Arch Linux as available on Docker Hub.) + When the message "Done. Press any key to close the terminal." appears in the terminal + named "Configuring", Sage is ready for use. To use Sage in a terminal, `open a new + terminal in VS Code `_, type ``sage`` + and hit :kbd:`Enter`. (Do not use ``./sage``; this will not work because the source tree is + not configured.) + - `downstream-conda-forge-latest/devcontainer.json `_ similarly configures a container with an installation of conda-forge and its SageMath package. From 9215621a6fa51b9cb914fc91fb25ac6c82ccdbef Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 22:20:03 -0700 Subject: [PATCH 427/591] Copy instructions for downstream-conda-latest --- src/doc/en/developer/portability_testing.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index bc7662d6b06..ffbbd969462 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1262,6 +1262,12 @@ work without change) or to adapt them to your needs. `_ similarly configures a container with an installation of conda-forge and its SageMath package. + When the message "Done. Press any key to close the terminal." appears in the terminal + named "Configuring", Sage is ready for use. To use Sage in a terminal, `open a new + terminal in VS Code `_, type ``sage`` + and hit :kbd:`Enter`. (Do not use ``./sage``; this will not work because the source tree is + not configured.) + - `downstream-docker-cocalc/devcontainer.json `_ configures a container with `the CoCalc Docker image `_. From 2cb5411af9ea4085291d4a6e729cbe53e29def84 Mon Sep 17 00:00:00 2001 From: Shriya M <25shriya@gmail.com> Date: Wed, 17 Aug 2022 11:02:16 +0530 Subject: [PATCH 428/591] Add multimajor index --- src/doc/en/reference/references/index.rst | 5 +++ src/sage/combinat/permutation.py | 37 +++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index bb77d546810..1050f95f802 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3321,6 +3321,11 @@ REFERENCES: *Combinatorics of symmetric designs*. Cambridge University Press, 2006. +.. [JS2000] \A. Joellenbeck, M. Schocker. + "Cyclic Characters of Symmetric Groups". + J. Algebraic Combin., **12** (2000), 155-161. + :doi:`10.1023/A:1026592027019`. + .. [JS2010] \B. Jones, A. Schilling. "Affine structures and a tableau model for `E_6` crystals", J. Algebra. **324** (2010). 2512-2542. diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index a2e7df2b130..9453cdb16f7 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -221,12 +221,18 @@ finite Weyl group to make it more uniform with :class:`SymmetricGroup`. Added ability to compute the conjugacy classes. +- Amrutha P, Shriya M, Divya Aggarwal (2022-08-16): Added Multimajor Index. + Classes and methods =================== """ # **************************************************************************** # Copyright (C) 2007 Mike Hansen +# 2022 Amrutha P +# 2022 Shriya M <25shriya@gmail.com> +# 2022 Divya Aggarwal +# # # 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 @@ -3365,6 +3371,37 @@ def major_index(self, final_descent=False) -> Integer: descents = self.descents(final_descent) return sum(descents) + def multi_major_index(self, composition): + r""" + Return the multimajor index of this permutation with respect to ``composition``. + + INPUT: + + - ``composition`` -- a :class:`Composition` of :meth:`size` + + EXAMPLES:: + + sage: Permutation([5, 6, 2, 1, 3, 7, 4]).multi_major_index(Composition([3, 2, 2])) + [2, 0, 1] + + REFERENCES: + + - [JS2000]_ + """ + if self.size() == composition.size(): + D = self.descents() + s = [0] + for i, qi in enumerate(q): + maj_qp = [0] * len(s) + s.append(s[i] + qi) + for j in range(len(s)): + for d in D: + if s[j - 1] < d < s[j]: + maj_qp[j - 1] += d - s[j - 1] + return maj_qp + raise ValueError("Invalid Input") + + def imajor_index(self, final_descent=False) -> Integer: """ Return the inverse major index of the permutation ``self``, which is From de05f69712024a42b171e76ba378761ba8c0d998 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 22:50:22 -0700 Subject: [PATCH 429/591] Copy instructions for downstream-* --- src/doc/en/developer/portability_testing.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index ffbbd969462..69d0895e52c 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1272,12 +1272,24 @@ work without change) or to adapt them to your needs. `_ configures a container with `the CoCalc Docker image `_. + When the message "Done. Press any key to close the terminal." appears in the terminal + named "Configuring", Sage is ready for use. To use Sage in a terminal, `open a new + terminal in VS Code `_, type ``sage`` + and hit :kbd:`Enter`. (Do not use ``./sage``; this will not work because the source tree is + not configured.) + - `downstream-docker-computop/devcontainer.json `_ configures a container with the `Docker image from the 3-manifolds project `_, providing SnapPy, Regina, PHCPack, etc. + When the message "Done. Press any key to close the terminal." appears in the terminal + named "Configuring", Sage is ready for use. To use Sage in a terminal, `open a new + terminal in VS Code `_, type ``sage`` + and hit :kbd:`Enter`. (Do not use ``./sage``; this will not work because the source tree is + not configured.) + Files named ``$SAGE_ROOT/.devcontainer/develop-.../devcontainer.json`` configure containers from a public Docker image that provides SageMath and then updates the installation of SageMath in this container by building from the current source tree. From 43abc572dca5342919c34406b3691d4cb67fe929 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 16 Aug 2022 22:52:30 -0700 Subject: [PATCH 430/591] .devcontainer/develop-docker-cocalc, portability-centos-7-devtoolset-gcc_11-standard: Remove --- .../develop-docker-cocalc/devcontainer.json | 16 ------------- .../devcontainer.json | 23 ------------------- src/doc/en/developer/portability_testing.rst | 6 ----- 3 files changed, 45 deletions(-) delete mode 100644 .devcontainer/develop-docker-cocalc/devcontainer.json delete mode 100644 .devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json diff --git a/.devcontainer/develop-docker-cocalc/devcontainer.json b/.devcontainer/develop-docker-cocalc/devcontainer.json deleted file mode 100644 index 20455fcebe1..00000000000 --- a/.devcontainer/develop-docker-cocalc/devcontainer.json +++ /dev/null @@ -1,16 +0,0 @@ -// See https://aka.ms/devcontainer.json for format details. -{ - "name": "CoCalc Docker", - "image": "sagemathinc/cocalc", - "containerEnv": { - "MAKE": "make -j4" - }, - // Run commands after the container is created. - // libgmp.a is broken and leads to a build failure of ecm. - "postCreateCommand": ".devcontainer/post_create.sh && rm -f /usr/local/sage/local/lib/libgmp.a", - // Run commands after the container is started. - "postStartCommand": "make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv && make build V=0", - "extensions": [ - "ms-python.python" - ] -} diff --git a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json b/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json deleted file mode 100644 index eb416d68c85..00000000000 --- a/.devcontainer/portability-centos-7-devtoolset-gcc_11-standard/devcontainer.json +++ /dev/null @@ -1,23 +0,0 @@ -// See https://aka.ms/devcontainer.json for format details. -{ - "name": "Centos 7", - "build": { - "dockerfile": "portability-Dockerfile", - // See tox.ini for definitions. - "args": { "SYSTEM_FACTOR": "centos-7-devtoolset-gcc_11", - "PACKAGE_FACTOR": "standard", - "DOCKER_TARGET": "with-targets", - "DOCKER_TAG": "dev" - } - }, - "containerEnv": { - "MAKE": "make -j4" - }, - // Run commands after the container is created. - "postCreateCommand": ".devcontainer/post_create.sh", - // Run commands after the container is started. - "postStartCommand": ". /opt/rh/devtoolset-11/enable && .devcontainer/portability-post_start.sh", - "extensions": [ - "ms-python.python" - ] -} diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 69d0895e52c..e296a168e72 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1294,12 +1294,6 @@ Files named ``$SAGE_ROOT/.devcontainer/develop-.../devcontainer.json`` configure containers from a public Docker image that provides SageMath and then updates the installation of SageMath in this container by building from the current source tree. -- `develop-docker-cocalc/devcontainer.json - `_ - configures a container with `the CoCalc Docker image `_. - It then updates the installation of SageMath in this container by building from - the current source tree. - - `develop-docker-computop/devcontainer.json `_ configures a container with the `Docker image from the 3-manifolds From 15f50e0685ee7daec6de61ca68acb147677767dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 8 Aug 2022 14:34:03 +0200 Subject: [PATCH 431/591] pep8 for one file in quadratic_forms --- ...c_form__local_representation_conditions.py | 279 +++++++----------- 1 file changed, 106 insertions(+), 173 deletions(-) diff --git a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py index 418365f3d60..5d39650ecb4 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py +++ b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py @@ -5,7 +5,7 @@ # Class for keeping track of the local conditions for representability # # of numbers by a quadratic form over ZZ (and eventually QQ also). # ######################################################################## - +from __future__ import annotations from copy import deepcopy from sage.arith.all import prime_divisors, valuation, is_square @@ -16,10 +16,9 @@ from sage.rings.rational_field import QQ - class QuadraticFormLocalRepresentationConditions(): """ - Creates a class for dealing with the local conditions of a + A class for dealing with the local conditions of a quadratic form, and checking local representability of numbers. EXAMPLES:: @@ -92,23 +91,21 @@ class QuadraticFormLocalRepresentationConditions(): sage: L = [m for m in range(100) if Q0.is_locally_represented_number(m)] sage: L [0] - """ - def __init__(self, Q): """ Takes a QuadraticForm and computes its local conditions (if - they don't already exist). The recompute_flag overrides the + they do not already exist). The recompute_flag overrides the previously computed conditions if they exist, and stores the new conditions. INPUT: - Q -- Quadratic form over ZZ + - Q -- Quadratic form over ZZ OUTPUT: - a QuadraticFormLocalRepresentationConditions object + a QuadraticFormLocalRepresentationConditions object EXAMPLES:: @@ -118,14 +115,11 @@ def __init__(self, Q): This form represents the p-adic integers Z_p for all primes p except []. For these and the reals, we have: Reals: [0, +Infinity] - """ - # Check that the form Q is integer-valued (we can relax this later) if Q.base_ring() != ZZ: raise TypeError("We require that the quadratic form be defined over ZZ (integer-values) for now.") - # Basic structure initialization self.local_repn_array = [] # List of all local conditions self.dim = Q.dim() # We allow this to be any non-negative integer. @@ -135,18 +129,17 @@ def __init__(self, Q): if self.dim == 0: self.coeff = None return - elif self.dim == 1: - self.coeff = Q[0,0] + if self.dim == 1: + self.coeff = Q[0, 0] return - else: - self.coeff = None + self.coeff = None # Compute the local conditions at the real numbers (i.e. "p = infinity") # ---------------------------------------------------------------------- M = Q.matrix() E = M.eigenspaces_left() - M_eigenvalues = [E[i][0] for i in range(len(E))] + M_eigenvalues = [E[i][0] for i in range(len(E))] pos_flag = infinity neg_flag = infinity @@ -160,30 +153,27 @@ def __init__(self, Q): real_vec = [infinity, pos_flag, neg_flag, None, None, None, None, None, None] self.local_repn_array.append(real_vec) - # Compute the local conditions for representability: # -------------------------------------------------- N = Q.level() level_primes = prime_divisors(N) # Make a table of local normal forms for each p | N - local_normal_forms = [Q.local_normal_form(p) for p in level_primes] + local_normal_forms = [Q.local_normal_form(p) for p in level_primes] # Check local representability conditions for each prime - for i in range(len(level_primes)): - p = level_primes[i] + for i, p in enumerate(level_primes): tmp_local_repn_vec = [p, None, None, None, None, None, None, None, None] sqclass = self.squareclass_vector(p) # Check the representability in each Z_p squareclass - for j in range(len(sqclass)): - m = sqclass[j] + for j, m in enumerate(sqclass): k = 0 repn_flag = False while ((not repn_flag) and (m < 4 * N * p * p)): - if (local_normal_forms[i].local_density(p, m) > 0): - tmp_local_repn_vec[j+1] = k + if local_normal_forms[i].local_density(p, m) > 0: + tmp_local_repn_vec[j + 1] = k repn_flag = True k = k + 1 m = m * p * p @@ -191,7 +181,7 @@ def __init__(self, Q): # If we're not represented, write "infinity" to signify # that this squareclass is fully obstructed if not repn_flag: - tmp_local_repn_vec[j+1] = infinity + tmp_local_repn_vec[j + 1] = infinity # Test if the conditions at p give exactly Z_p when dim >=3, or # if we represent the elements of even valuation >= 2 when dim = 2. @@ -207,21 +197,18 @@ def __init__(self, Q): self.local_repn_array.append(tmp_local_repn_vec) self.exceptional_primes.append(p) - - def __repr__(self): + def __repr__(self) -> str: r""" Print the local conditions. - INPUT: - - none - OUTPUT: - string + string - TO DO: Improve the output for the real numbers, and special output for locally universality. - Also give names to the squareclasses, so it's clear what the output means! =) + .. TODO:: + + Improve the output for the real numbers, and special output for locally universality. + Also give names to the squareclasses, so it's clear what the output means! =) EXAMPLES:: @@ -230,7 +217,6 @@ def __repr__(self): sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.__repr__() 'This 2-dimensional form represents the p-adic integers of even\nvaluation for all primes p except [2].\nFor these and the reals, we have:\n Reals: [0, +Infinity]\n p = 2: [0, +Infinity, 0, +Infinity, 0, +Infinity, 0, +Infinity]\n' - """ if self.dim == 0: out_str = "This 0-dimensional form only represents zero." @@ -254,19 +240,17 @@ def __repr__(self): return out_str - - - def __eq__(self, right): + def __eq__(self, right) -> bool: """ - Determines if two sets of local conditions are equal. + Determine if two sets of local conditions are equal. INPUT: - right -- a QuadraticFormLocalRepresentationConditions object + - right -- a QuadraticFormLocalRepresentationConditions object OUTPUT: - boolean + boolean EXAMPLES:: @@ -296,26 +280,24 @@ def __eq__(self, right): # Check equality by dimension if self.dim == 0: return True - elif self.dim == 1: + if self.dim == 1: return self.coeff == right.coeff # Compare coefficients in dimension 1 (since ZZ has only one unit square) - else: - return (self.exceptional_primes == right.exceptional_primes) \ - and (self.local_repn_array == right.local_repn_array) + return ((self.exceptional_primes == right.exceptional_primes) + and (self.local_repn_array == right.local_repn_array)) - - def squareclass_vector(self, p): + def squareclass_vector(self, p) -> list: """ - Gives a vector of integers which are normalized + Return a list of integers which are normalized representatives for the `p`-adic rational squareclasses (or the real squareclasses) at the prime `p`. INPUT: - `p` -- a positive prime number or "infinity". + - `p` -- a positive prime number or "infinity" OUTPUT: - a list of integers + a list of integers EXAMPLES:: @@ -324,29 +306,25 @@ def squareclass_vector(self, p): sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.squareclass_vector(5) [1, 2, 5, 10] - """ if p == infinity: return [1, -1] - elif p == 2: + if p == 2: return [1, 3, 5, 7, 2, 6, 10, 14] - else: - r = least_quadratic_nonresidue(p) - return [1, r, p, p*r] + r = least_quadratic_nonresidue(p) + return [1, r, p, p * r] - - - def local_conditions_vector_for_prime(self, p): + def local_conditions_vector_for_prime(self, p) -> list: """ - Returns a local representation vector for the (possibly infinite) prime `p`. + Return a local representation vector for the (possibly infinite) prime `p`. INPUT: - `p` -- a positive prime number. (Is 'infinity' allowed here?) + - `p` -- a positive prime number. (Is 'infinity' allowed here?) OUTPUT: - a list of integers + a list of integers EXAMPLES:: @@ -357,7 +335,6 @@ def local_conditions_vector_for_prime(self, p): [2, 0, 0, 0, +Infinity, 0, 0, 0, 0] sage: C.local_conditions_vector_for_prime(3) [3, 0, 0, 0, 0, None, None, None, None] - """ # Check if p is non-generic if p in self.exceptional_primes: @@ -380,31 +357,30 @@ def local_conditions_vector_for_prime(self, p): v = [p, None, None, None, None, None, None, None, None] sqclass = self.squareclass_vector(p) - for i in range(len(sqclass)): - if QQ(self.coeff / sqclass[i]).is_padic_square(p): # Note:This should happen only once! - nu = valuation(self.coeff / sqclass[i], p) / 2 + for i, sqi in enumerate(sqclass): + if QQ(self.coeff / sqi).is_padic_square(p): # Note:This should happen only once! + nu = valuation(self.coeff / sqi, p) / 2 # UNUSED VARIABLE ! else: - v[i+1] = infinity + v[i + 1] = infinity elif self.dim == 0: if p == 2: return [2, infinity, infinity, infinity, infinity, infinity, infinity, infinity, infinity] - else: - return [p, infinity, infinity, infinity, infinity, None, None, None, None] + return [p, infinity, infinity, infinity, infinity, None, None, None, None] - raise RuntimeError("Error... The dimension stored should be a non-negative integer!") + raise RuntimeError("the stored dimension should be a non-negative integer") - def is_universal_at_prime(self, p): + def is_universal_at_prime(self, p) -> bool: """ - Determines if the (integer-valued/rational) quadratic form represents all of `Z_p`. + Determine if the (integer-valued/rational) quadratic form represents all of `Z_p`. INPUT: - `p` -- a positive prime number or "infinity". + - `p` -- a positive prime number or "infinity". OUTPUT: - boolean + boolean EXAMPLES:: @@ -417,14 +393,13 @@ def is_universal_at_prime(self, p): True sage: C.is_universal_at_prime(infinity) False - """ # Check if the prime behaves generically for n >= 3. - if (self.dim >= 3) and not (p in self.exceptional_primes): + if self.dim >= 3 and p not in self.exceptional_primes: return True # Check if the prime behaves generically for n <= 2. - if (self.dim <= 2) and not (p in self.exceptional_primes): + if self.dim <= 2 and p not in self.exceptional_primes: return False # Check if the prime is "infinity" (for the reals) @@ -432,7 +407,7 @@ def is_universal_at_prime(self, p): v = self.local_repn_array[0] if p != v[0]: raise RuntimeError("Error... The first vector should be for the real numbers!") - return (v[1:3] == [0,0]) # True iff the form is indefinite + return (v[1:3] == [0, 0]) # True iff the form is indefinite # Check non-generic "finite" primes v = self.local_conditions_vector_for_prime(p) @@ -442,18 +417,13 @@ def is_universal_at_prime(self, p): Zp_univ_flag = False return Zp_univ_flag - - def is_universal_at_all_finite_primes(self): + def is_universal_at_all_finite_primes(self) -> bool: """ - Determines if the quadratic form represents `Z_p` for all finite/non-archimedean primes. - - INPUT: - - none + Determine if the quadratic form represents `Z_p` for all finite/non-archimedean primes. OUTPUT: - boolean + boolean EXAMPLES:: @@ -470,31 +440,24 @@ def is_universal_at_all_finite_primes(self): sage: C = QuadraticFormLocalRepresentationConditions(Q) sage: C.is_universal_at_all_finite_primes() True - """ # Check if dim <= 2. if self.dim <= 2: return False # Check that all non-generic finite primes are universal - univ_flag = True - for p in self.exceptional_primes[1:]: # Omit p = "infinity" here - univ_flag = univ_flag and self.is_universal_at_prime(p) - return univ_flag - + # Omit p = "infinity" here + return all(self.is_universal_at_prime(p) + for p in self.exceptional_primes[1:]) - def is_universal_at_all_places(self): + def is_universal_at_all_places(self) -> bool: """ - Determines if the quadratic form represents `Z_p` for all + Determine if the quadratic form represents `Z_p` for all finite/non-archimedean primes, and represents all real numbers. - INPUT: - - none - OUTPUT: - boolean + boolean EXAMPLES:: @@ -520,34 +483,29 @@ def is_universal_at_all_places(self): sage: C = QuadraticFormLocalRepresentationConditions(Q) # long time (8.5 s) sage: C.is_universal_at_all_places() # long time True - """ # Check if dim <= 2. if self.dim <= 2: return False # Check that all non-generic finite primes are universal - for p in self.exceptional_primes: - if not self.is_universal_at_prime(p): - return False - return True + return all(self.is_universal_at_prime(p) + for p in self.exceptional_primes) - - - def is_locally_represented_at_place(self, m, p): + def is_locally_represented_at_place(self, m, p) -> bool: """ - Determines if the rational number m is locally represented by the + Determine if the rational number `m` is locally represented by the quadratic form at the (possibly infinite) prime `p`. INPUT: - `m` -- an integer + - `m` -- an integer - `p` -- a positive prime number or "infinity". + - `p` -- a positive prime number or "infinity". OUTPUT: - boolean + boolean EXAMPLES:: @@ -565,7 +523,6 @@ def is_locally_represented_at_place(self, m, p): True sage: C.is_locally_represented_at_place(0, infinity) True - """ # Sanity Check if m not in QQ: @@ -583,9 +540,8 @@ def is_locally_represented_at_place(self, m, p): if self.dim == 1: m1 = QQ(m) / self.coeff if p == infinity: - return (m1 > 0) - else: - return (valuation(m1, p) >= 0) and m1.is_padic_square(p) + return m1 > 0 + return (valuation(m1, p) >= 0) and m1.is_padic_square(p) # >= 2-dim'l forms local_vec = self.local_conditions_vector_for_prime(p) @@ -594,31 +550,31 @@ def is_locally_represented_at_place(self, m, p): if p == infinity: if m > 0: return local_vec[1] == 0 - elif m < 0: + if m < 0: return local_vec[2] == 0 - else: # m == 0 - return True + # m == 0 + return True # Check at a finite place sqclass = self.squareclass_vector(p) for s in sqclass: - if (QQ(m)/s).is_padic_square(p): - nu = valuation(m//s, p) + if (QQ(m) / s).is_padic_square(p): + nu = valuation(m // s, p) return local_vec[sqclass.index(s) + 1] <= (nu / 2) - def is_locally_represented(self, m): + def is_locally_represented(self, m) -> bool: """ - Determines if the rational number `m` is locally represented by + Determine if the rational number `m` is locally represented by the quadratic form (allowing vectors with coefficients in `Z_p` at all places). INPUT: - `m` -- an integer + - `m` -- an integer OUTPUT: - boolean + boolean EXAMPLES:: @@ -634,7 +590,6 @@ def is_locally_represented(self, m): True sage: C.is_locally_represented(QQ(1)/QQ(2)) False - """ # Representing zero if m == 0: @@ -665,15 +620,14 @@ def is_locally_represented(self, m): # If we got here, we're locally represented! return True - - -# -------------------- End of QuadraticFormLocalRepresentationConditions Class ---------------------- - +# --- End of QuadraticFormLocalRepresentationConditions Class --- def local_representation_conditions(self, recompute_flag=False, silent_flag=False): """ - WARNING: THIS ONLY WORKS CORRECTLY FOR FORMS IN >=3 VARIABLES, + .. WARNING:: + + THIS ONLY WORKS CORRECTLY FOR FORMS IN >=3 VARIABLES, WHICH ARE LOCALLY UNIVERSAL AT ALMOST ALL PRIMES! This class finds the local conditions for a number to be integrally @@ -718,14 +672,10 @@ def local_representation_conditions(self, recompute_flag=False, silent_flag=Fals positive reals are represented). The real vector always appears, and is listed before the other ones. - INPUT: - - none - OUTPUT: - A list of 9-element vectors describing the representation - obstructions at primes dividing the level. + A list of 9-element vectors describing the representation + obstructions at primes dividing the level. EXAMPLES:: @@ -745,7 +695,6 @@ def local_representation_conditions(self, recompute_flag=False, silent_flag=Fals Reals: [0, +Infinity] p = 2: [0, +Infinity, 0, +Infinity, 0, +Infinity, 0, +Infinity] - sage: Q1 = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q1.local_representation_conditions() This form represents the p-adic integers Z_p for all primes p except @@ -778,9 +727,8 @@ def local_representation_conditions(self, recompute_flag=False, silent_flag=Fals This form represents the p-adic integers Z_p for all primes p except []. For these and the reals, we have: Reals: [0, +Infinity] - """ - # Recompute the local conditions if they don't exist or the recompute_flag is set. + # Recompute the local conditions if they do not exist or the recompute_flag is set. if not hasattr(self, "__local_representability_conditions") or recompute_flag: self.__local_representability_conditions = QuadraticFormLocalRepresentationConditions(self) @@ -789,17 +737,17 @@ def local_representation_conditions(self, recompute_flag=False, silent_flag=Fals return self.__local_representability_conditions -def is_locally_universal_at_prime(self, p): +def is_locally_universal_at_prime(self, p) -> bool: """ - Determines if the (integer-valued/rational) quadratic form represents all of `Z_p`. + Determine if the (integer-valued/rational) quadratic form represents all of `Z_p`. INPUT: - `p` -- a positive prime number or "infinity". + - `p` -- a positive prime number or "infinity". OUTPUT: - boolean + boolean EXAMPLES:: @@ -830,24 +778,18 @@ def is_locally_universal_at_prime(self, p): sage: Q = DiagonalQuadraticForm(ZZ, [1,1,-1]) sage: Q.is_locally_universal_at_prime(infinity) True - """ self.local_representation_conditions(silent_flag=True) return self.__local_representability_conditions.is_universal_at_prime(p) - -def is_locally_universal_at_all_primes(self): +def is_locally_universal_at_all_primes(self) -> bool: """ - Determines if the quadratic form represents `Z_p` for all finite/non-archimedean primes. - - INPUT: - - none + Determine if the quadratic form represents `Z_p` for all finite/non-archimedean primes. OUTPUT: - boolean + boolean EXAMPLES:: @@ -866,25 +808,19 @@ def is_locally_universal_at_all_primes(self): sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.is_locally_universal_at_all_primes() False - """ self.local_representation_conditions(silent_flag=True) return self.__local_representability_conditions.is_universal_at_all_finite_primes() - -def is_locally_universal_at_all_places(self): +def is_locally_universal_at_all_places(self) -> bool: """ - Determines if the quadratic form represents `Z_p` for all + Determine if the quadratic form represents `Z_p` for all finite/non-archimedean primes, and represents all real numbers. - INPUT: - - none - OUTPUT: - boolean + boolean EXAMPLES:: @@ -903,27 +839,25 @@ def is_locally_universal_at_all_places(self): sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,-1]) sage: Q.is_locally_universal_at_all_places() # long time (8.5 s) True - """ self.local_representation_conditions(silent_flag=True) return self.__local_representability_conditions.is_universal_at_all_places() - -def is_locally_represented_number_at_place(self, m, p): +def is_locally_represented_number_at_place(self, m, p) -> bool: """ - Determines if the rational number m is locally represented by the + Determine if the rational number `m` is locally represented by the quadratic form at the (possibly infinite) prime `p`. INPUT: - `m` -- an integer + - `m` -- an integer - `p` -- a prime number > 0 or 'infinity' + - `p` -- a prime number > 0 or 'infinity' OUTPUT: - boolean + boolean EXAMPLES:: @@ -952,24 +886,23 @@ def is_locally_represented_number_at_place(self, m, p): True sage: Q.is_locally_represented_number_at_place(7, 5) # long time True - """ self.local_representation_conditions(silent_flag=True) return self.__local_representability_conditions.is_locally_represented_at_place(m, p) - -def is_locally_represented_number(self, m): +def is_locally_represented_number(self, m) -> bool: """ - Determines if the rational number m is locally represented by the quadratic form. + Determine if the rational number `m` is locally represented + by the quadratic form. INPUT: - `m` -- an integer + - `m` -- an integer OUTPUT: - boolean + boolean EXAMPLES:: From 352fed20094a66ac10b1fa7614f232b48eee9cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 17 Aug 2022 09:38:23 +0200 Subject: [PATCH 432/591] new wavelet of fixed typos --- src/sage/algebras/commutative_dga.py | 2 +- src/sage/coding/linear_code_no_metric.py | 2 +- src/sage/combinat/designs/bibd.py | 2 +- src/sage/combinat/superpartition.py | 4 ++-- src/sage/data_structures/stream.py | 3 +-- src/sage/databases/knotinfo_db.py | 2 +- src/sage/dynamics/arithmetic_dynamics/projective_ds.py | 2 +- src/sage/graphs/generators/distance_regular.pyx | 2 +- src/sage/graphs/graph_generators.py | 2 +- src/sage/graphs/weakly_chordal.pyx | 4 ++-- src/sage/knots/knotinfo.py | 2 +- src/sage/matrix/matrix2.pyx | 3 ++- src/sage/misc/misc.py | 2 +- src/sage/modules/fp_graded/homspace.py | 2 +- src/sage/modules/fp_graded/morphism.py | 2 +- src/sage/plot/contour_plot.py | 2 +- src/sage/plot/hyperbolic_polygon.py | 4 ++-- src/sage/plot/misc.py | 2 +- src/sage/plot/plot3d/implicit_surface.pyx | 2 +- src/sage/plot/plot3d/parametric_surface.pyx | 2 +- src/sage/quadratic_forms/quadratic_form__neighbors.py | 6 +++--- src/sage/repl/rich_output/pretty_print.py | 2 +- src/sage/rings/number_field/number_field.py | 2 +- src/sage/rings/padics/padic_lattice_element.py | 2 +- src/sage/symbolic/ginac/infinity.cpp | 2 +- src/sage/symbolic/ginac/mpoly-ginac.cpp | 2 +- src/sage/symbolic/ginac/mul.cpp | 2 +- src/sage/symbolic/ginac/normal.cpp | 4 ++-- 28 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index ff80254caf9..a05ede46e52 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -114,7 +114,7 @@ def sorting_keys(element): OUTPUT: - Its coordinates in the corresponding cohomology_raw quotoent vector space + Its coordinates in the corresponding cohomology_raw quotient vector space EXAMPLES:: diff --git a/src/sage/coding/linear_code_no_metric.py b/src/sage/coding/linear_code_no_metric.py index 50b507a2011..9610c4e31ce 100644 --- a/src/sage/coding/linear_code_no_metric.py +++ b/src/sage/coding/linear_code_no_metric.py @@ -1,5 +1,5 @@ r""" -Generic structures for linear codes of any metirc +Generic structures for linear codes of any metric Class supporting methods available for linear codes over any metric (Hamming, rank). diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index ac6a869a98d..a681506f760 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -260,7 +260,7 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa return False raise EmptySetError("There exists no ({},{},{})-BIBD".format(v, k, lambd)) - # Non-esistence by BRC Theoerem + # Non-existence by BRC Theoerem if BruckRyserChowla_check(v, k, lambd) is False: if existence: return False diff --git a/src/sage/combinat/superpartition.py b/src/sage/combinat/superpartition.py index ced73e8dadd..057451e3765 100644 --- a/src/sage/combinat/superpartition.py +++ b/src/sage/combinat/superpartition.py @@ -255,7 +255,7 @@ def _repr_(self) -> str: def _repr_pair(self) -> str: r""" - Represention of a super partition as a pair. + Representation of a super partition as a pair. A super partition is represented by a list consisting of the antisymmetric and symmetric parts. @@ -273,7 +273,7 @@ def _repr_pair(self) -> str: def _repr_list(self) -> str: r""" - Represention of a super partition as a list. + Representation of a super partition as a list. A super partition is represented by a list consisting of the negative values for the antisymmetric part listed first followed diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index e606f25579b..7eb0725033c 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -1648,8 +1648,7 @@ def get_coefficient(self, n): class Stream_scalar(Stream_inexact): """ - Base class for operators multiplying a coeffeicient stream - by a scalar. + Base class for operators multiplying a coefficient stream by a scalar. """ def __init__(self, series, scalar): """ diff --git a/src/sage/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index 21be7479ef4..bd066b73809 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -2,7 +2,7 @@ r""" KnotInfo Database -This module contains the class :class:`KnotInfoDataBase` and auxilary classes +This module contains the class :class:`KnotInfoDataBase` and auxiliary classes for it which serves as an interface to the lists of named knots and links provided at the web-pages `KnotInfo `__ and `LinkInfo `__. diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index c814b81987a..6a3715dbb7b 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4847,7 +4847,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', Computes the values of the elementary symmetric polynomials evaluated on the ``n`` multiplier spectra of this dynamical system. - The sigma invariants are the symetric polynomials evaluated on the + The sigma invariants are the symmetric polynomials evaluated on the characteristic polynomial of the multipliers. See [Hutz2019]_ for the full definition. Spepcifically, this function returns either the following polynomial or its coefficients (with signs diff --git a/src/sage/graphs/generators/distance_regular.pyx b/src/sage/graphs/generators/distance_regular.pyx index 29e101f9473..97a69f25cbb 100644 --- a/src/sage/graphs/generators/distance_regular.pyx +++ b/src/sage/graphs/generators/distance_regular.pyx @@ -1220,7 +1220,7 @@ def is_from_GQ_spread(list arr): def graph_from_GQ_spread(const int s, const int t): r""" - Return the point graph of the generalised quandrangle with + Return the point graph of the generalised quadrangle with order `(s, t)` after removing one of its spreads. These graphs are antipodal covers of complete graphs and, in particular, diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index fc647b5499d..ed71bc8ed07 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -1040,7 +1040,7 @@ def nauty_genbg(self, options="", debug=False): confuse the creation of a Sage graph. Option ``-q`` which suppress auxiliary output (except from ``-v``) should never be used as we are unable to recover the partition of the vertices of the bipartite graph - without the auxilary output. Hence the partition of the vertices of + without the auxiliary output. Hence the partition of the vertices of returned bipartite graphs might not respect the requirement. The res/mod option can be useful when using the output in a routine run diff --git a/src/sage/graphs/weakly_chordal.pyx b/src/sage/graphs/weakly_chordal.pyx index 983155f3cdc..45c692d8955 100644 --- a/src/sage/graphs/weakly_chordal.pyx +++ b/src/sage/graphs/weakly_chordal.pyx @@ -225,7 +225,7 @@ def is_long_hole_free(g, certificate=False): bitset_add(dense_graph, u * n + v) bitset_add(dense_graph, v * n + u) - # Allocate some data strutures + # Allocate some data structures cdef MemoryAllocator mem = MemoryAllocator() cdef int* path = mem.allocarray(n, sizeof(int)) cdef int path_top @@ -456,7 +456,7 @@ def is_long_antihole_free(g, certificate=False): bitset_add(dense_graph, u * n + v) bitset_add(dense_graph, v * n + u) - # Allocate some data strutures + # Allocate some data structures cdef MemoryAllocator mem = MemoryAllocator() cdef int* path = mem.allocarray(n, sizeof(int)) cdef int path_top diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index ed0f90dc1b9..df893a488f6 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -324,7 +324,7 @@ class KnotInfoBase(Enum): def __gt__(self, other): r""" - Implement comparision of different items in order to have ``sorted`` work. + Implement comparison of different items in order to have ``sorted`` work. EXAMPLES:: diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 6887975bf35..ad0f7e58e15 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -2313,7 +2313,8 @@ cdef class Matrix(Matrix1): the implementation raises an error because correct results cannot be guaranteed. - To access the algorithm using the above defintion, use ``'definition'``. + To access the algorithm using the above definition, + use ``'definition'``. However, notice that this algorithm is usually very slow. By default, i.e. if no options are set, the implementation tries to diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index 924403e47d4..4d52e6b0538 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -575,7 +575,7 @@ def uniq(x): def _stable_uniq(L): """ Iterate over the elements of ``L``, yielding every element at most - once: keep only the first occurance of any item. + once: keep only the first occurence of any item. The items must be hashable. diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index ee3e4dfa59f..08e30a17dba 100755 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -94,7 +94,7 @@ def _element_constructor_(self, values): Defn: g[1] |--> Sq(1)*g[2] + g[3] g[3] |--> Sq(2)*g[3] - One can construct a homomorphism from another homomorhism:: + One can construct a homomorphism from another homomorphism:: sage: g = homset(f) sage: f == g diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 0417bd72347..fde00303230 100755 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -955,7 +955,7 @@ def solve(self, x): if self.is_zero(): return None - # Handle the case where both the morhism and the element is non-trivial. + # Handle the case where both morphism and element are non-trivial. n = x.degree() - self.degree() f_n = self.vector_presentation(n) diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index 06d9cb97d53..3cf3d0f932d 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -822,7 +822,7 @@ def f(x,y): return cos(x) + sin(y) g = contour_plot(f, (-pi,pi), (-pi,pi), fill=False, axes=True) sphinx_plot(g) - If you are plotting a sole countour and if all of your data lie on + If you are plotting a sole contour and if all of your data lie on one side of it, then (as part of :trac:`21042`) a heuristic may be used to improve the result; in that case, a warning is emitted:: diff --git a/src/sage/plot/hyperbolic_polygon.py b/src/sage/plot/hyperbolic_polygon.py index 11a090a0fad..1726525ff43 100644 --- a/src/sage/plot/hyperbolic_polygon.py +++ b/src/sage/plot/hyperbolic_polygon.py @@ -229,7 +229,7 @@ def hyperbolic_polygon(pts, model="UHP", resolution=200, **options): P = hyperbolic_polygon([1,I,-1,-I], model="PD", color='green', fill=True, linestyle="-") sphinx_plot(P) - Klein model is also supported via the paraeter ``model``. + Klein model is also supported via the parameter ``model``. Show a hyperbolic polygon in the Klein model with coordinates `1`, `e^{i\pi/3}`, `e^{i2\pi/3}`, `-1`, `e^{i4\pi/3}`, `e^{i5\pi/3}`:: @@ -253,7 +253,7 @@ def hyperbolic_polygon(pts, model="UHP", resolution=200, **options): P = hyperbolic_polygon([p1,p2,p3,p4,p5,p6], model="KM", fill=True, color='purple') sphinx_plot(P) - Hyperboloid model is supported partially, via the paraeter ``model``. + Hyperboloid model is supported partially, via the parameter ``model``. Show a hyperbolic polygon in the hyperboloid model with coordinates `(3,3,\sqrt(19))`, `(3,-3,\sqrt(19))`, `(-3,-3,\sqrt(19))`, `(-3,3,\sqrt(19))`:: diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index d5fb53223f6..a64457ef661 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -177,7 +177,7 @@ def try_make_fast(f): return FastCallablePlotWrapper(ff, imag_tol=imaginary_tolerance) elif isinstance(f, Wrapper_cdf): # Already a fast-callable, just wrap it. This can happen - # if, for example, a symolic expression is passed to a + # if, for example, a symbolic expression is passed to a # higher-level plot() function that converts it to a # fast-callable with expr._plot_fast_callable() before # we ever see it. diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index a3b4a2ea27a..aaa2db0c3a8 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -1153,7 +1153,7 @@ cdef class ImplicitSurface(IndexFaceSet): def threejs_repr(self, render_params): r""" - Return a represention of the surface suitable for plotting with three.js. + Return a representation of the surface suitable for plotting with three.js. EXAMPLES:: diff --git a/src/sage/plot/plot3d/parametric_surface.pyx b/src/sage/plot/plot3d/parametric_surface.pyx index 7d112049848..ad6ea410e4d 100644 --- a/src/sage/plot/plot3d/parametric_surface.pyx +++ b/src/sage/plot/plot3d/parametric_surface.pyx @@ -369,7 +369,7 @@ cdef class ParametricSurface(IndexFaceSet): def threejs_repr(self, render_params): r""" - Return a represention of the surface suitable for plotting with three.js. + Return a representation of the surface suitable for plotting with three.js. EXAMPLES:: diff --git a/src/sage/quadratic_forms/quadratic_form__neighbors.py b/src/sage/quadratic_forms/quadratic_form__neighbors.py index 6c38d7784ee..96a5203101d 100644 --- a/src/sage/quadratic_forms/quadratic_form__neighbors.py +++ b/src/sage/quadratic_forms/quadratic_form__neighbors.py @@ -248,7 +248,7 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=ZZ(10)**3, - ``max_classes`` -- (default: ``1000``) break the computation when ``max_classes`` are found - - ``algorithm`` -- (optional) one of 'orbits', 'random', 'exaustion' + - ``algorithm`` -- (optional) one of 'orbits', 'random', 'exhaustion' - ``max_random_trys`` -- (default: ``1000``) the maximum number of neighbors computed for a single lattice @@ -265,7 +265,7 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=ZZ(10)**3, 46 sage: mass = Q.conway_mass() sage: g1 = neighbor_iteration([Q],3, mass=mass, algorithm = 'random') # long time - sage: g2 = neighbor_iteration([Q],3, algorithm = 'exaustion') # long time + sage: g2 = neighbor_iteration([Q],3, algorithm = 'exhaustion') # long time sage: g3 = neighbor_iteration([Q],3, algorithm = 'orbits') sage: mass == sum(1/q.number_of_automorphisms() for q in g1) # long time True @@ -304,7 +304,7 @@ def p_divisible_vectors(Q, max_neighbors): yield from iter(v.lift() for v in Q.orbits_lines_mod_p(p) if v != 0 and Q(v.lift()).valuation(p) > 0) return - elif algorithm == 'exaustion': + elif algorithm == 'exhaustion': def p_divisible_vectors(Q, max_neighbors): k = 0 v = Q.find_primitive_p_divisible_vector__next(p) diff --git a/src/sage/repl/rich_output/pretty_print.py b/src/sage/repl/rich_output/pretty_print.py index 154f17b8290..4fcbfe4d5af 100644 --- a/src/sage/repl/rich_output/pretty_print.py +++ b/src/sage/repl/rich_output/pretty_print.py @@ -62,7 +62,7 @@ class SequencePrettyPrinter(SageObject): def __init__(self, *args, **kwds): r""" - Pretty Printer for Muliple Arguments. + Pretty Printer for Multiple Arguments. INPUT/OUTPUT: diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 66dddb5597e..bf60e7bd31a 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -3413,7 +3413,7 @@ def dirichlet_group(self): m = self.conductor() d = self.degree() A = _splitting_classes_gens_(self,m,d) - # d could be improve to be the exponenent of the Galois group rather than the degree, but I do not see how to how about it already. + # d could be improve to be the exponent of the Galois group rather than the degree, but I do not see how to how about it already. G = DirichletGroup(m, CyclotomicField(d)) H = [G(1)] for chi in G: diff --git a/src/sage/rings/padics/padic_lattice_element.py b/src/sage/rings/padics/padic_lattice_element.py index 5f679a5ea72..ace965211bf 100644 --- a/src/sage/rings/padics/padic_lattice_element.py +++ b/src/sage/rings/padics/padic_lattice_element.py @@ -501,7 +501,7 @@ def _richcmp_(self, other, op): def is_equal_to(self, other, prec): r""" - Return ``True`` if this element is indisting + Return ``True`` if this element is indistinguishable from ``other`` at precision ``prec`` EXAMPLES:: diff --git a/src/sage/symbolic/ginac/infinity.cpp b/src/sage/symbolic/ginac/infinity.cpp index cfb2161f2dd..3a2a7b8469e 100644 --- a/src/sage/symbolic/ginac/infinity.cpp +++ b/src/sage/symbolic/ginac/infinity.cpp @@ -76,7 +76,7 @@ infinity::infinity() infinity::infinity(const numeric & _direction) : basic(&infinity::tinfo_static) { - // Note: we cannot accept an arbirtary ex as argument + // Note: we cannot accept an arbitrary ex as argument // or we would take precedence over the copy constructor. set_direction(_direction); hashvalue = hash_from_dir(direction); diff --git a/src/sage/symbolic/ginac/mpoly-ginac.cpp b/src/sage/symbolic/ginac/mpoly-ginac.cpp index 4c84a5ddb2f..608e0f6f207 100644 --- a/src/sage/symbolic/ginac/mpoly-ginac.cpp +++ b/src/sage/symbolic/ginac/mpoly-ginac.cpp @@ -118,7 +118,7 @@ struct sym_desc { /** Maximum number of terms of leading coefficient of symbol in both polynomials */ size_t max_lcnops; - /** Commparison operator for sorting */ + /** Comparison operator for sorting */ bool operator<(const sym_desc &x) const { if (max_deg == x.max_deg) diff --git a/src/sage/symbolic/ginac/mul.cpp b/src/sage/symbolic/ginac/mul.cpp index 6a3a8321bd2..2d95d953a25 100644 --- a/src/sage/symbolic/ginac/mul.cpp +++ b/src/sage/symbolic/ginac/mul.cpp @@ -1459,7 +1459,7 @@ const epvector & mul::get_sorted_seq() const /** Member-wise expand the expairs representing this sequence. This must be * overridden from expairseq::expandchildren() and done iteratively in order - * to allow for early cancallations and thus safe memory. + * to allow for early cancellations and thus safe memory. * * @see mul::expand() * @return pointer to epvector containing expanded representation or zero diff --git a/src/sage/symbolic/ginac/normal.cpp b/src/sage/symbolic/ginac/normal.cpp index 2d34d8f16f2..3fe3b8457f2 100644 --- a/src/sage/symbolic/ginac/normal.cpp +++ b/src/sage/symbolic/ginac/normal.cpp @@ -633,7 +633,7 @@ ex add::normal(exmap & repl, exmap & rev_lookup, int level, unsigned options) co num_it++; den_it++; } - // Additiion of two fractions, taking advantage of the fact that + // Addition of two fractions, taking advantage of the fact that // the heuristic GCD algorithm computes the cofactors at no extra cost ex co_den1, co_den2; ex g = gcdpoly(den, next_den, &co_den1, &co_den2, false); @@ -848,7 +848,7 @@ ex ex::denom() const return e; } -/** Get numerator and denominator of an expression. If the expresison is not +/** Get numerator and denominator of an expression. If the expression is not * of the normal form "numerator/denominator", it is first converted to this * form and then a list [numerator, denominator] is returned. * From 6aeab7d2b6f5cf61be7f969039c3e3a1d93997ed Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 08:42:38 -0700 Subject: [PATCH 433/591] src/sage/sets/image_set.py: Clarify is_injective=False --- src/sage/sets/image_set.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/sets/image_set.py b/src/sage/sets/image_set.py index 752ee4987bb..44a219a3f24 100644 --- a/src/sage/sets/image_set.py +++ b/src/sage/sets/image_set.py @@ -50,7 +50,7 @@ class ImageSubobject(Parent): - ``is_injective`` -- whether the ``map`` is injective: - ``None`` (default): infer from ``map`` or default to ``False`` - - ``False``: ``map`` is known to be non-injective + - ``False``: do not assume that ``map`` is injective - ``True``: ``map`` is known to be injective - ``"check"``: raise an error when ``map`` is not injective From 6705b9e287e1970a8c882a8ae27108496dead21d Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Wed, 17 Aug 2022 17:56:21 +0200 Subject: [PATCH 434/591] 29717: test formal Markov trace against LG + typos --- .../algebras/hecke_algebras/cubic_hecke_algebra.py | 10 ++++++---- src/sage/databases/cubic_hecke_db.py | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 1c8a8f24b1b..6a09eb8634f 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -497,7 +497,7 @@ def formal_markov_trace(self, extended=False, field_embedding=False): Currently it is not known if all linear forms of this sub-module belong to a Markov trace, i.e. can be extended to the full tower of cubic Hecke algebras. Anyway, at least the four basis elements - (``U1``, ``U2, ``U3`` and ``K4``) can be reconstructed form + (``U1``, ``U2``, ``U3`` and ``K4``) can be reconstructed form the HOMFLY-PT and Kauffman polynomial. INPUT: @@ -557,8 +557,10 @@ def formal_markov_trace(self, extended=False, field_embedding=False): True sage: f = MT.specialize_links_gould() - sage: sum(f(LK3_1.coefficient(b)) * b.links_gould_polynomial() for b in sup) + sage: g = sum(f(LK3_1.coefficient(b)) * b.links_gould_polynomial() for b in sup); g -t0^2*t1 - t0*t1^2 + t0^2 + 2*t0*t1 + t1^2 - t0 - t1 + 1 + sage: g == K3_1.link().links_gould_polynomial() + True """ cha = self.parent() vs = self.to_vector() @@ -2577,7 +2579,7 @@ def _cubic_braid_image(self, cubic_braid, check=True): - ``cubic_braid`` -- :class:`~sage.groups.cubic_braid.CubicBraid` whose image in ``self`` should be returned - - ``check`` -- boolean (default: ``True``); check in the given cubic + - ``check`` -- boolean (default: ``True``); check if the given cubic braid is already registered in the finite sub basis; if set to ``False`` duplicate entries can occur. @@ -3457,7 +3459,7 @@ def characters(self, irr=None, original=True): - ``irr`` -- (optional) instance of :class:`AbsIrreducibeRep` selecting the irreducible representation corresponding to the character; if not given a list of all characters is returned - - ``original`` -- (default ``True``) see description above + - ``original`` -- (default: ``True``) see description above OUTPUT: diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 6d2ddb4f086..fd0068f8793 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -481,7 +481,7 @@ def link(self): def regular_homfly_polynomial(self): r""" - Return the regular variant of the KOMFLY-PT polynomial of the link that + Return the regular variant of the HOMFLY-PT polynomial of the link that represents this basis element. This is the HOMFLY-PT polynomial renormalized by the writhe factor @@ -1476,7 +1476,7 @@ def read_markov(bas_ele, variables, num_strands=4): Return precomputed Markov trace coefficients. This code was generated by ``create_markov_trace_data.py`` (from - the ``database_cubic_heck`` repository), please do not edit. + the ``database_cubic_hecke`` repository), please do not edit. INPUT: From bad3c162dbffb22c7367d9ebf585b340d4fe9485 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 10:19:55 -0700 Subject: [PATCH 435/591] .devcontainer/post_create.sh: Install bootstrapping prerequisites --- .devcontainer/post_create.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/post_create.sh b/.devcontainer/post_create.sh index 0e443230898..5067e93e4f7 100755 --- a/.devcontainer/post_create.sh +++ b/.devcontainer/post_create.sh @@ -3,7 +3,7 @@ export PATH=$(pwd)/build/bin:$PATH SYSTEM=$(sage-guess-package-system) eval $(sage-print-system-package-command $SYSTEM "$@" update) -eval $(sage-print-system-package-command $SYSTEM --yes "$@" --spkg install _prereq python3 git $EXTRA_SAGE_PACKAGES) +eval $(sage-print-system-package-command $SYSTEM --yes "$@" --spkg install _bootstrap _prereq python3 git $EXTRA_SAGE_PACKAGES) if [ -n "$EXTRA_SYSTEM_PACKAGES" ]; then eval $(sage-print-system-package-command $SYSTEM --yes "$@" install $EXTRA_SYSTEM_PACKAGES) fi From 4bf4dcc16caf08adc15f9a279ebc1bd965f1d7a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 17 Aug 2022 20:13:21 +0200 Subject: [PATCH 436/591] fix details --- src/sage/combinat/designs/bibd.py | 2 +- src/sage/misc/misc.py | 2 +- src/sage/rings/number_field/number_field.py | 2 +- src/sage/symbolic/ginac/mul.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index a681506f760..dc9b6c39f3f 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -260,7 +260,7 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa return False raise EmptySetError("There exists no ({},{},{})-BIBD".format(v, k, lambd)) - # Non-existence by BRC Theoerem + # Non-existence by BRC Theorem if BruckRyserChowla_check(v, k, lambd) is False: if existence: return False diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index 4d52e6b0538..c2c440daffb 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -575,7 +575,7 @@ def uniq(x): def _stable_uniq(L): """ Iterate over the elements of ``L``, yielding every element at most - once: keep only the first occurence of any item. + once: keep only the first occurrence of any item. The items must be hashable. diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index bf60e7bd31a..fb5466125d6 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -3413,7 +3413,7 @@ def dirichlet_group(self): m = self.conductor() d = self.degree() A = _splitting_classes_gens_(self,m,d) - # d could be improve to be the exponent of the Galois group rather than the degree, but I do not see how to how about it already. + # d could be improved to be the exponent of the Galois group rather than the degree, but I do not see how to go about that yet. G = DirichletGroup(m, CyclotomicField(d)) H = [G(1)] for chi in G: diff --git a/src/sage/symbolic/ginac/mul.cpp b/src/sage/symbolic/ginac/mul.cpp index 2d95d953a25..f7496cbb5e5 100644 --- a/src/sage/symbolic/ginac/mul.cpp +++ b/src/sage/symbolic/ginac/mul.cpp @@ -1459,7 +1459,7 @@ const epvector & mul::get_sorted_seq() const /** Member-wise expand the expairs representing this sequence. This must be * overridden from expairseq::expandchildren() and done iteratively in order - * to allow for early cancellations and thus safe memory. + * to allow for early cancellations and thus save memory. * * @see mul::expand() * @return pointer to epvector containing expanded representation or zero From b19a1ffe144f09f01aea3134630a2a8262c41c32 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 11:46:48 -0700 Subject: [PATCH 437/591] src/sage/sets/set.py: Accept and handle 'category' arguments --- src/sage/sets/set.py | 50 ++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 96e3b2ad7a4..3e034bd7125 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -48,6 +48,7 @@ from sage.categories.sets_cat import Sets from sage.categories.enumerated_sets import EnumeratedSets +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets import sage.rings.infinity @@ -85,7 +86,7 @@ def has_finite_length(obj): return True -def Set(X=None): +def Set(X=None, category=None): r""" Create the underlying set of ``X``. @@ -187,12 +188,12 @@ def Set(X=None): if X is None: X = [] elif isinstance(X, CategoryObject): - if isinstance(X, Set_generic): + if isinstance(X, Set_generic) and category is None: return X elif X in Sets().Finite(): - return Set_object_enumerated(X) + return Set_object_enumerated(X, category=category) else: - return Set_object(X) + return Set_object(X, category=category) if isinstance(X, Element) and not isinstance(X, Set_base): raise TypeError("Element has no defined underlying set") @@ -200,9 +201,9 @@ def Set(X=None): try: X = frozenset(X) except TypeError: - return Set_object(X) + return Set_object(X, category=category) else: - return Set_object_enumerated(X) + return Set_object_enumerated(X, category=category) class Set_base(): @@ -474,7 +475,7 @@ def __init__(self, X, category=None): sage: type(Set(QQ)) sage: Set(QQ).category() - Category of sets + Category of infinite sets TESTS:: @@ -492,6 +493,15 @@ def __init__(self, X, category=None): if category is None: category = Sets() + + if isinstance(X, CategoryObject): + if X in Sets().Finite(): + category = category.Finite() + elif X in Sets().Infinite(): + category = category.Infinite() + if X in Sets().Enumerated(): + category = category.Enumerated() + Parent.__init__(self, category=category) self.__object = X @@ -830,7 +840,7 @@ class Set_object_enumerated(Set_object): """ A finite enumerated set. """ - def __init__(self, X): + def __init__(self, X, category=None): r""" Initialize ``self``. @@ -839,12 +849,12 @@ def __init__(self, X): sage: S = Set(GF(19)); S {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} sage: S.category() - Category of finite sets + Category of finite enumerated sets sage: print(latex(S)) \left\{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18\right\} sage: TestSuite(S).run() """ - Set_object.__init__(self, X, category=Sets().Finite()) + Set_object.__init__(self, X, category=FiniteEnumeratedSets().or_subcategory(category)) def random_element(self): r""" @@ -1267,7 +1277,7 @@ def __classcall__(cls, X, Y, *args, **kwds): Y = Set(Y) return type.__call__(cls, X, Y, *args, **kwds) - def __init__(self, X, Y, op, latex_op): + def __init__(self, X, Y, op, latex_op, category=None): r""" Initialization. @@ -1284,7 +1294,7 @@ def __init__(self, X, Y, op, latex_op): self._Y = Y self._op = op self._latex_op = latex_op - Set_object.__init__(self, self) + Set_object.__init__(self, self, category=category) def _repr_(self): r""" @@ -1338,7 +1348,7 @@ class Set_object_union(Set_object_binary): """ A formal union of two sets. """ - def __init__(self, X, Y): + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1354,7 +1364,7 @@ def __init__(self, X, Y): sage: TestSuite(X).run() """ - Set_object_binary.__init__(self, X, Y, "union", "\\cup") + Set_object_binary.__init__(self, X, Y, "union", "\\cup", category=category) def is_finite(self): r""" @@ -1481,7 +1491,7 @@ class Set_object_intersection(Set_object_binary): """ Formal intersection of two sets. """ - def __init__(self, X, Y): + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1499,7 +1509,7 @@ def __init__(self, X, Y): True sage: TestSuite(X).run() """ - Set_object_binary.__init__(self, X, Y, "intersection", "\\cap") + Set_object_binary.__init__(self, X, Y, "intersection", "\\cap", category=category) def is_finite(self): r""" @@ -1643,7 +1653,7 @@ class Set_object_difference(Set_object_binary): """ Formal difference of two sets. """ - def __init__(self, X, Y): + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1658,7 +1668,7 @@ def __init__(self, X, Y): sage: TestSuite(X).run() """ - Set_object_binary.__init__(self, X, Y, "difference", "-") + Set_object_binary.__init__(self, X, Y, "difference", "-", category=category) def is_finite(self): r""" @@ -1807,7 +1817,7 @@ class Set_object_symmetric_difference(Set_object_binary): """ Formal symmetric difference of two sets. """ - def __init__(self, X, Y): + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1822,7 +1832,7 @@ def __init__(self, X, Y): sage: TestSuite(X).run() """ - Set_object_binary.__init__(self, X, Y, "symmetric difference", "\\bigtriangleup") + Set_object_binary.__init__(self, X, Y, "symmetric difference", "\\bigtriangleup", category=category) def is_finite(self): r""" From 19f582021bb6887ad45f824e1f3fcdf636e1cd77 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Wed, 17 Aug 2022 14:46:34 -0500 Subject: [PATCH 438/591] value->rank and check for integer value --- src/sage/categories/enumerated_sets.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index a556c4f3d2b..bbfce79c4dd 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -653,21 +653,23 @@ def _unrank_from_iterator(self, r): sage: C._unrank_from_iterator(5) Traceback (most recent call last): ... - ValueError: the value must be between 0 and 2 inclusive + ValueError: the rank must be between 0 and 2 inclusive sage: ZZ._unrank_from_iterator(-1) Traceback (most recent call last): ... - ValueError: the value must be greater than or equal to 0 - + ValueError: the rank must be greater than or equal to 0 """ + from sage.rings.integer_ring import ZZ if r < 0: - raise ValueError("the value must be greater than or equal to 0") + raise ValueError("the rank must be greater than or equal to 0") + if r not in ZZ: + raise ValueError(f"{r=} must be an integer") counter = 0 for u in self: if counter == r: return u counter += 1 - raise ValueError("the value must be between %s and %s inclusive"%(0,counter-1)) + raise ValueError("the rank must be between %s and %s inclusive"%(0,counter-1)) unrank = _unrank_from_iterator def _rank_from_iterator(self, x): From 8fbcc34f00da33c408200a970601d3112e1c1857 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Wed, 17 Aug 2022 15:24:36 -0500 Subject: [PATCH 439/591] Fix reviewer comments --- src/sage/combinat/schubert_polynomial.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/combinat/schubert_polynomial.py b/src/sage/combinat/schubert_polynomial.py index 22cbc410ea7..794dc7ee2c6 100644 --- a/src/sage/combinat/schubert_polynomial.py +++ b/src/sage/combinat/schubert_polynomial.py @@ -7,11 +7,7 @@ Schubert polynomials are representatives of cohomology classes in flag varieties. In `n` variables, they are indexed by permutations `w \in S_n`. They also form a basis for the coinvariant ring of the `S_n` action on -`\\Bold{Z}[x_1, x_2, \ldots, x_n]`. - -In Sage, they are modeled in the :class:`SchubertPolynomial_class`. Instances of -this class can be created by creating an instance ``X`` of a Schubert polynomial -ring using the constructor :func:`SchubertPolynomialRing`. +`\ZZ[x_1, x_2, \ldots, x_n]`. EXAMPLES:: From d461411617f8bca18f3e9575daaa3adf3bed1551 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 13:35:07 -0700 Subject: [PATCH 440/591] Update doctest outputs --- src/sage/categories/cartesian_product.py | 2 +- src/sage/categories/enumerated_sets.py | 2 +- src/sage/categories/homset.py | 2 +- src/sage/combinat/sidon_sets.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index 33f5c5b9b02..e6fbf670750 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -153,7 +153,7 @@ def __call__(self, args, **kwds): sage: cartesian_product([set([0,1,2]), [0,1]]) The Cartesian product of ({0, 1, 2}, {0, 1}) sage: _.category() - Category of Cartesian products of sets + Category of Cartesian products of finite enumerated sets Check that the empty product is handled correctly: diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 563a8025e6d..e1dcbd86839 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -137,7 +137,7 @@ def _call_(self, X): sage: S = EnumeratedSets()(Set([1, 2, 3])); S {1, 2, 3} sage: S.category() - Category of facade finite enumerated sets + Category of finite enumerated sets Also Python3 range are now accepted:: diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index bfd78e8d8a5..219286af8b9 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -828,7 +828,7 @@ def _element_constructor_(self, x, check=None, **options): sage: H = Hom(Set([1,2,3]), Set([1,2,3])) sage: f = H( lambda x: 4-x ) sage: f.parent() - Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of finite sets + Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of finite enumerated sets sage: f(1), f(2), f(3) # todo: not implemented sage: H = Hom(ZZ, QQ, Sets()) diff --git a/src/sage/combinat/sidon_sets.py b/src/sage/combinat/sidon_sets.py index 3f5cfcb3173..ec5038eb2c4 100644 --- a/src/sage/combinat/sidon_sets.py +++ b/src/sage/combinat/sidon_sets.py @@ -46,12 +46,12 @@ def sidon_sets(N, g = 1): sage: S.cardinality() 8 sage: S.category() - Category of finite sets + Category of finite enumerated sets sage: sid = S.an_element() sage: sid {2} sage: sid.category() - Category of finite sets + Category of finite enumerated sets TESTS:: From cd816e6a007fdb1c1430ca6897acc364d596d155 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Wed, 17 Aug 2022 15:42:43 -0500 Subject: [PATCH 441/591] Rephrase range --- src/sage/categories/enumerated_sets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index bbfce79c4dd..8a74d3f8437 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -669,7 +669,7 @@ def _unrank_from_iterator(self, r): if counter == r: return u counter += 1 - raise ValueError("the rank must be between %s and %s inclusive"%(0,counter-1)) + raise ValueError("the rank must be in the range from %s to %s"%(0,counter-1)) unrank = _unrank_from_iterator def _rank_from_iterator(self, x): From c777eca9975a5bf25902b5483d00853b8b4ce1f1 Mon Sep 17 00:00:00 2001 From: "Trevor K. Karn" Date: Wed, 17 Aug 2022 16:04:00 -0500 Subject: [PATCH 442/591] Rewrite using enumerate and fix doctests --- src/sage/categories/enumerated_sets.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 8a74d3f8437..2ff92233521 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -653,7 +653,7 @@ def _unrank_from_iterator(self, r): sage: C._unrank_from_iterator(5) Traceback (most recent call last): ... - ValueError: the rank must be between 0 and 2 inclusive + ValueError: the rank must be in the range from 0 to 2 sage: ZZ._unrank_from_iterator(-1) Traceback (most recent call last): ... @@ -664,12 +664,10 @@ def _unrank_from_iterator(self, r): raise ValueError("the rank must be greater than or equal to 0") if r not in ZZ: raise ValueError(f"{r=} must be an integer") - counter = 0 - for u in self: + for counter, u in enumerate(self): if counter == r: return u - counter += 1 - raise ValueError("the rank must be in the range from %s to %s"%(0,counter-1)) + raise ValueError("the rank must be in the range from %s to %s"%(0,counter)) unrank = _unrank_from_iterator def _rank_from_iterator(self, x): From df327b9d5d76bc5b9807a937b7bb04ed334b60ae Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 17:26:27 -0700 Subject: [PATCH 443/591] src/sage/sets/set.py: Refine categories of unions, intersections, differences --- src/sage/sets/set.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 3e034bd7125..5d2380b3d24 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -1358,12 +1358,22 @@ def __init__(self, X, Y, category=None): sage: T = Set(ZZ) sage: X = S.union(T); X Set-theoretic union of Set of elements of Vector space of dimension 2 over Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of infinite sets sage: latex(X) \Bold{Q}^{2} \cup \Bold{Z} sage: TestSuite(X).run() """ + if category is None: + category = Sets() + if all(S in Sets().Finite() for S in (X, Y)): + category = category.Finite() + if all(S in Sets().Enumerated() for S in (X, Y)): + category = category.Enumerated() + if any(S in Sets().Infinite() for S in (X, Y)): + category = category.Infinite() Set_object_binary.__init__(self, X, Y, "union", "\\cup", category=category) def is_finite(self): @@ -1501,16 +1511,47 @@ def __init__(self, X, Y, category=None): sage: T = Set(ZZ) sage: X = S.intersection(T); X Set-theoretic intersection of Set of elements of Vector space of dimension 2 over Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of enumerated sets sage: latex(X) \Bold{Q}^{2} \cap \Bold{Z} sage: X = Set(IntegerRange(100)).intersection(Primes()) sage: X.is_finite() True + sage: X.category() + Category of finite enumerated sets sage: TestSuite(X).run() """ + if category is None: + category = Sets() + if any(S in Sets().Finite() for S in (X, Y)): + category = category.Finite() + if any(S in Sets().Enumerated() for S in (X, Y)): + category = category.Enumerated() Set_object_binary.__init__(self, X, Y, "intersection", "\\cap", category=category) + def cardinality(self): + r""" + Return the cardinality of this set. + + EXAMPLES:: + + sage: X = Set(IntegerRange(100)).intersection(Primes()) + sage: X.cardinality() + 25 + + sage: X = Set(Primes(), category=Sets()).intersection(Set(IntegerRange(200))) + sage: X.cardinality() + 46 + """ + if self in Sets().Infinite(): + return Infinity + if self in Sets().Finite(): + from sage.rings.integer import Integer + return Integer(len(list(iter(self)))) + return super().cardinality() + def is_finite(self): r""" Return whether this set is finite. @@ -1663,11 +1704,21 @@ def __init__(self, X, Y, category=None): sage: T = Set(ZZ) sage: X = S.difference(T); X Set-theoretic difference of Set of elements of Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of sets sage: latex(X) \Bold{Q} - \Bold{Z} sage: TestSuite(X).run() """ + if category is None: + category = Sets() + if X in Sets().Finite(): + category = category.Finite() + if X in Sets().Enumerated(): + category = category.Enumerated() + if X in Sets().Infinite() and Y in Sets().Finite(): + category = category.Infinite() Set_object_binary.__init__(self, X, Y, "difference", "-", category=category) def is_finite(self): @@ -1797,6 +1848,8 @@ def _sympy_(self): Set-theoretic difference of Set of elements of Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of sets sage: X._sympy_() Complement(Rationals, Integers) @@ -1804,6 +1857,8 @@ def _sympy_(self): Set-theoretic difference of Set of elements of Integer Ring and Set of elements of Rational Field + sage: X.category() + Category of enumerated sets sage: X._sympy_() EmptySet """ @@ -1827,11 +1882,19 @@ def __init__(self, X, Y, category=None): sage: T = Set(ZZ) sage: X = S.symmetric_difference(T); X Set-theoretic symmetric difference of Set of elements of Rational Field and Set of elements of Integer Ring + sage: X.category() + Category of sets sage: latex(X) \Bold{Q} \bigtriangleup \Bold{Z} sage: TestSuite(X).run() """ + if category is None: + category = Sets() + if all(S in Sets().Finite() for S in (X, Y)): + category = category.Finite() + if all(S in Sets().Enumerated() for S in (X, Y)): + category = category.Enumerated() Set_object_binary.__init__(self, X, Y, "symmetric difference", "\\bigtriangleup", category=category) def is_finite(self): From ab79e40b1b93f50fa091403103336dc5c981675f Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 18 Aug 2022 11:07:00 +0900 Subject: [PATCH 444/591] Edit duplicates --- src/doc/en/developer/portability_testing.rst | 75 +++++++++----------- 1 file changed, 33 insertions(+), 42 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index e296a168e72..da89fad56f9 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1206,10 +1206,13 @@ you can see what it does: reusing the installation (:envvar:`SAGE_LOCAL`, :envvar:`SAGE_VENV`) from the prebuilt image. -After VS Code finished configuring the dev container, your local Sage -repository at ``$SAGE_ROOT`` is available in the container at the directory -``/workspaces/``. You may need to open a new Terminal to start -working from the directory. +After VS Code finished configuring the dev container (when the message "Done. +Press any key to close the terminal." appears in the terminal named +"Configuring"), your local Sage repository at ``$SAGE_ROOT`` is available in +the container at the directory ``/workspaces/``. To use Sage +in a terminal, `open a new terminal in VS Code +`_, type ``./sage`` and hit +:kbd:`Enter`. .. NOTE:: @@ -1235,6 +1238,22 @@ In addition to the provides several other sample ``devcontainer.json`` configuration files in the directory ``$SAGE_ROOT/.devcontainer``. +Files named ``$SAGE_ROOT/.devcontainer/develop-.../devcontainer.json`` configure +containers from a public Docker image that provides SageMath and then updates the +installation of SageMath in this container by building from the current source tree. + +- `develop-docker-computop/devcontainer.json + `_ + configures a container with the `Docker image from the 3-manifolds + project `_, providing + SnapPy, Regina, PHCPack, etc. + +If you want to use one of these ``devcontainer.json`` files, copy (or symlink) +it and start VS Code as explained above. After VS Code finished configuring the +dev container, to use Sage in a terminal, `open a new terminal in VS Code +`_, type ``./sage`` and hit +:kbd:`Enter`. + Files named ``$SAGE_ROOT/.devcontainer/downstream-.../devcontainer.json`` configure containers with an installation of downstream packages providing SageMath from a package manager (``downstream-archlinux-...``, ``downstream-conda-forge``; @@ -1247,56 +1266,28 @@ work without change) or to adapt them to your needs. - `downstream-archlinux-latest/devcontainer.json `_ - configures a container with an installation of `Arch Linux `_ - and its SageMath package. (Arch Linux packaging is downstream from the Sage project, - hence the prefix ``downstream-...``; the suffix ``latest`` indicates - the most recent version of Arch Linux as available on Docker Hub.) - - When the message "Done. Press any key to close the terminal." appears in the terminal - named "Configuring", Sage is ready for use. To use Sage in a terminal, `open a new - terminal in VS Code `_, type ``sage`` - and hit :kbd:`Enter`. (Do not use ``./sage``; this will not work because the source tree is - not configured.) + configures a container with an installation of `Arch Linux + `_ and its SageMath package. (The suffix ``latest`` + indicates the most recent version of Arch Linux as available on Docker Hub.) - `downstream-conda-forge-latest/devcontainer.json `_ - similarly configures a container with an installation of conda-forge and its SageMath package. - - When the message "Done. Press any key to close the terminal." appears in the terminal - named "Configuring", Sage is ready for use. To use Sage in a terminal, `open a new - terminal in VS Code `_, type ``sage`` - and hit :kbd:`Enter`. (Do not use ``./sage``; this will not work because the source tree is - not configured.) + configures a container with an installation of conda-forge and its SageMath package. - `downstream-docker-cocalc/devcontainer.json `_ configures a container with `the CoCalc Docker image `_. - When the message "Done. Press any key to close the terminal." appears in the terminal - named "Configuring", Sage is ready for use. To use Sage in a terminal, `open a new - terminal in VS Code `_, type ``sage`` - and hit :kbd:`Enter`. (Do not use ``./sage``; this will not work because the source tree is - not configured.) - - `downstream-docker-computop/devcontainer.json `_ configures a container with the `Docker image from the 3-manifolds project `_, providing SnapPy, Regina, PHCPack, etc. - When the message "Done. Press any key to close the terminal." appears in the terminal - named "Configuring", Sage is ready for use. To use Sage in a terminal, `open a new - terminal in VS Code `_, type ``sage`` - and hit :kbd:`Enter`. (Do not use ``./sage``; this will not work because the source tree is - not configured.) +If you want to use one of these ``devcontainer.json`` files, copy (or symlink) +it and start VS Code as explained above. After VS Code finished configuring the +dev container, to use Sage in a terminal, `open a new terminal in VS Code +`_, type ``sage`` and hit +:kbd:`Enter`. (Do not use ``./sage``; this will not work because the source +tree is not configured.) -Files named ``$SAGE_ROOT/.devcontainer/develop-.../devcontainer.json`` configure -containers from a public Docker image that provides SageMath and then updates the -installation of SageMath in this container by building from the current source tree. - -- `develop-docker-computop/devcontainer.json - `_ - configures a container with the `Docker image from the 3-manifolds - project `_, providing - SnapPy, Regina, PHCPack, etc. It then updates the installation of - SageMath in this container by building from the current source tree. From 5ca1db842c5b5038dd20a214cfb41f9c3a3c60c9 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 18 Aug 2022 12:09:46 +0900 Subject: [PATCH 445/591] Note for reusing a dev container --- src/doc/en/developer/portability_testing.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index da89fad56f9..e96aa0b9d1e 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1214,6 +1214,13 @@ in a terminal, `open a new terminal in VS Code `_, type ``./sage`` and hit :kbd:`Enter`. +.. NOTE:: + + If you restart VS Code after configuring a dev container, VS Code starts + again configuring a new dev container. If you want to reuse the previous dev + container, you need to enter "Remote-Containers: Attach to Running + Container" in the command palette of VS Code and choose the dev container. + .. NOTE:: Your Sage at ``$SAGE_ROOT`` was configured and rebuilt inside the dev From 8a304931879a0ce4292d284439c8e717540755cf Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 20:31:44 -0700 Subject: [PATCH 446/591] src/sage/sets/set.py: Simplify category checks as suggested --- src/sage/sets/set.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 5d2380b3d24..bd94a217e0d 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -1368,12 +1368,12 @@ def __init__(self, X, Y, category=None): """ if category is None: category = Sets() - if all(S in Sets().Finite() for S in (X, Y)): - category = category.Finite() if all(S in Sets().Enumerated() for S in (X, Y)): category = category.Enumerated() if any(S in Sets().Infinite() for S in (X, Y)): category = category.Infinite() + elif all(S in Sets().Finite() for S in (X, Y)): + category = category.Finite() Set_object_binary.__init__(self, X, Y, "union", "\\cup", category=category) def is_finite(self): @@ -1713,11 +1713,11 @@ def __init__(self, X, Y, category=None): """ if category is None: category = Sets() - if X in Sets().Finite(): - category = category.Finite() if X in Sets().Enumerated(): category = category.Enumerated() - if X in Sets().Infinite() and Y in Sets().Finite(): + if X in Sets().Finite(): + category = category.Finite() + elif X in Sets().Infinite() and Y in Sets().Finite(): category = category.Infinite() Set_object_binary.__init__(self, X, Y, "difference", "-", category=category) From 141ebf14d80478128540f39ff1bac46e80eaca26 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 20:39:59 -0700 Subject: [PATCH 447/591] src/sage/categories/sets_cat.py: Update doctest output --- src/sage/categories/sets_cat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 09a57770a3b..4d7e0c11da4 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -247,7 +247,7 @@ def _call_(self, X, enumerated_set=False): {1, 2, 3} sage: S = Sets()([1, 2, 3]); S.category() - Category of finite sets + Category of finite enumerated sets sage: S = Sets()([1, 2, 3], enumerated_set=True); S.category() Category of facade finite enumerated sets From 8aa274ef877e4c987daa7d20fa761d2e5af94567 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 20:47:41 -0700 Subject: [PATCH 448/591] src/sage/categories/sets_cat.py: Fix doctest --- src/sage/categories/sets_cat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 4d7e0c11da4..b6fc0779716 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1361,7 +1361,7 @@ def some_elements(self): sage: S.some_elements() [47] sage: S = Set([]) - sage: S.some_elements() + sage: list(S.some_elements()) [] This method should return an iterable, *not* an iterator. From f48d9111f944483334aecbf98f42c4e41e457d75 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 18 Aug 2022 12:49:13 +0900 Subject: [PATCH 449/591] Correct the new note --- src/doc/en/developer/portability_testing.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index e96aa0b9d1e..91ca5a460d4 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1216,9 +1216,8 @@ in a terminal, `open a new terminal in VS Code .. NOTE:: - If you restart VS Code after configuring a dev container, VS Code starts - again configuring a new dev container. If you want to reuse the previous dev - container, you need to enter "Remote-Containers: Attach to Running + If you want VS Code to use a previously configured dev container, first run + the dev container in Docker and enter "Remote-Containers: Attach to Running Container" in the command palette of VS Code and choose the dev container. .. NOTE:: From d711a61aeacde364b4ab76b59e55c2f01d8a90d7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 Aug 2022 22:50:41 -0700 Subject: [PATCH 450/591] src/sage/structure/parent.pyx: Update doctest output --- src/sage/structure/parent.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 36b1e45d223..585ec9e559e 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2863,7 +2863,7 @@ cdef class Set_generic(Parent): TESTS:: sage: Set(QQ).category() - Category of sets + Category of infinite sets """ def object(self): From 32f41584771a66f832a5b29ae236207ff00e6176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 18 Aug 2022 09:01:53 +0200 Subject: [PATCH 451/591] a few typos --- src/sage/algebras/orlik_terao.py | 2 +- src/sage/combinat/designs/subhypergraph_search.pyx | 2 +- src/sage/combinat/k_regular_sequence.py | 2 +- src/sage/combinat/perfect_matching.py | 6 +++--- src/sage/combinat/sf/sfa.py | 4 ++-- src/sage/combinat/similarity_class_type.py | 7 ++++--- src/sage/groups/matrix_gps/orthogonal.py | 7 +++---- src/sage/schemes/elliptic_curves/constructor.py | 2 +- src/sage/schemes/elliptic_curves/mod_sym_num.pyx | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/sage/algebras/orlik_terao.py b/src/sage/algebras/orlik_terao.py index 458bb07b926..7bd25496745 100644 --- a/src/sage/algebras/orlik_terao.py +++ b/src/sage/algebras/orlik_terao.py @@ -628,7 +628,7 @@ def action_on_groundset(g, x): self._side = kwargs.pop('side', 'left') - # the action on the Orlik-Terao is not neccesarily by ring automorphim, + # the action on the Orlik-Terao is not necessarily by ring automorphism, # so the best we can assume is a finite dimensional module with basis. if 'category' in kwargs: category = kwargs.pop('category') diff --git a/src/sage/combinat/designs/subhypergraph_search.pyx b/src/sage/combinat/designs/subhypergraph_search.pyx index dd762e9bc7a..0b48819e15a 100644 --- a/src/sage/combinat/designs/subhypergraph_search.pyx +++ b/src/sage/combinat/designs/subhypergraph_search.pyx @@ -147,7 +147,7 @@ cdef inline void bs_set(uint64_t * bitset, int index, int bit): cdef inline int bs_issubset64(uint64_t * b1, uint64_t b2, int limbs): r""" - Test whether bistet ``b1`` (on ``limbs`` blocks) is a subset of b2 (one block). + Test whether bitset ``b1`` (on ``limbs`` blocks) is a subset of b2 (one block). It implies in particular that all last `limbs-1` blocks of ``b1`` are equal to zero. diff --git a/src/sage/combinat/k_regular_sequence.py b/src/sage/combinat/k_regular_sequence.py index ae5e573fd0b..2d840e7416b 100644 --- a/src/sage/combinat/k_regular_sequence.py +++ b/src/sage/combinat/k_regular_sequence.py @@ -959,7 +959,7 @@ def from_recurrence(self, *args, **kwds): - `f(k^M n + r) = c_{r,l} f(k^m n + l) + c_{r,l + 1} f(k^m n + l + 1) + ... + c_{r,u} f(k^m n + u)` for some integers `0 \leq r < k^M`, `M > m \geq 0` and `l \leq u`, and some - coefficients `c_{r,j}` from the (semi)ring ``coefficents`` + coefficients `c_{r,j}` from the (semi)ring ``coefficients`` of the corresponding :class:`kRegularSequenceSpace`, valid for all integers `n \geq \text{offset}` for some integer `\text{offset} \geq \max(-l/k^m, 0)` (default: ``0``), and diff --git a/src/sage/combinat/perfect_matching.py b/src/sage/combinat/perfect_matching.py index 7d8ddf1bcca..383f6522903 100644 --- a/src/sage/combinat/perfect_matching.py +++ b/src/sage/combinat/perfect_matching.py @@ -36,7 +36,7 @@ REFERENCES: .. [MV] combinatorics of orthogonal polynomials (A. de Medicis et - X.Viennot, Moments des q-polynomes de Laguerre et la bijection de + X.Viennot, Moments des q-polynômes de Laguerre et la bijection de Foata-Zeilberger, Adv. Appl. Math., 15 (1994), 262-304) .. [McD] combinatorics of hyperoctahedral group, double coset algebra and @@ -44,8 +44,8 @@ polynomials, Oxford University Press, second edition, 1995, chapter VII). -.. [CM] Benoit Collins, Sho Matsumoto, On some properties of - orthogonal Weingarten functions, :arxiv:`0903.5143`. +.. [CM] Benoit Collins, Sho Matsumoto, *On some properties of + orthogonal Weingarten functions*, :arxiv:`0903.5143`. """ # **************************************************************************** # Copyright (C) 2010 Valentin Feray diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index d1fd77e8c69..29f30031092 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -1072,11 +1072,11 @@ def lehrer_solomon(self, lam): sage: s = Sym.s() sage: pi_2 = (s.gessel_reutenauer(2)).omega_involution() sage: pi_1 = (s.gessel_reutenauer(1)).omega_involution() - sage: s.lehrer_solomon([2,1]) == pi_2 * pi_1 # since h_1, e_1 are pletistic identities + sage: s.lehrer_solomon([2,1]) == pi_2 * pi_1 # since h_1, e_1 are plethystic identities True Note that this also gives the `S_n`-equivariant structure of the - Orlik-Solmon algebra of the braid arrangement (also known as the + Orlik-Solomon algebra of the braid arrangement (also known as the type-`A` reflection arrangement). The representation corresponding to `\mathbf{LS}_\lambda` exhibits diff --git a/src/sage/combinat/similarity_class_type.py b/src/sage/combinat/similarity_class_type.py index dad6ea70bb5..88515bb3cfe 100644 --- a/src/sage/combinat/similarity_class_type.py +++ b/src/sage/combinat/similarity_class_type.py @@ -105,11 +105,11 @@ class type, it is also possible to compute the number of classes of that type sage: simultaneous_similarity_classes(3, 2) q^10 + q^8 + 2*q^7 + 2*q^6 + 2*q^5 + q^4 -Similarity class types can be used to calculate the coefficients of generating +Similarity class types can be used to compute the coefficients of generating functions coming from the cycle index type techniques of Kung and Stong (see Morrison [Morrison06]_). -They can also be used to caclulate the number of invariant subspaces for a matrix +They can also be used to compute the number of invariant subspaces for a matrix over a finite field of any given dimension. For this we use the elegant recursive formula of Ramaré [R17]_ (see also [PR22]_). @@ -353,9 +353,10 @@ def centralizer_group_cardinality(la, q=None): q = ZZ['q'].gen() return q**centralizer_algebra_dim(la)*prod([fq(m, q=q) for m in la.to_exp()]) + def invariant_subspace_generating_function(la, q=None, t=None): """ - Return the invariant subpace generating function of a nilpotent matrix with + Return the invariant subspace generating function of a nilpotent matrix with Jordan block sizes given by ``la``. INPUT: diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index f6721afaacd..c6763ace0ef 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -135,16 +135,15 @@ def normalize_args_e(degree, ring, e): return ZZ(e) - - ############################################################################### # Orthogonal Group: common Code for both GO and SO ############################################################################### def _OG(n, R, special, e=0, var='a', invariant_form=None): r""" - This function is commonly used by the functions GO and SO to avoid uneccessarily - duplicated code. For documentation and examples see the individual functions. + This function is commonly used by the functions GO and SO to avoid + unecessarily duplicated code. For documentation and examples see + the individual functions. TESTS: diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py index 46de5dd8957..7f93bb19aee 100644 --- a/src/sage/schemes/elliptic_curves/constructor.py +++ b/src/sage/schemes/elliptic_curves/constructor.py @@ -615,7 +615,7 @@ def EllipticCurve_from_j(j, minimal_twist=True): minimal conductor; when there is more than one curve with minimal conductor, the curve returned is the one whose label comes first if the curves are in the CremonaDatabase, otherwise - the one whose minimal a-invarinats are first lexicographically. + the one whose minimal a-invariants are first lexicographically. If `j` is not in `\QQ` this parameter is ignored. OUTPUT: diff --git a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx index dd452869e2e..34a3d38d65c 100644 --- a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx +++ b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx @@ -1168,7 +1168,7 @@ cdef class ModularSymbolNumerical: # have to make sure that when twisting by a # prime ell, the twisted curve does not have # additive reduction. Otherwise, unitary - # cusps will become non-movalble. + # cusps will become non-movable. if D != 1: Nt = Et.conductor() for ell in D.prime_divisors(): From e583ff0b0d53e1062a00d7cfbff340753b7689df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Thu, 18 Aug 2022 15:42:56 +0200 Subject: [PATCH 452/591] fix suggestion --- src/sage/groups/matrix_gps/orthogonal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index c6763ace0ef..8ff96051a8b 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -142,7 +142,7 @@ def normalize_args_e(degree, ring, e): def _OG(n, R, special, e=0, var='a', invariant_form=None): r""" This function is commonly used by the functions GO and SO to avoid - unecessarily duplicated code. For documentation and examples see + unnecessarily duplicated code. For documentation and examples see the individual functions. TESTS: From 4e29451c723564147fa20aa9dd9e18b68a5a5eb4 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 19 Aug 2022 09:03:58 +0900 Subject: [PATCH 453/591] Improvments to the formal_markov_trace return. --- .../hecke_algebras/cubic_hecke_algebra.py | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 6a09eb8634f..a64c5d3c88f 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -9,11 +9,12 @@ s_i^3 = u s_i^2 - v s_i + w. -Here `u, v, w` are elements in an arbitrary integral domain and `i` is a positive -integer less than `n`, the number of the braid group's strands. By the analogue -to the *Iwahori Hecke algebras* (see :class:`~sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra`), -in which the braid generators satisfy a quadratic relation these algebras have been -called *cubic Hecke algebras*. The relations inherited from the braid group are: +Here `u, v, w` are elements in an arbitrary integral domain and `i` is a +positive integer less than `n`, the number of the braid group's strands. +By the analogue to the *Iwahori Hecke algebras* (see +:class:`~sage.algebras.iwahori_hecke_algebra.IwahoriHeckeAlgebra`), in which the +braid generators satisfy a quadratic relation these algebras have been called +*cubic Hecke algebras*. The relations inherited from the braid group are: .. MATH:: @@ -51,23 +52,23 @@ Hecke algebra which is in bijection to the cubic braid group and compatible with the specialization to the cubic braid group algebra as explained above. -For the algebras corresponding to braid groups of less than five strands such a -basis has been calculated by Ivan Marin. This one is used here. In the case of 5 -strands such a basis is not available, right now. Instead the elements of the cubic -braid group class themselves are used as basis elements. This is also the case when -the cubic braid group is infinite, even though it is not known if these elements -span all of the cubic Hecke algebra. +For the algebras corresponding to braid groups of less than five strands such +a basis has been calculated by Ivan Marin. This one is used here. In the case +of 5 strands such a basis is not available, right now. Instead the elements +of the cubic braid group class themselves are used as basis elements. This +is also the case when the cubic braid group is infinite, even though it is +not known if these elements span all of the cubic Hecke algebra. -Accordingly, be aware that the module embedding of the group algebra of the cubic -braid groups is known to be an isomorphism of free modules only in the cases of less -than five strands. +Accordingly, be aware that the module embedding of the group algebra of the +cubicbraid groups is known to be an isomorphism of free modules only in the +cases of less than five strands. EXAMPLES: -1. Consider the obstruction ``b`` of the *triple quadratic algebra* from Section - 2.6 of [Mar2018]_. We verify that the third power of it is a scalar multiple - of itself (explicitly ``2*w^2`` times the *Schur element* of the three - dimensional irreducible representation):: +Consider the obstruction ``b`` of the *triple quadratic algebra* from Section 2.6 +of [Mar2018]_. We verify that the third power of it is a scalar multiple +of itself (explicitly ``2*w^2`` times the *Schur element* of the three +dimensional irreducible representation):: sage: CHA3 = algebras.CubicHecke(3) sage: c1, c2 = CHA3.gens() @@ -81,25 +82,25 @@ sage: f = BR(b3.coefficients()[0]/w) sage: try: ....: sh = CHA3.schur_element(CHA3.irred_repr.W3_111) - ....: except NotImplementedError: # for the case GAP3 / CHEVIE not available + ....: except NotImplementedError: # for the case GAP3 / CHEVIE not available ....: sh = ER(f/(2*w^2)) sage: ER(f/(2*w^2)) == sh True sage: b3 == f*b True -2. Defining the cubic Hecke algebra on 6 strands will need some seconds for - initializing. But than you can do calculations inside the infinite algebra - as well:: +Defining the cubic Hecke algebra on 6 strands will need some seconds for +initializing. However, you can do calculations inside the infinite +algebra as well:: - sage: CHA6 = algebras.CubicHecke(6) # optional - database_cubic_hecke - sage: CHA6.inject_variables() # optional - database_cubic_hecke + sage: CHA6 = algebras.CubicHecke(6) # optional - database_cubic_hecke # long time + sage: CHA6.inject_variables() # optional - database_cubic_hecke # long time Defining c0, c1, c2, c3, c4 - sage: s = c0*c1*c2*c3*c4; s # optional - database_cubic_hecke + sage: s = c0*c1*c2*c3*c4; s # optional - database_cubic_hecke # long time c0*c1*c2*c3*c4 - sage: s^2 # optional - database_cubic_hecke + sage: s^2 # optional - database_cubic_hecke # long time (c0*c1*c2*c3*c4)^2 - sage: t = CHA6.an_element()*c4; t # optional - database_cubic_hecke + sage: t = CHA6.an_element() * c4; t # optional - database_cubic_hecke # long time (-w)*c0*c1^-1*c4 + v*c0*c2^-1*c4 + u*c2*c1*c4 + ((-v*w+u)/w)*c4 REFERENCES: @@ -576,7 +577,8 @@ def formal_markov_trace(self, extended=False, field_embedding=False): vs = vs.change_ring(RI) mtcf = [M.from_vector(cf.to_vector()) for cf in mtcf] - return sum(vs[i] * mtcf[i] for i in range(len(vs))) + R = M.base_ring() + return M.linear_combination((mtcf[i], R(val)) for i, val in vs.iteritems()) class CubicHeckeAlgebra(CombinatorialFreeModule): From df877ca2180c451a292fc442217c0bdac70917b5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 19 Aug 2022 10:22:55 +0900 Subject: [PATCH 454/591] Speeding up initializing of cubic Hecke algebras. --- .../hecke_algebras/cubic_hecke_algebra.py | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index a64c5d3c88f..467313ce9b9 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -93,14 +93,14 @@ initializing. However, you can do calculations inside the infinite algebra as well:: - sage: CHA6 = algebras.CubicHecke(6) # optional - database_cubic_hecke # long time - sage: CHA6.inject_variables() # optional - database_cubic_hecke # long time + sage: CHA6 = algebras.CubicHecke(6) # optional - database_cubic_hecke + sage: CHA6.inject_variables() # optional - database_cubic_hecke Defining c0, c1, c2, c3, c4 - sage: s = c0*c1*c2*c3*c4; s # optional - database_cubic_hecke # long time + sage: s = c0*c1*c2*c3*c4; s # optional - database_cubic_hecke c0*c1*c2*c3*c4 - sage: s^2 # optional - database_cubic_hecke # long time + sage: s^2 # optional - database_cubic_hecke (c0*c1*c2*c3*c4)^2 - sage: t = CHA6.an_element() * c4; t # optional - database_cubic_hecke # long time + sage: t = CHA6.an_element() * c4; t # optional - database_cubic_hecke (-w)*c0*c1^-1*c4 + v*c0*c2^-1*c4 + u*c2*c1*c4 + ((-v*w+u)/w)*c4 REFERENCES: @@ -835,7 +835,7 @@ def __classcall_private__(cls, n=None, names='c', cubic_equation_parameters=None def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=None): r""" - Python constructor. + Initialize ``self``. TESTS:: @@ -1331,18 +1331,45 @@ def get_order(self): if self._nstrands < 5: return self._order - # detect change of order of sub algebra - cbg = self.cubic_braid_group() + # detect change of _order of sub algebra sub_alg = self.cubic_hecke_subalgebra() former_len_sub = len(sub_alg._order) - sub_order = [cbg(cb) for cb in sub_alg.get_order()] + sub_order = sub_alg.get_order() if former_len_sub == len(sub_order): if len(self._order) == former_len_sub + len(self._basis_extension): return self._order - # order has changed! re-calculation necessary: + # _order has changed! re-calculation necessary: + cbg = self.cubic_braid_group() + sub_order = [cbg(cb) for cb in sub_order] self._order = sub_order + [cbg(tup) for tup in self._basis_extension] return self._order + def _order_key(self, x): + """ + Return a key for `x` compatible with the term order. + + INPUT: + + - ``x`` -- indices of the basis of ``self`` + + EXAMPLES:: + + sage: A = CombinatorialFreeModule(QQ, ['x','y','a','b']) + sage: A.set_order(['x', 'y', 'a', 'b']) + sage: A._order_key('x') + 0 + sage: A._order_key('y') + 1 + sage: A._order_key('a') + 2 + """ + try: + return self._rank_basis(x) + except AttributeError: + from sage.combinat.ranker import rank_from_list + self._rank_basis = rank_from_list(self._order) + return self._rank_basis(x) + def _dense_free_module(self, base_ring=None): r""" Return a dense free module with the same dimension as ``self``. @@ -1825,12 +1852,16 @@ def _init_basis_extension(self): tietze_list = self._basis_tietze() cbg = self._cubic_braid_group self._finite_sub_basis_tuples = {} + order_list = [cbg(tup) for tup in tietze_list] - self.set_order(order_list) + # We avoid the call to set_order for speed. + # This avoids hashing the keys, which can become expensive. + self._order = order_list verbose('finite sub basis length: %s' % (len(order_list)), level=2) if self._nstrands < 5: return + # ---------------------------------------------------------------------- # loading the extension of the basis from data file # ---------------------------------------------------------------------- @@ -2473,6 +2504,7 @@ def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preim # -------------------------------------------------------------------------- # _cubic_braid_append_to_basis # -------------------------------------------------------------------------- + def _cubic_braid_append_to_basis(self, cubic_braid): r""" Append the given cubic braid to the finite sub basis which is used for @@ -2509,7 +2541,10 @@ def _cubic_braid_append_to_basis(self, cubic_braid): order = self.get_order() next_index = len(order) self._basis_extension.append(cbTietze) - self._rank_basis.update({cubic_braid: next_index}) # supporting :meth:`get_order_key` + try: + self._rank_basis.update({cubic_braid: next_index}) # supporting :meth:`get_order_key` + except AttributeError: + pass order.append(cubic_braid) monomial = self.monomial(cubic_braid) self._finite_sub_basis_tuples.update({cubic_braid: cbTietze}) @@ -2583,7 +2618,7 @@ def _cubic_braid_image(self, cubic_braid, check=True): whose image in ``self`` should be returned - ``check`` -- boolean (default: ``True``); check if the given cubic braid is already registered in the finite sub basis; if set to - ``False`` duplicate entries can occur. + ``False`` duplicate entries can occur EXAMPLES:: @@ -3233,16 +3268,15 @@ def cubic_hecke_subalgebra(self, nstrands=None): if nstrands >= n or nstrands <= 0: raise ValueError('nstrands must be positive and less than %s' % self._nstrands) - Gens = self.gens() + names = self.variable_names() if nstrands == self._nstrands - 1 and self._cubic_hecke_subalgebra is not None: return self._cubic_hecke_subalgebra - gen_range = range(nstrands - 1) - GensRed = tuple([Gens[i] for i in gen_range]) + names_red = names[:nstrands-1] if self.base_ring() == self.base_ring(generic=True): - SubHeckeAlg = CubicHeckeAlgebra(names=GensRed) + SubHeckeAlg = CubicHeckeAlgebra(names=names_red) else: - SubHeckeAlg = CubicHeckeAlgebra(names=GensRed, + SubHeckeAlg = CubicHeckeAlgebra(names=names_red, cubic_equation_parameters=tuple(self._cubic_equation_parameters), cubic_equation_roots=tuple(self._cubic_equation_roots)) From e63e4f0bb4950985b13c4fbcc4c76110efb338c5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 18 Aug 2022 18:38:56 -0700 Subject: [PATCH 455/591] Set_object.is_finite: Check category --- src/sage/sets/set.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index bd94a217e0d..707f8887c72 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -743,6 +743,10 @@ def is_finite(self): sage: Set([1,'a',ZZ]).is_finite() True """ + if self in Sets().Finite(): + return True + if self in Sets().Infinite(): + return False obj = self.__object try: is_finite = obj.is_finite From 970d46772d84a0d31bc12517b16eb936be59a2c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 18 Aug 2022 18:47:32 -0700 Subject: [PATCH 456/591] Set_object.cardinality: Check category --- src/sage/sets/set.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 707f8887c72..8c0668724d0 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -676,6 +676,9 @@ def cardinality(self): sage: Set(GF(5^2,'a')).cardinality() 25 """ + if self in Sets().Infinite(): + return sage.rings.infinity.infinity + if not self.is_finite(): return sage.rings.infinity.infinity From e58d2abf9490496346fb4f114d98a9c9393a2b8d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 18 Aug 2022 18:48:10 -0700 Subject: [PATCH 457/591] Set_object_intersection.cardinality: Remove; move delegation to super to Set_object --- src/sage/sets/set.py | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 8c0668724d0..b76e6b064ef 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -693,7 +693,7 @@ def cardinality(self): except TypeError: pass - raise NotImplementedError("computation of cardinality of %s not yet implemented" % self.__object) + return super().cardinality() def is_empty(self): """ @@ -1526,9 +1526,16 @@ def __init__(self, X, Y, category=None): sage: X = Set(IntegerRange(100)).intersection(Primes()) sage: X.is_finite() True + sage: X.cardinality() + 25 sage: X.category() Category of finite enumerated sets sage: TestSuite(X).run() + + sage: X = Set(Primes(), category=Sets()).intersection(Set(IntegerRange(200))) + sage: X.cardinality() + 46 + sage: TestSuite(X).run() """ if category is None: category = Sets() @@ -1538,27 +1545,6 @@ def __init__(self, X, Y, category=None): category = category.Enumerated() Set_object_binary.__init__(self, X, Y, "intersection", "\\cap", category=category) - def cardinality(self): - r""" - Return the cardinality of this set. - - EXAMPLES:: - - sage: X = Set(IntegerRange(100)).intersection(Primes()) - sage: X.cardinality() - 25 - - sage: X = Set(Primes(), category=Sets()).intersection(Set(IntegerRange(200))) - sage: X.cardinality() - 46 - """ - if self in Sets().Infinite(): - return Infinity - if self in Sets().Finite(): - from sage.rings.integer import Integer - return Integer(len(list(iter(self)))) - return super().cardinality() - def is_finite(self): r""" Return whether this set is finite. From f113e5c1dfe1cbef8e9f74905edbe79e29b63796 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Fri, 19 Aug 2022 14:47:13 +0900 Subject: [PATCH 458/591] Doing the rest of my commit of cubic_braid.py. --- src/sage/groups/cubic_braid.py | 506 ++++++++++++++++----------------- 1 file changed, 239 insertions(+), 267 deletions(-) diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index 295d43aa1d2..35e82ccbf9e 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- r""" Cubic Braid Groups @@ -7,7 +6,7 @@ .. MATH:: - s_i^3 = 1 + s_i^3 = 1. In general these groups have firstly been investigated by Coxeter, H.S.M. in: "Factor groups of the braid groups, Proceedings of the Fourth Canadian @@ -22,13 +21,13 @@ `G_{32}`. Coxeter realized these groups as subgroups of unitary groups with respect -to a certain hermitian form over the complex numbers (in fact over `\QQ` +to a certain Hermitian form over the complex numbers (in fact over `\QQ` adjoined with a primitive 12-th root of unity). In "Einige endliche Faktorgruppen der Zopfgruppen" (Math. Z., 163 (1978), 291-302) J. Assion considered two series `S(m)` and `U(m)` of finite factors of these groups. The additional relations on the braid group -generators `\{ s_1, \cdot , s_{m-1}\}` are +generators `\{ s_1, \cdots, s_{m-1}\}` are .. MATH:: @@ -46,15 +45,14 @@ as symplectic groups over `GF(3)` (resp. subgroups therein) and `U(m)` as general unitary groups over `GF(4)` (resp. subgroups therein). -This class implements all the groups considered by Coxeter and Assion as -finitely presented groups together with the classical realizations given -by the authors. It also contains the conversion maps between the two ways -of realization. In addition the user can construct other realizations and -maps to matrix groups with help of the Burau representation. In case gap3 -and CHEVIE are installed the reflection groups (via the gap3 interface) -are available, too. The methods for all this functionality are -:meth:`as_classical_group`, :meth:`as_matrix_group`, :meth:`as_permutation_group` -and :meth:`as_reflection_group`. +All the groups considered by Coxeter and Assion are considered as finitely +presented groups together with the classical realizations. It also allows +for the conversion maps between the two realizations. In addition, we can +construct other realizations and maps to matrix groups with help of the +Burau representation. In case ``gap3`` and ``CHEVIE`` are installed, the +reflection groups (via the ``gap3`` interface) are available, too. This can +be done using the methods :meth:`as_classical_group`, :meth:`as_matrix_group`, +:meth:`as_permutation_group`, and :meth:`as_reflection_group`. TESTS:: @@ -116,11 +114,11 @@ def _reduce_tietze(tietze_list): """ def eliminate_item(tietze_list): """ - this sub method searches for an item in the Tietze expression such + This sub method searches for an item in the Tietze expression such that it together with the first entry gives a pair which can be replaced by the second braid relation and the generators degree - reduction. If no such pair exists, it returns None. Else-wise the - reduced tietze list is returned. + reduction. If no such pair exists, it returns ``None``. Otherwise + the reduced tietze list is returned. """ l = len(tietze_list) if l < 2: @@ -170,20 +168,19 @@ def eliminate_item(tietze_list): # ---------------------------------------------------------------------------------- def AssionGroupS(n=None, names='s'): r""" - Construct cubic braid groups as instance of :class:`CubicBraidGroup` which have been + Construct cubic braid groups :class:`CubicBraidGroup` which have been investigated by J.Assion using the notation S(m). This function is a short hand cut for setting the construction arguments ``cbg_type=CubicBraidGroup.type.AssionS`` and default ``names='s'``. - For more information type ``CubicBraidGroup?`` - INPUT: - - ``n`` -- integer or None (default). The number of strands. This argument is passed - to the corresponding argument of the classcall of :class:`CubicBraidGroup`. + - ``n`` -- integer (optional); the number of strands + - ``names`` -- (default: ``'s'``) string or list/tuple/iterable of strings + + .. SEEALSO:: - - ``names`` -- string or list/tuple/iterable of strings (default:'s'). This argument is - passed to the corresponding argument of the classcall of :class:`CubicBraidGroup`. + :class:`CubicBraidGroup` EXAMPLES:: @@ -194,7 +191,7 @@ def AssionGroupS(n=None, names='s'): sage: S3 == S3x True """ - return CubicBraidGroup(n = n, names = names, cbg_type=CubicBraidGroup.type.AssionS) + return CubicBraidGroup(n=n, names=names, cbg_type=CubicBraidGroup.type.AssionS) def AssionGroupU(n=None, names='u'): @@ -204,15 +201,14 @@ def AssionGroupU(n=None, names='u'): for setting the construction arguments ``cbg_type=CubicBraidGroup.type.AssionU`` and default ``names='u'``. - For more information type ``CubicBraidGroup?`` - INPUT: - - ``n`` -- integer or None (default). The number of strands. This argument is passed - to the corresponding argument of the classcall of :class:`CubicBraidGroup`. + - ``n`` -- integer (optional); the number of strands + - ``names`` -- (default: ``'s'``) string or list/tuple/iterable of strings + + .. SEEALSO:: - - ``names`` -- string or list/tuple/iterable of strings (default:'u'). This argument is - passed to the corresponding argument of the classcall of :class:`CubicBraidGroup`. + :class:`CubicBraidGroup` EXAMPLES:: @@ -224,7 +220,7 @@ def AssionGroupU(n=None, names='u'): True """ - return CubicBraidGroup(n = n, names = names, cbg_type=CubicBraidGroup.type.AssionU) + return CubicBraidGroup(n=n, names=names, cbg_type=CubicBraidGroup.type.AssionU) @@ -233,13 +229,12 @@ def AssionGroupU(n=None, names='u'): # Class CubicBraidElement (for elements) # ############################################################################## + class CubicBraidElement(FinitelyPresentedGroupElement): r""" - This class models elements of cubic factor groups of the braid group. - It is the element class of the CubicBraidGroup. + Elements of cubic factor groups of the braid group. - For more information see the documentation of the parent - :class:`CubicBraidGroup`. + For more information see :class:`CubicBraidGroup`. EXAMPLES:: @@ -250,11 +245,9 @@ class CubicBraidElement(FinitelyPresentedGroupElement): sage: ele1 == ele2 True """ - def __init__(self, parent, x, check=True): """ - The Python constructor. - It is overloaded to achieve a reduction of the Tietze expression + Initialize ``self``. EXAMPLES:: @@ -277,10 +270,11 @@ def _richcmp_(self, other, op): """ Rich comparison of ``self`` with ``other``. - Overwrite comparison since the inherited one from :class:`FinitelyPresentedGroupElement` - (via Gap) does not terminate in the case of more than 5 strands (not - only infinite cases). On less than 5 strands comparison is not assumed - to be random free (see the :trac:`33498` and section 47.3-2 of the + Overwrite comparison since the inherited one from + :class:`FinitelyPresentedGroupElement` (via Gap) does not terminate + in the case of more than 5 strands (not only infinite cases). + On less than 5 strands comparison is not assumed to be deterministic + (see the :trac:`33498` and section 47.3-2 of the `Gap Reference manual `__). Therefore, the comparison is done via the Burau representation. @@ -313,7 +307,6 @@ def _richcmp_(self, other, op): omat = other._matrix_() return smat._richcmp_(omat, op) - def __hash__(self): r""" Return a hash value for ``self``. @@ -329,10 +322,11 @@ def __hash__(self): @cached_method def _matrix_(self): r""" - Return self as a matrix group element according to its parent's default matrix group. - So far this method returns the same results as :meth:`burau_matrix` in the default - case. But its behavior with respect to performance is different: The first invocation - for a group will be slower but all successive ones will be faster! + Return ``self`` as a matrix according to its parent's default matrix + group. + + So far, this method returns the same results as :meth:`burau_matrix` + in the default case. EXAMPLES:: @@ -345,15 +339,9 @@ def _matrix_(self): mat_grp = self.parent().as_matrix_group() return mat_grp(self).matrix() - def braid(self): r""" - Return the canonical braid preimage of ``self`` as Object of the - class :class:`Braid`. - - OUTPUT: - - The preimage of ``self`` as instance of :class:`Braid`. + Return the canonical braid preimage of ``self`` as a :class:`Braid`. EXAMPLES:: @@ -363,7 +351,6 @@ class :class:`Braid`. sage: c1.braid().parent() Braid group on 3 strands """ - braid_group = self.parent().braid_group() return braid_group(self) @@ -375,28 +362,28 @@ def burau_matrix(self, root_bur = None, domain = None, characteristic = None, va This method uses the same method belonging to :class:`Braid`, but reduces the indeterminate to a primitive sixth (resp. twelfth in case - reduced='unitary') root of unity. + ``reduced='unitary'``) root of unity. INPUT (all arguments are optional keywords): - ``root_bur`` -- six (resp. twelfth) root of unity in some field - (default root of unity over `\QQ`). - - ``domain`` -- base_ring for the Burau matrix (default is Cyclotomic - Field of order 3 and degree 2, resp. the domain of `root_bur` if given). - - ``characteristic`` - integer giving the characteristic of the - domain (default is 0 or the characteristic of `domain` if given). - - ``var`` -- string used for the indeterminate name in case root_bur - must be constructed in a splitting field. - - ``reduced`` -- boolean (default: ``False``) or string; for more + (default: root of unity over `\QQ`) + - ``domain`` -- (default: cyclotomic field of order 3 and degree 2, resp. + the domain of `root_bur` if given) base ring for the Burau matrix + - ``characteristic`` -- integer giving the characteristic of the + domain (default: 0 or the characteristic of ``domain`` if given) + - ``var`` -- string used for the indeterminate name in case ``root_bur`` + must be constructed in a splitting field + - ``reduced`` -- boolean or string (default: ``False``); for more information see the documentation of :meth:`burau_matrix` of - :class:`Braid`. + :class:`Braid` OUTPUT: The Burau matrix of the cubic braid coset with entries in the - domain given by the options. In case the option `reduced='unitary'` + domain given by the options. In case the option ``reduced='unitary'`` is given a triple consisting of the Burau matrix, its adjoined and - the hermitian form is returned. + the Hermitian form is returned. EXAMPLES:: @@ -465,7 +452,7 @@ def burau_matrix(self, root_bur = None, domain = None, characteristic = None, va from sage.misc.functional import cyclotomic_polynomial min_pol_root_bur = cyclotomic_polynomial(6, var=var) unitary = False - if type(reduced) == str: + if isinstance(reduced, str): if reduced == 'unitary': unitary = True min_pol_root_bur = cyclotomic_polynomial(12, var=var) @@ -501,13 +488,13 @@ def find_root(domain): if domain is None: - if (characteristic is None): + if characteristic is None: # -------------------------------------------------------------------- # setting the default characteristic in order to achieve the according # representations being well defined # -------------------------------------------------------------------- cbg_type = self.parent()._cbg_type - if cbg_type == CubicBraidGroup.type.AssionS: + if cbg_type == CubicBraidGroup.type.AssionS: characteristic = 3 # making Assion type S relations vanish elif cbg_type == CubicBraidGroup.type.AssionU: characteristic = 2 # making Assion type U relations vanish @@ -572,9 +559,8 @@ def conv2domain (laur_pol): ############################################################################## class CubicBraidGroup(FinitelyPresentedGroup): r""" - This class implements factor groups of the Artin braid group mapping - their generators to elements of order 3 (see the module header for more - information on these groups). + Factor groups of the Artin braid group mapping their generators to elements + of order 3. These groups are implemented as a particular case of finitely presented groups similar to the :class:`BraidGroup_class`. @@ -583,35 +569,37 @@ class CubicBraidGroup(FinitelyPresentedGroup): the name of the generators in a similar way as it works for the :class:`BraidGroup_class`. - INPUT (to the constructor): + INPUT: - ``names`` -- see the corresponding documentation of :class:`BraidGroup_class`. + - ``cbg_type`` -- (default: ``CubicBraidGroup.type.Coxeter``; + see explanation below) enum type :class:`CubicBraidGroup.type` - - ``cbg_type`` -- (optional keyword, default = CubicBraidGroup.type.Coxeter, - see explanation below) of enum type :class:`CubicBraidGroup.type`. - - Setting the keyword ``cbg_type`` to one on the values ``CubicBraidGroup.type.AssionS`` - or ``CubicBraidGroup.type.AssionU`` the additional relations due to Assion are added: + Setting the keyword ``cbg_type`` to one on the values + ``CubicBraidGroup.type.AssionS`` or ``CubicBraidGroup.type.AssionU``, + the additional relations due to Assion are added: .. MATH:: \begin{array}{lll} \mbox{S:} & s_3 s_1 t_2 s_1 t_2^{-1} t_3 t_2 s_1 t_2^{-1} t_3^{-1} = 1 - & \mbox{ for } m >= 5 \mbox{ in case } S(m)\\ + & \mbox{ for } m >= 5 \mbox{ in case } S(m), \\ \mbox{U:} & t_1 t_3 = 1 - & \mbox{ for } m >= 5 \mbox{ in case } U(m) + & \mbox{ for } m >= 5 \mbox{ in case } U(m), \end{array} - where `t_i = (s_i s_{i+1})^3`. If ``cbg_type == CubicBraidGroup.type.Coxeter`` (default) - only the cubic relation on the generators is active (Coxeter's case of investigation). - Note that for `n = 2, 3, 4` the groups do not differ between the three possible - values of cbg_type (as finitely presented groups). But anyway, the instances for - ``CubicBraidGroup.type.Coxeter, CubicBraidGroup.type.AssionS`` and ``CubicBraidGroup.type.AssionU`` - are different, since they have different classical realizations implemented. + where `t_i = (s_i s_{i+1})^3`. If ``cbg_type == CubicBraidGroup.type.Coxeter`` + (default) only the cubic relation on the generators is active (Coxeter's + case of investigation). Note that for `n = 2, 3, 4`, the groups do not + differ between the three possible values of ``cbg_type`` (as finitely + presented groups). However, the ``CubicBraidGroup.type.Coxeter``, + ``CubicBraidGroup.type.AssionS`` and ``CubicBraidGroup.type.AssionU`` + are different, so they have different classical realizations implemented. + + .. SEEALSO:: - The creation of instances of this class can also be done more easily by help - of :func:`CubicBraidGroup`, :func:`AssionGroupS` and :func:`AssionGroupU` - (similar to :func:`BraidGroup` with respect to :class:`BraidGroup_class`). + Instances can also be constructed more easily by using + :func:`CubicBraidGroup`, :func:`AssionGroupS` and :func:`AssionGroupU`. EXAMPLES:: @@ -620,7 +608,7 @@ class CubicBraidGroup(FinitelyPresentedGroup): sage: U3.gens() (c0, c1) - alternative possibilities defining U3:: + Alternative possibilities defining ``U3``:: sage: U3 = AssionGroupU(3); U3 Assion group on 3 strands of type U @@ -631,7 +619,7 @@ class CubicBraidGroup(FinitelyPresentedGroup): sage: U3.gens() (u1, u2) - alternates naming the generators:: + Alternates naming the generators:: sage: U3 = AssionGroupU(3, 'a, b'); U3 Assion group on 3 strands of type U @@ -645,7 +633,8 @@ class CubicBraidGroup(FinitelyPresentedGroup): #I Forcing finiteness test True sage: U3.as_classical_group() - Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] of (The projective general unitary group of degree 3 over Finite Field of size 2) + Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] + of (The projective general unitary group of degree 3 over Finite Field of size 2) sage: C3.as_classical_group() Subgroup with 2 generators ( [ E(3)^2 0] [ 1 -E(12)^7] @@ -665,13 +654,14 @@ class CubicBraidGroup(FinitelyPresentedGroup): ############################################################################## # Enum for the type of the group ############################################################################## + class type(Enum): r""" Enum class to select the type of the group: - - ``Coxeter`` -- 'C' the full cubic braid group. - - ``AssionS`` -- 'S' finite factor group of type S considered by Assion. - - ``AssionU`` -- 'U' finite factor group of type U considered by Assion. + - ``Coxeter`` -- ``'C'`` the full cubic braid group. + - ``AssionS`` -- ``'S'`` finite factor group of type S considered by Assion + - ``AssionU`` -- ``'U'`` finite factor group of type U considered by Assion EXAMPLES:: @@ -695,19 +685,6 @@ def __classcall_private__(cls, n=None, names='c', cbg_type=None): r""" Normalize input to ensure a unique representation. - INPUT: - - - ``n`` -- integer or ``None`` (default). The number of - strands. If not specified the ``names`` are counted and the - group is assumed to have one more strand than generators. - - - ``names`` -- string or list/tuple/iterable of strings (default: - ``'c'``). The generator names or name prefix. - - - ``cbg_type`` -- (optional keyword, default = CubicBraidGroup.type.Coxeter) - of enum type :class:`CubicBraidGroup.type` is passed to the corresponding - keyword argument of the constructor of :class:`CubicBraidGroup`. - EXAMPLES:: sage: C3 = CubicBraidGroup(3); C3.generators() @@ -739,16 +716,9 @@ def __classcall_private__(cls, n=None, names='c', cbg_type=None): return super().__classcall__(cls, names, cbg_type=cbg_type) def __init__(self, names, cbg_type=None): - """ + r""" Python constructor. - INPUT: - - - ``names`` -- see the corresponding documentation of :class:`BraidGroup_class`. - - - ``cbg_type`` -- (optional keyword, default = CubicBraidGroup.type.Coxeter) of enum type - :class:`CubicBraidGroup.type` to select the type of the group. - TESTS:: sage: C3 = CubicBraidGroup(3) # indirect doctest @@ -775,18 +745,18 @@ def __init__(self, names, cbg_type=None): if cbg_type is None: cbg_type = CubicBraidGroup.type.Coxeter if not isinstance(cbg_type, CubicBraidGroup.type): - raise TypeError("the cbg_type must be an instance of %s" %(CubicBraidGroup.type)) + raise TypeError("the cbg_type must be an instance of %s" % CubicBraidGroup.type) - free_group = FreeGroup(names) - self._cbg_type = cbg_type - self._nstrands = n+1 - self._ident = self._cbg_type.value + self._nstrands.str() + free_group = FreeGroup(names) + self._cbg_type = cbg_type + self._nstrands = n + 1 + self._ident = self._cbg_type.value + self._nstrands.str() self._braid_group = BraidGroup(names) # internal naming of elements for convenience - b = [free_group([i]) for i in range(1 , n+1)] - t = [free_group([i, i+1])**3 for i in range(1 , n)] - ti = [free_group([-i, -i-1])**3 for i in range(1 , n)] + b = [free_group([i]) for i in range(1, n+1)] + t = [free_group([i, i+1]) ** 3 for i in range(1, n)] + ti = [free_group([-i, -i-1]) ** 3 for i in range(1, n)] # first the braid relation rels = list(self._braid_group.relations()) @@ -798,7 +768,7 @@ def __init__(self, names, cbg_type=None): # than Assion's relation Satz 2.2 for cbg_type=CubicBraidGroup.type.AssionS # and Satz 2.4 for cbg_type=CubicBraidGroup.type.AssionU if n > 3: - for i in range(n-3): + for i in range(n - 3): if cbg_type == CubicBraidGroup.type.AssionU: rels.append((t[i]*t[i+2])**3) elif cbg_type == CubicBraidGroup.type.AssionS: @@ -916,16 +886,17 @@ def codegrees(self): # ------------------------------------------------------------------------------- # Methods for test_suite # ------------------------------------------------------------------------------- + def _internal_test_attached_group(self, attached_group, tester): r""" - It tests conversion maps from ``self`` to the given attached Group + Test conversion maps from ``self`` to the given attached Group, which must have been defined using the :meth:`as_classical_group`, :meth:`as_matrix_group`, :meth:`as_permutation_group` or :meth:`as_reflection_group`. INPUT: - - ``attached_group`` -- attached group to be tested as specified above. + - ``attached_group`` -- attached group to be tested as specified above EXAMPLES:: @@ -941,14 +912,15 @@ def _internal_test_attached_group(self, attached_group, tester): tester.assertEqual(att_grp_elem_back, elem) return - def _test_classical_group(self, **options): r""" - Method called by TestSuite. + Check the classical group properties. The following is checked: - - construction of classical group was faithful. - - coercion maps to and from classical group exist and are inverse to each other. + + - Construction of classical group was faithful. + - Coercion maps to and from classical group exist and are + inverse to each other. EXAMPLES:: @@ -961,14 +933,15 @@ def _test_classical_group(self, **options): self._internal_test_attached_group(classic_grp, tester) return - def _test_permutation_group(self, **options): r""" - Method called by TestSuite. + Check the permutation group properties. The following is checked: - - construction of permutation group was faithful. - - coercion maps to and from permutation group exist and are inverse to each other. + + - Construction of permutation group was faithful. + - Coercion maps to and from permutation group exist and are + inverse to each other. EXAMPLES:: @@ -981,15 +954,15 @@ def _test_permutation_group(self, **options): self._internal_test_attached_group(permgrp, tester) return - def _test_matrix_group(self, **options): r""" - Method called by TestSuite. + Check the matrix group properties. The following is checked: - - construction of matrix group was faithful in several cases. - - coercion maps to and from matrix group exist. + - Construction of matrix group was faithful. + - Coercion maps to and from matrix group exist and are + inverse to each other. EXAMPLES:: sage: CBG2 = CubicBraidGroup(2) @@ -1022,11 +995,13 @@ def _test_matrix_group(self, **options): def _test_reflection_group(self, **options): r""" - Method called by TestSuite. + Check the reflection group properties. The following is checked: - - construction of reflection group was faithful. - - coercion maps to and from reflection group exist and are inverse to each other. + + - Construction of reflection group was faithful. + - Coercion maps to and from reflection group exist and are + inverse to each other. EXAMPLES:: @@ -1081,6 +1056,7 @@ def _create_classical_realization(self, just_embedded=False): # ------------------------------------------------------------------------------- # Set up data of the classical Assion group (generic part) # ------------------------------------------------------------------------------- + def set_classical_realization(self, base_group, proj_group, centralizing_matrix, transvec_matrices): r""" Internal method to create classical group for Assion groups. @@ -1158,6 +1134,7 @@ def set_classical_realization(self, base_group, proj_group, centralizing_matrix, # ------------------------------------------------------------------------------- # Case for symplectic groups # ------------------------------------------------------------------------------- + def create_sympl_realization(self, m): r""" Internal method to create classical group for symplectic @@ -1170,7 +1147,6 @@ def create_sympl_realization(self, m): The function calculates the centralizing matrix and the transvections as given by Assion and then uses set_classical_realization to complete the construction. """ - # ----------------------------------------------------------- # getting the invariant bilinear form of the group # and setting constants. @@ -1229,6 +1205,7 @@ def transvec2mat(v, bas=bas, bform=bform, fact=1): # ------------------------------------------------------------------------------- # Case for unitary groups # ------------------------------------------------------------------------------- + def create_unitary_realization(self, m): """ Internal method to create classical group for @@ -1241,7 +1218,6 @@ def create_unitary_realization(self, m): The function calculates the centralizing_matrix and the transvections as given by Assion and then uses set_classical_realization to complete the construction. """ - # --------------------------------------------------------------------- # getting the invariant bilinear form of the group # and setting constants @@ -1299,7 +1275,6 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): t = [x + fact *(x * bform * v.conjugate()) * v for x in bas] return matrix(F, t) - # ------------------------------------------------------------------------------ # setting the centralizing matrix for the case of projective group realization. # ------------------------------------------------------------------------------ @@ -1324,7 +1299,7 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): # ------------------------------------------------------------------------------- # Setting the Classical group # ------------------------------------------------------------------------------- - if self._cbg_type == CubicBraidGroup.type.AssionS: + if self._cbg_type == CubicBraidGroup.type.AssionS: dim_sympl_group = n-1 # S(n-1) = Sp(n-1, 3) if n % 2 == 0: dim_sympl_group = n # S(n-1) = subgroup of PSp(n, 3) @@ -1362,28 +1337,30 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): def _element_constructor_(self, x, **kwds): r""" - Extensions to the _element constructor of :class:`FinitelyPresentedGroup`: + Return an element of ``self``. + + Extensions to the element constructor of :class:`FinitelyPresentedGroup`: new functionalities are: - constructing element from an element of the attached classical group - (embedded and not embedded) + (embedded and not embedded) - constructing element from an element of the attached permutation group - constructing element from an element of the attached reflection group INPUT: - ``x`` -- can be one of the following: - - an instance of the element class of ``self`` (but possible to a different parent). - - an instance of the element class of the braid group. - - a tuple representing a braid in Tietze form. - - an instance of an element class of a parent P such that there is a map from ``self`` to P - having :meth:`lift`, for example an element of an alternative realization of ``self``, such - as the classical realization. - - any other object which works for the element constructor of :class:`FinitelyPresentedGroup`. - - OUTPUT: - instance of the element class of ``self`` + * an instance of the element class of ``self`` (but possible + to a different parent) + * an instance of the element class of the braid group + * a tuple representing a braid in Tietze form + * an instance of an element class of a parent ``P`` such that there + is a map from ``self`` to ``P`` having :meth:`lift`; for example, + an element of an alternative realization of ``self``, such as + the classical realization + * any other object which works for the element constructor + of :class:`FinitelyPresentedGroup` EXAMPLES:: @@ -1414,7 +1391,7 @@ def strands(self): r""" Return the number of strands of the braid group whose image is ``self``. - OUTPUT: Integer. + OUTPUT: :class:`Integer` EXAMPLES:: @@ -1430,12 +1407,12 @@ def strands(self): # ---------------------------------------------------------------------------------- def braid_group(self): r""" - Return an Instance of :class:`BraidGroup` with identical generators, such that + Return a :class:`BraidGroup` with identical generators, such that there exists an epimorphism to ``self``. OUTPUT: - Instance of :class:`BraidGroup` having conversion maps to and from ``self`` + A :class:`BraidGroup` having conversion maps to and from ``self`` (which is just a section in the latter case). EXAMPLES:: @@ -1476,29 +1453,24 @@ def braid_group(self): @cached_method def as_matrix_group(self, root_bur=None, domain=None, characteristic=None, var='t', reduced=False): r""" - Creates an epimorphic image of ``self`` as a matrix group by use of the burau representation. + Creates an epimorphic image of ``self`` as a matrix group by use of + the burau representation. - INPUT (all arguments are optional by keyword): + INPUT: - - ``root_bur`` -- six (resp. twelfth) root of unity in some field - (default root of unity over `\QQ`). - - ``domain`` -- base_ring for the Burau matrix (default is Cyclotomic - Field of order 3 and degree 2, resp. the domain of `root_bur` if given). - - ``characteristic`` - integer giving the characteristic of the - domain (default is 0 or the characteristic of `domain` if given) - If none of the keywords `root_bur`, `domain` and `characteristic` is - given the default characteristic is 3 (resp. 2) if ``self`` is of ``cbg_type - CubicBraidGroup.type.AssionS`` (resp. ``CubicBraidGroup.type.AssionU``). - - ``var`` -- string used for the indeterminate name in case `root_bur` - must be constructed in a splitting field. + - ``root_bur`` -- (default: root of unity over `\QQ`) six (resp. twelfth) + root of unity in some field + - ``domain`` -- (default: cyclotomic field of order 3 and degree 2, resp. + the domain of ``root_bur`` if given) base ring for the Burau matrix + - ``characteristic`` -- integer (optional); the characteristic of the + domain; if none of the keywords ``root_bur``, ``domain`` and + ``characteristic`` are given, the default characteristic is 3 + (resp. 2) if ``self`` is of ``cbg_type`` + ``CubicBraidGroup.type.AssionS`` (resp. ``CubicBraidGroup.type.AssionU``) + - ``var`` -- string used for the indeterminate name in case ``root_bur`` + must be constructed in a splitting field - ``reduced`` -- boolean (default: ``False``); for more information - see the documentation of :meth:`burau_matrix` of :class:`Braid`. - - OUTPUT: - - An instance of the class :class:`FinitelyGeneratedMatrixGroup_gap` according to the - input arguments together with a group homomorphism registered as a conversion - from ``self`` to it. + see the documentation of :meth:`Braid.burau_matrix` EXAMPLES:: @@ -1606,20 +1578,15 @@ def as_matrix_group(self, root_bur=None, domain=None, characteristic=None, var=' @cached_method def as_permutation_group(self, use_classical=True): r""" - This method returns a permutation group isomorphic to ``self`` together - with group isomorphism from ``self`` as a conversion. - - INPUT (all arguments are optional by keyword): + Return a permutation group isomorphic to ``self`` that has a + group isomorphism from ``self`` as a conversion. - - ``use_classical`` -- (boolean, default True) by default the permutation - group is calculated via the attached classical matrix group, since this - results in a smaller degree. If set to False the permutation group will - be calculated using ``self`` (as finitely presented group). - - OUTPUT: + INPUT: - An instance of class :class:`PermutationGroup_generic` together with a group homomorphism - from ``self`` registered as a conversion. + - ``use_classical`` -- boolean (default: ``True``); the permutation + group is calculated via the attached classical matrix group as this + results in a smaller degree; if ``False``, the permutation group will + be calculated using ``self`` (as finitely presented group) EXAMPLES:: @@ -1658,34 +1625,37 @@ def as_permutation_group(self, use_classical=True): # ---------------------------------------------------------------------------------- def as_classical_group(self, embedded=False): r""" - Creates an isomorphic image of ``self`` as a classical group according + Create an isomorphic image of ``self`` as a classical group according to the construction given by Coxeter resp. Assion. - INPUT (optional keyword): + INPU: - - ``embedded`` -- boolean (default = False). This boolean does effect the - cases of Assion groups when they are realized as projective groups, only. + - ``embedded`` -- boolean (default: ``False``); this boolean effects the + cases of Assion groups when they are realized as projective groups only. More precisely: if ``self`` is of ``cbg_type CubicBraidGroup.type.AssionS`` - (for example) and the number of strands ``n`` is even, than its classical group - is a subgroup of ``PSp(n,3)`` (being centralized by the element - ``self.centralizing_element(projective=True))``. By default this group will be - given. Setting ``embedded = True`` the classical realization is given as - subgroup of its classical enlargement with one more strand (in this - case as subgroup of ``Sp(n,3))``. + (for example) and the number of strands ``n`` is even, than its classical + group is a subgroup of ``PSp(n,3)`` (being centralized by the element + ``self.centralizing_element(projective=True))``. By default this group + will be given. Setting ``embedded = True`` the classical realization + is given as subgroup of its classical enlargement with one more strand + (in this case as subgroup of ``Sp(n,3))``. OUTPUT: - Depending on the type of ``self`` and the number of strands an instance of ``Sp(n-1,3)``, - ``GU(n-1,2)``, subgroup of ``PSp(n,3), PGU(n,2)`` or a subgroup of ``GU(n-1, UCF)`` - (``cbg_type == CubicBraidGroup.type.Coxeter``) with respect to a certain hermitian form - attached to the Burau representation (used by Coxeter and Squier). Here ``UCF`` stands - for the universal cyclotomic field. + Depending on the type of ``self`` and the number of strands an + instance of ``Sp(n-1,3)``, ``GU(n-1,2)``, subgroup of ``PSp(n,3)``, + ``PGU(n,2)``, or a subgroup of ``GU(n-1, UCF)`` + (``cbg_type == CubicBraidGroup.type.Coxeter``) with respect to a + certain Hermitian form attached to the Burau representation + (used by Coxeter and Squier). Here ``UCF`` stands for the universal + cyclotomic field. EXAMPLES:: sage: U3 = AssionGroupU(3) sage: U3Cl = U3.as_classical_group(); U3Cl - Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] of (The projective general unitary group of degree 3 over Finite Field of size 2) + Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] + of (The projective general unitary group of degree 3 over Finite Field of size 2) sage: U3Clemb = U3.as_classical_group(embedded=True); U3Clemb Subgroup with 2 generators ( [0 0 a] [a + 1 a a] @@ -1745,8 +1715,8 @@ def as_classical_group(self, embedded=False): return self._classical_embedding elif self._classical_group is not None: return self._classical_group - else: - raise ValueError("no classical embedding defined") + + raise ValueError("no classical embedding defined") # ---------------------------------------------------------------------------------- @@ -1754,18 +1724,17 @@ def as_classical_group(self, embedded=False): # ---------------------------------------------------------------------------------- def as_reflection_group(self): r""" - Creates an isomorphic image of ``self`` as irreducible complex reflection group. - This is possible only for the finite cubic braid groups of ``cbg_type - CubicBraidGroup.type.Coxeter``. + Return an isomorphic image of ``self`` as irreducible complex + reflection group. - This method uses the sage implementation of reflection group via the gap3 CHEVIE - package. To use this method you must have gap3 together with CHEVIE installed! + This is possible only for the finite cubic braid groups of ``cbg_type`` + ``CubicBraidGroup.type.Coxeter``. - OUTPUT: - - An instance of the class :class:`IrreducibleComplexReflectionGroup` together with - a group isomorphism from ``self`` registered as a conversion. + .. NOTE:: + This method uses the sage implementation of reflection group via + the ``gap3`` ``CHEVIE`` package. These must be installed in order + to use this method. EXAMPLES:: @@ -1793,10 +1762,11 @@ def as_reflection_group(self): [ E(3)^2 -E(4)] [-E(12)^7 0] - The reflection groups can also be viewed as subgroups of unitary groups - over the universal cyclotomic field. Note that the unitary group corresponding - to the reflection group is isomorphic but different from the classical group due - to different hermitian forms for the unitary groups they live in:: + The reflection groups can also be viewed as subgroups of unitary groups + over the universal cyclotomic field. Note that the unitary group + corresponding to the reflection group is isomorphic but different from + the classical group due to different hermitian forms for the unitary + groups they live in:: sage: C4 = CubicBraidGroup(4) # optional - gap3 sage: R4 = C4.as_reflection_group() # optional - gap3 @@ -1807,7 +1777,6 @@ def as_reflection_group(self): sage: _ == C4.classical_invariant_form() # optional - gap3 False """ - # ------------------------------------------------------------------------------- # the reflection groups are called according to the Shephard-Todd classification: # 2 strands -> G(2,1,1) @@ -1819,7 +1788,7 @@ def as_reflection_group(self): if not is_chevie_available(): raise ImportError("the GAP3 package 'CHEVIE' is needed to obtain the corresponding reflection groups") - if self._cbg_type != CubicBraidGroup.type.Coxeter or self.strands() > 5 or self.strands() < 2: + if self._cbg_type != CubicBraidGroup.type.Coxeter or self.strands() > 5 or self.strands() < 2: raise ValueError("no reflection group defined") # ------------------------------------------------------------------------------- @@ -1852,15 +1821,17 @@ def classical_invariant_form(self): OUTPUT: - A square matrix of dimension according to the space the classical realization is - operating on. In the case of the full cubic braid groups and of the Assion groups - of ``cbg_type CubicBraidGroup.type.AssionU`` the matrix is hermitian. In the case of - the Assion groups of ``cbg_type CubicBraidGroup.type.AssionS`` it is alternating. - Note that the invariant form of the full cubic braid group on more than 5 strands - is degenerated (causing the group to be infinite). + A square matrix of dimension according to the space the classical + realization is operating on. In the case of the full cubic braid groups + and of the Assion groups of ``cbg_type CubicBraidGroup.type.AssionU`` + the matrix is Hermitian. In the case of the Assion groups of + ``cbg_type CubicBraidGroup.type.AssionS`` it is alternating. + Note that the invariant form of the full cubic braid group on more + than 5 strands is degenerated (causing the group to be infinite). - In the case of Assion groups having projective classical groups the invariant form - corresponds to the ambient group of its classical embedding. + In the case of Assion groups having projective classical groups, + the invariant form corresponds to the ambient group of its + classical embedding. EXAMPLES:: @@ -1914,30 +1885,32 @@ def centralizing_element(self, embedded=False): Return the centralizing element defined by the work of Assion (Hilfssatz 1.1.3 and 1.2.3). - INPUT (optional): + INPUT: - - ``embedded`` -- boolean (default = False). This boolean just effects + - ``embedded`` -- boolean (default; ``False``); this boolean only effects the cases of Assion groups when they are realized as projective groups. More precisely: if ``self`` is of ``cbg_type CubicBraidGroup.type.AssionS`` - (for example) and the number of strands ``n`` is even, than its classical - group is a subgroup of ``PSp(n,3)`` being centralized by the element return - for option ``embedded=False``. Otherwise the image of this element inside - the embedded classical group will be returned (see option embedded of - :meth:`classical_group`)! + (for example) and the number of strands ``n`` is even, than its + classical group is a subgroup of ``PSp(n,3)`` being centralized + by the element return for option ``embedded=False``. Otherwise the + image of this element inside the embedded classical group will be + returned (see option embedded of :meth:`classical_group`). OUTPUT: - Depending on the optional keyword a permutation as an element of ``PSp(n,3)`` - (type S) or ``PGU(n,2)`` (type U) for ``n = 0 mod 2`` (type S) reps. ``n = 0 mod 3`` - (type U) is returned. Else-wise, the centralizing element is a matrix - belonging to ``Sp(n,3)`` reps. ``GU(n,2)``. + Depending on the optional keyword a permutation as an element + of ``PSp(n,3)`` (type S) or ``PGU(n,2)`` (type U) for ``n = 0 mod 2`` + (type S) resp. ``n = 0 mod 3`` (type U) is returned. Otherwise, the + centralizing element is a matrix belonging to ``Sp(n,3)`` + resp. ``GU(n,2)``. EXAMPLES:: sage: U3 = AssionGroupU(3); U3 Assion group on 3 strands of type U sage: U3Cl = U3.as_classical_group(); U3Cl - Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] of (The projective general unitary group of degree 3 over Finite Field of size 2) + Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), (1,12,13)(2,15,19)(4,9,14)(5,18,8)(6,21,16)] + of (The projective general unitary group of degree 3 over Finite Field of size 2) sage: c = U3.centralizing_element(); c (1,16)(2,9)(3,10)(4,19)(6,12)(7,20)(13,21)(14,15) sage: c in U3Cl @@ -1946,7 +1919,7 @@ def centralizing_element(self, embedded=False): sage: P.centralizer(c) == U3Cl True - embedded Version:: + Embedded version:: sage: cm = U3.centralizing_element(embedded=True); cm [a + 1 a + 1 1] @@ -1959,7 +1932,6 @@ def centralizing_element(self, embedded=False): sage: [cm * U4Cl(g) == U4Cl(g) * cm for g in U4.gens()] [True, True, False] """ - # ------------------------------------------------------------------------------- # create the centralizing elements if not already done # ------------------------------------------------------------------------------- @@ -2010,7 +1982,7 @@ def order(self): def is_finite(self): r""" - Method from :class:`GroupMixinLibGAP` overwritten because of performance reason. + Return if ``self`` is a finite group or not. EXAMPLES:: @@ -2019,30 +1991,28 @@ def is_finite(self): sage: AssionGroupS(6).is_finite() True """ - from sage.rings.infinity import infinity - return not self.order() is infinity + return not (self._cbg_type == CubicBraidGroup.type.Coxeter and self.strands() > 5) # ---------------------------------------------------------------------------------- # creating a CubicBraidGroup as subgroup of self on less strands # ---------------------------------------------------------------------------------- - def cubic_braid_subgroup(self, nstrands = None): + def cubic_braid_subgroup(self, nstrands=None): r""" - Creates a cubic braid group as subgroup of ``self`` on the first ``nstrands`` strands. + Return a cubic braid group as subgroup of ``self`` on the first + ``nstrands`` strands. INPUT: - - ``nstrands`` -- integer > 0 and < ``self.strands()`` giving the number of strands - for the subgroup. The default is one strand less than ``self`` has. + - ``nstrands`` -- (default: ``self.strands() - 1``) integer at least 1 + and at most ``self.strands()`` giving the number of strands of + the subgroup - OUTPUT: + .. WARNING:: - An instance of this class realizing the subgroup. - - .. NOTE:: - - Since ``self`` is inherited from :class:`UniqueRepresentation` the obtained instance - is identical to other instances created with the same arguments (see example - below). The ambient group corresponds to the last call of this method. + Since ``self`` is inherited from :class:`UniqueRepresentation`, the + obtained instance is identical to other instances created with the + same arguments (see example below). The ambient group corresponds + to the last call of this method. EXAMPLES:: @@ -2068,8 +2038,10 @@ def cubic_braid_subgroup(self, nstrands = None): if nstrands >= n or nstrands <= 0: raise ValueError("nstrands must be positive and less than %s" %(self.strands())) - gens = self.gens() - gens_red = tuple([gens[i] for i in range(nstrands -1)]) - subgrp = CubicBraidGroup(names=gens_red, cbg_type=self._cbg_type) + + names = self.variable_names() + names_red = names[:nstrands-1] + subgrp = CubicBraidGroup(names=names_red, cbg_type=self._cbg_type) subgrp._ambient = self return subgrp + From 8d9deb21de420e04b3ac9d7713dad2d814389409 Mon Sep 17 00:00:00 2001 From: Sebastian Oehms Date: Fri, 19 Aug 2022 11:38:30 +0200 Subject: [PATCH 459/591] 29717: add missing T --- src/sage/groups/cubic_braid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index 35e82ccbf9e..e86434536dd 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -1628,7 +1628,7 @@ def as_classical_group(self, embedded=False): Create an isomorphic image of ``self`` as a classical group according to the construction given by Coxeter resp. Assion. - INPU: + INPUT: - ``embedded`` -- boolean (default: ``False``); this boolean effects the cases of Assion groups when they are realized as projective groups only. From 79c3bcb261834938f8c0fff1f404ae7aecbc4ee7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 19 Aug 2022 21:41:27 -0700 Subject: [PATCH 460/591] .devcontainer/downstream-docker-cocalc/devcontainer.json: Use onCreateCommand, updateContentCommand --- .devcontainer/downstream-docker-cocalc/devcontainer.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.devcontainer/downstream-docker-cocalc/devcontainer.json b/.devcontainer/downstream-docker-cocalc/devcontainer.json index a7ec23682a8..fc37d271530 100644 --- a/.devcontainer/downstream-docker-cocalc/devcontainer.json +++ b/.devcontainer/downstream-docker-cocalc/devcontainer.json @@ -5,16 +5,14 @@ "containerEnv": { "MAKE": "make -j4" }, - // Run commands after the container is created. // libgmp.a is broken and leads to a build failure of ecm. - "postCreateCommand": ".devcontainer/post_create.sh && rm -f /usr/local/sage/local/lib/libgmp.a", - // Run commands after the container is started. + "onCreateCommand": ".devcontainer/post_create.sh && rm -f /usr/local/sage/local/lib/libgmp.a", // * If the workspace directory looks like a copy of the Sage source tree (SAGE_ROOT): // - it bootstraps the Sage distribution, // - sets the symlink ``venv`` as expected, // * Otherwise, it does nothing. This is so that users can copy this devcontainer.json file as is // into their projects. - "postStartCommand": "if [ -d pkgs/sagemath-standard ]; then make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv; else echo 'Edit .devcontainer/devcontainer.json (postStartCommand) to run project-specific startup commands'; fi", + "updateContentCommand": "if [ -d pkgs/sagemath-standard ]; then make configure && ./configure --enable-build-as-root --prefix=/usr/local/sage/local --with-sage-venv; else echo 'Edit .devcontainer/devcontainer.json (updateContentCommand) to run project-specific startup commands'; fi", "extensions": [ "ms-python.python" ] From fbfab5e4d5bc6c0c90d30f527c159ecb638c8782 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 19 Aug 2022 23:22:51 -0700 Subject: [PATCH 461/591] .devcontainer/downstream-docker-computop/devcontainer.json: Use onCreateCommand, updateContentCommand --- .devcontainer/downstream-docker-computop/devcontainer.json | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.devcontainer/downstream-docker-computop/devcontainer.json b/.devcontainer/downstream-docker-computop/devcontainer.json index bcf7f2e3cfe..923a18fdf89 100644 --- a/.devcontainer/downstream-docker-computop/devcontainer.json +++ b/.devcontainer/downstream-docker-computop/devcontainer.json @@ -5,16 +5,13 @@ "containerEnv": { "MAKE": "make -j4" }, - // Run commands after the container is created. // Install build tools, get rid of sourcing /sage/activate in non-login shells. // libgmp.a is broken and leads to a build failure of ecm. - "postCreateCommand": ".devcontainer/post_create.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", - // Run commands after the container is started. + "onCreateCommand": ".devcontainer/post_create.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", // Do not run configure within a sage-env (see #29485). // The pari package is broken in the computop/sage 9.5 image, need to reinstall. // Also libnauty is broken. - - "postStartCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv)", + "updateContentCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv)", "extensions": [ "ms-python.python" ] From 09289e5418e448bc0421a8bf4208930cd7a4dad5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 00:21:14 -0700 Subject: [PATCH 462/591] .devcontainer/downstream-archlinux-latest/devcontainer.json: Use onCreateCommand, updateContentCommand --- .devcontainer/downstream-archlinux-latest/devcontainer.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.devcontainer/downstream-archlinux-latest/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json index 93966269922..c1682662873 100644 --- a/.devcontainer/downstream-archlinux-latest/devcontainer.json +++ b/.devcontainer/downstream-archlinux-latest/devcontainer.json @@ -2,12 +2,11 @@ { "name": "archlinux:latest downstream Sage", "image": "archlinux:latest", - // Run commands after the container is created. // Create an empty bashrc to avoid the error "No such file or directory" when opening a terminal. - "postCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh && touch ~/.bashrc", + "onCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh && touch ~/.bashrc", // Run commands after the container is started. // There's no SAGE_LOCAL, so remove the symlink 'prefix'. - "postStartCommand": "rm -f prefix && ln -sf /usr venv", + "updateContentCommand": "rm -f prefix && ln -sf /usr venv", "extensions": [ "ms-python.python" ] From 968ec531a406c0fe1b938c8e37a10097505ac8df Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 00:47:21 -0700 Subject: [PATCH 463/591] .devcontainer/downstream-conda-forge-latest/devcontainer.json: Use onCreateCommand, updateContentCommand --- .../downstream-conda-forge-latest/devcontainer.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.devcontainer/downstream-conda-forge-latest/devcontainer.json b/.devcontainer/downstream-conda-forge-latest/devcontainer.json index d6799692c0a..fe9f18eef8b 100644 --- a/.devcontainer/downstream-conda-forge-latest/devcontainer.json +++ b/.devcontainer/downstream-conda-forge-latest/devcontainer.json @@ -2,9 +2,8 @@ { "name": "condaforge/mambaforge:latest downstream Sage", "image": "condaforge/mambaforge:latest", - // Run commands after the container is created. - "postCreateCommand": "mamba install --yes sage", - // Run commands after the container is started. + // Install Sage from the conda-forge package. + "onCreateCommand": "mamba install --yes sage", // * If the workspace directory looks like a copy of the Sage source tree (SAGE_ROOT): // - it bootstraps and configures the Sage distribution, // - thus, the script ``./sage`` and the symlinks ``prefix``, ``venv`` are set as expected, @@ -13,7 +12,7 @@ // - however, it does not start the build. // * Otherwise, it does nothing. This is so that users can copy this devcontainer.json file as is // into their projects. - "postStartCommand": "if [ -d pkgs/sagemath-standard ]; then make configure && ln -sf $CONDA_PREFIX venv; else echo 'Edit .devcontainer/devcontainer.json (postStartCommand) to run project-specific startup commands'; fi", + "updateContentCommand": "if [ -d pkgs/sagemath-standard ]; then make configure && ln -sf $CONDA_PREFIX venv; else echo 'Edit .devcontainer/devcontainer.json (updateContentCommand) to run project-specific startup commands'; fi", "extensions": [ "ms-python.python" ] From 1ab9559726239ed4196d26fa0d836ce6fda0799f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 01:02:27 -0700 Subject: [PATCH 464/591] .devcontainer/*/devcontainer.json: Use onCreateCommand, updateContentCommand --- .devcontainer/develop-docker-computop/devcontainer.json | 6 ++---- .devcontainer/downstream-archlinux-latest/devcontainer.json | 1 - .../portability-ubuntu-jammy-standard/devcontainer.json | 6 ++---- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.devcontainer/develop-docker-computop/devcontainer.json b/.devcontainer/develop-docker-computop/devcontainer.json index 9754febbc22..71424e8843e 100644 --- a/.devcontainer/develop-docker-computop/devcontainer.json +++ b/.devcontainer/develop-docker-computop/devcontainer.json @@ -5,16 +5,14 @@ "containerEnv": { "MAKE": "make -j4" }, - // Run commands after the container is created. // Install build tools, get rid of sourcing /sage/activate in non-login shells. // libgmp.a is broken and leads to a build failure of ecm. - "postCreateCommand": ".devcontainer/post_create.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", - // Run commands after the container is started. + "onCreateCommand": ".devcontainer/post_create.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", // Do not run configure within a sage-env (see #29485). // The pari package is broken in the computop/sage 9.5 image, need to reinstall. // Also libnauty is broken. - "postStartCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv) && make pari-clean nauty-clean build V=0", + "updateContentCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv) && make pari-clean nauty-clean build V=0", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/downstream-archlinux-latest/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json index c1682662873..5fff1dc7cdc 100644 --- a/.devcontainer/downstream-archlinux-latest/devcontainer.json +++ b/.devcontainer/downstream-archlinux-latest/devcontainer.json @@ -4,7 +4,6 @@ "image": "archlinux:latest", // Create an empty bashrc to avoid the error "No such file or directory" when opening a terminal. "onCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh && touch ~/.bashrc", - // Run commands after the container is started. // There's no SAGE_LOCAL, so remove the symlink 'prefix'. "updateContentCommand": "rm -f prefix && ln -sf /usr venv", "extensions": [ diff --git a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json index 80fdc0de1b3..358cdf2055a 100644 --- a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +++ b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json @@ -13,10 +13,8 @@ "containerEnv": { "MAKE": "make -j4" }, - // Run commands after the container is created. - "postCreateCommand": ".devcontainer/post_create.sh", - // Run commands after the container is started. - "postStartCommand": ".devcontainer/portability-post_start.sh", + "onCreateCommand": ".devcontainer/post_create.sh", + "updateContentCommand": ".devcontainer/portability-post_start.sh", "extensions": [ "ms-python.python" ] From 3ba737b841647ee112b2f01b5c54e3024baa8c65 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sat, 20 Aug 2022 18:30:28 +0900 Subject: [PATCH 465/591] Minor edits --- .../develop-docker-computop/devcontainer.json | 1 - .../devcontainer.json | 37 ++++++++++--------- .vscode/settings.json | 8 ++-- src/doc/en/developer/portability_testing.rst | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.devcontainer/develop-docker-computop/devcontainer.json b/.devcontainer/develop-docker-computop/devcontainer.json index 71424e8843e..3dd68a6e0e8 100644 --- a/.devcontainer/develop-docker-computop/devcontainer.json +++ b/.devcontainer/develop-docker-computop/devcontainer.json @@ -11,7 +11,6 @@ // Do not run configure within a sage-env (see #29485). // The pari package is broken in the computop/sage 9.5 image, need to reinstall. // Also libnauty is broken. - "updateContentCommand": "make configure && (export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin && unset CFLAGS LDFLAGS CXXFLAGS CPATH LIBRARY_PATH && ./configure --prefix=/sage/local --with-sage-venv) && make pari-clean nauty-clean build V=0", "extensions": [ "ms-python.python" diff --git a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json index 358cdf2055a..0c4015a8add 100644 --- a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +++ b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json @@ -1,21 +1,22 @@ // See https://aka.ms/devcontainer.json for format details. { - "name": "Ubuntu jammy", - "build": { - "dockerfile": "portability-Dockerfile", - // See tox.ini for definitions - "args": { "SYSTEM_FACTOR": "ubuntu-jammy", - "PACKAGE_FACTOR": "standard", - "DOCKER_TARGET": "with-targets", - "DOCKER_TAG": "dev" - } - }, - "containerEnv": { - "MAKE": "make -j4" - }, - "onCreateCommand": ".devcontainer/post_create.sh", - "updateContentCommand": ".devcontainer/portability-post_start.sh", - "extensions": [ - "ms-python.python" - ] + "name": "Ubuntu jammy", + "build": { + "dockerfile": "portability-Dockerfile", + // See tox.ini for definitions + "args": { + "SYSTEM_FACTOR": "ubuntu-jammy", + "PACKAGE_FACTOR": "standard", + "DOCKER_TARGET": "with-targets", + "DOCKER_TAG": "dev" + } + }, + "containerEnv": { + "MAKE": "make -j4" + }, + "onCreateCommand": ".devcontainer/post_create.sh", + "updateContentCommand": ".devcontainer/portability-post_start.sh", + "extensions": [ + "ms-python.python" + ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index af2b4536957..234021fa1f2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,7 @@ "files.exclude": { "**/__pycache__": true, "src/**/*.cpp": true, - "src/**/*.so": true, + "src/**/*.so": true }, "search.exclude": { "build/pkgs/sagemath_categories/src": true, @@ -12,13 +12,13 @@ "pkgs/sage-conf_pypi/sage_root/build": true, "pkgs/sagemath-categories/sage": true, "pkgs/sagemath-objects/sage": true, - "pkgs/sagemath-standard/sage": true, + "pkgs/sagemath-standard/sage": true }, "python.testing.pytestEnabled": true, "python.testing.pytestArgs": [ "--rootdir=src/sage", "-c=src/tox.ini", - "--doctest-modules", + "--doctest-modules" ], "python.testing.unittestEnabled": false, "python.linting.pycodestyleEnabled": true, @@ -28,5 +28,5 @@ "Conda", "sagemath", "Cython" - ], + ] } diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 91ca5a460d4..57ad0d57dcc 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1227,7 +1227,7 @@ in a terminal, `open a new terminal in VS Code (possibly) ``$SAGE_ROOT/logs`` will be symbolic links that work inside the dev container, but not in your local file system; and also the script ``$SAGE_ROOT/sage`` will not work. Hence after working with the dev container, - you will want to remove ``logs`` if it is a symbolic link, and to re-run the + you will want to remove ``logs`` if it is a symbolic link, and rerun the ``configure`` script. You can edit a copy of the configuration file to change to a different platform, another From 30f345364611205d3c8c6b9347a6f569e553d8ea Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 21 Aug 2022 01:15:09 +0900 Subject: [PATCH 466/591] Small edits --- src/doc/en/developer/portability_testing.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 57ad0d57dcc..f44a1d7cb7c 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1190,7 +1190,7 @@ application, then in the command palette of VS Code, enter "Remote-Containers: Open Folder in Container", and hit :kbd:`Enter`, and choose the directory ``$SAGE_ROOT`` of your local Sage repository. -Once VS Code starts running the dev container, by clicking on "show log", +Once VS Code starts configuring the dev container, by clicking on "show log", you can see what it does: - It pulls the prebuilt image from ghcr.io (via @@ -1216,9 +1216,10 @@ in a terminal, `open a new terminal in VS Code .. NOTE:: - If you want VS Code to use a previously configured dev container, first run - the dev container in Docker and enter "Remote-Containers: Attach to Running - Container" in the command palette of VS Code and choose the dev container. + If you want VS Code to use a previously configured dev container, first + start the dev container in Docker and enter "Remote-Containers: Attach to + Running Container" in the command palette of VS Code and choose the dev + container. .. NOTE:: From b0b8cfb988118d993acd5ef1e2bdac5bb7bf4dbe Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 21 Aug 2022 04:54:19 +0800 Subject: [PATCH 467/591] =?UTF-8?q?clarify=20that=20curves=20without=20a?= =?UTF-8?q?=20short=20Weierstra=C3=9F=20model=20only=20exist=20in=20charac?= =?UTF-8?q?teristics=202=20and=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 2b8b3c5699c..43ec48cfb92 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -82,7 +82,9 @@ From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 101 To: Elliptic Curve defined by y^2 = x^3 + 66*x + 86 over Finite Field of size 101 -However, this does imply not all elliptic curves are supported:: +However, this does imply not all elliptic curves are supported. +Curves without a short Weierstraß model exist in characteristics +`2` and `3`:: sage: F. = GF(3^3) sage: E = EllipticCurve(F, [1,1,1,1,1]) From f1f38b144836995613caae929a7eaebd2f83ea4d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 14:57:39 -0700 Subject: [PATCH 468/591] .devcontainer/portability-ubuntu-jammy-standard: Add symlink to portability-Dockerfile --- .../portability-ubuntu-jammy-standard/portability-Dockerfile | 1 + 1 file changed, 1 insertion(+) create mode 120000 .devcontainer/portability-ubuntu-jammy-standard/portability-Dockerfile diff --git a/.devcontainer/portability-ubuntu-jammy-standard/portability-Dockerfile b/.devcontainer/portability-ubuntu-jammy-standard/portability-Dockerfile new file mode 120000 index 00000000000..692e2a79d64 --- /dev/null +++ b/.devcontainer/portability-ubuntu-jammy-standard/portability-Dockerfile @@ -0,0 +1 @@ +../portability-Dockerfile \ No newline at end of file From 37eb95dcb3e68c19092c38cb49c9a75c5da35154 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 21 Aug 2022 07:18:27 +0900 Subject: [PATCH 469/591] Remove the note for starting configured dev container --- src/doc/en/developer/portability_testing.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index f44a1d7cb7c..41fb93e5a6d 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1214,13 +1214,6 @@ in a terminal, `open a new terminal in VS Code `_, type ``./sage`` and hit :kbd:`Enter`. -.. NOTE:: - - If you want VS Code to use a previously configured dev container, first - start the dev container in Docker and enter "Remote-Containers: Attach to - Running Container" in the command palette of VS Code and choose the dev - container. - .. NOTE:: Your Sage at ``$SAGE_ROOT`` was configured and rebuilt inside the dev From 7d390827eea3580f9fa998d7f59127ad0dd0a964 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 15:19:45 -0700 Subject: [PATCH 470/591] build/pkgs/sagetex/dependencies: Remove ninja; it is not a dependency of sagetex 3.6 --- build/pkgs/sagetex/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sagetex/dependencies b/build/pkgs/sagetex/dependencies index 2a21dc572ef..1a27955b054 100644 --- a/build/pkgs/sagetex/dependencies +++ b/build/pkgs/sagetex/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) maxima scipy matplotlib pillow tachyon pyparsing ninja | $(and $(filter-out no,$(SAGE_CHECK_sagetex)), $(SAGERUNTIME) sympy elliptic_curves jmol) +$(PYTHON) maxima scipy matplotlib pillow tachyon pyparsing | $(and $(filter-out no,$(SAGE_CHECK_sagetex)), $(SAGERUNTIME) sympy elliptic_curves jmol) To build SageTeX, you just need Python and pyparsing, but to test (SAGE_CHECK=yes) SageTeX, you actually need to run Sage, produce plots,... From 6e5af728ac0f786bf426dd75b06593b1919e7403 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 15:44:56 -0700 Subject: [PATCH 471/591] build/pkgs/sagetex/dependencies: Remove duplication from dependencies_check --- build/pkgs/sagetex/dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/sagetex/dependencies b/build/pkgs/sagetex/dependencies index 1a27955b054..6090d5dc3ac 100644 --- a/build/pkgs/sagetex/dependencies +++ b/build/pkgs/sagetex/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) maxima scipy matplotlib pillow tachyon pyparsing | $(and $(filter-out no,$(SAGE_CHECK_sagetex)), $(SAGERUNTIME) sympy elliptic_curves jmol) +$(PYTHON) maxima scipy matplotlib pillow tachyon pyparsing To build SageTeX, you just need Python and pyparsing, but to test (SAGE_CHECK=yes) SageTeX, you actually need to run Sage, produce plots,... From add10cdb567858d1971ababe2114be573d76c00c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 16:12:33 -0700 Subject: [PATCH 472/591] build/pkgs/sagetex: Use 3.6.1 release on PyPI --- build/pkgs/sagetex/checksums.ini | 8 ++++---- build/pkgs/sagetex/package-version.txt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/pkgs/sagetex/checksums.ini b/build/pkgs/sagetex/checksums.ini index 8d53b030a72..ec20a91fb3d 100644 --- a/build/pkgs/sagetex/checksums.ini +++ b/build/pkgs/sagetex/checksums.ini @@ -1,5 +1,5 @@ tarball=sagetex-VERSION.tar.gz -sha1=3f2a907d14bfff5243c9803c57bf9d46685291a0 -md5=a013fdbeaa4b9ba33a687a51ee390094 -cksum=3706582539 -upstream_url=https://github.com/sagemath/sagetex/releases/download/vVERSION/sagetex-VERSION.tar.gz +sha1=821c8a6ab11ee651d0dcc599c5582fefb6706775 +md5=a7ddbe41ea3d816e839ddda3ec28f89a +cksum=1768053059 +upstream_url=https://pypi.io/packages/source/s/sagetex/sagetex-VERSION.tar.gz diff --git a/build/pkgs/sagetex/package-version.txt b/build/pkgs/sagetex/package-version.txt index d70c8f8d89f..9575d51bad2 100644 --- a/build/pkgs/sagetex/package-version.txt +++ b/build/pkgs/sagetex/package-version.txt @@ -1 +1 @@ -3.6 +3.6.1 From bf55daf1f55c46c602ed06589da29c074b1b45e6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 16:54:21 -0700 Subject: [PATCH 473/591] EnumeratedSets.ParentMethods.tuple: New, replace many uses of list --- src/sage/categories/enumerated_sets.py | 81 ++++++++++++------- src/sage/categories/finite_enumerated_sets.py | 66 ++++++--------- src/sage/combinat/crystals/fast_crystals.py | 32 +++----- 3 files changed, 86 insertions(+), 93 deletions(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 563a8025e6d..7d3f6008984 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -46,10 +46,14 @@ class EnumeratedSets(CategoryWithAxiom): - ``iter(S)``: an iterator for the elements of the set; - - ``S.list()``: the list of the elements of the set, when + - ``S.list()``: a fresh list of the elements of the set, when possible; raises a NotImplementedError if the list is predictably too large to be expanded in memory. + - ``S.tuple()``: a tuple of the elements of the set, when + possible; raises a NotImplementedError if the tuple is + predictably too large to be expanded in memory. + - ``S.unrank(n)``: the ``n-th`` element of the set when ``n`` is a sage ``Integer``. This is the equivalent for ``l[n]`` on a list. @@ -312,8 +316,7 @@ def iterator_range(self, start=None, stop=None, step=None): return start = 0 elif start < 0: - for x in self.list()[start::step]: - yield x + yield from self.tuple()[start::step] return if step is None: step = 1 @@ -325,8 +328,7 @@ def iterator_range(self, start=None, stop=None, step=None): start += step elif stop < 0: - for x in self.list()[start:stop:step]: - yield x + yield from self.tuple()[start:stop:step] return if start is None: @@ -337,9 +339,7 @@ def iterator_range(self, start=None, stop=None, step=None): return start = 0 elif start < 0: - for x in self.list()[start:stop:step]: - yield x - return + yield from self.tuple()[start:stop:step] if step is None: step = 1 for j in range(start, stop, step): @@ -381,13 +381,13 @@ def unrank_range(self, start=None, stop=None, step=None): NotImplementedError: cannot list an infinite set """ if stop is None: - return self.list()[start::step] + return list(self.tuple()[start::step]) if stop < 0: - return self.list()[start:stop:step] + return list(self.tuple()[start:stop:step]) if start is not None and start < 0: - return self.list()[start:stop:step] + return list(self.tuple()[start:stop:step]) return list(self.iterator_range(start, stop, step)) @@ -479,13 +479,46 @@ def __len__(self): raise NotImplementedError('infinite set') return int(c) except AttributeError: - return len(self.list()) + return len(self.tuple()) + + def tuple(self): + r""" + Return a tuple of the elements of ``self``. + """ + try: # shortcut + if self._list is not None: + return self._tuple_from_list() + except AttributeError: + pass + + if self.list != self._list_default: + return tuple(self.list()) + + from sage.rings.infinity import Infinity + try: + if self.cardinality() is Infinity: + raise NotImplementedError('cannot list an infinite set') + else: # finite cardinality + return self._tuple_from_iterator() + except AttributeError: + raise NotImplementedError('unknown cardinality') + _tuple_default = tuple + + def _tuple_from_iterator(self): + # This creates one throw-away list. + return tuple(self._list_from_iterator()) + + def _tuple_from_list(self): + # Implementation classes may put any Sequence type in self._list. + # Traditionally, self._list was an actual list. + # When self._list is already a tuple, calling tuple on it is a no-op. + return tuple(self._list) def list(self): r""" Return a list of the elements of ``self``. - The elements of set ``x`` are created and cached on the fist call + The elements of set ``x`` are created and cached on the first call of ``x.list()``. Then each call of ``x.list()`` returns a new list from the cached result. Thus in looping, it may be better to do ``for e in x:``, not ``for e in x.list():``. @@ -506,21 +539,11 @@ def list(self): sage: R.list() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sage: C = FiniteEnumeratedSets().example() + sage: C.list() + [1, 2, 3] """ - try: # shortcut - if self._list is not None: - return list(self._list) - except AttributeError: - pass - - from sage.rings.infinity import Infinity - try: - if self.cardinality() is Infinity: - raise NotImplementedError('cannot list an infinite set') - else: # finite cardinality - return self._list_from_iterator() - except AttributeError: - raise NotImplementedError('unknown cardinality') + return list(self.tuple()) _list_default = list # needed by the check system. def _list_from_iterator(self): @@ -579,7 +602,7 @@ def _list_from_iterator(self): return list(self._list) except AttributeError: pass - result = list(self.__iter__()) + result = tuple(self.__iter__()) try: self._list = result except AttributeError: @@ -711,7 +734,7 @@ def _iterator_from_list(self): sage: [next(it), next(it), next(it)] [1, 2, 3] """ - for x in self.list(): + for x in self.tuple(): yield x def _iterator_from_next(self): diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index e35a55c65b4..8cdbf6e9ef3 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -187,13 +187,7 @@ def _cardinality_from_list(self, *ignored_args, **ignored_kwds): sage: C._cardinality_from_list(algorithm='testing') 3 """ - # We access directly the cache self._list to bypass the - # copy that self.list() currently does each time. - try: - lst = self._list - except AttributeError: - lst = self.list() - return Integer(len(lst)) + return Integer(len(self.tuple())) def _unrank_from_list(self, r): """ @@ -217,42 +211,28 @@ def _unrank_from_list(self, r): sage: C._unrank_from_list(1) 2 """ - # We access directly the cache self._list to bypass the - # copy that self.list() currently does each time. - try: - lst = self._list - except AttributeError: - lst = self.list() + lst = self.tuple() try: return lst[r] except IndexError: - raise ValueError("the value must be between %s and %s inclusive"%(0,len(lst)-1)) + raise ValueError("the value must be in the range from %s to %s" % (0, len(lst) - 1)) - def list(self): + def tuple(self): r""" - Return a list of the elements of ``self``. - - The elements of set ``x`` is created and cashed on the fist call - of ``x.list()``. Then each call of ``x.list()`` returns a new list - from the cashed result. Thus in looping, it may be better to do - ``for e in x:``, not ``for e in x.list():``. - - .. SEEALSO:: :meth:`_list_from_iterator`, :meth:`_cardinality_from_list`, - :meth:`_iterator_from_list`, and :meth:`_unrank_from_list` - - EXAMPLES:: - - sage: C = FiniteEnumeratedSets().example() - sage: C.list() - [1, 2, 3] + Return a :class:`tuple`of the elements of ``self``. """ + # Simpler implementation because it does not have to check whether cardinality is finite try: # shortcut if self._list is not None: - return list(self._list) + return self._tuple_from_list() except AttributeError: pass - return self._list_from_iterator() - _list_default = list # needed by the check system. + + if self.list != self._list_default: + return tuple(self.list()) + + return self._tuple_from_iterator() + _tuple_default = tuple def _list_from_iterator(self): r""" @@ -323,7 +303,7 @@ def _list_from_iterator(self): sage: class FreshExample(Example): pass sage: C = FreshExample(); C.rename("FreshExample") sage: C.list - + sage: C.unrank sage: C.cardinality @@ -331,7 +311,7 @@ def _list_from_iterator(self): sage: l1 = C.list(); l1 [1, 2, 3] sage: C.list - + sage: C.unrank sage: C.cardinality @@ -355,11 +335,12 @@ def _list_from_iterator(self): return list(self._list) except AttributeError: pass - result = list(self.__iter__()) + result = tuple(self.__iter__()) try: self._list = result self.__iter__ = self._iterator_from_list self.cardinality = self._cardinality_from_list + self.tuple = self._tuple_from_list self.unrank = self._unrank_from_list except AttributeError: pass @@ -391,12 +372,12 @@ def unrank_range(self, start=None, stop=None, step=None): [1, 2, 3, 4] """ try: - return self._list[start:stop:step] + return list(self._list[start:stop:step]) except AttributeError: pass card = self.cardinality() # This may set the list try: - return self._list[start:stop:step] + return list(self._list[start:stop:step]) except AttributeError: pass if start is None and stop is not None and stop >= 0 and step is None: @@ -404,7 +385,7 @@ def unrank_range(self, start=None, stop=None, step=None): it = self.__iter__() return [next(it) for j in range(stop)] return self.list() - return self.list()[start:stop:step] + return list(self.tuple()[start:stop:step]) def iterator_range(self, start=None, stop=None, step=None): r""" @@ -461,9 +442,8 @@ def iterator_range(self, start=None, stop=None, step=None): yield x return if L is None: - L = self.list() - for x in L[start:stop:step]: - yield x + L = self.tuple() + yield from L[start:stop:step] def _random_element_from_unrank(self): """ @@ -492,7 +472,7 @@ def _random_element_from_unrank(self): c = self.cardinality() r = randint(0, c-1) return self.unrank(r) - #Set the default implementation of random + # Set the default implementation of random_element random_element = _random_element_from_unrank @cached_method diff --git a/src/sage/combinat/crystals/fast_crystals.py b/src/sage/combinat/crystals/fast_crystals.py index 2f964bb60de..77d3885933a 100644 --- a/src/sage/combinat/crystals/fast_crystals.py +++ b/src/sage/combinat/crystals/fast_crystals.py @@ -87,6 +87,17 @@ class FastCrystal(UniqueRepresentation, Parent): sage: C.cardinality() 35 sage: TestSuite(C).run() + + sage: C = crystals.FastRankTwo(['A',2],shape=[2,1]) + sage: C.list() + [[0, 0, 0], + [1, 0, 0], + [0, 1, 1], + [0, 2, 1], + [1, 2, 1], + [0, 1, 0], + [1, 1, 0], + [2, 1, 0]] """ @staticmethod def __classcall__(cls, cartan_type, shape, format = "string"): @@ -166,8 +177,6 @@ def __init__(self, ct, shape, format): l2_str = "%d/2"%int(2*l2) self.rename("The fast crystal for %s2 with shape [%s,%s]"%(ct[0],l1_str,l2_str)) self.module_generators = [self(0)] -# self._list = ClassicalCrystal.list(self) - self._list = super(FastCrystal, self).list() # self._digraph = ClassicalCrystal.digraph(self) self._digraph = super(FastCrystal, self).digraph() self._digraph_closure = self.digraph().transitive_closure() @@ -249,25 +258,6 @@ def __call__(self, value): return value return self.element_class(self, value, self.format) - def list(self): - """ - Return a list of the elements of self. - - EXAMPLES:: - - sage: C = crystals.FastRankTwo(['A',2],shape=[2,1]) - sage: C.list() - [[0, 0, 0], - [1, 0, 0], - [0, 1, 1], - [0, 2, 1], - [1, 2, 1], - [0, 1, 0], - [1, 1, 0], - [2, 1, 0]] - """ - return self._list - def digraph(self): """ Return the digraph associated to self. From d573cbfec0408722bf95b07971165fcfd2672d39 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 17:27:29 -0700 Subject: [PATCH 474/591] InfiniteEnumeratedSets.ParentMethods.tuple: New --- .../categories/infinite_enumerated_sets.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/infinite_enumerated_sets.py b/src/sage/categories/infinite_enumerated_sets.py index cc3a09e9409..581faab5ff4 100644 --- a/src/sage/categories/infinite_enumerated_sets.py +++ b/src/sage/categories/infinite_enumerated_sets.py @@ -47,7 +47,7 @@ class ParentMethods: def random_element(self): """ - Returns an error since self is an infinite enumerated set. + Raise an error because ``self`` is an infinite enumerated set. EXAMPLES:: @@ -61,9 +61,23 @@ def random_element(self): """ raise NotImplementedError("infinite set") + def tuple(self): + """ + Raise an error because ``self`` is an infinite enumerated set. + + EXAMPLES:: + + sage: NN = InfiniteEnumeratedSets().example() + sage: NN.tuple() + Traceback (most recent call last): + ... + NotImplementedError: cannot list an infinite set + """ + raise NotImplementedError("cannot list an infinite set") + def list(self): """ - Returns an error since self is an infinite enumerated set. + Raise an error because ``self`` is an infinite enumerated set. EXAMPLES:: From 192a5a2067aa1f4754569fdf2488e73f933a6080 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 17:41:04 -0700 Subject: [PATCH 475/591] src/sage/categories/enumerated_sets.py: Add doc --- src/sage/categories/enumerated_sets.py | 30 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 7d3f6008984..1ecaf092098 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -47,14 +47,14 @@ class EnumeratedSets(CategoryWithAxiom): - ``iter(S)``: an iterator for the elements of the set; - ``S.list()``: a fresh list of the elements of the set, when - possible; raises a NotImplementedError if the list is + possible; raises a :class:`NotImplementedError` if the list is predictably too large to be expanded in memory. - ``S.tuple()``: a tuple of the elements of the set, when - possible; raises a NotImplementedError if the tuple is + possible; raises a :class:`NotImplementedError` if the tuple is predictably too large to be expanded in memory. - - ``S.unrank(n)``: the ``n-th`` element of the set when ``n`` is a sage + - ``S.unrank(n)``: the ``n``-th element of the set when ``n`` is a sage ``Integer``. This is the equivalent for ``l[n]`` on a list. - ``S.rank(e)``: the position of the element ``e`` in the set; @@ -65,8 +65,8 @@ class EnumeratedSets(CategoryWithAxiom): - ``S.first()``: the first object of the set; it is equivalent to ``S.unrank(0)``. - - ``S.next(e)``: the object of the set which follows ``e``; It is - equivalent to ``S.unrank(S.rank(e)+1)``. + - ``S.next(e)``: the object of the set which follows ``e``; it is + equivalent to ``S.unrank(S.rank(e) + 1)``. - ``S.random_element()``: a random generator for an element of the set. Unless otherwise stated, and for finite enumerated @@ -484,6 +484,23 @@ def __len__(self): def tuple(self): r""" Return a tuple of the elements of ``self``. + + The tuple of elements of ``x`` is created and cached on the first call + of ``x.tuple()``. Each following call of ``x.tuple()`` returns the same tuple. + + For looping, it may be better to do ``for e in x:``, not ``for e in x.tuple():``. + + If ``x`` is not known to be finite, then an exception is raised. + + EXAMPLES:: + + sage: (GF(3)^2).tuple() + ((0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)) + sage: R = Integers(11) + sage: l = R.tuple(); l + (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + sage: l is R.tuple() + True """ try: # shortcut if self._list is not None: @@ -509,6 +526,9 @@ def _tuple_from_iterator(self): return tuple(self._list_from_iterator()) def _tuple_from_list(self): + r""" + Return a tuple of the elements of ``self``. + """ # Implementation classes may put any Sequence type in self._list. # Traditionally, self._list was an actual list. # When self._list is already a tuple, calling tuple on it is a no-op. From d62fe4c128c380d34ce0d41c8c6855f3e5250c78 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 Aug 2022 17:51:48 -0700 Subject: [PATCH 476/591] src/sage/categories/enumerated_sets.py: Fix _tuple_from_iterator --- src/sage/categories/enumerated_sets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 1ecaf092098..b9676d67511 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -523,7 +523,8 @@ def tuple(self): def _tuple_from_iterator(self): # This creates one throw-away list. - return tuple(self._list_from_iterator()) + self._list_from_iterator() + return self._tuple_from_list() def _tuple_from_list(self): r""" From 9f9a77c3be5be220729d47f655627ec30aff2818 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 21 Aug 2022 05:01:39 +0800 Subject: [PATCH 477/591] =?UTF-8?q?improve=20documentation=20for=20?= =?UTF-8?q?=E2=88=9A=C3=A9lu=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schemes/elliptic_curves/hom_velusqrt.py | 101 +++++++++++++++--- 1 file changed, 87 insertions(+), 14 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 43ec48cfb92..fdb78ce9a33 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -1,7 +1,7 @@ r""" -√élu Formulas for Elliptic-Curve Isogenies +√élu Algorithm for Elliptic-Curve Isogenies -The √élu formulas compute isogenies of elliptic curves in time +The √élu algorithm computes isogenies of elliptic curves in time `\tilde O(\sqrt\ell)` rather than naïvely `O(\ell)`, where `\ell` is the degree. @@ -97,7 +97,8 @@ NotImplementedError: only implemented for curves having a short Weierstrass model Furthermore, the implementation is restricted to finite fields, -since this is the most relevant application:: +since this appears to be the most relevant application for the +√élu algorithm:: sage: E = EllipticCurve('26b1') sage: P = E(1,0) @@ -194,6 +195,10 @@ def __init__(self, leaves): Initialize a product tree having the given ring elements as its leaves. + INPUT: + + - ``leaves`` -- a sequence of elements in a common ring + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import ProductTree @@ -249,6 +254,13 @@ def remainders(self, x): Given a value `x`, return a list of all remainders of `x` modulo the leaves of this product tree. + The base ring must support the ``%`` operator for this + method to work. + + INPUT: + + - `x` -- an element of the base ring of this product tree + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import ProductTree @@ -272,6 +284,15 @@ def prod_with_derivative(pairs): the pair `(\prod f, \partial \prod f)`, assuming `\partial` is an operator obeying the standard product rule. + This function is entirely algebraic, hence still works when the + elements `f` and `\partial f` are all passed through some ring + homomorphism first. (See the polynomial-evaluation example below.) + + INPUT: + + - ``pairs`` -- a sequence of tuples `(f, \partial f)` of elements + of a common ring + ALGORITHM: This function wraps the given pairs in a thin helper class that @@ -294,8 +315,8 @@ def prod_with_derivative(pairs): 240*x^9 + 702*x^8 + 1056*x^7 + 630*x^6 + 128*x^3 + 420*x^2 + 586*x + 318 The main reason for this function to exist is that it allows us to - compute the *value* of the derivative at a point `\alpha` without - ever fully expanding the product *as a polynomial*:: + *evaluate* the derivative of a product of polynomials at a point + `\alpha` without ever fully expanding the product *as a polynomial*:: sage: alpha = 42 sage: F(alpha) @@ -323,6 +344,10 @@ def _choose_IJK(n): Helper function to choose an "index system" for the set `\{1,3,5,7,...,n-2\}` where `n \geq 5` is an odd integer. + INPUT: + + - `n` -- odd integer `\geq 5` + REFERENCES: [BDLS2020]_, Examples 4.7 and 4.12 EXAMPLES:: @@ -355,6 +380,12 @@ def _points_range(rr, P, Q=None): Return an iterator yielding all points `Q + [i]P` where `i` runs through the :class:`range` object ``rr``. + INPUT: + + - ``rr`` -- :class:`range` object defining a sequence `S \subseteq \ZZ` + - `P` -- element of an additive abelian group + - `Q` -- element of the same group, or ``None`` + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import _points_range @@ -421,7 +452,7 @@ class FastEllipticPolynomial: sage: E = EllipticCurve(GF(71), [5,5]) sage: P = E(4, 35) sage: hP = FastEllipticPolynomial(E, P.order(), P); hP - Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1) + Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1) sage: hP(7) 19 sage: prod(7 - (i*P).xy()[0] for i in range(1,P.order(),2)) @@ -476,13 +507,20 @@ def __init__(self, E, n, P, Q=None): Initialize this elliptic polynomial and precompute some input-independent data required for evaluation. + INPUT: + + - `E` -- an elliptic curve in short Weierstraß form + - `n` -- an odd integer `\geq 5` + - `P` -- a point on `E` + - `Q` -- a point on `E`, or ``None`` + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial sage: E = EllipticCurve(GF(71), [5,5]) sage: P = E(0, 17) sage: FastEllipticPolynomial(E, P.order(), P) - Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with n = 57, P = (0 : 17 : 1) + Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with n = 57, P = (0 : 17 : 1) """ if any(E.a_invariants()[:-2]): raise NotImplementedError('only implemented for short Weierstrass curves') @@ -519,9 +557,9 @@ def __init__(self, E, n, P, Q=None): self.dhK = self.hK.derivative() if Q is None: - self._repr = f"Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with {n = }, {P = }" + self._repr = f"Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with {n = }, {P = }" else: - self._repr = f"Fast elliptic polynomial prod(Z - x(Q+i*P)) for i in range(n)) with {n = }, {P = }, {Q = }" + self._repr = f"Fast elliptic polynomial prod(Z - x(Q+i*P) for i in range(n)) with {n = }, {P = }, {Q = }" def __call__(self, alpha, *, derivative=False): r""" @@ -529,13 +567,18 @@ def __call__(self, alpha, *, derivative=False): and if ``derivative`` is set to ``True`` also return the evaluation of the derivative at `\alpha`. + INPUT: + + - ``alpha`` -- an element of any algebra over the base ring + - ``derivative`` -- boolean (default: ``False``) + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial sage: E = EllipticCurve(GF(71), [5,5]) sage: P = E(4, 35) sage: hP = FastEllipticPolynomial(E, P.order(), P); hP - Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1) + Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1) sage: hP(7) 19 sage: hP(7, derivative=True) @@ -578,6 +621,12 @@ def _hI_resultant(self, poly, rems=None): Internal helper function to evaluate a resultant with `h_I` quickly, using the product tree constructed in :meth:`__init__`. + INPUT: + + - ``poly`` -- an element of the base ring of this product tree, + which must be a polynomial ring supporting ``%`` + - ``rems`` -- result of ``self.hItree.remainders(poly)``, or ``None`` + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial @@ -613,14 +662,16 @@ def __repr__(self): r""" Return a string representation of this elliptic polynomial. + EXAMPLES:: + sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial sage: E = EllipticCurve(GF(71), [5,5]) sage: P = E(4, 35) sage: FastEllipticPolynomial(E, P.order(), P) - Fast elliptic polynomial prod(Z - x(i*P)) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1) + Fast elliptic polynomial prod(Z - x(i*P) for i in range(1,n,2)) with n = 19, P = (4 : 35 : 1) sage: Q = E(0, 17) sage: FastEllipticPolynomial(E, P.order(), P, Q) - Fast elliptic polynomial prod(Z - x(Q+i*P)) for i in range(n)) with n = 19, P = (4 : 35 : 1), Q = (0 : 17 : 1) + Fast elliptic polynomial prod(Z - x(Q+i*P) for i in range(n)) with n = 19, P = (4 : 35 : 1), Q = (0 : 17 : 1) """ return self._repr @@ -631,6 +682,10 @@ def _point_outside_subgroup(P): curve `E` that is not a multiple of a given point `P`. The base field is extended if (and only if) necessary. + INPUT: + + - `P` -- a point on an elliptic curve over a finite field + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import _point_outside_subgroup @@ -698,7 +753,7 @@ def _point_outside_subgroup(P): class EllipticCurveHom_velusqrt(EllipticCurveHom): r""" This class implements separable odd-degree isogenies of elliptic - curves over finite fields using the √élu formulas. + curves over finite fields using the √élu algorithm. The complexity is `\tilde O(\sqrt{\ell})` base-field operations, where `\ell` is the degree. @@ -780,6 +835,14 @@ def __init__(self, E, P, *, model=None, Q=None): r""" Initialize this √élu isogeny from a kernel point of odd order. + INPUT: + + - `E` -- an elliptic curve over a finite field + - `P` -- a point on `E` of odd order `\geq 5` + - ``model`` -- string (optional); input to + :meth:`~sage.schemes.elliptic_curves.ell_field.compute_model` + - `Q` -- a point on `E` outside `\langle P\rangle`, or ``None`` + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt @@ -897,8 +960,14 @@ def _compute_codomain(self, model=None): r""" Helper method to compute the codomain of this √élu isogeny once the data for :meth:`_raw_eval` has been initialized. + Called by the constructor. + INPUT: + + - ``model`` -- string (optional); input to + :meth:`~sage.schemes.elliptic_curves.ell_field.compute_model` + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt @@ -952,6 +1021,10 @@ def _eval(self, P): r""" Evaluate this √élu isogeny at a point. + INPUT: + + - `P` -- point on the domain, defined over any algebra over the base field + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt @@ -1047,7 +1120,7 @@ def _random_example_for_testing(): sage: E # random Elliptic Curve defined by y^2 + (t^3+6*t^2)*x*y + (t^3+3*t^2+2*t+2)*y = x^3 + (6*t^3+2*t^2+t)*x^2 + (3*t^3+2*t^2+6*t+1)*x + (t^3+2*t^2+2) over Finite Field in t of size 7^4 sage: E.short_weierstrass_model() - Elliptic Curve defined by y^2 = x^3 + ...*x... over Finite Field ... + Elliptic Curve defined by y^2 = x^3 + ... over Finite Field ... sage: K # random (3*t^3 + 4*t^2 + 4*t + 3 : 6*t^3 + 5*t^2 + 5*t : 1) sage: K.order() # random From 8bdcd4516ce9b4f7d81a33e3f1420f660279b2d8 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 21 Aug 2022 06:13:38 +0800 Subject: [PATCH 478/591] move comparison by evaluation up from hom_composite.py to hom.py --- src/sage/schemes/elliptic_curves/hom.py | 78 +++++++++++++++++++ .../schemes/elliptic_curves/hom_composite.py | 53 +++---------- 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 82ebdb8cefd..02432c44892 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -26,6 +26,11 @@ from sage.categories.morphism import Morphism +from sage.arith.misc import integer_floor + +from sage.rings.finite_rings import finite_field_base +from sage.rings.number_field import number_field_base + class EllipticCurveHom(Morphism): """ @@ -136,6 +141,10 @@ def _richcmp_(self, other, op): [True, True] sage: [a == b for a in (wE,mE) for b in (wF,mF)] [False, False, False, False] + + .. SEEALSO:: + + :func:`compare_via_evaluation` """ # We cannot just compare kernel polynomials, as was done until # Trac #11327, as then phi and -phi compare equal, and @@ -621,3 +630,72 @@ def __hash__(self): Isogeny of degree 7 from Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 107*x + 552 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 5252*x - 178837 over Rational Field """ return hash((self.domain(), self.codomain(), self.kernel_polynomial())) + + +def compare_via_evaluation(left, right): + r""" + Test if two elliptic-curve morphisms are equal by evaluating + them at enough points. + + INPUT: + + - ``left``, ``right`` -- :class:`EllipticCurveHom` objects + + ALGORITHM: + + We use the fact that two isogenies of equal degree `d` must be + the same if and only if they behave identically on more than + `4d` points. (It suffices to check this on a few points that + generate a large enough subgroup.) + + If the domain curve does not have sufficiently many rational + points, the base field is extended first: Taking an extension + of degree `O(\log(d))` suffices. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(83), [1,0]) + sage: phi = E.isogeny(12*E.0, model='montgomery'); phi + Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 83 to Elliptic Curve defined by y^2 = x^3 + 70*x^2 + x over Finite Field of size 83 + sage: psi = phi.dual(); psi + Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 70*x^2 + x over Finite Field of size 83 to Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 83 + sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + sage: mu = EllipticCurveHom_composite.from_factors([phi, psi]) + sage: from sage.schemes.elliptic_curves.hom import compare_via_evaluation + sage: compare_via_evaluation(mu, E.multiplication_by_m_isogeny(7)) + True + + .. SEEALSO:: + + - :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite._richcmp_` + """ + if left.domain() != right.domain(): + return False + if left.codomain() != right.codomain(): + return False + if left.degree() != right.degree(): + return False + + E = left.domain() + F = E.base_ring() + + if isinstance(F, finite_field_base.FiniteField): + q = F.cardinality() + d = left.degree() + e = integer_floor(1 + 2 * (2*d.sqrt() + 1).log(q)) # from Hasse bound + e = next(i for i,n in enumerate(E.count_points(e+1), 1) if n > 4*d) + EE = E.base_extend(F.extension(e)) + Ps = EE.gens() + return all(left._eval(P) == right._eval(P) for P in Ps) + + elif isinstance(F, number_field_base.NumberField): + for _ in range(100): + P = E.lift_x(F.random_element(), extend=True) + if not P.has_finite_order(): + return left._eval(P) == right._eval(P) + else: + assert False, "couldn't find a point of infinite order" + + else: + raise NotImplementedError('not implemented for this base field') + diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index 5a163ca4479..62ca45a2af6 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -83,15 +83,10 @@ from sage.misc.cachefunc import cached_method from sage.structure.sequence import Sequence -from sage.arith.misc import prod, integer_floor -from sage.functions.log import log -from sage.functions.other import sqrt - -from sage.rings.finite_rings import finite_field_base -from sage.rings.number_field import number_field_base +from sage.arith.misc import prod from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic -from sage.schemes.elliptic_curves.hom import EllipticCurveHom +from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism @@ -542,15 +537,10 @@ def _richcmp_(self, other, op): ALGORITHM: - Over finite fields and number fields, we use the fact that two - isogenies of equal degree `d` are the same if and only if they - act identically on more than `4d` points. (It suffices to check - this on a few points that generate a large enough subgroup.) - - If the domain curve does not have sufficiently many rational - points, the base field is extended first. Since an extension of - degree `O(\log(d))` suffices, the complexity is polynomial in - the representation size of this morphism. + If possible, we use + :func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation` + The complexity in that case is polynomial in the representation + size of this morphism. Over more general base fields, we fall back to comparing the results of :meth:`rational_maps`, which takes time at least @@ -585,34 +575,9 @@ def _richcmp_(self, other, op): if op != op_EQ: return NotImplemented - if self.domain() != other.domain(): - return False - if self.codomain() != other.codomain(): - return False - if self.degree() != other.degree(): - return False - - E = self.domain() - F = E.base_ring() - - if isinstance(F, finite_field_base.FiniteField): - q = F.cardinality() - d = self.degree() - e = integer_floor(1 + 2 * log(2*sqrt(d) + 1, q)) # from Hasse bound - e = next(i for i,n in enumerate(E.count_points(e+1), 1) if n > 4*d) - EE = E.base_extend(F.extension(e)) - Ps = EE.gens() - return all(self._eval(P) == other._eval(P) for P in Ps) - - elif isinstance(F, number_field_base.NumberField): - for _ in range(100): - P = E.lift_x(F.random_element(), extend=True) - if not P.has_finite_order(): - return self._eval(P) == other._eval(P) - else: - assert False, "_richcmp_() couldn't find a point of infinite order" - - else: + try: + return compare_via_evaluation(self, other) + except NotImplementedError: # fall back to generic method return self.rational_maps() == other.rational_maps() From 1e80198ddfd554ab358d88b5740dee3ab20e02a9 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 21 Aug 2022 07:40:16 +0800 Subject: [PATCH 479/591] =?UTF-8?q?implement=20more=20flexible=20compariso?= =?UTF-8?q?n=20for=20EllipticCurveHom=20children=20including=20=E2=88=9A?= =?UTF-8?q?=C3=A9lu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/schemes/elliptic_curves/hom.py | 48 +++++++++++++++---- .../schemes/elliptic_curves/hom_composite.py | 28 +++++------ .../schemes/elliptic_curves/hom_velusqrt.py | 44 ++++++++++++++--- .../elliptic_curves/weierstrass_morphism.py | 29 ++++++----- 4 files changed, 104 insertions(+), 45 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 02432c44892..8d707e8e6b7 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -22,7 +22,7 @@ """ from sage.misc.cachefunc import cached_method -from sage.structure.richcmp import richcmp_not_equal, richcmp +from sage.structure.richcmp import richcmp_not_equal, richcmp, op_EQ, op_NE from sage.categories.morphism import Morphism @@ -97,13 +97,29 @@ def _composition_(self, other, homset): return Morphism._composition_(self, other, homset) + @staticmethod + def _comparison_impl(left, right, op): + """ + Called by :meth:`_richcmp_`. + + TESTS:: + + sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom + sage: EllipticCurveHom._comparison_impl(None, None, None) + NotImplemented + """ + return NotImplemented + def _richcmp_(self, other, op): r""" Compare :class:`EllipticCurveHom` objects. ALGORITHM: - This method compares domains, codomains, and :meth:`rational_maps`. + The method first makes sure that domain, codomain and degree match. + Then, it determines if there is a specialized comparison method by + trying :meth:`_comparison_impl` on either input. If not, it falls + back to comparing :meth:`rational_maps`. EXAMPLES:: @@ -144,14 +160,16 @@ def _richcmp_(self, other, op): .. SEEALSO:: - :func:`compare_via_evaluation` + - :meth:`_comparison_impl` + - :func:`compare_via_evaluation` """ - # We cannot just compare kernel polynomials, as was done until - # Trac #11327, as then phi and -phi compare equal, and - # similarly with phi and any composition of phi with an - # automorphism of its codomain, or any post-isomorphism. - # Comparing domains, codomains and rational maps seems much - # safer. + if not isinstance(self, EllipticCurveHom) or not isinstance(other, EllipticCurveHom): + raise TypeError(f'cannot compare {type(self)} to {type(other)}') + + if op == op_NE: + return not self._richcmp_(other, op_EQ) + + # We first compare domain, codomain, and degree; cf. Trac #11327 lx, rx = self.domain(), other.domain() if lx != rx: @@ -165,6 +183,18 @@ def _richcmp_(self, other, op): if lx != rx: return richcmp_not_equal(lx, rx, op) + # Do self or other have specialized comparison methods? + + ret = self._comparison_impl(self, other, op) + if ret is not NotImplemented: + return ret + + ret = other._comparison_impl(self, other, op) + if ret is not NotImplemented: + return ret + + # If not, fall back to comparing rational maps; cf. Trac #11327 + return richcmp(self.rational_maps(), other.rational_maps(), op) diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index 62ca45a2af6..32b1fa9e0bb 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -79,7 +79,7 @@ documentation and tests, equality testing """ -from sage.structure.richcmp import op_EQ, op_NE +from sage.structure.richcmp import op_EQ from sage.misc.cachefunc import cached_method from sage.structure.sequence import Sequence @@ -480,6 +480,8 @@ def factors(self): return self._phis + # EllipticCurveHom methods + @staticmethod def _composition_impl(left, right): """ @@ -528,24 +530,20 @@ def _composition_impl(left, right): return EllipticCurveHom_composite.from_factors(right.factors() + (left,)) return NotImplemented - - # EllipticCurveHom methods - - def _richcmp_(self, other, op): + @staticmethod + def _comparison_impl(left, right, op): r""" - Compare this composite isogeny to another elliptic-curve morphism. + Compare a composite isogeny to another elliptic-curve morphism. + + Called by :meth:`EllipticCurveHom._richcmp_`. ALGORITHM: If possible, we use - :func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation` + :func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation`. The complexity in that case is polynomial in the representation size of this morphism. - Over more general base fields, we fall back to comparing the - results of :meth:`rational_maps`, which takes time at least - linear in the degree. - TESTS:: sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite @@ -570,16 +568,12 @@ def _richcmp_(self, other, op): sage: phi2 * phi1 == psi2 * psi1 True """ - if op == op_NE: - return not self._richcmp_(other, op_EQ) if op != op_EQ: return NotImplemented - try: - return compare_via_evaluation(self, other) + return compare_via_evaluation(left, right) except NotImplementedError: - # fall back to generic method - return self.rational_maps() == other.rational_maps() + return NotImplemented def rational_maps(self): """ diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index fdb78ce9a33..70b03ccfe28 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -50,12 +50,8 @@ However, they are certainly separable isogenies with the same kernel and must therefore be equal *up to post-isomorphism*:: - sage: sum(iso * psi == phi for iso in isos) # TODO: comparison is not implemented yet - 1 - sage: Q = E.gens()[0] - sage: phiQ, psiQ = phi(Q), psi(Q) sage: isos = psi.codomain().isomorphisms(phi.codomain()) - sage: sum(iso(psiQ) == phiQ for iso in isos) + sage: sum(iso * psi == phi for iso in isos) 1 Just like @@ -140,9 +136,11 @@ from sage.misc.misc_c import prod +from sage.structure.richcmp import op_EQ + from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_finite_field -from sage.schemes.elliptic_curves.hom import EllipticCurveHom +from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation from sage.misc.superseded import experimental_warning experimental_warning(34303, 'This module is experimental.') @@ -1107,6 +1105,40 @@ def _repr_(self): f'\n From: {self._domain}' \ f'\n To: {self._codomain}' + @staticmethod + def _comparison_impl(left, right, op): + r""" + Compare a √élu isogeny to another elliptic-curve morphism. + + Called by :meth:`EllipticCurveHom._richcmp_`. + + INPUT: + + - ``left, right`` -- :class:`~sage.schemes.elliptic_curves.hom.EllipticCurveHom` objects + + ALGORITHM: + + :func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation` + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + sage: E = EllipticCurve(GF(101), [5,5,5,5,5]) + sage: phi = EllipticCurveHom_velusqrt(E, E.lift_x(11)); phi + Elliptic-curve isogeny (using √élu) of degree 59: + From: Elliptic Curve defined by y^2 + 5*x*y + 5*y = x^3 + 5*x^2 + 5*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 15*x + 25 over Finite Field of size 101 + sage: psi = EllipticCurveHom_velusqrt(E, E.lift_x(-1)); psi + Elliptic-curve isogeny (using √élu) of degree 59: + From: Elliptic Curve defined by y^2 + 5*x*y + 5*y = x^3 + 5*x^2 + 5*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 15*x + 25 over Finite Field of size 101 + sage: phi == psi + True + """ + if op != op_EQ: + return NotImplemented + return compare_via_evaluation(left, right) + def _random_example_for_testing(): r""" diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index ca5931fbd62..33549debee1 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -534,9 +534,12 @@ def __init__(self, E=None, urst=None, F=None): self._degree = Integer(1) EllipticCurveHom.__init__(self, self._domain, self._codomain) - def _richcmp_(self, other, op): + @staticmethod + def _comparison_impl(left, right, op): r""" - Standard comparison function for the WeierstrassIsomorphism class. + Compare an isomorphism to another elliptic-curve morphism. + + Called by :meth:`EllipticCurveHom._richcmp_`. EXAMPLES:: @@ -562,20 +565,20 @@ def _richcmp_(self, other, op): sage: a == c True """ - if isinstance(other, WeierstrassIsomorphism): - lx = self._domain - rx = other._domain - if lx != rx: - return richcmp_not_equal(lx, rx, op) + if not isinstance(left, WeierstrassIsomorphism) or not isinstance(right, WeierstrassIsomorphism): + return NotImplemented - lx = self._codomain - rx = other._codomain - if lx != rx: - return richcmp_not_equal(lx, rx, op) + lx = left._domain + rx = right._domain + if lx != rx: + return richcmp_not_equal(lx, rx, op) - return baseWI.__richcmp__(self, other, op) + lx = left._codomain + rx = right._codomain + if lx != rx: + return richcmp_not_equal(lx, rx, op) - return EllipticCurveHom._richcmp_(self, other, op) + return baseWI.__richcmp__(left, right, op) def _eval(self, P): r""" From ab4b4bf817ba3e7bd6dda4588d0047d28cd83a77 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 21 Aug 2022 08:47:03 +0800 Subject: [PATCH 480/591] ensure correct base rings (example from failing random doctest) --- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 70b03ccfe28..430c50fe96f 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -986,6 +986,16 @@ def _compute_codomain(self, model=None): Elliptic-curve isogeny (using √élu) of degree 19: From: Elliptic Curve defined by y^2 = x^3 + 5*x^2 + x over Finite Field of size 71 To: Elliptic Curve defined by y^2 = x^3 + 40*x^2 + x over Finite Field of size 71 + + TESTS:: + + sage: F. = GF(5^2) + sage: E = EllipticCurve([3*t, 2*t+4, 3*t+2, t+4, 3*t]) + sage: K = E(3*t, 2) + sage: EllipticCurveHom_velusqrt(E, K) # indirect doctest + Elliptic-curve isogeny (using √élu) of degree 19: + From: Elliptic Curve defined by y^2 + 3*t*x*y + (3*t+2)*y = x^3 + (2*t+4)*x^2 + (t+4)*x + 3*t over Finite Field in t of size 5^2 + To: Elliptic Curve defined by y^2 = x^3 + (4*t+3)*x + 2 over Finite Field in t of size 5^2 """ poly = self._raw_domain.two_division_polynomial().monic() R, Z = poly.parent().objgen() @@ -1001,6 +1011,7 @@ def _compute_codomain(self, model=None): imX0 = imX0.polynomial()(Z) # K is a FiniteField except AttributeError: imX0 = imX0.lift() # K is a PolynomialQuotientRing + imX0 = imX0.change_ring(R.base_ring()) V = R['V'].gen() f *= (Z - imX0(V)).resultant(g(V)) From 986462f5576f046fd7117c7585269b7fcaf79af6 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 21 Aug 2022 10:21:47 +0800 Subject: [PATCH 481/591] =?UTF-8?q?add=20glue=20code=20in=20EllipticCurve?= =?UTF-8?q?=5Ffield.isogeny()=20to=20use=20the=20=E2=88=9A=C3=A9lu=20imple?= =?UTF-8?q?mentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/schemes/elliptic_curves/ell_field.py | 35 +++++++++++++++---- .../schemes/elliptic_curves/hom_velusqrt.py | 28 ++++++++++++++- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 73f3358ebe8..1850db229fd 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1090,6 +1090,14 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al Kohel's algorithm is currently only implemented for cyclic isogenies, with the exception of `[2]`. + - √élu Algorithm (*experimental* --- see + :mod:`~sage.schemes.elliptic_curves.hom_velusqrt`): + A variant of Vélu's formulas with essentially square-root + instead of linear complexity (in the degree). Currently only + available over finite fields. The input must be a single + kernel point of odd order `\geq 5`. + This algorithm is selected using ``algorithm="velusqrt"``. + - Factored Isogenies (*experimental* --- see :mod:`~sage.schemes.elliptic_curves.hom_composite`): Given a list of points which generate a composite-order @@ -1137,14 +1145,26 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al - ``check`` (default: ``True``) -- check whether the input is valid. Setting this to ``False`` can lead to significant speedups. - - ``algorithm`` (optional) -- When ``algorithm="factored"`` is - passed, decompose the isogeny into prime-degree steps. - The ``degree`` parameter is not supported by - ``algorithm="factored"``. + - ``algorithm`` -- string (optional). By default (when ``algorithm`` + is omitted), the "traditional" implementation + :class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny` + is used. The other choices are: + + - ``"velusqrt"``: Use + :class:`~sage.schemes.elliptic_curves.hom_velusqrt.EllipticCurveHom_velusqrt`. + + - ``"factored"``: Use + :class:`~sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite` + to decompose the isogeny into prime-degree steps. + + The ``degree`` parameter is not supported when an ``algorithm`` + is specified. OUTPUT: An isogeny between elliptic curves. This is a morphism of curves. + (In all cases, the returned object will be an instance of + :class:`~sage.schemes.elliptic_curves.hom.EllipticCurveHom`.) EXAMPLES:: @@ -1221,9 +1241,12 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al sage: phi.codomain()._order 170141183460469231746191640949390434666 """ + if algorithm is not None and degree is not None: + raise TypeError('cannot pass "degree" and "algorithm" parameters simultaneously') + if algorithm == "velusqrt": + from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + return EllipticCurveHom_velusqrt(self, kernel, codomain=codomain, model=model) if algorithm == "factored": - if degree is not None: - raise TypeError('algorithm="factored" does not support the "degree" parameter') from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite return EllipticCurveHom_composite(self, kernel, codomain=codomain, model=model) try: diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 430c50fe96f..25030190c92 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -829,7 +829,7 @@ class EllipticCurveHom_velusqrt(EllipticCurveHom): :class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny` """ - def __init__(self, E, P, *, model=None, Q=None): + def __init__(self, E, P, *, codomain=None, model=None, Q=None): r""" Initialize this √élu isogeny from a kernel point of odd order. @@ -837,6 +837,7 @@ def __init__(self, E, P, *, model=None, Q=None): - `E` -- an elliptic curve over a finite field - `P` -- a point on `E` of odd order `\geq 5` + - ``codomain`` -- codomain elliptic curve (optional) - ``model`` -- string (optional); input to :meth:`~sage.schemes.elliptic_curves.ell_field.compute_model` - `Q` -- a point on `E` outside `\langle P\rangle`, or ``None`` @@ -850,10 +851,31 @@ def __init__(self, E, P, *, model=None, Q=None): Elliptic-curve isogeny (using √élu) of degree 19: From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 71 To: Elliptic Curve defined by y^2 = x^3 + 13*x + 11 over Finite Field of size 71 + + :: + + sage: E.

= EllipticCurve(GF(419), [1,0]) + sage: K = 4*P + sage: EllipticCurveHom_velusqrt(E, K) + Elliptic-curve isogeny (using √élu) of degree 105: + From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419 + To: Elliptic Curve defined by y^2 = x^3 + 301*x + 86 over Finite Field of size 419 + sage: E2 = EllipticCurve(GF(419), [0,6,0,385,42]) + sage: EllipticCurveHom_velusqrt(E, K, codomain=E2) + Elliptic-curve isogeny (using √élu) of degree 105: + From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419 + To: Elliptic Curve defined by y^2 = x^3 + 6*x^2 + 385*x + 42 over Finite Field of size 419 + sage: EllipticCurveHom_velusqrt(E, K, model="montgomery") + Elliptic-curve isogeny (using √élu) of degree 105: + From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 419 + To: Elliptic Curve defined by y^2 = x^3 + 6*x^2 + x over Finite Field of size 419 """ if not isinstance(E, EllipticCurve_finite_field): raise NotImplementedError('only implemented for elliptic curves over finite fields') + if codomain is not None and model is not None: + raise ValueError('cannot specify a codomain curve and model name simultaneously') + try: self._raw_domain = E.short_weierstrass_model() except ValueError: @@ -886,6 +908,10 @@ def __init__(self, E, P, *, model=None, Q=None): self._domain = E self._compute_codomain(model=model) + if codomain is not None: + self._post_iso = self._codomain.isomorphism_to(codomain) * self._post_iso + self._codomain = codomain + super().__init__(self._domain, self._codomain) def _raw_eval(self, x, y=None): From 2761f34749a1a5f9838d3dcd8e45adca0c4b95ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 21 Aug 2022 10:05:43 +0200 Subject: [PATCH 482/591] small enhancements in MZV --- src/sage/modular/multiple_zeta.py | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 8080c1b689e..dcd3d681eac 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -814,6 +814,19 @@ def some_elements(self): """ return self([]), self([2]), self([3]), self([4]), self((1, 2)) + def an_element(self): + r""" + Return an element of the algebra. + + EXAMPLES:: + + sage: M = Multizetas(QQ) + sage: M.an_element() + ζ() + ζ(1,2) + 1/2*ζ(5) + """ + cf = self.base_ring().an_element() + return self([]) + self([1, 2]) + cf * self([5]) + def product_on_basis(self, w1, w2): r""" Compute the product of two monomials. @@ -1790,6 +1803,29 @@ def D_on_basis(self, k, w): coprod += left.regularise().tensor(right.regularise()) return coprod + def D(self, k): + """ + Return the operator `D_k`. + + INPUT: + + - ``k`` -- an odd integer, at least 3 + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta import Multizetas_iterated + sage: M = Multizetas_iterated(QQ) + sage: D3 = M.D(3) + sage: elt = M((1,0,1,0,0)) + 2 * M((1,1,0,0,1,0)) + sage: D3(elt) + -6*I(100) # I(110) + 3*I(100) # I(10) + """ + def map_on_basis(elt): + return self.D_on_basis(k, elt) + cod = Multizetas_iterated(self.base_ring()).tensor_square() + return self.module_morphism(map_on_basis, position=0, + codomain=cod) + @cached_method def phi_extended(self, w): r""" From 33d36751d4c9479db75770107dfea4a3a277863f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 21 Aug 2022 16:40:22 -0700 Subject: [PATCH 483/591] src/sage/categories/pushout.py (VectorFunctor): Add support for other keywords of the FreeModule constructor --- src/sage/categories/pushout.py | 49 +++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index c48ec6ec672..a44a1e5cc40 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1822,7 +1822,8 @@ class VectorFunctor(ConstructionFunctor): rank = 10 # ranking of functor, not rank of module. # This coincides with the rank of the matrix construction functor, but this is OK since they cannot both be applied in any order - def __init__(self, n, is_sparse=False, inner_product_matrix=None): + def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, + with_basis='standard', basis_keys=None): """ INPUT: @@ -1830,6 +1831,7 @@ def __init__(self, n, is_sparse=False, inner_product_matrix=None): - ``is_sparse`` (optional bool, default ``False``), create sparse implementation of modules - ``inner_product_matrix``: ``n`` by ``n`` matrix, used to compute inner products in the to-be-created modules + - other keywords: see :func:`~sage.modules.free_module.FreeModule` TESTS:: @@ -1860,6 +1862,8 @@ def __init__(self, n, is_sparse=False, inner_product_matrix=None): self.n = n self.is_sparse = is_sparse self.inner_product_matrix = inner_product_matrix + self.with_basis = with_basis + self.basis_keys = basis_keys def _apply_functor(self, R): """ @@ -1887,7 +1891,8 @@ def _apply_functor(self, R): """ from sage.modules.free_module import FreeModule - return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix) + return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix, + with_basis=self.with_basis, basis_keys=self.basis_keys) def _apply_functor_to_morphism(self, f): """ @@ -1924,7 +1929,9 @@ def __eq__(self, other): """ if isinstance(other, VectorFunctor): return (self.n == other.n and - self.inner_product_matrix == other.inner_product_matrix) + self.inner_product_matrix == other.inner_product_matrix and + self.with_basis == other.with_basis and + self.basis_keys == other.basis_keys) return False def __ne__(self, other): @@ -2000,16 +2007,38 @@ def merge(self, other): """ if not isinstance(other, VectorFunctor): return None + + if self.with_basis != other.with_basis: + return None + else: + with_basis = self.with_basis + + if self.basis_keys != other.basis_keys: + # TODO: If both are enumerated families, should we try to take the union of the families? + return None + else: + basis_keys = self.basis_keys + + is_sparse = self.is_sparse and other.is_sparse + if self.inner_product_matrix is None: - return VectorFunctor(self.n, self.is_sparse and other.is_sparse, other.inner_product_matrix) - if other.inner_product_matrix is None: - return VectorFunctor(self.n, self.is_sparse and other.is_sparse, self.inner_product_matrix) - # At this point, we know that the user wants to take care of the inner product. - # So, we only merge if both coincide: - if self.inner_product_matrix != other.inner_product_matrix: + inner_product_matrix = other.inner_product_matrix + elif other.inner_product_matrix is None: + inner_product_matrix = self.inner_product_matrix + elif self.inner_product_matrix != other.inner_product_matrix: + # At this point, we know that the user wants to take care of the inner product. + # So, we only merge if both coincide: + return None + else: + inner_product_matrix = None + + if self.n != other.n: return None else: - return VectorFunctor(self.n, self.is_sparse and other.is_sparse, self.inner_product_matrix) + n = self.n + + return VectorFunctor(n, is_sparse, inner_product_matrix, + with_basis=with_basis, basis_keys=basis_keys) class SubspaceFunctor(ConstructionFunctor): From 91c56457dd89aebde5f54544ae2ee0a383743b47 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 21 Aug 2022 16:52:24 -0700 Subject: [PATCH 484/591] src/sage/combinat/free_module.py (CombinatorialFreeModule): Add construction method --- src/sage/combinat/free_module.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index a2f789a4202..7a6de38c778 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -458,6 +458,19 @@ def __init__(self, R, basis_keys=None, element_class=None, category=None, self._order = None + def construction(self): + """ + The construction functor and base ring for self. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], category=AlgebrasWithBasis(QQ)) + sage: F.construction() + """ + from sage.categories.pushout import VectorFunctor + return VectorFunctor(None, True, None, with_basis='standard', + basis_keys=self.basis().keys()), self.base_ring() + # For backwards compatibility _repr_term = IndexedGenerators._repr_generator _latex_term = IndexedGenerators._latex_generator From d5b890b947af0a6042c1ea4b9e10ee2ddc65b8e6 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 22 Aug 2022 09:16:09 +0900 Subject: [PATCH 485/591] Implementing a direct action. --- src/sage/rings/power_series_poly.pxd | 6 ++- src/sage/rings/power_series_poly.pyx | 80 +++++++++++++++------------- src/sage/rings/power_series_ring.py | 19 ++++++- 3 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/sage/rings/power_series_poly.pxd b/src/sage/rings/power_series_poly.pxd index f19d3567f9a..80c441798a1 100644 --- a/src/sage/rings/power_series_poly.pxd +++ b/src/sage/rings/power_series_poly.pxd @@ -1,6 +1,10 @@ from .power_series_ring_element cimport PowerSeries from sage.rings.polynomial.polynomial_element cimport Polynomial - +from sage.categories.action cimport Action cdef class PowerSeries_poly(PowerSeries): cdef Polynomial __f + +cdef class BaseRingFloorDivAction(Action): + pass + diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 42c4a5602ce..ccfcdbf3e19 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -720,42 +720,6 @@ cdef class PowerSeries_poly(PowerSeries): return self._parent(self.truncate().inverse_series_trunc(prec), prec=prec) - def _floor_division_by_coefficient_(self, c): - """ - Perform the exact division of ``self`` by a coefficient ``c``. - - .. WARNING:: - - This is not intended to be used with another power series. - - EXAMPLES:: - - sage: A = ZZ[['t']] - sage: f = A([3*2**n for n in range(6)]).O(6) - sage: g = f//3; g - 1 + 2*t + 4*t^2 + 8*t^3 + 16*t^4 + 32*t^5 + O(t^6) - sage: g.parent() - Power Series Ring in t over Integer Ring - - sage: s = polygen(QQ,'s') - sage: A = s.parent()[['t']] - sage: f = A([(s+2)*(s+n) for n in range(5)]).O(5) - sage: g = f//(s+2); g - s + (s + 1)*t + (s + 2)*t^2 + (s + 3)*t^3 + (s + 4)*t^4 + O(t^5) - sage: g.parent() - Power Series Ring in t over Univariate Polynomial Ring in s - over Rational Field - """ - prec = self.prec() - return PowerSeries_poly(self._parent, - self.__f // c, - prec=prec, - check=False) - - cpdef _acted_upon_(self, other, bint self_on_left): - if self_on_left and other in self.base_ring(): - return self._floor_division_by_coefficient_(other) - def truncate(self, prec=infinity): """ The polynomial obtained from power series by truncation at @@ -1265,3 +1229,47 @@ def make_powerseries_poly_v0(parent, f, prec, is_gen): t """ return PowerSeries_poly(parent, f, prec, 0, is_gen) + +cdef class BaseRingFloorDivAction(Action): + """ + The floor division action of the base ring on a formal power series. + """ + cpdef _act_(self, g, x): + r""" + Let ``g`` act on ``x`` under ``self``. + + Regardless of whether this is a left or right action, the acting + element comes first. + + INPUT: + + - ``g`` -- an object with parent ``self.G`` + - ``x`` -- an object with parent ``self.US()`` + + .. WARNING:: + + This is meant to be a fast internal function, so the + conditions on the input are not checked! + + EXAMPLES:: + + sage: A = ZZ[['t']] + sage: f = A([3*2**n for n in range(6)]).O(6) + sage: g = f // 3; g + 1 + 2*t + 4*t^2 + 8*t^3 + 16*t^4 + 32*t^5 + O(t^6) + sage: g.parent() + Power Series Ring in t over Integer Ring + + sage: s = polygen(QQ,'s') + sage: A = s.parent()[['t']] + sage: f = A([(s+2)*(s+n) for n in range(5)]).O(5) + sage: g = f // (s + 2); g + s + (s + 1)*t + (s + 2)*t^2 + (s + 3)*t^3 + (s + 4)*t^4 + O(t^5) + sage: g.parent() + Power Series Ring in t over Univariate Polynomial Ring in s + over Rational Field + """ + cdef PowerSeries_poly elt = x + prec = x.prec() + return type(x)(self.US(), elt.__f // g, prec=prec, check=False) + diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 88b60ebbe02..08d9fafe4ef 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -1289,11 +1289,26 @@ def fraction_field(self): return laurent.change_ring(self.base_ring().fraction_field()) def _get_action_(self, other, op, self_is_left): + r""" + Return the actions on ``self`` by ``other`` under ``op``. + + EXAMPLES:: + + sage: R. = PowerSeriesRing(ZZ) + sage: import operator + sage: act = coercion_model.get_action(R, ZZ, operator.floordiv); act + Right action by Integer Ring on Power Series Ring in t over Integer Ring + sage: type(act) + + sage: coercion_model.get_action(ZZ, R, operator.floordiv) is None + True + """ import operator - from sage.structure.coerce_actions import ActedUponAction if op is operator.floordiv and self_is_left and other is self.base_ring(): + from sage.rings.power_series_poly import BaseRingFloorDivAction # Floor division by coefficient. - return ActedUponAction(other, self, not self_is_left) + return BaseRingFloorDivAction(other, self, is_left=False) + return super()._get_action_(other, op, self_is_left) class PowerSeriesRing_over_field(PowerSeriesRing_domain): _default_category = CompleteDiscreteValuationRings() From c8a57e081e4c7634af795f2248ef5efbdebcd306 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 22 Aug 2022 09:27:44 +0900 Subject: [PATCH 486/591] Allowing actions from things that coercion into the base ring as well. --- src/sage/rings/power_series_poly.pyx | 8 +++++++- src/sage/rings/power_series_ring.py | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index ccfcdbf3e19..3f551860181 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -1268,8 +1268,14 @@ cdef class BaseRingFloorDivAction(Action): sage: g.parent() Power Series Ring in t over Univariate Polynomial Ring in s over Rational Field + + sage: R. = PowerSeriesRing(QQ) + sage: t // 2 + 1/2*t """ cdef PowerSeries_poly elt = x prec = x.prec() - return type(x)(self.US(), elt.__f // g, prec=prec, check=False) + P = self.US() + g = P.base_ring()(g) + return type(x)(P, elt.__f // g, prec=prec, check=False) diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 08d9fafe4ef..711c5fe3c6a 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -1302,9 +1302,13 @@ def _get_action_(self, other, op, self_is_left): sage: coercion_model.get_action(ZZ, R, operator.floordiv) is None True + + sage: R. = PowerSeriesRing(QQ) + sage: coercion_model.get_action(R, ZZ, operator.floordiv) + Right action by Integer Ring on Power Series Ring in t over Rational Field """ import operator - if op is operator.floordiv and self_is_left and other is self.base_ring(): + if op is operator.floordiv and self_is_left and self.base_ring().has_coerce_map_from(other): from sage.rings.power_series_poly import BaseRingFloorDivAction # Floor division by coefficient. return BaseRingFloorDivAction(other, self, is_left=False) From d5610b15885f79d8554c1d307759e8431c11bd1c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 22 Aug 2022 09:38:15 +0900 Subject: [PATCH 487/591] Edit: prefer symlink --- src/doc/en/developer/portability_testing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 41fb93e5a6d..205baa67c1d 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1248,7 +1248,7 @@ installation of SageMath in this container by building from the current source t project `_, providing SnapPy, Regina, PHCPack, etc. -If you want to use one of these ``devcontainer.json`` files, copy (or symlink) +If you want to use one of these ``devcontainer.json`` files, symlink (or copy) it and start VS Code as explained above. After VS Code finished configuring the dev container, to use Sage in a terminal, `open a new terminal in VS Code `_, type ``./sage`` and hit @@ -1284,7 +1284,7 @@ work without change) or to adapt them to your needs. project `_, providing SnapPy, Regina, PHCPack, etc. -If you want to use one of these ``devcontainer.json`` files, copy (or symlink) +If you want to use one of these ``devcontainer.json`` files, symlink (or copy) it and start VS Code as explained above. After VS Code finished configuring the dev container, to use Sage in a terminal, `open a new terminal in VS Code `_, type ``sage`` and hit From 156c82053308448eb9845741e93f097b4134b4e5 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 22 Aug 2022 09:04:33 +0800 Subject: [PATCH 488/591] prevent crash in _random_example_for_testing() when group is trivial --- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 25030190c92..33bf339e9f2 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -1214,6 +1214,8 @@ def _random_example_for_testing(): E.short_weierstrass_model() except ValueError: continue + if E.cardinality() < 5: + continue A = E.abelian_group() ds = max(A.invariants()).prime_to_m_part(2).divisors() ds = [d for d in ds if 5 <= d < 1000] From 3d63a50db73a3a77d3b65d3419ba195304e4d03e Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 22 Aug 2022 08:40:15 +0800 Subject: [PATCH 489/591] move INPUT blocks from .__init__() docstrings to class docstrings --- .../schemes/elliptic_curves/hom_velusqrt.py | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 33bf339e9f2..1973e05d66d 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -151,6 +151,10 @@ class ProductTree: r""" A simple product tree. + INPUT: + + - ``leaves`` -- a sequence of elements in a common ring + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import ProductTree @@ -193,10 +197,6 @@ def __init__(self, leaves): Initialize a product tree having the given ring elements as its leaves. - INPUT: - - - ``leaves`` -- a sequence of elements in a common ring - EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import ProductTree @@ -438,6 +438,13 @@ class FastEllipticPolynomial: - If `Q` is omitted, then `S = \{1,3,5,...,n-2\}`. Note that in this case, `h_{\{1,2,3,...,n-1\}}` can be computed as `h_S^2` since `n` is odd. + INPUT: + + - `E` -- an elliptic curve in short Weierstraß form + - `n` -- an odd integer `\geq 5` + - `P` -- a point on `E` + - `Q` -- a point on `E`, or ``None`` + ALGORITHM: [BDLS2020]_, Algorithm 2 .. NOTE:: @@ -505,13 +512,6 @@ def __init__(self, E, n, P, Q=None): Initialize this elliptic polynomial and precompute some input-independent data required for evaluation. - INPUT: - - - `E` -- an elliptic curve in short Weierstraß form - - `n` -- an odd integer `\geq 5` - - `P` -- a point on `E` - - `Q` -- a point on `E`, or ``None`` - EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import FastEllipticPolynomial @@ -758,6 +758,15 @@ class EllipticCurveHom_velusqrt(EllipticCurveHom): REFERENCES: [BDLS2020]_ + INPUT: + + - `E` -- an elliptic curve over a finite field + - `P` -- a point on `E` of odd order `\geq 5` + - ``codomain`` -- codomain elliptic curve (optional) + - ``model`` -- string (optional); input to + :meth:`~sage.schemes.elliptic_curves.ell_field.compute_model` + - `Q` -- a point on `E` outside `\langle P\rangle`, or ``None`` + EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt @@ -833,15 +842,6 @@ def __init__(self, E, P, *, codomain=None, model=None, Q=None): r""" Initialize this √élu isogeny from a kernel point of odd order. - INPUT: - - - `E` -- an elliptic curve over a finite field - - `P` -- a point on `E` of odd order `\geq 5` - - ``codomain`` -- codomain elliptic curve (optional) - - ``model`` -- string (optional); input to - :meth:`~sage.schemes.elliptic_curves.ell_field.compute_model` - - `Q` -- a point on `E` outside `\langle P\rangle`, or ``None`` - EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt From c874dc39504705108771bee98ec1d9d47bbcfc36 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 22 Aug 2022 08:45:04 +0800 Subject: [PATCH 490/591] explicitly convert given n to Integer in FastEllipticPolynomial --- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 1973e05d66d..839f3200cfd 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -138,6 +138,8 @@ from sage.structure.richcmp import op_EQ +from sage.rings.integer import Integer + from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_finite_field from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation @@ -523,6 +525,8 @@ def __init__(self, E, n, P, Q=None): if any(E.a_invariants()[:-2]): raise NotImplementedError('only implemented for short Weierstrass curves') + n = Integer(n) + if Q is None: IJK = _choose_IJK(n) # [1,3,5,7,...,n-4,n-2] else: From e499ea6549cbb1f05cfe6687250f9fae5d3e1197 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 22 Aug 2022 08:40:45 +0800 Subject: [PATCH 491/591] clarify that _choose_IJK needs an Integer; use .isqrt(); rename b_ to c --- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 839f3200cfd..9b9e8bad0da 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -346,7 +346,7 @@ def _choose_IJK(n): INPUT: - - `n` -- odd integer `\geq 5` + - `n` -- odd :class:`~sage.rings.integer.Integer` `\geq 5` REFERENCES: [BDLS2020]_, Examples 4.7 and 4.12 @@ -368,11 +368,11 @@ def _choose_IJK(n): """ if n % 2 != 1 or n < 5: raise ValueError('n must be odd and >= 5') - b = int((n-1).sqrt() / 2) - b_ = (n-1) // (4*b) - I = range(2*b, 2*b*(2*b_-1)+1, 4*b) + b = (n-1).isqrt() // 2 + c = (n-1) // (4*b) + I = range(2*b, 2*b*(2*c-1)+1, 4*b) J = range(1, 2*b, 2) - K = range(4*b*b_+1, n, 2) + K = range(4*b*c+1, n, 2) return I, J, K def _points_range(rr, P, Q=None): From 9c7b344986a85a95a3976ba8a10f3cf7f94675f3 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 22 Aug 2022 08:43:41 +0800 Subject: [PATCH 492/591] change all INPUT parameters to code formatting --- .../schemes/elliptic_curves/hom_velusqrt.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 9b9e8bad0da..62fcc58ed62 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -259,7 +259,7 @@ def remainders(self, x): INPUT: - - `x` -- an element of the base ring of this product tree + - ``x`` -- an element of the base ring of this product tree EXAMPLES:: @@ -346,7 +346,7 @@ def _choose_IJK(n): INPUT: - - `n` -- odd :class:`~sage.rings.integer.Integer` `\geq 5` + - ``n`` -- odd :class:`~sage.rings.integer.Integer` `\geq 5` REFERENCES: [BDLS2020]_, Examples 4.7 and 4.12 @@ -383,8 +383,8 @@ def _points_range(rr, P, Q=None): INPUT: - ``rr`` -- :class:`range` object defining a sequence `S \subseteq \ZZ` - - `P` -- element of an additive abelian group - - `Q` -- element of the same group, or ``None`` + - ``P`` -- element of an additive abelian group + - ``Q`` -- element of the same group, or ``None`` EXAMPLES:: @@ -442,10 +442,10 @@ class FastEllipticPolynomial: INPUT: - - `E` -- an elliptic curve in short Weierstraß form - - `n` -- an odd integer `\geq 5` - - `P` -- a point on `E` - - `Q` -- a point on `E`, or ``None`` + - ``E`` -- an elliptic curve in short Weierstraß form + - ``n`` -- an odd integer `\geq 5` + - ``P`` -- a point on `E` + - ``Q`` -- a point on `E`, or ``None`` ALGORITHM: [BDLS2020]_, Algorithm 2 @@ -686,7 +686,7 @@ def _point_outside_subgroup(P): INPUT: - - `P` -- a point on an elliptic curve over a finite field + - ``P`` -- a point on an elliptic curve over a finite field EXAMPLES:: @@ -764,12 +764,12 @@ class EllipticCurveHom_velusqrt(EllipticCurveHom): INPUT: - - `E` -- an elliptic curve over a finite field - - `P` -- a point on `E` of odd order `\geq 5` + - ``E`` -- an elliptic curve over a finite field + - ``P`` -- a point on `E` of odd order `\geq 5` - ``codomain`` -- codomain elliptic curve (optional) - ``model`` -- string (optional); input to :meth:`~sage.schemes.elliptic_curves.ell_field.compute_model` - - `Q` -- a point on `E` outside `\langle P\rangle`, or ``None`` + - ``Q`` -- a point on `E` outside `\langle P\rangle`, or ``None`` EXAMPLES:: @@ -1062,7 +1062,7 @@ def _eval(self, P): INPUT: - - `P` -- point on the domain, defined over any algebra over the base field + - ``P`` -- point on the domain, defined over any algebra over the base field EXAMPLES:: From d1c586b27e777ab25fac68ec378d3ba75af63df8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 21 Aug 2022 18:55:04 -0700 Subject: [PATCH 493/591] Sets.CartesianProducts: Add parent method 'construction' --- src/sage/categories/sets_cat.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 09a57770a3b..0cc9cd34f4f 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -2500,6 +2500,19 @@ def cartesian_projection(self, i): 42 """ + def construction(self): + """ + The construction functor and the list of Cartesian factors. + + EXAMPLES:: + + sage: C = cartesian_product([QQ, ZZ, ZZ]) + sage: C.construction() + (The cartesian_product functorial construction, + (Rational Field, Integer Ring, Integer Ring)) + """ + return cartesian_product, self.cartesian_factors() + @abstract_method def _cartesian_product_of_elements(self, elements): """ From 7014231dc3127a31f4271c0d9b6b1a5337e25795 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 21 Aug 2022 18:56:34 -0700 Subject: [PATCH 494/591] CombinatorialFreeModule: Fix UniqueRepresentation failure when category is passed --- src/sage/combinat/free_module.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 7a6de38c778..fa32e270969 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -290,8 +290,9 @@ def __classcall_private__(cls, base_ring, basis_keys=None, category=None, sage: F3 = CombinatorialFreeModule(QQ, ['a','b'], category = (ModulesWithBasis(QQ),)) sage: F4 = CombinatorialFreeModule(QQ, ['a','b'], category = (ModulesWithBasis(QQ),CommutativeAdditiveSemigroups())) sage: F5 = CombinatorialFreeModule(QQ, ['a','b'], category = (ModulesWithBasis(QQ),Category.join((LeftModules(QQ), RightModules(QQ))))) - sage: F1 is F, F2 is F, F3 is F, F4 is F, F5 is F - (True, True, True, True, True) + sage: F6 = CombinatorialFreeModule(QQ, ['a','b'], category=ModulesWithBasis(QQ).FiniteDimensional()) + sage: F1 is F, F2 is F, F3 is F, F4 is F, F5 is F, F6 is F + (True, True, True, True, True, True) sage: G = CombinatorialFreeModule(QQ, ['a','b'], category = AlgebrasWithBasis(QQ)) sage: F is G @@ -302,6 +303,8 @@ def __classcall_private__(cls, base_ring, basis_keys=None, category=None, if isinstance(basis_keys, (list, tuple)): basis_keys = FiniteEnumeratedSet(basis_keys) category = ModulesWithBasis(base_ring).or_subcategory(category) + if basis_keys in Sets().Finite(): + category = category.FiniteDimensional() # bracket or latex_bracket might be lists, so convert # them to tuples so that they're hashable. bracket = keywords.get('bracket', None) From 0c8e8ad8c11eef9cc51131f47c5b1e4c3b557fed Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 21 Aug 2022 19:07:25 -0700 Subject: [PATCH 495/591] CombinatorialFreeModule.construction: Allow the method from the category to take precedence --- src/sage/combinat/free_module.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index fa32e270969..c0c047edc6f 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -469,7 +469,12 @@ def construction(self): sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], category=AlgebrasWithBasis(QQ)) sage: F.construction() + (VectorFunctor, Rational Field) """ + # Try to take it from the category + c = super().construction() + if c is not None: + return c from sage.categories.pushout import VectorFunctor return VectorFunctor(None, True, None, with_basis='standard', basis_keys=self.basis().keys()), self.base_ring() From 7897a863fbeb5548dd0e393feeac05ae17c3b0a4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 21 Aug 2022 21:44:28 -0700 Subject: [PATCH 496/591] CombinatorialFreeModule: Move method 'contruction' to subclass CombinatorialFreeModule_with_construction --- src/sage/combinat/free_module.py | 40 ++++++++++++++++++-------------- src/sage/modules/free_module.py | 5 ++-- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index c0c047edc6f..87d6beaca4a 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -461,24 +461,6 @@ def __init__(self, R, basis_keys=None, element_class=None, category=None, self._order = None - def construction(self): - """ - The construction functor and base ring for self. - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], category=AlgebrasWithBasis(QQ)) - sage: F.construction() - (VectorFunctor, Rational Field) - """ - # Try to take it from the category - c = super().construction() - if c is not None: - return c - from sage.categories.pushout import VectorFunctor - return VectorFunctor(None, True, None, with_basis='standard', - basis_keys=self.basis().keys()), self.base_ring() - # For backwards compatibility _repr_term = IndexedGenerators._repr_generator _latex_term = IndexedGenerators._latex_generator @@ -1172,6 +1154,28 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): return self.element_class(self, d) +class CombinatorialFreeModule_with_construction(CombinatorialFreeModule): + + def construction(self): + """ + The construction functor and base ring for self. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], category=AlgebrasWithBasis(QQ)) + sage: F.construction() + (VectorFunctor, Rational Field) + """ + # Try to take it from the category + c = super().construction() + if c is not None: + return c + from sage.categories.pushout import VectorFunctor + return VectorFunctor(None, True, None, with_basis='standard', + basis_keys=self.basis().keys()), self.base_ring() + + + class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): """ Tensor Product of Free Modules diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 9946a588c85..9ea31ef00e8 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -489,11 +489,12 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m else: if inner_product_matrix is not None: raise NotImplementedError - from sage.combinat.free_module import CombinatorialFreeModule - return CombinatorialFreeModule(base_ring, basis_keys, **args) + from sage.combinat.free_module import CombinatorialFreeModule_with_construction + return CombinatorialFreeModule_with_construction(base_ring, basis_keys, **args) else: raise NotImplementedError + def VectorSpace(K, dimension_or_basis_keys=None, sparse=False, inner_product_matrix=None, *, with_basis='standard', dimension=None, basis_keys=None, **args): """ From e07ac34ec08515169cbaae9f202c36ddfc22686b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 21 Aug 2022 21:51:45 -0700 Subject: [PATCH 497/591] CombinatorialFreeModule_with_construction: Add __classcall_private__ --- src/sage/combinat/free_module.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 87d6beaca4a..7e66e822b41 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1156,6 +1156,8 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): class CombinatorialFreeModule_with_construction(CombinatorialFreeModule): + __classcall_private__ = CombinatorialFreeModule.__classcall_private__ + def construction(self): """ The construction functor and base ring for self. From 9d4d1dcb5552be791665272996d42d67425f2314 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 21 Aug 2022 21:54:09 -0700 Subject: [PATCH 498/591] sage.combinat.all: Import CombinatorialFreeModule_with_construction as CombinatorialFreeModule --- src/sage/combinat/all.py | 2 +- src/sage/combinat/free_module.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index e0450a1fbe3..67171e8624b 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -83,7 +83,7 @@ from sage.combinat.designs.all import * # Free modules and friends -from .free_module import CombinatorialFreeModule +from .free_module import CombinatorialFreeModule_with_construction as CombinatorialFreeModule from .debruijn_sequence import DeBruijnSequences from .schubert_polynomial import SchubertPolynomialRing diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 7e66e822b41..b3f379ea6da 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1177,7 +1177,6 @@ def construction(self): basis_keys=self.basis().keys()), self.base_ring() - class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): """ Tensor Product of Free Modules From 3947c02c971518be4df1267b496b2498b7080bbd Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 22 Aug 2022 14:47:49 +0900 Subject: [PATCH 499/591] Refactor conic curves --- src/sage/schemes/plane_conics/con_field.py | 44 +++++++------------ .../schemes/projective/projective_morphism.py | 9 +++- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index dbef426b0a0..30be61e8154 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -8,21 +8,21 @@ - Nick Alexander (2008-01-08) """ -#***************************************************************************** -# Copyright (C) 2008 Nick Alexander -# Copyright (C) 2009/2010 Marco Streng +# ***************************************************************************** +# Copyright (C) 2008 Nick Alexander +# Copyright (C) 2009/2010 Marco Streng # -# Distributed under the terms of the GNU General Public License (GPL) +# 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. +# 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: +# The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# http://www.gnu.org/licenses/ +# ***************************************************************************** from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -35,12 +35,12 @@ from sage.matrix.constructor import Matrix from sage.structure.element import is_Matrix -from sage.schemes.curves.projective_curve import ProjectivePlaneCurve +from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field from sage.categories.fields import Fields _Fields = Fields() -class ProjectiveConic_field(ProjectivePlaneCurve): +class ProjectiveConic_field(ProjectivePlaneCurve_field): r""" Create a projective plane conic curve over a field. See ``Conic`` for full documentation. @@ -68,7 +68,7 @@ def __init__(self, A, f): sage: c = Conic([1, 1, 1]); c Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2 """ - ProjectivePlaneCurve.__init__(self, A, f) + super().__init__(A, f) self._coefficients = [f[(2,0,0)], f[(1,1,0)], f[(1,0,1)], f[(0,2,0)], f[(0,1,1)], f[(0,0,2)]] self._parametrization = None @@ -76,9 +76,6 @@ def __init__(self, A, f): self._rational_point = None - - - def _repr_type(self): r""" Returns ``'Projective Conic'``, which is the first part of the @@ -128,7 +125,7 @@ def base_extend(self, S): # if (and only if) there is no point in the cache. pt = con.point(pt) return con - return ProjectivePlaneCurve.base_extend(self, S) + return super().base_extend(S) def cache_point(self, p): r""" @@ -168,7 +165,6 @@ def coefficients(self): """ return self._coefficients - def derivative_matrix(self): r""" Gives the derivative of the defining polynomial of @@ -702,7 +698,7 @@ def hom(self, x, Y=None): (x, self, Y)) x = Sequence(x*vector(self.ambient_space().gens())) return self.Hom(Y)(x, check = False) - return ProjectivePlaneCurve.hom(self, x, Y) + return super().hom(x, Y) def is_diagonal(self): r""" @@ -743,7 +739,6 @@ def is_smooth(self): return self.defining_polynomial()([e, c, b]) != 0 return self.determinant() != 0 - def _magma_init_(self, magma): """ Internal function. Returns a string to initialize this @@ -782,7 +777,6 @@ def _magma_init_(self, magma): magma_coeffs = [coeffs[i]._magma_init_(magma) for i in [0, 3, 5, 1, 4, 2]] return 'Conic([%s|%s])' % (kmn,','.join(magma_coeffs)) - def matrix(self): r""" Returns a matrix `M` such that `(x, y, z) M (x, y, z)^t` @@ -959,12 +953,11 @@ def point(self, v, check=True): """ if is_Vector(v): v = Sequence(v) - p = ProjectivePlaneCurve.point(self, v, check=check) + p = super().point(v, check=check) if self._rational_point is None: self._rational_point = p return p - def random_rational_point(self, *args1, **args2): r""" Return a random rational point of the conic ``self``. @@ -1013,7 +1006,6 @@ def random_rational_point(self, *args1, **args2): y = B.random_element(*args1, **args2) return par[0]([x,y]) - def rational_point(self, algorithm = 'default', read_cache = True): r""" Return a point on ``self`` defined over the base field. @@ -1135,7 +1127,6 @@ def rational_point(self, algorithm = 'default', read_cache = True): raise ValueError("Conic %s has no rational points over %s!" % \ (self, self.ambient_space().base_ring())) - def singular_point(self): r""" Returns a singular rational point of ``self`` @@ -1192,7 +1183,6 @@ def symmetric_matrix(self): [ b/2, d , e/2 ], [ c/2, e/2, f ]]) - def upper_triangular_matrix(self): r""" The upper-triangular matrix `M` such that `(x y z) M (x y z)^t` diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index ddc085b86d0..f7bd894f197 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -2252,7 +2252,7 @@ def __call__(self, x): - ``x`` -- a point in the domain of definition - OUTPUT: a point in the codomain + OUTPUT: the image of the point ``x`` under the morphism TESTS:: @@ -2266,7 +2266,12 @@ def __call__(self, x): sage: _ == C([0, -1, 2]) True """ - for m in self.representatives(): + try: + reprs = self.representatives() + except NotImplementedError: + reprs = [self.defining_polynomials()] + + for m in reprs: try: return super(SchemeMorphism_polynomial_projective_subscheme_field, m).__call__(x) except ValueError: From 368a18e9fc901f08596ee3ae4575eacfae77a7ac Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 22 Aug 2022 08:59:37 +0800 Subject: [PATCH 500/591] ensure correct base rings (for real this time); cf. ab4b4bf817b --- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 62fcc58ed62..638da5d54d0 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -1027,8 +1027,8 @@ def _compute_codomain(self, model=None): From: Elliptic Curve defined by y^2 + 3*t*x*y + (3*t+2)*y = x^3 + (2*t+4)*x^2 + (t+4)*x + 3*t over Finite Field in t of size 5^2 To: Elliptic Curve defined by y^2 = x^3 + (4*t+3)*x + 2 over Finite Field in t of size 5^2 """ - poly = self._raw_domain.two_division_polynomial().monic() - R, Z = poly.parent().objgen() + R, Z = self._base_ring['Z'].objgen() + poly = self._raw_domain.two_division_polynomial().monic()(Z) f = 1 for g,_ in poly.factor(): @@ -1038,10 +1038,9 @@ def _compute_codomain(self, model=None): K, X0 = self._base_ring.extension(g,'T').objgen() imX0 = self._raw_eval(X0) try: - imX0 = imX0.polynomial()(Z) # K is a FiniteField + imX0 = imX0.polynomial() # K is a FiniteField except AttributeError: imX0 = imX0.lift() # K is a PolynomialQuotientRing - imX0 = imX0.change_ring(R.base_ring()) V = R['V'].gen() f *= (Z - imX0(V)).resultant(g(V)) From ac60efe8687e7f1659615a133b0dbba909d2dd1f Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 22 Aug 2022 14:58:29 +0900 Subject: [PATCH 501/591] Fixes for reviewer comments --- .../elliptic_curves/ell_curve_isogeny.py | 4 +-- .../schemes/projective/projective_morphism.py | 26 ++++++++++++------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index aeec607fcdb..a137c1947d9 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -2652,7 +2652,7 @@ def scaling_factor(self): sc *= self.__post_isomorphism.scaling_factor() return sc - def morphism(self): + def as_morphism(self): r""" Return this isogeny as a morphism of projective schemes. @@ -2662,7 +2662,7 @@ def morphism(self): sage: E = EllipticCurve(k, [1,1]) sage: Q = E(6,5) sage: phi = E.isogeny(Q) - sage: mor = phi.morphism() + sage: mor = phi.as_morphism() sage: mor.domain() == E True sage: mor.codomain() == phi.codomain() diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index f7bd894f197..42402cfbc74 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -2268,8 +2268,11 @@ def __call__(self, x): """ try: reprs = self.representatives() - except NotImplementedError: - reprs = [self.defining_polynomials()] + except NotImplementedError: # Singular does not support the base field + try: + return super(SchemeMorphism_polynomial_projective_subscheme_field, self).__call__(x) + except ValueError: + raise ValueError('cannot apply the morphism to this point') for m in reprs: try: @@ -2382,13 +2385,13 @@ def representatives(self): reprs.append(hom([f / f0 for f in r[1:]])) return reprs - if not X.is_irreducible(): - raise ValueError("domain is not an irreducible scheme") - if not (X.base_ring() in _NumberFields or X.base_ring() in _FiniteFields): raise NotImplementedError("base ring {} is not supported by Singular".format(X.base_ring())) + if not X.is_irreducible(): + raise ValueError("domain is not an irreducible scheme") + # prepare homogeneous coordinate ring of X in Singular from sage.rings.polynomial.term_order import TermOrder T = TermOrder('degrevlex') @@ -2595,6 +2598,7 @@ def image(self): gens = [g.subs(dict(zip(R.gens()[n:],T.gens()))) for g in j] return AY.subscheme(gens) + @cached_method def graph(self): """ Return the graph of this morphism. @@ -2648,13 +2652,15 @@ def graph(self): # I + (y_iF_j - y_jF_i : 0 <= i, j <= m) # # saturated with respect to (F_0, F_1, ..., F_m). - n1 = n + 1; m1 = m + 1 + n1 = n + 1 + m1 = m + 1 I = X.defining_ideal().change_ring(R) h = [g[n1 + i] * F[j] - g[n1 + j] * F[i] for i in range(m1) for j in range(i + 1, m1)] J, _ = (I + R.ideal(h)).saturation(R.ideal(F)) return AXY.subscheme(J) + @cached_method def projective_degrees(self): """ Return the projective degrees of this rational map. @@ -2665,9 +2671,9 @@ def projective_degrees(self): sage: E = EllipticCurve(k,[1,1]) sage: Q = E(6,5) sage: phi = E.multiplication_by_m_isogeny(2) - sage: mor = phi.morphism() + sage: mor = phi.as_morphism() sage: mor.projective_degrees() - [12, 3] + (12, 3) """ X = self.domain() Y = self.codomain() @@ -2695,7 +2701,7 @@ def projective_degrees(self): n = AX.dimension() m = AY.dimension() k = X.dimension() - return [poly.monomial_coefficient(L.monomial(n - i, m - k + i)) for i in range(k + 1)] + return tuple(poly.monomial_coefficient(L.monomial(n - i, m - k + i)) for i in range(k + 1)) def degree(self): """ @@ -2707,7 +2713,7 @@ def degree(self): sage: E = EllipticCurve(k,[1,1]) sage: Q = E(6,5) sage: phi = E.multiplication_by_m_isogeny(2) - sage: mor = phi.morphism() + sage: mor = phi.as_morphism() sage: mor.degree() 4 """ From dff4fc4b7ecd86b9b8556867b490126ebc8d089f Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 22 Aug 2022 18:44:28 +0900 Subject: [PATCH 502/591] Adding a completion of graded algebras by formal series. --- .../categories/graded_algebras_with_basis.py | 17 ++ src/sage/combinat/sf/sfa.py | 21 +++ src/sage/rings/lazy_series.py | 155 +++++++++--------- src/sage/rings/lazy_series_ring.py | 144 +++++++++++----- 4 files changed, 223 insertions(+), 114 deletions(-) diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index e80c1b00bf4..8527c214277 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -126,6 +126,23 @@ def free_graded_module(self, generator_degrees, names=None): from sage.modules.fp_graded.free_module import FreeGradedModule return FreeGradedModule(self, generator_degrees, names=names) + def formal_series_ring(self): + r""" + Return the completion of all formal linear combinations of + ``self`` with finite linear combinations in each homogeneous + degree (computed lazily). + + EXAMPLES:: + + sage: NCSF = NonCommutativeSymmetricFunctions(QQ) + sage: S = NCSF.Complete() + sage: L = S.formal_series_ring() + sage: L + Lazy completion of Non-Commutative Symmetric Functions over + the Rational Field in the Complete basis + """ + from sage.rings.lazy_series_ring import LazyCompletionGradedAlgebra + return LazyCompletionGradedAlgebra(self) class ElementMethods: pass diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index d1fd77e8c69..9cf982ce6ca 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -1449,6 +1449,27 @@ def coeff_of_m_mu_in_result(mu): distinct=True) return self(r) + def formal_series_ring(self): + r""" + Return the completion of all formal linear combinations of + ``self`` with finite linear combinations in each homogeneous + degree (computed lazily). + + EXAMPLES:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: L = s.formal_series_ring() + sage: L + Lazy completion of Symmetric Functions over Integer Ring in the Schur basis + + TESTS:: + + sage: type(L) + + """ + from sage.rings.lazy_series_ring import LazySymmetricFunctions + return LazySymmetricFunctions(self) + class FilteredSymmetricFunctionsBases(Category_realization_of_parent): r""" The category of filtered bases of the ring of symmetric functions. diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 50a8577504e..9f4cd1b0f39 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -3615,7 +3615,86 @@ def polynomial(self, degree=None, names=None): return R.sum(self[:m]) -class LazySymmetricFunction(LazyCauchyProductSeries): +class LazyCompletionGradedAlgebraElement(LazyCauchyProductSeries): + """ + An element of a completion of a graded algebra that is computed lazily. + """ + def _format_series(self, formatter, format_strings=False): + r""" + Return nonzero ``self`` formatted by ``formatter``. + + TESTS:: + + sage: h = SymmetricFunctions(ZZ).h() + sage: e = SymmetricFunctions(ZZ).e() + sage: L = LazySymmetricFunctions(tensor([h, e])) + sage: f = L(lambda n: sum(tensor([h[k], e[n-k]]) for k in range(n+1))) + sage: f._format_series(repr) + '(h[]#e[]) + + (h[]#e[1]+h[1]#e[]) + + (h[]#e[2]+h[1]#e[1]+h[2]#e[]) + + (h[]#e[3]+h[1]#e[2]+h[2]#e[1]+h[3]#e[]) + + (h[]#e[4]+h[1]#e[3]+h[2]#e[2]+h[3]#e[1]+h[4]#e[]) + + (h[]#e[5]+h[1]#e[4]+h[2]#e[3]+h[3]#e[2]+h[4]#e[1]+h[5]#e[]) + + (h[]#e[6]+h[1]#e[5]+h[2]#e[4]+h[3]#e[3]+h[4]#e[2]+h[5]#e[1]+h[6]#e[]) + + O^7' + """ + P = self.parent() + cs = self._coeff_stream + v = cs._approximate_order + if isinstance(cs, Stream_exact): + if not cs._constant: + m = cs._degree + else: + m = cs._degree + P.options.constant_length + else: + m = v + P.options.display_length + + atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') + mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] + if not isinstance(cs, Stream_exact) or cs._constant: + if P._internal_poly_ring.base_ring() is P.base_ring(): + bigO = ["O(%s)" % P._monomial(1, m)] + else: + bigO = ["O^%s" % m] + else: + bigO = [] + + from sage.misc.latex import latex + from sage.typeset.unicode_art import unicode_art + from sage.typeset.ascii_art import ascii_art + from sage.misc.repr import repr_lincomb + from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis + from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: + poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) + elif formatter == latex: + poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) + elif formatter == ascii_art: + if atomic_repr: + poly = ascii_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = ascii_art(m) + h = a.height() + return ascii_art(ascii_left_parenthesis.character_art(h), + a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + elif formatter == unicode_art: + if atomic_repr: + poly = unicode_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = unicode_art(m) + h = a.height() + return unicode_art(unicode_left_parenthesis.character_art(h), + a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + + return poly + + +class LazySymmetricFunction(LazyCompletionGradedAlgebraElement): r""" A symmetric function where each degree is computed lazily. @@ -3752,80 +3831,6 @@ def __call__(self, *args, check=True): plethysm = __call__ - def _format_series(self, formatter, format_strings=False): - r""" - Return nonzero ``self`` formatted by ``formatter``. - - TESTS:: - - sage: h = SymmetricFunctions(ZZ).h() - sage: e = SymmetricFunctions(ZZ).e() - sage: L = LazySymmetricFunctions(tensor([h, e])) - sage: f = L(lambda n: sum(tensor([h[k], e[n-k]]) for k in range(n+1))) - sage: f._format_series(repr) - '(h[]#e[]) - + (h[]#e[1]+h[1]#e[]) - + (h[]#e[2]+h[1]#e[1]+h[2]#e[]) - + (h[]#e[3]+h[1]#e[2]+h[2]#e[1]+h[3]#e[]) - + (h[]#e[4]+h[1]#e[3]+h[2]#e[2]+h[3]#e[1]+h[4]#e[]) - + (h[]#e[5]+h[1]#e[4]+h[2]#e[3]+h[3]#e[2]+h[4]#e[1]+h[5]#e[]) - + (h[]#e[6]+h[1]#e[5]+h[2]#e[4]+h[3]#e[3]+h[4]#e[2]+h[5]#e[1]+h[6]#e[]) - + O^7' - """ - P = self.parent() - cs = self._coeff_stream - v = cs._approximate_order - if isinstance(cs, Stream_exact): - if not cs._constant: - m = cs._degree - else: - m = cs._degree + P.options.constant_length - else: - m = v + P.options.display_length - - atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') - mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] - if not isinstance(cs, Stream_exact) or cs._constant: - if P._internal_poly_ring.base_ring() is P.base_ring(): - bigO = ["O(%s)" % P._monomial(1, m)] - else: - bigO = ["O^%s" % m] - else: - bigO = [] - - from sage.misc.latex import latex - from sage.typeset.unicode_art import unicode_art - from sage.typeset.ascii_art import ascii_art - from sage.misc.repr import repr_lincomb - from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis - from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis - if formatter == repr: - poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) - elif formatter == latex: - poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) - elif formatter == ascii_art: - if atomic_repr: - poly = ascii_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = ascii_art(m) - h = a.height() - return ascii_art(ascii_left_parenthesis.character_art(h), - a, ascii_right_parenthesis.character_art(h)) - poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - elif formatter == unicode_art: - if atomic_repr: - poly = unicode_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = unicode_art(m) - h = a.height() - return unicode_art(unicode_left_parenthesis.character_art(h), - a, unicode_right_parenthesis.character_art(h)) - poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - - return poly - def symmetric_function(self, degree=None): r""" Return ``self`` as a symmetric function if ``self`` is actually so. diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 2626384097c..94a3c4ac465 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -10,6 +10,7 @@ :class:`LazyLaurentSeriesRing` | The ring of lazy Laurent series. :class:`LazyTaylorSeriesRing` | The ring of (possibly multivariate) lazy Taylor series. + :class:`LazyCompletionGradedAlgebra` | The completion of a graded alebra consisting of formal series. :class:`LazySymmetricFunctions` | The ring of (possibly multivariate) lazy symmetric functions. :class:`LazyDirichletSeriesRing` | The ring of lazy Dirichlet series. @@ -51,6 +52,7 @@ from sage.rings.lazy_series import (LazyModuleElement, LazyLaurentSeries, LazyTaylorSeries, + LazyCompletionGradedAlgebraElement, LazySymmetricFunction, LazyDirichletSeries) from sage.structure.global_options import GlobalOptions @@ -1479,27 +1481,49 @@ def _an_element_(self): ###################################################################### -class LazySymmetricFunctions(LazySeriesRing): - """ - The ring of lazy symmetric functions. +class LazyCompletionGradedAlgebra(LazySeriesRing): + r""" + The completion of a graded alebra consisting of formal series. + + For a graded algebra `A`, we can form a completion of `A` consisting of + all formal series of `A` such that each homogeneous component is + a finite linear combination of basis elements of `A`. INPUT: - - ``basis`` -- the ring of symmetric functions + - ``basis`` -- a graded algebra - ``names`` -- name(s) of the alphabets - - ``sparse`` -- (default: ``True``) whether we use a sparse or a dense representation + - ``sparse`` -- (default: ``True``) whether we use a sparse or + a dense representation EXAMPLES:: - sage: s = SymmetricFunctions(ZZ).s() - sage: LazySymmetricFunctions(s) - Lazy Symmetric Functions over Integer Ring in the Schur basis + sage: NCSF = NonCommutativeSymmetricFunctions(QQ) + sage: S = NCSF.Complete() + sage: L = S.formal_series_ring() + sage: L + Lazy completion of Non-Commutative Symmetric Functions over the Rational Field in the Complete basis - sage: m = SymmetricFunctions(ZZ).m() - sage: LazySymmetricFunctions(tensor([s, m])) - Lazy Symmetric Functions over Integer Ring in the Schur basis # Symmetric Functions over Integer Ring in the monomial basis + sage: f = 1 / (1 - L(S[1])) + sage: f + S[] + S[1] + (S[1,1]) + (S[1,1,1]) + (S[1,1,1,1]) + (S[1,1,1,1,1]) + (S[1,1,1,1,1,1]) + O^7 + sage: g = 1 / (1 - L(S[2])) + sage: g + S[] + S[2] + (S[2,2]) + (S[2,2,2]) + O^7 + sage: f * g + S[] + S[1] + (S[1,1]+S[2]) + (S[1,1,1]+S[1,2]) + + (S[1,1,1,1]+S[1,1,2]+S[2,2]) + (S[1,1,1,1,1]+S[1,1,1,2]+S[1,2,2]) + + (S[1,1,1,1,1,1]+S[1,1,1,1,2]+S[1,1,2,2]+S[2,2,2]) + O^7 + sage: g * f + S[] + S[1] + (S[1,1]+S[2]) + (S[1,1,1]+S[2,1]) + + (S[1,1,1,1]+S[2,1,1]+S[2,2]) + (S[1,1,1,1,1]+S[2,1,1,1]+S[2,2,1]) + + (S[1,1,1,1,1,1]+S[2,1,1,1,1]+S[2,2,1,1]+S[2,2,2]) + O^7 + sage: f * g - g * f + (S[1,2]-S[2,1]) + (S[1,1,2]-S[2,1,1]) + + (S[1,1,1,2]+S[1,2,2]-S[2,1,1,1]-S[2,2,1]) + + (S[1,1,1,1,2]+S[1,1,2,2]-S[2,1,1,1,1]-S[2,2,1,1]) + O^7 """ - Element = LazySymmetricFunction + Element = LazyCompletionGradedAlgebraElement def __init__(self, basis, sparse=True, category=None): """ @@ -1533,7 +1557,11 @@ def __init__(self, basis, sparse=True, category=None): Parent.__init__(self, base=base_ring, category=category) self._sparse = sparse self._laurent_poly_ring = basis - self._internal_poly_ring = PolynomialRing(self._laurent_poly_ring, "DUMMY_VARIABLE") + if self._laurent_poly_ring not in Rings().Commutative(): + from sage.algebras.free_algebra import FreeAlgebra + self._internal_poly_ring = FreeAlgebra(self._laurent_poly_ring, 1, "DUMMY_VARIABLE") + else: + self._internal_poly_ring = PolynomialRing(self._laurent_poly_ring, "DUMMY_VARIABLE") def _repr_(self): """ @@ -1543,9 +1571,9 @@ def _repr_(self): sage: s = SymmetricFunctions(GF(2)).s() sage: LazySymmetricFunctions(s) - Lazy Symmetric Functions over Finite Field of size 2 in the Schur basis + Lazy completion of Symmetric Functions over Finite Field of size 2 in the Schur basis """ - return "Lazy {}".format(self._laurent_poly_ring) + return "Lazy completion of {}".format(self._laurent_poly_ring) def _latex_(self): r""" @@ -1572,21 +1600,23 @@ def _monomial(self, c, n): sage: L = LazySymmetricFunctions(m) sage: L._monomial(s[2,1], 3) 2*m[1, 1, 1] + m[2, 1] - """ L = self._laurent_poly_ring return L(c) def _element_constructor_(self, x=None, valuation=None, degree=None, check=True): - """ - Construct a lazy symmetric function from ``x``. + r""" + Construct a lazy element in ``self`` from ``x``. INPUT: - - ``x`` -- data used to the define a symmetric function - - ``valuation`` -- integer (optional); integer; a lower bound for the valuation of the series - - ``degree`` -- (optional) the degree when the symmetric function has finite support - - ``check`` -- (optional) check that coefficients are homogeneous of the correct degree when they are retrieved + - ``x`` -- data used to the define a lazy element + - ``valuation`` -- integer (optional); integer; a lower bound for + the valuation of the series + - ``degree`` -- (optional) the degree when the lazy element + has finite support + - ``check`` -- (optional) check that coefficients are homogeneous of + the correct degree when they are retrieved EXAMPLES:: @@ -1640,24 +1670,22 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) sage: L(lambda n: n)[3]; Traceback (most recent call last): ... - ValueError: coefficient 3*h[] # e[] should be a symmetric function of homogeneous degree 3 but has degree 0 + ValueError: coefficient 3*h[] # e[] should be an element of homogeneous degree 3 but has degree 0 sage: L([1, 2, 3]); Traceback (most recent call last): ... - ValueError: coefficient 2*h[] # e[] should be a symmetric function of homogeneous degree 1 but has degree 0 + ValueError: coefficient 2*h[] # e[] should be an element of homogeneous degree 1 but has degree 0 sage: L(lambda n: n, degree=3); Traceback (most recent call last): ... - ValueError: coefficient h[] # e[] should be a symmetric function of homogeneous degree 1 but has degree 0 - + ValueError: coefficient h[] # e[] should be an element of homogeneous degree 1 but has degree 0 """ if valuation is None: valuation = 0 if valuation < 0: - raise ValueError("the valuation of a lazy symmetric function must be nonnegative") - + raise ValueError("the valuation of a lazy completion element must be nonnegative") R = self._laurent_poly_ring if x is None: @@ -1680,10 +1708,14 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) p_dict[d] = p_dict.get(d, 0) + f else: for f in x.terms(): - d = sum(p.size() for p in f.support()) + try: + d = f.degree() + except (TypeError, ValueError, AttributeError): + # FIXME: Fallback for symmetric functions in multiple variables + d = sum(p.size() for p in f.support()) p_dict[d] = p_dict.get(d, 0) + f - v = min(p_dict.keys()) - d = max(p_dict.keys()) + v = min(p_dict) + d = max(p_dict) p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] coeff_stream = Stream_exact(p_list, self._sparse, @@ -1692,7 +1724,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) degree=degree) return self.element_class(self, coeff_stream) - if isinstance(x, LazySymmetricFunction): + if isinstance(x, self.Element): if x._coeff_stream._is_sparse is self._sparse: return self.element_class(self, x._coeff_stream) # TODO: Implement a way to make a self._sparse copy @@ -1707,17 +1739,25 @@ def check_homogeneous_of_degree(f, d): if d1 == d: return except ValueError: - raise ValueError("coefficient %s should be a symmetric function of homogeneous degree %s" % (f, d)) - raise ValueError("coefficient %s should be a symmetric function of homogeneous degree %s but has degree %s" % (f, d, d1)) + raise ValueError("coefficient %s should be an element of homogeneous degree %s" % (f, d)) + raise ValueError("coefficient %s should be an element of homogeneous degree %s but has degree %s" % (f, d, d1)) else: def check_homogeneous_of_degree(f, d): if not f: return for m in f.monomials(): - for t in m.support(): - d1 = sum(p.size() for p in t) - if d1 != d: - raise ValueError("coefficient %s should be a symmetric function of homogeneous degree %s but has degree %s" % (f, d, d1)) + try: + d1 = m.degree() + except AttributeError: + # FIXME: Fallback for symmetric functions in multiple variables + for t in m.support(): + d1 = sum(p.size() for p in t) + if d1 != d: + raise ValueError("coefficient %s should be an element of homogeneous degree %s but has degree %s" % (f, d, d1)) + except (TypeError, ValueError): + raise ValueError("coefficient %s is not homogeneous") + if d1 != d: + raise ValueError("coefficient %s should be an element of homogeneous degree %s but has degree %s" % (f, d, d1)) if isinstance(x, (tuple, list)): if degree is None: @@ -1751,7 +1791,7 @@ def y(n): else: coeff_stream = Stream_function(x, coeff_ring, self._sparse, valuation) return self.element_class(self, coeff_stream) - raise ValueError(f"unable to convert {x} into a lazy symmetric function") + raise ValueError(f"unable to convert {x} into a lazy completion element") def _an_element_(self): """ @@ -1768,6 +1808,32 @@ def _an_element_(self): coeff_stream = Stream_exact([R.one()], self._sparse, order=1, constant=0) return self.element_class(self, coeff_stream) + +###################################################################### + +class LazySymmetricFunctions(LazyCompletionGradedAlgebra): + """ + The ring of lazy symmetric functions. + + INPUT: + + - ``basis`` -- the ring of symmetric functions + - ``names`` -- name(s) of the alphabets + - ``sparse`` -- (default: ``True``) whether we use a sparse or a dense representation + + EXAMPLES:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: LazySymmetricFunctions(s) + Lazy completion of Symmetric Functions over Integer Ring in the Schur basis + + sage: m = SymmetricFunctions(ZZ).m() + sage: LazySymmetricFunctions(tensor([s, m])) + Lazy completion of Symmetric Functions over Integer Ring in the Schur basis # Symmetric Functions over Integer Ring in the monomial basis + """ + Element = LazySymmetricFunction + + ###################################################################### class LazyDirichletSeriesRing(LazySeriesRing): From 5fe7ef4b54e1a249c42f2f5dc9147767ccf766b4 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 22 Aug 2022 18:32:37 +0800 Subject: [PATCH 503/591] add "short_weierstrass" to list of valid inputs for compute_model() --- src/sage/schemes/elliptic_curves/ell_curve_isogeny.py | 3 +++ src/sage/schemes/elliptic_curves/ell_field.py | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index c8225c78121..b52c9d11722 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -571,6 +571,9 @@ class EllipticCurveIsogeny(EllipticCurveHom): over a number field, then the codomain is a global minimal model where this exists. + - ``"short_weierstrass"``: The codomain is a short Weierstrass curve, + assuming one exists. + - ``"montgomery"``: The codomain is an (untwisted) Montgomery curve, assuming one exists over this field. diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 1850db229fd..a4ef287ce26 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1139,6 +1139,9 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al over a number field, then the codomain is a global minimal model where this exists. + - ``"short_weierstrass"``: The codomain is a short Weierstrass curve, + assuming one exists. + - ``"montgomery"``: The codomain is an (untwisted) Montgomery curve, assuming one exists over this field. @@ -1882,6 +1885,10 @@ def compute_model(E, name): For this choice, ``E`` must be defined over a number field. See :meth:`~sage.schemes.elliptic_curves.ell_number_field.EllipticCurve_number_field.global_minimal_model`. + - ``"short_weierstrass"``: Return a short Weierstrass model of ``E`` + assuming one exists. + See :meth:`~sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic.short_weierstrass_model`. + - ``"montgomery"``: Return an (untwisted) Montgomery model of ``E`` assuming one exists over this field. See :meth:`~sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic.montgomery_model`. From a0f4c4a994abeadc7719c44625b37b0c2ee7c828 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 22 Aug 2022 18:49:31 +0800 Subject: [PATCH 504/591] remove experimental warning --- src/sage/schemes/elliptic_curves/ell_field.py | 2 +- src/sage/schemes/elliptic_curves/hom_velusqrt.py | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index a4ef287ce26..50a3249dfd5 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1090,7 +1090,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al Kohel's algorithm is currently only implemented for cyclic isogenies, with the exception of `[2]`. - - √élu Algorithm (*experimental* --- see + - √élu Algorithm (see :mod:`~sage.schemes.elliptic_curves.hom_velusqrt`): A variant of Vélu's formulas with essentially square-root instead of linear complexity (in the degree). Currently only diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 638da5d54d0..86ca9e51de0 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -25,7 +25,6 @@ EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt - ... sage: E = EllipticCurve(GF(6666679), [5,5]) sage: K = E(9970, 1003793, 1) sage: K.order() @@ -111,11 +110,6 @@ all methods of :class:`EllipticCurveHom`. This will hopefully change in the future. -.. WARNING:: - - This module is currently considered experimental. - It may change in a future release without prior warning. - AUTHORS: - Lorenz Panny (2022) @@ -144,9 +138,6 @@ from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_finite_field from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation -from sage.misc.superseded import experimental_warning -experimental_warning(34303, 'This module is experimental.') - #TODO: This is general. It should be elsewhere. class ProductTree: From 179406f61466f123f95ab578dd179ed37ec6b456 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 08:38:29 -0700 Subject: [PATCH 505/591] src/doc/en/developer/portability_testing.rst: Update references to devcontainer ...Command --- src/doc/en/developer/portability_testing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/en/developer/portability_testing.rst b/src/doc/en/developer/portability_testing.rst index 205baa67c1d..54facbfd1ce 100644 --- a/src/doc/en/developer/portability_testing.rst +++ b/src/doc/en/developer/portability_testing.rst @@ -1198,10 +1198,10 @@ you can see what it does: `_); note that these are multi-gigabyte images, so it may take a while. -- As part of the "postCreateCommand", it installs additional system packages to +- As part of the "onCreateCommand", it installs additional system packages to support VS Code and for development. -- Then, as part of the "postStartCommand", it bootstraps and +- Then, as part of the "updateContentCommand", it bootstraps and configures the source tree and starts to build Sage from source, reusing the installation (:envvar:`SAGE_LOCAL`, :envvar:`SAGE_VENV`) from the prebuilt image. From 4affef24a703a5c9f2cd7dfc008637b57e04dade Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 09:08:04 -0700 Subject: [PATCH 506/591] .devcontainer/onCreate.sh, portability-updateContent.sh: Rename from post_create.sh, portability-post_start.sh --- .devcontainer/develop-docker-computop/devcontainer.json | 2 +- .devcontainer/downstream-archlinux-latest/devcontainer.json | 2 +- .devcontainer/downstream-docker-cocalc/devcontainer.json | 2 +- .devcontainer/downstream-docker-computop/devcontainer.json | 2 +- .devcontainer/{post_create.sh => onCreate.sh} | 0 .../portability-ubuntu-jammy-standard/devcontainer.json | 4 ++-- ...portability-post_start.sh => portability-updateContent.sh} | 0 7 files changed, 6 insertions(+), 6 deletions(-) rename .devcontainer/{post_create.sh => onCreate.sh} (100%) rename .devcontainer/{portability-post_start.sh => portability-updateContent.sh} (100%) diff --git a/.devcontainer/develop-docker-computop/devcontainer.json b/.devcontainer/develop-docker-computop/devcontainer.json index 3dd68a6e0e8..a8746244086 100644 --- a/.devcontainer/develop-docker-computop/devcontainer.json +++ b/.devcontainer/develop-docker-computop/devcontainer.json @@ -7,7 +7,7 @@ }, // Install build tools, get rid of sourcing /sage/activate in non-login shells. // libgmp.a is broken and leads to a build failure of ecm. - "onCreateCommand": ".devcontainer/post_create.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", + "onCreateCommand": ".devcontainer/onCreate.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", // Do not run configure within a sage-env (see #29485). // The pari package is broken in the computop/sage 9.5 image, need to reinstall. // Also libnauty is broken. diff --git a/.devcontainer/downstream-archlinux-latest/devcontainer.json b/.devcontainer/downstream-archlinux-latest/devcontainer.json index 5fff1dc7cdc..f0b79e01ae3 100644 --- a/.devcontainer/downstream-archlinux-latest/devcontainer.json +++ b/.devcontainer/downstream-archlinux-latest/devcontainer.json @@ -3,7 +3,7 @@ "name": "archlinux:latest downstream Sage", "image": "archlinux:latest", // Create an empty bashrc to avoid the error "No such file or directory" when opening a terminal. - "onCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/post_create.sh && touch ~/.bashrc", + "onCreateCommand": "EXTRA_SYSTEM_PACKAGES='sagemath sagemath-doc' EXTRA_SAGE_PACKAGES='notebook pip' .devcontainer/onCreate.sh && touch ~/.bashrc", // There's no SAGE_LOCAL, so remove the symlink 'prefix'. "updateContentCommand": "rm -f prefix && ln -sf /usr venv", "extensions": [ diff --git a/.devcontainer/downstream-docker-cocalc/devcontainer.json b/.devcontainer/downstream-docker-cocalc/devcontainer.json index fc37d271530..626bdbb9996 100644 --- a/.devcontainer/downstream-docker-cocalc/devcontainer.json +++ b/.devcontainer/downstream-docker-cocalc/devcontainer.json @@ -6,7 +6,7 @@ "MAKE": "make -j4" }, // libgmp.a is broken and leads to a build failure of ecm. - "onCreateCommand": ".devcontainer/post_create.sh && rm -f /usr/local/sage/local/lib/libgmp.a", + "onCreateCommand": ".devcontainer/onCreate.sh && rm -f /usr/local/sage/local/lib/libgmp.a", // * If the workspace directory looks like a copy of the Sage source tree (SAGE_ROOT): // - it bootstraps the Sage distribution, // - sets the symlink ``venv`` as expected, diff --git a/.devcontainer/downstream-docker-computop/devcontainer.json b/.devcontainer/downstream-docker-computop/devcontainer.json index 923a18fdf89..bb2e29e374e 100644 --- a/.devcontainer/downstream-docker-computop/devcontainer.json +++ b/.devcontainer/downstream-docker-computop/devcontainer.json @@ -7,7 +7,7 @@ }, // Install build tools, get rid of sourcing /sage/activate in non-login shells. // libgmp.a is broken and leads to a build failure of ecm. - "onCreateCommand": ".devcontainer/post_create.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", + "onCreateCommand": ".devcontainer/onCreate.sh --sudo && sudo rm -f /sage/local/lib/libgmp.a && sed -i.bak '/sage.*activate/d' ~/.bashrc", // Do not run configure within a sage-env (see #29485). // The pari package is broken in the computop/sage 9.5 image, need to reinstall. // Also libnauty is broken. diff --git a/.devcontainer/post_create.sh b/.devcontainer/onCreate.sh similarity index 100% rename from .devcontainer/post_create.sh rename to .devcontainer/onCreate.sh diff --git a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json index 0c4015a8add..f59a1178179 100644 --- a/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json +++ b/.devcontainer/portability-ubuntu-jammy-standard/devcontainer.json @@ -14,8 +14,8 @@ "containerEnv": { "MAKE": "make -j4" }, - "onCreateCommand": ".devcontainer/post_create.sh", - "updateContentCommand": ".devcontainer/portability-post_start.sh", + "onCreateCommand": ".devcontainer/onCreate.sh", + "updateContentCommand": ".devcontainer/portability-updateContent.sh", "extensions": [ "ms-python.python" ] diff --git a/.devcontainer/portability-post_start.sh b/.devcontainer/portability-updateContent.sh similarity index 100% rename from .devcontainer/portability-post_start.sh rename to .devcontainer/portability-updateContent.sh From a0177f9345b3df4189b557ebf6aa583e70ccbdea Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 10:17:32 -0700 Subject: [PATCH 507/591] Update doctest outputs for new class CombinatorialFreeModule_with_construction --- src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst | 2 +- src/sage/combinat/free_module.py | 2 +- src/sage/modules/with_basis/indexed_element.pyx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst index 51aec989810..024c347ec8a 100644 --- a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst +++ b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst @@ -220,7 +220,7 @@ In Python, everything is an object so there isn't any difference between types and classes. One can get the class of the object ``el`` by:: sage: type(el) - + As such, this is not very informative. We'll come back to it later. The data associated to objects are stored in so-called **attributes**. They are diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index b3f379ea6da..e817a3e7eac 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -507,7 +507,7 @@ def _element_class(self): sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: F._element_class - + """ return self.element_class diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 6b861a42da1..3f367acaae8 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -900,7 +900,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: truediv("hello", x) Traceback (most recent call last): ... - TypeError: unsupported operand type(s) for /: 'str' and 'CombinatorialFreeModule_with_category.element_class' + TypeError: unsupported operand type(s) for /: 'str' and 'CombinatorialFreeModule_with_construction_with_category.element_class' """ if not isinstance(left, IndexedFreeModuleElement): return NotImplemented From 96f082afafc59ba31abc6b225daf2e43b76a3c20 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 10:17:55 -0700 Subject: [PATCH 508/591] src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst: In subclassing example, import CombinatorialFreeModule --- .../tutorial-implementing-algebraic-structures.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst b/src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst index c319c38e7b9..b38e3647258 100644 --- a/src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst +++ b/src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst @@ -57,6 +57,7 @@ with the simple command:: We reproduce the same, but by deriving a subclass of :class:`CombinatorialFreeModule`:: + sage: from sage.combinat.free_module import CombinatorialFreeModule sage: class MyCyclicGroupModule(CombinatorialFreeModule): ....: """An absolutely minimal implementation of a module whose basis is a cyclic group""" ....: def __init__(self, R, n, *args, **kwargs): From 1d4120b04ca5c81bdae95248be5e9217099e31ce Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 10:35:41 -0700 Subject: [PATCH 509/591] src/sage/tensor/modules/finite_rank_free_module.py: Add construction --- .../tensor/modules/finite_rank_free_module.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 091dc252ad5..6d4e3625c10 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -845,6 +845,28 @@ def __init__( self._general_linear_group = None # to be set by # self.general_linear_group() + def construction(self): + """ + The construction functor and base ring for self. + + EXAMPLES:: + + sage: FiniteRankFreeModule._clear_cache_() # for doctests only + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M.construction() + (VectorFunctor, Integer Ring) + """ + # Try to take it from the category + c = super().construction() + if c is not None: + return c + # Implementation restrictions: + if self._sindex: + return None + from sage.categories.pushout import VectorFunctor + return (VectorFunctor(self.rank(), False, None, with_basis=None), + self.base_ring()) + #### Parent methods def _element_constructor_(self, comp=[], basis=None, name=None, From 61f3ca1884a826bbb67f06e52c26cf781158a7d4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 10:55:54 -0700 Subject: [PATCH 510/591] src/sage/modules/free_module.py (FreeModule): If with_basis=None, decode rank and start_index from basis_keys --- src/sage/modules/free_module.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 9ea31ef00e8..824d7cdfd2e 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -471,6 +471,21 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m sage: _.category() Category of finite dimensional vector spaces over Rational Field + sage: FreeModule(QQ, [1, 2, 3, 4], with_basis=None) + 4-dimensional vector space over the Rational Field + sage: _.category() + Category of finite dimensional vector spaces over Rational Field + + TESTS:: + + sage: FreeModule(QQ, ['a', 2, 3, 4], with_basis=None) + Traceback (most recent call last): + ... + NotImplementedError: FiniteRankFreeModule only supports integer ranges as basis_keys, got ['a', 2, 3, 4] + sage: FreeModule(QQ, [1, 3, 5], with_basis=None) + Traceback (most recent call last): + ... + NotImplementedError: FiniteRankFreeModule only supports integer ranges as basis_keys, got [1, 3, 5] """ if rank_or_basis_keys is not None: try: @@ -481,6 +496,19 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m if inner_product_matrix is not None: raise NotImplementedError from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule + if basis_keys: + if not all(key in sage.rings.integer_ring.ZZ for key in basis_keys): + raise NotImplementedError(f'FiniteRankFreeModule only supports integer ranges as basis_keys, got {basis_keys}') + start_index = min(basis_keys) + end_index = max(basis_keys) + rank = end_index - start_index + 1 + # Check that the ordered list of basis_keys is the range from start_index to end_index + if (len(basis_keys) != rank + or not all(key == index + for key, index in zip(basis_keys, + range(start_index, end_index + 1)))): + raise NotImplementedError(f'FiniteRankFreeModule only supports integer ranges as basis_keys, got {basis_keys}') + return FiniteRankFreeModule(base_ring, rank, start_index=start_index, **args) return FiniteRankFreeModule(base_ring, rank, **args) elif with_basis == 'standard': if rank is not None: From c9a499c36cdb1d24b5caffc4667e1f42c9c4f01f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 11:04:54 -0700 Subject: [PATCH 511/591] src/sage/tensor/modules/finite_rank_free_module.py (construction): Support start_index --- src/sage/tensor/modules/finite_rank_free_module.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 6d4e3625c10..31776514ad7 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -855,15 +855,22 @@ def construction(self): sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: M.construction() (VectorFunctor, Integer Ring) + sage: N = FiniteRankFreeModule(ZZ, 3, name='N', start_index=17) + sage: N.construction() + (VectorFunctor, Integer Ring) """ # Try to take it from the category c = super().construction() if c is not None: return c # Implementation restrictions: - if self._sindex: + if self._latex_name != self._name: return None from sage.categories.pushout import VectorFunctor + if self._sindex: + return (VectorFunctor(None, False, None, with_basis=None, + basis_keys=list(self.irange())), + self.base_ring()) return (VectorFunctor(self.rank(), False, None, with_basis=None), self.base_ring()) From 418be0214175b83a2d7c5b542b60d1bd01a6df75 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 12:02:10 -0700 Subject: [PATCH 512/591] FiniteRankFreeModule.construction, VectorFunctor: Preserve/construct name, latex_name --- src/sage/categories/pushout.py | 32 +++++++++++++++++-- .../tensor/modules/finite_rank_free_module.py | 12 ++++--- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index a44a1e5cc40..8cb68fa4513 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1823,7 +1823,7 @@ class VectorFunctor(ConstructionFunctor): # This coincides with the rank of the matrix construction functor, but this is OK since they cannot both be applied in any order def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, - with_basis='standard', basis_keys=None): + with_basis='standard', basis_keys=None, name_mapping=None, latex_name_mapping=None): """ INPUT: @@ -1831,6 +1831,7 @@ def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, - ``is_sparse`` (optional bool, default ``False``), create sparse implementation of modules - ``inner_product_matrix``: ``n`` by ``n`` matrix, used to compute inner products in the to-be-created modules + - ``name_mapping``, ``latex_name_mapping``: Dictionaries from base rings to names - other keywords: see :func:`~sage.modules.free_module.FreeModule` TESTS:: @@ -1864,6 +1865,12 @@ def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, self.inner_product_matrix = inner_product_matrix self.with_basis = with_basis self.basis_keys = basis_keys + if name_mapping is None: + name_mapping = {} + self.name_mapping = name_mapping + if latex_name_mapping is None: + latex_name_mapping = {} + self.latex_name_mapping = latex_name_mapping def _apply_functor(self, R): """ @@ -1871,7 +1878,7 @@ def _apply_functor(self, R): TESTS:: - sage: from sage.categories.pushout import VectorFunctor + sage: from sage.categories.pushout import VectorFunctor, pushout sage: F1 = VectorFunctor(3, inner_product_matrix = Matrix(3,3,range(9))) sage: M1 = F1(ZZ) # indirect doctest sage: M1.is_sparse() @@ -1889,10 +1896,29 @@ def _apply_functor(self, R): sage: v.inner_product(v) 14 + sage: M = FreeModule(ZZ, 4, with_basis=None, name='M') + sage: latex(M) + M + sage: M_QQ = pushout(M, QQ) + """ from sage.modules.free_module import FreeModule + name = self.name_mapping.get(R, None) + latex_name = self.latex_name_mapping.get(R, None) + if name is None: + for base_ring, name in self.name_mapping.items(): + name = f'{name}_base_ext' + break + if latex_name is None: + from sage.misc.latex import latex + for base_ring, latex_name in self.latex_name_mapping.items(): + latex_name = fr'{latex_name} \otimes {latex(R)}' + break + if name is None and latex_name is None: + return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix, + with_basis=self.with_basis, basis_keys=self.basis_keys) return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix, - with_basis=self.with_basis, basis_keys=self.basis_keys) + with_basis=self.with_basis, basis_keys=self.basis_keys, name=name, latex_name=latex_name) def _apply_functor_to_morphism(self, f): """ diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 31776514ad7..7102ac3d237 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -864,14 +864,18 @@ def construction(self): if c is not None: return c # Implementation restrictions: - if self._latex_name != self._name: + if self._output_formatter: return None from sage.categories.pushout import VectorFunctor + kwds = dict(is_sparse=False, + inner_product_matrix=None, + with_basis=None, + name_mapping={self.base_ring(): self._name}, + latex_name_mapping={self.base_ring(): self._latex_name}) if self._sindex: - return (VectorFunctor(None, False, None, with_basis=None, - basis_keys=list(self.irange())), + return (VectorFunctor(basis_keys=list(self.irange()), **kwds), self.base_ring()) - return (VectorFunctor(self.rank(), False, None, with_basis=None), + return (VectorFunctor(n=self.rank(), **kwds), self.base_ring()) #### Parent methods From f5c8afdfdd66ca774529ae3246a635aa211c9e94 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 12:08:50 -0700 Subject: [PATCH 513/591] src/sage/tensor/modules/ext_pow_free_module.py: No construction --- .../tensor/modules/ext_pow_free_module.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/sage/tensor/modules/ext_pow_free_module.py b/src/sage/tensor/modules/ext_pow_free_module.py index c68033fdf51..83b0d5b317f 100644 --- a/src/sage/tensor/modules/ext_pow_free_module.py +++ b/src/sage/tensor/modules/ext_pow_free_module.py @@ -253,6 +253,21 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): output_formatter=fmodule._output_formatter) fmodule._all_modules.add(self) + def construction(self): + r""" + TESTS:: + + sage: from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: A = ExtPowerFreeModule(M, 2) + sage: A.construction() is None + True + """ + # No construction until https://trac.sagemath.org/ticket/30242 + # makes this a quotient of TensorFreeModule + return None + #### Parent methods def _element_constructor_(self, comp=[], basis=None, name=None, @@ -654,6 +669,21 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): output_formatter=fmodule._output_formatter) fmodule._all_modules.add(self) + def construction(self): + r""" + TESTS:: + + sage: from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: e = M.basis('e') + sage: A = ExtPowerDualFreeModule(M, 2) + sage: A.construction() is None + True + """ + # No construction until https://trac.sagemath.org/ticket/30242 + # makes this a quotient of TensorFreeModule + return None + #### Parent methods def _element_constructor_(self, comp=[], basis=None, name=None, From 55606c8158ce69b99cca665eb6f5d4b553f1f082 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 12:12:33 -0700 Subject: [PATCH 514/591] src/sage/tensor/modules/tensor_free_module.py: No construction --- src/sage/tensor/modules/tensor_free_module.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index dbeb1f2be25..ded223bd2bf 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -393,6 +393,18 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None): output_formatter=fmodule._output_formatter) fmodule._all_modules.add(self) + def construction(self): + r""" + TESTS:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: T = M.tensor_module(2, 3) + sage: T.construction() is None + True + """ + # No construction until https://trac.sagemath.org/ticket/31276 provides tensor_product methods + return None + #### Parent Methods def _element_constructor_(self, comp=[], basis=None, name=None, From 1bb9ffa27ce20b7d17cd5808fb768ffcf8f18258 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 13:37:25 -0700 Subject: [PATCH 515/591] TangentSpace, VectorBundleFiber: No construction --- src/sage/manifolds/differentiable/tangent_space.py | 13 +++++++++++++ src/sage/manifolds/vector_bundle_fiber.py | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/sage/manifolds/differentiable/tangent_space.py b/src/sage/manifolds/differentiable/tangent_space.py index 0825f867e5e..36b68c7b5c5 100644 --- a/src/sage/manifolds/differentiable/tangent_space.py +++ b/src/sage/manifolds/differentiable/tangent_space.py @@ -252,6 +252,19 @@ def __init__(self, point): pass self._basis_changes[(basis1, basis2)] = auto + def construction(self): + """ + TESTS:: + + sage: M = Manifold(2, 'M') + sage: X. = M.chart() + sage: p = M.point((3,-2), name='p') + sage: Tp = M.tangent_space(p) + sage: Tp.construction() is None + True + """ + return None + def _repr_(self): r""" String representation of ``self``. diff --git a/src/sage/manifolds/vector_bundle_fiber.py b/src/sage/manifolds/vector_bundle_fiber.py index a79d42176e4..90a59e97169 100644 --- a/src/sage/manifolds/vector_bundle_fiber.py +++ b/src/sage/manifolds/vector_bundle_fiber.py @@ -242,6 +242,19 @@ def __init__(self, vector_bundle, point): pass self._basis_changes[(basis1, basis2)] = auto + def construction(self): + r""" + TESTS:: + + sage: M = Manifold(3, 'M', structure='top') + sage: X. = M.chart() + sage: p = M((0,0,0), name='p') + sage: E = M.vector_bundle(2, 'E') + sage: E.fiber(p).construction() is None + True + """ + return None + def _repr_(self): r""" String representation of ``self``. From 9c299cf7410b40b7e17da194433a0237be5bf9be Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 15:25:50 -0700 Subject: [PATCH 516/591] src/sage/categories/pushout.py: Expand doctest --- src/sage/categories/pushout.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 8cb68fa4513..9e3b3144a8e 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1900,6 +1900,8 @@ def _apply_functor(self, R): sage: latex(M) M sage: M_QQ = pushout(M, QQ) + sage: latex(M_QQ) + M \otimes \Bold{Q} """ from sage.modules.free_module import FreeModule From 1955c4bd75a0e4ed3c7ff22c23a75720a6871445 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 10:56:41 -0700 Subject: [PATCH 517/591] build/pkgs/_develop: New --- build/pkgs/_develop/SPKG.rst | 7 +++++++ build/pkgs/_develop/dependencies | 1 + build/pkgs/_develop/distros/conda.txt | 3 +++ build/pkgs/_develop/distros/debian.txt | 3 +++ build/pkgs/_develop/spkg-configure.m4 | 3 +++ build/pkgs/_develop/spkg-install | 2 ++ build/pkgs/_develop/type | 1 + 7 files changed, 20 insertions(+) create mode 100644 build/pkgs/_develop/SPKG.rst create mode 100644 build/pkgs/_develop/dependencies create mode 100644 build/pkgs/_develop/distros/conda.txt create mode 100644 build/pkgs/_develop/distros/debian.txt create mode 100644 build/pkgs/_develop/spkg-configure.m4 create mode 100755 build/pkgs/_develop/spkg-install create mode 100644 build/pkgs/_develop/type diff --git a/build/pkgs/_develop/SPKG.rst b/build/pkgs/_develop/SPKG.rst new file mode 100644 index 00000000000..65166cca172 --- /dev/null +++ b/build/pkgs/_develop/SPKG.rst @@ -0,0 +1,7 @@ +\_develop: Represents system packages recommended for development +================================================================= + +Description +----------- + +Script package representing a list of system packages recommended for developers. diff --git a/build/pkgs/_develop/dependencies b/build/pkgs/_develop/dependencies new file mode 100644 index 00000000000..5664e303b5d --- /dev/null +++ b/build/pkgs/_develop/dependencies @@ -0,0 +1 @@ +git diff --git a/build/pkgs/_develop/distros/conda.txt b/build/pkgs/_develop/distros/conda.txt new file mode 100644 index 00000000000..f8c24a05b53 --- /dev/null +++ b/build/pkgs/_develop/distros/conda.txt @@ -0,0 +1,3 @@ +openssh +pycodestyle +pytest diff --git a/build/pkgs/_develop/distros/debian.txt b/build/pkgs/_develop/distros/debian.txt new file mode 100644 index 00000000000..5c3c17488e8 --- /dev/null +++ b/build/pkgs/_develop/distros/debian.txt @@ -0,0 +1,3 @@ +# Needed for devcontainer support in VS code +gpgconf +openssh-client diff --git a/build/pkgs/_develop/spkg-configure.m4 b/build/pkgs/_develop/spkg-configure.m4 new file mode 100644 index 00000000000..dd308c02f47 --- /dev/null +++ b/build/pkgs/_develop/spkg-configure.m4 @@ -0,0 +1,3 @@ +SAGE_SPKG_CONFIGURE([_develop], [ + sage_spkg_install__develop=yes +]) diff --git a/build/pkgs/_develop/spkg-install b/build/pkgs/_develop/spkg-install new file mode 100755 index 00000000000..599e0b77a66 --- /dev/null +++ b/build/pkgs/_develop/spkg-install @@ -0,0 +1,2 @@ +#! /usr/bin/env bash +# Nothing to do diff --git a/build/pkgs/_develop/type b/build/pkgs/_develop/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/_develop/type @@ -0,0 +1 @@ +optional From f2b6bedcd42cf601c08d6b9ebc06969848e677d3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 11:20:26 -0700 Subject: [PATCH 518/591] bootstrap-conda: Use script package _develop instead of hardcoded list of dev tools; remove unused RECOMMENDED --- bootstrap-conda | 18 ++++++++++-------- build/pkgs/_develop/distros/conda.txt | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/bootstrap-conda b/bootstrap-conda index 596b449e3e0..495a75f251f 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -7,14 +7,17 @@ export PATH="$(pwd)/build/bin:$PATH" STRIP_COMMENTS="sed s/#.*//;" -RECOMMENDED_SPKG_PATTERN="@(_recommended$(for a in $(head -n 1 build/pkgs/_recommended/dependencies); do echo -n "|"$a; done))" + +shopt -s extglob + +DEVELOP_SPKG_PATTERN="@(_develop$(for a in $(head -n 1 build/pkgs/_develop/dependencies); do echo -n "|"$a; done))" BOOTSTRAP_PACKAGES=$(echo $(${STRIP_COMMENTS} build/pkgs/_bootstrap/distros/conda.txt)) SYSTEM_PACKAGES= OPTIONAL_SYSTEM_PACKAGES= SAGELIB_SYSTEM_PACKAGES= SAGELIB_OPTIONAL_SYSTEM_PACKAGES= -RECOMMENDED_SYSTEM_PACKAGES= +DEVELOP_SYSTEM_PACKAGES= for PKG_BASE in $(sage-package list --has-file distros/conda.txt); do PKG_SCRIPTS=build/pkgs/$PKG_BASE SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/distros/conda.txt @@ -26,8 +29,8 @@ for PKG_BASE in $(sage-package list --has-file distros/conda.txt); do *:standard) SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; - $RECOMMENDED_SPKG_PATTERN:*) - RECOMMENDED_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" + $DEVELOP_SPKG_PATTERN:*) + DEVELOP_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; *) OPTIONAL_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" @@ -64,10 +67,9 @@ for pkg in $SAGELIB_SYSTEM_PACKAGES; do done sed 's/name: sage/name: sage-dev/' src/environment.yml > src/environment-dev.yml echo " # Additional dev tools" >> src/environment-dev.yml -echo " - openssh" >> src/environment-dev.yml -echo " - pycodestyle" >> src/environment-dev.yml -echo " - pytest" >> src/environment-dev.yml -echo " - esbonio" >> src/environment-dev.yml +for pkg in $DEVELOP_SYSTEM_PACKAGES; do + echo " - $pkg" >> src/environment-dev.yml +done cp environment.yml environment-optional.yml echo " # optional packages" >> environment-optional.yml diff --git a/build/pkgs/_develop/distros/conda.txt b/build/pkgs/_develop/distros/conda.txt index f8c24a05b53..e07dcb57360 100644 --- a/build/pkgs/_develop/distros/conda.txt +++ b/build/pkgs/_develop/distros/conda.txt @@ -1,3 +1,4 @@ openssh pycodestyle pytest +esbonio From 3f6660bf8f82e26272048416df78b5d6c2fd8be1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 11:28:51 -0700 Subject: [PATCH 519/591] bootstrap-conda: Write an additional comment --- bootstrap-conda | 1 + 1 file changed, 1 insertion(+) diff --git a/bootstrap-conda b/bootstrap-conda index 495a75f251f..120bce29e67 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -62,6 +62,7 @@ for pkg in $BOOTSTRAP_PACKAGES; do echo " - $pkg" >> environment.yml done sed 's/name: sage-build/name: sage/' environment.yml > src/environment.yml +echo " # Additional packages providing all dependencies for the Sage library" for pkg in $SAGELIB_SYSTEM_PACKAGES; do echo " - $pkg" >> src/environment.yml done From 04045d3a05b3eb518c450e256e1a306a785e3234 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 11:40:51 -0700 Subject: [PATCH 520/591] build/pkgs/_develop/dependencies: Add pytest, pytest_xdist --- build/pkgs/_develop/dependencies | 2 +- build/pkgs/_develop/distros/conda.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/build/pkgs/_develop/dependencies b/build/pkgs/_develop/dependencies index 5664e303b5d..45d1294d4be 100644 --- a/build/pkgs/_develop/dependencies +++ b/build/pkgs/_develop/dependencies @@ -1 +1 @@ -git +git pytest pytest_xdist diff --git a/build/pkgs/_develop/distros/conda.txt b/build/pkgs/_develop/distros/conda.txt index e07dcb57360..7eda6f9cb56 100644 --- a/build/pkgs/_develop/distros/conda.txt +++ b/build/pkgs/_develop/distros/conda.txt @@ -1,4 +1,3 @@ openssh pycodestyle -pytest esbonio From 0856a000b99e94e842cd79db2f5e4a2f60a28019 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 11:49:46 -0700 Subject: [PATCH 521/591] bootstrap-conda: Write an additional comment (fixup) --- bootstrap-conda | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap-conda b/bootstrap-conda index 120bce29e67..177fc642751 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -62,7 +62,7 @@ for pkg in $BOOTSTRAP_PACKAGES; do echo " - $pkg" >> environment.yml done sed 's/name: sage-build/name: sage/' environment.yml > src/environment.yml -echo " # Additional packages providing all dependencies for the Sage library" +echo " # Additional packages providing all dependencies for the Sage library" >> src/environment.yml for pkg in $SAGELIB_SYSTEM_PACKAGES; do echo " - $pkg" >> src/environment.yml done From 8f17c1148f6f67b1459ad638fca508728cd79560 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 14 May 2022 11:59:08 -0700 Subject: [PATCH 522/591] bootstrap-conda: Rewrite using fewer redirects --- bootstrap-conda | 75 +++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/bootstrap-conda b/bootstrap-conda index 177fc642751..0065d6ee3f6 100755 --- a/bootstrap-conda +++ b/bootstrap-conda @@ -49,36 +49,49 @@ for PKG_BASE in $(sage-package list --has-file distros/conda.txt); do fi done echo >&2 $0:$LINENO: generate conda environment files -echo "name: sage-build" > environment.yml -echo "channels:" >> environment.yml -echo " - conda-forge" >> environment.yml -echo " - nodefaults" >> environment.yml -echo "dependencies:" >> environment.yml -for pkg in $SYSTEM_PACKAGES; do - echo " - $pkg" >> environment.yml -done -echo " # Packages needed for ./bootstrap" >> environment.yml -for pkg in $BOOTSTRAP_PACKAGES; do - echo " - $pkg" >> environment.yml -done -sed 's/name: sage-build/name: sage/' environment.yml > src/environment.yml -echo " # Additional packages providing all dependencies for the Sage library" >> src/environment.yml -for pkg in $SAGELIB_SYSTEM_PACKAGES; do - echo " - $pkg" >> src/environment.yml -done -sed 's/name: sage/name: sage-dev/' src/environment.yml > src/environment-dev.yml -echo " # Additional dev tools" >> src/environment-dev.yml -for pkg in $DEVELOP_SYSTEM_PACKAGES; do - echo " - $pkg" >> src/environment-dev.yml -done +( + echo "name: sage-build" + echo "channels:" + echo " - conda-forge" + echo " - nodefaults" + echo "dependencies:" + for pkg in $SYSTEM_PACKAGES; do + echo " - $pkg" + done + echo " # Packages needed for ./bootstrap" + for pkg in $BOOTSTRAP_PACKAGES; do + echo " - $pkg" + done +) > environment.yml -cp environment.yml environment-optional.yml - echo " # optional packages" >> environment-optional.yml -for pkg in $OPTIONAL_SYSTEM_PACKAGES; do - echo " - $pkg" >> environment-optional.yml +( + sed 's/name: sage-build/name: sage/' environment.yml + echo " # Additional packages providing all dependencies for the Sage library" + for pkg in $SAGELIB_SYSTEM_PACKAGES; do + echo " - $pkg" done -cp src/environment.yml src/environment-optional.yml - echo " # optional packages" >> src/environment-optional.yml -for pkg in $OPTIONAL_SYSTEM_PACKAGES $SAGELIB_OPTIONAL_SYSTEM_PACKAGES; do - echo " - $pkg" >> src/environment-optional.yml -done +) > src/environment.yml + +( + sed 's/name: sage/name: sage-dev/' src/environment.yml + echo " # Additional dev tools" + for pkg in $DEVELOP_SYSTEM_PACKAGES; do + echo " - $pkg" + done +) > src/environment-dev.yml + +( + cat environment.yml + echo " # optional packages" + for pkg in $OPTIONAL_SYSTEM_PACKAGES; do + echo " - $pkg" + done +) > environment-optional.yml + +( + cat src/environment.yml + echo " # optional packages" + for pkg in $OPTIONAL_SYSTEM_PACKAGES $SAGELIB_OPTIONAL_SYSTEM_PACKAGES; do + echo " - $pkg" + done +) > src/environment-optional.yml From 15598c5db021c225472c8a836a664066494984fe Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 15 May 2022 07:21:53 -0700 Subject: [PATCH 523/591] build/pkgs/_develop/distros: Add packages providing gpgconf --- build/pkgs/_develop/distros/alpine.txt | 1 + build/pkgs/_develop/distros/arch.txt | 1 + build/pkgs/_develop/distros/cygwin.txt | 1 + build/pkgs/_develop/distros/fedora.txt | 1 + build/pkgs/_develop/distros/freebsd.txt | 1 + build/pkgs/_develop/distros/gentoo.txt | 1 + build/pkgs/_develop/distros/homebrew.txt | 1 + build/pkgs/_develop/distros/macports.txt | 1 + build/pkgs/_develop/distros/nix.txt | 1 + build/pkgs/_develop/distros/opensuse.txt | 1 + build/pkgs/_develop/distros/repology.txt | 1 + build/pkgs/_develop/distros/slackware.txt | 1 + build/pkgs/_develop/distros/void.txt | 1 + 13 files changed, 13 insertions(+) create mode 100644 build/pkgs/_develop/distros/alpine.txt create mode 100644 build/pkgs/_develop/distros/arch.txt create mode 100644 build/pkgs/_develop/distros/cygwin.txt create mode 100644 build/pkgs/_develop/distros/fedora.txt create mode 100644 build/pkgs/_develop/distros/freebsd.txt create mode 100644 build/pkgs/_develop/distros/gentoo.txt create mode 100644 build/pkgs/_develop/distros/homebrew.txt create mode 100644 build/pkgs/_develop/distros/macports.txt create mode 100644 build/pkgs/_develop/distros/nix.txt create mode 100644 build/pkgs/_develop/distros/opensuse.txt create mode 100644 build/pkgs/_develop/distros/repology.txt create mode 100644 build/pkgs/_develop/distros/slackware.txt create mode 100644 build/pkgs/_develop/distros/void.txt diff --git a/build/pkgs/_develop/distros/alpine.txt b/build/pkgs/_develop/distros/alpine.txt new file mode 100644 index 00000000000..211ccf25f9b --- /dev/null +++ b/build/pkgs/_develop/distros/alpine.txt @@ -0,0 +1 @@ +gnupg-gpgconf diff --git a/build/pkgs/_develop/distros/arch.txt b/build/pkgs/_develop/distros/arch.txt new file mode 100644 index 00000000000..a8ef4049b5d --- /dev/null +++ b/build/pkgs/_develop/distros/arch.txt @@ -0,0 +1 @@ +gnupg diff --git a/build/pkgs/_develop/distros/cygwin.txt b/build/pkgs/_develop/distros/cygwin.txt new file mode 100644 index 00000000000..239772ed91d --- /dev/null +++ b/build/pkgs/_develop/distros/cygwin.txt @@ -0,0 +1 @@ +gnupg2 diff --git a/build/pkgs/_develop/distros/fedora.txt b/build/pkgs/_develop/distros/fedora.txt new file mode 100644 index 00000000000..239772ed91d --- /dev/null +++ b/build/pkgs/_develop/distros/fedora.txt @@ -0,0 +1 @@ +gnupg2 diff --git a/build/pkgs/_develop/distros/freebsd.txt b/build/pkgs/_develop/distros/freebsd.txt new file mode 100644 index 00000000000..d445ae4d109 --- /dev/null +++ b/build/pkgs/_develop/distros/freebsd.txt @@ -0,0 +1 @@ +security/gnupg diff --git a/build/pkgs/_develop/distros/gentoo.txt b/build/pkgs/_develop/distros/gentoo.txt new file mode 100644 index 00000000000..27e3402bcf7 --- /dev/null +++ b/build/pkgs/_develop/distros/gentoo.txt @@ -0,0 +1 @@ +app-crypt/gnupg diff --git a/build/pkgs/_develop/distros/homebrew.txt b/build/pkgs/_develop/distros/homebrew.txt new file mode 100644 index 00000000000..a8ef4049b5d --- /dev/null +++ b/build/pkgs/_develop/distros/homebrew.txt @@ -0,0 +1 @@ +gnupg diff --git a/build/pkgs/_develop/distros/macports.txt b/build/pkgs/_develop/distros/macports.txt new file mode 100644 index 00000000000..239772ed91d --- /dev/null +++ b/build/pkgs/_develop/distros/macports.txt @@ -0,0 +1 @@ +gnupg2 diff --git a/build/pkgs/_develop/distros/nix.txt b/build/pkgs/_develop/distros/nix.txt new file mode 100644 index 00000000000..a8ef4049b5d --- /dev/null +++ b/build/pkgs/_develop/distros/nix.txt @@ -0,0 +1 @@ +gnupg diff --git a/build/pkgs/_develop/distros/opensuse.txt b/build/pkgs/_develop/distros/opensuse.txt new file mode 100644 index 00000000000..eed13eaff0b --- /dev/null +++ b/build/pkgs/_develop/distros/opensuse.txt @@ -0,0 +1 @@ +gpg2 diff --git a/build/pkgs/_develop/distros/repology.txt b/build/pkgs/_develop/distros/repology.txt new file mode 100644 index 00000000000..a8ef4049b5d --- /dev/null +++ b/build/pkgs/_develop/distros/repology.txt @@ -0,0 +1 @@ +gnupg diff --git a/build/pkgs/_develop/distros/slackware.txt b/build/pkgs/_develop/distros/slackware.txt new file mode 100644 index 00000000000..239772ed91d --- /dev/null +++ b/build/pkgs/_develop/distros/slackware.txt @@ -0,0 +1 @@ +gnupg2 diff --git a/build/pkgs/_develop/distros/void.txt b/build/pkgs/_develop/distros/void.txt new file mode 100644 index 00000000000..239772ed91d --- /dev/null +++ b/build/pkgs/_develop/distros/void.txt @@ -0,0 +1 @@ +gnupg2 From eab7c5645612465fcc5c3c60379d1fffdbb5cab2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 15 May 2022 07:30:43 -0700 Subject: [PATCH 524/591] build/pkgs/_develop/distros: Add packages providing ssh --- build/pkgs/_develop/distros/alpine.txt | 1 + build/pkgs/_develop/distros/arch.txt | 1 + build/pkgs/_develop/distros/debian.txt | 1 + build/pkgs/_develop/distros/fedora.txt | 1 + build/pkgs/_develop/distros/freebsd.txt | 1 + build/pkgs/_develop/distros/gentoo.txt | 1 + build/pkgs/_develop/distros/nix.txt | 1 + build/pkgs/_develop/distros/opensuse.txt | 1 + build/pkgs/_develop/distros/repology.txt | 1 + build/pkgs/_develop/distros/slackware.txt | 1 + build/pkgs/_develop/distros/void.txt | 1 + 11 files changed, 11 insertions(+) diff --git a/build/pkgs/_develop/distros/alpine.txt b/build/pkgs/_develop/distros/alpine.txt index 211ccf25f9b..2b721fa34a4 100644 --- a/build/pkgs/_develop/distros/alpine.txt +++ b/build/pkgs/_develop/distros/alpine.txt @@ -1 +1,2 @@ gnupg-gpgconf +openssh-client diff --git a/build/pkgs/_develop/distros/arch.txt b/build/pkgs/_develop/distros/arch.txt index a8ef4049b5d..59d48b3e43b 100644 --- a/build/pkgs/_develop/distros/arch.txt +++ b/build/pkgs/_develop/distros/arch.txt @@ -1 +1,2 @@ gnupg +openssh diff --git a/build/pkgs/_develop/distros/debian.txt b/build/pkgs/_develop/distros/debian.txt index 5c3c17488e8..4598e83f3f5 100644 --- a/build/pkgs/_develop/distros/debian.txt +++ b/build/pkgs/_develop/distros/debian.txt @@ -1,3 +1,4 @@ # Needed for devcontainer support in VS code gpgconf openssh-client +openssh diff --git a/build/pkgs/_develop/distros/fedora.txt b/build/pkgs/_develop/distros/fedora.txt index 239772ed91d..66e987c8959 100644 --- a/build/pkgs/_develop/distros/fedora.txt +++ b/build/pkgs/_develop/distros/fedora.txt @@ -1 +1,2 @@ gnupg2 +openssh diff --git a/build/pkgs/_develop/distros/freebsd.txt b/build/pkgs/_develop/distros/freebsd.txt index d445ae4d109..8341acc726c 100644 --- a/build/pkgs/_develop/distros/freebsd.txt +++ b/build/pkgs/_develop/distros/freebsd.txt @@ -1 +1,2 @@ security/gnupg +security/openssh-portable diff --git a/build/pkgs/_develop/distros/gentoo.txt b/build/pkgs/_develop/distros/gentoo.txt index 27e3402bcf7..7f306e1b41b 100644 --- a/build/pkgs/_develop/distros/gentoo.txt +++ b/build/pkgs/_develop/distros/gentoo.txt @@ -1 +1,2 @@ app-crypt/gnupg +net-misc/openssh diff --git a/build/pkgs/_develop/distros/nix.txt b/build/pkgs/_develop/distros/nix.txt index a8ef4049b5d..59d48b3e43b 100644 --- a/build/pkgs/_develop/distros/nix.txt +++ b/build/pkgs/_develop/distros/nix.txt @@ -1 +1,2 @@ gnupg +openssh diff --git a/build/pkgs/_develop/distros/opensuse.txt b/build/pkgs/_develop/distros/opensuse.txt index eed13eaff0b..641f598082e 100644 --- a/build/pkgs/_develop/distros/opensuse.txt +++ b/build/pkgs/_develop/distros/opensuse.txt @@ -1 +1,2 @@ gpg2 +openssh diff --git a/build/pkgs/_develop/distros/repology.txt b/build/pkgs/_develop/distros/repology.txt index a8ef4049b5d..59d48b3e43b 100644 --- a/build/pkgs/_develop/distros/repology.txt +++ b/build/pkgs/_develop/distros/repology.txt @@ -1 +1,2 @@ gnupg +openssh diff --git a/build/pkgs/_develop/distros/slackware.txt b/build/pkgs/_develop/distros/slackware.txt index 239772ed91d..66e987c8959 100644 --- a/build/pkgs/_develop/distros/slackware.txt +++ b/build/pkgs/_develop/distros/slackware.txt @@ -1 +1,2 @@ gnupg2 +openssh diff --git a/build/pkgs/_develop/distros/void.txt b/build/pkgs/_develop/distros/void.txt index 239772ed91d..66e987c8959 100644 --- a/build/pkgs/_develop/distros/void.txt +++ b/build/pkgs/_develop/distros/void.txt @@ -1 +1,2 @@ gnupg2 +openssh From 6592b3833d0385738b01dacb952955efa382653d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 18:48:11 -0700 Subject: [PATCH 525/591] README.md: All developers should install _bootstrap packages --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fd467aa85f8..70df528319d 100644 --- a/README.md +++ b/README.md @@ -269,8 +269,8 @@ in the Installation Guide. [void.txt](build/pkgs/_prereq/distros/void.txt), or visit https://doc.sagemath.org/html/en/reference/spkg/_prereq.html#spkg-prereq -4. [Git] If you plan to work with ticket branches that make changes - to packages, install the bootstrapping prerequisites. See the +4. [Git] If you plan to do Sage development or otherwise work with ticket branches + and not only releases, install the bootstrapping prerequisites. See the files in the folder [build/pkgs/_bootstrap/distros](build/pkgs/_bootstrap/distros), or visit From 2e961722a5826e574795d5141ec6528dc6c5a807 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 19:02:09 -0700 Subject: [PATCH 526/591] src/doc/bootstrap: Generate *-develop.txt --- build/pkgs/_develop/dependencies | 2 +- src/doc/bootstrap | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/build/pkgs/_develop/dependencies b/build/pkgs/_develop/dependencies index 45d1294d4be..f50a34b8495 100644 --- a/build/pkgs/_develop/dependencies +++ b/build/pkgs/_develop/dependencies @@ -1 +1 @@ -git pytest pytest_xdist +_bootstrap git pytest pytest_xdist diff --git a/src/doc/bootstrap b/src/doc/bootstrap index 44c94627a53..6b44bc828d8 100755 --- a/src/doc/bootstrap +++ b/src/doc/bootstrap @@ -26,13 +26,15 @@ mkdir -p "$OUTPUT_DIR" shopt -s extglob RECOMMENDED_SPKG_PATTERN="@(_recommended$(for a in $(head -n 1 build/pkgs/_recommended/dependencies); do echo -n "|"$a; done))" +DEVELOP_SPKG_PATTERN="@(_develop$(for a in $(head -n 1 build/pkgs/_develop/dependencies); do echo -n "|"$a; done))" -for SYSTEM in arch debian fedora cygwin homebrew; do +for SYSTEM in arch debian fedora cygwin homebrew opensuse; do SYSTEM_PACKAGES= OPTIONAL_SYSTEM_PACKAGES= SAGELIB_SYSTEM_PACKAGES= SAGELIB_OPTIONAL_SYSTEM_PACKAGES= RECOMMENDED_SYSTEM_PACKAGES= + DEVELOP_SYSTEM_PACKAGES= for PKG_BASE in $(sage-package list --has-file distros/$SYSTEM.txt); do PKG_SCRIPTS=build/pkgs/$PKG_BASE SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/distros/$SYSTEM.txt @@ -44,6 +46,9 @@ for SYSTEM in arch debian fedora cygwin homebrew; do *:standard) SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; + $DEVELOP_SPKG_PATTERN:*) + DEVELOP_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" + ;; $RECOMMENDED_SPKG_PATTERN:*) RECOMMENDED_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; @@ -52,8 +57,11 @@ for SYSTEM in arch debian fedora cygwin homebrew; do ;; esac else - case "$PKG_TYPE" in - standard) + case "$PKG_BASE:$PKG_TYPE" in + $DEVELOP_SPKG_PATTERN:*) + DEVELOP_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" + ;; + *:standard) SAGELIB_SYSTEM_PACKAGES+=" $PKG_SYSTEM_PACKAGES" ;; *) @@ -70,6 +78,7 @@ for SYSTEM in arch debian fedora cygwin homebrew; do echo "$(sage-print-system-package-command $SYSTEM --prompt --sudo install $(echo $(echo $SYSTEM_PACKAGES | xargs -n 1 echo | sort | uniq)))" > "$OUTPUT_DIR"/$SYSTEM.txt echo "$(sage-print-system-package-command $SYSTEM --prompt --sudo install $(echo $(echo $OPTIONAL_SYSTEM_PACKAGES | xargs -n 1 echo | sort | uniq)))" > "$OUTPUT_DIR"/$SYSTEM-optional.txt echo "$(sage-print-system-package-command $SYSTEM --prompt --sudo install $(echo $(echo $RECOMMENDED_SYSTEM_PACKAGES | xargs -n 1 echo | sort | uniq)))" > "$OUTPUT_DIR"/$SYSTEM-recommended.txt + echo "$(sage-print-system-package-command $SYSTEM --prompt --sudo install $(echo $(echo $DEVELOP_SYSTEM_PACKAGES | xargs -n 1 echo | sort | uniq)))" > "$OUTPUT_DIR"/$SYSTEM-develop.txt done OUTPUT_DIR="src/doc/en/reference/spkg" From c96c7c5813bd70d7b2d8d51135d57cc6acba18ad Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 19:22:31 -0700 Subject: [PATCH 527/591] src/doc/en/installation/source.rst: Include *-develop.txt and *-recommended.txt --- src/doc/en/installation/source.rst | 112 +++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 30 deletions(-) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index f670cd925b9..19c1e2aa6b8 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -126,7 +126,7 @@ processor. On Linux, this means you need a recent version of Python for venv ^^^^^^^^^^^^^^^ -By default, Sage will try to use system's `python3` to set up a virtual +By default, Sage will try to use system's ``python3`` to set up a virtual environment, a.k.a. `venv `_ rather than building a Python 3 installation from scratch. Use the ``configure`` option ``--without-system-python3`` in case you want Python 3 @@ -170,6 +170,22 @@ package. On Cygwin, the ``lapack`` and ``liblapack-devel`` packages are required. +On Linux systems (e.g., Ubuntu, Redhat, etc), ``ar`` and ``ranlib`` are in the +`binutils `_ package. +The other programs are usually located in packages with their respective names. +Assuming you have sufficient privileges, you can install the ``binutils`` and +other necessary/standard components. The lists provided below are longer than +the minimal prerequisites, which are basically ``binutils``, ``gcc``/``clang``, ``make``, +``tar``, but there is no real need to build compilers and other standard tools +and libraries on a modern Linux system, in order to be able to build Sage. +If you do not have the privileges to do this, ask your system administrator to +do this, or build the components from source code. +The method of installing additional software varies from distribution to +distribution, but on a `Debian `_ based system (e.g. +`Ubuntu `_ or `Mint `_), +you would use +:wikipedia:`apt-get `. + Installing prerequisites ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -188,55 +204,83 @@ either ``perl`` is not installed, or it is installed but not in your .. _sec-installation-from-sources-linux-recommended-installation: -Linux recommended installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -On Linux systems (e.g., Ubuntu, Redhat, etc), ``ar`` and ``ranlib`` are in the -`binutils `_ package. -The other programs are usually located in packages with their respective names. -Assuming you have sufficient privileges, you can install the ``binutils`` and -other necessary/standard components. The lists provided below are longer than -the minimal prerequisites, which are basically ``binutils``, ``gcc``/``clang``, ``make``, -``tar``, but there is no real need to build compilers and other standard tools -and libraries on a modern Linux system, in order to be able to build Sage. -If you do not have the privileges to do this, ask your system administrator to -do this, or build the components from source code. -The method of installing additional software varies from distribution to -distribution, but on a `Debian `_ based system (e.g. -`Ubuntu `_ or `Mint `_), -you would use -:wikipedia:`apt-get `. +Debian/Ubuntu prerequisite installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ On Debian ("buster" or newer) or Ubuntu ("bionic" or newer): .. literalinclude:: debian.txt -On Fedora / Redhat / CentOS: +If you wish to do Sage development, additionally install the following: -.. literalinclude:: fedora.txt +.. literalinclude:: debian-develop.txt -On Arch Linux: +For all users, we recommend the following: -.. literalinclude:: arch.txt +.. literalinclude:: debian-recommended.txt In addition to these, if you don't want Sage to build optional packages that might be available from your OS, cf. the growing list of such packages on :trac:`27330`, -install on Debian ("buster" or newer) or Ubuntu ("bionic" or newer): +install: .. literalinclude:: debian-optional.txt -On Fedora / Redhat / CentOS: +Fedora/Redhat/CentOS prerequisite installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. literalinclude:: fedora.txt + +If you wish to do Sage development, additionally install the following: + +.. literalinclude:: fedora-develop.txt + +For all users, we recommend the following: + +.. literalinclude:: fedora-recommended.txt + +In addition to these, if you don't want Sage to build optional packages that might +be available from your OS, cf. the growing list of such packages on :trac:`27330`, +install: .. literalinclude:: fedora-optional.txt -On Arch Linux: +Arch Linux prerequisite installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. literalinclude:: arch.txt + +If you wish to do Sage development, additionally install the following: + +.. literalinclude:: arch-develop.txt + +For all users, we recommend the following: + +.. literalinclude:: arch-recommended.txt + +In addition to these, if you don't want Sage to build optional packages that might +be available from your OS, cf. the growing list of such packages on :trac:`27330`, +install: .. literalinclude:: arch-optional.txt -On other Linux systems, you might use -:wikipedia:`rpm `, -:wikipedia:`yum `, -or other package managers. +OpenSUSE prerequisite installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. literalinclude:: opensuse.txt + +If you wish to do Sage development, additionally install the following: + +.. literalinclude:: opensuse-develop.txt + +For all users, we recommend the following: + +.. literalinclude:: opensuse-recommended.txt + +In addition to these, if you don't want Sage to build optional packages that might +be available from your OS, cf. the growing list of such packages on :trac:`27330`, +install: + +.. literalinclude:: opensuse-optional.txt .. _section_macprereqs: @@ -302,6 +346,14 @@ Sage, run :: command like this to your shell profile if you want the settings to persist between shell sessions. +If you wish to do Sage development, additionally install the following: + +.. literalinclude:: homebrew-develop.txt + +For all users, we recommend the following: + +.. literalinclude:: homebrew-recommended.txt + Some additional optional packages are taken care of by: .. literalinclude:: homebrew-optional.txt From 2c6f7ee2dbc40bbdc599da9f4375d3533dd89b5f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 22:17:28 -0700 Subject: [PATCH 528/591] src/sage/categories/pushout.py: Fix pycodestyle --- src/sage/categories/pushout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 9e3b3144a8e..fe5e2fc9c14 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1873,7 +1873,7 @@ def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, self.latex_name_mapping = latex_name_mapping def _apply_functor(self, R): - """ + r""" Apply the functor to an object of ``self``'s domain. TESTS:: From 1ea94e13ae36f6e6b279ce81df6ae0a5f1843a0f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 22 Aug 2022 23:49:21 -0700 Subject: [PATCH 529/591] FiniteRankFreeModule.tensor_type: New --- src/sage/tensor/modules/finite_rank_free_module.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 091dc252ad5..f843168353d 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -2824,3 +2824,16 @@ def identity_map(self, name='Id', latex_name=None): latex_name = name self._identity_map.set_name(name=name, latex_name=latex_name) return self._identity_map + + def tensor_type(self): + r""" + Return the tensor type of ``self``, the pair `(1, 0)`. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3) + sage: M.tensor_type() + (1, 0) + + """ + return (1, 0) From 5e55c77d938bea28af8f86b0e4ff1169a500bd6d Mon Sep 17 00:00:00 2001 From: Amrutha P Date: Tue, 23 Aug 2022 12:30:01 +0530 Subject: [PATCH 530/591] Speed up multimajor index --- src/sage/combinat/permutation.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 9453cdb16f7..027ab25c8b5 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -3388,18 +3388,20 @@ def multi_major_index(self, composition): - [JS2000]_ """ - if self.size() == composition.size(): - D = self.descents() - s = [0] - for i, qi in enumerate(q): - maj_qp = [0] * len(s) - s.append(s[i] + qi) - for j in range(len(s)): - for d in D: - if s[j - 1] < d < s[j]: - maj_qp[j - 1] += d - s[j - 1] - return maj_qp - raise ValueError("Invalid Input") + composition = Composition(composition) + if self.size() != composition.size(): + raise ValueError("size of the composition should be equal to length of the permutation") + descents = self.descents() + partial_sum = [0] + composition.partial_sums() + multimajor_index = [] + for j in range(1, len(partial_sum)): + a = partial_sum[j-1] + b = partial_sum[j] + from bisect import bisect_right, bisect_left + start = bisect_right(descents, a) + end = bisect_left(descents, b) + multimajor_index.append(sum(descents[start: end])-(end-start)*a) + return multimajor_index def imajor_index(self, final_descent=False) -> Integer: From 0fe1f0d8747c041792fd5ae8562d9717458f1bb6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 00:09:33 -0700 Subject: [PATCH 531/591] FiniteRankFreeModule.tensor_product: New --- .../tensor/modules/finite_rank_free_module.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index f843168353d..0ddb8722e41 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -2825,6 +2825,19 @@ def identity_map(self, name='Id', latex_name=None): self._identity_map.set_name(name=name, latex_name=latex_name) return self._identity_map + def base_module(self): + r""" + Return the free module on which ``self`` is constructed, namely ``self`` itself. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M.base_module() is M + True + + """ + return self + def tensor_type(self): r""" Return the tensor type of ``self``, the pair `(1, 0)`. @@ -2837,3 +2850,27 @@ def tensor_type(self): """ return (1, 0) + + def tensor_product(self, *others): + r""" + Return the tensor product of ``self`` and ``others``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(QQ, 2) + sage: M.tensor_product(M) + Free module of type-(2,0) tensors on the 2-dimensional vector space over the Rational Field + sage: M.tensor_product(M.tensor_module(1,2)) + Free module of type-(2,2) tensors on the 2-dimensional vector space over the Rational Field + sage: M.tensor_module(1,2).tensor_product(M) + Free module of type-(2,2) tensors on the 2-dimensional vector space over the Rational Field + sage: M.tensor_module(1,1).tensor_product(M.tensor_module(1,2)) + Free module of type-(2,3) tensors on the 2-dimensional vector space over the Rational Field + + """ + from sage.modules.free_module_element import vector + base_module = self.base_module() + if not all(module.base_module() == base_module for module in others): + raise NotImplementedError('all factors must be tensor modules over the same base module') + tensor_type = sum(vector(module.tensor_type()) for module in [self] + list(others)) + return base_module.tensor_module(*tensor_type) From 3929d2e773da14c576ea0e37306ebeb342a6a4f9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 00:15:41 -0700 Subject: [PATCH 532/591] FiniteRankFreeModule.tensor_power: New --- .../tensor/modules/finite_rank_free_module.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 0ddb8722e41..3d014a4134d 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -2851,6 +2851,21 @@ def tensor_type(self): """ return (1, 0) + def tensor_power(self, n): + r""" + Return the ``n``-fold tensor product of ``self``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(QQ, 2) + sage: M.tensor_power(3) + Free module of type-(3,0) tensors on the 2-dimensional vector space over the Rational Field + sage: M.tensor_module(1,2).tensor_power(3) + Free module of type-(3,6) tensors on the 2-dimensional vector space over the Rational Field + """ + tensor_type = self.tensor_type() + return self.base_module().tensor_module(n * tensor_type[0], n * tensor_type[1]) + def tensor_product(self, *others): r""" Return the tensor product of ``self`` and ``others``. From 53cc12db10ba3deca505de659deda9ca54f71912 Mon Sep 17 00:00:00 2001 From: Shriya M <25shriya@gmail.com> Date: Tue, 23 Aug 2022 12:50:15 +0530 Subject: [PATCH 533/591] Add examples for multimajor index --- src/sage/combinat/permutation.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 027ab25c8b5..991f6d243a3 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -3377,12 +3377,19 @@ def multi_major_index(self, composition): INPUT: - - ``composition`` -- a :class:`Composition` of :meth:`size` + - ``composition`` -- a composition of :meth:`size` EXAMPLES:: - sage: Permutation([5, 6, 2, 1, 3, 7, 4]).multi_major_index(Composition([3, 2, 2])) + sage: p = Permutation([5, 6, 2, 1, 3, 7, 4]) + sage: p.multi_major_index([3, 2, 2]) [2, 0, 1] + sage: p.multi_major_index([7]) == [p.major_index()] + True + sage: p.multi_major_index([1]*7) + [0, 0, 0, 0, 0, 0, 0] + sage: Permutation([]).multi_major_index([]) + [] REFERENCES: From 1a468caa729117d650c9fd2b72ff1f947783ea6d Mon Sep 17 00:00:00 2001 From: aritra Date: Tue, 23 Aug 2022 13:03:03 +0530 Subject: [PATCH 534/591] Improve wording --- src/sage/combinat/permutation.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 991f6d243a3..c7c9cb78661 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -3397,7 +3397,7 @@ def multi_major_index(self, composition): """ composition = Composition(composition) if self.size() != composition.size(): - raise ValueError("size of the composition should be equal to length of the permutation") + raise ValueError("size of the composition should be equal to size of the permutation") descents = self.descents() partial_sum = [0] + composition.partial_sums() multimajor_index = [] @@ -3410,7 +3410,6 @@ def multi_major_index(self, composition): multimajor_index.append(sum(descents[start: end])-(end-start)*a) return multimajor_index - def imajor_index(self, final_descent=False) -> Integer: """ Return the inverse major index of the permutation ``self``, which is From 209d54f117605e63fcefb841ae9bd8b76e7d027b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 23 Aug 2022 16:07:15 +0200 Subject: [PATCH 535/591] adding one example in power series --- src/sage/rings/power_series_poly.pyx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 3f551860181..ea8fb0de813 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -1251,7 +1251,9 @@ cdef class BaseRingFloorDivAction(Action): This is meant to be a fast internal function, so the conditions on the input are not checked! - EXAMPLES:: + EXAMPLES: + + One gets the correct parent with floor division:: sage: A = ZZ[['t']] sage: f = A([3*2**n for n in range(6)]).O(6) @@ -1260,6 +1262,13 @@ cdef class BaseRingFloorDivAction(Action): sage: g.parent() Power Series Ring in t over Integer Ring + whereas the parent is larger with division:: + + sage: parent(f/3) + Power Series Ring in t over Rational Field + + Another example:: + sage: s = polygen(QQ,'s') sage: A = s.parent()[['t']] sage: f = A([(s+2)*(s+n) for n in range(5)]).O(5) From e4e834ac54d96c4fe9f90ce7b98d25b81d32ae0b Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 18:21:45 -0700 Subject: [PATCH 536/591] src/sage/categories/enumerated_sets.py: Add doc for _tuple_from_iterator, _tuple_from_list --- src/sage/categories/enumerated_sets.py | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index b9676d67511..016e04fcda2 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -522,6 +522,22 @@ def tuple(self): _tuple_default = tuple def _tuple_from_iterator(self): + r""" + Return a tuple of the elements of ``self``. + + This implementation of :meth:`tuple` creates the tuple of elements and caches it for + later uses. + + TESTS:: + + sage: R = Integers(11) + sage: R._list is None + False + sage: R._tuple_from_iterator() + (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + sage: _ is R._list + True + """ # This creates one throw-away list. self._list_from_iterator() return self._tuple_from_list() @@ -529,6 +545,17 @@ def _tuple_from_iterator(self): def _tuple_from_list(self): r""" Return a tuple of the elements of ``self``. + + This implementation of :meth:`tuple` assumes that the tuple of elements is already + cached and just returns it. + + TESTS:: + + sage: R = Integers(11) + sage: R.tuple() + (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + sage: R._tuple_from_list() is R.tuple() + True """ # Implementation classes may put any Sequence type in self._list. # Traditionally, self._list was an actual list. From fe5bb99ff815e471313ad2e36b4b2977d880bc20 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 18:59:36 -0700 Subject: [PATCH 537/591] src/sage/categories/finite_enumerated_sets.py: Add missing doctest --- src/sage/categories/finite_enumerated_sets.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index 8cdbf6e9ef3..d2fea15b3a4 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -220,6 +220,14 @@ def _unrank_from_list(self, r): def tuple(self): r""" Return a :class:`tuple`of the elements of ``self``. + + EXAMPLE:: + + sage: C = FiniteEnumeratedSets().example() + sage: C.tuple() + (1, 2, 3) + sage: C.tuple() is C.tuple() + True """ # Simpler implementation because it does not have to check whether cardinality is finite try: # shortcut From 0a0c014e4d50f104676ed25ff61f346c6711e6dc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 19:05:37 -0700 Subject: [PATCH 538/591] git grep -l 'all import' src/sage/schemes | xargs sed -i.bak 's/[.]all import Matrix$/.constructor import Matrix/' --- src/sage/schemes/elliptic_curves/constructor.py | 2 +- src/sage/schemes/elliptic_curves/ell_curve_isogeny.py | 2 +- src/sage/schemes/elliptic_curves/ell_field.py | 2 +- src/sage/schemes/elliptic_curves/ell_number_field.py | 2 +- src/sage/schemes/elliptic_curves/period_lattice.py | 4 ++-- src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx | 2 +- src/sage/schemes/hyperelliptic_curves/mestre.py | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py index 46de5dd8957..9348b30c6f5 100644 --- a/src/sage/schemes/elliptic_curves/constructor.py +++ b/src/sage/schemes/elliptic_curves/constructor.py @@ -1065,7 +1065,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): (-1/3*z : 3*x : -1/1008*x + 1/1008*y + 1/378*z) """ from sage.schemes.curves.constructor import Curve - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix from sage.schemes.elliptic_curves.weierstrass_transform import \ WeierstrassTransformationWithInverse diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index b46fe3c7bdc..07cc63a472b 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -3724,7 +3724,7 @@ def fill_isogeny_matrix(M): [ 6 3 2 18 1 9] [ 6 3 18 2 9 1] """ - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix from sage.rings.infinity import Infinity n = M.nrows() diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 5c06e94f88a..040b48426dc 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1782,7 +1782,7 @@ class of curves. If the j-invariant is not unique in the isogeny from warnings import warn from sage.graphs.graph import DiGraph, Graph - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix # warn users if things are getting big if l == 2: diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 351aab52aad..edbd1960907 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -794,7 +794,7 @@ def _scale_by_units(self): fu = K.units() c4, c6 = self.c_invariants() - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector prec = 1000 # initial value, will be increased if necessary diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 704fe7e4d0b..4824ee6bd1a 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -974,7 +974,7 @@ def basis_matrix(self, prec=None, normalised=False): [ 2.49021256085505 0.000000000000000] [0.000000000000000 -1.97173770155165] """ - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix if normalised: return Matrix([list(w) for w in self.normalised_basis(prec)]) @@ -1177,7 +1177,7 @@ def coordinates(self, z, rounding=None): except TypeError: raise TypeError("%s is not a complex number"%z) prec = C.precision() - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector if self.real_flag: w1,w2 = self.basis(prec) diff --git a/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx b/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx index 785b7812835..18ad918ac62 100644 --- a/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx +++ b/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx @@ -37,7 +37,7 @@ from libcpp.vector cimport vector from sage.libs.ntl.ntl_ZZ_pContext import ZZ_pContext_factory from sage.libs.ntl.all import ZZ, ZZX -from sage.matrix.all import Matrix +from sage.matrix.constructor import Matrix from sage.rings.all import Qp, O as big_oh from sage.arith.all import is_prime diff --git a/src/sage/schemes/hyperelliptic_curves/mestre.py b/src/sage/schemes/hyperelliptic_curves/mestre.py index eb0b1b671eb..31ba672800c 100644 --- a/src/sage/schemes/hyperelliptic_curves/mestre.py +++ b/src/sage/schemes/hyperelliptic_curves/mestre.py @@ -24,7 +24,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.matrix.all import Matrix +from sage.matrix.constructor import Matrix from sage.schemes.plane_conics.constructor import Conic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.schemes.hyperelliptic_curves.constructor import HyperellipticCurve From 0a5c6f8b04bb1580390857576c819782127d8052 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 19:07:04 -0700 Subject: [PATCH 539/591] git grep -l 'all import' src/sage/schemes | xargs sed -i.bak 's/[.]all import Rings$/.rings import Rings/' --- src/sage/schemes/generic/homset.py | 2 +- src/sage/schemes/generic/morphism.py | 2 +- src/sage/schemes/generic/scheme.py | 4 ++-- src/sage/schemes/plane_conics/con_number_field.py | 2 +- src/sage/schemes/plane_conics/con_rational_field.py | 4 ++-- src/sage/schemes/toric/homset.py | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index a1aa946614e..7e4b4e00c58 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -383,7 +383,7 @@ def _element_constructor_(self, x, check=True): return self.domain()._morphism(self, x, check=check) from sage.categories.map import Map - from sage.categories.all import Rings + from sage.categories.rings import Rings if isinstance(x, Map) and x.category_for().is_subcategory(Rings()): # x is a morphism of Rings return SchemeMorphism_spec(self, x, check=check) diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 4fdeb0e84b1..451c382c306 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -777,7 +777,7 @@ def __init__(self, parent, phi, check=True): """ SchemeMorphism.__init__(self, parent) if check: - from sage.categories.all import Rings + from sage.categories.rings import Rings if not (isinstance(phi, Map) and phi.category_for().is_subcategory(Rings())): raise TypeError("phi (=%s) must be a ring homomorphism" % phi) if phi.domain() != parent.codomain().coordinate_ring(): diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index 2793babda4a..610b75119e1 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -100,7 +100,7 @@ def __init__(self, X=None, category=None): """ from sage.schemes.generic.morphism import is_SchemeMorphism from sage.categories.map import Map - from sage.categories.all import Rings + from sage.categories.rings import Rings if X is None: self._base_ring = ZZ @@ -1212,7 +1212,7 @@ def hom(self, x, Y=None): (2, r) """ from sage.categories.map import Map - from sage.categories.all import Rings + from sage.categories.rings import Rings if is_Scheme(x): return self.Hom(x).natural_map() diff --git a/src/sage/schemes/plane_conics/con_number_field.py b/src/sage/schemes/plane_conics/con_number_field.py index 5390c77d804..4d2c55f36d9 100644 --- a/src/sage/schemes/plane_conics/con_number_field.py +++ b/src/sage/schemes/plane_conics/con_number_field.py @@ -369,7 +369,7 @@ def is_locally_solvable(self, p): if ret == -1: if self._local_obstruction is None: from sage.categories.map import Map - from sage.categories.all import Rings + from sage.categories.rings import Rings from sage.rings.qqbar import AA from sage.rings.real_lazy import RLF diff --git a/src/sage/schemes/plane_conics/con_rational_field.py b/src/sage/schemes/plane_conics/con_rational_field.py index 5c35f342c14..9a75336901f 100644 --- a/src/sage/schemes/plane_conics/con_rational_field.py +++ b/src/sage/schemes/plane_conics/con_rational_field.py @@ -190,7 +190,7 @@ def has_rational_point(self, point=False, obstruction=False, read_cache=read_cache) if point or obstruction: from sage.categories.map import Map - from sage.categories.all import Rings + from sage.categories.rings import Rings if isinstance(ret[1], Map) and ret[1].category_for().is_subcategory(Rings()): # ret[1] is a morphism of Rings ret[1] = -1 @@ -222,7 +222,7 @@ def is_locally_solvable(self, p) -> bool: True """ from sage.categories.map import Map - from sage.categories.all import Rings + from sage.categories.rings import Rings D, T = self.diagonal_matrix() abc = [D[j, j] for j in range(3)] diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py index 52a0730ddee..b5c97e10f83 100644 --- a/src/sage/schemes/toric/homset.py +++ b/src/sage/schemes/toric/homset.py @@ -250,7 +250,7 @@ def _element_constructor_(self, x, check=True): return SchemeMorphism_polynomial_toric_variety(self, x, check=check) from sage.categories.map import Map - from sage.categories.all import Rings + from sage.categories.rings import Rings if isinstance(x, Map) and x.category_for().is_subcategory(Rings()): # x is a morphism of Rings assert x.domain() is self.codomain().coordinate_ring() From a68b701415d0272d2b70645ef9756f072f8e22ba Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 19:19:08 -0700 Subject: [PATCH 540/591] src/sage/schemes: Remove some .all imports --- src/sage/schemes/affine/affine_space.py | 4 +++- src/sage/schemes/curves/affine_curve.py | 6 +++--- src/sage/schemes/curves/projective_curve.py | 7 +++---- src/sage/schemes/generic/algebraic_scheme.py | 6 ++++-- src/sage/schemes/generic/ambient_space.py | 4 +++- src/sage/schemes/generic/scheme.py | 5 +++-- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index b02ae6538fc..a4c48b334c3 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -11,7 +11,9 @@ # **************************************************************************** from sage.functions.orthogonal_polys import chebyshev_T, chebyshev_U -from sage.rings.all import (PolynomialRing, ZZ, Integer) +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import is_RationalField from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index f09cde624eb..bcdced80990 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -137,7 +137,7 @@ from sage.matrix.constructor import matrix -from sage.rings.all import degree_lowest_rational_function +from sage.rings.polynomial.multi_polynomial_element import degree_lowest_rational_function from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.qqbar import number_field_elements_from_algebraics, QQbar @@ -1675,7 +1675,7 @@ def tangent_line(self, p): if Tp.dimension() > 1: raise ValueError("the curve is not smooth at {}".format(p)) - from sage.schemes.curves.all import Curve + from sage.schemes.curves.constructor import Curve # translate to p I = [] @@ -2095,7 +2095,7 @@ def _nonsingular_model(self): y |--> z^2 z |--> z) """ - from sage.rings.function_field.all import FunctionField + from sage.rings.function_field.constructor import FunctionField k = self.base_ring() I = self.defining_ideal() diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 529721d8958..61158a4fbb5 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -139,17 +139,16 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method -from sage.categories.all import hom from sage.categories.fields import Fields +from sage.categories.homset import hom, Hom, End from sage.categories.number_fields import NumberFields -from sage.categories.homset import Hom, End from sage.interfaces.singular import singular from sage.matrix.constructor import matrix from builtins import sum as add from sage.misc.sage_eval import sage_eval -from sage.rings.all import degree_lowest_rational_function +from sage.rings.polynomial.multi_polynomial_element import degree_lowest_rational_function from sage.rings.integer_ring import IntegerRing from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -1877,7 +1876,7 @@ def rational_points_iterator(self): """ g = self.defining_polynomial() K = g.parent().base_ring() - from sage.rings.polynomial.all import PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(K,'X') X = R.gen() one = K.one() diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index f0d73d0dcd3..22dbacd8fe0 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -128,8 +128,9 @@ from sage.categories.number_fields import NumberFields -from sage.rings.all import ZZ, QQbar from sage.rings.ideal import is_Ideal +from sage.rings.integer_ring import ZZ +from sage.rings.qqbar import QQbar from sage.rings.rational_field import is_RationalField from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.rings.number_field.order import is_NumberFieldOrder @@ -142,7 +143,8 @@ from sage.calculus.functions import jacobian -from sage.arith.all import gcd, lcm +from sage.arith.functions import lcm +from sage.arith.misc import gcd import sage.schemes.affine from . import ambient_space diff --git a/src/sage/schemes/generic/ambient_space.py b/src/sage/schemes/generic/ambient_space.py index f6b5f91c686..bcf742c8b25 100644 --- a/src/sage/schemes/generic/ambient_space.py +++ b/src/sage/schemes/generic/ambient_space.py @@ -12,7 +12,9 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.all import Integer, ZZ, CommutativeRing +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.ring import CommutativeRing from sage.schemes.generic.scheme import Scheme diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index 610b75119e1..cf76b537e8b 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -21,7 +21,8 @@ from sage.structure.parent import Parent from sage.misc.cachefunc import cached_method -from sage.rings.all import (ZZ, CommutativeRing) +from sage.rings.integer_ring import ZZ +from sage.rings.ring import CommutativeRing from sage.rings.ideal import is_Ideal from sage.structure.unique_representation import UniqueRepresentation @@ -1055,7 +1056,7 @@ def _an_element_(self): Point on Spectrum of Integer Ring defined by the Principal ideal (811) of Integer Ring """ if self.coordinate_ring() is ZZ: - from sage.arith.all import random_prime + from sage.arith.misc import random_prime return self(ZZ.ideal(random_prime(1000))) return self(self.coordinate_ring().zero_ideal()) From cc5d6daf5843735baa87f6bedf8011eafa1737a3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 19:30:07 -0700 Subject: [PATCH 541/591] src/sage/schemes: Remove some more .all imports --- .../schemes/product_projective/rational_point.py | 5 +++-- src/sage/schemes/product_projective/space.py | 5 ++++- .../schemes/projective/projective_rational_point.py | 6 ++++-- src/sage/schemes/projective/projective_space.py | 13 +++++++------ src/sage/schemes/toric/fano_variety.py | 3 ++- src/sage/schemes/toric/weierstrass_covering.py | 2 +- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index fd9153da37e..b75ec0cde05 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -59,8 +59,9 @@ from sage.schemes.product_projective.space import is_ProductProjectiveSpaces from sage.misc.mrange import xmrange from sage.misc.misc_c import prod -from sage.arith.all import next_prime, previous_prime, crt -from sage.rings.all import ZZ, RR +from sage.arith.misc import next_prime, previous_prime, crt +from sage.rings.integer_ring import ZZ +from sage.rings.real_mpfr import RR from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.parallel.ncpus import ncpus from sage.parallel.use_fork import p_iter_fork diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index a7eb86ce43f..bf97be7e39e 100644 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -42,7 +42,10 @@ from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod -from sage.rings.all import (PolynomialRing, QQ, Integer, CommutativeRing) +from sage.rings.integer import Integer +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ +from sage.rings.ring import CommutativeRing from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.categories.fields import Fields from sage.rings.polynomial.polydict import ETuple diff --git a/src/sage/schemes/projective/projective_rational_point.py b/src/sage/schemes/projective/projective_rational_point.py index bc0b33e8dfb..93789be8d65 100644 --- a/src/sage/schemes/projective/projective_rational_point.py +++ b/src/sage/schemes/projective/projective_rational_point.py @@ -56,8 +56,10 @@ #***************************************************************************** -from sage.arith.all import gcd, srange, next_prime, previous_prime, crt -from sage.rings.all import ZZ, RR +from sage.arith.misc import gcd, next_prime, previous_prime, crt +from sage.arith.srange import srange +from sage.rings.integer_ring import ZZ +from sage.rings.real_mpfr import RR from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.misc.mrange import cartesian_product_iterator from sage.misc.misc_c import prod diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 90aaf8493bb..ed44ebcd6aa 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -79,16 +79,17 @@ # http://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.all import gcd, binomial, srange -from sage.rings.all import PolynomialRing +from sage.arith.misc import gcd, binomial +from sage.arith.srange import srange + +from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ - -from sage.rings.ring import CommutativeRing -from sage.rings.rational_field import is_RationalField from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing -from sage.rings.finite_rings.finite_field_constructor import is_FiniteField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.ring import CommutativeRing +from sage.rings.rational_field import is_RationalField from sage.categories.fields import Fields from sage.categories.number_fields import NumberFields diff --git a/src/sage/schemes/toric/fano_variety.py b/src/sage/schemes/toric/fano_variety.py index be1f476e395..1bf2b79ad36 100644 --- a/src/sage/schemes/toric/fano_variety.py +++ b/src/sage/schemes/toric/fano_variety.py @@ -138,7 +138,8 @@ from sage.geometry.all import Cone, FaceFan, Fan, LatticePolytope from sage.misc.latex import latex from sage.misc.misc_c import prod -from sage.rings.all import (PolynomialRing, QQ) +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.polynomial.polynomial_ring import is_PolynomialRing diff --git a/src/sage/schemes/toric/weierstrass_covering.py b/src/sage/schemes/toric/weierstrass_covering.py index 7e141ebfbd9..fe3c45ed722 100644 --- a/src/sage/schemes/toric/weierstrass_covering.py +++ b/src/sage/schemes/toric/weierstrass_covering.py @@ -106,7 +106,7 @@ from sage.rings.integer_ring import ZZ from sage.modules.free_module_element import vector -from sage.rings.all import invariant_theory +from sage.rings.invariants.invariant_theory import invariant_theory from sage.schemes.toric.weierstrass import ( _partial_discriminant, _check_polynomial_P2, From 165e6ff808463305c42be9336c7e5c5515d4e824 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 21:06:19 -0700 Subject: [PATCH 542/591] Revert "src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst: In subclassing example, import CombinatorialFreeModule" This reverts commit 96f082afafc59ba31abc6b225daf2e43b76a3c20. --- .../tutorial-implementing-algebraic-structures.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst b/src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst index b38e3647258..c319c38e7b9 100644 --- a/src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst +++ b/src/doc/en/thematic_tutorials/tutorial-implementing-algebraic-structures.rst @@ -57,7 +57,6 @@ with the simple command:: We reproduce the same, but by deriving a subclass of :class:`CombinatorialFreeModule`:: - sage: from sage.combinat.free_module import CombinatorialFreeModule sage: class MyCyclicGroupModule(CombinatorialFreeModule): ....: """An absolutely minimal implementation of a module whose basis is a cyclic group""" ....: def __init__(self, R, n, *args, **kwargs): From c95e97f5c9bd1162792e86018b1f3c4a5bf6e164 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 21:06:23 -0700 Subject: [PATCH 543/591] Revert "Update doctest outputs for new class CombinatorialFreeModule_with_construction" This reverts commit a0177f9345b3df4189b557ebf6aa583e70ccbdea. --- src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst | 2 +- src/sage/combinat/free_module.py | 2 +- src/sage/modules/with_basis/indexed_element.pyx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst index 024c347ec8a..51aec989810 100644 --- a/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst +++ b/src/doc/en/thematic_tutorials/tutorial-objects-and-classes.rst @@ -220,7 +220,7 @@ In Python, everything is an object so there isn't any difference between types and classes. One can get the class of the object ``el`` by:: sage: type(el) - + As such, this is not very informative. We'll come back to it later. The data associated to objects are stored in so-called **attributes**. They are diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index e817a3e7eac..b3f379ea6da 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -507,7 +507,7 @@ def _element_class(self): sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) sage: F._element_class - + """ return self.element_class diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 3f367acaae8..6b861a42da1 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -900,7 +900,7 @@ cdef class IndexedFreeModuleElement(ModuleElement): sage: truediv("hello", x) Traceback (most recent call last): ... - TypeError: unsupported operand type(s) for /: 'str' and 'CombinatorialFreeModule_with_construction_with_category.element_class' + TypeError: unsupported operand type(s) for /: 'str' and 'CombinatorialFreeModule_with_category.element_class' """ if not isinstance(left, IndexedFreeModuleElement): return NotImplemented From f22988f65c5ed36b0720b19cf4b02dc09653ff99 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 21:06:25 -0700 Subject: [PATCH 544/591] Revert "sage.combinat.all: Import CombinatorialFreeModule_with_construction as CombinatorialFreeModule" This reverts commit 9d4d1dcb5552be791665272996d42d67425f2314. --- src/sage/combinat/all.py | 2 +- src/sage/combinat/free_module.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index 67171e8624b..e0450a1fbe3 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -83,7 +83,7 @@ from sage.combinat.designs.all import * # Free modules and friends -from .free_module import CombinatorialFreeModule_with_construction as CombinatorialFreeModule +from .free_module import CombinatorialFreeModule from .debruijn_sequence import DeBruijnSequences from .schubert_polynomial import SchubertPolynomialRing diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index b3f379ea6da..7e66e822b41 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1177,6 +1177,7 @@ def construction(self): basis_keys=self.basis().keys()), self.base_ring() + class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): """ Tensor Product of Free Modules From 9a2c87e0f750460a70b125386689cf900af07a5a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 21:06:26 -0700 Subject: [PATCH 545/591] Revert "CombinatorialFreeModule_with_construction: Add __classcall_private__" This reverts commit e07ac34ec08515169cbaae9f202c36ddfc22686b. --- src/sage/combinat/free_module.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 7e66e822b41..87d6beaca4a 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1156,8 +1156,6 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): class CombinatorialFreeModule_with_construction(CombinatorialFreeModule): - __classcall_private__ = CombinatorialFreeModule.__classcall_private__ - def construction(self): """ The construction functor and base ring for self. From d78a002a34e91f24fe99217da990fb425632a15a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 21:06:28 -0700 Subject: [PATCH 546/591] Revert "CombinatorialFreeModule: Move method 'contruction' to subclass CombinatorialFreeModule_with_construction" This reverts commit 7897a863fbeb5548dd0e393feeac05ae17c3b0a4. --- src/sage/combinat/free_module.py | 40 ++++++++++++++------------------ src/sage/modules/free_module.py | 5 ++-- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 87d6beaca4a..c0c047edc6f 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -461,6 +461,24 @@ def __init__(self, R, basis_keys=None, element_class=None, category=None, self._order = None + def construction(self): + """ + The construction functor and base ring for self. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], category=AlgebrasWithBasis(QQ)) + sage: F.construction() + (VectorFunctor, Rational Field) + """ + # Try to take it from the category + c = super().construction() + if c is not None: + return c + from sage.categories.pushout import VectorFunctor + return VectorFunctor(None, True, None, with_basis='standard', + basis_keys=self.basis().keys()), self.base_ring() + # For backwards compatibility _repr_term = IndexedGenerators._repr_generator _latex_term = IndexedGenerators._latex_generator @@ -1154,28 +1172,6 @@ def _from_dict(self, d, coerce=False, remove_zeros=True): return self.element_class(self, d) -class CombinatorialFreeModule_with_construction(CombinatorialFreeModule): - - def construction(self): - """ - The construction functor and base ring for self. - - EXAMPLES:: - - sage: F = CombinatorialFreeModule(QQ, ['a','b','c'], category=AlgebrasWithBasis(QQ)) - sage: F.construction() - (VectorFunctor, Rational Field) - """ - # Try to take it from the category - c = super().construction() - if c is not None: - return c - from sage.categories.pushout import VectorFunctor - return VectorFunctor(None, True, None, with_basis='standard', - basis_keys=self.basis().keys()), self.base_ring() - - - class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): """ Tensor Product of Free Modules diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 824d7cdfd2e..b661c44b9a7 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -517,12 +517,11 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m else: if inner_product_matrix is not None: raise NotImplementedError - from sage.combinat.free_module import CombinatorialFreeModule_with_construction - return CombinatorialFreeModule_with_construction(base_ring, basis_keys, **args) + from sage.combinat.free_module import CombinatorialFreeModule + return CombinatorialFreeModule(base_ring, basis_keys, **args) else: raise NotImplementedError - def VectorSpace(K, dimension_or_basis_keys=None, sparse=False, inner_product_matrix=None, *, with_basis='standard', dimension=None, basis_keys=None, **args): """ From a81428a82f09fa6abf9793151700f58ea903ced2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 21:27:24 -0700 Subject: [PATCH 547/591] CombinatorialFreeModule.construction: On subclasses, return None --- src/sage/combinat/free_module.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index c0c047edc6f..f11f9b81499 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -475,6 +475,9 @@ def construction(self): c = super().construction() if c is not None: return c + if self.__class__.__base__ != CombinatorialFreeModule: + # The construction is not suitable for subclasses + return None from sage.categories.pushout import VectorFunctor return VectorFunctor(None, True, None, with_basis='standard', basis_keys=self.basis().keys()), self.base_ring() From 3f4417442c3a8e396e121b054794aa18b4d82154 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 22:05:35 -0700 Subject: [PATCH 548/591] src/sage/tensor/modules/finite_rank_free_module.py, src/sage/categories/pushout.py: Fix name mappings --- src/sage/categories/pushout.py | 38 ++++++++++++++++++- .../tensor/modules/finite_rank_free_module.py | 4 +- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index fe5e2fc9c14..ea4e3c22dcc 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1959,7 +1959,9 @@ def __eq__(self, other): return (self.n == other.n and self.inner_product_matrix == other.inner_product_matrix and self.with_basis == other.with_basis and - self.basis_keys == other.basis_keys) + self.basis_keys == other.basis_keys and + self.name_mapping == other.name_mapping and + self.latex_name_mapping == other.latex_name_mapping) return False def __ne__(self, other): @@ -2032,6 +2034,17 @@ def merge(self, other): [3 4 5] [6 7 8]' + Names are removed when they conflict:: + + sage: from sage.categories.pushout import VectorFunctor, pushout + sage: M_ZZx = FreeModule(ZZ['x'], 4, with_basis=None, name='M_ZZx') + sage: N_ZZx = FreeModule(ZZ['x'], 4, with_basis=None, name='N_ZZx') + sage: pushout(M_ZZx, QQ) + Rank-4 free module M_ZZx_base_ext over the Univariate Polynomial Ring in x over Rational Field + sage: pushout(M_ZZx, N_ZZx) + Rank-4 free module over the Univariate Polynomial Ring in x over Integer Ring + sage: pushout(pushout(M_ZZx, N_ZZx), QQ) + Rank-4 free module over the Univariate Polynomial Ring in x over Rational Field """ if not isinstance(other, VectorFunctor): return None @@ -2065,8 +2078,29 @@ def merge(self, other): else: n = self.n + name_mapping = dict() + for base_ring, name in self.name_mapping.items(): + try: + other_name = other.name_mapping[base_ring] + except KeyError: + name_mapping[base_ring] = name + else: + if name == other_name: + name_mapping[base_ring] = name + + latex_name_mapping = dict() + for base_ring, latex_name in self.latex_name_mapping.items(): + try: + other_latex_name = other.latex_name_mapping[base_ring] + except KeyError: + latex_name_mapping[base_ring] = latex_name + else: + if latex_name == other_latex_name: + latex_name_mapping[base_ring] = latex_name + return VectorFunctor(n, is_sparse, inner_product_matrix, - with_basis=with_basis, basis_keys=basis_keys) + with_basis=with_basis, basis_keys=basis_keys, + name_mapping=name_mapping, latex_name_mapping=latex_name_mapping) class SubspaceFunctor(ConstructionFunctor): diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 7102ac3d237..b2182291f5d 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -870,8 +870,8 @@ def construction(self): kwds = dict(is_sparse=False, inner_product_matrix=None, with_basis=None, - name_mapping={self.base_ring(): self._name}, - latex_name_mapping={self.base_ring(): self._latex_name}) + name_mapping={self.base_ring(): self._name} if self._name else None, + latex_name_mapping={self.base_ring(): self._latex_name} if self._latex_name else None) if self._sindex: return (VectorFunctor(basis_keys=list(self.irange()), **kwds), self.base_ring()) From 3525f0676f688f5dbc8b505d389f1c9bb0a68c4a Mon Sep 17 00:00:00 2001 From: Jonathan Kliem Date: Wed, 24 Aug 2022 07:33:57 +0200 Subject: [PATCH 549/591] add another test --- src/sage/rings/power_series_poly.pyx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index ea8fb0de813..41d32b85c3a 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -1267,6 +1267,12 @@ cdef class BaseRingFloorDivAction(Action): sage: parent(f/3) Power Series Ring in t over Rational Field + Floor division in case that the power series is not divisible by the divisor:: + + sage: f = A([2**n for n in range(6)]).O(6) + sage: g = f // 3; g + t^2 + 2*t^3 + 5*t^4 + 10*t^5 + O(t^6) + Another example:: sage: s = polygen(QQ,'s') From 9a93d1dacb6233b202b6d0adb1c5e1eacd467f89 Mon Sep 17 00:00:00 2001 From: aritra Date: Wed, 24 Aug 2022 11:12:21 +0530 Subject: [PATCH 550/591] Add doctest for multimajor index --- src/sage/combinat/permutation.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index c7c9cb78661..f6d802e2beb 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -3377,7 +3377,7 @@ def multi_major_index(self, composition): INPUT: - - ``composition`` -- a composition of :meth:`size` + - ``composition`` -- a composition of the :meth:`size` of this permutation EXAMPLES:: @@ -3391,6 +3391,13 @@ def multi_major_index(self, composition): sage: Permutation([]).multi_major_index([]) [] + TESTS:: + + sage: p.multi_major_index([1, 3, 3, 7]) + Traceback (most recent call last): + ... + ValueError: size of the composition should be equal to size of the permutation + REFERENCES: - [JS2000]_ From fe7ed4c121ca52c6f8d41e45fb1b5074208bb22c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 23 Aug 2022 22:51:36 -0700 Subject: [PATCH 551/591] src/sage/{symbolic,calculus,functions}: Remove imports from sage.rings.all --- src/sage/calculus/calculus.py | 2 +- src/sage/calculus/riemann.pyx | 2 +- src/sage/functions/bessel.py | 4 +++- src/sage/functions/gamma.py | 3 ++- src/sage/functions/generalized.py | 3 ++- src/sage/functions/orthogonal_polys.py | 2 +- src/sage/functions/other.py | 4 ++-- src/sage/functions/prime_pi.pyx | 2 +- src/sage/symbolic/callable.py | 2 +- src/sage/symbolic/expression.pyx | 17 ++++++++++++----- src/sage/symbolic/expression_conversions.py | 8 +++++--- src/sage/symbolic/function.pyx | 4 +++- src/sage/symbolic/relation.py | 9 ++++++--- src/sage/symbolic/ring.pyx | 10 ++++------ src/sage/symbolic/series_impl.pxi | 2 +- src/sage/symbolic/subring.py | 4 +++- 16 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index b1c9d1f81d7..d25775ad035 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -1140,7 +1140,7 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): raise ValueError("Could not find minimal polynomial (%s bits, degree %s)." % (bits, degree)) if algorithm is None or algorithm == 'algebraic': - from sage.rings.all import QQbar + from sage.rings.qqbar import QQbar return QQ[var](QQbar(ex).minpoly()) raise ValueError("Unknown algorithm: %s" % algorithm) diff --git a/src/sage/calculus/riemann.pyx b/src/sage/calculus/riemann.pyx index 97493b9d17c..4dc18b964f2 100644 --- a/src/sage/calculus/riemann.pyx +++ b/src/sage/calculus/riemann.pyx @@ -31,7 +31,7 @@ from sage.misc.decorators import options from sage.ext.fast_callable import fast_callable -from sage.rings.all import CDF +from sage.rings.complex_double import CDF from sage.arith.srange import srange diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index 718bd20cd52..6f460e9daa4 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -216,7 +216,9 @@ from sage.functions.trig import sin, cos from sage.libs.mpmath import utils as mpmath_utils from sage.misc.latex import latex -from sage.rings.all import Integer, ZZ, QQ +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.structure.element import get_coercion_model from sage.symbolic.constants import pi from sage.symbolic.ring import SR diff --git a/src/sage/functions/gamma.py b/src/sage/functions/gamma.py index 6e64a1683d8..e93e518b0b9 100644 --- a/src/sage/functions/gamma.py +++ b/src/sage/functions/gamma.py @@ -4,7 +4,8 @@ from sage.symbolic.function import GinacFunction, BuiltinFunction from sage.symbolic.expression import register_symbol, symbol_table from sage.structure.all import parent as s_parent -from sage.rings.all import Rational, ComplexField +from sage.rings.complex_mpfr import ComplexField +from sage.rings.rational import Rational from sage.functions.exp_integral import Ei from sage.libs.mpmath import utils as mpmath_utils from .log import exp diff --git a/src/sage/functions/generalized.py b/src/sage/functions/generalized.py index 8c3f3fcf9b9..a24268c9b6b 100644 --- a/src/sage/functions/generalized.py +++ b/src/sage/functions/generalized.py @@ -52,7 +52,8 @@ ############################################################################## from sage.symbolic.function import (BuiltinFunction, GinacFunction) -from sage.rings.all import ComplexIntervalField, ZZ +from sage.rings.complex_interval_field import ComplexIntervalField +from sage.rings.integer_ring import ZZ class FunctionDiracDelta(BuiltinFunction): diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 28f23f35ddf..a61f84649e9 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -2565,7 +2565,7 @@ def _eval_special_values_(self, n, a, x): if a == 0: return laguerre(n, x) if x == 0: - from sage.arith.all import binomial + from sage.arith.misc import binomial return binomial(n+a, n) def _pol_gen_laguerre(self, n, a, x): diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 04237301e62..1ce7569919f 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -36,7 +36,7 @@ from sage.functions.trig import arctan2 -from sage.arith.all import binomial as arith_binomial +from sage.arith.misc import binomial as arith_binomial from sage.misc.functional import sqrt @@ -220,7 +220,7 @@ def _eval_floor_ceil(self, x, method, bits=0, **kwds): # The strategy is to first reduce the absolute diameter of the # interval until its size is at most 10^(-6). Then we check for # (B) by simplifying the expression. - from sage.rings.all import RealIntervalField + from sage.rings.real_mpfi import RealIntervalField # Might it be needed to simplify x? This only applies for # elements of SR (or its subrings) diff --git a/src/sage/functions/prime_pi.pyx b/src/sage/functions/prime_pi.pyx index dc73f9593aa..0a576734777 100644 --- a/src/sage/functions/prime_pi.pyx +++ b/src/sage/functions/prime_pi.pyx @@ -192,7 +192,7 @@ cdef class PrimePi(BuiltinFunction): return plot_step_function([(xmin,0),(xmax,0)], **kwds) y = self(xmin) v = [(xmin, y)] - from sage.rings.all import prime_range + from sage.rings.fast_arith import prime_range for p in prime_range(xmin+1, xmax+1, py_ints=True): y += 1 v.append((p,y)) diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index b1411260884..4a123ec0e33 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -144,7 +144,7 @@ def __init__(self, arguments): CallableSymbolicExpressionFunctor(x, y) """ self._arguments = arguments - from sage.categories.all import Rings + from sage.categories.rings import Rings self.rank = 3 ConstructionFunctor.__init__(self, Rings(), Rings()) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index cc68b28bb90..20da68af4b9 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -376,6 +376,8 @@ More sanity tests:: from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr, ccreadstr +from copy import copy + import operator import sage.rings.integer import sage.rings.rational @@ -2548,8 +2550,9 @@ cdef class Expression(Expression_abc): sage: SR(1.2).is_algebraic() False """ + from sage.rings.qqbar import QQbar try: - ex = sage.rings.all.QQbar(self) + ex = QQbar(self) except (TypeError, ValueError, NotImplementedError): return False return True @@ -7793,7 +7796,7 @@ cdef class Expression(Expression_abc): if len(v) != 1: raise ValueError("self must be a polynomial in one variable but it is in the variables %s" % tuple([v])) f = self.polynomial(base_ring) - from sage.rings.all import PowerSeriesRing + from sage.rings.power_series_ring import PowerSeriesRing R = PowerSeriesRing(base_ring, names=f.parent().variable_names()) return R(f, f.degree()+1) @@ -11787,13 +11790,14 @@ cdef class Expression(Expression_abc): from sage.symbolic.operators import add_vararg as opadd, \ mul_vararg as opmul from sage.misc.misc_c import prod + from sage.symbolic.ring import SR def treat_term(op, term, args): - l = sage.all.copy(args) + l = copy(args) l.insert(0, term) return op(*l) - if self.parent() is not sage.all.SR: + if self.parent() is not SR: return self op = self.operator() @@ -13726,7 +13730,10 @@ cpdef new_Expression(parent, x): from sage.misc.misc_c import prod return prod([SR(p)**e for p,e in x], SR(x.unit())) elif x in Sets(): - from sage.rings.all import NN, ZZ, QQ, AA + from sage.rings.integer_ring import ZZ + from sage.rings.qqbar import AA + from sage.rings.rational_field import QQ + from sage.rings.semirings.non_negative_integer_semiring import NN from sage.sets.real_set import RealSet if (x.is_finite() or x in (NN, ZZ, QQ, AA) or isinstance(x, RealSet)): diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index c5a8240cda0..e5766522196 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -1200,7 +1200,7 @@ def arithmetic(self, ex, operator): # root is selected). try: if operator is _operator.pow: - from sage.rings.all import Rational + from sage.rings.rational import Rational base, expt = ex.operands() base = self.field(base) expt = Rational(expt) @@ -1636,7 +1636,7 @@ def __init__(self, ex, base_ring=None, ring=None): super().__init__(ex, base_ring, ring) if ring is None and base_ring is not None: - from sage.rings.all import LaurentPolynomialRing + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing self.ring = LaurentPolynomialRing(self.base_ring, names=self.varnames) @@ -1945,7 +1945,9 @@ def arithmetic(self, ex, operator): operands = ex.operands() if operator is _operator.pow: - from sage.all import Integer, Rational + from sage.rings.integer import Integer + from sage.rings.rational import Rational + base, expt = operands if expt == Rational(((1,2))): diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 10393548c88..06e626c7748 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -1060,7 +1060,9 @@ cdef class BuiltinFunction(Function): return res p = res.parent() - from sage.rings.all import ZZ, RDF, CDF + from sage.rings.complex_double import CDF + from sage.rings.integer_ring import ZZ + from sage.rings.real_double import RDF if ZZ.has_coerce_map_from(p): return int(res) elif RDF.has_coerce_map_from(p): diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 037d22a89f2..6bd6469dd22 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -572,7 +572,7 @@ def string_to_list_of_solutions(s): sage: sage.symbolic.relation.string_to_list_of_solutions(s) [x == -1/2*a - 1/2*sqrt(a^2 - 4*b), x == -1/2*a + 1/2*sqrt(a^2 - 4*b)] """ - from sage.categories.all import Objects + from sage.categories.objects import Objects from sage.structure.sequence import Sequence from sage.calculus.calculus import symbolic_expression_from_maxima_string v = symbolic_expression_from_maxima_string(s, equals_sub=True) @@ -1570,7 +1570,9 @@ def solve_mod(eqns, modulus, solution_dict=False): """ - from sage.rings.all import Integer, Integers, crt_basis + from sage.rings.finite_rings.integer_mod_ring import Integers + from sage.rings.integer import Integer + from sage.rings.integer_ring import crt_basis from sage.structure.element import Expression from sage.misc.mrange import cartesian_product_iterator from sage.modules.free_module_element import vector @@ -1686,7 +1688,8 @@ def _solve_mod_prime_power(eqns, p, m, vars): 13241296179, 19473547571, 2263241296179] """ - from sage.rings.all import Integers, PolynomialRing + from sage.rings.finite_rings.integer_mod_ring import Integers + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.modules.free_module_element import vector from sage.misc.mrange import cartesian_product_iterator diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index bd0b89f9374..2036a7331d4 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -214,11 +214,9 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing - - from sage.rings.all import (ComplexField, - RLF, CLF, - InfinityRing, - UnsignedInfinityRing) + from sage.rings.complex_mpfr import ComplexField + from sage.rings.infinity import InfinityRing, UnsignedInfinityRing + from sage.rings.real_lazy import RLF, CLF from sage.rings.finite_rings.finite_field_base import is_FiniteField from sage.interfaces.maxima import Maxima @@ -1225,7 +1223,7 @@ cdef class NumpyToSRMorphism(Morphism): from sage.rings.real_double import RDF self._intermediate_ring = RDF elif issubclass(numpy_type, numpy.complexfloating): - from sage.rings.all import CDF + from sage.rings.complex_double import CDF self._intermediate_ring = CDF else: raise TypeError("{} is not a numpy number type".format(numpy_type)) diff --git a/src/sage/symbolic/series_impl.pxi b/src/sage/symbolic/series_impl.pxi index cb68f8fe893..cc8ecfe93af 100644 --- a/src/sage/symbolic/series_impl.pxi +++ b/src/sage/symbolic/series_impl.pxi @@ -271,6 +271,6 @@ cdef class SymbolicSeries(Expression): sage: g.parent() Power Series Ring in x over Symbolic Ring """ - from sage.rings.all import PowerSeriesRing + from sage.rings.power_series_ring import PowerSeriesRing R = PowerSeriesRing(base_ring, names=str(self.default_variable())) return R(self.list(), self.degree(self.default_variable())) diff --git a/src/sage/symbolic/subring.py b/src/sage/symbolic/subring.py index 0bf7a182587..0f333c7a9d6 100644 --- a/src/sage/symbolic/subring.py +++ b/src/sage/symbolic/subring.py @@ -407,7 +407,9 @@ def _coerce_map_from_(self, P): # Workaround; can be deleted once #19231 is fixed return False - from sage.rings.all import RLF, CLF, AA, QQbar, InfinityRing + from sage.rings.infinity import InfinityRing + from sage.rings.qqbar import AA, QQbar + from sage.rings.real_lazy import RLF, CLF if isinstance(P, type): return SR._coerce_map_from_(P) From 9d3577e9667936d74f6fcecbb944ac29e92ffbc2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 24 Aug 2022 14:43:32 -0700 Subject: [PATCH 552/591] src/sage/symbolic/series_impl.pxi: Untabify --- src/sage/symbolic/series_impl.pxi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/symbolic/series_impl.pxi b/src/sage/symbolic/series_impl.pxi index cc8ecfe93af..18c017066f6 100644 --- a/src/sage/symbolic/series_impl.pxi +++ b/src/sage/symbolic/series_impl.pxi @@ -271,6 +271,6 @@ cdef class SymbolicSeries(Expression): sage: g.parent() Power Series Ring in x over Symbolic Ring """ - from sage.rings.power_series_ring import PowerSeriesRing + from sage.rings.power_series_ring import PowerSeriesRing R = PowerSeriesRing(base_ring, names=str(self.default_variable())) return R(self.list(), self.degree(self.default_variable())) From c5755d878540959d319e60236cb3e98f3e8c356d Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 24 Aug 2022 18:50:56 -0400 Subject: [PATCH 553/591] .vscode/settings.json: add pycodestyle arguments --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 25005ebbfbb..8f0070a54d9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,6 +23,7 @@ "python.testing.unittestEnabled": false, "python.linting.pycodestyleEnabled": true, "python.linting.enabled": true, + "python.linting.pycodestyleArgs": ["--select=E111,E306,E401,E701,E702,E703,W605,E711,E712,E713,E721,E722"], "cSpell.words": [ "furo", "Conda", From f76fe41aaa0e2a2d812f7f4c2fd68bae7c49b87f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 24 Aug 2022 17:39:36 -0700 Subject: [PATCH 554/591] src/sage/modular: Remove imports from sage.rings.all and .all of other namespace packages --- src/sage/modular/abvar/abvar.py | 64 +++++++------ src/sage/modular/abvar/cuspidal_subgroup.py | 9 +- src/sage/modular/abvar/finite_subgroup.py | 7 +- src/sage/modular/abvar/homology.py | 7 +- src/sage/modular/abvar/torsion_subgroup.py | 21 +++-- .../modular/arithgroup/arithgroup_generic.py | 2 +- .../modular/arithgroup/arithgroup_perm.py | 25 +++-- src/sage/modular/arithgroup/congroup_gamma.py | 13 ++- .../modular/arithgroup/congroup_gamma0.py | 33 +++---- .../modular/arithgroup/congroup_gamma1.py | 2 +- .../modular/arithgroup/congroup_gammaH.py | 3 +- .../modular/arithgroup/congroup_generic.py | 9 +- src/sage/modular/arithgroup/congroup_sl2z.py | 10 +- src/sage/modular/arithgroup/tests.py | 2 +- src/sage/modular/btquotients/btquotient.py | 42 +++++---- .../modular/btquotients/pautomorphicform.py | 31 ++++--- src/sage/modular/cusps.py | 17 ++-- src/sage/modular/cusps_nf.py | 6 +- src/sage/modular/dims.py | 13 +-- src/sage/modular/dirichlet.py | 93 ++++++++++--------- src/sage/modular/hecke/algebra.py | 3 +- src/sage/modular/hecke/module.py | 57 ++++++------ src/sage/modular/local_comp/liftings.py | 2 +- src/sage/modular/local_comp/local_comp.py | 5 +- src/sage/modular/local_comp/smoothchar.py | 28 +++--- src/sage/modular/local_comp/type_space.py | 14 ++- src/sage/modular/modform/ambient.py | 53 ++++++----- .../modular/modform/cuspidal_submodule.py | 9 +- src/sage/modular/modform/eis_series.py | 17 ++-- .../modular/modform/eis_series_cython.pyx | 2 +- .../modular/modform/eisenstein_submodule.py | 15 +-- src/sage/modular/modform/element.py | 24 +++-- src/sage/modular/modform/half_integral.py | 2 +- .../modular/modform/hecke_operator_on_qexp.py | 13 ++- .../modform/l_series_gross_zagier_coeffs.pyx | 5 +- src/sage/modular/modform/numerical.py | 6 +- src/sage/modular/modform/ring.py | 23 ++--- src/sage/modular/modform/space.py | 35 +++---- src/sage/modular/modform/theta.py | 4 +- src/sage/modular/modform/vm_basis.py | 15 ++- src/sage/modular/modform/weight1.py | 3 +- .../modform_hecketriangle/abstract_ring.py | 9 +- .../modform_hecketriangle/abstract_space.py | 24 ++--- .../modform_hecketriangle/graded_ring.py | 2 +- .../graded_ring_element.py | 22 ++--- .../hecke_triangle_groups.py | 23 +++-- .../series_constructor.py | 11 +-- src/sage/modular/modsym/ambient.py | 84 +++++++++-------- src/sage/modular/modsym/g1list.py | 3 +- src/sage/modular/modsym/hecke_operator.py | 2 +- src/sage/modular/modsym/manin_symbol.pyx | 6 +- src/sage/modular/modsym/p1list_nf.py | 2 +- src/sage/modular/modsym/relation_matrix.py | 13 ++- src/sage/modular/modsym/space.py | 30 +++--- src/sage/modular/overconvergent/genus0.py | 39 +++++--- .../modular/overconvergent/hecke_series.py | 17 ++-- .../modular/overconvergent/weightspace.py | 18 ++-- src/sage/modular/pollack_stevens/dist.pyx | 2 +- src/sage/modular/pollack_stevens/modsym.py | 19 ++-- .../modular/pollack_stevens/padic_lseries.py | 8 +- src/sage/modular/quasimodform/ring.py | 15 +-- src/sage/modular/quatalg/brandt.py | 26 +++--- src/sage/modular/ssmod/ssmod.py | 17 ++-- 63 files changed, 627 insertions(+), 509 deletions(-) diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 885b029d938..05a9c16b9a1 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -29,46 +29,53 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** + from copy import copy from random import randrange +from sage.arith.functions import lcm as LCM +from sage.arith.misc import divisors, next_prime, is_prime +from sage.categories.modular_abelian_varieties import ModularAbelianVarieties +from sage.matrix.constructor import matrix +from sage.matrix.special import block_diagonal_matrix, identity_matrix from sage.misc.lazy_import import lazy_import - -from sage.categories.all import ModularAbelianVarieties -from sage.structure.sequence import Sequence, Sequence_generic -from sage.structure.richcmp import (richcmp_method, richcmp_not_equal, - rich_to_bool) -from sage.structure.parent import Parent -from .morphism import HeckeOperator, Morphism, DegeneracyMap -from .torsion_subgroup import RationalTorsionSubgroup, QQbarTorsionSubgroup -from .finite_subgroup import (FiniteSubgroup_lattice, FiniteSubgroup, - TorsionPoint) -from .cuspidal_subgroup import (CuspidalSubgroup, RationalCuspidalSubgroup, - RationalCuspSubgroup) -from sage.rings.all import ZZ, QQ, QQbar, Integer -from sage.arith.all import LCM, divisors, prime_range, next_prime -from sage.rings.ring import is_Ring -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.infinity import infinity -from sage.modules.free_module import is_FreeModule -from sage.modular.arithgroup.all import (is_CongruenceSubgroup, is_Gamma0, - is_Gamma1, is_GammaH) -from sage.modular.modsym.all import ModularSymbols -from sage.modular.modsym.space import ModularSymbolsSpace +from sage.misc.misc_c import prod +from sage.modular.arithgroup.congroup_gamma0 import is_Gamma0 +from sage.modular.arithgroup.congroup_gamma1 import is_Gamma1 +from sage.modular.arithgroup.congroup_gammaH import is_GammaH +from sage.modular.arithgroup.congroup_generic import is_CongruenceSubgroup from sage.modular.modform.constructor import Newform -from sage.matrix.all import matrix, block_diagonal_matrix, identity_matrix +from sage.modular.modsym.modsym import ModularSymbols +from sage.modular.modsym.space import ModularSymbolsSpace +from sage.modular.quatalg.brandt import BrandtModule +from sage.modules.free_module import is_FreeModule from sage.modules.free_module_element import vector -from sage.misc.misc_c import prod -from sage.arith.misc import is_prime +from sage.rings.fast_arith import prime_range +from sage.rings.infinity import infinity +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.qqbar import QQbar +from sage.rings.rational_field import QQ +from sage.rings.ring import is_Ring from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.sets.primes import Primes - -from . import homspace -from . import lseries +from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp_method, richcmp_not_equal, rich_to_bool +from sage.structure.sequence import Sequence, Sequence_generic lazy_import('sage.databases.cremona', ['cremona_letter_code', 'CremonaDatabase']) +from . import homspace +from . import lseries +from .morphism import HeckeOperator, Morphism, DegeneracyMap +from .torsion_subgroup import RationalTorsionSubgroup, QQbarTorsionSubgroup +from .finite_subgroup import (FiniteSubgroup_lattice, FiniteSubgroup, + TorsionPoint) +from .cuspidal_subgroup import (CuspidalSubgroup, RationalCuspidalSubgroup, + RationalCuspSubgroup) + def is_ModularAbelianVariety(x) -> bool: """ @@ -4929,7 +4936,6 @@ def brandt_module(self, p): if self.level().valuation(p) != 1: raise ValueError("p must exactly divide the level") M = self.level() / p - from sage.modular.all import BrandtModule V = BrandtModule(p, M) # now cut out version of self in B S = self.modular_symbols(sign=1) diff --git a/src/sage/modular/abvar/cuspidal_subgroup.py b/src/sage/modular/abvar/cuspidal_subgroup.py index ed88939c919..a2769d7eff7 100644 --- a/src/sage/modular/abvar/cuspidal_subgroup.py +++ b/src/sage/modular/abvar/cuspidal_subgroup.py @@ -69,11 +69,14 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from .finite_subgroup import FiniteSubgroup -from sage.rings.all import infinity, QQ, ZZ -from sage.matrix.all import matrix +from sage.matrix.constructor import matrix from sage.modular.arithgroup.all import is_Gamma0 from sage.modular.cusps import Cusp +from sage.rings.infinity import infinity +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ + +from .finite_subgroup import FiniteSubgroup class CuspidalSubgroup_generic(FiniteSubgroup): diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 471386f3575..d2af5e29e00 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -103,8 +103,11 @@ from sage.structure.gens_py import abelian_iterator from sage.structure.sequence import Sequence from sage.structure.richcmp import richcmp_method, richcmp -from sage.rings.all import QQ, ZZ, QQbar, Integer -from sage.arith.all import lcm +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.qqbar import QQbar +from sage.rings.rational_field import QQ +from sage.arith.functions import lcm from sage.misc.misc_c import prod from sage.structure.element import coercion_model diff --git a/src/sage/modular/abvar/homology.py b/src/sage/modular/abvar/homology.py index 0e87e0da7c4..735bb48fb7f 100644 --- a/src/sage/modular/abvar/homology.py +++ b/src/sage/modular/abvar/homology.py @@ -50,9 +50,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.modular.hecke.module import HeckeModule_free_module +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.ring import CommutativeRing from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal -from sage.modular.hecke.all import HeckeModule_free_module -from sage.rings.all import Integer, ZZ, QQ, CommutativeRing # TODO: we will probably also need homology that is *not* a Hecke module. diff --git a/src/sage/modular/abvar/torsion_subgroup.py b/src/sage/modular/abvar/torsion_subgroup.py index affd131e1b9..b2a5c35f8b9 100644 --- a/src/sage/modular/abvar/torsion_subgroup.py +++ b/src/sage/modular/abvar/torsion_subgroup.py @@ -88,16 +88,19 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.richcmp import richcmp_method, richcmp +from sage.arith.misc import divisors, gcd +from sage.misc.misc_c import prod from sage.modular.abvar.torsion_point import TorsionPoint -from sage.modules.module import Module -from .finite_subgroup import FiniteSubgroup -from sage.rings.all import ZZ, QQ -from sage.sets.primes import Primes -from sage.modular.arithgroup.all import is_Gamma0, is_Gamma1 -from sage.all import divisors, gcd, prime_range -from sage.modular.dirichlet import DirichletGroup -from sage.misc.misc_c import prod +from sage.modular.arithgroup.all import is_Gamma0, is_Gamma1 +from sage.modular.dirichlet import DirichletGroup +from sage.modules.module import Module +from sage.rings.fast_arith import prime_range +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.sets.primes import Primes +from sage.structure.richcmp import richcmp_method, richcmp + +from .finite_subgroup import FiniteSubgroup @richcmp_method diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index 89b80dd9385..7e07c33e551 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -16,7 +16,7 @@ from sage.groups.old import Group from sage.categories.groups import Groups from sage.rings.integer_ring import ZZ -from sage.arith.all import lcm +from sage.arith.functions import lcm from sage.misc.cachefunc import cached_method from copy import copy # for making copies of lists of cusps from sage.modular.modsym.p1list import lift_to_sl2z diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index a1f16856cbe..0265f5b780a 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -98,14 +98,18 @@ # ################################################################################ +from sage.arith.functions import lcm +from sage.arith.misc import CRT_basis +from sage.groups.perm_gps.constructor import PermutationGroupElement as PermutationConstructor +from sage.groups.perm_gps.permgroup import PermutationGroup +from sage.groups.perm_gps.permgroup_element import PermutationGroupElement +from sage.misc.cachefunc import cached_method +from sage.misc.misc_c import prod +from sage.rings.integer_ring import ZZ + from .all import SL2Z from .arithgroup_generic import ArithmeticSubgroup -from sage.rings.integer_ring import ZZ -from sage.misc.cachefunc import cached_method -import sage.arith.all as arith -from sage.groups.perm_gps.permgroup_element import PermutationGroupElement -from sage.groups.perm_gps.constructor import PermutationGroupElement as PermutationConstructor Idm = SL2Z([1,0,0,1]) # identity @@ -206,8 +210,7 @@ def eval_sl2z_word(w): [ 66 -59] [ 47 -42] """ - from sage.all import prod - mat = [Lm,Rm] + mat = [Lm, Rm] w0 = Idm w1 = w return w0 * prod((mat[a[0]]**a[1] for a in w1), Idm) @@ -243,7 +246,6 @@ def word_of_perms(w, p1, p2): G = G2 p1 = G(p1) else: - from sage.groups.perm_gps.all import PermutationGroup G = PermutationGroup([p1,p2]) p1 = G(p1) p2 = G(p2) @@ -431,8 +433,6 @@ def ArithmeticSubgroup_Permutation( # Check transitivity. This is the most expensive check, so we do it # last. - from sage.groups.perm_gps.all import PermutationGroup - G = PermutationGroup(gens) if not G.is_transitive(): raise ValueError("Permutations do not generate a transitive group") @@ -676,7 +676,6 @@ def perm_group(self): sage: ap.HsuExample10().perm_group() Permutation Group with generators [(1,2)(3,4)(5,6)(7,8)(9,10), (1,8,3)(2,4,6)(5,7,10), (1,4)(2,5,9,10,8)(3,7,6), (1,7,9,10,6)(2,3)(4,5,8)] """ - from sage.groups.perm_gps.all import PermutationGroup # we set canonicalize to False as otherwise PermutationGroup changes the # order of the generators. return PermutationGroup([self.S2(), self.S3(), self.L(), self.R()], canonicalize=False) @@ -1288,7 +1287,7 @@ def generalised_level(self): sage: G.generalised_level() 3 """ - return arith.lcm(self.cusp_widths()) + return lcm(self.cusp_widths()) def congruence_closure(self): r""" @@ -1477,7 +1476,7 @@ def is_congruence(self): # e>1, m>1 onehalf = ZZ(2).inverse_mod(m) # i.e. 2^(-1) mod m onefifth = ZZ(5).inverse_mod(e) # i.e. 5^(-1) mod e - c,d = arith.CRT_basis([m, e]) + c, d = CRT_basis([m, e]) # c=0 mod e, c=1 mod m; d=1 mod e, d=0 mod m a = L**c b = R**c diff --git a/src/sage/modular/arithgroup/congroup_gamma.py b/src/sage/modular/arithgroup/congroup_gamma.py index 4625c7abc15..d6fbedbc16e 100644 --- a/src/sage/modular/arithgroup/congroup_gamma.py +++ b/src/sage/modular/arithgroup/congroup_gamma.py @@ -10,18 +10,21 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from .congroup_generic import CongruenceSubgroup -from sage.misc.misc_c import prod -from sage.rings.all import ZZ, Zmod, QQ -from sage.rings.integer import GCD_list +from sage.arith.misc import gcd from sage.groups.matrix_gps.finitely_generated import MatrixGroup from sage.matrix.constructor import matrix +from sage.misc.misc_c import prod from sage.modular.cusps import Cusp -from sage.arith.all import gcd +from sage.rings.finite_rings.integer_mod_ring import Zmod +from sage.rings.integer import GCD_list +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.structure.richcmp import richcmp_method, richcmp +from .congroup_generic import CongruenceSubgroup from .congroup_sl2z import SL2Z + _gamma_cache = {} def Gamma_constructor(N): r""" diff --git a/src/sage/modular/arithgroup/congroup_gamma0.py b/src/sage/modular/arithgroup/congroup_gamma0.py index aa404786fbc..1997f7f8cf6 100644 --- a/src/sage/modular/arithgroup/congroup_gamma0.py +++ b/src/sage/modular/arithgroup/congroup_gamma0.py @@ -10,18 +10,17 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from .congroup_gammaH import GammaH_class -from .congroup_gamma1 import is_Gamma1 -from sage.modular.modsym.p1list import lift_to_sl2z -from .congroup_generic import CongruenceSubgroup - -from sage.modular.cusps import Cusp +from sage.arith.misc import kronecker_symbol, divisors, euler_phi, gcd, moebius from sage.misc.cachefunc import cached_method -from sage.rings.all import IntegerModRing, ZZ -from sage.arith.all import kronecker_symbol from sage.misc.misc_c import prod -import sage.modular.modsym.p1list -import sage.arith.all as arith +from sage.modular.cusps import Cusp +from sage.modular.modsym.p1list import lift_to_sl2z, P1List +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.integer_ring import ZZ + +from .congroup_gamma1 import is_Gamma1 +from .congroup_gammaH import GammaH_class +from .congroup_generic import CongruenceSubgroup def is_Gamma0(x): @@ -211,7 +210,6 @@ def _list_of_elements_in_H(self): """ N = self.level() if N != 1: - gcd = arith.gcd H = [x for x in range(1, N) if gcd(x, N) == 1] else: H = [1] @@ -321,7 +319,7 @@ def coset_reps(self): if N == 1: # P1List isn't very happy working modulo 1 yield SL2Z([1,0,0,1]) else: - for z in sage.modular.modsym.p1list.P1List(N): + for z in P1List(N): yield SL2Z(lift_to_sl2z(z[0], z[1], N)) @cached_method @@ -455,8 +453,8 @@ def _find_cusps(self): N = self.level() s = [] - for d in arith.divisors(N): - w = arith.gcd(d, N//d) + for d in divisors(N): + w = gcd(d, N//d) if w == 1: if d == 1: s.append(Cusp(1,0)) @@ -466,8 +464,8 @@ def _find_cusps(self): s.append(Cusp(1,d)) else: for a in range(1, w): - if arith.gcd(a, w) == 1: - while arith.gcd(a, d//w) != 1: + if gcd(a, w) == 1: + while gcd(a, d//w) != 1: a += w s.append(Cusp(a,d)) return sorted(s) @@ -484,7 +482,7 @@ def ncusps(self): [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] """ n = self.level() - return sum([arith.euler_phi(arith.gcd(d,n//d)) for d in n.divisors()]) + return sum([euler_phi(gcd(d,n//d)) for d in n.divisors()]) def nu2(self): @@ -595,7 +593,6 @@ def dimension_new_cusp_forms(self, k=2, p=0): sage: all(Gamma0(N).dimension_new_cusp_forms(2)==100 for N in L) True """ - from sage.arith.all import moebius from sage.functions.other import floor N = self.level() diff --git a/src/sage/modular/arithgroup/congroup_gamma1.py b/src/sage/modular/arithgroup/congroup_gamma1.py index ca1bf498514..84c19cff70d 100644 --- a/src/sage/modular/arithgroup/congroup_gamma1.py +++ b/src/sage/modular/arithgroup/congroup_gamma1.py @@ -17,7 +17,7 @@ from sage.misc.misc_c import prod from .congroup_gammaH import GammaH_class, is_GammaH, GammaH_constructor from sage.rings.integer_ring import ZZ -from sage.arith.all import euler_phi as phi, moebius, divisors +from sage.arith.misc import euler_phi as phi, moebius, divisors from sage.modular.dirichlet import DirichletGroup diff --git a/src/sage/modular/arithgroup/congroup_gammaH.py b/src/sage/modular/arithgroup/congroup_gammaH.py index 8db52a92fcc..af0c27474a3 100644 --- a/src/sage/modular/arithgroup/congroup_gammaH.py +++ b/src/sage/modular/arithgroup/congroup_gammaH.py @@ -20,7 +20,8 @@ # ################################################################################ -from sage.arith.all import euler_phi, lcm, gcd, divisors, get_inverse_mod, get_gcd, factor, xgcd +from sage.arith.functions import lcm +from sage.arith.misc import euler_phi, gcd, divisors, get_inverse_mod, get_gcd, factor, xgcd from sage.modular.modsym.p1list import lift_to_sl2z from .congroup_generic import CongruenceSubgroup from sage.modular.cusps import Cusp diff --git a/src/sage/modular/arithgroup/congroup_generic.py b/src/sage/modular/arithgroup/congroup_generic.py index 2cc5335a3f9..99dbc5036fb 100644 --- a/src/sage/modular/arithgroup/congroup_generic.py +++ b/src/sage/modular/arithgroup/congroup_generic.py @@ -21,12 +21,15 @@ # ################################################################################ -from sage.rings.all import QQ, ZZ, Zmod -from sage.arith.all import gcd -from sage.sets.set import Set +from sage.arith.misc import gcd from sage.groups.matrix_gps.all import MatrixGroup from sage.matrix.matrix_space import MatrixSpace from sage.misc.misc_c import prod +from sage.rings.finite_rings.integer_mod_ring import Zmod +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.sets.set import Set + from .arithgroup_generic import ArithmeticSubgroup diff --git a/src/sage/modular/arithgroup/congroup_sl2z.py b/src/sage/modular/arithgroup/congroup_sl2z.py index 062f835517c..69a977994d0 100644 --- a/src/sage/modular/arithgroup/congroup_sl2z.py +++ b/src/sage/modular/arithgroup/congroup_sl2z.py @@ -19,12 +19,14 @@ # ################################################################################ -from .congroup_gamma0 import Gamma0_class -from .arithgroup_element import ArithmeticSubgroupElement -from sage.rings.integer_ring import ZZ +from sage.arith.misc import gcd from sage.modular.cusps import Cusp -from sage.arith.all import gcd from sage.modular.modsym.p1list import lift_to_sl2z +from sage.rings.integer_ring import ZZ + +from .congroup_gamma0 import Gamma0_class +from .arithgroup_element import ArithmeticSubgroupElement + def is_SL2Z(x): r""" diff --git a/src/sage/modular/arithgroup/tests.py b/src/sage/modular/arithgroup/tests.py index 7fae4d139a5..009f3d569e2 100644 --- a/src/sage/modular/arithgroup/tests.py +++ b/src/sage/modular/arithgroup/tests.py @@ -349,7 +349,7 @@ def test_spanning_trees(self): sage: from sage.modular.arithgroup.tests import Test sage: Test().test_spanning_trees() #random """ - from sage.all import prod + from sage.misc.misc_c import prod from .all import SL2Z from .arithgroup_perm import S2m, S3m, Lm diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 7b3fc44316c..c7564695c8a 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -41,32 +41,34 @@ from copy import copy from collections import deque -from sage.rings.integer import Integer +from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra +from sage.arith.misc import gcd, xgcd, kronecker_symbol, fundamental_discriminant +from sage.graphs.graph import Graph +from sage.interfaces.magma import magma +from sage.libs.pari.all import pari from sage.matrix.constructor import Matrix from sage.matrix.matrix_space import MatrixSpace -from sage.structure.sage_object import SageObject -from sage.rings.all import ZZ, Zmod, QQ -from sage.misc.latex import latex -from sage.rings.padics.precision_error import PrecisionError -from sage.misc.misc_c import prod -from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method -from sage.arith.all import gcd, xgcd, kronecker_symbol, fundamental_discriminant -from sage.rings.padics.all import Qp, Zp -from sage.rings.finite_rings.finite_field_constructor import GF -from sage.algebras.quatalg.all import QuaternionAlgebra -from sage.quadratic_forms.all import QuadraticForm -from sage.graphs.graph import Graph -from sage.libs.pari.all import pari -from sage.interfaces.magma import magma +from sage.misc.latex import latex +from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import lazy_import -lazy_import("sage.plot.colors", "rainbow") -from sage.rings.number_field.all import NumberField +from sage.misc.misc_c import prod +from sage.misc.verbose import verbose from sage.modular.arithgroup.all import Gamma0 -from sage.misc.lazy_attribute import lazy_attribute -from sage.modular.dirichlet import DirichletGroup from sage.modular.arithgroup.congroup_gammaH import GammaH_constructor -from sage.misc.verbose import verbose +from sage.modular.dirichlet import DirichletGroup +lazy_import("sage.plot.colors", "rainbow") +from sage.quadratic_forms.quadratic_form import QuadraticForm +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.finite_rings.integer_mod_ring import Zmod +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import NumberField +from sage.rings.padics.factory import Qp, Zp +from sage.rings.padics.precision_error import PrecisionError +from sage.rings.rational_field import QQ +from sage.structure.sage_object import SageObject +from sage.structure.unique_representation import UniqueRepresentation class DoubleCosetReduction(SageObject): diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index 540da704d3f..890cdc3cd4c 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -40,26 +40,29 @@ p-adic automorphic form of cohomological weight 0 """ -from sage.modular.btquotients.btquotient import DoubleCosetReduction -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.richcmp import op_EQ, op_NE +from copy import copy +import sage.modular.hecke.hecke_operator + +from sage.matrix.constructor import Matrix, zero_matrix from sage.matrix.matrix_space import MatrixSpace -from sage.structure.element import ModuleElement +from sage.misc.verbose import verbose +from sage.modular.btquotients.btquotient import DoubleCosetReduction +from sage.modular.hecke.all import AmbientHeckeModule, HeckeModuleElement +from sage.modular.pollack_stevens.distributions import OverconvergentDistributions, Symk +from sage.modular.pollack_stevens.sigma0 import Sigma0ActionAdjuster from sage.modules.module import Module +from sage.rings.infinity import Infinity from sage.rings.integer import Integer -from sage.matrix.constructor import Matrix, zero_matrix -from sage.rings.all import Qp, QQ, ZZ -from copy import copy -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.integer_ring import ZZ from sage.rings.laurent_series_ring import LaurentSeriesRing -from sage.modular.hecke.all import (AmbientHeckeModule, HeckeModuleElement) -from sage.rings.infinity import Infinity -import sage.modular.hecke.hecke_operator -from sage.misc.verbose import verbose +from sage.rings.padics.factory import Qp +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RR -from sage.modular.pollack_stevens.sigma0 import Sigma0ActionAdjuster -from sage.modular.pollack_stevens.distributions import OverconvergentDistributions, Symk +from sage.structure.element import ModuleElement +from sage.structure.richcmp import op_EQ, op_NE +from sage.structure.unique_representation import UniqueRepresentation # Need this to be pickleable diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index b7cd341e800..27147942a6a 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -28,17 +28,18 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import Rational, Integer, ZZ, QQ -from sage.rings.infinity import Infinity, InfinityRing - -from sage.structure.parent import Parent -from sage.misc.fast_methods import Singleton -from sage.structure.element import Element, is_InfinityElement -from sage.structure.richcmp import richcmp - from sage.libs.pari.all import pari, pari_gen +from sage.misc.fast_methods import Singleton from sage.modular.modsym.p1list import lift_to_sl2z_llong +from sage.rings.infinity import Infinity, InfinityRing +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational import Rational +from sage.rings.rational_field import QQ +from sage.structure.element import Element, is_InfinityElement from sage.structure.element import is_Matrix +from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp class Cusp(Element): diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index acfa7a5ebb7..25d93cac929 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -972,7 +972,7 @@ def is_Gamma0_equivalent(self, other, N, Transformation=False): w = ((1 - f) * Aux) / (M1[2] * M2[2]) AuxCoeff[3] = u AuxCoeff[1] = w - from sage.matrix.all import Matrix + from sage.matrix.constructor import Matrix Maux = Matrix(k, 2, AuxCoeff) M1inv = Matrix(k, 2, M1).inverse() Mtrans = Matrix(k, 2, M2) * Maux * M1inv @@ -1053,7 +1053,7 @@ def Gamma0_NFCusps(N): g = (A * B).gens_reduced()[0] # for every divisor of N we have to find cusps - from sage.arith.all import divisors + from sage.arith.misc import divisors for d in divisors(N): # find delta prime coprime to B in inverse class of d*A # by searching in our list of auxiliary prime ideals @@ -1117,7 +1117,7 @@ def number_of_Gamma0_NFCusps(N): """ k = N.number_field() # The number of Gamma0(N)-sub-orbits for each Gamma-orbit: - from sage.arith.all import divisors + from sage.arith.misc import divisors Ugens = [k(u) for u in k.unit_group().gens()] s = sum([len((d + N / d).invertible_residues_mod(Ugens)) for d in divisors(N)]) diff --git a/src/sage/modular/dims.py b/src/sage/modular/dims.py index 55d085b1e9a..f2f63b3433c 100644 --- a/src/sage/modular/dims.py +++ b/src/sage/modular/dims.py @@ -45,15 +45,16 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.all import factor, is_prime, valuation - +from sage.arith.misc import factor, is_prime, valuation from sage.misc.misc_c import prod -from sage.rings.all import Mod, Integer, IntegerModRing -from sage.rings.rational_field import frac -from . import dirichlet - from sage.modular.arithgroup.all import (Gamma0, Gamma1, is_ArithmeticSubgroup, is_GammaH) +from sage.rings.finite_rings.integer_mod import Mod +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.integer import Integer +from sage.rings.rational_field import frac + +from . import dirichlet ########################################################################## # Helper functions for calculating dimensions of spaces of modular forms diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index fd6f3c1f7cd..491664102a8 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -57,34 +57,39 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -import sage.categories.all as cat -from sage.misc.misc_c import prod import sage.misc.prandom as random -from sage.modules.free_module import FreeModule import sage.modules.free_module_element as free_module_element -import sage.rings.all as rings +import sage.rings.abc import sage.rings.number_field.number_field as number_field -from sage.libs.pari import pari +from sage.arith.functions import lcm +from sage.arith.misc import bernoulli, kronecker, factor, gcd, fundamental_discriminant, euler_phi, valuation from sage.categories.map import Map -from sage.rings.rational_field import is_RationalField -import sage.rings.abc -from sage.rings.ring import is_Ring - -from sage.misc.functional import round +from sage.categories.objects import Objects +from sage.functions.other import binomial, factorial +from sage.libs.pari import pari from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import WithEqualityById +from sage.misc.functional import round +from sage.misc.misc_c import prod +from sage.modules.free_module import FreeModule +from sage.rings.finite_rings.integer_mod import Mod +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import CyclotomicField +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import RationalField, QQ, is_RationalField +from sage.rings.ring import is_Ring from sage.structure.element import MultiplicativeGroupElement +from sage.structure.factory import UniqueFactory from sage.structure.gens_py import multiplicative_iterator from sage.structure.parent import Parent -from sage.structure.sequence import Sequence -from sage.structure.factory import UniqueFactory from sage.structure.richcmp import richcmp -from sage.arith.all import (binomial, bernoulli, kronecker, factor, gcd, - lcm, fundamental_discriminant, euler_phi, factorial, valuation) +from sage.structure.sequence import Sequence -def trivial_character(N, base_ring=rings.RationalField()): +def trivial_character(N, base_ring=RationalField()): r""" Return the trivial character of the given modulus, with values in the given base ring. @@ -126,12 +131,12 @@ def kronecker_character(d): - Jon Hanke (2006-08-06) """ - d = rings.Integer(d) + d = Integer(d) if d == 0: raise ValueError("d must be nonzero") D = fundamental_discriminant(d) - G = DirichletGroup(abs(D), rings.RationalField()) + G = DirichletGroup(abs(D), RationalField()) return G([kronecker(D, u) for u in G.unit_gens()]) @@ -149,11 +154,11 @@ def kronecker_character_upside_down(d): - Jon Hanke (2006-08-06) """ - d = rings.Integer(d) + d = Integer(d) if d <= 0: raise ValueError("d must be positive") - G = DirichletGroup(d, rings.RationalField()) + G = DirichletGroup(d, RationalField()) return G([kronecker(u.lift(), d) for u in G.unit_gens()]) @@ -709,7 +714,7 @@ def S(n): # This is better since it computes the same thing, but requires # no arith in a poly ring over a number field. prec = k + 2 - R = rings.PowerSeriesRing(rings.QQ, 't') + R = PowerSeriesRing(QQ, 't') t = R.gen() # g(t) = t/(e^{Nt}-1) g = t / ((N * t).exp(prec) - 1) @@ -789,7 +794,7 @@ def conductor(self): """ if self.modulus() == 1 or self.is_trivial(): - return rings.Integer(1) + return Integer(1) F = factor(self.modulus()) if len(F) > 1: return prod([d.conductor() for d in self.decomposition()]) @@ -803,7 +808,7 @@ def conductor(self): cond = p**(valuation(self.order(), p) + 1) if p == 2 and F[0][1] > 2 and self.values_on_gens()[1].multiplicative_order() != 1: cond *= 2 - return rings.Integer(cond) + return Integer(cond) @cached_method def fixed_field_polynomial(self, algorithm="pari"): @@ -994,7 +999,7 @@ def fixed_field_polynomial(self, algorithm="pari"): G, chi = self._pari_init_() K = pari.charker(G, chi) H = pari.galoissubcyclo(G, K) - P = PolynomialRing(rings.RationalField(), "x") + P = PolynomialRing(RationalField(), "x") x = P.gen() return H.sage({"x": x}) @@ -1352,7 +1357,7 @@ def gauss_sum(self, a=1): elif isinstance(K, sage.rings.abc.NumberField_cyclotomic) or is_RationalField(K): chi = chi.minimize_base_ring() n = lcm(m, G.zeta_order()) - L = rings.CyclotomicField(n) + L = CyclotomicField(n) zeta = L.gen(0) ** (n // m) else: raise NotImplementedError("Gauss sums only currently implemented when the base ring is a cyclotomic field, QQ, QQbar, or a complex field") @@ -1549,7 +1554,7 @@ def jacobi_sum(self, char, check=True): raise NotImplementedError("Characters must be from the same Dirichlet Group.") return sum([self(x) * char(1 - x) - for x in rings.IntegerModRing(self.modulus())]) + for x in IntegerModRing(self.modulus())]) def kloosterman_sum(self, a=1, b=0): r""" @@ -1602,7 +1607,7 @@ def kloosterman_sum(self, a=1, b=0): zo = G.zeta_order() m = G.modulus() g = 0 - L = rings.CyclotomicField(m.lcm(zo)) + L = CyclotomicField(m.lcm(zo)) zeta = L.gen(0) try: self(1) * zeta**(a + b) @@ -1612,7 +1617,7 @@ def kloosterman_sum(self, a=1, b=0): n = zeta.multiplicative_order() zeta = zeta**(n // m) for c in m.coprime_integers(m): - e = rings.Mod(c, m) + e = Mod(c, m) g += self(c) * zeta**int(a * e + b * e**(-1)) return g @@ -1657,7 +1662,7 @@ def kloosterman_sum_numerical(self, prec=53, a=1, b=0): m = G.modulus() zeta = CC.zeta(m) for c in m.coprime_integers(m): - e = rings.Mod(c, m) + e = Mod(c, m) z = zeta ** int(a * e + b * (e**(-1))) g += phi(self(c)) * z return g @@ -1836,7 +1841,7 @@ def maximize_base_ring(self): sage: DirichletGroup(20).base_ring() Cyclotomic Field of order 4 and degree 2 """ - g = rings.IntegerModRing(self.modulus()).unit_group_exponent() + g = IntegerModRing(self.modulus()).unit_group_exponent() if g == 1: g = 2 z = self.base_ring().zeta() @@ -1844,7 +1849,7 @@ def maximize_base_ring(self): m = lcm(g, n) if n == m: return self - K = rings.CyclotomicField(m) + K = CyclotomicField(m) return self.change_ring(K) def minimize_base_ring(self): @@ -1895,12 +1900,12 @@ def minimize_base_ring(self): p = R.characteristic() if p: - K = rings.IntegerModRing(p) + K = IntegerModRing(p) elif self.order() <= 2: - K = rings.QQ + K = QQ elif (isinstance(R, number_field.NumberField_generic) and euler_phi(self.order()) < R.absolute_degree()): - K = rings.CyclotomicField(self.order()) + K = CyclotomicField(self.order()) else: return self @@ -2449,15 +2454,15 @@ def create_key(self, N, base_ring=None, zeta=None, zeta_order=None, ... ValueError: modulus should be positive """ - modulus = rings.Integer(N) + modulus = Integer(N) if modulus <= 0: raise ValueError('modulus should be positive') if base_ring is None: if not (zeta is None and zeta_order is None): raise ValueError("zeta and zeta_order must be None if base_ring not specified") - e = rings.IntegerModRing(modulus).unit_group_exponent() - base_ring = rings.CyclotomicField(e) + e = IntegerModRing(modulus).unit_group_exponent() + base_ring = CyclotomicField(e) if integral: base_ring = base_ring.ring_of_integers() @@ -2473,7 +2478,7 @@ def create_key(self, N, base_ring=None, zeta=None, zeta_order=None, if not base_ring.is_integral_domain(): raise ValueError("base ring (= %s) must be an integral domain if only zeta_order is specified" % base_ring) - zeta_order = rings.Integer(zeta_order) + zeta_order = Integer(zeta_order) zeta = base_ring.zeta(zeta_order) return (base_ring, modulus, zeta, zeta_order) @@ -2560,7 +2565,7 @@ def __init__(self, base_ring, modulus, zeta, zeta_order): self._zeta = zeta self._zeta_order = zeta_order self._modulus = modulus - self._integers = rings.IntegerModRing(modulus) + self._integers = IntegerModRing(modulus) def __setstate__(self, state): """ @@ -2574,7 +2579,7 @@ def __setstate__(self, state): """ self._set_element_constructor() if '_zeta_order' in state: - state['_zeta_order'] = rings.Integer(state['_zeta_order']) + state['_zeta_order'] = Integer(state['_zeta_order']) super().__setstate__(state) @property @@ -2587,7 +2592,7 @@ def _module(self): sage: DirichletGroup(12)._module Vector space of dimension 2 over Ring of integers modulo 2 """ - return FreeModule(rings.IntegerModRing(self.zeta_order()), + return FreeModule(IntegerModRing(self.zeta_order()), len(self.unit_gens())) @property @@ -2890,7 +2895,7 @@ def decomposition(self): return Sequence([DirichletGroup(p**r, R) for p, r in factor(self.modulus())], cr=True, - universe=cat.Objects()) + universe=Objects()) def exponent(self): """ @@ -2938,13 +2943,13 @@ def _automorphisms(self): if p == 0: Auts = [e for e in range(1, n) if gcd(e, n) == 1] else: - if not rings.ZZ(p).is_prime(): + if not ZZ(p).is_prime(): raise NotImplementedError("Automorphisms for finite non-field base rings not implemented") # The automorphisms in characteristic p are # k-th powering for # k = 1, p, p^2, ..., p^(r-1), # where p^r = 1 (mod n), so r is the mult order of p modulo n. - r = rings.IntegerModRing(n)(p).multiplicative_order() + r = IntegerModRing(n)(p).multiplicative_order() Auts = [p**m for m in range(r)] return Auts @@ -3130,7 +3135,7 @@ def order(self): sage: DirichletGroup(37).order() 36 """ - ord = rings.Integer(1) + ord = Integer(1) for g in self.gens(): ord *= int(g.order()) return ord diff --git a/src/sage/modular/hecke/algebra.py b/src/sage/modular/hecke/algebra.py index 646f0ecb2cb..3699d2cb98e 100644 --- a/src/sage/modular/hecke/algebra.py +++ b/src/sage/modular/hecke/algebra.py @@ -28,7 +28,8 @@ import sage.rings.infinity from sage.matrix.constructor import matrix -from sage.arith.all import lcm, gcd +from sage.arith.functions import lcm +from sage.arith.misc import gcd from sage.misc.latex import latex from sage.matrix.matrix_space import MatrixSpace from sage.rings.ring import CommutativeAlgebra diff --git a/src/sage/modular/hecke/module.py b/src/sage/modular/hecke/module.py index 602f8f8b813..f559b6f1d3a 100644 --- a/src/sage/modular/hecke/module.py +++ b/src/sage/modular/hecke/module.py @@ -12,21 +12,22 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.all import ZZ, QQ, CommutativeRing -import sage.arith.all as arith -from sage.misc.verbose import verbose -import sage.modules.module -from sage.structure.all import Sequence -import sage.matrix.matrix_space as matrix_space - import sage.misc.prandom as random +from sage.arith.misc import is_prime, factor, prime_divisors, gcd, primes, valuation, GCD, next_prime +from sage.matrix.matrix_space import MatrixSpace +from sage.misc.verbose import verbose +from sage.modules.free_module import FreeModule +from sage.modules.module import Module +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.ring import CommutativeRing +from sage.structure.sequence import Sequence + from . import algebra from . import element from . import hecke_operator -from sage.modules.all import FreeModule - def is_HeckeModule(x): r""" @@ -45,7 +46,7 @@ def is_HeckeModule(x): return isinstance(x, HeckeModule_generic) -class HeckeModule_generic(sage.modules.module.Module): +class HeckeModule_generic(Module): r""" A very general base class for Hecke modules. @@ -84,7 +85,7 @@ def __init__(self, base_ring, level, category=None): else: assert category.is_subcategory(default_category), "%s is not a subcategory of %s" % (category, default_category) - sage.modules.module.Module.__init__(self, base_ring, category=category) + Module.__init__(self, base_ring, category=category) level = ZZ(level) if level <= 0: @@ -105,7 +106,7 @@ def __setstate__(self, state): if not self._is_category_initialized(): from sage.categories.hecke_modules import HeckeModules self._init_category_(HeckeModules(state['_base'])) - sage.modules.module.Module.__setstate__(self, state) + Module.__setstate__(self, state) def __hash__(self): r""" @@ -139,7 +140,7 @@ def _compute_hecke_matrix_prime_power(self, p, r, **kwds): """ # convert input arguments to int's. p, r = (int(p), int(r)) - if not arith.is_prime(p): + if not is_prime(p): raise ArithmeticError("p must be a prime") # T_{p^r} := T_p * T_{p^{r-1}} - eps(p)p^{k-1} T_{p^{r-2}}. pow = p**(r - 1) @@ -210,13 +211,13 @@ def _compute_hecke_matrix(self, n, **kwds): if n < 1: raise ValueError("Hecke operator T_%s is not defined." % n) if n == 1: - Mat = matrix_space.MatrixSpace(self.base_ring(), self.rank()) + Mat = MatrixSpace(self.base_ring(), self.rank()) return Mat(1) - if arith.is_prime(n): + if is_prime(n): return self._compute_hecke_matrix_prime(n, **kwds) - F = arith.factor(n) + F = factor(n) if len(F) == 1: # nontrivial prime power case return self._compute_hecke_matrix_prime_power(F[0][0], F[0][1], **kwds) @@ -389,7 +390,7 @@ def is_full_hecke_module(self): # dividing the level verbose("Determining if Hecke module is full.") N = self.level() - for p in arith.prime_divisors(N): + for p in prime_divisors(N): if not self.is_hecke_invariant(p): self._is_full_hecke_module = False return False @@ -420,7 +421,7 @@ def is_hecke_invariant(self, n): sage: [n for n in range(1,12) if S.is_hecke_invariant(n)] [1, 3, 5, 7, 9, 11] """ - if arith.gcd(n, self.level()) == 1: + if gcd(n, self.level()) == 1: return True if self.is_ambient(): return True @@ -684,7 +685,7 @@ def _is_hecke_equivariant_free_module(self, submodule): """ verbose("Determining if free module is Hecke equivariant.") bound = self.hecke_bound() - for p in arith.primes(bound + 1): + for p in primes(bound + 1): try: self.T(p).matrix().restrict(submodule, check=True) except ArithmeticError: @@ -843,8 +844,8 @@ def atkin_lehner_operator(self, d=None): raise ArithmeticError("d (=%s) must be a divisor of the level (=%s)" % (d, self.level())) N = self.level() - for p, e in arith.factor(d): - v = arith.valuation(N, p) + for p, e in factor(d): + v = valuation(N, p) if e < v: d *= p**(v - e) d = int(d) @@ -1004,8 +1005,8 @@ def decomposition(self, bound=None, anemic=True, height_guess=1, while U and p <= bound: verbose(mesg="p=%s" % p, t=time) if anemic: - while arith.GCD(p, self.level()) != 1: - p = arith.next_prime(p) + while GCD(p, self.level()) != 1: + p = next_prime(p) verbose("Decomposition using p=%s" % p) t = T.hecke_operator(p).matrix() Uprime = [] @@ -1027,7 +1028,7 @@ def decomposition(self, bound=None, anemic=True, height_guess=1, else: Uprime.append(W) # end for - p = arith.next_prime(p) + p = next_prime(p) U = Uprime # end while for i in range(len(U)): @@ -1137,7 +1138,7 @@ def dual_eigenvector(self, names='alpha', lift=True, nz=None): f = t.charpoly('x') if f.is_irreducible(): break - p = arith.next_prime(p) + p = next_prime(p) t += random.choice([-2, -1, 1, 2]) * self.dual_hecke_matrix(p) # Write down the eigenvector. @@ -1289,7 +1290,7 @@ def eigenvalue(self, n, name='alpha'): ev = self.__eigenvalues - if n == 1 or arith.is_prime(n): + if n == 1 or is_prime(n): Tn_e = self._eigen_nonzero_element(n) an = self._element_eigenvalue(Tn_e, name=name) _dict_set(ev, n, name, an) @@ -1300,7 +1301,7 @@ def eigenvalue(self, n, name='alpha'): # non-prime n and doing some big sum (i.e., computing T_n(e)). # Also by computing using the recurrence on eigenvalues # we use information about divisors. - F = arith.factor(n) + F = factor(n) prod = None for p, r in F: (p, r) = (int(p), int(r)) @@ -1443,7 +1444,7 @@ def diamond_bracket_matrix(self, d): d = int(d) % self.level() if d not in self._diamond_matrices: if self.character() is not None: - D = matrix_space.MatrixSpace(self.base_ring(), self.rank())(self.character()(d)) + D = MatrixSpace(self.base_ring(), self.rank())(self.character()(d)) else: D = self._compute_diamond_matrix(d) D.set_immutable() diff --git a/src/sage/modular/local_comp/liftings.py b/src/sage/modular/local_comp/liftings.py index e7f93896286..dbe80b59b14 100644 --- a/src/sage/modular/local_comp/liftings.py +++ b/src/sage/modular/local_comp/liftings.py @@ -7,7 +7,7 @@ """ from sage.rings.integer_ring import ZZ -from sage.arith.all import crt, inverse_mod +from sage.arith.misc import crt, inverse_mod from sage.modular.modsym.p1list import lift_to_sl2z diff --git a/src/sage/modular/local_comp/local_comp.py b/src/sage/modular/local_comp/local_comp.py index 131b5cc1a3f..693843b1afe 100644 --- a/src/sage/modular/local_comp/local_comp.py +++ b/src/sage/modular/local_comp/local_comp.py @@ -20,7 +20,10 @@ """ from sage.structure.sage_object import SageObject -from sage.rings.all import ZZ, QQbar, PolynomialRing, polygen +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.qqbar import QQbar from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.misc.verbose import verbose diff --git a/src/sage/modular/local_comp/smoothchar.py b/src/sage/modular/local_comp/smoothchar.py index c195b1aeccd..0e878b99277 100644 --- a/src/sage/modular/local_comp/smoothchar.py +++ b/src/sage/modular/local_comp/smoothchar.py @@ -40,21 +40,30 @@ sage: chi.multiplicative_order() +Infinity """ + import operator -from sage.structure.element import MultiplicativeGroupElement, parent -from sage.structure.parent import Parent -from sage.structure.sequence import Sequence -from sage.structure.richcmp import richcmp_not_equal, richcmp -from sage.rings.all import QQ, ZZ, Zmod, NumberField -from sage.misc.cachefunc import cached_method -from sage.misc.abstract_method import abstract_method -from sage.misc.misc_c import prod + +from sage.arith.functions import lcm from sage.arith.misc import crt from sage.categories.groups import Groups from sage.categories.rings import Rings +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.misc.misc_c import prod from sage.misc.mrange import xmrange from sage.misc.verbose import verbose from sage.modular.dirichlet import DirichletGroup +from sage.rings.finite_rings.conway_polynomials import conway_polynomial +from sage.rings.finite_rings.integer_mod_ring import Zmod +from sage.rings.infinity import Infinity +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import NumberField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ +from sage.structure.element import MultiplicativeGroupElement, parent +from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp_not_equal, richcmp +from sage.structure.sequence import Sequence class SmoothCharacterGeneric(MultiplicativeGroupElement): @@ -168,8 +177,6 @@ def multiplicative_order(self): sage: G.character(0, [1]).multiplicative_order() 1 """ - from sage.arith.all import lcm - from sage.rings.infinity import Infinity if self._values_on_gens[-1].multiplicative_order() == Infinity: return Infinity else: @@ -1468,7 +1475,6 @@ def number_field(self): sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ, 'c').number_field() Number Field in c with defining polynomial x^2 + x + 1 """ - from sage.rings.all import conway_polynomial, PolynomialRing fbar = conway_polynomial(self.prime(), 2) f = PolynomialRing(QQ, 'x')([a.lift() for a in fbar]) return NumberField(f, self._name) diff --git a/src/sage/modular/local_comp/type_space.py b/src/sage/modular/local_comp/type_space.py index fc2319727d7..87b3996dc04 100644 --- a/src/sage/modular/local_comp/type_space.py +++ b/src/sage/modular/local_comp/type_space.py @@ -15,19 +15,23 @@ """ import operator + +from sage.arith.misc import crt +from sage.matrix.constructor import matrix +from sage.misc.cachefunc import cached_method, cached_function from sage.modular.arithgroup.all import GammaH -from sage.modular.modform.element import Newform from sage.modular.modform.constructor import ModularForms +from sage.modular.modform.element import Newform from sage.modular.modsym.modsym import ModularSymbols -from sage.rings.all import ZZ, Zmod, QQ from sage.rings.fast_arith import prime_range -from sage.arith.all import crt +from sage.rings.finite_rings.integer_mod_ring import Zmod +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject -from sage.matrix.constructor import matrix -from sage.misc.cachefunc import cached_method, cached_function from .liftings import lift_gen_to_gamma1, lift_ramified + @cached_function def example_type_space(example_no = 0): r""" diff --git a/src/sage/modular/modform/ambient.py b/src/sage/modular/modform/ambient.py index febb0be8d37..df2bf8b66ab 100644 --- a/src/sage/modular/modform/ambient.py +++ b/src/sage/modular/modform/ambient.py @@ -68,17 +68,16 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -import sage.modular.arithgroup.all as arithgroup -import sage.modular.dirichlet as dirichlet -import sage.modular.hecke.all as hecke -import sage.modular.modsym.all as modsym -import sage.modules.free_module as free_module -import sage.rings.all as rings -from sage.arith.all import is_prime, sigma +from sage.arith.misc import is_prime, sigma from sage.matrix.constructor import matrix - -from sage.structure.sequence import Sequence from sage.misc.cachefunc import cached_method +from sage.modular.arithgroup.all import is_CongruenceSubgroup, is_Gamma0, is_Gamma1 +from sage.modular.dirichlet import TrivialCharacter +from sage.modular.hecke.ambient_module import AmbientHeckeModule +from sage.modular.modsym.modsym import ModularSymbols +from sage.modules.free_module import VectorSpace +from sage.rings.integer import Integer +from sage.structure.sequence import Sequence from . import defaults from . import eisenstein_submodule @@ -88,7 +87,7 @@ class ModularFormsAmbient(space.ModularFormsSpace, - hecke.AmbientHeckeModule): + AmbientHeckeModule): """ An ambient space of modular forms. """ @@ -103,12 +102,12 @@ def __init__(self, group, weight, base_ring, character=None, eis_only=False): sage: m.is_ambient() True """ - if not arithgroup.is_CongruenceSubgroup(group): + if not is_CongruenceSubgroup(group): raise TypeError('group (=%s) must be a congruence subgroup' % group) - weight = rings.Integer(weight) + weight = Integer(weight) - if character is None and arithgroup.is_Gamma0(group): - character = dirichlet.TrivialCharacter(group.level(), base_ring) + if character is None and is_Gamma0(group): + character = TrivialCharacter(group.level(), base_ring) self._eis_only = eis_only space.ModularFormsSpace.__init__(self, group, weight, character, base_ring) @@ -116,7 +115,7 @@ def __init__(self, group, weight, base_ring, character=None, eis_only=False): d = self._dim_eisenstein() else: d = self.dimension() - hecke.AmbientHeckeModule.__init__(self, base_ring, d, group.level(), weight) + AmbientHeckeModule.__init__(self, base_ring, d, group.level(), weight) def _repr_(self): """ @@ -302,7 +301,7 @@ def is_ambient(self): """ return True - @cached_method(key=lambda self, sign: rings.Integer(sign)) # convert sign to an Integer before looking this up in the cache + @cached_method(key=lambda self, sign: Integer(sign)) # convert sign to an Integer before looking this up in the cache def modular_symbols(self, sign=0): """ Return the corresponding space of modular symbols with the given @@ -323,8 +322,8 @@ def modular_symbols(self, sign=0): sage: ModularForms(1,12).modular_symbols() Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field """ - sign = rings.Integer(sign) - return modsym.ModularSymbols(group=self.group(), + sign = Integer(sign) + return ModularSymbols(group=self.group(), weight=self.weight(), sign=sign, base_ring=self.base_ring()) @@ -344,7 +343,7 @@ def module(self): Vector space of dimension 27 over Finite Field in b of size 7^2 """ d = self.dimension() - return free_module.VectorSpace(self.base_ring(), d) + return VectorSpace(self.base_ring(), d) # free_module -- stupid thing: there are functions in classes # ModularFormsSpace and HeckeModule that both do much the same @@ -428,7 +427,7 @@ def set_precision(self, n): """ if n < 0: raise ValueError("n (=%s) must be >= 0" % n) - self.__prec = rings.Integer(n) + self.__prec = Integer(n) #################################################################### # Computation of Special Submodules @@ -461,7 +460,7 @@ def eisenstein_submodule(self): """ return eisenstein_submodule.EisensteinSubmodule(self) - @cached_method(key=lambda self, p: (rings.Integer(p) if p is not None else p)) # convert p to an Integer before looking this up in the cache + @cached_method(key=lambda self, p: (Integer(p) if p is not None else p)) # convert p to an Integer before looking this up in the cache def new_submodule(self, p=None): """ Return the new or `p`-new submodule of this ambient @@ -512,7 +511,7 @@ def new_submodule(self, p=None): NotImplementedError """ if p is not None: - p = rings.Integer(p) + p = Integer(p) if not p.is_prime(): raise ValueError("p (=%s) must be a prime or None." % p) return self.cuspidal_submodule().new_submodule(p) + self.eisenstein_submodule().new_submodule(p) @@ -584,7 +583,7 @@ def _dim_cuspidal(self): """ if self._eis_only: return 0 - if arithgroup.is_Gamma1(self.group()) and self.character() is not None: + if is_Gamma1(self.group()) and self.character() is not None: return self.group().dimension_cusp_forms(self.weight(), self.character()) else: @@ -615,7 +614,7 @@ def _dim_eisenstein(self): sage: ModularForms(GammaH(40, [21]), 1).dimension() # indirect doctest 16 """ - if arithgroup.is_Gamma1(self.group()) and self.character() is not None: + if is_Gamma1(self.group()) and self.character() is not None: return self.group().dimension_eis(self.weight(), self.character()) else: return self.group().dimension_eis(self.weight()) @@ -637,7 +636,7 @@ def _dim_new_cuspidal(self): sage: m._dim_cuspidal() 22 """ - if arithgroup.is_Gamma1(self.group()) and self.character() is not None: + if is_Gamma1(self.group()) and self.character() is not None: return self.group().dimension_new_cusp_forms(self.weight(), self.character()) else: return self.group().dimension_new_cusp_forms(self.weight()) @@ -663,7 +662,7 @@ def _dim_new_eisenstein(self): sage: m._dim_eisenstein() 8 """ - if arithgroup.is_Gamma0(self.group()) and self.weight() == 2: + if is_Gamma0(self.group()) and self.weight() == 2: if is_prime(self.level()): d = 1 else: @@ -694,7 +693,7 @@ def eisenstein_params(self): """ eps = self.character() if eps is None: - if arithgroup.is_Gamma1(self.group()): + if is_Gamma1(self.group()): eps = self.level() else: raise NotImplementedError diff --git a/src/sage/modular/modform/cuspidal_submodule.py b/src/sage/modular/modform/cuspidal_submodule.py index decc402a839..d40af39c52e 100644 --- a/src/sage/modular/modform/cuspidal_submodule.py +++ b/src/sage/modular/modform/cuspidal_submodule.py @@ -37,10 +37,13 @@ # # http://www.gnu.org/licenses/ ######################################################################### -from sage.rings.all import QQ, Integer -from sage.misc.all import cached_method + +from sage.matrix.constructor import Matrix +from sage.matrix.special import identity_matrix +from sage.misc.cachefunc import cached_method from sage.misc.verbose import verbose -from sage.matrix.all import Matrix, identity_matrix +from sage.rings.integer import Integer +from sage.rings.rational_field import QQ from .submodule import ModularFormsSubmodule from . import vm_basis diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index e4a8e7c9592..65d43a39fda 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -12,12 +12,17 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.arith.functions import lcm +from sage.arith.misc import bernoulli, divisors, is_squarefree from sage.misc.misc import cputime -import sage.modular.dirichlet as dirichlet from sage.modular.arithgroup.congroup_gammaH import GammaH_class -from sage.rings.all import Integer, CyclotomicField, ZZ, QQ -from sage.arith.all import bernoulli, divisors, is_squarefree, lcm +from sage.modular.dirichlet import DirichletGroup +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import CyclotomicField from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import QQ + from .eis_series_cython import eisenstein_series_poly, Ek_ZZ @@ -227,7 +232,7 @@ def __find_eisen_chars(character, k): return V # Now include all pairs (chi,chi^(-1)) such that cond(chi)^2 divides N: # TODO: Optimize -- this is presumably way too hard work below. - G = dirichlet.DirichletGroup(N) + G = DirichletGroup(N) for chi in G: if not chi.is_trivial(): f = chi.conductor() @@ -298,7 +303,7 @@ def __find_eisen_chars_gammaH(N, H, k): [((1, 1), (-1, -1), 1), ((-1, 1), (1, -1), 1), ((1, -1), (-1, 1), 1), ((-1, -1), (1, 1), 1)] """ params = [] - for chi in dirichlet.DirichletGroup(N): + for chi in DirichletGroup(N): if all(chi(h) == 1 for h in H): params += __find_eisen_chars(chi, k) return params @@ -339,7 +344,7 @@ def __find_eisen_chars_gamma1(N, k): """ pairs = [] s = (-1)**k - G = dirichlet.DirichletGroup(N) + G = DirichletGroup(N) E = list(G) parity = [c(-1) for c in E] for i in range(len(E)): diff --git a/src/sage/modular/modform/eis_series_cython.pyx b/src/sage/modular/modform/eis_series_cython.pyx index 3557c6b8dc1..013ae32e62c 100644 --- a/src/sage/modular/modform/eis_series_cython.pyx +++ b/src/sage/modular/modform/eis_series_cython.pyx @@ -5,10 +5,10 @@ Eisenstein Series (optimized compiled functions) from cysignals.memory cimport check_allocarray, sig_free from cysignals.signals cimport sig_check +from sage.arith.misc import primes, bernoulli from sage.rings.rational_field import QQ from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.integer cimport Integer -from sage.arith.all import primes, bernoulli from sage.rings.fast_arith cimport prime_range from cpython.list cimport PyList_GET_ITEM diff --git a/src/sage/modular/modform/eisenstein_submodule.py b/src/sage/modular/modform/eisenstein_submodule.py index 0d606affd6d..17a5c506a81 100644 --- a/src/sage/modular/modform/eisenstein_submodule.py +++ b/src/sage/modular/modform/eisenstein_submodule.py @@ -3,13 +3,14 @@ The Eisenstein Subspace """ -from sage.structure.all import Sequence +from sage.arith.functions import lcm +from sage.arith.misc import euler_phi +from sage.categories.objects import Objects +from sage.matrix.constructor import Matrix from sage.misc.cachefunc import cached_method -import sage.rings.all as rings -from sage.categories.all import Objects -from sage.matrix.all import Matrix -from sage.rings.all import CyclotomicField -from sage.arith.all import lcm, euler_phi +from sage.rings.integer import Integer +from sage.rings.number_field.number_field import CyclotomicField +from sage.structure.sequence import Sequence from . import eis_series from . import element @@ -328,7 +329,7 @@ def _compute_q_expansion_basis(self, prec=None, new=False): if prec is None: prec = self.prec() else: - prec = rings.Integer(prec) + prec = Integer(prec) if new: E = self.new_eisenstein_series() diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 90043b2bb12..24f0bc19402 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -32,29 +32,34 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from . import defaults - -import sage.modular.hecke.element as element - -from sage.arith.all import lcm, divisors, moebius, sigma, factor, crt +from sage.arith.functions import lcm +from sage.arith.misc import divisors, moebius, sigma, factor, crt from sage.arith.srange import xsrange +from sage.combinat.integer_vector_weighted import WeightedIntegerVectors +from sage.matrix.constructor import Matrix from sage.matrix.constructor import matrix -from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method +from sage.misc.misc_c import prod from sage.misc.verbose import verbose from sage.modular.dirichlet import DirichletGroup from sage.modular.modsym.modsym import ModularSymbols from sage.modular.modsym.p1list import lift_to_sl2z from sage.modular.modsym.space import is_ModularSymbolsSpace from sage.modules.free_module_element import vector -from sage.rings.all import ZZ, QQ, Integer, RealField, ComplexField, PowerSeriesRing +from sage.rings.complex_mpfr import ComplexField from sage.rings.fast_arith import prime_range +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.rings.morphism import RingHomomorphism from sage.rings.number_field.number_field_morphisms import NumberFieldEmbedding +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RealField from sage.structure.element import coercion_model, ModuleElement, Element from sage.structure.richcmp import richcmp, op_NE, op_EQ -from sage.matrix.constructor import Matrix -from sage.combinat.integer_vector_weighted import WeightedIntegerVectors + +import sage.modular.hecke.element as element +from . import defaults def is_ModularFormElement(x): @@ -2689,7 +2694,6 @@ def twist(self, chi, level=None): """ from sage.modular.all import CuspForms, ModularForms - from sage.rings.all import PowerSeriesRing R = coercion_model.common_parent(self.base_ring(), chi.base_ring()) N = self.level() Q = chi.modulus() diff --git a/src/sage/modular/modform/half_integral.py b/src/sage/modular/modform/half_integral.py index 3bef523c33b..432b4318046 100644 --- a/src/sage/modular/modform/half_integral.py +++ b/src/sage/modular/modform/half_integral.py @@ -8,7 +8,7 @@ - William Stein (2007-08) """ -from sage.matrix.all import MatrixSpace +from sage.matrix.matrix_space import MatrixSpace from sage.modular.dirichlet import DirichletGroup from . import constructor diff --git a/src/sage/modular/modform/hecke_operator_on_qexp.py b/src/sage/modular/modform/hecke_operator_on_qexp.py index c6ab38d0905..6a61cbb46f2 100644 --- a/src/sage/modular/modform/hecke_operator_on_qexp.py +++ b/src/sage/modular/modform/hecke_operator_on_qexp.py @@ -12,13 +12,16 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.modular.dirichlet import DirichletGroup, is_DirichletCharacter -from sage.rings.all import ZZ, Integer, Infinity, CyclotomicField -from sage.arith.all import divisors, gcd - +from sage.arith.misc import divisors, gcd +from sage.matrix.constructor import matrix +from sage.matrix.matrix_space import MatrixSpace +from sage.rings.infinity import Infinity +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import CyclotomicField from sage.rings.power_series_ring_element import is_PowerSeries -from sage.matrix.all import matrix, MatrixSpace +from sage.modular.dirichlet import DirichletGroup, is_DirichletCharacter from .element import is_ModularFormElement def hecke_operator_on_qexp(f, n, k, eps = None, diff --git a/src/sage/modular/modform/l_series_gross_zagier_coeffs.pyx b/src/sage/modular/modform/l_series_gross_zagier_coeffs.pyx index 25d36c8fd52..3246146c9a0 100644 --- a/src/sage/modular/modform/l_series_gross_zagier_coeffs.pyx +++ b/src/sage/modular/modform/l_series_gross_zagier_coeffs.pyx @@ -4,8 +4,9 @@ from cysignals.signals cimport sig_check, sig_on, sig_off from sage.rings.fast_arith cimport arith_llong cdef arith_llong arith = arith_llong() -from sage.rings.all import ZZ, PowerSeriesRing -from sage.arith.all import kronecker_symbol +from sage.arith.misc import kronecker_symbol +from sage.rings.integer_ring import ZZ +from sage.rings.power_series_ring import PowerSeriesRing from libc.math cimport ceil, floor, sqrt from libc.string cimport memcpy diff --git a/src/sage/modular/modform/numerical.py b/src/sage/modular/modform/numerical.py index 7b38100be5b..1f7e8decd55 100644 --- a/src/sage/modular/modform/numerical.py +++ b/src/sage/modular/modform/numerical.py @@ -12,7 +12,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.arith.all import prime_range +from sage.rings.fast_arith import prime_range from sage.matrix.constructor import matrix from sage.misc.verbose import verbose from sage.misc.cachefunc import cached_method @@ -20,7 +20,9 @@ from sage.modular.arithgroup.all import Gamma0 from sage.modular.modsym.all import ModularSymbols from sage.modules.all import vector -from sage.rings.all import CDF, Integer, QQ +from sage.rings.complex_double import CDF +from sage.rings.integer import Integer +from sage.rings.rational_field import QQ from sage.structure.richcmp import richcmp_method, richcmp from sage.structure.sage_object import SageObject from sage.structure.sequence import Sequence diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index db1c76ab382..4c8865fd745 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -20,27 +20,28 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.richcmp import richcmp_method, richcmp -from sage.rings.all import Integer, QQ, ZZ +from random import shuffle + +from sage.categories.graded_algebras import GradedAlgebras +from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod +from sage.misc.superseded import deprecated_function_alias from sage.misc.verbose import verbose -from sage.misc.cachefunc import cached_method from sage.modular.arithgroup.all import Gamma0, is_CongruenceSubgroup -from .constructor import ModularForms -from .element import is_ModularFormElement, GradedModularFormElement -from .space import is_ModularFormsSpace -from random import shuffle - +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.term_order import TermOrder from sage.rings.power_series_poly import PowerSeries_poly - +from sage.rings.rational_field import QQ from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp_method, richcmp -from sage.categories.graded_algebras import GradedAlgebras +from .constructor import ModularForms +from .element import is_ModularFormElement, GradedModularFormElement +from .space import is_ModularFormsSpace -from sage.misc.superseded import deprecated_function_alias def _span_of_forms_in_weight(forms, weight, prec, stop_dim=None, use_random=False): r""" diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index 42ed9a9072e..5dfd3f568d8 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -57,27 +57,30 @@ # http://www.gnu.org/licenses/ ######################################################################### -from sage.structure.all import Sequence -from sage.structure.richcmp import (richcmp_method, richcmp, rich_to_bool, - richcmp_not_equal) +from sage.arith.misc import gcd +from sage.matrix.constructor import zero_matrix from sage.misc.cachefunc import cached_method import sage.modular.hecke.all as hecke import sage.modular.arithgroup.all as arithgroup import sage.modular.dirichlet as dirichlet -import sage.rings.all as rings +from sage.rings.infinity import PlusInfinity +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.power_series_ring_element import is_PowerSeries +from sage.rings.rational_field import QQ +from sage.rings.ring import Ring + +from sage.structure.all import Sequence +from sage.structure.richcmp import (richcmp_method, richcmp, rich_to_bool, + richcmp_not_equal) from .element import ModularFormElement, Newform from . import defaults from . import hecke_operator_on_qexp -from sage.matrix.constructor import zero_matrix -from sage.arith.all import gcd -from sage.rings.infinity import PlusInfinity -from sage.rings.integer import Integer - WARN=False def is_ModularFormsSpace(x): @@ -140,7 +143,7 @@ def __init__(self, group, weight, character, base_ring, category=None): weight = Integer(weight) if not ((character is None) or isinstance(character, dirichlet.DirichletCharacter)): raise TypeError("character must be a Dirichlet character") - if not isinstance(base_ring, rings.Ring): + if not isinstance(base_ring, Ring): raise TypeError("base_ring must be a ring") self.__sturm_bound = None self.__weight, self.__group, self.__character = weight, group, character @@ -399,7 +402,7 @@ def __normalize_prec(self, prec): if prec is None: prec = self.prec() else: - prec = rings.Integer(prec) + prec = Integer(prec) if prec < 0: raise ValueError("prec (=%s) must be at least 0"%prec) return prec @@ -689,7 +692,7 @@ def q_expansion_basis(self, prec=None): pass prec = -1 # big enough to determine forms else: - prec = rings.Integer(self.__normalize_prec(prec)) + prec = Integer(self.__normalize_prec(prec)) if prec == 0: z = self._q_expansion_ring()(0,prec) @@ -807,10 +810,10 @@ def q_integral_basis(self, prec=None): q - 2*q^2 - q^3 + 2*q^4 + O(q^5) ] """ - if not self.base_ring() == rings.QQ: + if not self.base_ring() == QQ: raise TypeError("the base ring must be Q") prec = self.__normalize_prec(prec) - R = rings.PowerSeriesRing(rings.ZZ, name=defaults.DEFAULT_VARIABLE) + R = PowerSeriesRing(ZZ, name=defaults.DEFAULT_VARIABLE) if prec == 0: z = R(0,prec) return Sequence([z]*int(self.dimension()), cr=True) @@ -827,7 +830,7 @@ def q_integral_basis(self, prec=None): B = self.q_expansion_basis(prec) # It's over Q; we just need to intersect it with ZZ^n. - A = rings.ZZ**prec + A = ZZ**prec gens = [f.padded_list(prec) for f in B] C = A.span(gens) D = C.saturation() @@ -849,7 +852,7 @@ def _q_expansion_ring(self): sage: M._q_expansion_ring() Power Series Ring in q over Rational Field """ - return rings.PowerSeriesRing(self.base_ring(), name=defaults.DEFAULT_VARIABLE) + return PowerSeriesRing(self.base_ring(), name=defaults.DEFAULT_VARIABLE) @cached_method def _q_expansion_zero(self): diff --git a/src/sage/modular/modform/theta.py b/src/sage/modular/modform/theta.py index e41532e2da2..9ebad5cfabc 100644 --- a/src/sage/modular/modform/theta.py +++ b/src/sage/modular/modform/theta.py @@ -5,7 +5,9 @@ William Stein """ -from sage.rings.all import Integer, ZZ, PowerSeriesRing +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.power_series_ring import PowerSeriesRing from math import sqrt diff --git a/src/sage/modular/modform/vm_basis.py b/src/sage/modular/modform/vm_basis.py index 4bd9e1921df..be690b7b503 100644 --- a/src/sage/modular/modform/vm_basis.py +++ b/src/sage/modular/modform/vm_basis.py @@ -26,16 +26,23 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** + import math -from sage.rings.all import QQ, ZZ, Integer, \ - PolynomialRing, PowerSeriesRing, O as bigO -from sage.structure.all import Sequence from sage.libs.flint.fmpz_poly import Fmpz_poly from sage.misc.verbose import verbose +from sage.rings.big_oh import O as bigO +from sage.rings.finite_rings.integer_mod_ring import Integers +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import QQ +from sage.structure.all import Sequence from .eis_series_cython import eisenstein_series_poly + def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): r""" Compute and return the Victor Miller basis for modular forms of @@ -303,8 +310,6 @@ def _delta_poly_modulo(N, prec=10): for n in range(stop+1): v[n*(n+1)//2] = ((N-1)*(2*n+1) if (n & 1) else (2*n+1)) - from sage.rings.all import Integers - P = PolynomialRing(Integers(N), 'q') f = P(v) t = verbose('made series') diff --git a/src/sage/modular/modform/weight1.py b/src/sage/modular/modform/weight1.py index 14b2fa4f85d..b7a2caa7a41 100644 --- a/src/sage/modular/modform/weight1.py +++ b/src/sage/modular/modform/weight1.py @@ -12,7 +12,8 @@ """ from sage.misc.cachefunc import cached_function -from sage.rings.all import PowerSeriesRing, ZZ +from sage.rings.integer_ring import ZZ +from sage.rings.power_series_ring import PowerSeriesRing from sage.misc.verbose import verbose from sage.structure.sequence import Sequence from sage.modular.arithgroup.all import Gamma0, GammaH diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index 52922f6a1f2..5a9b0e86258 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -16,14 +16,15 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.algebras.free_algebra import FreeAlgebra +from sage.misc.cachefunc import cached_method +from sage.rings.fraction_field import FractionField from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ -from sage.rings.all import FractionField, PolynomialRing, PowerSeriesRing -from sage.algebras.free_algebra import FreeAlgebra - from sage.structure.parent import Parent -from sage.misc.cachefunc import cached_method from .constructor import FormsRing, FormsSpace from .series_constructor import MFSeriesConstructor diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index 20455acff34..e7c59012429 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -16,20 +16,20 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.rings.infinity import infinity -from sage.rings.all import AlgebraicField, I -from sage.rings.polynomial.polynomial_ring import is_PolynomialRing -from sage.rings.power_series_ring import is_PowerSeriesRing -from sage.rings.laurent_series_ring import is_LaurentSeriesRing -from sage.modules.free_module_element import is_FreeModuleElement from sage.matrix.constructor import matrix +from sage.misc.cachefunc import cached_method +from sage.modules.free_module_element import is_FreeModuleElement from sage.modules.free_module_element import vector +from sage.rings.imaginary_unit import I +from sage.rings.infinity import infinity from sage.rings.integer import Integer -from sage.structure.all import parent - -from sage.misc.cachefunc import cached_method +from sage.rings.integer_ring import ZZ +from sage.rings.laurent_series_ring import is_LaurentSeriesRing +from sage.rings.polynomial.polynomial_ring import is_PolynomialRing +from sage.rings.power_series_ring import is_PowerSeriesRing +from sage.rings.qqbar import AlgebraicField +from sage.rings.rational_field import QQ +from sage.structure.element import parent from .abstract_ring import FormsRing_abstract @@ -2276,8 +2276,8 @@ def rationalize_series(self, laurent_series, coeff_bound = 1e-10, denom_factor = True """ - from sage.rings.all import prime_range from sage.misc.misc_c import prod + from sage.rings.fast_arith import prime_range from warnings import warn denom_factor = ZZ(denom_factor) diff --git a/src/sage/modular/modform_hecketriangle/graded_ring.py b/src/sage/modular/modform_hecketriangle/graded_ring.py index 13d00dbbef6..6da06db1b63 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring.py @@ -20,7 +20,7 @@ from sage.rings.infinity import infinity from sage.rings.ring import CommutativeAlgebra -from sage.categories.all import CommutativeAlgebras +from sage.categories.commutative_algebras import CommutativeAlgebras from sage.structure.unique_representation import UniqueRepresentation from .hecke_triangle_groups import HeckeTriangleGroup diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index 233fbc7fa75..d7b3a5094b6 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -16,23 +16,21 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.integer_ring import ZZ +from sage.functions.log import exp +from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane +from sage.misc.cachefunc import cached_method +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.modules.free_module_element import vector +from sage.rings.big_oh import O from sage.rings.infinity import infinity -from sage.rings.all import LaurentSeries, O -from sage.functions.all import exp +from sage.rings.integer_ring import ZZ +from sage.rings.laurent_series_ring_element import LaurentSeries from sage.rings.number_field.number_field import QuadraticField -from sage.symbolic.all import pi - +from sage.structure.element import CommutativeAlgebraElement from sage.structure.parent_gens import localvars from sage.structure.richcmp import op_NE, op_EQ -from sage.structure.element import CommutativeAlgebraElement from sage.structure.unique_representation import UniqueRepresentation - -from sage.modules.free_module_element import vector -from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane - -from sage.misc.cachefunc import cached_method -from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.symbolic.constants import pi from .constructor import rational_type, FormsSpace, FormsRing from .series_constructor import MFSeriesConstructor diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index f1783ed9457..c1fc60f724c 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -16,20 +16,24 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.rings.infinity import infinity -from sage.rings.all import AA, AlgebraicField, I, PolynomialRing, NumberField -from sage.functions.all import cos, exp, sec +from sage.arith.misc import divisors from sage.functions.gamma import psi1 -from sage.symbolic.all import pi +from sage.functions.log import exp +from sage.functions.trig import cos, sec +from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_generic from sage.matrix.constructor import matrix +from sage.misc.cachefunc import cached_method from sage.misc.latex import latex from sage.misc.misc_c import prod - -from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_generic +from sage.rings.imaginary_unit import I +from sage.rings.infinity import infinity +from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import NumberField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.qqbar import AA, AlgebraicField +from sage.rings.rational_field import QQ from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.cachefunc import cached_method +from sage.symbolic.constants import pi from .hecke_triangle_group_element import HeckeTriangleGroupElement, cyclic_representative, coerce_AA @@ -943,7 +947,6 @@ def _conjugacy_representatives(self, max_block_length=ZZ(0), D=None): from sage.combinat.partition import OrderedPartitions from sage.combinat.combinat import tuples - from sage.arith.all import divisors if D is not None: max_block_length = max(coerce_AA(0), coerce_AA((D + 4)/(self.lam()**2))).sqrt().floor() diff --git a/src/sage/modular/modform_hecketriangle/series_constructor.py b/src/sage/modular/modform_hecketriangle/series_constructor.py index 4181a802bbe..3b698833b2b 100644 --- a/src/sage/modular/modform_hecketriangle/series_constructor.py +++ b/src/sage/modular/modform_hecketriangle/series_constructor.py @@ -20,16 +20,15 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.arith.misc import bernoulli, sigma, rising_factorial +from sage.misc.cachefunc import cached_method +from sage.rings.big_oh import O +from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ +from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ -from sage.rings.infinity import infinity -from sage.rings.all import PowerSeriesRing -from sage.rings.big_oh import O -from sage.arith.all import bernoulli, sigma, rising_factorial - from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.cachefunc import cached_method from .hecke_triangle_groups import HeckeTriangleGroup diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 5022b0fc07e..6408405d520 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -71,23 +71,19 @@ class ``ModularSymbolsAmbient``, derived from # # https://www.gnu.org/licenses/ ################################################################################ -# Sage packages + +import sage.modular.arithgroup.all as arithgroup + +from sage.arith.misc import is_prime, divisors, number_of_divisors, crt +from sage.categories.homset import Hom +from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method -import sage.misc.latex as latex +from sage.misc.latex import latex from sage.misc.verbose import verbose - -import sage.matrix.matrix_space as matrix_space from sage.modular.arithgroup.arithgroup_element import M2Z -import sage.modules.free_module_element as free_module_element -import sage.modules.free_module as free_module -import sage.modular.arithgroup.all as arithgroup -import sage.modular.dirichlet as dirichlet -import sage.modular.hecke.all as hecke -from sage.rings.all import Integer, QQ, ZZ, Ring -from sage.arith.all import is_prime, divisors, number_of_divisors, crt -import sage.rings.polynomial.multi_polynomial_element -import sage.structure.formal_sum as formal_sum -import sage.categories.all as cat +from sage.modular.arithgroup.congroup_generic import is_CongruenceSubgroup +from sage.modular.dirichlet import TrivialCharacter, is_DirichletCharacter +from sage.modular.hecke.ambient_module import AmbientHeckeModule from sage.modular.cusps import Cusp from sage.modular.modsym.apply import apply_to_monomial from sage.modular.modsym.manin_symbol import ManinSymbol @@ -95,7 +91,15 @@ class ``ModularSymbolsAmbient``, derived from ManinSymbolList_gamma1, ManinSymbolList_gamma_h, ManinSymbolList_character) - +from sage.modules.free_module import is_FreeModule +from sage.modules.free_module_element import FreeModuleElement +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.multi_polynomial import is_MPolynomial +from sage.rings.rational_field import QQ +from sage.rings.ring import Ring +from sage.structure.factorization import Factorization +from sage.structure.formal_sum import FormalSum from . import boundary from . import element @@ -108,7 +112,7 @@ class ``ModularSymbolsAmbient``, derived from from . import subspace -class ModularSymbolsAmbient(ModularSymbolsSpace, hecke.AmbientHeckeModule): +class ModularSymbolsAmbient(ModularSymbolsSpace, AmbientHeckeModule): r""" An ambient space of modular symbols for a congruence subgroup of `SL_2(\ZZ)`. @@ -171,7 +175,7 @@ def __init__(self, group, weight, sign, base_ring, raise TypeError("base_ring must be a commutative ring") if character is None and arithgroup.is_Gamma0(group): - character = dirichlet.TrivialCharacter(group.level(), base_ring) + character = TrivialCharacter(group.level(), base_ring) ModularSymbolsSpace.__init__(self, group, weight, character, sign, base_ring, @@ -192,7 +196,7 @@ def __init__(self, group, weight, sign, base_ring, "ModularSymbolsAmbient: group = %s, weight = %s, sign = %s, base_ring = %s, character = %s"%( group, weight, sign, base_ring, character) - hecke.AmbientHeckeModule.__init__(self, base_ring, rank, group.level(), weight, category=category) + AmbientHeckeModule.__init__(self, base_ring, rank, group.level(), weight, category=category) def new_submodule(self, p=None): r""" @@ -220,7 +224,7 @@ def new_submodule(self, p=None): # If not in one of those cases, use the generic code. if self.level().is_prime() and self.weight() == 2: return self - return hecke.AmbientHeckeModule.new_submodule(self, p=p) + return AmbientHeckeModule.new_submodule(self, p=p) def manin_symbols(self): """ @@ -444,7 +448,7 @@ def _element_constructor_(self, x, computed_with_hecke=False): """ - if isinstance(x, free_module_element.FreeModuleElement): + if isinstance(x, FreeModuleElement): if x.degree() != self.dimension(): raise TypeError("Incompatible degrees: x has degree %s\ but modular symbols space has dimension %s"%( @@ -466,11 +470,11 @@ def _element_constructor_(self, x, computed_with_hecke=False): elif isinstance(x, tuple): return self.manin_symbol(x) - elif isinstance(x, formal_sum.FormalSum): + elif isinstance(x, FormalSum): return sum([c*self(y) for c, y in x], self(0)) elif isinstance(x, list): - if len(x) == 3 and sage.rings.polynomial.multi_polynomial_element.is_MPolynomial(x[0]): + if len(x) == 3 and is_MPolynomial(x[0]): return self.modular_symbol_sum(x) else: return self.modular_symbol(x) @@ -1067,7 +1071,7 @@ def __heilbronn_operator(self, M, H, t=1): """ - MS = matrix_space.MatrixSpace(self.base_ring(), self.dimension(), M.dimension()) + MS = MatrixSpace(self.base_ring(), self.dimension(), M.dimension()) hom = self.Hom(M) if self.dimension() == 0 or M.dimension() == 0: A = MS(0) @@ -1145,9 +1149,9 @@ def _latex_(self): """ return "\\mathrm{ModSym}_{%s}(%s,%s;%s)"%(self.weight(), - latex.latex(self.group()), - latex.latex(list(self.character().values_on_gens())), - latex.latex(self.base_ring())) + latex(self.group()), + latex(list(self.character().values_on_gens())), + latex(self.base_ring())) def _matrix_of_operator_on_modular_symbols(self, codomain, R): r""" @@ -1193,14 +1197,14 @@ def _matrix_of_operator_on_modular_symbols(self, codomain, R): """ rows = [] for b in self.basis(): - v = formal_sum.FormalSum(0, check=False) + v = FormalSum(0, check=False) for c, x in b.modular_symbol_rep(): for g in R: y = x.apply(g) v += y*c w = codomain(v).element() rows.append(w) - M = matrix_space.MatrixSpace(self.base_ring(), len(rows), codomain.degree(), sparse=False) + M = MatrixSpace(self.base_ring(), len(rows), codomain.degree(), sparse=False) return M(rows) def _compute_atkin_lehner_matrix(self, d): @@ -1324,7 +1328,7 @@ def boundary_map(self): # compute boundary map B = self.boundary_space() I = [B(b) for b in self.basis()] - W = matrix_space.MatrixSpace(self.base_ring(), len(I), B.rank(), sparse=True) + W = MatrixSpace(self.base_ring(), len(I), B.rank(), sparse=True) # Note -- the underlying elements have degree the number of distinct # cusps known when the element was computed. This isn't constant, @@ -1335,7 +1339,7 @@ def boundary_map(self): E = sum([ list(x) + [zero]*(n - len(x)) for x in E ], []) A = W( E ) - H = cat.Hom(self, B) + H = Hom(self, B) self.__boundary_map = H(A, "boundary map") return self.__boundary_map @@ -1800,7 +1804,7 @@ def factorization(self): r = self.dimension() s = sum(A.rank() * mult for A, mult in D) - D = sage.structure.all.Factorization(D, cr=True, sort=False) + D = Factorization(D, cr=True, sort=False) D.sort() assert r == s, "bug in factorization -- self has dimension %s, but sum of dimensions of factors is %s\n%s" % (r, s, D) self._factorization = D @@ -2144,7 +2148,7 @@ def submodule(self, M, dual_free_module=None, check=True): Stein, 2007-07-27 """ if check: - if not free_module.is_FreeModule(M): + if not is_FreeModule(M): V = self.free_module() if not isinstance(M, (list,tuple)): M = M.gens() @@ -2182,7 +2186,7 @@ def twisted_winding_element(self, i, eps): sage: M.twisted_winding_element(0,eps) 2*(1,23) - 2*(1,32) + 2*(1,34) """ - if not dirichlet.is_DirichletCharacter(eps): + if not is_DirichletCharacter(eps): raise TypeError("eps must be a Dirichlet character.") if (i < 0) or (i > self.weight() - 2): raise ValueError("i must be between 0 and k-2.") @@ -2714,7 +2718,7 @@ def _degeneracy_raising_matrix_1(self, M): # 2. The map is # [P,pi(g)] |--> sum_{h in H} [P, pi(h*g)] # - MS = matrix_space.MatrixSpace(self.base_ring(), self.dimension(), M.dimension()) + MS = MatrixSpace(self.base_ring(), self.dimension(), M.dimension()) if self.dimension() == 0 or M.dimension() == 0: return MS(0) rows = [] @@ -3322,13 +3326,13 @@ def _degeneracy_raising_matrix_1(self, M): # 2. The map is # [P,pi(g)] |--> sum_{h in H} [P, pi(h*g)] # - MS = matrix_space.MatrixSpace(self.base_ring(), self.dimension(), M.dimension()) + MS = MatrixSpace(self.base_ring(), self.dimension(), M.dimension()) if self.dimension() == 0 or M.dimension() == 0: return MS(0) rows = [] B = self.manin_basis() syms = self.manin_symbols() - G = matrix_space.MatrixSpace(ZZ, 2) + G = MatrixSpace(ZZ, 2) H = [G(h) for h in H] for n in B: z = M(0) @@ -3686,7 +3690,7 @@ def _matrix_of_operator_on_modular_symbols(self, codomain, R, character_twist=Fa eps = self.character() rows = [] for b in self.basis(): - v = formal_sum.FormalSum(0, check=False) + v = FormalSum(0, check=False) for c, x in b.modular_symbol_rep(): for g in R: y = x.apply(g) @@ -3696,7 +3700,7 @@ def _matrix_of_operator_on_modular_symbols(self, codomain, R, character_twist=Fa v += y*c w = codomain(v).element() rows.append(w) - M = matrix_space.MatrixSpace(self.base_ring(), len(rows), codomain.degree(), sparse=False) + M = MatrixSpace(self.base_ring(), len(rows), codomain.degree(), sparse=False) return M(rows) def _degeneracy_raising_matrix_1(self, M): @@ -3734,13 +3738,13 @@ def _degeneracy_raising_matrix_1(self, M): # 2. The map is # [P,pi(g)] |--> sum_{h in H} [P, pi(h*g)] # - MS = matrix_space.MatrixSpace(self.base_ring(), self.dimension(), M.dimension()) + MS = MatrixSpace(self.base_ring(), self.dimension(), M.dimension()) if self.dimension() == 0 or M.dimension() == 0: return MS(0) rows = [] B = self.manin_basis() syms = self.manin_symbols() - G = matrix_space.MatrixSpace(ZZ, 2) + G = MatrixSpace(ZZ, 2) H = [G(h) for h in H] eps = self.character() # note: in my thesis I twisted by eps^(-1), which is definitely a mistake # since twisting by eps gives the right answer and by eps^(-1) does not. diff --git a/src/sage/modular/modsym/g1list.py b/src/sage/modular/modsym/g1list.py index b1ccf4f1cf1..87e86e94814 100644 --- a/src/sage/modular/modsym/g1list.py +++ b/src/sage/modular/modsym/g1list.py @@ -18,7 +18,8 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.arith.all import GCD + +from sage.arith.misc import GCD from sage.structure.richcmp import richcmp_method, richcmp from sage.structure.sage_object import SageObject from sage.misc.persist import register_unpickle_override diff --git a/src/sage/modular/modsym/hecke_operator.py b/src/sage/modular/modsym/hecke_operator.py index 2e293c50d95..6d416eca8e3 100644 --- a/src/sage/modular/modsym/hecke_operator.py +++ b/src/sage/modular/modsym/hecke_operator.py @@ -13,7 +13,7 @@ ########################################################################## import sage.modular.hecke.hecke_operator -from sage.arith.all import is_prime +from sage.arith.misc import is_prime from . import heilbronn diff --git a/src/sage/modular/modsym/manin_symbol.pyx b/src/sage/modular/modsym/manin_symbol.pyx index 86927b91959..5d6df57c47d 100644 --- a/src/sage/modular/modsym/manin_symbol.pyx +++ b/src/sage/modular/modsym/manin_symbol.pyx @@ -20,11 +20,13 @@ factor. For general matrices (such as `T=[0,1,-1,-1]` and `T^2=[-1,-1;0,1]`) the image of a monomial Manin symbol is expressed as a formal sum of monomial Manin symbols, with integer coefficients. """ + +from sage.misc.persist import register_unpickle_override from sage.modular.cusps import Cusp -from sage.rings.all import Infinity, ZZ +from sage.rings.infinity import Infinity from sage.rings.integer cimport Integer +from sage.rings.integer_ring import ZZ from sage.structure.element cimport Element -from sage.misc.persist import register_unpickle_override from sage.structure.richcmp cimport richcmp_not_equal, richcmp diff --git a/src/sage/modular/modsym/p1list_nf.py b/src/sage/modular/modsym/p1list_nf.py index c366a15fbb6..222caacca80 100644 --- a/src/sage/modular/modsym/p1list_nf.py +++ b/src/sage/modular/modsym/p1list_nf.py @@ -997,7 +997,7 @@ def p1NFlist(N): #N.residues() = iterator through the residues mod N L = L+[MSymbol(N, k(1), r, check=False) for r in N.residues()] - from sage.arith.all import divisors + from sage.arith.misc import divisors for D in divisors(N): if not D.is_trivial() and D!=N: #we find Dp ideal coprime to N, in inverse class to D diff --git a/src/sage/modular/modsym/relation_matrix.py b/src/sage/modular/modsym/relation_matrix.py index dafb471b48f..99b3ebfd7b6 100644 --- a/src/sage/modular/modsym/relation_matrix.py +++ b/src/sage/modular/modsym/relation_matrix.py @@ -22,13 +22,13 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -import sage.matrix.matrix_space as matrix_space -from sage.rings.all import Ring +from sage.matrix.matrix_space import MatrixSpace from sage.misc.search import search -from sage.rings.rational_field import is_RationalField from sage.misc.verbose import verbose - from sage.modular.modsym.manin_symbol_list import ManinSymbolList +from sage.rings.rational_field import is_RationalField +from sage.rings.ring import Ring + SPARSE = True @@ -248,8 +248,7 @@ def T_relation_matrix_wtk_g0(syms, mod, field, sparse): entries[(row, j0)] = v[j0] row += 1 - MAT = matrix_space.MatrixSpace(field, row, - len(syms), sparse=True) + MAT = MatrixSpace(field, row, len(syms), sparse=True) R = MAT(entries) if not sparse: R = R.dense_matrix() @@ -330,7 +329,7 @@ def gens_to_basis_matrix(syms, relation_matrix, mod, field, sparse): verbose("done doing setup", tm) tm = verbose("now forming quotient matrix") - M = matrix_space.MatrixSpace(field, len(syms), len(basis), sparse=sparse) + M = MatrixSpace(field, len(syms), len(basis), sparse=sparse) B = M(0) cols_index = dict([(basis[i], i) for i in range(len(basis))]) diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index cd9ed42cf91..555a9be6aed 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -22,32 +22,32 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** + +from sage.arith.misc import divisors, next_prime from sage.categories.fields import Fields -import sage.modules.free_module as free_module -import sage.matrix.matrix_space as matrix_space -from sage.modules.free_module_element import FreeModuleElement -from sage.modules.free_module import EchelonMatrixKey +from sage.matrix.matrix_space import MatrixSpace +from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod -import sage.modular.hecke.all as hecke -from sage.arith.all import divisors, next_prime +from sage.modules.free_module import EchelonMatrixKey, FreeModule, VectorSpace +from sage.modules.free_module_element import FreeModuleElement from sage.rings.fast_arith import prime_range +from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ from sage.rings.integer import Integer from sage.rings.infinity import infinity -from sage.rings.all import PowerSeriesRing, Zmod from sage.rings.number_field.number_field_base import is_NumberField +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import QQ from sage.structure.all import Sequence, SageObject from sage.structure.richcmp import (richcmp_method, richcmp, rich_to_bool, richcmp_not_equal) from sage.modular.arithgroup.all import Gamma0, is_Gamma0 # for Sturm bound given a character +from sage.modular.hecke.module import HeckeModule_free_module from sage.modular.modsym.element import ModularSymbolsElement from . import hecke_operator -from sage.misc.cachefunc import cached_method - def is_ModularSymbolsSpace(x): r""" @@ -65,7 +65,7 @@ def is_ModularSymbolsSpace(x): @richcmp_method -class ModularSymbolsSpace(hecke.HeckeModule_free_module): +class ModularSymbolsSpace(HeckeModule_free_module): r""" Base class for spaces of modular symbols. """ @@ -86,7 +86,7 @@ def __init__(self, group, weight, character, sign, base_ring, category=None): self.__group = group self.__character = character self.__sign = sign - hecke.HeckeModule_free_module.__init__(self, base_ring, group.level(), weight, category=category) + HeckeModule_free_module.__init__(self, base_ring, group.level(), weight, category=category) def __richcmp__(self, other, op): """ @@ -1113,7 +1113,7 @@ def _q_expansion_module_integral(self, prec): [] """ V = self.q_expansion_module(prec, QQ) - return free_module.FreeModule(ZZ, V.degree()).span(V.basis()).saturation() + return FreeModule(ZZ, V.degree()).span(V.basis()).saturation() def congruence_number(self, other, prec=None): r""" @@ -1382,8 +1382,8 @@ def _q_expansion_basis_hecke_dual(self, prec): d = prec - 1 K = self.base_ring() - A = free_module.VectorSpace(K, prec - 1) - M = matrix_space.MatrixSpace(K, prec - 1, self.dimension()) + A = VectorSpace(K, prec - 1) + M = MatrixSpace(K, prec - 1, self.dimension()) V = A.zero_submodule() i = self.dimension() - 1 diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index 341cc835b6f..0e30f40d23b 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -168,25 +168,38 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.matrix.all import matrix, MatrixSpace, diagonal_matrix -from sage.misc.verbose import verbose -from sage.misc.cachefunc import cached_method -from sage.modular.all import (trivial_character, EtaProduct, - j_invariant_qexp, hecke_operator_on_qexp) + +import weakref + +import sage.rings.abc + +from sage.matrix.constructor import matrix +from sage.matrix.matrix_space import MatrixSpace +from sage.matrix.special import diagonal_matrix +from sage.misc.cachefunc import cached_method +from sage.misc.verbose import verbose from sage.modular.arithgroup.all import is_Gamma0, is_Gamma1 +from sage.modular.dirichlet import trivial_character +from sage.modular.etaproducts import EtaProduct from sage.modular.modform.element import ModularFormElement -from sage.modules.all import vector -from sage.modules.module import Module -from sage.structure.element import Vector, ModuleElement -from sage.structure.richcmp import richcmp -from sage.plot.plot import plot +from sage.modular.modform.hecke_operator_on_qexp import hecke_operator_on_qexp +from sage.modular.modform.j_invariant import j_invariant_qexp +from sage.modules.free_module_element import vector +from sage.modules.module import Module +from sage.plot.plot import plot +from sage.rings.big_oh import O +from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ +from sage.rings.padics.factory import Qp as pAdicField +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ -import sage.rings.abc -from sage.rings.all import (O, Infinity, pAdicField, PolynomialRing, PowerSeriesRing) -import weakref +from sage.structure.element import Vector, ModuleElement +from sage.structure.richcmp import richcmp from .weightspace import WeightSpace_constructor as WeightSpace, WeightCharacter + + __ocmfdict = {} #################### diff --git a/src/sage/modular/overconvergent/hecke_series.py b/src/sage/modular/overconvergent/hecke_series.py index e4028f8d10b..2da21b57b77 100644 --- a/src/sage/modular/overconvergent/hecke_series.py +++ b/src/sage/modular/overconvergent/hecke_series.py @@ -69,17 +69,20 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.functions.all import floor, ceil -from sage.arith.all import valuation -from sage.rings.all import ZZ, Zmod, Infinity, Integer -from sage.rings.finite_rings.finite_field_constructor import GF -from sage.modular.modform.all import ModularForms, ModularFormsRing, delta_qexp, eisenstein_series_qexp -from sage.modular.dims import dimension_modular_forms -from sage.misc.functional import dimension, transpose, charpoly +from sage.arith.misc import valuation +from sage.functions.other import floor, ceil from sage.matrix.constructor import matrix, random_matrix from sage.matrix.matrix_space import MatrixSpace +from sage.misc.functional import dimension, transpose, charpoly from sage.misc.misc import cputime from sage.misc.verbose import verbose +from sage.modular.dims import dimension_modular_forms +from sage.modular.modform.all import ModularForms, ModularFormsRing, delta_qexp, eisenstein_series_qexp +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.finite_rings.integer_mod_ring import Zmod +from sage.rings.infinity import Infinity +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ # AUXILIARY CODE: SPACES OF MODULAR FORMS AND LINEAR ALGEBRA diff --git a/src/sage/modular/overconvergent/weightspace.py b/src/sage/modular/overconvergent/weightspace.py index 14515dda101..e7716b173a6 100644 --- a/src/sage/modular/overconvergent/weightspace.py +++ b/src/sage/modular/overconvergent/weightspace.py @@ -65,16 +65,20 @@ # **************************************************************************** import weakref -from sage.structure.parent import Parent -from sage.structure.element import Element -from sage.structure.richcmp import richcmp +from sage.arith.misc import divisors +from sage.categories.sets_cat import Sets +from sage.misc.cachefunc import cached_method from sage.modular.dirichlet import DirichletGroup, trivial_character -from sage.rings.all import ZZ, QQ, IntegerModRing, Qp, Infinity -from sage.arith.all import divisors +from sage.rings.finite_rings.integer_mod_ring import IntegerModRing +from sage.rings.infinity import Infinity +from sage.rings.integer_ring import ZZ +from sage.rings.padics.factory import Qp from sage.rings.padics.padic_generic_element import pAdicGenericElement -from sage.misc.cachefunc import cached_method from sage.rings.padics.precision_error import PrecisionError -from sage.categories.sets_cat import Sets +from sage.rings.rational_field import QQ +from sage.structure.element import Element +from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp _wscache = {} diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index 1ee57f0c9c7..c52b9db5f0a 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -33,7 +33,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.finite_rings.integer_mod_ring import Zmod -from sage.arith.all import binomial, bernoulli +from sage.arith.misc import binomial, bernoulli from sage.modules.free_module_element import vector, zero_vector from sage.matrix.matrix cimport Matrix from sage.matrix.matrix_space import MatrixSpace diff --git a/src/sage/modular/pollack_stevens/modsym.py b/src/sage/modular/pollack_stevens/modsym.py index 1b6b2164b1a..96bdcfc3e07 100644 --- a/src/sage/modular/pollack_stevens/modsym.py +++ b/src/sage/modular/pollack_stevens/modsym.py @@ -36,24 +36,27 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # ***************************************************************************** + import operator -from sage.structure.element import ModuleElement -from sage.structure.richcmp import op_EQ, op_NE -from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ + +from sage.arith.misc import next_prime, gcd, kronecker +from sage.categories.action import Action from sage.misc.cachefunc import cached_method +from sage.misc.verbose import verbose +from sage.rings.integer_ring import ZZ from sage.rings.padics.factory import Qp -from sage.rings.polynomial.all import PolynomialRing from sage.rings.padics.padic_generic import pAdicGeneric -from sage.arith.all import next_prime, gcd, kronecker -from sage.misc.verbose import verbose from sage.rings.padics.precision_error import PrecisionError +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ +from sage.structure.element import ModuleElement +from sage.structure.richcmp import op_EQ, op_NE -from sage.categories.action import Action from .manin_map import ManinMap from .sigma0 import Sigma0 from .fund_domain import M2Z + minusproj = [1, 0, 0, -1] diff --git a/src/sage/modular/pollack_stevens/padic_lseries.py b/src/sage/modular/pollack_stevens/padic_lseries.py index 4a3beb12fdf..0692e81aef3 100644 --- a/src/sage/modular/pollack_stevens/padic_lseries.py +++ b/src/sage/modular/pollack_stevens/padic_lseries.py @@ -20,12 +20,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.padics.all import pAdicField +from sage.arith.misc import kronecker, binomial from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ -from sage.rings.power_series_ring import PowerSeriesRing -from sage.arith.all import binomial, kronecker +from sage.rings.padics.factory import Qp as pAdicField from sage.rings.padics.precision_error import PrecisionError +from sage.rings.power_series_ring import PowerSeriesRing +from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index cb92b17c88e..8f0d8baed62 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -100,26 +100,29 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.modular.arithgroup.all import Gamma0, is_CongruenceSubgroup +from sage.categories.graded_algebras import GradedAlgebras + +from sage.modular.arithgroup.congroup_gamma0 import Gamma0_constructor as Gamma0 +from sage.modular.arithgroup.congroup_generic import is_CongruenceSubgroup from sage.modular.modform.element import GradedModularFormElement, ModularFormElement from sage.modular.modform.space import ModularFormsSpace from sage.modular.modform.ring import ModularFormsRing -from sage.rings.all import Integer, QQ, ZZ -from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.multi_polynomial import MPolynomial +from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.term_order import TermOrder from sage.rings.power_series_poly import PowerSeries_poly +from sage.rings.rational_field import QQ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.categories.graded_algebras import GradedAlgebras - - from .element import QuasiModularFormsElement + class QuasiModularForms(Parent, UniqueRepresentation): r""" The graded ring of quasimodular forms for the full modular group diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index f123eaaf16a..996e9287697 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -202,21 +202,25 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -# imports -from sage.misc.misc_c import prod -from sage.misc.verbose import verbose -from sage.rings.all import Integer, ZZ, QQ, PolynomialRing, GF, CommutativeRing - from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra, basis_for_quaternion_lattice from sage.algebras.quatalg.quaternion_algebra_cython import rational_matrix_from_rational_quaternions - -from sage.arith.all import gcd, factor, prime_divisors, kronecker, next_prime -from sage.modular.hecke.all import (AmbientHeckeModule, HeckeSubmodule, - HeckeModuleElement) +from sage.arith.misc import gcd, factor, prime_divisors, kronecker, next_prime +from sage.matrix.constructor import matrix +from sage.matrix.matrix_space import MatrixSpace +from sage.misc.cachefunc import cached_method +from sage.misc.misc_c import prod +from sage.misc.verbose import verbose from sage.modular.dirichlet import TrivialCharacter -from sage.matrix.all import MatrixSpace, matrix +from sage.modular.hecke.ambient_module import AmbientHeckeModule +from sage.modular.hecke.element import HeckeModuleElement +from sage.modular.hecke.submodule import HeckeSubmodule +from sage.rings.finite_rings.finite_field_constructor import GF +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ +from sage.rings.ring import CommutativeRing from sage.structure.richcmp import richcmp, richcmp_method -from sage.misc.cachefunc import cached_method cache = {} diff --git a/src/sage/modular/ssmod/ssmod.py b/src/sage/modular/ssmod/ssmod.py index c0198b3fdfd..50865f10c80 100644 --- a/src/sage/modular/ssmod/ssmod.py +++ b/src/sage/modular/ssmod/ssmod.py @@ -66,17 +66,18 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -import sage.modular.hecke.all as hecke +from sage.arith.misc import kronecker, next_prime +from sage.libs.pari.all import pari +from sage.matrix.matrix_space import MatrixSpace +from sage.modular.arithgroup.all import Gamma0 +from sage.modular.hecke.module import HeckeModule_free_module from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.arith.all import kronecker, next_prime -from sage.matrix.matrix_space import MatrixSpace -from sage.modular.arithgroup.all import Gamma0 -from sage.libs.pari.all import pari from sage.structure.richcmp import richcmp_method, richcmp + ZZy = PolynomialRing(ZZ, 'y') @@ -364,7 +365,7 @@ def supersingular_j(FF): @richcmp_method -class SupersingularModule(hecke.HeckeModule_free_module): +class SupersingularModule(HeckeModule_free_module): r""" The module of supersingular points in a given characteristic, with given level structure. @@ -410,8 +411,8 @@ def __init__(self, prime=2, level=1, base_ring=ZZ): self.__finite_field = FiniteField(prime**2, 'a') self.__level = level self.__hecke_matrices = {} - hecke.HeckeModule_free_module.__init__(self, base_ring, - prime * level, weight=2) + HeckeModule_free_module.__init__(self, base_ring, + prime * level, weight=2) def _repr_(self): """ From a0d430b85091d4b8d411461fe265f48b40268ae3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 24 Aug 2022 17:46:54 -0700 Subject: [PATCH 555/591] src/sage/misc/dev_tools.py (import_statements): Accept more flexible input --- src/sage/misc/dev_tools.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index b08b6857623..ac79f58a95b 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -339,7 +339,7 @@ def import_statements(*objects, **kwds): INPUT: - - ``*objects`` -- a sequence of objects or names. + - ``*objects`` -- a sequence of objects or comma-separated strings of names. - ``lazy`` -- a boolean (default: ``False``) Whether to print a lazy import statement. @@ -406,6 +406,12 @@ def import_statements(*objects, **kwds): # - sage.rings.integer_ring from sage.rings.integer_ring import Z + The strings are allowed to be comma-separated names, and parenthesis + are stripped for convenience:: + + sage: import_statements('(floor, ceil)') + from sage.functions.other import floor, ceil + Specifying a string is also useful for objects that are not imported in the Sage interpreter namespace by default. In this case, an object with that name is looked up in all the modules @@ -502,6 +508,7 @@ def import_statements(*objects, **kwds): detect deprecated stuff). So, if you use it, double check the answer and report weird behaviors. """ + import itertools import inspect from sage.misc.lazy_import import LazyImport @@ -518,7 +525,15 @@ def import_statements(*objects, **kwds): if kwds: raise TypeError("Unexpected '{}' argument".format(next(iter(kwds)))) - for obj in objects: + def expand_comma_separated_names(object): + if isinstance(object, str): + for w in object.strip('()').split(','): + yield w.strip() + else: + yield object + + for obj in itertools.chain.from_iterable(expand_comma_separated_names(object) + for object in objects): name = None # the name of the object # 1. if obj is a string, we look for an object that has that name From d1a6b0801360ed364d27ff34da04273d4c68e620 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 24 Aug 2022 17:50:29 -0700 Subject: [PATCH 556/591] src/sage/categories/finite_enumerated_sets.py: EXAMPLE:: -> EXAMPLES:: --- src/sage/categories/finite_enumerated_sets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index d2fea15b3a4..4a872cf2fbf 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -221,7 +221,7 @@ def tuple(self): r""" Return a :class:`tuple`of the elements of ``self``. - EXAMPLE:: + EXAMPLES:: sage: C = FiniteEnumeratedSets().example() sage: C.tuple() From 0938385b6502c7d58d4a356ff8ba3039670230fe Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 24 Aug 2022 21:05:52 -0400 Subject: [PATCH 557/591] .vscode/settings.json: add comment --- .vscode/settings.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8f0070a54d9..1d7a2e7962f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,6 @@ { + // This settings file is not ignored by git. It should be kept in sync with + // the trac repo. "python.defaultInterpreterPath": "./venv/bin/python3", "files.exclude": { "**/__pycache__": true, From 77a761a2d07e512cecff9debfdf11e3f4c384c71 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 24 Aug 2022 21:07:19 -0400 Subject: [PATCH 558/591] src/doc/en/developer/tools.rst: update info on vscode pycodestyle linter --- src/doc/en/developer/tools.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/doc/en/developer/tools.rst b/src/doc/en/developer/tools.rst index ee2e8bf0b1c..1721f26640d 100644 --- a/src/doc/en/developer/tools.rst +++ b/src/doc/en/developer/tools.rst @@ -196,8 +196,12 @@ or a few related issues:: - Manual: Run ``pycodestyle path/to/the/file.py``. -- VS Code: Activate by adding the setting ``"python.linting.pycodestyleEnabled": true``, see `official VS Code documentation `__ for details. - +- VS Code: The minimal version of pycodestyle is activated by default in + ``SAGE_ROOT/.vscode/settings.json`` (the corresponding setting is + ``"python.linting.pycodestyleEnabled": true``). Note that the + ``settings.json`` file is not ignored by git so be aware to keep it in sync + with the trac repo. For further details, see the + `official VS Code documentation `__. *Configuration:* ``[pycodestyle]`` block in ``SAGE_ROOT/src/tox.ini`` *Documentation:* https://pycodestyle.pycqa.org/en/latest/index.html From ec65ffe15a4369cb64fa869cf9cb3ea86a40596e Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 24 Aug 2022 21:29:06 -0400 Subject: [PATCH 559/591] src/tox.ini: add general comment --- src/tox.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tox.ini b/src/tox.ini index a26fee98803..0ecf06018cb 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -1,6 +1,9 @@ ## Configuration for tox. ## Needs tox installed in the system python. ## +## Note that this file is not ignored by git. It should be kept in sync with the +## git trac repo. +## ## doctest: Run the sage doctests. From the SAGE_ROOT/src directory: ## ## $ tox From 2be15354df7713426016b1692a944ace5f2f35d5 Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 24 Aug 2022 21:50:32 -0400 Subject: [PATCH 560/591] .vscode/settings.json, src/tox.ini: add comments cross-referencing the two files --- .vscode/settings.json | 2 ++ src/tox.ini | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 1d7a2e7962f..10272f88543 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -25,6 +25,8 @@ "python.testing.unittestEnabled": false, "python.linting.pycodestyleEnabled": true, "python.linting.enabled": true, + // The following pycodestyle arguments are the same as the pycodestyle-minimal + // tox environnment, see the file SAGE_ROOT/src/tox.ini "python.linting.pycodestyleArgs": ["--select=E111,E306,E401,E701,E702,E703,W605,E711,E712,E713,E721,E722"], "cSpell.words": [ "furo", diff --git a/src/tox.ini b/src/tox.ini index 0ecf06018cb..0d8eb0ae729 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -1,9 +1,6 @@ ## Configuration for tox. ## Needs tox installed in the system python. ## -## Note that this file is not ignored by git. It should be kept in sync with the -## git trac repo. -## ## doctest: Run the sage doctests. From the SAGE_ROOT/src directory: ## ## $ tox @@ -93,6 +90,8 @@ deps = pycodestyle commands = pycodestyle {posargs:{toxinidir}/sage/} [testenv:pycodestyle-minimal] +## Note that the the pycodestyle linter provided by vscode checks against the +## same minimal conventions as defined below, see the file SAGE_ROOT/.vscode/settings.json. description = check against Sage's minimal style conventions # Check for the following issues: From 14b77808543428d32a56ce82bf1ac2da38aa83ad Mon Sep 17 00:00:00 2001 From: DavidAyotte Date: Wed, 24 Aug 2022 22:16:32 -0400 Subject: [PATCH 561/591] src/doc/en/developer/tools.rst: add missing blank line --- src/doc/en/developer/tools.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/en/developer/tools.rst b/src/doc/en/developer/tools.rst index 1721f26640d..becaad7f829 100644 --- a/src/doc/en/developer/tools.rst +++ b/src/doc/en/developer/tools.rst @@ -202,6 +202,7 @@ or a few related issues:: ``settings.json`` file is not ignored by git so be aware to keep it in sync with the trac repo. For further details, see the `official VS Code documentation `__. + *Configuration:* ``[pycodestyle]`` block in ``SAGE_ROOT/src/tox.ini`` *Documentation:* https://pycodestyle.pycqa.org/en/latest/index.html From e7af9f3522774bfb036e9a7e25f1e36f39838a5f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 24 Aug 2022 23:14:35 -0700 Subject: [PATCH 562/591] sage.manifolds, sage.tensor: Remove imports from sage.arith.all, sage.rings.all --- src/sage/manifolds/utilities.py | 3 ++- src/sage/tensor/modules/comp.py | 2 +- src/sage/tensor/modules/ext_pow_free_module.py | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py index 8fe6c439066..75a07519b0d 100644 --- a/src/sage/manifolds/utilities.py +++ b/src/sage/manifolds/utilities.py @@ -35,7 +35,8 @@ from sage.functions.other import abs_symbolic from sage.misc.functional import sqrt from sage.functions.trig import cos, sin -from sage.rings.all import Rational +from sage.rings.rational import Rational + class SimplifySqrtReal(ExpressionTreeWalker): r""" diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 04f14f782f0..23977e84f0d 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -5446,7 +5446,7 @@ def interior_product(self, other): True """ - from sage.arith.all import factorial + from sage.arith.misc import factorial # Sanity checks: if not isinstance(other, CompFullyAntiSym): raise TypeError("{} is not a fully antisymmetric ".format(other) + diff --git a/src/sage/tensor/modules/ext_pow_free_module.py b/src/sage/tensor/modules/ext_pow_free_module.py index c68033fdf51..f6661606fe3 100644 --- a/src/sage/tensor/modules/ext_pow_free_module.py +++ b/src/sage/tensor/modules/ext_pow_free_module.py @@ -236,7 +236,7 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): sage: TestSuite(A).run() """ - from sage.arith.all import binomial + from sage.arith.misc import binomial from sage.typeset.unicode_characters import unicode_bigwedge self._fmodule = fmodule self._degree = ZZ(degree) @@ -631,7 +631,7 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): sage: TestSuite(A).run() """ - from sage.arith.all import binomial + from sage.arith.misc import binomial from sage.typeset.unicode_characters import unicode_bigwedge self._fmodule = fmodule self._degree = ZZ(degree) From 987a32ee6d7e2cd1c7529651532a8d07a185ef49 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 25 Aug 2022 03:21:12 -0700 Subject: [PATCH 563/591] build/pkgs/jupyter_jsmol/spkg-install.in: Use --no-build-isolation --- build/pkgs/jupyter_jsmol/spkg-install.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/pkgs/jupyter_jsmol/spkg-install.in b/build/pkgs/jupyter_jsmol/spkg-install.in index 336f1829b2b..0735cfa336d 100644 --- a/build/pkgs/jupyter_jsmol/spkg-install.in +++ b/build/pkgs/jupyter_jsmol/spkg-install.in @@ -1,2 +1,3 @@ cd src -eval sdh_pip_install $(eval sdh_prefix_args "--build-option" build --skip-npm) . +# Use --no-build-isolation to avoid WARNING: Ignoring --build-option when building jupyter-jsmol using PEP 517 +eval sdh_pip_install --no-build-isolation $(eval sdh_prefix_args "--build-option" build --skip-npm) . From 6fb910f7e50e4c5f1ff1142cbff30043d10db239 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 25 Aug 2022 04:03:26 -0700 Subject: [PATCH 564/591] build/pkgs/jupyter_jsmol/spkg-install.in: Use --config-settings --- build/pkgs/jupyter_jsmol/spkg-install.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/jupyter_jsmol/spkg-install.in b/build/pkgs/jupyter_jsmol/spkg-install.in index 0735cfa336d..72d65dde8d5 100644 --- a/build/pkgs/jupyter_jsmol/spkg-install.in +++ b/build/pkgs/jupyter_jsmol/spkg-install.in @@ -1,3 +1,3 @@ cd src -# Use --no-build-isolation to avoid WARNING: Ignoring --build-option when building jupyter-jsmol using PEP 517 -eval sdh_pip_install --no-build-isolation $(eval sdh_prefix_args "--build-option" build --skip-npm) . +# Use --no-build-isolation because we have a different version of jupyter_packaging +eval sdh_pip_install --no-build-isolation --config-settings "--global-option=--skip-npm" . From 82701cc83ad73102472ad50c147002ccd2382280 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 25 Aug 2022 09:49:42 -0700 Subject: [PATCH 565/591] build/pkgs/python_igraph: Update to 0.9.11 --- build/pkgs/python_igraph/checksums.ini | 6 +++--- build/pkgs/python_igraph/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/python_igraph/checksums.ini b/build/pkgs/python_igraph/checksums.ini index ebbdae645c8..9311cc6fd6a 100644 --- a/build/pkgs/python_igraph/checksums.ini +++ b/build/pkgs/python_igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=python-igraph-VERSION.tar.gz -sha1=6b717972163a4abfc8324e1a760c830526cc1a66 -md5=81929a9ffe5e7c40bf0be5a40d11a211 -cksum=2293691814 +sha1=0078cc313c922ace451efc1abcfbb3f18710c5d1 +md5=6eb41918e72cb7a21ed8dd07e08e08bf +cksum=3180770708 upstream_url=https://pypi.io/packages/source/i/igraph/igraph-VERSION.tar.gz diff --git a/build/pkgs/python_igraph/package-version.txt b/build/pkgs/python_igraph/package-version.txt index 7e310bae199..8225a4ba4fd 100644 --- a/build/pkgs/python_igraph/package-version.txt +++ b/build/pkgs/python_igraph/package-version.txt @@ -1 +1 @@ -0.9.9 +0.9.11 From 5b6554f1584fae04586d29fe092881c649bb9aed Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 25 Aug 2022 09:52:14 -0700 Subject: [PATCH 566/591] build/pkgs/python_igraph/spkg-install.in: Use pip --config-settings --- build/pkgs/python_igraph/spkg-install.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/python_igraph/spkg-install.in b/build/pkgs/python_igraph/spkg-install.in index de8af8225a2..e5a7aa846c5 100644 --- a/build/pkgs/python_igraph/spkg-install.in +++ b/build/pkgs/python_igraph/spkg-install.in @@ -1,2 +1,2 @@ cd src -eval sdh_pip_install $(eval sdh_prefix_args "--build-option" --use-pkg-config) . +sdh_pip_install --config-settings "--global-option=--use-pkg-config --global-option=--no-wait" . From dab2856e6bfcbf12cee90c6bd2ed3e91739cbfb6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 25 Aug 2022 11:11:26 -0700 Subject: [PATCH 567/591] build/pkgs/python_igraph/checksums.ini: Fix up --- build/pkgs/python_igraph/checksums.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/python_igraph/checksums.ini b/build/pkgs/python_igraph/checksums.ini index 9311cc6fd6a..5fbaf1821bc 100644 --- a/build/pkgs/python_igraph/checksums.ini +++ b/build/pkgs/python_igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=python-igraph-VERSION.tar.gz -sha1=0078cc313c922ace451efc1abcfbb3f18710c5d1 -md5=6eb41918e72cb7a21ed8dd07e08e08bf -cksum=3180770708 +sha1=b54b4f1a0c7ce8a80ddb35d35b4e5d1552592793 +md5=9ce0139a294d1c738abc4eb75aab84cd +cksum=4113725847 upstream_url=https://pypi.io/packages/source/i/igraph/igraph-VERSION.tar.gz From 675fff96b9cb0cb94c74ef0e7c08cdd568e6630c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 25 Aug 2022 12:26:05 -0700 Subject: [PATCH 568/591] build/pkgs/python_igraph/spkg-install.in: Use PEP 517 explicitly --- build/pkgs/python_igraph/spkg-install.in | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/build/pkgs/python_igraph/spkg-install.in b/build/pkgs/python_igraph/spkg-install.in index e5a7aa846c5..bafbbda375e 100644 --- a/build/pkgs/python_igraph/spkg-install.in +++ b/build/pkgs/python_igraph/spkg-install.in @@ -1,2 +1,10 @@ cd src -sdh_pip_install --config-settings "--global-option=--use-pkg-config --global-option=--no-wait" . +# Use --use-pep517 because https://github.com/igraph/python-igraph as of 0.9.11 does not have pyproject.toml +# and so "pip wheel" would use a legacy build method, ignoring --config-settings. +# +# TODO: With setuptools 63.2.0, passing another --config-settings "--global-option=--no-wait" (not really needed) +# kills the "--global-option=--use-pkg-config". +# https://github.com/pypa/setuptools/issues/3380 makes changes to this, so we can revisit this after +# the next setuptools upgrade. +# +sdh_pip_install --use-pep517 --config-settings "--global-option=--use-pkg-config" . From cc422ab321584bcaf09f647c80d8ee777a203a35 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 26 Aug 2022 00:41:55 +0100 Subject: [PATCH 569/591] updated gforge (which is gone) links and emails --- build/pkgs/ecm/SPKG.rst | 2 +- build/pkgs/gf2x/SPKG.rst | 2 +- build/pkgs/mpc/SPKG.rst | 8 +++----- build/pkgs/mpfi/SPKG.rst | 5 ++--- src/doc/en/thematic_tutorials/linear_programming.rst | 3 ++- src/sage/combinat/tutorial.py | 2 +- src/sage/interfaces/ecm.py | 4 ++-- src/sage/libs/libecm.pyx | 2 +- .../books/computational-mathematics-with-sagemath/README | 2 +- 9 files changed, 14 insertions(+), 16 deletions(-) diff --git a/build/pkgs/ecm/SPKG.rst b/build/pkgs/ecm/SPKG.rst index ae289680f96..de7370109ce 100644 --- a/build/pkgs/ecm/SPKG.rst +++ b/build/pkgs/ecm/SPKG.rst @@ -17,7 +17,7 @@ LGPL V3+ Upstream Contact ---------------- -- ecm-discuss@lists.gforge.inria.fr (requires subscription) +- Paul.Zimmermann@inria.fr Special Update/Build Instructions --------------------------------- diff --git a/build/pkgs/gf2x/SPKG.rst b/build/pkgs/gf2x/SPKG.rst index 7f4b11e994f..d8b4694eb45 100644 --- a/build/pkgs/gf2x/SPKG.rst +++ b/build/pkgs/gf2x/SPKG.rst @@ -8,7 +8,7 @@ gf2x is a C/C++ software package containing routines for fast arithmetic in GF(2)[x] (multiplication, squaring, GCD) and searching for irreducible/primitive trinomials. -Website: http://gf2x.gforge.inria.fr/ +Website: https://gitlab.inria.fr/gf2x/gf2x License ------- diff --git a/build/pkgs/mpc/SPKG.rst b/build/pkgs/mpc/SPKG.rst index 821daf9f1db..5a205e0335f 100644 --- a/build/pkgs/mpc/SPKG.rst +++ b/build/pkgs/mpc/SPKG.rst @@ -4,7 +4,7 @@ mpc: Arithmetic of complex numbers with arbitrarily high precision and correct r Description ----------- -From http://www.multiprecision.org/mpc: GNU MPC is a C library for the +From https://www.multiprecision.org/mpc: GNU MPC is a C library for the arithmetic of complex numbers with arbitrarily high precision and correct rounding of the result. It extends the principles of the IEEE-754 standard for fixed precision real floating point numbers to @@ -22,11 +22,9 @@ documentation. Upstream Contact ---------------- -The MPC website is located at http://www.multiprecision.org/mpc . +The MPC website is located at https://www.multiprecision.org/mpc . -The MPC team can be contacted via the MPC mailing list: - - mpc-discuss@lists.gforge.inria.fr +The MPC team can be contacted via the MPC mailing list: mpc-discuss@inria.fr Special Update/Build Instructions --------------------------------- diff --git a/build/pkgs/mpfi/SPKG.rst b/build/pkgs/mpfi/SPKG.rst index cb145ca0e2a..9f16f859527 100644 --- a/build/pkgs/mpfi/SPKG.rst +++ b/build/pkgs/mpfi/SPKG.rst @@ -33,8 +33,7 @@ Upstream Contact http://perso.ens-lyon.fr/nathalie.revol/software.html -The MPFI website is located at http://mpfi.gforge.inria.fr/ +The MPFI website is located at https://gitlab.inria.fr/mpfi/mpfi -The MPFI team can be contacted via the MPFI mailing list: -mpfi-users@lists.gforge.inria.fr +The MPFI team can be contacted via the MPFI mailing list: mpfi-users@inria.fr diff --git a/src/doc/en/thematic_tutorials/linear_programming.rst b/src/doc/en/thematic_tutorials/linear_programming.rst index fcb2a131e48..c8bf14c4eb4 100644 --- a/src/doc/en/thematic_tutorials/linear_programming.rst +++ b/src/doc/en/thematic_tutorials/linear_programming.rst @@ -13,7 +13,8 @@ to reformulate an optimization (or existence) problem through linear constraints. This is a translation of a chapter from the book -`Calcul mathematique avec Sage `_. +`Calcul mathematique avec Sage `_. +This book now exists in `English, too `_. Definition ---------- diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index 557995ba872..e9df13c746c 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -1842,7 +1842,7 @@ .. [CMS2012] Alexandre Casamayou, Nathann Cohen, Guillaume Connan, Thierry Dumont, Laurent Fousse, François Maltey, Matthias Meulien, Marc Mezzarobba, Clément Pernet, Nicolas M. Thiéry, Paul Zimmermann *Calcul Mathématique avec Sage* - http://sagebook.gforge.inria.fr/ + https://www.sagemath.org/sagebook/french.html .. [1] Or at least that should be the case; there are still many corners to diff --git a/src/sage/interfaces/ecm.py b/src/sage/interfaces/ecm.py index 171040c77a3..db2cf4a5d37 100644 --- a/src/sage/interfaces/ecm.py +++ b/src/sage/interfaces/ecm.py @@ -10,7 +10,7 @@ Sage includes GMP-ECM, which is a highly optimized implementation of Lenstra's elliptic curve factorization method. See -http://ecm.gforge.inria.fr for more about GMP-ECM. +https://gitlab.inria.fr/zimmerma/ecm for more about GMP-ECM. AUTHORS: @@ -63,7 +63,7 @@ def __init__(self, B1=10, B2=None, **kwds): Create an interface to the GMP-ECM elliptic curve method factorization program. - See http://ecm.gforge.inria.fr + See https://gitlab.inria.fr/zimmerma/ecm INPUT: diff --git a/src/sage/libs/libecm.pyx b/src/sage/libs/libecm.pyx index 1deacb45b39..886a9b816e4 100644 --- a/src/sage/libs/libecm.pyx +++ b/src/sage/libs/libecm.pyx @@ -5,7 +5,7 @@ The Elliptic Curve Method for Integer Factorization (ECM) Sage includes GMP-ECM, which is a highly optimized implementation of Lenstra's elliptic curve factorization method. -See http://ecm.gforge.inria.fr/ for more about GMP-ECM. +See https://gitlab.inria.fr/zimmerma/ecm for more about GMP-ECM. This file provides a Cython interface to the GMP-ECM library. AUTHORS: diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/README b/src/sage/tests/books/computational-mathematics-with-sagemath/README index c1c375296d5..99f566480c5 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/README +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/README @@ -1,6 +1,6 @@ This directory contains all the example code from the book "Computational Mathematics with SageMath" by Paul Zimmermann et al, -freely available from http://sagebook.gforge.inria.fr/english.html +freely available from https://www.sagemath.org/sagebook/english.html Each file corresponds to a chapter of the book. The directory "sol" contains the code for Annex A: answers to exercises From b91ab9fbe905cba2c7cde0822b50c824f7eec857 Mon Sep 17 00:00:00 2001 From: Yuan Zhou Date: Mon, 11 Apr 2022 03:24:06 -0400 Subject: [PATCH 570/591] typo in docstings value=False by default in variable_upper_bound etc. --- src/sage/numerical/backends/cvxopt_backend.pyx | 8 ++++---- src/sage/numerical/backends/generic_backend.pyx | 4 ++-- src/sage/numerical/backends/interactivelp_backend.pyx | 4 ++-- src/sage/numerical/backends/ppl_backend.pyx | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/numerical/backends/cvxopt_backend.pyx b/src/sage/numerical/backends/cvxopt_backend.pyx index c3e19f9d9f0..59938bf175b 100644 --- a/src/sage/numerical/backends/cvxopt_backend.pyx +++ b/src/sage/numerical/backends/cvxopt_backend.pyx @@ -914,7 +914,7 @@ cdef class CVXOPTBackend(GenericBackend): return self.col_name_var[index] return "x_" + repr(index) - cpdef variable_upper_bound(self, int index, value = None): + cpdef variable_upper_bound(self, int index, value = False): """ Return or define the upper bound on a variable @@ -923,7 +923,7 @@ cdef class CVXOPTBackend(GenericBackend): - ``index`` (integer) -- the variable's id - ``value`` -- real value, or ``None`` to mean that the - variable has not upper bound. When set to ``None`` + variable has not upper bound. When set to ``False`` (default), the method returns the current value. EXAMPLES:: @@ -943,7 +943,7 @@ cdef class CVXOPTBackend(GenericBackend): else: return self.col_upper_bound[index] - cpdef variable_lower_bound(self, int index, value = None): + cpdef variable_lower_bound(self, int index, value = False): """ Return or define the lower bound on a variable @@ -952,7 +952,7 @@ cdef class CVXOPTBackend(GenericBackend): - ``index`` (integer) -- the variable's id - ``value`` -- real value, or ``None`` to mean that the - variable has not lower bound. When set to ``None`` + variable has not lower bound. When set to ``False`` (default), the method returns the current value. EXAMPLES:: diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index 083492018fe..ac167aefa8d 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -1314,7 +1314,7 @@ cdef class GenericBackend: - ``index`` (integer) -- the variable's id - ``value`` -- real value, or ``None`` to mean that the - variable has not upper bound. When set to ``None`` + variable has not upper bound. When set to ``False`` (default), the method returns the current value. EXAMPLES:: @@ -1340,7 +1340,7 @@ cdef class GenericBackend: - ``index`` (integer) -- the variable's id - ``value`` -- real value, or ``None`` to mean that the - variable has not lower bound. When set to ``None`` + variable has not lower bound. When set to ``False`` (default), the method returns the current value. EXAMPLES:: diff --git a/src/sage/numerical/backends/interactivelp_backend.pyx b/src/sage/numerical/backends/interactivelp_backend.pyx index e431c604b0c..89b823f2491 100644 --- a/src/sage/numerical/backends/interactivelp_backend.pyx +++ b/src/sage/numerical/backends/interactivelp_backend.pyx @@ -985,7 +985,7 @@ cdef class InteractiveLPBackend: - ``index`` (integer) -- the variable's id - ``value`` -- real value, or ``None`` to mean that the - variable has not upper bound. When set to ``None`` + variable has not upper bound. When set to ``False`` (default), the method returns the current value. EXAMPLES:: @@ -1029,7 +1029,7 @@ cdef class InteractiveLPBackend: - ``index`` (integer) -- the variable's id - ``value`` -- real value, or ``None`` to mean that the - variable has no lower bound. When set to ``None`` + variable has no lower bound. When set to ``False`` (default), the method returns the current value. EXAMPLES:: diff --git a/src/sage/numerical/backends/ppl_backend.pyx b/src/sage/numerical/backends/ppl_backend.pyx index b83aa82cbf9..9d59c226743 100644 --- a/src/sage/numerical/backends/ppl_backend.pyx +++ b/src/sage/numerical/backends/ppl_backend.pyx @@ -1070,7 +1070,7 @@ cdef class PPLBackend(GenericBackend): - ``index`` (integer) -- the variable's id - ``value`` -- real value, or ``None`` to mean that the - variable has not upper bound. When set to ``None`` + variable has not upper bound. When set to ``False`` (default), the method returns the current value. EXAMPLES:: @@ -1102,7 +1102,7 @@ cdef class PPLBackend(GenericBackend): - ``index`` (integer) -- the variable's id - ``value`` -- real value, or ``None`` to mean that the - variable has not lower bound. When set to ``None`` + variable has not lower bound. When set to ``False`` (default), the method returns the current value. EXAMPLES:: From 33dea5785a5ed3efad6a035010067aebc7a3cac6 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 26 Aug 2022 09:59:48 +0100 Subject: [PATCH 571/591] correct email address for ECM upstream --- build/pkgs/ecm/SPKG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/ecm/SPKG.rst b/build/pkgs/ecm/SPKG.rst index de7370109ce..9815c59cac9 100644 --- a/build/pkgs/ecm/SPKG.rst +++ b/build/pkgs/ecm/SPKG.rst @@ -17,7 +17,7 @@ LGPL V3+ Upstream Contact ---------------- -- Paul.Zimmermann@inria.fr +- ecm-discuss@inria.fr Special Update/Build Instructions --------------------------------- From 4196d9d6ebdee88f2f69f3ebb01ea0372d22d524 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 08:31:32 -0700 Subject: [PATCH 572/591] build/pkgs/setuptools/distros/conda.txt: Use setuptools < 64 --- build/pkgs/setuptools/distros/conda.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/pkgs/setuptools/distros/conda.txt b/build/pkgs/setuptools/distros/conda.txt index 49fe098d9e6..0a486bd850f 100644 --- a/build/pkgs/setuptools/distros/conda.txt +++ b/build/pkgs/setuptools/distros/conda.txt @@ -1 +1,4 @@ -setuptools +# Set this bound until https://trac.sagemath.org/ticket/34209 adds support for PEP660 editable builds +# By setting this version bound, we avoid having to include the following in our installation instructions. +# export SETUPTOOLS_ENABLE_FEATURES=legacy-editable +"setuptools<64" From 0e1d9e4d09bd7ede752fea6cd3e9f162b156c728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 26 Aug 2022 20:18:55 +0200 Subject: [PATCH 573/591] less enthusiasm in error messages --- src/sage/categories/crystals.py | 8 ++++---- src/sage/categories/finite_coxeter_groups.py | 4 ++-- src/sage/categories/finite_groups.py | 2 +- src/sage/coding/binary_code.pyx | 3 ++- src/sage/combinat/designs/incidence_structures.py | 2 +- src/sage/combinat/designs/steiner_quadruple_systems.py | 4 ++-- src/sage/databases/sql_db.py | 3 +-- src/sage/groups/cubic_braid.py | 2 +- src/sage/groups/generic.py | 2 +- src/sage/libs/glpk/error.pyx | 4 ++-- src/sage/matrix/matrix_integer_dense_hnf.py | 2 +- src/sage/misc/dev_tools.py | 2 +- src/sage/misc/lazy_format.py | 6 +++--- src/sage/modules/free_module.py | 2 +- src/sage/numerical/backends/generic_sdp_backend.pyx | 5 ++--- src/sage/numerical/optimize.py | 6 +++--- src/sage/quivers/representation.py | 5 ++--- src/sage/schemes/toric/divisor_class.pyx | 10 +++++----- src/sage/sets/family.py | 7 ++++--- src/sage/structure/coerce.pyx | 2 +- 20 files changed, 40 insertions(+), 41 deletions(-) diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 995dd7e63e6..68bbbf46a35 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -1582,12 +1582,12 @@ def to_highest_weight(self, index_set = None): sage: t.to_highest_weight() Traceback (most recent call last): ... - ValueError: This is not a highest weight crystals! + ValueError: this is not a highest weight crystal """ from sage.categories.highest_weight_crystals import HighestWeightCrystals if index_set is None: if HighestWeightCrystals() not in self.parent().categories(): - raise ValueError("This is not a highest weight crystals!") + raise ValueError("this is not a highest weight crystal") index_set = self.index_set() for i in index_set: next = self.e(i) @@ -1623,12 +1623,12 @@ def to_lowest_weight(self, index_set = None): sage: t.to_lowest_weight() Traceback (most recent call last): ... - ValueError: This is not a highest weight crystals! + ValueError: this is not a highest weight crystal """ from sage.categories.highest_weight_crystals import HighestWeightCrystals if index_set is None: if HighestWeightCrystals() not in self.parent().categories(): - raise ValueError("This is not a highest weight crystals!") + raise ValueError("this is not a highest weight crystal") index_set = self.index_set() for i in index_set: next = self.f(i) diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 1cf0d84a1e7..0f5b37577dd 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -827,11 +827,11 @@ def coxeter_knuth_neighbor(self, w): sage: w.coxeter_knuth_neighbor(word) Traceback (most recent call last): ... - NotImplementedError: This has only been implemented in finite type A so far! + NotImplementedError: this has only been implemented in finite type A so far """ C = self.parent().cartan_type() if not C[0] == 'A': - raise NotImplementedError("This has only been implemented in finite type A so far!") + raise NotImplementedError("this has only been implemented in finite type A so far") d = [] for i in range(2,len(w)): v = [j for j in w] diff --git a/src/sage/categories/finite_groups.py b/src/sage/categories/finite_groups.py index 0f1ecbc0a9c..42415233567 100644 --- a/src/sage/categories/finite_groups.py +++ b/src/sage/categories/finite_groups.py @@ -134,7 +134,7 @@ def cayley_graph_disabled(self, connecting_set=None): else: for g in connecting_set: if g not in self: - raise RuntimeError("Each element of the connecting set must be in the group!") + raise RuntimeError("each element of the connecting set must be in the group") connecting_set = [self(g) for g in connecting_set] from sage.graphs.digraph import DiGraph arrows = {} diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 7021531eedd..66192643aae 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -777,7 +777,8 @@ cdef class BinaryCode: self.nwords = 2 * other_nwords nrows = self.nrows nwords = self.nwords - else: raise NotImplementedError("!") + else: + raise NotImplementedError if self.nrows >= self.radix or self.ncols > self.radix: raise NotImplementedError("Columns and rows are stored as ints. This code is too big.") diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 5bbe6030ffb..49b564ce8c3 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1383,7 +1383,7 @@ def relabel(self, perm=None, inplace=True): raise ValueError("perm argument must be None, a list or a dictionary") if len(set(perm.values())) != len(perm): - raise ValueError("Two points are getting relabelled with the same name !") + raise ValueError("two points are getting relabelled with the same name") self._points = [perm[x] for x in self._points] if self._points == list(range(self.num_points())): diff --git a/src/sage/combinat/designs/steiner_quadruple_systems.py b/src/sage/combinat/designs/steiner_quadruple_systems.py index e022000bd61..2a8713fe323 100644 --- a/src/sage/combinat/designs/steiner_quadruple_systems.py +++ b/src/sage/combinat/designs/steiner_quadruple_systems.py @@ -741,10 +741,10 @@ def steiner_quadruple_system(n, check = False): nn = (n+10) // 12 sqs = twelve_n_minus_ten(steiner_quadruple_system(nn, check = False)) else: - raise ValueError("This shouldn't happen !") + raise ValueError("this should never happen") if check and not sqs.is_t_design(3,n,4,1): - raise RuntimeError("Something is very very wrong.") + raise RuntimeError("something is very very wrong") return sqs diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index 0487d770f65..5e29cad2685 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -1254,8 +1254,7 @@ def get_skeleton(self, check=False): d = construct_skeleton(self) if d == self.__skeleton__: return d - else: - raise RuntimeError("Skeleton structure is out of whack!") + raise RuntimeError("skeleton structure is out of whack") return self.__skeleton__ def query(self, *args, **kwds): diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index 295d43aa1d2..0f43a0f5d82 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -1901,7 +1901,7 @@ def classical_invariant_form(self): self._create_classical_realization() if self._classical_invariant_form is None: - raise ValueError("no classical invariant form defined!") + raise ValueError("no classical invariant form defined") return self._classical_invariant_form diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index de015974697..25a2f9d494b 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -1033,7 +1033,7 @@ def linear_relation(P, Q, operation='+', identity=None, inverse=None, op=None): m1 * h) except ValueError: pass # to next h - raise ValueError("No solution found in linear_relation!") + raise ValueError("no solution found in linear_relation") ################################################################ # diff --git a/src/sage/libs/glpk/error.pyx b/src/sage/libs/glpk/error.pyx index 9f7df469a22..2e3ac1c386a 100644 --- a/src/sage/libs/glpk/error.pyx +++ b/src/sage/libs/glpk/error.pyx @@ -29,10 +29,10 @@ class GLPKError(MIPSolverException): EXAMPLES:: sage: from sage.libs.glpk.error import GLPKError - sage: raise GLPKError("trouble!") + sage: raise GLPKError("trouble") Traceback (most recent call last): ... - GLPKError: trouble! + GLPKError: trouble """ pass diff --git a/src/sage/matrix/matrix_integer_dense_hnf.py b/src/sage/matrix/matrix_integer_dense_hnf.py index 735e7016eda..acdb0f09cc4 100644 --- a/src/sage/matrix/matrix_integer_dense_hnf.py +++ b/src/sage/matrix/matrix_integer_dense_hnf.py @@ -617,7 +617,7 @@ def hnf_square(A, proof): # weird cases where the det is large. # E.g., matrix all of whose rows but 1 are multiplied by some # fixed scalar n. - raise NotImplementedError("fallback to PARI!") + raise NotImplementedError("fallback to PARI") # H = W.hermite_form(algorithm='pari') else: H = W._hnf_mod(2 * g) diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index b08b6857623..80cb5191277 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -292,7 +292,7 @@ def find_object_modules(obj): if module_name: if module_name not in sys.modules: - raise ValueError("This should not happen!") + raise ValueError("this should never happen") d = sys.modules[module_name].__dict__ matching = sorted(key for key in d if d[key] is obj) if matching: diff --git a/src/sage/misc/lazy_format.py b/src/sage/misc/lazy_format.py index 4a529aa1bc6..e3050695b25 100644 --- a/src/sage/misc/lazy_format.py +++ b/src/sage/misc/lazy_format.py @@ -31,7 +31,7 @@ class LazyFormat(str): sage: class IDontLikeBeingPrinted(): ....: def __repr__(self): - ....: raise ValueError("Don't ever try to print me !") + ....: raise ValueError("do not ever try to print me") There is no error when binding a lazy format with the broken object:: @@ -40,7 +40,7 @@ class LazyFormat(str): The error only occurs upon printing:: sage: lf - ) failed: ValueError: Don't ever try to print me !> + ) failed: ValueError: do not ever try to print me> .. rubric:: Common use case: @@ -63,7 +63,7 @@ class LazyFormat(str): ....: "%s doesn't contain 0"%IDontLikeBeingPrinted()) Traceback (most recent call last): ... - ValueError: Don't ever try to print me ! + ValueError: do not ever try to print me This behavior can induce major performance penalties when testing. Note that this issue does not impact the usual assert:: diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 9946a588c85..0b39a41697c 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -687,7 +687,7 @@ def span(gens, base_ring=None, check=True, already_echelonized=False): gens = list(gens) R = base_ring except TypeError: - raise TypeError("generators must be given as an iterable structure!") + raise TypeError("generators must be given as an iterable structure") if R not in PrincipalIdealDomains(): raise TypeError("The base_ring (= %s) must be a principal ideal " diff --git a/src/sage/numerical/backends/generic_sdp_backend.pyx b/src/sage/numerical/backends/generic_sdp_backend.pyx index bff1e940b8f..45a56b3b6e3 100644 --- a/src/sage/numerical/backends/generic_sdp_backend.pyx +++ b/src/sage/numerical/backends/generic_sdp_backend.pyx @@ -717,13 +717,12 @@ cpdef GenericSDPBackend get_solver(solver=None, base_ring=None): sage: from sage.numerical.backends.generic_sdp_backend import GenericSDPBackend sage: class MockSDPBackend(GenericSDPBackend): ....: def solve(self): - ....: raise RuntimeError("SDP is too slow!") + ....: raise RuntimeError("SDP is too slow") sage: P = SemidefiniteProgram(solver=MockSDPBackend) sage: P.solve() Traceback (most recent call last): ... - RuntimeError: SDP is too slow! - + RuntimeError: SDP is too slow """ if solver is None: solver = default_sdp_solver() diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index 7a24fb6ab55..021c5b33aa9 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -926,7 +926,7 @@ def binpacking(items, maximum=1, k=None, solver=None, verbose=0, sage: binpacking([0.2,0.3,0.8,0.9], k=2) Traceback (most recent call last): ... - ValueError: this problem has no solution ! + ValueError: this problem has no solution We can also provide a dictionary keyed by items and associating to each item its weight. Then, the bins contain the name of the items inside it :: @@ -953,7 +953,7 @@ def binpacking(items, maximum=1, k=None, solver=None, verbose=0, raise TypeError("parameter items must be a list or a dictionary.") if max(weight.values()) > maximum: - raise ValueError("this problem has no solution !") + raise ValueError("this problem has no solution") if k is None: from sage.functions.other import ceil @@ -983,7 +983,7 @@ def binpacking(items, maximum=1, k=None, solver=None, verbose=0, try: p.solve(log=verbose) except MIPSolverException: - raise ValueError("this problem has no solution !") + raise ValueError("this problem has no solution") box = p.get_values(box, convert=bool, tolerance=integrality_tolerance) diff --git a/src/sage/quivers/representation.py b/src/sage/quivers/representation.py index fdd9bfda98e..78ed8ce6d2a 100644 --- a/src/sage/quivers/representation.py +++ b/src/sage/quivers/representation.py @@ -776,7 +776,7 @@ def create_object(self, version, key, **extra_args): Representation with dimension vector (0, 0) """ if len(key) < 4: - raise ValueError("invalid key used in QuiverRepFactory!") + raise ValueError("invalid key used in QuiverRepFactory") # Get the quiver P = key[1] @@ -807,8 +807,7 @@ def create_object(self, version, key, **extra_args): # Create and return the module return QuiverRep_with_dual_path_basis(key[0], P, key[3]) - else: - raise ValueError("invalid key used in QuiverRepFactory!") + raise ValueError("invalid key used in QuiverRepFactory") QuiverRep = QuiverRepFactory("sage.quivers.representation.QuiverRep") diff --git a/src/sage/schemes/toric/divisor_class.pyx b/src/sage/schemes/toric/divisor_class.pyx index dfbd518e951..1fde30da963 100644 --- a/src/sage/schemes/toric/divisor_class.pyx +++ b/src/sage/schemes/toric/divisor_class.pyx @@ -33,7 +33,7 @@ They behave much like ordinary vectors:: sage: D * E Traceback (most recent call last): ... - TypeError: cannot multiply two divisor classes! + TypeError: cannot multiply two divisor classes The only special method is :meth:`~ToricRationalDivisorClass.lift` to get a divisor representing a divisor class:: @@ -163,7 +163,7 @@ cdef class ToricRationalDivisorClass(Vector_rational_dense): sage: D * D Traceback (most recent call last): ... - TypeError: cannot multiply two divisor classes! + TypeError: cannot multiply two divisor classes We test standard behaviour:: @@ -223,13 +223,13 @@ cdef class ToricRationalDivisorClass(Vector_rational_dense): sage: c[0]._dot_product_(c[1]) Traceback (most recent call last): ... - TypeError: cannot multiply two divisor classes! + TypeError: cannot multiply two divisor classes sage: c[0] * c[1] # indirect doctest Traceback (most recent call last): ... - TypeError: cannot multiply two divisor classes! + TypeError: cannot multiply two divisor classes """ - raise TypeError("cannot multiply two divisor classes!") + raise TypeError("cannot multiply two divisor classes") def _latex_(self): r""" diff --git a/src/sage/sets/family.py b/src/sage/sets/family.py index 996eb106de6..a3c43af4bc5 100644 --- a/src/sage/sets/family.py +++ b/src/sage/sets/family.py @@ -325,7 +325,7 @@ def Family(indices, function=None, hidden_keys=[], hidden_function=None, lazy=Fa sage: f = Family({1:'a', 2:'b', 3:'c'}, lazy=True) Traceback (most recent call last): ... - ValueError: lazy keyword only makes sense together with function keyword ! + ValueError: lazy keyword only makes sense together with function keyword :: @@ -385,7 +385,7 @@ def Family(indices, function=None, hidden_keys=[], hidden_function=None, lazy=Fa "together with hidden_keys keyword !") if function is None: if lazy: - raise ValueError("lazy keyword only makes sense together with function keyword !") + raise ValueError("lazy keyword only makes sense together with function keyword") if isinstance(indices, dict): return FiniteFamily(indices) if isinstance(indices, (list, tuple) ): @@ -406,13 +406,14 @@ def Family(indices, function=None, hidden_keys=[], hidden_function=None, lazy=Fa return LazyFamily(indices, function, name) if lazy: - raise ValueError("lazy keyword is incompatible with hidden keys !") + raise ValueError("lazy keyword is incompatible with hidden keys") if hidden_function is None: hidden_function = function return FiniteFamilyWithHiddenKeys({i: function(i) for i in indices}, hidden_keys, hidden_function, keys=indices) + class AbstractFamily(Parent): """ The abstract class for family diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 6cf8ec78bae..227a62cb3ef 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -962,7 +962,7 @@ cdef class CoercionModel: all.append("Coercion on right operand via") all.append(y_mor) if res is not None and res is not y_mor.codomain(): - raise RuntimeError("BUG in coercion model: codomains not equal!", x_mor, y_mor) + raise RuntimeError("BUG in coercion model: codomains not equal", x_mor, y_mor) res = y_mor.codomain() all.append("Arithmetic performed after coercions.") if op is truediv and isinstance(res, Parent): From 8ff38941aac3c72947934a2e06e2e930f67c673d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 26 Aug 2022 11:21:04 -0700 Subject: [PATCH 574/591] build/pkgs/setuptools/install-requires.txt: Set upper bound --- build/pkgs/setuptools/install-requires.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/pkgs/setuptools/install-requires.txt b/build/pkgs/setuptools/install-requires.txt index 0810ca37277..486c3c348ee 100644 --- a/build/pkgs/setuptools/install-requires.txt +++ b/build/pkgs/setuptools/install-requires.txt @@ -1 +1,2 @@ -setuptools >=49.6.0 +# Set this bound until https://trac.sagemath.org/ticket/34209 adds support for PEP660 editable builds +setuptools >=49.6.0,<64.0.0 From 4c07a4d66efec0fbcc509cd222fd0e8ef5e86fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 27 Aug 2022 08:50:53 +0200 Subject: [PATCH 575/591] fix doctest --- src/sage/categories/finite_coxeter_groups.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 0f5b37577dd..f2e3b743f66 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -14,6 +14,7 @@ from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.coxeter_groups import CoxeterGroups + class FiniteCoxeterGroups(CategoryWithAxiom): r""" The category of finite Coxeter groups. @@ -889,7 +890,7 @@ def coxeter_knuth_graph(self): sage: w.coxeter_knuth_graph() Traceback (most recent call last): ... - NotImplementedError: This has only been implemented in finite type A so far! + NotImplementedError: this has only been implemented in finite type A so far """ from sage.graphs.graph import Graph R = [tuple(v) for v in self.reduced_words()] From cd72e6b8af74572a84648a759831e2f5bb5dcbb6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 09:11:26 -0700 Subject: [PATCH 576/591] src/doc/en/installation/source.rst: Fix up markup of material converted from README.md --- src/doc/en/installation/source.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index 39ccff55e52..c6377ac6077 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -380,29 +380,29 @@ Use the following instructions to get started. By default, your username in Cygwin is the same as your username in Windows. This might contain spaces and other traditionally non-UNIX-friendly characters, e.g., if it is your full name. You - can check this as follows: + can check this as follows:: $ whoami Erik M. Bray This means your default home directory on Cygwin contains this - username verbatim; in the above example, `/home/Erik M. Bray`. + username verbatim; in the above example, ``/home/Erik M. Bray``. It will save some potential trouble if you change your Cygwin home directory to contain only alphanumeric characters, for example, - `/home/embray`. The easiest way to do this is to first create + ``/home/embray``. The easiest way to do this is to first create the home directory you want to use instead, then create an - `/etc/passwd` file specifying that directory as your home, as follows: + ``/etc/passwd`` file specifying that directory as your home, as follows:: $ whocanibe=embray $ mkdir /home/$whocanibe $ mkpasswd.exe -l -u "$(whoami)" | sed -r 's,/home/[^:]+,/home/'$whocanibe, > /etc/passwd After this, close all Cygwin terminals (ensure nothing in - `C:\cygwin64` is running), then start a new Cygwin terminal and + ``C:\cygwin64`` is running), then start a new Cygwin terminal and your home directory should have moved. - There are [other ways to do - this](https://stackoverflow.com/questions/1494658/how-can-i-change-my-cygwin-home-folder-after-installation), + There are `other ways to do + this `_, but the above seems to be the simplest that's still supported. 5. (Optional) Although it is possible to install Sage's dependencies using the From 451ebe564d0adf19cf305e413d55b76db1d6b660 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 28 Aug 2022 16:51:50 -0700 Subject: [PATCH 577/591] src/sage/tensor/modules/finite_rank_free_module.py (FiniteRankFreeModule_abstract): Move tensor_power, tensor_product here from FiniteRankFreeModule --- .../tensor/modules/finite_rank_free_module.py | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 309a07cab4d..b7051065ffc 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -608,6 +608,45 @@ def _latex_(self): else: return self._latex_name + def tensor_power(self, n): + r""" + Return the ``n``-fold tensor product of ``self``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(QQ, 2) + sage: M.tensor_power(3) + Free module of type-(3,0) tensors on the 2-dimensional vector space over the Rational Field + sage: M.tensor_module(1,2).tensor_power(3) + Free module of type-(3,6) tensors on the 2-dimensional vector space over the Rational Field + """ + tensor_type = self.tensor_type() + return self.base_module().tensor_module(n * tensor_type[0], n * tensor_type[1]) + + def tensor_product(self, *others): + r""" + Return the tensor product of ``self`` and ``others``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(QQ, 2) + sage: M.tensor_product(M) + Free module of type-(2,0) tensors on the 2-dimensional vector space over the Rational Field + sage: M.tensor_product(M.tensor_module(1,2)) + Free module of type-(2,2) tensors on the 2-dimensional vector space over the Rational Field + sage: M.tensor_module(1,2).tensor_product(M) + Free module of type-(2,2) tensors on the 2-dimensional vector space over the Rational Field + sage: M.tensor_module(1,1).tensor_product(M.tensor_module(1,2)) + Free module of type-(2,3) tensors on the 2-dimensional vector space over the Rational Field + + """ + from sage.modules.free_module_element import vector + base_module = self.base_module() + if not all(module.base_module() == base_module for module in others): + raise NotImplementedError('all factors must be tensor modules over the same base module') + tensor_type = sum(vector(module.tensor_type()) for module in [self] + list(others)) + return base_module.tensor_module(*tensor_type) + def rank(self) -> int: r""" Return the rank of the free module ``self``. @@ -2881,42 +2920,3 @@ def tensor_type(self): """ return (1, 0) - - def tensor_power(self, n): - r""" - Return the ``n``-fold tensor product of ``self``. - - EXAMPLES:: - - sage: M = FiniteRankFreeModule(QQ, 2) - sage: M.tensor_power(3) - Free module of type-(3,0) tensors on the 2-dimensional vector space over the Rational Field - sage: M.tensor_module(1,2).tensor_power(3) - Free module of type-(3,6) tensors on the 2-dimensional vector space over the Rational Field - """ - tensor_type = self.tensor_type() - return self.base_module().tensor_module(n * tensor_type[0], n * tensor_type[1]) - - def tensor_product(self, *others): - r""" - Return the tensor product of ``self`` and ``others``. - - EXAMPLES:: - - sage: M = FiniteRankFreeModule(QQ, 2) - sage: M.tensor_product(M) - Free module of type-(2,0) tensors on the 2-dimensional vector space over the Rational Field - sage: M.tensor_product(M.tensor_module(1,2)) - Free module of type-(2,2) tensors on the 2-dimensional vector space over the Rational Field - sage: M.tensor_module(1,2).tensor_product(M) - Free module of type-(2,2) tensors on the 2-dimensional vector space over the Rational Field - sage: M.tensor_module(1,1).tensor_product(M.tensor_module(1,2)) - Free module of type-(2,3) tensors on the 2-dimensional vector space over the Rational Field - - """ - from sage.modules.free_module_element import vector - base_module = self.base_module() - if not all(module.base_module() == base_module for module in others): - raise NotImplementedError('all factors must be tensor modules over the same base module') - tensor_type = sum(vector(module.tensor_type()) for module in [self] + list(others)) - return base_module.tensor_module(*tensor_type) From 958359f81fe5027bf4bf502a7a1f42298bad60a5 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 29 Aug 2022 10:14:05 +0900 Subject: [PATCH 578/591] Making the copy of IndexedFreeModuleElement idempotent since it is immutable. --- .../modules/with_basis/indexed_element.pyx | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 6b861a42da1..f2fa03b81f7 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -5,10 +5,11 @@ An element in an indexed free module AUTHORS: - Travis Scrimshaw (03-2017): Moved code from :mod:`sage.combinat.free_module`. +- Travis Scrimshaw (29-08-2022): Implemented an idempotent copy. """ #***************************************************************************** -# Copyright (C) 2017 Travis Scrimshaw +# Copyright (C) 2017, 2022 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 @@ -180,6 +181,32 @@ cdef class IndexedFreeModuleElement(ModuleElement): for k, v in state[1].iteritems(): setattr(self, k, v) + def __copy__(self): + r""" + Return ``self`` since ``self`` is immutable. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: x = F.an_element() + sage: copy(x) is x + True + """ + return self + + def __deepcopy__(self, memo=None): + r""" + Return ``self`` since ``self`` is immutable. + + EXAMPLES:: + + sage: F = CombinatorialFreeModule(QQ, ['a','b','c']) + sage: x = F.an_element() + sage: deepcopy(x) is x + True + """ + return self + cpdef dict monomial_coefficients(self, bint copy=True): """ Return the internal dictionary which has the combinatorial objects From ac1bf2cea403972bf6c5e36b606c2077a28fccb0 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 29 Aug 2022 10:32:15 +0900 Subject: [PATCH 579/591] Tweak to module docstring of indexed_element.pyx. --- src/sage/modules/with_basis/indexed_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index f2fa03b81f7..cd1f17112f0 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -5,7 +5,7 @@ An element in an indexed free module AUTHORS: - Travis Scrimshaw (03-2017): Moved code from :mod:`sage.combinat.free_module`. -- Travis Scrimshaw (29-08-2022): Implemented an idempotent copy. +- Travis Scrimshaw (29-08-2022): Implemented ``copy`` as the identity map. """ #***************************************************************************** From 73f746f0016de94caddbad6fd7e74f07f4300e87 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 29 Aug 2022 11:55:26 +0900 Subject: [PATCH 580/591] Add unicode symbol 2295 for pdf docs --- src/sage_docbuild/conf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index 1e321ae14aa..336668a81fc 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -501,6 +501,7 @@ def set_intersphinx_mappings(app, config): \DeclareUnicodeCharacter{2323}{\ensuremath{\smile}} % cup product \DeclareUnicodeCharacter{00B1}{\ensuremath{\pm}} \DeclareUnicodeCharacter{2A02}{\ensuremath{\bigotimes}} + \DeclareUnicodeCharacter{2295}{\ensuremath{\oplus}} \DeclareUnicodeCharacter{2297}{\ensuremath{\otimes}} \DeclareUnicodeCharacter{2A01}{\ensuremath{\oplus}} \DeclareUnicodeCharacter{00BD}{\ensuremath{\nicefrac{1}{2}}} From cae9ee5177ad3d0d51c1344ca88c35e3cf9d2395 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Tue, 30 Aug 2022 22:32:54 +0200 Subject: [PATCH 581/591] Updated SageMath version to 9.7.rc0 --- .zenodo.json | 8 ++++---- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- build/pkgs/sage_conf/install-requires.txt | 2 +- build/pkgs/sage_docbuild/install-requires.txt | 2 +- build/pkgs/sage_setup/install-requires.txt | 2 +- build/pkgs/sage_sws2rst/install-requires.txt | 2 +- build/pkgs/sagelib/install-requires.txt | 2 +- build/pkgs/sagemath_categories/install-requires.txt | 2 +- build/pkgs/sagemath_environment/install-requires.txt | 2 +- build/pkgs/sagemath_objects/install-requires.txt | 2 +- pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf_pypi/VERSION.txt | 2 +- pkgs/sage-docbuild/VERSION.txt | 2 +- pkgs/sage-setup/VERSION.txt | 2 +- pkgs/sage-sws2rst/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 24 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 737a2a013df..022e38c3554 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -1,10 +1,10 @@ { "description": "Mirror of the Sage https://sagemath.org/ source tree", "license": "other-open", - "title": "sagemath/sage: 9.7.beta8", - "version": "9.7.beta8", + "title": "sagemath/sage: 9.7.rc0", + "version": "9.7.rc0", "upload_type": "software", - "publication_date": "2022-08-07", + "publication_date": "2022-08-30", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.7.beta8", + "identifier": "https://github.com/sagemath/sage/tree/9.7.rc0", "relation": "isSupplementTo" }, { diff --git a/VERSION.txt b/VERSION.txt index 57ef2726b25..23115dbdf96 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.7.beta8, Release Date: 2022-08-07 +SageMath version 9.7.rc0, Release Date: 2022-08-30 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 7d7f0332103..705a36ea8dd 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=41f4f552c7a5a508c229d1d2741215a1790a1520 -md5=dad74f799c46137f5d13da804da284b5 -cksum=605908675 +sha1=c44fe4052d0d6ba38b7e60b82fa757fe40290433 +md5=bd8ae7f5adee5ff7baea95f143c5f857 +cksum=371288794 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 5eeb9ce2978..07ff5381fec 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -b7acb5c14a6a13a8dd8fc8382a7f5adc0119910a +6da95c029d7e1c153af30f8f2f19396efcf7e199 diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 3e69e695072..1337b83837e 100644 --- a/build/pkgs/sage_conf/install-requires.txt +++ b/build/pkgs/sage_conf/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 9.7b8 +sage-conf ~= 9.7rc0 diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index 385ae2dc009..598d5d2c1da 100644 --- a/build/pkgs/sage_docbuild/install-requires.txt +++ b/build/pkgs/sage_docbuild/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 9.7b8 +sage-docbuild ~= 9.7rc0 diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index a638b3a1958..37423936b81 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 9.7b8 +sage-setup ~= 9.7rc0 diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index a0ebb31f9bb..ae814b1f5ca 100644 --- a/build/pkgs/sage_sws2rst/install-requires.txt +++ b/build/pkgs/sage_sws2rst/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 9.7b8 +sage-sws2rst ~= 9.7rc0 diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index dc87821cd9a..5e50bca2eb8 100644 --- a/build/pkgs/sagelib/install-requires.txt +++ b/build/pkgs/sagelib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagelib ~= 9.7b8 +sagelib ~= 9.7rc0 diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index 71565616331..ef34ec911bb 100644 --- a/build/pkgs/sagemath_categories/install-requires.txt +++ b/build/pkgs/sagemath_categories/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 9.7b8 +sagemath-categories ~= 9.7rc0 diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index d6a22924216..12ea11a8989 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 9.7b8 +sagemath-environment ~= 9.7rc0 diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index 9f70b502b2d..e79e569f420 100644 --- a/build/pkgs/sagemath_objects/install-requires.txt +++ b/build/pkgs/sagemath_objects/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 9.7b8 +sagemath-objects ~= 9.7rc0 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/src/VERSION.txt b/src/VERSION.txt index 41184bff2fe..c337fbc423a 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.7.beta8 +9.7.rc0 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 29ee897d655..aa65b1a245c 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.7.beta8' -SAGE_RELEASE_DATE='2022-08-07' -SAGE_VERSION_BANNER='SageMath version 9.7.beta8, Release Date: 2022-08-07' +SAGE_VERSION='9.7.rc0' +SAGE_RELEASE_DATE='2022-08-30' +SAGE_VERSION_BANNER='SageMath version 9.7.rc0, Release Date: 2022-08-30' diff --git a/src/sage/version.py b/src/sage/version.py index a6363c026c8..759f2141d1d 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,5 +1,5 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '9.7.beta8' -date = '2022-08-07' -banner = 'SageMath version 9.7.beta8, Release Date: 2022-08-07' +version = '9.7.rc0' +date = '2022-08-30' +banner = 'SageMath version 9.7.rc0, Release Date: 2022-08-30' From 319ecfaa335f8ba214ad59033fd91bf95579918f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:03:58 -0700 Subject: [PATCH 582/591] FiniteRankFreeModule.tensor: Use CompWithSym._canonicalize_sym_antisym --- .../tensor/modules/finite_rank_free_module.py | 27 +++++-------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 73b260a07c2..bb55959f4ed 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1609,7 +1609,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote the tensor; if none is provided, the LaTeX symbol is set to ``name`` - - ``sym`` -- (default: ``None``) a symmetry or a list of symmetries + - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries among the tensor arguments: each symmetry is described by a tuple containing the positions of the involved arguments, with the convention ``position = 0`` for the first argument. For instance: @@ -1618,7 +1618,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd arguments and a symmetry between the 2nd, 4th and 5th arguments. - - ``antisym`` -- (default: ``None``) antisymmetry or list of + - ``antisym`` -- (default: ``None``) antisymmetry or iterable of antisymmetries among the arguments, with the same convention as for ``sym`` @@ -1653,33 +1653,20 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, for more examples and documentation. """ + from .comp import CompWithSym + sym, antisym = CompWithSym._canonicalize_sym_antisym( + tensor_type[0] + tensor_type[1], sym, antisym) # Special cases: if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) elif tensor_type == (0,1): return self.linear_form(name=name, latex_name=latex_name) elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a range - # object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[1]: + if len(antisym[0]) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a range - # object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[0]: + if len(antisym[0]) == tensor_type[0]: return self.alternating_contravariant_tensor(tensor_type[0], name=name, latex_name=latex_name) # Generic case: From 8e93626a08496c71387cacd7bf9dae075803ebdc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:04:55 -0700 Subject: [PATCH 583/591] CompWithSym._canonicalize_sym_antisym: Add documentation --- src/sage/tensor/modules/comp.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 8e9cadbaa4a..9eea2bd1770 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3000,10 +3000,28 @@ def __init__(self, ring, frame, nb_indices, start_index=0, nb_indices, sym, antisym) @staticmethod - def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): + def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, + trivial_symmetries='drop'): r""" Bring sym and antisym into their canonical form. + INPUT: + + - ``nb_indices`` -- number of integer indices labeling the components + + - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries + among the tensor arguments: each symmetry is described by a tuple + containing the positions of the involved arguments, with the + convention ``position = 0`` for the first argument. For instance: + + * ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments + * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd + arguments and a symmetry between the 2nd, 4th and 5th arguments. + + - ``antisym`` -- (default: ``None``) antisymmetry or iterable of + antisymmetries among the arguments, with the same convention + as for ``sym`` + EXAMPLES:: sage: from sage.tensor.modules.comp import CompWithSym From 564be353b347cecfd4496a169b5eaff0642de03d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:26:30 -0700 Subject: [PATCH 584/591] FiniteRankFreeModule.tensor: Restore error when trivial symmetries are passed --- src/sage/tensor/modules/comp.py | 24 ++++++++++++++----- .../tensor/modules/finite_rank_free_module.py | 3 ++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 9eea2bd1770..d9a676711e1 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3022,6 +3022,10 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, antisymmetries among the arguments, with the same convention as for ``sym`` + - ``trivial_symmetries`` -- (default: ``"drop"``) if ``"error"``, raise + an :class:`IndexError` if any trivial symmetries are provided; + otherwise, silently drop them + EXAMPLES:: sage: from sage.tensor.modules.comp import CompWithSym @@ -3041,8 +3045,12 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, sym = [tuple(sym)] for isym in sym: if len(isym) < 2: - # Drop trivial symmetry - continue + if trivial_symmetries == 'error': + raise IndexError("at least two index positions must be " + + "provided to define a symmetry") + else: + # Drop trivial symmetry + continue for i in isym: if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + @@ -3053,16 +3061,20 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, antisym = [] else: # Handle the case that antisym is an iterator - antisym = list(antisym) + antisym = tuple(antisym) if antisym: if isinstance(antisym[0], (int, Integer)): # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: - antisym = [tuple(antisym)] + antisym = (tuple(antisym),) for isym in antisym: if len(isym) < 2: - # Drop trivial antisymmetry - continue + if trivial_symmetries == 'error': + raise IndexError("at least two index positions must be " + + "provided to define an antisymmetry") + else: + # Drop trivial antisymmetry + continue for i in isym: if i < 0 or i > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index bb55959f4ed..307605b2df4 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1655,7 +1655,8 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, """ from .comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym) + tensor_type[0] + tensor_type[1], sym, antisym, + trivial_symmetries='error') # Special cases: if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) From ffea896b41332047c9f6594358b8706873023c2e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:27:11 -0700 Subject: [PATCH 585/591] CompWithSym._canonicalize_sym_antisym: Code optimization --- src/sage/tensor/modules/comp.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index d9a676711e1..0854361076e 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3032,17 +3032,20 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, sage: CompWithSym._canonicalize_sym_antisym(6, [(2, 1)]) (((1, 2),), ()) """ + if not sym and not antisym: + # fast path + return (), () result_sym = [] if sym is None: - sym = [] + sym = () else: # Handle the case that sym is an iterator - sym = list(sym) + sym = tuple(sym) if sym: if isinstance(sym[0], (int, Integer)): # a single symmetry is provided as a tuple or a range object; # it is converted to a 1-item list: - sym = [tuple(sym)] + sym = (tuple(sym),) for isym in sym: if len(isym) < 2: if trivial_symmetries == 'error': @@ -3083,9 +3086,9 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, # Final consistency check: index_list = [] for isym in result_sym: - index_list += isym + index_list.extend(isym) for isym in result_antisym: - index_list += isym + index_list.extend(isym) if len(index_list) != len(set(index_list)): # There is a repeated index position: raise IndexError("incompatible lists of symmetries: the same " + From fed09d56502962e93ee9f1981a3eb6af70dbe42f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:35:42 -0700 Subject: [PATCH 586/591] CompWithSym._canonicalize_sym_antisym: Sort earlier to validate indices faster --- src/sage/tensor/modules/comp.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 0854361076e..330fe576168 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3054,11 +3054,11 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, else: # Drop trivial symmetry continue - for i in isym: - if i < 0 or i > nb_indices - 1: - raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(nb_indices-1) + "]") - result_sym.append(tuple(isym)) + isym = tuple(sorted(isym)) + if isym[0] < 0 or isym[-1] > nb_indices - 1: + raise IndexError("invalid index position: " + str(i) + + " not in [0," + str(nb_indices-1) + "]") + result_sym.append(isym) result_antisym = [] if antisym is None: antisym = [] @@ -3078,11 +3078,11 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, else: # Drop trivial antisymmetry continue - for i in isym: - if i < 0 or i > nb_indices - 1: - raise IndexError("invalid index position: " + str(i) + - " not in [0," + str(nb_indices - 1) + "]") - result_antisym.append(tuple(isym)) + isym = tuple(sorted(isym)) + if isym[0] < 0 or isym[-1] > nb_indices - 1: + raise IndexError("invalid index position: " + str(i) + + " not in [0," + str(nb_indices - 1) + "]") + result_antisym.append(isym) # Final consistency check: index_list = [] for isym in result_sym: @@ -3094,8 +3094,6 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, raise IndexError("incompatible lists of symmetries: the same " + "index position appears more than once") # Canonicalize sort order, make tuples - result_sym = [tuple(sorted(s)) for s in result_sym] - result_antisym = [tuple(sorted(s)) for s in result_antisym] result_sym = tuple(sorted(result_sym)) result_antisym = tuple(sorted(result_antisym)) return result_sym, result_antisym From 421c660af21de39acfcf53dc895d51064024fd6e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:38:59 -0700 Subject: [PATCH 587/591] src/sage/tensor/modules/finite_rank_free_module.py: Add doctest --- src/sage/tensor/modules/finite_rank_free_module.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 307605b2df4..5ffce01fe4a 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1652,6 +1652,20 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, See :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor` for more examples and documentation. + TESTS: + + Errors are raised if trivial symmetries appear in the list of symmetries or + antisymmetries. + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: M.tensor((3,0), sym=[[1]]) + Traceback (most recent call last): + ... + IndexError: at least two index positions must be provided to define a symmetry + sage: M.tensor((3,0), antisym=[[]]) + Traceback (most recent call last): + ... + IndexError: at least two index positions must be provided to define an antisymmetry """ from .comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( From a1a3f364657633f837a59022e85f0a4ba72c2512 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:49:45 -0700 Subject: [PATCH 588/591] CompWithSym.__init__: Accept keyword 'trivial_symmetries', add tests --- src/sage/tensor/modules/comp.py | 19 +++++++++++++++++-- .../tensor/modules/finite_rank_free_module.py | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 330fe576168..060295be280 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -2983,9 +2983,24 @@ class CompWithSym(Components): sage: e + d == d + e True + TESTS: + + Errors are raised if trivial symmetries appear in the list of symmetries or + antisymmetries:: + + sage: CompWithSym(QQ, V.basis(), 3, sym=[[1]]) + Traceback (most recent call last): + ... + IndexError: at least two index positions must be provided to define a symmetry + sage: CompWithSym(QQ, V.basis(), 2, antisym=[[]]) + Traceback (most recent call last): + ... + IndexError: at least two index positions must be provided to define an antisymmetry + """ def __init__(self, ring, frame, nb_indices, start_index=0, - output_formatter=None, sym=None, antisym=None): + output_formatter=None, sym=None, antisym=None, + trivial_symmetries='error'): r""" TESTS:: @@ -2997,7 +3012,7 @@ def __init__(self, ring, frame, nb_indices, start_index=0, Components.__init__(self, ring, frame, nb_indices, start_index, output_formatter) self._sym, self._antisym = self._canonicalize_sym_antisym( - nb_indices, sym, antisym) + nb_indices, sym, antisym, trivial_symmetries=trivial_symmetries) @staticmethod def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 5ffce01fe4a..889bc3fb7b0 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1655,7 +1655,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, TESTS: Errors are raised if trivial symmetries appear in the list of symmetries or - antisymmetries. + antisymmetries:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: M.tensor((3,0), sym=[[1]]) From 8a2c71a6d56ca08d8fb5793ec0cd3faa4682850f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 09:55:28 -0700 Subject: [PATCH 589/591] VectorFieldModule.tensor, VectorFieldFreeModule.tensor: Use CompWithSym._canonicalize_sym_antisym --- .../differentiable/vectorfield_module.py | 72 ++++++------------- 1 file changed, 23 insertions(+), 49 deletions(-) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 393218bc7c0..fbdd39b7aef 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -773,7 +773,11 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, AutomorphismField from sage.manifolds.differentiable.metric import (PseudoRiemannianMetric, DegenerateMetric) - if tensor_type==(1,0): + from sage.tensor.modules.comp import CompWithSym + sym, antisym = CompWithSym._canonicalize_sym_antisym( + tensor_type[0] + tensor_type[1], sym, antisym, + trivial_symmetries='error') + if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) elif tensor_type == (0,1): @@ -783,31 +787,14 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, return self.automorphism(name=name, latex_name=latex_name) elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a - # range object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[1]: + if len(antisym[0]) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a - # range object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[0]: + if len(antisym[0]) == tensor_type[0]: return self.alternating_contravariant_tensor( - tensor_type[0], name=name, - latex_name=latex_name) - elif tensor_type==(0,2) and specific_type is not None: + tensor_type[0], name=name, latex_name=latex_name) + elif tensor_type == (0,2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated @@ -816,9 +803,9 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, return self.metric(name, latex_name=latex_name, signature=(0, sign-1, 1)) # Generic case - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + return self.tensor_module(*tensor_type).element_class( + self, tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) def alternating_contravariant_tensor(self, degree, name=None, latex_name=None): @@ -2088,6 +2075,10 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, AutomorphismField, AutomorphismFieldParal) from sage.manifolds.differentiable.metric import (PseudoRiemannianMetric, DegenerateMetric) + from sage.tensor.modules.comp import CompWithSym + sym, antisym = CompWithSym._canonicalize_sym_antisym( + tensor_type[0] + tensor_type[1], sym, antisym, + trivial_symmetries='error') if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) @@ -2098,31 +2089,14 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, (AutomorphismField, AutomorphismFieldParal)): return self.automorphism(name=name, latex_name=latex_name) elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a - # range object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[1]: + if len(antisym[0]) == tensor_type[1]: return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: - if isinstance(antisym[0], (int, Integer)): - # a single antisymmetry is provided as a tuple or a - # range object; it is converted to a 1-item list: - antisym = [tuple(antisym)] - if isinstance(antisym, (tuple, list)): - antisym0 = antisym[0] - else: - antisym0 = antisym - if len(antisym0) == tensor_type[0]: + if len(antisym[0]) == tensor_type[0]: return self.alternating_contravariant_tensor( - tensor_type[0], name=name, - latex_name=latex_name) - elif tensor_type==(0,2) and specific_type is not None: + tensor_type[0], name=name, latex_name=latex_name) + elif tensor_type == (0,2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated @@ -2131,9 +2105,9 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, return self.metric(name, latex_name=latex_name, signature=(0, sign-1, 1)) # Generic case - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + return self.tensor_module(*tensor_type).element_class( + self, tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): From e34306bf0471fe2fa9da9e7b9bb86d5bf18cb8d9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 12:12:44 -0700 Subject: [PATCH 590/591] Revert "FiniteRankFreeModule.tensor: Restore error when trivial symmetries are passed" This reverts commit 564be353b347cecfd4496a169b5eaff0642de03d. --- src/sage/tensor/modules/comp.py | 24 +++++-------------- .../tensor/modules/finite_rank_free_module.py | 3 +-- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 060295be280..87d2dc0b473 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -3037,10 +3037,6 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, antisymmetries among the arguments, with the same convention as for ``sym`` - - ``trivial_symmetries`` -- (default: ``"drop"``) if ``"error"``, raise - an :class:`IndexError` if any trivial symmetries are provided; - otherwise, silently drop them - EXAMPLES:: sage: from sage.tensor.modules.comp import CompWithSym @@ -3063,12 +3059,8 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, sym = (tuple(sym),) for isym in sym: if len(isym) < 2: - if trivial_symmetries == 'error': - raise IndexError("at least two index positions must be " + - "provided to define a symmetry") - else: - # Drop trivial symmetry - continue + # Drop trivial symmetry + continue isym = tuple(sorted(isym)) if isym[0] < 0 or isym[-1] > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + @@ -3079,20 +3071,16 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, antisym = [] else: # Handle the case that antisym is an iterator - antisym = tuple(antisym) + antisym = list(antisym) if antisym: if isinstance(antisym[0], (int, Integer)): # a single antisymmetry is provided as a tuple or a range # object; it is converted to a 1-item list: - antisym = (tuple(antisym),) + antisym = [tuple(antisym)] for isym in antisym: if len(isym) < 2: - if trivial_symmetries == 'error': - raise IndexError("at least two index positions must be " + - "provided to define an antisymmetry") - else: - # Drop trivial antisymmetry - continue + # Drop trivial antisymmetry + continue isym = tuple(sorted(isym)) if isym[0] < 0 or isym[-1] > nb_indices - 1: raise IndexError("invalid index position: " + str(i) + diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 889bc3fb7b0..442b5576b49 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1669,8 +1669,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, """ from .comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym, - trivial_symmetries='error') + tensor_type[0] + tensor_type[1], sym, antisym) # Special cases: if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) From c6b6b2ed6ddc44044b8e0915d768cd22672f0dab Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Sep 2022 12:16:19 -0700 Subject: [PATCH 591/591] src/sage/tensor, src/sage/manifolds: Remove parameter 'trivial_symmetries' again --- .../differentiable/vectorfield_module.py | 6 ++--- src/sage/tensor/modules/comp.py | 23 +++---------------- .../tensor/modules/finite_rank_free_module.py | 12 ++++------ 3 files changed, 9 insertions(+), 32 deletions(-) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index fbdd39b7aef..1e097907967 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -775,8 +775,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, DegenerateMetric) from sage.tensor.modules.comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym, - trivial_symmetries='error') + tensor_type[0] + tensor_type[1], sym, antisym) if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) @@ -2077,8 +2076,7 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, DegenerateMetric) from sage.tensor.modules.comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym, - trivial_symmetries='error') + tensor_type[0] + tensor_type[1], sym, antisym) if tensor_type == (1,0): return self.element_class(self, name=name, latex_name=latex_name) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 87d2dc0b473..0bc56fe728c 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -2982,25 +2982,9 @@ class CompWithSym(Components): ) sage: e + d == d + e True - - TESTS: - - Errors are raised if trivial symmetries appear in the list of symmetries or - antisymmetries:: - - sage: CompWithSym(QQ, V.basis(), 3, sym=[[1]]) - Traceback (most recent call last): - ... - IndexError: at least two index positions must be provided to define a symmetry - sage: CompWithSym(QQ, V.basis(), 2, antisym=[[]]) - Traceback (most recent call last): - ... - IndexError: at least two index positions must be provided to define an antisymmetry - """ def __init__(self, ring, frame, nb_indices, start_index=0, - output_formatter=None, sym=None, antisym=None, - trivial_symmetries='error'): + output_formatter=None, sym=None, antisym=None): r""" TESTS:: @@ -3012,11 +2996,10 @@ def __init__(self, ring, frame, nb_indices, start_index=0, Components.__init__(self, ring, frame, nb_indices, start_index, output_formatter) self._sym, self._antisym = self._canonicalize_sym_antisym( - nb_indices, sym, antisym, trivial_symmetries=trivial_symmetries) + nb_indices, sym, antisym) @staticmethod - def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None, *, - trivial_symmetries='drop'): + def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): r""" Bring sym and antisym into their canonical form. diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 442b5576b49..53f1aa054b0 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -1654,18 +1654,14 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, TESTS: - Errors are raised if trivial symmetries appear in the list of symmetries or - antisymmetries:: + Trivial symmetries in the list of symmetries or antisymmetries are silently + ignored:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: M.tensor((3,0), sym=[[1]]) - Traceback (most recent call last): - ... - IndexError: at least two index positions must be provided to define a symmetry + Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring sage: M.tensor((3,0), antisym=[[]]) - Traceback (most recent call last): - ... - IndexError: at least two index positions must be provided to define an antisymmetry + Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring """ from .comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym(