From 1371efbf0086da87140bd920290689da62e5414b Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sat, 13 Aug 2022 06:03:45 +0800 Subject: [PATCH 001/538] generalize EllipticCurve_field.division_field() to composite orders --- src/sage/schemes/elliptic_curves/ell_field.py | 141 +++++++++++------- 1 file changed, 86 insertions(+), 55 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 5a5fdf1fcb6..42d813ca841 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -779,18 +779,17 @@ def descend_to(self, K, f=None): Elist = [E.minimal_model() for E in Elist] return Elist - def division_field(self, l, names='t', map=False, **kwds): + def division_field(self, n, names='t', map=False, **kwds): r""" - Given an elliptic curve over a number field or finite field `F` - and a prime number `\ell`, construct the `\ell`-division field - `F(E[\ell])`. + Given an elliptic curve over a number field or finite field `F` and + a positive integer `n`, construct the `n`-division field `F(E[n])`. - The `\ell`-division field is the smallest extension of `F` over - which all `\ell`-torsion points of `E` are defined. + The `n`-division field is the smallest extension of `F` over which + all `n`-torsion points of `E` are defined. INPUT: - - `\ell` -- a prime number (an element of `\ZZ`) + - `n` -- a positive integer - ``names`` -- (default: ``'t'``) a variable name for the division field - ``map`` -- (default: ``False``) also return an embedding of the :meth:`base_field` into the resulting field @@ -807,7 +806,7 @@ def division_field(self, l, names='t', map=False, **kwds): .. WARNING:: This can take a very long time when the degree of the division - field is large (e.g. when `\ell` is large or when the Galois + field is large (e.g. when `n` is large or when the Galois representation is surjective). The ``simplify`` flag also has a big influence on the running time over number fields: sometimes ``simplify=False`` is faster, sometimes the default @@ -832,8 +831,8 @@ def division_field(self, l, names='t', map=False, **kwds): Number Field in b with defining polynomial x^6 + 10*x^5 + 24*x^4 - 212*x^3 + 1364*x^2 + 24072*x + 104292 - For odd primes `\ell`, the division field is either the splitting - field of the `\ell`-division polynomial, or a quadratic extension + For odd primes `n`, the division field is either the splitting + field of the `n`-division polynomial, or a quadratic extension of it. :: sage: E = EllipticCurve('50a1') @@ -864,8 +863,7 @@ def division_field(self, l, names='t', map=False, **kwds): by y^2 = x^3 + 5*a0*x^2 + (-200*a0^2)*x + (-42000*a0^2+42000*a0+126000) over Number Field in a0 with defining polynomial x^3 - 3*x^2 + 3*x + 9 sage: K. = E.division_field(3, simplify_all=True); K # optional - sage.rings.number_field - Number Field in b with defining polynomial - x^12 + 5*x^10 + 40*x^8 + 315*x^6 + 750*x^4 + 675*x^2 + 2025 + Number Field in b with defining polynomial x^12 - 25*x^10 + 130*x^8 + 645*x^6 + 1050*x^4 + 675*x^2 + 225 Some higher-degree examples:: @@ -938,9 +936,35 @@ def division_field(self, l, names='t', map=False, **kwds): sage: K. = E.division_field(7); K # optional - sage.rings.finite_rings Finite Field in v of size 433^16 + It also works for composite orders:: + + sage: E = EllipticCurve(GF(11), [5,5]) + sage: E.change_ring(E.division_field(8)).abelian_group().torsion_subgroup(8).invariants() + (8, 8) + sage: E.change_ring(E.division_field(9)).abelian_group().torsion_subgroup(9).invariants() + (9, 9) + sage: E.change_ring(E.division_field(10)).abelian_group().torsion_subgroup(10).invariants() + (10, 10) + sage: E.change_ring(E.division_field(36)).abelian_group().torsion_subgroup(36).invariants() + (36, 36) + sage: E.change_ring(E.division_field(11)).abelian_group().torsion_subgroup(11).invariants() + (11,) + sage: E.change_ring(E.division_field(66)).abelian_group().torsion_subgroup(66).invariants() + (6, 66) + + ...also over number fields:: + + sage: R. = PolynomialRing(QQ) + sage: K. = NumberField(x^2 + 1) + sage: E = EllipticCurve([0,0,0,0,i]) + sage: L,emb = E.division_field(6, names='b', map=True); L + Number Field in b with defining polynomial x^24 + 12*x^23 + 66*x^22 - 504*x^21 + 92415*x^20 + 1372020*x^19 + 9791248*x^18 + 9161712*x^17 + 2248687014*x^16 + 39282444252*x^15 + 319379172870*x^14 + 1647604458936*x^13 + 6124888492503*x^12 + 17596271352348*x^11 + 40654930682496*x^10 + 76552797892176*x^9 + 116296878586974*x^8 + 139157022368196*x^7 + 127681305928690*x^6 + 87539428627680*x^5 + 43598049444279*x^4 + 15182945758692*x^3 + 3479289119772*x^2 + 468890060424*x + 28234163953 + sage: E.change_ring(emb).torsion_subgroup().invariants() + (6, 6) + .. SEEALSO:: - To compute a basis of the `\ell`-torsion once the base field + To compute a basis of the `n`-torsion once the base field has been extended, you may use :meth:`sage.schemes.elliptic_curves.ell_number_field.EllipticCurve_number_field.torsion_subgroup` or @@ -948,7 +972,7 @@ def division_field(self, l, names='t', map=False, **kwds): TESTS: - Some random testing:: + Some random for prime orders:: sage: def check(E, l, K): ....: EE = E.change_ring(K) @@ -994,71 +1018,78 @@ def division_field(self, l, names='t', map=False, **kwds): ``splitting_field`` method, moved from ``gal_reps.py``, make it work over number fields. - Lorenz Panny (2022): extend to finite fields + - Lorenz Panny (2023): extend to composite `n`. """ from sage.misc.verbose import verbose - l = rings.Integer(l) - if not l.is_prime(): - raise ValueError("l must be a prime number") + n = rings.Integer(n) + if n <= 0: + raise ValueError("n must be a positive integer") + + verbose("Adjoining X-coordinates of %s-torsion points" % n) - verbose("Adjoining X-coordinates of %s-torsion points" % l) F = self.base_ring() - f = self.division_polynomial(l) - if l == 2 or f.is_constant(): - # For l = 2, the division field is the splitting field of + f = self.division_polynomial(n) + + if n == 2 or f.is_constant(): + # For n = 2, the division field is the splitting field of # the division polynomial. - # If f is a non-zero constant, the l-torsion is trivial: - # This means the curve must be supersingular and l == p. + # If f is a non-zero constant, the n-torsion is trivial: + # This means the curve must be supersingular and n == p. return f.splitting_field(names, map=map, **kwds) + # We divide out the part defining points of non-maximal order. + # Clearly all points of non-maximal order are multiples of points + # of maximal order, so they cannot be defined over a larger field. + if not n.is_prime(): + for d in n.prime_divisors(): + g = self.division_polynomial(n // d) + f //= f.gcd(g) + # Compute splitting field of X-coordinates. - # The Galois group of the division field is a subgroup of GL(2,l). - # The Galois group of the X-coordinates is a subgroup of GL(2,l)/{-1,+1}. - # We need the map to change the elliptic curve invariants to K. + # The Galois group of the division field is a subgroup of GL(2,n). + # The Galois group of the X-coordinates is a subgroup of GL(2,n)/{-1,+1}. if F in NumberFields(): - deg_mult = F.degree() * l * (l+1) * (l-1)**2 // 2 + from sage.misc.misc_c import prod + deg_mult = F.degree() * prod(l * (l+1) * (l-1)**2 * l**(4*(e-1)) for l,e in n.factor()) // 2 K, F_to_K = f.splitting_field(names, degree_multiple=deg_mult, map=True, **kwds) elif F in FiniteFields(): K, F_to_K = f.splitting_field('u', map=True, **kwds) else: raise NotImplementedError('only number fields and finite fields are currently supported') - verbose("Adjoining Y-coordinates of %s-torsion points" % l) + verbose("Adjoining Y-coordinates of %s-torsion points" % n) - # THEOREM (Cremona, https://github.com/sagemath/sage/issues/11905#comment:21). - # Let K be a field, E an elliptic curve over K and p an odd - # prime number. Assume that K contains all roots of the - # p-division polynomial of E. Then either K contains all - # p-torsion points on E, or it does not contain any p-torsion - # point. + # THEOREM + # (Cremona, https://github.com/sagemath/sage/issues/11905#comment:21) + # (Later generalized to composite n by Lorenz Panny) + # + # Let K be a field, E an elliptic curve over K and n a positive + # integer. Assume that K contains all roots of the n-division + # polynomial of E, and that at least one point P of full order n + # is defined over K. Then K contains all n-torsion points on E. # # PROOF. Let G be the absolute Galois group of K (every element - # in it fixes all elements of K). For any p-torsion point P + # in it fixes all elements of K). For any n-torsion point Q # over the algebraic closure and any sigma in G, we must have - # either sigma(P) = P or sigma(P) = -P (since K contains the - # X-coordinate of P). Now assume that K does not contain all - # p-torsion points. Then there exists a point P1 and a sigma in - # G such that sigma(P1) = -P1. Now take a different p-torsion - # point P2. Since sigma(P2) must be P2 or -P2 and - # sigma(P1+P2) = sigma(P1)+sigma(P2) = sigma(P1)-P2 must - # be P1+P2 or -(P1+P2), it follows that sigma(P2) = -sigma(P2). - # Therefore, K cannot contain any p-torsion point. + # either sigma(Q) = Q or sigma(Q) = -Q (since K contains the + # X-coordinate of Q). Similarly, sigma(P+Q) must equal either + # P+Q or -(P+Q). However, since sigma is a group homomorphism, + # we have sigma(P+Q) = sigma(P) + sigma(Q) = P + sigma(Q), + # so either P + sigma(Q) = P+Q, which implies sigma(Q) = Q, + # or P + sigma(Q) = -(P+Q), which implies sigma(Q) = -2P-Q. + # The latter is impossible except for the easier case n = 2. + # Hence, sigma(Q) = Q in all cases. # # This implies that it suffices to adjoin the Y-coordinate - # of just one point. - - # First factor f over F and then compute a root X of f over K. - g = f.factor()[0][0] - X = g.map_coefficients(F_to_K).roots(multiplicities=False)[0] + # of just one full-order point. - # Polynomial defining the corresponding Y-coordinate - curve = self.defining_polynomial().map_coefficients(F_to_K) - ypol = curve(X, rings.polygen(K), 1) - L = ypol.splitting_field(names, map=map, **kwds) + x = f.change_ring(F_to_K).any_root(assume_squarefree=True) + h = self.defining_polynomial().change_ring(F_to_K)(x, rings.polygen(K), 1) + L = h.splitting_field(names, map=map, **kwds) if map: L, K_to_L = L - return L, F_to_K.post_compose(K_to_L) - else: - return L + L = L, F_to_K.post_compose(K_to_L) + return L def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, algorithm=None): r""" From 07379442e8a27ec4416995312816d89b19075a0a Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 8 Sep 2023 17:19:04 -0400 Subject: [PATCH 002/538] src/sage/doctest/control.py: double the default test timeout When running the test suite on an older machine, many files time out. For example, $ sage -t src/sage/manifolds/differentiable/tensorfield.py ... File "src/sage/manifolds/differentiable/tensorfield.py", line 248, in sage.manifolds.differentiable.tensorfield.TensorField Warning: Consider using a block-scoped tag by inserting the line 'sage: # long time' just before this line to avoid repeating the tag 4 times s = t(a.restrict(U), b) ; s # long time Timed out (and interrupt failed) ... ---------------------------------------------------------------------- Total time for all tests: 360.3 seconds cpu time: 0.0 seconds cumulative wall time: 0.0 seconds This has run over the default (non-long) test timeout of 300s. This commit doubles that default, a change that should be unobjectionable for a few reasons: 1. This timeout is a last line of defense intended to keep the test suite from looping forever when run unattended. For that purpose, ten minutes is as good as five. 2. As more tests get added to each file, those files take longer to test on the same hardware. It should therefore be expected that we will sometimes need to increase the timeout. (Basically, if anyone is hitting it, it's too low.) 3. We now use Github CI instead of patchbots for most automated testing, and Github has its own timeout. 4. There is a separate mechanism, --warn-long, intended to catch tests that run for too long. The test timeout should not be thought of as a solution to that problem. Closes: https://github.com/sagemath/sage/issues/32973 --- src/sage/doctest/control.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 9261c69dd4b..10338ec9549 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -417,7 +417,7 @@ def __init__(self, options, args): elif options.long: options.timeout = int(os.getenv('SAGE_TIMEOUT_LONG', 30 * 60)) else: - options.timeout = int(os.getenv('SAGE_TIMEOUT', 5 * 60)) + options.timeout = int(os.getenv('SAGE_TIMEOUT', 10 * 60)) # For non-default GC options, double the timeout if options.gc: options.timeout *= 2 From 27c60d767b60ba132ed942eb5113009ee624e5ab Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Wed, 20 Sep 2023 16:17:12 +0200 Subject: [PATCH 003/538] add is_noetherian and divides, for univariate --- src/sage/rings/polynomial/laurent_polynomial.pyx | 6 ++++++ src/sage/rings/polynomial/laurent_polynomial_ring_base.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index cd79996eed7..61ba3870357 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1969,3 +1969,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): 0 """ return self.__u[-self.__n] + + def divides(self, other): + R = self.parent().polynomial_ring() + p = R(self.polynomial_construction()[0]) + q = R(other.polynomial_construction()[0]) + return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index 0c9022c492c..f160502d43f 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -166,7 +166,7 @@ def is_noetherian(self): ... NotImplementedError """ - raise NotImplementedError + return self.base_ring().is_noetherian() def construction(self): """ From e4e3ced9931b4f1a34f4dbf55da90fc55b8e08bd Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Wed, 20 Sep 2023 23:17:32 +0200 Subject: [PATCH 004/538] . --- .../polynomial/laurent_polynomial_mpair.pyx | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 5db2df9dbbd..2e846ed7a53 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -113,16 +113,16 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): if isinstance(k, tuple): k = ETuple(k) D[k] = x_k - self._mon = self._mon.emin(k) # point-wise min of _mon and k + self._mon = self._mon.emin(k) # point-wise min of _mon and k else: x = D - if not self._mon.is_constant(): # factor out _mon + if not self._mon.is_constant(): # factor out _mon x = {k.esub(self._mon): x_k for k, x_k in x.iteritems()} elif (isinstance(x, LaurentPolynomial_mpair) and parent.variable_names() == x.parent().variable_names()): self._mon = (x)._mon x = (x)._poly - else: # since x should coerce into parent, _mon should be (0,...,0) + else: # since x should coerce into parent, _mon should be (0,...,0) self._mon = ETuple({}, int(parent.ngens())) self._poly = parent._R(x) CommutativeAlgebraElement.__init__(self, parent) @@ -275,7 +275,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): self._mon = ETuple({}, int(self._parent.ngens())) return - #cdef dict D = self._poly._mpoly_dict_recursive( + # cdef dict D = self._poly._mpoly_dict_recursive( # self._parent.variable_names(), # self._parent.base_ring() # ) @@ -310,7 +310,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: a.dict() # indirect doctest {(0, 0): 3, (2, -1): 1} """ - #cdef dict D = self._poly._mpoly_dict_recursive(self._parent.variable_names(), + # cdef dict D = self._poly._mpoly_dict_recursive(self._parent.variable_names(), # self._parent.base_ring()) cdef dict D = self._poly.dict() cdef dict DD @@ -1236,7 +1236,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): """ if kwds: f = self.subs(**kwds) - if x: # More than 1 non-keyword argument + if x: # More than 1 non-keyword argument return f(*x) else: return f @@ -1251,7 +1251,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): raise TypeError("number of arguments does not match the number" " of generators in parent") - #Check to make sure that we aren't dividing by zero + # Check to make sure that we aren't dividing by zero cdef Py_ssize_t m for m in range(l): if x[m] == 0: @@ -1514,11 +1514,40 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): x = 'x' i = 0 - #construct ring if none + # construct ring if none if R is None: R = LaurentPolynomialRing(self.base_ring(), x) - return R({m[i]: c for m,c in self.dict().iteritems()}) + return R({m[i]: c for m, c in self.dict().iteritems()}) + + def monomial_reduction(self): + """ + Factor ``self`` into a polynomial and a monomial. + + OUTPUT: + + A tuple ``(p, v)`` where ``p`` is the underlying polynomial and ``v`` + is a monomial. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(QQ) + sage: f = y / x + x^2 / y + 3 * x^4 * y^-2 + sage: f.monomial_reduction() + (3*x^5 + x^3*y + y^3, 1/(x*y^2)) + sage: f = y * x + x^2 / y + 3 * x^4 * y^-2 + sage: f.monomial_reduction() + (3*x^3 + y^3 + x*y, x/y^2) + sage: x.monomial_reduction() + (1, x) + sage: (y^-1).monomial_reduction() + (1, 1/y) + """ + self._normalize() + ring = self._parent._R + g = ring.gens() + mon = ring.prod(g[i] ** j for i, j in enumerate(self._mon)) + return (self._poly, mon) def factor(self): """ @@ -1825,3 +1854,9 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): if new_ring is not None: return new_ring(ans) return ans + + def divides(self, other): + R = self.parent().polynomial_ring() + p = R(self.monomial_reduction()[0]) + q = R(other.monomial_reduction()[0]) + return p.divides(q) From df7ed6f7836a303a62c38bf105e06faadd144edf Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Wed, 20 Sep 2023 23:33:56 +0200 Subject: [PATCH 005/538] divides --- src/sage/rings/polynomial/laurent_polynomial.pyx | 2 ++ src/sage/rings/polynomial/laurent_polynomial_mpair.pyx | 2 ++ src/sage/rings/polynomial/laurent_polynomial_ring.py | 5 +++-- src/sage/rings/polynomial/laurent_polynomial_ring_base.py | 4 +--- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 61ba3870357..ff043140e48 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1972,6 +1972,8 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): def divides(self, other): R = self.parent().polynomial_ring() + if not R.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 2e846ed7a53..fe199d281e3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1857,6 +1857,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): def divides(self, other): R = self.parent().polynomial_ring() + if not R.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") p = R(self.monomial_reduction()[0]) q = R(other.monomial_reduction()[0]) return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index ac40e815724..fcd7c90f2f6 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -442,9 +442,10 @@ def __init__(self, R): TESTS:: - sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() + # sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() - sage: TestSuite(LaurentPolynomialRing(Zmod(4)['T'], 'u')).run() + + # sage: TestSuite(LaurentPolynomialRing(Zmod(4)['T'], 'u')).run() """ if R.ngens() != 1: raise ValueError("must be 1 generator") diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index f160502d43f..c10cbb219b0 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -162,9 +162,7 @@ def is_noetherian(self): EXAMPLES:: sage: LaurentPolynomialRing(QQ, 2, 'x').is_noetherian() - Traceback (most recent call last): - ... - NotImplementedError + True """ return self.base_ring().is_noetherian() From 28530fb0a6ea28eb99290ebda0ed9c13ab177587 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 21 Sep 2023 16:18:20 +0200 Subject: [PATCH 006/538] avoid non integral domains --- .../rings/polynomial/laurent_polynomial.pyx | 3 +- .../polynomial/laurent_polynomial_ideal.py | 32 +++++++++++-------- .../polynomial/laurent_polynomial_ring.py | 5 ++- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index ff043140e48..b134b63ac5e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1970,10 +1970,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ return self.__u[-self.__n] + @coerce_binop def divides(self, other): R = self.parent().polynomial_ring() - if not R.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index aa18314e523..be0e109738d 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -24,6 +24,7 @@ from sage.rings.ideal import Ideal_generic from sage.structure.richcmp import op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE +from sage.arith.misc import GCD class LaurentPolynomialIdeal( Ideal_generic ): def __init__(self, ring, gens, coerce=True, hint=None): @@ -399,31 +400,36 @@ def polynomial_ideal(self, saturate=True): Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y over Rational Field """ - if self._poly_ideal is not None and (self._saturated or not saturate): - return self._poly_ideal P = self.ring() Q = self._poly_ring + if len(P.gens()) == 1: + a = [Q(p.polynomial_construction()[0]) for p in self.gens()] + if P.is_integral_domain(): + a = GCD(a) + return Q.ideal(a) + if self._poly_ideal is not None and (self._saturated or not saturate): + return self._poly_ideal gens = self.gens() if len(gens) == 0: - I = Q.ideal([]) - self._poly_ideal = I - self._hint = I + id = Q.ideal([]) + self._poly_ideal = id + self._hint = id self._saturated = True - return I + return id l2 = [f.__reduce__()[1][0] for f in gens] hint = self._hint l2 += list(hint.groebner_basis()) - I = Q.ideal(l2) + id = Q.ideal(l2) if not saturate: - self._poly_ideal = I - self._hint = I + self._poly_ideal = id + self._hint = id return Q.ideal(l2) n = P.ngens() - I = I.saturation(Q.ideal([Q.monomial(*((1,) * n))]))[0] - self._poly_ideal = I - self._hint = I + id = id.saturation(Q.ideal([Q.monomial(*((1,) * n))]))[0] + self._poly_ideal = id + self._hint = id self._saturated = True - return I + return id def groebner_basis(self, saturate=True): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index fcd7c90f2f6..22d97975cd6 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -442,10 +442,9 @@ def __init__(self, R): TESTS:: - # sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() + sage: TestSuite(LaurentPolynomialRing(Zmod(2), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() - - # sage: TestSuite(LaurentPolynomialRing(Zmod(4)['T'], 'u')).run() + sage: TestSuite(LaurentPolynomialRing(Zmod(2)['T'], 'u')).run() """ if R.ngens() != 1: raise ValueError("must be 1 generator") From fe8dbac479c135371f9d2825978a0264ce36b7cf Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 22 Sep 2023 09:04:24 +0200 Subject: [PATCH 007/538] typo in __contains__ --- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index be0e109738d..b9ead02ea3e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -197,7 +197,7 @@ def __contains__(self, f): if not f or f in self.gens(): return True f = self.ring()(f) - g = f.__reduce__()[1][0] + g = f.__reduce__()[1][1] return (g in self.polynomial_ideal()) # Operations on ideals From e79852927082127fd5c39fe03348877eee0b3367 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 22 Sep 2023 18:18:24 +0200 Subject: [PATCH 008/538] reduction of matrices of Laurent polynomials --- src/sage/matrix/matrix_mpolynomial_dense.pyx | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index d8819bdc7cc..4679f1c72a7 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -21,6 +21,7 @@ from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular +from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular from sage.libs.singular.function import singular_function @@ -554,3 +555,24 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.cache('det', d) return d + + def laurent_matrix_reduction(self): + R = self._base_ring + n_rows, n_cols = self.dimensions() + mat_l = identity_matrix(R, n_rows) + mat_r = identity_matrix(R, n_cols) + if not isinstance(R, LaurentPolynomialRing_generic): + return mat_l, self, mat_r + res = self + for j, rw in enumerate(self.rows()): + for t in R.gens(): + n = min(mon.degree(t) for a in rw for cf, mon in a) + res.rescale_row(j, t ** -n) + mat_l.rescale_col(j, t ** n) + for j, cl in enumerate(self.columns()): + for t in R.gens(): + n = min(mon.degree(t) for a in cl for cf, mon in a) + res.rescale_col(j, t ** -n) + mat_r.rescale_row(j, t ** n) + res = res.change_ring(R.polynomial_ring()) + return mat_l, res, mat_r From 97bd76c4f3e6057faa84c47da56ce7fafe8c37f1 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 22 Sep 2023 18:23:10 +0200 Subject: [PATCH 009/538] import identity --- src/sage/matrix/matrix_mpolynomial_dense.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 4679f1c72a7..ad8e8bceba3 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -19,6 +19,7 @@ AUTHOR: #***************************************************************************** from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix +from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic From 2888c7bdf8613dca8ff6cc71808bff9492815387 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 23 Sep 2023 01:29:29 +0200 Subject: [PATCH 010/538] doctests --- src/sage/matrix/matrix_mpolynomial_dense.pyx | 76 ++-- .../rings/polynomial/laurent_polynomial.pyx | 58 ++- .../polynomial/laurent_polynomial_ideal.py | 35 +- .../polynomial/laurent_polynomial_mpair.pyx | 10 +- .../polynomial/laurent_polynomial_ring.py | 6 +- .../laurent_polynomial_ring_base.py | 5 +- .../rings/polynomial/laurent_reduction.py | 50 +++ .../rings/polynomial/polynomial_element.pyx | 344 +++++++++--------- 8 files changed, 328 insertions(+), 256 deletions(-) create mode 100644 src/sage/rings/polynomial/laurent_reduction.py diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index ad8e8bceba3..0a7ba60db75 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -9,20 +9,18 @@ AUTHOR: * Martin Albrecht """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 Martin Albrecht # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix -from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular -from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular from sage.libs.singular.function import singular_function @@ -101,7 +99,8 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): [ 0 -x + y] """ x = self.fetch('echelon_form_'+algorithm) - if x is not None: return x + if x is not None: + return x if algorithm == "frac": E = self.matrix_over_field() @@ -116,8 +115,8 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if algorithm == "frac": self.cache('pivots', E.pivots()) elif algorithm == "bareiss": - l = E.swapped_columns() - self.cache('pivots', tuple(sorted(l))) + l1 = E.swapped_columns() + self.cache('pivots', tuple(sorted(l1))) elif algorithm == "row_reduction": pass @@ -154,7 +153,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): x = self.fetch('pivots') if x is None: - raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'"%self.parent()) + raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'" % self.parent()) return x def echelonize(self, algorithm='row_reduction', **kwds): @@ -262,7 +261,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.clear_cache() singular_bareiss = singular_function("bareiss") - E, l = singular_bareiss(self.T) + E, ln = singular_bareiss(self.T) m = len(E) n = len(E[0]) @@ -277,33 +276,33 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.set_unsafe(r, c, R._zero_element) from sage.rings.integer_ring import ZZ - l = [ZZ(e-1) for e in l] + ln = [ZZ(e-1) for e in ln] - self.cache('in_echelon_form_bareiss',True) + self.cache('in_echelon_form_bareiss', True) self.cache('rank', len(E)) self.cache('pivots', tuple(range(len(E)))) - self.cache('swapped_columns', tuple(l)) + self.cache('swapped_columns', tuple(ln)) elif can_convert_to_singular(self.base_ring()): self.check_mutability() self.clear_cache() - E,l = self.T._singular_().bareiss()._sage_(self.base_ring()) + E, ln = self.T._singular_().bareiss()._sage_(self.base_ring()) # clear matrix for r from 0 <= r < self._nrows: for c from 0 <= c < self._ncols: - self.set_unsafe(r,c,R._zero_element) + self.set_unsafe(r, c, R._zero_element) for r from 0 <= r < E.nrows(): for c from 0 <= c < E.ncols(): - self.set_unsafe(c,r, E[r,c]) + self.set_unsafe(c, r, E[r, c]) - self.cache('in_echelon_form_bareiss',True) + self.cache('in_echelon_form_bareiss', True) self.cache('rank', E.nrows()) self.cache('pivots', tuple(range(E.nrows()))) - self.cache('swapped_columns', l) + self.cache('swapped_columns', ln) else: @@ -387,14 +386,14 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if x is not None: return # already known to be in echelon form - nr,nc = self.nrows(),self.ncols() + nr, nc = self.nrows(), self.ncols() F = self.base_ring().base_ring() - cdef Matrix d = matrix(F,nr,nc) + cdef Matrix d = matrix(F, nr, nc) start_row = 0 for r from 0 <= r < nr: for c from 0 <= c < nc: - p = self.get_unsafe(r,c) + p = self.get_unsafe(r, c) if p.is_constant(): d.set_unsafe(r, c, p.constant_coefficient()) @@ -404,25 +403,25 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if d.get_unsafe(rc, c): r = rc break - if r!=-1: - a_inverse = ~self.get_unsafe(r,c) - self.rescale_row_c(r, a_inverse , c) + if r != -1: + a_inverse = ~self.get_unsafe(r, c) + self.rescale_row_c(r, a_inverse, c) self.swap_rows_c(r, start_row) for i from 0 <= i < nr: if i != start_row: - minus_b = -self.get_unsafe(i,c) + minus_b = -self.get_unsafe(i, c) self.add_multiple_of_row(i, start_row, minus_b, 0) - start_row +=1 + start_row += 1 d = d._parent(0) for i from start_row <= i < nr: for j from c+1 <= j < nc: - if self.get_unsafe(i,j).is_constant(): - d.set_unsafe(i,j, self.get_unsafe(i,j).constant_coefficient()) + if self.get_unsafe(i, j).is_constant(): + d.set_unsafe(i, j, self.get_unsafe(i, j).constant_coefficient()) - self.cache('in_echelon_form_row_reduction',True) + self.cache('in_echelon_form_row_reduction', True) def swapped_columns(self): """ @@ -556,24 +555,3 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.cache('det', d) return d - - def laurent_matrix_reduction(self): - R = self._base_ring - n_rows, n_cols = self.dimensions() - mat_l = identity_matrix(R, n_rows) - mat_r = identity_matrix(R, n_cols) - if not isinstance(R, LaurentPolynomialRing_generic): - return mat_l, self, mat_r - res = self - for j, rw in enumerate(self.rows()): - for t in R.gens(): - n = min(mon.degree(t) for a in rw for cf, mon in a) - res.rescale_row(j, t ** -n) - mat_l.rescale_col(j, t ** n) - for j, cl in enumerate(self.columns()): - for t in R.gens(): - n = min(mon.degree(t) for a in cl for cf, mon in a) - res.rescale_col(j, t ** -n) - mat_r.rescale_row(j, t ** n) - res = res.change_ring(R.polynomial_ring()) - return mat_l, res, mat_r diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index b134b63ac5e..917943f5619 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -592,11 +592,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif e == 0: var = "" else: - var = "*{}^{}".format(X,e) - s += "{}{}".format(x,var) + var = "*{}^{}".format(X, e) + s += "{}{}".format(x, var) first = False s = s.replace(" + -", " - ") - s = s.replace(" 1*"," ") + s = s.replace(" 1*", " ") s = s.replace(" -1*", " -") return s[1:] @@ -701,7 +701,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): # degrees cdef long result = 0 cdef long result_mon - cdef int i,j + cdef int i, j cdef long var_hash_name = hash(self.__u._parent._names[0]) for i in range(self.__u.degree()+1): result_mon = hash(self.__u[i]) @@ -913,11 +913,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): j = i - self.__n if j >= 0: self.__u._unsafe_mutate(j, value) - else: # off to the left + else: # off to the left if value != 0: self.__n = self.__n + j R = self._parent.base_ring() - coeffs = [value] + [R.zero() for _ in range(1,-j)] + self.__u.list() + coeffs = [value] + [R.zero() for _ in range(1, -j)] + self.__u.list() self.__u = self.__u._parent(coeffs) self._normalize() @@ -1282,7 +1282,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Fraction Field of Univariate Polynomial Ring in t over Rational Field """ cdef LaurentPolynomial_univariate ret - if self.__u.is_constant(): # this has a single term c*x^n + if self.__u.is_constant(): # this has a single term c*x^n ret = self._new_c() if self.__u.is_unit(): ret.__u = self.__u.inverse_of_unit() @@ -1599,7 +1599,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ return self.__n == 0 and self.__u.is_constant() - def is_square(self, root=False): r""" Return whether this Laurent polynomial is a square. @@ -1846,10 +1845,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): cdef list a = self.__u.list(copy=False) if n < 0: - v = [a[i]/(n+i+1) for i in range(min(-1-n,len(a)))] + [0] + v = [a[i] / (n + i + 1) for i in range(min(-1 - n, len(a)))] + [0] else: v = [] - v += [a[i]/(n+i+1) for i in range(max(-n,0), len(a))] + v += [a[i] / (n + i + 1) for i in range(max(-n, 0), len(a))] try: u = self._parent._R(v) except TypeError: @@ -1888,7 +1887,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ if kwds: f = self.subs(**kwds) - if x: # If there are non-keyword arguments + if x: # If there are non-keyword arguments return f(*x) else: return f @@ -1972,6 +1971,43 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): @coerce_binop def divides(self, other): + r""" + Return ``True`` if ``self`` divides ``other``. + + This method is only implemented for Laurent polynomials over an integral domain. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(ZZ) + sage: (2*x**-1 + 1).divides(4*x**-2 - 1) + True + sage: (2*x + 1).divides(4*x**2 + 1) + False + sage: (2*x + x**-1).divides(R(0)) + True + sage: R(0).divides(2*x ** -1 + 1) + False + sage: R(0).divides(R(0)) + True + sage: R. = LaurentPolynomialRing(Zmod(6)) + sage: p = 4*x + 3*x^-1 + sage: q = 5*x^2 + x + 2*x^-2 + sage: p.divides(q) + Traceback (most recent call last): + ... + NotImplementedError: divisibility test only implemented for Laurent polynomials over an integral domain + + + sage: R. = GF(2)[] + sage: S. = LaurentPolynomialRing(R) + sage: p = (x+y+1) * z**-1 + x*y + sage: q = (y^2-x^2) * z**-2 + z + x-y + sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular + (False, True) + """ + if not self.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for Laurent polynomials over an integral domain") + R = self.parent().polynomial_ring() p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index b9ead02ea3e..fbfa99fd8ac 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -26,7 +26,8 @@ from sage.structure.richcmp import op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE from sage.arith.misc import GCD -class LaurentPolynomialIdeal( Ideal_generic ): + +class LaurentPolynomialIdeal(Ideal_generic): def __init__(self, ring, gens, coerce=True, hint=None): r""" Create an ideal in a Laurent polynomial ring. @@ -92,7 +93,7 @@ def __init__(self, ring, gens, coerce=True, hint=None): """ Ideal_generic.__init__(self, ring, gens, coerce=coerce) self._poly_ring = ring.polynomial_ring() - self._poly_ideal = None # Create only as needed + self._poly_ideal = None # Create only as needed self._saturated = False if hint is None: self._hint = self._poly_ring.zero_ideal() @@ -167,11 +168,11 @@ def _richcmp_(self, right_r, op): True """ if op in (op_EQ, op_NE): - if set(self.gens()) == set(right_r.gens()): # Early abort + if set(self.gens()) == set(right_r.gens()): # Early abort return (op == op_EQ) return ((self.polynomial_ideal() == right_r.polynomial_ideal()) == (op == op_EQ)) elif op == op_LE: - if all(f in right_r.gens() for f in self.gens()): # Early abort + if all(f in right_r.gens() for f in self.gens()): # Early abort return True return self.polynomial_ideal(saturate=False) <= right_r.polynomial_ideal() elif op == op_GE: @@ -298,10 +299,10 @@ def apply_coeff_map(self, f, new_base_ring=None, forward_hint=True): else: R = ring.change_ring(new_base_ring) if forward_hint: - apply_to_hint = lambda x,f=f: x.map_coefficients(f) + apply_to_hint = lambda x, f=f: x.map_coefficients(f) else: apply_to_hint = None - return self.apply_map(lambda x,f=f: + return self.apply_map(lambda x, f=f: x.map_coefficients(f, new_base_ring=new_base_ring), new_ring=R, apply_to_hint=apply_to_hint) @@ -443,8 +444,8 @@ def groebner_basis(self, saturate=True): sage: (I + J).groebner_basis() (x - 1, y + 1) """ - l = self.polynomial_ideal(saturate=saturate).groebner_basis() - return tuple(self.ring()(x) for x in l) + gb = self.polynomial_ideal(saturate=saturate).groebner_basis() + return tuple(self.ring()(x) for x in gb) def is_one(self): """ @@ -476,10 +477,10 @@ def is_binomial(self, groebner_basis=False): True """ if groebner_basis: - l = self.groebner_basis() + gb = self.groebner_basis() else: - l = self.gens() - return all(not f or f.number_of_terms() == 2 for f in l) + gb = self.gens() + return all(not f or f.number_of_terms() == 2 for f in gb) def associated_primes(self): """ @@ -499,9 +500,9 @@ def associated_primes(self): Ideal (z^2 - y, y*z + 2, y^2 + 2*z) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ - l = self.polynomial_ideal(saturate=False).associated_primes() - l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] - return tuple(I for I in l2 if not I.is_one()) + ap = self.polynomial_ideal(saturate=False).associated_primes() + ap2 = [self.ring().ideal(id.gens(), hint=id) for Iid in ap] + return tuple(id for id in ap2 if not id.is_one()) def minimal_associated_primes(self, saturate=False): """ @@ -521,9 +522,9 @@ def minimal_associated_primes(self, saturate=False): Ideal (z^3 + 2, -z^2 + y) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ - l = self.polynomial_ideal(saturate=saturate).minimal_associated_primes() - l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] - return tuple(I for I in l2 if not I.is_one()) + ap = self.polynomial_ideal(saturate=saturate).minimal_associated_primes() + ap2 = [self.ring().ideal(id.gens(), hint=id) for id in ap] + return tuple(id for id in ap2 if not id.is_one()) def radical(self): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index fe199d281e3..efab709fd44 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1241,19 +1241,19 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): else: return f - cdef int l = len(x) + cdef int ln = len(x) - if l == 1 and isinstance(x[0], (tuple, list)): + if ln == 1 and isinstance(x[0], (tuple, list)): x = x[0] - l = len(x) + ln = len(x) - if l != self._parent.ngens(): + if ln != self._parent.ngens(): raise TypeError("number of arguments does not match the number" " of generators in parent") # Check to make sure that we aren't dividing by zero cdef Py_ssize_t m - for m in range(l): + for m in range(ln): if x[m] == 0: if self.has_inverse_of(m): raise ZeroDivisionError diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 22d97975cd6..38f9f7a8ebb 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -327,8 +327,8 @@ def extract(T, indices): if not all(r == 0 for r in extract(K, remaining)): raise SplitDictError('split not possible') G = extract(K, group_by) - I = extract(K, indices) - result.setdefault(G, dict()).update({I: V}) + In = extract(K, indices) + result.setdefault(G, dict()).update({In: V}) if not group_by: return result.popitem()[1] else: @@ -755,7 +755,7 @@ def _element_constructor_(self, x, mon=None): P = parent(x) if P is self.polynomial_ring(): from sage.rings.polynomial.polydict import ETuple - return self.element_class( self, x, mon=ETuple({}, int(self.ngens())) ) + return self.element_class(self, x, mon=ETuple({}, int(self.ngens()))) elif isinstance(x, Expression): return x.laurent_polynomial(ring=self) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index c10cbb219b0..95ea676e0d3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -278,8 +278,7 @@ def _coerce_map_from_(self, R): f = self._coerce_map_via([self._R], R) if f is not None: return f - if (isinstance(R, LaurentPolynomialRing_generic) - and self._R.has_coerce_map_from(R._R)): + if isinstance(R, LaurentPolynomialRing_generic) and self._R.has_coerce_map_from(R._R): return self._generic_coerce_map(R) def __eq__(self, right): @@ -480,7 +479,7 @@ def krull_dimension(self): """ raise NotImplementedError - def random_element(self, low_degree=-2, high_degree=2, terms=5, choose_degree=False,*args, **kwds): + def random_element(self, low_degree=-2, high_degree=2, terms=5, choose_degree=False, *args, **kwds): """ EXAMPLES:: diff --git a/src/sage/rings/polynomial/laurent_reduction.py b/src/sage/rings/polynomial/laurent_reduction.py new file mode 100644 index 00000000000..c26b667b492 --- /dev/null +++ b/src/sage/rings/polynomial/laurent_reduction.py @@ -0,0 +1,50 @@ +from sage.matrix.constructor import identity_matrix +from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic + + +def laurent_matrix_reduction(A): + """ + From a matrix `A` of Laurent polynomials, apply elementary operations + to obtain a matrix `P` of polynomials such that the variables do not divide + no column and no row. + + OUTPUT: Three matrices `L`, `P`, `R` such that `A = L P R`, where `L` and + `R` are diagonal with monomial entries. + + EXAMPLES: + + sage: from sage.rings.polynomial.laurent_reduction import laurent_matrix_reduction + sage: R. = LaurentPolynomialRing(QQ) + sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] + sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] + sage: A = matrix(R, 2, L) + sage: lf, P, rg = laurent_matrix_reduction(A) + sage: lf + [ x^-2 0] + [ 0 x^-1*y^-2] + sage: P + [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] + [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] + sage: rg + [y 0] + [0 1] + """ + R = A.base_ring() + n_rows, n_cols = A.dimensions() + mat_l = identity_matrix(R, n_rows) + mat_r = identity_matrix(R, n_cols) + if not isinstance(R, LaurentPolynomialRing_generic): + return mat_l, A, mat_r + res = A + for j, rw in enumerate(A.rows()): + for t in R.gens(): + n = min(mon.degree(t) for a in rw for cf, mon in a) + res.rescale_row(j, t ** -n) + mat_l.rescale_col(j, t ** n) + for j, cl in enumerate(A.columns()): + for t in R.gens(): + n = min(mon.degree(t) for a in cl for cf, mon in a) + res.rescale_col(j, t ** -n) + mat_r.rescale_row(j, t ** n) + res = res.change_ring(R.polynomial_ring()) + return mat_l, res, mat_r diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index c5a1129aecf..06b5ab0eb43 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -213,7 +213,7 @@ cdef class Polynomial(CommutativePolynomial): .. automethod:: _mul_trunc_ """ - def __init__(self, parent, is_gen = False, construct=False): + def __init__(self, parent, is_gen=False, construct=False): """ The following examples illustrate creation of elements of polynomial rings, and some basic arithmetic. @@ -357,7 +357,7 @@ cdef class Polynomial(CommutativePolynomial): from sage.plot.all import plot, point if R.characteristic() == 0: if xmin is None and xmax is None: - (xmin, xmax) = (-1,1) + (xmin, xmax) = (-1, 1) elif xmin is None or xmax is None: raise AttributeError("must give both plot endpoints") return plot(self.__call__, (xmin, xmax), *args, **kwds) @@ -365,10 +365,10 @@ cdef class Polynomial(CommutativePolynomial): if R.is_finite(): v = list(R) v.sort() - w = dict([(v[i],i) for i in range(len(v))]) + w = dict([(v[i], i) for i in range(len(v))]) z = [(i, w[self(v[i])]) for i in range(len(v))] return point(z, *args, **kwds) - raise NotImplementedError("plotting of polynomials over %s not implemented"%R) + raise NotImplementedError("plotting of polynomials over %s not implemented" % R) cpdef _lmul_(self, Element left): """ @@ -832,7 +832,7 @@ cdef class Polynomial(CommutativePolynomial): # is more permissive about its arguments than we are. top = top(*args, **kwds) except TypeError: - if args: # bwd compat: nonsense *keyword* arguments are okay + if args: # bwd compat: nonsense *keyword* arguments are okay raise TypeError("Wrong number of arguments") else: eval_coeffs = True @@ -912,7 +912,7 @@ cdef class Polynomial(CommutativePolynomial): d = pol.degree() if d <= 0 or (isinstance(a, Element) and R.is_exact() and a.is_zero()): - return cst # with the right parent thanks to the above coercion + return cst # with the right parent thanks to the above coercion elif pol._parent is R and a.is_gen(): return pol elif hasattr(a, "_evaluate_polynomial"): @@ -1078,18 +1078,18 @@ cdef class Polynomial(CommutativePolynomial): cdef Py_ssize_t d2 = pol.degree() # Special case constant polynomials - if d1 == -1: # self is the 0 polynomial + if d1 == -1: # self is the 0 polynomial if d2 == -1: - return rich_to_bool(op, 0) # both polynomials are 0 + return rich_to_bool(op, 0) # both polynomials are 0 elif d2 == 0: return richcmp(self._parent._base.zero(), pol.get_unsafe(0), op) - return rich_to_bool_sgn(op, -1) # we have d2 > 0 - elif d1 == 0: # self is a nonzero constant + return rich_to_bool_sgn(op, -1) # we have d2 > 0 + elif d1 == 0: # self is a nonzero constant if d2 == -1: return richcmp(self.get_unsafe(0), pol._parent._base.zero(), op) elif d2 == 0: return richcmp(self.get_unsafe(0), pol.get_unsafe(0), op) - return rich_to_bool_sgn(op, -1) # we have d2 > d1 == 0 + return rich_to_bool_sgn(op, -1) # we have d2 > d1 == 0 # For different degrees, compare the degree if d1 != d2: @@ -1272,12 +1272,12 @@ cdef class Polynomial(CommutativePolynomial): TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' """ - cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap + cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap cdef long result_mon cdef long c_hash cdef long var_name_hash cdef int i - for i from 0<= i <= self.degree(): + for i from 0 <= i <= self.degree(): if i == 1: # we delay the hashing until now to not waste it on a constant poly var_name_hash = hash(self._parent._names[0]) @@ -1331,7 +1331,7 @@ cdef class Polynomial(CommutativePolynomial): a = im_gens[0] d = self.degree() if d == -1: - return codomain.zero() # Special case: 0 should always coerce to 0 + return codomain.zero() # Special case: 0 should always coerce to 0 if base_map is None: base_map = codomain.coerce_map_from(self.base_ring()) result = base_map(self.get_unsafe(d)) @@ -1661,9 +1661,9 @@ cdef class Polynomial(CommutativePolynomial): for i in range(n+1): for j in range(n-1): M[i+j, j+n] = m[i] - v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 + v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 if M.is_invertible(): - x = M.solve_right(v) # there has to be a better way to solve + x = M.solve_right(v) # there has to be a better way to solve return a.parent()(list(x)[0:n]) else: raise ValueError("Impossible inverse modulo") @@ -1846,7 +1846,7 @@ cdef class Polynomial(CommutativePolynomial): This is the default implementation that does the multiplication and then truncate! There are custom implementations in several subclasses: - - :meth:`on dense polynomial over integers (via FLINT) ` + - :meth:`on dense polynomial over integers (via FLINT) ` - :meth:`on dense polynomial over Z/nZ (via FLINT) ` @@ -1961,7 +1961,7 @@ cdef class Polynomial(CommutativePolynomial): """ if self.degree() < 0: raise ValueError("square-free decomposition not defined for zero polynomial") - if hasattr(self.base_ring(),'_squarefree_decomposition_univariate_polynomial'): + if hasattr(self.base_ring(), '_squarefree_decomposition_univariate_polynomial'): return self.base_ring()._squarefree_decomposition_univariate_polynomial(self) raise NotImplementedError("square-free decomposition not implemented for this polynomial") @@ -2188,11 +2188,11 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("ring must be an extension of the base ring") if not (ring.is_field() and ring.is_finite()): raise NotImplementedError - allowed_deg_mult = Integer(ring.factored_order()[0][1]) # generally it will be the quotient of this by the degree of the base ring. + allowed_deg_mult = Integer(ring.factored_order()[0][1]) # generally it will be the quotient of this by the degree of the base ring. if degree is None: x = self._parent.gen() if allowed_deg_mult == 1: - xq = pow(x,q,self) + xq = pow(x, q, self) self = self.gcd(xq-x) degree = -1 if self.degree() == 0: @@ -2210,7 +2210,7 @@ cdef class Polynomial(CommutativePolynomial): break while d < allowed_deg_mult: d = d+1 - xq = pow(xq,q,self) + xq = pow(xq, q, self) if d.divides(allowed_deg_mult): break A = self.gcd(xq-x) @@ -2234,8 +2234,8 @@ cdef class Polynomial(CommutativePolynomial): break while True: # we waste a little effort here in computing the xq again. - d = d+1 - xq = pow(xq,q,self) + d = d + 1 + xq = pow(xq, q, self) if allowed_deg_mult.divides(d): break A = self.gcd(xq-x) @@ -2257,7 +2257,7 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("no roots D %s" % self) break d = d+1 - xq = pow(xq,q,self) + xq = pow(xq, q, self) if d == degree: break A = self.gcd(xq-x) @@ -2273,13 +2273,13 @@ cdef class Polynomial(CommutativePolynomial): if degree == 1: ring = self.base_ring() else: - ring = self.base_ring().extension(degree) # this won't work yet. + ring = self.base_ring().extension(degree) # this won't work yet. # now self has only roots of degree ``degree``. # for now, we only implement the Cantor-Zassenhaus split k = self.degree() // degree if k == 1: try: - return self.roots(ring, multiplicities=False)[0] # is there something better to do here? + return self.roots(ring, multiplicities=False)[0] # is there something better to do here? except IndexError: raise ValueError("no roots F %s" % self) if q % 2 == 0: @@ -2289,8 +2289,8 @@ cdef class Polynomial(CommutativePolynomial): continue T = T.monic() C = T - for i in range(degree-1): - C = T + pow(C,q,self) + for i in range(degree - 1): + C = T + pow(C, q, self) h = self.gcd(C) hd = h.degree() if hd != 0 and hd != self.degree(): @@ -2536,7 +2536,7 @@ cdef class Polynomial(CommutativePolynomial): else: v = [R.zero()]*right + [R.one()] return self.parent()(v, check=False) - if right > 20: # no gain below + if right > 20: # no gain below try: p = self.parent().characteristic() except (AttributeError, NotImplementedError): @@ -2557,7 +2557,7 @@ cdef class Polynomial(CommutativePolynomial): q, r = q.quo_rem(p) if r != 0: if sparse: - tmp = self.parent()({e*k : d[k]**e for k in d}) + tmp = self.parent()({e * k: d[k] ** e for k in d}) else: tmp = [0] * (e * len(c) - e + 1) for i in range(len(c)): @@ -2728,19 +2728,19 @@ cdef class Polynomial(CommutativePolynomial): if y.find("-") == 0: y = y[1:] if not atomic_repr and n > 0 and (y.find("+") != -1 or y.find("-") != -1): - x = "(%s)"%x + x = "(%s)" % x if n > 1: - var = "*%s^%s"%(name,n) - elif n==1: - var = "*%s"%name + var = "*%s^%s" % (name, n) + elif n == 1: + var = "*%s" % name else: var = "" sbuf.write(x) sbuf.write(var) s = sbuf.getvalue() s = s.replace(" + -", " - ") - s = re.sub(r' 1(\.0+)?\*',' ', s) - s = re.sub(r' -1(\.0+)?\*',' -', s) + s = re.sub(r' 1(\.0+)?\*', ' ', s) + s = re.sub(r' -1(\.0+)?\*', ' -', s) if s == " ": return "0" return s[1:] @@ -2813,7 +2813,7 @@ cdef class Polynomial(CommutativePolynomial): x = "\\left(%s\\right)" % x if n > 1: var = "|%s^{%s}" % (name, n) - elif n==1: + elif n == 1: var = "|%s" % name else: var = "" @@ -3150,12 +3150,12 @@ cdef class Polynomial(CommutativePolynomial): - Didier Deshommes (2006-05-25) """ - return self._parent(polynomial_fateman._mul_fateman_mul(self,right)) + return self._parent(polynomial_fateman._mul_fateman_mul(self, right)) @cython.boundscheck(False) @cython.wraparound(False) @cython.overflowcheck(False) - def _mul_karatsuba(self, right, K_threshold = None): + def _mul_karatsuba(self, right, K_threshold=None): r""" Compute the product of two polynomials using the Karatsuba divide and conquer multiplication algorithm. This is only used over a @@ -3328,8 +3328,8 @@ cdef class Polynomial(CommutativePolynomial): if n <= K_threshold or m <= K_threshold: return self._new_generic(do_schoolbook_product(f, g, -1)) if n == m: - return self._new_generic(do_karatsuba(f,g, K_threshold, 0, 0, n)) - return self._new_generic(do_karatsuba_different_size(f,g, K_threshold)) + return self._new_generic(do_karatsuba(f, g, K_threshold, 0, 0, n)) + return self._new_generic(do_karatsuba_different_size(f, g, K_threshold)) @cython.boundscheck(False) @cython.wraparound(False) @@ -3487,7 +3487,7 @@ cdef class Polynomial(CommutativePolynomial): if var not in variables: x = base_ring(self) if base_ring else self const_ix = ETuple((0,)*len(variables)) - return { const_ix: x } + return {const_ix: x} cdef tuple prev_variables = variables[:variables.index(var)] const_ix = ETuple((0,)*len(prev_variables)) @@ -3509,7 +3509,7 @@ cdef class Polynomial(CommutativePolynomial): cdef dict D = {} cdef tuple leftovers = (0,) * (len(variables) - len(prev_variables) - 1) for k in range(len(mpolys)): - for i,a in mpolys[k].iteritems(): + for i, a in mpolys[k].iteritems(): j = ETuple((k,) + leftovers) D[i + j] = a @@ -3680,7 +3680,7 @@ cdef class Polynomial(CommutativePolynomial): for y in x: d = d.lcm(y.denominator()) return d - except(AttributeError): + except (AttributeError): return self.base_ring().one() def numerator(self): @@ -3951,7 +3951,7 @@ cdef class Polynomial(CommutativePolynomial): """ return [self.diff()] - def integral(self,var=None): + def integral(self, var=None): """ Return the integral of this polynomial. @@ -4571,39 +4571,39 @@ cdef class Polynomial(CommutativePolynomial): # PARI for smaller degree over other rings besides Z, and use # NTL in general. # A remark from Bill Hart (2007-09-25) about the above observation: - ## NTL uses the Berlekamp-Zassenhaus method with van Hoeij's improvements. - ## But so does Magma since about Jul 2001. - ## - ## But here's the kicker. PARI also uses this algorithm. Even Maple uses - ## it! - ## - ## NTL's LLL algorithms are extremely well developed (van Hoeij uses - ## LLL). There is also a possible speed difference in whether one uses - ## quadratic convergence or not in the Hensel lift. But the right choice - ## is not always what one thinks. - ## - ## But more than likely NTL is just better for large problems because - ## Victor Shoup was very careful with the choice of strategies and - ## parameters he used. Paul Zimmerman supplied him with a pile of - ## polynomials to factor for comparison purposes and these seem to have - ## been used to tune the algorithm for a wide range of inputs, including - ## cases that van Hoeij's algorithm doesn't usually like. - ## - ## If you have a bound on the coefficients of the factors, one can surely - ## do better than a generic implementation, but probably not much better - ## if there are many factors. - ## - - ## HUGE TODO, refactor the code below here such that this method will - ## have as only the following code - ## - ## R = self.parent().base_ring() - ## return R._factor_univariate_polynomial(self) - ## - ## in this way we can move the specific logic of factoring to the - ## self.parent().base_ring() and get rid of all the ugly - ## is_SomeType(R) checks and get way nicer structured code - ## 200 lines of spaghetti code is just way to much! + # # NTL uses the Berlekamp-Zassenhaus method with van Hoeij's improvements. + # # But so does Magma since about Jul 2001. + # # + # # But here's the kicker. PARI also uses this algorithm. Even Maple uses + # # it! + # # + # # NTL's LLL algorithms are extremely well developed (van Hoeij uses + # # LLL). There is also a possible speed difference in whether one uses + # # quadratic convergence or not in the Hensel lift. But the right choice + # # is not always what one thinks. + # # + # # But more than likely NTL is just better for large problems because + # # Victor Shoup was very careful with the choice of strategies and + # # parameters he used. Paul Zimmerman supplied him with a pile of + # # polynomials to factor for comparison purposes and these seem to have + # # been used to tune the algorithm for a wide range of inputs, including + # # cases that van Hoeij's algorithm doesn't usually like. + # # + # # If you have a bound on the coefficients of the factors, one can surely + # # do better than a generic implementation, but probably not much better + # # if there are many factors. + # # + + # # HUGE TODO, refactor the code below here such that this method will + # # have as only the following code + # # + # # R = self.parent().base_ring() + # # return R._factor_univariate_polynomial(self) + # # + # # in this way we can move the specific logic of factoring to the + # # self.parent().base_ring() and get rid of all the ugly + # # is_SomeType(R) checks and get way nicer structured code + # # 200 lines of spaghetti code is just way to much! if self.degree() < 0: raise ArithmeticError("factorization of {!r} is not defined".format(self)) @@ -4617,7 +4617,7 @@ cdef class Polynomial(CommutativePolynomial): try: F = flatten(self).factor(**kwargs) unflatten = flatten.section() - return Factorization(((unflatten(f),m) for (f,m) in F), unit = F.unit()) + return Factorization(((unflatten(f), m) for (f, m) in F), unit=F.unit()) except NotImplementedError: pass @@ -4650,7 +4650,7 @@ cdef class Polynomial(CommutativePolynomial): # This was copied from the general multivariate implementation try: if R.is_finite(): - if R.characteristic() > 1<<29: + if R.characteristic() > 1 << 29: raise NotImplementedError("Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") P = self._parent @@ -4658,8 +4658,8 @@ cdef class Polynomial(CommutativePolynomial): S = self._singular_().factorize() factors = S[1] exponents = S[2] - v = sorted([( P(factors[i+1]), - sage.rings.integer.Integer(exponents[i+1])) + v = sorted([(P(factors[i + 1]), + sage.rings.integer.Integer(exponents[i + 1])) for i in range(len(factors))]) unit = P.one() for i in range(len(v)): @@ -4936,7 +4936,7 @@ cdef class Polynomial(CommutativePolynomial): raise NotImplementedError("splitting_field() is only implemented over number fields and finite fields") - def pseudo_quo_rem(self,other): + def pseudo_quo_rem(self, other): r""" Compute the pseudo-division of two polynomials. @@ -4996,7 +4996,7 @@ cdef class Polynomial(CommutativePolynomial): e -= 1 q = d**e - return (q*Q,q*R) + return (q * Q, q * R) @coerce_binop def gcd(self, other): @@ -5089,7 +5089,7 @@ cdef class Polynomial(CommutativePolynomial): try: doit = self._parent._base._gcd_univariate_polynomial except AttributeError: - raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials"%self._parent._base) + raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials" % self._parent._base) else: return doit(self, other) @@ -5462,7 +5462,7 @@ cdef class Polynomial(CommutativePolynomial): return R.fraction_field()[self._parent.variable_name()].quotient(self, names) - def sylvester_matrix(self, right, variable = None): + def sylvester_matrix(self, right, variable=None): """ Return the Sylvester matrix of ``self`` and ``right``. @@ -5588,10 +5588,10 @@ cdef class Polynomial(CommutativePolynomial): # sylvester_matrix() in multi_polynomial.pyx. if self._parent != right.parent(): - a, b = coercion_model.canonical_coercion(self,right) + a, b = coercion_model.canonical_coercion(self, right) variable = a.parent()(self.variables()[0]) - #We add the variable to cover the case that right is a multivariate - #polynomial + # We add the variable to cover the case that right is a multivariate + # polynomial return a.sylvester_matrix(b, variable) if variable: @@ -6446,13 +6446,18 @@ cdef class Polynomial(CommutativePolynomial): e = self.exponents() c = self.coefficients() - if len(e) == 0: return [] + if len(e) == 0: + return [] if len(e) == 1: - if e[0] == 0: return [] - else: return [(infinity.infinity, e[0])] + if e[0] == 0: + return [] + else: + return [(infinity.infinity, e[0])] - if e[0] == 0: slopes = [] - else: slopes = [(infinity.infinity, e[0])] + if e[0] == 0: + slopes = [] + else: + slopes = [(infinity.infinity, e[0])] points = [(e[0], c[0].valuation(p)), (e[1], c[1].valuation(p))] slopes.append((-(c[1].valuation(p)-c[0].valuation(p))/(e[1] - e[0]), e[1]-e[0])) @@ -6463,8 +6468,8 @@ cdef class Polynomial(CommutativePolynomial): slopes = slopes[:-1] points = points[:-1] s = -(v-points[-1][1])/(e[i]-points[-1][0]) - slopes.append((s,e[i]-points[-1][0])) - points.append((e[i],v)) + slopes.append((s, e[i] - points[-1][0])) + points.append((e[i], v)) return slopes @@ -6508,7 +6513,7 @@ cdef class Polynomial(CommutativePolynomial): if m != n or p[n] != q[n]: continue alpha = (q[n-1] - p[n-1])/(n*p[n]) - if alpha.is_integer(): # ZZ() might work for non-integers... + if alpha.is_integer(): # ZZ() might work for non-integers... alpha = ZZ(alpha) else: continue @@ -7178,7 +7183,7 @@ cdef class Polynomial(CommutativePolynomial): if Sf is not QQ or (d1 <= N and d2 <= N): algorithm = "resultant" else: - c = d1*sum(bool(p1[i]) for i in range(d1 + 1))*\ + c = d1*sum(bool(p1[i]) for i in range(d1 + 1)) * \ d2*sum(bool(p2[i]) for i in range(d2 + 1)) if c <= N**4: algorithm = "resultant" @@ -7591,8 +7596,7 @@ cdef class Polynomial(CommutativePolynomial): return self # return 0 n = self.degree() base_ring = self._parent.base_ring() - if (is_MPolynomialRing(base_ring) or - is_PowerSeriesRing(base_ring)): + if (is_MPolynomialRing(base_ring) or is_PowerSeriesRing(base_ring)): # It is often cheaper to compute discriminant of simple # multivariate polynomial and substitute the real # coefficients into that result (see #16014). @@ -7601,13 +7605,13 @@ cdef class Polynomial(CommutativePolynomial): k = d.degree() r = n % 4 - u = -1 # (-1)**(n*(n-1)/2) + u = -1 # (-1)**(n*(n-1)/2) if r == 0 or r == 1: u = 1 try: an = self.get_coeff_c(n)**(n - k - 2) except ZeroDivisionError: - assert(n-k-2 == -1) + assert (n-k-2 == -1) # Rather than dividing the resultant by the leading coefficient, # we alter the Sylvester matrix (see #11782). mat = self.sylvester_matrix(d) @@ -7656,14 +7660,14 @@ cdef class Polynomial(CommutativePolynomial): if degree is not None: d = degree if d != degree: - raise ValueError("degree argument must be a non-negative integer, got %s"%(degree)) + raise ValueError("degree argument must be a non-negative integer, got %s" % (degree)) if len(v) < degree+1: v.reverse() v = [self.base_ring().zero()]*(degree+1-len(v)) + v elif len(v) > degree+1: v = v[:degree+1] v.reverse() - else: # len(v) == degree + 1 + else: # len(v) == degree + 1 v.reverse() else: v.reverse() @@ -8418,9 +8422,9 @@ cdef class Polynomial(CommutativePolynomial): sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)) output_fp = isinstance(L, (sage.rings.abc.RealField, - sage.rings.abc.ComplexField, - sage.rings.abc.RealDoubleField, - sage.rings.abc.ComplexDoubleField)) + sage.rings.abc.ComplexField, + sage.rings.abc.RealDoubleField, + sage.rings.abc.ComplexDoubleField)) input_complex = isinstance(K, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) output_complex = isinstance(L, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) input_gaussian = (isinstance(K, sage.rings.abc.NumberField_quadratic) @@ -8503,20 +8507,20 @@ cdef class Polynomial(CommutativePolynomial): from sage.symbolic.constants import I coeffs = self.list() D = coeffs[1]*coeffs[1] - 4*coeffs[0]*coeffs[2] - l = None + l0 = None if D > 0: - l = [((-coeffs[1]-sqrt(D))/2/coeffs[2], 1), - ((-coeffs[1]+sqrt(D))/2/coeffs[2], 1)] + l0 = [((-coeffs[1] - sqrt(D)) / 2 / coeffs[2], 1), + ((-coeffs[1] + sqrt(D)) / 2 / coeffs[2], 1)] elif D < 0: - l = [((-coeffs[1]-I*sqrt(-D))/2/coeffs[2], 1), - ((-coeffs[1]+I*sqrt(-D))/2/coeffs[2], 1)] + l0 = [((-coeffs[1] - I * sqrt(-D)) / 2 / coeffs[2], 1), + ((-coeffs[1] + I * sqrt(-D)) / 2 / coeffs[2], 1)] elif D == 0: - l = [(-coeffs[1]/2/coeffs[2], 2)] - if l: + l0 = [(-coeffs[1] / 2 / coeffs[2], 2)] + if l0: if multiplicities: - return l + return l0 else: - return [val for val,m in l] + return [val for val, m in l0] from sage.symbolic.ring import SR vname = 'do_not_use_this_name_in_a_polynomial_coefficient' var = SR(vname) @@ -8534,7 +8538,7 @@ cdef class Polynomial(CommutativePolynomial): # and complex root isolation and for p-adic factorization if (is_IntegerRing(K) or is_RationalField(K) or isinstance(K, sage.rings.abc.AlgebraicRealField)) and \ - isinstance(L, (sage.rings.abc.AlgebraicRealField, sage.rings.abc.RealIntervalField)): + isinstance(L, (sage.rings.abc.AlgebraicRealField, sage.rings.abc.RealIntervalField)): from sage.rings.polynomial.real_roots import real_roots @@ -8564,7 +8568,7 @@ cdef class Polynomial(CommutativePolynomial): if (is_IntegerRing(K) or is_RationalField(K) or isinstance(K, sage.rings.abc.AlgebraicField_common) or input_gaussian) and \ - isinstance(L, (sage.rings.abc.ComplexIntervalField, sage.rings.abc.AlgebraicField_common)): + isinstance(L, (sage.rings.abc.ComplexIntervalField, sage.rings.abc.AlgebraicField_common)): from sage.rings.polynomial.complex_roots import complex_roots @@ -8682,7 +8686,7 @@ cdef class Polynomial(CommutativePolynomial): pass else: if multiplicities: - seq.append((rt,fac[1])) + seq.append((rt, fac[1])) else: seq.append(rt) return seq @@ -9088,7 +9092,7 @@ cdef class Polynomial(CommutativePolynomial): coeffs = [] m = Q.degree() // 2 for i in reversed(range(m + 1)): - coeffs.insert(0, Q[2*i]) # Note: degree of Q may be less than 2*i + coeffs.insert(0, Q[2*i]) # Note: degree of Q may be less than 2*i Q = (Q % (x**2 + q)**i) // x return S(coeffs), cofactor, q @@ -9294,7 +9298,7 @@ cdef class Polynomial(CommutativePolynomial): if hasattr(self.base_ring(), '_xgcd_univariate_polynomial'): return self.base_ring()._xgcd_univariate_polynomial(self, other) else: - raise NotImplementedError("%s does not provide an xgcd implementation for univariate polynomials"%self.base_ring()) + raise NotImplementedError("%s does not provide an xgcd implementation for univariate polynomials" % self.base_ring()) def rational_reconstruction(self, m, n_deg=None, d_deg=None): r""" @@ -9459,9 +9463,9 @@ cdef class Polynomial(CommutativePolynomial): sF = Pf(self) mF = Pf(m) n, d = sF.rational_reconstruction(mF, n_deg, d_deg) - l = lcm([n.denominator(), d.denominator()]) - n *= l - d *= l + lc = lcm([n.denominator(), d.denominator()]) + n *= lc + d *= lc return P(n), P(d) # n and d are unique if m.degree() > (n.degree() + d.degree()) @@ -9472,9 +9476,9 @@ cdef class Polynomial(CommutativePolynomial): if n_deg < 0 or d_deg < 0: raise ValueError("the degree bounds " - "n_deg and d_deg should be positive") + "n_deg and d_deg should be positive") - #XGCD until degree the degree of t1 surpasses the degree of n + # XGCD until degree the degree of t1 surpasses the degree of n s0 = P(0) t0 = P(1) s1 = P(m) @@ -9583,15 +9587,15 @@ cdef class Polynomial(CommutativePolynomial): _p = self._parent.coerce(p) elif p is infinity.infinity: return -self.degree() - elif is_Ideal(p) and p.ring() is self._parent: # eventually need to handle fractional ideals in the fraction field - if self._parent.base_ring().is_field(): # common case + elif is_Ideal(p) and p.ring() is self._parent: # eventually need to handle fractional ideals in the fraction field + if self._parent.base_ring().is_field(): # common case _p = p.gen() else: raise NotImplementedError else: from sage.rings.fraction_field import is_FractionField if is_FractionField(p.parent()) and self._parent.has_coerce_map_from(p.parent().ring()): - _p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. + _p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. else: raise TypeError("The polynomial, p, must have the same parent as self.") @@ -10846,13 +10850,13 @@ cdef class Polynomial(CommutativePolynomial): elif n == 1 or self.is_zero() or self.is_one(): return self elif self.degree() % n: - raise ValueError("not a %s power"%Integer(n).ordinal_str()) - elif self.get_unsafe(0).is_zero(): # We know that self is not 0, so it must have degree >= 0 + raise ValueError("not a %s power" % Integer(n).ordinal_str()) + elif self.get_unsafe(0).is_zero(): # We know that self is not 0, so it must have degree >= 0 # p = x^k q # p^(1/n) = x^(k/n) q^(1/n) i = self.valuation() - if i%n: - raise ValueError("not a %s power"%Integer(n).ordinal_str()) + if i % n: + raise ValueError("not a %s power" % Integer(n).ordinal_str()) return (self >> i).nth_root(n) << (i // n) if self.get_unsafe(0).is_one(): @@ -10871,7 +10875,7 @@ cdef class Polynomial(CommutativePolynomial): if q**n == p: return S(q) else: - raise ValueError("not a %s power"%Integer(n).ordinal_str()) + raise ValueError("not a %s power" % Integer(n).ordinal_str()) def _nth_root_series(self, long n, long prec, start=None): r""" @@ -10964,12 +10968,12 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("n (={}) must be positive".format(m)) elif m.is_one() or self.is_zero() or self.is_one(): return self - elif self.get_unsafe(0).is_zero(): # we know that self is not zero, so the degree >= 0 + elif self.get_unsafe(0).is_zero(): # we know that self is not zero, so the degree >= 0 # p = x^i q # p^(1/m) = x^(i/m) q^(1/m) i = self.valuation() if i % m: - raise ValueError("not a %s power"%m.ordinal_str()) + raise ValueError("not a %s power" % m.ordinal_str()) return (self >> i)._nth_root_series(m, prec - i // m) << (i // m) else: c = R.characteristic() @@ -10981,7 +10985,7 @@ cdef class Polynomial(CommutativePolynomial): for i in range(self.degree()+1): if self.get_unsafe(i): if i % cc: - raise ValueError("not a %s power"%m.ordinal_str()) + raise ValueError("not a %s power" % m.ordinal_str()) ans[i//cc] = self.get_unsafe(i).nth_root(cc) p = self._parent(ans) m = m // cc @@ -11077,12 +11081,16 @@ cdef class Polynomial(CommutativePolynomial): if not self.base_ring().is_integral_domain(): raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - if p.is_zero(): return True # everything divides 0 - if self.is_zero(): return False # 0 only divides 0 + if p.is_zero(): + return True # everything divides 0 + if self.is_zero(): + return False # 0 only divides 0 try: - if self.is_unit(): return True # units divide everything + if self.is_unit(): + return True # units divide everything except NotImplementedError: - if self.is_one(): return True # if is_unit is not implemented + if self.is_one(): + return True # if is_unit is not implemented if self.degree() > p.degree(): return False @@ -11134,10 +11142,9 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("either the dictionary or the specialization must be provided") else: from sage.rings.polynomial.flatten import SpecializationMorphism - phi = SpecializationMorphism(self._parent,D) + phi = SpecializationMorphism(self._parent, D) return phi(self) - def _log_series(self, long n): r""" Return the power series expansion of logarithm of this polynomial, @@ -11335,10 +11342,10 @@ cdef list do_schoolbook_product(list x, list y, Py_ssize_t deg): return y elif d1 == 0: c = x[0] - return [c*a for a in y[:deg]] # beware of noncommutative rings + return [c * a for a in y[:deg]] # beware of noncommutative rings elif d2 == 0: c = y[0] - return [a*c for a in x[:deg]] # beware of noncommutative rings + return [a * c for a in x[:deg]] # beware of noncommutative rings coeffs = [None]*deg for k in range(deg): start = 0 if k <= d2 else k-d2 # max(0, k-d2) @@ -11384,10 +11391,10 @@ cdef list do_karatsuba_different_size(list left, list right, Py_ssize_t K_thresh return [] if n == 1: c = left[0] - return [c*a for a in right] + return [c * a for a in right] if m == 1: c = right[0] - return [a*c for a in left] # beware of noncommutative rings + return [a * c for a in left] # beware of noncommutative rings if n <= K_threshold or m <= K_threshold: return do_schoolbook_product(left, right, -1) if n == m: @@ -11434,7 +11441,7 @@ cdef list do_karatsuba_different_size(list left, list right, Py_ssize_t K_thresh @cython.boundscheck(False) @cython.wraparound(False) @cython.overflowcheck(False) -cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold,Py_ssize_t start_l, Py_ssize_t start_r,Py_ssize_t num_elts): +cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold, Py_ssize_t start_l, Py_ssize_t start_r, Py_ssize_t num_elts): """ Core routine for Karatsuba multiplication. This function works for two polynomials of the same degree. @@ -11489,8 +11496,8 @@ cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold,Py_ssize_t d = right[start_r] c = right[start_r+1] return [b*d, a*d+b*c, a*c] - return do_schoolbook_product(left[start_l:start_l+num_elts], - right[start_r:start_r+num_elts], -1) + return do_schoolbook_product(left[start_l:start_l + num_elts], + right[start_r:start_r + num_elts], -1) if num_elts == 2: # beware of noncommutative rings b = left[start_l] @@ -11524,7 +11531,7 @@ cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold,Py_ssize_t bd[e+i] = bd[e+i] + tt1[i] bd.append(tt1[e-1]) for i from 0 <= i < lenac -e: - ac[i] = ac[i] + tt1[e+i] + ac[i] = ac[i] + tt1[e + i] return bd + ac @@ -11603,10 +11610,10 @@ cdef class Polynomial_generic_dense(Polynomial): check = 0 elif not isinstance(x, (list, tuple)): # We trust that the element constructors do not send x=0 -# if x: + # if x: x = [x] # constant polynomials -# else: -# x = [] # zero polynomial + # else: + # x = [] # zero polynomial if check: self._coeffs = [R(z, **kwds) for z in x] self._normalize() @@ -11639,9 +11646,9 @@ cdef class Polynomial_generic_dense(Polynomial): Univariate Polynomial Ring in x over Univariate Polynomial Ring in y over Rational Field """ if a: - return self._new_c([a],P) + return self._new_c([a], P) else: - return self._new_c([],P) + return self._new_c([], P) def __reduce__(self): """ @@ -11710,7 +11717,7 @@ cdef class Polynomial_generic_dense(Polynomial): for i in range(ell): v[i+d] = c * x[i] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - #if not v[len(v)-1]: + # if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -11853,7 +11860,7 @@ cdef class Polynomial_generic_dense(Polynomial): 2*y*x^3 + (y + 3)*x^2 + (-2*y + 1)*x + 1 """ cdef Polynomial_generic_dense res - cdef Py_ssize_t check=0, i, min + cdef Py_ssize_t check = 0, i, min x = (self)._coeffs y = (right)._coeffs if len(x) > len(y): @@ -11874,7 +11881,7 @@ cdef class Polynomial_generic_dense(Polynomial): cpdef _sub_(self, right): cdef Polynomial_generic_dense res - cdef Py_ssize_t check=0, i, min + cdef Py_ssize_t check = 0, i, min x = (self)._coeffs y = (right)._coeffs if len(x) > len(y): @@ -11900,7 +11907,7 @@ cdef class Polynomial_generic_dense(Polynomial): c = (self._coeffs[0])._parent.coerce(c) v = [c * a for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - #if not v[len(v)-1]: + # if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -11912,7 +11919,7 @@ cdef class Polynomial_generic_dense(Polynomial): c = (self._coeffs[0])._parent.coerce(c) v = [a * c for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - #if not v[len(v)-1]: + # if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -12121,7 +12128,7 @@ cdef class Polynomial_generic_dense(Polynomial): quo.append(q) quo.reverse() - return self._new_c(quo,self._parent), self._new_c(x,self._parent)._inplace_truncate(n-1) + return self._new_c(quo, self._parent), self._new_c(x, self._parent)._inplace_truncate(n-1) cpdef Polynomial truncate(self, long n): r""" @@ -12150,10 +12157,10 @@ cdef class Polynomial_generic_dense(Polynomial): sage: type(f) """ - l = len(self._coeffs) - if n > l: - n = l - while n > 0 and not self._coeffs[n-1]: + ln = len(self._coeffs) + if n > ln: + n = ln + while n > 0 and not self._coeffs[n - 1]: n -= 1 return self._new_c(self._coeffs[:n], self._parent) @@ -12164,6 +12171,7 @@ cdef class Polynomial_generic_dense(Polynomial): self._coeffs = self._coeffs[:n] return self + def make_generic_polynomial(parent, coeffs): return parent(coeffs) @@ -12205,7 +12213,7 @@ def universal_discriminant(n): pr1 = PolynomialRing(ZZ, n + 1, 'a') pr2 = PolynomialRing(pr1, 'x') p = pr2(list(pr1.gens())) - return (1 - (n&2))*p.resultant(p.derivative())//pr1.gen(n) + return (1 - (n & 2)) * p.resultant(p.derivative()) // pr1.gen(n) cpdef Polynomial generic_power_trunc(Polynomial p, Integer n, long prec): @@ -12301,7 +12309,7 @@ cpdef list _dict_to_list(dict x, zero): return [] n = max(x.keys()) cdef list v - if isinstance(n, tuple): # a mpoly dict + if isinstance(n, tuple): # a mpoly dict n = n[0] v = [zero] * (n+1) for i, z in x.iteritems(): From 9817b917c41f44feb02fc1971d3a4d91e62f64fe Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 23 Sep 2023 09:45:52 +0200 Subject: [PATCH 011/538] homogeneize __reduce__ for uni- and multi-variate Laurent polynomials --- src/sage/rings/polynomial/laurent_polynomial.pyx | 2 +- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 917943f5619..6d3168f4995 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -379,7 +379,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: loads(dumps(elt)) == elt True """ - return LaurentPolynomial_univariate, (self._parent, self.__u, self.__n) + return LaurentPolynomial_univariate, (self.__u, self.__n) # eliminate first term in the tuple for the previous definition def _polynomial_(self, R): r""" diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index fbfa99fd8ac..c36c52957cd 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -198,7 +198,7 @@ def __contains__(self, f): if not f or f in self.gens(): return True f = self.ring()(f) - g = f.__reduce__()[1][1] + g = f.__reduce__()[1][0] return (g in self.polynomial_ideal()) # Operations on ideals @@ -501,7 +501,7 @@ def associated_primes(self): Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ ap = self.polynomial_ideal(saturate=False).associated_primes() - ap2 = [self.ring().ideal(id.gens(), hint=id) for Iid in ap] + ap2 = [self.ring().ideal(id.gens(), hint=id) for id in ap] return tuple(id for id in ap2 if not id.is_one()) def minimal_associated_primes(self, saturate=False): From 5591d6cd8d41856327619fd68d894dc4933e155f Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 23 Sep 2023 11:08:00 +0200 Subject: [PATCH 012/538] style --- src/sage/matrix/matrix2.pyx | 731 +++++++++--------- .../rings/polynomial/laurent_polynomial.pyx | 14 +- .../polynomial/laurent_polynomial_ring.py | 5 + 3 files changed, 386 insertions(+), 364 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 1e871d9e553..d438453318f 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -206,10 +206,10 @@ cdef class Matrix(Matrix1): from sage.matrix.constructor import matrix if self.is_sparse(): return matrix({ij: self[ij].subs(*args, **kwds) for ij in self.nonzero_positions()}, - nrows=self._nrows, ncols=self._ncols, sparse=True) + nrows=self._nrows, ncols=self._ncols, sparse=True) else: return matrix([a.subs(*args, **kwds) for a in self.list()], - nrows=self._nrows, ncols=self._ncols, sparse=False) + nrows=self._nrows, ncols=self._ncols, sparse=False) def solve_left(self, B, check=True): """ @@ -887,8 +887,8 @@ cdef class Matrix(Matrix1): # Elements of SR "remember" whether or not they are exact. # If every element in the system is exact, we can probably # still check the solution over the inexact ring SR. - check = (check and all( e.is_exact() - for e in self.list() + B.list() )) + check = (check and all(e.is_exact() + for e in self.list() + B.list())) else: check = (check and K.is_exact()) @@ -972,7 +972,7 @@ cdef class Matrix(Matrix1): raise NotFullRankError D = self.augment(B) D.echelonize() - return D.matrix_from_columns(range(self.ncols(),D.ncols())) + return D.matrix_from_columns(range(self.ncols(), D.ncols())) def pivot_rows(self): """ @@ -1072,8 +1072,8 @@ cdef class Matrix(Matrix1): for row from 0 <= row < self._nrows: tmp = [] for c in cols: -# if c<0 or c >= self._ncols: -# raise IndexError("matrix column index out of range") + # if c<0 or c >= self._ncols: + # raise IndexError("matrix column index out of range") tmp.append(self.get_unsafe(row, c)) pr = pr * sum(tmp) return pr @@ -1170,7 +1170,10 @@ cdef class Matrix(Matrix1): sage: A.elementwise_product(vector(ZZ, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' and 'Ambient free module of rank 4 over the principal ideal domain Integer Ring' + TypeError: no common canonical parent for objects with parents: + 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' + and 'Ambient free module of rank 4 over the principal ideal + domain Integer Ring' sage: A = matrix(2, 2, range(4)) sage: A.elementwise_product(polygen(parent(A))) @@ -1185,7 +1188,11 @@ cdef class Matrix(Matrix1): sage: A.elementwise_product(B) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' and 'Full MatrixSpace of 10 by 5 dense matrices over Integer Ring' + TypeError: no common canonical parent + for objects with parents: 'Full MatrixSpace of + 5 by 10 dense matrices over Integer Ring' and + 'Full MatrixSpace of 10 by 5 dense matrices over + Integer Ring' Some pairs of rings do not have a common parent where multiplication makes sense. This will raise an error. :: @@ -1383,7 +1390,7 @@ cdef class Matrix(Matrix1): m = self._nrows n = self._ncols if not m <= n: - raise ValueError("must have m <= n, but m (=%s) and n (=%s)"%(m,n)) + raise ValueError("must have m <= n, but m (=%s) and n (=%s)" % (m, n)) for r from 1 <= r < m+1: lst = _choose(n, r) @@ -1504,8 +1511,8 @@ cdef class Matrix(Matrix1): return R.zero() pm = 0 - for cols in _choose(n,k): - for rows in _choose(m,k): + for cols in _choose(n, k): + for rows in _choose(m, k): pm = pm + self.matrix_from_rows_and_columns(rows, cols).permanent() return pm @@ -1814,14 +1821,14 @@ cdef class Matrix(Matrix1): ....: if v != [1, 16, 78, 128, 53]: ....: print("ERROR with algorithm={} use_complement=False".format(algorithm)) """ - cdef Py_ssize_t i,j + cdef Py_ssize_t i, j cdef unsigned int num_ones cdef int m = self._nrows cdef int n = self._ncols cdef int mn = min(m, n) cdef Matrix B zero = self.base_ring().zero() - one = self.base_ring().one() + one = self.base_ring().one() if algorithm is None: algorithm = "ButeraPernici" @@ -1835,7 +1842,7 @@ cdef class Matrix(Matrix1): num_ones = 1 for i in range(m): for j in range(n): - x = self.get_unsafe(i,j) + x = self.get_unsafe(i, j) if x != zero: if x != one: z2 = False @@ -1847,7 +1854,7 @@ cdef class Matrix(Matrix1): break if not z2 and (complement or algorithm == "Godsil"): - raise ValueError("coefficients must be zero or one, but we have '{}' in position ({},{}).".format(x,i,j)) + raise ValueError("coefficients must be zero or one, but we have '{}' in position ({},{}).".format(x, i, j)) if use_complement is None: use_complement = z2 and num_ones > 0.55 * m * n @@ -1861,7 +1868,7 @@ cdef class Matrix(Matrix1): complement = not complement elif algorithm == "Ryser": - b = [self.permanental_minor(k,algorithm="Ryser") + b = [self.permanental_minor(k, algorithm="Ryser") for k in range(mn + 1)] elif algorithm == "ButeraPernici": @@ -1950,9 +1957,9 @@ cdef class Matrix(Matrix1): all_rows = range(self.nrows()) all_cols = range(self.ncols()) m = [] - for rows in Combinations(all_rows,k): - for cols in Combinations(all_cols,k): - m.append(self.matrix_from_rows_and_columns(rows,cols).determinant()) + for rows in Combinations(all_rows, k): + for cols in Combinations(all_cols, k): + m.append(self.matrix_from_rows_and_columns(rows, cols).determinant()) return m def det(self, *args, **kwds): @@ -2110,13 +2117,13 @@ cdef class Matrix(Matrix1): if n == 0: d = R.one() elif n == 1: - d = self.get_unsafe(0,0) + d = self.get_unsafe(0, 0) elif n == 2: - d = self.get_unsafe(0,0)*self.get_unsafe(1,1) - self.get_unsafe(1,0)*self.get_unsafe(0,1) + d = self.get_unsafe(0, 0)*self.get_unsafe(1, 1) - self.get_unsafe(1, 0)*self.get_unsafe(0, 1) elif n == 3: - d = self.get_unsafe(0,0) * (self.get_unsafe(1,1)*self.get_unsafe(2,2) - self.get_unsafe(1,2)*self.get_unsafe(2,1)) \ - - self.get_unsafe(1,0) * (self.get_unsafe(0,1)*self.get_unsafe(2,2) - self.get_unsafe(0,2)*self.get_unsafe(2,1)) \ - + self.get_unsafe(2,0) * (self.get_unsafe(0,1)*self.get_unsafe(1,2) - self.get_unsafe(0,2)*self.get_unsafe(1,1)) + d = self.get_unsafe(0, 0) * (self.get_unsafe(1, 1)*self.get_unsafe(2, 2) - self.get_unsafe(1, 2)*self.get_unsafe(2, 1)) \ + - self.get_unsafe(1, 0) * (self.get_unsafe(0, 1)*self.get_unsafe(2, 2) - self.get_unsafe(0, 2)*self.get_unsafe(2, 1)) \ + + self.get_unsafe(2, 0) * (self.get_unsafe(0, 1)*self.get_unsafe(1, 2) - self.get_unsafe(0, 2)*self.get_unsafe(1, 1)) self.cache('det', d) return d @@ -2130,7 +2137,7 @@ cdef class Matrix(Matrix1): d = R(self.__pari__().matdet()) else: # Lift to ZZ and compute there. - d = R(self.apply_map(lambda x : x.lift_centered()).det()) + d = R(self.apply_map(lambda x: x.lift_centered()).det()) self.cache('det', d) return d @@ -2186,18 +2193,18 @@ cdef class Matrix(Matrix1): """ cdef Py_ssize_t n, i if level == 2: - return self.get_unsafe(0,0) * self.get_unsafe(1,1) - self.get_unsafe(0,1) * self.get_unsafe(1,0) + return self.get_unsafe(0, 0) * self.get_unsafe(1, 1) - self.get_unsafe(0, 1) * self.get_unsafe(1, 0) else: level -= 1 - d = self.get_unsafe(level,level) * self._det_by_minors(level) + d = self.get_unsafe(level, level) * self._det_by_minors(level) # on each iteration, row i will be missing in the first (level) rows # swapping is much faster than taking submatrices for i from level > i >= 0: self.swap_rows(level, i) if (level - i) % 2: - d -= self.get_unsafe(level,level) * self._det_by_minors(level) + d -= self.get_unsafe(level, level) * self._det_by_minors(level) else: - d += self.get_unsafe(level,level) * self._det_by_minors(level) + d += self.get_unsafe(level, level) * self._det_by_minors(level) # undo all our permutations to get us back to where we started for i from 0 <= i < level: self.swap_rows(level, i) @@ -2648,7 +2655,7 @@ cdef class Matrix(Matrix1): """ M = self.parent().change_ring(phi.codomain()) if self.is_sparse(): - values = {(i,j): phi(z) for (i,j),z in self.dict()} + values = {(i, j): phi(z) for (i, j), z in self.dict()} else: values = [phi(z) for z in self.list()] image = M(values) @@ -2757,7 +2764,7 @@ cdef class Matrix(Matrix1): return self.dense_matrix() if self.is_sparse(): - values = {(i,j): phi(v) for (i,j),v in self.dict().iteritems()} + values = {(i, j): phi(v) for (i, j), v in self.dict().iteritems()} if R is None: R = sage.structure.sequence.Sequence(values.values()).universe() else: @@ -2775,7 +2782,7 @@ cdef class Matrix(Matrix1): else: from sage.matrix.matrix_space import MatrixSpace M = MatrixSpace(R, self._nrows, - self._ncols, sparse=sparse) + self._ncols, sparse=sparse) image = M(values) if self._subdivisions is not None: image.subdivide(*self.subdivisions()) @@ -2886,7 +2893,7 @@ cdef class Matrix(Matrix1): # At least check that the minimal polynomial kills the matrix tester.assertTrue(self.minpoly().subs(x=self).is_zero()) - def charpoly(self, var = 'x', algorithm = None): + def charpoly(self, var='x', algorithm=None): r""" Returns the characteristic polynomial of self, as a polynomial over the base ring. @@ -3081,7 +3088,7 @@ cdef class Matrix(Matrix1): self.cache('charpoly', f) return f - def _charpoly_df(self, var = 'x'): + def _charpoly_df(self, var='x'): r""" Computes the characteristic polynomial of ``self`` without divisions. @@ -3169,10 +3176,10 @@ cdef class Matrix(Matrix1): # Extract parameters # - cdef Matrix M = self - n = M._ncols - R = M._base_ring - S = PolynomialRing(R, var) + cdef Matrix M = self + n = M._ncols + R = M._base_ring + S = PolynomialRing(R, var) # Corner cases # N.B. We already tested for M to be square, hence we do not need to @@ -3197,11 +3204,11 @@ cdef class Matrix(Matrix1): from sage.matrix.constructor import matrix F = [R.zero()] * n - cdef Matrix a = matrix(R, n-1, n) + cdef Matrix a = matrix(R, n - 1, n) A = [R.zero()] * n F[0] = - M.get_unsafe(0, 0) - for t in range(1,n): + for t in range(1, n): # Set a(1, t) to be M(<=t, t) # @@ -3372,7 +3379,7 @@ cdef class Matrix(Matrix1): [] """ n = min(self.nrows(), self.ncols()) - return [self[i,i] for i in range(n)] + return [self[i, i] for i in range(n)] def trace(self): """ @@ -3409,7 +3416,7 @@ cdef class Matrix(Matrix1): cdef object s s = R(0) for i from 0 <= i < self._nrows: - s = s + self.get_unsafe(i,i) + s = s + self.get_unsafe(i, i) return s def trace_of_product(self, Matrix other): @@ -3467,11 +3474,11 @@ cdef class Matrix(Matrix1): H = self.change_ring(K) H.hessenbergize() except TypeError as msg: - raise TypeError("%s\nHessenberg form only possible for matrices over a field"%msg) + raise TypeError("%s\nHessenberg form only possible for matrices over a field" % msg) else: H = self.__copy__() H.hessenbergize() - #end if + # end if self.cache('hessenberg_form', H) return H @@ -3515,7 +3522,7 @@ cdef class Matrix(Matrix1): cdef Py_ssize_t i, j, m, n, r n = self._nrows - tm = verbose("Computing Hessenberg Normal Form of %sx%s matrix"%(n,n)) + tm = verbose("Computing Hessenberg Normal Form of %sx%s matrix" % (n, n)) if not self.is_square(): raise TypeError("self must be square") @@ -3542,20 +3549,20 @@ cdef class Matrix(Matrix1): if i != -1: # Found a nonzero entry in column m-1 that is strictly below row m # Now set i to be the first nonzero position >= m in column m-1 - if not self.get_is_zero_unsafe(m,m-1): + if not self.get_is_zero_unsafe(m, m - 1): i = m - t = self.get_unsafe(i,m-1) + t = self.get_unsafe(i, m - 1) t_inv = None if i > m: - self.swap_rows_c(i,m) + self.swap_rows_c(i, m) # We must do the corresponding column swap to # maintain the characteristic polynomial (which is # an invariant of Hessenberg form) - self.swap_columns_c(i,m) + self.swap_columns_c(i, m) # Now the nonzero entry in position (m,m-1) is t. # Use t to clear the entries in column m-1 below m. for j from m+1 <= j < n: - x = self.get_unsafe(j, m-1) + x = self.get_unsafe(j, m - 1) if x != zero: if t_inv is None: t_inv = one / t @@ -3566,7 +3573,7 @@ cdef class Matrix(Matrix1): # column m, and we're only worried about column m-1 right now. # Add u*column_j to column_m. self.add_multiple_of_column_c(m, j, u, 0) - verbose("Finished Hessenberg Normal Form of %sx%s matrix"%(n,n),tm) + verbose("Finished Hessenberg Normal Form of %sx%s matrix" % (n, n), tm) def _charpoly_hessenberg(self, var): """ @@ -3617,9 +3624,9 @@ cdef class Matrix(Matrix1): n = self._nrows cdef Matrix c - c = H.new_matrix(nrows=n+1,ncols=n+1) # the 0 matrix + c = H.new_matrix(nrows=n + 1, ncols=n + 1) # the 0 matrix one = H._coerce_element(1) - c.set_unsafe(0,0,one) + c.set_unsafe(0, 0, one) for m from 1 <= m <= n: # Set the m-th row of c to (x - H[m-1,m-1])*c[m-1] = x*c[m-1] - H[m-1,m-1]*c[m-1] @@ -3627,20 +3634,21 @@ cdef class Matrix(Matrix1): # shifted to the right by one. We then add # -H[m-1,m-1]*c[m-1] to the resulting m-th row. for i from 1 <= i <= n: - c.set_unsafe(m, i, c.get_unsafe(m-1,i-1)) - c.add_multiple_of_row_c(m, m-1, -H.get_unsafe(m-1, m-1), 0) + c.set_unsafe(m, i, c.get_unsafe(m - 1, i - 1)) + c.add_multiple_of_row_c(m, m-1, -H.get_unsafe(m - 1, m - 1), 0) t = one for i from 1 <= i < m: - t = t * H.get_unsafe(m-i,m-i-1) + t = t * H.get_unsafe(m - i, m - i - 1) # Set the m-th row of c to c[m] - t*H[m-i-1,m-1]*c[m-i-1] - c.add_multiple_of_row_c(m, m-i-1, - t*H.get_unsafe(m-i-1,m-1), 0) + c.add_multiple_of_row_c(m, m - i - 1, -t * H.get_unsafe(m - i - 1, m - 1), 0) # The answer is now the n-th row of c. v = PyList_New(n+1) # this is really sort of v = []..." for i from 0 <= i <= n: # Finally, set v[i] = c[n,i] - o = c.get_unsafe(n,i) - Py_INCREF(o); PyList_SET_ITEM(v, i, o) + o = c.get_unsafe(n, i) + Py_INCREF(o) + PyList_SET_ITEM(v, i, o) R = self._base_ring[var] # polynomial ring over the base ring return R(v) @@ -3758,12 +3766,12 @@ cdef class Matrix(Matrix1): [0 0 1] """ from sage.matrix.matrix_space import MatrixSpace - tm = verbose("computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) + tm = verbose("computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) basis = self.__pari__().matker() # Coerce PARI representations into the number field R = self.base_ring() basis = [[R(x) for x in row] for row in basis] - verbose("done computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1,t=tm) + verbose("done computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) return 'pivot-pari-numberfield', MatrixSpace(R, len(basis), ncols=self._ncols)(basis) def _right_kernel_matrix_over_field(self, *args, **kwds): @@ -3817,7 +3825,7 @@ cdef class Matrix(Matrix1): [0 0 1] """ from sage.matrix.matrix_space import MatrixSpace - tm = verbose("computing right kernel matrix over an arbitrary field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) + tm = verbose("computing right kernel matrix over an arbitrary field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) E = self.echelon_form(*args, **kwds) pivots = E.pivots() pivots_set = set(pivots) @@ -3846,7 +3854,7 @@ cdef class Matrix(Matrix1): basis.append(v) M = MS(basis, coerce=False) tm = verbose("done computing right kernel matrix over an arbitrary field for %sx%s matrix" - % (self.nrows(), self.ncols()),level=1,t=tm) + % (self.nrows(), self.ncols()), level=1, t=tm) return 'pivot-generic', M def _right_kernel_matrix_over_domain(self): @@ -3910,7 +3918,7 @@ cdef class Matrix(Matrix1): cdef Py_ssize_t i, nrows = self._nrows for i in range(self._ncols): if i >= nrows or d[i, i] == 0: - basis.append( v.column(i) ) + basis.append(v.column(i)) verbose("done computing right kernel matrix over a domain for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) return 'computed-smith-form', self.new_matrix(nrows=len(basis), ncols=self._ncols, entries=basis) @@ -4501,7 +4509,7 @@ cdef class Matrix(Matrix1): if algorithm is None: algorithm = 'default' elif algorithm not in ['default', 'generic', 'flint', 'pari', 'padic', 'pluq']: - raise ValueError("matrix kernel algorithm '%s' not recognized" % algorithm ) + raise ValueError("matrix kernel algorithm '%s' not recognized" % algorithm) elif algorithm == 'padic' and not (is_IntegerRing(R) or is_RationalField(R)): raise ValueError("'padic' matrix kernel algorithm only available over the rationals and the integers, not over %s" % R) elif algorithm == 'flint' and not (is_IntegerRing(R) or is_RationalField(R)): @@ -4518,7 +4526,7 @@ cdef class Matrix(Matrix1): if basis is None: basis = 'default' elif basis not in ['default', 'computed', 'echelon', 'pivot', 'LLL']: - raise ValueError("matrix kernel basis format '%s' not recognized" % basis ) + raise ValueError("matrix kernel basis format '%s' not recognized" % basis) elif basis == 'pivot' and R not in _Fields: raise ValueError('pivot basis only available over a field, not over %s' % R) elif basis == 'LLL' and not is_IntegerRing(R): @@ -4552,7 +4560,8 @@ cdef class Matrix(Matrix1): # Third: generic first, if requested explicitly # then try specialized class methods, and finally # delegate to ad-hoc methods in greater generality - M = None; format = '' + M = None + format = '' if algorithm == 'generic': format, M = self._right_kernel_matrix_over_field() @@ -4582,7 +4591,7 @@ cdef class Matrix(Matrix1): # zero columns as well. (eg PARI?) This could be fixed at the source # with a careful study of the phenomenon. Start by commenting out # the following and running doctests in sage/matrix - if M.nrows()==0 and M.ncols()!=self.ncols(): + if M.nrows() == 0 and M.ncols() != self.ncols(): M = M.new_matrix(nrows=0, ncols=self.ncols()) # Convert basis to requested type and return the matrix @@ -5145,10 +5154,10 @@ cdef class Matrix(Matrix1): if K is not None: return K - tm = verbose("computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) + tm = verbose("computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) K = self.transpose().right_kernel(*args, **kwds) self.cache('left_kernel', K) - verbose("done computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1,t=tm) + verbose("done computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) return K kernel = left_kernel @@ -5520,15 +5529,15 @@ cdef class Matrix(Matrix1): False) ] """ if algorithm == 'kernel' or self.base_ring() not in _Fields: - return self._decomposition_using_kernels(is_diagonalizable = is_diagonalizable, dual=dual) + return self._decomposition_using_kernels(is_diagonalizable=is_diagonalizable, dual=dual) elif algorithm == 'spin': - X = self._decomposition_spin_generic(is_diagonalizable = is_diagonalizable) + X = self._decomposition_spin_generic(is_diagonalizable=is_diagonalizable) if dual: - Y = self.transpose()._decomposition_spin_generic(is_diagonalizable = is_diagonalizable) + Y = self.transpose()._decomposition_spin_generic(is_diagonalizable=is_diagonalizable) return X, Y return X else: - raise ValueError("no algorithm '%s'"%algorithm) + raise ValueError("no algorithm '%s'" % algorithm) def _decomposition_spin_generic(self, is_diagonalizable=False): r""" @@ -5558,13 +5567,13 @@ cdef class Matrix(Matrix1): if len(F) == 1: V = self.base_ring()**self.nrows() - return decomp_seq([(V,F[0][1]==1)]) + return decomp_seq([(V, F[0][1] == 1)]) V = self.base_ring()**self.nrows() v = V.random_element() num_iterates = max([0] + [f.degree() - g.degree() for g, _ in F if g.degree() > 1]) + 1 - S = [ ] + S = [] F.sort() for i in range(len(F)): @@ -5574,11 +5583,11 @@ cdef class Matrix(Matrix1): # Just use kernel -- much easier. B = self.__copy__() for k from 0 <= k < self.nrows(): - B[k,k] += g[0] + B[k, k] += g[0] if m > 1 and not is_diagonalizable: B = B**m W = B.kernel() - E.append((W, m==1)) + E.append((W, m == 1)) continue # General case, i.e., deg(g) > 1: @@ -5591,40 +5600,40 @@ cdef class Matrix(Matrix1): v = h.list() while len(S) < tries: - t = verbose('%s-spinning %s-th random vector'%(num_iterates, len(S)), level=2, caller_name='generic spin decomp') + t = verbose('%s-spinning %s-th random vector' % (num_iterates, len(S)), level=2, caller_name='generic spin decomp') S.append(self.iterates(V.random_element(), num_iterates)) verbose('done spinning', level=2, t=t, caller_name='generic spin decomp') for j in range(0 if W is None else W.nrows() // g.degree(), len(S)): # Compute one element of the kernel of g(A)**m. - t = verbose('compute element of kernel of g(A), for g of degree %s'%g.degree(),level=2, + t = verbose('compute element of kernel of g(A), for g of degree %s' % g.degree(), level=2, caller_name='generic spin decomp') w = S[j].linear_combination_of_rows(h.list()) - t = verbose('done computing element of kernel of g(A)', t=t,level=2, caller_name='generic spin decomp') + t = verbose('done computing element of kernel of g(A)', t=t, level=2, caller_name='generic spin decomp') # Get the rest of the kernel. - t = verbose('fill out rest of kernel',level=2, caller_name='generic spin decomp') + t = verbose('fill out rest of kernel', level=2, caller_name='generic spin decomp') if W is None: W = self.iterates(w, g.degree()) else: W = W.stack(self.iterates(w, g.degree())) - t = verbose('finished filling out more of kernel',level=2, t=t, caller_name='generic spin decomp') + t = verbose('finished filling out more of kernel', level=2, t=t, caller_name='generic spin decomp') if W.rank() == m * g.degree(): t = verbose('now computing row space', level=2, caller_name='generic spin decomp') W.echelonize() - E.append((W.row_space(), m==1)) - verbose('computed row space', level=2,t=t, caller_name='generic spin decomp') + E.append((W.row_space(), m == 1)) + verbose('computed row space', level=2, t=t, caller_name='generic spin decomp') break else: - verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)'%( + verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)' % ( W.rank(), m*g.degree()), level=2, caller_name='generic spin decomp') tries += 1 if tries > 1000*m: # avoid an insanely long infinite loop raise RuntimeError("likely bug in decomposition") # end if - #end while - #end for + # end while + # end for return E def _decomposition_using_kernels(self, is_diagonalizable=False, dual=False): @@ -5648,30 +5657,30 @@ cdef class Matrix(Matrix1): V = self.column_ambient_module() m = F[0][1] if dual: - return decomp_seq([(V, m==1)]), decomp_seq([(V, m==1)]) + return decomp_seq([(V, m == 1)]), decomp_seq([(V, m == 1)]) else: - return decomp_seq([(V, m==1)]) + return decomp_seq([(V, m == 1)]) F.sort() for g, m in f.factor(): - t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s'%g.degree(),level=2) + t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s' % g.degree(), level=2) if is_diagonalizable: B = g(self) else: B = g(self) - t2 = verbose('decomposition -- raising g(self) to the power %s'%m,level=2) + t2 = verbose('decomposition -- raising g(self) to the power %s' % m, level=2) B = B ** m - verbose('done powering',t2) + verbose('done powering', t2) t = verbose('decomposition -- done computing g(self)', level=2, t=t) - E.append((B.kernel(), m==1)) + E.append((B.kernel(), m == 1)) t = verbose('decomposition -- time to compute kernel', level=2, t=t) if dual: - Edual.append((B.transpose().kernel(), m==1)) + Edual.append((B.transpose().kernel(), m == 1)) verbose('decomposition -- time to compute dual kernel', level=2, t=t) if dual: return E, Edual return E - def decomposition_of_subspace(self, M, check_restrict = True, **kwds): + def decomposition_of_subspace(self, M, check_restrict=True, **kwds): """ Suppose the right action of self on M leaves M invariant. Return the decomposition of M as a list of pairs (W, is_irred) where @@ -5747,7 +5756,7 @@ cdef class Matrix(Matrix1): if not self.is_square(): raise ArithmeticError("self must be a square matrix") if M.base_ring() != self.base_ring(): - raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s"%( + raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s" % ( self.base_ring(), M.base_ring())) if M.degree() != self.ncols(): raise ArithmeticError("M must be a subspace of an %s-dimensional space" % self.ncols()) @@ -5755,16 +5764,18 @@ cdef class Matrix(Matrix1): time = verbose(t=0) # 1. Restrict - B = self.restrict(M, check = check_restrict) + B = self.restrict(M, check=check_restrict) time0 = verbose("decompose restriction -- ", time) # 2. Decompose restriction D = B.decomposition(**kwds) - sum_dim = sum([A.dimension() for A,_ in D]) + sum_dim = sum([A.dimension() for A, _ in D]) assert sum_dim == M.dimension(), \ "bug in decomposition; " + \ - "the sum of the dimensions (=%s) of the factors must equal the dimension (%s) of the acted on space:\nFactors found: %s\nSpace: %s"%(sum_dim, M.dimension(), D, M) + "the sum of the dimensions (=%s) of the factors must equal" + \ + "the dimension (%s) of the acted on space:\nFactors found:" + \ + "%s\nSpace: %s" % (sum_dim, M.dimension(), D, M) # 3. Lift decomposition to subspaces of ambient vector space. # Each basis vector for an element of D defines a linear @@ -5834,7 +5845,7 @@ cdef class Matrix(Matrix1): """ if not isinstance(V, sage.modules.free_module.FreeModule_generic): raise TypeError("V must be a free module") - #if V.base_ring() != self.base_ring(): + # if V.base_ring() != self.base_ring(): # raise ValueError("matrix and module must have the same base ring, but matrix is over %s and module is over %s"%(self.base_ring(), V.base_ring())) if V.degree() != self.nrows(): raise IndexError("degree of V (=%s) must equal number of rows of self (=%s)" % (V.degree(), self.nrows())) @@ -6016,7 +6027,8 @@ cdef class Matrix(Matrix1): sage: t.charpoly() # needs sage.libs.pari x^3 - 12*x^2 - 18*x """ - i = int(i); t=int(t) + i = int(i) + t = int(t) if self.nrows() != self.ncols(): raise ArithmeticError("self must be a square matrix") n = self.nrows() @@ -6421,7 +6433,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return x else: - return Sequence([(e[0],e[1]) for e in x], cr=True, check=False) + return Sequence([(e[0], e[1]) for e in x], cr=True, check=False) # Possible improvements: # algorithm for dual_eigenvector in sage/modular/hecke/module.py @@ -6433,7 +6445,7 @@ cdef class Matrix(Matrix1): G = self.fcp() # factored characteristic polynomial V = [] - i = -1 # variable name index, increments for each eigenvalue + i = -1 # variable name index, increments for each eigenvalue for h, e in G: i = i + 1 if h.degree() == 1: @@ -6445,7 +6457,7 @@ cdef class Matrix(Matrix1): W = A.kernel() V.append((alpha, W.ambient_module().span_of_basis(W.basis()), e)) else: - F = h.root_field('{0}{1}'.format(var,i)) + F = h.root_field('{0}{1}'.format(var, i)) alpha = F.gen(0) A = self.change_ring(F) - alpha W = A.kernel() @@ -6469,7 +6481,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return V else: - return Sequence([(e[0],e[1]) for e in V], cr=True, check=False) + return Sequence([(e[0], e[1]) for e in V], cr=True, check=False) left_eigenspaces = eigenspaces_left @@ -6673,7 +6685,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return x else: - return Sequence([(e[0],e[1]) for e in x], cr=True, check=False) + return Sequence([(e[0], e[1]) for e in x], cr=True, check=False) V = self.transpose().eigenspaces_left(format=format, var=var, algebraic_multiplicity=True) @@ -6681,7 +6693,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return V else: - return Sequence([(e[0],e[1]) for e in V], cr=True, check=False) + return Sequence([(e[0], e[1]) for e in V], cr=True, check=False) right_eigenspaces = eigenspaces_right @@ -6794,7 +6806,7 @@ cdef class Matrix(Matrix1): warn("Using generic algorithm for an inexact ring, which will probably give incorrect results due to numerical precision issues.") if not extend: - return Sequence(r for r,m in self.charpoly().roots() for _ in range(m)) + return Sequence(r for r, m in self.charpoly().roots() for _ in range(m)) # now we need to find a natural algebraic closure for the base ring K = self.base_ring() @@ -6814,7 +6826,7 @@ cdef class Matrix(Matrix1): if f.degree() == 1: res.extend([-f.constant_coefficient()]*e) else: - for r,ee in f.change_ring(A).roots(): + for r, ee in f.change_ring(A).roots(): res.extend([r]*(e*ee)) eigenvalues = Sequence(res) @@ -6925,7 +6937,7 @@ cdef class Matrix(Matrix1): V = [] from sage.categories.homset import hom eigenspaces = self.eigenspaces_left(format='galois', algebraic_multiplicity=True) - evec_list=[] + evec_list = [] n = self._nrows evec_eval_list = [] F = self.base_ring().fraction_field() @@ -6947,7 +6959,7 @@ cdef class Matrix(Matrix1): m = hom(eigval.parent(), e.parent(), e) space = (e.parent())**n evec_list = [(space)([m(i) for i in v]) for v in eigbasis] - evec_eval_list.append( (e, evec_list, eigmult)) + evec_eval_list.append((e, evec_list, eigmult)) return evec_eval_list @@ -7229,7 +7241,7 @@ cdef class Matrix(Matrix1): "failed to compute eigenvectors for eigenvalue %s, " "check eigenvectors_left() for partial results" % e[0]) P = matrix(rows) - return D,P + return D, P left_eigenmatrix = eigenmatrix_left @@ -7397,9 +7409,9 @@ cdef class Matrix(Matrix1): True """ - D,P = self.transpose().eigenmatrix_left(None if other is None - else other.transpose()) - return D,P.transpose() + D, P = self.transpose().eigenmatrix_left(None if other is None + else other.transpose()) + return D, P.transpose() right_eigenmatrix = eigenmatrix_right @@ -7615,7 +7627,7 @@ cdef class Matrix(Matrix1): d = self.dense_matrix().echelon_form(**kwds) for c from 0 <= c < self.ncols(): for r from 0 <= r < self.nrows(): - self.set_unsafe(r, c, d.get_unsafe(r,c)) + self.set_unsafe(r, c, d.get_unsafe(r, c)) self.clear_cache() self.cache('pivots', d.pivots()) self.cache('in_echelon_form', True) @@ -7623,11 +7635,11 @@ cdef class Matrix(Matrix1): try: a, d, p = self._echelon_form_PID() except TypeError as msg: - raise NotImplementedError("%s\nechelon form over %s not yet implemented"%(msg, self.base_ring())) + raise NotImplementedError("%s\nechelon form over %s not yet implemented" % (msg, self.base_ring())) for c from 0 <= c < self.ncols(): for r from 0 <= r < self.nrows(): - self.set_unsafe(r, c, d.get_unsafe(r,c)) + self.set_unsafe(r, c, d.get_unsafe(r, c)) self.clear_cache() self.cache('pivots', tuple(p)) self.cache('in_echelon_form', True) @@ -7827,7 +7839,7 @@ cdef class Matrix(Matrix1): kwds['algorithm'] = algorithm return self._echelonize_ring(**kwds) except ArithmeticError as msg: - raise NotImplementedError("%s\nEchelon form not implemented over '%s'."%(msg,basring)) + raise NotImplementedError("%s\nEchelon form not implemented over '%s'." % (msg, basring)) def echelon_form(self, algorithm="default", cutoff=0, **kwds): r""" @@ -7922,7 +7934,7 @@ cdef class Matrix(Matrix1): if algorithm == 'default': v = E.echelonize(cutoff=cutoff, **kwds) else: - v = E.echelonize(algorithm = algorithm, cutoff=cutoff, **kwds) + v = E.echelonize(algorithm=algorithm, cutoff=cutoff, **kwds) E.set_immutable() # so we can cache the echelon form. self.cache('echelon_form', E) if v is not None: @@ -8068,7 +8080,7 @@ cdef class Matrix(Matrix1): if self.fetch('in_echelon_form'): return self.fetch('pivots') - tm = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm'%(self._nrows, self._ncols, algorithm)) + tm = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) self.check_mutability() cdef Matrix A @@ -8124,21 +8136,21 @@ cdef class Matrix(Matrix1): if algorithm == 'partial_pivoting': for r in range(start_row, nr): - abs_val = A.get_unsafe(r,c).abs() + abs_val = A.get_unsafe(r, c).abs() if abs_val > max_abs_val: max_abs_val = abs_val best_r = r elif algorithm == 'scaled_partial_pivoting': for r in range(start_row, nr): if scale_factors[r]: - abs_val = A.get_unsafe(r,c).abs() / scale_factors[r] + abs_val = A.get_unsafe(r, c).abs() / scale_factors[r] if abs_val > max_abs_val: max_abs_val = abs_val best_r = r - else: # algorithm == 'scaled_partial_pivoting_valuation': + else: # algorithm == 'scaled_partial_pivoting_valuation': for r in range(start_row, nr): if scale_factors[r] is not None: - abs_val = scale_factors[r] - A.get_unsafe(r,c).valuation() + abs_val = scale_factors[r] - A.get_unsafe(r, c).valuation() if max_abs_val is None or abs_val > max_abs_val: max_abs_val = abs_val best_r = r @@ -8481,7 +8493,7 @@ cdef class Matrix(Matrix1): permutations.append( (PermutationGroupElement([p(1 + i) for i in range(nrows)]), PermutationGroupElement([p(1 + nrows + i) - nrows for i in range(ncols)]) - )) + )) return permutations def permutation_normal_form(self, check=False): @@ -8588,14 +8600,14 @@ cdef class Matrix(Matrix1): # Sort each row with respect to S for the first matrix in X = MS X = copy(MS) SM = [sorted([(S[j], X[0][k][j]) for j in range(ncols)], reverse=True) - for k in range(l, nrows)] + for k in range(l, nrows)] SM = [[k[1] for k in s] for s in SM] # and pick the maximal row b = max(SM) # Find all rows equal to the maximal (potential new cases) m = [[j for j in range(nrows - l) if SM[j] == b]] - w = 0 # keeps track of how many entries we have removed from MS + w = 0 # keeps track of how many entries we have removed from MS # Let us find the maximal row in each of the entries in X = MS for i in range(1, len(X)): SN = [sorted([(S[j], X[i][k][j]) for j in range(ncols)], reverse=True) @@ -8731,7 +8743,7 @@ cdef class Matrix(Matrix1): truth, perm = N_B.is_isomorphic(M_B, certificate=True, edge_labels=True) from sage.groups.perm_gps.constructor import PermutationGroupElement if perm: - s = sorted(perm.items(), key=lambda x:x[0]) + s = sorted(perm.items(), key=lambda x: x[0]) row_perms = [value for k, value in s if k <= nrows] col_perms = [value - nrows for k, value in s if k > nrows] perm = (PermutationGroupElement(row_perms), PermutationGroupElement(col_perms)) @@ -8782,16 +8794,15 @@ cdef class Matrix(Matrix1): output = self.new_matrix(self._nrows, right._ncols) # The following used to be a little faster, but meanwhile # the previous line is faster. - #if self.is_sparse(): + # if self.is_sparse(): # output = self.matrix_space(self._nrows, right._ncols, sparse = True)(0) - #else: + # else: # output = self.matrix_space(self._nrows, right._ncols, sparse = False).zero_matrix().__copy__() - self_window = self.matrix_window() - right_window = right.matrix_window() + self_window = self.matrix_window() + right_window = right.matrix_window() output_window = output.matrix_window() - from . import strassen strassen.strassen_window_multiply(output_window, self_window, right_window, cutoff) return output @@ -8813,7 +8824,7 @@ cdef class Matrix(Matrix1): [ 0 0 0 0] [ 0 0 0 0] """ - tm = verbose('strassen echelon of %s x %s matrix'%(self._nrows, self._ncols)) + tm = verbose('strassen echelon of %s x %s matrix' % (self._nrows, self._ncols)) self.check_mutability() @@ -8836,8 +8847,8 @@ cdef class Matrix(Matrix1): verbose('done with strassen', tm) cpdef matrix_window(self, Py_ssize_t row=0, Py_ssize_t col=0, - Py_ssize_t nrows=-1, Py_ssize_t ncols=-1, - bint check=1): + Py_ssize_t nrows=-1, Py_ssize_t ncols=-1, + bint check=1): """ Return the requested matrix window. @@ -9091,7 +9102,7 @@ cdef class Matrix(Matrix1): """ if self._subdivisions is None: self._subdivisions = ([0, self._nrows], [0, self._ncols]) - key = "subdivision %s %s"%(i,j) + key = "subdivision %s %s" % (i, j) sd = self.fetch(key) if sd is None: sd = self[self._subdivisions[0][i]:self._subdivisions[0][i+1], @@ -9137,13 +9148,13 @@ cdef class Matrix(Matrix1): """ if self._subdivisions is None: if not i and not j: - return self[x,y] + return self[x, y] else: - raise IndexError("No such submatrix %s, %s"%(i,j)) + raise IndexError("No such submatrix %s, %s" % (i, j)) if x >= self._subdivisions[0][i+1]-self._subdivisions[0][i] or \ y >= self._subdivisions[1][j+1]-self._subdivisions[1][j]: - raise IndexError("Submatrix %s,%s has no entry %s,%s"%(i,j, x, y)) - return self[self._subdivisions[0][i] + x , self._subdivisions[1][j] + y] + raise IndexError("Submatrix %s,%s has no entry %s,%s" % (i, j, x, y)) + return self[self._subdivisions[0][i] + x, self._subdivisions[1][j] + y] def _subdivide_on_augment(self, left, right): r""" @@ -9454,7 +9465,7 @@ cdef class Matrix(Matrix1): for i from 0 <= i < self._nrows: for j from 0 <= j < self._ncols: self.set_unsafe(i, j, R._random_nonzero_element(*args, - **kwds)) + **kwds)) else: num = int(self._nrows * self._ncols * density) for i from 0 <= i < num: @@ -9494,7 +9505,7 @@ cdef class Matrix(Matrix1): """ return self.is_scalar(self.base_ring().one()) - def is_scalar(self, a = None): + def is_scalar(self, a=None): """ Return True if this matrix is a scalar matrix. @@ -9529,13 +9540,13 @@ cdef class Matrix(Matrix1): if a is None: if self._nrows == 0: return True - a = self.get_unsafe(0,0) + a = self.get_unsafe(0, 0) else: a = self.base_ring()(a) for i in range(self._nrows): for j in range(self._ncols): if i != j: - if not self.get_unsafe(i,j).is_zero(): + if not self.get_unsafe(i, j).is_zero(): return False else: if self.get_unsafe(i, i) != a: @@ -9572,7 +9583,7 @@ cdef class Matrix(Matrix1): for i in range(self._nrows): for j in range(self._ncols): if i != j: - if not self.get_unsafe(i,j).is_zero(): + if not self.get_unsafe(i, j).is_zero(): return False return True @@ -9682,7 +9693,7 @@ cdef class Matrix(Matrix1): P = self.transpose() * self # Orthogonal return P.is_scalar(1) - def is_bistochastic(self, normalized = True): + def is_bistochastic(self, normalized=True): r""" Returns ``True`` if this matrix is bistochastic. @@ -9845,12 +9856,12 @@ cdef class Matrix(Matrix1): cdef Matrix left = self*CT cdef Matrix right = CT*self - cdef Py_ssize_t i,j + cdef Py_ssize_t i, j normal = True # two products are Hermitian, need only check lower triangle for i from 0 <= i < self._nrows: for j from 0 <= j <= i: - if left.get_unsafe(i,j) != right.get_unsafe(i,j): + if left.get_unsafe(i, j) != right.get_unsafe(i, j): normal = False break if not normal: @@ -9967,11 +9978,11 @@ cdef class Matrix(Matrix1): ir = mc ic = mr b = 1.0 - elif max(mr,mc) > maxsize: + elif max(mr, mc) > maxsize: maxsize = float(maxsize) - ir = int(mc * maxsize/max(mr,mc)) - ic = int(mr * maxsize/max(mr,mc)) - b = max(mr,mc)/maxsize + ir = int(mc * maxsize / max(mr, mc)) + ic = int(mr * maxsize / max(mr, mc)) + b = max(mr, mc) / maxsize else: ir = mc ic = mr @@ -9988,7 +9999,7 @@ cdef class Matrix(Matrix1): for _x in range(bi): for _y in range(bi): if not self.get_unsafe((x*b + _x), (y*b + _y)).is_zero(): - v -= 1 #increase darkness + v -= 1 # increase darkness v = (v * fct + 0.5) pixel[y, x] = (v, v, v) return img @@ -10024,7 +10035,7 @@ cdef class Matrix(Matrix1): sage: a.density() 0 """ - cdef int x,y,k + cdef int x, y, k k = 0 nr = self.nrows() nc = self.ncols() @@ -10032,8 +10043,8 @@ cdef class Matrix(Matrix1): return 0 for x from 0 <= x < nr: for y from 0 <= y < nc: - if not self.get_unsafe(x,y).is_zero(): - k+=1 + if not self.get_unsafe(x, y).is_zero(): + k += 1 return QQ(k)/QQ(nr*nc) def inverse(self): @@ -10253,13 +10264,13 @@ cdef class Matrix(Matrix1): This is all left to the method `adjugate`. """ - n = self._ncols + n = self._ncols if self._nrows != n: raise ValueError("self must be a square matrix") A = self.charpoly().shift(-1)(self) - return A if n%2 else -A + return A if n % 2 else -A def QR(self, full=True): r""" @@ -10529,16 +10540,16 @@ cdef class Matrix(Matrix1): scale = sqrt(hip) q = (1/scale)*v Q.append(q) - R[row,i] = scale - for j in range(i+1, n): - R[row,j] = q.hermitian_inner_product(V[j]) - V[j] = V[j] - R[row,j]*q + R[row, i] = scale + for j in range(i + 1, n): + R[row, j] = q.hermitian_inner_product(V[j]) + V[j] = V[j] - R[row, j] * q row = row + 1 except TypeError: raise TypeError('QR decomposition unable to compute square roots in %s' % F) # complete to full orthonormal basis, or reduce to truncated R if full: - Qt = matrix(Q) # as rows here + Qt = matrix(Q) # as rows here if Qt.nrows() == 0: Qt = zero_matrix(F, 0, m) orthogonal = Qt.right_kernel().basis_matrix().transpose() @@ -10687,12 +10698,12 @@ cdef class Matrix(Matrix1): zero = F(0) Bstar = [] R = zero_matrix(F, n) - nnz = 0 # number non-zero rows in R, or number of nonzero vectors in Bstar + nnz = 0 # number non-zero rows in R, or number of nonzero vectors in Bstar for i in range(n): ortho = B[i] for j in range(nnz): - R[j,i] = Bstar[j].hermitian_inner_product(B[i])/Bstar[j].hermitian_inner_product(Bstar[j]) - ortho = ortho - R[j,i]*Bstar[j] + R[j, i] = Bstar[j].hermitian_inner_product(B[i]) / Bstar[j].hermitian_inner_product(Bstar[j]) + ortho = ortho - R[j, i] * Bstar[j] if ortho.hermitian_inner_product(ortho) != zero: Bstar.append(ortho) R[nnz, i] = 1 @@ -11028,7 +11039,8 @@ cdef class Matrix(Matrix1): R = self.base_ring() if isinstance(R, (sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): Q, R = self.transpose().QR() - m = R.nrows(); n = R.ncols() + m = R.nrows() + n = R.ncols() if m > n: Q = Q[0:m, 0:n] R = R[0:n, 0:n] @@ -11465,7 +11477,7 @@ cdef class Matrix(Matrix1): blocks = [] for eval, mult in evals: if mult == 1: - blocks.append((eval,1)) + blocks.append((eval, 1)) else: B = A - diagonal_matrix([eval]*n, sparse=sparse) C = B @@ -11494,7 +11506,7 @@ cdef class Matrix(Matrix1): # a Jordan chain for each, adding the chain (a sequence of # vectors) to the entry for the eigenvalue (which is a list). jordan_chains = {} - for eval,_ in evals: + for eval, _ in evals: jordan_chains[eval] = [] # Let B be the matrix `A - eval Id`. @@ -11532,9 +11544,9 @@ cdef class Matrix(Matrix1): # Now ``jordan_chains`` has all the columns of the transformation # matrix; we just need to put them in the right order. jordan_basis = [] - for eval,size in blocks: + for eval, size in blocks: # Find a block with the right size - for index,chain in enumerate(jordan_chains[eval]): + for index, chain in enumerate(jordan_chains[eval]): if len(chain) == size: jordan_basis += jordan_chains[eval].pop(index) break @@ -12592,7 +12604,7 @@ cdef class Matrix(Matrix1): R = self.base_ring() if not is_Vector(v): raise TypeError('first input should be a vector, not {0}'.format(v)) - if not (var is None or isinstance(var, str)): + if not (var is None or isinstance(var, str)): generator = False try: generator = var.is_gen() @@ -12911,7 +12923,7 @@ cdef class Matrix(Matrix1): True """ - cdef Matrix C # output matrix + cdef Matrix C # output matrix C = self.fetch('cholesky') if C is not None: return C @@ -12933,7 +12945,7 @@ cdef class Matrix(Matrix1): cdef Matrix L # block_ldlt() results cdef list d # block_ldlt() results try: - _,L,d = self._block_ldlt(True) + _, L, d = self._block_ldlt(True) except ValueError: # If the matrix was positive-definite, that would # have worked. @@ -12946,7 +12958,7 @@ cdef class Matrix(Matrix1): cdef bint extend = False for X in d: # The X are guaranteed to be one-by-one blocks. - x = X[0,0] + x = X[0, 0] if x <= zero: raise ValueError("matrix is not positive definite") @@ -12973,7 +12985,7 @@ cdef class Matrix(Matrix1): from sage.rings.qqbar import AA try: C = L.change_ring(AA) - except ValueError: # cannot coerce... + except ValueError: # cannot coerce... C = L.change_ring(F_ac) else: C = L.__copy__() @@ -12981,11 +12993,11 @@ cdef class Matrix(Matrix1): # Overwrite the (strict) upper-triangular part of "C", since a # priori it contains junk after _block_ldlt(). zero = C.base_ring().zero() - cdef Py_ssize_t i, j # loop indices + cdef Py_ssize_t i, j # loop indices for i in range(n): C.rescale_col_c(i, splits[i], 0) - for j in range(i+1,n): - C.set_unsafe(i,j,zero) + for j in range(i + 1, n): + C.set_unsafe(i, j, zero) C.set_immutable() self.cache('cholesky', C) return C @@ -13105,7 +13117,7 @@ cdef class Matrix(Matrix1): sage: actual == expected True """ - P,L,D = self.block_ldlt() + P, L, D = self.block_ldlt() # The default "echelonize" inverse() method works just fine for # triangular matrices. @@ -13558,24 +13570,24 @@ cdef class Matrix(Matrix1): # abs() necessary to convert zero to the # correct type for comparisons (Issue #12208) max_entry = abs(zero) - for i in range(k,m): - entry = abs(M.get_unsafe(i,k)) + for i in range(k, m): + entry = abs(M.get_unsafe(i, k)) if entry > max_entry: max_location = i max_entry = entry else: - for i in range(k,m): - if M.get_unsafe(i,k) != zero: + for i in range(k, m): + if M.get_unsafe(i, k) != zero: max_location = i break if max_location != -1: perm[k], perm[max_location] = perm[max_location], perm[k] M.swap_rows(k, max_location) for j in range(k+1, m): - scale = -M.get_unsafe(j,k)/M.get_unsafe(k,k) - M.set_unsafe(j,k, -scale) - for p in range(k+1,n): - M.set_unsafe(j,p, M.get_unsafe(j,p) + scale*M.get_unsafe(k,p)) + scale = -M.get_unsafe(j, k) / M.get_unsafe(k, k) + M.set_unsafe(j, k, -scale) + for p in range(k + 1, n): + M.set_unsafe(j, p, M.get_unsafe(j, p) + scale * M.get_unsafe(k, p)) perm = tuple(perm) M.set_immutable() compact = (perm, M) @@ -13594,11 +13606,11 @@ cdef class Matrix(Matrix1): perm = [perm[i]+1 for i in range(m)] P = sage.combinat.permutation.Permutation(perm).to_matrix() P = P.change_ring(F) - L = M.matrix_space(m,m).identity_matrix().__copy__() + L = M.matrix_space(m, m).identity_matrix().__copy__() for i in range(1, m): - for k in range(min(i,d)): - L[i,k] = M[i,k] - M[i,k] = zero + for k in range(min(i, d)): + L[i, k] = M[i, k] + M[i, k] = zero return P, L, M def _indefinite_factorization(self, algorithm, check=True): @@ -13840,16 +13852,16 @@ cdef class Matrix(Matrix1): t = L.get_unsafe(i, j) if conjugate: for k in range(j): - t -= L.get_unsafe(k,i)*L.get_unsafe(j,k).conjugate() + t -= L.get_unsafe(k, i) * L.get_unsafe(j, k).conjugate() else: for k in range(j): - t -= L.get_unsafe(k,i)*L.get_unsafe(j,k) + t -= L.get_unsafe(k, i) * L.get_unsafe(j, k) if i == j: if not t: - self.cache(cache_string, (False,i+1)) - return (False, i+1) + self.cache(cache_string, (False, i + 1)) + return (False, i + 1) d.append(t) - d_inv.append(one/t) + d_inv.append(one / t) L.set_unsafe(i, i, one) else: L.set_unsafe(j, i, t) @@ -14065,7 +14077,7 @@ cdef class Matrix(Matrix1): if result is not None: return result - cdef Py_ssize_t i, j, k # loop indices + cdef Py_ssize_t i, j, k # loop indices cdef Py_ssize_t r # another row/column index # We need to construct 1x1 and 2x2 matrices to stick in d. @@ -14089,7 +14101,7 @@ cdef class Matrix(Matrix1): # at the end of the function, not as its columns are computed. ring = self.base_ring().fraction_field() - cdef Matrix A # A copy of the input matrix + cdef Matrix A # A copy of the input matrix if self.base_ring() == ring: A = self.__copy__() else: @@ -14127,7 +14139,7 @@ cdef class Matrix(Matrix1): cdef list d = [] # And the parent of those diagonal blocks that are 1x1... - one_by_one_space = A.matrix_space(1,1) + one_by_one_space = A.matrix_space(1, 1) # The case n == 0 is *almost* handled by skipping the # forthcoming loop entirely. However, we must stick a trivial @@ -14143,7 +14155,7 @@ cdef class Matrix(Matrix1): # where we're storing the next iterate. So our indices are # always "k" greater than those of Higham or B&K. - A_kk = A.get_unsafe(k,k) + A_kk = A.get_unsafe(k, k) if k == (n-1): # Handle this trivial case manually, since otherwise the @@ -14151,7 +14163,7 @@ cdef class Matrix(Matrix1): # meaningless. The corresponding entry of "L" will be # fixed later (since it's an on-diagonal element, it gets # set to one eventually). - d.append( one_by_one_space(A_kk) ) + d.append(one_by_one_space(A_kk)) k += 1 continue @@ -14161,8 +14173,8 @@ cdef class Matrix(Matrix1): # It's a back door that lets us escape with only the standard non-block # non-pivoting LDL^T factorization. This allows us to implement e.g. # indefinite_factorization() in terms of this method. - d.append( one_by_one_space(A_kk) ) - _block_ldlt_pivot1x1(A,k) + d.append(one_by_one_space(A_kk)) + _block_ldlt_pivot1x1(A, k) k += 1 continue except ZeroDivisionError: @@ -14177,8 +14189,8 @@ cdef class Matrix(Matrix1): # Note: omega_1 is defined as a C double, but the abs() # below would make a complex number approximate anyway. omega_1 = 0 - for i in range(k+1,n): - a_ik_abs = A.get_unsafe(i,k).abs() + for i in range(k + 1, n): + a_ik_abs = A.get_unsafe(i, k).abs() if a_ik_abs > omega_1: omega_1 = a_ik_abs # We record the index "r" that corresponds to @@ -14198,7 +14210,7 @@ cdef class Matrix(Matrix1): # the 1x1 pivot "a" in the top-left position. The entry "a" # will be adjusted to "1" later on to ensure that "L" is # (block) unit-lower-triangular. - d.append( one_by_one_space(A_kk) ) + d.append(one_by_one_space(A_kk)) k += 1 continue @@ -14210,8 +14222,8 @@ cdef class Matrix(Matrix1): # otherwise. We are performing a 1x1 pivot, but the # rows/columns are already where we want them, so nothing # needs to be permuted. - d.append( one_by_one_space(A_kk) ) - _block_ldlt_pivot1x1(A,k) + d.append(one_by_one_space(A_kk)) + _block_ldlt_pivot1x1(A, k) k += 1 continue @@ -14225,27 +14237,30 @@ cdef class Matrix(Matrix1): # Note: omega_r is defined as a C double, but the abs() # below would make a complex number approximate anyway. omega_r = 0 - for j in range(k,r): - a_rj_abs = A.get_unsafe(r,j).abs() + for j in range(k, r): + a_rj_abs = A.get_unsafe(r, j).abs() if a_rj_abs > omega_r: omega_r = a_rj_abs if A_kk.abs()*omega_r >= alpha*(omega_1**2): # Step (2) in Higham or Step (4) in B&K. - d.append( one_by_one_space(A_kk) ) - _block_ldlt_pivot1x1(A,k) + d.append(one_by_one_space(A_kk)) + _block_ldlt_pivot1x1(A, k) k += 1 continue - A_rr = A.get_unsafe(r,r) + A_rr = A.get_unsafe(r, r) if A_rr.abs() > alpha*omega_r: # This is Step (3) in Higham or Step (5) in B&K. Still # a 1x1 pivot, but this time we need to swap # rows/columns k and r. - d.append( one_by_one_space(A_rr) ) - A.swap_columns_c(k,r); A.swap_rows_c(k,r) - p_k = p[k]; p[k] = p[r]; p[r] = p_k - _block_ldlt_pivot1x1(A,k) + d.append(one_by_one_space(A_rr)) + A.swap_columns_c(k, r) + A.swap_rows_c(k, r) + p_k = p[k] + p[k] = p[r] + p[r] = p_k + _block_ldlt_pivot1x1(A, k) k += 1 continue @@ -14253,16 +14268,19 @@ cdef class Matrix(Matrix1): # or Step (6) in B&K, where we perform a 2x2 pivot. See # pivot1x1() for an explanation of why it's OK to permute # the entries of "L" here as well. - A.swap_columns_c(k+1,r); A.swap_rows_c(k+1,r) - p_k = p[k+1]; p[k+1] = p[r]; p[r] = p_k + A.swap_columns_c(k + 1, r) + A.swap_rows_c(k + 1, r) + p_k = p[k + 1] + p[k + 1] = p[r] + p[r] = p_k # The top-left 2x2 submatrix (starting at position k,k) is # now our pivot. - E = A[k:k+2,k:k+2] + E = A[k: k + 2, k: k + 2] d.append(E) - C = A[k+2:n,k:k+2] - B = A[k+2:,k+2:] + C = A[k + 2: n, k: k + 2] + B = A[k + 2:, k+2:] # We don't actually need the inverse of E, what we really need # is C*E.inverse(), and that can be found by setting @@ -14279,10 +14297,10 @@ cdef class Matrix(Matrix1): # Compute the Schur complement that we'll work on during # the following iteration, and store it back in the lower- # right-hand corner of "A". - for i in range(n-k-2): - for j in range(i+1): - A.set_unsafe(k+2+i, k+2+j, schur_complement[i,j]) - A.set_unsafe(k+2+j, k+2+i, schur_complement[j,i]) + for i in range(n - k - 2): + for j in range(i + 1): + A.set_unsafe(k + 2 + i, k + 2 + j, schur_complement[i, j]) + A.set_unsafe(k + 2 + j, k + 2 + i, schur_complement[j, i]) # The on- and above-diagonal entries of "L" will be fixed # later, so we only need to worry about the lower-left entry @@ -14293,8 +14311,7 @@ cdef class Matrix(Matrix1): for j in range(2): # Store the new (k and (k+1)st) columns of "L" within # the lower-left-hand corner of "A". - A.set_unsafe(k+i+2, k+j, CE_inverse[i,j]) - + A.set_unsafe(k+i+2, k+j, CE_inverse[i, j]) k += 2 @@ -14303,7 +14320,7 @@ cdef class Matrix(Matrix1): # correctness. A.set_unsafe(i, i, one) - result = (p,A,d) + result = (p, A, d) self.cache(cache_string, result) return result @@ -14608,12 +14625,12 @@ cdef class Matrix(Matrix1): """ cdef Py_ssize_t n # size of the matrices - cdef Py_ssize_t i, j # loop indices - cdef Matrix P,L,D # output matrices + cdef Py_ssize_t i, j # loop indices + cdef Matrix P, L, D # output matrices - p,L,d = self._block_ldlt(classical) + p, L, d = self._block_ldlt(classical) MS = L.matrix_space() - P = MS.matrix(lambda i,j: p[j] == i) + P = MS.matrix(lambda i, j: p[j] == i) # Warning: when n == 0, this works, but returns a matrix # whose (nonexistent) entries are in ZZ rather than in @@ -14626,11 +14643,10 @@ cdef class Matrix(Matrix1): n = L._nrows zero = MS.base_ring().zero() for i in range(n): - for j in range(i+1,n): - L.set_unsafe(i,j,zero) - - return (P,L,D) + for j in range(i + 1, n): + L.set_unsafe(i, j, zero) + return (P, L, D) cdef bint _is_positive_definite_or_semidefinite(self, bint semi) except -1: """ @@ -14640,7 +14656,7 @@ cdef class Matrix(Matrix1): code. The boolean ``semi`` argument exists only to change "greater than zero" into "greater than or equal to zero." """ - from sage.rings.real_lazy import RLF,CLF + from sage.rings.real_lazy import RLF, CLF R = self.base_ring() @@ -14660,10 +14676,10 @@ cdef class Matrix(Matrix1): return False if self._nrows == 0: - return True # vacuously + return True # vacuously cdef list d - _,_,d = self._block_ldlt(False) + _, _, d = self._block_ldlt(False) # Check each 1x1 block for a nonpositive (negative) entry. If # we don't find any, the matrix is positive-(semi)definite. The @@ -14673,8 +14689,7 @@ cdef class Matrix(Matrix1): if semi: op = operator.ge - return all(d_i.nrows() == 1 and op(d_i[0,0], 0) for d_i in d) - + return all(d_i.nrows() == 1 and op(d_i[0, 0], 0) for d_i in d) def is_positive_semidefinite(self): r""" @@ -14986,7 +15001,7 @@ cdef class Matrix(Matrix1): result = self._is_positive_definite_or_semidefinite(False) if certificate: from sage.misc.superseded import deprecation - msg = "the 'certificate' argument is deprecated; if you " + msg = "the 'certificate' argument is deprecated; if you " msg += "need the corresponding factorization, you can " msg += "simply compute it yourself (the results are cached)" deprecation(31619, msg) @@ -14994,7 +15009,7 @@ cdef class Matrix(Matrix1): d = None if result: from sage.modules.free_module_element import vector - _,L,D = self.block_ldlt() + _, L, D = self.block_ldlt() d = vector(D.base_ring(), D.diagonal()) return (result, L, d) else: @@ -15075,7 +15090,7 @@ cdef class Matrix(Matrix1): m2 = hadamard_row_bound_mpfr(A) return min(m1, m2) - def find(self,f, indices=False): + def find(self, f, indices=False): r""" Find elements in this matrix satisfying the constraints in the function `f`. The function is evaluated on each element of @@ -15141,7 +15156,7 @@ cdef class Matrix(Matrix1): True """ from sage.matrix.matrix_space import MatrixSpace - cdef Py_ssize_t size,i,j + cdef Py_ssize_t size, i, j cdef object M if not indices: @@ -15150,20 +15165,20 @@ cdef class Matrix(Matrix1): M = PyList_New(0) for i from 0 <= i < size: - PyList_Append(M,f(PyList_GET_ITEM(L,i))) + PyList_Append(M, f(PyList_GET_ITEM(L, i))) from sage.rings.finite_rings.integer_mod_ring import IntegerModRing return MatrixSpace(IntegerModRing(2), - nrows=self._nrows,ncols=self._ncols).matrix(M) + nrows=self._nrows, ncols=self._ncols).matrix(M) else: # return matrix along with indices in a dictionary d = {} for i from 0 <= i < self._nrows: for j from 0 <= j < self._ncols: - if f(self.get_unsafe(i,j)): - d[(i,j)] = self.get_unsafe(i,j) + if f(self.get_unsafe(i, j)): + d[(i, j)] = self.get_unsafe(i, j) return d @@ -15654,7 +15669,7 @@ cdef class Matrix(Matrix1): """ d = self.smith_form(transformation=False) r = min(self.nrows(), self.ncols()) - return [d[i,i] for i in range(r)] + return [d[i, i] for i in range(r)] def smith_form(self, transformation=True, integral=None, exact=True): r""" @@ -15878,20 +15893,20 @@ cdef class Matrix(Matrix1): raise NotImplementedError("Smith form over non-exact rings not implemented at present") # first clear the first row and column - u,t,v = _smith_onestep(self) + u, t, v = _smith_onestep(self) # now recurse: t now has a nonzero entry at 0,0 and zero entries in the rest # of the 0th row and column, so we apply smith_form to the smaller submatrix - mm = t.submatrix(1,1) + mm = t.submatrix(1, 1) if transformation: dd, uu, vv = mm.smith_form(transformation=True) else: dd = mm.smith_form(transformation=False) mone = self.new_matrix(1, 1, [1]) - d = dd.new_matrix(1,1,[t[0,0]]).block_sum(dd) + d = dd.new_matrix(1, 1, [t[0, 0]]).block_sum(dd) if transformation: - u = uu.new_matrix(1,1,[1]).block_sum(uu) * u - v = v * vv.new_matrix(1,1,[1]).block_sum(vv) + u = uu.new_matrix(1, 1, [1]).block_sum(uu) * u + v = v * vv.new_matrix(1, 1, [1]).block_sum(vv) dp, up, vp = _smith_diag(d, transformation=transformation) if integral is False: dp = dp.change_ring(R) @@ -15972,36 +15987,37 @@ cdef class Matrix(Matrix1): pivot_cols = [] while j < n: k = i - while k < m and A.get_unsafe(k,j).is_zero(): # first nonzero entry + while k < m and A.get_unsafe(k, j).is_zero(): # first nonzero entry k += 1 if k < m: l = k + 1 while l < m: - while l < m and A.get_unsafe(l,j).is_zero(): # nonzero entry below + while l < m and A.get_unsafe(l, j).is_zero(): # nonzero entry below l += 1 - if l >= m: break + if l >= m: + break - a = A.get_unsafe(k,j) - b = A.get_unsafe(l,j) - d,p,q = a.xgcd(b) # p * a + q * b = d = gcd(a,b) + a = A.get_unsafe(k, j) + b = A.get_unsafe(l, j) + d, p, q = a.xgcd(b) # p * a + q * b = d = gcd(a,b) e = a // d f = b // d - for c in range(j,n): - Akc = A.get_unsafe(k,c) - Alc = A.get_unsafe(l,c) + for c in range(j, n): + Akc = A.get_unsafe(k, c) + Alc = A.get_unsafe(l, c) A.set_unsafe(k, c, p * Akc + q * Alc) A.set_unsafe(l, c, (-f) * Akc + e * Alc) if transformation: for c in range(m): - Ukc = U.get_unsafe(k,c) - Ulc = U.get_unsafe(l,c) + Ukc = U.get_unsafe(k, c) + Ulc = U.get_unsafe(l, c) U.set_unsafe(k, c, p * Ukc + q * Ulc) U.set_unsafe(l, c, (-f) * Ukc + e * Ulc) if i != k: - A.swap_rows_c(i,k) + A.swap_rows_c(i, k) if transformation: - U.swap_rows_c(i,k) + U.swap_rows_c(i, k) pivot_cols.append(j) i += 1 j += 1 @@ -16009,26 +16025,26 @@ cdef class Matrix(Matrix1): # reduce entries above pivots for i in range(len(pivot_cols)): j = pivot_cols[i] - pivot = A.get_unsafe(i,j) + pivot = A.get_unsafe(i, j) # possibly normalize the pivot if normalization: coeff = normalization(pivot) - for c in range(j,n): - A.set_unsafe(i, c, A.get_unsafe(i,c) * coeff) + for c in range(j, n): + A.set_unsafe(i, c, A.get_unsafe(i, c) * coeff) if transformation: for c in range(m): - U.set_unsafe(i, c, U.get_unsafe(i,c) * coeff) + U.set_unsafe(i, c, U.get_unsafe(i, c) * coeff) - pivot = A.get_unsafe(i,j) + pivot = A.get_unsafe(i, j) for k in range(i): - q = - (A.get_unsafe(k,j) // pivot) + q = - (A.get_unsafe(k, j) // pivot) if not q.is_zero(): - for c in range(j,n): - A.set_unsafe(k, c, A.get_unsafe(k,c) + q * A.get_unsafe(i,c)) + for c in range(j, n): + A.set_unsafe(k, c, A.get_unsafe(k, c) + q * A.get_unsafe(i, c)) if transformation: for c in range(m): - U.set_unsafe(k, c, U.get_unsafe(k,c) + q * U.get_unsafe(i,c)) + U.set_unsafe(k, c, U.get_unsafe(k, c) + q * U.get_unsafe(i, c)) if transformation: return U @@ -16173,25 +16189,25 @@ cdef class Matrix(Matrix1): return self.new_matrix(self.nrows(), self.nrows(), 1), self, [] else: return self.new_matrix(self.nrows(), self.nrows(), 1), self, [ - self.nonzero_positions_in_row(0)[0] ] + self.nonzero_positions_in_row(0)[0]] R = self.base_ring() # data type checks on R if not R.is_integral_domain(): raise TypeError("Generic echelon form only defined over " - "integral domains") + "integral domains") if not R.is_exact(): raise NotImplementedError("Echelon form over generic non-exact " - "rings not implemented at present") + "rings not implemented at present") left_mat, a = _generic_clear_column(self) assert left_mat * self == a - if a[0,0] != 0: + if a[0, 0] != 0: aa = a.submatrix(1, 1) s, t, pivs = aa._echelon_form_PID() - left_mat = s.new_matrix(1,1,[1]).block_sum(s) * left_mat + left_mat = s.new_matrix(1, 1, [1]).block_sum(s) * left_mat a = left_mat * self pivs = [0] + [x + 1 for x in pivs] @@ -16209,12 +16225,12 @@ cdef class Matrix(Matrix1): I = ideal_or_fractional(R, y) s = a[0][pivs[i]] t = I.small_residue(s) - v = R( (s-t) / y) + v = R((s-t) / y) left_mat.add_multiple_of_row(0, i, -v) a.add_multiple_of_row(0, i, -v) assert left_mat * self == a - except AttributeError: # on I.small_residue + except AttributeError: # on I.small_residue pass return left_mat, a, pivs @@ -16321,7 +16337,7 @@ cdef class Matrix(Matrix1): cdef list corners = [] # zero or one in corner of off-diagonal blocks if basis: from sage.matrix.constructor import identity_matrix - U = identity_matrix(R, n) # transformation matrix + U = identity_matrix(R, n) # transformation matrix # parity switch, True iff working on transpose # if False, mimic row operations only on U # if True, mimic column operations only on U @@ -16334,7 +16350,7 @@ cdef class Matrix(Matrix1): while zigging: # zigging means we are building a block nonzero = -1 for i in range(c+1, n): - if Z.get_unsafe(i,c): + if Z.get_unsafe(i, c): nonzero = i break zigging = (nonzero != -1) @@ -16378,7 +16394,7 @@ cdef class Matrix(Matrix1): # (inclusive), use it to clear entries to the right # but first record polynomial for block just built # this is the full monic polynomial, with correct coefficients - p = [-Z.get_unsafe(i,c) for i in range(s,c+1)] + p = [-Z.get_unsafe(i, c) for i in range(s, c + 1)] p.append(one) polys.append(p) @@ -16394,7 +16410,7 @@ cdef class Matrix(Matrix1): # Effectively: Z.add_multiple_of_row(i, j, scale) for k in range(c+1, n): # Z[i,k] = Z[i,k] + scale*Z[j,k] - Z.set_unsafe(i, k, Z.get_unsafe(i,k)+scale*Z.get_unsafe(j,k)) + Z.set_unsafe(i, k, Z.get_unsafe(i, k) + scale * Z.get_unsafe(j, k)) if basis: if trans: U.add_multiple_of_column(j, i, -scale) @@ -17161,7 +17177,7 @@ cdef class Matrix(Matrix1): companions.append(companion_matrix(poly, format=format)) return block_diagonal_matrix(companions, subdivide=subdivide) - def is_positive_operator_on(self,K1,K2=None): + def is_positive_operator_on(self, K1, K2=None): r""" Determine if this matrix is a positive operator on a cone. @@ -17595,7 +17611,7 @@ cdef class Matrix(Matrix1): """ return (-self).is_cross_positive_on(K) - def is_lyapunov_like_on(self,K): + def is_lyapunov_like_on(self, K): r""" Determine if this matrix is Lyapunov-like on a cone. @@ -17965,35 +17981,35 @@ def _smith_diag(d, transformation=True): else: left = right = None for i in range(n): - I = ideal_or_fractional(R, dp[i,i]) + I = ideal_or_fractional(R, dp[i, i]) if I == ideal_or_fractional(R, 1): - if dp[i,i] != 1: + if dp[i, i] != 1: if transformation: - left.add_multiple_of_row(i,i,R(R(1)/(dp[i,i])) - 1) - dp[i,i] = R(1) + left.add_multiple_of_row(i, i, R(R(1) / (dp[i, i])) - 1) + dp[i, i] = R(1) continue - for j in range(i+1,n): - if dp[j,j] not in I: - t = ideal_or_fractional(R, [dp[i,i], dp[j,j]]).gens_reduced() + for j in range(i + 1, n): + if dp[j, j] not in I: + t = ideal_or_fractional(R, [dp[i, i], dp[j, j]]).gens_reduced() if len(t) > 1: raise ArithmeticError t = t[0] # find lambda, mu such that lambda*d[i,i] + mu*d[j,j] = t - lamb = R(dp[i,i]/t).inverse_mod( ideal_or_fractional(R, dp[j,j]/t)) - mu = R((t - lamb*dp[i,i]) / dp[j,j]) + lamb = R(dp[i, i] / t).inverse_mod(ideal_or_fractional(R, dp[j, j] / t)) + mu = R((t - lamb * dp[i, i]) / dp[j, j]) newlmat = dp.new_matrix(dp.nrows(), dp.nrows(), 1) - newlmat[i,i] = lamb - newlmat[i,j] = 1 - newlmat[j,i] = R(-dp[j,j]*mu/t) - newlmat[j,j] = R(dp[i,i]/t) + newlmat[i, i] = lamb + newlmat[i, j] = 1 + newlmat[j, i] = R(-dp[j, j] * mu / t) + newlmat[j, j] = R(dp[i, i] / t) newrmat = dp.new_matrix(dp.ncols(), dp.ncols(), 1) - newrmat[i,i] = 1 - newrmat[i,j] = R(-dp[j,j]/t) - newrmat[j,i] = mu - newrmat[j,j] = R(lamb*dp[i,i] / t) + newrmat[i, i] = 1 + newrmat[i, j] = R(-dp[j, j] / t) + newrmat[j, i] = mu + newrmat[j, j] = R(lamb * dp[i, i] / t) if transformation: left = newlmat*left @@ -18039,13 +18055,13 @@ def _generic_clear_column(m): k = 0 while a[k, 0] == 0: k += 1 - if k == a.nrows(): # first column is zero + if k == a.nrows(): # first column is zero return left_mat, a # k is now first row such that a[k, 0] is nonzero - left_mat[0,0] = 0 - left_mat[k,k] = 0 - left_mat[0,k] = 1 - left_mat[k,0] = -1 + left_mat[0, 0] = 0 + left_mat[k, k] = 0 + left_mat[0, k] = 1 + left_mat[k, 0] = -1 a = left_mat*a if left_mat * m != a: raise ArithmeticError("Something went wrong") @@ -18059,15 +18075,15 @@ def _generic_clear_column(m): # [e,f] # is invertible over R - I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes + I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes for k in range(1, a.nrows()): - if a[k,0] not in I: + if a[k, 0] not in I: try: - v = ideal_or_fractional(R, a[0,0], a[k,0]).gens_reduced() + v = ideal_or_fractional(R, a[0, 0], a[k, 0]).gens_reduced() except Exception as msg: - raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0,0], a[k,0])) + raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0, 0], a[k, 0])) if len(v) > 1: - raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0,0], a[k,0])) + raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0, 0], a[k, 0])) B = v[0] # now we find c,d, using the fact that c * (a_{0,0}/B) - d * @@ -18076,40 +18092,40 @@ def _generic_clear_column(m): # need to handle carefully the case when a_{k,0}/B is a unit, i.e. a_{k,0} divides # a_{0,0}. - c = R(a[0,0] / B).inverse_mod(ideal_or_fractional(R, a[k,0] / B)) - d = R( (c*a[0,0] - B)/(a[k,0]) ) + c = R(a[0, 0] / B).inverse_mod(ideal_or_fractional(R, a[k, 0] / B)) + d = R((c*a[0, 0] - B)/(a[k, 0])) # sanity check - if c*a[0,0] - d*a[k,0] != B: + if c*a[0, 0] - d*a[k, 0] != B: raise ArithmeticError # now we find e,f such that e*d + c*f = 1 in the same way if c != 0: - e = d.inverse_mod( ideal_or_fractional(R, c) ) + e = d.inverse_mod(ideal_or_fractional(R, c)) f = R((1 - d*e)/c) else: - e = R(-a[k,0]/B) # here d is a unit and this is just 1/d + e = R(-a[k, 0] / B) # here d is a unit and this is just 1/d f = R(1) if e*d + c*f != 1: raise ArithmeticError newlmat = left_mat.parent()(1) - newlmat[0,0] = c - newlmat[0,k] = -d - newlmat[k,0] = e - newlmat[k,k] = f + newlmat[0, 0] = c + newlmat[0, k] = -d + newlmat[k, 0] = e + newlmat[k, k] = f if newlmat.det() != 1: raise ArithmeticError a = newlmat*a - I = ideal_or_fractional(R, a[0,0]) + I = ideal_or_fractional(R, a[0, 0]) left_mat = newlmat*left_mat if left_mat * m != a: raise ArithmeticError # now everything in column 0 is divisible by the pivot - for i in range(1,a.nrows()): - s = R( a[i, 0]/a[0, 0]) - a.add_multiple_of_row(i, 0, -s ) + for i in range(1, a.nrows()): + s = R(a[i, 0] / a[0, 0]) + a.add_multiple_of_row(i, 0, -s) left_mat.add_multiple_of_row(i, 0, -s) if left_mat * m != a: raise ArithmeticError @@ -18147,11 +18163,12 @@ def _smith_onestep(m): # preparation: if column 0 is zero, swap it with the first nonzero column j = 0 - while a.column(j) == 0: j += 1 + while a.column(j) == 0: + j += 1 if j > 0: - right_mat[0,0] = right_mat[j,j] = 0 - right_mat[0,j] = 1 - right_mat[j,0] = -1 + right_mat[0, 0] = right_mat[j, j] = 0 + right_mat[0, j] = 1 + right_mat[j, 0] = -1 a = a*right_mat if m * right_mat != a: raise ArithmeticError @@ -18162,15 +18179,15 @@ def _smith_onestep(m): # test if everything to the right of the pivot in row 0 is good as well isdone = True for jj in range(j+1, a.ncols()): - if a[0,jj] != 0: + if a[0, jj] != 0: isdone = False # if not we recurse -- algorithm must terminate if R is Noetherian. if not isdone: - s,t,u = _smith_onestep(a.transpose()) + s, t, u = _smith_onestep(a.transpose()) left_mat = u.transpose() * left_mat a = t.transpose() - right_mat = right_mat* s.transpose() + right_mat = right_mat * s.transpose() return left_mat, a, right_mat @@ -18445,7 +18462,7 @@ def _matrix_power_symbolic(A, n): # Jordan block Jk, its dimension nk, the eigenvalue m Jk = J.subdivision(k, k) nk = Jk.ncols() - mk = Jk[0,0] + mk = Jk[0, 0] # First row of block Mk; its entries are of the form # D^i(f) / i! with f = x^n and D = differentiation wrt x @@ -18492,28 +18509,28 @@ cdef inline bint _block_ldlt_pivot1x1(Matrix A, Py_ssize_t k) except 1: to return zero/one so that ``1`` can be used to indicate that a python exception occurred. """ - cdef Py_ssize_t i,j # dumy loop indices + cdef Py_ssize_t i, j # dumy loop indices cdef Py_ssize_t n = A._nrows - pivot = A.get_unsafe(k,k) + pivot = A.get_unsafe(k, k) # Compute the Schur complement that we'll work on during # the following iteration, and store it back in the lower- # right-hand corner of "A". - for i in range(n-k-1): - for j in range(i+1): - A.set_unsafe(k+1+i, - k+1+j, - ( A.get_unsafe(k+1+i,k+1+j) - - A.get_unsafe(k+1+i,k)*A.get_unsafe(k,k+1+j)/pivot )) - A.set_unsafe(k+1+j, - k+1+i, - A.get_unsafe(k+1+i,k+1+j).conjugate()) + for i in range(n - k - 1): + for j in range(i + 1): + A.set_unsafe(k + 1 + i, + k + 1 + j, + (A.get_unsafe(k + 1 + i, k + 1 + j) - + A.get_unsafe(k + 1 + i, k) * A.get_unsafe(k, k + 1 + j) / pivot)) + A.set_unsafe(k + 1 + j, + k + 1 + i, + A.get_unsafe(k + 1 + i, k + 1 + j).conjugate()) for i in range(n-k-1): # Store the new (kth) column of "L" within the lower- # left-hand corner of "A". - A.set_unsafe(k+i+1, + A.set_unsafe(k + i + 1, k, - A.get_unsafe(k+i+1,k)/ pivot) + A.get_unsafe(k + i + 1, k) / pivot) return 0 diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 6d3168f4995..aba931ad022 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -359,7 +359,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif (not isinstance(f, Polynomial)) or (parent is not f.parent()): if isinstance(f, dict): v = min(f) if f else 0 - f = {i-v: c for i,c in f.items()} + f = {i-v: c for i, c in f.items()} n += v f = parent._R(f) @@ -653,19 +653,19 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif e == 0: var = "" elif e > 0: - var = "|{}^{{{}}}".format(X,e) + var = "|{}^{{{}}}".format(X, e) if e >= 0: - s += "{}{}".format(x,var) - else: # negative e + s += "{}{}".format(x, var) + else: # negative e if e == -1: s += "\\frac{{{}}}{{{}}}".format(x, X) else: - s += "\\frac{{{}}}{{{}^{{{}}}}}".format(x, X,-e) + s += "\\frac{{{}}}{{{}^{{{}}}}}".format(x, X, -e) first = False s = s.replace(" + -", " - ") - s = s.replace(" 1|"," ") + s = s.replace(" 1|", " ") s = s.replace(" -1|", " -") - s = s.replace("|","") + s = s.replace("|", "") return s[1:] diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 38f9f7a8ebb..4cf0880880e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -77,6 +77,8 @@ def is_LaurentPolynomialRing(R): _cache = {} + + def LaurentPolynomialRing(base_ring, *args, **kwds): r""" Return the globally unique univariate or multivariate Laurent polynomial @@ -252,6 +254,7 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): _cache[R] = P return P + def _split_dict_(D, indices, group_by=None): r""" Split the dictionary ``D`` by ``indices`` and ``group_by``. @@ -334,6 +337,7 @@ def extract(T, indices): else: return result + def _split_laurent_polynomial_dict_(P, M, d): r""" Helper function for splitting a multivariate Laurent polynomial @@ -395,6 +399,7 @@ def value(d, R): pass return sum(P({k: 1}) * value(v, P) for k, v in D.items()).dict() + def from_fraction_field(L, x): r""" Helper function to construct a Laurent polynomial from an element of its From 040d9ec01d60e15d99b4726a2fbdd71cb7f2e127 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 23 Sep 2023 22:00:00 +0200 Subject: [PATCH 013/538] change __reduce__ again to avoid further errors --- src/sage/rings/polynomial/laurent_polynomial.pyx | 2 +- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index aba931ad022..9a042d526d8 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -379,7 +379,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: loads(dumps(elt)) == elt True """ - return LaurentPolynomial_univariate, (self.__u, self.__n) # eliminate first term in the tuple for the previous definition + return LaurentPolynomial_univariate, (self._parent, self.__u, self.__n) def _polynomial_(self, R): r""" diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index c36c52957cd..b193569d3fa 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -198,7 +198,10 @@ def __contains__(self, f): if not f or f in self.gens(): return True f = self.ring()(f) - g = f.__reduce__()[1][0] + if self.ring().ngens() > 1: + g = f.__reduce__()[1][0] + else: + g = f.__reduce__()[1][1] return (g in self.polynomial_ideal()) # Operations on ideals From 4e9a8bd3727e33cf113b62b0ca61628947ee3f99 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 30 Jul 2023 12:36:05 -0700 Subject: [PATCH 014/538] LatticePolytope: Use experimental method PermutationGroupElement._transpose_left --- src/sage/geometry/lattice_polytope.py | 35 +++++++++---------- .../groups/perm_gps/permgroup_element.pyx | 10 ++++++ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 26c7d9a3819..a3d17d6cd51 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -3215,7 +3215,7 @@ def index_of_max(iterable): for j in range(n_v): m = index_of_max(PM[0, i] for i in range(j, n_v)) if m > 0: - permutations[0][1] = S_v((j + 1, m + j + 1), check=False) * permutations[0][1] + permutations[0][1] = permutations[0][1]._transpose_left(j + 1, m + j + 1) first_row = list(PM[0]) # Arrange other rows one by one and compare with first row @@ -3224,7 +3224,7 @@ def index_of_max(iterable): permutations[n_s] = [S_f.one(), S_v.one()] m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(n_v)) if m > 0: - permutations[n_s][1] = S_v((1, m + 1), check=False) * permutations[n_s][1] + permutations[n_s][1] = permutations[n_s][1]._transpose_left(1, m + 1) d = (PM[k, permutations[n_s][1](1) - 1] - permutations[0][1](first_row)[0]) if d < 0: @@ -3235,8 +3235,7 @@ def index_of_max(iterable): for i in range(1, n_v): m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(i,n_v)) if m > 0: - permutations[n_s][1] = S_v((i + 1, m + i + 1), check=False) \ - * permutations[n_s][1] + permutations[n_s][1] = permutations[n_s][1]._transpose_left(i + 1, m + i + 1) if d == 0: d = (PM[k, permutations[n_s][1](i+1) - 1] -permutations[0][1](first_row)[i]) @@ -3246,7 +3245,7 @@ def index_of_max(iterable): # This row is smaller than 1st row, so nothing to do del permutations[n_s] continue - permutations[n_s][0] = S_f((1, k + 1), check=False) * permutations[n_s][0] + permutations[n_s][0] = permutations[n_s][0]._transpose_left(1, k + 1) if d == 0: # This row is the same, so we have a symmetry! n_s += 1 @@ -3286,7 +3285,7 @@ def index_of_max(iterable): # number of local permutations associated with current global n_p = 0 ccf = cf - permutations_bar = {0: copy(permutations[k])} + permutations_bar = {0: list(permutations[k])} # We look for the line with the maximal entry in the first # subsymmetry block, i.e. we are allowed to swap elements # between 0 and S(0) @@ -3295,14 +3294,14 @@ def index_of_max(iterable): v0 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] vj = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](j+1) - 1] if v0 < vj: - permutations_bar[n_p][1] = S_v((1, j + 1), check=False) * permutations_bar[n_p][1] + permutations_bar[n_p][1] = permutations_bar[n_p][1]._transpose_left(1, j + 1) if ccf == 0: l_r[0] = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] if s != l: - permutations_bar[n_p][0] = S_f((l + 1, s + 1), check=False) * permutations_bar[n_p][0] + permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) n_p += 1 ccf = 1 - permutations_bar[n_p] = copy(permutations[k]) + permutations_bar[n_p] = list(permutations[k]) else: d1 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] d = d1 - l_r[0] @@ -3312,20 +3311,20 @@ def index_of_max(iterable): elif d==0: # Maximal values agree, so possible symmetry if s != l: - permutations_bar[n_p][0] = S_f((l + 1, s + 1), check=False) * permutations_bar[n_p][0] + permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) n_p += 1 - permutations_bar[n_p] = copy(permutations[k]) + permutations_bar[n_p] = list(permutations[k]) else: # We found a greater maximal value for first entry. # It becomes our new reference: l_r[0] = d1 if s != l: - permutations_bar[n_p][0] = S_f((l + 1, s + 1), check=False) * permutations_bar[n_p][0] + permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) # Forget previous work done cf = 0 - permutations_bar = {0:copy(permutations_bar[n_p])} + permutations_bar = {0: list(permutations_bar[n_p])} n_p = 1 - permutations_bar[n_p] = copy(permutations[k]) + permutations_bar[n_p] = list(permutations[k]) n_s = k + 1 # Check if the permutations found just now work # with other elements @@ -3345,7 +3344,7 @@ def index_of_max(iterable): vc = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] vj = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(j+1) - 1] if (vc < vj): - permutations_bar[s][1] = S_v((c + 1, j + 1), check=False) * permutations_bar[s][1] + permutations_bar[s][1] = permutations_bar[s][1]._transpose_left(c + 1, j + 1) if ccf == 0: # Set reference and carry on to next permutation l_r[c] = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] @@ -3356,7 +3355,7 @@ def index_of_max(iterable): if d < 0: n_p -= 1 if s < n_p: - permutations_bar[s] = copy(permutations_bar[n_p]) + permutations_bar[s] = list(permutations_bar[n_p]) elif d > 0: # The current case leads to a smaller matrix, # hence this case becomes our new reference @@ -3366,10 +3365,10 @@ def index_of_max(iterable): n_s = k + 1 # Update permutations if (n_s - 1) > k: - permutations[k] = copy(permutations[n_s - 1]) + permutations[k] = list(permutations[n_s - 1]) n_s -= 1 for s in range(n_p): - permutations[n_s] = copy(permutations_bar[s]) + permutations[n_s] = list(permutations_bar[s]) n_s += 1 cf = n_s permutations = {k: permutations[k] for k in permutations if k < n_s} diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 2522b5c346d..2b36616b27e 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -1298,6 +1298,16 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return coercion_model.bin_op(left, right, operator.mul) + def _transpose_left(self, j, k): + if j == k: + return self + cdef PermutationGroupElement prod = self._new_c() + cdef int i + for i from 0 <= i < self.n: + prod.perm[i] = self.perm[i] + prod.perm[j - 1], prod.perm[k - 1] = self.perm[k - 1], self.perm[j - 1] + return prod + cpdef _mul_(left, _right): r""" EXAMPLES:: From 684f35968d4c1691c7aaff87e1ac5403ac9cafb2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 20:24:47 -0700 Subject: [PATCH 015/538] sage.geometry.palp_normal_form: Cythonized _palp_PM_max method --- src/sage/geometry/lattice_polytope.py | 200 +------------------ src/sage/geometry/palp_normal_form.pyx | 262 +++++++++++++++++++++++++ 2 files changed, 264 insertions(+), 198 deletions(-) create mode 100644 src/sage/geometry/palp_normal_form.pyx diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index a3d17d6cd51..1ae8504a306 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -3199,204 +3199,8 @@ def _palp_PM_max(self, check=False): sage: all(results) # long time True """ - PM = self.vertex_facet_pairing_matrix() - n_v = PM.ncols() - n_f = PM.nrows() - S_v = SymmetricGroup(n_v) - S_f = SymmetricGroup(n_f) - - # and find all the ways of making the first row of PM_max - def index_of_max(iterable): - # returns the index of max of any iterable - return max(enumerate(iterable), key=lambda x: x[1])[0] - - n_s = 1 - permutations = {0: [S_f.one(), S_v.one()]} - for j in range(n_v): - m = index_of_max(PM[0, i] for i in range(j, n_v)) - if m > 0: - permutations[0][1] = permutations[0][1]._transpose_left(j + 1, m + j + 1) - first_row = list(PM[0]) - - # Arrange other rows one by one and compare with first row - for k in range(1, n_f): - # Error for k == 1 already! - permutations[n_s] = [S_f.one(), S_v.one()] - m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(n_v)) - if m > 0: - permutations[n_s][1] = permutations[n_s][1]._transpose_left(1, m + 1) - d = (PM[k, permutations[n_s][1](1) - 1] - - permutations[0][1](first_row)[0]) - if d < 0: - # The largest elt of this row is smaller than largest elt - # in 1st row, so nothing to do - continue - # otherwise: - for i in range(1, n_v): - m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(i,n_v)) - if m > 0: - permutations[n_s][1] = permutations[n_s][1]._transpose_left(i + 1, m + i + 1) - if d == 0: - d = (PM[k, permutations[n_s][1](i+1) - 1] - -permutations[0][1](first_row)[i]) - if d < 0: - break - if d < 0: - # This row is smaller than 1st row, so nothing to do - del permutations[n_s] - continue - permutations[n_s][0] = permutations[n_s][0]._transpose_left(1, k + 1) - if d == 0: - # This row is the same, so we have a symmetry! - n_s += 1 - else: - # This row is larger, so it becomes the first row and - # the symmetries reset. - first_row = list(PM[k]) - permutations = {0: permutations[n_s]} - n_s = 1 - permutations = {k: permutations[k] for k in permutations if k < n_s} - - b = tuple(PM[permutations[0][0](1) - 1, permutations[0][1](j+1) - 1] for j in range(n_v)) - # Work out the restrictions the current permutations - # place on other permutations as a automorphisms - # of the first row - # The array is such that: - # S = [i, 1, ..., 1 (ith), j, i+1, ..., i+1 (jth), k ... ] - # describes the "symmetry blocks" - S = list(range(1, n_v + 1)) - for i in range(1, n_v): - if b[i-1] == b[i]: - S[i] = S[i-1] - S[S[i]-1] += 1 - else: - S[i] = i + 1 - - # We determine the other rows of PM_max in turn by use of perms and - # aut on previous rows. - for l in range(1, n_f - 1): - n_s = len(permutations) - n_s_bar = n_s - cf = 0 - l_r = [0]*n_v - # Search for possible local permutations based off previous - # global permutations. - for k in range(n_s_bar - 1, -1, -1): - # number of local permutations associated with current global - n_p = 0 - ccf = cf - permutations_bar = {0: list(permutations[k])} - # We look for the line with the maximal entry in the first - # subsymmetry block, i.e. we are allowed to swap elements - # between 0 and S(0) - for s in range(l, n_f): - for j in range(1, S[0]): - v0 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] - vj = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](j+1) - 1] - if v0 < vj: - permutations_bar[n_p][1] = permutations_bar[n_p][1]._transpose_left(1, j + 1) - if ccf == 0: - l_r[0] = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] - if s != l: - permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) - n_p += 1 - ccf = 1 - permutations_bar[n_p] = list(permutations[k]) - else: - d1 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] - d = d1 - l_r[0] - if d < 0: - # We move to the next line - continue - elif d==0: - # Maximal values agree, so possible symmetry - if s != l: - permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) - n_p += 1 - permutations_bar[n_p] = list(permutations[k]) - else: - # We found a greater maximal value for first entry. - # It becomes our new reference: - l_r[0] = d1 - if s != l: - permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) - # Forget previous work done - cf = 0 - permutations_bar = {0: list(permutations_bar[n_p])} - n_p = 1 - permutations_bar[n_p] = list(permutations[k]) - n_s = k + 1 - # Check if the permutations found just now work - # with other elements - for c in range(1, n_v): - h = S[c] - ccf = cf - # Now let us find out where the end of the - # next symmetry block is: - if h < c + 1: - h = S[h - 1] - s = n_p - # Check through this block for each possible permutation - while s > 0: - s -= 1 - # Find the largest value in this symmetry block - for j in range(c + 1, h): - vc = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] - vj = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(j+1) - 1] - if (vc < vj): - permutations_bar[s][1] = permutations_bar[s][1]._transpose_left(c + 1, j + 1) - if ccf == 0: - # Set reference and carry on to next permutation - l_r[c] = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] - ccf = 1 - else: - d1 = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] - d = d1 - l_r[c] - if d < 0: - n_p -= 1 - if s < n_p: - permutations_bar[s] = list(permutations_bar[n_p]) - elif d > 0: - # The current case leads to a smaller matrix, - # hence this case becomes our new reference - l_r[c] = d1 - cf = 0 - n_p = s + 1 - n_s = k + 1 - # Update permutations - if (n_s - 1) > k: - permutations[k] = list(permutations[n_s - 1]) - n_s -= 1 - for s in range(n_p): - permutations[n_s] = list(permutations_bar[s]) - n_s += 1 - cf = n_s - permutations = {k: permutations[k] for k in permutations if k < n_s} - # If the automorphisms are not already completely restricted, - # update them - if S != list(range(1, n_v + 1)): - # Take the old automorphisms and update by - # the restrictions the last worked out - # row imposes. - c = 0 - M = tuple(PM[permutations[0][0](l+1) - 1, permutations[0][1](j+1) - 1] for j in range(n_v)) - while c < n_v: - s = S[c] + 1 - S[c] = c + 1 - c += 1 - while c < (s - 1): - if M[c] == M[c - 1]: - S[c] = S[c - 1] - S[S[c] - 1] += 1 - else: - S[c] = c + 1 - c += 1 - # Now we have the perms, we construct PM_max using one of them - PM_max = PM.with_permuted_rows_and_columns(*permutations[0]) - if check: - return (PM_max, permutations) - else: - return PM_max + from .palp_normal_form import _palp_PM_max + return _palp_PM_max(self, check) def npoints(self): r""" diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx new file mode 100644 index 00000000000..77fffa8b761 --- /dev/null +++ b/src/sage/geometry/palp_normal_form.pyx @@ -0,0 +1,262 @@ +from sage.groups.perm_gps.permgroup_named import SymmetricGroup + + +def _palp_PM_max(self, check=False): + r""" + Compute the permutation normal form of the vertex facet pairing + matrix . + + The permutation normal form of a matrix is defined as the lexicographic + maximum under all permutations of its rows and columns. For more + more detail, see also + :meth:`~sage.matrix.matrix2.Matrix.permutation_normal_form`. + + Instead of using the generic method for computing the permutation + normal form, this method uses the PALP algorithm to compute + the permutation normal form and its automorphisms concurrently. + + INPUT: + + - ``check`` -- Boolean (default: ``False``), whether to return + the permutations leaving the maximal vertex-facet pairing + matrix invariant. + + OUTPUT: + + A matrix or a tuple of a matrix and a dict whose values are the + permutation group elements corresponding to the permutations + that permute :meth:`vertices` such that the vertex-facet pairing + matrix is maximal. + + EXAMPLES:: + + sage: o = lattice_polytope.cross_polytope(2) + sage: PM = o.vertex_facet_pairing_matrix() + sage: PM_max = PM.permutation_normal_form() # optional - sage.graphs + sage: PM_max == o._palp_PM_max() # optional - sage.graphs + True + sage: P2 = ReflexivePolytope(2, 0) + sage: PM_max, permutations = P2._palp_PM_max(check=True) + sage: PM_max + [3 0 0] + [0 3 0] + [0 0 3] + sage: list(permutations.values()) + [[(1,2,3), (1,2,3)], + [(1,3,2), (1,3,2)], + [(1,3), (1,3)], + [(1,2), (1,2)], + [(), ()], + [(2,3), (2,3)]] + sage: PM_max.automorphisms_of_rows_and_columns() + [((), ()), + ((1,2,3), (1,2,3)), + ((1,3,2), (1,3,2)), + ((2,3), (2,3)), + ((1,2), (1,2)), + ((1,3), (1,3))] + sage: PMs = ( i._palp_PM_max(check=True) + ....: for i in ReflexivePolytopes(2) ) + sage: results = ( len(i) == len(j.automorphisms_of_rows_and_columns()) + ....: for j, i in PMs ) + sage: all(results) # long time + True + """ + PM = self.vertex_facet_pairing_matrix() + n_v = PM.ncols() + n_f = PM.nrows() + S_v = SymmetricGroup(n_v) + S_f = SymmetricGroup(n_f) + + # and find all the ways of making the first row of PM_max + def index_of_max(iterable): + # returns the index of max of any iterable + return max(enumerate(iterable), key=lambda x: x[1])[0] + + n_s = 1 + permutations = {0: [S_f.one(), S_v.one()]} + for j in range(n_v): + m = index_of_max(PM[0, i] for i in range(j, n_v)) + if m > 0: + permutations[0][1] = permutations[0][1]._transpose_left(j + 1, m + j + 1) + first_row = list(PM[0]) + + # Arrange other rows one by one and compare with first row + for k in range(1, n_f): + # Error for k == 1 already! + permutations[n_s] = [S_f.one(), S_v.one()] + m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(n_v)) + if m > 0: + permutations[n_s][1] = permutations[n_s][1]._transpose_left(1, m + 1) + d = (PM[k, permutations[n_s][1](1) - 1] + - permutations[0][1](first_row)[0]) + if d < 0: + # The largest elt of this row is smaller than largest elt + # in 1st row, so nothing to do + continue + # otherwise: + for i in range(1, n_v): + m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(i,n_v)) + if m > 0: + permutations[n_s][1] = permutations[n_s][1]._transpose_left(i + 1, m + i + 1) + if d == 0: + d = (PM[k, permutations[n_s][1](i+1) - 1] + -permutations[0][1](first_row)[i]) + if d < 0: + break + if d < 0: + # This row is smaller than 1st row, so nothing to do + del permutations[n_s] + continue + permutations[n_s][0] = permutations[n_s][0]._transpose_left(1, k + 1) + if d == 0: + # This row is the same, so we have a symmetry! + n_s += 1 + else: + # This row is larger, so it becomes the first row and + # the symmetries reset. + first_row = list(PM[k]) + permutations = {0: permutations[n_s]} + n_s = 1 + permutations = {k: permutations[k] for k in permutations if k < n_s} + + b = tuple(PM[permutations[0][0](1) - 1, permutations[0][1](j+1) - 1] for j in range(n_v)) + # Work out the restrictions the current permutations + # place on other permutations as a automorphisms + # of the first row + # The array is such that: + # S = [i, 1, ..., 1 (ith), j, i+1, ..., i+1 (jth), k ... ] + # describes the "symmetry blocks" + S = list(range(1, n_v + 1)) + for i in range(1, n_v): + if b[i-1] == b[i]: + S[i] = S[i-1] + S[S[i]-1] += 1 + else: + S[i] = i + 1 + + # We determine the other rows of PM_max in turn by use of perms and + # aut on previous rows. + for l in range(1, n_f - 1): + n_s = len(permutations) + n_s_bar = n_s + cf = 0 + l_r = [0]*n_v + # Search for possible local permutations based off previous + # global permutations. + for k in range(n_s_bar - 1, -1, -1): + # number of local permutations associated with current global + n_p = 0 + ccf = cf + permutations_bar = {0: list(permutations[k])} + # We look for the line with the maximal entry in the first + # subsymmetry block, i.e. we are allowed to swap elements + # between 0 and S(0) + for s in range(l, n_f): + for j in range(1, S[0]): + v0 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] + vj = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](j+1) - 1] + if v0 < vj: + permutations_bar[n_p][1] = permutations_bar[n_p][1]._transpose_left(1, j + 1) + if ccf == 0: + l_r[0] = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] + if s != l: + permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) + n_p += 1 + ccf = 1 + permutations_bar[n_p] = list(permutations[k]) + else: + d1 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] + d = d1 - l_r[0] + if d < 0: + # We move to the next line + continue + elif d==0: + # Maximal values agree, so possible symmetry + if s != l: + permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) + n_p += 1 + permutations_bar[n_p] = list(permutations[k]) + else: + # We found a greater maximal value for first entry. + # It becomes our new reference: + l_r[0] = d1 + if s != l: + permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) + # Forget previous work done + cf = 0 + permutations_bar = {0: list(permutations_bar[n_p])} + n_p = 1 + permutations_bar[n_p] = list(permutations[k]) + n_s = k + 1 + # Check if the permutations found just now work + # with other elements + for c in range(1, n_v): + h = S[c] + ccf = cf + # Now let us find out where the end of the + # next symmetry block is: + if h < c + 1: + h = S[h - 1] + s = n_p + # Check through this block for each possible permutation + while s > 0: + s -= 1 + # Find the largest value in this symmetry block + for j in range(c + 1, h): + vc = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] + vj = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(j+1) - 1] + if (vc < vj): + permutations_bar[s][1] = permutations_bar[s][1]._transpose_left(c + 1, j + 1) + if ccf == 0: + # Set reference and carry on to next permutation + l_r[c] = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] + ccf = 1 + else: + d1 = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] + d = d1 - l_r[c] + if d < 0: + n_p -= 1 + if s < n_p: + permutations_bar[s] = list(permutations_bar[n_p]) + elif d > 0: + # The current case leads to a smaller matrix, + # hence this case becomes our new reference + l_r[c] = d1 + cf = 0 + n_p = s + 1 + n_s = k + 1 + # Update permutations + if (n_s - 1) > k: + permutations[k] = list(permutations[n_s - 1]) + n_s -= 1 + for s in range(n_p): + permutations[n_s] = list(permutations_bar[s]) + n_s += 1 + cf = n_s + permutations = {k: permutations[k] for k in permutations if k < n_s} + # If the automorphisms are not already completely restricted, + # update them + if S != list(range(1, n_v + 1)): + # Take the old automorphisms and update by + # the restrictions the last worked out + # row imposes. + c = 0 + M = tuple(PM[permutations[0][0](l+1) - 1, permutations[0][1](j+1) - 1] for j in range(n_v)) + while c < n_v: + s = S[c] + 1 + S[c] = c + 1 + c += 1 + while c < (s - 1): + if M[c] == M[c - 1]: + S[c] = S[c - 1] + S[S[c] - 1] += 1 + else: + S[c] = c + 1 + c += 1 + # Now we have the perms, we construct PM_max using one of them + PM_max = PM.with_permuted_rows_and_columns(*permutations[0]) + if check: + return (PM_max, permutations) + else: + return PM_max From 26c8607cc4d47bc180537fc45401cd38d6e91e2c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 2 Aug 2023 21:06:45 -0700 Subject: [PATCH 016/538] src/sage/geometry/palp_normal_form.pyx: More cythonization --- src/sage/geometry/palp_normal_form.pyx | 78 ++++++++++++++++---------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index 77fffa8b761..ec1a1550e36 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -1,4 +1,6 @@ +from sage.groups.perm_gps.permgroup_element cimport PermutationGroupElement from sage.groups.perm_gps.permgroup_named import SymmetricGroup +from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense def _palp_PM_max(self, check=False): @@ -62,9 +64,9 @@ def _palp_PM_max(self, check=False): sage: all(results) # long time True """ - PM = self.vertex_facet_pairing_matrix() - n_v = PM.ncols() - n_f = PM.nrows() + cdef Matrix_integer_dense PM = self.vertex_facet_pairing_matrix() + cdef int n_v = PM.ncols() + cdef int n_f = PM.nrows() S_v = SymmetricGroup(n_v) S_f = SymmetricGroup(n_f) @@ -73,12 +75,14 @@ def _palp_PM_max(self, check=False): # returns the index of max of any iterable return max(enumerate(iterable), key=lambda x: x[1])[0] - n_s = 1 - permutations = {0: [S_f.one(), S_v.one()]} + cdef int n_s = 1 + cdef dict permutations = {0: [S_f.one(), S_v.one()]} + cdef int j, k, m, d + for j in range(n_v): m = index_of_max(PM[0, i] for i in range(j, n_v)) if m > 0: - permutations[0][1] = permutations[0][1]._transpose_left(j + 1, m + j + 1) + permutations[0][1] = ( permutations[0][1])._transpose_left(j + 1, m + j + 1) first_row = list(PM[0]) # Arrange other rows one by one and compare with first row @@ -87,28 +91,27 @@ def _palp_PM_max(self, check=False): permutations[n_s] = [S_f.one(), S_v.one()] m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(n_v)) if m > 0: - permutations[n_s][1] = permutations[n_s][1]._transpose_left(1, m + 1) - d = (PM[k, permutations[n_s][1](1) - 1] - - permutations[0][1](first_row)[0]) + permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(1, m + 1) + d = PM[k, ( permutations[n_s][1])(1) - 1] - ( permutations[0][1])(first_row)[0] if d < 0: # The largest elt of this row is smaller than largest elt # in 1st row, so nothing to do continue # otherwise: for i in range(1, n_v): - m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(i,n_v)) + m = index_of_max(PM[k, ( permutations[n_s][1](j+1)) - 1] for j in range(i,n_v)) if m > 0: - permutations[n_s][1] = permutations[n_s][1]._transpose_left(i + 1, m + i + 1) + permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(i + 1, m + i + 1) if d == 0: - d = (PM[k, permutations[n_s][1](i+1) - 1] - -permutations[0][1](first_row)[i]) + d = (PM[k, ( permutations[n_s][1])(i+1) - 1] + - ( permutations[0][1])(first_row)[i]) if d < 0: break if d < 0: # This row is smaller than 1st row, so nothing to do del permutations[n_s] continue - permutations[n_s][0] = permutations[n_s][0]._transpose_left(1, k + 1) + permutations[n_s][0] = ( permutations[n_s][0])._transpose_left(1, k + 1) if d == 0: # This row is the same, so we have a symmetry! n_s += 1 @@ -120,14 +123,15 @@ def _palp_PM_max(self, check=False): n_s = 1 permutations = {k: permutations[k] for k in permutations if k < n_s} - b = tuple(PM[permutations[0][0](1) - 1, permutations[0][1](j+1) - 1] for j in range(n_v)) + cdef tuple b = tuple(PM[( permutations[0][0])(1) - 1, + ( permutations[0][1])(j+1) - 1] for j in range(n_v)) # Work out the restrictions the current permutations # place on other permutations as a automorphisms # of the first row # The array is such that: # S = [i, 1, ..., 1 (ith), j, i+1, ..., i+1 (jth), k ... ] # describes the "symmetry blocks" - S = list(range(1, n_v + 1)) + cdef list S = list(range(1, n_v + 1)) for i in range(1, n_v): if b[i-1] == b[i]: S[i] = S[i-1] @@ -135,6 +139,9 @@ def _palp_PM_max(self, check=False): else: S[i] = i + 1 + cdef int l, np, cf, ccf, n_s_bar, d1, v0, vc, vj + cdef list l_r + # We determine the other rows of PM_max in turn by use of perms and # aut on previous rows. for l in range(1, n_f - 1): @@ -154,19 +161,23 @@ def _palp_PM_max(self, check=False): # between 0 and S(0) for s in range(l, n_f): for j in range(1, S[0]): - v0 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] - vj = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](j+1) - 1] + v0 = PM[( permutations_bar[n_p][0])(s+1) - 1, + ( permutations_bar[n_p][1])(1) - 1] + vj = PM[( permutations_bar[n_p][0])(s+1) - 1, + ( permutations_bar[n_p][1])(j+1) - 1] if v0 < vj: - permutations_bar[n_p][1] = permutations_bar[n_p][1]._transpose_left(1, j + 1) + permutations_bar[n_p][1] = ( permutations_bar[n_p][1])._transpose_left(1, j + 1) if ccf == 0: - l_r[0] = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] + l_r[0] = PM[( permutations_bar[n_p][0])(s+1) - 1, + ( permutations_bar[n_p][1])(1) - 1] if s != l: - permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) + permutations_bar[n_p][0] = ( permutations_bar[n_p][0])._transpose_left(l + 1, s + 1) n_p += 1 ccf = 1 permutations_bar[n_p] = list(permutations[k]) else: - d1 = PM[permutations_bar[n_p][0](s+1) - 1, permutations_bar[n_p][1](1) - 1] + d1 = PM[( permutations_bar[n_p][0])(s+1) - 1, + ( permutations_bar[n_p][1])(1) - 1] d = d1 - l_r[0] if d < 0: # We move to the next line @@ -174,7 +185,7 @@ def _palp_PM_max(self, check=False): elif d==0: # Maximal values agree, so possible symmetry if s != l: - permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) + permutations_bar[n_p][0] = ( permutations_bar[n_p][0])._transpose_left(l + 1, s + 1) n_p += 1 permutations_bar[n_p] = list(permutations[k]) else: @@ -182,7 +193,7 @@ def _palp_PM_max(self, check=False): # It becomes our new reference: l_r[0] = d1 if s != l: - permutations_bar[n_p][0] = permutations_bar[n_p][0]._transpose_left(l + 1, s + 1) + permutations_bar[n_p][0] = ( permutations_bar[n_p][0])._transpose_left(l + 1, s + 1) # Forget previous work done cf = 0 permutations_bar = {0: list(permutations_bar[n_p])} @@ -204,16 +215,20 @@ def _palp_PM_max(self, check=False): s -= 1 # Find the largest value in this symmetry block for j in range(c + 1, h): - vc = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] - vj = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(j+1) - 1] - if (vc < vj): - permutations_bar[s][1] = permutations_bar[s][1]._transpose_left(c + 1, j + 1) + vc = PM[( permutations_bar[s][0])(l+1) - 1, + ( permutations_bar[s][1])(c+1) - 1] + vj = PM[( permutations_bar[s][0])(l+1) - 1, + ( permutations_bar[s][1])(j+1) - 1] + if vc < vj: + permutations_bar[s][1] = ( permutations_bar[s][1])._transpose_left(c + 1, j + 1) if ccf == 0: # Set reference and carry on to next permutation - l_r[c] = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] + l_r[c] = PM[( permutations_bar[s][0])(l+1) - 1, + ( permutations_bar[s][1])(c+1) - 1] ccf = 1 else: - d1 = PM[(permutations_bar[s][0])(l+1) - 1, (permutations_bar[s][1])(c+1) - 1] + d1 = PM[( permutations_bar[s][0])(l+1) - 1, + ( permutations_bar[s][1])(c+1) - 1] d = d1 - l_r[c] if d < 0: n_p -= 1 @@ -242,7 +257,8 @@ def _palp_PM_max(self, check=False): # the restrictions the last worked out # row imposes. c = 0 - M = tuple(PM[permutations[0][0](l+1) - 1, permutations[0][1](j+1) - 1] for j in range(n_v)) + M = tuple(PM[( permutations[0][0])(l+1) - 1, + ( permutations[0][1])(j+1) - 1] for j in range(n_v)) while c < n_v: s = S[c] + 1 S[c] = c + 1 From e5d593549b16152bb6e439f3e71d426ba4f69b1c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Aug 2023 12:56:17 -0700 Subject: [PATCH 017/538] src/sage/geometry/palp_normal_form.pyx: Cython loop to replace index_of_max --- src/sage/geometry/palp_normal_form.pyx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index ec1a1550e36..27b847535d5 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -78,6 +78,7 @@ def _palp_PM_max(self, check=False): cdef int n_s = 1 cdef dict permutations = {0: [S_f.one(), S_v.one()]} cdef int j, k, m, d + cdef int element, max_element for j in range(n_v): m = index_of_max(PM[0, i] for i in range(j, n_v)) @@ -89,7 +90,7 @@ def _palp_PM_max(self, check=False): for k in range(1, n_f): # Error for k == 1 already! permutations[n_s] = [S_f.one(), S_v.one()] - m = index_of_max(PM[k, permutations[n_s][1](j+1) - 1] for j in range(n_v)) + m = index_of_max(PM[k, ( permutations[n_s][1])(j+1) - 1] for j in range(n_v)) if m > 0: permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(1, m + 1) d = PM[k, ( permutations[n_s][1])(1) - 1] - ( permutations[0][1])(first_row)[0] @@ -99,9 +100,15 @@ def _palp_PM_max(self, check=False): continue # otherwise: for i in range(1, n_v): - m = index_of_max(PM[k, ( permutations[n_s][1](j+1)) - 1] for j in range(i,n_v)) - if m > 0: - permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(i + 1, m + i + 1) + max_element = PM[k, ( permutations[n_s][1](i + 1)) - 1] + m = i + 1 + for j in range(i + 1, n_v): + element = PM[k, ( permutations[n_s][1](j+1)) - 1] + if element > max_element: + max_element = element + m = j + if m > i + 1: + permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(i + 1, m) if d == 0: d = (PM[k, ( permutations[n_s][1])(i+1) - 1] - ( permutations[0][1])(first_row)[i]) From 1425cb13d28b94dbe5e7c912f76eddf556392bd7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Aug 2023 14:12:10 -0700 Subject: [PATCH 018/538] src/sage/geometry/palp_normal_form.pyx: Cython loop to replace index_of_max (fixup) --- src/sage/geometry/palp_normal_form.pyx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index 27b847535d5..dbb37844f1e 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -100,15 +100,15 @@ def _palp_PM_max(self, check=False): continue # otherwise: for i in range(1, n_v): - max_element = PM[k, ( permutations[n_s][1](i + 1)) - 1] - m = i + 1 + max_element = PM[k, ( permutations[n_s][1])(i + 1) - 1] + m = i for j in range(i + 1, n_v): - element = PM[k, ( permutations[n_s][1](j+1)) - 1] + element = PM[k, ( permutations[n_s][1])(j + 1) - 1] if element > max_element: max_element = element m = j - if m > i + 1: - permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(i + 1, m) + if m > i: + permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(i + 1, m + 1) if d == 0: d = (PM[k, ( permutations[n_s][1])(i+1) - 1] - ( permutations[0][1])(first_row)[i]) From 5fba248fa287813384f4c7482595b43e8d1a41fb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Aug 2023 16:01:31 -0700 Subject: [PATCH 019/538] src/sage/geometry/palp_normal_form.pyx: Do not keep first_row as a list --- src/sage/geometry/palp_normal_form.pyx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index dbb37844f1e..e97f12c6dc5 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -84,7 +84,8 @@ def _palp_PM_max(self, check=False): m = index_of_max(PM[0, i] for i in range(j, n_v)) if m > 0: permutations[0][1] = ( permutations[0][1])._transpose_left(j + 1, m + j + 1) - first_row = list(PM[0]) + + cdef first_row_index = 0 # Arrange other rows one by one and compare with first row for k in range(1, n_f): @@ -93,7 +94,8 @@ def _palp_PM_max(self, check=False): m = index_of_max(PM[k, ( permutations[n_s][1])(j+1) - 1] for j in range(n_v)) if m > 0: permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(1, m + 1) - d = PM[k, ( permutations[n_s][1])(1) - 1] - ( permutations[0][1])(first_row)[0] + d = (PM[k, ( permutations[n_s][1])(1) - 1] + - PM[first_row_index, ( permutations[0][1])(1) - 1]) if d < 0: # The largest elt of this row is smaller than largest elt # in 1st row, so nothing to do @@ -111,7 +113,7 @@ def _palp_PM_max(self, check=False): permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(i + 1, m + 1) if d == 0: d = (PM[k, ( permutations[n_s][1])(i+1) - 1] - - ( permutations[0][1])(first_row)[i]) + - PM[first_row_index, ( permutations[0][1])(i + 1) - 1]) if d < 0: break if d < 0: @@ -125,7 +127,7 @@ def _palp_PM_max(self, check=False): else: # This row is larger, so it becomes the first row and # the symmetries reset. - first_row = list(PM[k]) + first_row_index = k permutations = {0: permutations[n_s]} n_s = 1 permutations = {k: permutations[k] for k in permutations if k < n_s} From 524c37c767ff501c3bd3485c729be4180489cb02 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Aug 2023 17:38:02 -0700 Subject: [PATCH 020/538] src/sage/geometry/palp_normal_form.pyx: Replace another use of index_of_max --- src/sage/geometry/palp_normal_form.pyx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index e97f12c6dc5..e772cb9455c 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -91,7 +91,13 @@ def _palp_PM_max(self, check=False): for k in range(1, n_f): # Error for k == 1 already! permutations[n_s] = [S_f.one(), S_v.one()] - m = index_of_max(PM[k, ( permutations[n_s][1])(j+1) - 1] for j in range(n_v)) + max_element = PM[k, ( permutations[n_s][1])(1) - 1] + m = 0 + for j in range(1, n_v): + element = PM[k, ( permutations[n_s][1])(j + 1) - 1] + if element > max_element: + max_element = element + m = j if m > 0: permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(1, m + 1) d = (PM[k, ( permutations[n_s][1])(1) - 1] From 011f6989bb74a75968fede4880d46f9f78d25f14 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Aug 2023 17:38:42 -0700 Subject: [PATCH 021/538] src/sage/groups/perm_gps/permgroup_element.pxd: Add cpdef --- src/sage/groups/perm_gps/permgroup_element.pxd | 1 + src/sage/groups/perm_gps/permgroup_element.pyx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/groups/perm_gps/permgroup_element.pxd b/src/sage/groups/perm_gps/permgroup_element.pxd index 0a584745f96..b013451d5a0 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pxd +++ b/src/sage/groups/perm_gps/permgroup_element.pxd @@ -18,6 +18,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): cpdef _set_permutation_group_element(self, PermutationGroupElement p, bint convert) cpdef _mul_(self, other) + cpdef PermutationGroupElement _transpose_left(self, int j, int k) cpdef PermutationGroupElement _generate_new(self, list new_list) cpdef PermutationGroupElement _generate_new_GAP(self, old) cpdef _gap_list(self) diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 2b36616b27e..d64c01efce8 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -1298,7 +1298,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return coercion_model.bin_op(left, right, operator.mul) - def _transpose_left(self, j, k): + cpdef PermutationGroupElement _transpose_left(self, int j, int k): if j == k: return self cdef PermutationGroupElement prod = self._new_c() From b15c25fb8c2fe59435e8c1be277320d5e697f6ad Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 3 Aug 2023 23:03:24 -0700 Subject: [PATCH 022/538] src/sage/geometry/palp_normal_form.pyx: Faster access to elements of PM --- src/sage/geometry/palp_normal_form.pyx | 58 +++++++++++++------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index e772cb9455c..54dd7239391 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -91,35 +91,35 @@ def _palp_PM_max(self, check=False): for k in range(1, n_f): # Error for k == 1 already! permutations[n_s] = [S_f.one(), S_v.one()] - max_element = PM[k, ( permutations[n_s][1])(1) - 1] + max_element = PM.get_unsafe_int(k, ( permutations[n_s][1])(1) - 1) m = 0 for j in range(1, n_v): - element = PM[k, ( permutations[n_s][1])(j + 1) - 1] + element = PM.get_unsafe_int(k, ( permutations[n_s][1])(j + 1) - 1) if element > max_element: max_element = element m = j if m > 0: permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(1, m + 1) - d = (PM[k, ( permutations[n_s][1])(1) - 1] - - PM[first_row_index, ( permutations[0][1])(1) - 1]) + d = (PM.get_unsafe_int(k, ( permutations[n_s][1])(1) - 1) + - PM.get_unsafe_int(first_row_index, ( permutations[0][1])(1) - 1)) if d < 0: # The largest elt of this row is smaller than largest elt # in 1st row, so nothing to do continue # otherwise: for i in range(1, n_v): - max_element = PM[k, ( permutations[n_s][1])(i + 1) - 1] + max_element = PM.get_unsafe_int(k, ( permutations[n_s][1])(i + 1) - 1) m = i for j in range(i + 1, n_v): - element = PM[k, ( permutations[n_s][1])(j + 1) - 1] + element = PM.get_unsafe_int(k, ( permutations[n_s][1])(j + 1) - 1) if element > max_element: max_element = element m = j if m > i: permutations[n_s][1] = ( permutations[n_s][1])._transpose_left(i + 1, m + 1) if d == 0: - d = (PM[k, ( permutations[n_s][1])(i+1) - 1] - - PM[first_row_index, ( permutations[0][1])(i + 1) - 1]) + d = (PM.get_unsafe_int(k, ( permutations[n_s][1])(i+1) - 1) + - PM.get_unsafe_int(first_row_index, ( permutations[0][1])(i + 1) - 1)) if d < 0: break if d < 0: @@ -138,8 +138,9 @@ def _palp_PM_max(self, check=False): n_s = 1 permutations = {k: permutations[k] for k in permutations if k < n_s} - cdef tuple b = tuple(PM[( permutations[0][0])(1) - 1, - ( permutations[0][1])(j+1) - 1] for j in range(n_v)) + cdef tuple b = tuple(PM.get_unsafe_int(( permutations[0][0])(1) - 1, + ( permutations[0][1])(j+1) - 1) + for j in range(n_v)) # Work out the restrictions the current permutations # place on other permutations as a automorphisms # of the first row @@ -176,23 +177,23 @@ def _palp_PM_max(self, check=False): # between 0 and S(0) for s in range(l, n_f): for j in range(1, S[0]): - v0 = PM[( permutations_bar[n_p][0])(s+1) - 1, - ( permutations_bar[n_p][1])(1) - 1] - vj = PM[( permutations_bar[n_p][0])(s+1) - 1, - ( permutations_bar[n_p][1])(j+1) - 1] + v0 = PM.get_unsafe_int(( permutations_bar[n_p][0])(s+1) - 1, + ( permutations_bar[n_p][1])(1) - 1) + vj = PM.get_unsafe_int(( permutations_bar[n_p][0])(s+1) - 1, + ( permutations_bar[n_p][1])(j+1) - 1) if v0 < vj: permutations_bar[n_p][1] = ( permutations_bar[n_p][1])._transpose_left(1, j + 1) if ccf == 0: - l_r[0] = PM[( permutations_bar[n_p][0])(s+1) - 1, - ( permutations_bar[n_p][1])(1) - 1] + l_r[0] = PM.get_unsafe_int(( permutations_bar[n_p][0])(s+1) - 1, + ( permutations_bar[n_p][1])(1) - 1) if s != l: permutations_bar[n_p][0] = ( permutations_bar[n_p][0])._transpose_left(l + 1, s + 1) n_p += 1 ccf = 1 permutations_bar[n_p] = list(permutations[k]) else: - d1 = PM[( permutations_bar[n_p][0])(s+1) - 1, - ( permutations_bar[n_p][1])(1) - 1] + d1 = PM.get_unsafe_int(( permutations_bar[n_p][0])(s+1) - 1, + ( permutations_bar[n_p][1])(1) - 1) d = d1 - l_r[0] if d < 0: # We move to the next line @@ -230,20 +231,20 @@ def _palp_PM_max(self, check=False): s -= 1 # Find the largest value in this symmetry block for j in range(c + 1, h): - vc = PM[( permutations_bar[s][0])(l+1) - 1, - ( permutations_bar[s][1])(c+1) - 1] - vj = PM[( permutations_bar[s][0])(l+1) - 1, - ( permutations_bar[s][1])(j+1) - 1] + vc = PM.get_unsafe_int(( permutations_bar[s][0])(l+1) - 1, + ( permutations_bar[s][1])(c+1) - 1) + vj = PM.get_unsafe_int(( permutations_bar[s][0])(l+1) - 1, + ( permutations_bar[s][1])(j+1) - 1) if vc < vj: permutations_bar[s][1] = ( permutations_bar[s][1])._transpose_left(c + 1, j + 1) if ccf == 0: # Set reference and carry on to next permutation - l_r[c] = PM[( permutations_bar[s][0])(l+1) - 1, - ( permutations_bar[s][1])(c+1) - 1] + l_r[c] = PM.get_unsafe_int(( permutations_bar[s][0])(l+1) - 1, + ( permutations_bar[s][1])(c+1) - 1) ccf = 1 else: - d1 = PM[( permutations_bar[s][0])(l+1) - 1, - ( permutations_bar[s][1])(c+1) - 1] + d1 = PM.get_unsafe_int(( permutations_bar[s][0])(l+1) - 1, + ( permutations_bar[s][1])(c+1) - 1) d = d1 - l_r[c] if d < 0: n_p -= 1 @@ -272,8 +273,9 @@ def _palp_PM_max(self, check=False): # the restrictions the last worked out # row imposes. c = 0 - M = tuple(PM[( permutations[0][0])(l+1) - 1, - ( permutations[0][1])(j+1) - 1] for j in range(n_v)) + M = tuple(PM.get_unsafe_int(( permutations[0][0])(l+1) - 1, + ( permutations[0][1])(j+1) - 1) + for j in range(n_v)) while c < n_v: s = S[c] + 1 S[c] = c + 1 From 9ba1cd85ab58873dae431aa98f284c1c124f9754 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 4 Aug 2023 21:22:07 -0700 Subject: [PATCH 023/538] sage.geometry.palp_normal_form: Add _palp_canonical_order, factored out from .lattice_polytope --- src/sage/geometry/lattice_polytope.py | 38 ++++---------- src/sage/geometry/palp_normal_form.pyx | 70 +++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 1ae8504a306..cd14c9d0ca6 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -3155,8 +3155,8 @@ def _palp_PM_max(self, check=False): INPUT: - ``check`` -- Boolean (default: ``False``), whether to return - the permutations leaving the maximal vertex-facet pairing - matrix invariant. + the permutations leaving the maximal vertex-facet pairing + matrix invariant. OUTPUT: @@ -3200,7 +3200,7 @@ def _palp_PM_max(self, check=False): True """ from .palp_normal_form import _palp_PM_max - return _palp_PM_max(self, check) + return _palp_PM_max(self.vertex_facet_pairing_matrix(), check) def npoints(self): r""" @@ -4978,12 +4978,13 @@ def _palp_canonical_order(V, PM_max, permutations): - ``PM_max`` -- the maximal vertex-facet pairing matrix - - ``permutation`` -- the permutations of the vertices yielding + - ``permutations`` -- the permutations of the vertices yielding ``PM_max``. OUTPUT: - The PALP normal form as a :class:`point collection `. + The PALP normal form as a :class:`point collection ` + and a permutation. TESTS:: @@ -4998,32 +4999,15 @@ def _palp_canonical_order(V, PM_max, permutations): M(-1, 0) in 2-d lattice M, (1,3,2,4)) """ - n_v = PM_max.ncols() - S_v = SymmetricGroup(n_v) - p_c = S_v.one() - M_max = [max(row[j] for row in PM_max.rows()) for j in range(n_v)] - S_max = sum(PM_max) - for i in range(n_v): - k = i - for j in range(i + 1, n_v): - if M_max[j] < M_max[k] or \ - (M_max[j] == M_max[k] and S_max[j] < S_max[k]): - k = j - if not k == i: - M_max[i], M_max[k] = M_max[k], M_max[i] - S_max[i], S_max[k] = S_max[k], S_max[i] - p_c = S_v((1 + i, 1 + k), check=False) * p_c - # Create array of possible NFs. - permutations = [p_c * l[1] for l in permutations.values()] + from .palp_normal_form import _palp_canonical_order + Vmatrix = V.column_matrix() - Vs = [(Vmatrix.with_permuted_columns(sig).hermite_form(), sig) - for sig in permutations] - Vmin = min(Vs, key=lambda x:x[0]) Vmodule = V.module() - vertices = [Vmodule(_) for _ in Vmin[0].columns()] + vertices, permutation = _palp_canonical_order(Vmatrix, PM_max, permutations) + vertices = [Vmodule(v) for v in vertices] for v in vertices: v.set_immutable() - return (PointCollection(vertices, Vmodule), Vmin[1]) + return PointCollection(vertices, Vmodule), permutation def _palp_convert_permutation(permutation): diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index 54dd7239391..e5efacb6d27 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -1,9 +1,11 @@ from sage.groups.perm_gps.permgroup_element cimport PermutationGroupElement from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense +from sage.matrix.special import column_matrix +from sage.structure.element import Matrix -def _palp_PM_max(self, check=False): +def _palp_PM_max(Matrix_integer_dense PM, check=False): r""" Compute the permutation normal form of the vertex facet pairing matrix . @@ -64,7 +66,6 @@ def _palp_PM_max(self, check=False): sage: all(results) # long time True """ - cdef Matrix_integer_dense PM = self.vertex_facet_pairing_matrix() cdef int n_v = PM.ncols() cdef int n_f = PM.nrows() S_v = SymmetricGroup(n_v) @@ -293,3 +294,68 @@ def _palp_PM_max(self, check=False): return (PM_max, permutations) else: return PM_max + + +def _palp_canonical_order(vertices, PM_max, permutations): + r""" + Compute the PALP normal form of vertices of a lattice polytope + using auxiliary data computed elsewhere. + + This is a helper function for + :meth:`~sage.geometry.lattice_polytope.LatticePolytopeClass.normal_form` + and should not be called directly. + + Given an iterable of vertices, the maximal vertex-facet pairing matrix + and the permutations realizing this matrix, apply the last part of the + PALP algorithm and return the normal form. + + INPUT: + + - ``vertices`` -- iterable of iterables. The vertices. + + - ``PM_max`` -- the maximal vertex-facet pairing matrix + + - ``permutation`` -- the permutations of the vertices yielding ``PM_max``. + + OUTPUT: + + The PALP normal form as an iterable of integer vectors. + + TESTS:: + + sage: L = lattice_polytope.cross_polytope(2) + sage: V = L.vertices() + sage: PM_max, permutations = L._palp_PM_max(check=True) # optional - sage.groups + sage: from sage.geometry.lattice_polytope import _palp_canonical_order + sage: _palp_canonical_order(V, PM_max, permutations) # optional - sage.groups + (M( 1, 0), + M( 0, 1), + M( 0, -1), + M(-1, 0) + in 2-d lattice M, (1,3,2,4)) + """ + n_v = PM_max.ncols() + S_v = SymmetricGroup(n_v) + p_c = S_v.one() + M_max = [max(row[j] for row in PM_max.rows()) for j in range(n_v)] + S_max = sum(PM_max) + for i in range(n_v): + k = i + for j in range(i + 1, n_v): + if M_max[j] < M_max[k] or \ + (M_max[j] == M_max[k] and S_max[j] < S_max[k]): + k = j + if not k == i: + M_max[i], M_max[k] = M_max[k], M_max[i] + S_max[i], S_max[k] = S_max[k], S_max[i] + p_c = S_v((1 + i, 1 + k), check=False) * p_c + # Create array of possible NFs. + permutations = [p_c * l[1] for l in permutations.values()] + if isinstance(vertices, Matrix): + Vmatrix = vertices + else: + Vmatrix = column_matrix(vertices) + Vs = [(Vmatrix.with_permuted_columns(sig).hermite_form(), sig) + for sig in permutations] + Vmin = min(Vs, key=lambda x: x[0]) + return Vmin[0].columns(), Vmin[1] From a47701b6374e9c894bee01f008267e7af213e3f4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 4 Aug 2023 21:43:44 -0700 Subject: [PATCH 024/538] Polyhedron_ZZ.normal_form: New --- src/sage/geometry/lattice_polytope.py | 2 +- src/sage/geometry/polyhedron/base_ZZ.py | 38 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index cd14c9d0ca6..fd1bc168bb1 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -5024,7 +5024,7 @@ def _palp_convert_permutation(permutation): OUTPUT: - A :class:`permutation group element `. + A :class:`permutation group element `. EXAMPLES:: diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 561ed76d70c..f40b88b284b 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -834,3 +834,41 @@ def is_known_summand(poly): decompositions.append((X, Y)) summands += [X, Y] return tuple(decompositions) + + def normal_form(self, algorithm="palp_native", permutation=False): + r""" + EXAMPLES: + + We compute the normal form of the "diamond":: + + sage: d = Polyhedron([(1,0), (0,1), (-1,0), (0,-1)]) + sage: d.vertices() + (A vertex at (-1, 0), + A vertex at (0, -1), + A vertex at (0, 1), + A vertex at (1, 0)) + sage: d.normal_form() + [(1, 0), (0, 1), (0, -1), (-1, 0)] + + It is not possible to compute normal forms for polytopes which do not + span the space:: + + sage: p = Polyhedron([(1,0,0), (0,1,0), (-1,0,0), (0,-1,0)]) + sage: p.normal_form() + Traceback (most recent call last): + ... + ValueError: normal form is not defined for A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices + """ + from sage.geometry.palp_normal_form import _palp_PM_max, _palp_canonical_order + + if self.dim() < self.ambient_dim(): + raise ValueError("normal form is not defined for %s" % self) + + PM = self.slack_matrix().transpose() + PM_max, permutations = _palp_PM_max(PM, check=True) + out = _palp_canonical_order(self.vertices(), PM_max, permutations) + + if permutation: + return out + else: + return out[0] From 3411205c29962fac2b1ec7a126157a28bd368cb9 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 22 Aug 2023 17:50:32 -0700 Subject: [PATCH 025/538] fix bug --- src/sage/geometry/palp_normal_form.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index e5efacb6d27..1dae6e70e1e 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -82,7 +82,7 @@ def _palp_PM_max(Matrix_integer_dense PM, check=False): cdef int element, max_element for j in range(n_v): - m = index_of_max(PM[0, i] for i in range(j, n_v)) + m = index_of_max(PM.get_unsafe_int(0, ( permutations[0][1])(i + 1) - 1) for i in range(j, n_v)) if m > 0: permutations[0][1] = ( permutations[0][1])._transpose_left(j + 1, m + j + 1) From 88ebcf72d3aec71219d55be1687734dd1442066d Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 22 Aug 2023 18:13:09 -0700 Subject: [PATCH 026/538] add the example --- src/sage/geometry/lattice_polytope.py | 7 +++++++ src/sage/geometry/palp_normal_form.pyx | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index fd1bc168bb1..0138f50a2b3 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -3198,6 +3198,13 @@ def _palp_PM_max(self, check=False): ....: for j, i in PMs ) sage: all(results) # long time True + sage: P = Polyhedron([(-4,-6),(-4,-5),(0,0),(1,0),(5,6)]) + sage: P.lattice_polytope()._palp_PM_max() + [9 5 4 0 0] + [6 0 6 5 0] + [1 5 0 0 4] + [0 6 0 1 6] + [0 0 3 5 3] """ from .palp_normal_form import _palp_PM_max return _palp_PM_max(self.vertex_facet_pairing_matrix(), check) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index 1dae6e70e1e..d2ffb05c8e1 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -65,6 +65,18 @@ def _palp_PM_max(Matrix_integer_dense PM, check=False): ....: for j, i in PMs ) sage: all(results) # long time True + sage: from sage.geometry.palp_normal_form import _palp_PM_max, _palp_canonical_order + sage: P = Polyhedron([(-4,-6),(-4,-5),(0,0),(1,0),(5,6)]) + sage: PM = P.slack_matrix().transpose() + sage: _palp_PM_max(PM) + [9 5 4 0 0] + [6 0 6 5 0] + [1 5 0 0 4] + [0 6 0 1 6] + [0 0 3 5 3] + sage: PM_max, permutations = _palp_PM_max(PM, check=True) + sage: _palp_canonical_order(P.vertices(), PM_max, permutations) + ([(1, 0), (0, 0), (2, 4), (1, 5), (-1, 1)], (1,2,3)) """ cdef int n_v = PM.ncols() cdef int n_f = PM.nrows() From 996191cc1c0d3677169cb8bd4d68bd3f7b380767 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Aug 2023 12:33:48 -0700 Subject: [PATCH 027/538] Put new tests in TESTS sections --- src/sage/geometry/lattice_polytope.py | 9 +++++++-- src/sage/geometry/palp_normal_form.pyx | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 0138f50a2b3..fc33c78a15f 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -3198,8 +3198,13 @@ def _palp_PM_max(self, check=False): ....: for j, i in PMs ) sage: all(results) # long time True - sage: P = Polyhedron([(-4,-6),(-4,-5),(0,0),(1,0),(5,6)]) - sage: P.lattice_polytope()._palp_PM_max() + + TESTS: + + Check that a bug introduced in :issue:`35997` is fixed:: + + sage: P = LatticePolytope([(-4,-6),(-4,-5),(0,0),(1,0),(5,6)]) + sage: P._palp_PM_max() [9 5 4 0 0] [6 0 6 5 0] [1 5 0 0 4] diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index d2ffb05c8e1..a08a9166831 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -65,6 +65,11 @@ def _palp_PM_max(Matrix_integer_dense PM, check=False): ....: for j, i in PMs ) sage: all(results) # long time True + + TESTS: + + Check that a bug introduced in :issue:`35997` is fixed:: + sage: from sage.geometry.palp_normal_form import _palp_PM_max, _palp_canonical_order sage: P = Polyhedron([(-4,-6),(-4,-5),(0,0),(1,0),(5,6)]) sage: PM = P.slack_matrix().transpose() From d6e433f4eb676110199dd2ffc5639925f35667cc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Aug 2023 12:58:30 -0700 Subject: [PATCH 028/538] src/sage/geometry/lattice_polytope.py: Update copyright --- src/sage/geometry/lattice_polytope.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index fc33c78a15f..5d4b0a45a41 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -93,8 +93,27 @@ """ # **************************************************************************** -# Copyright (C) 2007-2013 Andrey Novoseltsev -# Copyright (C) 2007-2013 William Stein +# Copyright (C) 2007-2017 Andrey Novoseltsev +# 2007-2013 William Stein +# 2009 Mike Hansen +# 2009-2020 John H. Palmieri +# 2010-2014 Volker Braun +# 2012 Samuel Gonshaw +# 2013 Jan Keitel +# 2014 André Apitzsch +# 2014 Wilfried Luebbe +# 2015-2022 Frédéric Chapoton +# 2015 Ursula Whitcher +# 2016 Jori Mäntysalo +# 2017 Travis Scrimshaw +# 2018 Christian Stump +# 2018 Vincent Klein +# 2019 Vincent Delecroix +# 2019 Jonathan Kliem +# 2020 Samuel Lelièvre +# 2021-2023 Matthias Koeppe +# 2022 David Coudert +# 2023 Luze Xu # # 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 From e241607216a5a0e4f5f7b2d10995ae3ca31acaed Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Aug 2023 12:58:49 -0700 Subject: [PATCH 029/538] src/sage/geometry/palp_normal_form.pyx: Add copyright --- src/sage/geometry/palp_normal_form.pyx | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index a08a9166831..6eca2a56b9b 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -1,3 +1,24 @@ +r""" +PALP normal form of vertices of a lattice polytope +""" +# **************************************************************************** +# Copyright (C) 2013 Jan Keitel +# 2014 Volker Braun +# 2018 Christian Stump +# 2019 Vincent Delecroix +# 2019 Jonathan Kliem +# 2021 Michael Orlitzky +# 2018-2022 Frédéric Chapoton +# 2023 Luze Xu +# 2023 Matthias Koeppe +# +# 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.groups.perm_gps.permgroup_element cimport PermutationGroupElement from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense @@ -7,8 +28,7 @@ from sage.structure.element import Matrix def _palp_PM_max(Matrix_integer_dense PM, check=False): r""" - Compute the permutation normal form of the vertex facet pairing - matrix . + Compute the permutation normal form of the vertex facet pairing matrix. The permutation normal form of a matrix is defined as the lexicographic maximum under all permutations of its rows and columns. For more From 6f8769be8e3c3c499d9ef42e20b896c7eaf34435 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 12 Aug 2023 13:18:33 -0700 Subject: [PATCH 030/538] src/sage/geometry/palp_normal_form.pyx: One more use of _transpose_left --- src/sage/geometry/palp_normal_form.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index 6eca2a56b9b..92bbd9a362d 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -385,7 +385,7 @@ def _palp_canonical_order(vertices, PM_max, permutations): if not k == i: M_max[i], M_max[k] = M_max[k], M_max[i] S_max[i], S_max[k] = S_max[k], S_max[i] - p_c = S_v((1 + i, 1 + k), check=False) * p_c + p_c = p_c._transpose_left(1 + i, 1 + k) # Create array of possible NFs. permutations = [p_c * l[1] for l in permutations.values()] if isinstance(vertices, Matrix): From 48348b5a490069825df3fdc9f9c649ab902ff26d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Aug 2023 13:41:34 -0700 Subject: [PATCH 031/538] src/sage/geometry/palp_normal_form.pyx: Update # needs --- src/sage/geometry/palp_normal_form.pyx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index 92bbd9a362d..212e7736023 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.groups r""" PALP normal form of vertices of a lattice polytope """ @@ -56,8 +57,8 @@ def _palp_PM_max(Matrix_integer_dense PM, check=False): sage: o = lattice_polytope.cross_polytope(2) sage: PM = o.vertex_facet_pairing_matrix() - sage: PM_max = PM.permutation_normal_form() # optional - sage.graphs - sage: PM_max == o._palp_PM_max() # optional - sage.graphs + sage: PM_max = PM.permutation_normal_form() + sage: PM_max == o._palp_PM_max() True sage: P2 = ReflexivePolytope(2, 0) sage: PM_max, permutations = P2._palp_PM_max(check=True) @@ -362,9 +363,9 @@ def _palp_canonical_order(vertices, PM_max, permutations): sage: L = lattice_polytope.cross_polytope(2) sage: V = L.vertices() - sage: PM_max, permutations = L._palp_PM_max(check=True) # optional - sage.groups + sage: PM_max, permutations = L._palp_PM_max(check=True) sage: from sage.geometry.lattice_polytope import _palp_canonical_order - sage: _palp_canonical_order(V, PM_max, permutations) # optional - sage.groups + sage: _palp_canonical_order(V, PM_max, permutations) (M( 1, 0), M( 0, 1), M( 0, -1), From 63abe415a738385c65400fa4d9783298a8035ce0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 23 Aug 2023 15:51:43 -0700 Subject: [PATCH 032/538] PermutationGroupElement._transpose_left: Generalize --- .../groups/perm_gps/permgroup_element.pxd | 2 +- .../groups/perm_gps/permgroup_element.pyx | 25 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/perm_gps/permgroup_element.pxd b/src/sage/groups/perm_gps/permgroup_element.pxd index b013451d5a0..21b509f06d1 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pxd +++ b/src/sage/groups/perm_gps/permgroup_element.pxd @@ -18,7 +18,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): cpdef _set_permutation_group_element(self, PermutationGroupElement p, bint convert) cpdef _mul_(self, other) - cpdef PermutationGroupElement _transpose_left(self, int j, int k) + cpdef PermutationGroupElement _transpose_left(self, j, k) cpdef PermutationGroupElement _generate_new(self, list new_list) cpdef PermutationGroupElement _generate_new_GAP(self, old) cpdef _gap_list(self) diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index d64c01efce8..f25db93010f 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -1298,13 +1298,36 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return coercion_model.bin_op(left, right, operator.mul) - cpdef PermutationGroupElement _transpose_left(self, int j, int k): + cpdef PermutationGroupElement _transpose_left(self, j, k): + r""" + Return the product of the transposition `(j, k)` with ``self``. + + EXAMPLES:: + + sage: S = SymmetricGroup(5) + sage: s = S([5, 2, 4, 3, 1]) + sage: s._transpose_left(2, 3) + (1,5)(2,4,3) + sage: S((2, 3)) * s + (1,5)(2,4,3) + + sage: S = SymmetricGroup(["a", "b", "c", "d", "e"]) + sage: s = S(["e", "b", "d", "c", "a"]) + sage: s._transpose_left("b", "c") + ('a','e')('b','d','c') + sage: S(("b", "c")) * s + ('a','e')('b','d','c') + """ if j == k: return self cdef PermutationGroupElement prod = self._new_c() cdef int i for i from 0 <= i < self.n: prod.perm[i] = self.perm[i] + if not self._parent._has_natural_domain(): + convert_dict = self._parent._domain_to_gap + j = convert_dict[j] + k = convert_dict[k] prod.perm[j - 1], prod.perm[k - 1] = self.perm[k - 1], self.perm[j - 1] return prod From 38da660c064a64ef1aa09b7c085d1a46ac105f81 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Wed, 23 Aug 2023 14:08:38 -0700 Subject: [PATCH 033/538] remove index_of_max --- src/sage/geometry/palp_normal_form.pyx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index 212e7736023..fad9f968c06 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -109,18 +109,19 @@ def _palp_PM_max(Matrix_integer_dense PM, check=False): S_v = SymmetricGroup(n_v) S_f = SymmetricGroup(n_f) - # and find all the ways of making the first row of PM_max - def index_of_max(iterable): - # returns the index of max of any iterable - return max(enumerate(iterable), key=lambda x: x[1])[0] - cdef int n_s = 1 cdef dict permutations = {0: [S_f.one(), S_v.one()]} cdef int j, k, m, d cdef int element, max_element for j in range(n_v): - m = index_of_max(PM.get_unsafe_int(0, ( permutations[0][1])(i + 1) - 1) for i in range(j, n_v)) + max_element = PM.get_unsafe_int(0, ( permutations[0][1])(j + 1) - 1) + m = 0 + for i in range(j + 1, n_v): + element = PM.get_unsafe_int(0, ( permutations[0][1])(i + 1) - 1) + if element > max_element: + max_element = element + m = i - j if m > 0: permutations[0][1] = ( permutations[0][1])._transpose_left(j + 1, m + j + 1) From e5025aea8fc425abdd2570e3c9195a79a6d79414 Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 5 Sep 2023 10:38:59 -0700 Subject: [PATCH 034/538] crash example --- src/sage/geometry/lattice_polytope.py | 63 +++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 5d4b0a45a41..4e30dbd242f 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -3032,6 +3032,69 @@ def normal_form(self, algorithm="palp", permutation=False): M( 0, -1), M(-1, 0) in 2-d lattice M + + Note that the default algorithm may crash for higher dimensions:: + + sage: P = LatticePolytope([[-3, -3, -6, -6, -1], [3, 3, 6, 6, 1], [-3, -3, -6, -6, 1], + ....: [-3, -3, -3, -6, 0], [-3, -3, -3, 0, 0], [-3, -3, 0, 0, 0], + ....: [-3, 0, -6, -6, 0], [-3, 0, -3, -6, 0], [-3, 0, -3, 0, 0], + ....: [-3, 0, 0, 0, -1], [3, 3, 6, 6, -1], [-3, 0, 0, 0, 1], + ....: [0, -3, -6, -6, 0], [0, -3, -3, -6, 0], [0, -3, -3, 0, 0], + ....: [0, -3, 0, 0, -1], [3, 3, 3, 6, 0], [0, -3, 0, 0, 1], + ....: [0, 0, -6, -6, 0], [0, 0, -3, -6, -1], [3, 3, 3, 0, 0], + ....: [0, 0, -3, -6, 1], [0, 0, -3, 0, -1], [3, 3, 0, 0, 0], + ....: [0, 0, -3, 0, 1], [0, 0, 3, 0, -1], [3, 0, 6, 6, 0], + ....: [0, 0, 3, 0, 1], [0, 0, 3, 6, -1], [3, 0, 3, 6, 0], + ....: [0, 0, 3, 6, 1], [0, 0, 6, 6, 0], [0, 3, 0, 0, -1], + ....: [3, 0, 3, 0, 0], [0, 3, 0, 0, 1], [0, 3, 3, 0, 0], + ....: [0, 3, 3, 6, 0], [0, 3, 6, 6, 0], [3, 0,0, 0, -1], [3, 0, 0, 0, 1]]) + sage: P.normal_form(algorithm="palp") + Traceback (most recent call last): + ... + Output: + b'*** stack smashing detected ***: terminated\nAborted\n' + sage: P.normal_form(algorithm="palp_native") + M( 6, 0, 0, 0, 0), + M( -6, 0, 0, 0, 0), + M( 0, 1, 0, 0, 0), + M( 0, 0, 3, 0, 0), + M( 0, 1, 0, 3, 0), + M( 0, 0, 0, 0, 3), + M( -6, 1, 6, 3, -6), + M( -6, 0, 6, 0, -3), + M(-12, 1, 6, 3, -3), + M( -6, 1, 0, 3, 0), + M( -6, 0, 3, 3, 0), + M( 6, 0, -6, -3, 6), + M(-12, 1, 6, 3, -6), + M(-12, 0, 9, 3, -6), + M( 0, 0, 0, -3, 0), + M(-12, 1, 6, 6, -6), + M(-12, 0, 6, 3, -3), + M( 0, 1, -3, 0, 0), + M( 0, 0, -3, -3, 3), + M( 0, 1, 0, 3, -3), + M( 0, -1, 0, -3, 3), + M( 0, 0, 3, 3, -3), + M( 0, -1, 3, 0, 0), + M( 12, 0, -6, -3, 3), + M( 12, -1, -6, -6, 6), + M( 0, 0, 0, 3, 0), + M( 12, 0, -9, -3, 6), + M( 12, -1, -6, -3, 6), + M( -6, 0, 6, 3, -6), + M( 6, 0, -3, -3, 0), + M( 6, -1, 0, -3, 0), + M(-12, 1, 9, 6, -6), + M( 6, 0, -6, 0, 3), + M( 6, -1, -6, -3, 6), + M( 0, 0, 0, 0, -3), + M( 0, -1, 0, -3, 0), + M( 0, 0, -3, 0, 0), + M( 0, -1, 0, 0, 0), + M( 12, -1, -9, -6, 6), + M( 12, -1, -6, -3, 3) + in 5-d lattice M """ if self.dim() < self.lattice_dim(): raise ValueError("normal form is not defined for %s" % self) From 4e06ea90547c481546092b680ed83d250498df3d Mon Sep 17 00:00:00 2001 From: Luze Xu Date: Tue, 5 Sep 2023 17:18:59 -0700 Subject: [PATCH 035/538] speed tests for palp_native --- src/sage/geometry/lattice_polytope.py | 96 ++++++++++++++++++++++++- src/sage/geometry/polyhedron/base_ZZ.py | 10 +++ 2 files changed, 103 insertions(+), 3 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 4e30dbd242f..4f7e21c4df2 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -2950,10 +2950,11 @@ def normal_form(self, algorithm="palp", permutation=False): - ``algorithm`` -- (default: "palp") The algorithm which is used to compute the normal form. Options are: - * "palp" -- Run external PALP code, usually the fastest option. + * "palp" -- Run external PALP code, usually the fastest option, + but may fail in higher dimensions. * "palp_native" -- The original PALP algorithm implemented - in sage. Currently considerably slower than PALP. + in sage. Currently competitive with PALP in many cases. * "palp_modified" -- A modified version of the PALP algorithm which determines the maximal vertex-facet @@ -3033,7 +3034,49 @@ def normal_form(self, algorithm="palp", permutation=False): M(-1, 0) in 2-d lattice M - Note that the default algorithm may crash for higher dimensions:: + The following examples demonstrate the speed improvement of ``"palp_native"``. + In low dimensions, ``"palp_native"`` is the fastest. + As the dimension increases, ``"palp"`` is relatively faster than ``"palp_native"``. + ``"palp_native"`` is usually much faster than ``"palp_modified"``. + But in some cases when the polytope has high symmetry, however, ``"palp_native"`` is slower:: + + sage: o = lattice_polytope.cross_polytope(2) + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") # not tested + 625 loops, best of 3: 3.07 ms per loop + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") # not tested + 625 loops, best of 3: 0.445 ms per loop + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") # not tested + 625 loops, best of 3: 5.01 ms per loop + + sage: o = lattice_polytope.cross_polytope(3) + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") # not tested + 625 loops, best of 3: 3.22 ms per loop + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") # not tested + 625 loops, best of 3: 2.73 ms per loop + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") # not tested + 625 loops, best of 3: 20.7 ms per loop + + sage: o = lattice_polytope.cross_polytope(4) + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") # not tested + 625 loops, best of 3: 4.84 ms per loop + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") # not tested + 625 loops, best of 3: 55.6 ms per loop + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") # not tested + 625 loops, best of 3: 129 ms per loop + + sage: o = lattice_polytope.cross_polytope(5) + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") # not tested + 10 loops, best of 3: 0.0364 s per loop + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") # not tested + 10 loops, best of 3: 1.68 s per loop + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") # not tested + 10 loops, best of 3: 0.858 s per loop + + Note that the default algorithm ``"palp"`` may crash for higher dimensions because of + the overflow errors as mentioned in :issue:`13525#comment:9`. + Then use ``"palp_native"`` instead, which is usually faster than ``"palp_modified"``. + Below is an example where ``"palp"`` fails, and + ``"palp_native"`` is much faster than ``"palp_modified"``:: sage: P = LatticePolytope([[-3, -3, -6, -6, -1], [3, 3, 6, 6, 1], [-3, -3, -6, -6, 1], ....: [-3, -3, -3, -6, 0], [-3, -3, -3, 0, 0], [-3, -3, 0, 0, 0], @@ -3051,6 +3094,7 @@ def normal_form(self, algorithm="palp", permutation=False): sage: P.normal_form(algorithm="palp") Traceback (most recent call last): ... + RuntimeError: Error executing ... for a polytope sequence! Output: b'*** stack smashing detected ***: terminated\nAborted\n' sage: P.normal_form(algorithm="palp_native") @@ -3095,6 +3139,52 @@ def normal_form(self, algorithm="palp", permutation=False): M( 12, -1, -9, -6, 6), M( 12, -1, -6, -3, 3) in 5-d lattice M + sage: P.normal_form(algorithm="palp_modified") + M( 6, 0, 0, 0, 0), + M( -6, 0, 0, 0, 0), + M( 0, 1, 0, 0, 0), + M( 0, 0, 3, 0, 0), + M( 0, 1, 0, 3, 0), + M( 0, 0, 0, 0, 3), + M( -6, 1, 6, 3, -6), + M( -6, 0, 6, 0, -3), + M(-12, 1, 6, 3, -3), + M( -6, 1, 0, 3, 0), + M( -6, 0, 3, 3, 0), + M( 6, 0, -6, -3, 6), + M(-12, 1, 6, 3, -6), + M(-12, 0, 9, 3, -6), + M( 0, 0, 0, -3, 0), + M(-12, 1, 6, 6, -6), + M(-12, 0, 6, 3, -3), + M( 0, 1, -3, 0, 0), + M( 0, 0, -3, -3, 3), + M( 0, 1, 0, 3, -3), + M( 0, -1, 0, -3, 3), + M( 0, 0, 3, 3, -3), + M( 0, -1, 3, 0, 0), + M( 12, 0, -6, -3, 3), + M( 12, -1, -6, -6, 6), + M( 0, 0, 0, 3, 0), + M( 12, 0, -9, -3, 6), + M( 12, -1, -6, -3, 6), + M( -6, 0, 6, 3, -6), + M( 6, 0, -3, -3, 0), + M( 6, -1, 0, -3, 0), + M(-12, 1, 9, 6, -6), + M( 6, 0, -6, 0, 3), + M( 6, -1, -6, -3, 6), + M( 0, 0, 0, 0, -3), + M( 0, -1, 0, -3, 0), + M( 0, 0, -3, 0, 0), + M( 0, -1, 0, 0, 0), + M( 12, -1, -9, -6, 6), + M( 12, -1, -6, -3, 3) + in 5-d lattice M + sage: %timeit P.normal_form.clear_cache(); P.normal_form("palp_native") # not tested + 10 loops, best of 3: 0.137 s per loop + sage: %timeit P.normal_form.clear_cache(); P.normal_form("palp_modified") # not tested + 10 loops, best of 3: 22.2 s per loop """ if self.dim() < self.lattice_dim(): raise ValueError("normal form is not defined for %s" % self) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index f40b88b284b..9ce438105f5 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -837,6 +837,10 @@ def is_known_summand(poly): def normal_form(self, algorithm="palp_native", permutation=False): r""" + Return the normal form of vertices of ``self`` if ``self`` is a lattice polytope, + i.e. all vertices have integer coordinates. For more more detail, + see also :meth:`~sage.geometry.lattice_polytope.LatticePolytopeClass.normal_form`. + EXAMPLES: We compute the normal form of the "diamond":: @@ -849,6 +853,12 @@ def normal_form(self, algorithm="palp_native", permutation=False): A vertex at (1, 0)) sage: d.normal_form() [(1, 0), (0, 1), (0, -1), (-1, 0)] + sage: d.lattice_polytope().normal_form("palp_native") + M( 1, 0), + M( 0, 1), + M( 0, -1), + M(-1, 0) + in 2-d lattice M It is not possible to compute normal forms for polytopes which do not span the space:: From 137c8482020819346985d15a8227d10ae53c27fd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Sep 2023 11:06:32 -0700 Subject: [PATCH 036/538] Polyhedron_ZZ.normal_form: Reject unbounded polyhedra --- src/sage/geometry/polyhedron/base_ZZ.py | 26 ++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 9ce438105f5..0a41dc9371a 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -837,9 +837,10 @@ def is_known_summand(poly): def normal_form(self, algorithm="palp_native", permutation=False): r""" - Return the normal form of vertices of ``self`` if ``self`` is a lattice polytope, - i.e. all vertices have integer coordinates. For more more detail, - see also :meth:`~sage.geometry.lattice_polytope.LatticePolytopeClass.normal_form`. + Return the normal form of vertices of the lattice polytope ``self``. + + For more more detail, + see :meth:`~sage.geometry.lattice_polytope.LatticePolytopeClass.normal_form`. EXAMPLES: @@ -867,12 +868,27 @@ def normal_form(self, algorithm="palp_native", permutation=False): sage: p.normal_form() Traceback (most recent call last): ... - ValueError: normal form is not defined for A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices + ValueError: normal form is not defined for lower-dimensional polyhedra, got + A 2-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices + + The normal form is also not defined for unbounded polyhedra:: + + sage: p = Polyhedron(vertices=[[1, 1]], rays=[[1, 0], [0, 1]], base_ring=ZZ) + sage: p.normal_form() + Traceback (most recent call last): + ... + ValueError: normal form is not defined for unbounded polyhedra, got + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 2 rays + + See :issue:`15280` for proposed extensions to these cases. """ from sage.geometry.palp_normal_form import _palp_PM_max, _palp_canonical_order if self.dim() < self.ambient_dim(): - raise ValueError("normal form is not defined for %s" % self) + raise ValueError("normal form is not defined for lower-dimensional polyhedra, got %s" % self) + + if not self.is_compact(): + raise ValueError("normal form is not defined for unbounded polyhedra, got %s" % self) PM = self.slack_matrix().transpose() PM_max, permutations = _palp_PM_max(PM, check=True) From 26c89cfb17a3d2e1bef63a3c99e8ef74d3f28ee8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Sep 2023 11:28:57 -0700 Subject: [PATCH 037/538] Docstring/doctest cosmetics --- src/sage/geometry/lattice_polytope.py | 52 +++++++++++++------------- src/sage/geometry/palp_normal_form.pyx | 12 +++--- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 4f7e21c4df2..a6c53e03f2d 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -2519,7 +2519,7 @@ def index(self): M(-1, 0) in 2-d lattice M - But they are in the same `GL(Z^n)` orbit and have the same + But they are in the same `GL(\ZZ^n)` orbit and have the same normal form:: sage: d.normal_form() # needs palp @@ -2937,26 +2937,26 @@ def normal_form(self, algorithm="palp", permutation=False): Return the normal form of vertices of ``self``. Two full-dimensional lattice polytopes are in the same - ``GL(\ZZ)``-orbit if and only if their normal forms are the + `GL(\ZZ^n)`-orbit if and only if their normal forms are the same. Normal form is not defined and thus cannot be used for polytopes whose dimension is smaller than the dimension of the ambient space. The original algorithm was presented in [KS1998]_ and implemented in PALP. A modified version of the PALP algorithm is discussed in - [GK2013]_ and available here as "palp_modified". + [GK2013]_ and available here as ``"palp_modified"``. INPUT: - - ``algorithm`` -- (default: "palp") The algorithm which is used + - ``algorithm`` -- (default: ``"palp"``) The algorithm which is used to compute the normal form. Options are: - * "palp" -- Run external PALP code, usually the fastest option, + * ``"palp"`` -- Run external PALP code, usually the fastest option, but may fail in higher dimensions. - * "palp_native" -- The original PALP algorithm implemented + * ``"palp_native"`` -- The original PALP algorithm implemented in sage. Currently competitive with PALP in many cases. - * "palp_modified" -- A modified version of the PALP + * ``"palp_modified"`` -- A modified version of the PALP algorithm which determines the maximal vertex-facet pairing matrix first and then computes its automorphisms, while the PALP algorithm does both things @@ -3040,42 +3040,40 @@ def normal_form(self, algorithm="palp", permutation=False): ``"palp_native"`` is usually much faster than ``"palp_modified"``. But in some cases when the polytope has high symmetry, however, ``"palp_native"`` is slower:: + sage: # not tested sage: o = lattice_polytope.cross_polytope(2) - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") 625 loops, best of 3: 3.07 ms per loop - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") 625 loops, best of 3: 0.445 ms per loop - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") 625 loops, best of 3: 5.01 ms per loop - sage: o = lattice_polytope.cross_polytope(3) - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") 625 loops, best of 3: 3.22 ms per loop - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") 625 loops, best of 3: 2.73 ms per loop - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") 625 loops, best of 3: 20.7 ms per loop - sage: o = lattice_polytope.cross_polytope(4) - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") 625 loops, best of 3: 4.84 ms per loop - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") 625 loops, best of 3: 55.6 ms per loop - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") 625 loops, best of 3: 129 ms per loop - sage: o = lattice_polytope.cross_polytope(5) - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp") 10 loops, best of 3: 0.0364 s per loop - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_native") 10 loops, best of 3: 1.68 s per loop - sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") # not tested + sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") 10 loops, best of 3: 0.858 s per loop Note that the default algorithm ``"palp"`` may crash for higher dimensions because of the overflow errors as mentioned in :issue:`13525#comment:9`. Then use ``"palp_native"`` instead, which is usually faster than ``"palp_modified"``. - Below is an example where ``"palp"`` fails, and + Below is an example where ``"palp"`` fails and ``"palp_native"`` is much faster than ``"palp_modified"``:: sage: P = LatticePolytope([[-3, -3, -6, -6, -1], [3, 3, 6, 6, 1], [-3, -3, -6, -6, 1], @@ -3091,7 +3089,7 @@ def normal_form(self, algorithm="palp", permutation=False): ....: [0, 0, 3, 6, 1], [0, 0, 6, 6, 0], [0, 3, 0, 0, -1], ....: [3, 0, 3, 0, 0], [0, 3, 0, 0, 1], [0, 3, 3, 0, 0], ....: [0, 3, 3, 6, 0], [0, 3, 6, 6, 0], [3, 0,0, 0, -1], [3, 0, 0, 0, 1]]) - sage: P.normal_form(algorithm="palp") + sage: P.normal_form(algorithm="palp") # not tested Traceback (most recent call last): ... RuntimeError: Error executing ... for a polytope sequence! @@ -3139,7 +3137,7 @@ def normal_form(self, algorithm="palp", permutation=False): M( 12, -1, -9, -6, 6), M( 12, -1, -6, -3, 3) in 5-d lattice M - sage: P.normal_form(algorithm="palp_modified") + sage: P.normal_form(algorithm="palp_modified") # long time (22s) M( 6, 0, 0, 0, 0), M( -6, 0, 0, 0, 0), M( 0, 1, 0, 0, 0), @@ -3181,9 +3179,9 @@ def normal_form(self, algorithm="palp", permutation=False): M( 12, -1, -9, -6, 6), M( 12, -1, -6, -3, 3) in 5-d lattice M - sage: %timeit P.normal_form.clear_cache(); P.normal_form("palp_native") # not tested + sage: %timeit P.normal_form.clear_cache(); P.normal_form("palp_native") # not tested 10 loops, best of 3: 0.137 s per loop - sage: %timeit P.normal_form.clear_cache(); P.normal_form("palp_modified") # not tested + sage: %timeit P.normal_form.clear_cache(); P.normal_form("palp_modified") # not tested 10 loops, best of 3: 22.2 s per loop """ if self.dim() < self.lattice_dim(): diff --git a/src/sage/geometry/palp_normal_form.pyx b/src/sage/geometry/palp_normal_form.pyx index fad9f968c06..fa756fe65b0 100644 --- a/src/sage/geometry/palp_normal_form.pyx +++ b/src/sage/geometry/palp_normal_form.pyx @@ -43,8 +43,8 @@ def _palp_PM_max(Matrix_integer_dense PM, check=False): INPUT: - ``check`` -- Boolean (default: ``False``), whether to return - the permutations leaving the maximal vertex-facet pairing - matrix invariant. + the permutations leaving the maximal vertex-facet pairing + matrix invariant. OUTPUT: @@ -80,10 +80,10 @@ def _palp_PM_max(Matrix_integer_dense PM, check=False): ((2,3), (2,3)), ((1,2), (1,2)), ((1,3), (1,3))] - sage: PMs = ( i._palp_PM_max(check=True) - ....: for i in ReflexivePolytopes(2) ) - sage: results = ( len(i) == len(j.automorphisms_of_rows_and_columns()) - ....: for j, i in PMs ) + sage: PMs = (i._palp_PM_max(check=True) + ....: for i in ReflexivePolytopes(2)) + sage: results = (len(i) == len(j.automorphisms_of_rows_and_columns()) + ....: for j, i in PMs) sage: all(results) # long time True From 7759c528fd989fcd1004ba5f9acf613e8fde77d0 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Sep 2023 11:40:45 -0700 Subject: [PATCH 038/538] Polyhedron_ZZ.normal_form: Add doc --- src/sage/geometry/polyhedron/base_ZZ.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 0a41dc9371a..06b93aea513 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -839,6 +839,13 @@ def normal_form(self, algorithm="palp_native", permutation=False): r""" Return the normal form of vertices of the lattice polytope ``self``. + INPUT: + + - ``algorithm`` -- must be ``"palp_native"``, the default. + + - ``permutation`` -- boolean (default: ``False``); if ``True``, the permutation + applied to vertices to obtain the normal form is returned as well. + For more more detail, see :meth:`~sage.geometry.lattice_polytope.LatticePolytopeClass.normal_form`. @@ -884,6 +891,9 @@ def normal_form(self, algorithm="palp_native", permutation=False): """ from sage.geometry.palp_normal_form import _palp_PM_max, _palp_canonical_order + if algorithm != "palp_native": + raise ValueError("algorithm must be 'palp_native'") + if self.dim() < self.ambient_dim(): raise ValueError("normal form is not defined for lower-dimensional polyhedra, got %s" % self) From ea4d8571ca257417e612429c61540175b7fe15f3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Sep 2023 11:41:37 -0700 Subject: [PATCH 039/538] LatticePolytope.normal_form: Change the default to algorithm='palp_native' --- src/sage/geometry/lattice_polytope.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index a6c53e03f2d..f7306d5b3ff 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -2932,7 +2932,7 @@ def nfacets(self): return len(self.facet_normals()) if self.dim() > 0 else 0 @cached_method - def normal_form(self, algorithm="palp", permutation=False): + def normal_form(self, algorithm="palp_native", permutation=False): r""" Return the normal form of vertices of ``self``. @@ -2947,11 +2947,12 @@ def normal_form(self, algorithm="palp", permutation=False): INPUT: - - ``algorithm`` -- (default: ``"palp"``) The algorithm which is used + - ``algorithm`` -- (default: ``"palp_native"``) The algorithm which is used to compute the normal form. Options are: - * ``"palp"`` -- Run external PALP code, usually the fastest option, - but may fail in higher dimensions. + * ``"palp"`` -- Run external PALP code, usually the fastest option + when it works; but reproducible crashes have been observed in dimension + 5 and higher. * ``"palp_native"`` -- The original PALP algorithm implemented in sage. Currently competitive with PALP in many cases. @@ -2962,7 +2963,7 @@ def normal_form(self, algorithm="palp", permutation=False): automorphisms, while the PALP algorithm does both things concurrently. - - ``permutation`` -- (default: ``False``) If ``True`` the permutation + - ``permutation`` -- boolean (default: ``False``); if ``True``, the permutation applied to vertices to obtain the normal form is returned as well. Note that the different algorithms may return different results that nevertheless lead to the same normal form. @@ -2983,7 +2984,7 @@ def normal_form(self, algorithm="palp", permutation=False): M(-1, 0), M( 0, -1) in 2-d lattice M - sage: d.normal_form() # needs palp + sage: d.normal_form() M( 1, 0), M( 0, 1), M( 0, -1), @@ -3034,11 +3035,11 @@ def normal_form(self, algorithm="palp", permutation=False): M(-1, 0) in 2-d lattice M - The following examples demonstrate the speed improvement of ``"palp_native"``. - In low dimensions, ``"palp_native"`` is the fastest. + The following examples demonstrate the speed of the available algorithms. + In low dimensions, the default algorithm, ``"palp_native"``, is the fastest. As the dimension increases, ``"palp"`` is relatively faster than ``"palp_native"``. ``"palp_native"`` is usually much faster than ``"palp_modified"``. - But in some cases when the polytope has high symmetry, however, ``"palp_native"`` is slower:: + In some cases when the polytope has high symmetry, however, ``"palp_native"`` is slower:: sage: # not tested sage: o = lattice_polytope.cross_polytope(2) @@ -3070,7 +3071,7 @@ def normal_form(self, algorithm="palp", permutation=False): sage: %timeit o.normal_form.clear_cache(); o.normal_form("palp_modified") 10 loops, best of 3: 0.858 s per loop - Note that the default algorithm ``"palp"`` may crash for higher dimensions because of + Note that the algorithm ``"palp"`` may crash for higher dimensions because of the overflow errors as mentioned in :issue:`13525#comment:9`. Then use ``"palp_native"`` instead, which is usually faster than ``"palp_modified"``. Below is an example where ``"palp"`` fails and @@ -3195,8 +3196,7 @@ def normal_form(self, algorithm="palp", permutation=False): elif algorithm == "palp_modified": result = self._palp_modified_normal_form(permutation=permutation) else: - raise ValueError('Algorithm must be palp, ' + - 'palp_native, or palp_modified.') + raise ValueError("algorithm must be 'palp', 'palp_native', or 'palp_modified'") if permutation: vertices, perm = result else: @@ -3219,7 +3219,7 @@ def _palp_modified_normal_form(self, permutation=False): INPUT: - - ``permutation`` -- a Boolean, whether to return the permutation of + - ``permutation`` -- boolean (default: ``False``); whether to return the permutation of the order of the vertices that was applied to obtain this matrix. OUTPUT: From 05f82288e41141de58454f3f68474fa8ab8f99eb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Sep 2023 11:45:14 -0700 Subject: [PATCH 040/538] Add # needs sage.groups --- src/sage/geometry/lattice_polytope.py | 6 +++--- src/sage/geometry/polyhedron/base_ZZ.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index f7306d5b3ff..c7dffd27341 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -2984,7 +2984,7 @@ def normal_form(self, algorithm="palp_native", permutation=False): M(-1, 0), M( 0, -1) in 2-d lattice M - sage: d.normal_form() + sage: d.normal_form() # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), @@ -3096,7 +3096,7 @@ def normal_form(self, algorithm="palp_native", permutation=False): RuntimeError: Error executing ... for a polytope sequence! Output: b'*** stack smashing detected ***: terminated\nAborted\n' - sage: P.normal_form(algorithm="palp_native") + sage: P.normal_form(algorithm="palp_native") # needs sage.groups M( 6, 0, 0, 0, 0), M( -6, 0, 0, 0, 0), M( 0, 1, 0, 0, 0), @@ -3138,7 +3138,7 @@ def normal_form(self, algorithm="palp_native", permutation=False): M( 12, -1, -9, -6, 6), M( 12, -1, -6, -3, 3) in 5-d lattice M - sage: P.normal_form(algorithm="palp_modified") # long time (22s) + sage: P.normal_form(algorithm="palp_modified") # long time (22s) # needs sage.groups M( 6, 0, 0, 0, 0), M( -6, 0, 0, 0, 0), M( 0, 1, 0, 0, 0), diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 06b93aea513..cd5dbaa1958 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -859,9 +859,9 @@ def normal_form(self, algorithm="palp_native", permutation=False): A vertex at (0, -1), A vertex at (0, 1), A vertex at (1, 0)) - sage: d.normal_form() + sage: d.normal_form() # needs sage.groups [(1, 0), (0, 1), (0, -1), (-1, 0)] - sage: d.lattice_polytope().normal_form("palp_native") + sage: d.lattice_polytope().normal_form("palp_native") # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), From 14a0fe4710f34070bea4b7f6b38babc2c72b21e4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Sep 2023 11:54:55 -0700 Subject: [PATCH 041/538] src/sage/geometry/polyhedron/base_ZZ.py: Update copyright --- src/sage/geometry/polyhedron/base_ZZ.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index cd5dbaa1958..2f280a4d74d 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -3,7 +3,14 @@ """ # **************************************************************************** -# Copyright (C) 2011 Volker Braun +# Copyright (C) 2011-2013 Volker Braun +# 2015 Nathann Cohen +# 2015 Vincent Delecroix +# 2017-2018 Frédéric Chapoton +# 2019 Sophia Elia +# 2019-2020 Jonathan Kliem +# 2023 Luze Xu +# 2023 Matthias Koeppe # # 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 From 13dbc7e56c0f538ed936fd4fe7c83be9413cacb7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 7 Sep 2023 11:58:28 -0700 Subject: [PATCH 042/538] src/sage/geometry/lattice_polytope.py: Update # needs --- src/sage/geometry/lattice_polytope.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index c7dffd27341..5874d2d7e9a 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -2522,13 +2522,13 @@ def index(self): But they are in the same `GL(\ZZ^n)` orbit and have the same normal form:: - sage: d.normal_form() # needs palp + sage: d.normal_form() # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), M(-1, 0) in 2-d lattice M - sage: lattice_polytope.ReflexivePolytope(2,3).normal_form() + sage: lattice_polytope.ReflexivePolytope(2,3).normal_form() # needs sage.groups M( 1, 0), M( 0, 1), M( 0, -1), From fdcfe1c7eb12fa1c2a79eaabed65ee83cdceb491 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 25 Sep 2023 09:17:46 +0200 Subject: [PATCH 043/538] merge --- src/sage/matrix/matrix2.pyx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 060f6620f87..3e5115ec5dd 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -8078,11 +8078,7 @@ cdef class Matrix(Matrix1): if self.fetch('in_echelon_form'): return self.fetch('pivots') -<<<<<<< HEAD - tm = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) -======= _ = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) ->>>>>>> develop self.check_mutability() cdef Matrix A From 04f314a01427dbbfa87c76a77884dc79046cb1e0 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 25 Sep 2023 09:20:37 +0200 Subject: [PATCH 044/538] merge --- src/sage/matrix/matrix2.pyx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 060f6620f87..3e5115ec5dd 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -8078,11 +8078,7 @@ cdef class Matrix(Matrix1): if self.fetch('in_echelon_form'): return self.fetch('pivots') -<<<<<<< HEAD - tm = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) -======= _ = verbose('generic in-place Gauss elimination on %s x %s matrix using %s algorithm' % (self._nrows, self._ncols, algorithm)) ->>>>>>> develop self.check_mutability() cdef Matrix A From dc8ff266955d97890a3b97c9d290b6a84d3ba037 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 5 Sep 2023 11:16:47 +0200 Subject: [PATCH 045/538] establish interface for instantiated classical modular polynomials --- .../en/reference/arithmetic_curves/index.rst | 1 + src/sage/schemes/elliptic_curves/all.py | 2 + src/sage/schemes/elliptic_curves/mod_poly.py | 140 ++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 src/sage/schemes/elliptic_curves/mod_poly.py diff --git a/src/doc/en/reference/arithmetic_curves/index.rst b/src/doc/en/reference/arithmetic_curves/index.rst index 6ab10dcf1c0..93c72854e05 100644 --- a/src/doc/en/reference/arithmetic_curves/index.rst +++ b/src/doc/en/reference/arithmetic_curves/index.rst @@ -25,6 +25,7 @@ Maps between them sage/schemes/elliptic_curves/hom_scalar sage/schemes/elliptic_curves/hom_frobenius sage/schemes/elliptic_curves/isogeny_small_degree + sage/schemes/elliptic_curves/mod_poly Elliptic curves over number fields diff --git a/src/sage/schemes/elliptic_curves/all.py b/src/sage/schemes/elliptic_curves/all.py index fd2fb992360..c58602ffc6a 100644 --- a/src/sage/schemes/elliptic_curves/all.py +++ b/src/sage/schemes/elliptic_curves/all.py @@ -40,4 +40,6 @@ from .ell_curve_isogeny import EllipticCurveIsogeny, isogeny_codomain_from_kernel +from .mod_poly import classical_modular_polynomial + from .heegner import heegner_points, heegner_point diff --git a/src/sage/schemes/elliptic_curves/mod_poly.py b/src/sage/schemes/elliptic_curves/mod_poly.py new file mode 100644 index 00000000000..d20b69c58e5 --- /dev/null +++ b/src/sage/schemes/elliptic_curves/mod_poly.py @@ -0,0 +1,140 @@ +r""" +Modular polynomials for elliptic curves + +For a positive integer `\ell`, the classical modular polynomial +`\Phi_\ell\in\ZZ[X,Y]` is characterized by the property that its +zero set is exactly the set of pairs of `j`-invariants connected +by a cyclic `\ell`-isogeny. + +AUTHORS: + +- Lorenz Panny (2023) +""" + +from sage.misc.cachefunc import cached_function +from sage.structure.parent import Parent +from sage.structure.element import parent, FieldElement + +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring import polygen, polygens + +from sage.libs.pari import pari +from cypari2.handle_error import PariError + +from sage.databases.db_modular_polynomials import ClassicalModularPolynomialDatabase +_db = ClassicalModularPolynomialDatabase() + +_cache = dict() + +def classical_modular_polynomial(l, j=None): + r""" + Return the classical modular polynomial `\Phi_\ell`, either as a + "generic" bivariate polynomial over `\ZZ`, or as an "instantiated" + modular polynomial where one variable has been replaced by the + given `j`-invariant. + + Generic polynomials are cached up to a certain size of `\ell`, + which significantly accelerates subsequent invocations with the + same `\ell`. The default bound is `\ell \leq 150`, which can be + adjusted by setting ``classical_modular_polynomial.cache_bound`` + to a different value. Beware that modular polynomials are very + large and the amount of memory consumed by the cache will grow + rapidly when the bound is set to a large value. + + INPUT: + + - ``l`` -- positive integer. + + - ``j`` -- either ``None`` or a ring element. + + - If ``None`` is given, the original modular polynomial + is returned as an element of `\ZZ[X,Y]`. + + - If a ring element `j \in R` is given, the evaluation + `\Phi_\ell(j,Y)` is returned as an element of the + univariate polynomial ring `R[Y]`. + + ALGORITHMS: + + - The Kohel database + :class:`~sage.databases.db_modular_polynomials.ClassicalModularPolynomialDatabase` + + - :pari:`polmodular` + + EXAMPLES:: + + sage: classical_modular_polynomial(2) + -X^2*Y^2 + X^3 + 1488*X^2*Y + 1488*X*Y^2 + Y^3 - 162000*X^2 + 40773375*X*Y - 162000*Y^2 + 8748000000*X + 8748000000*Y - 157464000000000 + sage: j = Mod(1728, 419) + sage: classical_modular_polynomial(3, j) + Y^4 + 230*Y^3 + 84*Y^2 + 118*Y + 329 + + TESTS:: + + sage: q = random_prime(50)^randrange(1,4) + sage: j = GF(q).random_element() + sage: l = random_prime(50) + sage: Y = polygen(parent(j), 'Y') + sage: classical_modular_polynomial(l,j) == classical_modular_polynomial(l)(j,Y) + True + """ + l = ZZ(l) + + if j is None: + # We are supposed to return the generic modular polynomial. First + # check if it is already in the cache, then check the database, + # finally compute it using PARI. + try: + return _cache[l] + except KeyError: + pass + + try: + Phi = ZZ['X,Y'](_db[l]) + except ValueError: + try: + pari_Phi = pari.polmodular(l) + except PariError: + raise NotImplementedError('modular polynomial is not in database and computing it on the fly is not yet implemented') + d = {(i,j): c for i,f in enumerate(pari_Phi) for j,c in enumerate(f)} + Phi = ZZ['X,Y'](d) + + if l <= classical_modular_polynomial.cache_bound: + _cache[l] = Phi + + return Phi + + R,Y = parent(j)['Y'].objgen() + + # If the generic polynomial is in the cache or the database, evaluating + # it directly should always be faster than recomputing it from scratch. + try: + Phi = _cache[l] + except KeyError: + pass + else: + return Phi(j, Y) + try: + Phi = _db[l] + except ValueError: + pass + else: + if l <= classical_modular_polynomial.cache_bound: + _cache[l] = ZZ['X,Y'](Phi) + return Phi(j, Y) + + # Now try to get the instantiated modular polynomial directly from PARI. + # This should be slightly more efficient (in particular regarding memory + # usage) than computing and evaluating the generic modular polynomial. + try: + pari_Phi = pari.polmodular(l, 0, j) + except PariError: + pass + else: + return R(pari_Phi) + + # Nothing worked. Fall back to computing the generic modular polynomial + # and simply evaluating it. + return classical_modular_polynomial(l)(j, Y) + +classical_modular_polynomial.cache_bound = 150 From 2ddd0d26beb2e3ee24d5336d5cf180c45e04cb74 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Tue, 26 Sep 2023 10:49:55 +0200 Subject: [PATCH 046/538] reviewer comments --- src/sage/schemes/elliptic_curves/all.py | 2 +- src/sage/schemes/elliptic_curves/mod_poly.py | 34 +++++++------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/all.py b/src/sage/schemes/elliptic_curves/all.py index c58602ffc6a..e339c40d843 100644 --- a/src/sage/schemes/elliptic_curves/all.py +++ b/src/sage/schemes/elliptic_curves/all.py @@ -40,6 +40,6 @@ from .ell_curve_isogeny import EllipticCurveIsogeny, isogeny_codomain_from_kernel -from .mod_poly import classical_modular_polynomial +lazy_import('sage.schemes.elliptic_curves.mod_poly', 'classical_modular_polynomial') from .heegner import heegner_points, heegner_point diff --git a/src/sage/schemes/elliptic_curves/mod_poly.py b/src/sage/schemes/elliptic_curves/mod_poly.py index d20b69c58e5..c034bed50aa 100644 --- a/src/sage/schemes/elliptic_curves/mod_poly.py +++ b/src/sage/schemes/elliptic_curves/mod_poly.py @@ -2,7 +2,7 @@ Modular polynomials for elliptic curves For a positive integer `\ell`, the classical modular polynomial -`\Phi_\ell\in\ZZ[X,Y]` is characterized by the property that its +`\Phi_\ell \in \ZZ[X,Y]` is characterized by the property that its zero set is exactly the set of pairs of `j`-invariants connected by a cyclic `\ell`-isogeny. @@ -11,12 +11,9 @@ - Lorenz Panny (2023) """ -from sage.misc.cachefunc import cached_function -from sage.structure.parent import Parent -from sage.structure.element import parent, FieldElement +from sage.structure.element import parent from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.polynomial_ring import polygen, polygens from sage.libs.pari import pari from cypari2.handle_error import PariError @@ -44,21 +41,17 @@ def classical_modular_polynomial(l, j=None): INPUT: - ``l`` -- positive integer. - - - ``j`` -- either ``None`` or a ring element. - - - If ``None`` is given, the original modular polynomial - is returned as an element of `\ZZ[X,Y]`. - - - If a ring element `j \in R` is given, the evaluation + - ``j`` -- either ``None`` or a ring element: + * if ``None`` is given, the original modular polynomial + is returned as an element of `\ZZ[X,Y]` + * if a ring element `j \in R` is given, the evaluation `\Phi_\ell(j,Y)` is returned as an element of the - univariate polynomial ring `R[Y]`. + univariate polynomial ring `R[Y]` ALGORITHMS: - The Kohel database :class:`~sage.databases.db_modular_polynomials.ClassicalModularPolynomialDatabase` - - :pari:`polmodular` EXAMPLES:: @@ -96,7 +89,7 @@ def classical_modular_polynomial(l, j=None): pari_Phi = pari.polmodular(l) except PariError: raise NotImplementedError('modular polynomial is not in database and computing it on the fly is not yet implemented') - d = {(i,j): c for i,f in enumerate(pari_Phi) for j,c in enumerate(f)} + d = {(i, j): c for i,f in enumerate(pari_Phi) for j, c in enumerate(f)} Phi = ZZ['X,Y'](d) if l <= classical_modular_polynomial.cache_bound: @@ -104,16 +97,13 @@ def classical_modular_polynomial(l, j=None): return Phi - R,Y = parent(j)['Y'].objgen() + R = parent(j)['Y'] + Y = R.gen() # If the generic polynomial is in the cache or the database, evaluating # it directly should always be faster than recomputing it from scratch. - try: - Phi = _cache[l] - except KeyError: - pass - else: - return Phi(j, Y) + if l in _cache: + return _cache[l](j, Y) try: Phi = _db[l] except ValueError: From 905d0420cc6d20fbb81a1876642268fc362ac996 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 15:26:34 +0200 Subject: [PATCH 047/538] class of matrices of Laurent mpolynomials --- .../matrix_laurent_mpolynomial_dense.pyx} | 0 src/sage/matrix/matrix_mpolynomial_dense.pyx | 52 ++++++++++++++++++- src/sage/matrix/matrix_space.py | 27 ++++++---- 3 files changed, 68 insertions(+), 11 deletions(-) rename src/sage/{rings/polynomial/laurent_reduction.py => matrix/matrix_laurent_mpolynomial_dense.pyx} (100%) diff --git a/src/sage/rings/polynomial/laurent_reduction.py b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx similarity index 100% rename from src/sage/rings/polynomial/laurent_reduction.py rename to src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index e20c662cc0e..57f80149e88 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -20,6 +20,8 @@ AUTHOR: from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix +from sage.matrix.constructor import identity_matrix +from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular @@ -500,7 +502,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): N = self.__copy__() for j in range(self.ncols()): if j != ncoef: - N.add_multiple_of_column(j, ncoef, -R(self[nrow,j] / coef)) + N.add_multiple_of_column(j, ncoef, -R(self[nrow, j] / coef)) return N.fitting_ideal(i) for (ncolumn, column) in enumerate(self.columns()): if not column: @@ -619,3 +621,51 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.cache('det', d) return d + +cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): + """ + Dense matrix over a multivariate polynomial ring over a field. + """ + def laurent_matrix_reduction(self): + """ + From a matrix `self` of Laurent polynomials, apply elementary operations + to obtain a matrix `P` of polynomials such that the variables do not divide + no column and no row. + + OUTPUT: Three matrices `L`, `P`, `R` such that `self = L P R`, where `L` and + `R` are diagonal with monomial entries. + + EXAMPLES: + + sage: R. = LaurentPolynomialRing(QQ) + sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] + sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] + sage: A = matrix(R, 2, L) + sage: lf, P, rg = A.laurent_matrix_reduction() + sage: lf + [ x^-2 0] + [ 0 x^-1*y^-2] + sage: P + [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] + [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] + sage: rg + [y 0] + [0 1] + """ + R = self.base_ring() + n_rows, n_cols = self.dimensions() + mat_l = identity_matrix(R, n_rows) + mat_r = identity_matrix(R, n_cols) + res = self + for j, rw in enumerate(self.rows()): + for t in R.gens(): + n = min(mon.degree(t) for a in rw for cf, mon in a) + res.rescale_row(j, t ** -n) + mat_l.rescale_col(j, t ** n) + for j, cl in enumerate(self.columns()): + for t in R.gens(): + n = min(mon.degree(t) for a in cl for cf, mon in a) + res.rescale_col(j, t ** -n) + mat_r.rescale_row(j, t ** n) + res = res.change_ring(R.polynomial_ring()) + return mat_l, res, mat_r diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 6aab58352be..31e2ce46224 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -306,6 +306,13 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): pass else: return matrix_mpolynomial_dense.Matrix_mpolynomial_dense + elif isinstance(R, sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_mpair) and R.base_ring() in _Fields: + try: + from . import matrix_mpolynomial_dense + except ImportError: + pass + else: + return matrix_mpolynomial_dense.Matrix_laurent_mpolynomial_dense # The fallback from sage.matrix.matrix_generic_dense import Matrix_generic_dense @@ -795,7 +802,7 @@ def transposed(self): Full MatrixSpace of 3 by 2 dense matrices over Integer Ring """ return MatrixSpace(self._base, self.__ncols, self.__nrows, - self.__is_sparse, self.Element) + self.__is_sparse, self.Element) @lazy_attribute def _copy_zero(self): @@ -2179,7 +2186,7 @@ def row_space(self): return self.__row_space except AttributeError: self.__row_space = sage.modules.free_module.FreeModule(self.base_ring(), - self.ncols(), sparse=self.is_sparse()) + self.ncols(), sparse=self.is_sparse()) return self.__row_space def column_space(self): @@ -2197,7 +2204,7 @@ def column_space(self): return self.__column_space except AttributeError: self.__column_space = sage.modules.free_module.FreeModule(self.base_ring(), self.nrows(), - sparse=self.is_sparse()) + sparse=self.is_sparse()) return self.__column_space def random_element(self, density=None, *args, **kwds): @@ -2255,10 +2262,10 @@ def random_element(self, density=None, *args, **kwds): Z = self.zero_matrix().__copy__() if density is None: Z.randomize(density=float(1), nonzero=kwds.pop('nonzero', False), - *args, **kwds) + *args, **kwds) else: Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), - *args, **kwds) + *args, **kwds) return Z def _an_element_(self): @@ -2582,13 +2589,13 @@ def _MatrixSpace_ZZ_2x2(): register_unpickle_override('sage.matrix.matrix_modn_dense', - 'Matrix_modn_dense', Matrix_modn_dense_double) + 'Matrix_modn_dense', Matrix_modn_dense_double) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'Matrix_integer_2x2', Matrix_integer_dense) + 'Matrix_integer_2x2', Matrix_integer_dense) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2_class', MatrixSpace) + 'MatrixSpace_ZZ_2x2_class', MatrixSpace) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) + 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) lazy_import('sage.matrix.matrix_gf2e_dense', 'unpickle_matrix_gf2e_dense_v0') register_unpickle_override('sage.matrix.matrix_mod2e_dense', - 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) + 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) From df401b2140d657bc778124266c2eb9a98dedf1ee Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 17:52:27 +0200 Subject: [PATCH 048/538] use fitting_ideals for characteristic varieties --- src/sage/groups/finitely_presented.py | 98 +++++++++++++------- src/sage/matrix/matrix_mpolynomial_dense.pyx | 46 +++++++++ 2 files changed, 108 insertions(+), 36 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 96d03e90c83..c96ea32c0da 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -145,6 +145,7 @@ from sage.sets.set import Set from sage.structure.unique_representation import UniqueRepresentation + class GroupMorphismWithGensImages(SetMorphism): r""" Class used for morphisms from finitely presented groups to @@ -1549,12 +1550,12 @@ def sorted_presentation(self): C = [rel] for j in range(len(rel) - 1): C.append(rel[j + 1:] + rel[:j + 1]) - C1 = [tuple(-j for j in reversed(l)) for l in C] + C1 = [tuple(-j for j in reversed(l1)) for l1 in C] C += C1 C.sort() L1.append(C[0]) L1.sort() - return F/L1 + return F / L1 def epimorphisms(self, H): r""" @@ -1762,65 +1763,90 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): OUTPUT: If ``groebner`` is ``False`` a list of ideals defining the characteristic varieties. - If it is ``True``, a list of lists for Gröbner bases for each ideal. + If it is ``True``, a list of lists for Gröbner bases for the ideal of each irreducible + component. EXAMPLES:: sage: L = [2*(i, j) + 2* (-i, -j) for i, j in ((1, 2), (2, 3), (3, 1))] sage: G = FreeGroup(3) / L sage: G.characteristic_varieties(groebner=True) - [[(f1 - 1, f2 - 1, f3 - 1), - (f1 + 1, f2 - 1, f3 - 1), - (f1 - 1, f2 - 1, f3 + 1), - (f3^2 + 1, f1 - f3, f2 - f3), - (f1 - 1, f2 + 1, f3 - 1)], - [(f1 - 1, f2 - 1, f3 - 1), + {0: [(0,)], + 1: [(f1 - 1, f2 - 1, f3 - 1), (f1*f3 + 1, f2 - 1), (f1*f2 + 1, f3 - 1), (f2*f3 + 1, f1 - 1), (f2*f3 + 1, f1 - f2), (f2*f3 + 1, f1 - f3), - (f1*f3 + 1, f2 - f3)]] + (f1*f3 + 1, f2 - f3)], + 2: [(f1 - 1, f2 - 1, f3 + 1), + (f3^2 + 1, f1 - f3, f2 - f3), + (f1 - 1, f2 - 1, f3 - 1), + (f1 - 1, f2 + 1, f3 - 1), + (f1 + 1, f2 - 1, f3 - 1)], + 3: [(f1 - 1, f2 - 1, f3 - 1)]} sage: G = FreeGroup(2)/[2*(1,2,-1,-2)] sage: G.characteristic_varieties() - [Ideal (-2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field] + {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} sage: G.characteristic_varieties(ring=ZZ) - [Ideal (-2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring] + {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} sage: G = FreeGroup(2)/[(1,2,1,-2,-1,-2)] sage: G.characteristic_varieties() - [Ideal (1 - f2 + f2^2, -1 + f2 - f2^2) of Univariate Laurent Polynomial Ring in f2 over Rational Field] + {0: Ideal (0, 0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3, 1 - 2*f2 + 2*f2^2 - f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 2: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} sage: G.characteristic_varieties(groebner=True) - [[1 - f2 + f2^2]] + {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: [1]} """ - A, ideal = self.abelian_alexander_matrix(ring=ring, simplified=True) + A, rels = self.abelian_alexander_matrix(ring=ring, simplified=True) R = A.base_ring() - res = [] + eval_1 = {x: ring(1) for x in R.gens()} + A_scalar = A.apply_map(lambda p: p.subs(eval_1)) + n = A.ncols() + n1 = n - A_scalar.rank() + ideal_1 = R.ideal([x - 1 for x in R.gens()]) S = R.polynomial_ring() - ideal = [S(elt) for elt in ideal] - for j in range(1, A.ncols()): - L = [p.monomial_reduction()[0] for p in A.minors(j)] - J = R.ideal(L + ideal) - res.append(J) - if not groebner or not R.base_ring().is_field(): + K = R.base_ring() + id_rels = R.ideal(rels) + res = dict() + for j in range(n + 1): + if R.ngens() != 1: + J = id_rels + A.fitting_ideal(j) + elif R.ngens() == 1: + J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) + if j <= n1: + J1 = K.ideal([K(p.subs(eval_1)) for p in J.gens()]) + if J1: + J *= ideal_1 + res[j] = J + if not groebner or not ring.is_field(): return res if R.ngens() == 1: - res0 = [gcd(S(p) for p in J.gens()) for J in res] - res1 = [] - for p in res0: - if p == 0: - res1.append([R(0)]) + res = {j: gcd(S(p) for p in res[j].gens()) for j in range(n + 1)} + char_var = dict() + for j in range(n + 1): + if res[j] == 0: + char_var[j] = [R(0)] else: - fct = [q[0] for q in R(p).factor()] + fct = [q[0] for q in R(res[j]).factor()] if fct: - res1.append(fct) - return res1 - res1 = [] - for J in res: - LJ = J.minimal_associated_primes() + char_var[j] = fct + else: + char_var[j] = [R(1)] + return char_var + char_var = dict() + for j in range(n + 1): + LJ = res[j].minimal_associated_primes() fct = [id.groebner_basis() for id in LJ] - if fct != [(S.one(),)]: - res1.append(fct) - return res1 + if fct != [(S.one(), )]: + char_var[j] = fct + else: + char_var[j] = [R(1)] + return char_var def rewriting_system(self): """ diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 57f80149e88..d3f22015465 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -669,3 +669,49 @@ cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): mat_r.rescale_row(j, t ** n) res = res.change_ring(R.polynomial_ring()) return mat_l, res, mat_r + + def _fitting_ideal(self, i): + r""" + Return the `i`-th Fitting ideal of the matrix. This is the ideal generated + by the `n - i` minors, where `n` is the number of columns. + + INPUT: + + ``i`` -- an integer + + OUTPUT: + + An ideal on the base ring. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(QQ) + sage: M = matrix(R, [[2*x^-1-z, 0, y-z^-2, 0], [0, z - y^-1, z - x, 0],[z - y, x^-2 - y, 0, z]]) + sage: M + [-z + 2*x^-1 0 y - z^-2 0] + [ 0 z - y^-1 -x + z 0] + [ -y + z -y + x^-2 0 z] + sage: M.fitting_ideal(0) + Ideal (0) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(1) == M._fitting_ideal(1) + True + sage: M.fitting_ideal(1).groebner_basis() + (x^4 - 2*x^3*y - x*z^3 - 4*x^2*y + 8*x*y^2 + 4*x*y*z + 2*z^2 - 8*y, + x*y*z^2 - x*z - 2*y*z + 2, + x^2*z - x*z^2 - 2*x + 2*z, + y^2*z + 1/4*x^2 - 1/2*x*y - 1/4*x*z - y + 1/2) + sage: M.fitting_ideal(2).groebner_basis() + (1,) + sage: M.fitting_ideal(3).groebner_basis() + (1,) + sage: M.fitting_ideal(4).groebner_basis() + (1,) + sage: [R.ideal(M.minors(i)) == M._fitting_ideal(4 - i) for i in range(5)] + [True, True, True, True, True] + + """ + R = self.base_ring() + S = R.polynomial_ring() + A = self.laurent_matrix_reduction()[1].change_ring(S) + J = A._fitting_ideal(i) + return J.change_ring(R) From 68a94e5fd3f168718044d11e5610894a7af2a86e Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 22:07:32 +0200 Subject: [PATCH 049/538] adding xgcd, etc, for laurent polynomials in one variable --- src/sage/groups/finitely_presented.py | 6 +- src/sage/matrix/matrix2.pyx | 14 +-- src/sage/matrix/matrix_mpolynomial_dense.pyx | 6 +- .../rings/polynomial/laurent_polynomial.pyx | 113 ++++++++++++++++++ .../polynomial/laurent_polynomial_ideal.py | 10 ++ 5 files changed, 135 insertions(+), 14 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index c96ea32c0da..d2192bdcbbd 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1814,10 +1814,8 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): id_rels = R.ideal(rels) res = dict() for j in range(n + 1): - if R.ngens() != 1: - J = id_rels + A.fitting_ideal(j) - elif R.ngens() == 1: - J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) + # J = id_rels + A.fitting_ideal(j) + J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) if j <= n1: J1 = K.ideal([K(p.subs(eval_1)) for p in J.gens()]) if J1: diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 09a90f0c2a1..a872e2264a2 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -15902,7 +15902,7 @@ cdef class Matrix(Matrix1): dd, uu, vv = mm.smith_form(transformation=True) else: dd = mm.smith_form(transformation=False) - d = dd.new_matrix(1,1,[t[0,0]]).block_sum(dd) + d = dd.new_matrix(1, 1, [t[0, 0]]).block_sum(dd) if transformation: u = uu.new_matrix(1, 1, [1]).block_sum(uu) * u v = v * vv.new_matrix(1, 1, [1]).block_sum(vv) @@ -18121,9 +18121,9 @@ def _smith_diag(d, transformation=True): else: left = right = None for i in range(n): - I = ideal_or_fractional(R, dp[i, i]) + I0 = ideal_or_fractional(R, dp[i, i]) - if I == ideal_or_fractional(R, 1): + if I0 == ideal_or_fractional(R, 1): if dp[i, i] != 1: if transformation: left.add_multiple_of_row(i, i, R(R(1) / (dp[i, i])) - 1) @@ -18131,7 +18131,7 @@ def _smith_diag(d, transformation=True): continue for j in range(i + 1, n): - if dp[j, j] not in I: + if dp[j, j] not in I0: t = ideal_or_fractional(R, [dp[i, i], dp[j, j]]).gens_reduced() if len(t) > 1: raise ArithmeticError @@ -18215,9 +18215,9 @@ def _generic_clear_column(m): # [e,f] # is invertible over R - I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes + I0 = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes for k in range(1, a.nrows()): - if a[k, 0] not in I: + if a[k, 0] not in I0: try: v = ideal_or_fractional(R, a[0, 0], a[k, 0]).gens_reduced() except Exception as msg: @@ -18257,7 +18257,7 @@ def _generic_clear_column(m): if newlmat.det() != 1: raise ArithmeticError a = newlmat*a - I = ideal_or_fractional(R, a[0, 0]) + I0 = ideal_or_fractional(R, a[0, 0]) left_mat = newlmat*left_mat if left_mat * m != a: raise ArithmeticError diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index d3f22015465..840be75c387 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -656,13 +656,13 @@ cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): n_rows, n_cols = self.dimensions() mat_l = identity_matrix(R, n_rows) mat_r = identity_matrix(R, n_cols) - res = self - for j, rw in enumerate(self.rows()): + res = self.__copy__() + for j, rw in enumerate(res.rows()): for t in R.gens(): n = min(mon.degree(t) for a in rw for cf, mon in a) res.rescale_row(j, t ** -n) mat_l.rescale_col(j, t ** n) - for j, cl in enumerate(self.columns()): + for j, cl in enumerate(res.columns()): for t in R.gens(): n = min(mon.degree(t) for a in cl for cf, mon in a) res.rescale_col(j, t ** -n) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 5f563725296..bfb9e4ddd57 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1316,6 +1316,119 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): return ~self raise ArithmeticError("element is not a unit") + def xgcd(self, other): + R = self.parent() + S = R.polynomial_ring() + f, df = self.monomial_reduction() + g, dg = other.monomial_reduction() + h, p, q = f.xgcd(g) + return R(h), p / df, q / dg + + def inverse_mod(a, m): + """ + Invert the polynomial ``a`` with respect to ``m``, or raise a :class:`ValueError` + if no such inverse exists. + + The parameter ``m`` may be either a single polynomial or an ideal + (for consistency with :meth:`inverse_mod` in other rings). + + EXAMPLES:: + + sage: S. = LaurentPolynomialRing(QQ) + sage: f = inverse_mod(t^2 + 1, t^3 + 1); f + -1/2*t^2 - 1/2*t + 1/2 + sage: f * (t^2 + 1) % (t^3 + 1) + 1 + sage: f = t.inverse_mod((t + 1)^7); f + -t^6 - 7*t^5 - 21*t^4 - 35*t^3 - 35*t^2 - 21*t - 7 + sage: (f * t) + (t + 1)^7 + 1 + sage: t.inverse_mod(S.ideal((t + 1)^7)) == f + True + + This also works over inexact rings, but note that due to rounding + error the product may not always exactly equal the constant + polynomial 1 and have extra terms with coefficients close to zero. :: + + sage: # needs sage.modules + sage: R. = RDF[] + sage: epsilon = RDF(1).ulp()*50 # Allow an error of up to 50 ulp + sage: f = inverse_mod(x^2 + 1, x^5 + x + 1); f # abs tol 1e-14 + 0.4*x^4 - 0.2*x^3 - 0.4*x^2 + 0.2*x + 0.8 + sage: poly = f * (x^2 + 1) % (x^5 + x + 1) + sage: # Remove noisy zero terms: + sage: parent(poly)([0.0 if abs(c) <= epsilon else c + ....: for c in poly.coefficients(sparse=False)]) + 1.0 + sage: f = inverse_mod(x^3 - x + 1, x - 2); f + 0.14285714285714285 + sage: f * (x^3 - x + 1) % (x - 2) + 1.0 + sage: g = 5*x^3 + x - 7; m = x^4 - 12*x + 13; f = inverse_mod(g, m); f + -0.0319636125...*x^3 - 0.0383269759...*x^2 - 0.0463050900...*x + 0.346479687... + sage: poly = f*g % m + sage: # Remove noisy zero terms: + sage: parent(poly)([0.0 if abs(c) <= epsilon else c # abs tol 1e-14 + ....: for c in poly.coefficients(sparse=False)]) + 1.0000000000000004 + + ALGORITHM: Solve the system `as + mt = 1`, returning `s` as the inverse + of `a` mod `m`. + + Uses the Euclidean algorithm for exact rings, and solves a linear + system for the coefficients of `s` and `t` for inexact rings (as the + Euclidean algorithm may not converge in that case). + """ + from sage.rings.ideal import is_Ideal + if is_Ideal(m): + v = m.gens_reduced() + if len(v) > 1: + raise NotImplementedError("Don't know how to invert modulo non-principal ideal %s" % m) + m = v[0] + if m.degree() == 1 and m[1].is_unit(): + # a(x) mod (x-r) = a(r) + r = -m[0] + if not m[1].is_one(): + r *= m.base_ring()(~m[1]) + u = a(r) + if u.is_unit(): + return a.parent()(~u) + if a.parent().is_exact(): + # use xgcd + g, s, _ = a.xgcd(m) + if g == 1: + return s + elif g.is_unit(): + return g.inverse_of_unit() * s + else: + raise ValueError("Impossible inverse modulo") + else: + # xgcd may not converge for inexact rings. + # Instead solve for the coefficients of + # s (degree n-1) and t (degree n-2) in + # as + mt = 1 + # as a linear system. + from sage.matrix.constructor import matrix + from sage.modules.free_module_element import vector + a %= m + n = m.degree() + R = a.parent().base_ring() + M = matrix(R, 2*n-1) + # a_i s_j x^{i+j} terms + for i in range(n): + for j in range(n): + M[i+j, j] = a[i] + # m_i t_j x^{i+j} terms + for i in range(n+1): + for j in range(n-1): + M[i+j, j+n] = m[i] + v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 + if M.is_invertible(): + x = M.solve_right(v) # there has to be a better way to solve + return a.parent()(list(x)[0:n]) + else: + raise ValueError("Impossible inverse modulo") + def _fraction_pair(self): """ Return one representation of ``self`` as a pair diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index b193569d3fa..991a3fa589c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -204,6 +204,16 @@ def __contains__(self, f): g = f.__reduce__()[1][1] return (g in self.polynomial_ideal()) + def gens_reduced(self): + R = self.ring() + if R.ngens() > 1 or not R.base_ring().is_field(): + return self.gens() + gns = self.gens() + res = R(0) + for p in gns: + res = res.gcd(p) + return (res, ) + # Operations on ideals def change_ring(self, R, hint=None): From 8da8781f109e97e87885c0a05c55e5a6d2fef45e Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 23:34:10 +0200 Subject: [PATCH 050/538] cut characteristic varieties when the total ideal is reached --- src/sage/groups/finitely_presented.py | 34 ++-- .../matrix_laurent_mpolynomial_dense.pyx | 168 +++++++++++++----- src/sage/matrix/matrix_mpolynomial_dense.pyx | 96 ---------- src/sage/matrix/matrix_space.py | 4 +- .../rings/polynomial/laurent_polynomial.pyx | 95 +++------- 5 files changed, 169 insertions(+), 228 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index d2192bdcbbd..391cefc336c 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1784,21 +1784,25 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): (f1 - 1, f2 - 1, f3 - 1), (f1 - 1, f2 + 1, f3 - 1), (f1 + 1, f2 - 1, f3 - 1)], - 3: [(f1 - 1, f2 - 1, f3 - 1)]} + 3: [(f1 - 1, f2 - 1, f3 - 1)], + 4: []} sage: G = FreeGroup(2)/[2*(1,2,-1,-2)] sage: G.characteristic_varieties() {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, - 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} + 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 3: Ideal (0, 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} sage: G.characteristic_varieties(ring=ZZ) {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, - 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} + 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 3: Ideal (0, 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} sage: G = FreeGroup(2)/[(1,2,1,-2,-1,-2)] sage: G.characteristic_varieties() {0: Ideal (0, 0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3, 1 - 2*f2 + 2*f2^2 - f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 2: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} + 2: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 3: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} sage: G.characteristic_varieties(groebner=True) {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: [1]} """ @@ -1813,7 +1817,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): K = R.base_ring() id_rels = R.ideal(rels) res = dict() - for j in range(n + 1): + for j in range(n + 2): # J = id_rels + A.fitting_ideal(j) J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) if j <= n1: @@ -1824,9 +1828,11 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): if not groebner or not ring.is_field(): return res if R.ngens() == 1: - res = {j: gcd(S(p) for p in res[j].gens()) for j in range(n + 1)} + res = {j: gcd(S(p) for p in res[j].gens()) for j in range(n + 2)} char_var = dict() - for j in range(n + 1): + strict = True + j = 0 + while strict and j <= n + 1: if res[j] == 0: char_var[j] = [R(0)] else: @@ -1835,15 +1841,19 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): char_var[j] = fct else: char_var[j] = [R(1)] + strict = False + j += 1 return char_var char_var = dict() - for j in range(n + 1): + strict = True + j = 0 + while strict and j <= n + 1: LJ = res[j].minimal_associated_primes() fct = [id.groebner_basis() for id in LJ] - if fct != [(S.one(), )]: - char_var[j] = fct - else: - char_var[j] = [R(1)] + char_var[j] = fct + if not fct: + strict = False + j += 1 return char_var def rewriting_system(self): diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index c26b667b492..769608b3ce1 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -1,50 +1,128 @@ +""" +Dense matrices over multivariate polynomials over fields + +This implementation inherits from Matrix_generic_dense, i.e. it is not +optimized for speed only some methods were added. + +AUTHOR: + +* Martin Albrecht +""" + +# ***************************************************************************** +# Copyright (C) 2013 Martin Albrecht +# +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# https://www.gnu.org/licenses/ +# ***************************************************************************** +from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense + +# from sage.matrix.matrix2 cimport Matrix +# +# from sage.matrix.constructor import identity_matrix +# from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic +# from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular +# from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular +# +# from sage.libs.singular.function import singular_function, lib +# +# from cysignals.signals cimport sig_on, sig_off + from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic - -def laurent_matrix_reduction(A): +cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): """ - From a matrix `A` of Laurent polynomials, apply elementary operations - to obtain a matrix `P` of polynomials such that the variables do not divide - no column and no row. - - OUTPUT: Three matrices `L`, `P`, `R` such that `A = L P R`, where `L` and - `R` are diagonal with monomial entries. - - EXAMPLES: - - sage: from sage.rings.polynomial.laurent_reduction import laurent_matrix_reduction - sage: R. = LaurentPolynomialRing(QQ) - sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] - sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] - sage: A = matrix(R, 2, L) - sage: lf, P, rg = laurent_matrix_reduction(A) - sage: lf - [ x^-2 0] - [ 0 x^-1*y^-2] - sage: P - [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] - [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] - sage: rg - [y 0] - [0 1] + Dense matrix over a multivariate polynomial ring over a field. """ - R = A.base_ring() - n_rows, n_cols = A.dimensions() - mat_l = identity_matrix(R, n_rows) - mat_r = identity_matrix(R, n_cols) - if not isinstance(R, LaurentPolynomialRing_generic): - return mat_l, A, mat_r - res = A - for j, rw in enumerate(A.rows()): - for t in R.gens(): - n = min(mon.degree(t) for a in rw for cf, mon in a) - res.rescale_row(j, t ** -n) - mat_l.rescale_col(j, t ** n) - for j, cl in enumerate(A.columns()): - for t in R.gens(): - n = min(mon.degree(t) for a in cl for cf, mon in a) - res.rescale_col(j, t ** -n) - mat_r.rescale_row(j, t ** n) - res = res.change_ring(R.polynomial_ring()) - return mat_l, res, mat_r + def laurent_matrix_reduction(self): + """ + From a matrix `self` of Laurent polynomials, apply elementary operations + to obtain a matrix `P` of polynomials such that the variables do not divide + no column and no row. + + OUTPUT: Three matrices `L`, `P`, `R` such that `self = L P R`, where `L` and + `R` are diagonal with monomial entries. + + EXAMPLES: + + sage: R. = LaurentPolynomialRing(QQ) + sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] + sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] + sage: A = matrix(R, 2, L) + sage: lf, P, rg = A.laurent_matrix_reduction() + sage: lf + [ x^-2 0] + [ 0 x^-1*y^-2] + sage: P + [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] + [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] + sage: rg + [y 0] + [0 1] + """ + R = self.base_ring() + n_rows, n_cols = self.dimensions() + mat_l = identity_matrix(R, n_rows) + mat_r = identity_matrix(R, n_cols) + res = self.__copy__() + for j, rw in enumerate(res.rows()): + for t in R.gens(): + n = min(mon.degree(t) for a in rw for cf, mon in a) + res.rescale_row(j, t ** -n) + mat_l.rescale_col(j, t ** n) + for j, cl in enumerate(res.columns()): + for t in R.gens(): + n = min(mon.degree(t) for a in cl for cf, mon in a) + res.rescale_col(j, t ** -n) + mat_r.rescale_row(j, t ** n) + res = res.change_ring(R.polynomial_ring()) + return mat_l, res, mat_r + + def _fitting_ideal(self, i): + r""" + Return the `i`-th Fitting ideal of the matrix. This is the ideal generated + by the `n - i` minors, where `n` is the number of columns. + + INPUT: + + ``i`` -- an integer + + OUTPUT: + + An ideal on the base ring. + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(QQ) + sage: M = matrix(R, [[2*x^-1-z, 0, y-z^-2, 0], [0, z - y^-1, z - x, 0],[z - y, x^-2 - y, 0, z]]) + sage: M + [-z + 2*x^-1 0 y - z^-2 0] + [ 0 z - y^-1 -x + z 0] + [ -y + z -y + x^-2 0 z] + sage: M.fitting_ideal(0) + Ideal (0) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field + sage: M.fitting_ideal(1) == M._fitting_ideal(1) + True + sage: M.fitting_ideal(1).groebner_basis() + (x^4 - 2*x^3*y - x*z^3 - 4*x^2*y + 8*x*y^2 + 4*x*y*z + 2*z^2 - 8*y, + x*y*z^2 - x*z - 2*y*z + 2, + x^2*z - x*z^2 - 2*x + 2*z, + y^2*z + 1/4*x^2 - 1/2*x*y - 1/4*x*z - y + 1/2) + sage: M.fitting_ideal(2).groebner_basis() + (1,) + sage: M.fitting_ideal(3).groebner_basis() + (1,) + sage: M.fitting_ideal(4).groebner_basis() + (1,) + sage: [R.ideal(M.minors(i)) == M._fitting_ideal(4 - i) for i in range(5)] + [True, True, True, True, True] + + """ + R = self.base_ring() + S = R.polynomial_ring() + A = self.laurent_matrix_reduction()[1].change_ring(S) + J = A._fitting_ideal(i) + return J.change_ring(R) diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 840be75c387..589b5b33331 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -20,8 +20,6 @@ AUTHOR: from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix -from sage.matrix.constructor import identity_matrix -from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular @@ -621,97 +619,3 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.cache('det', d) return d - -cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): - """ - Dense matrix over a multivariate polynomial ring over a field. - """ - def laurent_matrix_reduction(self): - """ - From a matrix `self` of Laurent polynomials, apply elementary operations - to obtain a matrix `P` of polynomials such that the variables do not divide - no column and no row. - - OUTPUT: Three matrices `L`, `P`, `R` such that `self = L P R`, where `L` and - `R` are diagonal with monomial entries. - - EXAMPLES: - - sage: R. = LaurentPolynomialRing(QQ) - sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6] - sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2] - sage: A = matrix(R, 2, L) - sage: lf, P, rg = A.laurent_matrix_reduction() - sage: lf - [ x^-2 0] - [ 0 x^-1*y^-2] - sage: P - [ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2] - [ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11] - sage: rg - [y 0] - [0 1] - """ - R = self.base_ring() - n_rows, n_cols = self.dimensions() - mat_l = identity_matrix(R, n_rows) - mat_r = identity_matrix(R, n_cols) - res = self.__copy__() - for j, rw in enumerate(res.rows()): - for t in R.gens(): - n = min(mon.degree(t) for a in rw for cf, mon in a) - res.rescale_row(j, t ** -n) - mat_l.rescale_col(j, t ** n) - for j, cl in enumerate(res.columns()): - for t in R.gens(): - n = min(mon.degree(t) for a in cl for cf, mon in a) - res.rescale_col(j, t ** -n) - mat_r.rescale_row(j, t ** n) - res = res.change_ring(R.polynomial_ring()) - return mat_l, res, mat_r - - def _fitting_ideal(self, i): - r""" - Return the `i`-th Fitting ideal of the matrix. This is the ideal generated - by the `n - i` minors, where `n` is the number of columns. - - INPUT: - - ``i`` -- an integer - - OUTPUT: - - An ideal on the base ring. - - EXAMPLES:: - - sage: R. = LaurentPolynomialRing(QQ) - sage: M = matrix(R, [[2*x^-1-z, 0, y-z^-2, 0], [0, z - y^-1, z - x, 0],[z - y, x^-2 - y, 0, z]]) - sage: M - [-z + 2*x^-1 0 y - z^-2 0] - [ 0 z - y^-1 -x + z 0] - [ -y + z -y + x^-2 0 z] - sage: M.fitting_ideal(0) - Ideal (0) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field - sage: M.fitting_ideal(1) == M._fitting_ideal(1) - True - sage: M.fitting_ideal(1).groebner_basis() - (x^4 - 2*x^3*y - x*z^3 - 4*x^2*y + 8*x*y^2 + 4*x*y*z + 2*z^2 - 8*y, - x*y*z^2 - x*z - 2*y*z + 2, - x^2*z - x*z^2 - 2*x + 2*z, - y^2*z + 1/4*x^2 - 1/2*x*y - 1/4*x*z - y + 1/2) - sage: M.fitting_ideal(2).groebner_basis() - (1,) - sage: M.fitting_ideal(3).groebner_basis() - (1,) - sage: M.fitting_ideal(4).groebner_basis() - (1,) - sage: [R.ideal(M.minors(i)) == M._fitting_ideal(4 - i) for i in range(5)] - [True, True, True, True, True] - - """ - R = self.base_ring() - S = R.polynomial_ring() - A = self.laurent_matrix_reduction()[1].change_ring(S) - J = A._fitting_ideal(i) - return J.change_ring(R) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 31e2ce46224..04ab6b138a2 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -308,11 +308,11 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): return matrix_mpolynomial_dense.Matrix_mpolynomial_dense elif isinstance(R, sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_mpair) and R.base_ring() in _Fields: try: - from . import matrix_mpolynomial_dense + from . import matrix_laurent_mpolynomial_dense except ImportError: pass else: - return matrix_mpolynomial_dense.Matrix_laurent_mpolynomial_dense + return matrix_laurent_mpolynomial_dense.Matrix_laurent_mpolynomial_dense # The fallback from sage.matrix.matrix_generic_dense import Matrix_generic_dense diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index bfb9e4ddd57..d4dff8b1361 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1317,7 +1317,18 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): raise ArithmeticError("element is not a unit") def xgcd(self, other): + """ + Extended `gcd` for univariate Laurent polynomial rings over a field. + + EXAMPLES:: + + sage: S. = LaurentPolynomialRing(QQ) + sage: (t^-2 + 1).xgcd(t^-3 + 1) + (1, 1/2*t^2 - 1/2*t^3 - 1/2*t^4, 1/2*t^3 + 1/2*t^4) + """ R = self.parent() + if not R.is_exact() or not R.base_ring().is_field: + raise NotImplementedError("Not implemented") S = R.polynomial_ring() f, df = self.monomial_reduction() g, dg = other.monomial_reduction() @@ -1335,49 +1346,13 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): EXAMPLES:: sage: S. = LaurentPolynomialRing(QQ) - sage: f = inverse_mod(t^2 + 1, t^3 + 1); f - -1/2*t^2 - 1/2*t + 1/2 - sage: f * (t^2 + 1) % (t^3 + 1) - 1 - sage: f = t.inverse_mod((t + 1)^7); f - -t^6 - 7*t^5 - 21*t^4 - 35*t^3 - 35*t^2 - 21*t - 7 - sage: (f * t) + (t + 1)^7 + sage: f = inverse_mod(t^-2 + 1, t^-3 + 1); f + 1/2*t^2 - 1/2*t^3 - 1/2*t^4 + sage: f * (t^-2 + 1) + (1/2*t^4 + 1/2*t^3) * (t^-3 + 1) 1 - sage: t.inverse_mod(S.ideal((t + 1)^7)) == f - True - - This also works over inexact rings, but note that due to rounding - error the product may not always exactly equal the constant - polynomial 1 and have extra terms with coefficients close to zero. :: - - sage: # needs sage.modules - sage: R. = RDF[] - sage: epsilon = RDF(1).ulp()*50 # Allow an error of up to 50 ulp - sage: f = inverse_mod(x^2 + 1, x^5 + x + 1); f # abs tol 1e-14 - 0.4*x^4 - 0.2*x^3 - 0.4*x^2 + 0.2*x + 0.8 - sage: poly = f * (x^2 + 1) % (x^5 + x + 1) - sage: # Remove noisy zero terms: - sage: parent(poly)([0.0 if abs(c) <= epsilon else c - ....: for c in poly.coefficients(sparse=False)]) - 1.0 - sage: f = inverse_mod(x^3 - x + 1, x - 2); f - 0.14285714285714285 - sage: f * (x^3 - x + 1) % (x - 2) - 1.0 - sage: g = 5*x^3 + x - 7; m = x^4 - 12*x + 13; f = inverse_mod(g, m); f - -0.0319636125...*x^3 - 0.0383269759...*x^2 - 0.0463050900...*x + 0.346479687... - sage: poly = f*g % m - sage: # Remove noisy zero terms: - sage: parent(poly)([0.0 if abs(c) <= epsilon else c # abs tol 1e-14 - ....: for c in poly.coefficients(sparse=False)]) - 1.0000000000000004 ALGORITHM: Solve the system `as + mt = 1`, returning `s` as the inverse of `a` mod `m`. - - Uses the Euclidean algorithm for exact rings, and solves a linear - system for the coefficients of `s` and `t` for inexact rings (as the - Euclidean algorithm may not converge in that case). """ from sage.rings.ideal import is_Ideal if is_Ideal(m): @@ -1393,41 +1368,15 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): u = a(r) if u.is_unit(): return a.parent()(~u) - if a.parent().is_exact(): - # use xgcd - g, s, _ = a.xgcd(m) - if g == 1: - return s - elif g.is_unit(): - return g.inverse_of_unit() * s - else: - raise ValueError("Impossible inverse modulo") + if not a.parent().is_exact(): + raise NotImplementedError("Not implemented") + g, s, _ = a.xgcd(m) + if g == 1: + return s + elif g.is_unit(): + return g.inverse_of_unit() * s else: - # xgcd may not converge for inexact rings. - # Instead solve for the coefficients of - # s (degree n-1) and t (degree n-2) in - # as + mt = 1 - # as a linear system. - from sage.matrix.constructor import matrix - from sage.modules.free_module_element import vector - a %= m - n = m.degree() - R = a.parent().base_ring() - M = matrix(R, 2*n-1) - # a_i s_j x^{i+j} terms - for i in range(n): - for j in range(n): - M[i+j, j] = a[i] - # m_i t_j x^{i+j} terms - for i in range(n+1): - for j in range(n-1): - M[i+j, j+n] = m[i] - v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 - if M.is_invertible(): - x = M.solve_right(v) # there has to be a better way to solve - return a.parent()(list(x)[0:n]) - else: - raise ValueError("Impossible inverse modulo") + raise ValueError("Impossible inverse modulo") def _fraction_pair(self): """ From 1153822b0e99841d74bf629ba51ec5d32ddd5d92 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 28 Sep 2023 23:41:51 +0200 Subject: [PATCH 051/538] trailing spaces --- src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 769608b3ce1..4a5d3b1ea2a 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -20,14 +20,14 @@ AUTHOR: from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense # from sage.matrix.matrix2 cimport Matrix -# +# # from sage.matrix.constructor import identity_matrix # from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic # from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular # from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular -# +# # from sage.libs.singular.function import singular_function, lib -# +# # from cysignals.signals cimport sig_on, sig_off from sage.matrix.constructor import identity_matrix From cbcc182b07a5f1664826aee23bf8e9712d5eec57 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 29 Sep 2023 12:16:03 +0200 Subject: [PATCH 052/538] redefine gens_reduced and more doctests --- src/sage/groups/finitely_presented.py | 63 +++++++++---------- .../matrix_laurent_mpolynomial_dense.pyx | 4 +- .../polynomial/laurent_polynomial_ideal.py | 9 +-- 3 files changed, 35 insertions(+), 41 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 391cefc336c..2552cc0940c 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1762,9 +1762,10 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): OUTPUT: - If ``groebner`` is ``False`` a list of ideals defining the characteristic varieties. - If it is ``True``, a list of lists for Gröbner bases for the ideal of each irreducible - component. + A dictionary with keys the indices of the varieties. If ``groebner`` is ``False`` + the values are the ideals defining the characteristic varieties. + If it is ``True``, lists for Gröbner bases for the ideal of each irreducible + component, stopping when the first time a characteristic variety is empty. EXAMPLES:: @@ -1772,39 +1773,37 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): sage: G = FreeGroup(3) / L sage: G.characteristic_varieties(groebner=True) {0: [(0,)], - 1: [(f1 - 1, f2 - 1, f3 - 1), - (f1*f3 + 1, f2 - 1), - (f1*f2 + 1, f3 - 1), - (f2*f3 + 1, f1 - 1), - (f2*f3 + 1, f1 - f2), - (f2*f3 + 1, f1 - f3), - (f1*f3 + 1, f2 - f3)], - 2: [(f1 - 1, f2 - 1, f3 + 1), - (f3^2 + 1, f1 - f3, f2 - f3), - (f1 - 1, f2 - 1, f3 - 1), - (f1 - 1, f2 + 1, f3 - 1), - (f1 + 1, f2 - 1, f3 - 1)], - 3: [(f1 - 1, f2 - 1, f3 - 1)], - 4: []} + 1: [(f1 - 1, f2 - 1, f3 - 1), (f1*f3 + 1, f2 - 1), (f1*f2 + 1, f3 - 1), (f2*f3 + 1, f1 - 1), + (f2*f3 + 1, f1 - f2), (f2*f3 + 1, f1 - f3), (f1*f3 + 1, f2 - f3)], + 2: [(f1 - 1, f2 - 1, f3 - 1), (f1 + 1, f2 - 1, f3 - 1), (f1 - 1, f2 - 1, f3 + 1), + (f3^2 + 1, f1 - f3, f2 - f3), (f1 - 1, f2 + 1, f3 - 1)], + 3: [(f1 - 1, f2 - 1, f3 - 1)], + 4: []} sage: G = FreeGroup(2)/[2*(1,2,-1,-2)] sage: G.characteristic_varieties() - {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, - 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, - 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, - 3: Ideal (0, 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} + {0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 1: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field, + 3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field} sage: G.characteristic_varieties(ring=ZZ) - {0: Ideal (0, 0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, - 1: Ideal (0, -2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, - 2: Ideal (f1 - 1, f2 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, - 3: Ideal (0, 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} + {0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 1: Ideal (2*f2 - 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring, + 3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring} sage: G = FreeGroup(2)/[(1,2,1,-2,-1,-2)] sage: G.characteristic_varieties() - {0: Ideal (0, 0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3, 1 - 2*f2 + 2*f2^2 - f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 2: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 3: Ideal (0, 1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} + {0: Ideal (0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 2: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field, + 3: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} sage: G.characteristic_varieties(groebner=True) - {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: [1]} + {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: []} + sage: G = FreeGroup(2)/[3 * (1, ), 2 * (2, )] + sage: G.characteristic_varieties(groebner=True) + {0: [-1 + F1, 1 + F1, 1 - F1 + F1^2, 1 + F1 + F1^2], 1: [1 - F1 + F1^2], 2: []} + sage: G = FreeGroup(2)/[2 * (2, )] + sage: G.characteristic_varieties(groebner=True) + {0: [(f1 + 1,), (f1 - 1,)], 1: [(f1 + 1,), (f1 - 1, f2 - 1)], 2: []} """ A, rels = self.abelian_alexander_matrix(ring=ring, simplified=True) R = A.base_ring() @@ -1824,7 +1823,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): J1 = K.ideal([K(p.subs(eval_1)) for p in J.gens()]) if J1: J *= ideal_1 - res[j] = J + res[j] = R.ideal(J.gens_reduced()) if not groebner or not ring.is_field(): return res if R.ngens() == 1: @@ -1840,7 +1839,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): if fct: char_var[j] = fct else: - char_var[j] = [R(1)] + char_var[j] = [] strict = False j += 1 return char_var diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 4a5d3b1ea2a..3f0c1e968f2 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -6,11 +6,11 @@ optimized for speed only some methods were added. AUTHOR: -* Martin Albrecht +* Enrique Artal """ # ***************************************************************************** -# Copyright (C) 2013 Martin Albrecht +# Copyright (C) 2023 Enrique Artal # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 991a3fa589c..5c938466e1c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -206,13 +206,8 @@ def __contains__(self, f): def gens_reduced(self): R = self.ring() - if R.ngens() > 1 or not R.base_ring().is_field(): - return self.gens() - gns = self.gens() - res = R(0) - for p in gns: - res = res.gcd(p) - return (res, ) + J = self.polynomial_ideal() + return tuple(R(p) for p in J.gens()) # Operations on ideals From fbb77c49de41e3d94404ea6861f0d2bab932175d Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 29 Sep 2023 15:47:12 +0200 Subject: [PATCH 053/538] sum of ideals --- src/sage/groups/finitely_presented.py | 4 ++-- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 2552cc0940c..5b16bd3a7aa 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1817,8 +1817,8 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): id_rels = R.ideal(rels) res = dict() for j in range(n + 2): - # J = id_rels + A.fitting_ideal(j) - J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) + J = id_rels + A.fitting_ideal(j) + # J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) if j <= n1: J1 = K.ideal([K(p.subs(eval_1)) for p in J.gens()]) if J1: diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 5c938466e1c..d8af3c8685d 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -95,10 +95,11 @@ def __init__(self, ring, gens, coerce=True, hint=None): self._poly_ring = ring.polynomial_ring() self._poly_ideal = None # Create only as needed self._saturated = False - if hint is None: - self._hint = self._poly_ring.zero_ideal() - else: - self._hint = hint.change_ring(self._poly_ring) + self._hint = self._poly_ring.ideal([f._fraction_pair()[0] for f in self.gens()]) + # if hint is None: + # self._hint = self._poly_ring.zero_ideal() + # else: + # self._hint = hint.change_ring(self._poly_ring) def set_hint(self, hint): """ From 56734816a8ba6e0784b23bca3b59ab5735ce9ef7 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sat, 30 Sep 2023 10:22:53 +0200 Subject: [PATCH 054/538] change hint definition --- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index d8af3c8685d..bea4b8bb76a 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -95,7 +95,7 @@ def __init__(self, ring, gens, coerce=True, hint=None): self._poly_ring = ring.polynomial_ring() self._poly_ideal = None # Create only as needed self._saturated = False - self._hint = self._poly_ring.ideal([f._fraction_pair()[0] for f in self.gens()]) + self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) # if hint is None: # self._hint = self._poly_ring.zero_ideal() # else: @@ -115,7 +115,7 @@ def set_hint(self, hint): sage: P. = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.hint() - Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field sage: I.set_hint(P.polynomial_ring().ideal([x + 3*y])) sage: I.hint() Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field @@ -136,7 +136,7 @@ def hint(self): sage: P. = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.hint() - Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field """ return self._hint From 9e9185cac2e9790e683d62f61d1d5506ef42b926 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:40:41 +0200 Subject: [PATCH 055/538] undo format changes for finitely_presented.py --- src/sage/groups/finitely_presented.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 5b16bd3a7aa..a961df9a4c5 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1550,12 +1550,12 @@ def sorted_presentation(self): C = [rel] for j in range(len(rel) - 1): C.append(rel[j + 1:] + rel[:j + 1]) - C1 = [tuple(-j for j in reversed(l1)) for l1 in C] + C1 = [tuple(-j for j in reversed(l)) for l in C] C += C1 C.sort() L1.append(C[0]) L1.sort() - return F / L1 + return F/L1 def epimorphisms(self, H): r""" From b498b59c637d094bff24eb0036d1cfaf7985f91b Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:49:39 +0200 Subject: [PATCH 056/538] undo format changes for matrix2.pyx --- src/sage/matrix/matrix2.pyx | 731 ++++++++++++++++++------------------ 1 file changed, 357 insertions(+), 374 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index a872e2264a2..86aca6e00d8 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -209,10 +209,10 @@ cdef class Matrix(Matrix1): from sage.matrix.constructor import matrix if self.is_sparse(): return matrix({ij: self[ij].subs(*args, **kwds) for ij in self.nonzero_positions()}, - nrows=self._nrows, ncols=self._ncols, sparse=True) + nrows=self._nrows, ncols=self._ncols, sparse=True) else: return matrix([a.subs(*args, **kwds) for a in self.list()], - nrows=self._nrows, ncols=self._ncols, sparse=False) + nrows=self._nrows, ncols=self._ncols, sparse=False) def solve_left(self, B, check=True): """ @@ -890,8 +890,8 @@ cdef class Matrix(Matrix1): # Elements of SR "remember" whether or not they are exact. # If every element in the system is exact, we can probably # still check the solution over the inexact ring SR. - check = (check and all(e.is_exact() - for e in self.list() + B.list())) + check = (check and all( e.is_exact() + for e in self.list() + B.list() )) else: check = (check and K.is_exact()) @@ -975,7 +975,7 @@ cdef class Matrix(Matrix1): raise NotFullRankError D = self.augment(B) D.echelonize() - return D.matrix_from_columns(range(self.ncols(), D.ncols())) + return D.matrix_from_columns(range(self.ncols(),D.ncols())) def pivot_rows(self): """ @@ -1075,8 +1075,8 @@ cdef class Matrix(Matrix1): for row from 0 <= row < self._nrows: tmp = [] for c in cols: - # if c<0 or c >= self._ncols: - # raise IndexError("matrix column index out of range") +# if c<0 or c >= self._ncols: +# raise IndexError("matrix column index out of range") tmp.append(self.get_unsafe(row, c)) pr = pr * sum(tmp) return pr @@ -1173,10 +1173,7 @@ cdef class Matrix(Matrix1): sage: A.elementwise_product(vector(ZZ, [1,2,3,4])) Traceback (most recent call last): ... - TypeError: no common canonical parent for objects with parents: - 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' - and 'Ambient free module of rank 4 over the principal ideal - domain Integer Ring' + TypeError: no common canonical parent for objects with parents: 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' and 'Ambient free module of rank 4 over the principal ideal domain Integer Ring' sage: A = matrix(2, 2, range(4)) sage: A.elementwise_product(polygen(parent(A))) @@ -1191,11 +1188,7 @@ cdef class Matrix(Matrix1): sage: A.elementwise_product(B) Traceback (most recent call last): ... - TypeError: no common canonical parent - for objects with parents: 'Full MatrixSpace of - 5 by 10 dense matrices over Integer Ring' and - 'Full MatrixSpace of 10 by 5 dense matrices over - Integer Ring' + TypeError: no common canonical parent for objects with parents: 'Full MatrixSpace of 5 by 10 dense matrices over Integer Ring' and 'Full MatrixSpace of 10 by 5 dense matrices over Integer Ring' Some pairs of rings do not have a common parent where multiplication makes sense. This will raise an error. :: @@ -1393,7 +1386,7 @@ cdef class Matrix(Matrix1): m = self._nrows n = self._ncols if not m <= n: - raise ValueError("must have m <= n, but m (=%s) and n (=%s)" % (m, n)) + raise ValueError("must have m <= n, but m (=%s) and n (=%s)"%(m,n)) for r from 1 <= r < m+1: lst = _choose(n, r) @@ -1514,8 +1507,8 @@ cdef class Matrix(Matrix1): return R.zero() pm = 0 - for cols in _choose(n, k): - for rows in _choose(m, k): + for cols in _choose(n,k): + for rows in _choose(m,k): pm = pm + self.matrix_from_rows_and_columns(rows, cols).permanent() return pm @@ -1824,14 +1817,14 @@ cdef class Matrix(Matrix1): ....: if v != [1, 16, 78, 128, 53]: ....: print("ERROR with algorithm={} use_complement=False".format(algorithm)) """ - cdef Py_ssize_t i, j + cdef Py_ssize_t i,j cdef unsigned int num_ones cdef int m = self._nrows cdef int n = self._ncols cdef int mn = min(m, n) cdef Matrix B zero = self.base_ring().zero() - one = self.base_ring().one() + one = self.base_ring().one() if algorithm is None: algorithm = "ButeraPernici" @@ -1845,7 +1838,7 @@ cdef class Matrix(Matrix1): num_ones = 1 for i in range(m): for j in range(n): - x = self.get_unsafe(i, j) + x = self.get_unsafe(i,j) if x != zero: if x != one: z2 = False @@ -1857,7 +1850,7 @@ cdef class Matrix(Matrix1): break if not z2 and (complement or algorithm == "Godsil"): - raise ValueError("coefficients must be zero or one, but we have '{}' in position ({},{}).".format(x, i, j)) + raise ValueError("coefficients must be zero or one, but we have '{}' in position ({},{}).".format(x,i,j)) if use_complement is None: use_complement = z2 and num_ones > 0.55 * m * n @@ -1871,7 +1864,7 @@ cdef class Matrix(Matrix1): complement = not complement elif algorithm == "Ryser": - b = [self.permanental_minor(k, algorithm="Ryser") + b = [self.permanental_minor(k,algorithm="Ryser") for k in range(mn + 1)] elif algorithm == "ButeraPernici": @@ -1960,9 +1953,9 @@ cdef class Matrix(Matrix1): all_rows = range(self.nrows()) all_cols = range(self.ncols()) m = [] - for rows in Combinations(all_rows, k): - for cols in Combinations(all_cols, k): - m.append(self.matrix_from_rows_and_columns(rows, cols).determinant()) + for rows in Combinations(all_rows,k): + for cols in Combinations(all_cols,k): + m.append(self.matrix_from_rows_and_columns(rows,cols).determinant()) return m def det(self, *args, **kwds): @@ -2120,13 +2113,13 @@ cdef class Matrix(Matrix1): if n == 0: d = R.one() elif n == 1: - d = self.get_unsafe(0, 0) + d = self.get_unsafe(0,0) elif n == 2: - d = self.get_unsafe(0, 0)*self.get_unsafe(1, 1) - self.get_unsafe(1, 0)*self.get_unsafe(0, 1) + d = self.get_unsafe(0,0)*self.get_unsafe(1,1) - self.get_unsafe(1,0)*self.get_unsafe(0,1) elif n == 3: - d = self.get_unsafe(0, 0) * (self.get_unsafe(1, 1)*self.get_unsafe(2, 2) - self.get_unsafe(1, 2)*self.get_unsafe(2, 1)) \ - - self.get_unsafe(1, 0) * (self.get_unsafe(0, 1)*self.get_unsafe(2, 2) - self.get_unsafe(0, 2)*self.get_unsafe(2, 1)) \ - + self.get_unsafe(2, 0) * (self.get_unsafe(0, 1)*self.get_unsafe(1, 2) - self.get_unsafe(0, 2)*self.get_unsafe(1, 1)) + d = self.get_unsafe(0,0) * (self.get_unsafe(1,1)*self.get_unsafe(2,2) - self.get_unsafe(1,2)*self.get_unsafe(2,1)) \ + - self.get_unsafe(1,0) * (self.get_unsafe(0,1)*self.get_unsafe(2,2) - self.get_unsafe(0,2)*self.get_unsafe(2,1)) \ + + self.get_unsafe(2,0) * (self.get_unsafe(0,1)*self.get_unsafe(1,2) - self.get_unsafe(0,2)*self.get_unsafe(1,1)) self.cache('det', d) return d @@ -2140,7 +2133,7 @@ cdef class Matrix(Matrix1): d = R(self.__pari__().matdet()) else: # Lift to ZZ and compute there. - d = R(self.apply_map(lambda x: x.lift_centered()).det()) + d = R(self.apply_map(lambda x : x.lift_centered()).det()) self.cache('det', d) return d @@ -2196,18 +2189,18 @@ cdef class Matrix(Matrix1): """ cdef Py_ssize_t i if level == 2: - return self.get_unsafe(0, 0) * self.get_unsafe(1, 1) - self.get_unsafe(0, 1) * self.get_unsafe(1, 0) + return self.get_unsafe(0,0) * self.get_unsafe(1,1) - self.get_unsafe(0,1) * self.get_unsafe(1,0) else: level -= 1 - d = self.get_unsafe(level, level) * self._det_by_minors(level) + d = self.get_unsafe(level,level) * self._det_by_minors(level) # on each iteration, row i will be missing in the first (level) rows # swapping is much faster than taking submatrices for i from level > i >= 0: self.swap_rows(level, i) if (level - i) % 2: - d -= self.get_unsafe(level, level) * self._det_by_minors(level) + d -= self.get_unsafe(level,level) * self._det_by_minors(level) else: - d += self.get_unsafe(level, level) * self._det_by_minors(level) + d += self.get_unsafe(level,level) * self._det_by_minors(level) # undo all our permutations to get us back to where we started for i from 0 <= i < level: self.swap_rows(level, i) @@ -2658,7 +2651,7 @@ cdef class Matrix(Matrix1): """ M = self.parent().change_ring(phi.codomain()) if self.is_sparse(): - values = {(i, j): phi(z) for (i, j), z in self.dict()} + values = {(i,j): phi(z) for (i,j),z in self.dict()} else: values = [phi(z) for z in self.list()] image = M(values) @@ -2767,7 +2760,7 @@ cdef class Matrix(Matrix1): return self.dense_matrix() if self.is_sparse(): - values = {(i, j): phi(v) for (i, j), v in self.dict().iteritems()} + values = {(i,j): phi(v) for (i,j),v in self.dict().iteritems()} if R is None: R = sage.structure.sequence.Sequence(values.values()).universe() else: @@ -2785,7 +2778,7 @@ cdef class Matrix(Matrix1): else: from sage.matrix.matrix_space import MatrixSpace M = MatrixSpace(R, self._nrows, - self._ncols, sparse=sparse) + self._ncols, sparse=sparse) image = M(values) if self._subdivisions is not None: image.subdivide(*self.subdivisions()) @@ -2896,7 +2889,7 @@ cdef class Matrix(Matrix1): # At least check that the minimal polynomial kills the matrix tester.assertTrue(self.minpoly().subs(x=self).is_zero()) - def charpoly(self, var='x', algorithm=None): + def charpoly(self, var = 'x', algorithm = None): r""" Returns the characteristic polynomial of self, as a polynomial over the base ring. @@ -3091,7 +3084,7 @@ cdef class Matrix(Matrix1): self.cache('charpoly', f) return f - def _charpoly_df(self, var='x'): + def _charpoly_df(self, var = 'x'): r""" Computes the characteristic polynomial of ``self`` without divisions. @@ -3179,10 +3172,10 @@ cdef class Matrix(Matrix1): # Extract parameters # - cdef Matrix M = self - n = M._ncols - R = M._base_ring - S = PolynomialRing(R, var) + cdef Matrix M = self + n = M._ncols + R = M._base_ring + S = PolynomialRing(R, var) # Corner cases # N.B. We already tested for M to be square, hence we do not need to @@ -3207,11 +3200,11 @@ cdef class Matrix(Matrix1): from sage.matrix.constructor import matrix F = [R.zero()] * n - cdef Matrix a = matrix(R, n - 1, n) + cdef Matrix a = matrix(R, n-1, n) A = [R.zero()] * n F[0] = - M.get_unsafe(0, 0) - for t in range(1, n): + for t in range(1,n): # Set a(1, t) to be M(<=t, t) # @@ -3381,7 +3374,7 @@ cdef class Matrix(Matrix1): [] """ n = min(self.nrows(), self.ncols()) - return [self[i, i] for i in range(n)] + return [self[i,i] for i in range(n)] def trace(self): """ @@ -3418,7 +3411,7 @@ cdef class Matrix(Matrix1): cdef object s s = R(0) for i from 0 <= i < self._nrows: - s = s + self.get_unsafe(i, i) + s = s + self.get_unsafe(i,i) return s def trace_of_product(self, Matrix other): @@ -3476,11 +3469,11 @@ cdef class Matrix(Matrix1): H = self.change_ring(K) H.hessenbergize() except TypeError as msg: - raise TypeError("%s\nHessenberg form only possible for matrices over a field" % msg) + raise TypeError("%s\nHessenberg form only possible for matrices over a field"%msg) else: H = self.__copy__() H.hessenbergize() - # end if + #end if self.cache('hessenberg_form', H) return H @@ -3524,7 +3517,7 @@ cdef class Matrix(Matrix1): cdef Py_ssize_t i, j, m, n, r n = self._nrows - tm = verbose("Computing Hessenberg Normal Form of %sx%s matrix" % (n, n)) + tm = verbose("Computing Hessenberg Normal Form of %sx%s matrix"%(n,n)) if not self.is_square(): raise TypeError("self must be square") @@ -3551,20 +3544,20 @@ cdef class Matrix(Matrix1): if i != -1: # Found a nonzero entry in column m-1 that is strictly below row m # Now set i to be the first nonzero position >= m in column m-1 - if not self.get_is_zero_unsafe(m, m - 1): + if not self.get_is_zero_unsafe(m,m-1): i = m - t = self.get_unsafe(i, m - 1) + t = self.get_unsafe(i,m-1) t_inv = None if i > m: - self.swap_rows_c(i, m) + self.swap_rows_c(i,m) # We must do the corresponding column swap to # maintain the characteristic polynomial (which is # an invariant of Hessenberg form) - self.swap_columns_c(i, m) + self.swap_columns_c(i,m) # Now the nonzero entry in position (m,m-1) is t. # Use t to clear the entries in column m-1 below m. for j from m+1 <= j < n: - x = self.get_unsafe(j, m - 1) + x = self.get_unsafe(j, m-1) if x != zero: if t_inv is None: t_inv = one / t @@ -3575,7 +3568,7 @@ cdef class Matrix(Matrix1): # column m, and we're only worried about column m-1 right now. # Add u*column_j to column_m. self.add_multiple_of_column_c(m, j, u, 0) - verbose("Finished Hessenberg Normal Form of %sx%s matrix" % (n, n), tm) + verbose("Finished Hessenberg Normal Form of %sx%s matrix"%(n,n),tm) def _charpoly_hessenberg(self, var): """ @@ -3626,9 +3619,9 @@ cdef class Matrix(Matrix1): n = self._nrows cdef Matrix c - c = H.new_matrix(nrows=n + 1, ncols=n + 1) # the 0 matrix + c = H.new_matrix(nrows=n+1,ncols=n+1) # the 0 matrix one = H._coerce_element(1) - c.set_unsafe(0, 0, one) + c.set_unsafe(0,0,one) for m from 1 <= m <= n: # Set the m-th row of c to (x - H[m-1,m-1])*c[m-1] = x*c[m-1] - H[m-1,m-1]*c[m-1] @@ -3636,21 +3629,20 @@ cdef class Matrix(Matrix1): # shifted to the right by one. We then add # -H[m-1,m-1]*c[m-1] to the resulting m-th row. for i from 1 <= i <= n: - c.set_unsafe(m, i, c.get_unsafe(m - 1, i - 1)) - c.add_multiple_of_row_c(m, m-1, -H.get_unsafe(m - 1, m - 1), 0) + c.set_unsafe(m, i, c.get_unsafe(m-1,i-1)) + c.add_multiple_of_row_c(m, m-1, -H.get_unsafe(m-1, m-1), 0) t = one for i from 1 <= i < m: - t = t * H.get_unsafe(m - i, m - i - 1) + t = t * H.get_unsafe(m-i,m-i-1) # Set the m-th row of c to c[m] - t*H[m-i-1,m-1]*c[m-i-1] - c.add_multiple_of_row_c(m, m - i - 1, -t * H.get_unsafe(m - i - 1, m - 1), 0) + c.add_multiple_of_row_c(m, m-i-1, - t*H.get_unsafe(m-i-1,m-1), 0) # The answer is now the n-th row of c. v = PyList_New(n+1) # this is really sort of v = []..." for i from 0 <= i <= n: # Finally, set v[i] = c[n,i] - o = c.get_unsafe(n, i) - Py_INCREF(o) - PyList_SET_ITEM(v, i, o) + o = c.get_unsafe(n,i) + Py_INCREF(o); PyList_SET_ITEM(v, i, o) R = self._base_ring[var] # polynomial ring over the base ring return R(v) @@ -3768,12 +3760,12 @@ cdef class Matrix(Matrix1): [0 0 1] """ from sage.matrix.matrix_space import MatrixSpace - tm = verbose("computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) + tm = verbose("computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) basis = self.__pari__().matker() # Coerce PARI representations into the number field R = self.base_ring() basis = [[R(x) for x in row] for row in basis] - verbose("done computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) + verbose("done computing right kernel matrix over a number field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1,t=tm) return 'pivot-pari-numberfield', MatrixSpace(R, len(basis), ncols=self._ncols)(basis) def _right_kernel_matrix_over_field(self, *args, **kwds): @@ -3827,7 +3819,7 @@ cdef class Matrix(Matrix1): [0 0 1] """ from sage.matrix.matrix_space import MatrixSpace - tm = verbose("computing right kernel matrix over an arbitrary field for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) + tm = verbose("computing right kernel matrix over an arbitrary field for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) E = self.echelon_form(*args, **kwds) pivots = E.pivots() pivots_set = set(pivots) @@ -3856,7 +3848,7 @@ cdef class Matrix(Matrix1): basis.append(v) M = MS(basis, coerce=False) tm = verbose("done computing right kernel matrix over an arbitrary field for %sx%s matrix" - % (self.nrows(), self.ncols()), level=1, t=tm) + % (self.nrows(), self.ncols()),level=1,t=tm) return 'pivot-generic', M def _right_kernel_matrix_over_domain(self): @@ -3920,7 +3912,7 @@ cdef class Matrix(Matrix1): cdef Py_ssize_t i, nrows = self._nrows for i in range(self._ncols): if i >= nrows or d[i, i] == 0: - basis.append(v.column(i)) + basis.append( v.column(i) ) verbose("done computing right kernel matrix over a domain for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) return 'computed-smith-form', self.new_matrix(nrows=len(basis), ncols=self._ncols, entries=basis) @@ -4511,7 +4503,7 @@ cdef class Matrix(Matrix1): if algorithm is None: algorithm = 'default' elif algorithm not in ['default', 'generic', 'flint', 'pari', 'padic', 'pluq']: - raise ValueError("matrix kernel algorithm '%s' not recognized" % algorithm) + raise ValueError("matrix kernel algorithm '%s' not recognized" % algorithm ) elif algorithm == 'padic' and not (is_IntegerRing(R) or is_RationalField(R)): raise ValueError("'padic' matrix kernel algorithm only available over the rationals and the integers, not over %s" % R) elif algorithm == 'flint' and not (is_IntegerRing(R) or is_RationalField(R)): @@ -4528,7 +4520,7 @@ cdef class Matrix(Matrix1): if basis is None: basis = 'default' elif basis not in ['default', 'computed', 'echelon', 'pivot', 'LLL']: - raise ValueError("matrix kernel basis format '%s' not recognized" % basis) + raise ValueError("matrix kernel basis format '%s' not recognized" % basis ) elif basis == 'pivot' and R not in _Fields: raise ValueError('pivot basis only available over a field, not over %s' % R) elif basis == 'LLL' and not is_IntegerRing(R): @@ -4562,8 +4554,7 @@ cdef class Matrix(Matrix1): # Third: generic first, if requested explicitly # then try specialized class methods, and finally # delegate to ad-hoc methods in greater generality - M = None - format = '' + M = None; format = '' if algorithm == 'generic': format, M = self._right_kernel_matrix_over_field() @@ -4593,7 +4584,7 @@ cdef class Matrix(Matrix1): # zero columns as well. (eg PARI?) This could be fixed at the source # with a careful study of the phenomenon. Start by commenting out # the following and running doctests in sage/matrix - if M.nrows() == 0 and M.ncols() != self.ncols(): + if M.nrows()==0 and M.ncols()!=self.ncols(): M = M.new_matrix(nrows=0, ncols=self.ncols()) # Convert basis to requested type and return the matrix @@ -5156,10 +5147,10 @@ cdef class Matrix(Matrix1): if K is not None: return K - tm = verbose("computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()), level=1) + tm = verbose("computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1) K = self.transpose().right_kernel(*args, **kwds) self.cache('left_kernel', K) - verbose("done computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()), level=1, t=tm) + verbose("done computing left kernel for %sx%s matrix" % (self.nrows(), self.ncols()),level=1,t=tm) return K kernel = left_kernel @@ -5531,15 +5522,15 @@ cdef class Matrix(Matrix1): False) ] """ if algorithm == 'kernel' or self.base_ring() not in _Fields: - return self._decomposition_using_kernels(is_diagonalizable=is_diagonalizable, dual=dual) + return self._decomposition_using_kernels(is_diagonalizable = is_diagonalizable, dual=dual) elif algorithm == 'spin': - X = self._decomposition_spin_generic(is_diagonalizable=is_diagonalizable) + X = self._decomposition_spin_generic(is_diagonalizable = is_diagonalizable) if dual: - Y = self.transpose()._decomposition_spin_generic(is_diagonalizable=is_diagonalizable) + Y = self.transpose()._decomposition_spin_generic(is_diagonalizable = is_diagonalizable) return X, Y return X else: - raise ValueError("no algorithm '%s'" % algorithm) + raise ValueError("no algorithm '%s'"%algorithm) def _decomposition_spin_generic(self, is_diagonalizable=False): r""" @@ -5569,13 +5560,13 @@ cdef class Matrix(Matrix1): if len(F) == 1: V = self.base_ring()**self.nrows() - return decomp_seq([(V, F[0][1] == 1)]) + return decomp_seq([(V,F[0][1]==1)]) V = self.base_ring()**self.nrows() v = V.random_element() num_iterates = max([0] + [f.degree() - g.degree() for g, _ in F if g.degree() > 1]) + 1 - S = [] + S = [ ] F.sort() for i in range(len(F)): @@ -5585,11 +5576,11 @@ cdef class Matrix(Matrix1): # Just use kernel -- much easier. B = self.__copy__() for k from 0 <= k < self.nrows(): - B[k, k] += g[0] + B[k,k] += g[0] if m > 1 and not is_diagonalizable: B = B**m W = B.kernel() - E.append((W, m == 1)) + E.append((W, m==1)) continue # General case, i.e., deg(g) > 1: @@ -5602,40 +5593,40 @@ cdef class Matrix(Matrix1): v = h.list() while len(S) < tries: - t = verbose('%s-spinning %s-th random vector' % (num_iterates, len(S)), level=2, caller_name='generic spin decomp') + t = verbose('%s-spinning %s-th random vector'%(num_iterates, len(S)), level=2, caller_name='generic spin decomp') S.append(self.iterates(V.random_element(), num_iterates)) verbose('done spinning', level=2, t=t, caller_name='generic spin decomp') for j in range(0 if W is None else W.nrows() // g.degree(), len(S)): # Compute one element of the kernel of g(A)**m. - t = verbose('compute element of kernel of g(A), for g of degree %s' % g.degree(), level=2, + t = verbose('compute element of kernel of g(A), for g of degree %s'%g.degree(),level=2, caller_name='generic spin decomp') w = S[j].linear_combination_of_rows(h.list()) - t = verbose('done computing element of kernel of g(A)', t=t, level=2, caller_name='generic spin decomp') + t = verbose('done computing element of kernel of g(A)', t=t,level=2, caller_name='generic spin decomp') # Get the rest of the kernel. - t = verbose('fill out rest of kernel', level=2, caller_name='generic spin decomp') + t = verbose('fill out rest of kernel',level=2, caller_name='generic spin decomp') if W is None: W = self.iterates(w, g.degree()) else: W = W.stack(self.iterates(w, g.degree())) - t = verbose('finished filling out more of kernel', level=2, t=t, caller_name='generic spin decomp') + t = verbose('finished filling out more of kernel',level=2, t=t, caller_name='generic spin decomp') if W.rank() == m * g.degree(): t = verbose('now computing row space', level=2, caller_name='generic spin decomp') W.echelonize() - E.append((W.row_space(), m == 1)) - verbose('computed row space', level=2, t=t, caller_name='generic spin decomp') + E.append((W.row_space(), m==1)) + verbose('computed row space', level=2,t=t, caller_name='generic spin decomp') break else: - verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)' % ( + verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)'%( W.rank(), m*g.degree()), level=2, caller_name='generic spin decomp') tries += 1 if tries > 1000*m: # avoid an insanely long infinite loop raise RuntimeError("likely bug in decomposition") # end if - # end while - # end for + #end while + #end for return E def _decomposition_using_kernels(self, is_diagonalizable=False, dual=False): @@ -5659,30 +5650,30 @@ cdef class Matrix(Matrix1): V = self.column_ambient_module() m = F[0][1] if dual: - return decomp_seq([(V, m == 1)]), decomp_seq([(V, m == 1)]) + return decomp_seq([(V, m==1)]), decomp_seq([(V, m==1)]) else: - return decomp_seq([(V, m == 1)]) + return decomp_seq([(V, m==1)]) F.sort() for g, m in f.factor(): - t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s' % g.degree(), level=2) + t = verbose('decomposition -- Computing g(self) for an irreducible factor g of degree %s'%g.degree(),level=2) if is_diagonalizable: B = g(self) else: B = g(self) - t2 = verbose('decomposition -- raising g(self) to the power %s' % m, level=2) + t2 = verbose('decomposition -- raising g(self) to the power %s'%m,level=2) B = B ** m - verbose('done powering', t2) + verbose('done powering',t2) t = verbose('decomposition -- done computing g(self)', level=2, t=t) - E.append((B.kernel(), m == 1)) + E.append((B.kernel(), m==1)) t = verbose('decomposition -- time to compute kernel', level=2, t=t) if dual: - Edual.append((B.transpose().kernel(), m == 1)) + Edual.append((B.transpose().kernel(), m==1)) verbose('decomposition -- time to compute dual kernel', level=2, t=t) if dual: return E, Edual return E - def decomposition_of_subspace(self, M, check_restrict=True, **kwds): + def decomposition_of_subspace(self, M, check_restrict = True, **kwds): """ Suppose the right action of self on M leaves M invariant. Return the decomposition of M as a list of pairs (W, is_irred) where @@ -5758,7 +5749,7 @@ cdef class Matrix(Matrix1): if not self.is_square(): raise ArithmeticError("self must be a square matrix") if M.base_ring() != self.base_ring(): - raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s" % ( + raise ArithmeticError("base rings must be the same, but self is over %s and module is over %s"%( self.base_ring(), M.base_ring())) if M.degree() != self.ncols(): raise ArithmeticError("M must be a subspace of an %s-dimensional space" % self.ncols()) @@ -5766,18 +5757,16 @@ cdef class Matrix(Matrix1): time = verbose(t=0) # 1. Restrict - B = self.restrict(M, check=check_restrict) + B = self.restrict(M, check = check_restrict) time0 = verbose("decompose restriction -- ", time) # 2. Decompose restriction D = B.decomposition(**kwds) - sum_dim = sum([A.dimension() for A, _ in D]) + sum_dim = sum([A.dimension() for A,_ in D]) assert sum_dim == M.dimension(), \ "bug in decomposition; " + \ - "the sum of the dimensions (=%s) of the factors must equal" + \ - "the dimension (%s) of the acted on space:\nFactors found:" + \ - "%s\nSpace: %s" % (sum_dim, M.dimension(), D, M) + "the sum of the dimensions (=%s) of the factors must equal the dimension (%s) of the acted on space:\nFactors found: %s\nSpace: %s"%(sum_dim, M.dimension(), D, M) # 3. Lift decomposition to subspaces of ambient vector space. # Each basis vector for an element of D defines a linear @@ -5847,7 +5836,7 @@ cdef class Matrix(Matrix1): """ if not isinstance(V, sage.modules.free_module.FreeModule_generic): raise TypeError("V must be a free module") - # if V.base_ring() != self.base_ring(): + #if V.base_ring() != self.base_ring(): # raise ValueError("matrix and module must have the same base ring, but matrix is over %s and module is over %s"%(self.base_ring(), V.base_ring())) if V.degree() != self.nrows(): raise IndexError("degree of V (=%s) must equal number of rows of self (=%s)" % (V.degree(), self.nrows())) @@ -6029,8 +6018,7 @@ cdef class Matrix(Matrix1): sage: t.charpoly() # needs sage.libs.pari x^3 - 12*x^2 - 18*x """ - i = int(i) - t = int(t) + i = int(i); t=int(t) if self.nrows() != self.ncols(): raise ArithmeticError("self must be a square matrix") n = self.nrows() @@ -6435,7 +6423,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return x else: - return Sequence([(e[0], e[1]) for e in x], cr=True, check=False) + return Sequence([(e[0],e[1]) for e in x], cr=True, check=False) # Possible improvements: # algorithm for dual_eigenvector in sage/modular/hecke/module.py @@ -6447,7 +6435,7 @@ cdef class Matrix(Matrix1): G = self.fcp() # factored characteristic polynomial V = [] - i = -1 # variable name index, increments for each eigenvalue + i = -1 # variable name index, increments for each eigenvalue for h, e in G: i = i + 1 if h.degree() == 1: @@ -6459,7 +6447,7 @@ cdef class Matrix(Matrix1): W = A.kernel() V.append((alpha, W.ambient_module().span_of_basis(W.basis()), e)) else: - F = h.root_field('{0}{1}'.format(var, i)) + F = h.root_field('{0}{1}'.format(var,i)) alpha = F.gen(0) A = self.change_ring(F) - alpha W = A.kernel() @@ -6483,7 +6471,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return V else: - return Sequence([(e[0], e[1]) for e in V], cr=True, check=False) + return Sequence([(e[0],e[1]) for e in V], cr=True, check=False) left_eigenspaces = eigenspaces_left @@ -6687,7 +6675,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return x else: - return Sequence([(e[0], e[1]) for e in x], cr=True, check=False) + return Sequence([(e[0],e[1]) for e in x], cr=True, check=False) V = self.transpose().eigenspaces_left(format=format, var=var, algebraic_multiplicity=True) @@ -6695,7 +6683,7 @@ cdef class Matrix(Matrix1): if algebraic_multiplicity: return V else: - return Sequence([(e[0], e[1]) for e in V], cr=True, check=False) + return Sequence([(e[0],e[1]) for e in V], cr=True, check=False) right_eigenspaces = eigenspaces_right @@ -6808,7 +6796,7 @@ cdef class Matrix(Matrix1): warn("Using generic algorithm for an inexact ring, which will probably give incorrect results due to numerical precision issues.") if not extend: - return Sequence(r for r, m in self.charpoly().roots() for _ in range(m)) + return Sequence(r for r,m in self.charpoly().roots() for _ in range(m)) # now we need to find a natural algebraic closure for the base ring K = self.base_ring() @@ -6828,7 +6816,7 @@ cdef class Matrix(Matrix1): if f.degree() == 1: res.extend([-f.constant_coefficient()]*e) else: - for r, ee in f.change_ring(A).roots(): + for r,ee in f.change_ring(A).roots(): res.extend([r]*(e*ee)) eigenvalues = Sequence(res) @@ -6938,7 +6926,7 @@ cdef class Matrix(Matrix1): from sage.categories.homset import hom eigenspaces = self.eigenspaces_left(format='galois', algebraic_multiplicity=True) - evec_list = [] + evec_list=[] n = self._nrows evec_eval_list = [] F = self.base_ring().fraction_field() @@ -6960,7 +6948,7 @@ cdef class Matrix(Matrix1): m = hom(eigval.parent(), e.parent(), e) space = (e.parent())**n evec_list = [(space)([m(i) for i in v]) for v in eigbasis] - evec_eval_list.append((e, evec_list, eigmult)) + evec_eval_list.append( (e, evec_list, eigmult)) return evec_eval_list @@ -7242,7 +7230,7 @@ cdef class Matrix(Matrix1): "failed to compute eigenvectors for eigenvalue %s, " "check eigenvectors_left() for partial results" % e[0]) P = matrix(rows) - return D, P + return D,P left_eigenmatrix = eigenmatrix_left @@ -7410,9 +7398,9 @@ cdef class Matrix(Matrix1): True """ - D, P = self.transpose().eigenmatrix_left(None if other is None - else other.transpose()) - return D, P.transpose() + D,P = self.transpose().eigenmatrix_left(None if other is None + else other.transpose()) + return D,P.transpose() right_eigenmatrix = eigenmatrix_right @@ -7628,7 +7616,7 @@ cdef class Matrix(Matrix1): d = self.dense_matrix().echelon_form(**kwds) for c from 0 <= c < self.ncols(): for r from 0 <= r < self.nrows(): - self.set_unsafe(r, c, d.get_unsafe(r, c)) + self.set_unsafe(r, c, d.get_unsafe(r,c)) self.clear_cache() self.cache('pivots', d.pivots()) self.cache('in_echelon_form', True) @@ -7636,11 +7624,11 @@ cdef class Matrix(Matrix1): try: a, d, p = self._echelon_form_PID() except TypeError as msg: - raise NotImplementedError("%s\nechelon form over %s not yet implemented" % (msg, self.base_ring())) + raise NotImplementedError("%s\nechelon form over %s not yet implemented"%(msg, self.base_ring())) for c from 0 <= c < self.ncols(): for r from 0 <= r < self.nrows(): - self.set_unsafe(r, c, d.get_unsafe(r, c)) + self.set_unsafe(r, c, d.get_unsafe(r,c)) self.clear_cache() self.cache('pivots', tuple(p)) self.cache('in_echelon_form', True) @@ -7840,7 +7828,7 @@ cdef class Matrix(Matrix1): kwds['algorithm'] = algorithm return self._echelonize_ring(**kwds) except ArithmeticError as msg: - raise NotImplementedError("%s\nEchelon form not implemented over '%s'." % (msg, basring)) + raise NotImplementedError("%s\nEchelon form not implemented over '%s'."%(msg,basring)) def echelon_form(self, algorithm="default", cutoff=0, **kwds): r""" @@ -7935,7 +7923,7 @@ cdef class Matrix(Matrix1): if algorithm == 'default': v = E.echelonize(cutoff=cutoff, **kwds) else: - v = E.echelonize(algorithm=algorithm, cutoff=cutoff, **kwds) + v = E.echelonize(algorithm = algorithm, cutoff=cutoff, **kwds) E.set_immutable() # so we can cache the echelon form. self.cache('echelon_form', E) if v is not None: @@ -8137,21 +8125,21 @@ cdef class Matrix(Matrix1): if algorithm == 'partial_pivoting': for r in range(start_row, nr): - abs_val = A.get_unsafe(r, c).abs() + abs_val = A.get_unsafe(r,c).abs() if abs_val > max_abs_val: max_abs_val = abs_val best_r = r elif algorithm == 'scaled_partial_pivoting': for r in range(start_row, nr): if scale_factors[r]: - abs_val = A.get_unsafe(r, c).abs() / scale_factors[r] + abs_val = A.get_unsafe(r,c).abs() / scale_factors[r] if abs_val > max_abs_val: max_abs_val = abs_val best_r = r - else: # algorithm == 'scaled_partial_pivoting_valuation': + else: # algorithm == 'scaled_partial_pivoting_valuation': for r in range(start_row, nr): if scale_factors[r] is not None: - abs_val = scale_factors[r] - A.get_unsafe(r, c).valuation() + abs_val = scale_factors[r] - A.get_unsafe(r,c).valuation() if max_abs_val is None or abs_val > max_abs_val: max_abs_val = abs_val best_r = r @@ -8493,7 +8481,7 @@ cdef class Matrix(Matrix1): permutations.append( (PermutationGroupElement([p(1 + i) for i in range(nrows)]), PermutationGroupElement([p(1 + nrows + i) - nrows for i in range(ncols)]) - )) + )) return permutations def permutation_normal_form(self, check=False): @@ -8600,14 +8588,14 @@ cdef class Matrix(Matrix1): # Sort each row with respect to S for the first matrix in X = MS X = copy(MS) SM = [sorted([(S[j], X[0][k][j]) for j in range(ncols)], reverse=True) - for k in range(l, nrows)] + for k in range(l, nrows)] SM = [[k[1] for k in s] for s in SM] # and pick the maximal row b = max(SM) # Find all rows equal to the maximal (potential new cases) m = [[j for j in range(nrows - l) if SM[j] == b]] - w = 0 # keeps track of how many entries we have removed from MS + w = 0 # keeps track of how many entries we have removed from MS # Let us find the maximal row in each of the entries in X = MS for i in range(1, len(X)): SN = [sorted([(S[j], X[i][k][j]) for j in range(ncols)], reverse=True) @@ -8743,7 +8731,7 @@ cdef class Matrix(Matrix1): truth, perm = N_B.is_isomorphic(M_B, certificate=True, edge_labels=True) from sage.groups.perm_gps.constructor import PermutationGroupElement if perm: - s = sorted(perm.items(), key=lambda x: x[0]) + s = sorted(perm.items(), key=lambda x:x[0]) row_perms = [value for k, value in s if k <= nrows] col_perms = [value - nrows for k, value in s if k > nrows] perm = (PermutationGroupElement(row_perms), PermutationGroupElement(col_perms)) @@ -8794,15 +8782,16 @@ cdef class Matrix(Matrix1): output = self.new_matrix(self._nrows, right._ncols) # The following used to be a little faster, but meanwhile # the previous line is faster. - # if self.is_sparse(): + #if self.is_sparse(): # output = self.matrix_space(self._nrows, right._ncols, sparse = True)(0) - # else: + #else: # output = self.matrix_space(self._nrows, right._ncols, sparse = False).zero_matrix().__copy__() - self_window = self.matrix_window() - right_window = right.matrix_window() + self_window = self.matrix_window() + right_window = right.matrix_window() output_window = output.matrix_window() + from . import strassen strassen.strassen_window_multiply(output_window, self_window, right_window, cutoff) return output @@ -8824,7 +8813,7 @@ cdef class Matrix(Matrix1): [ 0 0 0 0] [ 0 0 0 0] """ - tm = verbose('strassen echelon of %s x %s matrix' % (self._nrows, self._ncols)) + tm = verbose('strassen echelon of %s x %s matrix'%(self._nrows, self._ncols)) self.check_mutability() @@ -8847,8 +8836,8 @@ cdef class Matrix(Matrix1): verbose('done with strassen', tm) cpdef matrix_window(self, Py_ssize_t row=0, Py_ssize_t col=0, - Py_ssize_t nrows=-1, Py_ssize_t ncols=-1, - bint check=1): + Py_ssize_t nrows=-1, Py_ssize_t ncols=-1, + bint check=1): """ Return the requested matrix window. @@ -9102,7 +9091,7 @@ cdef class Matrix(Matrix1): """ if self._subdivisions is None: self._subdivisions = ([0, self._nrows], [0, self._ncols]) - key = "subdivision %s %s" % (i, j) + key = "subdivision %s %s"%(i,j) sd = self.fetch(key) if sd is None: sd = self[self._subdivisions[0][i]:self._subdivisions[0][i+1], @@ -9148,13 +9137,13 @@ cdef class Matrix(Matrix1): """ if self._subdivisions is None: if not i and not j: - return self[x, y] + return self[x,y] else: - raise IndexError("No such submatrix %s, %s" % (i, j)) + raise IndexError("No such submatrix %s, %s"%(i,j)) if x >= self._subdivisions[0][i+1]-self._subdivisions[0][i] or \ y >= self._subdivisions[1][j+1]-self._subdivisions[1][j]: - raise IndexError("Submatrix %s,%s has no entry %s,%s" % (i, j, x, y)) - return self[self._subdivisions[0][i] + x, self._subdivisions[1][j] + y] + raise IndexError("Submatrix %s,%s has no entry %s,%s"%(i,j, x, y)) + return self[self._subdivisions[0][i] + x , self._subdivisions[1][j] + y] def _subdivide_on_augment(self, left, right): r""" @@ -9465,7 +9454,7 @@ cdef class Matrix(Matrix1): for i from 0 <= i < self._nrows: for j from 0 <= j < self._ncols: self.set_unsafe(i, j, R._random_nonzero_element(*args, - **kwds)) + **kwds)) else: num = int(self._nrows * self._ncols * density) for i from 0 <= i < num: @@ -9505,7 +9494,7 @@ cdef class Matrix(Matrix1): """ return self.is_scalar(self.base_ring().one()) - def is_scalar(self, a=None): + def is_scalar(self, a = None): """ Return True if this matrix is a scalar matrix. @@ -9540,13 +9529,13 @@ cdef class Matrix(Matrix1): if a is None: if self._nrows == 0: return True - a = self.get_unsafe(0, 0) + a = self.get_unsafe(0,0) else: a = self.base_ring()(a) for i in range(self._nrows): for j in range(self._ncols): if i != j: - if not self.get_unsafe(i, j).is_zero(): + if not self.get_unsafe(i,j).is_zero(): return False else: if self.get_unsafe(i, i) != a: @@ -9583,7 +9572,7 @@ cdef class Matrix(Matrix1): for i in range(self._nrows): for j in range(self._ncols): if i != j: - if not self.get_unsafe(i, j).is_zero(): + if not self.get_unsafe(i,j).is_zero(): return False return True @@ -9693,7 +9682,7 @@ cdef class Matrix(Matrix1): P = self.transpose() * self # Orthogonal return P.is_scalar(1) - def is_bistochastic(self, normalized=True): + def is_bistochastic(self, normalized = True): r""" Returns ``True`` if this matrix is bistochastic. @@ -9856,12 +9845,12 @@ cdef class Matrix(Matrix1): cdef Matrix left = self*CT cdef Matrix right = CT*self - cdef Py_ssize_t i, j + cdef Py_ssize_t i,j normal = True # two products are Hermitian, need only check lower triangle for i from 0 <= i < self._nrows: for j from 0 <= j <= i: - if left.get_unsafe(i, j) != right.get_unsafe(i, j): + if left.get_unsafe(i,j) != right.get_unsafe(i,j): normal = False break if not normal: @@ -9978,11 +9967,11 @@ cdef class Matrix(Matrix1): ir = mc ic = mr b = 1.0 - elif max(mr, mc) > maxsize: + elif max(mr,mc) > maxsize: maxsize = float(maxsize) - ir = int(mc * maxsize / max(mr, mc)) - ic = int(mr * maxsize / max(mr, mc)) - b = max(mr, mc) / maxsize + ir = int(mc * maxsize/max(mr,mc)) + ic = int(mr * maxsize/max(mr,mc)) + b = max(mr,mc)/maxsize else: ir = mc ic = mr @@ -9999,7 +9988,7 @@ cdef class Matrix(Matrix1): for _x in range(bi): for _y in range(bi): if not self.get_unsafe((x*b + _x), (y*b + _y)).is_zero(): - v -= 1 # increase darkness + v -= 1 #increase darkness v = (v * fct + 0.5) pixel[y, x] = (v, v, v) return img @@ -10035,7 +10024,7 @@ cdef class Matrix(Matrix1): sage: a.density() 0 """ - cdef int x, y, k + cdef int x,y,k k = 0 nr = self.nrows() nc = self.ncols() @@ -10043,8 +10032,8 @@ cdef class Matrix(Matrix1): return 0 for x from 0 <= x < nr: for y from 0 <= y < nc: - if not self.get_unsafe(x, y).is_zero(): - k += 1 + if not self.get_unsafe(x,y).is_zero(): + k+=1 return QQ(k)/QQ(nr*nc) def inverse(self): @@ -10264,13 +10253,13 @@ cdef class Matrix(Matrix1): This is all left to the method `adjugate`. """ - n = self._ncols + n = self._ncols if self._nrows != n: raise ValueError("self must be a square matrix") A = self.charpoly().shift(-1)(self) - return A if n % 2 else -A + return A if n%2 else -A def QR(self, full=True): r""" @@ -10540,16 +10529,16 @@ cdef class Matrix(Matrix1): scale = sqrt(hip) q = (1/scale)*v Q.append(q) - R[row, i] = scale - for j in range(i + 1, n): - R[row, j] = q.hermitian_inner_product(V[j]) - V[j] = V[j] - R[row, j] * q + R[row,i] = scale + for j in range(i+1, n): + R[row,j] = q.hermitian_inner_product(V[j]) + V[j] = V[j] - R[row,j]*q row = row + 1 except TypeError: raise TypeError('QR decomposition unable to compute square roots in %s' % F) # complete to full orthonormal basis, or reduce to truncated R if full: - Qt = matrix(Q) # as rows here + Qt = matrix(Q) # as rows here if Qt.nrows() == 0: Qt = zero_matrix(F, 0, m) orthogonal = Qt.right_kernel().basis_matrix().transpose() @@ -10698,12 +10687,12 @@ cdef class Matrix(Matrix1): zero = F(0) Bstar = [] R = zero_matrix(F, n) - nnz = 0 # number non-zero rows in R, or number of nonzero vectors in Bstar + nnz = 0 # number non-zero rows in R, or number of nonzero vectors in Bstar for i in range(n): ortho = B[i] for j in range(nnz): - R[j, i] = Bstar[j].hermitian_inner_product(B[i]) / Bstar[j].hermitian_inner_product(Bstar[j]) - ortho = ortho - R[j, i] * Bstar[j] + R[j,i] = Bstar[j].hermitian_inner_product(B[i])/Bstar[j].hermitian_inner_product(Bstar[j]) + ortho = ortho - R[j,i]*Bstar[j] if ortho.hermitian_inner_product(ortho) != zero: Bstar.append(ortho) R[nnz, i] = 1 @@ -11039,8 +11028,7 @@ cdef class Matrix(Matrix1): R = self.base_ring() if isinstance(R, (sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): Q, R = self.transpose().QR() - m = R.nrows() - n = R.ncols() + m = R.nrows(); n = R.ncols() if m > n: Q = Q[0:m, 0:n] R = R[0:n, 0:n] @@ -11477,7 +11465,7 @@ cdef class Matrix(Matrix1): blocks = [] for eval, mult in evals: if mult == 1: - blocks.append((eval, 1)) + blocks.append((eval,1)) else: B = A - diagonal_matrix([eval]*n, sparse=sparse) C = B @@ -11506,7 +11494,7 @@ cdef class Matrix(Matrix1): # a Jordan chain for each, adding the chain (a sequence of # vectors) to the entry for the eigenvalue (which is a list). jordan_chains = {} - for eval, _ in evals: + for eval,_ in evals: jordan_chains[eval] = [] # Let B be the matrix `A - eval Id`. @@ -11544,9 +11532,9 @@ cdef class Matrix(Matrix1): # Now ``jordan_chains`` has all the columns of the transformation # matrix; we just need to put them in the right order. jordan_basis = [] - for eval, size in blocks: + for eval,size in blocks: # Find a block with the right size - for index, chain in enumerate(jordan_chains[eval]): + for index,chain in enumerate(jordan_chains[eval]): if len(chain) == size: jordan_basis += jordan_chains[eval].pop(index) break @@ -12604,7 +12592,7 @@ cdef class Matrix(Matrix1): R = self.base_ring() if not is_Vector(v): raise TypeError('first input should be a vector, not {0}'.format(v)) - if not (var is None or isinstance(var, str)): + if not (var is None or isinstance(var, str)): generator = False try: generator = var.is_gen() @@ -12923,7 +12911,7 @@ cdef class Matrix(Matrix1): True """ - cdef Matrix C # output matrix + cdef Matrix C # output matrix C = self.fetch('cholesky') if C is not None: return C @@ -12945,7 +12933,7 @@ cdef class Matrix(Matrix1): cdef Matrix L # block_ldlt() results cdef list d # block_ldlt() results try: - _, L, d = self._block_ldlt(True) + _,L,d = self._block_ldlt(True) except ValueError: # If the matrix was positive-definite, that would # have worked. @@ -12958,7 +12946,7 @@ cdef class Matrix(Matrix1): cdef bint extend = False for X in d: # The X are guaranteed to be one-by-one blocks. - x = X[0, 0] + x = X[0,0] if x <= zero: raise ValueError("matrix is not positive definite") @@ -12985,7 +12973,7 @@ cdef class Matrix(Matrix1): from sage.rings.qqbar import AA try: C = L.change_ring(AA) - except ValueError: # cannot coerce... + except ValueError: # cannot coerce... C = L.change_ring(F_ac) else: C = L.__copy__() @@ -12993,11 +12981,11 @@ cdef class Matrix(Matrix1): # Overwrite the (strict) upper-triangular part of "C", since a # priori it contains junk after _block_ldlt(). zero = C.base_ring().zero() - cdef Py_ssize_t i, j # loop indices + cdef Py_ssize_t i, j # loop indices for i in range(n): C.rescale_col_c(i, splits[i], 0) - for j in range(i + 1, n): - C.set_unsafe(i, j, zero) + for j in range(i+1,n): + C.set_unsafe(i,j,zero) C.set_immutable() self.cache('cholesky', C) return C @@ -13117,7 +13105,7 @@ cdef class Matrix(Matrix1): sage: actual == expected True """ - P, L, D = self.block_ldlt() + P,L,D = self.block_ldlt() # The default "echelonize" inverse() method works just fine for # triangular matrices. @@ -13570,24 +13558,24 @@ cdef class Matrix(Matrix1): # abs() necessary to convert zero to the # correct type for comparisons (Issue #12208) max_entry = abs(zero) - for i in range(k, m): - entry = abs(M.get_unsafe(i, k)) + for i in range(k,m): + entry = abs(M.get_unsafe(i,k)) if entry > max_entry: max_location = i max_entry = entry else: - for i in range(k, m): - if M.get_unsafe(i, k) != zero: + for i in range(k,m): + if M.get_unsafe(i,k) != zero: max_location = i break if max_location != -1: perm[k], perm[max_location] = perm[max_location], perm[k] M.swap_rows(k, max_location) for j in range(k+1, m): - scale = -M.get_unsafe(j, k) / M.get_unsafe(k, k) - M.set_unsafe(j, k, -scale) - for p in range(k + 1, n): - M.set_unsafe(j, p, M.get_unsafe(j, p) + scale * M.get_unsafe(k, p)) + scale = -M.get_unsafe(j,k)/M.get_unsafe(k,k) + M.set_unsafe(j,k, -scale) + for p in range(k+1,n): + M.set_unsafe(j,p, M.get_unsafe(j,p) + scale*M.get_unsafe(k,p)) perm = tuple(perm) M.set_immutable() compact = (perm, M) @@ -13606,11 +13594,11 @@ cdef class Matrix(Matrix1): perm = [perm[i]+1 for i in range(m)] P = sage.combinat.permutation.Permutation(perm).to_matrix() P = P.change_ring(F) - L = M.matrix_space(m, m).identity_matrix().__copy__() + L = M.matrix_space(m,m).identity_matrix().__copy__() for i in range(1, m): - for k in range(min(i, d)): - L[i, k] = M[i, k] - M[i, k] = zero + for k in range(min(i,d)): + L[i,k] = M[i,k] + M[i,k] = zero return P, L, M def _indefinite_factorization(self, algorithm, check=True): @@ -13852,16 +13840,16 @@ cdef class Matrix(Matrix1): t = L.get_unsafe(i, j) if conjugate: for k in range(j): - t -= L.get_unsafe(k, i) * L.get_unsafe(j, k).conjugate() + t -= L.get_unsafe(k,i)*L.get_unsafe(j,k).conjugate() else: for k in range(j): - t -= L.get_unsafe(k, i) * L.get_unsafe(j, k) + t -= L.get_unsafe(k,i)*L.get_unsafe(j,k) if i == j: if not t: - self.cache(cache_string, (False, i + 1)) - return (False, i + 1) + self.cache(cache_string, (False,i+1)) + return (False, i+1) d.append(t) - d_inv.append(one / t) + d_inv.append(one/t) L.set_unsafe(i, i, one) else: L.set_unsafe(j, i, t) @@ -14077,7 +14065,7 @@ cdef class Matrix(Matrix1): if result is not None: return result - cdef Py_ssize_t i, j, k # loop indices + cdef Py_ssize_t i, j, k # loop indices cdef Py_ssize_t r # another row/column index # We need to construct 1x1 and 2x2 matrices to stick in d. @@ -14101,7 +14089,7 @@ cdef class Matrix(Matrix1): # at the end of the function, not as its columns are computed. ring = self.base_ring().fraction_field() - cdef Matrix A # A copy of the input matrix + cdef Matrix A # A copy of the input matrix if self.base_ring() == ring: A = self.__copy__() else: @@ -14139,7 +14127,7 @@ cdef class Matrix(Matrix1): cdef list d = [] # And the parent of those diagonal blocks that are 1x1... - one_by_one_space = A.matrix_space(1, 1) + one_by_one_space = A.matrix_space(1,1) # The case n == 0 is *almost* handled by skipping the # forthcoming loop entirely. However, we must stick a trivial @@ -14155,7 +14143,7 @@ cdef class Matrix(Matrix1): # where we're storing the next iterate. So our indices are # always "k" greater than those of Higham or B&K. - A_kk = A.get_unsafe(k, k) + A_kk = A.get_unsafe(k,k) if k == (n-1): # Handle this trivial case manually, since otherwise the @@ -14163,7 +14151,7 @@ cdef class Matrix(Matrix1): # meaningless. The corresponding entry of "L" will be # fixed later (since it's an on-diagonal element, it gets # set to one eventually). - d.append(one_by_one_space(A_kk)) + d.append( one_by_one_space(A_kk) ) k += 1 continue @@ -14173,8 +14161,8 @@ cdef class Matrix(Matrix1): # It's a back door that lets us escape with only the standard non-block # non-pivoting LDL^T factorization. This allows us to implement e.g. # indefinite_factorization() in terms of this method. - d.append(one_by_one_space(A_kk)) - _block_ldlt_pivot1x1(A, k) + d.append( one_by_one_space(A_kk) ) + _block_ldlt_pivot1x1(A,k) k += 1 continue except ZeroDivisionError: @@ -14189,8 +14177,8 @@ cdef class Matrix(Matrix1): # Note: omega_1 is defined as a C double, but the abs() # below would make a complex number approximate anyway. omega_1 = 0 - for i in range(k + 1, n): - a_ik_abs = A.get_unsafe(i, k).abs() + for i in range(k+1,n): + a_ik_abs = A.get_unsafe(i,k).abs() if a_ik_abs > omega_1: omega_1 = a_ik_abs # We record the index "r" that corresponds to @@ -14210,7 +14198,7 @@ cdef class Matrix(Matrix1): # the 1x1 pivot "a" in the top-left position. The entry "a" # will be adjusted to "1" later on to ensure that "L" is # (block) unit-lower-triangular. - d.append(one_by_one_space(A_kk)) + d.append( one_by_one_space(A_kk) ) k += 1 continue @@ -14222,8 +14210,8 @@ cdef class Matrix(Matrix1): # otherwise. We are performing a 1x1 pivot, but the # rows/columns are already where we want them, so nothing # needs to be permuted. - d.append(one_by_one_space(A_kk)) - _block_ldlt_pivot1x1(A, k) + d.append( one_by_one_space(A_kk) ) + _block_ldlt_pivot1x1(A,k) k += 1 continue @@ -14237,30 +14225,27 @@ cdef class Matrix(Matrix1): # Note: omega_r is defined as a C double, but the abs() # below would make a complex number approximate anyway. omega_r = 0 - for j in range(k, r): - a_rj_abs = A.get_unsafe(r, j).abs() + for j in range(k,r): + a_rj_abs = A.get_unsafe(r,j).abs() if a_rj_abs > omega_r: omega_r = a_rj_abs if A_kk.abs()*omega_r >= alpha*(omega_1**2): # Step (2) in Higham or Step (4) in B&K. - d.append(one_by_one_space(A_kk)) - _block_ldlt_pivot1x1(A, k) + d.append( one_by_one_space(A_kk) ) + _block_ldlt_pivot1x1(A,k) k += 1 continue - A_rr = A.get_unsafe(r, r) + A_rr = A.get_unsafe(r,r) if A_rr.abs() > alpha*omega_r: # This is Step (3) in Higham or Step (5) in B&K. Still # a 1x1 pivot, but this time we need to swap # rows/columns k and r. - d.append(one_by_one_space(A_rr)) - A.swap_columns_c(k, r) - A.swap_rows_c(k, r) - p_k = p[k] - p[k] = p[r] - p[r] = p_k - _block_ldlt_pivot1x1(A, k) + d.append( one_by_one_space(A_rr) ) + A.swap_columns_c(k,r); A.swap_rows_c(k,r) + p_k = p[k]; p[k] = p[r]; p[r] = p_k + _block_ldlt_pivot1x1(A,k) k += 1 continue @@ -14268,19 +14253,16 @@ cdef class Matrix(Matrix1): # or Step (6) in B&K, where we perform a 2x2 pivot. See # pivot1x1() for an explanation of why it's OK to permute # the entries of "L" here as well. - A.swap_columns_c(k + 1, r) - A.swap_rows_c(k + 1, r) - p_k = p[k + 1] - p[k + 1] = p[r] - p[r] = p_k + A.swap_columns_c(k+1,r); A.swap_rows_c(k+1,r) + p_k = p[k+1]; p[k+1] = p[r]; p[r] = p_k # The top-left 2x2 submatrix (starting at position k,k) is # now our pivot. - E = A[k: k + 2, k: k + 2] + E = A[k:k+2,k:k+2] d.append(E) - C = A[k + 2: n, k: k + 2] - B = A[k + 2:, k+2:] + C = A[k+2:n,k:k+2] + B = A[k+2:,k+2:] # We don't actually need the inverse of E, what we really need # is C*E.inverse(), and that can be found by setting @@ -14297,10 +14279,10 @@ cdef class Matrix(Matrix1): # Compute the Schur complement that we'll work on during # the following iteration, and store it back in the lower- # right-hand corner of "A". - for i in range(n - k - 2): - for j in range(i + 1): - A.set_unsafe(k + 2 + i, k + 2 + j, schur_complement[i, j]) - A.set_unsafe(k + 2 + j, k + 2 + i, schur_complement[j, i]) + for i in range(n-k-2): + for j in range(i+1): + A.set_unsafe(k+2+i, k+2+j, schur_complement[i,j]) + A.set_unsafe(k+2+j, k+2+i, schur_complement[j,i]) # The on- and above-diagonal entries of "L" will be fixed # later, so we only need to worry about the lower-left entry @@ -14311,7 +14293,8 @@ cdef class Matrix(Matrix1): for j in range(2): # Store the new (k and (k+1)st) columns of "L" within # the lower-left-hand corner of "A". - A.set_unsafe(k+i+2, k+j, CE_inverse[i, j]) + A.set_unsafe(k+i+2, k+j, CE_inverse[i,j]) + k += 2 @@ -14320,7 +14303,7 @@ cdef class Matrix(Matrix1): # correctness. A.set_unsafe(i, i, one) - result = (p, A, d) + result = (p,A,d) self.cache(cache_string, result) return result @@ -14625,12 +14608,12 @@ cdef class Matrix(Matrix1): """ cdef Py_ssize_t n # size of the matrices - cdef Py_ssize_t i, j # loop indices - cdef Matrix P, L, D # output matrices + cdef Py_ssize_t i, j # loop indices + cdef Matrix P,L,D # output matrices - p, L, d = self._block_ldlt(classical) + p,L,d = self._block_ldlt(classical) MS = L.matrix_space() - P = MS.matrix(lambda i, j: p[j] == i) + P = MS.matrix(lambda i,j: p[j] == i) # Warning: when n == 0, this works, but returns a matrix # whose (nonexistent) entries are in ZZ rather than in @@ -14643,10 +14626,11 @@ cdef class Matrix(Matrix1): n = L._nrows zero = MS.base_ring().zero() for i in range(n): - for j in range(i + 1, n): - L.set_unsafe(i, j, zero) + for j in range(i+1,n): + L.set_unsafe(i,j,zero) + + return (P,L,D) - return (P, L, D) cdef bint _is_positive_definite_or_semidefinite(self, bint semi) except -1: """ @@ -14656,7 +14640,7 @@ cdef class Matrix(Matrix1): code. The boolean ``semi`` argument exists only to change "greater than zero" into "greater than or equal to zero." """ - from sage.rings.real_lazy import RLF, CLF + from sage.rings.real_lazy import RLF,CLF R = self.base_ring() @@ -14676,10 +14660,10 @@ cdef class Matrix(Matrix1): return False if self._nrows == 0: - return True # vacuously + return True # vacuously cdef list d - _, _, d = self._block_ldlt(False) + _,_,d = self._block_ldlt(False) # Check each 1x1 block for a nonpositive (negative) entry. If # we don't find any, the matrix is positive-(semi)definite. The @@ -14689,7 +14673,8 @@ cdef class Matrix(Matrix1): if semi: op = operator.ge - return all(d_i.nrows() == 1 and op(d_i[0, 0], 0) for d_i in d) + return all(d_i.nrows() == 1 and op(d_i[0,0], 0) for d_i in d) + def is_positive_semidefinite(self): r""" @@ -15001,7 +14986,7 @@ cdef class Matrix(Matrix1): result = self._is_positive_definite_or_semidefinite(False) if certificate: from sage.misc.superseded import deprecation - msg = "the 'certificate' argument is deprecated; if you " + msg = "the 'certificate' argument is deprecated; if you " msg += "need the corresponding factorization, you can " msg += "simply compute it yourself (the results are cached)" deprecation(31619, msg) @@ -15009,7 +14994,7 @@ cdef class Matrix(Matrix1): d = None if result: from sage.modules.free_module_element import vector - _, L, D = self.block_ldlt() + _,L,D = self.block_ldlt() d = vector(D.base_ring(), D.diagonal()) return (result, L, d) else: @@ -15090,7 +15075,7 @@ cdef class Matrix(Matrix1): m2 = hadamard_row_bound_mpfr(A) return min(m1, m2) - def find(self, f, indices=False): + def find(self,f, indices=False): r""" Find elements in this matrix satisfying the constraints in the function `f`. The function is evaluated on each element of @@ -15156,7 +15141,7 @@ cdef class Matrix(Matrix1): True """ from sage.matrix.matrix_space import MatrixSpace - cdef Py_ssize_t size, i, j + cdef Py_ssize_t size,i,j cdef object M if not indices: @@ -15165,20 +15150,20 @@ cdef class Matrix(Matrix1): M = PyList_New(0) for i from 0 <= i < size: - PyList_Append(M, f(PyList_GET_ITEM(L, i))) + PyList_Append(M,f(PyList_GET_ITEM(L,i))) from sage.rings.finite_rings.integer_mod_ring import IntegerModRing return MatrixSpace(IntegerModRing(2), - nrows=self._nrows, ncols=self._ncols).matrix(M) + nrows=self._nrows,ncols=self._ncols).matrix(M) else: # return matrix along with indices in a dictionary d = {} for i from 0 <= i < self._nrows: for j from 0 <= j < self._ncols: - if f(self.get_unsafe(i, j)): - d[(i, j)] = self.get_unsafe(i, j) + if f(self.get_unsafe(i,j)): + d[(i,j)] = self.get_unsafe(i,j) return d @@ -15669,7 +15654,7 @@ cdef class Matrix(Matrix1): """ d = self.smith_form(transformation=False) r = min(self.nrows(), self.ncols()) - return [d[i, i] for i in range(r)] + return [d[i,i] for i in range(r)] def smith_form(self, transformation=True, integral=None, exact=True): r""" @@ -15893,19 +15878,19 @@ cdef class Matrix(Matrix1): raise NotImplementedError("Smith form over non-exact rings not implemented at present") # first clear the first row and column - u, t, v = _smith_onestep(self) + u,t,v = _smith_onestep(self) # now recurse: t now has a nonzero entry at 0,0 and zero entries in the rest # of the 0th row and column, so we apply smith_form to the smaller submatrix - mm = t.submatrix(1, 1) + mm = t.submatrix(1,1) if transformation: dd, uu, vv = mm.smith_form(transformation=True) else: dd = mm.smith_form(transformation=False) - d = dd.new_matrix(1, 1, [t[0, 0]]).block_sum(dd) + d = dd.new_matrix(1,1,[t[0,0]]).block_sum(dd) if transformation: - u = uu.new_matrix(1, 1, [1]).block_sum(uu) * u - v = v * vv.new_matrix(1, 1, [1]).block_sum(vv) + u = uu.new_matrix(1,1,[1]).block_sum(uu) * u + v = v * vv.new_matrix(1,1,[1]).block_sum(vv) dp, up, vp = _smith_diag(d, transformation=transformation) if integral is False: dp = dp.change_ring(R) @@ -16128,37 +16113,36 @@ cdef class Matrix(Matrix1): pivot_cols = [] while j < n: k = i - while k < m and A.get_unsafe(k, j).is_zero(): # first nonzero entry + while k < m and A.get_unsafe(k,j).is_zero(): # first nonzero entry k += 1 if k < m: l = k + 1 while l < m: - while l < m and A.get_unsafe(l, j).is_zero(): # nonzero entry below + while l < m and A.get_unsafe(l,j).is_zero(): # nonzero entry below l += 1 - if l >= m: - break + if l >= m: break - a = A.get_unsafe(k, j) - b = A.get_unsafe(l, j) - d, p, q = a.xgcd(b) # p * a + q * b = d = gcd(a,b) + a = A.get_unsafe(k,j) + b = A.get_unsafe(l,j) + d,p,q = a.xgcd(b) # p * a + q * b = d = gcd(a,b) e = a // d f = b // d - for c in range(j, n): - Akc = A.get_unsafe(k, c) - Alc = A.get_unsafe(l, c) + for c in range(j,n): + Akc = A.get_unsafe(k,c) + Alc = A.get_unsafe(l,c) A.set_unsafe(k, c, p * Akc + q * Alc) A.set_unsafe(l, c, (-f) * Akc + e * Alc) if transformation: for c in range(m): - Ukc = U.get_unsafe(k, c) - Ulc = U.get_unsafe(l, c) + Ukc = U.get_unsafe(k,c) + Ulc = U.get_unsafe(l,c) U.set_unsafe(k, c, p * Ukc + q * Ulc) U.set_unsafe(l, c, (-f) * Ukc + e * Ulc) if i != k: - A.swap_rows_c(i, k) + A.swap_rows_c(i,k) if transformation: - U.swap_rows_c(i, k) + U.swap_rows_c(i,k) pivot_cols.append(j) i += 1 j += 1 @@ -16166,26 +16150,26 @@ cdef class Matrix(Matrix1): # reduce entries above pivots for i in range(len(pivot_cols)): j = pivot_cols[i] - pivot = A.get_unsafe(i, j) + pivot = A.get_unsafe(i,j) # possibly normalize the pivot if normalization: coeff = normalization(pivot) - for c in range(j, n): - A.set_unsafe(i, c, A.get_unsafe(i, c) * coeff) + for c in range(j,n): + A.set_unsafe(i, c, A.get_unsafe(i,c) * coeff) if transformation: for c in range(m): - U.set_unsafe(i, c, U.get_unsafe(i, c) * coeff) + U.set_unsafe(i, c, U.get_unsafe(i,c) * coeff) - pivot = A.get_unsafe(i, j) + pivot = A.get_unsafe(i,j) for k in range(i): - q = - (A.get_unsafe(k, j) // pivot) + q = - (A.get_unsafe(k,j) // pivot) if not q.is_zero(): - for c in range(j, n): - A.set_unsafe(k, c, A.get_unsafe(k, c) + q * A.get_unsafe(i, c)) + for c in range(j,n): + A.set_unsafe(k, c, A.get_unsafe(k,c) + q * A.get_unsafe(i,c)) if transformation: for c in range(m): - U.set_unsafe(k, c, U.get_unsafe(k, c) + q * U.get_unsafe(i, c)) + U.set_unsafe(k, c, U.get_unsafe(k,c) + q * U.get_unsafe(i,c)) if transformation: return U @@ -16329,25 +16313,25 @@ cdef class Matrix(Matrix1): return self.new_matrix(self.nrows(), self.nrows(), 1), self, [] else: return self.new_matrix(self.nrows(), self.nrows(), 1), self, [ - self.nonzero_positions_in_row(0)[0]] + self.nonzero_positions_in_row(0)[0] ] R = self.base_ring() # data type checks on R if not R.is_integral_domain(): raise TypeError("Generic echelon form only defined over " - "integral domains") + "integral domains") if not R.is_exact(): raise NotImplementedError("Echelon form over generic non-exact " - "rings not implemented at present") + "rings not implemented at present") left_mat, a = _generic_clear_column(self) assert left_mat * self == a - if a[0, 0] != 0: + if a[0,0] != 0: aa = a.submatrix(1, 1) s, t, pivs = aa._echelon_form_PID() - left_mat = s.new_matrix(1, 1, [1]).block_sum(s) * left_mat + left_mat = s.new_matrix(1,1,[1]).block_sum(s) * left_mat a = left_mat * self pivs = [0] + [x + 1 for x in pivs] @@ -16365,12 +16349,12 @@ cdef class Matrix(Matrix1): I = ideal_or_fractional(R, y) s = a[0][pivs[i]] t = I.small_residue(s) - v = R((s-t) / y) + v = R( (s-t) / y) left_mat.add_multiple_of_row(0, i, -v) a.add_multiple_of_row(0, i, -v) assert left_mat * self == a - except AttributeError: # on I.small_residue + except AttributeError: # on I.small_residue pass return left_mat, a, pivs @@ -16477,7 +16461,7 @@ cdef class Matrix(Matrix1): cdef list corners = [] # zero or one in corner of off-diagonal blocks if basis: from sage.matrix.constructor import identity_matrix - U = identity_matrix(R, n) # transformation matrix + U = identity_matrix(R, n) # transformation matrix # parity switch, True iff working on transpose # if False, mimic row operations only on U # if True, mimic column operations only on U @@ -16490,7 +16474,7 @@ cdef class Matrix(Matrix1): while zigging: # zigging means we are building a block nonzero = -1 for i in range(c+1, n): - if Z.get_unsafe(i, c): + if Z.get_unsafe(i,c): nonzero = i break zigging = (nonzero != -1) @@ -16534,7 +16518,7 @@ cdef class Matrix(Matrix1): # (inclusive), use it to clear entries to the right # but first record polynomial for block just built # this is the full monic polynomial, with correct coefficients - p = [-Z.get_unsafe(i, c) for i in range(s, c + 1)] + p = [-Z.get_unsafe(i,c) for i in range(s,c+1)] p.append(one) polys.append(p) @@ -16550,7 +16534,7 @@ cdef class Matrix(Matrix1): # Effectively: Z.add_multiple_of_row(i, j, scale) for k in range(c+1, n): # Z[i,k] = Z[i,k] + scale*Z[j,k] - Z.set_unsafe(i, k, Z.get_unsafe(i, k) + scale * Z.get_unsafe(j, k)) + Z.set_unsafe(i, k, Z.get_unsafe(i,k)+scale*Z.get_unsafe(j,k)) if basis: if trans: U.add_multiple_of_column(j, i, -scale) @@ -17317,7 +17301,7 @@ cdef class Matrix(Matrix1): companions.append(companion_matrix(poly, format=format)) return block_diagonal_matrix(companions, subdivide=subdivide) - def is_positive_operator_on(self, K1, K2=None): + def is_positive_operator_on(self,K1,K2=None): r""" Determine if this matrix is a positive operator on a cone. @@ -17751,7 +17735,7 @@ cdef class Matrix(Matrix1): """ return (-self).is_cross_positive_on(K) - def is_lyapunov_like_on(self, K): + def is_lyapunov_like_on(self,K): r""" Determine if this matrix is Lyapunov-like on a cone. @@ -18121,35 +18105,35 @@ def _smith_diag(d, transformation=True): else: left = right = None for i in range(n): - I0 = ideal_or_fractional(R, dp[i, i]) + I = ideal_or_fractional(R, dp[i,i]) - if I0 == ideal_or_fractional(R, 1): - if dp[i, i] != 1: + if I == ideal_or_fractional(R, 1): + if dp[i,i] != 1: if transformation: - left.add_multiple_of_row(i, i, R(R(1) / (dp[i, i])) - 1) - dp[i, i] = R(1) + left.add_multiple_of_row(i,i,R(R(1)/(dp[i,i])) - 1) + dp[i,i] = R(1) continue - for j in range(i + 1, n): - if dp[j, j] not in I0: - t = ideal_or_fractional(R, [dp[i, i], dp[j, j]]).gens_reduced() + for j in range(i+1,n): + if dp[j,j] not in I: + t = ideal_or_fractional(R, [dp[i,i], dp[j,j]]).gens_reduced() if len(t) > 1: raise ArithmeticError t = t[0] # find lambda, mu such that lambda*d[i,i] + mu*d[j,j] = t - lamb = R(dp[i, i] / t).inverse_mod(ideal_or_fractional(R, dp[j, j] / t)) - mu = R((t - lamb * dp[i, i]) / dp[j, j]) + lamb = R(dp[i,i]/t).inverse_mod( ideal_or_fractional(R, dp[j,j]/t)) + mu = R((t - lamb*dp[i,i]) / dp[j,j]) newlmat = dp.new_matrix(dp.nrows(), dp.nrows(), 1) - newlmat[i, i] = lamb - newlmat[i, j] = 1 - newlmat[j, i] = R(-dp[j, j] * mu / t) - newlmat[j, j] = R(dp[i, i] / t) + newlmat[i,i] = lamb + newlmat[i,j] = 1 + newlmat[j,i] = R(-dp[j,j]*mu/t) + newlmat[j,j] = R(dp[i,i]/t) newrmat = dp.new_matrix(dp.ncols(), dp.ncols(), 1) - newrmat[i, i] = 1 - newrmat[i, j] = R(-dp[j, j] / t) - newrmat[j, i] = mu - newrmat[j, j] = R(lamb * dp[i, i] / t) + newrmat[i,i] = 1 + newrmat[i,j] = R(-dp[j,j]/t) + newrmat[j,i] = mu + newrmat[j,j] = R(lamb*dp[i,i] / t) if transformation: left = newlmat*left @@ -18195,13 +18179,13 @@ def _generic_clear_column(m): k = 0 while a[k, 0] == 0: k += 1 - if k == a.nrows(): # first column is zero + if k == a.nrows(): # first column is zero return left_mat, a # k is now first row such that a[k, 0] is nonzero - left_mat[0, 0] = 0 - left_mat[k, k] = 0 - left_mat[0, k] = 1 - left_mat[k, 0] = -1 + left_mat[0,0] = 0 + left_mat[k,k] = 0 + left_mat[0,k] = 1 + left_mat[k,0] = -1 a = left_mat*a if left_mat * m != a: raise ArithmeticError("Something went wrong") @@ -18215,15 +18199,15 @@ def _generic_clear_column(m): # [e,f] # is invertible over R - I0 = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes + I = ideal_or_fractional(R, a[0, 0]) # need to make sure we change this when a[0,0] changes for k in range(1, a.nrows()): - if a[k, 0] not in I0: + if a[k,0] not in I: try: - v = ideal_or_fractional(R, a[0, 0], a[k, 0]).gens_reduced() + v = ideal_or_fractional(R, a[0,0], a[k,0]).gens_reduced() except Exception as msg: - raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0, 0], a[k, 0])) + raise ArithmeticError("%s\nCan't create ideal on %s and %s" % (msg, a[0,0], a[k,0])) if len(v) > 1: - raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0, 0], a[k, 0])) + raise ArithmeticError("Ideal %s not principal" % ideal_or_fractional(R, a[0,0], a[k,0])) B = v[0] # now we find c,d, using the fact that c * (a_{0,0}/B) - d * @@ -18232,40 +18216,40 @@ def _generic_clear_column(m): # need to handle carefully the case when a_{k,0}/B is a unit, i.e. a_{k,0} divides # a_{0,0}. - c = R(a[0, 0] / B).inverse_mod(ideal_or_fractional(R, a[k, 0] / B)) - d = R((c*a[0, 0] - B)/(a[k, 0])) + c = R(a[0,0] / B).inverse_mod(ideal_or_fractional(R, a[k,0] / B)) + d = R( (c*a[0,0] - B)/(a[k,0]) ) # sanity check - if c*a[0, 0] - d*a[k, 0] != B: + if c*a[0,0] - d*a[k,0] != B: raise ArithmeticError # now we find e,f such that e*d + c*f = 1 in the same way if c != 0: - e = d.inverse_mod(ideal_or_fractional(R, c)) + e = d.inverse_mod( ideal_or_fractional(R, c) ) f = R((1 - d*e)/c) else: - e = R(-a[k, 0] / B) # here d is a unit and this is just 1/d + e = R(-a[k,0]/B) # here d is a unit and this is just 1/d f = R(1) if e*d + c*f != 1: raise ArithmeticError newlmat = left_mat.parent()(1) - newlmat[0, 0] = c - newlmat[0, k] = -d - newlmat[k, 0] = e - newlmat[k, k] = f + newlmat[0,0] = c + newlmat[0,k] = -d + newlmat[k,0] = e + newlmat[k,k] = f if newlmat.det() != 1: raise ArithmeticError a = newlmat*a - I0 = ideal_or_fractional(R, a[0, 0]) + I = ideal_or_fractional(R, a[0,0]) left_mat = newlmat*left_mat if left_mat * m != a: raise ArithmeticError # now everything in column 0 is divisible by the pivot - for i in range(1, a.nrows()): - s = R(a[i, 0] / a[0, 0]) - a.add_multiple_of_row(i, 0, -s) + for i in range(1,a.nrows()): + s = R( a[i, 0]/a[0, 0]) + a.add_multiple_of_row(i, 0, -s ) left_mat.add_multiple_of_row(i, 0, -s) if left_mat * m != a: raise ArithmeticError @@ -18303,12 +18287,11 @@ def _smith_onestep(m): # preparation: if column 0 is zero, swap it with the first nonzero column j = 0 - while a.column(j) == 0: - j += 1 + while a.column(j) == 0: j += 1 if j > 0: - right_mat[0, 0] = right_mat[j, j] = 0 - right_mat[0, j] = 1 - right_mat[j, 0] = -1 + right_mat[0,0] = right_mat[j,j] = 0 + right_mat[0,j] = 1 + right_mat[j,0] = -1 a = a*right_mat if m * right_mat != a: raise ArithmeticError @@ -18319,15 +18302,15 @@ def _smith_onestep(m): # test if everything to the right of the pivot in row 0 is good as well isdone = True for jj in range(j+1, a.ncols()): - if a[0, jj] != 0: + if a[0,jj] != 0: isdone = False # if not we recurse -- algorithm must terminate if R is Noetherian. if not isdone: - s, t, u = _smith_onestep(a.transpose()) + s,t,u = _smith_onestep(a.transpose()) left_mat = u.transpose() * left_mat a = t.transpose() - right_mat = right_mat * s.transpose() + right_mat = right_mat* s.transpose() return left_mat, a, right_mat @@ -18602,7 +18585,7 @@ def _matrix_power_symbolic(A, n): # Jordan block Jk, its dimension nk, the eigenvalue m Jk = J.subdivision(k, k) nk = Jk.ncols() - mk = Jk[0, 0] + mk = Jk[0,0] # First row of block Mk; its entries are of the form # D^i(f) / i! with f = x^n and D = differentiation wrt x @@ -18649,28 +18632,28 @@ cdef inline bint _block_ldlt_pivot1x1(Matrix A, Py_ssize_t k) except 1: to return zero/one so that ``1`` can be used to indicate that a python exception occurred. """ - cdef Py_ssize_t i, j # dumy loop indices + cdef Py_ssize_t i,j # dumy loop indices cdef Py_ssize_t n = A._nrows - pivot = A.get_unsafe(k, k) + pivot = A.get_unsafe(k,k) # Compute the Schur complement that we'll work on during # the following iteration, and store it back in the lower- # right-hand corner of "A". - for i in range(n - k - 1): - for j in range(i + 1): - A.set_unsafe(k + 1 + i, - k + 1 + j, - (A.get_unsafe(k + 1 + i, k + 1 + j) - - A.get_unsafe(k + 1 + i, k) * A.get_unsafe(k, k + 1 + j) / pivot)) - A.set_unsafe(k + 1 + j, - k + 1 + i, - A.get_unsafe(k + 1 + i, k + 1 + j).conjugate()) + for i in range(n-k-1): + for j in range(i+1): + A.set_unsafe(k+1+i, + k+1+j, + ( A.get_unsafe(k+1+i,k+1+j) - + A.get_unsafe(k+1+i,k)*A.get_unsafe(k,k+1+j)/pivot )) + A.set_unsafe(k+1+j, + k+1+i, + A.get_unsafe(k+1+i,k+1+j).conjugate()) for i in range(n-k-1): # Store the new (kth) column of "L" within the lower- # left-hand corner of "A". - A.set_unsafe(k + i + 1, + A.set_unsafe(k+i+1, k, - A.get_unsafe(k + i + 1, k) / pivot) + A.get_unsafe(k+i+1,k)/ pivot) return 0 From d22015ca69e5bfff517a129c0c3df639ab060efd Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:52:33 +0200 Subject: [PATCH 057/538] undo format changes for matrix_mpolynomial_dense.pyx --- src/sage/matrix/matrix_mpolynomial_dense.pyx | 55 ++++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/sage/matrix/matrix_mpolynomial_dense.pyx b/src/sage/matrix/matrix_mpolynomial_dense.pyx index 589b5b33331..e3de9bbdb57 100644 --- a/src/sage/matrix/matrix_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_mpolynomial_dense.pyx @@ -9,14 +9,14 @@ AUTHOR: * Martin Albrecht """ -# ***************************************************************************** +#***************************************************************************** # Copyright (C) 2013 Martin Albrecht # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -# ***************************************************************************** +#***************************************************************************** from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense from sage.matrix.matrix2 cimport Matrix @@ -101,8 +101,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): [ 0 -x + y] """ x = self.fetch('echelon_form_'+algorithm) - if x is not None: - return x + if x is not None: return x if algorithm == "frac": E = self.matrix_over_field() @@ -117,8 +116,8 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if algorithm == "frac": self.cache('pivots', E.pivots()) elif algorithm == "bareiss": - l1 = E.swapped_columns() - self.cache('pivots', tuple(sorted(l1))) + l = E.swapped_columns() + self.cache('pivots', tuple(sorted(l))) elif algorithm == "row_reduction": pass @@ -155,7 +154,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): x = self.fetch('pivots') if x is None: - raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'" % self.parent()) + raise RuntimeError("BUG: matrix pivots should have been set but weren't, matrix parent = '%s'"%self.parent()) return x def echelonize(self, algorithm='row_reduction', **kwds): @@ -263,7 +262,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.clear_cache() singular_bareiss = singular_function("bareiss") - E, ln = singular_bareiss(self.T) + E, l = singular_bareiss(self.T) m = len(E) n = len(E[0]) @@ -278,33 +277,33 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): self.set_unsafe(r, c, R._zero_element) from sage.rings.integer_ring import ZZ - ln = [ZZ(e-1) for e in ln] + l = [ZZ(e-1) for e in l] - self.cache('in_echelon_form_bareiss', True) + self.cache('in_echelon_form_bareiss',True) self.cache('rank', len(E)) self.cache('pivots', tuple(range(len(E)))) - self.cache('swapped_columns', tuple(ln)) + self.cache('swapped_columns', tuple(l)) elif can_convert_to_singular(self.base_ring()): self.check_mutability() self.clear_cache() - E, ln = self.T._singular_().bareiss()._sage_(self.base_ring()) + E,l = self.T._singular_().bareiss()._sage_(self.base_ring()) # clear matrix for r from 0 <= r < self._nrows: for c from 0 <= c < self._ncols: - self.set_unsafe(r, c, R._zero_element) + self.set_unsafe(r,c,R._zero_element) for r from 0 <= r < E.nrows(): for c from 0 <= c < E.ncols(): - self.set_unsafe(c, r, E[r, c]) + self.set_unsafe(c,r, E[r,c]) - self.cache('in_echelon_form_bareiss', True) + self.cache('in_echelon_form_bareiss',True) self.cache('rank', E.nrows()) self.cache('pivots', tuple(range(E.nrows()))) - self.cache('swapped_columns', ln) + self.cache('swapped_columns', l) else: @@ -388,14 +387,14 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if x is not None: return # already known to be in echelon form - nr, nc = self.nrows(), self.ncols() + nr,nc = self.nrows(),self.ncols() F = self.base_ring().base_ring() - cdef Matrix d = matrix(F, nr, nc) + cdef Matrix d = matrix(F,nr,nc) start_row = 0 for r from 0 <= r < nr: for c from 0 <= c < nc: - p = self.get_unsafe(r, c) + p = self.get_unsafe(r,c) if p.is_constant(): d.set_unsafe(r, c, p.constant_coefficient()) @@ -405,25 +404,25 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): if d.get_unsafe(rc, c): r = rc break - if r != -1: - a_inverse = ~self.get_unsafe(r, c) - self.rescale_row_c(r, a_inverse, c) + if r!=-1: + a_inverse = ~self.get_unsafe(r,c) + self.rescale_row_c(r, a_inverse , c) self.swap_rows_c(r, start_row) for i from 0 <= i < nr: if i != start_row: - minus_b = -self.get_unsafe(i, c) + minus_b = -self.get_unsafe(i,c) self.add_multiple_of_row(i, start_row, minus_b, 0) - start_row += 1 + start_row +=1 d = d._parent(0) for i from start_row <= i < nr: for j from c+1 <= j < nc: - if self.get_unsafe(i, j).is_constant(): - d.set_unsafe(i, j, self.get_unsafe(i, j).constant_coefficient()) + if self.get_unsafe(i,j).is_constant(): + d.set_unsafe(i,j, self.get_unsafe(i,j).constant_coefficient()) - self.cache('in_echelon_form_row_reduction', True) + self.cache('in_echelon_form_row_reduction',True) def swapped_columns(self): """ @@ -500,7 +499,7 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense): N = self.__copy__() for j in range(self.ncols()): if j != ncoef: - N.add_multiple_of_column(j, ncoef, -R(self[nrow, j] / coef)) + N.add_multiple_of_column(j, ncoef, -R(self[nrow,j] / coef)) return N.fitting_ideal(i) for (ncolumn, column) in enumerate(self.columns()): if not column: From 53c99d2044076ce5c459e395f2fb562c6890a58a Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:55:46 +0200 Subject: [PATCH 058/538] undo format changes for matrix_mpolynomial_dense.pyx and laurent_polynomial.pyx --- .../rings/polynomial/laurent_polynomial.pyx | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index d4dff8b1361..f0ccb4e2ce0 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -359,7 +359,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif (not isinstance(f, Polynomial)) or (parent is not f.parent()): if isinstance(f, dict): v = min(f) if f else 0 - f = {i-v: c for i, c in f.items()} + f = {i-v: c for i,c in f.items()} n += v f = parent._R(f) @@ -592,11 +592,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif e == 0: var = "" else: - var = "*{}^{}".format(X, e) - s += "{}{}".format(x, var) + var = "*{}^{}".format(X,e) + s += "{}{}".format(x,var) first = False s = s.replace(" + -", " - ") - s = s.replace(" 1*", " ") + s = s.replace(" 1*"," ") s = s.replace(" -1*", " -") return s[1:] @@ -653,19 +653,19 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): elif e == 0: var = "" elif e > 0: - var = "|{}^{{{}}}".format(X, e) + var = "|{}^{{{}}}".format(X,e) if e >= 0: - s += "{}{}".format(x, var) - else: # negative e + s += "{}{}".format(x,var) + else: # negative e if e == -1: s += "\\frac{{{}}}{{{}}}".format(x, X) else: - s += "\\frac{{{}}}{{{}^{{{}}}}}".format(x, X, -e) + s += "\\frac{{{}}}{{{}^{{{}}}}}".format(x, X,-e) first = False s = s.replace(" + -", " - ") - s = s.replace(" 1|", " ") + s = s.replace(" 1|"," ") s = s.replace(" -1|", " -") - s = s.replace("|", "") + s = s.replace("|","") return s[1:] @@ -701,7 +701,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): # degrees cdef long result = 0 cdef long result_mon - cdef int i, j + cdef int i,j cdef long var_hash_name = hash(self.__u._parent._names[0]) for i in range(self.__u.degree()+1): result_mon = hash(self.__u[i]) @@ -913,11 +913,11 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): j = i - self.__n if j >= 0: self.__u._unsafe_mutate(j, value) - else: # off to the left + else: # off to the left if value != 0: self.__n = self.__n + j R = self._parent.base_ring() - coeffs = [value] + [R.zero() for _ in range(1, -j)] + self.__u.list() + coeffs = [value] + [R.zero() for _ in range(1,-j)] + self.__u.list() self.__u = self.__u._parent(coeffs) self._normalize() @@ -1282,7 +1282,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): Fraction Field of Univariate Polynomial Ring in t over Rational Field """ cdef LaurentPolynomial_univariate ret - if self.__u.is_constant(): # this has a single term c*x^n + if self.__u.is_constant(): # this has a single term c*x^n ret = self._new_c() if self.__u.is_unit(): ret.__u = self.__u.inverse_of_unit() @@ -1680,6 +1680,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ return self.__n == 0 and self.__u.is_constant() + def is_square(self, root=False): r""" Return whether this Laurent polynomial is a square. @@ -1926,10 +1927,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): cdef list a = self.__u.list(copy=False) if n < 0: - v = [a[i] / (n + i + 1) for i in range(min(-1 - n, len(a)))] + [0] + v = [a[i]/(n+i+1) for i in range(min(-1-n,len(a)))] + [0] else: v = [] - v += [a[i] / (n + i + 1) for i in range(max(-n, 0), len(a))] + v += [a[i]/(n+i+1) for i in range(max(-n,0), len(a))] try: u = self._parent._R(v) except TypeError: @@ -1968,7 +1969,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): """ if kwds: f = self.subs(**kwds) - if x: # If there are non-keyword arguments + if x: # If there are non-keyword arguments return f(*x) else: return f From e5664d71849e6a367144ca9836c06510a6584307 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 10:59:37 +0200 Subject: [PATCH 059/538] undo format changes for laurent_polynomial_ideal.py --- .../polynomial/laurent_polynomial_ideal.py | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index bea4b8bb76a..81bc095c382 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -26,8 +26,7 @@ from sage.structure.richcmp import op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE from sage.arith.misc import GCD - -class LaurentPolynomialIdeal(Ideal_generic): +class LaurentPolynomialIdeal( Ideal_generic ): def __init__(self, ring, gens, coerce=True, hint=None): r""" Create an ideal in a Laurent polynomial ring. @@ -93,7 +92,7 @@ def __init__(self, ring, gens, coerce=True, hint=None): """ Ideal_generic.__init__(self, ring, gens, coerce=coerce) self._poly_ring = ring.polynomial_ring() - self._poly_ideal = None # Create only as needed + self._poly_ideal = None # Create only as needed self._saturated = False self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) # if hint is None: @@ -169,11 +168,11 @@ def _richcmp_(self, right_r, op): True """ if op in (op_EQ, op_NE): - if set(self.gens()) == set(right_r.gens()): # Early abort + if set(self.gens()) == set(right_r.gens()): # Early abort return (op == op_EQ) return ((self.polynomial_ideal() == right_r.polynomial_ideal()) == (op == op_EQ)) elif op == op_LE: - if all(f in right_r.gens() for f in self.gens()): # Early abort + if all(f in right_r.gens() for f in self.gens()): # Early abort return True return self.polynomial_ideal(saturate=False) <= right_r.polynomial_ideal() elif op == op_GE: @@ -308,10 +307,10 @@ def apply_coeff_map(self, f, new_base_ring=None, forward_hint=True): else: R = ring.change_ring(new_base_ring) if forward_hint: - apply_to_hint = lambda x, f=f: x.map_coefficients(f) + apply_to_hint = lambda x,f=f: x.map_coefficients(f) else: apply_to_hint = None - return self.apply_map(lambda x, f=f: + return self.apply_map(lambda x,f=f: x.map_coefficients(f, new_base_ring=new_base_ring), new_ring=R, apply_to_hint=apply_to_hint) @@ -429,17 +428,17 @@ def polynomial_ideal(self, saturate=True): l2 = [f.__reduce__()[1][0] for f in gens] hint = self._hint l2 += list(hint.groebner_basis()) - id = Q.ideal(l2) + I = Q.ideal(l2) if not saturate: - self._poly_ideal = id - self._hint = id + self._poly_ideal = I + self._hint = I return Q.ideal(l2) n = P.ngens() - id = id.saturation(Q.ideal([Q.monomial(*((1,) * n))]))[0] - self._poly_ideal = id - self._hint = id + I = I.saturation(Q.ideal([Q.monomial(*((1,) * n))]))[0] + self._poly_ideal = I + self._hint = I self._saturated = True - return id + return I def groebner_basis(self, saturate=True): """ @@ -453,8 +452,8 @@ def groebner_basis(self, saturate=True): sage: (I + J).groebner_basis() (x - 1, y + 1) """ - gb = self.polynomial_ideal(saturate=saturate).groebner_basis() - return tuple(self.ring()(x) for x in gb) + l = self.polynomial_ideal(saturate=saturate).groebner_basis() + return tuple(self.ring()(x) for x in l) def is_one(self): """ @@ -486,10 +485,10 @@ def is_binomial(self, groebner_basis=False): True """ if groebner_basis: - gb = self.groebner_basis() + l = self.groebner_basis() else: - gb = self.gens() - return all(not f or f.number_of_terms() == 2 for f in gb) + l = self.gens() + return all(not f or f.number_of_terms() == 2 for f in l) def associated_primes(self): """ @@ -509,9 +508,9 @@ def associated_primes(self): Ideal (z^2 - y, y*z + 2, y^2 + 2*z) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ - ap = self.polynomial_ideal(saturate=False).associated_primes() - ap2 = [self.ring().ideal(id.gens(), hint=id) for id in ap] - return tuple(id for id in ap2 if not id.is_one()) + l = self.polynomial_ideal(saturate=False).associated_primes() + l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] + return tuple(I for I in l2 if not I.is_one()) def minimal_associated_primes(self, saturate=False): """ @@ -531,9 +530,9 @@ def minimal_associated_primes(self, saturate=False): Ideal (z^3 + 2, -z^2 + y) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field) """ - ap = self.polynomial_ideal(saturate=saturate).minimal_associated_primes() - ap2 = [self.ring().ideal(id.gens(), hint=id) for id in ap] - return tuple(id for id in ap2 if not id.is_one()) + l = self.polynomial_ideal(saturate=saturate).minimal_associated_primes() + l2 = [self.ring().ideal(I.gens(), hint=I) for I in l] + return tuple(I for I in l2 if not I.is_one()) def radical(self): """ From 7285ecc55919324e6fb31c15500844b4cd6009fc Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:00:54 +0200 Subject: [PATCH 060/538] undo format changes for laurent_polynomial_mpair.pyx --- src/sage/rings/polynomial/laurent_polynomial_mpair.pyx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index efab709fd44..fe199d281e3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1241,19 +1241,19 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): else: return f - cdef int ln = len(x) + cdef int l = len(x) - if ln == 1 and isinstance(x[0], (tuple, list)): + if l == 1 and isinstance(x[0], (tuple, list)): x = x[0] - ln = len(x) + l = len(x) - if ln != self._parent.ngens(): + if l != self._parent.ngens(): raise TypeError("number of arguments does not match the number" " of generators in parent") # Check to make sure that we aren't dividing by zero cdef Py_ssize_t m - for m in range(ln): + for m in range(l): if x[m] == 0: if self.has_inverse_of(m): raise ZeroDivisionError From 61ea6e89a36e01741228e05a5f5d47e4395f64db Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:02:27 +0200 Subject: [PATCH 061/538] undo format changes for laurent_polynomial_ring.py --- src/sage/rings/polynomial/laurent_polynomial_ring.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 4cf0880880e..22d97975cd6 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -77,8 +77,6 @@ def is_LaurentPolynomialRing(R): _cache = {} - - def LaurentPolynomialRing(base_ring, *args, **kwds): r""" Return the globally unique univariate or multivariate Laurent polynomial @@ -254,7 +252,6 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): _cache[R] = P return P - def _split_dict_(D, indices, group_by=None): r""" Split the dictionary ``D`` by ``indices`` and ``group_by``. @@ -330,14 +327,13 @@ def extract(T, indices): if not all(r == 0 for r in extract(K, remaining)): raise SplitDictError('split not possible') G = extract(K, group_by) - In = extract(K, indices) - result.setdefault(G, dict()).update({In: V}) + I = extract(K, indices) + result.setdefault(G, dict()).update({I: V}) if not group_by: return result.popitem()[1] else: return result - def _split_laurent_polynomial_dict_(P, M, d): r""" Helper function for splitting a multivariate Laurent polynomial @@ -399,7 +395,6 @@ def value(d, R): pass return sum(P({k: 1}) * value(v, P) for k, v in D.items()).dict() - def from_fraction_field(L, x): r""" Helper function to construct a Laurent polynomial from an element of its @@ -760,7 +755,7 @@ def _element_constructor_(self, x, mon=None): P = parent(x) if P is self.polynomial_ring(): from sage.rings.polynomial.polydict import ETuple - return self.element_class(self, x, mon=ETuple({}, int(self.ngens()))) + return self.element_class( self, x, mon=ETuple({}, int(self.ngens())) ) elif isinstance(x, Expression): return x.laurent_polynomial(ring=self) From 16ce3c760dc7c12a72d9b3ac1dc2a33b19631c87 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:03:57 +0200 Subject: [PATCH 062/538] undo format changes for laurent_polynomial_ring_base.py --- src/sage/rings/polynomial/laurent_polynomial_ring_base.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index 95ea676e0d3..c10cbb219b0 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -278,7 +278,8 @@ def _coerce_map_from_(self, R): f = self._coerce_map_via([self._R], R) if f is not None: return f - if isinstance(R, LaurentPolynomialRing_generic) and self._R.has_coerce_map_from(R._R): + if (isinstance(R, LaurentPolynomialRing_generic) + and self._R.has_coerce_map_from(R._R)): return self._generic_coerce_map(R) def __eq__(self, right): @@ -479,7 +480,7 @@ def krull_dimension(self): """ raise NotImplementedError - def random_element(self, low_degree=-2, high_degree=2, terms=5, choose_degree=False, *args, **kwds): + def random_element(self, low_degree=-2, high_degree=2, terms=5, choose_degree=False,*args, **kwds): """ EXAMPLES:: From 7bfdabf63b36743b5f43f646dc30681f7c5da921 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:09:55 +0200 Subject: [PATCH 063/538] undo format changes for polynomial_element.pyx --- .../rings/polynomial/polynomial_element.pyx | 344 +++++++++--------- 1 file changed, 168 insertions(+), 176 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 06b5ab0eb43..c5a1129aecf 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -213,7 +213,7 @@ cdef class Polynomial(CommutativePolynomial): .. automethod:: _mul_trunc_ """ - def __init__(self, parent, is_gen=False, construct=False): + def __init__(self, parent, is_gen = False, construct=False): """ The following examples illustrate creation of elements of polynomial rings, and some basic arithmetic. @@ -357,7 +357,7 @@ cdef class Polynomial(CommutativePolynomial): from sage.plot.all import plot, point if R.characteristic() == 0: if xmin is None and xmax is None: - (xmin, xmax) = (-1, 1) + (xmin, xmax) = (-1,1) elif xmin is None or xmax is None: raise AttributeError("must give both plot endpoints") return plot(self.__call__, (xmin, xmax), *args, **kwds) @@ -365,10 +365,10 @@ cdef class Polynomial(CommutativePolynomial): if R.is_finite(): v = list(R) v.sort() - w = dict([(v[i], i) for i in range(len(v))]) + w = dict([(v[i],i) for i in range(len(v))]) z = [(i, w[self(v[i])]) for i in range(len(v))] return point(z, *args, **kwds) - raise NotImplementedError("plotting of polynomials over %s not implemented" % R) + raise NotImplementedError("plotting of polynomials over %s not implemented"%R) cpdef _lmul_(self, Element left): """ @@ -832,7 +832,7 @@ cdef class Polynomial(CommutativePolynomial): # is more permissive about its arguments than we are. top = top(*args, **kwds) except TypeError: - if args: # bwd compat: nonsense *keyword* arguments are okay + if args: # bwd compat: nonsense *keyword* arguments are okay raise TypeError("Wrong number of arguments") else: eval_coeffs = True @@ -912,7 +912,7 @@ cdef class Polynomial(CommutativePolynomial): d = pol.degree() if d <= 0 or (isinstance(a, Element) and R.is_exact() and a.is_zero()): - return cst # with the right parent thanks to the above coercion + return cst # with the right parent thanks to the above coercion elif pol._parent is R and a.is_gen(): return pol elif hasattr(a, "_evaluate_polynomial"): @@ -1078,18 +1078,18 @@ cdef class Polynomial(CommutativePolynomial): cdef Py_ssize_t d2 = pol.degree() # Special case constant polynomials - if d1 == -1: # self is the 0 polynomial + if d1 == -1: # self is the 0 polynomial if d2 == -1: - return rich_to_bool(op, 0) # both polynomials are 0 + return rich_to_bool(op, 0) # both polynomials are 0 elif d2 == 0: return richcmp(self._parent._base.zero(), pol.get_unsafe(0), op) - return rich_to_bool_sgn(op, -1) # we have d2 > 0 - elif d1 == 0: # self is a nonzero constant + return rich_to_bool_sgn(op, -1) # we have d2 > 0 + elif d1 == 0: # self is a nonzero constant if d2 == -1: return richcmp(self.get_unsafe(0), pol._parent._base.zero(), op) elif d2 == 0: return richcmp(self.get_unsafe(0), pol.get_unsafe(0), op) - return rich_to_bool_sgn(op, -1) # we have d2 > d1 == 0 + return rich_to_bool_sgn(op, -1) # we have d2 > d1 == 0 # For different degrees, compare the degree if d1 != d2: @@ -1272,12 +1272,12 @@ cdef class Polynomial(CommutativePolynomial): TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement' """ - cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap + cdef long result = 0 # store it in a c-int and just let the overflowing additions wrap cdef long result_mon cdef long c_hash cdef long var_name_hash cdef int i - for i from 0 <= i <= self.degree(): + for i from 0<= i <= self.degree(): if i == 1: # we delay the hashing until now to not waste it on a constant poly var_name_hash = hash(self._parent._names[0]) @@ -1331,7 +1331,7 @@ cdef class Polynomial(CommutativePolynomial): a = im_gens[0] d = self.degree() if d == -1: - return codomain.zero() # Special case: 0 should always coerce to 0 + return codomain.zero() # Special case: 0 should always coerce to 0 if base_map is None: base_map = codomain.coerce_map_from(self.base_ring()) result = base_map(self.get_unsafe(d)) @@ -1661,9 +1661,9 @@ cdef class Polynomial(CommutativePolynomial): for i in range(n+1): for j in range(n-1): M[i+j, j+n] = m[i] - v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 + v = vector(R, [R.one()] + [R.zero()]*(2*n-2)) # the constant polynomial 1 if M.is_invertible(): - x = M.solve_right(v) # there has to be a better way to solve + x = M.solve_right(v) # there has to be a better way to solve return a.parent()(list(x)[0:n]) else: raise ValueError("Impossible inverse modulo") @@ -1846,7 +1846,7 @@ cdef class Polynomial(CommutativePolynomial): This is the default implementation that does the multiplication and then truncate! There are custom implementations in several subclasses: - - :meth:`on dense polynomial over integers (via FLINT) ` + - :meth:`on dense polynomial over integers (via FLINT) ` - :meth:`on dense polynomial over Z/nZ (via FLINT) ` @@ -1961,7 +1961,7 @@ cdef class Polynomial(CommutativePolynomial): """ if self.degree() < 0: raise ValueError("square-free decomposition not defined for zero polynomial") - if hasattr(self.base_ring(), '_squarefree_decomposition_univariate_polynomial'): + if hasattr(self.base_ring(),'_squarefree_decomposition_univariate_polynomial'): return self.base_ring()._squarefree_decomposition_univariate_polynomial(self) raise NotImplementedError("square-free decomposition not implemented for this polynomial") @@ -2188,11 +2188,11 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("ring must be an extension of the base ring") if not (ring.is_field() and ring.is_finite()): raise NotImplementedError - allowed_deg_mult = Integer(ring.factored_order()[0][1]) # generally it will be the quotient of this by the degree of the base ring. + allowed_deg_mult = Integer(ring.factored_order()[0][1]) # generally it will be the quotient of this by the degree of the base ring. if degree is None: x = self._parent.gen() if allowed_deg_mult == 1: - xq = pow(x, q, self) + xq = pow(x,q,self) self = self.gcd(xq-x) degree = -1 if self.degree() == 0: @@ -2210,7 +2210,7 @@ cdef class Polynomial(CommutativePolynomial): break while d < allowed_deg_mult: d = d+1 - xq = pow(xq, q, self) + xq = pow(xq,q,self) if d.divides(allowed_deg_mult): break A = self.gcd(xq-x) @@ -2234,8 +2234,8 @@ cdef class Polynomial(CommutativePolynomial): break while True: # we waste a little effort here in computing the xq again. - d = d + 1 - xq = pow(xq, q, self) + d = d+1 + xq = pow(xq,q,self) if allowed_deg_mult.divides(d): break A = self.gcd(xq-x) @@ -2257,7 +2257,7 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("no roots D %s" % self) break d = d+1 - xq = pow(xq, q, self) + xq = pow(xq,q,self) if d == degree: break A = self.gcd(xq-x) @@ -2273,13 +2273,13 @@ cdef class Polynomial(CommutativePolynomial): if degree == 1: ring = self.base_ring() else: - ring = self.base_ring().extension(degree) # this won't work yet. + ring = self.base_ring().extension(degree) # this won't work yet. # now self has only roots of degree ``degree``. # for now, we only implement the Cantor-Zassenhaus split k = self.degree() // degree if k == 1: try: - return self.roots(ring, multiplicities=False)[0] # is there something better to do here? + return self.roots(ring, multiplicities=False)[0] # is there something better to do here? except IndexError: raise ValueError("no roots F %s" % self) if q % 2 == 0: @@ -2289,8 +2289,8 @@ cdef class Polynomial(CommutativePolynomial): continue T = T.monic() C = T - for i in range(degree - 1): - C = T + pow(C, q, self) + for i in range(degree-1): + C = T + pow(C,q,self) h = self.gcd(C) hd = h.degree() if hd != 0 and hd != self.degree(): @@ -2536,7 +2536,7 @@ cdef class Polynomial(CommutativePolynomial): else: v = [R.zero()]*right + [R.one()] return self.parent()(v, check=False) - if right > 20: # no gain below + if right > 20: # no gain below try: p = self.parent().characteristic() except (AttributeError, NotImplementedError): @@ -2557,7 +2557,7 @@ cdef class Polynomial(CommutativePolynomial): q, r = q.quo_rem(p) if r != 0: if sparse: - tmp = self.parent()({e * k: d[k] ** e for k in d}) + tmp = self.parent()({e*k : d[k]**e for k in d}) else: tmp = [0] * (e * len(c) - e + 1) for i in range(len(c)): @@ -2728,19 +2728,19 @@ cdef class Polynomial(CommutativePolynomial): if y.find("-") == 0: y = y[1:] if not atomic_repr and n > 0 and (y.find("+") != -1 or y.find("-") != -1): - x = "(%s)" % x + x = "(%s)"%x if n > 1: - var = "*%s^%s" % (name, n) - elif n == 1: - var = "*%s" % name + var = "*%s^%s"%(name,n) + elif n==1: + var = "*%s"%name else: var = "" sbuf.write(x) sbuf.write(var) s = sbuf.getvalue() s = s.replace(" + -", " - ") - s = re.sub(r' 1(\.0+)?\*', ' ', s) - s = re.sub(r' -1(\.0+)?\*', ' -', s) + s = re.sub(r' 1(\.0+)?\*',' ', s) + s = re.sub(r' -1(\.0+)?\*',' -', s) if s == " ": return "0" return s[1:] @@ -2813,7 +2813,7 @@ cdef class Polynomial(CommutativePolynomial): x = "\\left(%s\\right)" % x if n > 1: var = "|%s^{%s}" % (name, n) - elif n == 1: + elif n==1: var = "|%s" % name else: var = "" @@ -3150,12 +3150,12 @@ cdef class Polynomial(CommutativePolynomial): - Didier Deshommes (2006-05-25) """ - return self._parent(polynomial_fateman._mul_fateman_mul(self, right)) + return self._parent(polynomial_fateman._mul_fateman_mul(self,right)) @cython.boundscheck(False) @cython.wraparound(False) @cython.overflowcheck(False) - def _mul_karatsuba(self, right, K_threshold=None): + def _mul_karatsuba(self, right, K_threshold = None): r""" Compute the product of two polynomials using the Karatsuba divide and conquer multiplication algorithm. This is only used over a @@ -3328,8 +3328,8 @@ cdef class Polynomial(CommutativePolynomial): if n <= K_threshold or m <= K_threshold: return self._new_generic(do_schoolbook_product(f, g, -1)) if n == m: - return self._new_generic(do_karatsuba(f, g, K_threshold, 0, 0, n)) - return self._new_generic(do_karatsuba_different_size(f, g, K_threshold)) + return self._new_generic(do_karatsuba(f,g, K_threshold, 0, 0, n)) + return self._new_generic(do_karatsuba_different_size(f,g, K_threshold)) @cython.boundscheck(False) @cython.wraparound(False) @@ -3487,7 +3487,7 @@ cdef class Polynomial(CommutativePolynomial): if var not in variables: x = base_ring(self) if base_ring else self const_ix = ETuple((0,)*len(variables)) - return {const_ix: x} + return { const_ix: x } cdef tuple prev_variables = variables[:variables.index(var)] const_ix = ETuple((0,)*len(prev_variables)) @@ -3509,7 +3509,7 @@ cdef class Polynomial(CommutativePolynomial): cdef dict D = {} cdef tuple leftovers = (0,) * (len(variables) - len(prev_variables) - 1) for k in range(len(mpolys)): - for i, a in mpolys[k].iteritems(): + for i,a in mpolys[k].iteritems(): j = ETuple((k,) + leftovers) D[i + j] = a @@ -3680,7 +3680,7 @@ cdef class Polynomial(CommutativePolynomial): for y in x: d = d.lcm(y.denominator()) return d - except (AttributeError): + except(AttributeError): return self.base_ring().one() def numerator(self): @@ -3951,7 +3951,7 @@ cdef class Polynomial(CommutativePolynomial): """ return [self.diff()] - def integral(self, var=None): + def integral(self,var=None): """ Return the integral of this polynomial. @@ -4571,39 +4571,39 @@ cdef class Polynomial(CommutativePolynomial): # PARI for smaller degree over other rings besides Z, and use # NTL in general. # A remark from Bill Hart (2007-09-25) about the above observation: - # # NTL uses the Berlekamp-Zassenhaus method with van Hoeij's improvements. - # # But so does Magma since about Jul 2001. - # # - # # But here's the kicker. PARI also uses this algorithm. Even Maple uses - # # it! - # # - # # NTL's LLL algorithms are extremely well developed (van Hoeij uses - # # LLL). There is also a possible speed difference in whether one uses - # # quadratic convergence or not in the Hensel lift. But the right choice - # # is not always what one thinks. - # # - # # But more than likely NTL is just better for large problems because - # # Victor Shoup was very careful with the choice of strategies and - # # parameters he used. Paul Zimmerman supplied him with a pile of - # # polynomials to factor for comparison purposes and these seem to have - # # been used to tune the algorithm for a wide range of inputs, including - # # cases that van Hoeij's algorithm doesn't usually like. - # # - # # If you have a bound on the coefficients of the factors, one can surely - # # do better than a generic implementation, but probably not much better - # # if there are many factors. - # # - - # # HUGE TODO, refactor the code below here such that this method will - # # have as only the following code - # # - # # R = self.parent().base_ring() - # # return R._factor_univariate_polynomial(self) - # # - # # in this way we can move the specific logic of factoring to the - # # self.parent().base_ring() and get rid of all the ugly - # # is_SomeType(R) checks and get way nicer structured code - # # 200 lines of spaghetti code is just way to much! + ## NTL uses the Berlekamp-Zassenhaus method with van Hoeij's improvements. + ## But so does Magma since about Jul 2001. + ## + ## But here's the kicker. PARI also uses this algorithm. Even Maple uses + ## it! + ## + ## NTL's LLL algorithms are extremely well developed (van Hoeij uses + ## LLL). There is also a possible speed difference in whether one uses + ## quadratic convergence or not in the Hensel lift. But the right choice + ## is not always what one thinks. + ## + ## But more than likely NTL is just better for large problems because + ## Victor Shoup was very careful with the choice of strategies and + ## parameters he used. Paul Zimmerman supplied him with a pile of + ## polynomials to factor for comparison purposes and these seem to have + ## been used to tune the algorithm for a wide range of inputs, including + ## cases that van Hoeij's algorithm doesn't usually like. + ## + ## If you have a bound on the coefficients of the factors, one can surely + ## do better than a generic implementation, but probably not much better + ## if there are many factors. + ## + + ## HUGE TODO, refactor the code below here such that this method will + ## have as only the following code + ## + ## R = self.parent().base_ring() + ## return R._factor_univariate_polynomial(self) + ## + ## in this way we can move the specific logic of factoring to the + ## self.parent().base_ring() and get rid of all the ugly + ## is_SomeType(R) checks and get way nicer structured code + ## 200 lines of spaghetti code is just way to much! if self.degree() < 0: raise ArithmeticError("factorization of {!r} is not defined".format(self)) @@ -4617,7 +4617,7 @@ cdef class Polynomial(CommutativePolynomial): try: F = flatten(self).factor(**kwargs) unflatten = flatten.section() - return Factorization(((unflatten(f), m) for (f, m) in F), unit=F.unit()) + return Factorization(((unflatten(f),m) for (f,m) in F), unit = F.unit()) except NotImplementedError: pass @@ -4650,7 +4650,7 @@ cdef class Polynomial(CommutativePolynomial): # This was copied from the general multivariate implementation try: if R.is_finite(): - if R.characteristic() > 1 << 29: + if R.characteristic() > 1<<29: raise NotImplementedError("Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") P = self._parent @@ -4658,8 +4658,8 @@ cdef class Polynomial(CommutativePolynomial): S = self._singular_().factorize() factors = S[1] exponents = S[2] - v = sorted([(P(factors[i + 1]), - sage.rings.integer.Integer(exponents[i + 1])) + v = sorted([( P(factors[i+1]), + sage.rings.integer.Integer(exponents[i+1])) for i in range(len(factors))]) unit = P.one() for i in range(len(v)): @@ -4936,7 +4936,7 @@ cdef class Polynomial(CommutativePolynomial): raise NotImplementedError("splitting_field() is only implemented over number fields and finite fields") - def pseudo_quo_rem(self, other): + def pseudo_quo_rem(self,other): r""" Compute the pseudo-division of two polynomials. @@ -4996,7 +4996,7 @@ cdef class Polynomial(CommutativePolynomial): e -= 1 q = d**e - return (q * Q, q * R) + return (q*Q,q*R) @coerce_binop def gcd(self, other): @@ -5089,7 +5089,7 @@ cdef class Polynomial(CommutativePolynomial): try: doit = self._parent._base._gcd_univariate_polynomial except AttributeError: - raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials" % self._parent._base) + raise NotImplementedError("%s does not provide a gcd implementation for univariate polynomials"%self._parent._base) else: return doit(self, other) @@ -5462,7 +5462,7 @@ cdef class Polynomial(CommutativePolynomial): return R.fraction_field()[self._parent.variable_name()].quotient(self, names) - def sylvester_matrix(self, right, variable=None): + def sylvester_matrix(self, right, variable = None): """ Return the Sylvester matrix of ``self`` and ``right``. @@ -5588,10 +5588,10 @@ cdef class Polynomial(CommutativePolynomial): # sylvester_matrix() in multi_polynomial.pyx. if self._parent != right.parent(): - a, b = coercion_model.canonical_coercion(self, right) + a, b = coercion_model.canonical_coercion(self,right) variable = a.parent()(self.variables()[0]) - # We add the variable to cover the case that right is a multivariate - # polynomial + #We add the variable to cover the case that right is a multivariate + #polynomial return a.sylvester_matrix(b, variable) if variable: @@ -6446,18 +6446,13 @@ cdef class Polynomial(CommutativePolynomial): e = self.exponents() c = self.coefficients() - if len(e) == 0: - return [] + if len(e) == 0: return [] if len(e) == 1: - if e[0] == 0: - return [] - else: - return [(infinity.infinity, e[0])] + if e[0] == 0: return [] + else: return [(infinity.infinity, e[0])] - if e[0] == 0: - slopes = [] - else: - slopes = [(infinity.infinity, e[0])] + if e[0] == 0: slopes = [] + else: slopes = [(infinity.infinity, e[0])] points = [(e[0], c[0].valuation(p)), (e[1], c[1].valuation(p))] slopes.append((-(c[1].valuation(p)-c[0].valuation(p))/(e[1] - e[0]), e[1]-e[0])) @@ -6468,8 +6463,8 @@ cdef class Polynomial(CommutativePolynomial): slopes = slopes[:-1] points = points[:-1] s = -(v-points[-1][1])/(e[i]-points[-1][0]) - slopes.append((s, e[i] - points[-1][0])) - points.append((e[i], v)) + slopes.append((s,e[i]-points[-1][0])) + points.append((e[i],v)) return slopes @@ -6513,7 +6508,7 @@ cdef class Polynomial(CommutativePolynomial): if m != n or p[n] != q[n]: continue alpha = (q[n-1] - p[n-1])/(n*p[n]) - if alpha.is_integer(): # ZZ() might work for non-integers... + if alpha.is_integer(): # ZZ() might work for non-integers... alpha = ZZ(alpha) else: continue @@ -7183,7 +7178,7 @@ cdef class Polynomial(CommutativePolynomial): if Sf is not QQ or (d1 <= N and d2 <= N): algorithm = "resultant" else: - c = d1*sum(bool(p1[i]) for i in range(d1 + 1)) * \ + c = d1*sum(bool(p1[i]) for i in range(d1 + 1))*\ d2*sum(bool(p2[i]) for i in range(d2 + 1)) if c <= N**4: algorithm = "resultant" @@ -7596,7 +7591,8 @@ cdef class Polynomial(CommutativePolynomial): return self # return 0 n = self.degree() base_ring = self._parent.base_ring() - if (is_MPolynomialRing(base_ring) or is_PowerSeriesRing(base_ring)): + if (is_MPolynomialRing(base_ring) or + is_PowerSeriesRing(base_ring)): # It is often cheaper to compute discriminant of simple # multivariate polynomial and substitute the real # coefficients into that result (see #16014). @@ -7605,13 +7601,13 @@ cdef class Polynomial(CommutativePolynomial): k = d.degree() r = n % 4 - u = -1 # (-1)**(n*(n-1)/2) + u = -1 # (-1)**(n*(n-1)/2) if r == 0 or r == 1: u = 1 try: an = self.get_coeff_c(n)**(n - k - 2) except ZeroDivisionError: - assert (n-k-2 == -1) + assert(n-k-2 == -1) # Rather than dividing the resultant by the leading coefficient, # we alter the Sylvester matrix (see #11782). mat = self.sylvester_matrix(d) @@ -7660,14 +7656,14 @@ cdef class Polynomial(CommutativePolynomial): if degree is not None: d = degree if d != degree: - raise ValueError("degree argument must be a non-negative integer, got %s" % (degree)) + raise ValueError("degree argument must be a non-negative integer, got %s"%(degree)) if len(v) < degree+1: v.reverse() v = [self.base_ring().zero()]*(degree+1-len(v)) + v elif len(v) > degree+1: v = v[:degree+1] v.reverse() - else: # len(v) == degree + 1 + else: # len(v) == degree + 1 v.reverse() else: v.reverse() @@ -8422,9 +8418,9 @@ cdef class Polynomial(CommutativePolynomial): sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)) output_fp = isinstance(L, (sage.rings.abc.RealField, - sage.rings.abc.ComplexField, - sage.rings.abc.RealDoubleField, - sage.rings.abc.ComplexDoubleField)) + sage.rings.abc.ComplexField, + sage.rings.abc.RealDoubleField, + sage.rings.abc.ComplexDoubleField)) input_complex = isinstance(K, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) output_complex = isinstance(L, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField)) input_gaussian = (isinstance(K, sage.rings.abc.NumberField_quadratic) @@ -8507,20 +8503,20 @@ cdef class Polynomial(CommutativePolynomial): from sage.symbolic.constants import I coeffs = self.list() D = coeffs[1]*coeffs[1] - 4*coeffs[0]*coeffs[2] - l0 = None + l = None if D > 0: - l0 = [((-coeffs[1] - sqrt(D)) / 2 / coeffs[2], 1), - ((-coeffs[1] + sqrt(D)) / 2 / coeffs[2], 1)] + l = [((-coeffs[1]-sqrt(D))/2/coeffs[2], 1), + ((-coeffs[1]+sqrt(D))/2/coeffs[2], 1)] elif D < 0: - l0 = [((-coeffs[1] - I * sqrt(-D)) / 2 / coeffs[2], 1), - ((-coeffs[1] + I * sqrt(-D)) / 2 / coeffs[2], 1)] + l = [((-coeffs[1]-I*sqrt(-D))/2/coeffs[2], 1), + ((-coeffs[1]+I*sqrt(-D))/2/coeffs[2], 1)] elif D == 0: - l0 = [(-coeffs[1] / 2 / coeffs[2], 2)] - if l0: + l = [(-coeffs[1]/2/coeffs[2], 2)] + if l: if multiplicities: - return l0 + return l else: - return [val for val, m in l0] + return [val for val,m in l] from sage.symbolic.ring import SR vname = 'do_not_use_this_name_in_a_polynomial_coefficient' var = SR(vname) @@ -8538,7 +8534,7 @@ cdef class Polynomial(CommutativePolynomial): # and complex root isolation and for p-adic factorization if (is_IntegerRing(K) or is_RationalField(K) or isinstance(K, sage.rings.abc.AlgebraicRealField)) and \ - isinstance(L, (sage.rings.abc.AlgebraicRealField, sage.rings.abc.RealIntervalField)): + isinstance(L, (sage.rings.abc.AlgebraicRealField, sage.rings.abc.RealIntervalField)): from sage.rings.polynomial.real_roots import real_roots @@ -8568,7 +8564,7 @@ cdef class Polynomial(CommutativePolynomial): if (is_IntegerRing(K) or is_RationalField(K) or isinstance(K, sage.rings.abc.AlgebraicField_common) or input_gaussian) and \ - isinstance(L, (sage.rings.abc.ComplexIntervalField, sage.rings.abc.AlgebraicField_common)): + isinstance(L, (sage.rings.abc.ComplexIntervalField, sage.rings.abc.AlgebraicField_common)): from sage.rings.polynomial.complex_roots import complex_roots @@ -8686,7 +8682,7 @@ cdef class Polynomial(CommutativePolynomial): pass else: if multiplicities: - seq.append((rt, fac[1])) + seq.append((rt,fac[1])) else: seq.append(rt) return seq @@ -9092,7 +9088,7 @@ cdef class Polynomial(CommutativePolynomial): coeffs = [] m = Q.degree() // 2 for i in reversed(range(m + 1)): - coeffs.insert(0, Q[2*i]) # Note: degree of Q may be less than 2*i + coeffs.insert(0, Q[2*i]) # Note: degree of Q may be less than 2*i Q = (Q % (x**2 + q)**i) // x return S(coeffs), cofactor, q @@ -9298,7 +9294,7 @@ cdef class Polynomial(CommutativePolynomial): if hasattr(self.base_ring(), '_xgcd_univariate_polynomial'): return self.base_ring()._xgcd_univariate_polynomial(self, other) else: - raise NotImplementedError("%s does not provide an xgcd implementation for univariate polynomials" % self.base_ring()) + raise NotImplementedError("%s does not provide an xgcd implementation for univariate polynomials"%self.base_ring()) def rational_reconstruction(self, m, n_deg=None, d_deg=None): r""" @@ -9463,9 +9459,9 @@ cdef class Polynomial(CommutativePolynomial): sF = Pf(self) mF = Pf(m) n, d = sF.rational_reconstruction(mF, n_deg, d_deg) - lc = lcm([n.denominator(), d.denominator()]) - n *= lc - d *= lc + l = lcm([n.denominator(), d.denominator()]) + n *= l + d *= l return P(n), P(d) # n and d are unique if m.degree() > (n.degree() + d.degree()) @@ -9476,9 +9472,9 @@ cdef class Polynomial(CommutativePolynomial): if n_deg < 0 or d_deg < 0: raise ValueError("the degree bounds " - "n_deg and d_deg should be positive") + "n_deg and d_deg should be positive") - # XGCD until degree the degree of t1 surpasses the degree of n + #XGCD until degree the degree of t1 surpasses the degree of n s0 = P(0) t0 = P(1) s1 = P(m) @@ -9587,15 +9583,15 @@ cdef class Polynomial(CommutativePolynomial): _p = self._parent.coerce(p) elif p is infinity.infinity: return -self.degree() - elif is_Ideal(p) and p.ring() is self._parent: # eventually need to handle fractional ideals in the fraction field - if self._parent.base_ring().is_field(): # common case + elif is_Ideal(p) and p.ring() is self._parent: # eventually need to handle fractional ideals in the fraction field + if self._parent.base_ring().is_field(): # common case _p = p.gen() else: raise NotImplementedError else: from sage.rings.fraction_field import is_FractionField if is_FractionField(p.parent()) and self._parent.has_coerce_map_from(p.parent().ring()): - _p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. + _p = self._parent.coerce(p.parent().ring()(p)) # here we require that p be integral. else: raise TypeError("The polynomial, p, must have the same parent as self.") @@ -10850,13 +10846,13 @@ cdef class Polynomial(CommutativePolynomial): elif n == 1 or self.is_zero() or self.is_one(): return self elif self.degree() % n: - raise ValueError("not a %s power" % Integer(n).ordinal_str()) - elif self.get_unsafe(0).is_zero(): # We know that self is not 0, so it must have degree >= 0 + raise ValueError("not a %s power"%Integer(n).ordinal_str()) + elif self.get_unsafe(0).is_zero(): # We know that self is not 0, so it must have degree >= 0 # p = x^k q # p^(1/n) = x^(k/n) q^(1/n) i = self.valuation() - if i % n: - raise ValueError("not a %s power" % Integer(n).ordinal_str()) + if i%n: + raise ValueError("not a %s power"%Integer(n).ordinal_str()) return (self >> i).nth_root(n) << (i // n) if self.get_unsafe(0).is_one(): @@ -10875,7 +10871,7 @@ cdef class Polynomial(CommutativePolynomial): if q**n == p: return S(q) else: - raise ValueError("not a %s power" % Integer(n).ordinal_str()) + raise ValueError("not a %s power"%Integer(n).ordinal_str()) def _nth_root_series(self, long n, long prec, start=None): r""" @@ -10968,12 +10964,12 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("n (={}) must be positive".format(m)) elif m.is_one() or self.is_zero() or self.is_one(): return self - elif self.get_unsafe(0).is_zero(): # we know that self is not zero, so the degree >= 0 + elif self.get_unsafe(0).is_zero(): # we know that self is not zero, so the degree >= 0 # p = x^i q # p^(1/m) = x^(i/m) q^(1/m) i = self.valuation() if i % m: - raise ValueError("not a %s power" % m.ordinal_str()) + raise ValueError("not a %s power"%m.ordinal_str()) return (self >> i)._nth_root_series(m, prec - i // m) << (i // m) else: c = R.characteristic() @@ -10985,7 +10981,7 @@ cdef class Polynomial(CommutativePolynomial): for i in range(self.degree()+1): if self.get_unsafe(i): if i % cc: - raise ValueError("not a %s power" % m.ordinal_str()) + raise ValueError("not a %s power"%m.ordinal_str()) ans[i//cc] = self.get_unsafe(i).nth_root(cc) p = self._parent(ans) m = m // cc @@ -11081,16 +11077,12 @@ cdef class Polynomial(CommutativePolynomial): if not self.base_ring().is_integral_domain(): raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - if p.is_zero(): - return True # everything divides 0 - if self.is_zero(): - return False # 0 only divides 0 + if p.is_zero(): return True # everything divides 0 + if self.is_zero(): return False # 0 only divides 0 try: - if self.is_unit(): - return True # units divide everything + if self.is_unit(): return True # units divide everything except NotImplementedError: - if self.is_one(): - return True # if is_unit is not implemented + if self.is_one(): return True # if is_unit is not implemented if self.degree() > p.degree(): return False @@ -11142,9 +11134,10 @@ cdef class Polynomial(CommutativePolynomial): raise ValueError("either the dictionary or the specialization must be provided") else: from sage.rings.polynomial.flatten import SpecializationMorphism - phi = SpecializationMorphism(self._parent, D) + phi = SpecializationMorphism(self._parent,D) return phi(self) + def _log_series(self, long n): r""" Return the power series expansion of logarithm of this polynomial, @@ -11342,10 +11335,10 @@ cdef list do_schoolbook_product(list x, list y, Py_ssize_t deg): return y elif d1 == 0: c = x[0] - return [c * a for a in y[:deg]] # beware of noncommutative rings + return [c*a for a in y[:deg]] # beware of noncommutative rings elif d2 == 0: c = y[0] - return [a * c for a in x[:deg]] # beware of noncommutative rings + return [a*c for a in x[:deg]] # beware of noncommutative rings coeffs = [None]*deg for k in range(deg): start = 0 if k <= d2 else k-d2 # max(0, k-d2) @@ -11391,10 +11384,10 @@ cdef list do_karatsuba_different_size(list left, list right, Py_ssize_t K_thresh return [] if n == 1: c = left[0] - return [c * a for a in right] + return [c*a for a in right] if m == 1: c = right[0] - return [a * c for a in left] # beware of noncommutative rings + return [a*c for a in left] # beware of noncommutative rings if n <= K_threshold or m <= K_threshold: return do_schoolbook_product(left, right, -1) if n == m: @@ -11441,7 +11434,7 @@ cdef list do_karatsuba_different_size(list left, list right, Py_ssize_t K_thresh @cython.boundscheck(False) @cython.wraparound(False) @cython.overflowcheck(False) -cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold, Py_ssize_t start_l, Py_ssize_t start_r, Py_ssize_t num_elts): +cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold,Py_ssize_t start_l, Py_ssize_t start_r,Py_ssize_t num_elts): """ Core routine for Karatsuba multiplication. This function works for two polynomials of the same degree. @@ -11496,8 +11489,8 @@ cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold, Py_ssize_t d = right[start_r] c = right[start_r+1] return [b*d, a*d+b*c, a*c] - return do_schoolbook_product(left[start_l:start_l + num_elts], - right[start_r:start_r + num_elts], -1) + return do_schoolbook_product(left[start_l:start_l+num_elts], + right[start_r:start_r+num_elts], -1) if num_elts == 2: # beware of noncommutative rings b = left[start_l] @@ -11531,7 +11524,7 @@ cdef list do_karatsuba(list left, list right, Py_ssize_t K_threshold, Py_ssize_t bd[e+i] = bd[e+i] + tt1[i] bd.append(tt1[e-1]) for i from 0 <= i < lenac -e: - ac[i] = ac[i] + tt1[e + i] + ac[i] = ac[i] + tt1[e+i] return bd + ac @@ -11610,10 +11603,10 @@ cdef class Polynomial_generic_dense(Polynomial): check = 0 elif not isinstance(x, (list, tuple)): # We trust that the element constructors do not send x=0 - # if x: +# if x: x = [x] # constant polynomials - # else: - # x = [] # zero polynomial +# else: +# x = [] # zero polynomial if check: self._coeffs = [R(z, **kwds) for z in x] self._normalize() @@ -11646,9 +11639,9 @@ cdef class Polynomial_generic_dense(Polynomial): Univariate Polynomial Ring in x over Univariate Polynomial Ring in y over Rational Field """ if a: - return self._new_c([a], P) + return self._new_c([a],P) else: - return self._new_c([], P) + return self._new_c([],P) def __reduce__(self): """ @@ -11717,7 +11710,7 @@ cdef class Polynomial_generic_dense(Polynomial): for i in range(ell): v[i+d] = c * x[i] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - # if not v[len(v)-1]: + #if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -11860,7 +11853,7 @@ cdef class Polynomial_generic_dense(Polynomial): 2*y*x^3 + (y + 3)*x^2 + (-2*y + 1)*x + 1 """ cdef Polynomial_generic_dense res - cdef Py_ssize_t check = 0, i, min + cdef Py_ssize_t check=0, i, min x = (self)._coeffs y = (right)._coeffs if len(x) > len(y): @@ -11881,7 +11874,7 @@ cdef class Polynomial_generic_dense(Polynomial): cpdef _sub_(self, right): cdef Polynomial_generic_dense res - cdef Py_ssize_t check = 0, i, min + cdef Py_ssize_t check=0, i, min x = (self)._coeffs y = (right)._coeffs if len(x) > len(y): @@ -11907,7 +11900,7 @@ cdef class Polynomial_generic_dense(Polynomial): c = (self._coeffs[0])._parent.coerce(c) v = [c * a for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - # if not v[len(v)-1]: + #if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -11919,7 +11912,7 @@ cdef class Polynomial_generic_dense(Polynomial): c = (self._coeffs[0])._parent.coerce(c) v = [a * c for a in self._coeffs] cdef Polynomial_generic_dense res = self._new_c(v, self._parent) - # if not v[len(v)-1]: + #if not v[len(v)-1]: # "normalize" checks this anyway... res._normalize() return res @@ -12128,7 +12121,7 @@ cdef class Polynomial_generic_dense(Polynomial): quo.append(q) quo.reverse() - return self._new_c(quo, self._parent), self._new_c(x, self._parent)._inplace_truncate(n-1) + return self._new_c(quo,self._parent), self._new_c(x,self._parent)._inplace_truncate(n-1) cpdef Polynomial truncate(self, long n): r""" @@ -12157,10 +12150,10 @@ cdef class Polynomial_generic_dense(Polynomial): sage: type(f) """ - ln = len(self._coeffs) - if n > ln: - n = ln - while n > 0 and not self._coeffs[n - 1]: + l = len(self._coeffs) + if n > l: + n = l + while n > 0 and not self._coeffs[n-1]: n -= 1 return self._new_c(self._coeffs[:n], self._parent) @@ -12171,7 +12164,6 @@ cdef class Polynomial_generic_dense(Polynomial): self._coeffs = self._coeffs[:n] return self - def make_generic_polynomial(parent, coeffs): return parent(coeffs) @@ -12213,7 +12205,7 @@ def universal_discriminant(n): pr1 = PolynomialRing(ZZ, n + 1, 'a') pr2 = PolynomialRing(pr1, 'x') p = pr2(list(pr1.gens())) - return (1 - (n & 2)) * p.resultant(p.derivative()) // pr1.gen(n) + return (1 - (n&2))*p.resultant(p.derivative())//pr1.gen(n) cpdef Polynomial generic_power_trunc(Polynomial p, Integer n, long prec): @@ -12309,7 +12301,7 @@ cpdef list _dict_to_list(dict x, zero): return [] n = max(x.keys()) cdef list v - if isinstance(n, tuple): # a mpoly dict + if isinstance(n, tuple): # a mpoly dict n = n[0] v = [zero] * (n+1) for i, z in x.iteritems(): From 5f215beed284d864663931cd95bdd067918c832c Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Sun, 1 Oct 2023 11:32:17 +0200 Subject: [PATCH 064/538] undo format changes for matrix_space.py --- src/sage/matrix/matrix_space.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 04ab6b138a2..905b6fcc779 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -802,7 +802,7 @@ def transposed(self): Full MatrixSpace of 3 by 2 dense matrices over Integer Ring """ return MatrixSpace(self._base, self.__ncols, self.__nrows, - self.__is_sparse, self.Element) + self.__is_sparse, self.Element) @lazy_attribute def _copy_zero(self): @@ -2186,7 +2186,7 @@ def row_space(self): return self.__row_space except AttributeError: self.__row_space = sage.modules.free_module.FreeModule(self.base_ring(), - self.ncols(), sparse=self.is_sparse()) + self.ncols(), sparse=self.is_sparse()) return self.__row_space def column_space(self): @@ -2204,7 +2204,7 @@ def column_space(self): return self.__column_space except AttributeError: self.__column_space = sage.modules.free_module.FreeModule(self.base_ring(), self.nrows(), - sparse=self.is_sparse()) + sparse=self.is_sparse()) return self.__column_space def random_element(self, density=None, *args, **kwds): @@ -2262,10 +2262,10 @@ def random_element(self, density=None, *args, **kwds): Z = self.zero_matrix().__copy__() if density is None: Z.randomize(density=float(1), nonzero=kwds.pop('nonzero', False), - *args, **kwds) + *args, **kwds) else: Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), - *args, **kwds) + *args, **kwds) return Z def _an_element_(self): @@ -2589,13 +2589,13 @@ def _MatrixSpace_ZZ_2x2(): register_unpickle_override('sage.matrix.matrix_modn_dense', - 'Matrix_modn_dense', Matrix_modn_dense_double) + 'Matrix_modn_dense', Matrix_modn_dense_double) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'Matrix_integer_2x2', Matrix_integer_dense) + 'Matrix_integer_2x2', Matrix_integer_dense) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2_class', MatrixSpace) + 'MatrixSpace_ZZ_2x2_class', MatrixSpace) register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) + 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) lazy_import('sage.matrix.matrix_gf2e_dense', 'unpickle_matrix_gf2e_dense_v0') register_unpickle_override('sage.matrix.matrix_mod2e_dense', - 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) + 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) From 2a244659f345684656ac77fdee70f70adc45b33d Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 9 Oct 2023 20:07:00 -0600 Subject: [PATCH 065/538] after first review --- .../matrix_laurent_mpolynomial_dense.pyx | 7 ++----- .../rings/polynomial/laurent_polynomial.pyx | 21 ++++++++++++------- .../polynomial/laurent_polynomial_ideal.py | 10 +++++++++ .../polynomial/laurent_polynomial_mpair.pyx | 7 ++++++- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 3f0c1e968f2..31ccba6c5d7 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -1,12 +1,9 @@ """ -Dense matrices over multivariate polynomials over fields - -This implementation inherits from Matrix_generic_dense, i.e. it is not -optimized for speed only some methods were added. +Dense matrices over multivariate polynomials over fields. AUTHOR: -* Enrique Artal +- Enrique Artal (2023-??): initial version """ # ***************************************************************************** diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index f0ccb4e2ce0..c69859d443c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1325,10 +1325,17 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: S. = LaurentPolynomialRing(QQ) sage: (t^-2 + 1).xgcd(t^-3 + 1) (1, 1/2*t^2 - 1/2*t^3 - 1/2*t^4, 1/2*t^3 + 1/2*t^4) + sage: R. = LaurentPolynomialRing(ZZ) + sage: f = 2*x^-2 - x^-1 + 4 + x + 139*x^2 - 5*x^3 + sage: g = -2 - x + 5*x^2 + 4*x^3 - x^4 + x^5 + sage: f.xgcd(g) + Traceback (most recent call last): + ... + NotImplementedError: only implemented when the base ring is an exact field """ R = self.parent() - if not R.is_exact() or not R.base_ring().is_field: - raise NotImplementedError("Not implemented") + if not R.is_exact() or not R.base_ring().is_field(): + raise NotImplementedError("only implemented when the base ring is an exact field") S = R.polynomial_ring() f, df = self.monomial_reduction() g, dg = other.monomial_reduction() @@ -1369,14 +1376,13 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): if u.is_unit(): return a.parent()(~u) if not a.parent().is_exact(): - raise NotImplementedError("Not implemented") + raise NotImplementedError("only implemented when the base ring is exact") g, s, _ = a.xgcd(m) if g == 1: return s elif g.is_unit(): return g.inverse_of_unit() * s - else: - raise ValueError("Impossible inverse modulo") + raise ValueError("impossible inverse modulo") def _fraction_pair(self): """ @@ -2079,7 +2085,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): ... NotImplementedError: divisibility test only implemented for Laurent polynomials over an integral domain - sage: R. = GF(2)[] sage: S. = LaurentPolynomialRing(R) sage: p = (x+y+1) * z**-1 + x*y @@ -2087,10 +2092,10 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ - if not self.base_ring().is_integral_domain(): + if not self._parent.base_ring().is_integral_domain(): raise NotImplementedError("divisibility test only implemented for Laurent polynomials over an integral domain") - R = self.parent().polynomial_ring() + R = self._parent.polynomial_ring() p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 81bc095c382..b3b1d391eb4 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -205,6 +205,16 @@ def __contains__(self, f): return (g in self.polynomial_ideal()) def gens_reduced(self): + """ + A reduced system of generators. + + EXAMPLES:: + + sage: P. = LaurentPolynomialRing(QQ) + sage: J = P.ideal([x^2 - y^-2, x * y^3 + 2 * y^2+ y]) + sage: J.gens_reduced() + (x + 6*y + 5, 3*y^2 + 4*y + 1) + """ R = self.ring() J = self.polynomial_ideal() return tuple(R(p) for p in J.gens()) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index fe199d281e3..e8b919b437e 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1856,9 +1856,14 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): return ans def divides(self, other): - R = self.parent().polynomial_ring() + """ + Check if `self` divides `other` + """ + R = self._parent.polynomial_ring() if not R.base_ring().is_integral_domain(): raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") + if other.parent() != R: + return None p = R(self.monomial_reduction()[0]) q = R(other.monomial_reduction()[0]) return p.divides(q) From cc813a04bbc5501525ebdd8825c91fe9a7b9cab0 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 10 Oct 2023 09:47:51 -0600 Subject: [PATCH 066/538] changes in divides --- src/sage/rings/polynomial/laurent_polynomial.pyx | 5 +---- .../rings/polynomial/laurent_polynomial_ideal.py | 2 +- .../polynomial/laurent_polynomial_mpair.pyx | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index c69859d443c..fba83a5ff42 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -2083,7 +2083,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p.divides(q) Traceback (most recent call last): ... - NotImplementedError: divisibility test only implemented for Laurent polynomials over an integral domain + NotImplementedError: divisibility test only implemented for polynomials over an integral domain sage: R. = GF(2)[] sage: S. = LaurentPolynomialRing(R) @@ -2092,9 +2092,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ - if not self._parent.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for Laurent polynomials over an integral domain") - R = self._parent.polynomial_ring() p = R(self.polynomial_construction()[0]) q = R(other.polynomial_construction()[0]) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index b3b1d391eb4..0d5a6ad38ce 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -92,7 +92,7 @@ def __init__(self, ring, gens, coerce=True, hint=None): """ Ideal_generic.__init__(self, ring, gens, coerce=coerce) self._poly_ring = ring.polynomial_ring() - self._poly_ideal = None # Create only as needed + self._poly_ideal = None # Create only as needed self._saturated = False self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) # if hint is None: diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index e8b919b437e..fe7c0bdd787 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1858,12 +1858,20 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): def divides(self, other): """ Check if `self` divides `other` + + EXAMPLES:: + + sage: R. = LaurentPolynomialRing(QQ) + sage: f1 = x^-2*y^3 - 9 - 1/14*x^-1*y - 1/3*x^-1 + sage: h = 3*x^-1 - 3*x^-2*y - 1/2*x^-3*y^2 - x^-3*y + x^-3 + sage: f2 = f1 * h + sage: f3 = f2 + x * y + sage: f1.divides(f2) + True + sage: f1.divides(f3) + False """ R = self._parent.polynomial_ring() - if not R.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - if other.parent() != R: - return None p = R(self.monomial_reduction()[0]) q = R(other.monomial_reduction()[0]) return p.divides(q) From d68f6a5625fb661c12475099ef0f2c3155be19ce Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 13 Oct 2023 07:51:57 -0600 Subject: [PATCH 067/538] trick to solve the hint issue --- src/sage/rings/polynomial/ideal.py | 15 +++++++++++++++ src/sage/rings/polynomial/laurent_polynomial.pyx | 9 --------- .../rings/polynomial/laurent_polynomial_ideal.py | 10 +++++----- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index 1ab86736d5b..e61b6de3f39 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -85,3 +85,18 @@ def groebner_basis(self, algorithm=None): gb = self.gens_reduced() from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence_generic return PolynomialSequence_generic([gb], self.ring(), immutable=True) + + def change_ring(self, R): + """ + Coerce an ideal into a new ring. + + EXAMPLES:: + + sage: P. = LaurentPolynomialRing(QQ, 2) + sage: I = P.ideal([x + y]) + sage: Q. = LaurentPolynomialRing(QQ, 3) + sage: I.change_ring(Q) + Ideal (x + y) of Multivariate Laurent Polynomial Ring in x, y, z + over Rational Field + """ + return R.ideal(self.gens()) diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index fba83a5ff42..748a07f7270 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1325,17 +1325,8 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: S. = LaurentPolynomialRing(QQ) sage: (t^-2 + 1).xgcd(t^-3 + 1) (1, 1/2*t^2 - 1/2*t^3 - 1/2*t^4, 1/2*t^3 + 1/2*t^4) - sage: R. = LaurentPolynomialRing(ZZ) - sage: f = 2*x^-2 - x^-1 + 4 + x + 139*x^2 - 5*x^3 - sage: g = -2 - x + 5*x^2 + 4*x^3 - x^4 + x^5 - sage: f.xgcd(g) - Traceback (most recent call last): - ... - NotImplementedError: only implemented when the base ring is an exact field """ R = self.parent() - if not R.is_exact() or not R.base_ring().is_field(): - raise NotImplementedError("only implemented when the base ring is an exact field") S = R.polynomial_ring() f, df = self.monomial_reduction() g, dg = other.monomial_reduction() diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 0d5a6ad38ce..7b3b3a12ad3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -94,11 +94,11 @@ def __init__(self, ring, gens, coerce=True, hint=None): self._poly_ring = ring.polynomial_ring() self._poly_ideal = None # Create only as needed self._saturated = False - self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) - # if hint is None: - # self._hint = self._poly_ring.zero_ideal() - # else: - # self._hint = hint.change_ring(self._poly_ring) + # self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) + if hint is None: + self._hint = self._poly_ring.zero_ideal() + else: + self._hint = hint.change_ring(self._poly_ring) def set_hint(self, hint): """ From fe045a2a5eceb4f73dd53e20097d60b56697aba1 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 16 Oct 2023 16:09:22 +0200 Subject: [PATCH 068/538] descripion of Laurent matrix class --- src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 31ccba6c5d7..3794854e222 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -32,7 +32,7 @@ from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomial cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): """ - Dense matrix over a multivariate polynomial ring over a field. + Dense matrix over a Laurent multivariate polynomial ring over a field. """ def laurent_matrix_reduction(self): """ From 59e7c09eb75e8ca578e2ff56106cf6c1eba6b571 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 17 Oct 2023 17:58:56 +0200 Subject: [PATCH 069/538] tests polynomial ideal --- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 7b3b3a12ad3..c556e1a7205 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -114,7 +114,7 @@ def set_hint(self, hint): sage: P. = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.hint() - Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field sage: I.set_hint(P.polynomial_ring().ideal([x + 3*y])) sage: I.hint() Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field @@ -135,7 +135,7 @@ def hint(self): sage: P. = LaurentPolynomialRing(QQ, 3) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.hint() - Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field + Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field """ return self._hint From 01977ca18e1a818c73a0014f7568094891212f75 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 23 Oct 2023 09:08:51 +0200 Subject: [PATCH 070/538] changes from revision october 23rd --- .../matrix/matrix_laurent_mpolynomial_dense.pxd | 6 ++++++ .../matrix/matrix_laurent_mpolynomial_dense.pyx | 17 ++++------------- .../rings/polynomial/laurent_polynomial.pyx | 12 ++++-------- .../polynomial/laurent_polynomial_ideal.py | 6 +++--- .../polynomial/laurent_polynomial_mpair.pyx | 5 ++++- 5 files changed, 21 insertions(+), 25 deletions(-) create mode 100644 src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd new file mode 100644 index 00000000000..4679933c7f5 --- /dev/null +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd @@ -0,0 +1,6 @@ +from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense + +from sage.libs.singular.decl cimport ideal + +cdef class Matrix_Laurent_mpolynomial_dense(Matrix_generic_dense): + pass diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 3794854e222..775f6318bac 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -16,17 +16,6 @@ AUTHOR: # ***************************************************************************** from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense -# from sage.matrix.matrix2 cimport Matrix -# -# from sage.matrix.constructor import identity_matrix -# from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic -# from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular -# from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular -# -# from sage.libs.singular.function import singular_function, lib -# -# from cysignals.signals cimport sig_on, sig_off - from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic @@ -40,8 +29,10 @@ cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense): to obtain a matrix `P` of polynomials such that the variables do not divide no column and no row. - OUTPUT: Three matrices `L`, `P`, `R` such that `self = L P R`, where `L` and - `R` are diagonal with monomial entries. + OUTPUT: + + Three matrices `L`, `P`, `R` such that ``self` equals `L P R`, where `L` and + `R` are diagonal with monomial entries. EXAMPLES: diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 748a07f7270..91619cdfd69 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -1341,6 +1341,9 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): The parameter ``m`` may be either a single polynomial or an ideal (for consistency with :meth:`inverse_mod` in other rings). + ALGORITHM: Solve the system `as + mt = 1`, returning `s` as the inverse + of `a` mod `m`. + EXAMPLES:: sage: S. = LaurentPolynomialRing(QQ) @@ -1348,15 +1351,12 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): 1/2*t^2 - 1/2*t^3 - 1/2*t^4 sage: f * (t^-2 + 1) + (1/2*t^4 + 1/2*t^3) * (t^-3 + 1) 1 - - ALGORITHM: Solve the system `as + mt = 1`, returning `s` as the inverse - of `a` mod `m`. """ from sage.rings.ideal import is_Ideal if is_Ideal(m): v = m.gens_reduced() if len(v) > 1: - raise NotImplementedError("Don't know how to invert modulo non-principal ideal %s" % m) + raise NotImplementedError("only inversion modulo principal ideals implemented") m = v[0] if m.degree() == 1 and m[1].is_unit(): # a(x) mod (x-r) = a(r) @@ -1366,8 +1366,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): u = a(r) if u.is_unit(): return a.parent()(~u) - if not a.parent().is_exact(): - raise NotImplementedError("only implemented when the base ring is exact") g, s, _ = a.xgcd(m) if g == 1: return s @@ -2053,8 +2051,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): r""" Return ``True`` if ``self`` divides ``other``. - This method is only implemented for Laurent polynomials over an integral domain. - EXAMPLES:: sage: R. = LaurentPolynomialRing(ZZ) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index c556e1a7205..1b836305af1 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -206,7 +206,7 @@ def __contains__(self, f): def gens_reduced(self): """ - A reduced system of generators. + A reduced system of generators. EXAMPLES:: @@ -217,7 +217,7 @@ def gens_reduced(self): """ R = self.ring() J = self.polynomial_ideal() - return tuple(R(p) for p in J.gens()) + return tuple([R(p) for p in J.gens()]) # Operations on ideals @@ -423,7 +423,7 @@ def polynomial_ideal(self, saturate=True): Q = self._poly_ring if len(P.gens()) == 1: a = [Q(p.polynomial_construction()[0]) for p in self.gens()] - if P.is_integral_domain(): + if P.base_ring().is_field(): a = GCD(a) return Q.ideal(a) if self._poly_ideal is not None and (self._saturated or not saturate): diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index fe7c0bdd787..27c31754d8f 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1855,9 +1855,10 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): return new_ring(ans) return ans + @coerce_binop def divides(self, other): """ - Check if `self` divides `other` + Check if ``self`` divides ``other`` EXAMPLES:: @@ -1870,6 +1871,8 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): True sage: f1.divides(f3) False + sage: f1.divides(3) + False """ R = self._parent.polynomial_ring() p = R(self.monomial_reduction()[0]) From 314c4bb23283b0b9a155db6e2e4d41f7e0396f4c Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Mon, 23 Oct 2023 11:50:19 +0200 Subject: [PATCH 071/538] change position of conditional in divides --- .../polynomial/laurent_polynomial_ring.py | 1 + .../rings/polynomial/polynomial_element.pyx | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 22d97975cd6..fdc04260001 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -443,6 +443,7 @@ def __init__(self, R): TESTS:: sage: TestSuite(LaurentPolynomialRing(Zmod(2), 'y')).run() + sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() sage: TestSuite(LaurentPolynomialRing(Zmod(2)['T'], 'u')).run() """ diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index a5b7f937cfe..7e006973db3 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -11074,15 +11074,19 @@ cdef class Polynomial(CommutativePolynomial): sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ - if not self.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - - if p.is_zero(): return True # everything divides 0 - if self.is_zero(): return False # 0 only divides 0 + if p.is_zero(): + return True # everything divides 0 + if self.is_zero(): + return False # 0 only divides 0 try: - if self.is_unit(): return True # units divide everything + if self.is_unit(): + return True # units divide everything except NotImplementedError: - if self.is_one(): return True # if is_unit is not implemented + if self.is_one(): + return True # if is_unit is not implemented + + if not self.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") if self.degree() > p.degree(): return False From 72a36de551a5d05841c6e025a76e2e54bdff6821 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 24 Oct 2023 14:37:14 +0200 Subject: [PATCH 072/538] revision october 24th --- .../matrix_laurent_mpolynomial_dense.pxd | 2 -- .../matrix_laurent_mpolynomial_dense.pyx | 2 -- .../rings/polynomial/laurent_polynomial.pyx | 9 +++----- .../polynomial/laurent_polynomial_ideal.py | 22 ++++++++++++++++--- .../polynomial/laurent_polynomial_mpair.pyx | 5 ++--- .../polynomial/laurent_polynomial_ring.py | 1 + 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd index 4679933c7f5..2a1170d0bc5 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd @@ -1,6 +1,4 @@ from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense -from sage.libs.singular.decl cimport ideal - cdef class Matrix_Laurent_mpolynomial_dense(Matrix_generic_dense): pass diff --git a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx index 775f6318bac..1f345a68ba6 100644 --- a/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx +++ b/src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx @@ -14,8 +14,6 @@ AUTHOR: # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense - from sage.matrix.constructor import identity_matrix from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 91619cdfd69..1e04abe3bf5 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -2068,9 +2068,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p = 4*x + 3*x^-1 sage: q = 5*x^2 + x + 2*x^-2 sage: p.divides(q) - Traceback (most recent call last): - ... - NotImplementedError: divisibility test only implemented for polynomials over an integral domain + False sage: R. = GF(2)[] sage: S. = LaurentPolynomialRing(R) @@ -2079,7 +2077,6 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) """ - R = self._parent.polynomial_ring() - p = R(self.polynomial_construction()[0]) - q = R(other.polynomial_construction()[0]) + p = self.polynomial_construction()[0] + q = other.polynomial_construction()[0] return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 1b836305af1..43f9bca511c 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -94,7 +94,6 @@ def __init__(self, ring, gens, coerce=True, hint=None): self._poly_ring = ring.polynomial_ring() self._poly_ideal = None # Create only as needed self._saturated = False - # self._hint = self._poly_ring.ideal([f.monomial_reduction()[0] for f in self.gens()]) if hint is None: self._hint = self._poly_ring.zero_ideal() else: @@ -194,6 +193,14 @@ def __contains__(self, f): sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: x + 3*y in I True + sage: I.gen(0).__reduce__() + (Multivariate Laurent Polynomial Ring in x, y over Rational Field, + (x^2*y + 3*x*y^2, (0, 0))) + sage: P. = LaurentPolynomialRing(QQ, 1) + sage: I = P.ideal([x^2 + 3*x]) + sage: I.gen(0).__reduce__() # Check the differences of __reduce__ for distinct Laurent polynomial rings + (Multivariate Laurent Polynomial Ring in x over Rational Field, + (x^2 + 3*x, (0,))) """ if not f or f in self.gens(): return True @@ -416,8 +423,17 @@ def polynomial_ideal(self, saturate=True): sage: P. = LaurentPolynomialRing(QQ, 2) sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: I.polynomial_ideal() - Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y - over Rational Field + Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y over Rational Field + sage: P. = LaurentPolynomialRing(QQ) + sage: J = P.ideal(t^2 - t^-1) + sage: J.polynomial_ideal() + Principal ideal (t^3 - 1) of Univariate Polynomial Ring in t over Rational Field + sage: J = P.ideal([t^2 - t^-1, t + t^-1]) + sage: J.polynomial_ideal() + Principal ideal (1) of Univariate Polynomial Ring in t over Rational Field + sage: J = P.ideal([t^2 - t^-1, t - t^-1]) + sage: J.polynomial_ideal() + Principal ideal (t - 1) of Univariate Polynomial Ring in t over Rational Field """ P = self.ring() Q = self._poly_ring diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 27c31754d8f..470c3b4ecc3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1874,7 +1874,6 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: f1.divides(3) False """ - R = self._parent.polynomial_ring() - p = R(self.monomial_reduction()[0]) - q = R(other.monomial_reduction()[0]) + p = self.monomial_reduction()[0] + q = other.monomial_reduction()[0] return p.divides(q) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index fdc04260001..812a4b3a351 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -446,6 +446,7 @@ def __init__(self, R): sage: TestSuite(LaurentPolynomialRing(Zmod(4), 'y')).run() sage: TestSuite(LaurentPolynomialRing(ZZ, 'u')).run() sage: TestSuite(LaurentPolynomialRing(Zmod(2)['T'], 'u')).run() + sage: TestSuite(LaurentPolynomialRing(Zmod(4)['T'], 'u')).run() """ if R.ngens() != 1: raise ValueError("must be 1 generator") From a859ac2863821f89a82b8539457e3a0f732002ca Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 24 Oct 2023 08:23:45 -0400 Subject: [PATCH 073/538] src/sage/misc/latex.py: fix view() Rewriting the view() function to use python's tempfile module instead of sage's own tmp_dir() accidentally broke this function, because the viewer program needs the file to be slightly less temporary than we made it. The viewer would launch, but then view() would immediately return, causing the file that the viewer was about to look for to be deleted. To fix it, we now launch the viewer program synchronously within a helper function, but launch that helper function asynchronously in a new thread. This allows us to clean up the temporary directory only after the subprocess has completed, but still lets view() return immediately. Closes: https://github.com/sagemath/sage/issues/36526 --- src/sage/misc/latex.py | 65 ++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index e0d32725cec..602a24f404a 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -29,7 +29,7 @@ import random import re import shutil -from subprocess import call, PIPE +from subprocess import call, run, PIPE from tempfile import TemporaryDirectory from sage.misc.cachefunc import cached_function, cached_method @@ -1923,27 +1923,48 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, if pdflatex or (viewer == "pdf" and engine == "latex"): engine = "pdflatex" # command line or notebook with viewer - with TemporaryDirectory() as tmp: - tex_file = os.path.join(tmp, "sage.tex") - with open(tex_file, 'w') as file: - file.write(s) - suffix = _run_latex_(tex_file, debug=debug, engine=engine, png=False) - if suffix == "pdf": - from sage.misc.viewer import pdf_viewer - viewer = pdf_viewer() - elif suffix == "dvi": - from sage.misc.viewer import dvi_viewer - viewer = dvi_viewer() - else: - print("Latex error") - return - output_file = os.path.join(tmp, "sage." + suffix) - # this should get changed if we switch the stuff in misc.viewer to - # producing lists - if debug: - print('viewer: "{}"'.format(viewer)) - call('%s %s' % (viewer, output_file), shell=True, - stdout=PIPE, stderr=PIPE) + + # We can't automatically delete the temporary file in this case + # because we need it to live at least long enough for the viewer + # to open it. Since we're launching the viewer asynchronously, + # that would be tricky. + tmp = TemporaryDirectory() + + tex_file = os.path.join(tmp.name, "sage.tex") + with open(tex_file, 'w') as file: + file.write(s) + suffix = _run_latex_(tex_file, debug=debug, engine=engine, png=False) + if suffix == "pdf": + from sage.misc.viewer import pdf_viewer + viewer = pdf_viewer() + elif suffix == "dvi": + from sage.misc.viewer import dvi_viewer + viewer = dvi_viewer() + else: + print("Latex error") + tmp.cleanup() + return + output_file = os.path.join(tmp.name, "sage." + suffix) + # this should get changed if we switch the stuff in misc.viewer to + # producing lists + if debug: + print('viewer: "{}"'.format(viewer)) + + # Return immediately but only clean up the temporary file after + # the viewer has closed. This function is synchronous and waits + # for the process to complete... + def run_viewer(): + run([viewer, output_file], capture_output=True) + tmp.cleanup() + + # ...but we execute it asynchronously so that view() completes + # immediately. The "daemon" flag is important because, without it, + # sage won't quit until the viewer does. + from threading import Thread + t = Thread(target=run_viewer) + t.daemon = True + t.start() + return From 146508ebf4b48566127b1e92260b292d184c98bc Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 24 Oct 2023 22:57:38 +0200 Subject: [PATCH 074/538] forgot to push polynomial_element.pyx --- .../rings/polynomial/polynomial_element.pyx | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 7e006973db3..e6fc136df5e 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -11047,10 +11047,10 @@ cdef class Polynomial(CommutativePolynomial): sage: R. = Zmod(6)[] sage: p = 4*x + 3 sage: q = 5*x**2 + x + 2 + sage: q.divides(p) + False sage: p.divides(q) - Traceback (most recent call last): - ... - NotImplementedError: divisibility test only implemented for polynomials over an integral domain + False TESTS:: @@ -11073,6 +11073,13 @@ cdef class Polynomial(CommutativePolynomial): sage: q = (y^2-x^2) * z^2 + z + x-y sage: p.divides(q), p.divides(p*q) # needs sage.libs.singular (False, True) + sage: R. = Zmod(6)[] + sage: p = 4*x + 3 + sage: q = 2*x**2 + x + 2 + sage: p.divides(q) + Traceback (most recent call last): + ... + NotImplementedError: divisibility test only implemented for polynomials over an integral domain unless obvious non divisibility of leading terms """ if p.is_zero(): return True # everything divides 0 @@ -11085,19 +11092,19 @@ cdef class Polynomial(CommutativePolynomial): if self.is_one(): return True # if is_unit is not implemented - if not self.base_ring().is_integral_domain(): - raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain") - if self.degree() > p.degree(): return False if not self.leading_coefficient().divides(p.leading_coefficient()): return False + if not self.base_ring().is_integral_domain(): + raise NotImplementedError("divisibility test only implemented for polynomials over an integral domain unless obvious non divisibility of leading terms") + try: return (p % self).is_zero() # if quo_rem is defined except ArithmeticError: - return False # if division is not exact + return False def specialization(self, D=None, phi=None): r""" From d514d8d4a124e3b98a00e36426db3715c95c1bd6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 19 Dec 2022 19:17:31 -0800 Subject: [PATCH 075/538] pkgs/sage-sws2rst (pyproject.toml): Convert from setup.cfg using ini2toml-0.11.3 --- pkgs/sage-sws2rst/pyproject.toml | 25 +++++++++++++++++++++++++ pkgs/sage-sws2rst/setup.cfg | 16 ---------------- 2 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 pkgs/sage-sws2rst/pyproject.toml delete mode 100644 pkgs/sage-sws2rst/setup.cfg diff --git a/pkgs/sage-sws2rst/pyproject.toml b/pkgs/sage-sws2rst/pyproject.toml new file mode 100644 index 00000000000..1232437fb1e --- /dev/null +++ b/pkgs/sage-sws2rst/pyproject.toml @@ -0,0 +1,25 @@ +[build-system] +requires = ["setuptools>=61.2"] +build-backend = "setuptools.build_meta" + +[project] +name = "sage-sws2rst" +description = "Sage: Open Source Mathematics Software: SageNB worksheet converter" +license = {text = "GNU General Public License (GPL) v3 or later"} +authors = [{name = "The Sage Developers", email = "sage-support@googlegroups.com"}] +urls = {Homepage = "https://www.sagemath.org"} +dynamic = ["version"] + +[project.readme] +file = "README.rst" +content-type = "text/x-rst" + +[tool.setuptools] +script-files = ["bin/sage-sws2rst"] +include-package-data = false + +[tool.setuptools.packages] +find = {namespaces = false} + +[tool.setuptools.dynamic] +version = {file = ["VERSION.txt"]} diff --git a/pkgs/sage-sws2rst/setup.cfg b/pkgs/sage-sws2rst/setup.cfg deleted file mode 100644 index 129f46d55e2..00000000000 --- a/pkgs/sage-sws2rst/setup.cfg +++ /dev/null @@ -1,16 +0,0 @@ -[metadata] -name = sage-sws2rst -version = file: VERSION.txt -description = Sage: Open Source Mathematics Software: SageNB worksheet converter -long_description = file: README.rst -long_description_content_type = text/x-rst -license = GNU General Public License (GPL) v3 or later -author = The Sage Developers -author_email = sage-support@googlegroups.com -url = https://www.sagemath.org - -[options] -packages = find: - -scripts = - bin/sage-sws2rst From 6fa10e9add40e04d0faa9525adcdb299543b2b05 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 28 Oct 2023 11:03:06 -0700 Subject: [PATCH 076/538] pkgs/sage-docbuild (pyproject.toml): Convert from setup.cfg using ini2toml-0.13 --- pkgs/sage-docbuild/pyproject.toml | 40 +++++++++++++++++++++++++++++++ pkgs/sage-docbuild/setup.cfg | 32 ------------------------- 2 files changed, 40 insertions(+), 32 deletions(-) create mode 100644 pkgs/sage-docbuild/pyproject.toml delete mode 100644 pkgs/sage-docbuild/setup.cfg diff --git a/pkgs/sage-docbuild/pyproject.toml b/pkgs/sage-docbuild/pyproject.toml new file mode 100644 index 00000000000..77840653af0 --- /dev/null +++ b/pkgs/sage-docbuild/pyproject.toml @@ -0,0 +1,40 @@ +[build-system] +requires = ["setuptools>=61.2"] +build-backend = "setuptools.build_meta" + +[project] +name = "sage-docbuild" +description = "Sage: Open Source Mathematics Software: Build system of the Sage documentation" +license = {text = "GNU General Public License (GPL) v2 or later"} +authors = [{name = "The Sage Developers", email = "sage-support@googlegroups.com"}] +classifiers = [ + "Development Status :: 6 - Mature", + "Intended Audience :: Education", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", + "Operating System :: POSIX", + "Operating System :: MacOS :: MacOS X", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Scientific/Engineering :: Mathematics", +] +urls = {Homepage = "https://www.sagemath.org"} +dependencies = ["sphinx"] +dynamic = ["version"] + +[project.readme] +file = "README.rst" +content-type = "text/x-rst" + +[tool.setuptools] +packages = [ + "sage_docbuild", + "sage_docbuild.ext", +] +include-package-data = false + +[tool.setuptools.dynamic] +version = {file = ["VERSION.txt"]} diff --git a/pkgs/sage-docbuild/setup.cfg b/pkgs/sage-docbuild/setup.cfg deleted file mode 100644 index 596f9b4506e..00000000000 --- a/pkgs/sage-docbuild/setup.cfg +++ /dev/null @@ -1,32 +0,0 @@ -[metadata] -name = sage-docbuild -version = file: VERSION.txt -description = Sage: Open Source Mathematics Software: Build system of the Sage documentation -long_description = file: README.rst -long_description_content_type = text/x-rst -license = GNU General Public License (GPL) v2 or later -author = The Sage Developers -author_email = sage-support@googlegroups.com -url = https://www.sagemath.org - -classifiers = - Development Status :: 6 - Mature - Intended Audience :: Education - Intended Audience :: Science/Research - License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) - Operating System :: POSIX - Operating System :: MacOS :: MacOS X - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: Implementation :: CPython - Topic :: Scientific/Engineering :: Mathematics - -[options] -packages = - sage_docbuild - sage_docbuild.ext - -install_requires = - sphinx From c67bd9a39f8c5556c335a36a788f9fbde2504789 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 28 Oct 2023 11:04:33 -0700 Subject: [PATCH 077/538] pkgs/sage-setup (pyproject.toml): Convert from setup.cfg using ini2toml-0.13 --- pkgs/sage-setup/pyproject.toml | 48 ++++++++++++++++++++++++++++++++++ pkgs/sage-setup/setup.cfg | 39 --------------------------- 2 files changed, 48 insertions(+), 39 deletions(-) create mode 100644 pkgs/sage-setup/pyproject.toml delete mode 100644 pkgs/sage-setup/setup.cfg diff --git a/pkgs/sage-setup/pyproject.toml b/pkgs/sage-setup/pyproject.toml new file mode 100644 index 00000000000..8042e92a244 --- /dev/null +++ b/pkgs/sage-setup/pyproject.toml @@ -0,0 +1,48 @@ +[build-system] +requires = ["setuptools>=61.2"] +build-backend = "setuptools.build_meta" + +[project] +name = "sage-setup" +description = "Sage: Open Source Mathematics Software: Build system of the Sage library" +license = {text = "GNU General Public License (GPL) v2 or later"} +authors = [{name = "The Sage Developers", email = "sage-support@googlegroups.com"}] +classifiers = [ + "Development Status :: 6 - Mature", + "Intended Audience :: Education", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", + "Operating System :: POSIX", + "Operating System :: MacOS :: MacOS X", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Scientific/Engineering :: Mathematics", +] +urls = {Homepage = "https://www.sagemath.org"} +requires-python = ">=3.9, <3.12" +dependencies = [ + "pkgconfig", + "jinja2", +] +dynamic = ["version"] + +[project.readme] +file = "README.rst" +content-type = "text/x-rst" + +[tool.setuptools] +packages = [ + "sage_setup", + "sage_setup.autogen", + "sage_setup.autogen.interpreters", + "sage_setup.autogen.interpreters.specs", + "sage_setup.command", +] +include-package-data = false + +[tool.setuptools.dynamic] +version = {file = ["VERSION.txt"]} diff --git a/pkgs/sage-setup/setup.cfg b/pkgs/sage-setup/setup.cfg deleted file mode 100644 index 2355ef6b301..00000000000 --- a/pkgs/sage-setup/setup.cfg +++ /dev/null @@ -1,39 +0,0 @@ -[metadata] -name = sage-setup -version = file: VERSION.txt -description = Sage: Open Source Mathematics Software: Build system of the Sage library -long_description = file: README.rst -long_description_content_type = text/x-rst -license = GNU General Public License (GPL) v2 or later -author = The Sage Developers -author_email = sage-support@googlegroups.com -url = https://www.sagemath.org - -classifiers = - Development Status :: 6 - Mature - Intended Audience :: Education - Intended Audience :: Science/Research - License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) - Operating System :: POSIX - Operating System :: MacOS :: MacOS X - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: Implementation :: CPython - Topic :: Scientific/Engineering :: Mathematics - -[options] -packages = - sage_setup - sage_setup.autogen - sage_setup.autogen.interpreters - sage_setup.autogen.interpreters.specs - sage_setup.command - -python_requires = >=3.9, <3.12 - -install_requires = - pkgconfig - jinja2 From 2b94d8d8f676ea39e3e8adb588af735b198a0a0d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 28 Oct 2023 11:05:31 -0700 Subject: [PATCH 078/538] pkgs/sage-setup/pyproject.toml: Remove Python 3.8 --- pkgs/sage-setup/pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/sage-setup/pyproject.toml b/pkgs/sage-setup/pyproject.toml index 8042e92a244..d8a870d2c92 100644 --- a/pkgs/sage-setup/pyproject.toml +++ b/pkgs/sage-setup/pyproject.toml @@ -15,7 +15,6 @@ classifiers = [ "Operating System :: POSIX", "Operating System :: MacOS :: MacOS X", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", From 9eab4588e5235fc887089f93184769e01401d977 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Sun, 29 Oct 2023 16:25:53 +0000 Subject: [PATCH 079/538] Replace relative imports by absolute ones in categories --- src/sage/categories/action.pxd | 6 +- src/sage/categories/action.pyx | 8 +- src/sage/categories/algebra_ideals.py | 8 +- src/sage/categories/algebra_modules.py | 9 +- src/sage/categories/algebras_with_basis.py | 8 +- src/sage/categories/all.py | 99 ++----------------- src/sage/categories/all__sagemath_objects.py | 15 --- src/sage/categories/basic.py | 37 ++----- src/sage/categories/category_singleton.pyx | 2 + src/sage/categories/category_types.py | 6 +- src/sage/categories/chain_complexes.py | 9 +- src/sage/categories/coalgebras.py | 8 +- .../categories/commutative_algebra_ideals.py | 8 +- .../categories/commutative_ring_ideals.py | 5 +- .../categories/complete_discrete_valuation.py | 7 +- ...ensional_semisimple_algebras_with_basis.py | 5 +- src/sage/categories/functor.pyx | 2 +- src/sage/categories/g_sets.py | 3 +- src/sage/categories/groupoid.py | 3 +- src/sage/categories/homset.py | 10 +- src/sage/categories/hopf_algebras.py | 8 +- src/sage/categories/l_trivial_semigroups.py | 5 +- .../categories/lambda_bracket_algebras.py | 11 ++- src/sage/categories/left_modules.py | 3 +- src/sage/categories/lie_conformal_algebras.py | 12 ++- src/sage/categories/map.pyx | 2 +- src/sage/categories/matrix_algebras.py | 5 +- .../categories/modular_abelian_varieties.py | 11 ++- src/sage/categories/modules.py | 25 ++--- src/sage/categories/morphism.pxd | 2 +- src/sage/categories/pointed_sets.py | 3 +- src/sage/categories/pushout.py | 18 ++-- src/sage/categories/r_trivial_semigroups.py | 3 +- src/sage/categories/right_modules.py | 3 +- src/sage/categories/ring_ideals.py | 5 +- src/sage/categories/semirings.py | 3 +- src/sage/categories/semisimple_algebras.py | 7 +- src/sage/categories/sets_with_grading.py | 12 +-- src/sage/categories/sets_with_partial_maps.py | 2 +- 39 files changed, 155 insertions(+), 243 deletions(-) diff --git a/src/sage/categories/action.pxd b/src/sage/categories/action.pxd index 0c9e322d455..5883adebc97 100644 --- a/src/sage/categories/action.pxd +++ b/src/sage/categories/action.pxd @@ -1,7 +1,7 @@ from sage.structure.element cimport Element -from .morphism cimport Morphism -from .map cimport Map -from .functor cimport Functor +from sage.categories.morphism cimport Morphism +from sage.categories.map cimport Map +from sage.categories.functor cimport Functor cdef class Action(Functor): cdef readonly G diff --git a/src/sage/categories/action.pyx b/src/sage/categories/action.pyx index b3244f766d4..0d564e46c4d 100644 --- a/src/sage/categories/action.pyx +++ b/src/sage/categories/action.pyx @@ -56,13 +56,13 @@ AUTHOR: from cpython.tuple cimport PyTuple_GET_ITEM -from .functor cimport Functor -from .morphism cimport Morphism -from .map cimport Map +from sage.categories.functor cimport Functor +from sage.categories.morphism cimport Morphism +from sage.categories.map cimport Map from sage.structure.element cimport parent from sage.structure.parent cimport Parent -from . import homset +from sage.categories import homset from weakref import ref diff --git a/src/sage/categories/algebra_ideals.py b/src/sage/categories/algebra_ideals.py index 1d6e3775e7b..c33fa0ef7b0 100644 --- a/src/sage/categories/algebra_ideals.py +++ b/src/sage/categories/algebra_ideals.py @@ -10,10 +10,10 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from .algebra_modules import AlgebraModules -from .algebras import Algebras -from .rings import Rings -from .category_types import Category_ideal +from sage.categories.algebra_modules import AlgebraModules +from sage.categories.algebras import Algebras +from sage.categories.category_types import Category_ideal +from sage.categories.rings import Rings class AlgebraIdeals(Category_ideal): diff --git a/src/sage/categories/algebra_modules.py b/src/sage/categories/algebra_modules.py index 7be7de2c471..e827cc7130d 100644 --- a/src/sage/categories/algebra_modules.py +++ b/src/sage/categories/algebra_modules.py @@ -10,10 +10,11 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from .category_types import Category_module -from .commutative_algebras import CommutativeAlgebras -from .commutative_rings import CommutativeRings -from .modules import Modules +from sage.categories.category_types import Category_module +from sage.categories.commutative_algebras import CommutativeAlgebras +from sage.categories.commutative_rings import CommutativeRings +from sage.categories.modules import Modules + class AlgebraModules(Category_module): """ diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index 28177a1ff45..dfd693a9520 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -9,13 +9,13 @@ # https://www.gnu.org/licenses/ #****************************************************************************** +from sage.categories.cartesian_product import CartesianProductsCategory +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.tensor import TensorProductsCategory, tensor +from sage.categories.unital_algebras import UnitalAlgebras from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import LazyImport -from sage.categories.tensor import TensorProductsCategory, tensor -from sage.categories.cartesian_product import CartesianProductsCategory -from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from .unital_algebras import UnitalAlgebras class AlgebrasWithBasis(CategoryWithAxiom_over_base_ring): diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index 110a9954da3..936346c5d13 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -25,130 +25,49 @@ """ # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc -install_doc(__package__, __doc__) - -from . import primer - -from sage.misc.lazy_import import lazy_import - -from .all__sagemath_objects import * - -from .basic import * - -from .chain_complexes import ChainComplexes, HomologyFunctor - -from .simplicial_complexes import SimplicialComplexes - -from .tensor import tensor -from .signed_tensor import tensor_signed -from .g_sets import GSets -from .pointed_sets import PointedSets +install_doc(__package__, __doc__) -from .sets_with_grading import SetsWithGrading -from .groupoid import Groupoid -from .permutation_groups import PermutationGroups +from sage.categories.all__sagemath_objects import * +from sage.categories.basic import * # enumerated sets -from .finite_sets import FiniteSets -from .enumerated_sets import EnumeratedSets -from .finite_enumerated_sets import FiniteEnumeratedSets -from .infinite_enumerated_sets import InfiniteEnumeratedSets - # posets -from .posets import Posets -from .finite_posets import FinitePosets -from .lattice_posets import LatticePosets -from .finite_lattice_posets import FiniteLatticePosets - # finite groups/... -from .finite_semigroups import FiniteSemigroups -from .finite_monoids import FiniteMonoids -from .finite_groups import FiniteGroups -from .finite_permutation_groups import FinitePermutationGroups - # fields -from .number_fields import NumberFields -from .function_fields import FunctionFields - # modules -from .left_modules import LeftModules -from .right_modules import RightModules -from .bimodules import Bimodules +from sage.categories.modules import Modules +from sage.misc.lazy_import import lazy_import -from .modules import Modules RingModules = Modules -from .vector_spaces import VectorSpaces # (hopf) algebra structures -from .algebras import Algebras -from .commutative_algebras import CommutativeAlgebras -from .coalgebras import Coalgebras -from .bialgebras import Bialgebras -from .hopf_algebras import HopfAlgebras -from .lie_algebras import LieAlgebras # specific algebras -from .monoid_algebras import MonoidAlgebras -from .group_algebras import GroupAlgebras -from .matrix_algebras import MatrixAlgebras # ideals -from .ring_ideals import RingIdeals +from sage.categories.ring_ideals import RingIdeals + Ideals = RingIdeals -from .commutative_ring_ideals import CommutativeRingIdeals -from .algebra_modules import AlgebraModules -from .algebra_ideals import AlgebraIdeals -from .commutative_algebra_ideals import CommutativeAlgebraIdeals # schemes and varieties -from .modular_abelian_varieties import ModularAbelianVarieties -from .schemes import Schemes # * with basis -from .modules_with_basis import ModulesWithBasis +from sage.categories.modules_with_basis import ModulesWithBasis + FreeModules = ModulesWithBasis -from .hecke_modules import HeckeModules -from .algebras_with_basis import AlgebrasWithBasis -from .coalgebras_with_basis import CoalgebrasWithBasis -from .bialgebras_with_basis import BialgebrasWithBasis -from .hopf_algebras_with_basis import HopfAlgebrasWithBasis # finite dimensional * with basis -from .finite_dimensional_modules_with_basis import FiniteDimensionalModulesWithBasis -from .finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis -from .finite_dimensional_coalgebras_with_basis import FiniteDimensionalCoalgebrasWithBasis -from .finite_dimensional_bialgebras_with_basis import FiniteDimensionalBialgebrasWithBasis -from .finite_dimensional_hopf_algebras_with_basis import FiniteDimensionalHopfAlgebrasWithBasis # graded * -from .graded_modules import GradedModules -from .graded_algebras import GradedAlgebras -from .graded_coalgebras import GradedCoalgebras -from .graded_bialgebras import GradedBialgebras -from .graded_hopf_algebras import GradedHopfAlgebras # graded * with basis -from .graded_modules_with_basis import GradedModulesWithBasis -from .graded_algebras_with_basis import GradedAlgebrasWithBasis -from .graded_coalgebras_with_basis import GradedCoalgebrasWithBasis -from .graded_bialgebras_with_basis import GradedBialgebrasWithBasis -from .graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis # Coxeter groups -from .coxeter_groups import CoxeterGroups lazy_import('sage.categories.finite_coxeter_groups', 'FiniteCoxeterGroups') -from .weyl_groups import WeylGroups -from .finite_weyl_groups import FiniteWeylGroups -from .affine_weyl_groups import AffineWeylGroups # crystal bases -from .crystals import Crystals -from .highest_weight_crystals import HighestWeightCrystals -from .regular_crystals import RegularCrystals -from .finite_crystals import FiniteCrystals -from .classical_crystals import ClassicalCrystals # polyhedra lazy_import('sage.categories.polyhedra', 'PolyhedralSets') diff --git a/src/sage/categories/all__sagemath_objects.py b/src/sage/categories/all__sagemath_objects.py index dee0881d787..979ce64ce7b 100644 --- a/src/sage/categories/all__sagemath_objects.py +++ b/src/sage/categories/all__sagemath_objects.py @@ -1,31 +1,16 @@ # Subset of sage.categories.all that is made available by the sage-objects distribution -from sage.misc.lazy_import import lazy_import # Resolve a circular import so that "import sage.categories.all" can succeed # in initializing the category system. -import sage.structure.category_object # imports sage.categories.category # Small part of "from .basic import *": -from .objects import Objects -from .sets_cat import Sets, EmptySetError -from .category import Category -from .category_types import Elements -from .cartesian_product import cartesian_product -from .functor import (ForgetfulFunctor, - IdentityFunctor) -from .homset import (Hom, hom, - End, end, - Homset, HomsetWithBase) -from .morphism import Morphism -from .realizations import Realizations -from .sets_with_partial_maps import SetsWithPartialMaps diff --git a/src/sage/categories/basic.py b/src/sage/categories/basic.py index b3cf1d3a29c..f81d226fb36 100644 --- a/src/sage/categories/basic.py +++ b/src/sage/categories/basic.py @@ -9,42 +9,17 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from .objects import Objects -from .sets_cat import Sets, EmptySetError -from .posets import Posets +from sage.categories.posets import Posets + # For backward compatibility; will be deprecated at some point PartiallyOrderedSets = Posets OrderedSets = Posets -from .additive_magmas import AdditiveMagmas -from .commutative_additive_semigroups import CommutativeAdditiveSemigroups -from .commutative_additive_monoids import CommutativeAdditiveMonoids -from .commutative_additive_groups import CommutativeAdditiveGroups -from .magmas import Magmas -from .semigroups import Semigroups -from .monoids import Monoids -from .groups import Groups -from .partially_ordered_monoids import PartiallyOrderedMonoids +from sage.categories.partially_ordered_monoids import PartiallyOrderedMonoids + # For backward compatibility; might be deprecated at some point OrderedMonoids = PartiallyOrderedMonoids -from .rngs import Rngs -from .semirings import Semirings -from .rings import Rings -from .domains import Domains -from .division_rings import DivisionRings - -from .commutative_rings import CommutativeRings -from .integral_domains import IntegralDomains -from .gcd_domains import GcdDomains -from .principal_ideal_domains import PrincipalIdealDomains -from .euclidean_domains import EuclideanDomains -from .unique_factorization_domains import UniqueFactorizationDomains -from .complete_discrete_valuation import CompleteDiscreteValuationRings - -from .fields import Fields -from .quotient_fields import QuotientFields -from .finite_fields import FiniteFields -from .discrete_valuation import DiscreteValuationRings, DiscreteValuationFields -from .complete_discrete_valuation import CompleteDiscreteValuationRings, CompleteDiscreteValuationFields + + diff --git a/src/sage/categories/category_singleton.pyx b/src/sage/categories/category_singleton.pyx index 543ce0375f7..d07bcaa5586 100644 --- a/src/sage/categories/category_singleton.pyx +++ b/src/sage/categories/category_singleton.pyx @@ -15,6 +15,8 @@ from sage.categories.category import Category from sage.structure.category_object cimport CategoryObject from sage.structure.dynamic_class import DynamicMetaclass +# I have no idea why this is necessary, but otherwise the type import fails +from cpython.method cimport PyMethod_Check from cpython.type cimport PyType_IsSubtype # This helper class is used to implement Category_singleton.__contains__ diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index cb18dcd42c0..c9e2fe79130 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -14,9 +14,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.unknown import Unknown -from .category import JoinCategory, Category, CategoryWithParameters +from sage.categories.category import Category, CategoryWithParameters, JoinCategory from sage.misc.lazy_import import lazy_import +from sage.misc.unknown import Unknown + lazy_import('sage.categories.objects', 'Objects') lazy_import('sage.misc.latex', 'latex') @@ -196,6 +197,7 @@ def _test_category_over_bases(self, **options): """ tester = self._tester(**options) from sage.categories.category_singleton import Category_singleton + from .bimodules import Bimodules from .schemes import Schemes for cat in self.super_categories(): diff --git a/src/sage/categories/chain_complexes.py b/src/sage/categories/chain_complexes.py index db9c5d03f56..2d3823aba73 100644 --- a/src/sage/categories/chain_complexes.py +++ b/src/sage/categories/chain_complexes.py @@ -13,11 +13,12 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from .category_types import Category_module -from .commutative_additive_groups import CommutativeAdditiveGroups -from .functor import Functor +from sage.categories.category_types import Category_module +from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups +from sage.categories.functor import Functor from sage.misc.abstract_method import abstract_method + ############################################################# # ChainComplex ############################################################# @@ -259,8 +260,8 @@ def _apply_functor_to_morphism(self, f): sage: id_star(one) [one] """ - from .morphism import SetMorphism from .homset import Hom + from .morphism import SetMorphism domain = f.domain() codomain = f.codomain() diff --git a/src/sage/categories/coalgebras.py b/src/sage/categories/coalgebras.py index abe36aef0bb..b69fdf29784 100644 --- a/src/sage/categories/coalgebras.py +++ b/src/sage/categories/coalgebras.py @@ -10,14 +10,14 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from .category_types import Category_over_base_ring -from sage.categories.modules import Modules +from sage.categories.category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from sage.categories.tensor import TensorProductsCategory from sage.categories.dual import DualObjectsCategory from sage.categories.filtered_modules import FilteredModulesCategory -from sage.categories.super_modules import SuperModulesCategory +from sage.categories.modules import Modules from sage.categories.realizations import RealizationsCategory +from sage.categories.super_modules import SuperModulesCategory +from sage.categories.tensor import TensorProductsCategory from sage.categories.with_realizations import WithRealizationsCategory from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method diff --git a/src/sage/categories/commutative_algebra_ideals.py b/src/sage/categories/commutative_algebra_ideals.py index 070503ae6c8..e47e1c4f87e 100644 --- a/src/sage/categories/commutative_algebra_ideals.py +++ b/src/sage/categories/commutative_algebra_ideals.py @@ -10,10 +10,10 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from .algebra_ideals import AlgebraIdeals -from .category_types import Category_ideal, Category_in_ambient -from .commutative_algebras import CommutativeAlgebras -from .commutative_rings import CommutativeRings +from sage.categories.algebra_ideals import AlgebraIdeals +from sage.categories.category_types import Category_ideal, Category_in_ambient +from sage.categories.commutative_algebras import CommutativeAlgebras +from sage.categories.commutative_rings import CommutativeRings class CommutativeAlgebraIdeals(Category_ideal): diff --git a/src/sage/categories/commutative_ring_ideals.py b/src/sage/categories/commutative_ring_ideals.py index 5aef6d7d31d..8659b0c793b 100644 --- a/src/sage/categories/commutative_ring_ideals.py +++ b/src/sage/categories/commutative_ring_ideals.py @@ -10,9 +10,10 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from .category_types import Category_ideal +from sage.categories.category_types import Category_ideal from sage.categories.commutative_rings import CommutativeRings -from .ring_ideals import RingIdeals +from sage.categories.ring_ideals import RingIdeals + class CommutativeRingIdeals(Category_ideal): """ diff --git a/src/sage/categories/complete_discrete_valuation.py b/src/sage/categories/complete_discrete_valuation.py index 442360465a1..7376d947530 100644 --- a/src/sage/categories/complete_discrete_valuation.py +++ b/src/sage/categories/complete_discrete_valuation.py @@ -9,10 +9,13 @@ #************************************************************************** +from sage.categories.category_singleton import Category_singleton +from sage.categories.discrete_valuation import ( + DiscreteValuationFields, + DiscreteValuationRings, +) from sage.misc.abstract_method import abstract_method -from sage.categories.category_singleton import Category_singleton -from .discrete_valuation import DiscreteValuationRings, DiscreteValuationFields #from sage.misc.cachefunc import cached_method diff --git a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py index 531ee7145a4..da4b297ddde 100644 --- a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py @@ -9,10 +9,11 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.categories.algebras import Algebras from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring +from sage.categories.semisimple_algebras import SemisimpleAlgebras from sage.misc.cachefunc import cached_method -from .algebras import Algebras -from .semisimple_algebras import SemisimpleAlgebras + class FiniteDimensionalSemisimpleAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ diff --git a/src/sage/categories/functor.pyx b/src/sage/categories/functor.pyx index c25e99f2164..32bd079fc73 100644 --- a/src/sage/categories/functor.pyx +++ b/src/sage/categories/functor.pyx @@ -33,7 +33,7 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from . import category +from sage.categories import category def _Functor_unpickle(Cl, D, domain, codomain): diff --git a/src/sage/categories/g_sets.py b/src/sage/categories/g_sets.py index 7fd09bafea4..5967fcf7d5f 100644 --- a/src/sage/categories/g_sets.py +++ b/src/sage/categories/g_sets.py @@ -11,7 +11,8 @@ #****************************************************************************** from sage.categories.category import Category -from .sets_cat import Sets +from sage.categories.sets_cat import Sets + ############################################################# # GSets diff --git a/src/sage/categories/groupoid.py b/src/sage/categories/groupoid.py index 850e63a2c09..95af5df164c 100644 --- a/src/sage/categories/groupoid.py +++ b/src/sage/categories/groupoid.py @@ -12,7 +12,8 @@ #****************************************************************************** from sage.categories.category import CategoryWithParameters -from .sets_cat import Sets +from sage.categories.sets_cat import Sets + class Groupoid(CategoryWithParameters): """ diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 2a8b8aeedeb..d2203299512 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -65,12 +65,9 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.categories import morphism from sage.categories.category import Category, JoinCategory -from . import morphism -from sage.structure.parent import Parent, Set_generic from sage.misc.fast_methods import WithEqualityById -from sage.structure.dynamic_class import dynamic_class -from sage.structure.unique_representation import UniqueRepresentation from sage.misc.lazy_attribute import lazy_attribute ################################### @@ -78,8 +75,11 @@ # introduced in github issue #715 # with weak values, as introduced in # github issue #14159 - from sage.structure.coerce_dict import TripleDict +from sage.structure.dynamic_class import dynamic_class +from sage.structure.parent import Parent, Set_generic +from sage.structure.unique_representation import UniqueRepresentation + _cache = TripleDict(weak_values=True) diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index 41e349690fe..218abc1ca27 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -8,14 +8,14 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.misc.lazy_import import LazyImport -from .category import Category -from .category_types import Category_over_base_ring from sage.categories.bialgebras import Bialgebras -from sage.categories.tensor import TensorProductsCategory # tensor +from sage.categories.category import Category +from sage.categories.category_types import Category_over_base_ring from sage.categories.realizations import RealizationsCategory from sage.categories.super_modules import SuperModulesCategory +from sage.categories.tensor import TensorProductsCategory # tensor from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import LazyImport class HopfAlgebras(Category_over_base_ring): diff --git a/src/sage/categories/l_trivial_semigroups.py b/src/sage/categories/l_trivial_semigroups.py index 53f03701e6f..9c483dcd3d1 100644 --- a/src/sage/categories/l_trivial_semigroups.py +++ b/src/sage/categories/l_trivial_semigroups.py @@ -13,8 +13,9 @@ #***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom -from .magmas import Magmas -from .semigroups import Semigroups +from sage.categories.magmas import Magmas +from sage.categories.semigroups import Semigroups + class LTrivialSemigroups(CategoryWithAxiom): def extra_super_categories(self): diff --git a/src/sage/categories/lambda_bracket_algebras.py b/src/sage/categories/lambda_bracket_algebras.py index 40cb5ed70c4..16dbd7c7fa9 100644 --- a/src/sage/categories/lambda_bracket_algebras.py +++ b/src/sage/categories/lambda_bracket_algebras.py @@ -16,13 +16,14 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from .category_types import Category_over_base_ring -from sage.misc.abstract_method import abstract_method +from sage.categories.category_types import Category_over_base_ring +from sage.categories.commutative_rings import CommutativeRings from sage.categories.modules import Modules -from sage.structure.element import coerce_binop +from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method -from sage.categories.commutative_rings import CommutativeRings from sage.misc.lazy_import import LazyImport +from sage.structure.element import coerce_binop + _CommutativeRings = CommutativeRings() @@ -53,7 +54,7 @@ def __classcall_private__(cls, R, check=True): Category of Lie conformal algebras over Integer Ring """ if check: - if not (R in _CommutativeRings): + if R not in _CommutativeRings: raise ValueError("base must be a commutative ring got {}".format(R)) return super().__classcall__(cls, R) diff --git a/src/sage/categories/left_modules.py b/src/sage/categories/left_modules.py index c92a13f7979..51de3497a53 100644 --- a/src/sage/categories/left_modules.py +++ b/src/sage/categories/left_modules.py @@ -8,9 +8,10 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from .category_types import Category_over_base_ring +from sage.categories.category_types import Category_over_base_ring from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups + #?class LeftModules(Category_over_base_rng): class LeftModules(Category_over_base_ring): """ diff --git a/src/sage/categories/lie_conformal_algebras.py b/src/sage/categories/lie_conformal_algebras.py index ee48889dd0b..8ade3811845 100644 --- a/src/sage/categories/lie_conformal_algebras.py +++ b/src/sage/categories/lie_conformal_algebras.py @@ -125,11 +125,12 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from .category_types import Category_over_base_ring -from sage.misc.cachefunc import cached_method +from sage.categories.category_types import Category_over_base_ring from sage.categories.lambda_bracket_algebras import LambdaBracketAlgebras +from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import LazyImport + class LieConformalAlgebras(Category_over_base_ring): r""" The category of Lie conformal algebras. @@ -224,8 +225,9 @@ def example(self): sage: LieConformalAlgebras(QQ).example() # needs sage.combinat sage.modules The Virasoro Lie conformal algebra over Rational Field """ - from sage.algebras.lie_conformal_algebras.virasoro_lie_conformal_algebra\ - import VirasoroLieConformalAlgebra + from sage.algebras.lie_conformal_algebras.virasoro_lie_conformal_algebra import ( + VirasoroLieConformalAlgebra, + ) return VirasoroLieConformalAlgebra(self.base_ring()) def _repr_object_names(self): @@ -284,8 +286,8 @@ def _test_jacobi(self, **options): """ tester = self._tester(**options) S = tester.some_elements() - from sage.misc.misc import some_tuples from sage.arith.misc import binomial + from sage.misc.misc import some_tuples pz = tester._instance.zero() for x,y,z in some_tuples(S, 3, tester._max_runs): brxy = x.bracket(y) diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index 45c30ae6c31..71c3ef3f1d2 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -21,7 +21,7 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from . import homset +from sage.categories import homset import weakref from sage.ext.stdsage cimport HAS_DICTIONARY from sage.arith.power cimport generic_power diff --git a/src/sage/categories/matrix_algebras.py b/src/sage/categories/matrix_algebras.py index 90eef738be6..08b102d7451 100644 --- a/src/sage/categories/matrix_algebras.py +++ b/src/sage/categories/matrix_algebras.py @@ -10,8 +10,9 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from .category_types import Category_over_base_ring -from .algebras import Algebras +from sage.categories.algebras import Algebras +from sage.categories.category_types import Category_over_base_ring + class MatrixAlgebras(Category_over_base_ring): """ diff --git a/src/sage/categories/modular_abelian_varieties.py b/src/sage/categories/modular_abelian_varieties.py index a1337e700cd..804361a7f99 100644 --- a/src/sage/categories/modular_abelian_varieties.py +++ b/src/sage/categories/modular_abelian_varieties.py @@ -10,11 +10,12 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from .category_types import Category_over_base -from .category_with_axiom import CategoryWithAxiom -from .homsets import HomsetsCategory -from .rings import Rings -from .sets_cat import Sets +from sage.categories.category_types import Category_over_base +from sage.categories.category_with_axiom import CategoryWithAxiom +from sage.categories.homsets import HomsetsCategory +from sage.categories.rings import Rings +from sage.categories.sets_cat import Sets + class ModularAbelianVarieties(Category_over_base): """ diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index e65bab4faf8..c4f5127306f 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -11,21 +11,22 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.misc.cachefunc import cached_method -from sage.misc.abstract_method import abstract_method -from sage.misc.lazy_import import LazyImport +from sage.categories.bimodules import Bimodules +from sage.categories.cartesian_product import CartesianProductsCategory +from sage.categories.category import Category +from sage.categories.category_types import Category_module from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from sage.categories.morphism import SetMorphism -from sage.categories.homsets import HomsetsCategory +from sage.categories.dual import DualObjectsCategory +from sage.categories.fields import Fields from sage.categories.homset import Hom -from .category import Category -from .category_types import Category_module -from sage.categories.tensor import TensorProductsCategory, TensorProductFunctor, tensor -from .dual import DualObjectsCategory -from sage.categories.cartesian_product import CartesianProductsCategory +from sage.categories.homsets import HomsetsCategory +from sage.categories.morphism import SetMorphism from sage.categories.sets_cat import Sets -from sage.categories.bimodules import Bimodules -from sage.categories.fields import Fields +from sage.categories.tensor import TensorProductFunctor, TensorProductsCategory, tensor +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import LazyImport + _Fields = Fields() diff --git a/src/sage/categories/morphism.pxd b/src/sage/categories/morphism.pxd index fce5487d829..2222a9c679a 100644 --- a/src/sage/categories/morphism.pxd +++ b/src/sage/categories/morphism.pxd @@ -1,5 +1,5 @@ from sage.structure.element cimport Element -from .map cimport Map +from sage.categories.map cimport Map cdef class Morphism(Map): diff --git a/src/sage/categories/pointed_sets.py b/src/sage/categories/pointed_sets.py index fd91b3b07f3..27376140dbe 100644 --- a/src/sage/categories/pointed_sets.py +++ b/src/sage/categories/pointed_sets.py @@ -11,7 +11,8 @@ #****************************************************************************** from sage.categories.category_singleton import Category_singleton -from .sets_cat import Sets +from sage.categories.sets_cat import Sets + class PointedSets(Category_singleton): """ diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 3b7b8238d52..a23557037b0 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -27,9 +27,9 @@ import operator +from sage.categories.functor import Functor, IdentityFunctor_generic from sage.misc.lazy_import import lazy_import from sage.structure.coerce_exceptions import CoercionException -from .functor import Functor, IdentityFunctor_generic lazy_import('sage.categories.commutative_additive_groups', 'CommutativeAdditiveGroups') lazy_import('sage.categories.commutative_rings', 'CommutativeRings') @@ -902,7 +902,9 @@ def _apply_functor_to_morphism(self, f): From: Integer Ring To: Finite Field of size 3 """ - from sage.rings.polynomial.polynomial_ring_homomorphism import PolynomialRingHomomorphism_from_base + from sage.rings.polynomial.polynomial_ring_homomorphism import ( + PolynomialRingHomomorphism_from_base, + ) R = self._apply_functor(f.domain()) S = self._apply_functor(f.codomain()) return PolynomialRingHomomorphism_from_base(R.Hom(S), f) @@ -1329,7 +1331,9 @@ def _apply_functor(self, R): Infinite polynomial ring in a, b, x over Univariate Polynomial Ring in t over Rational Field """ - from sage.rings.polynomial.infinite_polynomial_ring import InfinitePolynomialRing + from sage.rings.polynomial.infinite_polynomial_ring import ( + InfinitePolynomialRing, + ) return InfinitePolynomialRing(R, self._gens, order=self._order, implementation=self._imple) def _repr_(self): @@ -1795,7 +1799,9 @@ def _apply_functor(self, R): """ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing - from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic + from sage.rings.polynomial.laurent_polynomial_ring_base import ( + LaurentPolynomialRing_generic, + ) if self.multi_variate and isinstance(R, LaurentPolynomialRing_generic): return LaurentPolynomialRing(R.base_ring(), list(R.variable_names()) + [self.var]) else: @@ -2474,8 +2480,8 @@ def __init__(self): sage: F(ZZ['t']) Fraction Field of Univariate Polynomial Ring in t over Integer Ring """ - from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields + from sage.categories.integral_domains import IntegralDomains Functor.__init__(self, IntegralDomains(), Fields()) def _apply_functor(self, R): @@ -3383,8 +3389,8 @@ def _apply_functor(self, R): 3-adic Eisenstein Extension Field in a defined by a^2 - 3 """ - from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ + from sage.rings.rational_field import QQ if self.cyclotomic: from sage.rings.number_field.number_field import CyclotomicField if R == QQ: diff --git a/src/sage/categories/r_trivial_semigroups.py b/src/sage/categories/r_trivial_semigroups.py index 93ba9e61ca8..7b5c9fea5ed 100644 --- a/src/sage/categories/r_trivial_semigroups.py +++ b/src/sage/categories/r_trivial_semigroups.py @@ -13,7 +13,8 @@ #***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom -from .semigroups import Semigroups +from sage.categories.semigroups import Semigroups + class RTrivialSemigroups(CategoryWithAxiom): def extra_super_categories(self): diff --git a/src/sage/categories/right_modules.py b/src/sage/categories/right_modules.py index 5a7557c4663..47a8081d2a9 100644 --- a/src/sage/categories/right_modules.py +++ b/src/sage/categories/right_modules.py @@ -8,9 +8,10 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from .category_types import Category_over_base_ring +from sage.categories.category_types import Category_over_base_ring from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups + ##?class RightModules(Category_over_base_rng): class RightModules(Category_over_base_ring): """ diff --git a/src/sage/categories/ring_ideals.py b/src/sage/categories/ring_ideals.py index 51573635ef0..fd634f1caef 100644 --- a/src/sage/categories/ring_ideals.py +++ b/src/sage/categories/ring_ideals.py @@ -10,9 +10,10 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from .category_types import Category_ideal -from .modules import Modules +from sage.categories.category_types import Category_ideal +from sage.categories.modules import Modules from sage.categories.rings import Rings + _Rings = Rings() diff --git a/src/sage/categories/semirings.py b/src/sage/categories/semirings.py index cbff0b29a8e..62e6f7d918f 100644 --- a/src/sage/categories/semirings.py +++ b/src/sage/categories/semirings.py @@ -9,7 +9,8 @@ #****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom -from .magmas_and_additive_magmas import MagmasAndAdditiveMagmas +from sage.categories.magmas_and_additive_magmas import MagmasAndAdditiveMagmas + class Semirings(CategoryWithAxiom): """ diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 9a310614290..453b854b7e7 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -8,12 +8,13 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.categories.algebras import Algebras +from sage.categories.category_types import Category_over_base_ring +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.misc.bindable_class import BoundClass from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import LazyImport -from .category_types import Category_over_base_ring -from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring -from .algebras import Algebras + class SemisimpleAlgebras(Category_over_base_ring): """ diff --git a/src/sage/categories/sets_with_grading.py b/src/sage/categories/sets_with_grading.py index b1e321f67f2..a29d8c9c59c 100644 --- a/src/sage/categories/sets_with_grading.py +++ b/src/sage/categories/sets_with_grading.py @@ -8,11 +8,11 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.misc.cachefunc import cached_method -from sage.misc.abstract_method import abstract_method -from .category_types import Category -from sage.categories.sets_cat import Sets +from sage.categories.category_types import Category from sage.categories.enumerated_sets import EnumeratedSets +from sage.categories.sets_cat import Sets +from sage.misc.abstract_method import abstract_method +from sage.misc.cachefunc import cached_method class SetsWithGrading(Category): @@ -220,9 +220,9 @@ def generating_series(self): - Very likely, this should always return a lazy power series. """ - from sage.sets.non_negative_integers import NonNegativeIntegers - from sage.rings.lazy_series_ring import LazyPowerSeriesRing from sage.rings.integer_ring import ZZ + from sage.rings.lazy_series_ring import LazyPowerSeriesRing + from sage.sets.non_negative_integers import NonNegativeIntegers if isinstance(self.grading_set(), NonNegativeIntegers): R = LazyPowerSeriesRing(ZZ, names="z") return R(lambda n: self.graded_component(n).cardinality()) diff --git a/src/sage/categories/sets_with_partial_maps.py b/src/sage/categories/sets_with_partial_maps.py index 5b2f9b35427..4210548b0fd 100644 --- a/src/sage/categories/sets_with_partial_maps.py +++ b/src/sage/categories/sets_with_partial_maps.py @@ -11,7 +11,7 @@ #****************************************************************************** from sage.categories.category_singleton import Category_singleton -from .objects import Objects +from sage.categories.objects import Objects class SetsWithPartialMaps(Category_singleton): From 5a273243a934697f39f432af434f10939ea1a094 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 29 Oct 2023 19:13:30 +0100 Subject: [PATCH 080/538] address siggestions from issue 36530 --- src/sage/graphs/generic_graph.py | 71 +++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 15 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index eedbc36bef3..33f50fd712d 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -7865,25 +7865,35 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", argument is set to ``None`` by default, which means that no constraint is set upon the first vertex in the path. + This parameter can only be used when ``algorithm`` is ``"MILP"``. + - ``t`` -- a vertex (default: ``None``); forces the destination of the path (the method then returns the longest path ending at ``t``). The argument is set to ``None`` by default, which means that no constraint is set upon the last vertex in the path. + This parameter can only be used when ``algorithm`` is ``"MILP"``. + - ``use_edge_labels`` -- boolean (default: ``False``); whether to compute a path with maximum weight where the weight of an edge is defined by its label (a label set to ``None`` or ``{}`` being considered as a weight of `1`), or to compute a path with the longest possible number of edges (i.e., edge weights are set to 1) + This parameter can only be used when ``algorithm`` is ``"MILP"``. + - ``algorithm`` -- string (default: ``"MILP"``); the algorithm to use - among ``"MILP"`` and ``"backtrack"``. Two remarks on this respect: + among ``"MILP"``, ``"backtrack"`` and ``"heuristic"``: - * While the MILP formulation returns an exact answer, the backtrack - algorithm is a randomized heuristic. + * ``"MILP"`` returns an exact answer. - * As the backtrack algorithm does not support edge weighting, setting - ``use_edge_labels=True`` will force the use of the MILP algorithm. + * ``"backtrack"`` will be renamed ``"heuristic"`` in the future. A + warning is raised when used. + + * ``"heuristic"`` is a randomized heuristic for finding a long path in + an unweighted (di)graph. This heuristic does not take into account + parameters ``s``, ``t`` and ``use_edge_labels``. An error is raised + if these parameters are set. - ``solver`` -- string (default: ``None``); specify a Mixed Integer Linear Programming (MILP) solver to be used. If set to ``None``, the @@ -7928,7 +7938,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", The heuristic totally agrees:: sage: g = graphs.PetersenGraph() - sage: p = g.longest_path(algorithm="backtrack").edges(sort=True, labels=False) + sage: p = g.longest_path(algorithm="heuristic").edges(sort=True, labels=False) sage: len(p) 9 @@ -7950,13 +7960,13 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", TESTS: - The argument ``algorithm`` must be either ``'backtrack'`` or - ``'MILP'``:: + The argument ``algorithm`` must be either ``'backtrack'``, + ``'heuristic'`` or ``'MILP'``:: sage: graphs.PetersenGraph().longest_path(algorithm="abc") Traceback (most recent call last): ... - ValueError: algorithm must be either 'backtrack' or 'MILP' + ValueError: algorithm must be either 'backtrack', 'heuristic' or 'MILP' Disconnected graphs not weighted:: @@ -8029,13 +8039,44 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: H = {(0, 3), (2, 0), (3, 4)} sage: H == {x for x in G.longest_path().edge_iterator(labels=False)} # needs sage.numerical.mip True + + :gh:`12345`:: + + sage: G = graphs.PathGraph(3) + sage: P = G.longest_path(algorithm='backtrack') + doctest:...: FutureWarning: algorithm 'backtrack' will be renamed 'heuristic' in the future. + See https://github.com/sagemath/sage/issues/12345 for details. + sage: G.longest_path(algorithm='heuristic', s=0) + Traceback (most recent call last): + ... + ValueError: parameters s, t, and use_edge_labels can not be used in + combinaiton with algorithms 'backtrack' and 'heuristic' + sage: G.longest_path(algorithm='heuristic', t=2) + Traceback (most recent call last): + ... + ValueError: parameters s, t, and use_edge_labels can not be used in + combinaiton with algorithms 'backtrack' and 'heuristic' + sage: G.longest_path(algorithm='heuristic', use_edge_labels=True) + Traceback (most recent call last): + ... + ValueError: parameters s, t, and use_edge_labels can not be used in + combinaiton with algorithms 'backtrack' and 'heuristic' """ self._scream_if_not_simple() - if use_edge_labels: - algorithm = "MILP" - if algorithm not in ("backtrack", "MILP"): - raise ValueError("algorithm must be either 'backtrack' or 'MILP'") + if algorithm not in ("backtrack", "heuristic", "MILP"): + raise ValueError("algorithm must be either 'backtrack', 'heuristic' or 'MILP'") + if algorithm == "backtrack": + from sage.misc.superseded import warning + warning(12345, + "algorithm 'backtrack' will be renamed 'heuristic' in the future.", + FutureWarning) + algorithm = 'heuristic' + if algorithm == 'heuristic': + if s is not None or t is not None or use_edge_labels: + raise ValueError("parameters s, t, and use_edge_labels can not " + "be used in combinaiton with algorithms " + "'backtrack' and 'heuristic'") # Quick improvement if not self.is_connected(): @@ -8080,8 +8121,8 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", from sage.graphs.graph import Graph return [0, Graph()] if use_edge_labels else Graph() - # Calling the backtrack heuristic if asked - if algorithm == "backtrack": + # Calling the heuristic if asked + if algorithm == "heuristic": from sage.graphs.generic_graph_pyx import find_hamiltonian as fh x = fh(self, find_path=True)[1] return self.subgraph(vertices=x, edges=list(zip(x[:-1], x[1:]))) From 2aee48ba969c3f2e92b00574abba36ab7d4adee5 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Sun, 29 Oct 2023 19:24:27 +0100 Subject: [PATCH 081/538] add the number of this PR --- src/sage/graphs/generic_graph.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 33f50fd712d..0c2f0f88725 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8040,12 +8040,12 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: H == {x for x in G.longest_path().edge_iterator(labels=False)} # needs sage.numerical.mip True - :gh:`12345`:: + :issue:`36574`:: sage: G = graphs.PathGraph(3) sage: P = G.longest_path(algorithm='backtrack') doctest:...: FutureWarning: algorithm 'backtrack' will be renamed 'heuristic' in the future. - See https://github.com/sagemath/sage/issues/12345 for details. + See https://github.com/sagemath/sage/issues/36574 for details. sage: G.longest_path(algorithm='heuristic', s=0) Traceback (most recent call last): ... @@ -8068,7 +8068,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", raise ValueError("algorithm must be either 'backtrack', 'heuristic' or 'MILP'") if algorithm == "backtrack": from sage.misc.superseded import warning - warning(12345, + warning(36574, "algorithm 'backtrack' will be renamed 'heuristic' in the future.", FutureWarning) algorithm = 'heuristic' From 02799e4c29a068e386259ea8908a87ca4289b9a5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 Oct 2023 18:06:30 -0700 Subject: [PATCH 082/538] pkgs/sage-setup/pyproject.toml: Remove pkgconfig, make jinja2 an optional dep --- pkgs/sage-setup/pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/sage-setup/pyproject.toml b/pkgs/sage-setup/pyproject.toml index d8a870d2c92..1499fe4c9ba 100644 --- a/pkgs/sage-setup/pyproject.toml +++ b/pkgs/sage-setup/pyproject.toml @@ -23,16 +23,16 @@ classifiers = [ ] urls = {Homepage = "https://www.sagemath.org"} requires-python = ">=3.9, <3.12" -dependencies = [ - "pkgconfig", - "jinja2", -] +dependencies = [] dynamic = ["version"] [project.readme] file = "README.rst" content-type = "text/x-rst" +[project.optional-dependencies] +autogen = ["jinja2"] + [tool.setuptools] packages = [ "sage_setup", From 0eef9811bcef33209b3e8140f1275978c26578cd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 Oct 2023 18:08:01 -0700 Subject: [PATCH 083/538] src/pyproject.toml.m4: Use sage_setup[autogen] --- src/pyproject.toml.m4 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pyproject.toml.m4 b/src/pyproject.toml.m4 index f707b6f890e..2b61ea041ea 100644 --- a/src/pyproject.toml.m4 +++ b/src/pyproject.toml.m4 @@ -1,6 +1,7 @@ [build-system] # Minimum requirements for the build system to execute. requires = [ + "sage_setup[autogen]", # Some version of sage-conf is required. # Note that PEP517/518 have no notion of optional sage_spkg dependencies: # https://github.com/pypa/pip/issues/6144 From 7da883413705c480d3ad37232b01bbc9e627fa17 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 Oct 2023 21:23:28 -0700 Subject: [PATCH 084/538] pkgs/sagemath-{bliss,coxeter3,...}/pyproject.toml.m4: Add pkgconfig to build-system requires --- pkgs/sagemath-bliss/pyproject.toml.m4 | 1 + pkgs/sagemath-coxeter3/pyproject.toml.m4 | 1 + pkgs/sagemath-mcqd/pyproject.toml.m4 | 1 + pkgs/sagemath-meataxe/pyproject.toml.m4 | 1 + pkgs/sagemath-sirocco/pyproject.toml.m4 | 1 + pkgs/sagemath-tdlib/pyproject.toml.m4 | 1 + 6 files changed, 6 insertions(+) diff --git a/pkgs/sagemath-bliss/pyproject.toml.m4 b/pkgs/sagemath-bliss/pyproject.toml.m4 index 1cbcdf7e162..7783c12c118 100644 --- a/pkgs/sagemath-bliss/pyproject.toml.m4 +++ b/pkgs/sagemath-bliss/pyproject.toml.m4 @@ -8,5 +8,6 @@ requires = [ SPKG_INSTALL_REQUIRES_sagemath_environment SPKG_INSTALL_REQUIRES_cython SPKG_INSTALL_REQUIRES_cysignals + SPKG_INSTALL_REQUIRES_pkgconfig ] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-coxeter3/pyproject.toml.m4 b/pkgs/sagemath-coxeter3/pyproject.toml.m4 index a7d65382b21..69613011371 100644 --- a/pkgs/sagemath-coxeter3/pyproject.toml.m4 +++ b/pkgs/sagemath-coxeter3/pyproject.toml.m4 @@ -7,5 +7,6 @@ requires = [ SPKG_INSTALL_REQUIRES_sagemath_environment SPKG_INSTALL_REQUIRES_cython SPKG_INSTALL_REQUIRES_cysignals + SPKG_INSTALL_REQUIRES_pkgconfig ] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-mcqd/pyproject.toml.m4 b/pkgs/sagemath-mcqd/pyproject.toml.m4 index 7e651119193..bb34e4c5eb9 100644 --- a/pkgs/sagemath-mcqd/pyproject.toml.m4 +++ b/pkgs/sagemath-mcqd/pyproject.toml.m4 @@ -8,5 +8,6 @@ requires = [ SPKG_INSTALL_REQUIRES_cython SPKG_INSTALL_REQUIRES_memory_allocator SPKG_INSTALL_REQUIRES_cysignals + SPKG_INSTALL_REQUIRES_pkgconfig ] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-meataxe/pyproject.toml.m4 b/pkgs/sagemath-meataxe/pyproject.toml.m4 index a7d65382b21..69613011371 100644 --- a/pkgs/sagemath-meataxe/pyproject.toml.m4 +++ b/pkgs/sagemath-meataxe/pyproject.toml.m4 @@ -7,5 +7,6 @@ requires = [ SPKG_INSTALL_REQUIRES_sagemath_environment SPKG_INSTALL_REQUIRES_cython SPKG_INSTALL_REQUIRES_cysignals + SPKG_INSTALL_REQUIRES_pkgconfig ] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-sirocco/pyproject.toml.m4 b/pkgs/sagemath-sirocco/pyproject.toml.m4 index 99894dd5e5e..684ed189d9f 100644 --- a/pkgs/sagemath-sirocco/pyproject.toml.m4 +++ b/pkgs/sagemath-sirocco/pyproject.toml.m4 @@ -8,5 +8,6 @@ requires = [ SPKG_INSTALL_REQUIRES_cython SPKG_INSTALL_REQUIRES_cypari SPKG_INSTALL_REQUIRES_cysignals + SPKG_INSTALL_REQUIRES_pkgconfig ] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-tdlib/pyproject.toml.m4 b/pkgs/sagemath-tdlib/pyproject.toml.m4 index a7d65382b21..69613011371 100644 --- a/pkgs/sagemath-tdlib/pyproject.toml.m4 +++ b/pkgs/sagemath-tdlib/pyproject.toml.m4 @@ -7,5 +7,6 @@ requires = [ SPKG_INSTALL_REQUIRES_sagemath_environment SPKG_INSTALL_REQUIRES_cython SPKG_INSTALL_REQUIRES_cysignals + SPKG_INSTALL_REQUIRES_pkgconfig ] build-backend = "setuptools.build_meta" From 815ce133a4ad4e937b6cc22e78528e3c44e945fc Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 29 Oct 2023 21:42:04 -0700 Subject: [PATCH 085/538] pkgs/sagemath-{objects,categories}/pyproject.toml.m4: Add pkgconfig to build-system requires --- pkgs/sagemath-categories/pyproject.toml.m4 | 1 + pkgs/sagemath-objects/pyproject.toml.m4 | 1 + 2 files changed, 2 insertions(+) diff --git a/pkgs/sagemath-categories/pyproject.toml.m4 b/pkgs/sagemath-categories/pyproject.toml.m4 index cf4c97f1fd1..4049f5868a4 100644 --- a/pkgs/sagemath-categories/pyproject.toml.m4 +++ b/pkgs/sagemath-categories/pyproject.toml.m4 @@ -10,5 +10,6 @@ requires = [ SPKG_INSTALL_REQUIRES_cython SPKG_INSTALL_REQUIRES_gmpy2 SPKG_INSTALL_REQUIRES_cysignals + SPKG_INSTALL_REQUIRES_pkgconfig ] build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-objects/pyproject.toml.m4 b/pkgs/sagemath-objects/pyproject.toml.m4 index d8fda57a8f8..ec98813d439 100644 --- a/pkgs/sagemath-objects/pyproject.toml.m4 +++ b/pkgs/sagemath-objects/pyproject.toml.m4 @@ -9,5 +9,6 @@ requires = [ SPKG_INSTALL_REQUIRES_cython SPKG_INSTALL_REQUIRES_gmpy2 SPKG_INSTALL_REQUIRES_cysignals + SPKG_INSTALL_REQUIRES_pkgconfig ] build-backend = "setuptools.build_meta" From 88f6795ebb75f3ab2ef379d523eddbdc291b3336 Mon Sep 17 00:00:00 2001 From: Saatvik Rao Date: Mon, 30 Oct 2023 14:36:53 +0530 Subject: [PATCH 086/538] implemented power of graph function under basic methods --- src/sage/graphs/graph.py | 56 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 2435bd815b7..b1e6573356d 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -4890,6 +4890,62 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, return repr + @doc_index("Basic methods") + def power_of_graph(self, k): + r""" + Compute the kth power graph of an undirected, unweighted graph based on + shortest distances between nodes using BFS. + + INPUT: + - graph: An undirected, unweighted graph. + - k: The maximum path length for considering edges in the power graph. + + OUTPUT: + - The kth power graph based on shortest distances between nodes. + + EXAMPLE: + + sage: G = Graph([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4), (4, 5)]) + sage: k = 2 + sage: PG = power_graph_with_shortest_distances(G, k) + sage: PG.edges() + [(0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (5, 4), (4, 5)] + + """ + n = self.order() + all_distances = {} # Dictionary to store shortest distances between all pairs of nodes + + from collections import deque + + # Step 1: Compute shortest distances using BFS + for u in self.vertices(): + distances = {} # Dictionary to store distances from u to all other nodes + visited = {v: False for v in self.vertices()} + queue = deque() + + visited[u] = True + distances[u] = 0 + queue.append(u) + + while queue: + v = queue.popleft() + for neighbor in self.neighbors(v): + if not visited[neighbor]: + visited[neighbor] = True + distances[neighbor] = distances[v] + 1 + queue.append(neighbor) + + all_distances[u] = distances + + # Step 2: Create the kth power graph based on distances + PG = Graph() + for u in self.vertices(): + for v in self.vertices(): + if u != v and all_distances[u].get(v, float('inf')) <= k: + PG.add_edge(u, v) + + return PG + @doc_index("Algorithmically hard stuff") def minor(self, H, solver=None, verbose=0, induced=False, *, integrality_tolerance=1e-3): r""" From bac9d7c7aba31d18c813d4bbf9c0af6d76dc1464 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 11:31:23 +0000 Subject: [PATCH 087/538] cleanup --- src/sage/categories/all.py | 91 ++++++++++++++++++-- src/sage/categories/all__sagemath_objects.py | 14 ++- src/sage/categories/basic.py | 45 ++++++++-- src/sage/categories/category_singleton.pyx | 2 - src/sage/categories/chain_complexes.py | 4 +- 5 files changed, 141 insertions(+), 15 deletions(-) diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index 936346c5d13..9c2b8bd6518 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -25,49 +25,130 @@ """ # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc - install_doc(__package__, __doc__) +from sage.categories import primer + +from sage.misc.lazy_import import lazy_import from sage.categories.all__sagemath_objects import * + from sage.categories.basic import * +from sage.categories.chain_complexes import ChainComplexes, HomologyFunctor + +from sage.categories.simplicial_complexes import SimplicialComplexes + +from sage.categories.tensor import tensor +from sage.categories.signed_tensor import tensor_signed + +from sage.categories.g_sets import GSets +from sage.categories.pointed_sets import PointedSets + +from sage.categories.sets_with_grading import SetsWithGrading + +from sage.categories.groupoid import Groupoid +from sage.categories.permutation_groups import PermutationGroups + # enumerated sets +from sage.categories.finite_sets import FiniteSets +from sage.categories.enumerated_sets import EnumeratedSets +from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets + # posets +from sage.categories.posets import Posets +from sage.categories.finite_posets import FinitePosets +from sage.categories.lattice_posets import LatticePosets +from sage.categories.finite_lattice_posets import FiniteLatticePosets + # finite groups/... +from sage.categories.finite_semigroups import FiniteSemigroups +from sage.categories.finite_monoids import FiniteMonoids +from sage.categories.finite_groups import FiniteGroups +from sage.categories.finite_permutation_groups import FinitePermutationGroups + # fields +from sage.categories.number_fields import NumberFields +from sage.categories.function_fields import FunctionFields + # modules -from sage.categories.modules import Modules -from sage.misc.lazy_import import lazy_import +from sage.categories.left_modules import LeftModules +from sage.categories.right_modules import RightModules +from sage.categories.bimodules import Bimodules +from sage.categories.modules import Modules RingModules = Modules +from sage.categories.vector_spaces import VectorSpaces # (hopf) algebra structures +from sage.categories.algebras import Algebras +from sage.categories.commutative_algebras import CommutativeAlgebras +from sage.categories.coalgebras import Coalgebras +from sage.categories.bialgebras import Bialgebras +from sage.categories.hopf_algebras import HopfAlgebras +from sage.categories.lie_algebras import LieAlgebras # specific algebras +from sage.categories.monoid_algebras import MonoidAlgebras +from sage.categories.group_algebras import GroupAlgebras +from sage.categories.matrix_algebras import MatrixAlgebras # ideals from sage.categories.ring_ideals import RingIdeals - Ideals = RingIdeals +from sage.categories.commutative_ring_ideals import CommutativeRingIdeals +from sage.categories.algebra_modules import AlgebraModules +from sage.categories.algebra_ideals import AlgebraIdeals +from sage.categories.commutative_algebra_ideals import CommutativeAlgebraIdeals # schemes and varieties +from sage.categories.modular_abelian_varieties import ModularAbelianVarieties +from sage.categories.schemes import Schemes # * with basis from sage.categories.modules_with_basis import ModulesWithBasis - FreeModules = ModulesWithBasis +from sage.categories.hecke_modules import HeckeModules +from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.categories.coalgebras_with_basis import CoalgebrasWithBasis +from sage.categories.bialgebras_with_basis import BialgebrasWithBasis +from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis # finite dimensional * with basis +from sage.categories.finite_dimensional_modules_with_basis import FiniteDimensionalModulesWithBasis +from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis +from sage.categories.finite_dimensional_coalgebras_with_basis import FiniteDimensionalCoalgebrasWithBasis +from sage.categories.finite_dimensional_bialgebras_with_basis import FiniteDimensionalBialgebrasWithBasis +from sage.categories.finite_dimensional_hopf_algebras_with_basis import FiniteDimensionalHopfAlgebrasWithBasis # graded * +from sage.categories.graded_modules import GradedModules +from sage.categories.graded_algebras import GradedAlgebras +from sage.categories.graded_coalgebras import GradedCoalgebras +from sage.categories.graded_bialgebras import GradedBialgebras +from sage.categories.graded_hopf_algebras import GradedHopfAlgebras # graded * with basis +from sage.categories.graded_modules_with_basis import GradedModulesWithBasis +from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis +from sage.categories.graded_coalgebras_with_basis import GradedCoalgebrasWithBasis +from sage.categories.graded_bialgebras_with_basis import GradedBialgebrasWithBasis +from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis # Coxeter groups +from sage.categories.coxeter_groups import CoxeterGroups lazy_import('sage.categories.finite_coxeter_groups', 'FiniteCoxeterGroups') +from sage.categories.weyl_groups import WeylGroups +from sage.categories.finite_weyl_groups import FiniteWeylGroups +from sage.categories.affine_weyl_groups import AffineWeylGroups # crystal bases +from sage.categories.crystals import Crystals +from sage.categories.highest_weight_crystals import HighestWeightCrystals +from sage.categories.regular_crystals import RegularCrystals +from sage.categories.finite_crystals import FiniteCrystals +from sage.categories.classical_crystals import ClassicalCrystals # polyhedra lazy_import('sage.categories.polyhedra', 'PolyhedralSets') diff --git a/src/sage/categories/all__sagemath_objects.py b/src/sage/categories/all__sagemath_objects.py index 979ce64ce7b..d87b4a1d20e 100644 --- a/src/sage/categories/all__sagemath_objects.py +++ b/src/sage/categories/all__sagemath_objects.py @@ -1,16 +1,28 @@ # Subset of sage.categories.all that is made available by the sage-objects distribution +from sage.misc.lazy_import import lazy_import # Resolve a circular import so that "import sage.categories.all" can succeed # in initializing the category system. +import sage.structure.category_object # imports sage.categories.category -# Small part of "from .basic import *": +# Small part of "from sage.categories.basic import *": +from sage.categories.objects import Objects +from sage.categories.sets_cat import Sets, EmptySetError +from sage.categories.category import Category +from sage.categories.category_types import Elements +from sage.categories.cartesian_product import cartesian_product +from sage.categories.functor import ForgetfulFunctor, IdentityFunctor +from sage.categories.homset import Hom, hom, End, end, Homset, HomsetWithBase +from sage.categories.morphism import Morphism +from sage.categories.realizations import Realizations +from sage.categories.sets_with_partial_maps import SetsWithPartialMaps diff --git a/src/sage/categories/basic.py b/src/sage/categories/basic.py index f81d226fb36..f3574db469d 100644 --- a/src/sage/categories/basic.py +++ b/src/sage/categories/basic.py @@ -2,24 +2,59 @@ A subset of sage.categories.all with just the basic categories needed for sage startup (i.e. to define ZZ, QQ, ...). """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** +from sage.categories.objects import Objects +from sage.categories.sets_cat import Sets, EmptySetError from sage.categories.posets import Posets # For backward compatibility; will be deprecated at some point PartiallyOrderedSets = Posets OrderedSets = Posets - +from sage.categories.additive_magmas import AdditiveMagmas +from sage.categories.commutative_additive_semigroups import ( + CommutativeAdditiveSemigroups, +) +from sage.categories.commutative_additive_monoids import CommutativeAdditiveMonoids +from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups + +from sage.categories.magmas import Magmas +from sage.categories.semigroups import Semigroups +from sage.categories.monoids import Monoids +from sage.categories.groups import Groups from sage.categories.partially_ordered_monoids import PartiallyOrderedMonoids # For backward compatibility; might be deprecated at some point OrderedMonoids = PartiallyOrderedMonoids - - +from sage.categories.rngs import Rngs +from sage.categories.semirings import Semirings +from sage.categories.rings import Rings +from sage.categories.domains import Domains +from sage.categories.division_rings import DivisionRings + +from sage.categories.commutative_rings import CommutativeRings +from sage.categories.integral_domains import IntegralDomains +from sage.categories.gcd_domains import GcdDomains +from sage.categories.principal_ideal_domains import PrincipalIdealDomains +from sage.categories.euclidean_domains import EuclideanDomains +from sage.categories.unique_factorization_domains import UniqueFactorizationDomains +from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationRings + +from sage.categories.fields import Fields +from sage.categories.quotient_fields import QuotientFields +from sage.categories.finite_fields import FiniteFields +from sage.categories.discrete_valuation import ( + DiscreteValuationRings, + DiscreteValuationFields, +) +from sage.categories.complete_discrete_valuation import ( + CompleteDiscreteValuationRings, + CompleteDiscreteValuationFields, +) diff --git a/src/sage/categories/category_singleton.pyx b/src/sage/categories/category_singleton.pyx index d07bcaa5586..543ce0375f7 100644 --- a/src/sage/categories/category_singleton.pyx +++ b/src/sage/categories/category_singleton.pyx @@ -15,8 +15,6 @@ from sage.categories.category import Category from sage.structure.category_object cimport CategoryObject from sage.structure.dynamic_class import DynamicMetaclass -# I have no idea why this is necessary, but otherwise the type import fails -from cpython.method cimport PyMethod_Check from cpython.type cimport PyType_IsSubtype # This helper class is used to implement Category_singleton.__contains__ diff --git a/src/sage/categories/chain_complexes.py b/src/sage/categories/chain_complexes.py index 2d3823aba73..9616aa608c4 100644 --- a/src/sage/categories/chain_complexes.py +++ b/src/sage/categories/chain_complexes.py @@ -260,8 +260,8 @@ def _apply_functor_to_morphism(self, f): sage: id_star(one) [one] """ - from .homset import Hom - from .morphism import SetMorphism + from sage.categories.homset import Hom + from sage.categories.morphism import SetMorphism domain = f.domain() codomain = f.codomain() From 604ec20ac85d68e17723cc57550f7a2244d673ca Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 11:50:44 +0000 Subject: [PATCH 088/538] Replace relative imports by absolute ones in rings --- src/sage/rings/abc.pxd | 2 +- src/sage/rings/all.py | 94 +++++++++---------- src/sage/rings/all__sagemath_categories.py | 6 +- src/sage/rings/big_oh.py | 11 ++- src/sage/rings/cc.py | 2 +- src/sage/rings/cif.py | 2 +- src/sage/rings/complex_conversion.pyx | 4 +- src/sage/rings/complex_double.pyx | 6 +- src/sage/rings/complex_interval.pxd | 2 +- src/sage/rings/complex_interval.pyx | 8 +- src/sage/rings/complex_interval_field.py | 19 ++-- src/sage/rings/complex_mpc.pyx | 12 +-- src/sage/rings/complex_mpfr.pxd | 2 +- src/sage/rings/complex_mpfr.pyx | 8 +- src/sage/rings/continued_fraction.py | 23 ++--- src/sage/rings/fraction_field.py | 27 +++--- src/sage/rings/fraction_field_element.pyx | 2 +- src/sage/rings/homset.py | 5 +- src/sage/rings/ideal_monoid.py | 4 +- src/sage/rings/imaginary_unit.py | 2 +- src/sage/rings/integer.pyx | 2 +- src/sage/rings/integer_ring.pxd | 4 +- src/sage/rings/integer_ring.pyx | 2 +- src/sage/rings/laurent_series_ring.py | 25 +++-- .../rings/laurent_series_ring_element.pyx | 4 +- src/sage/rings/morphism.pyx | 2 +- src/sage/rings/power_series_mpoly.pxd | 2 +- src/sage/rings/power_series_mpoly.pyx | 8 +- src/sage/rings/power_series_pari.pxd | 2 +- src/sage/rings/power_series_poly.pxd | 2 +- src/sage/rings/power_series_poly.pyx | 4 +- src/sage/rings/power_series_ring.py | 46 ++++----- src/sage/rings/power_series_ring_element.pyx | 4 +- src/sage/rings/qqbar.py | 68 +++++++++----- src/sage/rings/quotient_ring.py | 28 +++--- src/sage/rings/rational.pyx | 4 +- src/sage/rings/rational_field.py | 27 +++--- src/sage/rings/real_double_element_gsl.pxd | 2 +- src/sage/rings/real_mpfi.pxd | 4 +- src/sage/rings/real_mpfi.pyx | 10 +- src/sage/rings/real_mpfr.pyx | 6 +- src/sage/rings/sum_of_squares.pyx | 2 +- 42 files changed, 266 insertions(+), 233 deletions(-) diff --git a/src/sage/rings/abc.pxd b/src/sage/rings/abc.pxd index a53b512d62f..a2d2e3f0ce4 100644 --- a/src/sage/rings/abc.pxd +++ b/src/sage/rings/abc.pxd @@ -1,4 +1,4 @@ -from .ring cimport CommutativeRing, Field +from sage.rings.ring cimport CommutativeRing, Field cdef class RealField(Field): diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 1d7b89601f5..a5d85204866 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -12,10 +12,10 @@ # **************************************************************************** from sage.misc.lazy_import import lazy_import -from .all__sagemath_categories import * +from sage.rings.all__sagemath_categories import * # Ring base classes -from .ring import (Ring, Field, CommutativeRing, IntegralDomain, +from sage.rings.ring import (Ring, Field, CommutativeRing, IntegralDomain, DedekindDomain, PrincipalIdealDomain, EuclideanDomain) # Ring element base classes @@ -25,22 +25,22 @@ EuclideanDomainElement, FieldElement) # Ideals -from .ideal import Ideal +from sage.rings.ideal import Ideal ideal = Ideal # Quotient -from .quotient_ring import QuotientRing +from sage.rings.quotient_ring import QuotientRing # Infinities -from .infinity import infinity, Infinity, InfinityRing, unsigned_infinity, UnsignedInfinityRing +from sage.rings.infinity import infinity, Infinity, InfinityRing, unsigned_infinity, UnsignedInfinityRing # Rational integers. -from .integer_ring import IntegerRing, ZZ, crt_basis -from .integer import Integer +from sage.rings.integer_ring import IntegerRing, ZZ, crt_basis +from sage.rings.integer import Integer # Rational numbers -from .rational_field import RationalField, QQ -from .rational import Rational +from sage.rings.rational_field import RationalField, QQ +from sage.rings.rational import Rational Rationals = RationalField # Integers modulo n. @@ -49,120 +49,120 @@ Integers = IntegerModRing # Finite fields -from .finite_rings.all import * +from sage.rings.finite_rings.all import * # Number field -from .number_field.all import * +from sage.rings.number_field.all import * # Function field -from .function_field.all import * +from sage.rings.function_field.all import * # Finite residue fields -from .finite_rings.residue_field import ResidueField +from sage.rings.finite_rings.residue_field import ResidueField # p-adic field -from .padics.all import * -from .padics.padic_printing import _printer_defaults as padic_printing +from sage.rings.padics.all import * +from sage.rings.padics.padic_printing import _printer_defaults as padic_printing # valuations -from .valuation.all import * +from sage.rings.valuation.all import * # Semirings -from .semirings.all import * +from sage.rings.semirings.all import * # Real numbers -from .real_mpfr import (RealField, RR, +from sage.rings.real_mpfr import (RealField, RR, create_RealNumber as RealNumber) # this is used by the preparser to wrap real literals -- very important. Reals = RealField -from .real_double import RealDoubleField, RDF, RealDoubleElement +from sage.rings.real_double import RealDoubleField, RDF, RealDoubleElement -from .real_lazy import RealLazyField, RLF, ComplexLazyField, CLF +from sage.rings.real_lazy import RealLazyField, RLF, ComplexLazyField, CLF from sage.rings.real_arb import RealBallField, RBF # Polynomial Rings and Polynomial Quotient Rings -from .polynomial.all import * +from sage.rings.polynomial.all import * # Algebraic numbers -from .qqbar import (AlgebraicRealField, AA, +from sage.rings.qqbar import (AlgebraicRealField, AA, AlgebraicReal, AlgebraicField, QQbar, AlgebraicNumber, number_field_elements_from_algebraics) -from .universal_cyclotomic_field import UniversalCyclotomicField, E +from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField, E # Intervals -from .real_mpfi import (RealIntervalField, +from sage.rings.real_mpfi import (RealIntervalField, RIF, RealInterval) # Complex numbers -from .complex_mpfr import ComplexField -from .complex_mpfr import create_ComplexNumber as ComplexNumber +from sage.rings.complex_mpfr import ComplexField +from sage.rings.complex_mpfr import create_ComplexNumber as ComplexNumber Complexes = ComplexField -from .complex_interval_field import ComplexIntervalField -from .complex_interval import (create_ComplexIntervalFieldElement as ComplexIntervalFieldElement) +from sage.rings.complex_interval_field import ComplexIntervalField +from sage.rings.complex_interval import (create_ComplexIntervalFieldElement as ComplexIntervalFieldElement) -from .complex_double import ComplexDoubleField, ComplexDoubleElement, CDF +from sage.rings.complex_double import ComplexDoubleField, ComplexDoubleElement, CDF -from .complex_mpc import MPComplexField +from sage.rings.complex_mpc import MPComplexField from sage.rings.complex_arb import ComplexBallField, CBF lazy_import("sage.rings.imaginary_unit", "I") # Power series rings -from .power_series_ring import PowerSeriesRing +from sage.rings.power_series_ring import PowerSeriesRing # Laurent series ring in one variable -from .laurent_series_ring import LaurentSeriesRing +from sage.rings.laurent_series_ring import LaurentSeriesRing # Lazy Laurent series ring lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyPowerSeriesRing', 'LazySymmetricFunctions', 'LazyDirichletSeriesRing']) # Tate algebras -from .tate_algebra import TateAlgebra +from sage.rings.tate_algebra import TateAlgebra # Puiseux series ring -from .puiseux_series_ring import PuiseuxSeriesRing +from sage.rings.puiseux_series_ring import PuiseuxSeriesRing # Pseudo-ring of PARI objects. -from .pari_ring import PariRing, Pari +from sage.rings.pari_ring import PariRing, Pari # Big-oh notation -from .big_oh import O +from sage.rings.big_oh import O # Fraction field -from .fraction_field import FractionField +from sage.rings.fraction_field import FractionField Frac = FractionField # Localization -from .localization import Localization +from sage.rings.localization import Localization # c-finite sequences -from .cfinite_sequence import CFiniteSequence, CFiniteSequences +from sage.rings.cfinite_sequence import CFiniteSequence, CFiniteSequences -from .bernoulli_mod_p import bernoulli_mod_p, bernoulli_mod_p_single +from sage.rings.bernoulli_mod_p import bernoulli_mod_p, bernoulli_mod_p_single -from .monomials import monomials +from sage.rings.monomials import monomials -from .cc import CC -from .cif import CIF +from sage.rings.cc import CC +from sage.rings.cif import CIF # invariant theory -from .invariants.all import * +from sage.rings.invariants.all import * -from .fast_arith import prime_range +from sage.rings.fast_arith import prime_range # continued fractions from sage.rings.continued_fraction import (continued_fraction, continued_fraction_list) # asymptotic ring -from .asymptotic.all import * +from sage.rings.asymptotic.all import * # Register classes in numbers abc -from . import numbers_abc +from sage.rings. import numbers_abc diff --git a/src/sage/rings/all__sagemath_categories.py b/src/sage/rings/all__sagemath_categories.py index 8d14e7afcda..d03d1c6b483 100644 --- a/src/sage/rings/all__sagemath_categories.py +++ b/src/sage/rings/all__sagemath_categories.py @@ -1,6 +1,6 @@ # Ring base classes -from .ring import Ring - +from sage.rings.ring import Ring # Ideals -from .ideal import Ideal +from sage.rings.ideal import Ideal + ideal = Ideal diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index e9b22e77b37..917c81e0a3d 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -11,6 +11,7 @@ from sage.arith.misc import factor from sage.misc.lazy_import import lazy_import + lazy_import('sage.rings.padics.factory', ['Qp', 'Zp']) lazy_import('sage.rings.padics.padic_generic_element', 'pAdicGenericElement') from sage.rings.polynomial.polynomial_element import Polynomial @@ -25,10 +26,12 @@ except ImportError: PuiseuxSeries = () -from . import power_series_ring_element -from . import integer -from . import rational -from . import multi_power_series_ring_element +from sage.rings import ( + integer, + multi_power_series_ring_element, + power_series_ring_element, + rational, +) def O(*x, **kwds): diff --git a/src/sage/rings/cc.py b/src/sage/rings/cc.py index 6db89579029..94e3093488b 100644 --- a/src/sage/rings/cc.py +++ b/src/sage/rings/cc.py @@ -1,3 +1,3 @@ -from .complex_mpfr import ComplexField +from sage.rings.complex_mpfr import ComplexField CC = ComplexField() diff --git a/src/sage/rings/cif.py b/src/sage/rings/cif.py index 91924f4d26c..900c635e87b 100644 --- a/src/sage/rings/cif.py +++ b/src/sage/rings/cif.py @@ -1,3 +1,3 @@ -from .complex_interval_field import ComplexIntervalField +from sage.rings.complex_interval_field import ComplexIntervalField CIF = ComplexIntervalField() diff --git a/src/sage/rings/complex_conversion.pyx b/src/sage/rings/complex_conversion.pyx index abf179064c6..d692e2801d7 100644 --- a/src/sage/rings/complex_conversion.pyx +++ b/src/sage/rings/complex_conversion.pyx @@ -1,5 +1,5 @@ -from .complex_double cimport ComplexDoubleElement -from .complex_mpfr cimport ComplexNumber +from sage.rings.complex_double cimport ComplexDoubleElement +from sage.rings.complex_mpfr cimport ComplexNumber from sage.libs.mpfr cimport mpfr_get_d, MPFR_RNDN from sage.libs.gsl.complex cimport GSL_SET_COMPLEX diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 8b9883d1279..65134903644 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -105,10 +105,10 @@ complex_double_element_gamma = None complex_double_element_gamma_inc = None complex_double_element_zeta = None -from .complex_conversion cimport CCtoCDF +from sage.rings.complex_conversion cimport CCtoCDF -from .real_double cimport RealDoubleElement, double_repr -from .real_double import RDF +from sage.rings.real_double cimport RealDoubleElement, double_repr +from sage.rings.real_double import RDF from sage.rings.integer_ring import ZZ from sage.structure.richcmp cimport rich_to_bool diff --git a/src/sage/rings/complex_interval.pxd b/src/sage/rings/complex_interval.pxd index b0a64632ad5..f5c59de4d7a 100644 --- a/src/sage/rings/complex_interval.pxd +++ b/src/sage/rings/complex_interval.pxd @@ -2,7 +2,7 @@ from sage.libs.mpfr.types cimport mpfr_prec_t from sage.libs.mpfi.types cimport mpfi_t cimport sage.structure.element -from .real_mpfi cimport RealIntervalFieldElement, RealIntervalField_class +from sage.rings.real_mpfi cimport RealIntervalFieldElement, RealIntervalField_class cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 7fe25fd8114..aab048e784c 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -66,12 +66,12 @@ from sage.arith.constants cimport LOG_TEN_TWO_PLUS_EPSILON from sage.structure.element cimport FieldElement from sage.structure.parent cimport Parent -from .complex_mpfr cimport ComplexNumber +from sage.rings.complex_mpfr cimport ComplexNumber from sage.rings.integer cimport Integer cimport sage.rings.real_mpfi as real_mpfi -from .real_mpfr cimport RealNumber -from .convert.mpfi cimport mpfi_set_sage -from .infinity import infinity +from sage.rings.real_mpfr cimport RealNumber +from sage.rings.convert.mpfi cimport mpfi_set_sage +from sage.rings.infinity import infinity def is_ComplexIntervalFieldElement(x): diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index 5c5e6bbb906..358c8caf367 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -36,18 +36,17 @@ # **************************************************************************** -from sage.structure.parent import Parent -from .integer_ring import ZZ -from .rational_field import QQ -from .ring import Field -import sage.rings.abc -from . import integer -from . import complex_interval import weakref -from .real_mpfi import RealIntervalField, RealIntervalField_class -from .complex_mpfr import ComplexField -from sage.misc.cachefunc import cached_method +import sage.rings.abc +from sage.misc.cachefunc import cached_method +from sage.rings import complex_interval, integer +from sage.rings.complex_mpfr import ComplexField +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.rings.real_mpfi import RealIntervalField, RealIntervalField_class +from sage.rings.ring import Field +from sage.structure.parent import Parent cache = {} def ComplexIntervalField(prec=53, names=None): diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index ae2bd50c735..ce0772be6f3 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -59,7 +59,7 @@ EXAMPLES:: # **************************************************************************** import re -from . import real_mpfr +from sage.rings import real_mpfr import weakref from cpython.object cimport Py_NE @@ -74,13 +74,13 @@ from sage.structure.richcmp cimport rich_to_bool from sage.categories.map cimport Map from sage.libs.pari.all import pari -from .integer cimport Integer -from .complex_mpfr cimport ComplexNumber -from .complex_mpfr import ComplexField_class +from sage.rings.integer cimport Integer +from sage.rings.complex_mpfr cimport ComplexNumber +from sage.rings.complex_mpfr import ComplexField_class from sage.misc.randstate cimport randstate, current_randstate -from .real_mpfr cimport RealField_class, RealNumber -from .real_mpfr import mpfr_prec_min, mpfr_prec_max +from sage.rings.real_mpfr cimport RealField_class, RealNumber +from sage.rings.real_mpfr import mpfr_prec_min, mpfr_prec_max from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.categories.fields import Fields diff --git a/src/sage/rings/complex_mpfr.pxd b/src/sage/rings/complex_mpfr.pxd index 9b8c8d08bf4..385feec8c37 100644 --- a/src/sage/rings/complex_mpfr.pxd +++ b/src/sage/rings/complex_mpfr.pxd @@ -1,7 +1,7 @@ from sage.libs.mpfr.types cimport mpfr_t, mpfr_prec_t cimport sage.structure.element -from .real_mpfr cimport RealNumber +from sage.rings.real_mpfr cimport RealNumber cdef class ComplexNumber(sage.structure.element.FieldElement): cdef mpfr_t __re diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index 1862cea7bbf..37945788aa5 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -46,11 +46,11 @@ from sage.misc.sage_eval import sage_eval import sage.rings.abc from sage.arith.constants cimport LOG_TEN_TWO_PLUS_EPSILON -from . import infinity -from .integer cimport Integer +from sage.rings import infinity +from sage.rings.integer cimport Integer -from .complex_double cimport ComplexDoubleElement -from .real_mpfr cimport RealNumber +from sage.rings.complex_double cimport ComplexDoubleElement +from sage.rings.real_mpfr cimport RealNumber from sage.libs.gsl.complex cimport * from sage.libs.mpmath.utils cimport mpfr_to_mpfval diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index e701c917062..4ce221dc331 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -207,12 +207,12 @@ import numbers -from sage.structure.sage_object import SageObject -from sage.structure.richcmp import richcmp_method, rich_to_bool import sage.rings.abc -from .integer import Integer -from .integer_ring import ZZ -from .infinity import Infinity +from sage.rings.infinity import Infinity +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.structure.richcmp import rich_to_bool, richcmp_method +from sage.structure.sage_object import SageObject ZZ_0 = Integer(0) ZZ_1 = Integer(1) @@ -849,8 +849,9 @@ def convergents(self): Add an example with infinite list. """ if self.length() == Infinity: - from sage.misc.lazy_list import lazy_list from itertools import count + + from sage.misc.lazy_list import lazy_list return lazy_list(self.numerator(n) / self.denominator(n) for n in count()) return [self.numerator(n) / self.denominator(n) @@ -876,8 +877,9 @@ def quotients(self): Add an example with infinite list. """ if self.length() == Infinity: - from sage.misc.lazy_list import lazy_list from itertools import count + + from sage.misc.lazy_list import lazy_list return lazy_list(self.quotient(n) for n in count()) return [self.quotient(n) for n in range(len(self))] @@ -1147,8 +1149,7 @@ def numerical_approx(self, prec=None, digits=None, algorithm=None): sage: cf.n(digits=33) # needs sage.combinat 1.28102513329556981555293038097590 """ - from sage.arith.numerical_approx import (digits_to_bits, - numerical_approx_generic) + from sage.arith.numerical_approx import digits_to_bits, numerical_approx_generic if prec is None: prec = digits_to_bits(digits) return numerical_approx_generic(self, prec) @@ -1564,8 +1565,8 @@ def value(self): # now x is one of the root of the equation # q1 x^2 + (q0 - p1) x - p0 = 0 - from sage.rings.number_field.number_field import QuadraticField from sage.misc.functional import squarefree_part + from sage.rings.number_field.number_field import QuadraticField D = (q0-p1)**2 + 4*q1*p0 DD = squarefree_part(D) Q = QuadraticField(DD, 'sqrt%d' % DD) @@ -2674,8 +2675,8 @@ def continued_fraction(x, value=None): return ContinuedFraction_periodic(x1, x2) # input for infinite partial quotient expansion - from sage.misc.lazy_list import lazy_list_generic from sage.combinat.words.infinite_word import InfiniteWord_class + from sage.misc.lazy_list import lazy_list_generic if isinstance(x, (lazy_list_generic, InfiniteWord_class)): return ContinuedFraction_infinite(x, value) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 5d298720a90..bfa690cec0e 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -83,19 +83,17 @@ # http://www.gnu.org/licenses/ # **************************************************************************** -from . import ring -from . import fraction_field_element import sage.misc.latex as latex +from sage.categories.basic import QuotientFields, Rings +from sage.categories.map import Section from sage.misc.cachefunc import cached_method - +from sage.rings import fraction_field_element, ring from sage.rings.integer_ring import ZZ -from sage.structure.richcmp import richcmp -from sage.structure.parent import Parent -from sage.structure.element import parent from sage.structure.coerce import py_scalar_to_element from sage.structure.coerce_maps import CallableConvertMap, DefaultConvertMap_unique -from sage.categories.basic import QuotientFields, Rings -from sage.categories.map import Section +from sage.structure.element import parent +from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp def FractionField(R, names=None): @@ -327,10 +325,11 @@ def _coerce_map_from_(self, S): sage: f(L(1/7)) == 1/7 True """ - from sage.rings.rational_field import QQ from sage.rings.number_field.number_field_base import NumberField - from sage.rings.polynomial.laurent_polynomial_ring_base import \ - LaurentPolynomialRing_generic + from sage.rings.polynomial.laurent_polynomial_ring_base import ( + LaurentPolynomialRing_generic, + ) + from sage.rings.rational_field import QQ if S is self._R: parent = self._R.Hom(self) @@ -1079,7 +1078,9 @@ def _coerce_map_from_(self, R): 1/t """ - from sage.rings.function_field.function_field_rational import RationalFunctionField + from sage.rings.function_field.function_field_rational import ( + RationalFunctionField, + ) if isinstance(R, RationalFunctionField) and self.variable_name() == R.variable_name() and self.base_ring() is R.constant_base_field(): from sage.categories.homset import Hom parent = Hom(R, self) @@ -1160,8 +1161,8 @@ def section(self): To: Univariate Polynomial Ring in x over Rational Field """ - from sage.categories.sets_with_partial_maps import SetsWithPartialMaps from sage.categories.homset import Hom + from sage.categories.sets_with_partial_maps import SetsWithPartialMaps parent = Hom(self.codomain(), self.domain(), SetsWithPartialMaps()) return parent.__make_element_class__(FractionFieldEmbeddingSection)(self) diff --git a/src/sage/rings/fraction_field_element.pyx b/src/sage/rings/fraction_field_element.pyx index 2134c2fa07b..b19c3d8c876 100644 --- a/src/sage/rings/fraction_field_element.pyx +++ b/src/sage/rings/fraction_field_element.pyx @@ -22,7 +22,7 @@ AUTHORS: from sage.structure.element cimport FieldElement, parent from sage.structure.richcmp cimport richcmp -from .rational_field import QQ +from sage.rings.rational_field import QQ import sage.misc.latex as latex diff --git a/src/sage/rings/homset.py b/src/sage/rings/homset.py index 0e500de2608..b2f24a3800a 100644 --- a/src/sage/rings/homset.py +++ b/src/sage/rings/homset.py @@ -12,10 +12,11 @@ from sage.categories.homset import HomsetWithBase from sage.categories.rings import Rings + _Rings = Rings() -from . import morphism -from . import quotient_ring +from sage.rings import morphism, quotient_ring + def is_RingHomset(H): """ diff --git a/src/sage/rings/ideal_monoid.py b/src/sage/rings/ideal_monoid.py index 0988ffc72e5..019348a6afe 100644 --- a/src/sage/rings/ideal_monoid.py +++ b/src/sage/rings/ideal_monoid.py @@ -8,10 +8,10 @@ """ -from sage.structure.parent import Parent import sage.rings.integer_ring -from . import ideal from sage.categories.monoids import Monoids +from sage.rings import ideal +from sage.structure.parent import Parent def IdealMonoid(R): diff --git a/src/sage/rings/imaginary_unit.py b/src/sage/rings/imaginary_unit.py index 09349e66e8b..bb29cd32630 100644 --- a/src/sage/rings/imaginary_unit.py +++ b/src/sage/rings/imaginary_unit.py @@ -1,5 +1,5 @@ # coding: utf-8 -from .number_field.number_field import GaussianField +from sage.rings.number_field.number_field import GaussianField I = GaussianField().gen() diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 4202bcc9a10..8fb2a557e69 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -182,7 +182,7 @@ from sage.structure.element import coerce_binop from sage.structure.richcmp cimport rich_to_bool_sgn -from . import integer_ring +from sage.rings import integer_ring cimport gmpy2 gmpy2.import_gmpy2() diff --git a/src/sage/rings/integer_ring.pxd b/src/sage/rings/integer_ring.pxd index 41afccaa514..d0af1bc068f 100644 --- a/src/sage/rings/integer_ring.pxd +++ b/src/sage/rings/integer_ring.pxd @@ -1,5 +1,5 @@ -from .ring cimport PrincipalIdealDomain -from .integer cimport Integer +from sage.rings.ring cimport PrincipalIdealDomain +from sage.rings.integer cimport Integer from sage.libs.gmp.types cimport mpz_t cdef class IntegerRing_class(PrincipalIdealDomain): diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index c7a05a13e16..d90625f86ed 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -69,7 +69,7 @@ from sage.misc.randstate cimport randstate, current_randstate, SAGE_RAND_MAX cimport sage.rings.integer as integer -from . import ring +from sage.rings import ring arith = None cdef void late_import(): diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 565e5d12f4c..187ac847522 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -32,20 +32,17 @@ # **************************************************************************** -from sage.categories.rings import Rings -from sage.rings.infinity import infinity from sage.categories.algebras import Algebras -from sage.categories.integral_domains import IntegralDomains -from sage.categories.fields import Fields from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields - -from .laurent_series_ring_element import LaurentSeries -from .ring import CommutativeRing - -from sage.structure.unique_representation import UniqueRepresentation +from sage.categories.fields import Fields +from sage.categories.integral_domains import IntegralDomains +from sage.categories.rings import Rings from sage.misc.cachefunc import cached_method - +from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ +from sage.rings.laurent_series_ring_element import LaurentSeries +from sage.rings.ring import CommutativeRing +from sage.structure.unique_representation import UniqueRepresentation try: from sage.libs.pari.all import pari_gen @@ -315,8 +312,8 @@ def fraction_field(self): ... ValueError: must be an integral domain """ - from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields + from sage.categories.integral_domains import IntegralDomains if self in Fields(): return self elif self in IntegralDomains(): @@ -489,8 +486,8 @@ def _element_constructor_(self, x, n=0, prec=infinity): x^-3 """ from sage.rings.fraction_field_element import is_FractionFieldElement - from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.multi_polynomial import MPolynomial + from sage.rings.polynomial.polynomial_element import Polynomial from sage.structure.element import parent P = parent(x) @@ -643,9 +640,11 @@ def _coerce_map_from_(self, P): True """ A = self.base_ring() + from sage.rings.polynomial.laurent_polynomial_ring_base import ( + LaurentPolynomialRing_generic, + ) from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.power_series_ring import is_PowerSeriesRing - from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic if ((is_LaurentSeriesRing(P) or isinstance(P, LaurentPolynomialRing_generic) or diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index d56996f3f78..d24c10a2f4d 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -66,12 +66,12 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from .infinity import infinity +from sage.rings.infinity import infinity from sage.rings.rational_field import QQ import sage.misc.latex from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_univariate -from .power_series_ring_element cimport PowerSeries +from sage.rings.power_series_ring_element cimport PowerSeries from sage.structure.element cimport Element, AlgebraElement from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool from sage.misc.derivative import multi_derivative diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index 5f7dc12cdb1..0c014e5d593 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -407,7 +407,7 @@ compare equal:: # https://www.gnu.org/licenses/ # **************************************************************************** -from . import ideal +from sage.rings import ideal import sage.structure.all from sage.structure.richcmp cimport (richcmp, rich_to_bool) from sage.misc.cachefunc import cached_method diff --git a/src/sage/rings/power_series_mpoly.pxd b/src/sage/rings/power_series_mpoly.pxd index d358ada1356..d8816e694b7 100644 --- a/src/sage/rings/power_series_mpoly.pxd +++ b/src/sage/rings/power_series_mpoly.pxd @@ -1,5 +1,5 @@ from sage.structure.element cimport ModuleElement -from .power_series_ring_element cimport PowerSeries +from sage.rings.power_series_ring_element cimport PowerSeries cdef class PowerSeries_mpoly(PowerSeries): cdef ModuleElement __f diff --git a/src/sage/rings/power_series_mpoly.pyx b/src/sage/rings/power_series_mpoly.pyx index be59294e75b..e3844c55299 100644 --- a/src/sage/rings/power_series_mpoly.pyx +++ b/src/sage/rings/power_series_mpoly.pyx @@ -1,10 +1,10 @@ # NOT ready to be used -- possibly should be deleted. -from .power_series_ring_element cimport PowerSeries +from sage.rings.power_series_ring_element cimport PowerSeries from sage.structure.element cimport Element -from .infinity import infinity -from .polynomial.multi_polynomial_ring_base import is_MPolynomialRing -from . import power_series_poly +from sage.rings.infinity import infinity +from sage.rings.polynomial.multi_polynomial_ring_base import is_MPolynomialRing +from sage.rings import power_series_poly cdef class PowerSeries_mpoly(PowerSeries): diff --git a/src/sage/rings/power_series_pari.pxd b/src/sage/rings/power_series_pari.pxd index fadf7f0fd08..35b37929c33 100644 --- a/src/sage/rings/power_series_pari.pxd +++ b/src/sage/rings/power_series_pari.pxd @@ -1,5 +1,5 @@ from cypari2.gen cimport Gen as pari_gen -from .power_series_ring_element cimport PowerSeries +from sage.rings.power_series_ring_element cimport PowerSeries cdef class PowerSeries_pari(PowerSeries): cdef pari_gen g diff --git a/src/sage/rings/power_series_poly.pxd b/src/sage/rings/power_series_poly.pxd index 80c441798a1..e37e1fb26cf 100644 --- a/src/sage/rings/power_series_poly.pxd +++ b/src/sage/rings/power_series_poly.pxd @@ -1,4 +1,4 @@ -from .power_series_ring_element cimport PowerSeries +from sage.rings.power_series_ring_element cimport PowerSeries from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.categories.action cimport Action diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index c7cd78db093..699370b386c 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -4,9 +4,9 @@ Power Series Methods The class ``PowerSeries_poly`` provides additional methods for univariate power series. """ -from .power_series_ring_element cimport PowerSeries +from sage.rings.power_series_ring_element cimport PowerSeries from sage.structure.element cimport Element -from .infinity import infinity +from sage.rings.infinity import infinity from sage.libs.pari.all import pari_gen, PariError diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index b43306adb36..0349bfbe373 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -134,34 +134,36 @@ """ -from . import power_series_poly -from . import power_series_mpoly -from .power_series_pari import PowerSeries_pari -from . import power_series_ring_element - -from sage.rings.polynomial.polynomial_ring import is_PolynomialRing -from sage.rings.polynomial.multi_polynomial_ring_base import is_MPolynomialRing -from .polynomial.polynomial_ring_constructor import PolynomialRing -from . import laurent_series_ring -from . import laurent_series_ring_element -from . import integer -from . import ring -from .infinity import infinity +import sage.categories.commutative_rings as commutative_rings import sage.misc.latex as latex -from sage.structure.nonexact import Nonexact - from sage.interfaces.abc import MagmaElement -from sage.rings.fraction_field_element import FractionFieldElement from sage.misc.sage_eval import sage_eval - -from sage.structure.unique_representation import UniqueRepresentation +from sage.rings import ( + integer, + laurent_series_ring, + laurent_series_ring_element, + power_series_mpoly, + power_series_poly, + power_series_ring_element, + ring, +) +from sage.rings.fraction_field_element import FractionFieldElement +from sage.rings.infinity import infinity +from sage.rings.polynomial.multi_polynomial_ring_base import is_MPolynomialRing +from sage.rings.polynomial.polynomial_ring import is_PolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_pari import PowerSeries_pari from sage.structure.category_object import normalize_names -from sage.structure.element import parent, Expression -import sage.categories.commutative_rings as commutative_rings +from sage.structure.element import Expression, parent +from sage.structure.nonexact import Nonexact +from sage.structure.unique_representation import UniqueRepresentation + _CommutativeRings = commutative_rings.CommutativeRings() import sage.categories.integral_domains as integral_domains + _IntegralDomains = integral_domains.IntegralDomains() import sage.categories.fields as fields + _Fields = fields.Fields() from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationRings @@ -535,7 +537,9 @@ def __init__(self, base_ring, name=None, default_prec=None, sparse=False, ValueError: default_prec (= -5) must be non-negative """ - from sage.rings.finite_rings.finite_field_pari_ffelt import FiniteField_pari_ffelt + from sage.rings.finite_rings.finite_field_pari_ffelt import ( + FiniteField_pari_ffelt, + ) if implementation is None: if isinstance(base_ring, FiniteField_pari_ffelt): diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 5e2c4511e49..0f88f00e034 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -96,7 +96,7 @@ With power series the behavior is the same. # **************************************************************************** from cpython.object cimport Py_EQ, Py_NE -from .infinity import infinity, is_Infinite +from sage.rings.infinity import infinity, is_Infinite from sage.rings.rational_field import QQ @@ -104,7 +104,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing import sage.misc.misc import sage.arith.all as arith import sage.misc.latex -from .integer import Integer +from sage.rings.integer import Integer from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.categories.fields import Fields diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 77d035896d0..5aa889c5403 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -557,36 +557,52 @@ import itertools import operator -import sage.rings.ring import sage.rings.abc import sage.rings.number_field.number_field_base -from sage.misc.fast_methods import Singleton +import sage.rings.ring +from sage.arith.misc import factor +from sage.categories.action import Action from sage.misc.cachefunc import cached_method +from sage.misc.fast_methods import Singleton from sage.misc.lazy_string import lazy_string from sage.misc.misc import increase_recursion_limit -from sage.structure.coerce import parent_is_numerical, parent_is_real_numerical -from sage.structure.sage_object import SageObject -from sage.structure.richcmp import (richcmp, richcmp_method, - rich_to_bool, richcmp_not_equal, - op_EQ, op_NE, op_GT) -from sage.rings.real_arb import RealBallField -from sage.rings.real_mpfr import RR -from sage.rings.real_mpfi import RealIntervalField, RIF, is_RealIntervalFieldElement, RealIntervalField_class +from sage.rings import infinity from sage.rings.cc import CC from sage.rings.cif import CIF -from sage.rings.complex_interval_field import ComplexIntervalField from sage.rings.complex_interval import is_ComplexIntervalFieldElement -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.complex_interval_field import ComplexIntervalField from sage.rings.integer_ring import ZZ +from sage.rings.number_field.number_field import ( + CyclotomicField, + GaussianField, + NumberField, +) +from sage.rings.number_field.number_field_element_quadratic import ( + NumberFieldElement_gaussian, +) +from sage.rings.polynomial.polynomial_element import Polynomial +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ -from sage.rings.number_field.number_field import NumberField, GaussianField, CyclotomicField -from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_gaussian -from sage.arith.misc import factor -from . import infinity -from sage.categories.action import Action - +from sage.rings.real_arb import RealBallField +from sage.rings.real_mpfi import ( + RIF, + RealIntervalField, + RealIntervalField_class, + is_RealIntervalFieldElement, +) +from sage.rings.real_mpfr import RR +from sage.structure.coerce import parent_is_numerical, parent_is_real_numerical from sage.structure.global_options import GlobalOptions +from sage.structure.richcmp import ( + op_EQ, + op_GT, + op_NE, + rich_to_bool, + richcmp, + richcmp_method, + richcmp_not_equal, +) +from sage.structure.sage_object import SageObject class AlgebraicField_common(sage.rings.abc.AlgebraicField_common): @@ -900,8 +916,8 @@ def _factor_multivariate_polynomial(self, f, proof=True): 1 """ - from sage.structure.factorization import Factorization from sage.interfaces.singular import singular + from sage.structure.factorization import Factorization if f.degree() == 0: return Factorization([], f.lc()) @@ -1984,8 +2000,8 @@ def random_element(self, poly_degree=2, *args, **kwds): sage: v # random (0.4694381338921299?, -0.500000000000000? + 0.866025403784439?*I) """ - from sage.rings.integer_ring import ZZ import sage.misc.prandom + from sage.rings.integer_ring import ZZ try: poly_degree = ZZ(poly_degree) except TypeError: @@ -3447,7 +3463,7 @@ def __call__(self, elt): return elt.field_element_value() gen = elt.generator() sp = gen.super_poly(self) - assert (not (sp is None)) + assert (sp is not None) return self._field(elt.field_element_value().polynomial()(sp)) @@ -5323,7 +5339,7 @@ def multiplicative_order(self): sage: QQbar(3/5 + 4/5*I).multiplicative_order() +Infinity """ - if not (1 in CIF(self).norm()): + if 1 not in CIF(self).norm(): return infinity.infinity if self.norm() != 1: return infinity.infinity @@ -5807,7 +5823,7 @@ def multiplicative_order(self): sage: AA(5).sqrt().multiplicative_order() +Infinity """ - if not (1 in RIF(self).abs()): + if 1 not in RIF(self).abs(): return infinity.infinity if self == 1: return 1 @@ -7394,7 +7410,7 @@ def _complex_refine_interval(self, interval, prec): # Give up and fall back on root isolation. return self._complex_isolate_interval(interval, prec) - if not (zero in slope): + if zero not in slope: new_range = center - val / slope interval = interval.intersection(new_range) @@ -8596,7 +8612,6 @@ def exactify(self): sage: sys.setrecursionlimit(old_recursion_limit) """ - import sys with increase_recursion_limit(10): left = self._left right = self._right @@ -8825,5 +8840,6 @@ def get_AA_golden_ratio(): # Support Python's numbers abstract base class import numbers + numbers.Real.register(AlgebraicReal) numbers.Complex.register(AlgebraicNumber) diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index 7dc4e0803c8..a6a0a8ce7f8 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -112,16 +112,15 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ # **************************************************************************** +import sage.interfaces.abc import sage.misc.latex as latex -from . import ring, ideal, quotient_ring_element -from sage.structure.category_object import normalize_names -from sage.structure.richcmp import richcmp_method, richcmp import sage.structure.parent_gens -from sage.misc.cachefunc import cached_method -from sage.categories.rings import Rings from sage.categories.commutative_rings import CommutativeRings - -import sage.interfaces.abc +from sage.categories.rings import Rings +from sage.misc.cachefunc import cached_method +from sage.rings import ideal, quotient_ring_element, ring +from sage.structure.category_object import normalize_names +from sage.structure.richcmp import richcmp, richcmp_method _Rings = Rings() _CommRings = CommutativeRings() @@ -302,7 +301,9 @@ def QuotientRing(R, I, names=None, **kwds): else: names = normalize_names(R.ngens(), names) if kwds.get('implementation') == 'pbori': - from sage.rings.polynomial.polynomial_ring_constructor import BooleanPolynomialRing_constructor as BooleanPolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import ( + BooleanPolynomialRing_constructor as BooleanPolynomialRing, + ) kwds.pop('implementation') return BooleanPolynomialRing(R.ngens(), names=names, **kwds) # workaround to silence warning from #34806 @@ -538,6 +539,7 @@ def construction(self): Finite Field of size 5 """ from sage.categories.pushout import QuotientFunctor + # Is there a better generic way to distinguish between things like Z/pZ as a field and Z/pZ as a ring? from sage.rings.ring import Field try: @@ -1006,7 +1008,9 @@ def ideal(self, *gens, **kwds): """ if len(gens) == 1: gens = gens[0] - from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base + from sage.rings.polynomial.multi_polynomial_ring_base import ( + MPolynomialRing_base, + ) if not (isinstance(self.__R, MPolynomialRing_base) and self.__R._has_singular): # pass through return super().ideal(gens, **kwds) @@ -1019,7 +1023,9 @@ def ideal(self, *gens, **kwds): global MPolynomialIdeal_quotient if MPolynomialIdeal_quotient is None: - from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal_quotient + from sage.rings.polynomial.multi_polynomial_ideal import ( + MPolynomialIdeal_quotient, + ) return MPolynomialIdeal_quotient(self, gens, **kwds) def _element_constructor_(self, x, coerce=True): @@ -1276,7 +1282,7 @@ def _singular_(self, singular=None): try: Q = self.__singular - if not (Q.parent() is singular): + if Q.parent() is not singular: raise ValueError Q._check_valid() return Q diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index f8843a2cee7..e78b11e956c 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -72,9 +72,9 @@ from sage.structure.richcmp cimport rich_to_bool_sgn import sage.rings.rational_field cimport sage.rings.integer as integer -from .integer cimport Integer +from sage.rings.integer cimport Integer -from .integer_ring import ZZ +from sage.rings.integer_ring import ZZ from sage.structure.coerce cimport is_numpy_type diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 104c5463bf5..91e290877dd 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -54,16 +54,17 @@ """ -from .rational import Rational -from .integer import Integer +from sage.rings.integer import Integer +from sage.rings.rational import Rational ZZ = None -from sage.structure.parent_gens import ParentWithGens -from sage.structure.sequence import Sequence import sage.rings.number_field.number_field_base as number_field_base from sage.misc.fast_methods import Singleton from sage.misc.superseded import deprecated_function_alias +from sage.structure.parent_gens import ParentWithGens +from sage.structure.sequence import Sequence + class RationalField(Singleton, number_field_base.NumberField): r""" @@ -317,6 +318,7 @@ def construction(self): (FractionField, Integer Ring) """ from sage.categories.pushout import FractionField + from . import integer_ring return FractionField(), integer_ring.ZZ @@ -446,8 +448,8 @@ def __truediv__(self, I): sage: QQ / ZZ # needs sage.modules Q/Z """ - from sage.rings.ideal import Ideal_generic from sage.groups.additive_abelian.qmodnz import QmodnZ + from sage.rings.ideal import Ideal_generic if I is ZZ: return QmodnZ(1) elif isinstance(I, Ideal_generic) and I.base_ring() is ZZ: @@ -834,15 +836,15 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): - Simon Brandhorst, Juanita Duque, Anna Haensch, Manami Roy, Sandi Rudzinski (10-24-2017) """ + from sage.arith.misc import hilbert_symbol, is_prime + from sage.matrix.constructor import matrix + from sage.modules.free_module import VectorSpace from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.rings.padics.factory import Qp - from sage.modules.free_module import VectorSpace - from sage.matrix.constructor import matrix from sage.sets.primes import Primes - from sage.arith.misc import hilbert_symbol, is_prime # input checks - if not type(S) is list: + if type(S) is not list: raise TypeError("first argument must be a list or integer") # -1 is used for the infinite place infty = -1 @@ -1375,8 +1377,9 @@ def selmer_group_iterator(self, S, m, proof=True): """ KSgens, ords = self.selmer_generators(S=S, m=m, proof=proof, orders=True) one = self.one() - from sage.misc.misc_c import prod from itertools import product + + from sage.misc.misc_c import prod for ev in product(*[range(o) for o in ords]): yield prod((p**e for p,e in zip(KSgens, ev)), one) @@ -1490,8 +1493,8 @@ def quadratic_defect(self, a, p, check=True): sage: QQ.quadratic_defect(5, 5) 1 """ - from sage.rings.infinity import Infinity from sage.arith.misc import legendre_symbol + from sage.rings.infinity import Infinity if a not in self: raise TypeError(str(a) + " must be an element of " + str(self)) if p.parent() == ZZ.ideal_monoid(): @@ -1596,8 +1599,8 @@ def _sympy_(self): sage: QQ._sympy_() # needs sympy Rationals """ - from sympy import Rationals from sage.interfaces.sympy import sympy_init + from sympy import Rationals sympy_init() return Rationals diff --git a/src/sage/rings/real_double_element_gsl.pxd b/src/sage/rings/real_double_element_gsl.pxd index 4ddc886cdf1..8025174d15c 100644 --- a/src/sage/rings/real_double_element_gsl.pxd +++ b/src/sage/rings/real_double_element_gsl.pxd @@ -1,4 +1,4 @@ -from .real_double cimport RealDoubleElement +from sage.rings.real_double cimport RealDoubleElement cdef class RealDoubleElement_gsl(RealDoubleElement): diff --git a/src/sage/rings/real_mpfi.pxd b/src/sage/rings/real_mpfi.pxd index 4201788d198..f107dbdd89a 100644 --- a/src/sage/rings/real_mpfi.pxd +++ b/src/sage/rings/real_mpfi.pxd @@ -5,8 +5,8 @@ from sage.rings.ring cimport Field cimport sage.rings.abc from sage.structure.element cimport RingElement -from .rational cimport Rational -from .real_mpfr cimport RealField_class +from sage.rings.rational cimport Rational +from sage.rings.real_mpfr cimport RealField_class cdef class RealIntervalFieldElement(RingElement) # forward decl diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 461b87db869..f801e232e3d 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -269,11 +269,11 @@ from sage.structure.element cimport have_same_parent from sage.structure.parent cimport Parent from sage.structure.richcmp cimport richcmp -from .convert.mpfi cimport mpfi_set_sage -from .real_mpfr cimport RealField_class, RealNumber, RealField -from .integer cimport Integer -from .integer_ring import ZZ -from .rational_field import QQ +from sage.rings.convert.mpfi cimport mpfi_set_sage +from sage.rings.real_mpfr cimport RealField_class, RealNumber, RealField +from sage.rings.integer cimport Integer +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ cimport sage.rings.abc diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index fb2eb1d718c..8a658e302cf 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -148,12 +148,12 @@ from cypari2.stack cimport new_gen from sage.libs.mpmath.utils cimport mpfr_to_mpfval -from .integer cimport Integer -from .rational cimport Rational +from sage.rings.integer cimport Integer +from sage.rings.rational cimport Rational from sage.categories.map cimport Map -from .real_double cimport RealDoubleElement +from sage.rings.real_double cimport RealDoubleElement import sage.rings.rational_field diff --git a/src/sage/rings/sum_of_squares.pyx b/src/sage/rings/sum_of_squares.pyx index b8f719d4dac..7cc5ae32e34 100644 --- a/src/sage/rings/sum_of_squares.pyx +++ b/src/sage/rings/sum_of_squares.pyx @@ -22,7 +22,7 @@ from libc.math cimport sqrt from cysignals.signals cimport sig_on, sig_off cimport sage.rings.integer as integer -from . import integer +from sage.rings import integer cdef int two_squares_c(uint_fast32_t n, uint_fast32_t res[2]): r""" From 289d658e5b0410963b726a52c9b9d412372cce33 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 11:57:05 +0000 Subject: [PATCH 089/538] Replace relative imports by absolute ones in a few packages --- src/sage/arith/all.py | 109 ++++++++++++++++----- src/sage/arith/power.pyx | 2 +- src/sage/cpython/all.py | 4 +- src/sage/cpython/debug.pyx | 2 +- src/sage/data_structures/all.py | 2 +- src/sage/data_structures/bitset.pxd | 2 +- src/sage/data_structures/bitset.pyx | 2 +- src/sage/misc/all.py | 56 +++++------ src/sage/misc/all__sagemath_environment.py | 2 +- src/sage/misc/all__sagemath_objects.py | 30 +++--- src/sage/misc/all__sagemath_repl.py | 4 +- src/sage/misc/benchmark.py | 2 +- src/sage/misc/copying.py | 2 +- src/sage/misc/cython.py | 2 +- src/sage/misc/func_persist.py | 2 +- src/sage/misc/lazy_import_cache.py | 2 +- src/sage/misc/misc.py | 2 +- src/sage/misc/sagedoc.py | 4 +- 18 files changed, 146 insertions(+), 85 deletions(-) diff --git a/src/sage/arith/all.py b/src/sage/arith/all.py index c93e9f05bc9..3446336de68 100644 --- a/src/sage/arith/all.py +++ b/src/sage/arith/all.py @@ -1,35 +1,96 @@ from sage.misc.lazy_import import lazy_import -from .misc import (algdep, bernoulli, is_prime, is_prime_power, - is_pseudoprime, is_pseudoprime_power, - prime_powers, primes_first_n, eratosthenes, primes, - next_prime_power, next_probable_prime, next_prime, - previous_prime, previous_prime_power, random_prime, - divisors, sigma, gcd, GCD, xlcm, xgcd, xkcd, - inverse_mod, get_gcd, get_inverse_mod, power_mod, - rational_reconstruction, mqrr_rational_reconstruction, - trial_division, factor, prime_divisors, odd_part, prime_to_m_part, - is_square, is_squarefree, euler_phi, carmichael_lambda, crt, CRT, - CRT_list, CRT_basis, CRT_vectors, multinomial, multinomial_coefficients, - binomial, factorial, kronecker_symbol, kronecker, legendre_symbol, - primitive_root, nth_prime, quadratic_residues, moebius, - continuant, number_of_divisors, hilbert_symbol, hilbert_conductor, - hilbert_conductor_inverse, falling_factorial, rising_factorial, - integer_ceil, integer_floor, - two_squares, three_squares, four_squares, sum_of_k_squares, - subfactorial, is_power_of_two, differences, +from sage.arith.misc import ( + algdep, + bernoulli, + is_prime, + is_prime_power, + is_pseudoprime, + is_pseudoprime_power, + prime_powers, + primes_first_n, + eratosthenes, + primes, + next_prime_power, + next_probable_prime, + next_prime, + previous_prime, + previous_prime_power, + random_prime, + divisors, + sigma, + gcd, + GCD, + xlcm, + xgcd, + xkcd, + inverse_mod, + get_gcd, + get_inverse_mod, + power_mod, + rational_reconstruction, + mqrr_rational_reconstruction, + trial_division, + factor, + prime_divisors, + odd_part, + prime_to_m_part, + is_square, + is_squarefree, + euler_phi, + carmichael_lambda, + crt, + CRT, + CRT_list, + CRT_basis, + CRT_vectors, + multinomial, + multinomial_coefficients, + binomial, + factorial, + kronecker_symbol, + kronecker, + legendre_symbol, + primitive_root, + nth_prime, + quadratic_residues, + moebius, + continuant, + number_of_divisors, + hilbert_symbol, + hilbert_conductor, + hilbert_conductor_inverse, + falling_factorial, + rising_factorial, + integer_ceil, + integer_floor, + two_squares, + three_squares, + four_squares, + sum_of_k_squares, + subfactorial, + is_power_of_two, + differences, sort_complex_numbers_for_display, - fundamental_discriminant, squarefree_divisors, - radical, binomial_coefficients, jacobi_symbol, + fundamental_discriminant, + squarefree_divisors, + radical, + binomial_coefficients, + jacobi_symbol, dedekind_sum, - prime_factors, prime_range, valuation) + prime_factors, + prime_range, + valuation, +) -lazy_import('sage.arith.misc', ('Sigma', 'Moebius', 'Euler_Phi'), deprecation=30322) +lazy_import("sage.arith.misc", ("Sigma", "Moebius", "Euler_Phi"), deprecation=30322) + +from sage.arith.functions import lcm -from .functions import lcm LCM = lcm -from .srange import xsrange, srange, ellipsis_iter, ellipsis_range +from sage.arith.srange import xsrange, srange, ellipsis_iter, ellipsis_range + sxrange = xsrange σ = sigma diff --git a/src/sage/arith/power.pyx b/src/sage/arith/power.pyx index acd5f885e85..e9a1f7972eb 100644 --- a/src/sage/arith/power.pyx +++ b/src/sage/arith/power.pyx @@ -17,7 +17,7 @@ square-and-multiply algorithm. from cysignals.signals cimport sig_check -from .long cimport integer_check_long +from sage.arith.long cimport integer_check_long cpdef generic_power(a, n): diff --git a/src/sage/cpython/all.py b/src/sage/cpython/all.py index d35cd6f2e8a..d48ee4c7d45 100644 --- a/src/sage/cpython/all.py +++ b/src/sage/cpython/all.py @@ -1,2 +1,2 @@ -from .debug import getattr_debug, type_debug -from .getattr import raw_getattr +from sage.cpython.debug import getattr_debug, type_debug +from sage.cpython.getattr import raw_getattr diff --git a/src/sage/cpython/debug.pyx b/src/sage/cpython/debug.pyx index cdaca3a4854..0cfc1fc2388 100644 --- a/src/sage/cpython/debug.pyx +++ b/src/sage/cpython/debug.pyx @@ -21,7 +21,7 @@ cdef extern from "Python.h": cdef extern from "sage/cpython/debugimpl.c": void _type_debug(PyTypeObject*) -from .getattr cimport AttributeErrorMessage +from sage.cpython.getattr cimport AttributeErrorMessage # Determine subtype_traverse, subtype_clear, subtype_dealloc functions diff --git a/src/sage/data_structures/all.py b/src/sage/data_structures/all.py index 43c5de52d5a..eac1b4b8931 100644 --- a/src/sage/data_structures/all.py +++ b/src/sage/data_structures/all.py @@ -1,2 +1,2 @@ -from .bitset import Bitset, FrozenBitset +from sage.data_structures.bitset import Bitset, FrozenBitset diff --git a/src/sage/data_structures/bitset.pxd b/src/sage/data_structures/bitset.pxd index 08394ffcf5f..03a2189e5b2 100644 --- a/src/sage/data_structures/bitset.pxd +++ b/src/sage/data_structures/bitset.pxd @@ -7,7 +7,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from .bitset_base cimport bitset_t +from sage.data_structures.bitset_base cimport bitset_t # Python layer over bitset_t cdef class FrozenBitset: diff --git a/src/sage/data_structures/bitset.pyx b/src/sage/data_structures/bitset.pyx index d9906b5edd2..4ef756987fc 100644 --- a/src/sage/data_structures/bitset.pyx +++ b/src/sage/data_structures/bitset.pyx @@ -31,7 +31,7 @@ linear in ``capacity``. # http://www.gnu.org/licenses/ #***************************************************************************** -from .bitset_base cimport * +from sage.data_structures.bitset_base cimport * from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE diff --git a/src/sage/misc/all.py b/src/sage/misc/all.py index e5a6418043a..5876ef9484d 100644 --- a/src/sage/misc/all.py +++ b/src/sage/misc/all.py @@ -1,11 +1,11 @@ -from .lazy_attribute import lazy_attribute, lazy_class_attribute -from .lazy_import import lazy_import +from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute +from sage.misc.lazy_import import lazy_import -from .all__sagemath_objects import * -from .all__sagemath_environment import * -from .all__sagemath_repl import * +from sage.misc.all__sagemath_objects import * +from sage.misc.all__sagemath_environment import * +from sage.misc.all__sagemath_repl import * -from .misc import (BackslashOperator, +from sage.misc.misc import (BackslashOperator, exists, forall, is_iterator, random_sublist, pad_zeros, @@ -15,27 +15,27 @@ lazy_import('sage.misc.misc', 'union', deprecation=32096) -from .banner import version +from sage.misc.banner import version -from .dev_tools import import_statements +from sage.misc.dev_tools import import_statements -from .html import html, pretty_print_default +from sage.misc.html import html, pretty_print_default -from .table import table +from sage.misc.table import table -from .sage_timeit_class import timeit +from sage.misc.sage_timeit_class import timeit -from .edit_module import edit +from sage.misc.edit_module import edit -from .map_threaded import map_threaded +from sage.misc.map_threaded import map_threaded -from .session import load_session, save_session, show_identifiers +from sage.misc.session import load_session, save_session, show_identifiers -from .remote_file import get_remote_file +from sage.misc.remote_file import get_remote_file -from .mrange import xmrange, mrange, xmrange_iter, mrange_iter, cartesian_product_iterator +from sage.misc.mrange import xmrange, mrange, xmrange_iter, mrange_iter, cartesian_product_iterator -from .fpickle import pickle_function, unpickle_function +from sage.misc.fpickle import pickle_function, unpickle_function lazy_import('sage.misc.pager', 'pager') @@ -45,21 +45,21 @@ 'constructions', 'help']) lazy_import('pydoc', 'help', 'python_help') -from .classgraph import class_graph +from sage.misc.classgraph import class_graph -from .reset import reset, restore +from sage.misc.reset import reset, restore -from .mathml import mathml +from sage.misc.mathml import mathml -from .defaults import (set_default_variable_name, +from sage.misc.defaults import (set_default_variable_name, series_precision, set_series_precision) lazy_import("sage.misc.cython", "cython_lambda") lazy_import("sage.misc.cython", "cython_compile", "cython") -from .func_persist import func_persist +from sage.misc.func_persist import func_persist -from .functional import (additive_order, +from sage.misc.functional import (additive_order, base_ring, base_field, basis, @@ -118,15 +118,15 @@ transpose) -from .latex import LatexExpr, latex, view +from sage.misc.latex import LatexExpr, latex, view -from .randstate import seed, set_random_seed, initial_seed, current_randstate +from sage.misc.randstate import seed, set_random_seed, initial_seed, current_randstate -from .prandom import * +from sage.misc.prandom import * -from .timing import walltime, cputime +from sage.misc.timing import walltime, cputime -from .explain_pickle import explain_pickle, unpickle_newobj, unpickle_global, unpickle_build, unpickle_instantiate, unpickle_persistent, unpickle_extension, unpickle_appends +from sage.misc.explain_pickle import explain_pickle, unpickle_newobj, unpickle_global, unpickle_build, unpickle_instantiate, unpickle_persistent, unpickle_extension, unpickle_appends lazy_import('sage.misc.inline_fortran', 'fortran') diff --git a/src/sage/misc/all__sagemath_environment.py b/src/sage/misc/all__sagemath_environment.py index f25faa1289d..9ebcc85870b 100644 --- a/src/sage/misc/all__sagemath_environment.py +++ b/src/sage/misc/all__sagemath_environment.py @@ -1 +1 @@ -from .temporary_file import tmp_dir, tmp_filename +from sage.misc.temporary_file import tmp_dir, tmp_filename diff --git a/src/sage/misc/all__sagemath_objects.py b/src/sage/misc/all__sagemath_objects.py index 43a9c1c06d5..30a76f38fab 100644 --- a/src/sage/misc/all__sagemath_objects.py +++ b/src/sage/misc/all__sagemath_objects.py @@ -2,35 +2,35 @@ import sage.structure.all # to break a cyclic import -from .lazy_attribute import lazy_attribute, lazy_class_attribute -from .lazy_import import lazy_import +from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute +from sage.misc.lazy_import import lazy_import -from .verbose import (set_verbose, set_verbose_files, +from sage.misc.verbose import (set_verbose, set_verbose_files, get_verbose_files, unset_verbose_files, get_verbose) lazy_import('sage.misc.verbose', 'verbose', deprecation=17815) -from .call import attrcall +from sage.misc.call import attrcall -from .misc_c import prod, running_total, balanced_sum +from sage.misc.misc_c import prod, running_total, balanced_sum mul = prod add = sum -from .repr import repr_lincomb +from sage.misc.repr import repr_lincomb -from .flatten import flatten +from sage.misc.flatten import flatten -from .persist import save, load, dumps, loads, db, db_save +from sage.misc.persist import save, load, dumps, loads, db, db_save -from .constant_function import ConstantFunction +from sage.misc.constant_function import ConstantFunction -from .sage_unittest import TestSuite +from sage.misc.sage_unittest import TestSuite -from .decorators import specialize, sage_wraps, infix_operator +from sage.misc.decorators import specialize, sage_wraps, infix_operator -from .unknown import Unknown, UnknownError +from sage.misc.unknown import Unknown, UnknownError -from .cachefunc import CachedFunction, cached_function, cached_method, cached_in_parent_method, disk_cached_function +from sage.misc.cachefunc import CachedFunction, cached_function, cached_method, cached_in_parent_method, disk_cached_function -from .abstract_method import abstract_method +from sage.misc.abstract_method import abstract_method -from .timing import walltime, cputime +from sage.misc.timing import walltime, cputime diff --git a/src/sage/misc/all__sagemath_repl.py b/src/sage/misc/all__sagemath_repl.py index f5891ff1242..c7acba4ab07 100644 --- a/src/sage/misc/all__sagemath_repl.py +++ b/src/sage/misc/all__sagemath_repl.py @@ -1,3 +1,3 @@ -from .sage_eval import sage_eval, sageobj +from sage.misc.sage_eval import sage_eval, sageobj -from .sage_input import sage_input +from sage.misc.sage_input import sage_input diff --git a/src/sage/misc/benchmark.py b/src/sage/misc/benchmark.py index 2a6ee53a0c1..0309571905d 100644 --- a/src/sage/misc/benchmark.py +++ b/src/sage/misc/benchmark.py @@ -1,6 +1,6 @@ "Benchmarks" -from .misc import cputime +from sage.misc.misc import cputime from sage.all import * diff --git a/src/sage/misc/copying.py b/src/sage/misc/copying.py index bcd6c9c3646..cec1a5189cd 100644 --- a/src/sage/misc/copying.py +++ b/src/sage/misc/copying.py @@ -1,7 +1,7 @@ "License" import os -from . import pager +from sage.misc import pager from sage.env import SAGE_ROOT diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 5631cc092e3..95ec447df2e 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -27,7 +27,7 @@ from sage.env import (SAGE_LOCAL, cython_aliases, sage_include_directories) -from .temporary_file import spyx_tmp, tmp_filename +from sage.misc.temporary_file import spyx_tmp, tmp_filename from sage.repl.user_globals import get_globals from sage.misc.sage_ostools import restore_cwd, redirection from sage.cpython.string import str_to_bytes diff --git a/src/sage/misc/func_persist.py b/src/sage/misc/func_persist.py index 12dd35d1f88..8638ec14694 100644 --- a/src/sage/misc/func_persist.py +++ b/src/sage/misc/func_persist.py @@ -43,7 +43,7 @@ def bern(n): import inspect import os -from . import persist +from sage.misc import persist class func_persist: diff --git a/src/sage/misc/lazy_import_cache.py b/src/sage/misc/lazy_import_cache.py index e34c0ca6942..191a2058e2b 100644 --- a/src/sage/misc/lazy_import_cache.py +++ b/src/sage/misc/lazy_import_cache.py @@ -6,7 +6,7 @@ import os import hashlib -from ..env import SAGE_LIB, DOT_SAGE +from sage.env import SAGE_LIB, DOT_SAGE def get_cache_file(): diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index 936f279a690..4f60a11b780 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -45,7 +45,7 @@ import sys import warnings -from .lazy_string import lazy_string +from sage.misc.lazy_string import lazy_string from sage.env import DOT_SAGE, HOSTNAME from sage.misc.lazy_import import lazy_import diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index fb11088dac9..2632d0c4359 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -45,8 +45,8 @@ import sys import pydoc from sage.misc.temporary_file import tmp_dir -from .viewer import browser -from . import sageinspect +from sage.misc.viewer import browser +from sage.misc import sageinspect import sage.version from sage.env import SAGE_DOC, SAGE_SRC From 10dfc9955a73d75cfebca9674d05459668ee6670 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 12:22:26 +0000 Subject: [PATCH 090/538] fix import --- src/sage/rings/all.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index a5d85204866..2c2f6a0523e 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -165,4 +165,4 @@ from sage.rings.asymptotic.all import * # Register classes in numbers abc -from sage.rings. import numbers_abc +from sage.rings import numbers_abc From 1c20f088711648a6673a04987ab2fb9ab303db6f Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 17:48:09 +0000 Subject: [PATCH 091/538] add more absolute paths --- src/sage/rings/convert/mpfi.pyx | 16 ++++++++-------- src/sage/rings/finite_rings/element_givaro.pyx | 2 +- src/sage/rings/finite_rings/element_ntl_gf2e.pyx | 4 ++-- .../rings/finite_rings/element_pari_ffelt.pyx | 4 ++-- .../finite_rings/hom_finite_field_givaro.pxd | 4 ++-- .../finite_rings/hom_finite_field_givaro.pyx | 12 ++++++------ .../finite_rings/hom_prime_finite_field.pxd | 2 +- .../finite_rings/hom_prime_finite_field.pyx | 6 +++--- src/sage/rings/finite_rings/integer_mod_ring.py | 2 +- .../number_field_element_quadratic.pxd | 2 +- src/sage/rings/polynomial/multi_polynomial.pxd | 2 +- src/sage/rings/polynomial/polynomial_element.pxd | 4 ++-- src/sage/rings/polynomial/polynomial_element.pyx | 4 ++-- .../polynomial/polynomial_real_mpfr_dense.pyx | 2 +- 14 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/sage/rings/convert/mpfi.pyx b/src/sage/rings/convert/mpfi.pyx index 3ca01ac276f..a03e6a9828f 100644 --- a/src/sage/rings/convert/mpfi.pyx +++ b/src/sage/rings/convert/mpfi.pyx @@ -23,14 +23,14 @@ from sage.cpython.string cimport bytes_to_str from sage.structure.element cimport Element import sage.rings.abc -from ..integer cimport Integer -from ..rational cimport Rational -from ..real_mpfi cimport RealIntervalFieldElement, RealIntervalField_class -from ..real_mpfr cimport RealNumber -from ..real_double cimport RealDoubleElement -from ..complex_mpfr cimport ComplexNumber -from ..complex_interval cimport ComplexIntervalFieldElement -from ..complex_double cimport ComplexDoubleElement +from sage.rings.integer cimport Integer +from sage.rings.rational cimport Rational +from sage.rings.real_mpfi cimport RealIntervalFieldElement, RealIntervalField_class +from sage.rings.real_mpfr cimport RealNumber +from sage.rings.real_double cimport RealDoubleElement +from sage.rings.complex_mpfr cimport ComplexNumber +from sage.rings.complex_interval cimport ComplexIntervalFieldElement +from sage.rings.complex_double cimport ComplexDoubleElement from cypari2.gen cimport Gen diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index ead2551ded5..fbf9f1b6c3b 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -57,7 +57,7 @@ from cysignals.signals cimport sig_on, sig_off from cypari2.paridecl cimport * from sage.misc.randstate cimport current_randstate -from .element_pari_ffelt cimport FiniteFieldElement_pari_ffelt +from sage.rings.finite_rings.element_pari_ffelt cimport FiniteFieldElement_pari_ffelt from sage.structure.richcmp cimport richcmp import sage.arith.all diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index 7c5ab521b7a..1c1ffb73f9a 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -44,8 +44,8 @@ from sage.libs.pari.all import pari from cypari2.gen cimport Gen from cypari2.stack cimport clear_stack -from .element_pari_ffelt import FiniteFieldElement_pari_ffelt -from .finite_field_ntl_gf2e import FiniteField_ntl_gf2e +from sage.rings.finite_rings.element_pari_ffelt import FiniteFieldElement_pari_ffelt +from sage.rings.finite_rings.finite_field_ntl_gf2e import FiniteField_ntl_gf2e from sage.interfaces.abc import GapElement diff --git a/src/sage/rings/finite_rings/element_pari_ffelt.pyx b/src/sage/rings/finite_rings/element_pari_ffelt.pyx index 2d29f424e3b..42301d8ee4f 100644 --- a/src/sage/rings/finite_rings/element_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/element_pari_ffelt.pyx @@ -24,8 +24,8 @@ from sage.libs.pari.convert_gmp cimport _new_GEN_from_mpz_t from cypari2.stack cimport new_gen, new_gen_noclear, clear_stack from cypari2.gen cimport Gen as pari_gen, objtogen -from .element_base cimport FinitePolyExtElement -from .integer_mod import IntegerMod_abstract +from sage.rings.finite_rings.element_base cimport FinitePolyExtElement +from sage.rings.finite_rings.integer_mod import IntegerMod_abstract import sage.rings.integer from sage.rings.integer cimport Integer diff --git a/src/sage/rings/finite_rings/hom_finite_field_givaro.pxd b/src/sage/rings/finite_rings/hom_finite_field_givaro.pxd index eec5a6d299d..dc401d526c0 100644 --- a/src/sage/rings/finite_rings/hom_finite_field_givaro.pxd +++ b/src/sage/rings/finite_rings/hom_finite_field_givaro.pxd @@ -1,8 +1,8 @@ -from .hom_finite_field cimport (SectionFiniteFieldHomomorphism_generic, +from sage.rings.finite_rings.hom_finite_field cimport (SectionFiniteFieldHomomorphism_generic, FiniteFieldHomomorphism_generic, FrobeniusEndomorphism_finite_field) from sage.structure.element cimport Element -from .element_givaro cimport Cache_givaro +from sage.rings.finite_rings.element_givaro cimport Cache_givaro cdef class SectionFiniteFieldHomomorphism_givaro(SectionFiniteFieldHomomorphism_generic): diff --git a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx index aae6c84ab25..de8e6e2180a 100644 --- a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx @@ -33,21 +33,21 @@ AUTHOR: from sage.rings.finite_rings.finite_field_constructor import FiniteField -from .hom_finite_field cimport SectionFiniteFieldHomomorphism_generic -from .hom_finite_field cimport FiniteFieldHomomorphism_generic -from .hom_finite_field cimport FrobeniusEndomorphism_finite_field +from sage.rings.finite_rings.hom_finite_field cimport SectionFiniteFieldHomomorphism_generic +from sage.rings.finite_rings.hom_finite_field cimport FiniteFieldHomomorphism_generic +from sage.rings.finite_rings.hom_finite_field cimport FrobeniusEndomorphism_finite_field -from .hom_prime_finite_field cimport FiniteFieldHomomorphism_prime +from sage.rings.finite_rings.hom_prime_finite_field cimport FiniteFieldHomomorphism_prime from sage.categories.homset import Hom from sage.structure.element cimport Element from sage.rings.finite_rings.finite_field_givaro import FiniteField_givaro -from .element_givaro cimport FiniteField_givaroElement +from sage.rings.finite_rings.element_givaro cimport FiniteField_givaroElement #from element_givaro cimport make_FiniteField_givaroElement from sage.structure.parent cimport Parent -from .element_givaro cimport Cache_givaro +from sage.rings.finite_rings.element_givaro cimport Cache_givaro cdef class SectionFiniteFieldHomomorphism_givaro(SectionFiniteFieldHomomorphism_generic): diff --git a/src/sage/rings/finite_rings/hom_prime_finite_field.pxd b/src/sage/rings/finite_rings/hom_prime_finite_field.pxd index c0da361fb42..b146b0c9169 100644 --- a/src/sage/rings/finite_rings/hom_prime_finite_field.pxd +++ b/src/sage/rings/finite_rings/hom_prime_finite_field.pxd @@ -1,4 +1,4 @@ -from .hom_finite_field cimport (SectionFiniteFieldHomomorphism_generic, +from sage.rings.finite_rings.hom_finite_field cimport (SectionFiniteFieldHomomorphism_generic, FiniteFieldHomomorphism_generic, FrobeniusEndomorphism_finite_field) diff --git a/src/sage/rings/finite_rings/hom_prime_finite_field.pyx b/src/sage/rings/finite_rings/hom_prime_finite_field.pyx index e141120d918..ad65ce8bc2c 100644 --- a/src/sage/rings/finite_rings/hom_prime_finite_field.pyx +++ b/src/sage/rings/finite_rings/hom_prime_finite_field.pyx @@ -27,9 +27,9 @@ AUTHOR: from sage.categories.homset import Hom from sage.structure.element cimport Element -from .hom_finite_field cimport SectionFiniteFieldHomomorphism_generic -from .hom_finite_field cimport FiniteFieldHomomorphism_generic -from .hom_finite_field cimport FrobeniusEndomorphism_finite_field +from sage.rings.finite_rings.hom_finite_field cimport SectionFiniteFieldHomomorphism_generic +from sage.rings.finite_rings.hom_finite_field cimport FiniteFieldHomomorphism_generic +from sage.rings.finite_rings.hom_finite_field cimport FrobeniusEndomorphism_finite_field from sage.rings.finite_rings.finite_field_base import FiniteField diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index 92b99d050ba..31a75f07271 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -67,7 +67,7 @@ from sage.arith.misc import CRT_basis import sage.rings.ring as ring import sage.rings.abc -from . import integer_mod +from sage.rings.finite_rings. import integer_mod import sage.rings.integer as integer import sage.rings.integer_ring as integer_ring import sage.rings.quotient_ring as quotient_ring diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pxd b/src/sage/rings/number_field/number_field_element_quadratic.pxd index 7a4f063de73..341c89c7aa6 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pxd +++ b/src/sage/rings/number_field/number_field_element_quadratic.pxd @@ -2,7 +2,7 @@ from sage.libs.gmp.types cimport mpz_t from sage.libs.arb.types cimport arb_t from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational -from .number_field_element cimport NumberFieldElement, NumberFieldElement_absolute +from sage.rings.number_field.number_field_element cimport NumberFieldElement, NumberFieldElement_absolute cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): diff --git a/src/sage/rings/polynomial/multi_polynomial.pxd b/src/sage/rings/polynomial/multi_polynomial.pxd index 5dc75e6bd3f..9c96ce7a505 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pxd +++ b/src/sage/rings/polynomial/multi_polynomial.pxd @@ -1,4 +1,4 @@ -from .commutative_polynomial cimport CommutativePolynomial +from sage.rings.polynomial.commutative_polynomial cimport CommutativePolynomial cdef class MPolynomial(CommutativePolynomial): diff --git a/src/sage/rings/polynomial/polynomial_element.pxd b/src/sage/rings/polynomial/polynomial_element.pxd index 5dcbf4597d0..e89ba5360d0 100644 --- a/src/sage/rings/polynomial/polynomial_element.pxd +++ b/src/sage/rings/polynomial/polynomial_element.pxd @@ -2,8 +2,8 @@ from sage.structure.element import Element from sage.structure.element cimport Element, CommutativeAlgebraElement, ModuleElement from sage.structure.parent cimport Parent from sage.rings.integer cimport Integer -from .commutative_polynomial cimport CommutativePolynomial -from .polynomial_compiled cimport CompiledPolynomialFunction +from sage.rings.polynomial.commutative_polynomial cimport CommutativePolynomial +from sage.rings.polynomial.polynomial_compiled cimport CompiledPolynomialFunction cdef class Polynomial(CommutativePolynomial): diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index a5b7f937cfe..47482703f30 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -118,7 +118,7 @@ from sage.misc.derivative import multi_derivative from sage.arith.misc import sort_complex_numbers_for_display, power_mod, is_prime from sage.arith.functions import lcm -from . import polynomial_fateman +from sage.rings.polynomial import polynomial_fateman from sage.rings.ideal import is_Ideal from sage.rings.polynomial.polynomial_ring import is_PolynomialRing @@ -182,7 +182,7 @@ cpdef is_Polynomial(f): return isinstance(f, Polynomial) -from .polynomial_compiled cimport CompiledPolynomialFunction +from sage.rings.polynomial.polynomial_compiled cimport CompiledPolynomialFunction from sage.rings.polynomial.polydict cimport ETuple diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index da5462cddd4..cf3326246dd 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -30,7 +30,7 @@ from cpython.long cimport PyLong_AsLong from cpython.float cimport PyFloat_AS_DOUBLE from sage.structure.parent cimport Parent -from .polynomial_element cimport Polynomial, _dict_to_list +from sage.rings.polynomial.polynomial_element cimport Polynomial, _dict_to_list from sage.rings.real_mpfr cimport RealField_class, RealNumber from sage.rings.integer cimport Integer, smallInteger from sage.rings.rational cimport Rational From 6260d1473f68395df16e02be7705d1d3cf05f365 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 17:51:03 +0000 Subject: [PATCH 092/538] Replace relative imports by absolute ones in modules --- src/sage/modules/all.py | 33 +++++---- src/sage/modules/complex_double_vector.py | 2 +- src/sage/modules/free_module.py | 70 ++++++++++++------- src/sage/modules/free_module_morphism.py | 6 +- src/sage/modules/free_quadratic_module.py | 4 +- src/sage/modules/quotient_module.py | 9 +-- src/sage/modules/real_double_vector.py | 2 +- src/sage/modules/submodule.py | 10 +-- .../modules/vector_callable_symbolic_dense.py | 2 +- .../modules/vector_complex_double_dense.pxd | 2 +- src/sage/modules/vector_double_dense.pxd | 2 +- src/sage/modules/vector_integer_dense.pxd | 2 +- src/sage/modules/vector_mod2_dense.pxd | 2 +- src/sage/modules/vector_modn_dense.pxd | 2 +- src/sage/modules/vector_numpy_dense.pxd | 2 +- src/sage/modules/vector_numpy_dense.pyx | 2 +- .../modules/vector_numpy_integer_dense.pxd | 2 +- src/sage/modules/vector_rational_dense.pxd | 2 +- src/sage/modules/vector_real_double_dense.pxd | 2 +- src/sage/modules/vector_space_morphism.py | 13 ++-- src/sage/modules/vector_symbolic_dense.py | 2 +- src/sage/modules/vector_symbolic_sparse.py | 2 +- 22 files changed, 103 insertions(+), 72 deletions(-) diff --git a/src/sage/modules/all.py b/src/sage/modules/all.py index 87621e61b29..660f1ef3807 100644 --- a/src/sage/modules/all.py +++ b/src/sage/modules/all.py @@ -1,4 +1,4 @@ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -11,23 +11,30 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** -from .free_module import FreeModule, VectorSpace, span +from sage.modules.free_module import FreeModule, VectorSpace, span -from .free_quadratic_module import (FreeQuadraticModule, QuadraticSpace, - InnerProductSpace) +from sage.modules.free_quadratic_module import ( + FreeQuadraticModule, + QuadraticSpace, + InnerProductSpace, +) -from .free_module_element import (vector, free_module_element, zero_vector, - random_vector) +from sage.modules.free_module_element import ( + vector, + free_module_element, + zero_vector, + random_vector, +) -from .vector_space_morphism import linear_transformation +from sage.modules.vector_space_morphism import linear_transformation -from .with_basis.all import * +from sage.modules.with_basis.all import * from sage.misc.lazy_import import lazy_import -lazy_import('sage.modules.filtered_vector_space', 'FilteredVectorSpace') -lazy_import('sage.modules.multi_filtered_vector_space', 'MultiFilteredVectorSpace') -lazy_import('sage.modules.free_quadratic_module_integer_symmetric', 'IntegralLattice') -lazy_import('sage.modules.torsion_quadratic_module', 'TorsionQuadraticForm') +lazy_import("sage.modules.filtered_vector_space", "FilteredVectorSpace") +lazy_import("sage.modules.multi_filtered_vector_space", "MultiFilteredVectorSpace") +lazy_import("sage.modules.free_quadratic_module_integer_symmetric", "IntegralLattice") +lazy_import("sage.modules.torsion_quadratic_module", "TorsionQuadraticForm") diff --git a/src/sage/modules/complex_double_vector.py b/src/sage/modules/complex_double_vector.py index 88ad6bb6d67..728d862e8fc 100644 --- a/src/sage/modules/complex_double_vector.py +++ b/src/sage/modules/complex_double_vector.py @@ -19,6 +19,6 @@ # http://www.gnu.org/licenses/ ############################################################################### -from .vector_complex_double_dense import Vector_complex_double_dense +from sage.modules.vector_complex_double_dense import Vector_complex_double_dense ComplexDoubleVectorSpaceElement = Vector_complex_double_dense diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 8f584a211ef..cadae277429 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -177,33 +177,41 @@ ########################################################################### import itertools +from warnings import warn -from . import free_module_element import sage.matrix.matrix_space import sage.misc.latex as latex - -from sage.modules.module import Module -import sage.rings.ring as ring import sage.rings.abc -import sage.rings.integer_ring -import sage.rings.rational_field import sage.rings.infinity import sage.rings.integer -from sage.categories.principal_ideal_domains import PrincipalIdealDomains -from sage.categories.integral_domains import IntegralDomains +import sage.rings.integer_ring +import sage.rings.rational_field +import sage.rings.ring as ring from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +from sage.categories.integral_domains import IntegralDomains +from sage.categories.principal_ideal_domains import PrincipalIdealDomains +from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import LazyImport from sage.misc.randstate import current_randstate +from sage.modules import free_module_element +from sage.modules.module import Module from sage.rings.finite_rings.finite_field_base import FiniteField from sage.structure.factory import UniqueFactory +from sage.structure.richcmp import ( + op_EQ, + op_GE, + op_GT, + op_LE, + op_LT, + op_NE, + revop, + rich_to_bool, + richcmp, + richcmp_method, + richcmp_not_equal, +) from sage.structure.sequence import Sequence -from sage.structure.richcmp import (richcmp_method, rich_to_bool, richcmp, - richcmp_not_equal, revop, - op_LT,op_LE,op_EQ,op_NE,op_GT,op_GE) -from sage.misc.cachefunc import cached_method -from sage.misc.lazy_import import LazyImport - -from warnings import warn ############################################################################### # @@ -226,7 +234,7 @@ def create_key(self, base_ring, rank, sparse=False, inner_product_matrix=None): """ rank = int(sage.rings.integer.Integer(rank)) - if not (inner_product_matrix is None): + if inner_product_matrix is not None: inner_product_matrix = sage.matrix.matrix_space.MatrixSpace(base_ring, rank)(inner_product_matrix) inner_product_matrix.set_immutable() @@ -1821,7 +1829,9 @@ def free_resolution(self, *args, **kwds): [ z x*z] 0 <-- C_0 <-------------- C_1 <-- 0 """ - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + from sage.rings.polynomial.multi_polynomial_libsingular import ( + MPolynomialRing_libsingular, + ) if isinstance(self.base_ring(), MPolynomialRing_libsingular): from sage.homology.free_resolution import FiniteFreeResolution_singular return FiniteFreeResolution_singular(self, *args, **kwds) @@ -1854,13 +1864,19 @@ def graded_free_resolution(self, *args, **kwds): sage: N.graded_free_resolution(degrees=[2, 1, 3], shifts=[2, 3]) # needs sage.libs.singular S(-2)⊕S(-3) <-- S(-6)⊕S(-8) <-- 0 """ - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + from sage.rings.polynomial.multi_polynomial_libsingular import ( + MPolynomialRing_libsingular, + ) if isinstance(self.base_ring(), MPolynomialRing_libsingular): - from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + from sage.homology.graded_resolution import ( + GradedFiniteFreeResolution_singular, + ) return GradedFiniteFreeResolution_singular(self, *args, **kwds) if isinstance(self, FreeModule_generic): - from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + from sage.homology.graded_resolution import ( + GradedFiniteFreeResolution_free_module, + ) return GradedFiniteFreeResolution_free_module(self, *args, **kwds) raise NotImplementedError("the module must be a free module or " @@ -4084,7 +4100,9 @@ def span_of_basis(self, basis, base_ring=None, check=True, already_echelonized=F if base_ring is None or base_ring == self.base_ring(): try: if self.is_dense(): - from .free_module_integer import FreeModule_submodule_with_basis_integer + from .free_module_integer import ( + FreeModule_submodule_with_basis_integer, + ) return FreeModule_submodule_with_basis_integer(self.ambient_module(), basis=basis, check=check, already_echelonized=already_echelonized, @@ -5370,8 +5388,8 @@ def _coerce_map_from_(self, M): sage: V = QQ^2 sage: V.coerce_map_from(M) """ - from sage.modules.submodule import Submodule_free_ambient from sage.modules.quotient_module import FreeModule_ambient_field_quotient + from sage.modules.submodule import Submodule_free_ambient if isinstance(M, FreeModule_ambient_field_quotient): # No forgetful map. @@ -5989,8 +6007,8 @@ def _sympy_(self): sage: (1, 2, 3) in sZZ3 # needs sympy True """ - from sympy import ProductSet from sage.interfaces.sympy import sympy_init + from sympy import ProductSet sympy_init() return ProductSet(*([self.coordinate_ring()] * self.rank())) @@ -8194,7 +8212,7 @@ def element_class(R, is_sparse): else: return Vector_mod2_dense try: - from .vector_modn_dense import Vector_modn_dense, MAX_MODULUS + from .vector_modn_dense import MAX_MODULUS, Vector_modn_dense except ImportError: pass else: @@ -8210,7 +8228,9 @@ def element_class(R, is_sparse): return Vector_real_double_dense elif isinstance(R, sage.rings.abc.ComplexDoubleField) and not is_sparse: try: - from sage.modules.vector_complex_double_dense import Vector_complex_double_dense + from sage.modules.vector_complex_double_dense import ( + Vector_complex_double_dense, + ) except ImportError: pass else: diff --git a/src/sage/modules/free_module_morphism.py b/src/sage/modules/free_module_morphism.py index cdc933f23d0..6cf1add1f75 100644 --- a/src/sage/modules/free_module_morphism.py +++ b/src/sage/modules/free_module_morphism.py @@ -41,12 +41,10 @@ # be coercible into vector space of appropriate dimension. import sage.modules.free_module as free_module -from . import matrix_morphism from sage.categories.morphism import Morphism +from sage.modules import free_module_homspace, matrix_morphism +from sage.structure.richcmp import rich_to_bool, richcmp from sage.structure.sequence import Sequence -from sage.structure.richcmp import richcmp, rich_to_bool - -from . import free_module_homspace def is_FreeModuleMorphism(x): diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index ff112b9a5c2..df0f90a4fb6 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -71,7 +71,7 @@ import sage.misc.latex as latex import sage.rings.ring as ring from sage.categories.principal_ideal_domains import PrincipalIdealDomains -from . import free_module +from sage.modules import free_module # ############################################################################# # @@ -154,7 +154,7 @@ def FreeQuadraticModule(base_ring, rank, inner_product_matrix, if key in _cache: M = _cache[key]() - if not (M is None): + if M is not None: return M if not base_ring.is_commutative(): diff --git a/src/sage/modules/quotient_module.py b/src/sage/modules/quotient_module.py index c50c1d044fc..09c8b313c91 100644 --- a/src/sage/modules/quotient_module.py +++ b/src/sage/modules/quotient_module.py @@ -19,10 +19,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from .free_module import (Module_free_ambient, - FreeModule_ambient, - FreeModule_ambient_field) - +from sage.modules.free_module import ( + FreeModule_ambient, + FreeModule_ambient_field, + Module_free_ambient, +) ############################################################################### # diff --git a/src/sage/modules/real_double_vector.py b/src/sage/modules/real_double_vector.py index 1ceb320078e..5430e175f11 100644 --- a/src/sage/modules/real_double_vector.py +++ b/src/sage/modules/real_double_vector.py @@ -16,6 +16,6 @@ # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ ############################################################################### -from .vector_real_double_dense import Vector_real_double_dense +from sage.modules.vector_real_double_dense import Vector_real_double_dense RealDoubleVectorSpaceElement = Vector_real_double_dense diff --git a/src/sage/modules/submodule.py b/src/sage/modules/submodule.py index 3ab5a195f49..8d00d4f4553 100644 --- a/src/sage/modules/submodule.py +++ b/src/sage/modules/submodule.py @@ -34,10 +34,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.modules.free_module import (basis_seq, - Module_free_ambient, - FreeModule_ambient_domain) -from .quotient_module import QuotientModule_free_ambient +from sage.modules.free_module import ( + FreeModule_ambient_domain, + Module_free_ambient, + basis_seq, +) +from sage.modules.quotient_module import QuotientModule_free_ambient class Submodule_free_ambient(Module_free_ambient): diff --git a/src/sage/modules/vector_callable_symbolic_dense.py b/src/sage/modules/vector_callable_symbolic_dense.py index 1929eabcf46..70b05d98b66 100644 --- a/src/sage/modules/vector_callable_symbolic_dense.py +++ b/src/sage/modules/vector_callable_symbolic_dense.py @@ -49,7 +49,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from . import free_module_element +from sage.modules import free_module_element from sage.symbolic.ring import SR diff --git a/src/sage/modules/vector_complex_double_dense.pxd b/src/sage/modules/vector_complex_double_dense.pxd index f26526a1669..1681bad8c34 100644 --- a/src/sage/modules/vector_complex_double_dense.pxd +++ b/src/sage/modules/vector_complex_double_dense.pxd @@ -1,4 +1,4 @@ -from .vector_double_dense cimport Vector_double_dense +from sage.modules .vector_double_dense cimport Vector_double_dense cdef class Vector_complex_double_dense(Vector_double_dense): pass diff --git a/src/sage/modules/vector_double_dense.pxd b/src/sage/modules/vector_double_dense.pxd index f29b4597d15..c378db6c1d6 100644 --- a/src/sage/modules/vector_double_dense.pxd +++ b/src/sage/modules/vector_double_dense.pxd @@ -1,4 +1,4 @@ -from .vector_numpy_dense cimport Vector_numpy_dense +from sage.modules .vector_numpy_dense cimport Vector_numpy_dense cdef class Vector_double_dense(Vector_numpy_dense): pass diff --git a/src/sage/modules/vector_integer_dense.pxd b/src/sage/modules/vector_integer_dense.pxd index 6a221546b34..ebd69249b70 100644 --- a/src/sage/modules/vector_integer_dense.pxd +++ b/src/sage/modules/vector_integer_dense.pxd @@ -1,4 +1,4 @@ -from .free_module_element cimport FreeModuleElement +from sage.modules .free_module_element cimport FreeModuleElement from sage.libs.gmp.types cimport mpz_t from sage.structure.parent cimport Parent diff --git a/src/sage/modules/vector_mod2_dense.pxd b/src/sage/modules/vector_mod2_dense.pxd index a5542fe1345..06dc10fc841 100644 --- a/src/sage/modules/vector_mod2_dense.pxd +++ b/src/sage/modules/vector_mod2_dense.pxd @@ -1,4 +1,4 @@ -from .free_module_element cimport FreeModuleElement +from sage.modules .free_module_element cimport FreeModuleElement from sage.libs.m4ri cimport mzd_t diff --git a/src/sage/modules/vector_modn_dense.pxd b/src/sage/modules/vector_modn_dense.pxd index 4e0aff593fe..b3a7df6aac7 100644 --- a/src/sage/modules/vector_modn_dense.pxd +++ b/src/sage/modules/vector_modn_dense.pxd @@ -1,4 +1,4 @@ -from .free_module_element cimport FreeModuleElement +from sage.modules .free_module_element cimport FreeModuleElement from sage.ext.mod_int cimport mod_int cdef class Vector_modn_dense(FreeModuleElement): diff --git a/src/sage/modules/vector_numpy_dense.pxd b/src/sage/modules/vector_numpy_dense.pxd index b019bc8ebac..ec1bea61727 100644 --- a/src/sage/modules/vector_numpy_dense.pxd +++ b/src/sage/modules/vector_numpy_dense.pxd @@ -1,4 +1,4 @@ -from .free_module_element cimport FreeModuleElement +from sage.modules .free_module_element cimport FreeModuleElement cimport numpy cdef class Vector_numpy_dense(FreeModuleElement): diff --git a/src/sage/modules/vector_numpy_dense.pyx b/src/sage/modules/vector_numpy_dense.pyx index f0e2224b96d..8e0650aa90f 100644 --- a/src/sage/modules/vector_numpy_dense.pyx +++ b/src/sage/modules/vector_numpy_dense.pyx @@ -29,7 +29,7 @@ AUTHORS: cimport numpy import numpy -from .free_module_element import FreeModuleElement +from sage.modules .free_module_element import FreeModuleElement # This is for the NumPy C API (the PyArray... functions) to work numpy.import_array() diff --git a/src/sage/modules/vector_numpy_integer_dense.pxd b/src/sage/modules/vector_numpy_integer_dense.pxd index e39b90bbcb9..e2e3dbf8359 100644 --- a/src/sage/modules/vector_numpy_integer_dense.pxd +++ b/src/sage/modules/vector_numpy_integer_dense.pxd @@ -1,4 +1,4 @@ -from .vector_numpy_dense cimport Vector_numpy_dense +from sage.modules .vector_numpy_dense cimport Vector_numpy_dense cdef class Vector_numpy_integer_dense(Vector_numpy_dense): diff --git a/src/sage/modules/vector_rational_dense.pxd b/src/sage/modules/vector_rational_dense.pxd index 34db6f6252b..b70048c8705 100644 --- a/src/sage/modules/vector_rational_dense.pxd +++ b/src/sage/modules/vector_rational_dense.pxd @@ -1,4 +1,4 @@ -from .free_module_element cimport FreeModuleElement +from sage.modules .free_module_element cimport FreeModuleElement from sage.libs.gmp.types cimport mpq_t from sage.structure.parent cimport Parent diff --git a/src/sage/modules/vector_real_double_dense.pxd b/src/sage/modules/vector_real_double_dense.pxd index 6f75ec0c4dd..e5d4ad284b5 100644 --- a/src/sage/modules/vector_real_double_dense.pxd +++ b/src/sage/modules/vector_real_double_dense.pxd @@ -1,4 +1,4 @@ -from .vector_double_dense cimport Vector_double_dense +from sage.modules .vector_double_dense cimport Vector_double_dense cdef class Vector_real_double_dense(Vector_double_dense): pass diff --git a/src/sage/modules/vector_space_morphism.py b/src/sage/modules/vector_space_morphism.py index 2685462a74e..97c99d8da5b 100644 --- a/src/sage/modules/vector_space_morphism.py +++ b/src/sage/modules/vector_space_morphism.py @@ -329,11 +329,12 @@ #################################################################################### -import sage.modules.matrix_morphism as matrix_morphism import sage.modules.free_module_morphism as free_module_morphism -from . import vector_space_homspace +import sage.modules.matrix_morphism as matrix_morphism +from sage.modules import vector_space_homspace from sage.structure.element import is_Matrix + def linear_transformation(arg0, arg1=None, arg2=None, side='left'): r""" Create a linear transformation from a variety of possible inputs. @@ -692,12 +693,14 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): ArithmeticError: some image of the function is not in the codomain, because element [1, 0] is not in free module """ + from sage.categories.homset import Hom from sage.matrix.constructor import matrix - from sage.modules.module import is_VectorSpace from sage.modules.free_module import VectorSpace - from sage.categories.homset import Hom + from sage.modules.module import is_VectorSpace try: - from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense + from sage.modules.vector_callable_symbolic_dense import ( + Vector_callable_symbolic_dense, + ) except ImportError: Vector_callable_symbolic_dense = () diff --git a/src/sage/modules/vector_symbolic_dense.py b/src/sage/modules/vector_symbolic_dense.py index ce134c0462e..46ea21be585 100644 --- a/src/sage/modules/vector_symbolic_dense.py +++ b/src/sage/modules/vector_symbolic_dense.py @@ -54,7 +54,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from . import free_module_element +from sage.modules import free_module_element from sage.symbolic.expression import Expression diff --git a/src/sage/modules/vector_symbolic_sparse.py b/src/sage/modules/vector_symbolic_sparse.py index 73cb41ae611..ff53995021c 100644 --- a/src/sage/modules/vector_symbolic_sparse.py +++ b/src/sage/modules/vector_symbolic_sparse.py @@ -56,7 +56,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from . import free_module_element +from sage.modules import free_module_element from sage.symbolic.expression import Expression From 5251c2fa964b0e510d2043fee805d9c9c95c2781 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Mon, 30 Oct 2023 15:56:20 -0700 Subject: [PATCH 093/538] sage-env: identify the version of command-line tools (OS X) --- src/bin/sage-env | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bin/sage-env b/src/bin/sage-env index 5c1b4b87ac7..9cdd5db453f 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -277,6 +277,15 @@ export UNAME=`uname | sed 's/CYGWIN.*/CYGWIN/' ` # Mac OS X-specific setup if [ "$UNAME" = "Darwin" ]; then export MACOSX_VERSION=`uname -r | awk -F. '{print $1}'` + # Try to identify command-line tools version. + # See https://apple.stackexchange.com/q/180957/351985. + XCLT_VERSION=`pkgutil --pkg-info=com.apple.pkg.CLTools_Executables | awk '/version: / { print $NF }' | cut -d. -f-1` + # If this didn't produce an integer, set to 0. + case $XCLT_VERSION in + ''|*[!0-9]*) export XCLT_VERSION=0 ;; # bad + *) : ;; # good + esac + export XCLT_VERSION # Work around problems on recent OS X crashing with an error message # "... may have been in progress in another thread when fork() was called" # when objective-C functions are called after fork(). See Issue #25921. From e7e6736037c40e7b3b1f450d037ffd09a49a6ed5 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Tue, 31 Oct 2023 00:40:50 +0000 Subject: [PATCH 094/538] fix import --- src/sage/rings/finite_rings/integer_mod_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index 31a75f07271..c62db10a17c 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -67,7 +67,7 @@ from sage.arith.misc import CRT_basis import sage.rings.ring as ring import sage.rings.abc -from sage.rings.finite_rings. import integer_mod +from sage.rings.finite_rings import integer_mod import sage.rings.integer as integer import sage.rings.integer_ring as integer_ring import sage.rings.quotient_ring as quotient_ring From 43a334e2645ef9a7a891b4dc3e168a83042278dd Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Tue, 31 Oct 2023 00:54:19 +0000 Subject: [PATCH 095/538] fix imports --- src/sage/modules/free_module.py | 26 +++++++++---------- .../modules/vector_complex_double_dense.pxd | 2 +- src/sage/modules/vector_double_dense.pxd | 2 +- src/sage/modules/vector_integer_dense.pxd | 2 +- src/sage/modules/vector_mod2_dense.pxd | 2 +- src/sage/modules/vector_modn_dense.pxd | 2 +- src/sage/modules/vector_numpy_dense.pxd | 2 +- src/sage/modules/vector_numpy_dense.pyx | 2 +- .../modules/vector_numpy_integer_dense.pxd | 2 +- src/sage/modules/vector_rational_dense.pxd | 2 +- src/sage/modules/vector_real_double_dense.pxd | 2 +- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 18da92bf386..133ad98c9a7 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -261,7 +261,7 @@ def create_object(self, version, key): base_ring, rank, sparse, inner_product_matrix = key if inner_product_matrix is not None: - from .free_quadratic_module import FreeQuadraticModule + from sage.modules.free_quadratic_module import FreeQuadraticModule return FreeQuadraticModule(base_ring, rank, inner_product_matrix=inner_product_matrix, sparse=sparse) if not isinstance(sparse,bool): @@ -1792,7 +1792,7 @@ def quotient_module(self, sub, check=True): sub = self.submodule(sub) except (TypeError, ArithmeticError): raise ArithmeticError("sub must be a subspace of self") - from .quotient_module import QuotientModule_free_ambient + from sage.modules.quotient_module import QuotientModule_free_ambient return QuotientModule_free_ambient(self, sub) def __truediv__(self, sub): @@ -2007,7 +2007,7 @@ def construction(self): # Should there be a category for free modules accepting it as hom space? # See similar method for FreeModule_generic_field class def _Hom_(self, Y, category): - from .free_module_homspace import FreeModuleHomspace + from sage.modules.free_module_homspace import FreeModuleHomspace return FreeModuleHomspace(self, Y, category) def dense_module(self): @@ -4100,7 +4100,7 @@ def span_of_basis(self, basis, base_ring=None, check=True, already_echelonized=F if base_ring is None or base_ring == self.base_ring(): try: if self.is_dense(): - from .free_module_integer import ( + from sage.modules.free_module_integer import ( FreeModule_submodule_with_basis_integer, ) return FreeModule_submodule_with_basis_integer(self.ambient_module(), @@ -4317,7 +4317,7 @@ def quotient_module(self, sub, check=True, **kwds): except (TypeError, ArithmeticError): raise ArithmeticError("sub must be a subspace of self") if self.base_ring() == sage.rings.integer_ring.ZZ: - from .fg_pid.fgp_module import FGP_Module + from sage.modules.fg_pid.fgp_module import FGP_Module return FGP_Module(self, sub, check=False, **kwds) raise NotImplementedError("quotients of modules over rings other than fields or ZZ is not fully implemented") @@ -4394,9 +4394,9 @@ def _Hom_(self, Y, category): (number fields and quotient fields and metric spaces) """ if Y.base_ring().is_field(): - from . import vector_space_homspace + from sage.modules import vector_space_homspace return vector_space_homspace.VectorSpaceHomspace(self, Y, category) - from . import free_module_homspace + from sage.modules import free_module_homspace return free_module_homspace.FreeModuleHomspace(self, Y, category) def scale(self, other): @@ -5145,7 +5145,7 @@ def quotient_module(self, sub, check=True): except (TypeError, ArithmeticError): raise ArithmeticError("sub must be a subspace of self") A, L = self.__quotient_matrices(sub) - from . import quotient_module + from sage.modules import quotient_module return quotient_module.FreeModule_ambient_field_quotient(self, sub, A, L) def __quotient_matrices(self, sub): @@ -5750,7 +5750,7 @@ def change_ring(self, R): """ if self.base_ring() is R: return self - from .free_quadratic_module import is_FreeQuadraticModule + from sage.modules.free_quadratic_module import is_FreeQuadraticModule if is_FreeQuadraticModule(self): return FreeModule(R, self.rank(), inner_product_matrix=self.inner_product_matrix(), @@ -8198,21 +8198,21 @@ def element_class(R, is_sparse): """ import sage.rings.integer_ring if sage.rings.integer_ring.is_IntegerRing(R) and not is_sparse: - from .vector_integer_dense import Vector_integer_dense + from sage.modules.vector_integer_dense import Vector_integer_dense return Vector_integer_dense elif sage.rings.rational_field.is_RationalField(R) and not is_sparse: - from .vector_rational_dense import Vector_rational_dense + from sage.modules.vector_rational_dense import Vector_rational_dense return Vector_rational_dense elif isinstance(R, sage.rings.abc.IntegerModRing) and not is_sparse: if R.order() == 2: try: - from .vector_mod2_dense import Vector_mod2_dense + from sage.modules.vector_mod2_dense import Vector_mod2_dense except ImportError: pass else: return Vector_mod2_dense try: - from .vector_modn_dense import MAX_MODULUS, Vector_modn_dense + from sage.modules.vector_modn_dense import MAX_MODULUS, Vector_modn_dense except ImportError: pass else: diff --git a/src/sage/modules/vector_complex_double_dense.pxd b/src/sage/modules/vector_complex_double_dense.pxd index 1681bad8c34..b4181738d11 100644 --- a/src/sage/modules/vector_complex_double_dense.pxd +++ b/src/sage/modules/vector_complex_double_dense.pxd @@ -1,4 +1,4 @@ -from sage.modules .vector_double_dense cimport Vector_double_dense +from sage.modules.vector_double_dense cimport Vector_double_dense cdef class Vector_complex_double_dense(Vector_double_dense): pass diff --git a/src/sage/modules/vector_double_dense.pxd b/src/sage/modules/vector_double_dense.pxd index c378db6c1d6..15db44dac31 100644 --- a/src/sage/modules/vector_double_dense.pxd +++ b/src/sage/modules/vector_double_dense.pxd @@ -1,4 +1,4 @@ -from sage.modules .vector_numpy_dense cimport Vector_numpy_dense +from sage.modules.vector_numpy_dense cimport Vector_numpy_dense cdef class Vector_double_dense(Vector_numpy_dense): pass diff --git a/src/sage/modules/vector_integer_dense.pxd b/src/sage/modules/vector_integer_dense.pxd index ea57f938ffe..99900c8ccde 100644 --- a/src/sage/modules/vector_integer_dense.pxd +++ b/src/sage/modules/vector_integer_dense.pxd @@ -1,4 +1,4 @@ -from sage.modules .free_module_element cimport FreeModuleElement +from sage.modules.free_module_element cimport FreeModuleElement from sage.libs.gmp.types cimport mpz_t from sage.structure.parent cimport Parent diff --git a/src/sage/modules/vector_mod2_dense.pxd b/src/sage/modules/vector_mod2_dense.pxd index 4d8bd04ae0e..1292762a76e 100644 --- a/src/sage/modules/vector_mod2_dense.pxd +++ b/src/sage/modules/vector_mod2_dense.pxd @@ -1,4 +1,4 @@ -from sage.modules .free_module_element cimport FreeModuleElement +from sage.modules.free_module_element cimport FreeModuleElement from sage.libs.m4ri cimport mzd_t diff --git a/src/sage/modules/vector_modn_dense.pxd b/src/sage/modules/vector_modn_dense.pxd index 99e217e3889..474aa0dbe73 100644 --- a/src/sage/modules/vector_modn_dense.pxd +++ b/src/sage/modules/vector_modn_dense.pxd @@ -1,4 +1,4 @@ -from sage.modules .free_module_element cimport FreeModuleElement +from sage.modules.free_module_element cimport FreeModuleElement from sage.ext.mod_int cimport mod_int cdef class Vector_modn_dense(FreeModuleElement): diff --git a/src/sage/modules/vector_numpy_dense.pxd b/src/sage/modules/vector_numpy_dense.pxd index 608e65d3a53..e4e123b829f 100644 --- a/src/sage/modules/vector_numpy_dense.pxd +++ b/src/sage/modules/vector_numpy_dense.pxd @@ -1,4 +1,4 @@ -from sage.modules .free_module_element cimport FreeModuleElement +from sage.modules.free_module_element cimport FreeModuleElement cimport numpy cdef class Vector_numpy_dense(FreeModuleElement): diff --git a/src/sage/modules/vector_numpy_dense.pyx b/src/sage/modules/vector_numpy_dense.pyx index 3326e0a4a29..0c7a67dbbd5 100644 --- a/src/sage/modules/vector_numpy_dense.pyx +++ b/src/sage/modules/vector_numpy_dense.pyx @@ -29,7 +29,7 @@ AUTHORS: cimport numpy import numpy -from sage.modules .free_module_element import FreeModuleElement +from sage.modules.free_module_element import FreeModuleElement # This is for the NumPy C API (the PyArray... functions) to work numpy.import_array() diff --git a/src/sage/modules/vector_numpy_integer_dense.pxd b/src/sage/modules/vector_numpy_integer_dense.pxd index e2e3dbf8359..bb4e9bd3ca7 100644 --- a/src/sage/modules/vector_numpy_integer_dense.pxd +++ b/src/sage/modules/vector_numpy_integer_dense.pxd @@ -1,4 +1,4 @@ -from sage.modules .vector_numpy_dense cimport Vector_numpy_dense +from sage.modules.vector_numpy_dense cimport Vector_numpy_dense cdef class Vector_numpy_integer_dense(Vector_numpy_dense): diff --git a/src/sage/modules/vector_rational_dense.pxd b/src/sage/modules/vector_rational_dense.pxd index 2b5bee1c104..ef727196479 100644 --- a/src/sage/modules/vector_rational_dense.pxd +++ b/src/sage/modules/vector_rational_dense.pxd @@ -1,4 +1,4 @@ -from sage.modules .free_module_element cimport FreeModuleElement +from sage.modules.free_module_element cimport FreeModuleElement from sage.libs.gmp.types cimport mpq_t from sage.structure.parent cimport Parent diff --git a/src/sage/modules/vector_real_double_dense.pxd b/src/sage/modules/vector_real_double_dense.pxd index e5d4ad284b5..96f98b7d467 100644 --- a/src/sage/modules/vector_real_double_dense.pxd +++ b/src/sage/modules/vector_real_double_dense.pxd @@ -1,4 +1,4 @@ -from sage.modules .vector_double_dense cimport Vector_double_dense +from sage.modules.vector_double_dense cimport Vector_double_dense cdef class Vector_real_double_dense(Vector_double_dense): pass From 9fd89da36df7521fa85f3a787b70beef18b7d04d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 31 Oct 2023 12:38:15 -0700 Subject: [PATCH 096/538] .github/workflows: Replace always() by (success() || failure()), except for uploads of logs etc --- .github/workflows/build.yml | 20 ++++++++++---------- .github/workflows/doc-build-pdf.yml | 8 ++++---- .github/workflows/doc-build.yml | 8 ++++---- .github/workflows/lint.yml | 6 +++--- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7ac9c6154d0..ab66ec4fa95 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -96,7 +96,7 @@ jobs: SAGE_NUM_THREADS: 2 - name: Build modularized distributions - if: always() && steps.worktree.outcome == 'success' + if: (success() || failure()) && steps.worktree.outcome == 'success' run: make V=0 tox && make SAGE_CHECK=no pypi-wheels working-directory: ./worktree-image env: @@ -104,7 +104,7 @@ jobs: SAGE_NUM_THREADS: 2 - name: Static code check with pyright - if: always() && steps.worktree.outcome == 'success' + if: (success() || failure()) && steps.worktree.outcome == 'success' uses: jakebailey/pyright-action@v1 with: version: 1.1.332 @@ -116,7 +116,7 @@ jobs: NODE_OPTIONS: --max-old-space-size=8192 - name: Static code check with pyright (annotated) - if: always() && steps.worktree.outcome == 'success' + if: (success() || failure()) && steps.worktree.outcome == 'success' uses: jakebailey/pyright-action@v1 with: version: 1.1.332 @@ -130,7 +130,7 @@ jobs: - name: Clean (fallback to non-incremental) id: clean - if: always() && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' + if: (success() || failure()) && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' run: | set -ex ./bootstrap && make doc-clean doc-uninstall sagelib-clean && git clean -fx src/sage && ./config.status @@ -143,7 +143,7 @@ jobs: # This step is needed because building the modularized distributions installs some optional packages, # so the editable install of sagelib needs to build the corresponding optional extension modules. id: build - if: always() && (steps.incremental.outcome == 'success' || steps.clean.outcome == 'success') + if: (success() || failure()) && (steps.incremental.outcome == 'success' || steps.clean.outcome == 'success') run: | make build working-directory: ./worktree-image @@ -154,7 +154,7 @@ jobs: # Testing - name: Test changed files (sage -t --new) - if: always() && steps.build.outcome == 'success' + if: (success() || failure()) && steps.build.outcome == 'success' run: | # We run tests with "sage -t --new"; this only tests the uncommitted changes. ./sage -t --new -p2 @@ -164,7 +164,7 @@ jobs: SAGE_NUM_THREADS: 2 - name: Test modularized distributions - if: always() && steps.build.outcome == 'success' + if: (success() || failure()) && steps.build.outcome == 'success' run: make V=0 tox && make pypi-wheels-check working-directory: ./worktree-image env: @@ -182,14 +182,14 @@ jobs: COLUMNS: 120 - name: Test all files (sage -t --all --long) - if: always() && steps.build.outcome == 'success' + if: (success() || failure()) && steps.build.outcome == 'success' run: | ../sage -python -m pip install coverage ../sage -python -m coverage run ./bin/sage-runtests --all --long -p2 --random-seed=286735480429121101562228604801325644303 working-directory: ./worktree-image/src - name: Prepare coverage results - if: always() && steps.build.outcome == 'success' + if: (success() || failure()) && steps.build.outcome == 'success' run: | ./venv/bin/python3 -m coverage combine src/.coverage/ ./venv/bin/python3 -m coverage xml @@ -197,7 +197,7 @@ jobs: working-directory: ./worktree-image - name: Upload coverage to codecov - if: always() && steps.build.outcome == 'success' + if: (success() || failure()) && steps.build.outcome == 'success' uses: codecov/codecov-action@v3 with: files: ./worktree-image/coverage.xml diff --git a/.github/workflows/doc-build-pdf.yml b/.github/workflows/doc-build-pdf.yml index 2128277fbca..227ae001870 100644 --- a/.github/workflows/doc-build-pdf.yml +++ b/.github/workflows/doc-build-pdf.yml @@ -94,7 +94,7 @@ jobs: - name: Build (fallback to non-incremental) id: build - if: always() && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' + if: (success() || failure()) && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' run: | set -ex make sagelib-clean && git clean -fx src/sage && ./config.status && make build @@ -105,7 +105,7 @@ jobs: - name: Build docs (PDF) id: docbuild - if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') + if: (success() || failure()) && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') run: | make doc-clean doc-uninstall; make doc-pdf working-directory: ./worktree-image @@ -114,7 +114,7 @@ jobs: SAGE_NUM_THREADS: 2 - name: Copy docs - if: always() && steps.docbuild.outcome == 'success' + if: (success() || failure()) && steps.docbuild.outcome == 'success' run: | # For some reason the deploy step below cannot find /sage/... # So copy everything from there to local folder @@ -124,7 +124,7 @@ jobs: zip -r docs-pdf.zip docs - name: Upload docs - if: always() && steps.copy.outcome == 'success' + if: (success() || failure()) && steps.copy.outcome == 'success' uses: actions/upload-artifact@v3 with: name: docs-pdf diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 5eb3998feee..4e66cdac5f0 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -99,7 +99,7 @@ jobs: - name: Build (fallback to non-incremental) id: build - if: always() && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' + if: (success() || failure()) && steps.worktree.outcome == 'success' && steps.incremental.outcome != 'success' run: | set -ex make sagelib-clean && git clean -fx src/sage && ./config.status && make sagemath_doc_html-build-deps @@ -110,7 +110,7 @@ jobs: - name: Build docs id: docbuild - if: always() && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') + if: (success() || failure()) && (steps.incremental.outcome == 'success' || steps.build.outcome == 'success') # Always non-incremental because of the concern that # incremental docbuild may introduce broken links (inter-file references) though build succeeds run: | @@ -127,7 +127,7 @@ jobs: - name: Copy docs id: copy - if: always() && steps.docbuild.outcome == 'success' + if: (success() || failure()) && steps.docbuild.outcome == 'success' run: | set -ex mkdir -p ./docs @@ -191,7 +191,7 @@ jobs: zip -r docs.zip docs - name: Upload docs - if: always() && steps.copy.outcome == 'success' + if: (success() || failure()) && steps.copy.outcome == 'success' uses: actions/upload-artifact@v3 with: name: docs diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 41560674b49..7821ea20212 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -37,13 +37,13 @@ jobs: run: pip install tox - name: Code style check with pycodestyle - if: always() && steps.deps.outcome == 'success' + if: (success() || failure()) && steps.deps.outcome == 'success' run: tox -e pycodestyle-minimal - name: Code style check with relint - if: always() && steps.deps.outcome == 'success' + if: (success() || failure()) && steps.deps.outcome == 'success' run: tox -e relint -- src/sage/ - name: Validate docstring markup as RST - if: always() && steps.deps.outcome == 'success' + if: (success() || failure()) && steps.deps.outcome == 'success' run: tox -e rst From e939eca866393268569a2630e58257d72d666486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 1 Nov 2023 12:03:03 +0100 Subject: [PATCH 097/538] cylint cleanup in combinatorial polyhedra --- .../combinatorial_polyhedron/base.pxd | 1 + .../combinatorial_polyhedron/base.pyx | 35 ++++++-------- .../combinatorial_face.pxd | 1 + .../combinatorial_face.pyx | 46 +++++++++---------- .../combinatorial_polyhedron/conversions.pyx | 18 ++++++-- .../face_iterator.pxd | 2 + .../face_iterator.pyx | 35 +++++++------- .../face_list_data_structure.pxd | 5 +- .../face_list_data_structure.pyx | 2 +- .../list_of_faces.pxd | 1 + .../list_of_faces.pyx | 2 +- .../polyhedron_face_lattice.pxd | 1 + .../polyhedron_face_lattice.pyx | 32 ++++++------- 13 files changed, 90 insertions(+), 91 deletions(-) diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd index 85a020df78a..8e1f3765e81 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pxd @@ -6,6 +6,7 @@ from .list_of_faces cimport ListOfFaces from .face_data_structure cimport face_t from .polyhedron_face_lattice cimport PolyhedronFaceLattice + @cython.final cdef class CombinatorialPolyhedron(SageObject): cdef public dict _cached_methods diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx index 8282fbbd1ca..33aac3d70f7 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/base.pyx @@ -93,11 +93,10 @@ from sage.geometry.cone import ConvexRationalPolyhedralCone from sage.structure.element import Matrix from sage.matrix.matrix_dense cimport Matrix_dense from sage.misc.misc import is_iterator -from .conversions \ - import incidence_matrix_to_bit_rep_of_facets, \ - incidence_matrix_to_bit_rep_of_Vrep, \ - facets_tuple_to_bit_rep_of_facets, \ - facets_tuple_to_bit_rep_of_Vrep +from .conversions import (incidence_matrix_to_bit_rep_of_facets, + incidence_matrix_to_bit_rep_of_Vrep, + facets_tuple_to_bit_rep_of_facets, + facets_tuple_to_bit_rep_of_Vrep) from .conversions cimport Vrep_list_to_bit_rep from sage.misc.cachefunc import cached_method @@ -437,7 +436,7 @@ cdef class CombinatorialPolyhedron(SageObject): from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ incidence_matrix = matrix(ZZ, data.incidence_matrix().rows() - + [[ZZ.one() for _ in range(len(data.facet_normals()))]]) + + [[ZZ.one() for _ in range(len(data.facet_normals()))]]) return self._init_from_incidence_matrix(incidence_matrix) cdef _init_facet_names(self, facets) noexcept: @@ -481,11 +480,10 @@ cdef class CombinatorialPolyhedron(SageObject): data.set_immutable() self.incidence_matrix.set_cache(data) - # Delete equations. data = data.delete_columns( [i for i in range(data.ncols()) - if all(data[j,i] for j in range(data.nrows()))], + if all(data[j, i] for j in range(data.nrows()))], check=False) # Initializing the facets in their Bit-representation. @@ -515,7 +513,7 @@ cdef class CombinatorialPolyhedron(SageObject): n_Vrepresentation = len(Vrep) if Vrep != range(len(Vrep)): self._Vrep = tuple(Vrep) - Vinv = {v: i for i,v in enumerate(self._Vrep)} + Vinv = {v: i for i, v in enumerate(self._Vrep)} else: # Assuming the user gave as correct names for the vertices # and labeled them instead by `0,...,n`. @@ -548,7 +546,7 @@ cdef class CombinatorialPolyhedron(SageObject): Initialize self from two ``ListOfFaces``. """ self._bitrep_facets = facets - self._bitrep_Vrep = Vrep + self._bitrep_Vrep = Vrep self._n_Hrepresentation = self._bitrep_facets.n_faces() self._n_Vrepresentation = self._bitrep_Vrep.n_faces() @@ -629,7 +627,7 @@ cdef class CombinatorialPolyhedron(SageObject): 'A 2-dimensional combinatorial polyhedron with 1 facet' """ desc = "A {}-dimensional combinatorial polyhedron with {} facet"\ - .format(self.dimension(), self.n_facets()) + .format(self.dimension(), self.n_facets()) if self.n_facets() != 1: desc += "s" return desc @@ -1694,7 +1692,7 @@ cdef class CombinatorialPolyhedron(SageObject): if not names: vertices = [i for i in range(n_facets + n_Vrep)] - edges = tuple((j, n_Vrep + n_facets - 1 - i) for i,facet in enumerate(facet_iter) for j in facet.ambient_V_indices()) + edges = tuple((j, n_Vrep + n_facets - 1 - i) for i, facet in enumerate(facet_iter) for j in facet.ambient_V_indices()) else: facet_names = self.facet_names() if facet_names is None: @@ -1707,7 +1705,7 @@ cdef class CombinatorialPolyhedron(SageObject): Vrep = [("V", i) for i in range(n_Vrep)] vertices = Vrep + facet_names - edges = tuple((Vrep[j], facet_names[n_facets - 1 - i]) for i,facet in enumerate(facet_iter) for j in facet.ambient_V_indices()) + edges = tuple((Vrep[j], facet_names[n_facets - 1 - i]) for i, facet in enumerate(facet_iter) for j in facet.ambient_V_indices()) return DiGraph([vertices, edges], format='vertices_and_edges', immutable=True) @cached_method @@ -2126,7 +2124,7 @@ cdef class CombinatorialPolyhedron(SageObject): cdef simpliciality = dim - 1 # For each face in the iterator, check if its a simplex. - face_iter.structure.lowest_dimension = 2 # every 1-face is a simplex + face_iter.structure.lowest_dimension = 2 # every 1-face is a simplex d = face_iter.next_dimension() while d < dim: sig_check() @@ -2237,7 +2235,7 @@ cdef class CombinatorialPolyhedron(SageObject): cdef simplicity = dim - 1 # For each coface in the iterator, check if its a simplex. - coface_iter.structure.lowest_dimension = 2 # every coface of dimension 1 is a simplex + coface_iter.structure.lowest_dimension = 2 # every coface of dimension 1 is a simplex d = coface_iter.next_dimension() while d < dim: sig_check() @@ -2623,7 +2621,6 @@ cdef class CombinatorialPolyhedron(SageObject): return (False, None) - def join_of_Vrep(self, *indices): r""" Return the smallest face containing all Vrepresentatives indicated by the indices. @@ -2793,7 +2790,6 @@ cdef class CombinatorialPolyhedron(SageObject): if 'dual' in kwds and dual == -1 and kwds['dual'] in (False, True): dual = int(kwds['dual']) - cdef FaceIterator face_iter if dual == -1: # Determine the faster way, to iterate through all faces. if not self.is_bounded() or self.n_facets() <= self.n_Vrepresentation(): @@ -3354,7 +3350,6 @@ cdef class CombinatorialPolyhedron(SageObject): and self.far_face_tuple() == other_C.far_face_tuple() and self.incidence_matrix() == other.incidence_matrix()) - # Methods to obtain a different combinatorial polyhedron. cpdef CombinatorialPolyhedron dual(self) noexcept: @@ -3484,7 +3479,6 @@ cdef class CombinatorialPolyhedron(SageObject): return CombinatorialPolyhedron((new_facets, new_Vrep), Vrep=new_Vrep_names, facets=new_facet_names) - # Internal methods. cdef int _compute_f_vector(self, size_t num_threads, size_t parallelization_depth, int dual) except -1: @@ -3497,7 +3491,6 @@ cdef class CombinatorialPolyhedron(SageObject): return 0 # There is no need to recompute the f_vector. cdef int dim = self.dimension() - cdef int d # dimension of the current face of the iterator cdef MemoryAllocator mem = MemoryAllocator() if num_threads == 0: @@ -3686,7 +3679,7 @@ cdef class CombinatorialPolyhedron(SageObject): from sage.arith.misc import binomial estimate_n_faces = self.dimension() * binomial(min(self.n_facets(), self.n_Vrepresentation()), - self.dimension() // 2) + self.dimension() // 2) # Note that the runtime per face already computes the coatoms of the next level, i.e. # the runtime for each facet suffices to compute all ridges in primal, diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd index 2169fe539f6..6dea4305ba7 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pxd @@ -4,6 +4,7 @@ from .list_of_faces cimport ListOfFaces from .face_data_structure cimport face_t from .face_iterator cimport FaceIterator + @cython.final cdef class CombinatorialFace(SageObject): cdef readonly bint _dual # if 1, then iterate over dual Polyhedron diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx index 541927c6c11..87ec3a1eb90 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/combinatorial_face.pyx @@ -173,9 +173,9 @@ cdef class CombinatorialFace(SageObject): # Copy data from FaceIterator. it = data - self._dual = it.dual - self.atoms = it.atoms - self.coatoms = it.coatoms + self._dual = it.dual + self.atoms = it.atoms + self.coatoms = it.coatoms if it.structure.face_status == FaceStatus.NOT_INITIALIZED: raise LookupError("face iterator not set to a face") @@ -183,15 +183,15 @@ cdef class CombinatorialFace(SageObject): face_init(self.face, self.coatoms.n_atoms(), self.coatoms.n_coatoms()) face_copy(self.face, it.structure.face) - self._dimension = it.structure.current_dimension + self._dimension = it.structure.current_dimension self._ambient_dimension = it.structure.dimension - self._ambient_Vrep = it._Vrep - self._ambient_facets = it._facet_names - self._n_ambient_facets = it._n_facets - self._equations = it._equations - self._n_equations = it._n_equations - self._hash_index = it.structure._index - self._ambient_bounded = it._bounded + self._ambient_Vrep = it._Vrep + self._ambient_facets = it._facet_names + self._n_ambient_facets = it._n_facets + self._equations = it._equations + self._n_equations = it._n_equations + self._hash_index = it.structure._index + self._ambient_bounded = it._bounded self._initialized_from_face_lattice = False @@ -203,35 +203,35 @@ cdef class CombinatorialFace(SageObject): assert 0 <= index < all_faces.f_vector[dimension + 1], "index is out of range" # Copy data from PolyhedronFaceLattice. - self._dual = all_faces.dual - self.atoms = all_faces.atoms - self.coatoms = all_faces.coatoms + self._dual = all_faces.dual + self.atoms = all_faces.atoms + self.coatoms = all_faces.coatoms face_init(self.face, self.coatoms.n_atoms(), self.coatoms.n_coatoms()) face_copy(self.face, all_faces.faces[dimension+1].faces[index]) - self._dimension = dimension + self._dimension = dimension self._ambient_dimension = all_faces.dimension - self._ambient_Vrep = all_faces._Vrep - self._ambient_facets = all_faces._facet_names - self._equations = all_faces._equations - self._n_equations = len(self._equations) if self._equations else 0 + self._ambient_Vrep = all_faces._Vrep + self._ambient_facets = all_faces._facet_names + self._equations = all_faces._equations + self._n_equations = len(self._equations) if self._equations else 0 if self._dual: self._n_ambient_facets = self.atoms.n_faces() else: self._n_ambient_facets = self.coatoms.n_faces() - self._ambient_bounded = all_faces._bounded + self._ambient_bounded = all_faces._bounded self._initialized_from_face_lattice = True self._hash_index = index - for i in range(-1,dimension): + for i in range(-1, dimension): self._hash_index += all_faces.f_vector[i+1] # Add the complete ``f-vector`` to the hash index, # such that hash values obtained by an iterator or by the face lattice # do not collide. - for i in range(-1,self._ambient_dimension+1): + for i in range(-1, self._ambient_dimension+1): self._hash_index += all_faces.f_vector[i+1] else: raise ValueError("data must be face iterator or a list of all faces") @@ -273,7 +273,7 @@ cdef class CombinatorialFace(SageObject): 'A 3-dimensional face of a 5-dimensional combinatorial polyhedron' """ return "A {}-dimensional face of a {}-dimensional combinatorial polyhedron"\ - .format(self.dimension(), self.ambient_dimension()) + .format(self.dimension(), self.ambient_dimension()) def __reduce__(self): r""" diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx index baeb8fc4855..2f686364ac0 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/conversions.pyx @@ -58,15 +58,15 @@ AUTHOR: - Jonathan Kliem (2019-04) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2019 Jonathan Kliem # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from memory_allocator cimport MemoryAllocator @@ -94,6 +94,7 @@ def _Vrep_list_to_bit_rep_wrapper(tup): Vrep_list_to_bit_rep(tup, output.data.faces[0]) return output + cdef int Vrep_list_to_bit_rep(tuple Vrep_list, face_t output) except -1: r""" Convert a vertex list into Bit-representation. Store it in ``output``. @@ -135,6 +136,7 @@ cdef int Vrep_list_to_bit_rep(tuple Vrep_list, face_t output) except -1: for entry in Vrep_list: face_add_atom_safe(output, entry) + def _incidences_to_bit_rep_wrapper(tup): r""" A function to allow doctesting of :func:`incidences_to_bit_rep`. @@ -150,6 +152,7 @@ def _incidences_to_bit_rep_wrapper(tup): incidences_to_bit_rep(tup, output.data.faces[0]) return output + cdef int incidences_to_bit_rep(tuple incidences, face_t output) except -1: r""" Convert a tuple of incidences into Bit-representation. @@ -185,6 +188,7 @@ cdef int incidences_to_bit_rep(tuple incidences, face_t output) except -1: # Vrep ``entry`` is contained in the face, so set the corresponding bit face_add_atom_safe(output, entry) + def incidence_matrix_to_bit_rep_of_facets(Matrix_dense matrix): r""" Initialize facets in Bit-representation as :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces`. @@ -249,6 +253,7 @@ def incidence_matrix_to_bit_rep_of_facets(Matrix_dense matrix): face_add_atom_safe(output, entry) return facets + def incidence_matrix_to_bit_rep_of_Vrep(Matrix_dense matrix): r""" Initialize Vrepresentatives in Bit-representation as :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces`. @@ -307,6 +312,7 @@ def incidence_matrix_to_bit_rep_of_Vrep(Matrix_dense matrix): """ return incidence_matrix_to_bit_rep_of_facets(matrix.transpose()) + def facets_tuple_to_bit_rep_of_facets(tuple facets_input, size_t n_Vrep): r""" Initializes facets in Bit-representation as :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces`. @@ -348,6 +354,7 @@ def facets_tuple_to_bit_rep_of_facets(tuple facets_input, size_t n_Vrep): facet_set_coatom(facets.data.faces[i], i) return facets + def facets_tuple_to_bit_rep_of_Vrep(tuple facets_input, size_t n_Vrep): r""" Initialize Vrepresentatives in Bit-representation as :class:`~sage.geometry.polyhedron.combinatorial_polyhedron.list_of_faces.ListOfFaces`. @@ -408,6 +415,7 @@ def facets_tuple_to_bit_rep_of_Vrep(tuple facets_input, size_t n_Vrep): face_add_atom_safe(Vrep_data[input_Vrep], input_facet) return Vrep + def _bit_rep_to_Vrep_list_wrapper(ListOfFaces faces, index=0): r""" A function to test :func:`bit_rep_to_Vrep_list`. @@ -433,10 +441,10 @@ def _bit_rep_to_Vrep_list_wrapper(ListOfFaces faces, index=0): output = mem.allocarray(faces.n_atoms(), sizeof(size_t)) - length = bit_rep_to_Vrep_list( - faces.data.faces[index], output) + length = bit_rep_to_Vrep_list(faces.data.faces[index], output) return tuple(output[i] for i in range(length)) + cdef inline size_t bit_rep_to_Vrep_list(face_t face, size_t *output) except -1: r""" Convert a bitrep-representation to a list of Vrep. Return length of representation. diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd index f148c81f7a9..8df85938e91 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pxd @@ -80,10 +80,12 @@ cdef class FaceIterator_base(SageObject): cdef int only_subsets(self) except -1 cdef int find_face(self, face_t face) except -1 + @cython.final cdef class FaceIterator(FaceIterator_base): pass + @cython.final cdef class FaceIterator_geom(FaceIterator_base): cdef int _trivial_faces # Whether to yield the trivial faces. diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx index d35033fc855..ea0c36eeb72 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_iterator.pyx @@ -164,15 +164,15 @@ AUTHOR: - Jonathan Kliem (2019-04) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2019 Jonathan Kliem # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cython.parallel cimport prange, threadid from cysignals.memory cimport check_allocarray, sig_free @@ -244,7 +244,6 @@ cdef class FaceIterator_base(SageObject): if dual and not C.is_bounded(): raise ValueError("cannot iterate over dual of unbounded Polyedron") cdef int i - cdef size_t j self.dual = dual self.structure.dual = dual @@ -1189,7 +1188,7 @@ cdef class FaceIterator_base(SageObject): cdef size_t yet_to_visit = self.structure.yet_to_visit if unlikely(yet_to_visit >= faces[0].n_faces - or not faces_are_identical(faces[0].faces[yet_to_visit], self.structure.face)): + or not faces_are_identical(faces[0].faces[yet_to_visit], self.structure.face)): raise ValueError("iterator is not set to the correct face") swap_faces(faces[0].faces[yet_to_visit], faces[0].faces[faces[0].n_faces - 1]) @@ -1294,7 +1293,7 @@ cdef class FaceIterator_base(SageObject): self.structure.current_dimension = -1 return 0 - cdef int d = self.next_dimension() + self.next_dimension() while self.structure.current_dimension != self.structure.dimension: if face_issubset(face, self.structure.face): if face_issubset(self.structure.face, face): @@ -1304,7 +1303,7 @@ cdef class FaceIterator_base(SageObject): # The face is not a subface/supface of the current face. self.ignore_subsets() - d = self.next_dimension() + self.next_dimension() raise ValueError("the face appears to be incorrect") @@ -1883,7 +1882,7 @@ cdef class FaceIterator_geom(FaceIterator_base): if unlikely(self._trivial_faces): if self._trivial_faces == -1: raise StopIteration - if self._trivial_faces in (2,4): # Return the polyhedron. + if self._trivial_faces in (2, 4): # Return the polyhedron. if self._trivial_faces == 2: self._trivial_faces = 1 # Return the empty face next. else: @@ -2076,30 +2075,29 @@ cdef int parallel_f_vector(iter_t* structures, size_t num_threads, size_t parall if num_threads == 0: num_threads = 1 - cdef size_t thread_id cdef MemoryAllocator mem = MemoryAllocator() # Setting up for each thread some storage space. cdef parallel_f_t* parallel_structs = \ - mem.allocarray(num_threads, sizeof(parallel_f_t)) + mem.allocarray(num_threads, sizeof(parallel_f_t)) for i in range(num_threads): # Partial f-vectors. parallel_structs[i].f_vector = \ - mem.calloc(dim+2, sizeof(size_t)) + mem.calloc(dim+2, sizeof(size_t)) parallel_structs[i].current_job_id = \ - mem.calloc(parallelization_depth+1, sizeof(size_t)) + mem.calloc(parallelization_depth+1, sizeof(size_t)) # Keeping back of the original number of faces allows faster starting the next job. parallel_structs[i].original_n_faces = \ - mem.calloc(parallelization_depth+1, sizeof(size_t)) + mem.calloc(parallelization_depth+1, sizeof(size_t)) parallel_structs[i].original_n_faces[0] = \ - structures[0].new_faces[dim - 1].n_faces + structures[0].new_faces[dim - 1].n_faces parallel_structs[i].original_n_visited_all = \ - mem.calloc(parallelization_depth+1, sizeof(size_t)) + mem.calloc(parallelization_depth+1, sizeof(size_t)) parallel_structs[i].original_n_visited_all[0] = \ - structures[0].visited_all[dim - 1].n_faces + structures[0].visited_all[dim - 1].n_faces for i in prange(n_jobs, schedule='dynamic', chunksize=1, num_threads=num_threads, nogil=True): @@ -2155,9 +2153,9 @@ cdef inline int prepare_face_iterator_for_partial_job( # Recover all faces. structure.new_faces[d].n_faces = \ - parallel_struct.original_n_faces[current_depth -1] + parallel_struct.original_n_faces[current_depth -1] structure.visited_all[d].n_faces = \ - parallel_struct.original_n_visited_all[current_depth -1] + parallel_struct.original_n_visited_all[current_depth -1] structure.first_time[d] = True structure.yet_to_visit = 0 # just to be on the safe side @@ -2172,7 +2170,6 @@ cdef inline int prepare_face_iterator_for_partial_job( cdef size_t n_coatoms = structure.n_coatoms cdef size_t job_id_c cdef size_t i - cdef size_t diff cdef size_t new_faces_counter for current_depth in range(1, parallelization_depth + 1): diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd index 105cc81b9a4..708b176ef16 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pxd @@ -188,7 +188,6 @@ cdef inline size_t find_face(face_t face, face_list_t faces) noexcept: cdef face_t* faces_pt = faces.faces cdef int val - while (n_faces > 1): # In each iteration step, we will look for ``face`` in # ``faces_pt[start:start+n_faces]``. @@ -367,6 +366,6 @@ cdef inline bint face_list_check_alignment(face_list_t faces) noexcept: """ cdef size_t i for i in range(faces.n_faces): - if not face_check_alignment(faces.faces[i]): - return False + if not face_check_alignment(faces.faces[i]): + return False return True diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx index 3f33aec8ec6..34adfb092dd 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/face_list_data_structure.pyx @@ -9,7 +9,7 @@ Sorting of a list of faces. # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#**************************************************************************** +# *************************************************************************** cdef void sort_faces_list(face_list_t faces) noexcept: r""" diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd index d50c8f85539..420afcbb7d9 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pxd @@ -1,6 +1,7 @@ cimport cython from .face_list_data_structure cimport face_list_t, face_t + @cython.final cdef class ListOfFaces: # ``data`` points to the raw data. diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx index 9b5f3dd4ada..ad708569ec2 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/list_of_faces.pyx @@ -294,7 +294,7 @@ cdef class ListOfFaces: # Calculating ``newfaces`` # such that ``newfaces`` points to all facets of ``faces[n_faces -1]``. - cdef size_t new_n_faces = get_next_level(self.data, new_faces.data, empty_forbidden) + get_next_level(self.data, new_faces.data, empty_forbidden) # Undo what ``get_next_level`` does. self.data.n_faces += 1 diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd index 438dc8de6f7..2d6f1bc996f 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pxd @@ -4,6 +4,7 @@ from .face_data_structure cimport face_t from .face_list_data_structure cimport face_list_t from .combinatorial_face cimport CombinatorialFace + @cython.final cdef class PolyhedronFaceLattice: cdef int dimension # dimension of Polyhedron 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 9f5a98c7ece..f347f5bb0f9 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/polyhedron_face_lattice.pyx @@ -50,7 +50,7 @@ AUTHOR: - Jonathan Kliem (2019-04) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2019 Jonathan Kliem # # This program is free software: you can redistribute it and/or modify @@ -58,11 +58,10 @@ AUTHOR: # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** -from .conversions \ - import facets_tuple_to_bit_rep_of_facets, \ - facets_tuple_to_bit_rep_of_Vrep +from .conversions import (facets_tuple_to_bit_rep_of_facets, + facets_tuple_to_bit_rep_of_Vrep) from .conversions cimport bit_rep_to_Vrep_list @@ -166,7 +165,6 @@ cdef class PolyhedronFaceLattice: self.atoms = face_iter.atoms self.coatoms = face_iter.coatoms - cdef size_t n_atoms = self.atoms.n_faces() self.atom_rep = check_allocarray(self.coatoms.n_atoms(), sizeof(size_t)) self.coatom_rep = check_allocarray(self.coatoms.n_faces(), sizeof(size_t)) @@ -361,7 +359,6 @@ cdef class PolyhedronFaceLattice: ....: face.ambient_V_indices() for face in it) True """ - cdef size_t length if self.dual: # if dual, the Vrepresentation corresponds to the coatom-representation dimension = self.dimension - 1 - dimension # if dual, the dimensions are reversed @@ -376,9 +373,9 @@ cdef class PolyhedronFaceLattice: This is a shortcut of :class:`sage.geometry.polyhedron.combinatorial_polyhedron.combinatorial_face.CombinatorialFace.set_coatom_rep` """ if unlikely(dimension < -1 or dimension > self.dimension): - raise ValueError("no face of dimension %s"%dimension) + raise ValueError("no face of dimension %s" % dimension) if unlikely(index >= self.f_vector[dimension + 1]): - raise IndexError("no %s-th face of dimension %s"%(index, dimension)) + raise IndexError("no %s-th face of dimension %s" % (index, dimension)) if unlikely(self.coatoms.n_faces() == 0): return 0 @@ -394,9 +391,9 @@ cdef class PolyhedronFaceLattice: This is a shortcut of :class:`sage.geometry.polyhedron.combinatorial_polyhedron.combinatorial_face.CombinatorialFace.set_atom_rep` """ if unlikely(dimension < -1 or dimension > self.dimension): - raise ValueError("no face of dimension %s"%dimension) + raise ValueError("no face of dimension %s" % dimension) if unlikely(index >= self.f_vector[dimension + 1]): - raise IndexError("no %s-th face of dimension %s"%(index, dimension)) + raise IndexError("no %s-th face of dimension %s" % (index, dimension)) cdef face_t face = self.faces[dimension+1].faces[index] return bit_rep_to_Vrep_list(face, self.atom_rep) @@ -412,13 +409,12 @@ cdef class PolyhedronFaceLattice: with empty and full polyhedron are implemented, which suffices for the face-lattice. """ - cdef size_t i if dimension_one == self.dimension: # The full polyhedron is incident to every face. if dimension_two < -1: - raise ValueError("no faces of dimension %s"%dimension_two) + raise ValueError("no faces of dimension %s" % dimension_two) if dimension_two > self.dimension: - raise ValueError("no faces of dimension %s"%dimension_two) + raise ValueError("no faces of dimension %s" % dimension_two) self.incidence_dim_one = dimension_one self.incidence_dim_two = dimension_two self.incidence_counter_one = 0 @@ -429,9 +425,9 @@ cdef class PolyhedronFaceLattice: if dimension_two == -1: # The empty polyhedron is incident to every face. if dimension_one < -1: - raise ValueError("no faces of dimension %s"%dimension_two) + raise ValueError("no faces of dimension %s" % dimension_two) if dimension_one > self.dimension: - raise ValueError("no faces of dimension %s"%dimension_two) + raise ValueError("no faces of dimension %s" % dimension_two) self.incidence_dim_one = dimension_one self.incidence_dim_two = dimension_two self.incidence_counter_one = 0 @@ -444,9 +440,9 @@ cdef class PolyhedronFaceLattice: # At the moment, this is not implemented. if dimension_one > self.dimension: - raise ValueError("no faces of dimension %s"%dimension_one) + raise ValueError("no faces of dimension %s" % dimension_one) if dimension_two < -1: - raise ValueError("no faces of dimension %s"%dimension_two) + raise ValueError("no faces of dimension %s" % dimension_two) self.incidence_dim_one = dimension_one self.incidence_dim_two = dimension_two From 2341fb400fa20b673422c56337ba03d9befed48e Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Wed, 1 Nov 2023 21:39:31 -0700 Subject: [PATCH 098/538] Set LDFLAGS depending on version of OS X command-line tools --- src/bin/sage-env | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bin/sage-env b/src/bin/sage-env index 9cdd5db453f..72aa454bf4a 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -383,7 +383,11 @@ if [ -n "$PYTHONHOME" ]; then fi if [ -n "$SAGE_LOCAL" ]; then - LDFLAGS="-L$SAGE_LOCAL/lib -Wl,-rpath,$SAGE_LOCAL/lib $LDFLAGS" + if [ "$UNAME" = "Darwin" ] && [ "$XCLT_VERSION" -ge 15 ]; then + LDFLAGS="-L$SAGE_LOCAL/lib -Wl,-ld_classic,-rpath,$SAGE_LOCAL/lib $LDFLAGS" + else + LDFLAGS="-L$SAGE_LOCAL/lib -Wl,-rpath,$SAGE_LOCAL/lib $LDFLAGS" + fi if [ "$UNAME" = "Linux" ]; then LDFLAGS="-Wl,-rpath-link,$SAGE_LOCAL/lib $LDFLAGS" fi From 0d47115ef51b312b8dbdda9d1df657b838580ade Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 20:52:40 -0700 Subject: [PATCH 099/538] tox.ini (centos-7): Download mirror_list using http, not https --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 6293831c44f..ad3d833eeef 100644 --- a/tox.ini +++ b/tox.ini @@ -308,6 +308,7 @@ setenv = centos: BASE_IMAGE=centos centos: IGNORE_MISSING_SYSTEM_PACKAGES=yes centos-7: BASE_TAG=centos7 + centos-7: BOOTSTRAP=sed -i.bak s/https/http/ .upstream.d/*_mirror_list; ./bootstrap centos-stream: BASE_IMAGE=quay.io/centos/centos centos-stream: BASE_TAG=stream centos-stream-8: BASE_TAG=stream8 From 5f29842a5a57fafb3338277683518dc31a95e03c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 20:53:12 -0700 Subject: [PATCH 100/538] .github/workflows/docker.yml: Remove gentoo-python3.12 for now --- .github/workflows/docker.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c12ec820f83..a3986899a7d 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -51,7 +51,6 @@ on: "almalinux-9-python3.11", "gentoo-python3.10", "gentoo-python3.11", - "gentoo-python3.12", "archlinux-latest", "opensuse-15.3-gcc_11-python3.9", "opensuse-15.4-gcc_11-python3.10", From fc7427d67be7efae323852ef49bcb9a525d53966 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 21:04:15 -0700 Subject: [PATCH 101/538] tox.ini (centos-7): Download mirror_list using http, not https (fixup) --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index ad3d833eeef..c039103f422 100644 --- a/tox.ini +++ b/tox.ini @@ -308,7 +308,7 @@ setenv = centos: BASE_IMAGE=centos centos: IGNORE_MISSING_SYSTEM_PACKAGES=yes centos-7: BASE_TAG=centos7 - centos-7: BOOTSTRAP=sed -i.bak s/https/http/ .upstream.d/*_mirror_list; ./bootstrap + centos-7: BOOTSTRAP=sed -i.bak s/https/http/ .upstream.d/*mirror_list; ./bootstrap centos-stream: BASE_IMAGE=quay.io/centos/centos centos-stream: BASE_TAG=stream centos-stream-8: BASE_TAG=stream8 From d862f7c71f68edf5b176ada4211e0a67a5731837 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 1 Nov 2023 22:53:39 -0700 Subject: [PATCH 102/538] build/pkgs/_python3.*/distros/conda.txt: New --- build/pkgs/_python3.10/distros/conda.txt | 1 + build/pkgs/_python3.11/distros/conda.txt | 1 + build/pkgs/_python3.12/distros/conda.txt | 1 + build/pkgs/_python3.9/distros/conda.txt | 1 + 4 files changed, 4 insertions(+) create mode 100644 build/pkgs/_python3.10/distros/conda.txt create mode 100644 build/pkgs/_python3.11/distros/conda.txt create mode 100644 build/pkgs/_python3.12/distros/conda.txt create mode 100644 build/pkgs/_python3.9/distros/conda.txt diff --git a/build/pkgs/_python3.10/distros/conda.txt b/build/pkgs/_python3.10/distros/conda.txt new file mode 100644 index 00000000000..0e2312f6abf --- /dev/null +++ b/build/pkgs/_python3.10/distros/conda.txt @@ -0,0 +1 @@ +python==3.10 diff --git a/build/pkgs/_python3.11/distros/conda.txt b/build/pkgs/_python3.11/distros/conda.txt new file mode 100644 index 00000000000..875818d94e8 --- /dev/null +++ b/build/pkgs/_python3.11/distros/conda.txt @@ -0,0 +1 @@ +python==3.11 diff --git a/build/pkgs/_python3.12/distros/conda.txt b/build/pkgs/_python3.12/distros/conda.txt new file mode 100644 index 00000000000..08c4473f336 --- /dev/null +++ b/build/pkgs/_python3.12/distros/conda.txt @@ -0,0 +1 @@ +python==3.12 diff --git a/build/pkgs/_python3.9/distros/conda.txt b/build/pkgs/_python3.9/distros/conda.txt new file mode 100644 index 00000000000..ca224649651 --- /dev/null +++ b/build/pkgs/_python3.9/distros/conda.txt @@ -0,0 +1 @@ +python==3.9 From 1d2231b9f77ce9bf09a5eddd6bc7c88756ef7678 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 1 Nov 2023 22:54:27 -0700 Subject: [PATCH 103/538] CI Linux: Switch conda-forge to conda-forge-python3.11 --- .github/workflows/docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index a3986899a7d..4b579562876 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -57,7 +57,7 @@ on: "opensuse-15.5-gcc_11-python3.11", "opensuse-tumbleweed-python3.10", "opensuse-tumbleweed", - "conda-forge", + "conda-forge-python3.11", "ubuntu-bionic-gcc_8-i386", "debian-bullseye-i386", ] From d1e90b9cf38582b6e79e640b3b568292c6f2bd19 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 2 Nov 2023 08:24:55 +0100 Subject: [PATCH 104/538] more doctests --- .../rings/polynomial/laurent_polynomial_ideal.py | 12 +++++++++--- .../rings/polynomial/laurent_polynomial_mpair.pyx | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 43f9bca511c..4cf7b8b3414 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -193,14 +193,20 @@ def __contains__(self, f): sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: x + 3*y in I True + sage: P.__contains__(x + 3*y) + True sage: I.gen(0).__reduce__() (Multivariate Laurent Polynomial Ring in x, y over Rational Field, (x^2*y + 3*x*y^2, (0, 0))) - sage: P. = LaurentPolynomialRing(QQ, 1) + sage: P. = LaurentPolynomialRing(QQ) sage: I = P.ideal([x^2 + 3*x]) + sage: 1 + 3*x^-1 in I + True + sage: P.__contains__(1 + 3*x^-1) + True sage: I.gen(0).__reduce__() # Check the differences of __reduce__ for distinct Laurent polynomial rings - (Multivariate Laurent Polynomial Ring in x over Rational Field, - (x^2 + 3*x, (0,))) + (, + (Univariate Laurent Polynomial Ring in x over Rational Field, x + 3, 1)) """ if not f or f in self.gens(): return True diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 3b2ebf177ea..9cf123b5a52 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1858,7 +1858,7 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): @coerce_binop def divides(self, other): """ - Check if ``self`` divides ``other`` + Check if ``self`` divides ``other``. EXAMPLES:: From 60d683e3dc2ff03376fff875652a724958ed6131 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 13 Mar 2023 15:24:34 +0800 Subject: [PATCH 105/538] add class groups of binary quadratic forms --- .../en/reference/quadratic_forms/index.rst | 1 + src/sage/quadratic_forms/all.py | 2 + src/sage/quadratic_forms/binary_qf.py | 112 ++++ src/sage/quadratic_forms/bqf_class_group.py | 593 ++++++++++++++++++ 4 files changed, 708 insertions(+) create mode 100644 src/sage/quadratic_forms/bqf_class_group.py diff --git a/src/doc/en/reference/quadratic_forms/index.rst b/src/doc/en/reference/quadratic_forms/index.rst index 7169e7ac503..e553ecd1b82 100644 --- a/src/doc/en/reference/quadratic_forms/index.rst +++ b/src/doc/en/reference/quadratic_forms/index.rst @@ -6,6 +6,7 @@ Quadratic Forms sage/quadratic_forms/quadratic_form sage/quadratic_forms/binary_qf + sage/quadratic_forms/bqf_class_group sage/quadratic_forms/constructions sage/quadratic_forms/random_quadraticform sage/quadratic_forms/special_values diff --git a/src/sage/quadratic_forms/all.py b/src/sage/quadratic_forms/all.py index 3445705978a..81d395f375c 100644 --- a/src/sage/quadratic_forms/all.py +++ b/src/sage/quadratic_forms/all.py @@ -1,5 +1,7 @@ from .binary_qf import BinaryQF, BinaryQF_reduced_representatives +from .bqf_class_group import BQFClassGroup + from .ternary_qf import TernaryQF, find_all_ternary_qf_by_level_disc, find_a_ternary_qf_by_level_disc from .quadratic_form import QuadraticForm, DiagonalQuadraticForm, quadratic_form_from_invariants diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index 6516888e3ac..14a1f0049db 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -179,6 +179,101 @@ def _pari_init_(self): """ return 'Qfb(%s,%s,%s)' % (self._a, self._b, self._c) + @staticmethod + def principal(D): + r""" + Return the principal binary quadratic form of the given discriminant. + + EXAMPLES:: + + sage: BinaryQF.principal(8) + x^2 - 2*y^2 + sage: BinaryQF.principal(5) + x^2 + x*y - y^2 + sage: BinaryQF.principal(4) + x^2 - y^2 + sage: BinaryQF.principal(1) + x^2 + x*y + sage: BinaryQF.principal(-3) + x^2 + x*y + y^2 + sage: BinaryQF.principal(-4) + x^2 + y^2 + sage: BinaryQF.principal(-7) + x^2 + x*y + 2*y^2 + sage: BinaryQF.principal(-8) + x^2 + 2*y^2 + + TESTS: + + Some randomized testing:: + + sage: D = 1 + sage: while D.is_square(): + ....: D = choice((-4,+4)) * randrange(9999) + randrange(2) + sage: Q = BinaryQF.principal(D) + sage: Q.discriminant() == D # correct discriminant + True + sage: (Q*Q).is_equivalent(Q) # idempotent (hence identity) + True + """ + D = ZZ(D) + D4 = D % 4 + if D4 not in (0,1): + raise ValueError('discriminant must be congruent to 0 or 1 modulo 4') + return BinaryQF([1, D4, (D4-D)//4]) + + @staticmethod + def random(D): + r""" + Return a somewhat random primitive binary quadratic form of the + given discriminant. + + (In the case `D < 0`, only positive definite forms are returned.) + + .. NOTE:: + + No guarantees are being made about the distribution of forms + sampled by this function. + + EXAMPLES:: + + sage: BinaryQF.random(5) # random + 448219*x^2 - 597179*x*y + 198911*y^2 + sage: BinaryQF.random(-7) # random + 10007*x^2 + 10107*x*y + 2552*y^2 + + TESTS:: + + sage: D = choice((-4,+4)) * randrange(9999) + randrange(2) or 1 + sage: Q = BinaryQF.random(D) + sage: Q.discriminant() == D + True + sage: Q.is_primitive() + True + sage: Q.is_indefinite() or Q.is_positive_definite() + True + """ + D = ZZ(D) + D4 = D % 4 + if D4 not in (0,1): + raise ValueError('discriminant must be congruent to 0 or 1 modulo 4') + + from sage.misc.prandom import randrange + from sage.misc.misc_c import prod + from sage.matrix.special import random_matrix + B = (D.abs() or 1) * 99 # kind of arbitrary + while True: + b = randrange(D4, B, 2) + ac = (b**2 - D) // 4 + if ac: + break + a = prod(l**randrange(e+1) for l,e in ac.factor()) + a = a.prime_to_m_part(gcd([a, b, ac//a])) + c = ac // a + M = random_matrix(ZZ, 2, 2, 'unimodular') + M.rescale_row(0, (-1)**randrange(2)) + return BinaryQF([a, b, c]) * M + def __mul__(self, right): """ Gauss composition or right action by a 2x2 integer matrix. @@ -1706,6 +1801,23 @@ def solve_integer(self, n, *, algorithm="general"): sol = self.__pari__().qfbsolve(n, flag) return tuple(map(ZZ, sol)) if sol else None + def form_class(self): + r""" + Return the class of this form modulo equivalence. + + EXAMPLES:: + + sage: F = BinaryQF([3, -16, 161]) + sage: cl = F.form_class(); cl + Class of 3*x^2 + 2*x*y + 140*y^2 + sage: cl.parent() + Form Class Group of Discriminant -1676 + sage: cl.parent() is BQFClassGroup(-4*419) + True + """ + from sage.quadratic_forms.bqf_class_group import BQFClassGroup + return BQFClassGroup(self.discriminant())(self) + def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): r""" diff --git a/src/sage/quadratic_forms/bqf_class_group.py b/src/sage/quadratic_forms/bqf_class_group.py new file mode 100644 index 00000000000..58cd10468bf --- /dev/null +++ b/src/sage/quadratic_forms/bqf_class_group.py @@ -0,0 +1,593 @@ +r""" +Class groups of binary quadratic forms + +EXAMPLES: + +Constructing the class of a given binary quadratic form is straightforward:: + + sage: F1 = BinaryQF([22, 91, 99]) + sage: cl1 = F1.form_class(); cl1 + Class of 5*x^2 - 3*x*y + 22*y^2 + +Every class is represented by a reduced form in it:: + + sage: cl1.form() + 5*x^2 - 3*x*y + 22*y^2 + sage: cl1.form() == F1.reduced_form() + True + +Addition of form classes and derived operations are defined by composition +of binary quadratic forms:: + + sage: F2 = BinaryQF([4, 1, 27]) + sage: cl2 = F2.form_class(); cl2 + Class of 4*x^2 + x*y + 27*y^2 + sage: cl1 + cl2 + Class of 9*x^2 + x*y + 12*y^2 + sage: cl1 + cl2 == (F1 * F2).form_class() + True + sage: -cl1 + Class of 5*x^2 + 3*x*y + 22*y^2 + sage: cl1 - cl1 + Class of x^2 + x*y + 108*y^2 + +The form class group can be constructed as an explicit parent object:: + + sage: F1.discriminant() + -431 + sage: Cl = BQFClassGroup(-431); Cl + Form Class Group of Discriminant -431 + sage: cl1.parent() is Cl + True + sage: Cl(F1) == cl1 + True + +Structural properties of the form class group, such as the class number, +the group invariants, and element orders, can be computed:: + + sage: Cl.order() + 21 + sage: cl1 * Cl.order() == Cl.zero() + True + sage: cl2 * Cl.order() == Cl.zero() + True + sage: cl2.order() + 7 + sage: cl2 * cl2.order() == Cl.zero() + True + sage: Cl.abelian_group() + Additive abelian group isomorphic to Z/21 embedded in Form Class Group of Discriminant -431 + sage: Cl.gens() # random + [Class of 5*x^2 + 3*x*y + 22*y^2] + sage: Cl.gens()[0].order() + 21 + +AUTHORS: + +- Lorenz Panny (2023) +""" + +# **************************************************************************** +# Copyright (C) 2023 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.misc.cachefunc import cached_method + +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.element import AdditiveGroupElement + +from sage.misc.prandom import randrange +from sage.rings.integer_ring import ZZ +from sage.groups.generic import order_from_multiple, multiple +from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper +from sage.quadratic_forms.binary_qf import BinaryQF + +from sage.libs.pari import pari + + +class BQFClassGroup(Parent, UniqueRepresentation): + r""" + This type represents the class group for a given discriminant `D`. + + - For `D < 0`, the group is the class group of *positive definite* + binary quadratic forms. The "full" form class group is the direct + sum of two isomorphic copies of this group (one for positive + definite forms and one for negative definite forms). + + - For `D > 0`, this functionality is currently not implemented. + + EXAMPLES:: + + sage: BQFClassGroup(-4) + Form Class Group of Discriminant -4 + sage: BQFClassGroup(-6) + Traceback (most recent call last): + ... + ValueError: not a discriminant + + The discriminant need not be fundamental:: + + sage: BQFClassGroup(-22^2) + Form Class Group of Discriminant -484 + """ + + def __init__(self, D, *, check=True): + r""" + Construct the class group for a given discriminant `D`. + + TESTS: + + Check that positive discriminants are rejected until code is + written for them:: + + sage: BQFClassGroup(101) + Traceback (most recent call last): + ... + NotImplementedError: positive discriminants are not yet supported + """ + self._disc = ZZ(D) + if check: + if not self._disc or self._disc % 4 not in (0,1): + raise ValueError('not a discriminant') + if self._disc > 0: + raise NotImplementedError('positive discriminants are not yet supported') + super().__init__() + + def _element_constructor_(self, F, *, check=True): + r""" + Construct an element of this form class group as a :class:`BQFClassGroup_element`. + + EXAMPLES:: + + sage: Cl = BQFClassGroup(-999) + sage: Cl(0) # indirect doctest + Class of x^2 + x*y + 250*y^2 + sage: Cl(BinaryQF([16, 5, 16])) # indirect doctest + Class of 16*x^2 + 5*x*y + 16*y^2 + """ + if isinstance(F, BQFClassGroup_element): + if check and F.parent() is not self: # class group is unique parent + raise ValueError('quadratic form has incorrect discriminant') + return F + if F == 0: + return self.zero() + if check and not isinstance(F, BinaryQF): + raise TypeError('not a binary quadratic form') + return BQFClassGroup_element(F, parent=self, check=check) + + def zero(self): + r""" + Return the neutral element of this group, i.e., the class of the + principal binary quadratic form of the respective discriminant. + + EXAMPLES:: + + sage: Cl = BQFClassGroup(-999) + sage: cl = Cl.zero(); cl + Class of x^2 + x*y + 250*y^2 + sage: cl + cl == cl + True + """ + return self(BinaryQF.principal(self._disc)) + + def random_element(self): + r""" + Return a somewhat random element of this form class group. + + ALGORITHM: :meth:`BinaryQF.random` + + .. NOTE:: + + No guarantees are being made about the distribution of classes + sampled by this function. Heuristically, however, it should be + fairly close to uniform. + + EXAMPLES:: + + sage: Cl = BQFClassGroup(-999); Cl + Form Class Group of Discriminant -999 + sage: cl = Cl.random_element(); cl # random + Class of 10*x^2 + x*y + 25*y^2 + sage: cl.form().discriminant() + -999 + """ + return self(BinaryQF.random(self._disc)) + + def __hash__(self): + r""" + Return a hash value for this form class group. + + EXAMPLES:: + + sage: hash(BQFClassGroup(-999)) # random + -4246560339810542104 + """ + return hash(('BQFClassGroup', self._disc)) + + def _repr_(self): + r""" + Return a string describing this form class group. + + EXAMPLES:: + + sage: BQFClassGroup(-999) # indirect doctest + Form Class Group of Discriminant -999 + """ + return f'Form Class Group of Discriminant {self._disc}' + + def discriminant(self): + r""" + Return the discriminant of the forms in this form class group. + + EXAMPLES:: + + sage: BQFClassGroup(-999).discriminant() + -999 + """ + return self._disc + + @cached_method + def order(self): + r""" + Return the order of this form class group (the *class number*). + + ALGORITHM: :pari:`qfbclassno` + + EXAMPLES:: + + sage: BQFClassGroup(-4).order() + 1 + sage: BQFClassGroup(-11).order() + 1 + sage: BQFClassGroup(-67).order() + 1 + sage: BQFClassGroup(-163).order() + 1 + sage: BQFClassGroup(-999).order() + 24 + sage: BQFClassGroup(-9999).order() + 88 + sage: BQFClassGroup(-99999).order() + 224 + """ + return ZZ(pari.qfbclassno(self._disc)) + + cardinality = order + + @cached_method + def abelian_group(self): + r""" + Return the structure of this form class group as an + :class:`AdditiveAbelianGroupWrapper` object. + + ALGORITHM: :pari:`quadclassunit` + + EXAMPLES:: + + sage: Cl = BQFClassGroup(-4*777) + sage: Cl.order() + 16 + sage: G = Cl.abelian_group(); G + Additive abelian group isomorphic to Z/4 + Z/2 + Z/2 embedded in Form Class Group of Discriminant -3108 + sage: G.gens() # random + (Class of 11*x^2 + 4*x*y + 71*y^2, + Class of 6*x^2 + 6*x*y + 131*y^2, + Class of 2*x^2 + 2*x*y + 389*y^2) + sage: [g.order() for g in G.gens()] + [4, 2, 2] + sage: G.discrete_log(Cl.random_element()) # random + (3, 0, 1) + """ + h, ords, gens, reg = pari.quadclassunit(self._disc) + ords = [ZZ(o) for o in ords] + gens = [BinaryQF(g) for g in gens] + return AdditiveAbelianGroupWrapper(self, gens, ords) + + def gens(self): + r""" + Return a generating set of this form class group. + + EXAMPLES:: + + sage: Cl = BQFClassGroup(-4*419) + sage: Cl.gens() + [Class of 3*x^2 + 2*x*y + 140*y^2] + + :: + + sage: Cl = BQFClassGroup(-4*777) + sage: Cl.gens() # random + [Class of 11*x^2 + 4*x*y + 71*y^2, + Class of 6*x^2 + 6*x*y + 131*y^2, + Class of 2*x^2 + 2*x*y + 389*y^2] + """ + return [g.element() for g in self.abelian_group().gens()] + + +class BQFClassGroup_element(AdditiveGroupElement): + r""" + This type represents elements of class groups of binary quadratic forms. + + Users should not need to construct objects of this type directly; it can + be accessed via either the :class:`BQFClassGroup` parent object or the + :meth:`~BinaryQF.form_class` method associated to binary quadratic forms. + + Currently only classes of positive definite forms are supported. + + EXAMPLES:: + + sage: F = BinaryQF([22, 91, 99]) + sage: F.form_class() # implicit doctest + Class of 5*x^2 - 3*x*y + 22*y^2 + + :: + + sage: Cl = BQFClassGroup(-4*419) + sage: Cl.zero() + Class of x^2 + 419*y^2 + sage: Cl.gens()[0] # implicit doctest + Class of 3*x^2 + 2*x*y + 140*y^2 + """ + + def __init__(self, F, parent, *, check=True, reduce=True): + r""" + Constructor for classes of binary quadratic forms. + + EXAMPLES:: + + sage: Cl = BQFClassGroup(-431) + sage: F = BinaryQF([22, 91, 99]) + sage: from sage.quadratic_forms.bqf_class_group import BQFClassGroup_element + sage: BQFClassGroup_element(F, parent=Cl) + Class of 5*x^2 - 3*x*y + 22*y^2 + """ + if check: + if not isinstance(F, BinaryQF): + raise TypeError('not a binary quadratic form') + if F.discriminant() != parent.discriminant(): + raise ValueError('given quadratic form has wrong discriminant') + if not F.is_primitive(): + raise ValueError('given quadratic form is not primitive') + if not F.is_positive_definite(): + raise NotImplemented('only positive definite forms are currently supported') + if reduce: + F = F.reduced_form() + self._form = F + super().__init__(parent=parent) + + def form(self): + r""" + Return a reduced quadratic form in this class. + + (For `D < 0`, each class contains a *unique* reduced form.) + + EXAMPLES:: + + sage: F = BinaryQF([3221, 2114, 350]) + sage: cl = F.form_class() + sage: cl.form() + 29*x^2 + 14*x*y + 350*y^2 + sage: cl.form() == F.reduced_form() + True + """ + return self._form + + def _neg_(self): + r""" + Return the inverse of this form class. + + The inverse class of a form `[a,b,c]` is represented by `[a,-b,c]`. + + EXAMPLES:: + + sage: F = BinaryQF([11,21,31]) + sage: cl = F.form_class(); cl + Class of 11*x^2 - x*y + 21*y^2 + sage: -cl # indirect doctest + Class of 11*x^2 + x*y + 21*y^2 + sage: cl + (-cl) == cl.parent().zero() # indirect doctest + True + """ + a,b,c = self._form + F = BinaryQF([a,-b,c]) + return BQFClassGroup_element(F, parent=self.parent()) + + def _add_(self, other): + r""" + Return the composition of two form classes. + + EXAMPLES:: + + sage: cl1 = BinaryQF([11,21,31]).form_class(); cl1 + Class of 11*x^2 - x*y + 21*y^2 + sage: cl2 = BinaryQF([7,55,141]).form_class(); cl2 + Class of 7*x^2 - x*y + 33*y^2 + sage: cl1 + cl2 # indirect doctest + Class of 3*x^2 + x*y + 77*y^2 + """ + F = self._form * other._form + return BQFClassGroup_element(F, parent=self.parent()) + + def _sub_(self, other): + r""" + Return the composition of a form class with the inverse of another. + + EXAMPLES:: + + sage: cl1 = BinaryQF([11,21,31]).form_class(); cl1 + Class of 11*x^2 - x*y + 21*y^2 + sage: cl2 = BinaryQF([7,55,141]).form_class(); cl2 + Class of 7*x^2 - x*y + 33*y^2 + sage: cl1 - cl2 # indirect doctest + Class of 9*x^2 - 7*x*y + 27*y^2 + sage: cl1 - cl2 == cl1 + (-cl2) # indirect doctest + True + """ + return self + (-other) + + def __mul__(self, other): + r""" + Return an integer multiple of this form class with respect to + repeated composition. + + ALGORITHM: :func:`multiple` + + EXAMPLES:: + + sage: F = BinaryQF([11,21,31]) + sage: cl = F.form_class(); cl + Class of 11*x^2 - x*y + 21*y^2 + sage: cl*0 == cl.parent().zero() # indirect doctest + True + sage: cl*1 == cl # indirect doctest + True + sage: cl*(-1) == -cl # indirect doctest + True + sage: cl*2 == cl + cl # indirect doctest + True + sage: cl*5 == cl + cl + cl + cl + cl # indirect doctest + True + sage: 5*cl == cl*5 # indirect doctest + True + sage: cl*(-5) == -(5*cl) # indirect doctest + True + """ + return multiple(self, other, operation='+') + + __rmul__ = __mul__ + + def __eq__(self, other): + r""" + Test two form classes for equality. + + EXAMPLES:: + + sage: F = BinaryQF([11,21,31]) + sage: cl = F.form_class(); cl + Class of 11*x^2 - x*y + 21*y^2 + sage: cl == cl # indirect doctest + True + sage: -cl == cl # indirect doctest + False + """ + # When generalizing to positive discriminants in the future, keep + # in mind that for indefinite forms there can be multiple reduced + # forms per class. This also affects the other comparison methods + # as well as hashing. + return self._form == other._form + + def __ne__(self, other): + r""" + Test two form classes for inequality. + + EXAMPLES:: + + sage: F = BinaryQF([11,21,31]) + sage: cl = F.form_class(); cl + Class of 11*x^2 - x*y + 21*y^2 + sage: cl != cl # indirect doctest + False + sage: -cl != cl # indirect doctest + True + """ + return self._form != other._form + + def __lt__(self, other): + r""" + Compare two form classes according to the lexicographic ordering + on their coefficient lists. + + EXAMPLES:: + + sage: cl1 = BinaryQF([7,55,141]).form_class(); cl1 + Class of 7*x^2 - x*y + 33*y^2 + sage: cl2 = BinaryQF([11,21,31]).form_class(); cl2 + Class of 11*x^2 - x*y + 21*y^2 + sage: cl1 < cl2 # indirect doctest + True + sage: cl1 > cl2 # indirect doctest + False + """ + return self._form < other._form + + def __bool__(self): + r""" + Return ``True`` if this form class is *not* the principal class + and ``False`` otherwise. + + EXAMPLES:: + + sage: cl = BinaryQF([11,21,31]).form_class() + sage: bool(cl) + True + sage: bool(0*cl) + False + """ + return self != self.parent().zero() + + def is_zero(self): + r""" + Return ``True`` if this form class is the principal class and + ``False`` otherwise. + + EXAMPLES:: + + sage: cl = BinaryQF([11,21,31]).form_class() + sage: cl.is_zero() + False + sage: (0*cl).is_zero() + True + """ + return not self + + def __repr__(self): + r""" + Return a string representation of this form class. + + EXAMPLES:: + + sage: F = BinaryQF([11,21,31]) + sage: F.form_class() # indirect doctest + Class of 11*x^2 - x*y + 21*y^2 + """ + return f'Class of {self._form}' + + def __hash__(self): + r""" + Return a hash value for this form class. + + EXAMPLES:: + + sage: cl = BinaryQF([11,21,31]).form_class() + sage: hash(cl) # random + -7760578299759721732 + """ + return hash(('BQFClassGroup_element', self._form)) + + @cached_method + def order(self): + r""" + Return the order of this form class in its class group. + + ALGORITHM: :meth:`BQFClassGroup.order` and :func:`order_from_multiple` + + EXAMPLES:: + + sage: cl = BinaryQF([11,21,31]).form_class() + sage: cl.order() + 10 + sage: (cl+cl).order() + 5 + sage: (cl+cl+cl).order() + 10 + sage: (5*cl).order() + 2 + """ + return order_from_multiple(self, self.parent().cardinality()) From 7c0a6c7e976fa5436c246842b20a9b5c5bbc5698 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 4 Sep 2023 19:35:26 +0200 Subject: [PATCH 106/538] remove BinaryQF.random() since its distribution was far from uniform on classes --- src/sage/quadratic_forms/binary_qf.py | 52 --------------------- src/sage/quadratic_forms/bqf_class_group.py | 25 ++++++++-- 2 files changed, 20 insertions(+), 57 deletions(-) diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index 14a1f0049db..ade5cf1561e 100755 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -222,58 +222,6 @@ def principal(D): raise ValueError('discriminant must be congruent to 0 or 1 modulo 4') return BinaryQF([1, D4, (D4-D)//4]) - @staticmethod - def random(D): - r""" - Return a somewhat random primitive binary quadratic form of the - given discriminant. - - (In the case `D < 0`, only positive definite forms are returned.) - - .. NOTE:: - - No guarantees are being made about the distribution of forms - sampled by this function. - - EXAMPLES:: - - sage: BinaryQF.random(5) # random - 448219*x^2 - 597179*x*y + 198911*y^2 - sage: BinaryQF.random(-7) # random - 10007*x^2 + 10107*x*y + 2552*y^2 - - TESTS:: - - sage: D = choice((-4,+4)) * randrange(9999) + randrange(2) or 1 - sage: Q = BinaryQF.random(D) - sage: Q.discriminant() == D - True - sage: Q.is_primitive() - True - sage: Q.is_indefinite() or Q.is_positive_definite() - True - """ - D = ZZ(D) - D4 = D % 4 - if D4 not in (0,1): - raise ValueError('discriminant must be congruent to 0 or 1 modulo 4') - - from sage.misc.prandom import randrange - from sage.misc.misc_c import prod - from sage.matrix.special import random_matrix - B = (D.abs() or 1) * 99 # kind of arbitrary - while True: - b = randrange(D4, B, 2) - ac = (b**2 - D) // 4 - if ac: - break - a = prod(l**randrange(e+1) for l,e in ac.factor()) - a = a.prime_to_m_part(gcd([a, b, ac//a])) - c = ac // a - M = random_matrix(ZZ, 2, 2, 'unimodular') - M.rescale_row(0, (-1)**randrange(2)) - return BinaryQF([a, b, c]) * M - def __mul__(self, right): """ Gauss composition or right action by a 2x2 integer matrix. diff --git a/src/sage/quadratic_forms/bqf_class_group.py b/src/sage/quadratic_forms/bqf_class_group.py index 58cd10468bf..185a869b8b2 100644 --- a/src/sage/quadratic_forms/bqf_class_group.py +++ b/src/sage/quadratic_forms/bqf_class_group.py @@ -85,6 +85,8 @@ from sage.misc.prandom import randrange from sage.rings.integer_ring import ZZ +from sage.rings.finite_rings.integer_mod import Mod +from sage.arith.misc import random_prime from sage.groups.generic import order_from_multiple, multiple from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper from sage.quadratic_forms.binary_qf import BinaryQF @@ -181,13 +183,17 @@ def random_element(self): r""" Return a somewhat random element of this form class group. - ALGORITHM: :meth:`BinaryQF.random` + ALGORITHM: + + Sample random odd primes `a` until `b^2 = D \pmod{4a}` has a + solution `b \in \ZZ` and set `c = (b^2-D)/(4a)`. Flip a coin + to choose the sign of `b`. Then return the class of `[a,b,c]`. .. NOTE:: - No guarantees are being made about the distribution of classes - sampled by this function. Heuristically, however, it should be - fairly close to uniform. + No strict guarantees are being made about the distribution of + classes sampled by this function. Heuristically, however, it + should be fairly close to uniform. EXAMPLES:: @@ -198,7 +204,16 @@ def random_element(self): sage: cl.form().discriminant() -999 """ - return self(BinaryQF.random(self._disc)) + B = self._disc.abs() * 100 + 9999 + while True: + a = random_prime(B, proof=False, lbound=3) + if self._disc.kronecker(a) == 1: + break + b = ZZ(Mod(self._disc, 4*a).sqrt()) + c = (b**2 - self._disc) // (4*a) + if randrange(2): + b = -b + return self(BinaryQF([a,b,c])) def __hash__(self): r""" From 3c9c4c9812d86ccdbff782cd980a4daa10379236 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Thu, 2 Nov 2023 10:56:47 +0000 Subject: [PATCH 107/538] Allow to specify output directory for generated interpreters --- src/sage_setup/autogen/__init__.py | 4 +++- src/sage_setup/autogen/interpreters/__main__.py | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/sage_setup/autogen/__init__.py b/src/sage_setup/autogen/__init__.py index 6a0a6fdc5da..380983c06c7 100644 --- a/src/sage_setup/autogen/__init__.py +++ b/src/sage_setup/autogen/__init__.py @@ -1,6 +1,7 @@ import os + from . import interpreters -from sage.env import SAGE_SRC + def autogen_all(): """ @@ -9,6 +10,7 @@ def autogen_all(): Return a list of sub-packages that should be appended to the list of packages built/installed by setup.py. """ + from sage.env import SAGE_SRC interpreters.rebuild(os.path.join(SAGE_SRC, "sage", "ext", "interpreters")) return ['sage.ext.interpreters'] diff --git a/src/sage_setup/autogen/interpreters/__main__.py b/src/sage_setup/autogen/interpreters/__main__.py index fa78a6ab9b8..de07210db06 100644 --- a/src/sage_setup/autogen/interpreters/__main__.py +++ b/src/sage_setup/autogen/interpreters/__main__.py @@ -1,9 +1,18 @@ -from __future__ import print_function, absolute_import +from __future__ import absolute_import, print_function +import argparse import os -from sage.env import SAGE_SRC from . import rebuild +parser = argparse.ArgumentParser() +parser.add_argument("output_dir") +args = parser.parse_args() -rebuild(os.path.join(SAGE_SRC, "sage", "ext", "interpreters")) +output_dir = args.output_dir +if not output_dir: + from sage.env import SAGE_SRC + output_dir = os.path.join(SAGE_SRC, "sage", "ext", "interpreters") + + +rebuild(output_dir) From d47aebf2854e65a70a6c0d6bc1c4559bb9122644 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 2 Nov 2023 14:25:59 +0100 Subject: [PATCH 108/538] reviewer comments --- src/sage/schemes/elliptic_curves/mod_poly.py | 35 +++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/mod_poly.py b/src/sage/schemes/elliptic_curves/mod_poly.py index c034bed50aa..50fd1108e91 100644 --- a/src/sage/schemes/elliptic_curves/mod_poly.py +++ b/src/sage/schemes/elliptic_curves/mod_poly.py @@ -21,6 +21,7 @@ from sage.databases.db_modular_polynomials import ClassicalModularPolynomialDatabase _db = ClassicalModularPolynomialDatabase() +_cache_bound = 100 _cache = dict() def classical_modular_polynomial(l, j=None): @@ -32,16 +33,17 @@ def classical_modular_polynomial(l, j=None): Generic polynomials are cached up to a certain size of `\ell`, which significantly accelerates subsequent invocations with the - same `\ell`. The default bound is `\ell \leq 150`, which can be - adjusted by setting ``classical_modular_polynomial.cache_bound`` - to a different value. Beware that modular polynomials are very - large and the amount of memory consumed by the cache will grow - rapidly when the bound is set to a large value. + same `\ell`. The default bound is `\ell \leq 100`, which can be + adjusted using ``classical_modular_polynomial.set_cache_bound()`` + with a different value. Beware that modular polynomials are very + big objects and the amount of memory consumed by the cache will + grow rapidly when the bound is set to a large value. INPUT: - ``l`` -- positive integer. - ``j`` -- either ``None`` or a ring element: + * if ``None`` is given, the original modular polynomial is returned as an element of `\ZZ[X,Y]` * if a ring element `j \in R` is given, the evaluation @@ -62,6 +64,20 @@ def classical_modular_polynomial(l, j=None): sage: classical_modular_polynomial(3, j) Y^4 + 230*Y^3 + 84*Y^2 + 118*Y + 329 + Increasing the cache size can be useful for repeated invocations:: + + sage: %timeit classical_modular_polynomial(101) # random + 6.11 s ± 1.21 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) + sage: %timeit classical_modular_polynomial(101, GF(65537).random_element()) # random + 5.43 s ± 2.71 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) + + sage: classical_modular_polynomial.set_cache_bound(150) + sage: %timeit classical_modular_polynomial(101) # random + The slowest run took 10.35 times longer than the fastest. This could mean that an intermediate result is being cached. + 1.84 µs ± 1.84 µs per loop (mean ± std. dev. of 7 runs, 1 loop each) + sage: %timeit classical_modular_polynomial(101, GF(65537).random_element()) # random + 59.8 ms ± 29.4 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) + TESTS:: sage: q = random_prime(50)^randrange(1,4) @@ -92,7 +108,7 @@ def classical_modular_polynomial(l, j=None): d = {(i, j): c for i,f in enumerate(pari_Phi) for j, c in enumerate(f)} Phi = ZZ['X,Y'](d) - if l <= classical_modular_polynomial.cache_bound: + if l <= _cache_bound: _cache[l] = Phi return Phi @@ -109,7 +125,7 @@ def classical_modular_polynomial(l, j=None): except ValueError: pass else: - if l <= classical_modular_polynomial.cache_bound: + if l <= _cache_bound: _cache[l] = ZZ['X,Y'](Phi) return Phi(j, Y) @@ -127,4 +143,7 @@ def classical_modular_polynomial(l, j=None): # and simply evaluating it. return classical_modular_polynomial(l)(j, Y) -classical_modular_polynomial.cache_bound = 150 +def _set_cache_bound(bnd): + global _cache_bound + _cache_bound = bnd +classical_modular_polynomial.set_cache_bound = _set_cache_bound From 4ef28839c726a495332aca4d254a6c5925a58ee6 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 2 Nov 2023 17:16:46 +0100 Subject: [PATCH 109/538] doctests for change_ring in ideal_py and __contains_ in laurent_polynomial_ideal --- src/sage/rings/polynomial/ideal.py | 10 +++---- .../polynomial/laurent_polynomial_ideal.py | 26 ++++++++----------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index e61b6de3f39..9719c81ba41 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -92,11 +92,9 @@ def change_ring(self, R): EXAMPLES:: - sage: P. = LaurentPolynomialRing(QQ, 2) - sage: I = P.ideal([x + y]) - sage: Q. = LaurentPolynomialRing(QQ, 3) - sage: I.change_ring(Q) - Ideal (x + y) of Multivariate Laurent Polynomial Ring in x, y, z - over Rational Field + sage: R. = QQ[] + sage: I = R.ideal([q^2+q-1]) + sage: I.change_ring(RR['q']) + Principal ideal (q^2 + q - 1.00000000000000) of Univariate Polynomial Ring in q over Real Field with 53 bits of precision """ return R.ideal(self.gens()) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 4cf7b8b3414..924ce7ed7d3 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -23,6 +23,7 @@ # **************************************************************************** from sage.rings.ideal import Ideal_generic +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_univariate from sage.structure.richcmp import op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE from sage.arith.misc import GCD @@ -193,28 +194,23 @@ def __contains__(self, f): sage: I = P.ideal([x^2*y + 3*x*y^2]) sage: x + 3*y in I True - sage: P.__contains__(x + 3*y) - True - sage: I.gen(0).__reduce__() - (Multivariate Laurent Polynomial Ring in x, y over Rational Field, - (x^2*y + 3*x*y^2, (0, 0))) + + We test that these changes allow to use this method in the inivariate case. + + TESTS:: + sage: P. = LaurentPolynomialRing(QQ) sage: I = P.ideal([x^2 + 3*x]) sage: 1 + 3*x^-1 in I True - sage: P.__contains__(1 + 3*x^-1) - True - sage: I.gen(0).__reduce__() # Check the differences of __reduce__ for distinct Laurent polynomial rings - (, - (Univariate Laurent Polynomial Ring in x over Rational Field, x + 3, 1)) """ if not f or f in self.gens(): return True f = self.ring()(f) - if self.ring().ngens() > 1: - g = f.__reduce__()[1][0] - else: + if isinstance(self.ring(), LaurentPolynomialRing_univariate): g = f.__reduce__()[1][1] + else: + g = f.__reduce__()[1][0] return (g in self.polynomial_ideal()) def gens_reduced(self): @@ -356,7 +352,7 @@ def toric_coordinate_change(self, M, forward_hint=True): """ if forward_hint: R = self.ring() - apply_to_hint = lambda x, M=M, R=R: R(x).toric_coordinate_change(M).__reduce__()[1][0] + apply_to_hint = lambda x, M=M, R=R: R(x).toric_coordinate_change(M).monomial_reduction()[0] else: apply_to_hint = None return self.apply_map(lambda x, M=M: x.toric_coordinate_change(M), @@ -443,7 +439,7 @@ def polynomial_ideal(self, saturate=True): """ P = self.ring() Q = self._poly_ring - if len(P.gens()) == 1: + if isinstance(self.ring(), LaurentPolynomialRing_univariate): a = [Q(p.polynomial_construction()[0]) for p in self.gens()] if P.base_ring().is_field(): a = GCD(a) From 7030a05215a9178259241cae21ece3288e1acbc3 Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Thu, 2 Nov 2023 19:05:01 +0100 Subject: [PATCH 110/538] change in monomial_reduction --- src/sage/rings/polynomial/laurent_polynomial_mpair.pyx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx index 9cf123b5a52..c0fd659591f 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial_mpair.pyx @@ -1534,17 +1534,17 @@ cdef class LaurentPolynomial_mpair(LaurentPolynomial): sage: R. = LaurentPolynomialRing(QQ) sage: f = y / x + x^2 / y + 3 * x^4 * y^-2 sage: f.monomial_reduction() - (3*x^5 + x^3*y + y^3, 1/(x*y^2)) + (3*x^5 + x^3*y + y^3, x^-1*y^-2) sage: f = y * x + x^2 / y + 3 * x^4 * y^-2 sage: f.monomial_reduction() - (3*x^3 + y^3 + x*y, x/y^2) + (3*x^3 + y^3 + x*y, x*y^-2) sage: x.monomial_reduction() (1, x) sage: (y^-1).monomial_reduction() - (1, 1/y) + (1, y^-1) """ self._normalize() - ring = self._parent._R + ring = self._parent g = ring.gens() mon = ring.prod(g[i] ** j for i, j in enumerate(self._mon)) return (self._poly, mon) From 650e0606748e57db9773a0f3e8201082771aae5d Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Fri, 3 Nov 2023 11:52:18 +0100 Subject: [PATCH 111/538] some cases missing in characteristic varieties --- src/sage/groups/finitely_presented.py | 35 +++++++++++++++++++++------ 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index a961df9a4c5..a351e544ce7 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1703,12 +1703,18 @@ def abelian_alexander_matrix(self, ring=QQ, simplified=True): sage: g = FreeGroup(1) / [] sage: g.abelian_alexander_matrix() ([], []) + sage: g.abelian_alexander_matrix()[0].base_ring() + Univariate Laurent Polynomial Ring in f1 over Rational Field sage: g = FreeGroup(0) / [] - sage: g.abelian_alexander_matrix() - ([], []) + sage: A, ideal = g.abelian_alexander_matrix(); A + [] + sage: A.base_ring() + Rational Field """ ab, R, ideal, images = self.abelianization_to_algebra(ring=ring) A = self.alexander_matrix(im_gens=images) + if A.base_ring() != R: + A = A.change_ring(R) if simplified: n, m = A.dimensions() if n == 0 or m == 0: @@ -1794,8 +1800,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): sage: G.characteristic_varieties() {0: Ideal (0) of Univariate Laurent Polynomial Ring in f2 over Rational Field, 1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 2: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field, - 3: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} + 2: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field} sage: G.characteristic_varieties(groebner=True) {0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: []} sage: G = FreeGroup(2)/[3 * (1, ), 2 * (2, )] @@ -1804,7 +1809,17 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): sage: G = FreeGroup(2)/[2 * (2, )] sage: G.characteristic_varieties(groebner=True) {0: [(f1 + 1,), (f1 - 1,)], 1: [(f1 + 1,), (f1 - 1, f2 - 1)], 2: []} + sage: G = (FreeGroup(0) / []) + sage: G.characteristic_varieties() + {0: Principal ideal (0) of Rational Field, + 1: Principal ideal (1) of Rational Field} + sage: G.characteristic_varieties(groebner=True) + {0: [(0,)], 1: [(1,)]} """ + if self.ngens() == 0: + if groebner: + return {j: [(ring(j),)] for j in (0, 1)} + return {j: ring.ideal(j) for j in (0, 1)} A, rels = self.abelian_alexander_matrix(ring=ring, simplified=True) R = A.base_ring() eval_1 = {x: ring(1) for x in R.gens()} @@ -1816,7 +1831,8 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): K = R.base_ring() id_rels = R.ideal(rels) res = dict() - for j in range(n + 2): + bound = n + 1 + for j in range(bound + 1): J = id_rels + A.fitting_ideal(j) # J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens()) if j <= n1: @@ -1824,14 +1840,17 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): if J1: J *= ideal_1 res[j] = R.ideal(J.gens_reduced()) + if R(1) in res[j].gens(): + bound = j + break if not groebner or not ring.is_field(): return res if R.ngens() == 1: - res = {j: gcd(S(p) for p in res[j].gens()) for j in range(n + 2)} + res = {j: gcd(S(p) for p in res[j].gens()) for j in range(bound + 1)} char_var = dict() strict = True j = 0 - while strict and j <= n + 1: + while strict and j <= bound: if res[j] == 0: char_var[j] = [R(0)] else: @@ -1846,7 +1865,7 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False): char_var = dict() strict = True j = 0 - while strict and j <= n + 1: + while strict and j <= bound: LJ = res[j].minimal_associated_primes() fct = [id.groebner_basis() for id in LJ] char_var[j] = fct From a508ff91840b6bf4ca69ec82c96541741a1c62ff Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sat, 30 Sep 2023 08:21:59 +0200 Subject: [PATCH 112/538] always return .scaling_factor() in base field for EllipticCurveIsogeny --- src/sage/schemes/elliptic_curves/ell_curve_isogeny.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index cccfce646b3..192334f73ba 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -2838,11 +2838,18 @@ def scaling_factor(self): sage: phi.dual().scaling_factor() 43 + TESTS: + + Check for :issue:`36638`:: + + sage: phi.scaling_factor().parent() # needs sage.rings.finite_rings + Finite Field in z2 of size 257^2 + ALGORITHM: The "inner" isogeny is normalized by construction, so we only need to account for the scaling factors of a pre- and post-isomorphism. """ - sc = Integer(1) + sc = self.__base_field.one() if self.__pre_isomorphism is not None: sc *= self.__pre_isomorphism.scaling_factor() if self.__post_isomorphism is not None: From 372ed15b03b92f273c8fab6d56f585926ee6207a Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 3 Nov 2023 13:52:55 +0100 Subject: [PATCH 113/538] add and fix doctests --- src/sage/schemes/elliptic_curves/mod_poly.py | 27 ++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/mod_poly.py b/src/sage/schemes/elliptic_curves/mod_poly.py index 50fd1108e91..88af6185a7b 100644 --- a/src/sage/schemes/elliptic_curves/mod_poly.py +++ b/src/sage/schemes/elliptic_curves/mod_poly.py @@ -66,16 +66,16 @@ def classical_modular_polynomial(l, j=None): Increasing the cache size can be useful for repeated invocations:: - sage: %timeit classical_modular_polynomial(101) # random + sage: %timeit classical_modular_polynomial(101) # not tested 6.11 s ± 1.21 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) - sage: %timeit classical_modular_polynomial(101, GF(65537).random_element()) # random + sage: %timeit classical_modular_polynomial(101, GF(65537).random_element()) # not tested 5.43 s ± 2.71 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) - sage: classical_modular_polynomial.set_cache_bound(150) - sage: %timeit classical_modular_polynomial(101) # random + sage: classical_modular_polynomial.set_cache_bound(150) # not tested + sage: %timeit classical_modular_polynomial(101) # not tested The slowest run took 10.35 times longer than the fastest. This could mean that an intermediate result is being cached. 1.84 µs ± 1.84 µs per loop (mean ± std. dev. of 7 runs, 1 loop each) - sage: %timeit classical_modular_polynomial(101, GF(65537).random_element()) # random + sage: %timeit classical_modular_polynomial(101, GF(65537).random_element()) # not tested 59.8 ms ± 29.4 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) TESTS:: @@ -144,6 +144,23 @@ def classical_modular_polynomial(l, j=None): return classical_modular_polynomial(l)(j, Y) def _set_cache_bound(bnd): + r""" + Internal helper function to allow setting the caching cutoff for + :func:`classical_modular_polynomial`. + + Exposed as ``classical_modular_polynomial.set_cache_bound()``. + + EXAMPLES:: + + sage: import sage.schemes.elliptic_curves.mod_poly as m + sage: m._cache_bound + 100 + sage: m._set_cache_bound(123) + sage: m._cache_bound + 123 + sage: classical_modular_polynomial.set_cache_bound is m._set_cache_bound + True + """ global _cache_bound _cache_bound = bnd classical_modular_polynomial.set_cache_bound = _set_cache_bound From 5de7eb67e15ddfa193ab78b1ae3c6c0956c257b7 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Mon, 10 Jul 2023 11:28:49 +0200 Subject: [PATCH 114/538] implement sums of elliptic-curve morphisms --- .../en/reference/arithmetic_curves/index.rst | 3 +- src/sage/schemes/elliptic_curves/ell_field.py | 41 +- src/sage/schemes/elliptic_curves/ell_point.py | 7 +- src/sage/schemes/elliptic_curves/hom.py | 58 +- src/sage/schemes/elliptic_curves/hom_sum.py | 644 ++++++++++++++++++ 5 files changed, 737 insertions(+), 16 deletions(-) create mode 100644 src/sage/schemes/elliptic_curves/hom_sum.py diff --git a/src/doc/en/reference/arithmetic_curves/index.rst b/src/doc/en/reference/arithmetic_curves/index.rst index 6ab10dcf1c0..669a05b02a9 100644 --- a/src/doc/en/reference/arithmetic_curves/index.rst +++ b/src/doc/en/reference/arithmetic_curves/index.rst @@ -18,10 +18,11 @@ Maps between them :maxdepth: 1 sage/schemes/elliptic_curves/hom + sage/schemes/elliptic_curves/hom_composite + sage/schemes/elliptic_curves/hom_sum sage/schemes/elliptic_curves/weierstrass_morphism sage/schemes/elliptic_curves/ell_curve_isogeny sage/schemes/elliptic_curves/hom_velusqrt - sage/schemes/elliptic_curves/hom_composite sage/schemes/elliptic_curves/hom_scalar sage/schemes/elliptic_curves/hom_frobenius sage/schemes/elliptic_curves/isogeny_small_degree diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 7dd65c95749..064aeeed78b 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -2049,13 +2049,13 @@ def compute_model(E, name): raise NotImplementedError(f'cannot compute {name} model') -def point_of_order(E, l): +def point_of_order(E, n): r""" Given an elliptic curve `E` over a finite field or a number field - and an integer `\ell \geq 1`, construct a point of order `\ell` on `E`, + and an integer `n \geq 1`, construct a point of order `n` on `E`, possibly defined over an extension of the base field of `E`. - Currently only prime values of `\ell` are supported. + Currently only prime powers `n` are supported. EXAMPLES:: @@ -2070,6 +2070,13 @@ def point_of_order(E, l): sage: P.curve().a_invariants() (1, 2, 3, 4, 5) + :: + + sage: Q = point_of_order(E, 8); Q + (69*x^5 + 24*x^4 + 100*x^3 + 65*x^2 + 88*x + 97 : 65*x^5 + 28*x^4 + 5*x^3 + 45*x^2 + 42*x + 18 : 1) + sage: 8*Q == 0 and 4*Q != 0 + True + :: sage: from sage.schemes.elliptic_curves.ell_field import point_of_order @@ -2078,10 +2085,23 @@ def point_of_order(E, l): (x : -Y : 1) sage: P.base_ring() Number Field in Y with defining polynomial Y^2 - x^3 - 7*x - 7 over its base field + sage: P.base_ring().base_field() + Number Field in x with defining polynomial x^4 + 14*x^2 + 28*x - 49/3 sage: P.order() 3 sage: P.curve().a_invariants() (0, 0, 0, 7, 7) + + :: + + sage: Q = point_of_order(E, 4); Q # random + (x : Y : 1) + sage: Q.base_ring() + Number Field in Y with defining polynomial Y^2 - x^3 - 7*x - 7 over its base field + sage: Q.base_ring().base_field() + Number Field in x with defining polynomial x^6 + 35*x^4 + 140*x^3 - 245*x^2 - 196*x - 735 + sage: Q.order() + 4 """ # Construct the field extension defined by the given polynomial, # in such a way that the result is recognized by Sage as a field. @@ -2094,14 +2114,15 @@ def ffext(poly): return poly.splitting_field(rng.variable_name()) return fld.extension(poly, rng.variable_name()) - l = ZZ(l) - if l == 1: + n = ZZ(n) + if n == 1: return E(0) - if not l.is_prime(): - raise NotImplementedError('composite orders are currently unsupported') + l,m = n.is_prime_power(get_data=True) + if not m: + raise NotImplementedError('only prime-power orders are currently supported') - xpoly = E.division_polynomial(l) + xpoly = E.division_polynomial(n) // E.division_polynomial(n//l) if xpoly.degree() < 1: # supersingular and l == p raise ValueError('curve does not have any points of the specified order') @@ -2116,4 +2137,6 @@ def ffext(poly): xx = FF(xx) EE = E.change_ring(FF) - return EE.lift_x(xx) + pt = EE.lift_x(xx) + pt.set_order(n, check=False) + return pt diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 24908b9743e..db3b8ae52d1 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -1359,9 +1359,10 @@ def set_order(self, value=None, *, multiple=None, check=True): raise ValueError('Value %s illegal for point order' % value) E = self.curve() q = E.base_ring().cardinality() - low, hi = Hasse_bounds(q) - if value > hi: - raise ValueError('Value %s illegal: outside max Hasse bound' % value) + if q < oo: + _, hi = Hasse_bounds(q) + if value > hi: + raise ValueError('Value %s illegal: outside max Hasse bound' % value) if value * self != E(0): raise ValueError('Value %s illegal: %s * %s is not the identity' % (value, value, self)) if hasattr(self, '_order') and self._order != value: # already known diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 995420ae438..fe95bb7e2b3 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_composite.EllipticCurveHom_sum` - :class:`~sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar` - :class:`~sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius` - :class:`~sage.schemes.elliptic_curves.hom_velusqrt.EllipticCurveHom_velusqrt` @@ -134,6 +135,51 @@ def _composition_(self, other, homset): from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite return EllipticCurveHom_composite.from_factors([other, self]) + def _add_(self, other): + r""" + Add two :class:`EllipticCurveHom` objects by constructing a + formal :class:`EllipticCurveHom_sum`. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: phi + phi # indirect doctest + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 + Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101) + """ + from sage.schemes.elliptic_curves.hom_sum import EllipticCurveHom_sum + phis = [] + if isinstance(self, EllipticCurveHom_sum): + phis += self.summands() + else: + phis.append(self) + if isinstance(other, EllipticCurveHom_sum): + phis += other.summands() + else: + phis.append(other) + #TODO should probably try to simplify some more? + return EllipticCurveHom_sum(phis) + + def _sub_(self, other): + r""" + Subtract two :class:`EllipticCurveHom` objects by negating + and constructing a formal :class:`EllipticCurveHom_sum`. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: phi - phi # indirect doctest + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 + Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101) + """ + return self + (-other) + @staticmethod def _comparison_impl(left, right, op): r""" @@ -384,6 +430,7 @@ def kernel_polynomial(self): - :meth:`EllipticCurveIsogeny.kernel_polynomial` - :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.kernel_polynomial` - :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.kernel_polynomial` + - :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.kernel_polynomial` - :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.kernel_polynomial` - :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.kernel_polynomial` @@ -406,6 +453,7 @@ def dual(self): - :meth:`EllipticCurveIsogeny.dual` - :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.dual` - :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.dual` + - :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.dual` - :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.dual` - :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.dual` @@ -430,6 +478,7 @@ def rational_maps(self): - :meth:`EllipticCurveIsogeny.rational_maps` - :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.rational_maps` - :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.rational_maps` + - :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.rational_maps` - :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.rational_maps` - :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.rational_maps` @@ -453,6 +502,7 @@ def x_rational_map(self): - :meth:`EllipticCurveIsogeny.x_rational_map` - :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.x_rational_map` - :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.x_rational_map` + - :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.x_rational_map` - :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.x_rational_map` - :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.x_rational_map` @@ -484,6 +534,7 @@ def scaling_factor(self): - :meth:`EllipticCurveIsogeny.scaling_factor` - :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.scaling_factor` - :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.scaling_factor` + - :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.scaling_factor` - :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.scaling_factor` TESTS:: @@ -634,6 +685,7 @@ def is_separable(self): - :meth:`EllipticCurveIsogeny.is_separable` - :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.is_separable` - :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.is_separable` + - :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.is_separable` - :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.is_separable` - :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.is_separable` @@ -926,11 +978,11 @@ def matrix_on_subgroup(self, domain_gens, codomain_gens=None): if R.weil_pairing(S, n).multiplicative_order() != n: raise ValueError('generator points on codomain are not independent') - imP = self(P) - imQ = self(Q) + imP = self._eval(P) + imQ = self._eval(Q) from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper - H = AdditiveAbelianGroupWrapper(self.codomain().point_homset(), [R,S], [n,n]) + H = AdditiveAbelianGroupWrapper(R.parent(), [R,S], [n,n]) vecP = H.discrete_log(imP) vecQ = H.discrete_log(imQ) diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py new file mode 100644 index 00000000000..cfe6a7e85a6 --- /dev/null +++ b/src/sage/schemes/elliptic_curves/hom_sum.py @@ -0,0 +1,644 @@ +r""" +Sums of morphisms of elliptic curves + +The set `\mathrm{Hom}(E,E')` of morphisms between two elliptic curves +forms an abelian group under pointwise addition. An important special +case is the endomorphism ring `\mathrm{End}(E) = \mathrm{Hom}(E,E)`. +However, it is not immediately obvious how to compute some properties +of the sum `\varphi+\psi` of two isogenies, even when both are given +explicitly. This class provides functionality for representing sums of +elliptic-curve morphisms (in particular, isogenies and endomorphisms) +formally, and explicitly computing important properties (such as the +degree or the kernel polynomial) from the formal representation. + +EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: phi + phi + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 + Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101) + sage: phi + phi == phi * E.scalar_multiplication(2) + True + sage: phi + phi + phi == phi * E.scalar_multiplication(3) + True + +An example of computing with a supersingular endomorphism ring:: + + sage: E = EllipticCurve(GF(419^2), [1,0]) + sage: i = E.automorphisms()[-1] + sage: j = E.frobenius_isogeny() + sage: i * j == - j * i # i,j anticommute + True + sage: (i + j) * i == i^2 - i*j # distributive law + True + sage: (j - E.scalar_multiplication(1)).degree() # point counting! + 420 + +AUTHORS: + +- Lorenz Panny (2023) +""" + +from sage.misc.cachefunc import cached_method +from sage.structure.sequence import Sequence + +from sage.arith.misc import integer_floor, gcd +from sage.functions.other import sqrt + +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring import polygen + +from sage.sets.primes import Primes + +from sage.schemes.elliptic_curves.ell_field import point_of_order +from sage.groups.generic import discrete_log, order_from_multiple + +from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation + + +class EllipticCurveHom_sum(EllipticCurveHom): + + _degree = None + _phis = None + + def __init__(self, phis, domain=None, codomain=None): + r""" + Construct a sum morphism of elliptic curves from its summands. + (For empty sums, the domain and codomain curves must be given.) + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.hom_sum import EllipticCurveHom_sum + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: EllipticCurveHom_sum([phi, phi]) + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 + Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101) + + The zero morphism can be constructed even between non-isogenous curves:: + + sage: E1 = EllipticCurve(GF(101), [5,5]) + sage: E2 = EllipticCurve(GF(101), [7,7]) + sage: E1.is_isogenous(E2) + False + sage: EllipticCurveHom_sum([], E1, E2) + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 7*x + 7 over Finite Field of size 101 + Via: () + """ + phis = tuple(phis) + + if not phis and (domain is None or codomain is None): + raise ValueError('need either phis or both domain and codomain') + + for phi in phis: + if not isinstance(phi, EllipticCurveHom): + raise ValueError(f'not an elliptic-curve morphism: {phi}') + + if domain is None: + domain = phis[0].domain() + if codomain is None: + codomain = phis[0].codomain() + for phi in phis: + if phi.domain() != domain: + raise ValueError(f'summand {phi} has incorrect domain (need {domain})') + if phi.codomain() != codomain: + raise ValueError(f'summand {phi} has incorrect codomain (need {codomain})') + + self._phis = phis + self._domain = domain + self._codomain = codomain + + # We temporarily overwrite the _degree attribute here to prevent the + # EllipticCurveHom constructor from attempting to compute the degree. + self._degree = 0 + EllipticCurveHom.__init__(self, self._domain, self._codomain) + self._degree = None + + def _call_(self, P): + r""" + Evaluate this sum morphism at a point. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: P = E.lift_x(0) + sage: (phi + phi)(P) + (72 : 56 : 1) + sage: (phi - phi)(P) + (0 : 1 : 0) + """ + return sum((phi(P) for phi in self._phis), self._codomain(0)) + + def _eval(self, P): + r""" + Less strict evaluation method for internal use. + + In particular, this can be used to evaluate ``self`` at a + point defined over an extension field. + + INPUT: a sequence of 3 coordinates defining a point on ``self`` + + OUTPUT: the result of evaluating ``self`` at the given point + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: P = E.change_ring(GF(101^2)).lift_x(1) + sage: (phi + phi)._eval(P) + (11 : 15*z2 + 71 : 1) + sage: (phi - phi)._eval(P) + (0 : 1 : 0) + """ + if self._domain.defining_polynomial()(*P): + raise ValueError(f'{P} not on {self._domain}') + k = Sequence(P).universe() + return sum((phi._eval(P) for phi in self._phis), self._codomain.base_extend(k)(0)) + + def _repr_(self): + r""" + Return basic facts about this sum morphism as a string. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: phi + phi # indirect doctest + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 + Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101) + """ + return f'Sum morphism:' \ + f'\n From: {self._domain}' \ + f'\n To: {self._codomain}' \ + f'\n Via: {self._phis}' + + def summands(self): + r""" + Return the individual summands making up this sum morphism. + + EXAMPLES:: + + sage: E = EllipticCurve(j=5) + sage: m2 = E.scalar_multiplication(2) + sage: m3 = E.scalar_multiplication(3) + sage: m2 + m3 + Sum morphism: + From: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + Via: (Scalar-multiplication endomorphism [2] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field, Scalar-multiplication endomorphism [3] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field) + """ + return self._phis + + @cached_method + def to_isogeny_chain(self): + r""" + Convert this formal sum of elliptic-curve morphisms into a + :class:`EllipticCurveHom_composite` object representing the + same morphism. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: (phi + phi).to_isogeny_chain() + Composite morphism of degree 28 = 4*1*7: + From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 + + :: + + sage: p = 419 + sage: E = EllipticCurve(GF(p^2), [1,0]) + sage: iota = E.automorphisms()[2] # sqrt(-1) + sage: pi = E.frobenius_isogeny() # sqrt(-p) + sage: endo = iota + pi + sage: endo.degree() + 420 + sage: endo.to_isogeny_chain() + Composite morphism of degree 420 = 4*1*3*5*7: + From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 419^2 + To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 419^2 + + The decomposition is impossible for the constant zero map:: + + sage: endo = iota*pi + pi*iota + sage: endo.degree() + 0 + sage: endo.to_isogeny_chain() + Traceback (most recent call last): + ... + ValueError: zero morphism cannot be written as a composition of isogenies + + Isomorphisms are supported as well:: + + sage: E = EllipticCurve(j=5); E + Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + sage: m2 = E.scalar_multiplication(2) + sage: m3 = E.scalar_multiplication(3) + sage: (m2 - m3).to_isogeny_chain() + Composite morphism of degree 1 = 1^2: + From: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + sage: (m2 - m3).rational_maps() + (x, -x - y) + """ + deg = self.degree() + if deg.is_zero(): + raise ValueError('zero morphism cannot be written as a composition of isogenies') + + p = self.base_ring().characteristic() + insep = 0 + scalar = 1 #TODO Can we detect scalar factors earlier to save some extensions below? + + ker = [] + for l,m in deg.factor(): + if l == p: # possibly inseparable + try: + P = point_of_order(self.domain(), l**m) + except ValueError: + # supersingular; every p-isogeny is purely inseparable + insep = m + continue + Q = self._eval(P) + u = order_from_multiple(Q, l**m).valuation(l) + if u < m: + pt = l**u * P + pt.set_order(l**(m-u)) + ker.append(pt) + insep = u + continue + +# F = self.domain().division_field(l**m) #FIXME this can be used once #35936 is done; workaround below + F = self.domain().division_polynomial(l**m).splitting_field('X').extension(2,'Y') + + P,Q = self.domain().change_ring(F).torsion_basis(l**m) + if self.is_endomorphism(): + R,S = P,Q + else: + R,S = self.codomain().change_ring(F).torsion_basis(l**m) + M = self.matrix_on_subgroup((P,Q), (R,S)) + g = ZZ(gcd(M.list())).p_primary_part(l) + if g > 1: + scalar *= g + M = (M.change_ring(ZZ) / g).change_ring(M.base_ring()) + K = M.left_kernel_matrix() + for row in K: + u,v = map(ZZ, row) + pt = u*P + v*Q + pt.set_order(row.additive_order()) + ker.append(pt) + + from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + phi = EllipticCurveHom_composite(self.domain(), []) + + if scalar != 1: + phi *= phi.codomain().scalar_multiplication(scalar) + + while ker: + K = ker.pop(0) + + (l,e), = K.order().factor() + for i in reversed(range(e)): + Kl = l**i * K + Kl.set_order(l) + + from sage.groups.generic import multiples + from sage.misc.misc_c import prod + x = polygen(Kl.base_ring()) + poly = prod(x - T.xy()[0] for T in multiples(Kl, l//2, Kl)) + poly = poly.change_ring(self.base_ring()) + + psi = phi.codomain().isogeny(poly) + phi = psi * phi + K = psi._eval(K) + ker = [psi._eval(P) for P in ker] + + if insep: + frob = phi.codomain().frobenius_isogeny(insep) + phi = frob * phi + + from sage.schemes.elliptic_curves.hom import find_post_isomorphism + iso = find_post_isomorphism(phi, self) + return iso * phi + + # EllipticCurveHom methods + + def _degree_bound(self): + r""" + Return an upper bound on the degree of this sum morphism. + + ALGORITHM: Induction using the bound + `|\deg(f+g) - \deg(f) - \deg(g)| \leq 2\sqrt{\deg(f)\cdot\deg(g)}`; + see for instance Lemma V.1.2 of [Sil2009]_. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: (phi + phi)._degree_bound() + 28 + sage: (phi + phi).degree() + 28 + sage: (phi - phi)._degree_bound() + 28 + sage: (phi - phi).degree() + 0 + + :: + + sage: E = EllipticCurve(GF(443), [1,1]) + sage: pi = E.frobenius_endomorphism() + sage: m1 = E.scalar_multiplication(1) + sage: (pi - m1)._degree_bound() + 486 + sage: (pi - m1).degree() + 433 + """ + B = ZZ(0) + for phi in self._phis: + B += phi.degree() + 2*sqrt(B * phi.degree()) + return integer_floor(B) + + def _compute_degree(self): + r""" + Internal method to compute and cache the degree of this sum morphism + (and its dual). + + ALGORITHM: Evaluate the composition with the dual on points of small + order and solve logarithms to eventually recover the degree using CRT. + (This is essentially Schoof's algorithm, applied to a scalar.) + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: isog = phi + phi + sage: print(isog._degree) + None + sage: isog._compute_degree() + sage: isog._degree + 28 + + :: + + sage: E = EllipticCurve(GF(443), [1,1]) + sage: pi = E.frobenius_endomorphism() + sage: m1 = E.scalar_multiplication(1) + sage: endo = pi - m1 + sage: print(endo._degree) + None + sage: endo._compute_degree() + sage: endo._degree + 433 + sage: endo.dual()._degree + 433 + """ + if self._degree is not None: + return + if len(self._phis) == 0: + self._degree = 0 + elif len(self._phis) == 1: + self._degree = self._phis[0].degree() + else: + #TODO In some cases it would probably be faster to simply + # compute the kernel polynomial using the addition formulas? + from sage.rings.finite_rings.integer_mod import Mod + + M = self._degree_bound() + 1 + deg = Mod(0,1) + for l in Primes(): + if deg.modulus() >= M: + break + try: + P = point_of_order(self._domain, l) + except ValueError: + continue # supersingular and l == p + + Q = self.dual()._eval(self._eval(P)) + d = discrete_log(Q, P, ord=l, operation='+') + deg = deg.crt(Mod(d, l)) + + self._degree = ZZ(deg) + self.dual()._degree = self._degree + + @staticmethod + def _comparison_impl(left, right, op): + r""" + Compare a sum morphism to another elliptic-curve morphism. + + Called by :meth:`EllipticCurveHom._richcmp_`. + + If possible, we use + :func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation`. + The complexity in that case is polynomial in the logarithm of + the degree. + + TESTS:: + + sage: from sage.schemes.elliptic_curves.hom_sum import EllipticCurveHom_sum + sage: E = EllipticCurve(GF(419^2), [1,0]) + sage: i = E.automorphisms()[-1] + sage: j = E.frobenius_isogeny() + sage: i + j == j + i + True + """ + from sage.structure.richcmp import op_EQ + if op != op_EQ: + return NotImplemented + try: + return compare_via_evaluation(left, right) + except NotImplementedError: + return NotImplemented + + def degree(self): + r""" + Return the degree of this sum morphism. + + EXAMPLES: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: (phi + phi).degree() + 28 + + This method yields a simple toy point-counting algorithm:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: m1 = E.scalar_multiplication(1) + sage: pi = E.frobenius_endomorphism() + sage: (pi - m1).degree() + 119 + sage: E.count_points() + 119 + + ALGORITHM: Essentially Schoof's algorithm; see :meth:`_compute_degree`. + """ + if self._degree is None: + self._compute_degree() + return self._degree + + def rational_maps(self): + r""" + Return the rational maps of this sum morphism. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: (phi + phi).rational_maps() + ((5*x^28 + 43*x^27 + 26*x^26 - ... + 7*x^2 - 23*x + 38)/(23*x^27 + 16*x^26 + 9*x^25 + ... - 43*x^2 - 22*x + 37), + (42*x^42*y - 44*x^41*y - 22*x^40*y + ... - 26*x^2*y - 50*x*y - 18*y)/(-24*x^42 - 47*x^41 - 12*x^40 + ... + 18*x^2 - 48*x + 18)) + + ALGORITHM: :meth:`to_isogeny_chain`. + """ + #TODO In some cases it would probably be faster to compute this + # directly using the addition formulas? + return self.to_isogeny_chain().rational_maps() + + def x_rational_map(self): + r""" + Return the `x`-coordinate rational map of this sum morphism. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: (phi + phi).x_rational_map() + (9*x^28 + 37*x^27 + 67*x^26 + ... + 53*x^2 + 100*x + 28)/(x^27 + 49*x^26 + 97*x^25 + ... + 64*x^2 + 21*x + 6) + + ALGORITHM: :meth:`to_isogeny_chain`. + """ + #TODO In some cases it would probably be faster to compute this + # directly using the addition formulas? + return self.to_isogeny_chain().x_rational_map() + + def kernel_polynomial(self): + r""" + Return the kernel polynomial of this sum morphism. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: (phi + phi).kernel_polynomial() + x^15 + 75*x^14 + 16*x^13 + 59*x^12 + 28*x^11 + 60*x^10 + 69*x^9 + 79*x^8 + 79*x^7 + 52*x^6 + 35*x^5 + 11*x^4 + 37*x^3 + 69*x^2 + 66*x + 63 + + :: + + sage: E = EllipticCurve(GF(11), [5,5]) + sage: pi = E.frobenius_endomorphism() + sage: m1 = E.scalar_multiplication(1) + sage: (pi - m1).kernel_polynomial() + x^9 + 7*x^8 + 2*x^7 + 4*x^6 + 10*x^4 + 4*x^3 + 9*x^2 + 7*x + + ALGORITHM: :meth:`to_isogeny_chain`. + """ + #TODO In some cases it would probably be faster to compute this + # directly using the addition formulas? + return self.to_isogeny_chain().kernel_polynomial() + + def scaling_factor(self): + r""" + Return the Weierstrass scaling factor associated to this + sum morphism. + + The scaling factor is the constant `u` (in the base field) + such that `\varphi^* \omega_2 = u \omega_1`, where + `\varphi: E_1\to E_2` is this morphism and `\omega_i` are + the standard Weierstrass differentials on `E_i` defined by + `\mathrm dx/(2y+a_1x+a_3)`. + + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: phi.scaling_factor() + 84 + sage: (phi + phi).scaling_factor() + 67 + + ALGORITHM: The scaling factor is additive under addition + of elliptic-curve morphisms, so we simply add together the + scaling factors of the :meth:`summands`. + """ + return sum(phi.scaling_factor() for phi in self._phis) + + @cached_method + def dual(self): + r""" + Return the dual of this sum morphism. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: (phi + phi).dual() + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 + To: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 + Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101) + sage: (phi + phi).dual() == phi.dual() + phi.dual() + True + + :: + + sage: E = EllipticCurve(GF(431^2), [1,0]) + sage: iota = E.automorphisms()[2] + sage: m2 = E.scalar_multiplication(2) + sage: endo = m2 + iota + sage: endo.dual() + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 431^2 + To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 431^2 + Via: (Scalar-multiplication endomorphism [2] of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 431^2, Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 431^2 + Via: (u,r,s,t) = (8*z2 + 427, 0, 0, 0)) + sage: endo.dual() == (m2 - iota) + True + + ALGORITHM: Taking the dual distributes over addition. + """ + psi = EllipticCurveHom_sum((phi.dual() for phi in self._phis), + domain=self._codomain, codomain=self._domain) + psi._degree = self._degree + if self.trace.is_in_cache(): + psi.trace.set_cache(-self.trace.cache) + psi.dual.set_cache(self) + return psi + + def is_separable(self): + r""" + Test whether this sum morphism is a separable isogeny. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(5^2), [0,1]) + sage: m2 = E.scalar_multiplication(2) + sage: m3 = E.scalar_multiplication(3) + sage: m2.is_separable() + True + sage: E.frobenius() + -5 + sage: (m2 + m3).is_separable() + False + sage: (m2 - m2).is_separable() + Traceback (most recent call last): + ... + ValueError: zero morphism is not an isogeny + """ + deg = self.degree() + if deg.is_zero(): + raise ValueError('zero morphism is not an isogeny') + if not self.domain().base_field().characteristic().divides(deg): + return True + return self.to_isogeny_chain().is_separable() From e348fd91a5b042bbdc9e440840beae7cc154f185 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 3 Nov 2023 11:35:29 -0700 Subject: [PATCH 115/538] src/sage/groups/perm_gps/permgroup_element.pyx: use a standard python-style loop --- src/sage/groups/perm_gps/permgroup_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index cb47bf05033..a459451bd6d 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -1322,7 +1322,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): return self cdef PermutationGroupElement prod = self._new_c() cdef int i - for i from 0 <= i < self.n: + for i in range(self.n): prod.perm[i] = self.perm[i] if not self._parent._has_natural_domain(): convert_dict = self._parent._domain_to_gap From 8469a642f1bcc9def53f57874345af014d786abd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 3 Nov 2023 12:03:24 -0700 Subject: [PATCH 116/538] src/sage/geometry/polyhedron/base_ZZ.py: Add more tests --- src/sage/geometry/polyhedron/base_ZZ.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index 14eadcc7ae9..20b3c95bbcc 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -875,6 +875,11 @@ def normal_form(self, algorithm="palp_native", permutation=False): M(-1, 0) in 2-d lattice M + Using ``permutation=True``:: + + sage: d.normal_form(permutation=True) # needs sage.groups + ([(1, 0), (0, 1), (0, -1), (-1, 0)], ()) + It is not possible to compute normal forms for polytopes which do not span the space:: @@ -895,6 +900,13 @@ def normal_form(self, algorithm="palp_native", permutation=False): A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 2 rays See :issue:`15280` for proposed extensions to these cases. + + TESTS:: + + sage: d.normal_form(algorithm="palp_fiction") + Traceback (most recent call last): + ... + ValueError: algorithm must be 'palp_native' """ from sage.geometry.palp_normal_form import _palp_PM_max, _palp_canonical_order From 4797a51839b2d9215ffb3a5d61d47fed4b6a9f0c Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 3 Nov 2023 21:26:25 +0100 Subject: [PATCH 117/538] switch from qfbclassno() to quadclassunit() for large discriminants --- src/sage/quadratic_forms/bqf_class_group.py | 9 ++++++-- src/sage/rings/number_field/order.py | 25 ++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/sage/quadratic_forms/bqf_class_group.py b/src/sage/quadratic_forms/bqf_class_group.py index 185a869b8b2..30c9bd7782a 100644 --- a/src/sage/quadratic_forms/bqf_class_group.py +++ b/src/sage/quadratic_forms/bqf_class_group.py @@ -253,7 +253,7 @@ def order(self): r""" Return the order of this form class group (the *class number*). - ALGORITHM: :pari:`qfbclassno` + ALGORITHM: :func:`sage.rings.number_field.order.quadratic_order_class_number`. EXAMPLES:: @@ -272,7 +272,12 @@ def order(self): sage: BQFClassGroup(-99999).order() 224 """ - return ZZ(pari.qfbclassno(self._disc)) + # Beware: If this code is ever generalized to positive + # discriminants, care must be taken to use the correct + # notion of class number. We may need the *narrow* class + # number here; see PARI's documentation for qfbclassno(). + from sage.rings.number_field.order import quadratic_order_class_number + return quadratic_order_class_number(self._disc) cardinality = order diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index f0b24b74630..857f33ffc4d 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -92,6 +92,29 @@ from sage.libs.pari.all import pari +def quadratic_order_class_number(disc): + r""" + Return the class number of the quadratic order of given discriminant. + + EXAMPLES:: + + sage: from sage.rings.number_field.order import quadratic_order_class_number + sage: quadratic_order_class_number(-419) + 9 + sage: quadratic_order_class_number(60) + 2 + + ALGORITHM: Either :pari:`qfbclassno` or :pari:`quadclassunit`, + depending on the size of the discriminant. + """ + # cutoffs from PARI documentation + if disc < -10**25 or disc > 10**10: + h = pari.quadclassunit(disc)[0] + else: + h = pari.qfbclassno(disc) + return ZZ(h) + + class OrderFactory(UniqueFactory): r""" Abstract base class for factories creating orders, such as @@ -1096,7 +1119,7 @@ def class_number(self, proof=None): K = self.number_field() if K.degree() != 2: raise NotImplementedError("computation of class numbers of non-maximal orders not in quadratic fields is not implemented") - return ZZ(pari.qfbclassno(self.discriminant())) + return quadratic_order_class_number(self.discriminant()) return self.number_field().class_number(proof=proof) def class_group(self, proof=None, names='c'): From 4ac814afde928dba62809984e3a0680f78e28369 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 15 May 2023 14:10:59 -0700 Subject: [PATCH 118/538] sage.algebras: Add # optional --- src/sage/algebras/clifford_algebra.py | 8 +++---- src/sage/algebras/lie_algebras/morphism.py | 4 ++-- src/sage/algebras/lie_algebras/quotient.py | 8 +++---- .../lie_algebras/structure_coefficients.py | 4 ++-- src/sage/algebras/lie_algebras/subalgebra.py | 24 +++++++++---------- .../algebras/quaternion_algebra_element.py | 8 +++---- src/sage/algebras/weyl_algebra.py | 8 +++---- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 220a2eb27a5..adb065e31b7 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1770,11 +1770,11 @@ def interior_product_on_basis(self, a, b): Check :trac:`34694`:: - sage: E = ExteriorAlgebra(SR,'e',3) - sage: E.inject_variables() + sage: E = ExteriorAlgebra(SR,'e',3) # optional - sage.symbolic + sage: E.inject_variables() # optional - sage.symbolic Defining e0, e1, e2 - sage: a = (e0*e1).interior_product(e0) - sage: a * e0 + sage: a = (e0*e1).interior_product(e0) # optional - sage.symbolic + sage: a * e0 # optional - sage.symbolic -e0*e1 """ sgn = True diff --git a/src/sage/algebras/lie_algebras/morphism.py b/src/sage/algebras/lie_algebras/morphism.py index f71001ce98f..a4c03e22104 100644 --- a/src/sage/algebras/lie_algebras/morphism.py +++ b/src/sage/algebras/lie_algebras/morphism.py @@ -461,8 +461,8 @@ class LieAlgebraMorphism_from_generators(LieAlgebraHomomorphism_im_gens): A quotient type Lie algebra morphism:: - sage: K. = LieAlgebra(SR, abelian=True) - sage: L.morphism({X: A, Y: B}) + sage: K. = LieAlgebra(SR, abelian=True) # optional - sage.symbolic + sage: L.morphism({X: A, Y: B}) # optional - sage.symbolic Lie algebra morphism: From: Lie algebra on 4 generators (X, Y, Z, W) over Rational Field To: Abelian Lie algebra on 2 generators (A, B) over Symbolic Ring diff --git a/src/sage/algebras/lie_algebras/quotient.py b/src/sage/algebras/lie_algebras/quotient.py index 7fe6b29677f..a0400221af6 100644 --- a/src/sage/algebras/lie_algebras/quotient.py +++ b/src/sage/algebras/lie_algebras/quotient.py @@ -242,11 +242,11 @@ def __init__(self, I, L, names, index_set, category=None): TESTS:: - sage: L. = LieAlgebra(SR, {('x','y'): {'x':1}}) - sage: K = L.quotient(y) - sage: K.dimension() + sage: L. = LieAlgebra(SR, {('x','y'): {'x':1}}) # optional - sage.symbolic + sage: K = L.quotient(y) # optional - sage.symbolic + sage: K.dimension() # optional - sage.symbolic 1 - sage: TestSuite(K).run() + sage: TestSuite(K).run() # optional - sage.symbolic """ B = L.basis() sm = L.module().submodule_with_basis([I.reduce(B[i]).to_vector() diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 16c2cf51029..48b1bbecf41 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -411,8 +411,8 @@ def change_ring(self, R): sage: LQQ = L.change_ring(QQ) sage: LQQ.structure_coefficients() Finite family {('x', 'y'): z} - sage: LSR = LQQ.change_ring(SR) - sage: LSR.structure_coefficients() + sage: LSR = LQQ.change_ring(SR) # optional - sage.symbolic + sage: LSR.structure_coefficients() # optional - sage.symbolic Finite family {('x', 'y'): z} """ return LieAlgebraWithStructureCoefficients( diff --git a/src/sage/algebras/lie_algebras/subalgebra.py b/src/sage/algebras/lie_algebras/subalgebra.py index 90779eb91fc..ab7b6922083 100644 --- a/src/sage/algebras/lie_algebras/subalgebra.py +++ b/src/sage/algebras/lie_algebras/subalgebra.py @@ -75,32 +75,32 @@ class LieSubalgebra_finite_dimensional_with_basis(Parent, UniqueRepresentation): Elements of the ambient Lie algebra can be reduced modulo an ideal or subalgebra:: - sage: L. = LieAlgebra(SR, {('X','Y'): {'Z': 1}}) - sage: I = L.ideal(Y) - sage: I.reduce(X + 2*Y + 3*Z) + sage: L. = LieAlgebra(SR, {('X','Y'): {'Z': 1}}) # optional - sage.symbolic + sage: I = L.ideal(Y) # optional - sage.symbolic + sage: I.reduce(X + 2*Y + 3*Z) # optional - sage.symbolic X - sage: S = L.subalgebra(Y) - sage: S.reduce(X + 2*Y + 3*Z) + sage: S = L.subalgebra(Y) # optional - sage.symbolic + sage: S.reduce(X + 2*Y + 3*Z) # optional - sage.symbolic X + 3*Z The reduction gives elements in a fixed complementary subspace. When the base ring is a field, the complementary subspace is spanned by those basis elements which are not leading supports of the basis:: - sage: I = L.ideal(X + Y) - sage: I.basis() + sage: I = L.ideal(X + Y) # optional - sage.symbolic + sage: I.basis() # optional - sage.symbolic Family (X + Y, Z) - sage: el = var('x')*X + var('y')*Y + var('z')*Z; el + sage: el = var('x')*X + var('y')*Y + var('z')*Z; el # optional - sage.symbolic x*X + y*Y + z*Z - sage: I.reduce(el) + sage: I.reduce(el) # optional - sage.symbolic (x-y)*X Giving a different ``order`` may change the reduction of elements:: - sage: I = L.ideal(X + Y, order=lambda s: ['Z','Y','X'].index(s)) - sage: I.basis() + sage: I = L.ideal(X + Y, order=lambda s: ['Z','Y','X'].index(s)) # optional - sage.symbolic + sage: I.basis() # optional - sage.symbolic Family (Z, X + Y) - sage: I.reduce(el) + sage: I.reduce(el) # optional - sage.symbolic (-x+y)*Y A subalgebra of a subalgebra is a subalgebra of the original:: diff --git a/src/sage/algebras/quaternion_algebra_element.py b/src/sage/algebras/quaternion_algebra_element.py index ef527e2f269..48c1c9871ec 100644 --- a/src/sage/algebras/quaternion_algebra_element.py +++ b/src/sage/algebras/quaternion_algebra_element.py @@ -37,12 +37,12 @@ def unpickle_QuaternionAlgebraElement_number_field_v0(*args): """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a); z = i + j - sage: f, t = z.__reduce__() + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a); z = i + j # optional - sage.symbolic + sage: f, t = z.__reduce__() # optional - sage.symbolic sage: import sage.algebras.quaternion_algebra_element - sage: sage.algebras.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) + sage: sage.algebras.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) # optional - sage.symbolic i + j - sage: sage.algebras.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) == z + sage: sage.algebras.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) == z # optional - sage.symbolic True """ return QuaternionAlgebraElement_number_field(*args) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 13604578430..48b1dee6075 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -53,12 +53,12 @@ def repr_from_monomials(monomials, term_repr, use_latex=False): sage: from sage.algebras.weyl_algebra import repr_from_monomials sage: R. = QQ[] - sage: d = [(z, 4/7), (y, sqrt(2)), (x, -5)] - sage: repr_from_monomials(d, lambda m: repr(m)) + sage: d = [(z, 4/7), (y, sqrt(2)), (x, -5)] # optional - sage.symbolic + sage: repr_from_monomials(d, lambda m: repr(m)) # optional - sage.symbolic '4/7*z + sqrt(2)*y - 5*x' - sage: a = repr_from_monomials(d, lambda m: latex(m), True); a + sage: a = repr_from_monomials(d, lambda m: latex(m), True); a # optional - sage.symbolic \frac{4}{7} z + \sqrt{2} y - 5 x - sage: type(a) + sage: type(a) # optional - sage.symbolic The zero element:: From ce226276941f66b5c8c2187caccd2ebee71fbaf5 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 May 2023 13:20:30 -0700 Subject: [PATCH 119/538] Massive modularization fixes --- src/sage/algebras/commutative_dga.py | 18 +- src/sage/algebras/lie_algebras/morphism.py | 14 +- .../algebras/quatalg/quaternion_algebra.py | 155 ++++++++++++------ .../quatalg/quaternion_algebra_element.pyx | 82 ++++----- src/sage/algebras/weyl_algebra.py | 8 +- 5 files changed, 164 insertions(+), 113 deletions(-) diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index 953364d6813..2b5f2ccffd1 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -3925,8 +3925,8 @@ class CohomologyClass(SageObject, CachedRepresentation): sage: from sage.algebras.commutative_dga import CohomologyClass sage: CohomologyClass(3) [3] - sage: A. = GradedCommutativeAlgebra(QQ, degrees = (2,2,3,3)) - sage: CohomologyClass(x^2+2*y*z, A) + sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2,2,3,3)) + sage: CohomologyClass(x^2 + 2*y*z, A) [2*y*z + x^2] TESTS: @@ -3978,7 +3978,7 @@ def __init__(self, x, cdga=None): EXAMPLES:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: CohomologyClass(x-2) + sage: CohomologyClass(x - 2) # optional - sage.symbolic [x - 2] """ self._x = x @@ -3989,7 +3989,7 @@ def __hash__(self): TESTS:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: hash(CohomologyClass(sin)) == hash(sin) + sage: hash(CohomologyClass(sin)) == hash(sin) # optional - sage.symbolic True """ return hash(self._x) @@ -3999,7 +3999,7 @@ def _repr_(self): EXAMPLES:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: CohomologyClass(sin) + sage: CohomologyClass(sin) # optional - sage.symbolic [sin] """ return '[{}]'.format(self._x) @@ -4009,9 +4009,9 @@ def _latex_(self): EXAMPLES:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: latex(CohomologyClass(sin)) + sage: latex(CohomologyClass(sin)) # optional - sage.symbolic \left[ \sin \right] - sage: latex(CohomologyClass(x^2)) + sage: latex(CohomologyClass(x^2)) # optional - sage.symbolic \left[ x^{2} \right] """ from sage.misc.latex import latex @@ -4024,8 +4024,8 @@ def representative(self): EXAMPLES:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: x = CohomologyClass(sin) - sage: x.representative() == sin + sage: x = CohomologyClass(sin) # optional - sage.symbolic + sage: x.representative() == sin # optional - sage.symbolic True """ return self._x diff --git a/src/sage/algebras/lie_algebras/morphism.py b/src/sage/algebras/lie_algebras/morphism.py index a4c03e22104..2d04a5e6b65 100644 --- a/src/sage/algebras/lie_algebras/morphism.py +++ b/src/sage/algebras/lie_algebras/morphism.py @@ -623,17 +623,17 @@ def _call_(self, x): EXAMPLES:: sage: L. = LieAlgebra(QQ, {('X','Y'): {'Z':1}, ('X','Z'): {'W':1}}) - sage: K. = LieAlgebra(SR, abelian=True) - sage: phi = L.morphism({X: A, Y: B}) - sage: phi(X) + sage: K. = LieAlgebra(SR, abelian=True) # optional - sage.symbolic + sage: phi = L.morphism({X: A, Y: B}) # optional - sage.symbolic + sage: phi(X) # optional - sage.symbolic A - sage: phi(Y) + sage: phi(Y) # optional - sage.symbolic B - sage: phi(Z) + sage: phi(Z) # optional - sage.symbolic 0 - sage: phi(W) + sage: phi(W) # optional - sage.symbolic 0 - sage: phi(-X + 3*Y) + sage: phi(-X + 3*Y) # optional - sage.symbolic -A + 3*B sage: K. = LieAlgebra(QQ, {('A','B'): {'C':2}}) diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index 1b6001209a0..f0a31dca349 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -119,15 +119,17 @@ class QuaternionAlgebraFactory(UniqueFactory): Quaternion Algebra (2, 3) with base ring Finite Field of size 5 sage: QuaternionAlgebra(2, GF(5)(3)) Quaternion Algebra (2, 3) with base ring Finite Field of size 5 - sage: QuaternionAlgebra(QQ[sqrt(2)](-1), -5) - Quaternion Algebra (-1, -5) with base ring Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? - sage: QuaternionAlgebra(sqrt(-1), sqrt(-3)) + sage: QuaternionAlgebra(QQ[sqrt(2)](-1), -5) # optional - sage.symbolic + Quaternion Algebra (-1, -5) with base ring Number Field in sqrt2 + with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? + sage: QuaternionAlgebra(sqrt(-1), sqrt(-3)) # optional - sage.symbolic Quaternion Algebra (I, sqrt(-3)) with base ring Symbolic Ring sage: QuaternionAlgebra(1r,1) Quaternion Algebra (1, 1) with base ring Rational Field sage: A. = ZZ[] sage: QuaternionAlgebra(-1, t) - Quaternion Algebra (-1, t) with base ring Fraction Field of Univariate Polynomial Ring in t over Integer Ring + Quaternion Algebra (-1, t) with base ring + Fraction Field of Univariate Polynomial Ring in t over Integer Ring Python ints and floats may be passed to the ``QuaternionAlgebra(a, b)`` constructor, as may all pairs of @@ -138,11 +140,13 @@ class QuaternionAlgebraFactory(UniqueFactory): sage: QuaternionAlgebra(1r,1) Quaternion Algebra (1, 1) with base ring Rational Field sage: QuaternionAlgebra(1,1.0r) - Quaternion Algebra (1.00000000000000, 1.00000000000000) with base ring Real Field with 53 bits of precision + Quaternion Algebra (1.00000000000000, 1.00000000000000) with base ring + Real Field with 53 bits of precision sage: QuaternionAlgebra(0,0) Traceback (most recent call last): ... - ValueError: defining elements of quaternion algebra (0, 0) are not invertible in Rational Field + ValueError: defining elements of quaternion algebra (0, 0) + are not invertible in Rational Field sage: QuaternionAlgebra(GF(2)(1),1) Traceback (most recent call last): ... @@ -158,8 +162,9 @@ class QuaternionAlgebraFactory(UniqueFactory): sage: QuaternionAlgebra(QQ, -7, -21) Quaternion Algebra (-7, -21) with base ring Rational Field - sage: QuaternionAlgebra(QQ[sqrt(2)], -2,-3) - Quaternion Algebra (-2, -3) with base ring Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? + sage: QuaternionAlgebra(QQ[sqrt(2)], -2,-3) # optional - sage.symbolic + Quaternion Algebra (-2, -3) with base ring Number Field in sqrt2 + with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? ``QuaternionAlgebra(D)`` -- `D` is a squarefree integer; return a rational quaternion algebra of discriminant `D`:: @@ -540,8 +545,8 @@ def random_element(self, *args, **kwds): EXAMPLES:: - sage: g = QuaternionAlgebra(QQ[sqrt(2)], -3, 7).random_element() - sage: g.parent() is QuaternionAlgebra(QQ[sqrt(2)], -3, 7) + sage: g = QuaternionAlgebra(QQ[sqrt(2)], -3, 7).random_element() # optional - sage.symbolic + sage: g.parent() is QuaternionAlgebra(QQ[sqrt(2)], -3, 7) # optional - sage.symbolic True sage: g = QuaternionAlgebra(-3, 19).random_element() sage: g.parent() is QuaternionAlgebra(-3, 19) @@ -576,12 +581,13 @@ def free_module(self): sage: A. = LaurentPolynomialRing(GF(3)) sage: B = QuaternionAlgebra(A, -1, t) sage: B.free_module() - Ambient free quadratic module of rank 4 over the principal ideal domain Univariate Laurent Polynomial Ring in t over Finite Field of size 3 - Inner product matrix: - [2 0 0 0] - [0 2 0 0] - [0 0 t 0] - [0 0 0 t] + Ambient free quadratic module of rank 4 over the principal ideal domain + Univariate Laurent Polynomial Ring in t over Finite Field of size 3 + Inner product matrix: + [2 0 0 0] + [0 2 0 0] + [0 0 t 0] + [0 0 0 t] """ return FreeModule(self.base_ring(), 4, inner_product_matrix=self.inner_product_matrix()) @@ -594,10 +600,10 @@ def vector_space(self): sage: QuaternionAlgebra(-3,19).vector_space() Ambient quadratic space of dimension 4 over Rational Field Inner product matrix: - [ 2 0 0 0] - [ 0 6 0 0] - [ 0 0 -38 0] - [ 0 0 0 -114] + [ 2 0 0 0] + [ 0 6 0 0] + [ 0 0 -38 0] + [ 0 0 0 -114] """ return self.free_module() @@ -697,7 +703,8 @@ def maximal_order(self, take_shortcuts=True): EXAMPLES:: sage: QuaternionAlgebra(-1,-7).maximal_order() - Order of Quaternion Algebra (-1, -7) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k) + Order of Quaternion Algebra (-1, -7) with base ring Rational Field + with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k) sage: QuaternionAlgebra(-1,-1).maximal_order().basis() (1/2 + 1/2*i + 1/2*j + 1/2*k, i, j, k) @@ -732,13 +739,16 @@ def maximal_order(self, take_shortcuts=True): If you want bases containing 1, switch off ``take_shortcuts``:: sage: QuaternionAlgebra(-3,-89).maximal_order(take_shortcuts=False) - Order of Quaternion Algebra (-3, -89) with base ring Rational Field with basis (1, 1/2 + 1/2*i, j, 1/2 + 1/6*i + 1/2*j + 1/6*k) + Order of Quaternion Algebra (-3, -89) with base ring Rational Field + with basis (1, 1/2 + 1/2*i, j, 1/2 + 1/6*i + 1/2*j + 1/6*k) sage: QuaternionAlgebra(1,1).maximal_order(take_shortcuts=False) # Matrix ring - Order of Quaternion Algebra (1, 1) with base ring Rational Field with basis (1, 1/2 + 1/2*i, j, 1/2*j + 1/2*k) + Order of Quaternion Algebra (1, 1) with base ring Rational Field + with basis (1, 1/2 + 1/2*i, j, 1/2*j + 1/2*k) sage: QuaternionAlgebra(-22,210).maximal_order(take_shortcuts=False) - Order of Quaternion Algebra (-22, 210) with base ring Rational Field with basis (1, i, 1/2*i + 1/2*j, 1/2 + 17/22*i + 1/44*k) + Order of Quaternion Algebra (-22, 210) with base ring Rational Field + with basis (1, i, 1/2*i + 1/2*j, 1/2 + 17/22*i + 1/44*k) sage: for d in ( m for m in range(1, 750) if is_squarefree(m) ): # long time (3s) ....: A = QuaternionAlgebra(d) @@ -751,7 +761,8 @@ def maximal_order(self, take_shortcuts=True): sage: QuaternionAlgebra(K,-1,-1).maximal_order() Traceback (most recent call last): ... - NotImplementedError: maximal order only implemented for rational quaternion algebras + NotImplementedError: maximal order only implemented + for rational quaternion algebras """ if self.base_ring() != QQ: raise NotImplementedError("maximal order only implemented for rational quaternion algebras") @@ -1037,7 +1048,7 @@ def discriminant(self): sage: B.discriminant() Fractional ideal (2) - sage: QuaternionAlgebra(QQ[sqrt(2)],3,19).discriminant() + sage: QuaternionAlgebra(QQ[sqrt(2)], 3, 19).discriminant() # optional - sage.symbolic Fractional ideal (1) """ if not is_RationalField(self.base_ring()): @@ -1082,11 +1093,13 @@ def _magma_init_(self, magma): A more complicated example involving a quaternion algebra over a number field:: - sage: K. = QQ[sqrt(2)]; Q = QuaternionAlgebra(K,-1,a); Q - Quaternion Algebra (-1, sqrt2) with base ring Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? - sage: magma(Q) # optional - magma - Quaternion Algebra with base ring Number Field with defining polynomial x^2 - 2 over the Rational Field, defined by i^2 = -1, j^2 = sqrt2 - sage: Q._magma_init_(magma) # optional - magma + sage: K. = QQ[sqrt(2)]; Q = QuaternionAlgebra(K,-1,a); Q # optional - sage.symbolic + Quaternion Algebra (-1, sqrt2) with base ring Number Field in sqrt2 + with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? + sage: magma(Q) # optional - magma sage.symbolic + Quaternion Algebra with base ring Number Field with defining polynomial + x^2 - 2 over the Rational Field, defined by i^2 = -1, j^2 = sqrt2 + sage: Q._magma_init_(magma) # optional - magma sage.symbolic 'QuaternionAlgebra(_sage_[...],(_sage_[...]![-1, 0]),(_sage_[...]![0, 1]))' """ R = magma(self.base_ring()) @@ -1107,14 +1120,17 @@ def quaternion_order(self, basis, check=True): sage: Q. = QuaternionAlgebra(-11,-1) sage: Q.quaternion_order([1,i,j,k]) - Order of Quaternion Algebra (-11, -1) with base ring Rational Field with basis (1, i, j, k) + Order of Quaternion Algebra (-11, -1) with base ring Rational Field + with basis (1, i, j, k) We test out ``check=False``:: sage: Q.quaternion_order([1,i,j,k], check=False) - Order of Quaternion Algebra (-11, -1) with base ring Rational Field with basis (1, i, j, k) + Order of Quaternion Algebra (-11, -1) with base ring Rational Field + with basis (1, i, j, k) sage: Q.quaternion_order([i,j,k], check=False) - Order of Quaternion Algebra (-11, -1) with base ring Rational Field with basis (i, j, k) + Order of Quaternion Algebra (-11, -1) with base ring Rational Field + with basis (i, j, k) """ return QuaternionOrder(self, basis, check=check) @@ -1210,7 +1226,9 @@ def modp_splitting_data(self, p): sage: Q.modp_splitting_data(5) Traceback (most recent call last): ... - NotImplementedError: algorithm for computing local splittings not implemented in general (currently require the first invariant to be coprime to p) + NotImplementedError: algorithm for computing local splittings + not implemented in general (currently require the first invariant + to be coprime to p) sage: Q.modp_splitting_data(2) Traceback (most recent call last): @@ -1363,7 +1381,8 @@ def __init__(self, A, basis, check=True): sage: K = QuadraticField(10) sage: A. = QuaternionAlgebra(K,-1,-1) sage: A.quaternion_order([1,i,j,k]) - Order of Quaternion Algebra (-1, -1) with base ring Number Field in a with defining polynomial x^2 - 10 with a = 3.162277660168380? with basis (1, i, j, k) + Order of Quaternion Algebra (-1, -1) with base ring Number Field in a + with defining polynomial x^2 - 10 with a = 3.162277660168380? with basis (1, i, j, k) sage: A.quaternion_order([1,i/2,j,k]) Traceback (most recent call last): ... @@ -1508,7 +1527,8 @@ def gen(self, n): EXAMPLES:: sage: R = QuaternionAlgebra(-11,-1).maximal_order(); R - Order of Quaternion Algebra (-11, -1) with base ring Rational Field with basis (1/2 + 1/2*i, 1/2*j - 1/2*k, i, -k) + Order of Quaternion Algebra (-11, -1) with base ring Rational Field + with basis (1/2 + 1/2*i, 1/2*j - 1/2*k, i, -k) sage: R.gen(0) 1/2 + 1/2*i sage: R.gen(1) @@ -1649,20 +1669,23 @@ def intersection(self, other): sage: R = QuaternionAlgebra(-11,-1).maximal_order() sage: R.intersection(R) - Order of Quaternion Algebra (-11, -1) with base ring Rational Field with basis (1/2 + 1/2*i, i, 1/2*j + 1/2*k, k) + Order of Quaternion Algebra (-11, -1) with base ring Rational Field + with basis (1/2 + 1/2*i, i, 1/2*j + 1/2*k, k) We intersect various orders in the quaternion algebra ramified at 11:: sage: B = BrandtModule(11,3) sage: R = B.maximal_order(); S = B.order_of_level_N() sage: R.intersection(S) - Order of Quaternion Algebra (-1, -11) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 5/2*k, j, 3*k) + Order of Quaternion Algebra (-1, -11) with base ring Rational Field + with basis (1/2 + 1/2*j, 1/2*i + 5/2*k, j, 3*k) sage: R.intersection(S) == S True sage: B = BrandtModule(11,5) sage: T = B.order_of_level_N() sage: S.intersection(T) - Order of Quaternion Algebra (-1, -11) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 23/2*k, j, 15*k) + Order of Quaternion Algebra (-1, -11) with base ring Rational Field + with basis (1/2 + 1/2*j, 1/2*i + 23/2*k, j, 15*k) """ if not isinstance(other, QuaternionOrder): raise TypeError("other must be a QuaternionOrder") @@ -2021,7 +2044,8 @@ def scale(self, alpha, left=False): EXAMPLES:: - sage: B = BrandtModule(5,37); I = B.right_ideals()[0]; i,j,k = B.quaternion_algebra().gens(); I + sage: B = BrandtModule(5,37); I = B.right_ideals()[0] + sage: i,j,k = B.quaternion_algebra().gens(); I Fractional ideal (2 + 2*j + 106*k, i + 2*j + 105*k, 4*j + 64*k, 148*k) sage: I.scale(i) Fractional ideal (2*i + 212*j - 2*k, -2 + 210*j - 2*k, 128*j - 4*k, 296*j) @@ -2101,9 +2125,11 @@ def _compute_order(self, side='left'): sage: R. = QuaternionAlgebra(-1,-11) sage: I = R.ideal([2 + 2*j + 140*k, 2*i + 4*j + 150*k, 8*j + 104*k, 152*k]) sage: Ol = I._compute_order('left'); Ol - Order of Quaternion Algebra (-1, -11) with base ring Rational Field with basis (1/2 + 1/2*j + 35*k, 1/4*i + 1/2*j + 75/4*k, j + 32*k, 38*k) + Order of Quaternion Algebra (-1, -11) with base ring Rational Field + with basis (1/2 + 1/2*j + 35*k, 1/4*i + 1/2*j + 75/4*k, j + 32*k, 38*k) sage: Or = I._compute_order('right'); Or - Order of Quaternion Algebra (-1, -11) with base ring Rational Field with basis (1/2 + 1/2*j + 16*k, 1/2*i + 11/2*k, j + 13*k, 19*k) + Order of Quaternion Algebra (-1, -11) with base ring Rational Field + with basis (1/2 + 1/2*j + 16*k, 1/2*i + 11/2*k, j + 13*k, 19*k) sage: Ol.discriminant() 209 sage: Or.discriminant() @@ -2163,7 +2189,8 @@ def left_order(self): sage: R = B.maximal_order() sage: I = R.unit_ideal() sage: I.left_order() - Order of Quaternion Algebra (-1, -11) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k) + Order of Quaternion Algebra (-1, -11) with base ring Rational Field + with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k) We do a consistency check:: @@ -2186,9 +2213,11 @@ def right_order(self): sage: I = BrandtModule(389).right_ideals()[1]; I Fractional ideal (2 + 6*j + 2*k, i + 2*j + k, 8*j, 8*k) sage: I.right_order() - Order of Quaternion Algebra (-2, -389) with base ring Rational Field with basis (1/2 + 1/2*j + 1/2*k, 1/4*i + 1/2*j + 1/4*k, j, k) + Order of Quaternion Algebra (-2, -389) with base ring Rational Field + with basis (1/2 + 1/2*j + 1/2*k, 1/4*i + 1/2*j + 1/4*k, j, k) sage: I.left_order() - Order of Quaternion Algebra (-2, -389) with base ring Rational Field with basis (1/2 + 1/2*j + 3/2*k, 1/8*i + 1/4*j + 9/8*k, j + k, 2*k) + Order of Quaternion Algebra (-2, -389) with base ring Rational Field + with basis (1/2 + 1/2*j + 3/2*k, 1/8*i + 1/4*j + 9/8*k, j + k, 2*k) The following is a big consistency check. We take reps for all the right ideal classes of a certain order, take the @@ -2238,7 +2267,8 @@ def quaternion_order(self): sage: R = QuaternionAlgebra(-11,-1).maximal_order() sage: R.unit_ideal().quaternion_order() is R - doctest:...: DeprecationWarning: quaternion_order() is deprecated, please use left_order() or right_order() + doctest:...: DeprecationWarning: quaternion_order() is deprecated, + please use left_order() or right_order() See https://github.com/sagemath/sage/issues/31583 for details. True """ @@ -2838,31 +2868,47 @@ def cyclic_right_subideals(self, p, alpha=None): sage: B = BrandtModule(2,37); I = B.right_ideals()[0] sage: I.cyclic_right_subideals(3) - [Fractional ideal (2 + 2*i + 10*j + 90*k, 4*i + 4*j + 152*k, 12*j + 132*k, 444*k), Fractional ideal (2 + 2*i + 2*j + 150*k, 4*i + 8*j + 196*k, 12*j + 132*k, 444*k), Fractional ideal (2 + 2*i + 6*j + 194*k, 4*i + 8*j + 344*k, 12*j + 132*k, 444*k), Fractional ideal (2 + 2*i + 6*j + 46*k, 4*i + 4*j + 4*k, 12*j + 132*k, 444*k)] + [Fractional ideal (2 + 2*i + 10*j + 90*k, 4*i + 4*j + 152*k, 12*j + 132*k, 444*k), + Fractional ideal (2 + 2*i + 2*j + 150*k, 4*i + 8*j + 196*k, 12*j + 132*k, 444*k), + Fractional ideal (2 + 2*i + 6*j + 194*k, 4*i + 8*j + 344*k, 12*j + 132*k, 444*k), + Fractional ideal (2 + 2*i + 6*j + 46*k, 4*i + 4*j + 4*k, 12*j + 132*k, 444*k)] sage: B = BrandtModule(5,389); I = B.right_ideals()[0] sage: C = I.cyclic_right_subideals(3); C - [Fractional ideal (2 + 10*j + 546*k, i + 6*j + 133*k, 12*j + 3456*k, 4668*k), Fractional ideal (2 + 2*j + 2910*k, i + 6*j + 3245*k, 12*j + 3456*k, 4668*k), Fractional ideal (2 + i + 2295*k, 3*i + 2*j + 3571*k, 4*j + 2708*k, 4668*k), Fractional ideal (2 + 2*i + 2*j + 4388*k, 3*i + 2*j + 2015*k, 4*j + 4264*k, 4668*k)] + [Fractional ideal (2 + 10*j + 546*k, i + 6*j + 133*k, 12*j + 3456*k, 4668*k), + Fractional ideal (2 + 2*j + 2910*k, i + 6*j + 3245*k, 12*j + 3456*k, 4668*k), + Fractional ideal (2 + i + 2295*k, 3*i + 2*j + 3571*k, 4*j + 2708*k, 4668*k), + Fractional ideal (2 + 2*i + 2*j + 4388*k, 3*i + 2*j + 2015*k, 4*j + 4264*k, 4668*k)] sage: [(I.free_module()/J.free_module()).invariants() for J in C] [(3, 3), (3, 3), (3, 3), (3, 3)] sage: I.scale(3).cyclic_right_subideals(3) - [Fractional ideal (6 + 30*j + 1638*k, 3*i + 18*j + 399*k, 36*j + 10368*k, 14004*k), Fractional ideal (6 + 6*j + 8730*k, 3*i + 18*j + 9735*k, 36*j + 10368*k, 14004*k), Fractional ideal (6 + 3*i + 6885*k, 9*i + 6*j + 10713*k, 12*j + 8124*k, 14004*k), Fractional ideal (6 + 6*i + 6*j + 13164*k, 9*i + 6*j + 6045*k, 12*j + 12792*k, 14004*k)] + [Fractional ideal (6 + 30*j + 1638*k, 3*i + 18*j + 399*k, 36*j + 10368*k, 14004*k), + Fractional ideal (6 + 6*j + 8730*k, 3*i + 18*j + 9735*k, 36*j + 10368*k, 14004*k), + Fractional ideal (6 + 3*i + 6885*k, 9*i + 6*j + 10713*k, 12*j + 8124*k, 14004*k), + Fractional ideal (6 + 6*i + 6*j + 13164*k, 9*i + 6*j + 6045*k, 12*j + 12792*k, 14004*k)] sage: C = I.scale(1/9).cyclic_right_subideals(3); C - [Fractional ideal (2/9 + 10/9*j + 182/3*k, 1/9*i + 2/3*j + 133/9*k, 4/3*j + 384*k, 1556/3*k), Fractional ideal (2/9 + 2/9*j + 970/3*k, 1/9*i + 2/3*j + 3245/9*k, 4/3*j + 384*k, 1556/3*k), Fractional ideal (2/9 + 1/9*i + 255*k, 1/3*i + 2/9*j + 3571/9*k, 4/9*j + 2708/9*k, 1556/3*k), Fractional ideal (2/9 + 2/9*i + 2/9*j + 4388/9*k, 1/3*i + 2/9*j + 2015/9*k, 4/9*j + 4264/9*k, 1556/3*k)] + [Fractional ideal (2/9 + 10/9*j + 182/3*k, 1/9*i + 2/3*j + 133/9*k, 4/3*j + 384*k, 1556/3*k), + Fractional ideal (2/9 + 2/9*j + 970/3*k, 1/9*i + 2/3*j + 3245/9*k, 4/3*j + 384*k, 1556/3*k), + Fractional ideal (2/9 + 1/9*i + 255*k, 1/3*i + 2/9*j + 3571/9*k, 4/9*j + 2708/9*k, 1556/3*k), + Fractional ideal (2/9 + 2/9*i + 2/9*j + 4388/9*k, 1/3*i + 2/9*j + 2015/9*k, 4/9*j + 4264/9*k, 1556/3*k)] sage: [(I.scale(1/9).free_module()/J.free_module()).invariants() for J in C] [(3, 3), (3, 3), (3, 3), (3, 3)] sage: Q. = QuaternionAlgebra(-2,-5) sage: I = Q.ideal([Q(1),i,j,k]) sage: I.cyclic_right_subideals(3) - [Fractional ideal (1 + 2*j, i + k, 3*j, 3*k), Fractional ideal (1 + j, i + 2*k, 3*j, 3*k), Fractional ideal (1 + 2*i, 3*i, j + 2*k, 3*k), Fractional ideal (1 + i, 3*i, j + k, 3*k)] + [Fractional ideal (1 + 2*j, i + k, 3*j, 3*k), + Fractional ideal (1 + j, i + 2*k, 3*j, 3*k), + Fractional ideal (1 + 2*i, 3*i, j + 2*k, 3*k), + Fractional ideal (1 + i, 3*i, j + k, 3*k)] The general algorithm is not yet implemented here:: sage: I.cyclic_right_subideals(3)[0].cyclic_right_subideals(3) Traceback (most recent call last): ... - NotImplementedError: general algorithm not implemented (The given basis vectors must be linearly independent.) + NotImplementedError: general algorithm not implemented + (The given basis vectors must be linearly independent.) """ R = self.right_order() Q = self.quaternion_algebra() @@ -3075,7 +3121,8 @@ def normalize_basis_at_p(e, p, B=QuaternionAlgebraElement_abstract.pair): sage: A. = QuaternionAlgebra(-1,-7) sage: e = [A(1), k, j, 1/2 + 1/2*i + 1/2*j + 1/2*k] sage: normalize_basis_at_p(e, 2) - [(1, 0), (1/2 + 1/2*i + 1/2*j + 1/2*k, 0), (-34/105*i - 463/735*j + 71/105*k, 1), (-34/105*i - 463/735*j + 71/105*k, 1)] + [(1, 0), (1/2 + 1/2*i + 1/2*j + 1/2*k, 0), (-34/105*i - 463/735*j + 71/105*k, 1), + (-34/105*i - 463/735*j + 71/105*k, 1)] """ N = len(e) diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index a1dd86a224c..71188038aa9 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -1658,8 +1658,8 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra EXAMPLES:: - sage: K. = QQ[2^(1/5)]; Q. = QuaternionAlgebra(K,-a,a*17/3) - sage: Q([a,-2/3,a^2-1/2,a*2]) # implicit doctest + sage: K. = QQ[2^(1/5)]; Q. = QuaternionAlgebra(K,-a,a*17/3) # optional - sage.symbolic + sage: Q([a,-2/3,a^2-1/2,a*2]) # implicit doctest # optional - sage.symbolic a + (-2/3)*i + (a^2 - 1/2)*j + 2*a*k """ fmpz_poly_init(self.x) @@ -1688,8 +1688,8 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K,-a,a+1) - sage: Q([a,-2/3,a^2-1/2,a*2]) # implicit doctest + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K,-a,a+1) # optional - sage.symbolic + sage: Q([a,-2/3,a^2-1/2,a*2]) # implicit doctest # optional - sage.symbolic a + (-2/3)*i + (a^2 - 1/2)*j + 2*a*k """ self._parent = parent @@ -1732,21 +1732,21 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K,-a,a+1) - sage: Q([a,-2/3,a^2-1/2,a*2]) + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K,-a,a+1) # optional - sage.symbolic + sage: Q([a,-2/3,a^2-1/2,a*2]) # optional - sage.symbolic a + (-2/3)*i + (a^2 - 1/2)*j + 2*a*k - sage: x = Q([a,-2/3,a^2-1/2,a*2]) - sage: type(x) + sage: x = Q([a,-2/3,a^2-1/2,a*2]) # optional - sage.symbolic + sage: type(x) # optional - sage.symbolic - sage: x[0] + sage: x[0] # optional - sage.symbolic a - sage: x[1] + sage: x[1] # optional - sage.symbolic -2/3 - sage: x[2] + sage: x[2] # optional - sage.symbolic a^2 - 1/2 - sage: x[3] + sage: x[3] # optional - sage.symbolic 2*a - sage: list(x) + sage: list(x) # optional - sage.symbolic [a, -2/3, a^2 - 1/2, 2*a] """ # general number -- this code assumes that the number field is not quadratic!! @@ -1773,13 +1773,13 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) - sage: z = (i+j+k+a)^2; z + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) # optional - sage.symbolic + sage: z = (i+j+k+a)^2; z # optional - sage.symbolic a^2 + 4*a - 3 + 2*a*i + 2*a*j + 2*a*k - sage: f, t = z.__reduce__() - sage: f(*t) + sage: f, t = z.__reduce__() # optional - sage.symbolic + sage: f(*t) # optional - sage.symbolic a^2 + 4*a - 3 + 2*a*i + 2*a*j + 2*a*k - sage: loads(dumps(z)) == z + sage: loads(dumps(z)) == z # optional - sage.symbolic True """ return (unpickle_QuaternionAlgebraElement_number_field_v0, @@ -1791,11 +1791,12 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) - sage: z = a + i + (2/3)*a^3*j + (1+a)*k; w = a - i - (2/3)*a^3*j + (1/3+a)*k - sage: type(z) + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) # optional - sage.symbolic + sage: z = a + i + (2/3)*a^3*j + (1+a)*k # optional - sage.symbolic + sage: w = a - i - (2/3)*a^3*j + (1/3+a)*k # optional - sage.symbolic + sage: type(z) # optional - sage.symbolic - sage: z._add_(w) + sage: z._add_(w) # optional - sage.symbolic 2*a + (2*a + 4/3)*k Check that the fix in :trac:`17099` is correct:: @@ -1863,11 +1864,12 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) - sage: z = a + i + (2/3)*a^3*j + (1+a)*k; w = a - i - (2/3)*a^3*j + (1/3+a)*k - sage: type(z) + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) # optional - sage.symbolic + sage: z = a + i + (2/3)*a^3*j + (1+a)*k # optional - sage.symbolic + sage: w = a - i - (2/3)*a^3*j + (1/3+a)*k # optional - sage.symbolic + sage: type(z) # optional - sage.symbolic - sage: z._sub_(w) + sage: z._sub_(w) # optional - sage.symbolic 2*i + 8/3*j + 2/3*k """ # Implementation Note: To obtain _sub_, we simply replace every occurrence of @@ -1912,11 +1914,12 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) - sage: z = a + i + (2/3)*a^3*j + (1+a)*k; w = a - i - (2/3)*a^3*j + (1/3+a)*k - sage: type(z) + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) # optional - sage.symbolic + sage: z = a + i + (2/3)*a^3*j + (1+a)*k # optional - sage.symbolic + sage: w = a - i - (2/3)*a^3*j + (1/3+a)*k # optional - sage.symbolic + sage: type(z) # optional - sage.symbolic - sage: z._mul_(w) + sage: z._mul_(w) # optional - sage.symbolic 5*a^2 - 7/9*a + 9 + (-8/3*a^2 - 16/9*a)*i + (-6*a - 4)*j + (2*a^2 + 4/3*a)*k """ # We use the following formula for multiplication: @@ -2060,11 +2063,12 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra TESTS:: - sage: F = QQ[3^(1/3)] - sage: a = F.gen() - sage: K. = QuaternionAlgebra(F, -10 + a, -7 - a) - sage: ((1/4 + 1/2 * i + a^3/7 * j + a/28 * k)*14*i)^3 # implicit doctest - 34503/2*a^2 + 132195/2*a + 791399/4 + (203/8*a^2 - 10591*a + 169225/4)*i + (-84695/4*a^2 + 483413/8*a + 18591/4)*j + (-87/2*a^2 + 18156*a - 72525)*k + sage: F = QQ[3^(1/3)] # optional - sage.symbolic + sage: a = F.gen() # optional - sage.symbolic + sage: K. = QuaternionAlgebra(F, -10 + a, -7 - a) # optional - sage.symbolic + sage: ((1/4 + 1/2 * i + a^3/7 * j + a/28 * k)*14*i)^3 # implicit doctest # optional - sage.symbolic + 34503/2*a^2 + 132195/2*a + 791399/4 + (203/8*a^2 - 10591*a + 169225/4)*i + + (-84695/4*a^2 + 483413/8*a + 18591/4)*j + (-87/2*a^2 + 18156*a - 72525)*k """ # Note: this function changes the module-level global variables @@ -2137,11 +2141,11 @@ def unpickle_QuaternionAlgebraElement_number_field_v0(*args): """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a); z = i + j - sage: f, t = z.__reduce__() - sage: sage.algebras.quatalg.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a); z = i + j # optional - sage.symbolic + sage: f, t = z.__reduce__() # optional - sage.symbolic + sage: sage.algebras.quatalg.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) # optional - sage.symbolic i + j - sage: sage.algebras.quatalg.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) == z + sage: sage.algebras.quatalg.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) == z # optional - sage.symbolic True """ return QuaternionAlgebraElement_number_field(*args, check=False) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 48b1dee6075..efb148bb5b3 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -90,12 +90,12 @@ def repr_from_monomials(monomials, term_repr, use_latex=False): Leading minus signs are dealt with appropriately:: - sage: d = [(z, -4/7), (y, -sqrt(2)), (x, -5)] - sage: repr_from_monomials(d, lambda m: repr(m)) + sage: d = [(z, -4/7), (y, -sqrt(2)), (x, -5)] # optional - sage.symbolic + sage: repr_from_monomials(d, lambda m: repr(m)) # optional - sage.symbolic '-4/7*z - sqrt(2)*y - 5*x' - sage: a = repr_from_monomials(d, lambda m: latex(m), True); a + sage: a = repr_from_monomials(d, lambda m: latex(m), True); a # optional - sage.symbolic -\frac{4}{7} z - \sqrt{2} y - 5 x - sage: type(a) + sage: type(a) # optional - sage.symbolic Indirect doctests using a class that uses this function:: From c6b3d5719c0908ee7c102cff3d79403143a97cff Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 1 Jun 2023 23:00:42 -0700 Subject: [PATCH 120/538] sage.algebras: Add # optional --- .../finite_dimensional_algebra.py | 321 +++++++++++------- .../finite_dimensional_algebra_element.pyx | 137 +++++--- .../finite_dimensional_algebra_morphism.py | 32 +- 3 files changed, 313 insertions(+), 177 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index af2b5e7dd3c..67625148ecd 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -57,22 +57,28 @@ class FiniteDimensionalAlgebra(UniqueRepresentation, Algebra): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]); A Finite-dimensional algebra of degree 2 over Finite Field of size 3 - sage: TestSuite(A).run() + sage: TestSuite(A).run() # optional - sage.rings.finite_rings - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B Finite-dimensional algebra of degree 3 over Rational Field TESTS:: - sage: A.category() - Category of finite dimensional magmatic algebras with basis over Finite Field of size 3 - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])], assume_associative=True) - sage: A.category() - Category of finite dimensional associative algebras with basis over Finite Field of size 3 + sage: A.category() # optional - sage.rings.finite_rings + Category of finite dimensional magmatic algebras with basis + over Finite Field of size 3 + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])], + ....: assume_associative=True) + sage: A.category() # optional - sage.rings.finite_rings + Category of finite dimensional associative algebras with basis + over Finite Field of size 3 """ @staticmethod def __classcall_private__(cls, k, table, names='e', assume_associative=False, @@ -83,46 +89,47 @@ def __classcall_private__(cls, k, table, names='e', assume_associative=False, TESTS:: sage: table = [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])] - sage: A1 = FiniteDimensionalAlgebra(GF(3), table) - sage: A2 = FiniteDimensionalAlgebra(GF(3), table, names='e') - sage: A3 = FiniteDimensionalAlgebra(GF(3), table, names=['e0', 'e1']) - sage: A1 is A2 and A2 is A3 + sage: A1 = FiniteDimensionalAlgebra(GF(3), table) # optional - sage.rings.finite_rings + sage: A2 = FiniteDimensionalAlgebra(GF(3), table, names='e') # optional - sage.rings.finite_rings + sage: A3 = FiniteDimensionalAlgebra(GF(3), table, names=['e0', 'e1']) # optional - sage.rings.finite_rings + sage: A1 is A2 and A2 is A3 # optional - sage.rings.finite_rings True The ``assume_associative`` keyword is built into the category:: sage: from sage.categories.magmatic_algebras import MagmaticAlgebras - sage: cat = MagmaticAlgebras(GF(3)).FiniteDimensional().WithBasis() - sage: A1 = FiniteDimensionalAlgebra(GF(3), table, category=cat.Associative()) - sage: A2 = FiniteDimensionalAlgebra(GF(3), table, assume_associative=True) - sage: A1 is A2 + sage: cat = MagmaticAlgebras(GF(3)).FiniteDimensional().WithBasis() # optional - sage.rings.finite_rings + sage: A1 = FiniteDimensionalAlgebra(GF(3), table, # optional - sage.rings.finite_rings + ....: category=cat.Associative()) + sage: A2 = FiniteDimensionalAlgebra(GF(3), table, assume_associative=True) # optional - sage.rings.finite_rings + sage: A1 is A2 # optional - sage.rings.finite_rings True Uniqueness depends on the category:: - sage: cat = Algebras(GF(3)).FiniteDimensional().WithBasis() - sage: A1 = FiniteDimensionalAlgebra(GF(3), table) - sage: A2 = FiniteDimensionalAlgebra(GF(3), table, category=cat) - sage: A1 == A2 + sage: cat = Algebras(GF(3)).FiniteDimensional().WithBasis() # optional - sage.rings.finite_rings + sage: A1 = FiniteDimensionalAlgebra(GF(3), table) # optional - sage.rings.finite_rings + sage: A2 = FiniteDimensionalAlgebra(GF(3), table, category=cat) # optional - sage.rings.finite_rings + sage: A1 == A2 # optional - sage.rings.finite_rings False - sage: A1 is A2 + sage: A1 is A2 # optional - sage.rings.finite_rings False Checking that equality is still as expected:: - sage: A = FiniteDimensionalAlgebra(GF(3), table) - sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])]) - sage: A == A + sage: A = FiniteDimensionalAlgebra(GF(3), table) # optional - sage.rings.finite_rings + sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])]) # optional - sage.rings.finite_rings + sage: A == A # optional - sage.rings.finite_rings True - sage: B == B + sage: B == B # optional - sage.rings.finite_rings True - sage: A == B + sage: A == B # optional - sage.rings.finite_rings False - sage: A != A + sage: A != A # optional - sage.rings.finite_rings False - sage: B != B + sage: B != B # optional - sage.rings.finite_rings False - sage: A != B + sage: A != B # optional - sage.rings.finite_rings True """ n = len(table) @@ -154,17 +161,17 @@ def __init__(self, k, table, names='e', category=None): sage: TestSuite(A).run() - sage: B = FiniteDimensionalAlgebra(GF(7), [Matrix([1])]) - sage: B + sage: B = FiniteDimensionalAlgebra(GF(7), [Matrix([1])]) # optional - sage.rings.finite_rings + sage: B # optional - sage.rings.finite_rings Finite-dimensional algebra of degree 1 over Finite Field of size 7 - sage: TestSuite(B).run() + sage: TestSuite(B).run() # optional - sage.rings.finite_rings sage: C = FiniteDimensionalAlgebra(CC, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) sage: C Finite-dimensional algebra of degree 2 over Complex Field with 53 bits of precision sage: TestSuite(C).run() - sage: FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]])]) + sage: FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]])]) # optional - sage.rings.finite_rings Traceback (most recent call last): ... ValueError: input is not a multiplication table @@ -197,14 +204,15 @@ def _coerce_map_from_(self, S): """ TESTS:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.has_coerce_map_from(ZZ) + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.has_coerce_map_from(ZZ) # optional - sage.rings.finite_rings True - sage: A.has_coerce_map_from(GF(3)) + sage: A.has_coerce_map_from(GF(3)) # optional - sage.rings.finite_rings True - sage: A.has_coerce_map_from(GF(5)) + sage: A.has_coerce_map_from(GF(5)) # optional - sage.rings.finite_rings False - sage: A.has_coerce_map_from(QQ) + sage: A.has_coerce_map_from(QQ) # optional - sage.rings.finite_rings False """ return S == self or (self.base_ring().has_coerce_map_from(S) and self.is_unitary()) @@ -224,7 +232,9 @@ def _element_constructor_(self, x): ... TypeError: algebra is not unitary - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(17) 17*e0 + 17*e2 """ @@ -243,7 +253,9 @@ def _Hom_(self, B, category): sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([1])]) sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) sage: A._Hom_(B, A.category()) - Set of Homomorphisms from Finite-dimensional algebra of degree 1 over Rational Field to Finite-dimensional algebra of degree 2 over Rational Field + Set of Homomorphisms + from Finite-dimensional algebra of degree 1 over Rational Field + to Finite-dimensional algebra of degree 2 over Rational Field """ cat = MagmaticAlgebras(self.base_ring()).FiniteDimensional().WithBasis() if category.is_subcategory(cat): @@ -258,8 +270,9 @@ def ngens(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.ngens() + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.ngens() # optional - sage.rings.finite_rings 2 """ return len(self._table) @@ -273,8 +286,9 @@ def gen(self, i): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.gen(0) + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.gen(0) # optional - sage.rings.finite_rings e0 """ return self.element_class(self, [j == i for j in range(self.ngens())]) @@ -286,8 +300,9 @@ def basis(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.basis() + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.basis() # optional - sage.rings.finite_rings Family (e0, e1) """ from sage.sets.family import Family @@ -299,8 +314,9 @@ def __iter__(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: list(A) + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: list(A) # optional - sage.rings.finite_rings [0, e0, 2*e0, e1, e0 + e1, 2*e0 + e1, 2*e1, e0 + 2*e1, 2*e0 + 2*e1] This is used in the :class:`Testsuite`'s when ``self`` is @@ -319,8 +335,9 @@ def _ideal_class_(self, n=0): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A._ideal_class_() + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A._ideal_class_() # optional - sage.rings.finite_rings """ return FiniteDimensionalAlgebraIdeal @@ -332,8 +349,9 @@ def table(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.table() + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.table() # optional - sage.rings.finite_rings ( [1 0] [0 1] [0 1], [0 0] @@ -349,7 +367,8 @@ def left_table(self): EXAMPLES:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1],[-1,0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: T = B.left_table(); T ( [1 0] [ 0 1] @@ -381,9 +400,9 @@ def base_extend(self, F): EXAMPLES:: - sage: C = FiniteDimensionalAlgebra(GF(2), [Matrix([1])]) - sage: k. = GF(4) - sage: C.base_extend(k) + sage: C = FiniteDimensionalAlgebra(GF(2), [Matrix([1])]) # optional - sage.rings.finite_rings + sage: k. = GF(4) # optional - sage.rings.finite_rings + sage: C.base_extend(k) # optional - sage.rings.finite_rings Finite-dimensional algebra of degree 1 over Finite Field in y of size 2^2 """ # Base extension of the multiplication table is done by __classcall_private__. @@ -395,11 +414,13 @@ def cardinality(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(7), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [2, 3]])]) - sage: A.cardinality() + sage: A = FiniteDimensionalAlgebra(GF(7), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [2, 3]])]) + sage: A.cardinality() # optional - sage.rings.finite_rings 49 - sage: B = FiniteDimensionalAlgebra(RR, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [2, 3]])]) + sage: B = FiniteDimensionalAlgebra(RR, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [2, 3]])]) sage: B.cardinality() +Infinity @@ -431,9 +452,11 @@ def ideal(self, gens=None, given_by_matrix=False, side=None): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.ideal(A([1,1])) - Ideal (e0 + e1) of Finite-dimensional algebra of degree 2 over Finite Field of size 3 + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.ideal(A([1,1])) # optional - sage.rings.finite_rings + Ideal (e0 + e1) of + Finite-dimensional algebra of degree 2 over Finite Field of size 3 """ return self._ideal_class_()(self, gens=gens, given_by_matrix=given_by_matrix) @@ -445,11 +468,14 @@ def is_associative(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1],[-1,0]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: A.is_associative() True - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,1], [0,0,0], [1,0,0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,1], [0,0,0], [1,0,0]])]) sage: B.is_associative() False @@ -473,11 +499,15 @@ def is_commutative(self): EXAMPLES:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B.is_commutative() True - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,1,0], [0,0,1]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,1,0], [0,0,1]])]) sage: C.is_commutative() False """ @@ -495,11 +525,13 @@ def is_finite(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(7), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [2, 3]])]) - sage: A.is_finite() + sage: A = FiniteDimensionalAlgebra(GF(7), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [2, 3]])]) + sage: A.is_finite() # optional - sage.rings.finite_rings True - sage: B = FiniteDimensionalAlgebra(RR, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [2, 3]])]) + sage: B = FiniteDimensionalAlgebra(RR, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [2, 3]])]) sage: B.is_finite() False @@ -526,27 +558,35 @@ def is_unitary(self): sage: A.is_unitary() True - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: B.is_unitary() True - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[0,0], [0,0]]), Matrix([[0,0], [0,0]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[0,0], [0,0]]), + ....: Matrix([[0,0], [0,0]])]) sage: C.is_unitary() False - sage: D = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[1,0], [0,1]])]) + sage: D = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[1,0], [0,1]])]) sage: D.is_unitary() False - sage: E = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0],[1,0]]), Matrix([[0,1],[0,1]])]) + sage: E = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0],[1,0]]), + ....: Matrix([[0,1],[0,1]])]) sage: E.is_unitary() False - sage: F = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,1], [0,0,0], [1,0,0]])]) + sage: F = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,1], [0,0,0], [1,0,0]])]) sage: F.is_unitary() True - sage: G = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [1,0,0]])]) + sage: G = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [1,0,0]])]) sage: G.is_unitary() # Unique right identity, but no left identity. False """ @@ -583,8 +623,8 @@ def is_zero(self): sage: A.is_zero() True - sage: B = FiniteDimensionalAlgebra(GF(7), [Matrix([0])]) - sage: B.is_zero() + sage: B = FiniteDimensionalAlgebra(GF(7), [Matrix([0])]) # optional - sage.rings.finite_rings + sage: B.is_zero() # optional - sage.rings.finite_rings False """ return self.degree() == 0 @@ -600,21 +640,27 @@ def one(self): sage: A.one() 0 - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: B.one() e0 - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[0,0], [0,0]]), Matrix([[0,0], [0,0]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[0,0], [0,0]]), + ....: Matrix([[0,0], [0,0]])]) sage: C.one() Traceback (most recent call last): ... TypeError: algebra is not unitary - sage: D = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,1], [0,0,0], [1,0,0]])]) + sage: D = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,1], [0,0,0], [1,0,0]])]) sage: D.one() e0 - sage: E = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [1,0,0]])]) + sage: E = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,1]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [1,0,0]])]) sage: E.one() Traceback (most recent call last): ... @@ -634,11 +680,14 @@ def random_element(self, *args, **kwargs): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.random_element() # random + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.random_element() # random # optional - sage.rings.finite_rings e0 + 2*e1 - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B.random_element(num_bound=1000) # random 215/981*e0 + 709/953*e1 + 931/264*e2 """ @@ -648,32 +697,39 @@ def _is_valid_homomorphism_(self, other, im_gens, base_map=None): """ TESTS:: - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([1])]) sage: Hom(A, B)(Matrix([[1], [0]])) - Morphism from Finite-dimensional algebra of degree 2 over Rational Field to Finite-dimensional algebra of degree 1 over Rational Field given by matrix + Morphism from Finite-dimensional algebra of degree 2 over Rational Field + to Finite-dimensional algebra of degree 1 over Rational Field given by matrix [1] [0] sage: Hom(B, A)(Matrix([[1, 0]])) - Morphism from Finite-dimensional algebra of degree 1 over Rational Field to Finite-dimensional algebra of degree 2 over Rational Field given by matrix + Morphism from Finite-dimensional algebra of degree 1 over Rational Field + to Finite-dimensional algebra of degree 2 over Rational Field given by matrix [1 0] sage: H = Hom(A, A) sage: H(Matrix.identity(QQ, 2)) - Morphism from Finite-dimensional algebra of degree 2 over Rational Field to Finite-dimensional algebra of degree 2 over Rational Field given by matrix + Morphism from Finite-dimensional algebra of degree 2 over Rational Field + to Finite-dimensional algebra of degree 2 over Rational Field given by matrix [1 0] [0 1] sage: H(Matrix([[1, 0], [0, 0]])) - Morphism from Finite-dimensional algebra of degree 2 over Rational Field to Finite-dimensional algebra of degree 2 over Rational Field given by matrix + Morphism from Finite-dimensional algebra of degree 2 over Rational Field + to Finite-dimensional algebra of degree 2 over Rational Field given by matrix [1 0] [0 0] sage: H(Matrix([[1, 0], [1, 1]])) Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators sage: Hom(B, B)(Matrix([[2]])) Traceback (most recent call last): ... - ValueError: relations do not all (canonically) map to 0 under map determined by images of generators + ValueError: relations do not all (canonically) map to 0 + under map determined by images of generators """ assert len(im_gens) == self.degree() @@ -694,7 +750,7 @@ def quotient_map(self, ideal): INPUT: - - ``ideal`` -- a ``FiniteDimensionalAlgebraIdeal`` + - ``ideal`` -- a :class:`FiniteDimensionalAlgebraIdeal` OUTPUT: @@ -703,17 +759,22 @@ def quotient_map(self, ideal): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: q0 = A.quotient_map(A.zero_ideal()) - sage: q0 - Morphism from Finite-dimensional algebra of degree 2 over Finite Field of size 3 to Finite-dimensional algebra of degree 2 over Finite Field of size 3 given by matrix - [1 0] - [0 1] - sage: q1 = A.quotient_map(A.ideal(A.gen(1))) - sage: q1 - Morphism from Finite-dimensional algebra of degree 2 over Finite Field of size 3 to Finite-dimensional algebra of degree 1 over Finite Field of size 3 given by matrix - [1] - [0] + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: q0 = A.quotient_map(A.zero_ideal()); q0 # optional - sage.rings.finite_rings + Morphism + from Finite-dimensional algebra of degree 2 over Finite Field of size 3 + to Finite-dimensional algebra of degree 2 over Finite Field of size 3 + given by matrix + [1 0] + [0 1] + sage: q1 = A.quotient_map(A.ideal(A.gen(1))); q1 # optional - sage.rings.finite_rings + Morphism + from Finite-dimensional algebra of degree 2 over Finite Field of size 3 + to Finite-dimensional algebra of degree 1 over Finite Field of size 3 + given by matrix + [1] + [0] """ k = self.base_ring() f = ideal.basis_matrix().transpose().kernel().basis_matrix().echelon_form().transpose() @@ -744,11 +805,15 @@ def maximal_ideal(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.maximal_ideal() - Ideal (0, e1) of Finite-dimensional algebra of degree 2 over Finite Field of size 3 + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.maximal_ideal() # optional - sage.rings.finite_rings + Ideal (0, e1) of + Finite-dimensional algebra of degree 2 over Finite Field of size 3 - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B.maximal_ideal() Traceback (most recent call last): ... @@ -783,18 +848,31 @@ def primary_decomposition(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.primary_decomposition() - [Morphism from Finite-dimensional algebra of degree 2 over Finite Field of size 3 to Finite-dimensional algebra of degree 2 over Finite Field of size 3 given by matrix [1 0] - [0 1]] - - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.primary_decomposition() # optional - sage.rings.finite_rings + [Morphism + from Finite-dimensional algebra of degree 2 over Finite Field of size 3 + to Finite-dimensional algebra of degree 2 over Finite Field of size 3 + given by matrix [1 0] + [0 1]] + + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B.primary_decomposition() - [Morphism from Finite-dimensional algebra of degree 3 over Rational Field to Finite-dimensional algebra of degree 1 over Rational Field given by matrix [0] - [0] - [1], Morphism from Finite-dimensional algebra of degree 3 over Rational Field to Finite-dimensional algebra of degree 2 over Rational Field given by matrix [1 0] - [0 1] - [0 0]] + [Morphism + from Finite-dimensional algebra of degree 3 over Rational Field + to Finite-dimensional algebra of degree 1 over Rational Field + given by matrix [0] + [0] + [1], + Morphism + from Finite-dimensional algebra of degree 3 over Rational Field + to Finite-dimensional algebra of degree 2 over Rational Field + given by matrix [1 0] + [0 1] + [0 0]] """ k = self.base_ring() n = self.degree() @@ -838,8 +916,9 @@ def maximal_ideals(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) - sage: A.maximal_ideals() + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0, 1], [0, 0]])]) + sage: A.maximal_ideals() # optional - sage.rings.finite_rings [Ideal (e1) of Finite-dimensional algebra of degree 2 over Finite Field of size 3] sage: B = FiniteDimensionalAlgebra(QQ, []) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx index e4901439e19..d0724bca028 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx @@ -26,7 +26,9 @@ cpdef FiniteDimensionalAlgebraElement unpickle_FiniteDimensionalAlgebraElement(A TESTS:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[1,1,0], [0,1,1], [0,1,1]]), Matrix([[0,0,1], [0,1,0], [1,0,0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[1,1,0], [0,1,1], [0,1,1]]), + ....: Matrix([[0,0,1], [0,1,0], [1,0,0]])]) sage: x = B([1,2,3]) sage: loads(dumps(x)) == x # indirect doctest True @@ -59,23 +61,26 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) - sage: A(17) + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0,1], [0,0]])]) + sage: A(17) # optional - sage.rings.finite_rings 2*e0 - sage: A([1,1]) + sage: A([1,1]) # optional - sage.rings.finite_rings e0 + e1 """ def __init__(self, A, elt=None, check=True): """ TESTS:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) - sage: A(QQ(4)) + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0,1], [0,0]])]) + sage: A(QQ(4)) # optional - sage.rings.finite_rings Traceback (most recent call last): ... TypeError: elt should be a vector, a matrix, or an element of the base field - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: elt = B(Matrix([[1,1], [-1,1]])); elt e0 + e1 sage: TestSuite(elt).run() @@ -133,7 +138,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ TESTS:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[1,1,0], [0,1,1], [0,1,1]]), Matrix([[0,0,1], [0,1,0], [1,0,0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[1,1,0], [0,1,1], [0,1,1]]), + ....: Matrix([[0,0,1], [0,1,0], [1,0,0]])]) sage: x = B([1,2,3]) sage: loads(dumps(x)) == x # indirect doctest True @@ -149,7 +156,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): TESTS:: - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: x = A.element_class.__new__(A.element_class) sage: x.__setstate__((A, {'_vector':vector([1,1,1]), '_matrix':matrix(QQ,3,[1,1,0, 0,1,0, 0,0,1])})) sage: x @@ -183,7 +192,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ TESTS:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[1,1,0], [0,1,1], [0,1,1]]), Matrix([[0,0,1], [0,1,0], [1,0,0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[1,1,0], [0,1,1], [0,1,1]]), + ....: Matrix([[0,0,1], [0,1,0], [1,0,0]])]) sage: x = B([1,2,3]) sage: x._matrix [3 2 3] @@ -205,7 +216,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(5).vector() (5, 0, 5) """ @@ -220,7 +233,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(5).matrix() [5 0 0] [0 5 0] @@ -240,7 +255,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: elt = B(Matrix([[1,1], [-1,1]])) sage: elt.monomial_coefficients() {0: 1, 1: 1} @@ -254,7 +270,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,1,0], [0,0,1]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,1,0], [0,0,1]])]) sage: C([1,2,0]).left_matrix() [1 0 0] [0 1 0] @@ -272,8 +290,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) - sage: A(1) + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0,1], [0,0]])]) + sage: A(1) # optional - sage.rings.finite_rings e0 """ s = " " @@ -308,8 +327,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) - sage: latex(A(1)) # indirect doctest + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0,1], [0,0]])]) + sage: latex(A(1)) # indirect doctest # optional - sage.rings.finite_rings \left(\begin{array}{rr} 1 & 0 \\ 0 & 1 @@ -324,7 +344,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: A([2,1/4,3])[2] 3 """ @@ -334,7 +356,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: len(A([2,1/4,3])) 3 """ @@ -345,15 +369,18 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) - sage: A(2) == 2 + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0,1], [0,0]])]) + sage: A(2) == 2 # optional - sage.rings.finite_rings True - sage: A(2) == 3 + sage: A(2) == 3 # optional - sage.rings.finite_rings False - sage: A(2) == GF(5)(2) + sage: A(2) == GF(5)(2) # optional - sage.rings.finite_rings False - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(1) != 0 True @@ -362,13 +389,13 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): the algebra corresponds to the standard monomials of the relation ideal, when the algebra is considered as a quotient of a path algebra. :: - sage: A(1) > 0 + sage: A(1) > 0 # optional - sage.rings.finite_rings True - sage: A(1) < 0 + sage: A(1) < 0 # optional - sage.rings.finite_rings False - sage: A(1) >= 0 + sage: A(1) >= 0 # optional - sage.rings.finite_rings True - sage: A(1) <= 0 + sage: A(1) <= 0 # optional - sage.rings.finite_rings False """ return richcmp(self._vector, right._vector, op) @@ -377,8 +404,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) - sage: A.basis()[0] + A.basis()[1] + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0,1], [0,0]])]) + sage: A.basis()[0] + A.basis()[1] # optional - sage.rings.finite_rings e0 + e1 """ return self._parent.element_class(self._parent, self._vector + other._vector) @@ -387,8 +415,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) - sage: A.basis()[0] - A.basis()[1] + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + ....: Matrix([[0,1], [0,0]])]) + sage: A.basis()[0] - A.basis()[1] # optional - sage.rings.finite_rings e0 + 2*e1 """ return self._parent.element_class(self._parent, self._vector - other._vector) @@ -397,7 +426,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ EXAMPLES:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,1,0], [0,0,1]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,1,0], [0,0,1]])]) sage: C.basis()[1] * C.basis()[2] e1 """ @@ -407,7 +438,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ TESTS:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,1,0], [0,0,1]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,1,0], [0,0,1]])]) sage: c = C.random_element() sage: c * 2 == c + c True @@ -421,7 +454,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ TESTS:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,1,0], [0,0,1]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,1,0], [0,0,1]])]) sage: c = C.random_element() sage: 2 * c == c + c True @@ -438,7 +473,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: b = B([2,3,4]) sage: b^6 64*e0 + 576*e1 + 4096*e2 @@ -459,7 +496,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ TESTS:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: x = C([1,2]) sage: y = ~x; y # indirect doctest 1/5*e0 - 2/5*e1 @@ -486,7 +524,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: C([1,2]).is_invertible() True sage: C(0).is_invertible() @@ -505,7 +544,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: C([1,2])._inverse 1/5*e0 - 2/5*e1 sage: C(0)._inverse is None @@ -543,7 +583,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [-1,0]])]) sage: C([1,2]).inverse() 1/5*e0 - 2/5*e1 """ @@ -561,7 +602,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [0,0]])]) sage: C([1,0]).is_zerodivisor() False sage: C([0,1]).is_zerodivisor() @@ -575,7 +617,8 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])]) + sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), + ....: Matrix([[0,1], [0,0]])]) sage: C([1,0]).is_nilpotent() False sage: C([0,1]).is_nilpotent() @@ -596,7 +639,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(0).minimal_polynomial() x sage: b = B.random_element() @@ -625,7 +670,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), Matrix([[0,1,0], [0,0,0], [0,0,0]]), Matrix([[0,0,0], [0,0,0], [0,0,1]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), + ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), + ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) sage: B(0).characteristic_polynomial() x^3 sage: b = B.random_element() diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py index 22f12ce6bb5..eea375c01d0 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py @@ -41,7 +41,8 @@ class FiniteDimensionalAlgebraMorphism(RingHomomorphism_im_gens): EXAMPLES:: sage: from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_morphism import FiniteDimensionalAlgebraMorphism - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([1])]) sage: H = Hom(A, B) sage: f = H(Matrix([[1], [0]])) @@ -62,7 +63,8 @@ def __init__(self, parent, f, check=True, unitary=True): sage: from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_morphism import FiniteDimensionalAlgebraMorphism sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([1])]) - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: H = Hom(A, B) sage: phi = FiniteDimensionalAlgebraMorphism(H, Matrix([[1, 0]])) sage: TestSuite(phi).run(skip="_test_category") @@ -82,7 +84,8 @@ def _repr_(self): r""" TESTS:: - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: I = A.maximal_ideal() sage: q = A.quotient_map(I) sage: q._repr_() @@ -95,7 +98,8 @@ def __call__(self, x): """ TESTS:: - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: I = A.maximal_ideal() sage: q = A.quotient_map(I) sage: q(0) == 0 and q(1) == 1 @@ -112,7 +116,8 @@ def __eq__(self, other): TESTS:: sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([1])]) - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: H = Hom(A, B) sage: phi = H(Matrix([[1, 0]])) sage: psi = H(Matrix([[1, 0]])) @@ -132,7 +137,8 @@ def __ne__(self, other): TESTS:: sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([1])]) - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: H = Hom(A, B) sage: phi = H(Matrix([[1, 0]])) sage: psi = H(Matrix([[1, 0]])) @@ -149,7 +155,8 @@ def matrix(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([1])]) sage: M = Matrix([[1], [0]]) sage: H = Hom(A, B) @@ -169,11 +176,12 @@ def inverse_image(self, I): OUTPUT: - -- ``FiniteDimensionalAlgebraIdeal``, the inverse image of `I` under ``self``. + :class:`FiniteDimensionalAlgebraIdeal`, the inverse image of `I` under ``self``. EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: I = A.maximal_ideal() sage: q = A.quotient_map(I) sage: B = q.codomain() @@ -195,7 +203,8 @@ def zero(self): EXAMPLES:: sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([1])]) - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: H = Hom(A, B) sage: H.zero() Morphism from Finite-dimensional algebra of degree 1 over Rational Field to @@ -218,7 +227,8 @@ def __call__(self, f, check=True, unitary=True): EXAMPLES:: sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([1])]) - sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) + sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), + ....: Matrix([[0, 1], [0, 0]])]) sage: H = Hom(A, B) sage: H(Matrix([[1, 0]])) Morphism from Finite-dimensional algebra of degree 1 over Rational Field to From 6b25b45e0e3df18a37a9f12b610f3d0b1273992e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 3 Jun 2023 17:00:52 -0700 Subject: [PATCH 121/538] sage.algebras: Modularization fixes --- .../algebras/affine_nil_temperley_lieb.py | 1 + src/sage/algebras/algebra.py | 1 + src/sage/algebras/askey_wilson.py | 1 + src/sage/algebras/associated_graded.py | 1 + src/sage/algebras/catalog.py | 21 +- src/sage/algebras/cellular_basis.py | 1 + src/sage/algebras/clifford_algebra.py | 1 + .../algebras/clifford_algebra_element.pyx | 1 + src/sage/algebras/cluster_algebra.py | 8 +- src/sage/algebras/commutative_dga.py | 363 +++++++++++------- src/sage/algebras/down_up_algebra.py | 1 + .../algebras/exterior_algebra_groebner.pyx | 1 + src/sage/algebras/finite_gca.py | 1 + src/sage/algebras/free_algebra.py | 197 +++++----- src/sage/algebras/free_algebra_element.py | 2 +- src/sage/algebras/free_algebra_quotient.py | 31 +- .../algebras/free_algebra_quotient_element.py | 1 + src/sage/algebras/free_zinbiel_algebra.py | 27 +- src/sage/algebras/group_algebra.py | 1 + src/sage/algebras/hall_algebra.py | 1 + src/sage/algebras/iwahori_hecke_algebra.py | 1 + src/sage/algebras/nil_coxeter_algebra.py | 1 + src/sage/algebras/octonion_algebra.pyx | 1 + src/sage/algebras/orlik_solomon.py | 119 +++--- src/sage/algebras/orlik_terao.py | 1 + src/sage/algebras/q_commuting_polynomials.py | 1 + src/sage/algebras/q_system.py | 2 +- src/sage/algebras/quantum_clifford.py | 1 + .../algebras/quantum_groups/fock_space.py | 2 +- .../quantum_matrix_coordinate_algebra.py | 1 + src/sage/algebras/quaternion_algebra.py | 2 + .../algebras/quaternion_algebra_element.py | 2 + .../algebras/rational_cherednik_algebra.py | 1 + src/sage/algebras/schur_algebra.py | 1 + src/sage/algebras/shuffle_algebra.py | 2 +- src/sage/algebras/splitting_algebra.py | 2 +- .../algebras/steenrod/steenrod_algebra.py | 2 +- .../steenrod/steenrod_algebra_bases.py | 22 +- src/sage/algebras/tensor_algebra.py | 1 + src/sage/algebras/weyl_algebra.py | 1 + src/sage/algebras/yangian.py | 1 + src/sage/algebras/yokonuma_hecke_algebra.py | 1 + 42 files changed, 478 insertions(+), 352 deletions(-) diff --git a/src/sage/algebras/affine_nil_temperley_lieb.py b/src/sage/algebras/affine_nil_temperley_lieb.py index 720c5f481cd..8f88e2bb3b7 100644 --- a/src/sage/algebras/affine_nil_temperley_lieb.py +++ b/src/sage/algebras/affine_nil_temperley_lieb.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Affine nilTemperley Lieb Algebra of type A """ diff --git a/src/sage/algebras/algebra.py b/src/sage/algebras/algebra.py index 5aac6f22b9a..547eee6c699 100644 --- a/src/sage/algebras/algebra.py +++ b/src/sage/algebras/algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Abstract base class for algebras """ diff --git a/src/sage/algebras/askey_wilson.py b/src/sage/algebras/askey_wilson.py index 37303e030c3..1d597987c60 100644 --- a/src/sage/algebras/askey_wilson.py +++ b/src/sage/algebras/askey_wilson.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Askey-Wilson Algebras diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 5e9d7b1f6b9..9afb563923b 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules r""" Associated Graded Algebras To Filtered Algebras diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index efda74ed00e..ec48a6debed 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -84,17 +84,18 @@ ` """ -from sage.algebras.free_algebra import FreeAlgebra as Free -from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra as Quaternion -from sage.algebras.steenrod.steenrod_algebra import SteenrodAlgebra as Steenrod -from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra as FiniteDimensional -from sage.algebras.group_algebra import GroupAlgebra as Group -from sage.algebras.clifford_algebra import CliffordAlgebra as Clifford -from sage.algebras.clifford_algebra import ExteriorAlgebra as Exterior -from sage.algebras.weyl_algebra import DifferentialWeylAlgebra as DifferentialWeyl -from sage.algebras.lie_algebras.lie_algebra import LieAlgebra as Lie - from sage.misc.lazy_import import lazy_import +lazy_import('sage.algebras.free_algebra', 'FreeAlgebra', as_='Free') +lazy_import('sage.algebras.quatalg.quaternion_algebra', 'QuaternionAlgebra', as_='Quaternion') +lazy_import('sage.algebras.steenrod.steenrod_algebra', 'SteenrodAlgebra', as_='Steenrod') +lazy_import('sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra', + 'FiniteDimensionalAlgebra', as_='FiniteDimensional') +lazy_import('sage.algebras.group_algebra', 'GroupAlgebra', as_='Group') +lazy_import('sage.algebras.clifford_algebra', 'CliffordAlgebra', as_='Clifford') +lazy_import('sage.algebras.clifford_algebra', 'ExteriorAlgebra', as_='Exterior') +lazy_import('sage.algebras.weyl_algebra', 'DifferentialWeylAlgebra', as_='DifferentialWeyl') +lazy_import('sage.algebras.lie_algebras.lie_algebra', 'LieAlgebra', as_='Lie') + lazy_import('sage.algebras.iwahori_hecke_algebra', 'IwahoriHeckeAlgebra', 'IwahoriHecke') lazy_import('sage.algebras.nil_coxeter_algebra', 'NilCoxeterAlgebra', 'NilCoxeter') lazy_import('sage.algebras.free_zinbiel_algebra', 'FreeZinbielAlgebra', 'FreeZinbiel') diff --git a/src/sage/algebras/cellular_basis.py b/src/sage/algebras/cellular_basis.py index 873bd899b3e..62aeaa03bdd 100644 --- a/src/sage/algebras/cellular_basis.py +++ b/src/sage/algebras/cellular_basis.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Cellular Basis ============== diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index adb065e31b7..7d517534792 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules r""" Clifford Algebras diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index 0a1a4adb681..fc70360dab3 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules """ Clifford algebra elements diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index 14669dfed5c..8a468dad0e1 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.graphs sage.modules r""" Cluster algebras @@ -360,12 +361,11 @@ from sage.categories.rings import Rings from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver from sage.combinat.permutation import Permutation -from sage.geometry.cone import Cone -from sage.geometry.fan import Fan from sage.graphs.digraph import DiGraph from sage.matrix.constructor import identity_matrix, matrix from sage.matrix.special import block_matrix from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modules.free_module_element import vector from sage.rings.infinity import infinity @@ -380,6 +380,8 @@ from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation +lazy_import('sage.geometry.cone', 'Cone') +lazy_import('sage.geometry.fan', 'Fan') ############################################################################## # Elements of a cluster algebra @@ -2371,7 +2373,7 @@ def cluster_fan(self, depth=infinity): EXAMPLES:: sage: A = ClusterAlgebra(['A', 2]) - sage: A.cluster_fan() + sage: A.cluster_fan() # optional - sage.geometry.polyhedron Rational polyhedral fan in 2-d lattice N """ seeds = self.seeds(depth=depth, mutating_F=False) diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index 2b5f2ccffd1..39da2cd3772 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Commutative Differential Graded Algebras @@ -42,7 +43,8 @@ sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1,1,2)) sage: B = A.cdg_algebra({x: x*y, y: -x*y}) sage: B - Commutative Differential Graded Algebra with generators ('x', 'y', 'z') in degrees (1, 1, 2) over Rational Field with differential: + Commutative Differential Graded Algebra with generators ('x', 'y', 'z') + in degrees (1, 1, 2) over Rational Field with differential: x --> x*y y --> -x*y z --> 0 @@ -116,7 +118,7 @@ def sorting_keys(element): OUTPUT: - Its coordinates in the corresponding cohomology_raw quotient vector space + Its coordinates in the corresponding ``cohomology_raw`` quotient vector space EXAMPLES:: @@ -155,7 +157,8 @@ class Differential(UniqueRepresentation, Morphism, sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1, 1, 2, 3)) sage: B = A.cdg_algebra({x: x*y, y: -x*y , z: t}) sage: B - Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') in degrees (1, 1, 2, 3) over Rational Field with differential: + Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') + in degrees (1, 1, 2, 3) over Rational Field with differential: x --> x*y y --> -x*y z --> t @@ -181,7 +184,9 @@ def __classcall__(cls, A, im_gens): sage: A. = GradedCommutativeAlgebra(QQ,degrees=(2,2,3,3)) sage: A = A.quotient(A.ideal([a*u,b*u,x*u])) sage: A.cdg_algebra({x:a*b,a:u}) - Commutative Differential Graded Algebra with generators ('a', 'b', 'x', 'u') in degrees (2, 2, 3, 3) with relations [a*u, b*u, x*u] over Rational Field with differential: + Commutative Differential Graded Algebra with generators ('a', 'b', 'x', 'u') + in degrees (2, 2, 3, 3) with relations [a*u, b*u, x*u] over Rational Field + with differential: a --> u b --> 0 x --> a*b @@ -910,7 +915,8 @@ class GCAlgebra(UniqueRepresentation, QuotientRing_nc): 2 sage: B = A.quotient(A.ideal(a**2*b)) sage: B - Graded Commutative Algebra with generators ('a', 'b') in degrees (2, 3) with relations [a^2*b] over Rational Field + Graded Commutative Algebra with generators ('a', 'b') in degrees (2, 3) + with relations [a^2*b] over Rational Field sage: A.basis(7) [a^2*b] sage: B.basis(7) @@ -943,8 +949,8 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None, category= TESTS:: - sage: A1 = GradedCommutativeAlgebra(GF(2), 'x,y', (3, 6)) - sage: A2 = GradedCommutativeAlgebra(GF(2), ['x', 'y'], [3, 6]) + sage: A1 = GradedCommutativeAlgebra(GF(2), 'x,y', (3, 6)) # optional - sage.rings.finite_rings + sage: A2 = GradedCommutativeAlgebra(GF(2), ['x', 'y'], [3, 6]) # optional - sage.rings.finite_rings sage: A1 is A2 True @@ -956,8 +962,8 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None, category= sage: A4. = GradedCommutativeAlgebra(QQ, degrees=[4]) sage: z**2 == 0 False - sage: A5. = GradedCommutativeAlgebra(GF(2)) - sage: z**2 == 0 + sage: A5. = GradedCommutativeAlgebra(GF(2)) # optional - sage.rings.finite_rings + sage: z**2 == 0 # optional - sage.rings.finite_rings False """ if names is None: @@ -1201,18 +1207,19 @@ def quotient(self, I, check=True): EXAMPLES:: - sage: A. = GradedCommutativeAlgebra(GF(5), degrees=(2, 2, 3, 4)) - sage: I = A.ideal([x*t+z^2, x*y - t]) - sage: B = A.quotient(I) - sage: B - Graded Commutative Algebra with generators ('x', 'y', 'z', 't') in degrees (2, 2, 3, 4) with relations [x*t, x*y - t] over Finite Field of size 5 - sage: B(x*t) + sage: A. = GradedCommutativeAlgebra(GF(5), degrees=(2, 2, 3, 4)) # optional - sage.rings.finite_rings + sage: I = A.ideal([x*t+z^2, x*y - t]) # optional - sage.rings.finite_rings + sage: B = A.quotient(I); B # optional - sage.rings.finite_rings + Graded Commutative Algebra with generators ('x', 'y', 'z', 't') + in degrees (2, 2, 3, 4) with relations [x*t, x*y - t] + over Finite Field of size 5 + sage: B(x*t) # optional - sage.rings.finite_rings 0 - sage: B(x*y) + sage: B(x*y) # optional - sage.rings.finite_rings t - sage: A.basis(7) + sage: A.basis(7) # optional - sage.rings.finite_rings [x^2*z, x*y*z, y^2*z, z*t] - sage: B.basis(7) + sage: B.basis(7) # optional - sage.rings.finite_rings [x^2*z, y^2*z, z*t] """ if check and any(not i.is_homogeneous() for i in I.gens()): @@ -1304,13 +1311,22 @@ def _Hom_(self, B, category): sage: B. = GradedCommutativeAlgebra(QQ, degrees=(1,2,3)) sage: C. = GradedCommutativeAlgebra(GF(17)) sage: Hom(A,A) - Set of Homomorphisms from Graded Commutative Algebra with generators ('x', 'y') in degrees (1, 1) over Rational Field to Graded Commutative Algebra with generators ('x', 'y') in degrees (1, 1) over Rational Field + Set of Homomorphisms + from Graded Commutative Algebra with generators ('x', 'y') + in degrees (1, 1) over Rational Field + to Graded Commutative Algebra with generators ('x', 'y') + in degrees (1, 1) over Rational Field sage: Hom(A,B) - Set of Homomorphisms from Graded Commutative Algebra with generators ('x', 'y') in degrees (1, 1) over Rational Field to Graded Commutative Algebra with generators ('a', 'b', 'c') in degrees (1, 2, 3) over Rational Field + Set of Homomorphisms + from Graded Commutative Algebra with generators ('x', 'y') + in degrees (1, 1) over Rational Field + to Graded Commutative Algebra with generators ('a', 'b', 'c') + in degrees (1, 2, 3) over Rational Field sage: Hom(A,C) Traceback (most recent call last): ... - NotImplementedError: homomorphisms of graded commutative algebras have only been implemented when the base rings are the same + NotImplementedError: homomorphisms of graded commutative algebras + have only been implemented when the base rings are the same """ R = self.base_ring() # The base rings need to be checked before the categories, or @@ -1345,7 +1361,8 @@ def differential(self, diff): sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1, 1, 2)) sage: A.differential({y:x*y, x: x*y}) - Differential of Graded Commutative Algebra with generators ('x', 'y', 'z') in degrees (1, 1, 2) over Rational Field + Differential of Graded Commutative Algebra with generators ('x', 'y', 'z') + in degrees (1, 1, 2) over Rational Field Defn: x --> x*y y --> x*y z --> 0 @@ -1382,7 +1399,8 @@ def cdg_algebra(self, differential): sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1, 1, 1)) sage: B = A.cdg_algebra({a: b*c, b: a*c}) sage: B - Commutative Differential Graded Algebra with generators ('a', 'b', 'c') in degrees (1, 1, 1) over Rational Field with differential: + Commutative Differential Graded Algebra with generators ('a', 'b', 'c') + in degrees (1, 1, 1) over Rational Field with differential: a --> b*c b --> a*c c --> 0 @@ -1391,7 +1409,8 @@ def cdg_algebra(self, differential): sage: d = A.differential({a: b*c, b: a*c}) sage: d - Differential of Graded Commutative Algebra with generators ('a', 'b', 'c') in degrees (1, 1, 1) over Rational Field + Differential of Graded Commutative Algebra with generators ('a', 'b', 'c') + in degrees (1, 1, 1) over Rational Field Defn: a --> b*c b --> a*c c --> 0 @@ -1646,7 +1665,8 @@ class GCAlgebra_multigraded(GCAlgebra): sage: A. = GradedCommutativeAlgebra(QQ, degrees=((1,0), (0,1), (1,1))) sage: A - Graded Commutative Algebra with generators ('a', 'b', 'c') in degrees ((1, 0), (0, 1), (1, 1)) over Rational Field + Graded Commutative Algebra with generators ('a', 'b', 'c') + in degrees ((1, 0), (0, 1), (1, 1)) over Rational Field sage: a**2 0 sage: c.degree(total=True) @@ -1727,7 +1747,9 @@ def quotient(self, I, check=True): sage: I = A.ideal([x*t+z^2, x*y - t]) sage: B = A.quotient(I) sage: B - Graded Commutative Algebra with generators ('x', 'y', 'z', 't') in degrees (2, 2, 3, 4) with relations [x*t, x*y - t] over Finite Field of size 5 + Graded Commutative Algebra with generators ('x', 'y', 'z', 't') + in degrees (2, 2, 3, 4) with relations [x*t, x*y - t] + over Finite Field of size 5 sage: B(x*t) 0 sage: B(x*y) @@ -1823,7 +1845,8 @@ def differential(self, diff): sage: A. = GradedCommutativeAlgebra(QQ, degrees=((1,0), (0, 1), (0,2))) sage: A.differential({a: c}) - Differential of Graded Commutative Algebra with generators ('a', 'b', 'c') in degrees ((1, 0), (0, 1), (0, 2)) over Rational Field + Differential of Graded Commutative Algebra with generators ('a', 'b', 'c') + in degrees ((1, 0), (0, 1), (0, 2)) over Rational Field Defn: a --> c b --> 0 c --> 0 @@ -1855,13 +1878,15 @@ def cdg_algebra(self, differential): sage: A. = GradedCommutativeAlgebra(QQ, degrees=((1,0), (0, 1), (0,2))) sage: A.cdg_algebra({a: c}) - Commutative Differential Graded Algebra with generators ('a', 'b', 'c') in degrees ((1, 0), (0, 1), (0, 2)) over Rational Field with differential: + Commutative Differential Graded Algebra with generators ('a', 'b', 'c') + in degrees ((1, 0), (0, 1), (0, 2)) over Rational Field with differential: a --> c b --> 0 c --> 0 sage: d = A.differential({a: c}) sage: A.cdg_algebra(d) - Commutative Differential Graded Algebra with generators ('a', 'b', 'c') in degrees ((1, 0), (0, 1), (0, 2)) over Rational Field with differential: + Commutative Differential Graded Algebra with generators ('a', 'b', 'c') + in degrees ((1, 0), (0, 1), (0, 2)) over Rational Field with differential: a --> c b --> 0 c --> 0 @@ -1884,18 +1909,19 @@ def degree(self, total=False): EXAMPLES:: - sage: A. = GradedCommutativeAlgebra(GF(2), degrees=((1,0), (0,1), (1,1))) - sage: (a**2*b).degree() + sage: A. = GradedCommutativeAlgebra(GF(2), # optional - sage.rings.finite_rings + ....: degrees=((1,0), (0,1), (1,1))) + sage: (a**2*b).degree() # optional - sage.rings.finite_rings (2, 1) - sage: (a**2*b).degree(total=True) + sage: (a**2*b).degree(total=True) # optional - sage.rings.finite_rings 3 - sage: (a**2*b + c).degree() + sage: (a**2*b + c).degree() # optional - sage.rings.finite_rings Traceback (most recent call last): ... ValueError: this element is not homogeneous - sage: (a**2*b + c).degree(total=True) + sage: (a**2*b + c).degree(total=True) # optional - sage.rings.finite_rings 3 - sage: A(0).degree() + sage: A(0).degree() # optional - sage.rings.finite_rings Traceback (most recent call last): ... ValueError: the zero element does not have a well-defined degree @@ -1944,7 +1970,8 @@ class DifferentialGCAlgebra(GCAlgebra): sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3, 3)) sage: A.cdg_algebra({z: x*y}) - Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') in degrees (2, 2, 3, 3) over Rational Field with differential: + Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') + in degrees (2, 2, 3, 3) over Rational Field with differential: x --> 0 y --> 0 z --> x*y @@ -1954,7 +1981,8 @@ class DifferentialGCAlgebra(GCAlgebra): sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3, 3)) sage: A.cdg_algebra(differential={z: x*y}) - Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') in degrees (2, 2, 3, 3) over Rational Field with differential: + Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') + in degrees (2, 2, 3, 3) over Rational Field with differential: x --> 0 y --> 0 z --> x*y @@ -2052,13 +2080,17 @@ def cdg_algebra(self, differential): sage: B = A.quotient(A.ideal(x^3-z*t)) sage: C = B.cdg_algebra({y:t}) sage: C - Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') in degrees (2, 3, 2, 4) with relations [x^3 - z*t] over Finite Field of size 5 with differential: + Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') + in degrees (2, 3, 2, 4) with relations [x^3 - z*t] + over Finite Field of size 5 with differential: x --> 0 y --> t z --> 0 t --> 0 sage: C.cdg_algebra({}) - Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') in degrees (2, 3, 2, 4) with relations [x^3 - z*t] over Finite Field of size 5 with differential: + Commutative Differential Graded Algebra with generators ('x', 'y', 'z', 't') + in degrees (2, 3, 2, 4) with relations [x^3 - z*t] + over Finite Field of size 5 with differential: x --> 0 y --> 0 z --> 0 @@ -2168,7 +2200,8 @@ def differential(self, x=None): sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1,1,2)) sage: B = A.cdg_algebra({y:x*y, x: y*x}) sage: d = B.differential(); d - Differential of Commutative Differential Graded Algebra with generators ('x', 'y', 'z') in degrees (1, 1, 2) over Rational Field + Differential of Commutative Differential Graded Algebra + with generators ('x', 'y', 'z') in degrees (1, 1, 2) over Rational Field Defn: x --> -x*y y --> x*y z --> 0 @@ -2281,7 +2314,8 @@ def cohomology(self, n): sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1,1,1,1,1)) sage: B = A.cdg_algebra({d: a*b, e: b*c}) sage: B.cohomology(2) - Free module generated by {[a*c], [a*d], [b*d], [c*d - a*e], [b*e], [c*e]} over Rational Field + Free module generated by {[a*c], [a*d], [b*d], [c*d - a*e], [b*e], [c*e]} + over Rational Field Compare to :meth:`cohomology_raw`:: @@ -2354,21 +2388,23 @@ def cohomology_generators(self, max_degree): In contrast, the corresponding algebra in characteristic `p` has finitely generated cohomology:: - sage: A3. = GradedCommutativeAlgebra(GF(3), degrees=(1,2,2)) - sage: B3 = A3.cdg_algebra(differential={y: a*x}) - sage: B3.cohomology_generators(16) + sage: A3. = GradedCommutativeAlgebra(GF(3), degrees=(1,2,2)) # optional - sage.rings.finite_rings + sage: B3 = A3.cdg_algebra(differential={y: a*x}) # optional - sage.rings.finite_rings + sage: B3.cohomology_generators(16) # optional - sage.rings.finite_rings {1: [a], 2: [x], 3: [a*y], 5: [a*y^2], 6: [y^3]} This method works with both singly graded and multi-graded algebras:: - sage: Cs. = GradedCommutativeAlgebra(GF(2), degrees=(1,2,2,3)) - sage: Ds = Cs.cdg_algebra({a:c, b:d}) - sage: Ds.cohomology_generators(10) + sage: Cs. = GradedCommutativeAlgebra(GF(2), degrees=(1,2,2,3)) # optional - sage.rings.finite_rings + sage: Ds = Cs.cdg_algebra({a:c, b:d}) # optional - sage.rings.finite_rings + sage: Ds.cohomology_generators(10) # optional - sage.rings.finite_rings {2: [a^2], 4: [b^2]} - sage: Cm. = GradedCommutativeAlgebra(GF(2), degrees=((1,0), (1,1), (0,2), (0,3))) - sage: Dm = Cm.cdg_algebra({a:c, b:d}) - sage: Dm.cohomology_generators(10) + sage: Cm. = GradedCommutativeAlgebra(GF(2), # optional - sage.rings.finite_rings + ....: degrees=((1,0), (1,1), + ....: (0,2), (0,3))) + sage: Dm = Cm.cdg_algebra({a:c, b:d}) # optional - sage.rings.finite_rings + sage: Dm.cohomology_generators(10) # optional - sage.rings.finite_rings {2: [a^2], 4: [b^2]} TESTS: @@ -2459,13 +2495,17 @@ def minimal_model(self, i=3, max_iterations=3, partial_result=False): sage: T = p.domain() sage: p Commutative Differential Graded Algebra morphism: - From: Commutative Differential Graded Algebra with generators ('x1_0', 'x2_0') in degrees (1, 2) over Rational Field with differential: - x1_0 --> 0 - x2_0 --> 0 - To: Commutative Differential Graded Algebra with generators ('x', 'y', 'z') in degrees (1, 1, 2) over Rational Field with differential: - x --> x*y - y --> x*y - z --> 0 + From: Commutative Differential Graded Algebra + with generators ('x1_0', 'x2_0') in degrees (1, 2) + over Rational Field with differential: + x1_0 --> 0 + x2_0 --> 0 + To: Commutative Differential Graded Algebra + with generators ('x', 'y', 'z') in degrees (1, 1, 2) + over Rational Field with differential: + x --> x*y + y --> x*y + z --> 0 Defn: (x1_0, x2_0) --> (x - y, z) sage: R.cohomology(1) Free module generated by {[x - y]} over Rational Field @@ -2488,7 +2528,11 @@ def minimal_model(self, i=3, max_iterations=3, partial_result=False): sage: phi = B.minimal_model(i=3) sage: M = phi.domain() sage: M - Commutative Differential Graded Algebra with generators ('x1_0', 'x1_1', 'x1_2', 'x2_0', 'x2_1', 'x2_2', 'x2_3', 'y3_0', 'y3_1', 'y3_2', 'y3_3', 'y3_4', 'y3_5', 'y3_6', 'y3_7', 'y3_8') in degrees (1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) over Rational Field with differential: + Commutative Differential Graded Algebra with generators + ('x1_0', 'x1_1', 'x1_2', 'x2_0', 'x2_1', 'x2_2', 'x2_3', + 'y3_0', 'y3_1', 'y3_2', 'y3_3', 'y3_4', 'y3_5', 'y3_6', 'y3_7', 'y3_8') + in degrees (1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) + over Rational Field with differential: x1_0 --> 0 x1_1 --> 0 x1_2 --> 0 @@ -2508,32 +2552,40 @@ def minimal_model(self, i=3, max_iterations=3, partial_result=False): sage: phi Commutative Differential Graded Algebra morphism: - From: Commutative Differential Graded Algebra with generators ('x1_0', 'x1_1', 'x1_2', 'x2_0', 'x2_1', 'x2_2', 'x2_3', 'y3_0', 'y3_1', 'y3_2', 'y3_3', 'y3_4', 'y3_5', 'y3_6', 'y3_7', 'y3_8') in degrees (1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) over Rational Field with differential: - x1_0 --> 0 - x1_1 --> 0 - x1_2 --> 0 - x2_0 --> 0 - x2_1 --> 0 - x2_2 --> 0 - x2_3 --> 0 - y3_0 --> x2_0^2 - y3_1 --> x2_0*x2_1 - y3_2 --> x2_1^2 - y3_3 --> x2_0*x2_2 - y3_4 --> x2_1*x2_2 + x2_0*x2_3 - y3_5 --> x2_2^2 - y3_6 --> x2_1*x2_3 - y3_7 --> x2_2*x2_3 - y3_8 --> x2_3^2 - To: Commutative Differential Graded Algebra with generators ('e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7') in degrees (1, 1, 1, 1, 1, 1, 1) over Rational Field with differential: - e1 --> e1*e7 - e2 --> e2*e7 - e3 --> -e3*e7 - e4 --> -e4*e7 - e5 --> 0 - e6 --> 0 - e7 --> 0 - Defn: (x1_0, x1_1, x1_2, x2_0, x2_1, x2_2, x2_3, y3_0, y3_1, y3_2, y3_3, y3_4, y3_5, y3_6, y3_7, y3_8) --> (e5, e6, e7, e1*e3, e2*e3, e1*e4, e2*e4, 0, 0, 0, 0, 0, 0, 0, 0, 0) + From: Commutative Differential Graded Algebra with generators + ('x1_0', 'x1_1', 'x1_2', 'x2_0', 'x2_1', 'x2_2', 'x2_3', + 'y3_0', 'y3_1', 'y3_2', 'y3_3', 'y3_4', 'y3_5', 'y3_6', 'y3_7', 'y3_8') + in degrees (1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) + over Rational Field with differential: + x1_0 --> 0 + x1_1 --> 0 + x1_2 --> 0 + x2_0 --> 0 + x2_1 --> 0 + x2_2 --> 0 + x2_3 --> 0 + y3_0 --> x2_0^2 + y3_1 --> x2_0*x2_1 + y3_2 --> x2_1^2 + y3_3 --> x2_0*x2_2 + y3_4 --> x2_1*x2_2 + x2_0*x2_3 + y3_5 --> x2_2^2 + y3_6 --> x2_1*x2_3 + y3_7 --> x2_2*x2_3 + y3_8 --> x2_3^2 + To: Commutative Differential Graded Algebra with generators + ('e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7') + in degrees (1, 1, 1, 1, 1, 1, 1) over Rational Field with differential: + e1 --> e1*e7 + e2 --> e2*e7 + e3 --> -e3*e7 + e4 --> -e4*e7 + e5 --> 0 + e6 --> 0 + e7 --> 0 + Defn: (x1_0, x1_1, x1_2, x2_0, x2_1, x2_2, x2_3, + y3_0, y3_1, y3_2, y3_3, y3_4, y3_5, y3_6, y3_7, y3_8) + --> (e5, e6, e7, e1*e3, e2*e3, e1*e4, e2*e4, 0, 0, 0, 0, 0, 0, 0, 0, 0) sage: [B.cohomology(i).dimension() for i in [1..3]] [3, 7, 13] sage: [M.cohomology(i).dimension() for i in [1..3]] @@ -2772,7 +2824,8 @@ def cohomology_algebra(self, max_degree=3): sage: B = A.cdg_algebra(d) sage: M = B.cohomology_algebra() sage: M - Commutative Differential Graded Algebra with generators ('x0', 'x1', 'x2') in degrees (1, 1, 2) over Rational Field with differential: + Commutative Differential Graded Algebra with generators ('x0', 'x1', 'x2') + in degrees (1, 1, 2) over Rational Field with differential: x0 --> 0 x1 --> 0 x2 --> 0 @@ -2843,14 +2896,18 @@ def numerical_invariants(self, max_degree=3, max_iterations=3): sage: B = A.cdg_algebra({e3 : e1*e2}) sage: B.minimal_model(4) Commutative Differential Graded Algebra morphism: - From: Commutative Differential Graded Algebra with generators ('x1_0', 'x1_1', 'y1_0') in degrees (1, 1, 1) over Rational Field with differential: - x1_0 --> 0 - x1_1 --> 0 - y1_0 --> x1_0*x1_1 - To: Commutative Differential Graded Algebra with generators ('e1', 'e2', 'e3') in degrees (1, 1, 1) over Rational Field with differential: - e1 --> 0 - e2 --> 0 - e3 --> e1*e2 + From: Commutative Differential Graded Algebra with + generators ('x1_0', 'x1_1', 'y1_0') in degrees (1, 1, 1) + over Rational Field with differential: + x1_0 --> 0 + x1_1 --> 0 + y1_0 --> x1_0*x1_1 + To: Commutative Differential Graded Algebra with + generators ('e1', 'e2', 'e3') in degrees (1, 1, 1) + over Rational Field with differential: + e1 --> 0 + e2 --> 0 + e3 --> e1*e2 Defn: (x1_0, x1_1, y1_0) --> (e1, e2, e3) sage: B.numerical_invariants(2) {1: [2, 1, 0], 2: [0, 0]} @@ -2908,7 +2965,7 @@ def is_formal(self, i, max_iterations=3): EXAMPLES:: sage: A. = GradedCommutativeAlgebra(QQ) - sage: B = A.cdg_algebra({e5 : e1*e2 + e3*e4}) + sage: B = A.cdg_algebra({e5: e1*e2 + e3*e4}) sage: B.is_formal(1) True sage: B.is_formal(2) @@ -2946,7 +3003,7 @@ def differential(self): EXAMPLES:: - sage: A. = GradedCommutativeAlgebra(QQ, degrees = (2, 2, 3, 4)) + sage: A. = GradedCommutativeAlgebra(QQ, degrees=(2, 2, 3, 4)) sage: B = A.cdg_algebra({t: x*z, x: z, y: z}) sage: B.inject_variables() Defining x, y, z, t @@ -2973,9 +3030,9 @@ def is_coboundary(self): False sage: (x*z).is_coboundary() True - sage: (x*z+x*y).is_coboundary() + sage: (x*z + x*y).is_coboundary() False - sage: (x*z+y**2).is_coboundary() + sage: (x*z + y**2).is_coboundary() Traceback (most recent call last): ... ValueError: this element is not homogeneous @@ -3000,7 +3057,7 @@ def is_cohomologous_to(self, other): EXAMPLES:: sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1,1,1,1)) - sage: B = A.cdg_algebra(differential={a:b*c-c*d}) + sage: B = A.cdg_algebra(differential={a: b*c-c*d}) sage: w, x, y, z = B.gens() sage: (x*y).is_cohomologous_to(y*z) True @@ -3016,7 +3073,7 @@ def is_cohomologous_to(self, other): False sage: (x*y-y*z).is_cohomologous_to(x*y*z) True - sage: (x*y*z).is_cohomologous_to(0) # make sure 0 works + sage: (x*y*z).is_cohomologous_to(0) # make sure 0 works True """ if other.is_zero(): @@ -3036,17 +3093,17 @@ def cohomology_class(self): EXAMPLES:: sage: A. = GradedCommutativeAlgebra(QQ) - sage: B = A.cdg_algebra({e5:e1*e2+e3*e4}) + sage: B = A.cdg_algebra({e5: e1*e2+e3*e4}) sage: B.inject_variables() Defining e1, e2, e3, e4, e5 - sage: a = e1*e3*e5-3*e2*e3*e5 + sage: a = e1*e3*e5 - 3*e2*e3*e5 sage: a.cohomology_class() B[[e1*e3*e5]] - 3*B[[e2*e3*e5]] TESTS:: sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1, 2, 3)) - sage: B = A.cdg_algebra({a:b}) + sage: B = A.cdg_algebra({a: b}) sage: B.inject_variables() Defining a, b, c sage: b.cohomology_class() @@ -3057,10 +3114,10 @@ def cohomology_class(self): Check that the issue detected in :trac:`28155` is solved:: sage: A. = GradedCommutativeAlgebra(QQ) - sage: B = A.cdg_algebra({e5:e1*e2+e3*e4}) + sage: B = A.cdg_algebra({e5: e1*e2+e3*e4}) sage: B.inject_variables() Defining e1, e2, e3, e4, e5 - sage: a = e1*e3*e5-3*e2*e3*e5 + sage: a = e1*e3*e5 - 3*e2*e3*e5 sage: ca = a.cohomology_class() sage: C = B.cohomology(3) sage: ca in C @@ -3087,7 +3144,7 @@ def _cohomology_class_dict(self): EXAMPLES:: sage: A. = GradedCommutativeAlgebra(QQ) - sage: B = A.cdg_algebra({e5:e1*e2+e3*e4}) + sage: B = A.cdg_algebra({e5: e1*e2+e3*e4}) sage: a = B(e1*e3*e5-3*e2*e3*e5) sage: a._cohomology_class_dict() {(0, 0, 0, 0, 0, 0, 1, 0, 0): -3, (0, 0, 0, 0, 0, 1, 0, 0, 0): 1} @@ -3096,7 +3153,7 @@ def _cohomology_class_dict(self): x5 - 3*x6 sage: B.cohomology_generators(3) {1: [e1, e2, e3, e4], - 3: [e1*e2*e5 - e3*e4*e5, e1*e3*e5, e2*e3*e5, e1*e4*e5, e2*e4*e5]} + 3: [e1*e2*e5 - e3*e4*e5, e1*e3*e5, e2*e3*e5, e1*e4*e5, e2*e4*e5]} sage: [H(g._cohomology_class_dict()) for g in flatten(B.cohomology_generators(3).values())] [x0, x1, x2, x3, x4, x5, x6, x7, x8] """ @@ -3380,9 +3437,11 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, Defining a graded commutative algebra:: sage: GradedCommutativeAlgebra(QQ, 'x, y, z') - Graded Commutative Algebra with generators ('x', 'y', 'z') in degrees (1, 1, 1) over Rational Field + Graded Commutative Algebra with generators ('x', 'y', 'z') + in degrees (1, 1, 1) over Rational Field sage: GradedCommutativeAlgebra(QQ, degrees=(2, 3, 4)) - Graded Commutative Algebra with generators ('x0', 'x1', 'x2') in degrees (2, 3, 4) over Rational Field + Graded Commutative Algebra with generators ('x0', 'x1', 'x2') + in degrees (2, 3, 4) over Rational Field As usual in Sage, the ``A.<...>`` notation defines both the algebra and the generator names:: @@ -3390,21 +3449,21 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1, 1, 2)) sage: x^2 0 - sage: y*x # Odd classes anticommute. + sage: y*x # Odd classes anticommute. -x*y - sage: z*y # z is central since it is in degree 2. + sage: z*y # z is central since it is in degree 2. y*z sage: (x*y*z**3).degree() 8 - sage: A.basis(3) # basis of homogeneous degree 3 elements + sage: A.basis(3) # basis of homogeneous degree 3 elements [x*z, y*z] Defining a quotient:: sage: I = A.ideal(x*z) - sage: AQ = A.quotient(I) - sage: AQ - Graded Commutative Algebra with generators ('x', 'y', 'z') in degrees (1, 1, 2) with relations [x*z] over Rational Field + sage: AQ = A.quotient(I); AQ + Graded Commutative Algebra with generators ('x', 'y', 'z') + in degrees (1, 1, 2) with relations [x*z] over Rational Field sage: AQ.basis(3) [y*z] @@ -3421,14 +3480,15 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, Now we add a differential to ``AQ``:: - sage: B = AQ.cdg_algebra({z:y*z}) - sage: B - Commutative Differential Graded Algebra with generators ('x', 'y', 'z') in degrees (1, 1, 2) with relations [x*z] over Rational Field with differential: + sage: B = AQ.cdg_algebra({z: y*z}); B + Commutative Differential Graded Algebra with generators ('x', 'y', 'z') + in degrees (1, 1, 2) with relations [x*z] over Rational Field with differential: x --> 0 y --> 0 z --> y*z sage: B.differential() - Differential of Commutative Differential Graded Algebra with generators ('x', 'y', 'z') in degrees (1, 1, 2) with relations [x*z] over Rational Field + Differential of Commutative Differential Graded Algebra with generators + ('x', 'y', 'z') in degrees (1, 1, 2) with relations [x*z] over Rational Field Defn: x --> 0 y --> 0 z --> y*z @@ -3447,10 +3507,12 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, We can construct multi-graded rings as well. We work in characteristic 2 for a change, so the algebras here are honestly commutative:: - sage: C. = GradedCommutativeAlgebra(GF(2), degrees=((1,0), (1,1), (0,2), (0,3))) - sage: D = C.cdg_algebra(differential={a:c, b:d}) - sage: D - Commutative Differential Graded Algebra with generators ('a', 'b', 'c', 'd') in degrees ((1, 0), (1, 1), (0, 2), (0, 3)) over Finite Field of size 2 with differential: + sage: C. = GradedCommutativeAlgebra(GF(2), # optional - sage.rings.finite_rings + ....: degrees=((1,0), (1,1), (0,2), (0,3))) + sage: D = C.cdg_algebra(differential={a: c, b: d}); D # optional - sage.rings.finite_rings + Commutative Differential Graded Algebra with generators ('a', 'b', 'c', 'd') + in degrees ((1, 0), (1, 1), (0, 2), (0, 3)) over Finite Field of size 2 + with differential: a --> c b --> d c --> 0 @@ -3460,52 +3522,51 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, Use tuples, lists, vectors, or elements of additive abelian groups to specify degrees:: - sage: D.basis(3) # basis in total degree 3 + sage: D.basis(3) # basis in total degree 3 # optional - sage.rings.finite_rings [a^3, a*b, a*c, d] - sage: D.basis((1,2)) # basis in degree (1,2) + sage: D.basis((1,2)) # basis in degree (1,2) # optional - sage.rings.finite_rings [a*c] - sage: D.basis([1,2]) + sage: D.basis([1,2]) # optional - sage.rings.finite_rings [a*c] - sage: D.basis(vector([1,2])) + sage: D.basis(vector([1,2])) # optional - sage.rings.finite_rings [a*c] sage: G = AdditiveAbelianGroup([0,0]); G Additive abelian group isomorphic to Z + Z - sage: D.basis(G(vector([1,2]))) + sage: D.basis(G(vector([1,2]))) # optional - sage.rings.finite_rings [a*c] At this point, ``a``, for example, is an element of ``C``. We can redefine it so that it is instead an element of ``D`` in several ways, for instance using :meth:`gens` method:: - sage: a, b, c, d = D.gens() - sage: a.differential() + sage: a, b, c, d = D.gens() # optional - sage.rings.finite_rings + sage: a.differential() # optional - sage.rings.finite_rings c Or the :meth:`inject_variables` method:: - sage: D.inject_variables() + sage: D.inject_variables() # optional - sage.rings.finite_rings Defining a, b, c, d - sage: (a*b).differential() + sage: (a*b).differential() # optional - sage.rings.finite_rings b*c + a*d - sage: (a*b*c**2).degree() + sage: (a*b*c**2).degree() # optional - sage.rings.finite_rings (2, 5) Degrees are returned as elements of additive abelian groups:: - sage: (a*b*c**2).degree() in G + sage: (a*b*c**2).degree() in G # optional - sage.rings.finite_rings True - sage: (a*b*c**2).degree(total=True) # total degree + sage: (a*b*c**2).degree(total=True) # total degree # optional - sage.rings.finite_rings 7 - sage: D.cohomology(4) + sage: D.cohomology(4) # optional - sage.rings.finite_rings Free module generated by {[a^4], [b^2]} over Finite Field of size 2 - sage: D.cohomology((2,2)) + sage: D.cohomology((2,2)) # optional - sage.rings.finite_rings Free module generated by {[b^2]} over Finite Field of size 2 Graded algebra with maximal degree:: - sage: A. = GradedCommutativeAlgebra(QQ, degrees=(4,2), max_degree=6) - sage: A + sage: A. = GradedCommutativeAlgebra(QQ, degrees=(4,2), max_degree=6); A Graded commutative algebra with generators ('p', 'e') in degrees (4, 2) with maximal degree 6 sage: p^2 @@ -3563,7 +3624,8 @@ class GCAlgebraMorphism(RingHomomorphism_im_gens): sage: H = Hom(A,A) sage: f = H([y,x]) sage: f - Graded Commutative Algebra endomorphism of Graded Commutative Algebra with generators ('x', 'y') in degrees (1, 1) over Rational Field + Graded Commutative Algebra endomorphism of Graded Commutative Algebra + with generators ('x', 'y') in degrees (1, 1) over Rational Field Defn: (x, y) --> (y, x) sage: f(x*y) -x*y @@ -3590,7 +3652,8 @@ def __init__(self, parent, im_gens, check=True): sage: H = Hom(A,A) sage: f = H([x,x]) sage: f - Graded Commutative Algebra endomorphism of Graded Commutative Algebra with generators ('x', 'y') in degrees (1, 2) over Rational Field + Graded Commutative Algebra endomorphism of Graded Commutative Algebra + with generators ('x', 'y') in degrees (1, 2) over Rational Field Defn: (x, y) --> (x, x) sage: f.is_graded() False @@ -3608,7 +3671,8 @@ def __init__(self, parent, im_gens, check=True): sage: A2. = GradedCommutativeAlgebra(GF(2), degrees=(1,2)) sage: H2 = Hom(A2,A2) sage: H2([y,y]) - Graded Commutative Algebra endomorphism of Graded Commutative Algebra with generators ('x', 'y') in degrees (1, 2) over Finite Field of size 2 + Graded Commutative Algebra endomorphism of Graded Commutative Algebra + with generators ('x', 'y') in degrees (1, 2) over Finite Field of size 2 Defn: (x, y) --> (y, y) The "nc-relations" `a*b = -b*a`, for `a` and `b` in odd @@ -3652,7 +3716,8 @@ def __init__(self, parent, im_gens, check=True): sage: A.cover_ring() Multivariate Polynomial Ring in e1 over Rational Field sage: A.hom([2*e1]) - Graded Commutative Algebra endomorphism of Graded Commutative Algebra with generators ('e1',) in degrees (1,) over Rational Field + Graded Commutative Algebra endomorphism of Graded Commutative Algebra + with generators ('e1',) in degrees (1,) over Rational Field Defn: (e1,) --> (2*e1,) """ @@ -3834,13 +3899,17 @@ class GCAlgebraHomset(RingHomset_generic): sage: H = Hom(A,B) sage: H([y,0]) Graded Commutative Algebra morphism: - From: Graded Commutative Algebra with generators ('w', 'x') in degrees (1, 2) over Rational Field - To: Graded Commutative Algebra with generators ('y', 'z') in degrees (1, 1) over Rational Field + From: Graded Commutative Algebra with generators ('w', 'x') + in degrees (1, 2) over Rational Field + To: Graded Commutative Algebra with generators ('y', 'z') + in degrees (1, 1) over Rational Field Defn: (w, x) --> (y, 0) sage: H([y,y*z]) Graded Commutative Algebra morphism: - From: Graded Commutative Algebra with generators ('w', 'x') in degrees (1, 2) over Rational Field - To: Graded Commutative Algebra with generators ('y', 'z') in degrees (1, 1) over Rational Field + From: Graded Commutative Algebra with generators ('w', 'x') + in degrees (1, 2) over Rational Field + To: Graded Commutative Algebra with generators ('y', 'z') + in degrees (1, 1) over Rational Field Defn: (w, x) --> (y, y*z) """ @@ -4085,7 +4154,7 @@ def total_degree(deg): INPUT: - - ``deg`` - an element of a free abelian group. + - ``deg`` -- an element of a free abelian group. In fact, ``deg`` could be an integer, a Python int, a list, a tuple, a vector, etc. This function returns the sum of the diff --git a/src/sage/algebras/down_up_algebra.py b/src/sage/algebras/down_up_algebra.py index 3ee1bcea25f..b39c86b3d4f 100644 --- a/src/sage/algebras/down_up_algebra.py +++ b/src/sage/algebras/down_up_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules r""" Down-Up Algebras diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 376eb454082..ee54b5e4baf 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules r""" Exterior algebras Gröbner bases diff --git a/src/sage/algebras/finite_gca.py b/src/sage/algebras/finite_gca.py index 5f21cdc8290..9c76ddf3199 100644 --- a/src/sage/algebras/finite_gca.py +++ b/src/sage/algebras/finite_gca.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules r""" Finite dimensional graded commutative algebras diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index 460b623b877..eaddfc54e5a 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.combinat sage.modules """ Free algebras @@ -17,11 +17,12 @@ EXAMPLES:: - sage: F = FreeAlgebra(ZZ,3,'x,y,z') + sage: F = FreeAlgebra(ZZ, 3, 'x,y,z') sage: F.base_ring() Integer Ring sage: G = FreeAlgebra(F, 2, 'm,n'); G - Free Algebra on 2 generators (m, n) over Free Algebra on 3 generators (x, y, z) over Integer Ring + Free Algebra on 2 generators (m, n) over + Free Algebra on 3 generators (x, y, z) over Integer Ring sage: G.base_ring() Free Algebra on 3 generators (x, y, z) over Integer Ring @@ -34,11 +35,10 @@ Moreover, we can compute Groebner bases with degree bound for its two-sided ideals, and thus provide ideal containment tests:: - sage: F. = FreeAlgebra(QQ, implementation='letterplace') - sage: F + sage: F. = FreeAlgebra(QQ, implementation='letterplace'); F # optional - sage.libs.singular Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F - sage: I.groebner_basis(degbound=4) + sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F # optional - sage.libs.singular + sage: I.groebner_basis(degbound=4) # optional - sage.libs.singular Twosided Ideal (x*y + y*z, x*x - y*x - y*y - y*z, y*y*y - y*y*z + y*z*y - y*z*z, @@ -48,67 +48,67 @@ y*y*z*x + y*y*z*z + y*z*z*x + y*z*z*z, y*z*y*x + y*z*y*z + y*z*z*x + y*z*z*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field - sage: y*z*y*y*z*z + 2*y*z*y*z*z*x + y*z*y*z*z*z - y*z*z*y*z*x + y*z*z*z*z*x in I + sage: y*z*y*y*z*z + 2*y*z*y*z*z*x + y*z*y*z*z*z - y*z*z*y*z*x + y*z*z*z*z*x in I # optional - sage.libs.singular True Positive integral degree weights for the letterplace implementation was introduced in :trac:`7797`:: - sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) - sage: x.degree() + sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) # optional - sage.libs.singular + sage: x.degree() # optional - sage.libs.singular 2 - sage: y.degree() + sage: y.degree() # optional - sage.libs.singular 1 - sage: z.degree() + sage: z.degree() # optional - sage.libs.singular 3 - sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F - sage: Q. = F.quo(I) - sage: TestSuite(Q).run() - sage: a^2*b^2 + sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F # optional - sage.libs.singular + sage: Q. = F.quo(I) # optional - sage.libs.singular + sage: TestSuite(Q).run() # optional - sage.libs.singular + sage: a^2*b^2 # optional - sage.libs.singular c*c TESTS:: - sage: F = FreeAlgebra(GF(5),3,'x') - sage: TestSuite(F).run() - sage: F is loads(dumps(F)) + sage: F = FreeAlgebra(GF(5),3,'x') # optional - sage.rings.finite_rings + sage: TestSuite(F).run() # optional - sage.rings.finite_rings + sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings True - sage: F = FreeAlgebra(GF(5),3,'x', implementation='letterplace') - sage: TestSuite(F).run() - sage: F is loads(dumps(F)) + sage: F = FreeAlgebra(GF(5),3,'x', implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: TestSuite(F).run() # optional - sage.libs.singular sage.rings.finite_rings + sage: F is loads(dumps(F)) # optional - sage.libs.singular sage.rings.finite_rings True :: - sage: F. = FreeAlgebra(GF(5),3) - sage: TestSuite(F).run() - sage: F is loads(dumps(F)) + sage: F. = FreeAlgebra(GF(5),3) # optional - sage.rings.finite_rings + sage: TestSuite(F).run() # optional - sage.rings.finite_rings + sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings True - sage: F. = FreeAlgebra(GF(5),3, implementation='letterplace') - sage: TestSuite(F).run() - sage: F is loads(dumps(F)) + sage: F. = FreeAlgebra(GF(5),3, implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: TestSuite(F).run() # optional - sage.libs.singular sage.rings.finite_rings + sage: F is loads(dumps(F)) # optional - sage.libs.singular sage.rings.finite_rings True :: - sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y']) - sage: TestSuite(F).run() - sage: F is loads(dumps(F)) + sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y']) # optional - sage.rings.finite_rings + sage: TestSuite(F).run() # optional - sage.rings.finite_rings + sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings True - sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'], implementation='letterplace') - sage: TestSuite(F).run() - sage: F is loads(dumps(F)) + sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'], implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: TestSuite(F).run() # optional - sage.libs.singular sage.rings.finite_rings + sage: F is loads(dumps(F)) # optional - sage.libs.singular sage.rings.finite_rings True :: - sage: F = FreeAlgebra(GF(5),3, 'abc') - sage: TestSuite(F).run() - sage: F is loads(dumps(F)) + sage: F = FreeAlgebra(GF(5),3, 'abc') # optional - sage.rings.finite_rings + sage: TestSuite(F).run() # optional - sage.rings.finite_rings + sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings True - sage: F = FreeAlgebra(GF(5),3, 'abc', implementation='letterplace') - sage: TestSuite(F).run() - sage: F is loads(dumps(F)) + sage: F = FreeAlgebra(GF(5),3, 'abc', implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: TestSuite(F).run() # optional - sage.libs.singular sage.rings.finite_rings + sage: F is loads(dumps(F)) # optional - sage.libs.singular sage.rings.finite_rings True :: @@ -121,7 +121,7 @@ Note that the letterplace implementation can only be used if the corresponding (multivariate) polynomial ring has an implementation in Singular:: - sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace') + sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError: polynomials over Free Algebra on 2 generators (a, b) over Integer Ring are not supported in Singular @@ -165,21 +165,22 @@ class FreeAlgebraFactory(UniqueFactory): EXAMPLES:: - sage: FreeAlgebra(GF(5),3,'x') + sage: FreeAlgebra(GF(5),3,'x') # optional - sage.rings.finite_rings Free Algebra on 3 generators (x0, x1, x2) over Finite Field of size 5 - sage: F. = FreeAlgebra(GF(5),3) - sage: (x+y+z)^2 + sage: F. = FreeAlgebra(GF(5),3) # optional - sage.rings.finite_rings + sage: (x+y+z)^2 # optional - sage.rings.finite_rings x^2 + x*y + x*z + y*x + y^2 + y*z + z*x + z*y + z^2 - sage: FreeAlgebra(GF(5),3, 'xx, zba, Y') + sage: FreeAlgebra(GF(5),3, 'xx, zba, Y') # optional - sage.rings.finite_rings Free Algebra on 3 generators (xx, zba, Y) over Finite Field of size 5 - sage: FreeAlgebra(GF(5),3, 'abc') + sage: FreeAlgebra(GF(5),3, 'abc') # optional - sage.rings.finite_rings Free Algebra on 3 generators (a, b, c) over Finite Field of size 5 - sage: FreeAlgebra(GF(5),1, 'z') + sage: FreeAlgebra(GF(5),1, 'z') # optional - sage.rings.finite_rings Free Algebra on 1 generators (z,) over Finite Field of size 5 - sage: FreeAlgebra(GF(5),1, ['alpha']) + sage: FreeAlgebra(GF(5),1, ['alpha']) # optional - sage.rings.finite_rings Free Algebra on 1 generators (alpha,) over Finite Field of size 5 sage: FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x') - Free Algebra on 2 generators (x0, x1) over Free Algebra on 1 generators (a,) over Integer Ring + Free Algebra on 2 generators (x0, x1) over + Free Algebra on 1 generators (a,) over Integer Ring Free algebras are globally unique:: @@ -187,14 +188,14 @@ class FreeAlgebraFactory(UniqueFactory): sage: G = FreeAlgebra(ZZ,3,'x,y,z') sage: F is G True - sage: F. = FreeAlgebra(GF(5),3) # indirect doctest - sage: F is loads(dumps(F)) + sage: F. = FreeAlgebra(GF(5),3) # indirect doctest # optional - sage.rings.finite_rings + sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings True - sage: F is FreeAlgebra(GF(5),['x','y','z']) + sage: F is FreeAlgebra(GF(5),['x','y','z']) # optional - sage.rings.finite_rings True - sage: copy(F) is F is loads(dumps(F)) + sage: copy(F) is F is loads(dumps(F)) # optional - sage.rings.finite_rings True - sage: TestSuite(F).run() + sage: TestSuite(F).run() # optional - sage.rings.finite_rings By :trac:`7797`, we provide a different implementation of free algebras, based on Singular's "letterplace rings". Our letterplace @@ -203,25 +204,27 @@ class FreeAlgebraFactory(UniqueFactory): elements are supported. Of course, isomorphic algebras in different implementations are not identical:: - sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') - sage: F == G + sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: F == G # optional - sage.libs.singular sage.rings.finite_rings False - sage: G is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') + sage: G is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings True - sage: copy(G) is G is loads(dumps(G)) + sage: copy(G) is G is loads(dumps(G)) # optional - sage.libs.singular sage.rings.finite_rings True - sage: TestSuite(G).run() + sage: TestSuite(G).run() # optional - sage.libs.singular sage.rings.finite_rings :: - sage: H = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', degrees=[1,2,3]) - sage: F != H != G + sage: H = FreeAlgebra(GF(5), ['x','y','z'], implementation='letterplace', # optional - sage.libs.singular sage.rings.finite_rings + ....: degrees=[1,2,3]) + sage: F != H != G # optional - sage.libs.singular sage.rings.finite_rings True - sage: H is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', degrees=[1,2,3]) + sage: H is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', # optional - sage.libs.singular sage.rings.finite_rings + ....: degrees=[1,2,3]) True - sage: copy(H) is H is loads(dumps(H)) + sage: copy(H) is H is loads(dumps(H)) # optional - sage.libs.singular sage.rings.finite_rings True - sage: TestSuite(H).run() + sage: TestSuite(H).run() # optional - sage.libs.singular sage.rings.finite_rings Free algebras commute with their base ring. :: @@ -235,7 +238,8 @@ class FreeAlgebraFactory(UniqueFactory): sage: s = a*b^2 * c^3; s a*b^2*c^3 sage: parent(s) - Free Algebra on 1 generators (c,) over Free Algebra on 2 generators (a, b) over Rational Field + Free Algebra on 1 generators (c,) over + Free Algebra on 2 generators (a, b) over Rational Field sage: c^3 * a * b^2 a*b^2*c^3 """ @@ -248,19 +252,23 @@ def create_key(self, base_ring, arg1=None, arg2=None, TESTS:: - sage: FreeAlgebra.create_key(GF(5),['x','y','z']) + sage: FreeAlgebra.create_key(GF(5),['x','y','z']) # optional - sage.rings.finite_rings (Finite Field of size 5, ('x', 'y', 'z')) - sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3) + sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3) # optional - sage.rings.finite_rings (Finite Field of size 5, ('x', 'y', 'z')) - sage: FreeAlgebra.create_key(GF(5),3,'xyz') + sage: FreeAlgebra.create_key(GF(5),3,'xyz') # optional - sage.rings.finite_rings (Finite Field of size 5, ('x', 'y', 'z')) - sage: FreeAlgebra.create_key(GF(5),['x','y','z'], implementation='letterplace') + sage: FreeAlgebra.create_key(GF(5),['x','y','z'], # optional - sage.libs.singular sage.rings.finite_rings + ....: implementation='letterplace') (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) - sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, implementation='letterplace') + sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, # optional - sage.libs.singular sage.rings.finite_rings + ....: implementation='letterplace') (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) - sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace') + sage: FreeAlgebra.create_key(GF(5),3,'xyz', # optional - sage.libs.singular sage.rings.finite_rings + ....: implementation='letterplace') (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) - sage: FreeAlgebra.create_key(GF(5),3,'xyz', implementation='letterplace', degrees=[1,2,3]) + sage: FreeAlgebra.create_key(GF(5),3,'xyz', # optional - sage.libs.singular sage.rings.finite_rings + ....: implementation='letterplace', degrees=[1,2,3]) ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5) """ @@ -543,21 +551,21 @@ def _element_constructor_(self, x): TESTS:: - sage: F. = FreeAlgebra(GF(5),3) - sage: L. = FreeAlgebra(ZZ,3,implementation='letterplace') - sage: F(x) # indirect doctest + sage: F. = FreeAlgebra(GF(5),3) # optional - sage.rings.finite_rings + sage: L. = FreeAlgebra(ZZ,3,implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: F(x) # indirect doctest # optional - sage.libs.singular sage.rings.finite_rings x - sage: F.1*L.2 + sage: F.1*L.2 # optional - sage.libs.singular sage.rings.finite_rings y*z - sage: (F.1*L.2).parent() is F + sage: (F.1*L.2).parent() is F # optional - sage.libs.singular sage.rings.finite_rings True :: - sage: K. = GF(25) - sage: F. = FreeAlgebra(K,3) - sage: L. = FreeAlgebra(K,3, implementation='letterplace') - sage: F.1+(z+1)*L.2 + sage: K. = GF(25) # optional - sage.rings.finite_rings + sage: F. = FreeAlgebra(K,3) # optional - sage.rings.finite_rings + sage: L. = FreeAlgebra(K,3, implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: F.1+(z+1)*L.2 # optional - sage.libs.singular sage.rings.finite_rings b + (z+1)*c Check that :trac:`15169` is fixed:: @@ -667,23 +675,23 @@ def _coerce_map_from_(self, R): sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z')) False - sage: K. = GF(25) - sage: F. = FreeAlgebra(K,3) - sage: F._coerce_map_from_(ZZ) + sage: K. = GF(25) # optional - sage.rings.finite_rings + sage: F. = FreeAlgebra(K,3) # optional - sage.rings.finite_rings + sage: F._coerce_map_from_(ZZ) # optional - sage.rings.finite_rings True - sage: F._coerce_map_from_(QQ) + sage: F._coerce_map_from_(QQ) # optional - sage.rings.finite_rings False - sage: F._coerce_map_from_(F.monoid()) + sage: F._coerce_map_from_(F.monoid()) # optional - sage.rings.finite_rings True - sage: F._coerce_map_from_(F.pbw_basis()) + sage: F._coerce_map_from_(F.pbw_basis()) # optional - sage.rings.finite_rings True sage: G = FreeAlgebra(ZZ, 3, 'a,b,c') - sage: F._coerce_map_from_(G) + sage: F._coerce_map_from_(G) # optional - sage.rings.finite_rings True - sage: G._coerce_map_from_(F) + sage: G._coerce_map_from_(F) # optional - sage.rings.finite_rings False - sage: L. = FreeAlgebra(K,3, implementation='letterplace') - sage: F.1 + (z+1) * L.2 + sage: L. = FreeAlgebra(K,3, implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: F.1 + (z+1) * L.2 # optional - sage.libs.singular sage.rings.finite_rings b + (z+1)*c """ if self._indices.has_coerce_map_from(R): @@ -780,9 +788,12 @@ def quotient(self, mons, mats=None, names=None, **args): sage: i, j, k = F.gens() sage: mons = [ F(1), i, j, k ] sage: M = MatrixSpace(QQ,4) - sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]), M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ] + sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), + ....: M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]), + ....: M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ] sage: H. = A.quotient(mons, mats); H - Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Rational Field + Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 + over Rational Field """ if mats is None: return super().quotient(mons, names) diff --git a/src/sage/algebras/free_algebra_element.py b/src/sage/algebras/free_algebra_element.py index 559df673fbf..f5bf4277f16 100644 --- a/src/sage/algebras/free_algebra_element.py +++ b/src/sage/algebras/free_algebra_element.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.combinat sage.modules """ Free algebra elements diff --git a/src/sage/algebras/free_algebra_quotient.py b/src/sage/algebras/free_algebra_quotient.py index b19884335c4..d79b9a2ac47 100644 --- a/src/sage/algebras/free_algebra_quotient.py +++ b/src/sage/algebras/free_algebra_quotient.py @@ -21,11 +21,12 @@ sage: A = FreeAlgebra(QQ,n,'x') sage: F = A.monoid() sage: i, j = F.gens() - sage: mons = [ F(1), i, j, i*j ] + sage: mons = [F(1), i, j, i*j] sage: r = len(mons) sage: M = MatrixSpace(QQ,r) - sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]) ] - sage: H2. = A.quotient(mons,mats) + sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), +....: M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]) ] + sage: H2. = A.quotient(mons, mats) sage: H2 == loads(dumps(H2)) True sage: i == loads(dumps(i)) @@ -106,15 +107,20 @@ def __init__(self, A, mons, mats, names): sage: A = FreeAlgebra(QQ,n,'i') sage: F = A.monoid() sage: i, j, k = F.gens() - sage: mons = [ F(1), i, j, k ] + sage: mons = [F(1), i, j, k] sage: M = MatrixSpace(QQ,4) - sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]), M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ] + sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), + ....: M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]), + ....: M([0,0,0,1, 0,0,-1,0, 0,1,0,0, -1,0,0,0]) ] sage: H3. = FreeAlgebraQuotient(A,mons,mats) sage: x = 1 + i + j + k sage: x 1 + i + j + k sage: x**128 - -170141183460469231731687303715884105728 + 170141183460469231731687303715884105728*i + 170141183460469231731687303715884105728*j + 170141183460469231731687303715884105728*k + -170141183460469231731687303715884105728 + + 170141183460469231731687303715884105728*i + + 170141183460469231731687303715884105728*j + + 170141183460469231731687303715884105728*k Same algebra defined in terms of two generators, with some penalty on already slow arithmetic. @@ -128,14 +134,18 @@ def __init__(self, A, mons, mats, names): sage: mons = [ F(1), i, j, i*j ] sage: r = len(mons) sage: M = MatrixSpace(QQ,r) - sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]) ] + sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), + ....: M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]) ] sage: H2. = A.quotient(mons,mats) sage: k = i*j sage: x = 1 + i + j + k sage: x 1 + i + j + i*j sage: x**128 - -170141183460469231731687303715884105728 + 170141183460469231731687303715884105728*i + 170141183460469231731687303715884105728*j + 170141183460469231731687303715884105728*i*j + -170141183460469231731687303715884105728 + + 170141183460469231731687303715884105728*i + + 170141183460469231731687303715884105728*j + + 170141183460469231731687303715884105728*i*j TESTS:: @@ -180,7 +190,7 @@ def _coerce_map_from_(self, S): True sage: H._coerce_map_from_(QQ) True - sage: H._coerce_map_from_(GF(7)) + sage: H._coerce_map_from_(GF(7)) # optional - sage.rings.finite_rings False """ return S == self or self.__free_algebra.has_coerce_map_from(S) @@ -345,7 +355,8 @@ def hamilton_quatalg(R): sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(ZZ) sage: H - Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 over Integer Ring + Free algebra quotient on 3 generators ('i', 'j', 'k') and dimension 4 + over Integer Ring sage: i^2 -1 sage: i in H diff --git a/src/sage/algebras/free_algebra_quotient_element.py b/src/sage/algebras/free_algebra_quotient_element.py index c841a9210cf..738e5b723a3 100644 --- a/src/sage/algebras/free_algebra_quotient_element.py +++ b/src/sage/algebras/free_algebra_quotient_element.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Free algebra quotient elements diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index 39ac9091618..f7e2f97e50c 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Free Zinbiel Algebras @@ -539,14 +540,14 @@ def _coerce_map_from_(self, R): EXAMPLES:: - sage: F = algebras.FreeZinbiel(GF(7), 'x,y,z'); F + sage: F = algebras.FreeZinbiel(GF(7), 'x,y,z'); F # optional - sage.rings.finite_rings Free Zinbiel algebra on generators (Z[x], Z[y], Z[z]) over Finite Field of size 7 Elements of the free Zinbiel algebra canonically coerce in:: - sage: x, y, z = F.gens() - sage: F.coerce(x+y) == x+y + sage: x, y, z = F.gens() # optional - sage.rings.finite_rings + sage: F.coerce(x+y) == x+y # optional - sage.rings.finite_rings True The free Zinbiel algebra over `\ZZ` on `x, y, z` coerces in, since @@ -554,15 +555,15 @@ def _coerce_map_from_(self, R): sage: G = algebras.FreeZinbiel(ZZ, 'x,y,z') sage: Gx,Gy,Gz = G.gens() - sage: z = F.coerce(Gx+Gy); z + sage: z = F.coerce(Gx+Gy); z # optional - sage.rings.finite_rings Z[x] + Z[y] - sage: z.parent() is F + sage: z.parent() is F # optional - sage.rings.finite_rings True However, `\GF{7}` does not coerce to `\ZZ`, so the free Zinbiel algebra over `\GF{7}` does not coerce to the one over `\ZZ`:: - sage: G.coerce(y) + sage: G.coerce(y) # optional - sage.rings.finite_rings Traceback (most recent call last): ... TypeError: no canonical coercion from Free Zinbiel algebra on @@ -641,18 +642,18 @@ class ZinbielFunctor(ConstructionFunctor): sage: F = P.construction()[0]; F Zinbiel[x,y] - sage: A = GF(5)['a,b'] - sage: a, b = A.gens() - sage: F(A) + sage: A = GF(5)['a,b'] # optional - sage.rings.finite_rings + sage: a, b = A.gens() # optional - sage.rings.finite_rings + sage: F(A) # optional - sage.rings.finite_rings Free Zinbiel algebra on generators (Z[x], Z[y]) over Multivariate Polynomial Ring in a, b over Finite Field of size 5 - sage: f = A.hom([a+b,a-b],A) - sage: F(f) + sage: f = A.hom([a+b,a-b],A) # optional - sage.rings.finite_rings + sage: F(f) # optional - sage.rings.finite_rings Generic endomorphism of Free Zinbiel algebra on generators (Z[x], Z[y]) over Multivariate Polynomial Ring in a, b over Finite Field of size 5 - sage: F(f)(a * F(A)(x)) + sage: F(f)(a * F(A)(x)) # optional - sage.rings.finite_rings (a+b)*Z[x] """ rank = 9 @@ -705,7 +706,7 @@ def _apply_functor_to_morphism(self, f): TESTS:: sage: R = algebras.FreeZinbiel(ZZ, 'x').construction()[0] - sage: R(ZZ.hom(GF(3))) # indirect doctest + sage: R(ZZ.hom(GF(3))) # indirect doctest # optional - sage.rings.finite_rings Generic morphism: From: Free Zinbiel algebra on generators (Z[x],) over Integer Ring diff --git a/src/sage/algebras/group_algebra.py b/src/sage/algebras/group_algebra.py index e16b0c08a21..38698c5f00d 100644 --- a/src/sage/algebras/group_algebra.py +++ b/src/sage/algebras/group_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.groups sage.modules r""" Group algebras diff --git a/src/sage/algebras/hall_algebra.py b/src/sage/algebras/hall_algebra.py index 3492ba5e073..1da3c8f397e 100644 --- a/src/sage/algebras/hall_algebra.py +++ b/src/sage/algebras/hall_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Hall Algebras diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 0b6696af043..abd613791d3 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Iwahori-Hecke Algebras diff --git a/src/sage/algebras/nil_coxeter_algebra.py b/src/sage/algebras/nil_coxeter_algebra.py index 862fdc3b97e..32d9de8638e 100644 --- a/src/sage/algebras/nil_coxeter_algebra.py +++ b/src/sage/algebras/nil_coxeter_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Nil-Coxeter Algebra """ diff --git a/src/sage/algebras/octonion_algebra.pyx b/src/sage/algebras/octonion_algebra.pyx index aef4f54aa9d..85984dff57c 100644 --- a/src/sage/algebras/octonion_algebra.pyx +++ b/src/sage/algebras/octonion_algebra.pyx @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules """ Octonion Algebras diff --git a/src/sage/algebras/orlik_solomon.py b/src/sage/algebras/orlik_solomon.py index 920056787c6..8a57893dc7f 100644 --- a/src/sage/algebras/orlik_solomon.py +++ b/src/sage/algebras/orlik_solomon.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules r""" Orlik-Solomon Algebras """ @@ -545,10 +546,10 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): Lets start with the action of `S_3` on the rank `2` braid matroid:: - sage: M = matroids.CompleteGraphic(3) - sage: M.groundset() + sage: M = matroids.CompleteGraphic(3) # optional - sage.graphs + sage: M.groundset() # optional - sage.graphs frozenset({0, 1, 2}) - sage: G = SymmetricGroup(3) + sage: G = SymmetricGroup(3) # optional - sage.groups Calling elements ``g`` of ``G`` on an element `i` of `\{1, 2, 3\}` defines the action we want, but since the groundset is `\{0, 1, 2\}` @@ -560,30 +561,30 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): Now that we have defined an action we can create the invariant, and get its basis:: - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, on_groundset)) - sage: OSG.basis() + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, on_groundset)) # optional - sage.graphs sage.groups + sage: OSG.basis() # optional - sage.graphs sage.groups Finite family {0: B[0], 1: B[1]} - sage: [OSG.lift(b) for b in OSG.basis()] + sage: [OSG.lift(b) for b in OSG.basis()] # optional - sage.graphs sage.groups [OS{}, OS{0} + OS{1} + OS{2}] Since it is invariant, the action of any ``g`` in ``G`` is trivial:: - sage: x = OSG.an_element(); x + sage: x = OSG.an_element(); x # optional - sage.graphs sage.groups 2*B[0] + 2*B[1] - sage: g = G.an_element(); g + sage: g = G.an_element(); g # optional - sage.graphs sage.groups (2,3) - sage: g * x + sage: g * x # optional - sage.graphs sage.groups 2*B[0] + 2*B[1] - sage: x = OSG.random_element() - sage: g = G.random_element() - sage: g * x == x + sage: x = OSG.random_element() # optional - sage.graphs sage.groups + sage: g = G.random_element() # optional - sage.graphs sage.groups + sage: g * x == x # optional - sage.graphs sage.groups True The underlying ambient module is the Orlik-Solomon algebra, which is accessible via :meth:`ambient()`:: - sage: M.orlik_solomon_algebra(QQ) is OSG.ambient() + sage: M.orlik_solomon_algebra(QQ) is OSG.ambient() # optional - sage.graphs sage.groups True There is not much structure here, so lets look at a bigger example. @@ -591,53 +592,53 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): easier, we'll start the indexing at `1` so that the `S_6` action on the groundset is simply calling `g`:: - sage: M = matroids.CompleteGraphic(4); M.groundset() + sage: M = matroids.CompleteGraphic(4); M.groundset() # optional - sage.graphs frozenset({0, 1, 2, 3, 4, 5}) - sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] - sage: M = Matroid(bases=new_bases); M.groundset() + sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] # optional - sage.graphs + sage: M = Matroid(bases=new_bases); M.groundset() # optional - sage.graphs frozenset({1, 2, 3, 4, 5, 6}) - sage: G = SymmetricGroup(6) - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) - sage: OSG.basis() + sage: G = SymmetricGroup(6) # optional - sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) # optional - sage.graphs sage.groups + sage: OSG.basis() # optional - sage.graphs sage.groups Finite family {0: B[0], 1: B[1]} - sage: [OSG.lift(b) for b in OSG.basis()] + sage: [OSG.lift(b) for b in OSG.basis()] # optional - sage.graphs sage.groups [OS{}, OS{1} + OS{2} + OS{3} + OS{4} + OS{5} + OS{6}] - sage: (OSG.basis()[1])^2 + sage: (OSG.basis()[1])^2 # optional - sage.graphs sage.groups 0 - sage: 5 * OSG.basis()[1] + sage: 5 * OSG.basis()[1] # optional - sage.graphs sage.groups 5*B[1] Next, we look at the same matroid but with an `S_3 \times S_3` action (here realized as a Young subgroup of `S_6`):: - sage: H = G.young_subgroup([3, 3]) - sage: OSH = M.orlik_solomon_algebra(QQ, invariant=H) - sage: OSH.basis() + sage: H = G.young_subgroup([3, 3]) # optional - sage.graphs sage.groups + sage: OSH = M.orlik_solomon_algebra(QQ, invariant=H) # optional - sage.graphs sage.groups + sage: OSH.basis() # optional - sage.graphs sage.groups Finite family {0: B[0], 1: B[1], 2: B[2]} - sage: [OSH.lift(b) for b in OSH.basis()] + sage: [OSH.lift(b) for b in OSH.basis()] # optional - sage.graphs sage.groups [OS{}, OS{4} + OS{5} + OS{6}, OS{1} + OS{2} + OS{3}] We implement an `S_4` action on the vertices:: - sage: M = matroids.CompleteGraphic(4) - sage: G = SymmetricGroup(4) - sage: edge_map = {i: M.groundset_to_edges([i])[0][:2] + sage: M = matroids.CompleteGraphic(4) # optional - sage.graphs + sage: G = SymmetricGroup(4) # optional - sage.groups + sage: edge_map = {i: M.groundset_to_edges([i])[0][:2] # optional - sage.graphs ....: for i in M.groundset()} - sage: inv_map = {v: k for k, v in edge_map.items()} + sage: inv_map = {v: k for k, v in edge_map.items()} # optional - sage.graphs sage: def vert_action(g, x): ....: a, b = edge_map[x] ....: return inv_map[tuple(sorted([g(a+1)-1, g(b+1)-1]))] - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, vert_action)) - sage: B = OSG.basis() - sage: [OSG.lift(b) for b in B] + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, vert_action)) # optional - sage.graphs sage.groups + sage: B = OSG.basis() # optional - sage.graphs sage.groups + sage: [OSG.lift(b) for b in B] # optional - sage.graphs sage.groups [OS{}, OS{0} + OS{1} + OS{2} + OS{3} + OS{4} + OS{5}] We use this to describe the Young subgroup `S_2 \times S_2` action:: - sage: H = G.young_subgroup([2,2]) - sage: OSH = M.orlik_solomon_algebra(QQ, invariant=(H, vert_action)) - sage: B = OSH.basis() - sage: [OSH.lift(b) for b in B] + sage: H = G.young_subgroup([2,2]) # optional - sage.graphs sage.groups + sage: OSH = M.orlik_solomon_algebra(QQ, invariant=(H, vert_action)) # optional - sage.graphs sage.groups + sage: B = OSH.basis() # optional - sage.graphs sage.groups + sage: [OSH.lift(b) for b in B] # optional - sage.graphs sage.groups [OS{}, OS{5}, OS{1} + OS{2} + OS{3} + OS{4}, OS{0}, -1/2*OS{1, 2} + OS{1, 5} - 1/2*OS{3, 4} + OS{3, 5}, OS{0, 5}, OS{0, 1} + OS{0, 2} + OS{0, 3} + OS{0, 4}, @@ -645,7 +646,7 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): We demonstrate the algebra structure:: - sage: matrix([[b*bp for b in B] for bp in B]) + sage: matrix([[b*bp for b in B] for bp in B]) # optional - sage.graphs sage.groups [ B[0] B[1] B[2] B[3] B[4] B[5] B[6] B[7]] [ B[1] 0 2*B[4] B[5] 0 0 2*B[7] 0] [ B[2] -2*B[4] 0 B[6] 0 -2*B[7] 0 0] @@ -668,12 +669,12 @@ def __init__(self, R, M, G, action_on_groundset=None, *args, **kwargs): EXAMPLES:: - sage: M = matroids.CompleteGraphic(4) - sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] - sage: M = Matroid(bases=new_bases) - sage: G = SymmetricGroup(6) - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) - sage: TestSuite(OSG).run() + sage: M = matroids.CompleteGraphic(4) # optional - sage.graphs + sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] # optional - sage.graphs + sage: M = Matroid(bases=new_bases) # optional - sage.graphs + sage: G = SymmetricGroup(6) # optional - sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) # optional - sage.graphs sage.groups + sage: TestSuite(OSG).run() # optional - sage.graphs sage.groups """ ordering = kwargs.pop('ordering', None) OS = OrlikSolomonAlgebra(R, M, ordering) @@ -756,16 +757,16 @@ def _basis_action(self, g, f): EXAMPLES:: - sage: M = matroids.CompleteGraphic(3) - sage: M.groundset() + sage: M = matroids.CompleteGraphic(3) # optional - sage.graphs + sage: M.groundset() # optional - sage.graphs frozenset({0, 1, 2}) - sage: G = SymmetricGroup(3) - sage: def on_groundset(g,x): + sage: G = SymmetricGroup(3) # optional - sage.groups + sage: def on_groundset(g, x): ....: return g(x+1)-1 - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G,on_groundset)) + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G,on_groundset)) # optional - sage.graphs sage.groups sage: act = lambda g: (OSG._basis_action(g,frozenset({0,1})), ....: OSG._basis_action(g,frozenset({0,2}))) - sage: [act(g) for g in G] + sage: [act(g) for g in G] # optional - sage.graphs sage.groups [(OS{0, 1}, OS{0, 2}), (-OS{0, 2}, OS{0, 1} - OS{0, 2}), (-OS{0, 1} + OS{0, 2}, -OS{0, 1}), @@ -775,26 +776,26 @@ def _basis_action(self, g, f): We also check that the ordering is respected:: - sage: fset = frozenset({1,2}) - sage: OS1 = M.orlik_solomon_algebra(QQ) - sage: OS1.subset_image(fset) + sage: fset = frozenset({1,2}) # optional - sage.graphs sage.groups + sage: OS1 = M.orlik_solomon_algebra(QQ) # optional - sage.graphs sage.groups + sage: OS1.subset_image(fset) # optional - sage.graphs sage.groups -OS{0, 1} + OS{0, 2} - sage: OS2 = M.orlik_solomon_algebra(QQ, range(2,-1,-1)) - sage: OS2.subset_image(fset) + sage: OS2 = M.orlik_solomon_algebra(QQ, range(2,-1,-1)) # optional - sage.graphs sage.groups + sage: OS2.subset_image(fset) # optional - sage.graphs sage.groups OS{1, 2} - sage: OSG2 = M.orlik_solomon_algebra(QQ, + sage: OSG2 = M.orlik_solomon_algebra(QQ, # optional - sage.graphs sage.groups ....: invariant=(G,on_groundset), ....: ordering=range(2,-1,-1)) - sage: g = G.an_element(); g + sage: g = G.an_element(); g # optional - sage.graphs sage.groups (2,3) This choice of ``g`` acting on this choice of ``fset`` reverses the sign:: - sage: OSG._basis_action(g, fset) + sage: OSG._basis_action(g, fset) # optional - sage.graphs sage.groups OS{0, 1} - OS{0, 2} - sage: OSG2._basis_action(g, fset) + sage: OSG2._basis_action(g, fset) # optional - sage.graphs sage.groups -OS{1, 2} """ OS = self._ambient diff --git a/src/sage/algebras/orlik_terao.py b/src/sage/algebras/orlik_terao.py index 55fd2bdb641..f7728124ec3 100644 --- a/src/sage/algebras/orlik_terao.py +++ b/src/sage/algebras/orlik_terao.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules r""" Orlik-Terao Algebras """ diff --git a/src/sage/algebras/q_commuting_polynomials.py b/src/sage/algebras/q_commuting_polynomials.py index a50b2335787..670e890ecd8 100644 --- a/src/sage/algebras/q_commuting_polynomials.py +++ b/src/sage/algebras/q_commuting_polynomials.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules r""" `q`-Commuting Polynomials diff --git a/src/sage/algebras/q_system.py b/src/sage/algebras/q_system.py index f7d495aac50..c39a97db88c 100644 --- a/src/sage/algebras/q_system.py +++ b/src/sage/algebras/q_system.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.combinat sage.modules r""" Q-Systems diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index 2b85615cf20..3a414418c52 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules r""" Quantum Clifford Algebras diff --git a/src/sage/algebras/quantum_groups/fock_space.py b/src/sage/algebras/quantum_groups/fock_space.py index 3352f143a7c..965247f858f 100644 --- a/src/sage/algebras/quantum_groups/fock_space.py +++ b/src/sage/algebras/quantum_groups/fock_space.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.combinat sage.modules r""" Fock Space diff --git a/src/sage/algebras/quantum_matrix_coordinate_algebra.py b/src/sage/algebras/quantum_matrix_coordinate_algebra.py index 1579896fa86..64b29c82a45 100644 --- a/src/sage/algebras/quantum_matrix_coordinate_algebra.py +++ b/src/sage/algebras/quantum_matrix_coordinate_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Quantum Matrix Coordinate Algebras diff --git a/src/sage/algebras/quaternion_algebra.py b/src/sage/algebras/quaternion_algebra.py index 0f577bbd0b9..bb617738cdc 100644 --- a/src/sage/algebras/quaternion_algebra.py +++ b/src/sage/algebras/quaternion_algebra.py @@ -1,3 +1,5 @@ +# sage.doctest: optional - sage.modules + ############################################################ # Backwards compatible unpickling ############################################################ diff --git a/src/sage/algebras/quaternion_algebra_element.py b/src/sage/algebras/quaternion_algebra_element.py index 48c1c9871ec..aa4f349f1da 100644 --- a/src/sage/algebras/quaternion_algebra_element.py +++ b/src/sage/algebras/quaternion_algebra_element.py @@ -1,3 +1,5 @@ +# sage.doctest: optional - sage.modules + ####################################################################### # Backward compatible unpickle functions ####################################################################### diff --git a/src/sage/algebras/rational_cherednik_algebra.py b/src/sage/algebras/rational_cherednik_algebra.py index 3b85c1e13a3..d17c415f027 100644 --- a/src/sage/algebras/rational_cherednik_algebra.py +++ b/src/sage/algebras/rational_cherednik_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Rational Cherednik Algebras """ diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index ff960e56dd9..0329c502fc1 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -1,3 +1,4 @@ +# optional - sage.combinat sage.modules r""" Schur algebras for `GL_n` diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index 5d383f8dfab..50d43f2a8f7 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# optional - sage.combinat sage.modules r""" Shuffle algebras diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index 3b0dfce4586..57bbf71b64e 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# optional - sage.modules r""" Splitting Algebras diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index 7c4d444f81c..ba94cf6311b 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.combinat sage.modules r""" The Steenrod algebra diff --git a/src/sage/algebras/steenrod/steenrod_algebra_bases.py b/src/sage/algebras/steenrod/steenrod_algebra_bases.py index c289b284fe1..367c854249e 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_bases.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_bases.py @@ -132,12 +132,12 @@ def convert_to_milnor_matrix(n, basis, p=2, generic='auto'): EXAMPLES:: sage: from sage.algebras.steenrod.steenrod_algebra_bases import convert_to_milnor_matrix - sage: convert_to_milnor_matrix(5, 'adem') # indirect doctest + sage: convert_to_milnor_matrix(5, 'adem') # indirect doctest # optional - sage.modules sage.rings.finite_rings [0 1] [1 1] - sage: convert_to_milnor_matrix(45, 'milnor') + sage: convert_to_milnor_matrix(45, 'milnor') # optional - sage.modules sage.rings.finite_rings 111 x 111 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) - sage: convert_to_milnor_matrix(12,'wall') + sage: convert_to_milnor_matrix(12,'wall') # optional - sage.modules sage.rings.finite_rings [1 0 0 1 0 0 0] [1 1 0 0 0 1 0] [0 1 0 1 0 0 0] @@ -149,15 +149,15 @@ def convert_to_milnor_matrix(n, basis, p=2, generic='auto'): The function takes an optional argument, the prime `p` over which to work:: - sage: convert_to_milnor_matrix(17,'adem',3) + sage: convert_to_milnor_matrix(17,'adem',3) # optional - sage.modules sage.rings.finite_rings [0 0 1 1] [0 0 0 1] [1 1 1 1] [0 1 0 1] - sage: convert_to_milnor_matrix(48,'adem',5) + sage: convert_to_milnor_matrix(48,'adem',5) # optional - sage.modules sage.rings.finite_rings [0 1] [1 1] - sage: convert_to_milnor_matrix(36,'adem',3) + sage: convert_to_milnor_matrix(36,'adem',3) # optional - sage.modules sage.rings.finite_rings [0 0 1] [0 1 0] [1 2 0] @@ -206,7 +206,7 @@ def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): EXAMPLES:: sage: from sage.algebras.steenrod.steenrod_algebra_bases import convert_from_milnor_matrix, convert_to_milnor_matrix - sage: convert_from_milnor_matrix(12,'wall') + sage: convert_from_milnor_matrix(12,'wall') # optional - sage.modules sage.rings.finite_rings [1 0 0 1 0 0 0] [0 0 1 1 0 0 0] [0 0 0 1 0 1 1] @@ -214,10 +214,10 @@ def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): [1 0 1 0 1 0 0] [1 1 1 0 0 0 0] [1 0 1 0 1 0 1] - sage: convert_from_milnor_matrix(38,'serre_cartan') + sage: convert_from_milnor_matrix(38,'serre_cartan') # optional - sage.modules sage.rings.finite_rings 72 x 72 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) - sage: x = convert_to_milnor_matrix(20,'wood_y') - sage: y = convert_from_milnor_matrix(20,'wood_y') + sage: x = convert_to_milnor_matrix(20,'wood_y') # optional - sage.modules sage.rings.finite_rings + sage: y = convert_from_milnor_matrix(20,'wood_y') # optional - sage.modules sage.rings.finite_rings sage: x*y [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] @@ -240,7 +240,7 @@ def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): The function takes an optional argument, the prime `p` over which to work:: - sage: convert_from_milnor_matrix(17,'adem',3) + sage: convert_from_milnor_matrix(17,'adem',3) # optional - sage.modules sage.rings.finite_rings [2 1 1 2] [0 2 0 1] [1 2 0 0] diff --git a/src/sage/algebras/tensor_algebra.py b/src/sage/algebras/tensor_algebra.py index 664027ee6ae..6054ef8f6c5 100644 --- a/src/sage/algebras/tensor_algebra.py +++ b/src/sage/algebras/tensor_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Tensor Algebras diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index efb148bb5b3..142136d2232 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Weyl Algebras diff --git a/src/sage/algebras/yangian.py b/src/sage/algebras/yangian.py index 55bb61fccf5..2b9702fa247 100644 --- a/src/sage/algebras/yangian.py +++ b/src/sage/algebras/yangian.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Yangians diff --git a/src/sage/algebras/yokonuma_hecke_algebra.py b/src/sage/algebras/yokonuma_hecke_algebra.py index df474b8d4f7..8651e5d32bd 100644 --- a/src/sage/algebras/yokonuma_hecke_algebra.py +++ b/src/sage/algebras/yokonuma_hecke_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.modules """ Yokonuma-Hecke Algebras From 1bddc6b40312479e222980c2ce89ea62223f7384 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 9 Jun 2023 00:55:41 -0700 Subject: [PATCH 122/538] More # optional --- .../algebras/hecke_algebras/ariki_koike_algebra.py | 2 +- .../algebras/hecke_algebras/cubic_hecke_algebra.py | 2 +- .../algebras/hecke_algebras/cubic_hecke_matrix_rep.py | 2 +- src/sage/algebras/jordan_algebra.py | 1 + .../abelian_lie_conformal_algebra.py | 1 + .../affine_lie_conformal_algebra.py | 1 + .../bosonic_ghosts_lie_conformal_algebra.py | 1 + .../fermionic_ghosts_lie_conformal_algebra.py | 1 + .../finitely_freely_generated_lca.py | 1 + .../free_bosons_lie_conformal_algebra.py | 1 + .../free_fermions_lie_conformal_algebra.py | 1 + .../freely_generated_lie_conformal_algebra.py | 1 + .../graded_lie_conformal_algebra.py | 1 + .../lie_conformal_algebras/lie_conformal_algebra.py | 1 + .../lie_conformal_algebra_element.py | 1 + .../lie_conformal_algebra_with_basis.py | 1 + .../lie_conformal_algebra_with_structure_coefs.py | 1 + .../n2_lie_conformal_algebra.py | 1 + .../neveu_schwarz_lie_conformal_algebra.py | 1 + .../virasoro_lie_conformal_algebra.py | 1 + .../weyl_lie_conformal_algebra.py | 1 + .../algebras/quantum_groups/ace_quantum_onsager.py | 1 + src/sage/algebras/quantum_groups/quantum_group_gap.py | 11 +++++++---- src/sage/algebras/quantum_groups/representations.py | 1 + src/sage/algebras/shuffle_algebra.py | 2 +- src/sage/algebras/steenrod/steenrod_algebra_mult.py | 1 + 26 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py index cf1c7a04c39..15a0566747c 100644 --- a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py +++ b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.combinat sage.modules r""" Ariki-Koike Algebras diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 29d444e745f..a1c175e9151 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.combinat sage.groups sage.modules r""" Cubic Hecke Algebras 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 ef8ba7316c9..ceda4ec816b 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: optional - sage.modules r""" Cubic Hecke matrix representations diff --git a/src/sage/algebras/jordan_algebra.py b/src/sage/algebras/jordan_algebra.py index 81c40105f8a..0e3a05b4026 100644 --- a/src/sage/algebras/jordan_algebra.py +++ b/src/sage/algebras/jordan_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Jordan Algebras diff --git a/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py index aa8b71901e1..d1efd6e21f2 100644 --- a/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Abelian Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py index 9fdf888fe39..5b7aea16317 100644 --- a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Affine Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py index 178493b13e8..7367bab5c4d 100644 --- a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Bosonic Ghosts Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py index e6bca4de671..4a21da4370b 100644 --- a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Fermionic Ghosts Super Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py b/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py index 9077ef8f6a2..4aaf9da36eb 100644 --- a/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +++ b/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Finitely and Freely Generated Lie Conformal Algebras. diff --git a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py index 53952f38c91..9008a9770ad 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Free Bosons Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py index 8cc6533b781..83f7bdc0698 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Free Fermions Super Lie Conformal Algebra. 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 8fa5460d29a..21fc30d393b 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 @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Freely Generated Lie Conformal Algebras diff --git a/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py index 35863aece41..a2f1eb8fdf1 100644 --- a/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Graded Lie Conformal Algebras diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py index 1007488e165..16758675fdd 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Lie Conformal Algebra 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 723ae5c385a..ccf3ce24111 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 @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Lie Conformal Algebra Element diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py index ae4882dbad0..3b3e3674897 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Lie Conformal Algebras With Basis diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py index 7581daf0ddb..89f7ecc0483 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Lie Conformal Algebras With Structure Coefficients diff --git a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py index 045bfb6e57a..3d02419cc18 100644 --- a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules sage.rings.number_field r""" N=2 Super Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py index 8f5756f993f..45e28ab3a3c 100644 --- a/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Neveu-Schwarz Super Lie Conformal Algebra 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 cc11ec06a0a..6c16820f412 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 @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Virasoro Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py index 343ee8a66f9..07c6007e0a4 100644 --- a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Weyl Lie Conformal Algebra diff --git a/src/sage/algebras/quantum_groups/ace_quantum_onsager.py b/src/sage/algebras/quantum_groups/ace_quantum_onsager.py index 91138258e5a..4d2a8386980 100644 --- a/src/sage/algebras/quantum_groups/ace_quantum_onsager.py +++ b/src/sage/algebras/quantum_groups/ace_quantum_onsager.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Alternating Central Extension Quantum Onsager Algebra diff --git a/src/sage/algebras/quantum_groups/quantum_group_gap.py b/src/sage/algebras/quantum_groups/quantum_group_gap.py index 8925c047916..4998af7b588 100644 --- a/src/sage/algebras/quantum_groups/quantum_group_gap.py +++ b/src/sage/algebras/quantum_groups/quantum_group_gap.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - gap_package_quagroup +# sage.doctest: optional - gap_package_quagroup sage.combinat sage.libs.gap sage.modules """ Quantum Groups Using GAP's QuaGroup Package @@ -21,7 +21,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +import re + +from copy import copy + from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.lazy_import import lazy_import from sage.misc.cachefunc import cached_method from sage.structure.parent import Parent from sage.structure.element import Element @@ -33,7 +38,6 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.libs.gap.libgap import libgap from sage.features.gap import GapPackage -from sage.graphs.digraph import DiGraph from sage.rings.rational_field import QQ from sage.categories.algebras import Algebras from sage.categories.cartesian_product import cartesian_product @@ -44,8 +48,7 @@ from sage.categories.morphism import Morphism from sage.categories.rings import Rings -from copy import copy -import re +lazy_import('sage.graphs.digraph', 'DiGraph') class QuaGroupModuleElement(Element): diff --git a/src/sage/algebras/quantum_groups/representations.py b/src/sage/algebras/quantum_groups/representations.py index b874d264669..19a35b0aa53 100644 --- a/src/sage/algebras/quantum_groups/representations.py +++ b/src/sage/algebras/quantum_groups/representations.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules r""" Quantum Group Representations diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index 50d43f2a8f7..d137e2bc9d6 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -1,4 +1,4 @@ -# optional - sage.combinat sage.modules +# sage.doctest: optional - sage.combinat sage.modules r""" Shuffle algebras diff --git a/src/sage/algebras/steenrod/steenrod_algebra_mult.py b/src/sage/algebras/steenrod/steenrod_algebra_mult.py index 1fb52aba028..35c06d9f711 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_mult.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_mult.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.rings.finite_rings r""" Multiplication for elements of the Steenrod algebra From c78b53caee3fa98e9d86c392e09ad420b3b6d756 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Jun 2023 17:42:47 -0700 Subject: [PATCH 123/538] sage.algebras: More # optional --- src/sage/algebras/free_algebra_quotient.py | 2 +- src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py | 1 + src/sage/algebras/schur_algebra.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/free_algebra_quotient.py b/src/sage/algebras/free_algebra_quotient.py index d79b9a2ac47..9ac3706444d 100644 --- a/src/sage/algebras/free_algebra_quotient.py +++ b/src/sage/algebras/free_algebra_quotient.py @@ -25,7 +25,7 @@ sage: r = len(mons) sage: M = MatrixSpace(QQ,r) sage: mats = [M([0,1,0,0, -1,0,0,0, 0,0,0,-1, 0,0,1,0]), -....: M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]) ] + ....: M([0,0,1,0, 0,0,0,1, -1,0,0,0, 0,-1,0,0]) ] sage: H2. = A.quotient(mons, mats) sage: H2 == loads(dumps(H2)) True 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 7c2fe4a2210..159ab06db3a 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.libs.pari (for factorization) r""" Cubic Hecke Base Rings diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 0329c502fc1..9356d18cd4b 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -1,4 +1,4 @@ -# optional - sage.combinat sage.modules +# sage.doctest: optional - sage.combinat sage.modules r""" Schur algebras for `GL_n` From 4fef2a5a0ef42aad72c87e0e8fe9e196d35da9b6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Jun 2023 10:51:37 -0700 Subject: [PATCH 124/538] More # optional --- .../finite_dimensional_algebra.py | 4 ++-- .../finite_dimensional_algebra_element.pyx | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 67625148ecd..ed6c762ac23 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -814,7 +814,7 @@ def maximal_ideal(self): sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) - sage: B.maximal_ideal() + sage: B.maximal_ideal() # optional - sage.libs.pari Traceback (most recent call last): ... ValueError: algebra is not local @@ -860,7 +860,7 @@ def primary_decomposition(self): sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) - sage: B.primary_decomposition() + sage: B.primary_decomposition() # optional - sage.libs.pari [Morphism from Finite-dimensional algebra of degree 3 over Rational Field to Finite-dimensional algebra of degree 1 over Rational Field diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx index d0724bca028..b51f5ed4f7a 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx @@ -642,12 +642,12 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) - sage: B(0).minimal_polynomial() + sage: B(0).minimal_polynomial() # optional - sage.libs.pari x sage: b = B.random_element() - sage: f = b.minimal_polynomial(); f # random + sage: f = b.minimal_polynomial(); f # random # optional - sage.libs.pari x^3 + 1/2*x^2 - 7/16*x + 1/16 - sage: f(b) == 0 + sage: f(b) == 0 # optional - sage.libs.pari True """ A = self.parent() @@ -673,12 +673,12 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) - sage: B(0).characteristic_polynomial() + sage: B(0).characteristic_polynomial() # optional - sage.libs.pari x^3 sage: b = B.random_element() - sage: f = b.characteristic_polynomial(); f # random + sage: f = b.characteristic_polynomial(); f # random # optional - sage.libs.pari x^3 - 8*x^2 + 16*x - sage: f(b) == 0 + sage: f(b) == 0 # optional - sage.libs.pari True """ return self.matrix().characteristic_polynomial() From a9fdb2224a3e35bb2e4020c950b1ee2ed4276084 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Jun 2023 23:46:46 -0700 Subject: [PATCH 125/538] src/sage/algebras/free_algebra.py: Use lazy_import --- src/sage/algebras/free_algebra.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index eaddfc54e5a..ea4e2707e67 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -149,6 +149,7 @@ from sage.structure.factory import UniqueFactory from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.ring import Algebra from sage.categories.algebras_with_basis import AlgebrasWithBasis @@ -156,6 +157,8 @@ from sage.combinat.words.word import Word from sage.structure.category_object import normalize_names +lazy_import('sage.algebras.letterplace.free_algebra_letterplace', 'FreeAlgebra_letterplace') + class FreeAlgebraFactory(UniqueFactory): """ @@ -362,8 +365,7 @@ def is_FreeAlgebra(x): True """ - from sage.algebras.letterplace.free_algebra_letterplace import FreeAlgebra_letterplace - return isinstance(x, (FreeAlgebra_generic,FreeAlgebra_letterplace)) + return isinstance(x, (FreeAlgebra_generic, FreeAlgebra_letterplace)) class FreeAlgebra_generic(CombinatorialFreeModule, Algebra): From 445721d621620feb36d3ccb6f9a35fb7ae4bc02c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Jun 2023 23:47:37 -0700 Subject: [PATCH 126/538] More # optional --- src/sage/algebras/free_algebra_quotient.py | 1 + src/sage/algebras/splitting_algebra.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/algebras/free_algebra_quotient.py b/src/sage/algebras/free_algebra_quotient.py index 9ac3706444d..e54d92ae482 100644 --- a/src/sage/algebras/free_algebra_quotient.py +++ b/src/sage/algebras/free_algebra_quotient.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.combinat sage.modules """ Finite dimensional free algebra quotients diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index 57bbf71b64e..8e6d35e7c1b 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -1,4 +1,4 @@ -# optional - sage.modules +# sage.doctest: optional - sage.libs.pari sage.modules r""" Splitting Algebras From aa70cd75243ee4743c458114a687f00eda173446 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 12 Jun 2023 20:59:16 -0700 Subject: [PATCH 127/538] More # optional --- .../finite_dimensional_algebra_morphism.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py index eea375c01d0..5f6512baccf 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py @@ -86,9 +86,9 @@ def _repr_(self): sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: I = A.maximal_ideal() - sage: q = A.quotient_map(I) - sage: q._repr_() + sage: I = A.maximal_ideal() # optional - sage.libs.pari + sage: q = A.quotient_map(I) # optional - sage.libs.pari + sage: q._repr_() # optional - sage.libs.pari 'Morphism from Finite-dimensional algebra of degree 2 over Rational Field to Finite-dimensional algebra of degree 1 over Rational Field given by matrix\n[1]\n[0]' """ return "Morphism from {} to {} given by matrix\n{}".format( @@ -100,9 +100,9 @@ def __call__(self, x): sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: I = A.maximal_ideal() - sage: q = A.quotient_map(I) - sage: q(0) == 0 and q(1) == 1 + sage: I = A.maximal_ideal() # optional - sage.libs.pari + sage: q = A.quotient_map(I) # optional - sage.libs.pari + sage: q(0) == 0 and q(1) == 1 # optional - sage.libs.pari True """ x = self.domain()(x) @@ -182,10 +182,10 @@ def inverse_image(self, I): sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: I = A.maximal_ideal() - sage: q = A.quotient_map(I) - sage: B = q.codomain() - sage: q.inverse_image(B.zero_ideal()) == I + sage: I = A.maximal_ideal() # optional - sage.libs.pari + sage: q = A.quotient_map(I) # optional - sage.libs.pari + sage: B = q.codomain() # optional - sage.libs.pari + sage: q.inverse_image(B.zero_ideal()) == I # optional - sage.libs.pari True """ coker_I = I.basis_matrix().transpose().kernel().basis_matrix().transpose() From 017f8bf14432565a9749e432f61281ebf10a1d23 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 30 Jun 2023 18:57:29 -0700 Subject: [PATCH 128/538] ./sage -fixdoctests --long --distribution 'sagemath-modules' --probe sage.rings.finite_rings,sage.libs.pari --overwrite src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx --- .../finite_dimensional_algebra_element.pyx | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx index b51f5ed4f7a..f953a9fab7c 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx @@ -61,20 +61,20 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), ....: Matrix([[0,1], [0,0]])]) - sage: A(17) # optional - sage.rings.finite_rings + sage: A(17) 2*e0 - sage: A([1,1]) # optional - sage.rings.finite_rings + sage: A([1,1]) e0 + e1 """ def __init__(self, A, elt=None, check=True): """ TESTS:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), ....: Matrix([[0,1], [0,0]])]) - sage: A(QQ(4)) # optional - sage.rings.finite_rings + sage: A(QQ(4)) Traceback (most recent call last): ... TypeError: elt should be a vector, a matrix, or an element of the base field @@ -290,9 +290,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), ....: Matrix([[0,1], [0,0]])]) - sage: A(1) # optional - sage.rings.finite_rings + sage: A(1) e0 """ s = " " @@ -327,9 +327,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), ....: Matrix([[0,1], [0,0]])]) - sage: latex(A(1)) # indirect doctest # optional - sage.rings.finite_rings + sage: latex(A(1)) # indirect doctest \left(\begin{array}{rr} 1 & 0 \\ 0 & 1 @@ -369,13 +369,13 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), ....: Matrix([[0,1], [0,0]])]) - sage: A(2) == 2 # optional - sage.rings.finite_rings + sage: A(2) == 2 True - sage: A(2) == 3 # optional - sage.rings.finite_rings + sage: A(2) == 3 False - sage: A(2) == GF(5)(2) # optional - sage.rings.finite_rings + sage: A(2) == GF(5)(2) # needs sage.rings.finite_rings False sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), @@ -389,13 +389,13 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): the algebra corresponds to the standard monomials of the relation ideal, when the algebra is considered as a quotient of a path algebra. :: - sage: A(1) > 0 # optional - sage.rings.finite_rings + sage: A(1) > 0 True - sage: A(1) < 0 # optional - sage.rings.finite_rings + sage: A(1) < 0 False - sage: A(1) >= 0 # optional - sage.rings.finite_rings + sage: A(1) >= 0 True - sage: A(1) <= 0 # optional - sage.rings.finite_rings + sage: A(1) <= 0 False """ return richcmp(self._vector, right._vector, op) @@ -404,9 +404,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), ....: Matrix([[0,1], [0,0]])]) - sage: A.basis()[0] + A.basis()[1] # optional - sage.rings.finite_rings + sage: A.basis()[0] + A.basis()[1] e0 + e1 """ return self._parent.element_class(self._parent, self._vector + other._vector) @@ -415,9 +415,9 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): """ EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), ....: Matrix([[0,1], [0,0]])]) - sage: A.basis()[0] - A.basis()[1] # optional - sage.rings.finite_rings + sage: A.basis()[0] - A.basis()[1] e0 + 2*e1 """ return self._parent.element_class(self._parent, self._vector - other._vector) @@ -642,12 +642,12 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) - sage: B(0).minimal_polynomial() # optional - sage.libs.pari + sage: B(0).minimal_polynomial() # needs sage.libs.pari x sage: b = B.random_element() - sage: f = b.minimal_polynomial(); f # random # optional - sage.libs.pari + sage: f = b.minimal_polynomial(); f # random # needs sage.libs.pari x^3 + 1/2*x^2 - 7/16*x + 1/16 - sage: f(b) == 0 # optional - sage.libs.pari + sage: f(b) == 0 # needs sage.libs.pari True """ A = self.parent() @@ -673,12 +673,12 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) - sage: B(0).characteristic_polynomial() # optional - sage.libs.pari + sage: B(0).characteristic_polynomial() # needs sage.libs.pari x^3 sage: b = B.random_element() - sage: f = b.characteristic_polynomial(); f # random # optional - sage.libs.pari + sage: f = b.characteristic_polynomial(); f # random # needs sage.libs.pari x^3 - 8*x^2 + 16*x - sage: f(b) == 0 # optional - sage.libs.pari + sage: f(b) == 0 # needs sage.libs.pari True """ return self.matrix().characteristic_polynomial() From 6f704455414c78e2ddfbecf0f9460bf68eb539f6 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 1 Jul 2023 17:45:47 -0700 Subject: [PATCH 129/538] ./sage -fixdoctests --long --distribution 'sagemath-modules' --only-tags --probe sage.rings.finite_rings --overwrite src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py --- .../finite_dimensional_algebra.py | 142 +++++++++--------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index ed6c762ac23..448c1916aed 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -57,10 +57,10 @@ class FiniteDimensionalAlgebra(UniqueRepresentation, Algebra): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]); A Finite-dimensional algebra of degree 2 over Finite Field of size 3 - sage: TestSuite(A).run() # optional - sage.rings.finite_rings + sage: TestSuite(A).run() sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), @@ -70,13 +70,13 @@ class FiniteDimensionalAlgebra(UniqueRepresentation, Algebra): TESTS:: - sage: A.category() # optional - sage.rings.finite_rings + sage: A.category() Category of finite dimensional magmatic algebras with basis over Finite Field of size 3 - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])], ....: assume_associative=True) - sage: A.category() # optional - sage.rings.finite_rings + sage: A.category() Category of finite dimensional associative algebras with basis over Finite Field of size 3 """ @@ -89,47 +89,47 @@ def __classcall_private__(cls, k, table, names='e', assume_associative=False, TESTS:: sage: table = [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])] - sage: A1 = FiniteDimensionalAlgebra(GF(3), table) # optional - sage.rings.finite_rings - sage: A2 = FiniteDimensionalAlgebra(GF(3), table, names='e') # optional - sage.rings.finite_rings - sage: A3 = FiniteDimensionalAlgebra(GF(3), table, names=['e0', 'e1']) # optional - sage.rings.finite_rings - sage: A1 is A2 and A2 is A3 # optional - sage.rings.finite_rings + sage: A1 = FiniteDimensionalAlgebra(GF(3), table) + sage: A2 = FiniteDimensionalAlgebra(GF(3), table, names='e') + sage: A3 = FiniteDimensionalAlgebra(GF(3), table, names=['e0', 'e1']) + sage: A1 is A2 and A2 is A3 True The ``assume_associative`` keyword is built into the category:: sage: from sage.categories.magmatic_algebras import MagmaticAlgebras - sage: cat = MagmaticAlgebras(GF(3)).FiniteDimensional().WithBasis() # optional - sage.rings.finite_rings - sage: A1 = FiniteDimensionalAlgebra(GF(3), table, # optional - sage.rings.finite_rings + sage: cat = MagmaticAlgebras(GF(3)).FiniteDimensional().WithBasis() + sage: A1 = FiniteDimensionalAlgebra(GF(3), table, ....: category=cat.Associative()) - sage: A2 = FiniteDimensionalAlgebra(GF(3), table, assume_associative=True) # optional - sage.rings.finite_rings - sage: A1 is A2 # optional - sage.rings.finite_rings + sage: A2 = FiniteDimensionalAlgebra(GF(3), table, assume_associative=True) + sage: A1 is A2 True Uniqueness depends on the category:: - sage: cat = Algebras(GF(3)).FiniteDimensional().WithBasis() # optional - sage.rings.finite_rings - sage: A1 = FiniteDimensionalAlgebra(GF(3), table) # optional - sage.rings.finite_rings - sage: A2 = FiniteDimensionalAlgebra(GF(3), table, category=cat) # optional - sage.rings.finite_rings - sage: A1 == A2 # optional - sage.rings.finite_rings + sage: cat = Algebras(GF(3)).FiniteDimensional().WithBasis() + sage: A1 = FiniteDimensionalAlgebra(GF(3), table) + sage: A2 = FiniteDimensionalAlgebra(GF(3), table, category=cat) + sage: A1 == A2 False - sage: A1 is A2 # optional - sage.rings.finite_rings + sage: A1 is A2 False Checking that equality is still as expected:: - sage: A = FiniteDimensionalAlgebra(GF(3), table) # optional - sage.rings.finite_rings - sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])]) # optional - sage.rings.finite_rings - sage: A == A # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), table) + sage: B = FiniteDimensionalAlgebra(GF(5), [Matrix([0])]) + sage: A == A True - sage: B == B # optional - sage.rings.finite_rings + sage: B == B True - sage: A == B # optional - sage.rings.finite_rings + sage: A == B False - sage: A != A # optional - sage.rings.finite_rings + sage: A != A False - sage: B != B # optional - sage.rings.finite_rings + sage: B != B False - sage: A != B # optional - sage.rings.finite_rings + sage: A != B True """ n = len(table) @@ -161,17 +161,17 @@ def __init__(self, k, table, names='e', category=None): sage: TestSuite(A).run() - sage: B = FiniteDimensionalAlgebra(GF(7), [Matrix([1])]) # optional - sage.rings.finite_rings - sage: B # optional - sage.rings.finite_rings + sage: B = FiniteDimensionalAlgebra(GF(7), [Matrix([1])]) + sage: B Finite-dimensional algebra of degree 1 over Finite Field of size 7 - sage: TestSuite(B).run() # optional - sage.rings.finite_rings + sage: TestSuite(B).run() sage: C = FiniteDimensionalAlgebra(CC, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])]) sage: C Finite-dimensional algebra of degree 2 over Complex Field with 53 bits of precision sage: TestSuite(C).run() - sage: FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]])]) # optional - sage.rings.finite_rings + sage: FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]])]) Traceback (most recent call last): ... ValueError: input is not a multiplication table @@ -204,15 +204,15 @@ def _coerce_map_from_(self, S): """ TESTS:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.has_coerce_map_from(ZZ) # optional - sage.rings.finite_rings + sage: A.has_coerce_map_from(ZZ) True - sage: A.has_coerce_map_from(GF(3)) # optional - sage.rings.finite_rings + sage: A.has_coerce_map_from(GF(3)) True - sage: A.has_coerce_map_from(GF(5)) # optional - sage.rings.finite_rings + sage: A.has_coerce_map_from(GF(5)) # needs sage.rings.finite_rings False - sage: A.has_coerce_map_from(QQ) # optional - sage.rings.finite_rings + sage: A.has_coerce_map_from(QQ) False """ return S == self or (self.base_ring().has_coerce_map_from(S) and self.is_unitary()) @@ -270,9 +270,9 @@ def ngens(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.ngens() # optional - sage.rings.finite_rings + sage: A.ngens() 2 """ return len(self._table) @@ -286,9 +286,9 @@ def gen(self, i): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.gen(0) # optional - sage.rings.finite_rings + sage: A.gen(0) e0 """ return self.element_class(self, [j == i for j in range(self.ngens())]) @@ -300,9 +300,9 @@ def basis(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.basis() # optional - sage.rings.finite_rings + sage: A.basis() Family (e0, e1) """ from sage.sets.family import Family @@ -314,9 +314,9 @@ def __iter__(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: list(A) # optional - sage.rings.finite_rings + sage: list(A) [0, e0, 2*e0, e1, e0 + e1, 2*e0 + e1, 2*e1, e0 + 2*e1, 2*e0 + 2*e1] This is used in the :class:`Testsuite`'s when ``self`` is @@ -335,9 +335,9 @@ def _ideal_class_(self, n=0): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A._ideal_class_() # optional - sage.rings.finite_rings + sage: A._ideal_class_() """ return FiniteDimensionalAlgebraIdeal @@ -349,9 +349,9 @@ def table(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.table() # optional - sage.rings.finite_rings + sage: A.table() ( [1 0] [0 1] [0 1], [0 0] @@ -400,9 +400,9 @@ def base_extend(self, F): EXAMPLES:: - sage: C = FiniteDimensionalAlgebra(GF(2), [Matrix([1])]) # optional - sage.rings.finite_rings - sage: k. = GF(4) # optional - sage.rings.finite_rings - sage: C.base_extend(k) # optional - sage.rings.finite_rings + sage: C = FiniteDimensionalAlgebra(GF(2), [Matrix([1])]) + sage: k. = GF(4) # needs sage.rings.finite_rings + sage: C.base_extend(k) # needs sage.rings.finite_rings Finite-dimensional algebra of degree 1 over Finite Field in y of size 2^2 """ # Base extension of the multiplication table is done by __classcall_private__. @@ -414,9 +414,9 @@ def cardinality(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(7), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(7), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [2, 3]])]) - sage: A.cardinality() # optional - sage.rings.finite_rings + sage: A.cardinality() 49 sage: B = FiniteDimensionalAlgebra(RR, [Matrix([[1, 0], [0, 1]]), @@ -452,9 +452,9 @@ def ideal(self, gens=None, given_by_matrix=False, side=None): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.ideal(A([1,1])) # optional - sage.rings.finite_rings + sage: A.ideal(A([1,1])) Ideal (e0 + e1) of Finite-dimensional algebra of degree 2 over Finite Field of size 3 """ @@ -525,9 +525,9 @@ def is_finite(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(7), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(7), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [2, 3]])]) - sage: A.is_finite() # optional - sage.rings.finite_rings + sage: A.is_finite() True sage: B = FiniteDimensionalAlgebra(RR, [Matrix([[1, 0], [0, 1]]), @@ -623,8 +623,8 @@ def is_zero(self): sage: A.is_zero() True - sage: B = FiniteDimensionalAlgebra(GF(7), [Matrix([0])]) # optional - sage.rings.finite_rings - sage: B.is_zero() # optional - sage.rings.finite_rings + sage: B = FiniteDimensionalAlgebra(GF(7), [Matrix([0])]) + sage: B.is_zero() False """ return self.degree() == 0 @@ -680,9 +680,9 @@ def random_element(self, *args, **kwargs): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.random_element() # random # optional - sage.rings.finite_rings + sage: A.random_element() # random e0 + 2*e1 sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), @@ -759,16 +759,16 @@ def quotient_map(self, ideal): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: q0 = A.quotient_map(A.zero_ideal()); q0 # optional - sage.rings.finite_rings + sage: q0 = A.quotient_map(A.zero_ideal()); q0 Morphism from Finite-dimensional algebra of degree 2 over Finite Field of size 3 to Finite-dimensional algebra of degree 2 over Finite Field of size 3 given by matrix [1 0] [0 1] - sage: q1 = A.quotient_map(A.ideal(A.gen(1))); q1 # optional - sage.rings.finite_rings + sage: q1 = A.quotient_map(A.ideal(A.gen(1))); q1 Morphism from Finite-dimensional algebra of degree 2 over Finite Field of size 3 to Finite-dimensional algebra of degree 1 over Finite Field of size 3 @@ -805,16 +805,16 @@ def maximal_ideal(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.maximal_ideal() # optional - sage.rings.finite_rings + sage: A.maximal_ideal() # needs sage.rings.finite_rings Ideal (0, e1) of Finite-dimensional algebra of degree 2 over Finite Field of size 3 sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) - sage: B.maximal_ideal() # optional - sage.libs.pari + sage: B.maximal_ideal() # needs sage.libs.pari Traceback (most recent call last): ... ValueError: algebra is not local @@ -848,9 +848,9 @@ def primary_decomposition(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.primary_decomposition() # optional - sage.rings.finite_rings + sage: A.primary_decomposition() # needs sage.rings.finite_rings [Morphism from Finite-dimensional algebra of degree 2 over Finite Field of size 3 to Finite-dimensional algebra of degree 2 over Finite Field of size 3 @@ -860,7 +860,7 @@ def primary_decomposition(self): sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), ....: Matrix([[0,1,0], [0,0,0], [0,0,0]]), ....: Matrix([[0,0,0], [0,0,0], [0,0,1]])]) - sage: B.primary_decomposition() # optional - sage.libs.pari + sage: B.primary_decomposition() # needs sage.libs.pari [Morphism from Finite-dimensional algebra of degree 3 over Rational Field to Finite-dimensional algebra of degree 1 over Rational Field @@ -916,9 +916,9 @@ def maximal_ideals(self): EXAMPLES:: - sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), # optional - sage.rings.finite_rings + sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: A.maximal_ideals() # optional - sage.rings.finite_rings + sage: A.maximal_ideals() # needs sage.rings.finite_rings [Ideal (e1) of Finite-dimensional algebra of degree 2 over Finite Field of size 3] sage: B = FiniteDimensionalAlgebra(QQ, []) From 88c05fd59806e6312847e3dad4ca57849a823740 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 2 Jul 2023 01:00:55 -0700 Subject: [PATCH 130/538] sage.algebras: Update # optional / # needs --- src/sage/algebras/algebra.py | 2 +- .../algebras/clifford_algebra_element.pyx | 1 + src/sage/algebras/group_algebra.py | 2 +- src/sage/algebras/octonion_algebra.pyx | 12 +- src/sage/algebras/orlik_solomon.py | 188 ++++++++++-------- src/sage/algebras/orlik_terao.py | 32 ++- 6 files changed, 137 insertions(+), 100 deletions(-) diff --git a/src/sage/algebras/algebra.py b/src/sage/algebras/algebra.py index 547eee6c699..e69ea7da530 100644 --- a/src/sage/algebras/algebra.py +++ b/src/sage/algebras/algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Abstract base class for algebras """ diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index fc70360dab3..3ebad1013fe 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -945,6 +945,7 @@ cdef class CohomologyRAAGElement(CliffordAlgebraElement): EXAMPLES:: + sage: # needs sage.graphs sage: C4 = graphs.CycleGraph(4) sage: A = groups.misc.RightAngledArtin(C4) sage: H = A.cohomology() diff --git a/src/sage/algebras/group_algebra.py b/src/sage/algebras/group_algebra.py index 38698c5f00d..eaffe7538b7 100644 --- a/src/sage/algebras/group_algebra.py +++ b/src/sage/algebras/group_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.groups sage.modules +# sage.doctest: needs sage.groups sage.modules r""" Group algebras diff --git a/src/sage/algebras/octonion_algebra.pyx b/src/sage/algebras/octonion_algebra.pyx index 85984dff57c..ee69aca6a7e 100644 --- a/src/sage/algebras/octonion_algebra.pyx +++ b/src/sage/algebras/octonion_algebra.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules """ Octonion Algebras @@ -416,7 +416,7 @@ cdef class Octonion_generic(AlgebraElement): sage: O = OctonionAlgebra(QQ, 1, 3, 7) sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) - sage: elt.norm() + sage: elt.norm() # needs sage.symbolic 2*sqrt(-61) sage: elt = sum(O.basis()) sage: elt.norm() @@ -439,7 +439,7 @@ cdef class Octonion_generic(AlgebraElement): sage: O = OctonionAlgebra(QQ, 1, 3, 7) sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) - sage: elt.abs() + sage: elt.abs() # needs sage.symbolic 2*sqrt(-61) sage: elt = sum(O.basis()) sage: elt.abs() @@ -577,10 +577,10 @@ cdef class Octonion(Octonion_generic): sage: O = OctonionAlgebra(QQ) sage: elt = sum(i * b for i, b in enumerate(O.basis(), start=2)) - sage: elt.norm() + sage: elt.norm() # needs sage.symbolic 2*sqrt(71) sage: elt = sum(O.basis()) - sage: elt.norm() + sage: elt.norm() # needs sage.symbolic 2*sqrt(2) """ return self.vec.norm() @@ -751,7 +751,7 @@ class OctonionAlgebra(UniqueRepresentation, Parent): EXAMPLES:: sage: O = OctonionAlgebra(QQ) - sage: TestSuite(O).run() + sage: TestSuite(O).run() # needs sage.symbolic sage: O = OctonionAlgebra(QQ, 1, 3, 7) sage: TestSuite(O).run() diff --git a/src/sage/algebras/orlik_solomon.py b/src/sage/algebras/orlik_solomon.py index 8a57893dc7f..f92a93c7e21 100644 --- a/src/sage/algebras/orlik_solomon.py +++ b/src/sage/algebras/orlik_solomon.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Orlik-Solomon Algebras """ @@ -115,9 +115,10 @@ def __init__(self, R, M, ordering=None): We check on the matroid associated to the graph with 3 vertices and 2 edges between each vertex:: + sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[2,3],[1,3],[1,3]], multiedges=True) - sage: M = Matroid(G) - sage: OS = M.orlik_solomon_algebra(QQ) + sage: MG = Matroid(G) + sage: OS = MG.orlik_solomon_algebra(QQ) sage: elts = OS.some_elements() + list(OS.algebra_generators()) sage: TestSuite(OS).run(elements=elts) """ @@ -254,10 +255,11 @@ def product_on_basis(self, a, b): Let us check that `e_{s_1} e_{s_2} \cdots e_{s_k} = e_S` for any subset `S = \{ s_1 < s_2 < \cdots < s_k \}` of the ground set:: + sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[3,4],[4,2]], multiedges=True) - sage: M = Matroid(G).regular_matroid() - sage: E = M.groundset_list() - sage: OS = M.orlik_solomon_algebra(ZZ) + sage: MG = Matroid(G).regular_matroid() + sage: E = MG.groundset_list() + sage: OS = MG.orlik_solomon_algebra(ZZ) sage: G = OS.algebra_generators() sage: import itertools sage: def test_prod(F): @@ -327,31 +329,33 @@ def subset_image(self, S): ([2, 5], -OS{0, 2} + OS{0, 5}) ([4, 5], -OS{3, 4} + OS{3, 5}) + sage: # needs sage.graphs sage: M4 = matroids.CompleteGraphic(4) - sage: OS = M4.orlik_solomon_algebra(QQ) - sage: OS.subset_image(frozenset({2,3,4})) + sage: OSM4 = M4.orlik_solomon_algebra(QQ) + sage: OSM4.subset_image(frozenset({2,3,4})) OS{0, 2, 3} + OS{0, 3, 4} An example of a custom ordering:: + sage: # needs sage.graphs sage: G = Graph([[3, 4], [4, 1], [1, 2], [2, 3], [3, 5], [5, 6], [6, 3]]) - sage: M = Matroid(G) + sage: MG = Matroid(G) sage: s = [(5, 6), (1, 2), (3, 5), (2, 3), (1, 4), (3, 6), (3, 4)] - sage: sorted([sorted(c) for c in M.circuits()]) + sage: sorted([sorted(c) for c in MG.circuits()]) [[(1, 2), (1, 4), (2, 3), (3, 4)], [(3, 5), (3, 6), (5, 6)]] - sage: OS = M.orlik_solomon_algebra(QQ, ordering=s) - sage: OS.subset_image(frozenset([])) + sage: OSMG = MG.orlik_solomon_algebra(QQ, ordering=s) + sage: OSMG.subset_image(frozenset([])) OS{} - sage: OS.subset_image(frozenset([(1,2),(3,4),(1,4),(2,3)])) + sage: OSMG.subset_image(frozenset([(1,2),(3,4),(1,4),(2,3)])) 0 - sage: OS.subset_image(frozenset([(2,3),(1,2),(3,4)])) + sage: OSMG.subset_image(frozenset([(2,3),(1,2),(3,4)])) OS{(1, 2), (2, 3), (3, 4)} - sage: OS.subset_image(frozenset([(1,4),(3,4),(2,3),(3,6),(5,6)])) + sage: OSMG.subset_image(frozenset([(1,4),(3,4),(2,3),(3,6),(5,6)])) -OS{(1, 2), (1, 4), (2, 3), (3, 6), (5, 6)} + OS{(1, 2), (1, 4), (3, 4), (3, 6), (5, 6)} - OS{(1, 2), (2, 3), (3, 4), (3, 6), (5, 6)} - sage: OS.subset_image(frozenset([(1,4),(3,4),(2,3),(3,6),(3,5)])) + sage: OSMG.subset_image(frozenset([(1,4),(3,4),(2,3),(3,6),(3,5)])) OS{(1, 2), (1, 4), (2, 3), (3, 5), (5, 6)} - OS{(1, 2), (1, 4), (2, 3), (3, 6), (5, 6)} + OS{(1, 2), (1, 4), (3, 4), (3, 5), (5, 6)} @@ -361,34 +365,36 @@ def subset_image(self, S): TESTS:: + sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[2,3],[1,3],[1,3]], multiedges=True) - sage: M = Matroid(G) + sage: MG = Matroid(G) sage: sorted([sorted(c) for c in M.circuits()]) [[0, 1], [0, 2, 4], [0, 2, 5], [0, 3, 4], [0, 3, 5], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [2, 3], [4, 5]] - sage: OS = M.orlik_solomon_algebra(QQ) - sage: OS.subset_image(frozenset([])) + sage: OSMG = MG.orlik_solomon_algebra(QQ) + sage: OSMG.subset_image(frozenset([])) OS{} - sage: OS.subset_image(frozenset([1, 2, 3])) + sage: OSMG.subset_image(frozenset([1, 2, 3])) 0 - sage: OS.subset_image(frozenset([1, 3, 5])) + sage: OSMG.subset_image(frozenset([1, 3, 5])) 0 - sage: OS.subset_image(frozenset([1, 2])) + sage: OSMG.subset_image(frozenset([1, 2])) OS{0, 2} - sage: OS.subset_image(frozenset([3, 4])) + sage: OSMG.subset_image(frozenset([3, 4])) -OS{0, 2} + OS{0, 4} - sage: OS.subset_image(frozenset([1, 5])) + sage: OSMG.subset_image(frozenset([1, 5])) OS{0, 4} + sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[3,4],[4,2]], multiedges=True) - sage: M = Matroid(G) - sage: sorted([sorted(c) for c in M.circuits()]) + sage: MG = Matroid(G) + sage: sorted([sorted(c) for c in MG.circuits()]) [[0, 1], [2, 3, 4]] - sage: OS = M.orlik_solomon_algebra(QQ) - sage: OS.subset_image(frozenset([])) + sage: OSMG = MG.orlik_solomon_algebra(QQ) + sage: OSMG.subset_image(frozenset([])) OS{} - sage: OS.subset_image(frozenset([1, 3, 4])) + sage: OSMG.subset_image(frozenset([1, 3, 4])) -OS{0, 2, 3} + OS{0, 2, 4} We check on a non-standard ordering:: @@ -453,6 +459,7 @@ def as_gca(self): EXAMPLES:: + sage: # needs sage.geometry.polyhedron sage: H = hyperplane_arrangements.braid(3) sage: O = H.orlik_solomon_algebra(QQ) sage: O.as_gca() @@ -477,6 +484,7 @@ def as_gca(self): TESTS:: + sage: # needs sage.geometry.polyhedron sage: H = hyperplane_arrangements.Catalan(3,QQ).cone() sage: O = H.orlik_solomon_algebra(QQ) sage: A = O.as_gca() @@ -516,6 +524,7 @@ def as_cdga(self): EXAMPLES:: + sage: # needs sage.geometry.polyhedron sage: H = hyperplane_arrangements.braid(3) sage: O = H.orlik_solomon_algebra(QQ) sage: O.as_cdga() @@ -546,10 +555,11 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): Lets start with the action of `S_3` on the rank `2` braid matroid:: - sage: M = matroids.CompleteGraphic(3) # optional - sage.graphs - sage: M.groundset() # optional - sage.graphs + sage: # needs sage.graphs + sage: M = matroids.CompleteGraphic(3) + sage: M.groundset() frozenset({0, 1, 2}) - sage: G = SymmetricGroup(3) # optional - sage.groups + sage: G = SymmetricGroup(3) # needs sage.groups Calling elements ``g`` of ``G`` on an element `i` of `\{1, 2, 3\}` defines the action we want, but since the groundset is `\{0, 1, 2\}` @@ -561,30 +571,33 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): Now that we have defined an action we can create the invariant, and get its basis:: - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, on_groundset)) # optional - sage.graphs sage.groups - sage: OSG.basis() # optional - sage.graphs sage.groups + sage: # needs sage.graphs sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, on_groundset)) + sage: OSG.basis() Finite family {0: B[0], 1: B[1]} - sage: [OSG.lift(b) for b in OSG.basis()] # optional - sage.graphs sage.groups + sage: [OSG.lift(b) for b in OSG.basis()] [OS{}, OS{0} + OS{1} + OS{2}] Since it is invariant, the action of any ``g`` in ``G`` is trivial:: - sage: x = OSG.an_element(); x # optional - sage.graphs sage.groups + sage: # needs sage.graphs sage.groups + sage: x = OSG.an_element(); x 2*B[0] + 2*B[1] - sage: g = G.an_element(); g # optional - sage.graphs sage.groups + sage: g = G.an_element(); g (2,3) - sage: g * x # optional - sage.graphs sage.groups + sage: g * x 2*B[0] + 2*B[1] - sage: x = OSG.random_element() # optional - sage.graphs sage.groups - sage: g = G.random_element() # optional - sage.graphs sage.groups - sage: g * x == x # optional - sage.graphs sage.groups + sage: # needs sage.graphs sage.groups + sage: x = OSG.random_element() + sage: g = G.random_element() + sage: g * x == x True The underlying ambient module is the Orlik-Solomon algebra, which is accessible via :meth:`ambient()`:: - sage: M.orlik_solomon_algebra(QQ) is OSG.ambient() # optional - sage.graphs sage.groups + sage: M.orlik_solomon_algebra(QQ) is OSG.ambient() # needs sage.graphs sage.groups True There is not much structure here, so lets look at a bigger example. @@ -592,53 +605,53 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): easier, we'll start the indexing at `1` so that the `S_6` action on the groundset is simply calling `g`:: - sage: M = matroids.CompleteGraphic(4); M.groundset() # optional - sage.graphs + sage: M = matroids.CompleteGraphic(4); M.groundset() # needs sage.graphs frozenset({0, 1, 2, 3, 4, 5}) - sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] # optional - sage.graphs - sage: M = Matroid(bases=new_bases); M.groundset() # optional - sage.graphs + sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] # needs sage.graphs + sage: M = Matroid(bases=new_bases); M.groundset() # needs sage.graphs frozenset({1, 2, 3, 4, 5, 6}) - sage: G = SymmetricGroup(6) # optional - sage.groups - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) # optional - sage.graphs sage.groups - sage: OSG.basis() # optional - sage.graphs sage.groups + sage: G = SymmetricGroup(6) # needs sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) # needs sage.graphs sage.groups + sage: OSG.basis() # needs sage.graphs sage.groups Finite family {0: B[0], 1: B[1]} - sage: [OSG.lift(b) for b in OSG.basis()] # optional - sage.graphs sage.groups + sage: [OSG.lift(b) for b in OSG.basis()] # needs sage.graphs sage.groups [OS{}, OS{1} + OS{2} + OS{3} + OS{4} + OS{5} + OS{6}] - sage: (OSG.basis()[1])^2 # optional - sage.graphs sage.groups + sage: (OSG.basis()[1])^2 # needs sage.graphs sage.groups 0 - sage: 5 * OSG.basis()[1] # optional - sage.graphs sage.groups + sage: 5 * OSG.basis()[1] # needs sage.graphs sage.groups 5*B[1] Next, we look at the same matroid but with an `S_3 \times S_3` action (here realized as a Young subgroup of `S_6`):: - sage: H = G.young_subgroup([3, 3]) # optional - sage.graphs sage.groups - sage: OSH = M.orlik_solomon_algebra(QQ, invariant=H) # optional - sage.graphs sage.groups - sage: OSH.basis() # optional - sage.graphs sage.groups + sage: H = G.young_subgroup([3, 3]) # needs sage.graphs sage.groups + sage: OSH = M.orlik_solomon_algebra(QQ, invariant=H) # needs sage.graphs sage.groups + sage: OSH.basis() # needs sage.graphs sage.groups Finite family {0: B[0], 1: B[1], 2: B[2]} - sage: [OSH.lift(b) for b in OSH.basis()] # optional - sage.graphs sage.groups + sage: [OSH.lift(b) for b in OSH.basis()] # needs sage.graphs sage.groups [OS{}, OS{4} + OS{5} + OS{6}, OS{1} + OS{2} + OS{3}] We implement an `S_4` action on the vertices:: - sage: M = matroids.CompleteGraphic(4) # optional - sage.graphs - sage: G = SymmetricGroup(4) # optional - sage.groups - sage: edge_map = {i: M.groundset_to_edges([i])[0][:2] # optional - sage.graphs + sage: M = matroids.CompleteGraphic(4) # needs sage.graphs + sage: G = SymmetricGroup(4) # needs sage.groups + sage: edge_map = {i: M.groundset_to_edges([i])[0][:2] # needs sage.graphs ....: for i in M.groundset()} - sage: inv_map = {v: k for k, v in edge_map.items()} # optional - sage.graphs + sage: inv_map = {v: k for k, v in edge_map.items()} # needs sage.graphs sage: def vert_action(g, x): ....: a, b = edge_map[x] ....: return inv_map[tuple(sorted([g(a+1)-1, g(b+1)-1]))] - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, vert_action)) # optional - sage.graphs sage.groups - sage: B = OSG.basis() # optional - sage.graphs sage.groups - sage: [OSG.lift(b) for b in B] # optional - sage.graphs sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, vert_action)) # needs sage.graphs sage.groups + sage: B = OSG.basis() # needs sage.graphs sage.groups + sage: [OSG.lift(b) for b in B] # needs sage.graphs sage.groups [OS{}, OS{0} + OS{1} + OS{2} + OS{3} + OS{4} + OS{5}] We use this to describe the Young subgroup `S_2 \times S_2` action:: - sage: H = G.young_subgroup([2,2]) # optional - sage.graphs sage.groups - sage: OSH = M.orlik_solomon_algebra(QQ, invariant=(H, vert_action)) # optional - sage.graphs sage.groups - sage: B = OSH.basis() # optional - sage.graphs sage.groups - sage: [OSH.lift(b) for b in B] # optional - sage.graphs sage.groups + sage: H = G.young_subgroup([2,2]) # needs sage.graphs sage.groups + sage: OSH = M.orlik_solomon_algebra(QQ, invariant=(H, vert_action)) # needs sage.graphs sage.groups + sage: B = OSH.basis() # needs sage.graphs sage.groups + sage: [OSH.lift(b) for b in B] # needs sage.graphs sage.groups [OS{}, OS{5}, OS{1} + OS{2} + OS{3} + OS{4}, OS{0}, -1/2*OS{1, 2} + OS{1, 5} - 1/2*OS{3, 4} + OS{3, 5}, OS{0, 5}, OS{0, 1} + OS{0, 2} + OS{0, 3} + OS{0, 4}, @@ -646,7 +659,7 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): We demonstrate the algebra structure:: - sage: matrix([[b*bp for b in B] for bp in B]) # optional - sage.graphs sage.groups + sage: matrix([[b*bp for b in B] for bp in B]) # needs sage.graphs sage.groups [ B[0] B[1] B[2] B[3] B[4] B[5] B[6] B[7]] [ B[1] 0 2*B[4] B[5] 0 0 2*B[7] 0] [ B[2] -2*B[4] 0 B[6] 0 -2*B[7] 0 0] @@ -669,12 +682,12 @@ def __init__(self, R, M, G, action_on_groundset=None, *args, **kwargs): EXAMPLES:: - sage: M = matroids.CompleteGraphic(4) # optional - sage.graphs - sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] # optional - sage.graphs - sage: M = Matroid(bases=new_bases) # optional - sage.graphs - sage: G = SymmetricGroup(6) # optional - sage.groups - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) # optional - sage.graphs sage.groups - sage: TestSuite(OSG).run() # optional - sage.graphs sage.groups + sage: M = matroids.CompleteGraphic(4) # needs sage.graphs + sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] # needs sage.graphs + sage: M = Matroid(bases=new_bases) # needs sage.graphs + sage: G = SymmetricGroup(6) # needs sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) # needs sage.graphs sage.groups + sage: TestSuite(OSG).run() # needs sage.graphs sage.groups """ ordering = kwargs.pop('ordering', None) OS = OrlikSolomonAlgebra(R, M, ordering) @@ -757,16 +770,17 @@ def _basis_action(self, g, f): EXAMPLES:: - sage: M = matroids.CompleteGraphic(3) # optional - sage.graphs - sage: M.groundset() # optional - sage.graphs + sage: # needs sage.graphs + sage: M = matroids.CompleteGraphic(3) + sage: M.groundset() frozenset({0, 1, 2}) - sage: G = SymmetricGroup(3) # optional - sage.groups + sage: G = SymmetricGroup(3) # needs sage.groups sage: def on_groundset(g, x): ....: return g(x+1)-1 - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G,on_groundset)) # optional - sage.graphs sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G,on_groundset)) # needs sage.groups sage: act = lambda g: (OSG._basis_action(g,frozenset({0,1})), ....: OSG._basis_action(g,frozenset({0,2}))) - sage: [act(g) for g in G] # optional - sage.graphs sage.groups + sage: [act(g) for g in G] # needs sage.groups [(OS{0, 1}, OS{0, 2}), (-OS{0, 2}, OS{0, 1} - OS{0, 2}), (-OS{0, 1} + OS{0, 2}, -OS{0, 1}), @@ -776,26 +790,26 @@ def _basis_action(self, g, f): We also check that the ordering is respected:: - sage: fset = frozenset({1,2}) # optional - sage.graphs sage.groups - sage: OS1 = M.orlik_solomon_algebra(QQ) # optional - sage.graphs sage.groups - sage: OS1.subset_image(fset) # optional - sage.graphs sage.groups + sage: fset = frozenset({1,2}) # needs sage.graphs sage.groups + sage: OS1 = M.orlik_solomon_algebra(QQ) # needs sage.graphs sage.groups + sage: OS1.subset_image(fset) # needs sage.graphs sage.groups -OS{0, 1} + OS{0, 2} - sage: OS2 = M.orlik_solomon_algebra(QQ, range(2,-1,-1)) # optional - sage.graphs sage.groups - sage: OS2.subset_image(fset) # optional - sage.graphs sage.groups + sage: OS2 = M.orlik_solomon_algebra(QQ, range(2,-1,-1)) # needs sage.graphs sage.groups + sage: OS2.subset_image(fset) # needs sage.graphs sage.groups OS{1, 2} - sage: OSG2 = M.orlik_solomon_algebra(QQ, # optional - sage.graphs sage.groups + sage: OSG2 = M.orlik_solomon_algebra(QQ, # needs sage.graphs sage.groups ....: invariant=(G,on_groundset), ....: ordering=range(2,-1,-1)) - sage: g = G.an_element(); g # optional - sage.graphs sage.groups + sage: g = G.an_element(); g # needs sage.graphs sage.groups (2,3) This choice of ``g`` acting on this choice of ``fset`` reverses the sign:: - sage: OSG._basis_action(g, fset) # optional - sage.graphs sage.groups + sage: OSG._basis_action(g, fset) # needs sage.graphs sage.groups OS{0, 1} - OS{0, 2} - sage: OSG2._basis_action(g, fset) # optional - sage.graphs sage.groups + sage: OSG2._basis_action(g, fset) # needs sage.graphs sage.groups -OS{1, 2} """ OS = self._ambient diff --git a/src/sage/algebras/orlik_terao.py b/src/sage/algebras/orlik_terao.py index f7728124ec3..db493ac6b1b 100644 --- a/src/sage/algebras/orlik_terao.py +++ b/src/sage/algebras/orlik_terao.py @@ -131,10 +131,12 @@ def __init__(self, R, M, ordering=None): sage: OT = M.orlik_terao_algebra(QQ) sage: TestSuite(OT).run(elements=OT.basis()) + sage: # needs sage.graphs sage: M = matroids.CompleteGraphic(4).ternary_matroid() sage: OT = M.orlik_terao_algebra(GF(3)['t']) sage: TestSuite(OT).run(elements=OT.basis()) + sage: # needs sage.geometry.polyhedron sage: H = hyperplane_arrangements.Catalan(4).cone() sage: M = H.matroid() sage: OT = M.orlik_terao_algebra() @@ -145,6 +147,7 @@ def __init__(self, R, M, ordering=None): We check on the matroid associated to the graph with 3 vertices and 2 edges between each vertex:: + sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[2,3],[1,3],[1,3]], multiedges=True) sage: M = Matroid(G).regular_matroid() sage: OT = M.orlik_terao_algebra(QQ) @@ -322,6 +325,7 @@ def product_on_basis(self, a, b): Let us check that `e_{s_1} e_{s_2} \cdots e_{s_k} = e_S` for any subset `S = \{ s_1 < s_2 < \cdots < s_k \}` of the ground set:: + sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[3,4],[4,2]], multiedges=True) sage: M = Matroid(G).regular_matroid() sage: E = M.groundset_list() @@ -371,6 +375,7 @@ def subset_image(self, S): ([2, 5], -OT{0, 2} + OT{0, 5}) ([4, 5], -OT{3, 4} - OT{3, 5}) + sage: # needs sage.graphs sage: M4 = matroids.CompleteGraphic(4).ternary_matroid() sage: OT = M4.orlik_terao_algebra() sage: OT.subset_image(frozenset({2,3,4})) @@ -378,6 +383,7 @@ def subset_image(self, S): An example of a custom ordering:: + sage: # needs sage.graphs sage: G = Graph([[3, 4], [4, 1], [1, 2], [2, 3], [3, 5], [5, 6], [6, 3]]) sage: M = Matroid(G).regular_matroid() sage: s = [(5, 6), (1, 2), (3, 5), (2, 3), (1, 4), (3, 6), (3, 4)] @@ -405,6 +411,7 @@ def subset_image(self, S): TESTS:: + sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[2,3],[1,3],[1,3]], multiedges=True) sage: M = Matroid(G).regular_matroid() sage: sorted([sorted(c) for c in M.circuits()]) @@ -425,6 +432,7 @@ def subset_image(self, S): sage: OT.subset_image(frozenset([1, 5])) OT{0, 4} + sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[3,4],[4,2]], multiedges=True) sage: M = Matroid(G).regular_matroid() sage: sorted([sorted(c) for c in M.circuits()]) @@ -499,6 +507,7 @@ def _chi(self, X): EXAMPLES:: + sage: # needs sage.geometry.polyhedron sage: H = hyperplane_arrangements.Catalan(2).cone() sage: M = H.matroid() sage: OT = M.orlik_terao_algebra() @@ -542,7 +551,7 @@ class OrlikTeraoInvariantAlgebra(FiniteDimensionalInvariantModule): sage: M = Matroid(A) sage: M.groundset() frozenset({0, 1, 2}) - sage: G = SymmetricGroup(3) + sage: G = SymmetricGroup(3) # needs sage.groups Calling elements ``g`` of ``G`` on an element `i` of `\{1,2,3\}` defines the action we want, but since the groundset is `\{0,1,2\}` @@ -554,7 +563,8 @@ class OrlikTeraoInvariantAlgebra(FiniteDimensionalInvariantModule): Now that we have defined an action we can create the invariant, and get its basis:: - sage: OTG = M.orlik_terao_algebra(QQ, invariant = (G, on_groundset)) + sage: # needs sage.groups + sage: OTG = M.orlik_terao_algebra(QQ, invariant=(G, on_groundset)) sage: OTG.basis() Finite family {0: B[0], 1: B[1]} sage: [OTG.lift(b) for b in OTG.basis()] @@ -562,6 +572,7 @@ class OrlikTeraoInvariantAlgebra(FiniteDimensionalInvariantModule): Since it is invariant, the action of any ``g`` in ``G`` is trivial:: + sage: # needs sage.groups sage: x = OTG.an_element(); x 2*B[0] + 2*B[1] sage: g = G.an_element(); g @@ -569,6 +580,7 @@ class OrlikTeraoInvariantAlgebra(FiniteDimensionalInvariantModule): sage: g*x 2*B[0] + 2*B[1] + sage: # needs sage.groups sage: x = OTG.random_element() sage: g = G.random_element() sage: g*x == x @@ -577,11 +589,12 @@ class OrlikTeraoInvariantAlgebra(FiniteDimensionalInvariantModule): The underlying ambient module is the Orlik-Terao algebra, which is accessible via :meth:`ambient()`:: - sage: M.orlik_terao_algebra(QQ) is OTG.ambient() + sage: M.orlik_terao_algebra(QQ) is OTG.ambient() # needs sage.groups True For a bigger example, here we will look at the rank-`3` braid matroid:: + sage: # needs sage.groups sage: A = matrix([[1,1,1,0,0,0],[-1,0,0,1,1,0], ....: [0,-1,0,-1,0,1],[0,0,-1,0,-1,-1]]); A [ 1 1 1 0 0 0] @@ -591,9 +604,11 @@ class OrlikTeraoInvariantAlgebra(FiniteDimensionalInvariantModule): sage: M = Matroid(A); M.groundset() frozenset({0, 1, 2, 3, 4, 5}) sage: G = SymmetricGroup(6) - sage: OTG = M.orlik_terao_algebra(QQ, invariant = (G, on_groundset)) + sage: OTG = M.orlik_terao_algebra(QQ, invariant=(G, on_groundset)) sage: OTG.ambient() - Orlik-Terao algebra of Linear matroid of rank 3 on 6 elements represented over the Rational Field over Rational Field + Orlik-Terao algebra of + Linear matroid of rank 3 on 6 elements represented over the Rational Field + over Rational Field sage: OTG.basis() Finite family {0: B[0], 1: B[1]} sage: [OTG.lift(b) for b in OTG.basis()] @@ -606,6 +621,7 @@ def __init__(self, R, M, G, action_on_groundset=None, *args, **kwargs): EXAMPLES:: + sage: # needs sage.groups sage: A = matrix([[1,1,1,0,0,0],[-1,0,0,1,1,0],[0,-1,0,-1,0,1], ....: [0,0,-1,0,-1,-1]]) sage: M = Matroid(A); @@ -669,6 +685,7 @@ def construction(self): TESTS:: + sage: # needs sage.groups sage: A = matrix([[1,1,0],[-1,0,1],[0,-1,-1]]) sage: M = Matroid(A) sage: G = SymmetricGroup(3) @@ -697,6 +714,7 @@ def _basis_action(self, g, f): EXAMPLES:: + sage: # needs sage.groups sage: A = matrix([[1,1,0],[-1,0,1],[0,-1,-1]]) sage: M = Matroid(A) sage: M.groundset() @@ -719,6 +737,7 @@ def _basis_action(self, g, f): We also check that the ordering is respected:: + sage: # needs sage.groups sage: fset = frozenset({1,2}) sage: OT1 = M.orlik_terao_algebra(QQ) sage: OT1.subset_image(fset) @@ -727,6 +746,7 @@ def _basis_action(self, g, f): sage: OT2.subset_image(fset) OT{1, 2} + sage: # needs sage.groups sage: OTG2 = M.orlik_terao_algebra(QQ, ....: invariant=(G,on_groundset), ....: ordering=range(2,-1,-1)) @@ -735,6 +755,7 @@ def _basis_action(self, g, f): This choice of ``g`` fixes these elements:: + sage: # needs sage.groups sage: OTG._basis_action(g, fset) -OT{0, 1} + OT{0, 2} sage: OTG2._basis_action(g, fset) @@ -742,6 +763,7 @@ def _basis_action(self, g, f): TESTS:: + sage: # needs sage.groups sage: [on_groundset(g, e) for e in M.groundset()] [0, 2, 1] sage: [OTG._groundset_action(g,e) for e in M.groundset()] From 6857ee2ab51b999e267a9a9d7f65c786e5b80c70 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 6 Aug 2023 20:44:52 -0700 Subject: [PATCH 131/538] src/sage/algebras: Update file-level doctest tag --- src/sage/algebras/affine_nil_temperley_lieb.py | 2 +- src/sage/algebras/askey_wilson.py | 2 +- src/sage/algebras/associated_graded.py | 2 +- src/sage/algebras/cellular_basis.py | 2 +- src/sage/algebras/clifford_algebra.py | 2 +- src/sage/algebras/clifford_algebra_element.pyx | 2 +- src/sage/algebras/cluster_algebra.py | 2 +- src/sage/algebras/commutative_dga.py | 2 +- src/sage/algebras/down_up_algebra.py | 2 +- src/sage/algebras/exterior_algebra_groebner.pyx | 2 +- .../finite_dimensional_algebra_ideal.py | 1 + src/sage/algebras/finite_gca.py | 2 +- src/sage/algebras/free_algebra.py | 2 +- src/sage/algebras/free_algebra_element.py | 2 +- src/sage/algebras/free_algebra_quotient.py | 2 +- src/sage/algebras/free_algebra_quotient_element.py | 2 +- src/sage/algebras/free_zinbiel_algebra.py | 2 +- src/sage/algebras/hall_algebra.py | 2 +- src/sage/algebras/hecke_algebras/ariki_koike_algebra.py | 2 +- src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py | 2 +- src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py | 2 +- src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py | 2 +- src/sage/algebras/iwahori_hecke_algebra.py | 2 +- src/sage/algebras/jordan_algebra.py | 2 +- .../lie_conformal_algebras/abelian_lie_conformal_algebra.py | 2 +- .../lie_conformal_algebras/affine_lie_conformal_algebra.py | 2 +- .../bosonic_ghosts_lie_conformal_algebra.py | 2 +- .../fermionic_ghosts_lie_conformal_algebra.py | 2 +- .../lie_conformal_algebras/finitely_freely_generated_lca.py | 2 +- .../lie_conformal_algebras/free_bosons_lie_conformal_algebra.py | 2 +- .../free_fermions_lie_conformal_algebra.py | 2 +- .../freely_generated_lie_conformal_algebra.py | 2 +- .../lie_conformal_algebras/graded_lie_conformal_algebra.py | 2 +- .../algebras/lie_conformal_algebras/lie_conformal_algebra.py | 2 +- .../lie_conformal_algebras/lie_conformal_algebra_element.py | 2 +- .../lie_conformal_algebras/lie_conformal_algebra_with_basis.py | 2 +- .../lie_conformal_algebra_with_structure_coefs.py | 2 +- .../algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py | 2 +- .../neveu_schwarz_lie_conformal_algebra.py | 2 +- .../lie_conformal_algebras/virasoro_lie_conformal_algebra.py | 2 +- .../lie_conformal_algebras/weyl_lie_conformal_algebra.py | 2 +- src/sage/algebras/nil_coxeter_algebra.py | 2 +- src/sage/algebras/orlik_terao.py | 2 +- src/sage/algebras/q_commuting_polynomials.py | 2 +- src/sage/algebras/q_system.py | 2 +- src/sage/algebras/quantum_clifford.py | 2 +- src/sage/algebras/quantum_groups/ace_quantum_onsager.py | 2 +- src/sage/algebras/quantum_groups/fock_space.py | 2 +- src/sage/algebras/quantum_groups/representations.py | 2 +- src/sage/algebras/quantum_matrix_coordinate_algebra.py | 2 +- src/sage/algebras/quaternion_algebra.py | 2 +- src/sage/algebras/quaternion_algebra_element.py | 2 +- src/sage/algebras/rational_cherednik_algebra.py | 2 +- src/sage/algebras/schur_algebra.py | 2 +- src/sage/algebras/shuffle_algebra.py | 2 +- src/sage/algebras/splitting_algebra.py | 2 +- src/sage/algebras/steenrod/steenrod_algebra.py | 2 +- src/sage/algebras/steenrod/steenrod_algebra_mult.py | 2 +- src/sage/algebras/tensor_algebra.py | 2 +- src/sage/algebras/weyl_algebra.py | 2 +- src/sage/algebras/yangian.py | 2 +- src/sage/algebras/yokonuma_hecke_algebra.py | 2 +- 62 files changed, 62 insertions(+), 61 deletions(-) diff --git a/src/sage/algebras/affine_nil_temperley_lieb.py b/src/sage/algebras/affine_nil_temperley_lieb.py index 8f88e2bb3b7..1fa213bd4bc 100644 --- a/src/sage/algebras/affine_nil_temperley_lieb.py +++ b/src/sage/algebras/affine_nil_temperley_lieb.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Affine nilTemperley Lieb Algebra of type A """ diff --git a/src/sage/algebras/askey_wilson.py b/src/sage/algebras/askey_wilson.py index 1d597987c60..4943c73b36d 100644 --- a/src/sage/algebras/askey_wilson.py +++ b/src/sage/algebras/askey_wilson.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Askey-Wilson Algebras diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 9afb563923b..5dd01321114 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Associated Graded Algebras To Filtered Algebras diff --git a/src/sage/algebras/cellular_basis.py b/src/sage/algebras/cellular_basis.py index 62aeaa03bdd..e6e7487cba9 100644 --- a/src/sage/algebras/cellular_basis.py +++ b/src/sage/algebras/cellular_basis.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Cellular Basis ============== diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 7d517534792..ed24df4abfc 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Clifford Algebras diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index 3ebad1013fe..ce4708313b4 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules """ Clifford algebra elements diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index 8a468dad0e1..bdd8164955c 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.graphs sage.modules +# sage.doctest: needs sage.graphs sage.modules r""" Cluster algebras diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index 39da2cd3772..f3ef35660cc 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Commutative Differential Graded Algebras diff --git a/src/sage/algebras/down_up_algebra.py b/src/sage/algebras/down_up_algebra.py index b39c86b3d4f..d5fe1c257eb 100644 --- a/src/sage/algebras/down_up_algebra.py +++ b/src/sage/algebras/down_up_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Down-Up Algebras diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index ee54b5e4baf..265e9323536 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Exterior algebras Gröbner bases diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py index 54f137e1966..15f0881bb8b 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.rings.finite_rings (because all doctests use GF) """ Ideals of Finite Algebras """ diff --git a/src/sage/algebras/finite_gca.py b/src/sage/algebras/finite_gca.py index 9c76ddf3199..f2e7d9af301 100644 --- a/src/sage/algebras/finite_gca.py +++ b/src/sage/algebras/finite_gca.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Finite dimensional graded commutative algebras diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index ea4e2707e67..70ccb24c63f 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Free algebras diff --git a/src/sage/algebras/free_algebra_element.py b/src/sage/algebras/free_algebra_element.py index f5bf4277f16..1854414e2d0 100644 --- a/src/sage/algebras/free_algebra_element.py +++ b/src/sage/algebras/free_algebra_element.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Free algebra elements diff --git a/src/sage/algebras/free_algebra_quotient.py b/src/sage/algebras/free_algebra_quotient.py index e54d92ae482..21284681549 100644 --- a/src/sage/algebras/free_algebra_quotient.py +++ b/src/sage/algebras/free_algebra_quotient.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Finite dimensional free algebra quotients diff --git a/src/sage/algebras/free_algebra_quotient_element.py b/src/sage/algebras/free_algebra_quotient_element.py index 738e5b723a3..559d4246ac0 100644 --- a/src/sage/algebras/free_algebra_quotient_element.py +++ b/src/sage/algebras/free_algebra_quotient_element.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Free algebra quotient elements diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index f7e2f97e50c..3f4a41ea751 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Free Zinbiel Algebras diff --git a/src/sage/algebras/hall_algebra.py b/src/sage/algebras/hall_algebra.py index 1da3c8f397e..83442eabc94 100644 --- a/src/sage/algebras/hall_algebra.py +++ b/src/sage/algebras/hall_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Hall Algebras diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py index 15a0566747c..df2818d5dd5 100644 --- a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py +++ b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Ariki-Koike Algebras diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index a1c175e9151..df4b748dca4 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.groups sage.modules +# sage.doctest: needs sage.combinat sage.groups sage.modules r""" Cubic Hecke Algebras 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 159ab06db3a..99e359b518f 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.libs.pari (for factorization) +# sage.doctest: needs sage.libs.pari (for factorization) r""" Cubic Hecke Base Rings 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 ceda4ec816b..49ea61b5f3a 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Cubic Hecke matrix representations diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index abd613791d3..d0141592724 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Iwahori-Hecke Algebras diff --git a/src/sage/algebras/jordan_algebra.py b/src/sage/algebras/jordan_algebra.py index 0e3a05b4026..f783dc890c8 100644 --- a/src/sage/algebras/jordan_algebra.py +++ b/src/sage/algebras/jordan_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Jordan Algebras diff --git a/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py index d1efd6e21f2..80df46c57d3 100644 --- a/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Abelian Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py index 5b7aea16317..f5d39cacbf2 100644 --- a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Affine Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py index 7367bab5c4d..0b0b61b4e25 100644 --- a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Bosonic Ghosts Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py index 4a21da4370b..098644908e6 100644 --- a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Fermionic Ghosts Super Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py b/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py index 4aaf9da36eb..8aefdd9d3a6 100644 --- a/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +++ b/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Finitely and Freely Generated Lie Conformal Algebras. diff --git a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py index 9008a9770ad..0787226252d 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Free Bosons Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py index 83f7bdc0698..1e7525ae1d3 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Free Fermions Super Lie Conformal Algebra. 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 21fc30d393b..b26d0bb4ca0 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 @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Freely Generated Lie Conformal Algebras diff --git a/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py index a2f1eb8fdf1..c335daf98f7 100644 --- a/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Graded Lie Conformal Algebras diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py index 16758675fdd..5ca0c8f6d07 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Lie Conformal Algebra 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 ccf3ce24111..09fb63a0a4c 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 @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Lie Conformal Algebra Element diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py index 3b3e3674897..4fef0fcf2e6 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Lie Conformal Algebras With Basis diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py index 89f7ecc0483..3c4252ce905 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Lie Conformal Algebras With Structure Coefficients diff --git a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py index 3d02419cc18..baf7a896144 100644 --- a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules sage.rings.number_field +# sage.doctest: needs sage.combinat sage.modules sage.rings.number_field r""" N=2 Super Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py index 45e28ab3a3c..5542b9fc097 100644 --- a/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Neveu-Schwarz Super Lie Conformal Algebra 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 6c16820f412..0db2d545290 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 @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Virasoro Lie Conformal Algebra diff --git a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py index 07c6007e0a4..3c319db7ca3 100644 --- a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Weyl Lie Conformal Algebra diff --git a/src/sage/algebras/nil_coxeter_algebra.py b/src/sage/algebras/nil_coxeter_algebra.py index 32d9de8638e..b5dbd2d62c8 100644 --- a/src/sage/algebras/nil_coxeter_algebra.py +++ b/src/sage/algebras/nil_coxeter_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Nil-Coxeter Algebra """ diff --git a/src/sage/algebras/orlik_terao.py b/src/sage/algebras/orlik_terao.py index db493ac6b1b..81158f3e9b7 100644 --- a/src/sage/algebras/orlik_terao.py +++ b/src/sage/algebras/orlik_terao.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Orlik-Terao Algebras """ diff --git a/src/sage/algebras/q_commuting_polynomials.py b/src/sage/algebras/q_commuting_polynomials.py index 670e890ecd8..0b23a756fd5 100644 --- a/src/sage/algebras/q_commuting_polynomials.py +++ b/src/sage/algebras/q_commuting_polynomials.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" `q`-Commuting Polynomials diff --git a/src/sage/algebras/q_system.py b/src/sage/algebras/q_system.py index c39a97db88c..74bf87c2787 100644 --- a/src/sage/algebras/q_system.py +++ b/src/sage/algebras/q_system.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Q-Systems diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index 3a414418c52..dc61084f2f8 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules r""" Quantum Clifford Algebras diff --git a/src/sage/algebras/quantum_groups/ace_quantum_onsager.py b/src/sage/algebras/quantum_groups/ace_quantum_onsager.py index 4d2a8386980..9d983529c73 100644 --- a/src/sage/algebras/quantum_groups/ace_quantum_onsager.py +++ b/src/sage/algebras/quantum_groups/ace_quantum_onsager.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Alternating Central Extension Quantum Onsager Algebra diff --git a/src/sage/algebras/quantum_groups/fock_space.py b/src/sage/algebras/quantum_groups/fock_space.py index 965247f858f..22665746325 100644 --- a/src/sage/algebras/quantum_groups/fock_space.py +++ b/src/sage/algebras/quantum_groups/fock_space.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Fock Space diff --git a/src/sage/algebras/quantum_groups/representations.py b/src/sage/algebras/quantum_groups/representations.py index 19a35b0aa53..cb026008d6d 100644 --- a/src/sage/algebras/quantum_groups/representations.py +++ b/src/sage/algebras/quantum_groups/representations.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Quantum Group Representations diff --git a/src/sage/algebras/quantum_matrix_coordinate_algebra.py b/src/sage/algebras/quantum_matrix_coordinate_algebra.py index 64b29c82a45..c9f7e312788 100644 --- a/src/sage/algebras/quantum_matrix_coordinate_algebra.py +++ b/src/sage/algebras/quantum_matrix_coordinate_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Quantum Matrix Coordinate Algebras diff --git a/src/sage/algebras/quaternion_algebra.py b/src/sage/algebras/quaternion_algebra.py index bb617738cdc..4e92b73de69 100644 --- a/src/sage/algebras/quaternion_algebra.py +++ b/src/sage/algebras/quaternion_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules ############################################################ # Backwards compatible unpickling diff --git a/src/sage/algebras/quaternion_algebra_element.py b/src/sage/algebras/quaternion_algebra_element.py index aa4f349f1da..dbd70e25856 100644 --- a/src/sage/algebras/quaternion_algebra_element.py +++ b/src/sage/algebras/quaternion_algebra_element.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules ####################################################################### # Backward compatible unpickle functions diff --git a/src/sage/algebras/rational_cherednik_algebra.py b/src/sage/algebras/rational_cherednik_algebra.py index d17c415f027..58b3ce5441d 100644 --- a/src/sage/algebras/rational_cherednik_algebra.py +++ b/src/sage/algebras/rational_cherednik_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules """ Rational Cherednik Algebras """ diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 9356d18cd4b..0df04485a2a 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Schur algebras for `GL_n` diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index d137e2bc9d6..2db55513d66 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Shuffle algebras diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index 8e6d35e7c1b..8913932ffac 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.libs.pari sage.modules +# sage.doctest: needs sage.libs.pari sage.modules r""" Splitting Algebras diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index ba94cf6311b..ce764f0a258 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" The Steenrod algebra diff --git a/src/sage/algebras/steenrod/steenrod_algebra_mult.py b/src/sage/algebras/steenrod/steenrod_algebra_mult.py index 35c06d9f711..e2d48f616b7 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_mult.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_mult.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.finite_rings +# sage.doctest: needs sage.rings.finite_rings r""" Multiplication for elements of the Steenrod algebra diff --git a/src/sage/algebras/tensor_algebra.py b/src/sage/algebras/tensor_algebra.py index 6054ef8f6c5..a14ab916336 100644 --- a/src/sage/algebras/tensor_algebra.py +++ b/src/sage/algebras/tensor_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Tensor Algebras diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 142136d2232..14ae670b00e 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Weyl Algebras diff --git a/src/sage/algebras/yangian.py b/src/sage/algebras/yangian.py index 2b9702fa247..8e19b92ba07 100644 --- a/src/sage/algebras/yangian.py +++ b/src/sage/algebras/yangian.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.modules r""" Yangians diff --git a/src/sage/algebras/yokonuma_hecke_algebra.py b/src/sage/algebras/yokonuma_hecke_algebra.py index 8651e5d32bd..779beb95ffe 100644 --- a/src/sage/algebras/yokonuma_hecke_algebra.py +++ b/src/sage/algebras/yokonuma_hecke_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.modules +# sage.doctest: needs sage.modules """ Yokonuma-Hecke Algebras From 63aba2094249585afb47b197d3b6b43de4ff57ff Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 7 Aug 2023 22:43:56 -0700 Subject: [PATCH 132/538] src/sage/algebras: sage -fixdoctests --only-tags --- src/sage/algebras/clifford_algebra.py | 9 +- src/sage/algebras/cluster_algebra.py | 17 +- src/sage/algebras/commutative_dga.py | 102 +++++----- .../finite_dimensional_algebra_morphism.py | 20 +- src/sage/algebras/free_algebra.py | 181 ++++++++++-------- src/sage/algebras/free_algebra_quotient.py | 2 +- src/sage/algebras/free_zinbiel_algebra.py | 26 +-- .../hecke_algebras/cubic_hecke_algebra.py | 71 +++---- .../hecke_algebras/cubic_hecke_base_ring.py | 13 +- src/sage/algebras/iwahori_hecke_algebra.py | 67 ++++--- src/sage/algebras/lie_algebras/morphism.py | 18 +- src/sage/algebras/lie_algebras/quotient.py | 9 +- .../lie_algebras/structure_coefficients.py | 4 +- src/sage/algebras/lie_algebras/subalgebra.py | 26 +-- src/sage/algebras/orlik_solomon.py | 29 +-- .../algebras/quatalg/quaternion_algebra.py | 27 +-- .../quatalg/quaternion_algebra_element.pyx | 89 +++++---- .../algebras/quaternion_algebra_element.py | 9 +- .../steenrod/steenrod_algebra_bases.py | 33 ++-- src/sage/algebras/weyl_algebra.py | 17 +- 20 files changed, 406 insertions(+), 363 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index ed24df4abfc..ad8bd314c25 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -1771,11 +1771,12 @@ def interior_product_on_basis(self, a, b): Check :trac:`34694`:: - sage: E = ExteriorAlgebra(SR,'e',3) # optional - sage.symbolic - sage: E.inject_variables() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: E = ExteriorAlgebra(SR,'e',3) + sage: E.inject_variables() Defining e0, e1, e2 - sage: a = (e0*e1).interior_product(e0) # optional - sage.symbolic - sage: a * e0 # optional - sage.symbolic + sage: a = (e0*e1).interior_product(e0) + sage: a * e0 -e0*e1 """ sgn = True diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index bdd8164955c..fa29367d014 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -298,15 +298,16 @@ which might not be a good idea in algebras that are too big. One workaround is to first disable F-polynomials and then recompute only the desired mutations:: - sage: A.reset_exploring_iterator(mutating_F=False) # long time - sage: v = (-1, 1, -2, 2, -1, 1, -1, 1, 1) # long time - sage: seq = A.find_g_vector(v); seq # long time random + sage: # long time + sage: A.reset_exploring_iterator(mutating_F=False) + sage: v = (-1, 1, -2, 2, -1, 1, -1, 1, 1) + sage: seq = A.find_g_vector(v); seq [1, 0, 2, 6, 5, 4, 3, 8, 1] - sage: S = A.initial_seed().mutate(seq, inplace=False) # long time - sage: v in S.g_vectors() # long time + sage: S = A.initial_seed().mutate(seq, inplace=False) + sage: v in S.g_vectors() True - sage: A.current_seed().mutate(seq) # long time - sage: A.F_polynomial((-1, 1, -2, 2, -1, 1, -1, 1, 1)) # long time + sage: A.current_seed().mutate(seq) + sage: A.F_polynomial((-1, 1, -2, 2, -1, 1, -1, 1, 1)) u0*u1^2*u2^2*u3*u4*u5*u6*u8 + ... 2*u2 + u4 + u6 + 1 @@ -2373,7 +2374,7 @@ def cluster_fan(self, depth=infinity): EXAMPLES:: sage: A = ClusterAlgebra(['A', 2]) - sage: A.cluster_fan() # optional - sage.geometry.polyhedron + sage: A.cluster_fan() # needs sage.geometry.polyhedron Rational polyhedral fan in 2-d lattice N """ seeds = self.seeds(depth=depth, mutating_F=False) diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index f3ef35660cc..d1ea9b782e4 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -949,9 +949,9 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None, category= TESTS:: - sage: A1 = GradedCommutativeAlgebra(GF(2), 'x,y', (3, 6)) # optional - sage.rings.finite_rings - sage: A2 = GradedCommutativeAlgebra(GF(2), ['x', 'y'], [3, 6]) # optional - sage.rings.finite_rings - sage: A1 is A2 + sage: A1 = GradedCommutativeAlgebra(GF(2), 'x,y', (3, 6)) # needs sage.rings.finite_rings + sage: A2 = GradedCommutativeAlgebra(GF(2), ['x', 'y'], [3, 6]) # needs sage.rings.finite_rings + sage: A1 is A2 # needs sage.rings.finite_rings True Testing the single generator case (:trac:`25276`):: @@ -962,8 +962,8 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None, category= sage: A4. = GradedCommutativeAlgebra(QQ, degrees=[4]) sage: z**2 == 0 False - sage: A5. = GradedCommutativeAlgebra(GF(2)) # optional - sage.rings.finite_rings - sage: z**2 == 0 # optional - sage.rings.finite_rings + sage: A5. = GradedCommutativeAlgebra(GF(2)) # needs sage.rings.finite_rings + sage: z**2 == 0 # needs sage.rings.finite_rings False """ if names is None: @@ -1207,19 +1207,20 @@ def quotient(self, I, check=True): EXAMPLES:: - sage: A. = GradedCommutativeAlgebra(GF(5), degrees=(2, 2, 3, 4)) # optional - sage.rings.finite_rings - sage: I = A.ideal([x*t+z^2, x*y - t]) # optional - sage.rings.finite_rings - sage: B = A.quotient(I); B # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: A. = GradedCommutativeAlgebra(GF(5), degrees=(2, 2, 3, 4)) + sage: I = A.ideal([x*t+z^2, x*y - t]) + sage: B = A.quotient(I); B Graded Commutative Algebra with generators ('x', 'y', 'z', 't') in degrees (2, 2, 3, 4) with relations [x*t, x*y - t] over Finite Field of size 5 - sage: B(x*t) # optional - sage.rings.finite_rings + sage: B(x*t) 0 - sage: B(x*y) # optional - sage.rings.finite_rings + sage: B(x*y) t - sage: A.basis(7) # optional - sage.rings.finite_rings + sage: A.basis(7) [x^2*z, x*y*z, y^2*z, z*t] - sage: B.basis(7) # optional - sage.rings.finite_rings + sage: B.basis(7) [x^2*z, y^2*z, z*t] """ if check and any(not i.is_homogeneous() for i in I.gens()): @@ -1909,19 +1910,20 @@ def degree(self, total=False): EXAMPLES:: - sage: A. = GradedCommutativeAlgebra(GF(2), # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: A. = GradedCommutativeAlgebra(GF(2), ....: degrees=((1,0), (0,1), (1,1))) - sage: (a**2*b).degree() # optional - sage.rings.finite_rings + sage: (a**2*b).degree() (2, 1) - sage: (a**2*b).degree(total=True) # optional - sage.rings.finite_rings + sage: (a**2*b).degree(total=True) 3 - sage: (a**2*b + c).degree() # optional - sage.rings.finite_rings + sage: (a**2*b + c).degree() Traceback (most recent call last): ... ValueError: this element is not homogeneous - sage: (a**2*b + c).degree(total=True) # optional - sage.rings.finite_rings + sage: (a**2*b + c).degree(total=True) 3 - sage: A(0).degree() # optional - sage.rings.finite_rings + sage: A(0).degree() Traceback (most recent call last): ... ValueError: the zero element does not have a well-defined degree @@ -2388,23 +2390,23 @@ def cohomology_generators(self, max_degree): In contrast, the corresponding algebra in characteristic `p` has finitely generated cohomology:: - sage: A3. = GradedCommutativeAlgebra(GF(3), degrees=(1,2,2)) # optional - sage.rings.finite_rings - sage: B3 = A3.cdg_algebra(differential={y: a*x}) # optional - sage.rings.finite_rings - sage: B3.cohomology_generators(16) # optional - sage.rings.finite_rings + sage: A3. = GradedCommutativeAlgebra(GF(3), degrees=(1,2,2)) # needs sage.rings.finite_rings + sage: B3 = A3.cdg_algebra(differential={y: a*x}) # needs sage.rings.finite_rings + sage: B3.cohomology_generators(16) # needs sage.rings.finite_rings {1: [a], 2: [x], 3: [a*y], 5: [a*y^2], 6: [y^3]} This method works with both singly graded and multi-graded algebras:: - sage: Cs. = GradedCommutativeAlgebra(GF(2), degrees=(1,2,2,3)) # optional - sage.rings.finite_rings - sage: Ds = Cs.cdg_algebra({a:c, b:d}) # optional - sage.rings.finite_rings - sage: Ds.cohomology_generators(10) # optional - sage.rings.finite_rings + sage: Cs. = GradedCommutativeAlgebra(GF(2), degrees=(1,2,2,3)) # needs sage.rings.finite_rings + sage: Ds = Cs.cdg_algebra({a:c, b:d}) # needs sage.rings.finite_rings + sage: Ds.cohomology_generators(10) # needs sage.rings.finite_rings {2: [a^2], 4: [b^2]} - sage: Cm. = GradedCommutativeAlgebra(GF(2), # optional - sage.rings.finite_rings + sage: Cm. = GradedCommutativeAlgebra(GF(2), # needs sage.rings.finite_rings ....: degrees=((1,0), (1,1), ....: (0,2), (0,3))) - sage: Dm = Cm.cdg_algebra({a:c, b:d}) # optional - sage.rings.finite_rings - sage: Dm.cohomology_generators(10) # optional - sage.rings.finite_rings + sage: Dm = Cm.cdg_algebra({a:c, b:d}) # needs sage.rings.finite_rings + sage: Dm.cohomology_generators(10) # needs sage.rings.finite_rings {2: [a^2], 4: [b^2]} TESTS: @@ -3507,9 +3509,9 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, We can construct multi-graded rings as well. We work in characteristic 2 for a change, so the algebras here are honestly commutative:: - sage: C. = GradedCommutativeAlgebra(GF(2), # optional - sage.rings.finite_rings + sage: C. = GradedCommutativeAlgebra(GF(2), # needs sage.rings.finite_rings ....: degrees=((1,0), (1,1), (0,2), (0,3))) - sage: D = C.cdg_algebra(differential={a: c, b: d}); D # optional - sage.rings.finite_rings + sage: D = C.cdg_algebra(differential={a: c, b: d}); D # needs sage.rings.finite_rings Commutative Differential Graded Algebra with generators ('a', 'b', 'c', 'd') in degrees ((1, 0), (1, 1), (0, 2), (0, 3)) over Finite Field of size 2 with differential: @@ -3522,46 +3524,46 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, Use tuples, lists, vectors, or elements of additive abelian groups to specify degrees:: - sage: D.basis(3) # basis in total degree 3 # optional - sage.rings.finite_rings + sage: D.basis(3) # basis in total degree 3 # needs sage.rings.finite_rings [a^3, a*b, a*c, d] - sage: D.basis((1,2)) # basis in degree (1,2) # optional - sage.rings.finite_rings + sage: D.basis((1,2)) # basis in degree (1,2) # needs sage.rings.finite_rings [a*c] - sage: D.basis([1,2]) # optional - sage.rings.finite_rings + sage: D.basis([1,2]) # needs sage.rings.finite_rings [a*c] - sage: D.basis(vector([1,2])) # optional - sage.rings.finite_rings + sage: D.basis(vector([1,2])) # needs sage.rings.finite_rings [a*c] sage: G = AdditiveAbelianGroup([0,0]); G Additive abelian group isomorphic to Z + Z - sage: D.basis(G(vector([1,2]))) # optional - sage.rings.finite_rings + sage: D.basis(G(vector([1,2]))) # needs sage.rings.finite_rings [a*c] At this point, ``a``, for example, is an element of ``C``. We can redefine it so that it is instead an element of ``D`` in several ways, for instance using :meth:`gens` method:: - sage: a, b, c, d = D.gens() # optional - sage.rings.finite_rings - sage: a.differential() # optional - sage.rings.finite_rings + sage: a, b, c, d = D.gens() # needs sage.rings.finite_rings + sage: a.differential() # needs sage.rings.finite_rings c Or the :meth:`inject_variables` method:: - sage: D.inject_variables() # optional - sage.rings.finite_rings + sage: D.inject_variables() # needs sage.rings.finite_rings Defining a, b, c, d - sage: (a*b).differential() # optional - sage.rings.finite_rings + sage: (a*b).differential() # needs sage.rings.finite_rings b*c + a*d - sage: (a*b*c**2).degree() # optional - sage.rings.finite_rings + sage: (a*b*c**2).degree() # needs sage.rings.finite_rings (2, 5) Degrees are returned as elements of additive abelian groups:: - sage: (a*b*c**2).degree() in G # optional - sage.rings.finite_rings + sage: (a*b*c**2).degree() in G # needs sage.rings.finite_rings True - sage: (a*b*c**2).degree(total=True) # total degree # optional - sage.rings.finite_rings + sage: (a*b*c**2).degree(total=True) # total degree # needs sage.rings.finite_rings 7 - sage: D.cohomology(4) # optional - sage.rings.finite_rings + sage: D.cohomology(4) # needs sage.rings.finite_rings Free module generated by {[a^4], [b^2]} over Finite Field of size 2 - sage: D.cohomology((2,2)) # optional - sage.rings.finite_rings + sage: D.cohomology((2,2)) # needs sage.rings.finite_rings Free module generated by {[b^2]} over Finite Field of size 2 Graded algebra with maximal degree:: @@ -4047,7 +4049,7 @@ def __init__(self, x, cdga=None): EXAMPLES:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: CohomologyClass(x - 2) # optional - sage.symbolic + sage: CohomologyClass(x - 2) # needs sage.symbolic [x - 2] """ self._x = x @@ -4058,7 +4060,7 @@ def __hash__(self): TESTS:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: hash(CohomologyClass(sin)) == hash(sin) # optional - sage.symbolic + sage: hash(CohomologyClass(sin)) == hash(sin) # needs sage.symbolic True """ return hash(self._x) @@ -4068,7 +4070,7 @@ def _repr_(self): EXAMPLES:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: CohomologyClass(sin) # optional - sage.symbolic + sage: CohomologyClass(sin) # needs sage.symbolic [sin] """ return '[{}]'.format(self._x) @@ -4078,9 +4080,9 @@ def _latex_(self): EXAMPLES:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: latex(CohomologyClass(sin)) # optional - sage.symbolic + sage: latex(CohomologyClass(sin)) # needs sage.symbolic \left[ \sin \right] - sage: latex(CohomologyClass(x^2)) # optional - sage.symbolic + sage: latex(CohomologyClass(x^2)) # needs sage.symbolic \left[ x^{2} \right] """ from sage.misc.latex import latex @@ -4093,8 +4095,8 @@ def representative(self): EXAMPLES:: sage: from sage.algebras.commutative_dga import CohomologyClass - sage: x = CohomologyClass(sin) # optional - sage.symbolic - sage: x.representative() == sin # optional - sage.symbolic + sage: x = CohomologyClass(sin) # needs sage.symbolic + sage: x.representative() == sin # needs sage.symbolic True """ return self._x diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py index 5f6512baccf..d2114511ae6 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py @@ -86,9 +86,9 @@ def _repr_(self): sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: I = A.maximal_ideal() # optional - sage.libs.pari - sage: q = A.quotient_map(I) # optional - sage.libs.pari - sage: q._repr_() # optional - sage.libs.pari + sage: I = A.maximal_ideal() # needs sage.libs.pari + sage: q = A.quotient_map(I) # needs sage.libs.pari + sage: q._repr_() # needs sage.libs.pari 'Morphism from Finite-dimensional algebra of degree 2 over Rational Field to Finite-dimensional algebra of degree 1 over Rational Field given by matrix\n[1]\n[0]' """ return "Morphism from {} to {} given by matrix\n{}".format( @@ -100,9 +100,9 @@ def __call__(self, x): sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: I = A.maximal_ideal() # optional - sage.libs.pari - sage: q = A.quotient_map(I) # optional - sage.libs.pari - sage: q(0) == 0 and q(1) == 1 # optional - sage.libs.pari + sage: I = A.maximal_ideal() # needs sage.libs.pari + sage: q = A.quotient_map(I) # needs sage.libs.pari + sage: q(0) == 0 and q(1) == 1 # needs sage.libs.pari True """ x = self.domain()(x) @@ -182,10 +182,10 @@ def inverse_image(self, I): sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) - sage: I = A.maximal_ideal() # optional - sage.libs.pari - sage: q = A.quotient_map(I) # optional - sage.libs.pari - sage: B = q.codomain() # optional - sage.libs.pari - sage: q.inverse_image(B.zero_ideal()) == I # optional - sage.libs.pari + sage: I = A.maximal_ideal() # needs sage.libs.pari + sage: q = A.quotient_map(I) # needs sage.libs.pari + sage: B = q.codomain() # needs sage.libs.pari + sage: q.inverse_image(B.zero_ideal()) == I # needs sage.libs.pari True """ coker_I = I.basis_matrix().transpose().kernel().basis_matrix().transpose() diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index 70ccb24c63f..d1a536a7043 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -35,10 +35,11 @@ Moreover, we can compute Groebner bases with degree bound for its two-sided ideals, and thus provide ideal containment tests:: - sage: F. = FreeAlgebra(QQ, implementation='letterplace'); F # optional - sage.libs.singular + sage: # needs sage.libs.singular + sage: F. = FreeAlgebra(QQ, implementation='letterplace'); F Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field - sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F # optional - sage.libs.singular - sage: I.groebner_basis(degbound=4) # optional - sage.libs.singular + sage: I = F*[x*y+y*z,x^2+x*y-y*x-y^2]*F + sage: I.groebner_basis(degbound=4) Twosided Ideal (x*y + y*z, x*x - y*x - y*y - y*z, y*y*y - y*y*z + y*z*y - y*z*z, @@ -48,67 +49,72 @@ y*y*z*x + y*y*z*z + y*z*z*x + y*z*z*z, y*z*y*x + y*z*y*z + y*z*z*x + y*z*z*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field - sage: y*z*y*y*z*z + 2*y*z*y*z*z*x + y*z*y*z*z*z - y*z*z*y*z*x + y*z*z*z*z*x in I # optional - sage.libs.singular + sage: y*z*y*y*z*z + 2*y*z*y*z*z*x + y*z*y*z*z*z - y*z*z*y*z*x + y*z*z*z*z*x in I True Positive integral degree weights for the letterplace implementation was introduced in :trac:`7797`:: - sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) # optional - sage.libs.singular - sage: x.degree() # optional - sage.libs.singular + sage: # needs sage.libs.singular + sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) + sage: x.degree() 2 - sage: y.degree() # optional - sage.libs.singular + sage: y.degree() 1 - sage: z.degree() # optional - sage.libs.singular + sage: z.degree() 3 - sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F # optional - sage.libs.singular - sage: Q. = F.quo(I) # optional - sage.libs.singular - sage: TestSuite(Q).run() # optional - sage.libs.singular - sage: a^2*b^2 # optional - sage.libs.singular + sage: I = F*[x*y-y*x, x^2+2*y*z, (x*y)^2-z^2]*F + sage: Q. = F.quo(I) + sage: TestSuite(Q).run() + sage: a^2*b^2 c*c TESTS:: - sage: F = FreeAlgebra(GF(5),3,'x') # optional - sage.rings.finite_rings - sage: TestSuite(F).run() # optional - sage.rings.finite_rings - sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F = FreeAlgebra(GF(5),3,'x') + sage: TestSuite(F).run() + sage: F is loads(dumps(F)) True - sage: F = FreeAlgebra(GF(5),3,'x', implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings - sage: TestSuite(F).run() # optional - sage.libs.singular sage.rings.finite_rings - sage: F is loads(dumps(F)) # optional - sage.libs.singular sage.rings.finite_rings + sage: F = FreeAlgebra(GF(5),3,'x', implementation='letterplace') # needs sage.libs.singular + sage: TestSuite(F).run() # needs sage.libs.singular + sage: F is loads(dumps(F)) # needs sage.libs.singular True :: - sage: F. = FreeAlgebra(GF(5),3) # optional - sage.rings.finite_rings - sage: TestSuite(F).run() # optional - sage.rings.finite_rings - sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F. = FreeAlgebra(GF(5),3) + sage: TestSuite(F).run() + sage: F is loads(dumps(F)) True - sage: F. = FreeAlgebra(GF(5),3, implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings - sage: TestSuite(F).run() # optional - sage.libs.singular sage.rings.finite_rings - sage: F is loads(dumps(F)) # optional - sage.libs.singular sage.rings.finite_rings + sage: F. = FreeAlgebra(GF(5),3, implementation='letterplace') # needs sage.libs.singular + sage: TestSuite(F).run() # needs sage.libs.singular + sage: F is loads(dumps(F)) # needs sage.libs.singular True :: - sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y']) # optional - sage.rings.finite_rings - sage: TestSuite(F).run() # optional - sage.rings.finite_rings - sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y']) + sage: TestSuite(F).run() + sage: F is loads(dumps(F)) True - sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'], implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings - sage: TestSuite(F).run() # optional - sage.libs.singular sage.rings.finite_rings - sage: F is loads(dumps(F)) # optional - sage.libs.singular sage.rings.finite_rings + sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'], implementation='letterplace') # needs sage.libs.singular + sage: TestSuite(F).run() # needs sage.libs.singular + sage: F is loads(dumps(F)) # needs sage.libs.singular True :: - sage: F = FreeAlgebra(GF(5),3, 'abc') # optional - sage.rings.finite_rings - sage: TestSuite(F).run() # optional - sage.rings.finite_rings - sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F = FreeAlgebra(GF(5),3, 'abc') + sage: TestSuite(F).run() + sage: F is loads(dumps(F)) True - sage: F = FreeAlgebra(GF(5),3, 'abc', implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings - sage: TestSuite(F).run() # optional - sage.libs.singular sage.rings.finite_rings - sage: F is loads(dumps(F)) # optional - sage.libs.singular sage.rings.finite_rings + sage: F = FreeAlgebra(GF(5),3, 'abc', implementation='letterplace') # needs sage.libs.singular + sage: TestSuite(F).run() # needs sage.libs.singular + sage: F is loads(dumps(F)) # needs sage.libs.singular True :: @@ -121,7 +127,7 @@ Note that the letterplace implementation can only be used if the corresponding (multivariate) polynomial ring has an implementation in Singular:: - sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace') # needs sage.libs.singular sage.rings.finite_rings Traceback (most recent call last): ... NotImplementedError: polynomials over Free Algebra on 2 generators (a, b) over Integer Ring are not supported in Singular @@ -168,18 +174,18 @@ class FreeAlgebraFactory(UniqueFactory): EXAMPLES:: - sage: FreeAlgebra(GF(5),3,'x') # optional - sage.rings.finite_rings + sage: FreeAlgebra(GF(5),3,'x') # needs sage.rings.finite_rings Free Algebra on 3 generators (x0, x1, x2) over Finite Field of size 5 - sage: F. = FreeAlgebra(GF(5),3) # optional - sage.rings.finite_rings - sage: (x+y+z)^2 # optional - sage.rings.finite_rings + sage: F. = FreeAlgebra(GF(5),3) # needs sage.rings.finite_rings + sage: (x+y+z)^2 # needs sage.rings.finite_rings x^2 + x*y + x*z + y*x + y^2 + y*z + z*x + z*y + z^2 - sage: FreeAlgebra(GF(5),3, 'xx, zba, Y') # optional - sage.rings.finite_rings + sage: FreeAlgebra(GF(5),3, 'xx, zba, Y') # needs sage.rings.finite_rings Free Algebra on 3 generators (xx, zba, Y) over Finite Field of size 5 - sage: FreeAlgebra(GF(5),3, 'abc') # optional - sage.rings.finite_rings + sage: FreeAlgebra(GF(5),3, 'abc') # needs sage.rings.finite_rings Free Algebra on 3 generators (a, b, c) over Finite Field of size 5 - sage: FreeAlgebra(GF(5),1, 'z') # optional - sage.rings.finite_rings + sage: FreeAlgebra(GF(5),1, 'z') # needs sage.rings.finite_rings Free Algebra on 1 generators (z,) over Finite Field of size 5 - sage: FreeAlgebra(GF(5),1, ['alpha']) # optional - sage.rings.finite_rings + sage: FreeAlgebra(GF(5),1, ['alpha']) # needs sage.rings.finite_rings Free Algebra on 1 generators (alpha,) over Finite Field of size 5 sage: FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x') Free Algebra on 2 generators (x0, x1) over @@ -191,14 +197,14 @@ class FreeAlgebraFactory(UniqueFactory): sage: G = FreeAlgebra(ZZ,3,'x,y,z') sage: F is G True - sage: F. = FreeAlgebra(GF(5),3) # indirect doctest # optional - sage.rings.finite_rings - sage: F is loads(dumps(F)) # optional - sage.rings.finite_rings + sage: F. = FreeAlgebra(GF(5),3) # indirect doctest # needs sage.rings.finite_rings + sage: F is loads(dumps(F)) # needs sage.rings.finite_rings True - sage: F is FreeAlgebra(GF(5),['x','y','z']) # optional - sage.rings.finite_rings + sage: F is FreeAlgebra(GF(5),['x','y','z']) # needs sage.rings.finite_rings True - sage: copy(F) is F is loads(dumps(F)) # optional - sage.rings.finite_rings + sage: copy(F) is F is loads(dumps(F)) # needs sage.rings.finite_rings True - sage: TestSuite(F).run() # optional - sage.rings.finite_rings + sage: TestSuite(F).run() # needs sage.rings.finite_rings By :trac:`7797`, we provide a different implementation of free algebras, based on Singular's "letterplace rings". Our letterplace @@ -207,27 +213,29 @@ class FreeAlgebraFactory(UniqueFactory): elements are supported. Of course, isomorphic algebras in different implementations are not identical:: - sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings - sage: F == G # optional - sage.libs.singular sage.rings.finite_rings + sage: # needs sage.libs.singular sage.rings.finite_rings + sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') + sage: F == G False - sage: G is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings + sage: G is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') True - sage: copy(G) is G is loads(dumps(G)) # optional - sage.libs.singular sage.rings.finite_rings + sage: copy(G) is G is loads(dumps(G)) True - sage: TestSuite(G).run() # optional - sage.libs.singular sage.rings.finite_rings + sage: TestSuite(G).run() :: - sage: H = FreeAlgebra(GF(5), ['x','y','z'], implementation='letterplace', # optional - sage.libs.singular sage.rings.finite_rings + sage: # needs sage.libs.singular sage.rings.finite_rings + sage: H = FreeAlgebra(GF(5), ['x','y','z'], implementation='letterplace', ....: degrees=[1,2,3]) - sage: F != H != G # optional - sage.libs.singular sage.rings.finite_rings + sage: F != H != G True - sage: H is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', # optional - sage.libs.singular sage.rings.finite_rings + sage: H is FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace', ....: degrees=[1,2,3]) True - sage: copy(H) is H is loads(dumps(H)) # optional - sage.libs.singular sage.rings.finite_rings + sage: copy(H) is H is loads(dumps(H)) True - sage: TestSuite(H).run() # optional - sage.libs.singular sage.rings.finite_rings + sage: TestSuite(H).run() Free algebras commute with their base ring. :: @@ -255,22 +263,23 @@ def create_key(self, base_ring, arg1=None, arg2=None, TESTS:: - sage: FreeAlgebra.create_key(GF(5),['x','y','z']) # optional - sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: FreeAlgebra.create_key(GF(5),['x','y','z']) (Finite Field of size 5, ('x', 'y', 'z')) - sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3) # optional - sage.rings.finite_rings + sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3) (Finite Field of size 5, ('x', 'y', 'z')) - sage: FreeAlgebra.create_key(GF(5),3,'xyz') # optional - sage.rings.finite_rings + sage: FreeAlgebra.create_key(GF(5),3,'xyz') (Finite Field of size 5, ('x', 'y', 'z')) - sage: FreeAlgebra.create_key(GF(5),['x','y','z'], # optional - sage.libs.singular sage.rings.finite_rings + sage: FreeAlgebra.create_key(GF(5),['x','y','z'], # needs sage.libs.singular ....: implementation='letterplace') (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) - sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, # optional - sage.libs.singular sage.rings.finite_rings + sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, # needs sage.libs.singular ....: implementation='letterplace') (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) - sage: FreeAlgebra.create_key(GF(5),3,'xyz', # optional - sage.libs.singular sage.rings.finite_rings + sage: FreeAlgebra.create_key(GF(5),3,'xyz', # needs sage.libs.singular ....: implementation='letterplace') (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) - sage: FreeAlgebra.create_key(GF(5),3,'xyz', # optional - sage.libs.singular sage.rings.finite_rings + sage: FreeAlgebra.create_key(GF(5),3,'xyz', # needs sage.libs.singular ....: implementation='letterplace', degrees=[1,2,3]) ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5) @@ -553,21 +562,23 @@ def _element_constructor_(self, x): TESTS:: - sage: F. = FreeAlgebra(GF(5),3) # optional - sage.rings.finite_rings - sage: L. = FreeAlgebra(ZZ,3,implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings - sage: F(x) # indirect doctest # optional - sage.libs.singular sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: F. = FreeAlgebra(GF(5),3) + sage: L. = FreeAlgebra(ZZ,3,implementation='letterplace') # needs sage.libs.singular + sage: F(x) # indirect doctest # needs sage.libs.singular x - sage: F.1*L.2 # optional - sage.libs.singular sage.rings.finite_rings + sage: F.1*L.2 # needs sage.libs.singular y*z - sage: (F.1*L.2).parent() is F # optional - sage.libs.singular sage.rings.finite_rings + sage: (F.1*L.2).parent() is F # needs sage.libs.singular True :: - sage: K. = GF(25) # optional - sage.rings.finite_rings - sage: F. = FreeAlgebra(K,3) # optional - sage.rings.finite_rings - sage: L. = FreeAlgebra(K,3, implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings - sage: F.1+(z+1)*L.2 # optional - sage.libs.singular sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K. = GF(25) + sage: F. = FreeAlgebra(K,3) + sage: L. = FreeAlgebra(K,3, implementation='letterplace') # needs sage.libs.singular + sage: F.1+(z+1)*L.2 # needs sage.libs.singular b + (z+1)*c Check that :trac:`15169` is fixed:: @@ -677,23 +688,23 @@ def _coerce_map_from_(self, R): sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z')) False - sage: K. = GF(25) # optional - sage.rings.finite_rings - sage: F. = FreeAlgebra(K,3) # optional - sage.rings.finite_rings - sage: F._coerce_map_from_(ZZ) # optional - sage.rings.finite_rings + sage: K. = GF(25) # needs sage.rings.finite_rings + sage: F. = FreeAlgebra(K,3) # needs sage.rings.finite_rings + sage: F._coerce_map_from_(ZZ) # needs sage.rings.finite_rings True - sage: F._coerce_map_from_(QQ) # optional - sage.rings.finite_rings + sage: F._coerce_map_from_(QQ) # needs sage.rings.finite_rings False - sage: F._coerce_map_from_(F.monoid()) # optional - sage.rings.finite_rings + sage: F._coerce_map_from_(F.monoid()) # needs sage.rings.finite_rings True - sage: F._coerce_map_from_(F.pbw_basis()) # optional - sage.rings.finite_rings + sage: F._coerce_map_from_(F.pbw_basis()) # needs sage.rings.finite_rings True sage: G = FreeAlgebra(ZZ, 3, 'a,b,c') - sage: F._coerce_map_from_(G) # optional - sage.rings.finite_rings + sage: F._coerce_map_from_(G) # needs sage.rings.finite_rings True - sage: G._coerce_map_from_(F) # optional - sage.rings.finite_rings + sage: G._coerce_map_from_(F) # needs sage.rings.finite_rings False - sage: L. = FreeAlgebra(K,3, implementation='letterplace') # optional - sage.libs.singular sage.rings.finite_rings - sage: F.1 + (z+1) * L.2 # optional - sage.libs.singular sage.rings.finite_rings + sage: L. = FreeAlgebra(K,3, implementation='letterplace') # needs sage.libs.singular sage.rings.finite_rings + sage: F.1 + (z+1) * L.2 # needs sage.libs.singular sage.rings.finite_rings b + (z+1)*c """ if self._indices.has_coerce_map_from(R): diff --git a/src/sage/algebras/free_algebra_quotient.py b/src/sage/algebras/free_algebra_quotient.py index 21284681549..b0f0efed0cd 100644 --- a/src/sage/algebras/free_algebra_quotient.py +++ b/src/sage/algebras/free_algebra_quotient.py @@ -191,7 +191,7 @@ def _coerce_map_from_(self, S): True sage: H._coerce_map_from_(QQ) True - sage: H._coerce_map_from_(GF(7)) # optional - sage.rings.finite_rings + sage: H._coerce_map_from_(GF(7)) # needs sage.rings.finite_rings False """ return S == self or self.__free_algebra.has_coerce_map_from(S) diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index 3f4a41ea751..cee797e37c4 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -540,14 +540,14 @@ def _coerce_map_from_(self, R): EXAMPLES:: - sage: F = algebras.FreeZinbiel(GF(7), 'x,y,z'); F # optional - sage.rings.finite_rings + sage: F = algebras.FreeZinbiel(GF(7), 'x,y,z'); F # needs sage.rings.finite_rings Free Zinbiel algebra on generators (Z[x], Z[y], Z[z]) over Finite Field of size 7 Elements of the free Zinbiel algebra canonically coerce in:: - sage: x, y, z = F.gens() # optional - sage.rings.finite_rings - sage: F.coerce(x+y) == x+y # optional - sage.rings.finite_rings + sage: x, y, z = F.gens() # needs sage.rings.finite_rings + sage: F.coerce(x+y) == x+y # needs sage.rings.finite_rings True The free Zinbiel algebra over `\ZZ` on `x, y, z` coerces in, since @@ -555,15 +555,15 @@ def _coerce_map_from_(self, R): sage: G = algebras.FreeZinbiel(ZZ, 'x,y,z') sage: Gx,Gy,Gz = G.gens() - sage: z = F.coerce(Gx+Gy); z # optional - sage.rings.finite_rings + sage: z = F.coerce(Gx+Gy); z # needs sage.rings.finite_rings Z[x] + Z[y] - sage: z.parent() is F # optional - sage.rings.finite_rings + sage: z.parent() is F # needs sage.rings.finite_rings True However, `\GF{7}` does not coerce to `\ZZ`, so the free Zinbiel algebra over `\GF{7}` does not coerce to the one over `\ZZ`:: - sage: G.coerce(y) # optional - sage.rings.finite_rings + sage: G.coerce(y) # needs sage.rings.finite_rings Traceback (most recent call last): ... TypeError: no canonical coercion from Free Zinbiel algebra on @@ -642,18 +642,18 @@ class ZinbielFunctor(ConstructionFunctor): sage: F = P.construction()[0]; F Zinbiel[x,y] - sage: A = GF(5)['a,b'] # optional - sage.rings.finite_rings - sage: a, b = A.gens() # optional - sage.rings.finite_rings - sage: F(A) # optional - sage.rings.finite_rings + sage: A = GF(5)['a,b'] # needs sage.rings.finite_rings + sage: a, b = A.gens() # needs sage.rings.finite_rings + sage: F(A) # needs sage.rings.finite_rings Free Zinbiel algebra on generators (Z[x], Z[y]) over Multivariate Polynomial Ring in a, b over Finite Field of size 5 - sage: f = A.hom([a+b,a-b],A) # optional - sage.rings.finite_rings - sage: F(f) # optional - sage.rings.finite_rings + sage: f = A.hom([a+b,a-b],A) # needs sage.rings.finite_rings + sage: F(f) # needs sage.rings.finite_rings Generic endomorphism of Free Zinbiel algebra on generators (Z[x], Z[y]) over Multivariate Polynomial Ring in a, b over Finite Field of size 5 - sage: F(f)(a * F(A)(x)) # optional - sage.rings.finite_rings + sage: F(f)(a * F(A)(x)) # needs sage.rings.finite_rings (a+b)*Z[x] """ rank = 9 @@ -706,7 +706,7 @@ def _apply_functor_to_morphism(self, f): TESTS:: sage: R = algebras.FreeZinbiel(ZZ, 'x').construction()[0] - sage: R(ZZ.hom(GF(3))) # indirect doctest # optional - sage.rings.finite_rings + sage: R(ZZ.hom(GF(3))) # indirect doctest # needs sage.rings.finite_rings Generic morphism: From: Free Zinbiel algebra on generators (Z[x],) over Integer Ring diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index df4b748dca4..c0c055ccc65 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -93,14 +93,15 @@ 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: # optional - database_cubic_hecke + sage: CHA6 = algebras.CubicHecke(6) + sage: CHA6.inject_variables() 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 c0*c1*c2*c3*c4 - sage: s^2 # optional - database_cubic_hecke + sage: s^2 (c0*c1*c2*c3*c4)^2 - sage: t = CHA6.an_element() * c4; t # optional - database_cubic_hecke + sage: t = CHA6.an_element() * c4; t (-w)*c0*c1^-1*c4 + v*c0*c2^-1*c4 + u*c2*c1*c4 + ((-v*w+u)/w)*c4 REFERENCES: @@ -1833,18 +1834,19 @@ def _init_basis_extension(self): EXAMPLES:: - 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 + sage: # optional - database_cubic_hecke + sage: CHA5 = algebras.CubicHecke(5) + sage: fc = CHA5._filecache + sage: be = fc.section.basis_extensions + sage: CHA5.reset_filecache(be) + sage: fc.read(be) [[4], [-4]] - sage: ele = CHA5.an_element() # optional - database_cubic_hecke - sage: CHA5.inject_variables() # optional - database_cubic_hecke + sage: ele = CHA5.an_element() + sage: CHA5.inject_variables() Defining c0, c1, c2, c3 - 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 + sage: ele2 = ele * c3 + sage: bex = fc.read(be) + sage: bex.sort(); bex [[-4], [1, -3, 4], [1, -2, 4], [3, 2, 4], [4]] """ self._basis_extension = [] @@ -2220,14 +2222,15 @@ def _braid_image_by_basis_extension(self, braid_tietze): EXAMPLES:: - sage: CHA5 = algebras.CubicHecke(5) # 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 + sage: # optional - database_cubic_hecke + sage: CHA5 = algebras.CubicHecke(5) + sage: be = CHA5.filecache_section().basis_extensions + sage: CHA5.reset_filecache(be) + sage: CHA5._basis_extension [[4], [-4]] - sage: CHA5._braid_image_by_basis_extension((4,1)) # optional - database_cubic_hecke + sage: CHA5._braid_image_by_basis_extension((4,1)) c3*c0 - sage: CHA5._basis_extension # optional - database_cubic_hecke + sage: CHA5._basis_extension [[4], [-4], [4, 1]] case where the braid already has an corresponding basis element:: @@ -2524,15 +2527,16 @@ def _cubic_braid_append_to_basis(self, cubic_braid): EXAMPLES:: - sage: CHA5 = algebras.CubicHecke(5) # 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 + sage: # optional - database_cubic_hecke + sage: CHA5 = algebras.CubicHecke(5) + sage: be = CHA5.filecache_section().basis_extensions + sage: CHA5.reset_filecache(be) + sage: CHA5._basis_extension [[4], [-4]] - sage: CBG = CHA5.cubic_braid_group() # optional - database_cubic_hecke - sage: CHA5._cubic_braid_append_to_basis(CBG((4,1))) # optional - database_cubic_hecke + sage: CBG = CHA5.cubic_braid_group() + sage: CHA5._cubic_braid_append_to_basis(CBG((4,1))) c3*c0 - sage: CHA5._basis_extension # optional - database_cubic_hecke + sage: CHA5._basis_extension [[4], [-4], [4, 1]] """ @@ -2807,12 +2811,13 @@ def reset_filecache(self, section=None, commit=True): EXAMPLES:: - sage: CHA5 = algebras.CubicHecke(5) # 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 + sage: # optional - database_cubic_hecke + sage: CHA5 = algebras.CubicHecke(5) + sage: be = CHA5.filecache_section().basis_extensions + sage: CHA5.is_filecache_empty(be) False - sage: CHA5.reset_filecache(be) # optional - database_cubic_hecke - sage: CHA5.is_filecache_empty(be) # optional - database_cubic_hecke + sage: CHA5.reset_filecache(be) + sage: CHA5.is_filecache_empty(be) True """ fc = self._filecache 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 99e359b518f..90d6657d309 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -298,14 +298,15 @@ def _element_constructor_(self, x, mon=None): 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 + sage: # optional - gap3 + sage: CHA3 = algebras.CubicHecke(3) + sage: GER = CHA3.extension_ring(generic=True) + sage: sch7 = CHA3.chevie().SchurElements()[7] + sage: GER(sch7) 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: rep4_gap3 = CHA3.chevie().Representations(4) + sage: matrix(GER, rep4_gap3[1]) [ b 0] [-b c] """ diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index d0141592724..9608d684409 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1955,12 +1955,13 @@ class Cp(_KLHeckeBasis): implemented with ``coxeter3`` to avoid unnecessary conversions, as in the following example with the same product computed in the last one:: - sage: R = LaurentPolynomialRing(QQ, 'v') # optional - coxeter3 - sage: v = R.gen(0) # optional - coxeter3 - sage: W = CoxeterGroup('A9', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 - sage: Cp = H.Cp() # optional - coxeter3 - sage: Cp[1,2,1,8,9,8]*Cp[1,2,3,7,8,9] # optional - coxeter3 + sage: # optional - coxeter3 + sage: R = LaurentPolynomialRing(QQ, 'v') + sage: v = R.gen(0) + sage: W = CoxeterGroup('A9', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2) + sage: Cp = H.Cp() + sage: Cp[1,2,1,8,9,8]*Cp[1,2,3,7,8,9] (v^-2+2+v^2)*Cp[1,2,1,3,7,8,7,9,8,7] + (v^-2+2+v^2)*Cp[1,2,1,3,8,9,8,7] + (v^-3+3*v^-1+3*v+v^3)*Cp[1,2,1,3,8,9,8] @@ -1984,17 +1985,18 @@ def __init__(self, IHAlgebra, prefix=None): r""" TESTS:: - sage: R. = LaurentPolynomialRing(QQ) # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2) # optional - coxeter3 - sage: Cp = H.Cp() # optional - coxeter3 - sage: Cp._delta == v + ~v # optional - coxeter3 + sage: # optional - coxeter3 + sage: R. = LaurentPolynomialRing(QQ) + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2) + sage: Cp = H.Cp() + sage: Cp._delta == v + ~v True - sage: Cp._W_Coxeter3 == H._W # optional - coxeter3 + sage: Cp._W_Coxeter3 == H._W True - sage: H = IwahoriHeckeAlgebra(W, QQ(1)) # optional - coxeter3 - sage: Cp = H.Cp() # optional - coxeter3 - sage: Cp._W_Coxeter3 is None # optional - coxeter3 + sage: H = IwahoriHeckeAlgebra(W, QQ(1)) + sage: Cp = H.Cp() + sage: Cp._W_Coxeter3 is None True """ super().__init__(IHAlgebra, prefix) @@ -2128,12 +2130,13 @@ def product_on_basis(self, w1, w2): EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() # optional - coxeter3 - sage: Cp.product_on_basis(W([1,2,1]), W([3,1])) # optional - coxeter3 + sage: # optional - coxeter3 + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp=H.Cp() + sage: Cp.product_on_basis(W([1,2,1]), W([3,1])) (v^-1+v)*Cp[1,2,1,3] - sage: Cp.product_on_basis(W([1,2,1]), W([3,1,2])) # optional - coxeter3 + sage: Cp.product_on_basis(W([1,2,1]), W([3,1,2])) (v^-1+v)*Cp[1,2,1,3,2] + (v^-1+v)*Cp[1,2,1] """ if self._W_Coxeter3 is None: @@ -2195,14 +2198,15 @@ def _product_with_generator_on_basis(self, s, w, side='left'): EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp = H.Cp() # optional - coxeter3 - sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'left') # optional - coxeter3 + sage: # optional - coxeter3 + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp = H.Cp() + sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'left') Cp[1,2,1] + Cp[1] - sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'right') # optional - coxeter3 + sage: Cp._product_with_generator_on_basis(1, W([2,1]), 'right') (v^-1+v)*Cp[2,1] - sage: Cp._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') # optional - coxeter3 + sage: Cp._product_with_generator_on_basis(2, W([1,3,2,1,3]), 'right') Cp[1,2,1,3,2,1] + Cp[1,2,3,2] + Cp[1,3,2,1] """ # use the product formula described in the class' documentation @@ -2237,12 +2241,13 @@ def _product_with_generator(self, s, x, side='left'): EXAMPLES:: - sage: R. = LaurentPolynomialRing(ZZ, 'v') # optional - coxeter3 - sage: W = CoxeterGroup('A3', implementation='coxeter3') # optional - coxeter3 - sage: H = IwahoriHeckeAlgebra(W, v**2); Cp = H.Cp() # optional - coxeter3 - sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'left') # optional - coxeter3 + sage: # optional - coxeter3 + sage: R. = LaurentPolynomialRing(ZZ, 'v') + sage: W = CoxeterGroup('A3', implementation='coxeter3') + sage: H = IwahoriHeckeAlgebra(W, v**2); Cp = H.Cp() + sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'left') Cp[1,2] + (v^-1+v)*Cp[1] - sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'right') # optional - coxeter3 + sage: Cp._product_with_generator(1, Cp[1]+Cp[2], 'right') Cp[2,1] + (v^-1+v)*Cp[1] """ return self.linear_combination((self._product_with_generator_on_basis(s, w, side), coeff) for (w, coeff) in x) diff --git a/src/sage/algebras/lie_algebras/morphism.py b/src/sage/algebras/lie_algebras/morphism.py index 2d04a5e6b65..3fa39f8ff78 100644 --- a/src/sage/algebras/lie_algebras/morphism.py +++ b/src/sage/algebras/lie_algebras/morphism.py @@ -461,8 +461,8 @@ class LieAlgebraMorphism_from_generators(LieAlgebraHomomorphism_im_gens): A quotient type Lie algebra morphism:: - sage: K. = LieAlgebra(SR, abelian=True) # optional - sage.symbolic - sage: L.morphism({X: A, Y: B}) # optional - sage.symbolic + sage: K. = LieAlgebra(SR, abelian=True) # needs sage.symbolic + sage: L.morphism({X: A, Y: B}) # needs sage.symbolic Lie algebra morphism: From: Lie algebra on 4 generators (X, Y, Z, W) over Rational Field To: Abelian Lie algebra on 2 generators (A, B) over Symbolic Ring @@ -623,17 +623,17 @@ def _call_(self, x): EXAMPLES:: sage: L. = LieAlgebra(QQ, {('X','Y'): {'Z':1}, ('X','Z'): {'W':1}}) - sage: K. = LieAlgebra(SR, abelian=True) # optional - sage.symbolic - sage: phi = L.morphism({X: A, Y: B}) # optional - sage.symbolic - sage: phi(X) # optional - sage.symbolic + sage: K. = LieAlgebra(SR, abelian=True) # needs sage.symbolic + sage: phi = L.morphism({X: A, Y: B}) # needs sage.symbolic + sage: phi(X) # needs sage.symbolic A - sage: phi(Y) # optional - sage.symbolic + sage: phi(Y) # needs sage.symbolic B - sage: phi(Z) # optional - sage.symbolic + sage: phi(Z) # needs sage.symbolic 0 - sage: phi(W) # optional - sage.symbolic + sage: phi(W) # needs sage.symbolic 0 - sage: phi(-X + 3*Y) # optional - sage.symbolic + sage: phi(-X + 3*Y) # needs sage.symbolic -A + 3*B sage: K. = LieAlgebra(QQ, {('A','B'): {'C':2}}) diff --git a/src/sage/algebras/lie_algebras/quotient.py b/src/sage/algebras/lie_algebras/quotient.py index a0400221af6..ed64e6ee279 100644 --- a/src/sage/algebras/lie_algebras/quotient.py +++ b/src/sage/algebras/lie_algebras/quotient.py @@ -242,11 +242,12 @@ def __init__(self, I, L, names, index_set, category=None): TESTS:: - sage: L. = LieAlgebra(SR, {('x','y'): {'x':1}}) # optional - sage.symbolic - sage: K = L.quotient(y) # optional - sage.symbolic - sage: K.dimension() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: L. = LieAlgebra(SR, {('x','y'): {'x':1}}) + sage: K = L.quotient(y) + sage: K.dimension() 1 - sage: TestSuite(K).run() # optional - sage.symbolic + sage: TestSuite(K).run() """ B = L.basis() sm = L.module().submodule_with_basis([I.reduce(B[i]).to_vector() diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 48b1bbecf41..ed200875e32 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -411,8 +411,8 @@ def change_ring(self, R): sage: LQQ = L.change_ring(QQ) sage: LQQ.structure_coefficients() Finite family {('x', 'y'): z} - sage: LSR = LQQ.change_ring(SR) # optional - sage.symbolic - sage: LSR.structure_coefficients() # optional - sage.symbolic + sage: LSR = LQQ.change_ring(SR) # needs sage.symbolic + sage: LSR.structure_coefficients() # needs sage.symbolic Finite family {('x', 'y'): z} """ return LieAlgebraWithStructureCoefficients( diff --git a/src/sage/algebras/lie_algebras/subalgebra.py b/src/sage/algebras/lie_algebras/subalgebra.py index ab7b6922083..7dc6e8ef37e 100644 --- a/src/sage/algebras/lie_algebras/subalgebra.py +++ b/src/sage/algebras/lie_algebras/subalgebra.py @@ -75,32 +75,34 @@ class LieSubalgebra_finite_dimensional_with_basis(Parent, UniqueRepresentation): Elements of the ambient Lie algebra can be reduced modulo an ideal or subalgebra:: - sage: L. = LieAlgebra(SR, {('X','Y'): {'Z': 1}}) # optional - sage.symbolic - sage: I = L.ideal(Y) # optional - sage.symbolic - sage: I.reduce(X + 2*Y + 3*Z) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: L. = LieAlgebra(SR, {('X','Y'): {'Z': 1}}) + sage: I = L.ideal(Y) + sage: I.reduce(X + 2*Y + 3*Z) X - sage: S = L.subalgebra(Y) # optional - sage.symbolic - sage: S.reduce(X + 2*Y + 3*Z) # optional - sage.symbolic + sage: S = L.subalgebra(Y) + sage: S.reduce(X + 2*Y + 3*Z) X + 3*Z The reduction gives elements in a fixed complementary subspace. When the base ring is a field, the complementary subspace is spanned by those basis elements which are not leading supports of the basis:: - sage: I = L.ideal(X + Y) # optional - sage.symbolic - sage: I.basis() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: I = L.ideal(X + Y) + sage: I.basis() Family (X + Y, Z) - sage: el = var('x')*X + var('y')*Y + var('z')*Z; el # optional - sage.symbolic + sage: el = var('x')*X + var('y')*Y + var('z')*Z; el x*X + y*Y + z*Z - sage: I.reduce(el) # optional - sage.symbolic + sage: I.reduce(el) (x-y)*X Giving a different ``order`` may change the reduction of elements:: - sage: I = L.ideal(X + Y, order=lambda s: ['Z','Y','X'].index(s)) # optional - sage.symbolic - sage: I.basis() # optional - sage.symbolic + sage: I = L.ideal(X + Y, order=lambda s: ['Z','Y','X'].index(s)) # needs sage.symbolic + sage: I.basis() # needs sage.symbolic Family (Z, X + Y) - sage: I.reduce(el) # optional - sage.symbolic + sage: I.reduce(el) # needs sage.symbolic (-x+y)*Y A subalgebra of a subalgebra is a subalgebra of the original:: diff --git a/src/sage/algebras/orlik_solomon.py b/src/sage/algebras/orlik_solomon.py index f92a93c7e21..2cb2dcb8299 100644 --- a/src/sage/algebras/orlik_solomon.py +++ b/src/sage/algebras/orlik_solomon.py @@ -624,11 +624,12 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): Next, we look at the same matroid but with an `S_3 \times S_3` action (here realized as a Young subgroup of `S_6`):: - sage: H = G.young_subgroup([3, 3]) # needs sage.graphs sage.groups - sage: OSH = M.orlik_solomon_algebra(QQ, invariant=H) # needs sage.graphs sage.groups - sage: OSH.basis() # needs sage.graphs sage.groups + sage: # needs sage.graphs sage.groups + sage: H = G.young_subgroup([3, 3]) + sage: OSH = M.orlik_solomon_algebra(QQ, invariant=H) + sage: OSH.basis() Finite family {0: B[0], 1: B[1], 2: B[2]} - sage: [OSH.lift(b) for b in OSH.basis()] # needs sage.graphs sage.groups + sage: [OSH.lift(b) for b in OSH.basis()] [OS{}, OS{4} + OS{5} + OS{6}, OS{1} + OS{2} + OS{3}] We implement an `S_4` action on the vertices:: @@ -648,10 +649,11 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): We use this to describe the Young subgroup `S_2 \times S_2` action:: - sage: H = G.young_subgroup([2,2]) # needs sage.graphs sage.groups - sage: OSH = M.orlik_solomon_algebra(QQ, invariant=(H, vert_action)) # needs sage.graphs sage.groups - sage: B = OSH.basis() # needs sage.graphs sage.groups - sage: [OSH.lift(b) for b in B] # needs sage.graphs sage.groups + sage: # needs sage.graphs sage.groups + sage: H = G.young_subgroup([2,2]) + sage: OSH = M.orlik_solomon_algebra(QQ, invariant=(H, vert_action)) + sage: B = OSH.basis() + sage: [OSH.lift(b) for b in B] [OS{}, OS{5}, OS{1} + OS{2} + OS{3} + OS{4}, OS{0}, -1/2*OS{1, 2} + OS{1, 5} - 1/2*OS{3, 4} + OS{3, 5}, OS{0, 5}, OS{0, 1} + OS{0, 2} + OS{0, 3} + OS{0, 4}, @@ -790,12 +792,13 @@ def _basis_action(self, g, f): We also check that the ordering is respected:: - sage: fset = frozenset({1,2}) # needs sage.graphs sage.groups - sage: OS1 = M.orlik_solomon_algebra(QQ) # needs sage.graphs sage.groups - sage: OS1.subset_image(fset) # needs sage.graphs sage.groups + sage: # needs sage.graphs sage.groups + sage: fset = frozenset({1,2}) + sage: OS1 = M.orlik_solomon_algebra(QQ) + sage: OS1.subset_image(fset) -OS{0, 1} + OS{0, 2} - sage: OS2 = M.orlik_solomon_algebra(QQ, range(2,-1,-1)) # needs sage.graphs sage.groups - sage: OS2.subset_image(fset) # needs sage.graphs sage.groups + sage: OS2 = M.orlik_solomon_algebra(QQ, range(2,-1,-1)) + sage: OS2.subset_image(fset) OS{1, 2} sage: OSG2 = M.orlik_solomon_algebra(QQ, # needs sage.graphs sage.groups diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index f0a31dca349..9c1562041e4 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -119,10 +119,10 @@ class QuaternionAlgebraFactory(UniqueFactory): Quaternion Algebra (2, 3) with base ring Finite Field of size 5 sage: QuaternionAlgebra(2, GF(5)(3)) Quaternion Algebra (2, 3) with base ring Finite Field of size 5 - sage: QuaternionAlgebra(QQ[sqrt(2)](-1), -5) # optional - sage.symbolic + sage: QuaternionAlgebra(QQ[sqrt(2)](-1), -5) # needs sage.symbolic Quaternion Algebra (-1, -5) with base ring Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? - sage: QuaternionAlgebra(sqrt(-1), sqrt(-3)) # optional - sage.symbolic + sage: QuaternionAlgebra(sqrt(-1), sqrt(-3)) # needs sage.symbolic Quaternion Algebra (I, sqrt(-3)) with base ring Symbolic Ring sage: QuaternionAlgebra(1r,1) Quaternion Algebra (1, 1) with base ring Rational Field @@ -162,7 +162,7 @@ class QuaternionAlgebraFactory(UniqueFactory): sage: QuaternionAlgebra(QQ, -7, -21) Quaternion Algebra (-7, -21) with base ring Rational Field - sage: QuaternionAlgebra(QQ[sqrt(2)], -2,-3) # optional - sage.symbolic + sage: QuaternionAlgebra(QQ[sqrt(2)], -2,-3) # needs sage.symbolic Quaternion Algebra (-2, -3) with base ring Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? @@ -545,8 +545,8 @@ def random_element(self, *args, **kwds): EXAMPLES:: - sage: g = QuaternionAlgebra(QQ[sqrt(2)], -3, 7).random_element() # optional - sage.symbolic - sage: g.parent() is QuaternionAlgebra(QQ[sqrt(2)], -3, 7) # optional - sage.symbolic + sage: g = QuaternionAlgebra(QQ[sqrt(2)], -3, 7).random_element() # needs sage.symbolic + sage: g.parent() is QuaternionAlgebra(QQ[sqrt(2)], -3, 7) # needs sage.symbolic True sage: g = QuaternionAlgebra(-3, 19).random_element() sage: g.parent() is QuaternionAlgebra(-3, 19) @@ -1048,7 +1048,7 @@ def discriminant(self): sage: B.discriminant() Fractional ideal (2) - sage: QuaternionAlgebra(QQ[sqrt(2)], 3, 19).discriminant() # optional - sage.symbolic + sage: QuaternionAlgebra(QQ[sqrt(2)], 3, 19).discriminant() # needs sage.symbolic Fractional ideal (1) """ if not is_RationalField(self.base_ring()): @@ -1093,13 +1093,13 @@ def _magma_init_(self, magma): A more complicated example involving a quaternion algebra over a number field:: - sage: K. = QQ[sqrt(2)]; Q = QuaternionAlgebra(K,-1,a); Q # optional - sage.symbolic + sage: K. = QQ[sqrt(2)]; Q = QuaternionAlgebra(K,-1,a); Q # needs sage.symbolic Quaternion Algebra (-1, sqrt2) with base ring Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095? - sage: magma(Q) # optional - magma sage.symbolic + sage: magma(Q) # optional - magma, needs sage.symbolic Quaternion Algebra with base ring Number Field with defining polynomial x^2 - 2 over the Rational Field, defined by i^2 = -1, j^2 = sqrt2 - sage: Q._magma_init_(magma) # optional - magma sage.symbolic + sage: Q._magma_init_(magma) # optional - magma, needs sage.symbolic 'QuaternionAlgebra(_sage_[...],(_sage_[...]![-1, 0]),(_sage_[...]![0, 1]))' """ R = magma(self.base_ring()) @@ -2546,12 +2546,13 @@ def norm(self): sage: [I.norm() for I in C] [16, 32, 32] - sage: (a,b) = M.quaternion_algebra().invariants() # optional - magma - sage: magma.eval('A := QuaternionAlgebra' % (a,b)) # optional - magma + sage: # optional - magma + sage: (a,b) = M.quaternion_algebra().invariants() + sage: magma.eval('A := QuaternionAlgebra' % (a,b)) '' - sage: magma.eval('O := QuaternionOrder(%s)' % str(list(C[0].right_order().basis()))) # optional - magma + sage: magma.eval('O := QuaternionOrder(%s)' % str(list(C[0].right_order().basis()))) '' - sage: [ magma('rideal' % str(list(I.basis()))).Norm() for I in C] # optional - magma + sage: [ magma('rideal' % str(list(I.basis()))).Norm() for I in C] [16, 32, 32] sage: A. = QuaternionAlgebra(-1,-1) diff --git a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx index 71188038aa9..b4c5eed5b49 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_element.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_element.pyx @@ -1658,8 +1658,8 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra EXAMPLES:: - sage: K. = QQ[2^(1/5)]; Q. = QuaternionAlgebra(K,-a,a*17/3) # optional - sage.symbolic - sage: Q([a,-2/3,a^2-1/2,a*2]) # implicit doctest # optional - sage.symbolic + sage: K. = QQ[2^(1/5)]; Q. = QuaternionAlgebra(K,-a,a*17/3) # needs sage.symbolic + sage: Q([a,-2/3,a^2-1/2,a*2]) # implicit doctest # needs sage.symbolic a + (-2/3)*i + (a^2 - 1/2)*j + 2*a*k """ fmpz_poly_init(self.x) @@ -1688,8 +1688,8 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K,-a,a+1) # optional - sage.symbolic - sage: Q([a,-2/3,a^2-1/2,a*2]) # implicit doctest # optional - sage.symbolic + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K,-a,a+1) # needs sage.symbolic + sage: Q([a,-2/3,a^2-1/2,a*2]) # implicit doctest # needs sage.symbolic a + (-2/3)*i + (a^2 - 1/2)*j + 2*a*k """ self._parent = parent @@ -1732,21 +1732,22 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K,-a,a+1) # optional - sage.symbolic - sage: Q([a,-2/3,a^2-1/2,a*2]) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K,-a,a+1) + sage: Q([a,-2/3,a^2-1/2,a*2]) a + (-2/3)*i + (a^2 - 1/2)*j + 2*a*k - sage: x = Q([a,-2/3,a^2-1/2,a*2]) # optional - sage.symbolic - sage: type(x) # optional - sage.symbolic + sage: x = Q([a,-2/3,a^2-1/2,a*2]) + sage: type(x) - sage: x[0] # optional - sage.symbolic + sage: x[0] a - sage: x[1] # optional - sage.symbolic + sage: x[1] -2/3 - sage: x[2] # optional - sage.symbolic + sage: x[2] a^2 - 1/2 - sage: x[3] # optional - sage.symbolic + sage: x[3] 2*a - sage: list(x) # optional - sage.symbolic + sage: list(x) [a, -2/3, a^2 - 1/2, 2*a] """ # general number -- this code assumes that the number field is not quadratic!! @@ -1773,13 +1774,14 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) # optional - sage.symbolic - sage: z = (i+j+k+a)^2; z # optional - sage.symbolic + sage: # needs sage.symbolic + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) + sage: z = (i+j+k+a)^2; z a^2 + 4*a - 3 + 2*a*i + 2*a*j + 2*a*k - sage: f, t = z.__reduce__() # optional - sage.symbolic - sage: f(*t) # optional - sage.symbolic + sage: f, t = z.__reduce__() + sage: f(*t) a^2 + 4*a - 3 + 2*a*i + 2*a*j + 2*a*k - sage: loads(dumps(z)) == z # optional - sage.symbolic + sage: loads(dumps(z)) == z True """ return (unpickle_QuaternionAlgebraElement_number_field_v0, @@ -1791,12 +1793,13 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) # optional - sage.symbolic - sage: z = a + i + (2/3)*a^3*j + (1+a)*k # optional - sage.symbolic - sage: w = a - i - (2/3)*a^3*j + (1/3+a)*k # optional - sage.symbolic - sage: type(z) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) + sage: z = a + i + (2/3)*a^3*j + (1+a)*k + sage: w = a - i - (2/3)*a^3*j + (1/3+a)*k + sage: type(z) - sage: z._add_(w) # optional - sage.symbolic + sage: z._add_(w) 2*a + (2*a + 4/3)*k Check that the fix in :trac:`17099` is correct:: @@ -1864,12 +1867,13 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) # optional - sage.symbolic - sage: z = a + i + (2/3)*a^3*j + (1+a)*k # optional - sage.symbolic - sage: w = a - i - (2/3)*a^3*j + (1/3+a)*k # optional - sage.symbolic - sage: type(z) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) + sage: z = a + i + (2/3)*a^3*j + (1+a)*k + sage: w = a - i - (2/3)*a^3*j + (1/3+a)*k + sage: type(z) - sage: z._sub_(w) # optional - sage.symbolic + sage: z._sub_(w) 2*i + 8/3*j + 2/3*k """ # Implementation Note: To obtain _sub_, we simply replace every occurrence of @@ -1914,12 +1918,13 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) # optional - sage.symbolic - sage: z = a + i + (2/3)*a^3*j + (1+a)*k # optional - sage.symbolic - sage: w = a - i - (2/3)*a^3*j + (1/3+a)*k # optional - sage.symbolic - sage: type(z) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a) + sage: z = a + i + (2/3)*a^3*j + (1+a)*k + sage: w = a - i - (2/3)*a^3*j + (1/3+a)*k + sage: type(z) - sage: z._mul_(w) # optional - sage.symbolic + sage: z._mul_(w) 5*a^2 - 7/9*a + 9 + (-8/3*a^2 - 16/9*a)*i + (-6*a - 4)*j + (2*a^2 + 4/3*a)*k """ # We use the following formula for multiplication: @@ -2063,10 +2068,11 @@ cdef class QuaternionAlgebraElement_number_field(QuaternionAlgebraElement_abstra TESTS:: - sage: F = QQ[3^(1/3)] # optional - sage.symbolic - sage: a = F.gen() # optional - sage.symbolic - sage: K. = QuaternionAlgebra(F, -10 + a, -7 - a) # optional - sage.symbolic - sage: ((1/4 + 1/2 * i + a^3/7 * j + a/28 * k)*14*i)^3 # implicit doctest # optional - sage.symbolic + sage: # needs sage.symbolic + sage: F = QQ[3^(1/3)] + sage: a = F.gen() + sage: K. = QuaternionAlgebra(F, -10 + a, -7 - a) + sage: ((1/4 + 1/2 * i + a^3/7 * j + a/28 * k)*14*i)^3 # implicit doctest 34503/2*a^2 + 132195/2*a + 791399/4 + (203/8*a^2 - 10591*a + 169225/4)*i + (-84695/4*a^2 + 483413/8*a + 18591/4)*j + (-87/2*a^2 + 18156*a - 72525)*k """ @@ -2141,11 +2147,12 @@ def unpickle_QuaternionAlgebraElement_number_field_v0(*args): """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a); z = i + j # optional - sage.symbolic - sage: f, t = z.__reduce__() # optional - sage.symbolic - sage: sage.algebras.quatalg.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a); z = i + j + sage: f, t = z.__reduce__() + sage: sage.algebras.quatalg.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) i + j - sage: sage.algebras.quatalg.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) == z # optional - sage.symbolic + sage: sage.algebras.quatalg.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) == z True """ return QuaternionAlgebraElement_number_field(*args, check=False) diff --git a/src/sage/algebras/quaternion_algebra_element.py b/src/sage/algebras/quaternion_algebra_element.py index dbd70e25856..ed0baaf0152 100644 --- a/src/sage/algebras/quaternion_algebra_element.py +++ b/src/sage/algebras/quaternion_algebra_element.py @@ -39,12 +39,13 @@ def unpickle_QuaternionAlgebraElement_number_field_v0(*args): """ EXAMPLES:: - sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a); z = i + j # optional - sage.symbolic - sage: f, t = z.__reduce__() # optional - sage.symbolic + sage: # needs sage.symbolic + sage: K. = QQ[2^(1/3)]; Q. = QuaternionAlgebra(K, -3, a); z = i + j + sage: f, t = z.__reduce__() sage: import sage.algebras.quaternion_algebra_element - sage: sage.algebras.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) # optional - sage.symbolic + sage: sage.algebras.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) i + j - sage: sage.algebras.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) == z # optional - sage.symbolic + sage: sage.algebras.quaternion_algebra_element.unpickle_QuaternionAlgebraElement_number_field_v0(*t) == z True """ return QuaternionAlgebraElement_number_field(*args) diff --git a/src/sage/algebras/steenrod/steenrod_algebra_bases.py b/src/sage/algebras/steenrod/steenrod_algebra_bases.py index 367c854249e..d2a8760581e 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_bases.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_bases.py @@ -132,12 +132,12 @@ def convert_to_milnor_matrix(n, basis, p=2, generic='auto'): EXAMPLES:: sage: from sage.algebras.steenrod.steenrod_algebra_bases import convert_to_milnor_matrix - sage: convert_to_milnor_matrix(5, 'adem') # indirect doctest # optional - sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(5, 'adem') # indirect doctest # needs sage.modules sage.rings.finite_rings [0 1] [1 1] - sage: convert_to_milnor_matrix(45, 'milnor') # optional - sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(45, 'milnor') # needs sage.modules sage.rings.finite_rings 111 x 111 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) - sage: convert_to_milnor_matrix(12,'wall') # optional - sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(12,'wall') # needs sage.modules sage.rings.finite_rings [1 0 0 1 0 0 0] [1 1 0 0 0 1 0] [0 1 0 1 0 0 0] @@ -149,15 +149,15 @@ def convert_to_milnor_matrix(n, basis, p=2, generic='auto'): The function takes an optional argument, the prime `p` over which to work:: - sage: convert_to_milnor_matrix(17,'adem',3) # optional - sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(17,'adem',3) # needs sage.modules sage.rings.finite_rings [0 0 1 1] [0 0 0 1] [1 1 1 1] [0 1 0 1] - sage: convert_to_milnor_matrix(48,'adem',5) # optional - sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(48,'adem',5) # needs sage.modules sage.rings.finite_rings [0 1] [1 1] - sage: convert_to_milnor_matrix(36,'adem',3) # optional - sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(36,'adem',3) # needs sage.modules sage.rings.finite_rings [0 0 1] [0 1 0] [1 2 0] @@ -206,7 +206,7 @@ def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): EXAMPLES:: sage: from sage.algebras.steenrod.steenrod_algebra_bases import convert_from_milnor_matrix, convert_to_milnor_matrix - sage: convert_from_milnor_matrix(12,'wall') # optional - sage.modules sage.rings.finite_rings + sage: convert_from_milnor_matrix(12,'wall') # needs sage.modules sage.rings.finite_rings [1 0 0 1 0 0 0] [0 0 1 1 0 0 0] [0 0 0 1 0 1 1] @@ -214,11 +214,11 @@ def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): [1 0 1 0 1 0 0] [1 1 1 0 0 0 0] [1 0 1 0 1 0 1] - sage: convert_from_milnor_matrix(38,'serre_cartan') # optional - sage.modules sage.rings.finite_rings + sage: convert_from_milnor_matrix(38,'serre_cartan') # needs sage.modules sage.rings.finite_rings 72 x 72 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) - sage: x = convert_to_milnor_matrix(20,'wood_y') # optional - sage.modules sage.rings.finite_rings - sage: y = convert_from_milnor_matrix(20,'wood_y') # optional - sage.modules sage.rings.finite_rings - sage: x*y + sage: x = convert_to_milnor_matrix(20,'wood_y') # needs sage.modules sage.rings.finite_rings + sage: y = convert_from_milnor_matrix(20,'wood_y') # needs sage.modules sage.rings.finite_rings + sage: x*y # needs sage.modules sage.rings.finite_rings [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0] @@ -240,7 +240,7 @@ def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): The function takes an optional argument, the prime `p` over which to work:: - sage: convert_from_milnor_matrix(17,'adem',3) # optional - sage.modules sage.rings.finite_rings + sage: convert_from_milnor_matrix(17,'adem',3) # needs sage.modules sage.rings.finite_rings [2 1 1 2] [0 2 0 1] [1 2 0 0] @@ -1108,11 +1108,12 @@ def steenrod_basis_error_check(dim, p, **kwds): EXAMPLES:: + sage: # long time sage: from sage.algebras.steenrod.steenrod_algebra_bases import steenrod_basis_error_check - sage: steenrod_basis_error_check(15,2) # long time - sage: steenrod_basis_error_check(15,2,generic=True) # long time - sage: steenrod_basis_error_check(40,3) # long time - sage: steenrod_basis_error_check(80,5) # long time + sage: steenrod_basis_error_check(15,2) + sage: steenrod_basis_error_check(15,2,generic=True) + sage: steenrod_basis_error_check(40,3) + sage: steenrod_basis_error_check(80,5) """ from sage.misc.verbose import verbose generic = kwds.get('generic', p != 2) diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 14ae670b00e..b033a24065c 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -54,12 +54,12 @@ def repr_from_monomials(monomials, term_repr, use_latex=False): sage: from sage.algebras.weyl_algebra import repr_from_monomials sage: R. = QQ[] - sage: d = [(z, 4/7), (y, sqrt(2)), (x, -5)] # optional - sage.symbolic - sage: repr_from_monomials(d, lambda m: repr(m)) # optional - sage.symbolic + sage: d = [(z, 4/7), (y, sqrt(2)), (x, -5)] # needs sage.symbolic + sage: repr_from_monomials(d, lambda m: repr(m)) # needs sage.symbolic '4/7*z + sqrt(2)*y - 5*x' - sage: a = repr_from_monomials(d, lambda m: latex(m), True); a # optional - sage.symbolic + sage: a = repr_from_monomials(d, lambda m: latex(m), True); a # needs sage.symbolic \frac{4}{7} z + \sqrt{2} y - 5 x - sage: type(a) # optional - sage.symbolic + sage: type(a) # needs sage.symbolic The zero element:: @@ -91,12 +91,13 @@ def repr_from_monomials(monomials, term_repr, use_latex=False): Leading minus signs are dealt with appropriately:: - sage: d = [(z, -4/7), (y, -sqrt(2)), (x, -5)] # optional - sage.symbolic - sage: repr_from_monomials(d, lambda m: repr(m)) # optional - sage.symbolic + sage: # needs sage.symbolic + sage: d = [(z, -4/7), (y, -sqrt(2)), (x, -5)] + sage: repr_from_monomials(d, lambda m: repr(m)) '-4/7*z - sqrt(2)*y - 5*x' - sage: a = repr_from_monomials(d, lambda m: latex(m), True); a # optional - sage.symbolic + sage: a = repr_from_monomials(d, lambda m: latex(m), True); a -\frac{4}{7} z - \sqrt{2} y - 5 x - sage: type(a) # optional - sage.symbolic + sage: type(a) Indirect doctests using a class that uses this function:: From 28588b78a4bb66f4786a59235443a853c4e53e79 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 12 Aug 2023 21:49:25 -0700 Subject: [PATCH 133/538] Add # needs --- src/sage/algebras/clifford_algebra_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index ce4708313b4..2e6ad0a8547 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -945,7 +945,7 @@ cdef class CohomologyRAAGElement(CliffordAlgebraElement): EXAMPLES:: - sage: # needs sage.graphs + sage: # needs sage.graphs sage.groups sage: C4 = graphs.CycleGraph(4) sage: A = groups.misc.RightAngledArtin(C4) sage: H = A.cohomology() From 78dfa45507859af40a7e5a64acf80ec1603c9d6d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Sep 2023 14:28:28 -0700 Subject: [PATCH 134/538] src/sage/algebras/schur_algebra.py: Update # needs --- src/sage/algebras/schur_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 0df04485a2a..4fca609ecf7 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: needs sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.groups sage.modules r""" Schur algebras for `GL_n` From b528606d24464e1891b7dbd758df3df11402b15e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Sep 2023 17:23:19 -0700 Subject: [PATCH 135/538] src/sage/algebras: Add file-level tags; src/sage/rings/finite_rings: Add tags --- src/sage/algebras/iwahori_hecke_algebra.py | 2 +- src/sage/algebras/q_commuting_polynomials.py | 2 +- src/sage/algebras/q_system.py | 2 +- src/sage/algebras/quantum_groups/representations.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 9608d684409..5ff849c8786 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1,4 +1,4 @@ -# sage.doctest: needs sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.graphs sage.modules r""" Iwahori-Hecke Algebras diff --git a/src/sage/algebras/q_commuting_polynomials.py b/src/sage/algebras/q_commuting_polynomials.py index 0b23a756fd5..10f5f55a987 100644 --- a/src/sage/algebras/q_commuting_polynomials.py +++ b/src/sage/algebras/q_commuting_polynomials.py @@ -1,4 +1,4 @@ -# sage.doctest: needs sage.modules +# sage.doctest: needs sage.combinat sage.groups sage.modules r""" `q`-Commuting Polynomials diff --git a/src/sage/algebras/q_system.py b/src/sage/algebras/q_system.py index 74bf87c2787..d35c51a32a5 100644 --- a/src/sage/algebras/q_system.py +++ b/src/sage/algebras/q_system.py @@ -1,4 +1,4 @@ -# sage.doctest: needs sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.graphs sage.modules r""" Q-Systems diff --git a/src/sage/algebras/quantum_groups/representations.py b/src/sage/algebras/quantum_groups/representations.py index cb026008d6d..cea110137db 100644 --- a/src/sage/algebras/quantum_groups/representations.py +++ b/src/sage/algebras/quantum_groups/representations.py @@ -1,4 +1,4 @@ -# sage.doctest: needs sage.combinat sage.modules +# sage.doctest: needs sage.combinat sage.graphs sage.modules r""" Quantum Group Representations From 26fc8187d436bdb5e68d47ecc2e6fa76fb178b78 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Sep 2023 17:49:04 -0700 Subject: [PATCH 136/538] src/sage/algebras/steenrod/steenrod_algebra_bases.py: Update # needs, doctest cosmetics --- .../steenrod/steenrod_algebra_bases.py | 233 +++++++++--------- 1 file changed, 119 insertions(+), 114 deletions(-) diff --git a/src/sage/algebras/steenrod/steenrod_algebra_bases.py b/src/sage/algebras/steenrod/steenrod_algebra_bases.py index d2a8760581e..9c8cc0935c8 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_bases.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_bases.py @@ -20,29 +20,29 @@ Monks [Mon1998]_ and Wood [Woo1998]_ for more information about them. For commutator bases, see the preprint by Palmieri and Zhang [PZ2008]_. -- 'milnor': Milnor basis. +- ``'milnor'``: Milnor basis. -- 'serre-cartan' or 'adem' or 'admissible': Serre-Cartan basis. +- ``'serre-cartan'`` or ``'adem'`` or ``'admissible'``: Serre-Cartan basis. Most of the rest of the bases are only defined when `p=2`. The only exceptions are the `P^s_t`-bases and the commutator bases, which are defined at all primes. -- 'wood_y': Wood's Y basis. +- ``'wood_y'``: Wood's Y basis. -- 'wood_z': Wood's Z basis. +- ``'wood_z'``: Wood's Z basis. -- 'wall', 'wall_long': Wall's basis. +- ``'wall'``, ``'wall_long'``: Wall's basis. -- 'arnon_a', 'arnon_a_long': Arnon's A basis. +- ``'arnon_a'``, ``'arnon_a_long'``: Arnon's A basis. -- 'arnon_c': Arnon's C basis. +- ``'arnon_c'``: Arnon's C basis. -- 'pst', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz': +- ``'pst'``, ``'pst_rlex'``, ``'pst_llex'``, ``'pst_deg'``, ``'pst_revz'``: various `P^s_t`-bases. -- 'comm', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz', - or these with '_long' appended: various commutator bases. +- ``'comm'``, ``'comm_rlex'``, ``'comm_llex'``, ``'comm_deg'``, ``'comm_revz'``, + or these with ``'_long'`` appended: various commutator bases. The main functions provided here are @@ -121,23 +121,24 @@ def convert_to_milnor_matrix(n, basis, p=2, generic='auto'): INPUT: - - ``n`` - non-negative integer, the dimension - - ``basis`` - string, the basis from which to convert - - ``p`` - positive prime number (optional, default 2) + - ``n`` -- non-negative integer, the dimension + - ``basis`` -- string, the basis from which to convert + - ``p`` -- positive prime number (optional, default 2) OUTPUT: - ``matrix`` - change-of-basis matrix, a square matrix over ``GF(p)`` + ``matrix`` -- change-of-basis matrix, a square matrix over `\GF{p}` EXAMPLES:: + sage: # needs sage.modules sage: from sage.algebras.steenrod.steenrod_algebra_bases import convert_to_milnor_matrix - sage: convert_to_milnor_matrix(5, 'adem') # indirect doctest # needs sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(5, 'adem') # indirect doctest [0 1] [1 1] - sage: convert_to_milnor_matrix(45, 'milnor') # needs sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(45, 'milnor') 111 x 111 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) - sage: convert_to_milnor_matrix(12,'wall') # needs sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(12, 'wall') [1 0 0 1 0 0 0] [1 1 0 0 0 1 0] [0 1 0 1 0 0 0] @@ -149,15 +150,16 @@ def convert_to_milnor_matrix(n, basis, p=2, generic='auto'): The function takes an optional argument, the prime `p` over which to work:: - sage: convert_to_milnor_matrix(17,'adem',3) # needs sage.modules sage.rings.finite_rings + sage: # needs sage.modules + sage: convert_to_milnor_matrix(17, 'adem', 3) [0 0 1 1] [0 0 0 1] [1 1 1 1] [0 1 0 1] - sage: convert_to_milnor_matrix(48,'adem',5) # needs sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(48, 'adem', 5) [0 1] [1 1] - sage: convert_to_milnor_matrix(36,'adem',3) # needs sage.modules sage.rings.finite_rings + sage: convert_to_milnor_matrix(36, 'adem', 3) [0 0 1] [0 1 0] [1 2 0] @@ -182,20 +184,19 @@ def convert_to_milnor_matrix(n, basis, p=2, generic='auto'): def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): r""" - Change-of-basis matrix, Milnor to 'basis', in dimension - `n`. + Change-of-basis matrix, Milnor to ``basis``, in dimension `n`. INPUT: - - ``n`` - non-negative integer, the dimension + - ``n`` -- non-negative integer, the dimension - - ``basis`` - string, the basis to which to convert + - ``basis`` -- string, the basis to which to convert - - ``p`` - positive prime number (optional, default 2) + - ``p`` -- positive prime number (optional, default 2) OUTPUT: - ``matrix`` - change-of-basis matrix, a square matrix over GF(p) + ``matrix`` -- change-of-basis matrix, a square matrix over `\GF{p}` .. note:: @@ -205,8 +206,9 @@ def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): EXAMPLES:: + sage: # needs sage.modules sage: from sage.algebras.steenrod.steenrod_algebra_bases import convert_from_milnor_matrix, convert_to_milnor_matrix - sage: convert_from_milnor_matrix(12,'wall') # needs sage.modules sage.rings.finite_rings + sage: convert_from_milnor_matrix(12, 'wall') [1 0 0 1 0 0 0] [0 0 1 1 0 0 0] [0 0 0 1 0 1 1] @@ -214,11 +216,11 @@ def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): [1 0 1 0 1 0 0] [1 1 1 0 0 0 0] [1 0 1 0 1 0 1] - sage: convert_from_milnor_matrix(38,'serre_cartan') # needs sage.modules sage.rings.finite_rings + sage: convert_from_milnor_matrix(38, 'serre_cartan') 72 x 72 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) - sage: x = convert_to_milnor_matrix(20,'wood_y') # needs sage.modules sage.rings.finite_rings - sage: y = convert_from_milnor_matrix(20,'wood_y') # needs sage.modules sage.rings.finite_rings - sage: x*y # needs sage.modules sage.rings.finite_rings + sage: x = convert_to_milnor_matrix(20, 'wood_y') + sage: y = convert_from_milnor_matrix(20, 'wood_y') + sage: x*y [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0] @@ -240,7 +242,7 @@ def convert_from_milnor_matrix(n, basis, p=2, generic='auto'): The function takes an optional argument, the prime `p` over which to work:: - sage: convert_from_milnor_matrix(17,'adem',3) # needs sage.modules sage.rings.finite_rings + sage: convert_from_milnor_matrix(17, 'adem', 3) # needs sage.modules [2 1 1 2] [0 2 0 1] [1 2 0 0] @@ -259,17 +261,17 @@ def steenrod_algebra_basis(n, basis='milnor', p=2, **kwds): INPUT: - - ``n`` - non-negative integer - - ``basis`` - string, which basis to use (optional, default = 'milnor') - - ``p`` - positive prime number (optional, default = 2) - - ``profile`` - profile function (optional, default None). This + - ``n`` -- non-negative integer + - ``basis`` -- string, which basis to use (optional, default: ``'milnor'``) + - ``p`` -- positive prime number (optional, default: 2) + - ``profile`` -- profile function (optional, default: ``None``). This is just passed on to the functions :func:`milnor_basis` and :func:`pst_basis`. - - ``truncation_type`` - truncation type, either 0 or Infinity + - ``truncation_type`` -- truncation type, either 0 or Infinity (optional, default Infinity if no profile function is specified, 0 otherwise). This is just passed on to the function :func:`milnor_basis`. - - ``generic`` - boolean (optional, default = None) + - ``generic`` -- boolean (optional, default: ``None``) OUTPUT: @@ -280,25 +282,25 @@ def steenrod_algebra_basis(n, basis='milnor', p=2, **kwds): documentation for :mod:`sage.algebras.steenrod.steenrod_algebra` for details on each basis: - - 'milnor': Milnor basis. - - 'serre-cartan' or 'adem' or 'admissible': Serre-Cartan basis. - - 'pst', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz': + - ``'milnor'``: Milnor basis. + - ``'serre-cartan'`` or ``'adem'`` or ``'admissible'``: Serre-Cartan basis. + - ``'pst'``, ``'pst_rlex'``, ``'pst_llex'``, ``'pst_deg'``, ``'pst_revz'``: various `P^s_t`-bases. - - 'comm', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz', or - any of these with '_long' appended: various commutator bases. + - ``'comm'``, ``'comm_rlex'``, ``'comm_llex'``, ``'comm_deg'``, ``'comm_revz'``, or + any of these with ``'_long'`` appended: various commutator bases. The rest of these bases are only defined when `p=2`. - - 'wood_y': Wood's Y basis. - - 'wood_z': Wood's Z basis. - - 'wall' or 'wall_long': Wall's basis. - - 'arnon_a' or 'arnon_a_long': Arnon's A basis. - - 'arnon_c': Arnon's C basis. + - ``'wood_y'``: Wood's Y basis. + - ``'wood_z'``: Wood's Z basis. + - ``'wall'`` or ``'wall_long'``: Wall's basis. + - ``'arnon_a'`` or ``'arnon_a_long'``: Arnon's A basis. + - ``'arnon_c'``: Arnon's C basis. EXAMPLES:: sage: from sage.algebras.steenrod.steenrod_algebra_bases import steenrod_algebra_basis - sage: steenrod_algebra_basis(7,'milnor') # indirect doctest + sage: steenrod_algebra_basis(7, 'milnor') # indirect doctest ((0, 0, 1), (1, 2), (4, 1), (7,)) sage: steenrod_algebra_basis(5) # milnor basis is the default ((2, 1), (5,)) @@ -320,15 +322,15 @@ def steenrod_algebra_basis(n, basis='milnor', p=2, **kwds): Other bases:: - sage: steenrod_algebra_basis(7,'admissible') + sage: steenrod_algebra_basis(7, 'admissible') ((7,), (6, 1), (4, 2, 1), (5, 2)) - sage: steenrod_algebra_basis(13,'admissible',p=3) + sage: steenrod_algebra_basis(13, 'admissible', p=3) ((1, 3, 0), (0, 3, 1)) - sage: steenrod_algebra_basis(5,'wall') + sage: steenrod_algebra_basis(5, 'wall') (((2, 2), (0, 0)), ((1, 1), (1, 0))) - sage: steenrod_algebra_basis(5,'wall_long') + sage: steenrod_algebra_basis(5, 'wall_long') (((2, 2), (0, 0)), ((1, 1), (1, 0))) - sage: steenrod_algebra_basis(5,'pst-rlex') + sage: steenrod_algebra_basis(5, 'pst-rlex') (((0, 1), (2, 1)), ((1, 1), (0, 2))) """ from .steenrod_algebra_misc import get_basis_name @@ -375,14 +377,14 @@ def steenrod_algebra_basis(n, basis='milnor', p=2, **kwds): def restricted_partitions(n, l, no_repeats=False): """ - List of 'restricted' partitions of n: partitions with parts taken - from list. + List of 'restricted' partitions of `n`: partitions with parts taken + from list `l`. INPUT: - - ``n`` - non-negative integer - - ``l`` - list of positive integers - - ``no_repeats`` - boolean (optional, default = False), if True, + - ``n`` -- non-negative integer + - ``l`` -- list of positive integers + - ``no_repeats`` -- boolean (optional, default: ``False``), if ``True``, only return partitions with no repeated parts OUTPUT: list of lists @@ -406,10 +408,10 @@ def restricted_partitions(n, l, no_repeats=False): sage: restricted_partitions(10, [6,4,2], no_repeats=True) [[6, 4]] - 'l' may have repeated elements. If 'no_repeats' is False, this - has no effect. If 'no_repeats' is True, and if the repeated - elements appear consecutively in 'l', then each element may be - used only as many times as it appears in 'l':: + ``l`` may have repeated elements. If ``no_repeats`` is ``False``, this + has no effect. If ``no_repeats`` is ``True``, and if the repeated + elements appear consecutively in ``l``, then each element may be + used only as many times as it appears in ``l``:: sage: restricted_partitions(10, [6,4,2,2], no_repeats=True) [[6, 4], [6, 2, 2]] @@ -420,7 +422,7 @@ def restricted_partitions(n, l, no_repeats=False): are likely meaningless, containing several partitions more than once, for example.) - In the following examples, 'no_repeats' is False:: + In the following examples, ``no_repeats`` is ``False``:: sage: restricted_partitions(10, [6,4,2]) [[6, 4], [6, 2, 2], [4, 4, 2], [4, 2, 2, 2], [2, 2, 2, 2, 2]] @@ -448,25 +450,25 @@ def restricted_partitions(n, l, no_repeats=False): old_i = i return results -def xi_degrees(n,p=2, reverse=True): +def xi_degrees(n, p=2, reverse=True): r""" - Decreasing list of degrees of the xi_i's, starting in degree n. + Decreasing list of degrees of the `\xi_i`'s, starting in degree `n`. INPUT: - - `n` - integer - - `p` - prime number, optional (default 2) - - ``reverse`` - bool, optional (default True) + - ``n`` -- integer + - ``p`` -- prime number, optional (default: 2) + - ``reverse`` -- bool, optional (default: ``True``) - OUTPUT: ``list`` - list of integers + OUTPUT: ``list`` -- list of integers When `p=2`: decreasing list of the degrees of the `\xi_i`'s with - degree at most n. + degree at most `n`. At odd primes: decreasing list of these degrees, each divided by `2(p-1)`. - If ``reverse`` is False, then return an increasing list rather + If ``reverse`` is ``False``, then return an increasing list rather than a decreasing one. EXAMPLES:: @@ -475,9 +477,9 @@ def xi_degrees(n,p=2, reverse=True): [15, 7, 3, 1] sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(17, reverse=False) [1, 3, 7, 15] - sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(17,p=3) + sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(17, p=3) [13, 4, 1] - sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(400,p=17) + sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(400, p=17) [307, 18, 1] """ from sage.rings.integer import Integer @@ -505,23 +507,23 @@ def milnor_basis(n, p=2, **kwds): INPUT: - - ``n`` - non-negative integer + - ``n`` -- non-negative integer - - ``p`` - positive prime number (optional, default 2) + - ``p`` -- positive prime number (optional, default 2) - - ``profile`` - profile function (optional, default None). + - ``profile`` - profile function (optional, default ``None``). Together with ``truncation_type``, specify the profile function - to be used; None means the profile function for the entire + to be used; ``None`` means the profile function for the entire Steenrod algebra. See :mod:`sage.algebras.steenrod.steenrod_algebra` and :func:`SteenrodAlgebra ` for information on profile functions. - - ``truncation_type`` - truncation type, either 0 or Infinity + - ``truncation_type`` -- truncation type, either 0 or Infinity (optional, default Infinity if no profile function is specified, 0 otherwise) - OUTPUT: tuple of mod p Milnor basis elements in dimension n + OUTPUT: tuple of mod `p` Milnor basis elements in dimension `n` At the prime 2, the Milnor basis consists of symbols of the form `\text{Sq}(m_1, m_2, ..., m_t)`, where each @@ -669,11 +671,11 @@ def serre_cartan_basis(n, p=2, bound=1, **kwds): INPUT: - - ``n`` - non-negative integer - - ``bound`` - positive integer (optional) - - ``prime`` - positive prime number (optional, default 2) + - ``n`` -- non-negative integer + - ``bound`` -- positive integer (optional) + - ``prime`` -- positive prime number (optional, default 2) - OUTPUT: tuple of mod p Serre-Cartan basis elements in dimension n + OUTPUT: tuple of mod `p` Serre-Cartan basis elements in dimension `n` The Serre-Cartan basis consists of 'admissible monomials in the Steenrod squares'. Thus at the prime 2, it consists of monomials @@ -694,8 +696,8 @@ def serre_cartan_basis(n, p=2, bound=1, **kwds): ((1, 5, 0, 1, 1), (1, 6, 1)) If optional argument ``bound`` is present, include only those monomials - whose last term is at least ``bound`` (when p=2), or those for which - `s_k - e_k \geq bound` (when p is odd). :: + whose last term is at least ``bound`` (when `p=2`), or those for which + `s_k - e_k \geq bound` (when `p` is odd). :: sage: serre_cartan_basis(7, bound=2) ((7,), (5, 2)) @@ -753,27 +755,28 @@ def atomic_basis(n, basis, **kwds): INPUT: - - ``n`` - non-negative integer - - ``basis`` - string, the name of the basis + - ``n`` -- non-negative integer - - ``profile`` - profile function (optional, default None). + - ``basis`` -- string, the name of the basis + + - ``profile`` -- profile function (optional, default: ``None``). Together with ``truncation_type``, specify the profile function - to be used; None means the profile function for the entire + to be used; ``None`` means the profile function for the entire Steenrod algebra. See :mod:`sage.algebras.steenrod.steenrod_algebra` and :func:`SteenrodAlgebra` for information on profile functions. - - ``truncation_type`` - truncation type, either 0 or Infinity + - ``truncation_type`` -- truncation type, either 0 or Infinity (optional, default Infinity if no profile function is specified, 0 otherwise). - OUTPUT: tuple of basis elements in dimension n + OUTPUT: tuple of basis elements in dimension `n` The atomic bases include Wood's Y and Z bases, Wall's basis, Arnon's A basis, the `P^s_t`-bases, and the commutator bases. (All of these bases are constructed similarly, hence their constructions have been consolidated into a single function. Also, - see the documentation for 'steenrod_algebra_basis' for + see the documentation for :func:`steenrod_algebra_basis` for descriptions of them.) For `P^s_t`-bases, you may also specify a profile function and truncation type; profile functions are ignored for the other bases. @@ -824,12 +827,12 @@ def atomic_basis(n, basis, **kwds): """ def degree_dictionary(n, basis): """ - Dictionary of atomic degrees for basis up to degree n. + Dictionary of atomic degrees for basis up to degree `n`. - The keys for the dictionary are the atomic degrees - the numbers of - the form 2^i (2^j - 1) - which are less than or equal to n. The value + The keys for the dictionary are the atomic degrees -- the numbers of + the form `2^i (2^j - 1)` -- which are less than or equal to `n`. The value associated to such a degree depends on basis; it has the form - (s,t), where (s,t) is a pair of integers which indexes the + `(s,t)`, where `(s,t)` is a pair of integers which indexes the corresponding element. """ dict = {} @@ -931,11 +934,11 @@ def arnonC_basis(n,bound=1): INPUT: - - ``n`` - non-negative integer + - ``n`` -- non-negative integer - - ``bound`` - positive integer (optional) + - ``bound`` -- positive integer (optional) - OUTPUT: tuple of basis elements in dimension n + OUTPUT: tuple of basis elements in dimension `n` The elements of Arnon's C basis are monomials of the form `\text{Sq}^{t_1} ... \text{Sq}^{t_m}` where for each @@ -978,22 +981,24 @@ def atomic_basis_odd(n, basis, p, **kwds): INPUT: - - ``n`` - non-negative integer - - ``basis`` - string, the name of the basis - - ``p`` - positive prime number + - ``n`` -- non-negative integer + + - ``basis`` -- string, the name of the basis + + - ``p`` -- positive prime number - - ``profile`` - profile function (optional, default None). + - ``profile`` -- profile function (optional, default: ``None``). Together with ``truncation_type``, specify the profile function - to be used; None means the profile function for the entire + to be used; ``None`` means the profile function for the entire Steenrod algebra. See :mod:`sage.algebras.steenrod.steenrod_algebra` and :func:`SteenrodAlgebra` for information on profile functions. - - ``truncation_type`` - truncation type, either 0 or Infinity + - ``truncation_type`` -- truncation type, either 0 or Infinity (optional, default Infinity if no profile function is specified, 0 otherwise). - OUTPUT: tuple of basis elements in dimension n + OUTPUT: tuple of basis elements in dimension `n` The only possible difference in the implementations for `P^s_t` bases and commutator bases is that the former make sense, and @@ -1091,8 +1096,8 @@ def steenrod_basis_error_check(dim, p, **kwds): INPUT: - - ``dim`` - non-negative integer - - ``p`` - positive prime number + - ``dim`` -- non-negative integer + - ``p`` -- positive prime number OUTPUT: None @@ -1100,7 +1105,7 @@ def steenrod_basis_error_check(dim, p, **kwds): if the change-of-basis matrices are invertible. If something goes wrong, an error message is printed. - This function checks at the prime ``p`` as the dimension goes up + This function checks at the prime `p` as the dimension goes up from 0 to ``dim``. If you set the Sage verbosity level to a positive integer (using @@ -1110,10 +1115,10 @@ def steenrod_basis_error_check(dim, p, **kwds): sage: # long time sage: from sage.algebras.steenrod.steenrod_algebra_bases import steenrod_basis_error_check - sage: steenrod_basis_error_check(15,2) - sage: steenrod_basis_error_check(15,2,generic=True) - sage: steenrod_basis_error_check(40,3) - sage: steenrod_basis_error_check(80,5) + sage: steenrod_basis_error_check(15, 2) + sage: steenrod_basis_error_check(15, 2, generic=True) + sage: steenrod_basis_error_check(40, 3) + sage: steenrod_basis_error_check(80, 5) """ from sage.misc.verbose import verbose generic = kwds.get('generic', p != 2) From a20a928d7b9a12cfbfec424e2fa3cdaaa72c72ce Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 2 Sep 2023 22:42:26 -0700 Subject: [PATCH 137/538] sage.algebras: Docstring cosmetics, update # needs --- src/sage/algebras/down_up_algebra.py | 5 +- .../finite_dimensional_algebra.py | 2 +- .../finite_dimensional_algebra_element.pyx | 2 +- src/sage/algebras/finite_gca.py | 2 +- src/sage/algebras/free_algebra.py | 125 ++++++++++-------- src/sage/algebras/free_algebra_quotient.py | 2 +- src/sage/algebras/free_zinbiel_algebra.py | 26 ++-- .../hecke_algebras/ariki_koike_algebra.py | 2 + src/sage/algebras/iwahori_hecke_algebra.py | 28 ++-- src/sage/algebras/orlik_solomon.py | 66 ++++----- .../algebras/steenrod/steenrod_algebra.py | 69 +++++----- 11 files changed, 176 insertions(+), 153 deletions(-) diff --git a/src/sage/algebras/down_up_algebra.py b/src/sage/algebras/down_up_algebra.py index d5fe1c257eb..088e7ac30ad 100644 --- a/src/sage/algebras/down_up_algebra.py +++ b/src/sage/algebras/down_up_algebra.py @@ -540,12 +540,13 @@ class VermaModule(CombinatorialFreeModule): construction of the irreducible representation `V(5)` (but they are different as `\mathfrak{gl}_2` weights):: - sage: B = crystals.Tableaux(['A',1], shape=[5]) - sage: [b.weight() for b in B] + sage: B = crystals.Tableaux(['A',1], shape=[5]) # needs sage.graphs + sage: [b.weight() for b in B] # needs sage.graphs [(5, 0), (4, 1), (3, 2), (2, 3), (1, 4), (0, 5)] An example with periodic weights (see Theorem 2.13 of [BR1998]_):: + sage: # needs sage.rings.number_field sage: k. = CyclotomicField(6) sage: al = z6 + 1 sage: (al - 1)^6 == 1 diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 448c1916aed..a3b8742b4e0 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -210,7 +210,7 @@ def _coerce_map_from_(self, S): True sage: A.has_coerce_map_from(GF(3)) True - sage: A.has_coerce_map_from(GF(5)) # needs sage.rings.finite_rings + sage: A.has_coerce_map_from(GF(5)) False sage: A.has_coerce_map_from(QQ) False diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx index f953a9fab7c..d58e1ac8647 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx @@ -375,7 +375,7 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): True sage: A(2) == 3 False - sage: A(2) == GF(5)(2) # needs sage.rings.finite_rings + sage: A(2) == GF(5)(2) False sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0,0], [0,1,0], [0,0,0]]), diff --git a/src/sage/algebras/finite_gca.py b/src/sage/algebras/finite_gca.py index f2e7d9af301..08ebb27616e 100644 --- a/src/sage/algebras/finite_gca.py +++ b/src/sage/algebras/finite_gca.py @@ -127,7 +127,7 @@ class FiniteGCAlgebra(CombinatorialFreeModule, Algebra): omitted, an instance of the class :class:`sage.algebras.commutative_dga.GCAlgebra` is created instead:: - sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1,2,6,6)) + sage: A. = GradedCommutativeAlgebra(QQ, degrees=(1,2,6,6)) # needs sage.libs.singular sage: type(A) diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index d1a536a7043..61fc6175a8c 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -71,50 +71,54 @@ TESTS:: - sage: # needs sage.rings.finite_rings sage: F = FreeAlgebra(GF(5),3,'x') sage: TestSuite(F).run() sage: F is loads(dumps(F)) True - sage: F = FreeAlgebra(GF(5),3,'x', implementation='letterplace') # needs sage.libs.singular - sage: TestSuite(F).run() # needs sage.libs.singular - sage: F is loads(dumps(F)) # needs sage.libs.singular + + sage: # needs sage.libs.singular + sage: F = FreeAlgebra(GF(5),3,'x', implementation='letterplace') + sage: TestSuite(F).run() + sage: F is loads(dumps(F)) True :: - sage: # needs sage.rings.finite_rings sage: F. = FreeAlgebra(GF(5),3) sage: TestSuite(F).run() sage: F is loads(dumps(F)) True - sage: F. = FreeAlgebra(GF(5),3, implementation='letterplace') # needs sage.libs.singular - sage: TestSuite(F).run() # needs sage.libs.singular - sage: F is loads(dumps(F)) # needs sage.libs.singular + + sage: # needs sage.libs.singular + sage: F. = FreeAlgebra(GF(5),3, implementation='letterplace') + sage: TestSuite(F).run() + sage: F is loads(dumps(F)) True :: - sage: # needs sage.rings.finite_rings sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y']) sage: TestSuite(F).run() sage: F is loads(dumps(F)) True - sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'], implementation='letterplace') # needs sage.libs.singular - sage: TestSuite(F).run() # needs sage.libs.singular - sage: F is loads(dumps(F)) # needs sage.libs.singular + + sage: # needs sage.libs.singular + sage: F = FreeAlgebra(GF(5),3, ['xx', 'zba', 'Y'], implementation='letterplace') + sage: TestSuite(F).run() + sage: F is loads(dumps(F)) True :: - sage: # needs sage.rings.finite_rings sage: F = FreeAlgebra(GF(5),3, 'abc') sage: TestSuite(F).run() sage: F is loads(dumps(F)) True - sage: F = FreeAlgebra(GF(5),3, 'abc', implementation='letterplace') # needs sage.libs.singular - sage: TestSuite(F).run() # needs sage.libs.singular - sage: F is loads(dumps(F)) # needs sage.libs.singular + + sage: # needs sage.libs.singular + sage: F = FreeAlgebra(GF(5),3, 'abc', implementation='letterplace') + sage: TestSuite(F).run() + sage: F is loads(dumps(F)) True :: @@ -127,10 +131,11 @@ Note that the letterplace implementation can only be used if the corresponding (multivariate) polynomial ring has an implementation in Singular:: - sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace') # needs sage.libs.singular sage.rings.finite_rings + sage: FreeAlgebra(FreeAlgebra(ZZ,2,'ab'), 2, 'x', implementation='letterplace') # needs sage.libs.singular Traceback (most recent call last): ... - NotImplementedError: polynomials over Free Algebra on 2 generators (a, b) over Integer Ring are not supported in Singular + NotImplementedError: polynomials over Free Algebra on 2 generators (a, b) + over Integer Ring are not supported in Singular """ #***************************************************************************** @@ -174,18 +179,18 @@ class FreeAlgebraFactory(UniqueFactory): EXAMPLES:: - sage: FreeAlgebra(GF(5),3,'x') # needs sage.rings.finite_rings + sage: FreeAlgebra(GF(5),3,'x') Free Algebra on 3 generators (x0, x1, x2) over Finite Field of size 5 - sage: F. = FreeAlgebra(GF(5),3) # needs sage.rings.finite_rings - sage: (x+y+z)^2 # needs sage.rings.finite_rings + sage: F. = FreeAlgebra(GF(5),3) + sage: (x+y+z)^2 x^2 + x*y + x*z + y*x + y^2 + y*z + z*x + z*y + z^2 - sage: FreeAlgebra(GF(5),3, 'xx, zba, Y') # needs sage.rings.finite_rings + sage: FreeAlgebra(GF(5),3, 'xx, zba, Y') Free Algebra on 3 generators (xx, zba, Y) over Finite Field of size 5 - sage: FreeAlgebra(GF(5),3, 'abc') # needs sage.rings.finite_rings + sage: FreeAlgebra(GF(5),3, 'abc') Free Algebra on 3 generators (a, b, c) over Finite Field of size 5 - sage: FreeAlgebra(GF(5),1, 'z') # needs sage.rings.finite_rings + sage: FreeAlgebra(GF(5),1, 'z') Free Algebra on 1 generators (z,) over Finite Field of size 5 - sage: FreeAlgebra(GF(5),1, ['alpha']) # needs sage.rings.finite_rings + sage: FreeAlgebra(GF(5),1, ['alpha']) Free Algebra on 1 generators (alpha,) over Finite Field of size 5 sage: FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x') Free Algebra on 2 generators (x0, x1) over @@ -197,14 +202,14 @@ class FreeAlgebraFactory(UniqueFactory): sage: G = FreeAlgebra(ZZ,3,'x,y,z') sage: F is G True - sage: F. = FreeAlgebra(GF(5),3) # indirect doctest # needs sage.rings.finite_rings - sage: F is loads(dumps(F)) # needs sage.rings.finite_rings + sage: F. = FreeAlgebra(GF(5),3) # indirect doctest + sage: F is loads(dumps(F)) True - sage: F is FreeAlgebra(GF(5),['x','y','z']) # needs sage.rings.finite_rings + sage: F is FreeAlgebra(GF(5),['x','y','z']) True - sage: copy(F) is F is loads(dumps(F)) # needs sage.rings.finite_rings + sage: copy(F) is F is loads(dumps(F)) True - sage: TestSuite(F).run() # needs sage.rings.finite_rings + sage: TestSuite(F).run() By :trac:`7797`, we provide a different implementation of free algebras, based on Singular's "letterplace rings". Our letterplace @@ -213,7 +218,7 @@ class FreeAlgebraFactory(UniqueFactory): elements are supported. Of course, isomorphic algebras in different implementations are not identical:: - sage: # needs sage.libs.singular sage.rings.finite_rings + sage: # needs sage.libs.singular sage: G = FreeAlgebra(GF(5),['x','y','z'], implementation='letterplace') sage: F == G False @@ -225,7 +230,7 @@ class FreeAlgebraFactory(UniqueFactory): :: - sage: # needs sage.libs.singular sage.rings.finite_rings + sage: # needs sage.libs.singular sage: H = FreeAlgebra(GF(5), ['x','y','z'], implementation='letterplace', ....: degrees=[1,2,3]) sage: F != H != G @@ -263,23 +268,24 @@ def create_key(self, base_ring, arg1=None, arg2=None, TESTS:: - sage: # needs sage.rings.finite_rings sage: FreeAlgebra.create_key(GF(5),['x','y','z']) (Finite Field of size 5, ('x', 'y', 'z')) sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3) (Finite Field of size 5, ('x', 'y', 'z')) sage: FreeAlgebra.create_key(GF(5),3,'xyz') (Finite Field of size 5, ('x', 'y', 'z')) - sage: FreeAlgebra.create_key(GF(5),['x','y','z'], # needs sage.libs.singular + + sage: # needs sage.libs.singular + sage: FreeAlgebra.create_key(GF(5),['x','y','z'], ....: implementation='letterplace') (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) - sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, # needs sage.libs.singular + sage: FreeAlgebra.create_key(GF(5),['x','y','z'],3, ....: implementation='letterplace') (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) - sage: FreeAlgebra.create_key(GF(5),3,'xyz', # needs sage.libs.singular + sage: FreeAlgebra.create_key(GF(5),3,'xyz', ....: implementation='letterplace') (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5,) - sage: FreeAlgebra.create_key(GF(5),3,'xyz', # needs sage.libs.singular + sage: FreeAlgebra.create_key(GF(5),3,'xyz', ....: implementation='letterplace', degrees=[1,2,3]) ((1, 2, 3), Multivariate Polynomial Ring in x, y, z, x_ over Finite Field of size 5) @@ -370,7 +376,8 @@ def is_FreeAlgebra(x): True sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace')) True - sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace', degrees=list(range(1,11)))) + sage: is_FreeAlgebra(FreeAlgebra(ZZ,10,'x',implementation='letterplace', + ....: degrees=list(range(1,11)))) True """ @@ -562,23 +569,23 @@ def _element_constructor_(self, x): TESTS:: - sage: # needs sage.rings.finite_rings + sage: # needs sage.libs.singular sage: F. = FreeAlgebra(GF(5),3) - sage: L. = FreeAlgebra(ZZ,3,implementation='letterplace') # needs sage.libs.singular - sage: F(x) # indirect doctest # needs sage.libs.singular + sage: L. = FreeAlgebra(ZZ,3,implementation='letterplace') + sage: F(x) # indirect doctest x - sage: F.1*L.2 # needs sage.libs.singular + sage: F.1*L.2 y*z - sage: (F.1*L.2).parent() is F # needs sage.libs.singular + sage: (F.1*L.2).parent() is F True :: - sage: # needs sage.rings.finite_rings + sage: # needs sage.libs.singular sage.rings.finite_rings sage: K. = GF(25) sage: F. = FreeAlgebra(K,3) - sage: L. = FreeAlgebra(K,3, implementation='letterplace') # needs sage.libs.singular - sage: F.1+(z+1)*L.2 # needs sage.libs.singular + sage: L. = FreeAlgebra(K,3, implementation='letterplace') + sage: F.1 + (z+1)*L.2 b + (z+1)*c Check that :trac:`15169` is fixed:: @@ -688,23 +695,24 @@ def _coerce_map_from_(self, R): sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z')) False - sage: K. = GF(25) # needs sage.rings.finite_rings - sage: F. = FreeAlgebra(K,3) # needs sage.rings.finite_rings - sage: F._coerce_map_from_(ZZ) # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: K. = GF(25) + sage: F. = FreeAlgebra(K,3) + sage: F._coerce_map_from_(ZZ) True - sage: F._coerce_map_from_(QQ) # needs sage.rings.finite_rings + sage: F._coerce_map_from_(QQ) False - sage: F._coerce_map_from_(F.monoid()) # needs sage.rings.finite_rings + sage: F._coerce_map_from_(F.monoid()) True - sage: F._coerce_map_from_(F.pbw_basis()) # needs sage.rings.finite_rings + sage: F._coerce_map_from_(F.pbw_basis()) True sage: G = FreeAlgebra(ZZ, 3, 'a,b,c') - sage: F._coerce_map_from_(G) # needs sage.rings.finite_rings + sage: F._coerce_map_from_(G) True - sage: G._coerce_map_from_(F) # needs sage.rings.finite_rings + sage: G._coerce_map_from_(F) False - sage: L. = FreeAlgebra(K,3, implementation='letterplace') # needs sage.libs.singular sage.rings.finite_rings - sage: F.1 + (z+1) * L.2 # needs sage.libs.singular sage.rings.finite_rings + sage: L. = FreeAlgebra(K,3, implementation='letterplace') # needs sage.libs.singular + sage: F.1 + (z+1) * L.2 # needs sage.libs.singular b + (z+1)*c """ if self._indices.has_coerce_map_from(R): @@ -854,6 +862,7 @@ def g_algebra(self, relations, names=None, order='degrevlex', check=True): EXAMPLES:: + sage: # needs sage.libs.singular sage: A. = FreeAlgebra(QQ,3) sage: G = A.g_algebra({y*x: -x*y}) sage: (x,y,z) = G.gens() @@ -864,12 +873,12 @@ def g_algebra(self, relations, names=None, order='degrevlex', check=True): sage: z*x x*z sage: (x,y,z) = A.gens() - sage: G = A.g_algebra({y*x: -x*y+1}) + sage: G = A.g_algebra({y*x: -x*y + 1}) sage: (x,y,z) = G.gens() sage: y*x -x*y + 1 sage: (x,y,z) = A.gens() - sage: G = A.g_algebra({y*x: -x*y+z}) + sage: G = A.g_algebra({y*x: -x*y + z}) sage: (x,y,z) = G.gens() sage: y*x -x*y + z diff --git a/src/sage/algebras/free_algebra_quotient.py b/src/sage/algebras/free_algebra_quotient.py index b0f0efed0cd..e41e9c877c5 100644 --- a/src/sage/algebras/free_algebra_quotient.py +++ b/src/sage/algebras/free_algebra_quotient.py @@ -191,7 +191,7 @@ def _coerce_map_from_(self, S): True sage: H._coerce_map_from_(QQ) True - sage: H._coerce_map_from_(GF(7)) # needs sage.rings.finite_rings + sage: H._coerce_map_from_(GF(7)) False """ return S == self or self.__free_algebra.has_coerce_map_from(S) diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index cee797e37c4..d421b2d7aee 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -540,14 +540,14 @@ def _coerce_map_from_(self, R): EXAMPLES:: - sage: F = algebras.FreeZinbiel(GF(7), 'x,y,z'); F # needs sage.rings.finite_rings + sage: F = algebras.FreeZinbiel(GF(7), 'x,y,z'); F Free Zinbiel algebra on generators (Z[x], Z[y], Z[z]) over Finite Field of size 7 Elements of the free Zinbiel algebra canonically coerce in:: - sage: x, y, z = F.gens() # needs sage.rings.finite_rings - sage: F.coerce(x+y) == x+y # needs sage.rings.finite_rings + sage: x, y, z = F.gens() + sage: F.coerce(x+y) == x+y True The free Zinbiel algebra over `\ZZ` on `x, y, z` coerces in, since @@ -555,15 +555,15 @@ def _coerce_map_from_(self, R): sage: G = algebras.FreeZinbiel(ZZ, 'x,y,z') sage: Gx,Gy,Gz = G.gens() - sage: z = F.coerce(Gx+Gy); z # needs sage.rings.finite_rings + sage: z = F.coerce(Gx+Gy); z Z[x] + Z[y] - sage: z.parent() is F # needs sage.rings.finite_rings + sage: z.parent() is F True However, `\GF{7}` does not coerce to `\ZZ`, so the free Zinbiel algebra over `\GF{7}` does not coerce to the one over `\ZZ`:: - sage: G.coerce(y) # needs sage.rings.finite_rings + sage: G.coerce(y) Traceback (most recent call last): ... TypeError: no canonical coercion from Free Zinbiel algebra on @@ -642,18 +642,18 @@ class ZinbielFunctor(ConstructionFunctor): sage: F = P.construction()[0]; F Zinbiel[x,y] - sage: A = GF(5)['a,b'] # needs sage.rings.finite_rings - sage: a, b = A.gens() # needs sage.rings.finite_rings - sage: F(A) # needs sage.rings.finite_rings + sage: A = GF(5)['a,b'] + sage: a, b = A.gens() + sage: F(A) Free Zinbiel algebra on generators (Z[x], Z[y]) over Multivariate Polynomial Ring in a, b over Finite Field of size 5 - sage: f = A.hom([a+b,a-b],A) # needs sage.rings.finite_rings - sage: F(f) # needs sage.rings.finite_rings + sage: f = A.hom([a+b,a-b],A) + sage: F(f) Generic endomorphism of Free Zinbiel algebra on generators (Z[x], Z[y]) over Multivariate Polynomial Ring in a, b over Finite Field of size 5 - sage: F(f)(a * F(A)(x)) # needs sage.rings.finite_rings + sage: F(f)(a * F(A)(x)) (a+b)*Z[x] """ rank = 9 @@ -706,7 +706,7 @@ def _apply_functor_to_morphism(self, f): TESTS:: sage: R = algebras.FreeZinbiel(ZZ, 'x').construction()[0] - sage: R(ZZ.hom(GF(3))) # indirect doctest # needs sage.rings.finite_rings + sage: R(ZZ.hom(GF(3))) # indirect doctest Generic morphism: From: Free Zinbiel algebra on generators (Z[x],) over Integer Ring diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py index df2818d5dd5..f34beb5a1f8 100644 --- a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py +++ b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py @@ -234,6 +234,7 @@ class ArikiKoikeAlgebra(Parent, UniqueRepresentation): We construct an Ariki-Koike algebra with `u = (1, \zeta_3, \zeta_3^2)`, where `\zeta_3` is a primitive third root of unity:: + sage: # needs sage.rings.number_field sage: F = CyclotomicField(3) sage: zeta3 = F.gen() sage: R. = LaurentPolynomialRing(F) @@ -248,6 +249,7 @@ class ArikiKoikeAlgebra(Parent, UniqueRepresentation): Next, we additionally take `q = 1` to obtain the group algebra of `G(r, 1, n)`:: + sage: # needs sage.rings.number_field sage: F = CyclotomicField(3) sage: zeta3 = F.gen() sage: H = algebras.ArikiKoike(3, 4, q=1, u=[1, zeta3, zeta3^2], R=F) diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 5ff849c8786..a599c28a488 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -52,15 +52,15 @@ def normalized_laurent_polynomial(R, p): the base ring. This function is a hack to recover from this. This occurs somewhat haphazardly with Laurent polynomial rings:: - sage: R.=LaurentPolynomialRing(ZZ) + sage: R. = LaurentPolynomialRing(ZZ) sage: [type(c) for c in (q**-1).coefficients()] [] It also happens in any ring when dividing by units:: - sage: type ( 3/1 ) + sage: type(3/1) - sage: type ( -1/-1 ) + sage: type(-1/-1) This function is a variation on a suggested workaround of Nils Bruin. @@ -68,19 +68,19 @@ def normalized_laurent_polynomial(R, p): EXAMPLES:: sage: from sage.algebras.iwahori_hecke_algebra import normalized_laurent_polynomial - sage: type ( normalized_laurent_polynomial(ZZ, 3/1) ) + sage: type(normalized_laurent_polynomial(ZZ, 3/1)) - sage: R.=LaurentPolynomialRing(ZZ) + sage: R. = LaurentPolynomialRing(ZZ) sage: [type(c) for c in normalized_laurent_polynomial(R, q**-1).coefficients()] [] - sage: R.=LaurentPolynomialRing(ZZ,2) - sage: p=normalized_laurent_polynomial(R, 2*u**-1*v**-1+u*v) - sage: ui=normalized_laurent_polynomial(R, u^-1) - sage: vi=normalized_laurent_polynomial(R, v^-1) - sage: p(ui,vi) + sage: R. = LaurentPolynomialRing(ZZ,2) + sage: p = normalized_laurent_polynomial(R, 2*u**-1*v**-1 + u*v) + sage: ui = normalized_laurent_polynomial(R, u^-1) + sage: vi = normalized_laurent_polynomial(R, v^-1) + sage: p(ui, vi) 2*u*v + u^-1*v^-1 - sage: q= u+v+ui - sage: q(ui,vi) + sage: q = u+v+ui + sage: q(ui, vi) u + v^-1 + u^-1 """ try: @@ -208,8 +208,8 @@ class IwahoriHeckeAlgebra(Parent, UniqueRepresentation): The Kazhdan-Lusztig bases are implemented inside `H` whenever `-q_1 q_2` has a square root:: - sage: H = IwahoriHeckeAlgebra('A3', u^2,-v^2) - sage: T=H.T(); Cp= H.Cp(); C=H.C() + sage: H = IwahoriHeckeAlgebra('A3', u^2, -v^2) + sage: T = H.T(); Cp = H.Cp(); C = H.C() sage: T(Cp[1]) (u^-1*v^-1)*T[1] + (u^-1*v) sage: T(C[1]) diff --git a/src/sage/algebras/orlik_solomon.py b/src/sage/algebras/orlik_solomon.py index 2cb2dcb8299..7cb469f09cc 100644 --- a/src/sage/algebras/orlik_solomon.py +++ b/src/sage/algebras/orlik_solomon.py @@ -459,7 +459,7 @@ def as_gca(self): EXAMPLES:: - sage: # needs sage.geometry.polyhedron + sage: # needs sage.geometry.polyhedron sage.graphs sage: H = hyperplane_arrangements.braid(3) sage: O = H.orlik_solomon_algebra(QQ) sage: O.as_gca() @@ -470,7 +470,7 @@ def as_gca(self): sage: N = matroids.named_matroids.Fano() sage: O = N.orlik_solomon_algebra(QQ) - sage: O.as_gca() + sage: O.as_gca() # needs sage.libs.singular Graded Commutative Algebra with generators ('e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6') in degrees (1, 1, 1, 1, 1, 1, 1) with relations [e1*e2 - e1*e3 + e2*e3, e0*e1*e3 - e0*e1*e4 + e0*e3*e4 - e1*e3*e4, @@ -524,7 +524,7 @@ def as_cdga(self): EXAMPLES:: - sage: # needs sage.geometry.polyhedron + sage: # needs sage.geometry.polyhedron sage.graphs sage: H = hyperplane_arrangements.braid(3) sage: O = H.orlik_solomon_algebra(QQ) sage: O.as_cdga() @@ -605,20 +605,21 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): easier, we'll start the indexing at `1` so that the `S_6` action on the groundset is simply calling `g`:: - sage: M = matroids.CompleteGraphic(4); M.groundset() # needs sage.graphs + sage: # needs sage.graphs sage.groups + sage: M = matroids.CompleteGraphic(4); M.groundset() frozenset({0, 1, 2, 3, 4, 5}) - sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] # needs sage.graphs - sage: M = Matroid(bases=new_bases); M.groundset() # needs sage.graphs + sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] + sage: M = Matroid(bases=new_bases); M.groundset() frozenset({1, 2, 3, 4, 5, 6}) - sage: G = SymmetricGroup(6) # needs sage.groups - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) # needs sage.graphs sage.groups - sage: OSG.basis() # needs sage.graphs sage.groups + sage: G = SymmetricGroup(6) + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) + sage: OSG.basis() Finite family {0: B[0], 1: B[1]} - sage: [OSG.lift(b) for b in OSG.basis()] # needs sage.graphs sage.groups + sage: [OSG.lift(b) for b in OSG.basis()] [OS{}, OS{1} + OS{2} + OS{3} + OS{4} + OS{5} + OS{6}] - sage: (OSG.basis()[1])^2 # needs sage.graphs sage.groups + sage: (OSG.basis()[1])^2 0 - sage: 5 * OSG.basis()[1] # needs sage.graphs sage.groups + sage: 5 * OSG.basis()[1] 5*B[1] Next, we look at the same matroid but with an `S_3 \times S_3` action @@ -634,17 +635,18 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): We implement an `S_4` action on the vertices:: - sage: M = matroids.CompleteGraphic(4) # needs sage.graphs - sage: G = SymmetricGroup(4) # needs sage.groups - sage: edge_map = {i: M.groundset_to_edges([i])[0][:2] # needs sage.graphs + sage: # needs sage.graphs sage.groups + sage: M = matroids.CompleteGraphic(4) + sage: G = SymmetricGroup(4) + sage: edge_map = {i: M.groundset_to_edges([i])[0][:2] ....: for i in M.groundset()} - sage: inv_map = {v: k for k, v in edge_map.items()} # needs sage.graphs + sage: inv_map = {v: k for k, v in edge_map.items()} sage: def vert_action(g, x): ....: a, b = edge_map[x] ....: return inv_map[tuple(sorted([g(a+1)-1, g(b+1)-1]))] - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, vert_action)) # needs sage.graphs sage.groups - sage: B = OSG.basis() # needs sage.graphs sage.groups - sage: [OSG.lift(b) for b in B] # needs sage.graphs sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G, vert_action)) + sage: B = OSG.basis() + sage: [OSG.lift(b) for b in B] [OS{}, OS{0} + OS{1} + OS{2} + OS{3} + OS{4} + OS{5}] We use this to describe the Young subgroup `S_2 \times S_2` action:: @@ -684,12 +686,13 @@ def __init__(self, R, M, G, action_on_groundset=None, *args, **kwargs): EXAMPLES:: - sage: M = matroids.CompleteGraphic(4) # needs sage.graphs - sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] # needs sage.graphs - sage: M = Matroid(bases=new_bases) # needs sage.graphs - sage: G = SymmetricGroup(6) # needs sage.groups - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) # needs sage.graphs sage.groups - sage: TestSuite(OSG).run() # needs sage.graphs sage.groups + sage: # needs sage.graphs sage.groups + sage: M = matroids.CompleteGraphic(4) + sage: new_bases = [frozenset(i+1 for i in j) for j in M.bases()] + sage: M = Matroid(bases=new_bases) + sage: G = SymmetricGroup(6) + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=G) + sage: TestSuite(OSG).run() """ ordering = kwargs.pop('ordering', None) OS = OrlikSolomonAlgebra(R, M, ordering) @@ -772,17 +775,17 @@ def _basis_action(self, g, f): EXAMPLES:: - sage: # needs sage.graphs + sage: # needs sage.graphs sage.groups sage: M = matroids.CompleteGraphic(3) sage: M.groundset() frozenset({0, 1, 2}) - sage: G = SymmetricGroup(3) # needs sage.groups + sage: G = SymmetricGroup(3) sage: def on_groundset(g, x): ....: return g(x+1)-1 - sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G,on_groundset)) # needs sage.groups + sage: OSG = M.orlik_solomon_algebra(QQ, invariant=(G,on_groundset)) sage: act = lambda g: (OSG._basis_action(g,frozenset({0,1})), ....: OSG._basis_action(g,frozenset({0,2}))) - sage: [act(g) for g in G] # needs sage.groups + sage: [act(g) for g in G] [(OS{0, 1}, OS{0, 2}), (-OS{0, 2}, OS{0, 1} - OS{0, 2}), (-OS{0, 1} + OS{0, 2}, -OS{0, 1}), @@ -800,11 +803,10 @@ def _basis_action(self, g, f): sage: OS2 = M.orlik_solomon_algebra(QQ, range(2,-1,-1)) sage: OS2.subset_image(fset) OS{1, 2} - - sage: OSG2 = M.orlik_solomon_algebra(QQ, # needs sage.graphs sage.groups + sage: OSG2 = M.orlik_solomon_algebra(QQ, ....: invariant=(G,on_groundset), ....: ordering=range(2,-1,-1)) - sage: g = G.an_element(); g # needs sage.graphs sage.groups + sage: g = G.an_element(); g (2,3) This choice of ``g`` acting on this choice of ``fset`` reverses diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index ce764f0a258..993e94dc828 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -552,8 +552,8 @@ def __init__(self, p=2, basis='milnor', **kwds): sage: TestSuite(SteenrodAlgebra(profile=[4,3,2,2,1])).run() sage: TestSuite(SteenrodAlgebra(basis='adem')).run() sage: TestSuite(SteenrodAlgebra(basis='wall')).run() - sage: TestSuite(SteenrodAlgebra(basis='arnonc')).run() # long time - sage: TestSuite(SteenrodAlgebra(basis='woody')).run() # long time + sage: TestSuite(SteenrodAlgebra(basis='arnonc')).run() # long time + sage: TestSuite(SteenrodAlgebra(basis='woody')).run() # long time sage: A3 = SteenrodAlgebra(3) sage: A3.category() Category of supercocommutative super hopf algebras @@ -562,7 +562,7 @@ def __init__(self, p=2, basis='milnor', **kwds): sage: TestSuite(SteenrodAlgebra(basis='adem', p=3)).run() sage: TestSuite(SteenrodAlgebra(basis='pst_llex', p=7)).run() # long time sage: TestSuite(SteenrodAlgebra(basis='comm_deg', p=5)).run() # long time - sage: TestSuite(SteenrodAlgebra(p=2, generic=True)).run() # long time + sage: TestSuite(SteenrodAlgebra(p=2, generic=True)).run() # long time Two Steenrod algebras are equal iff their associated primes, bases, and profile functions (if present) are equal. Because @@ -753,8 +753,8 @@ def _repr_(self): mod 3 Steenrod algebra, milnor basis sage: SteenrodAlgebra(2, basis='adem') mod 2 Steenrod algebra, serre-cartan basis - sage: B = SteenrodAlgebra(2003) - sage: B._repr_() + sage: B = SteenrodAlgebra(2003) # needs sage.rings.finite_rings + sage: B._repr_() # needs sage.rings.finite_rings 'mod 2003 Steenrod algebra, milnor basis' sage: SteenrodAlgebra(generic=True, basis='adem') generic mod 2 Steenrod algebra, serre-cartan basis @@ -1393,14 +1393,14 @@ def coproduct(self, x, algorithm='milnor'): INPUT: - - ``x`` -- element of self + - ``x`` -- element of ``self`` - - ``algorithm`` -- ``None`` or a string, either 'milnor' or - 'serre-cartan' (or anything which will be converted to one + - ``algorithm`` -- ``None`` or a string, either ``'milnor'`` or + ``'serre-cartan'`` (or anything which will be converted to one of these by the function :func:`get_basis_name `. - If ``None``, default to 'serre-cartan' if current basis is - 'serre-cartan'; otherwise use 'milnor'. + If ``None``, default to ``'serre-cartan'`` if current basis is + ``'serre-cartan'``; otherwise use ``'milnor'``. This calls :meth:`coproduct_on_basis` on the summands of ``x`` and extends linearly. @@ -1440,12 +1440,12 @@ def antipode_on_basis(self, t): INPUT: - - ``t`` -- tuple, the index of a basis element of self + - ``t`` -- tuple, the index of a basis element of ``self`` OUTPUT: the antipode of the corresponding basis element, - as an element of self. + as an element of ``self``. ALGORITHM: according to a result of Milnor's, the antipode of `\text{Sq}(n)` is the sum of all of the Milnor basis elements @@ -1490,7 +1490,7 @@ def antipode_on_basis(self, t): TESTS:: sage: Milnor = SteenrodAlgebra() - sage: all(x.antipode().antipode() == x for x in Milnor.basis(11)) # long time + sage: all(x.antipode().antipode() == x for x in Milnor.basis(11)) # long time True sage: A5 = SteenrodAlgebra(p=5, basis='adem') sage: all(x.antipode().antipode() == x for x in A5.basis(25)) @@ -1531,7 +1531,7 @@ def counit_on_basis(self, t): INPUT: - - ``t`` -- tuple, the index of a basis element of self + - ``t`` -- tuple, the index of a basis element of ``self`` EXAMPLES:: @@ -2237,7 +2237,9 @@ def basis(self, d=None): This does not print in a very helpful way, unfortunately:: sage: A7.basis() - Lazy family (Term map from basis key family of mod 7 Steenrod algebra, milnor basis to mod 7 Steenrod algebra, milnor basis(i))_{i in basis key family of mod 7 Steenrod algebra, milnor basis} + Lazy family (Term map from basis key family of mod 7 Steenrod algebra, milnor basis + to mod 7 Steenrod algebra, milnor basis(i))_{i in basis key family + of mod 7 Steenrod algebra, milnor basis} sage: for (idx,a) in zip((1,..,9),A7.basis()): ....: print("{} {}".format(idx, a)) 1 1 @@ -2251,7 +2253,8 @@ def basis(self, d=None): 9 Q_0 P(2) sage: D = SteenrodAlgebra(p=3, profile=([1], [2,2])) sage: sorted(D.basis()) - [1, P(1), P(2), Q_0, Q_0 P(1), Q_0 P(2), Q_0 Q_1, Q_0 Q_1 P(1), Q_0 Q_1 P(2), Q_1, Q_1 P(1), Q_1 P(2)] + [1, P(1), P(2), Q_0, Q_0 P(1), Q_0 P(2), Q_0 Q_1, + Q_0 Q_1 P(1), Q_0 Q_1 P(2), Q_1, Q_1 P(1), Q_1 P(2)] """ from sage.sets.family import Family if d is None: @@ -2573,7 +2576,7 @@ def pst(self,s,t): def ngens(self): r""" - Number of generators of self. + Number of generators of ``self``. OUTPUT: number or Infinity @@ -2601,7 +2604,7 @@ def ngens(self): 3 sage: SteenrodAlgebra(profile=[3,2,1], basis='pst').ngens() 3 - sage: SteenrodAlgebra(p=3, profile=[[3,2,1], [2,2,2,2]]).ngens() # A(3) at p=3 + sage: SteenrodAlgebra(p=3, profile=[[3,2,1], [2,2,2,2]]).ngens() # A(3) at p=3 4 sage: SteenrodAlgebra(profile=[1,2,1,1]).ngens() 5 @@ -2647,7 +2650,8 @@ def gens(self): sage: A3 = SteenrodAlgebra(3, 'adem') sage: A3.gens() - Lazy family ((i))_{i in Non negative integers} + Lazy family ((i))_{i in Non negative integers} sage: A3.gens()[0] beta sage: A3.gens()[1] @@ -2666,7 +2670,9 @@ def gens(self): sage: SteenrodAlgebra(p=5, profile=[[2,1], [2,2,2]]).gens() Family (Q_0, P(1), P(5)) sage: SteenrodAlgebra(profile=lambda n: n).gens() - Lazy family ((i))_{i in Non negative integers} + Lazy family ((i))_{i in Non negative integers} You may also use ``algebra_generators`` instead of ``gens``:: @@ -2932,16 +2938,16 @@ def top_class(self): EXAMPLES:: - sage: SteenrodAlgebra(2,profile=(3,2,1)).top_class() + sage: SteenrodAlgebra(2, profile=(3,2,1)).top_class() Sq(7,3,1) - sage: SteenrodAlgebra(3,profile=((2,2,1),(1,2,2,2,2))).top_class() + sage: SteenrodAlgebra(3, profile=((2,2,1),(1,2,2,2,2))).top_class() Q_1 Q_2 Q_3 Q_4 P(8,8,2) TESTS:: - sage: SteenrodAlgebra(2,profile=(3,2,1),basis='pst').top_class() + sage: SteenrodAlgebra(2, profile=(3,2,1), basis='pst').top_class() P^0_1 P^0_2 P^1_1 P^0_3 P^1_2 P^2_1 - sage: SteenrodAlgebra(5,profile=((0,),(2,1,2,2))).top_class() + sage: SteenrodAlgebra(5, profile=((0,),(2,1,2,2))).top_class() Q_0 Q_2 Q_3 sage: SteenrodAlgebra(5).top_class() Traceback (most recent call last): @@ -2953,12 +2959,12 @@ def top_class(self): but far from optimal for the 'pst' basis. Occasionally, it also gives an awkward leading coefficient:: - sage: SteenrodAlgebra(3,profile=((2,1),(1,2,2)),basis='pst').top_class() + sage: SteenrodAlgebra(3, profile=((2,1),(1,2,2)), basis='pst').top_class() 2 Q_1 Q_2 (P^0_1)^2 (P^0_2)^2 (P^1_1)^2 TESTS:: - sage: A=SteenrodAlgebra(2,profile=(3,2,1),basis='pst') + sage: A=SteenrodAlgebra(2, profile=(3,2,1), basis='pst') sage: A.top_class().parent() is A True """ @@ -3080,7 +3086,7 @@ def is_generic(self): True sage: SteenrodAlgebra(2).is_generic() False - sage: SteenrodAlgebra(2,generic=True).is_generic() + sage: SteenrodAlgebra(2, generic=True).is_generic() True """ return self._generic @@ -4146,7 +4152,8 @@ def SteenrodAlgebra(p=2, basis='milnor', generic='auto', **kwds): sage: EA = SteenrodAlgebra(p=2,generic=True) ; EA generic mod 2 Steenrod algebra, milnor basis sage: EA[8] - Vector space spanned by (Q_0 Q_2, Q_0 Q_1 P(2), P(1,1), P(4)) over Finite Field of size 2 + Vector space spanned by (Q_0 Q_2, Q_0 Q_1 P(2), P(1,1), P(4)) + over Finite Field of size 2 TESTS: @@ -4201,9 +4208,11 @@ def AA(n=None, p=2): sage: A() mod 2 Steenrod algebra, milnor basis sage: A(2) - sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1] + sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, + profile function [3, 2, 1] sage: A(2, p=5) - sub-Hopf algebra of mod 5 Steenrod algebra, milnor basis, profile function ([2, 1], [2, 2, 2]) + sub-Hopf algebra of mod 5 Steenrod algebra, milnor basis, + profile function ([2, 1], [2, 2, 2]) """ if n is None: return SteenrodAlgebra(p=p) From 8f795cc2cc97053fb5578e70920d6304176bc570 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Sep 2023 14:51:43 -0700 Subject: [PATCH 138/538] src/sage/algebras/lie_algebras/lie_algebra_element.pyx: # needs --- src/sage/algebras/lie_algebras/lie_algebra_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index ed9680a0af5..f221fe6ab55 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# sage.doctest: needs sage.combinat """ Lie Algebra Elements From 0b39a2b72da015f0b49b0c59c7d6c75582587736 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 3 Jun 2023 16:59:56 -0700 Subject: [PATCH 139/538] sage.combinat: Modularization fixes --- src/sage/combinat/species/generating_series.py | 7 ++++--- src/sage/combinat/species/misc.py | 12 +++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index e7f7c8ee978..3d7e7e81341 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -53,11 +53,12 @@ from sage.rings.lazy_series_ring import LazyPowerSeriesRing, LazySymmetricFunctions from sage.rings.integer import Integer from sage.rings.rational_field import QQ -from sage.arith.misc import divisors +from sage.arith.misc import divisors, factorial from sage.combinat.partition import Partition, Partitions -from sage.combinat.sf.sf import SymmetricFunctions from sage.misc.cachefunc import cached_function -from sage.arith.misc import factorial +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.combinat.sf.sf', 'SymmetricFunctions') class OrdinaryGeneratingSeries(LazyPowerSeries): diff --git a/src/sage/combinat/species/misc.py b/src/sage/combinat/species/misc.py index a516beb56ae..12a9b2c8f70 100644 --- a/src/sage/combinat/species/misc.py +++ b/src/sage/combinat/species/misc.py @@ -17,13 +17,15 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.groups.perm_gps.permgroup import PermutationGroup -from sage.groups.perm_gps.permgroup import PermutationGroup_generic -from sage.groups.perm_gps.constructor import PermutationGroupElement -from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.misc.misc_c import prod from functools import wraps +from sage.misc.misc_c import prod +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.groups.perm_gps.permgroup', ['PermutationGroup', 'PermutationGroup_generic']) +lazy_import('sage.groups.perm_gps.constructor', 'PermutationGroupElement') +lazy_import('sage.groups.perm_gps.permgroup_named', 'SymmetricGroup') + def change_support(perm, support, change_perm=None): """ From c934842512612d049daf34902e30e4da365515fb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 8 Jun 2023 18:33:43 -0700 Subject: [PATCH 140/538] sage.combinat: More # optional --- .../combinat/species/generating_series.py | 56 +++++++++---------- src/sage/combinat/species/library.py | 12 ++-- .../combinat/species/recursive_species.py | 12 ++-- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index 3d7e7e81341..88358916946 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -17,7 +17,7 @@ sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() # optional - sage.modules - sage: CIS = CycleIndexSeriesRing(QQ) + sage: CIS = CycleIndexSeriesRing(QQ) # optional - sage.modules sage: geo1 = CIS(lambda i: p([1])^i) # optional - sage.modules sage: geo2 = CIS(lambda i: p([2])^(i // 2) if is_even(i) else 0) # optional - sage.modules sage: s = geo1 * geo2 # optional - sage.modules @@ -294,7 +294,7 @@ def count(self, t): sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() # optional - sage.modules - sage: CIS = CycleIndexSeriesRing(QQ) + sage: CIS = CycleIndexSeriesRing(QQ) # optional - sage.modules sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])]) # optional - sage.modules sage: f.count([1]) # optional - sage.modules 1 @@ -314,7 +314,7 @@ def coefficient_cycle_type(self, t): sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() # optional - sage.modules - sage: CIS = CycleIndexSeriesRing(QQ) + sage: CIS = CycleIndexSeriesRing(QQ) # optional - sage.modules sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])]) # optional - sage.modules sage: f.coefficient_cycle_type([1]) # optional - sage.modules 1 @@ -334,9 +334,9 @@ def isotype_generating_series(self): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: cis = P.cycle_index_series() - sage: f = cis.isotype_generating_series() - sage: f[:10] + sage: cis = P.cycle_index_series() # optional - sage.modules + sage: f = cis.isotype_generating_series() # optional - sage.modules + sage: f[:10] # optional - sage.modules [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ R = self.base_ring() @@ -352,8 +352,8 @@ def _ogs_gen(self, n, ao): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: cis = P.cycle_index_series() - sage: [cis._ogs_gen(i, 0) for i in range(10)] + sage: cis = P.cycle_index_series() # optional - sage.modules + sage: [cis._ogs_gen(i, 0) for i in range(10)] # optional - sage.modules [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ if n < ao: @@ -367,9 +367,9 @@ def generating_series(self): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: cis = P.cycle_index_series() - sage: f = cis.generating_series() - sage: f[:5] + sage: cis = P.cycle_index_series() # optional - sage.modules + sage: f = cis.generating_series() # optional - sage.modules + sage: f[:5] # optional - sage.modules [1, 1, 1, 5/6, 5/8] """ R = self.base_ring() @@ -385,8 +385,8 @@ def _egs_gen(self, n, ao): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: cis = P.cycle_index_series() - sage: [cis._egs_gen(i, 0) for i in range(10)] + sage: cis = P.cycle_index_series() # optional - sage.modules + sage: [cis._egs_gen(i, 0) for i in range(10)] # optional - sage.modules [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] """ if n < ao: @@ -409,16 +409,16 @@ def derivative(self, n=1): The species `E` of sets satisfies the relationship `E' = E`:: - sage: E = species.SetSpecies().cycle_index_series() - sage: E[:8] == E.derivative()[:8] + sage: E = species.SetSpecies().cycle_index_series() # optional - sage.modules + sage: E[:8] == E.derivative()[:8] # optional - sage.modules True The species `C` of cyclic orderings and the species `L` of linear orderings satisfy the relationship `C' = L`:: - sage: C = species.CycleSpecies().cycle_index_series() - sage: L = species.LinearOrderSpecies().cycle_index_series() - sage: L[:8] == C.derivative()[:8] + sage: C = species.CycleSpecies().cycle_index_series() # optional - sage.modules + sage: L = species.LinearOrderSpecies().cycle_index_series() # optional - sage.modules + sage: L[:8] == C.derivative()[:8] # optional - sage.modules True """ return self.derivative_with_respect_to_p1(n=n) @@ -439,9 +439,9 @@ def pointing(self): The species `E^{\bullet}` of "pointed sets" satisfies `E^{\bullet} = X \cdot E`:: - sage: E = species.SetSpecies().cycle_index_series() - sage: X = species.SingletonSpecies().cycle_index_series() - sage: E.pointing()[:8] == (X*E)[:8] + sage: E = species.SetSpecies().cycle_index_series() # optional - sage.modules + sage: X = species.SingletonSpecies().cycle_index_series() # optional - sage.modules + sage: E.pointing()[:8] == (X*E)[:8] # optional - sage.modules True """ X = self.parent()([1], valuation=1) @@ -463,9 +463,9 @@ def exponential(self): Let `BT` be the species of binary trees, `BF` the species of binary forests, and `E` the species of sets. Then we have `BF = E \circ BT`:: - sage: BT = species.BinaryTreeSpecies().cycle_index_series() - sage: BF = species.BinaryForestSpecies().cycle_index_series() - sage: BT.exponential().isotype_generating_series()[:8] == BF.isotype_generating_series()[:8] + sage: BT = species.BinaryTreeSpecies().cycle_index_series() # optional - sage.modules + sage: BF = species.BinaryForestSpecies().cycle_index_series() # optional - sage.modules + sage: BT.exponential().isotype_generating_series()[:8] == BF.isotype_generating_series()[:8] # optional - sage.modules True """ base_ring = self.parent().base_ring().base_ring() @@ -490,10 +490,10 @@ def logarithm(self): Let `G` be the species of nonempty graphs and `CG` be the species of nonempty connected graphs. Then `G = E^{+} \circ CG`, so `CG = \Omega \circ G`:: - sage: G = species.SimpleGraphSpecies().cycle_index_series() - 1 + sage: G = species.SimpleGraphSpecies().cycle_index_series() - 1 # optional - sage.modules sage: from sage.combinat.species.generating_series import LogarithmCycleIndexSeries - sage: CG = LogarithmCycleIndexSeries()(G) - sage: CG.isotype_generating_series()[0:8] + sage: CG = LogarithmCycleIndexSeries()(G) # optional - sage.modules + sage: CG.isotype_generating_series()[0:8] # optional - sage.modules [0, 1, 1, 2, 6, 21, 112, 853] """ base_ring = self.parent().base_ring().base_ring() @@ -546,7 +546,7 @@ class CycleIndexSeriesRing(LazySymmetricFunctions): We test to make sure that caching works:: - sage: R is CycleIndexSeriesRing(QQ) + sage: R is CycleIndexSeriesRing(QQ) # optional - sage.modules True """ Element = CycleIndexSeries diff --git a/src/sage/combinat/species/library.py b/src/sage/combinat/species/library.py index d4235273a9f..e9f7cf0c734 100644 --- a/src/sage/combinat/species/library.py +++ b/src/sage/combinat/species/library.py @@ -43,7 +43,7 @@ def SimpleGraphSpecies(): sage: S = species.SimpleGraphSpecies() sage: S.generating_series().counts(10) [1, 1, 2, 8, 64, 1024, 32768, 2097152, 268435456, 68719476736] - sage: S.cycle_index_series()[:5] + sage: S.cycle_index_series()[:5] # optional - sage.modules [p[], p[1], p[1, 1] + p[2], @@ -94,7 +94,7 @@ def BinaryTreeSpecies(): sage: B = species.BinaryTreeSpecies() sage: a = B.structures([1,2,3,4,5])[187]; a 2*((5*3)*(4*1)) - sage: a.automorphism_group() + sage: a.automorphism_group() # optional - sage.groups Permutation Group with generators [()] TESTS:: @@ -121,9 +121,9 @@ def BinaryForestSpecies(): sage: F = species.BinaryForestSpecies() sage: F.generating_series().counts(10) [1, 1, 3, 19, 193, 2721, 49171, 1084483, 28245729, 848456353] - sage: F.isotype_generating_series().counts(10) + sage: F.isotype_generating_series().counts(10) # optional - sage.modules [1, 1, 2, 4, 10, 26, 77, 235, 758, 2504] - sage: F.cycle_index_series()[:7] + sage: F.cycle_index_series()[:7] # optional - sage.modules [p[], p[1], 3/2*p[1, 1] + 1/2*p[2], @@ -134,8 +134,8 @@ def BinaryForestSpecies(): TESTS:: - sage: seq = F.isotype_generating_series().counts(10)[1:] - sage: oeis(seq)[0] # optional -- internet + sage: seq = F.isotype_generating_series().counts(10)[1:] # optional - sage.modules + sage: oeis(seq)[0] # optional -- internet # optional - sage.modules A052854: Number of forests of ordered trees on n total nodes. """ B = BinaryTreeSpecies() diff --git a/src/sage/combinat/species/recursive_species.py b/src/sage/combinat/species/recursive_species.py index 3cd073f9f9c..a87bb27866b 100644 --- a/src/sage/combinat/species/recursive_species.py +++ b/src/sage/combinat/species/recursive_species.py @@ -263,7 +263,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: F = CombinatorialSpecies() - sage: F.cycle_index_series() + sage: F.cycle_index_series() # optional - sage.modules Uninitialized Lazy Series """ if base_ring not in self._cycle_index_series: @@ -429,17 +429,17 @@ def _add_to_digraph(self, d): EXAMPLES:: - sage: d = DiGraph(multiedges=True) + sage: d = DiGraph(multiedges=True) # optional - sage.graphs sage: X = species.SingletonSpecies() sage: B = species.CombinatorialSpecies() sage: B.define(X+B*B) - sage: B._add_to_digraph(d); d + sage: B._add_to_digraph(d); d # optional - sage.graphs Multi-digraph on 4 vertices TESTS:: sage: C = species.CombinatorialSpecies() - sage: C._add_to_digraph(d) + sage: C._add_to_digraph(d) # optional - sage.graphs Traceback (most recent call last): ... NotImplementedError @@ -461,7 +461,7 @@ def _equation(self, var_mapping): EXAMPLES:: sage: C = species.CombinatorialSpecies() - sage: C.algebraic_equation_system() + sage: C.algebraic_equation_system() # optional - sage.graphs Traceback (most recent call last): ... NotImplementedError @@ -469,7 +469,7 @@ def _equation(self, var_mapping): :: sage: B = species.BinaryTreeSpecies() - sage: B.algebraic_equation_system() + sage: B.algebraic_equation_system() # optional - sage.graphs [-node3^2 + node1, -node1 + node3 + (-z)] """ try: From 36ee07472a1a2246e77f4d3b71b54280ca74dc00 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 9 Jun 2023 00:55:41 -0700 Subject: [PATCH 141/538] More # optional --- .../combinat/species/generating_series.py | 4 +- src/sage/combinat/species/library.py | 10 ++-- .../combinat/species/permutation_species.py | 6 +-- src/sage/combinat/species/product_species.py | 30 ++++++------ src/sage/combinat/species/set_species.py | 10 ++-- src/sage/combinat/species/species.py | 48 ++++++++++--------- src/sage/combinat/species/subset_species.py | 14 +++--- src/sage/combinat/species/sum_species.py | 4 +- 8 files changed, 65 insertions(+), 61 deletions(-) diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index 88358916946..24830b17bcd 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -669,8 +669,8 @@ def LogarithmCycleIndexSeries(R=QQ): (that is, that composition with `E^{+}` in both directions yields the multiplicative identity `X`):: - sage: Eplus = sage.combinat.species.set_species.SetSpecies(min=1).cycle_index_series() - sage: LogarithmCycleIndexSeries()(Eplus)[0:4] # optional - sage.modules + sage: Eplus = sage.combinat.species.set_species.SetSpecies(min=1).cycle_index_series() # optional - sage.modules + sage: LogarithmCycleIndexSeries()(Eplus)[0:4] # optional - sage.modules [0, p[1], 0, 0] """ CIS = CycleIndexSeriesRing(R) diff --git a/src/sage/combinat/species/library.py b/src/sage/combinat/species/library.py index e9f7cf0c734..3e3025d87f6 100644 --- a/src/sage/combinat/species/library.py +++ b/src/sage/combinat/species/library.py @@ -49,19 +49,19 @@ def SimpleGraphSpecies(): p[1, 1] + p[2], 4/3*p[1, 1, 1] + 2*p[2, 1] + 2/3*p[3], 8/3*p[1, 1, 1, 1] + 4*p[2, 1, 1] + 2*p[2, 2] + 4/3*p[3, 1] + p[4]] - sage: S.isotype_generating_series()[:6] + sage: S.isotype_generating_series()[:6] # optional - sage.modules [1, 1, 2, 4, 11, 34] TESTS:: - sage: seq = S.isotype_generating_series().counts(6)[1:] - sage: oeis(seq)[0] # optional -- internet + sage: seq = S.isotype_generating_series().counts(6)[1:] # optional - sage.modules + sage: oeis(seq)[0] # optional -- internet # optional - sage.modules A000088: Number of graphs on n unlabeled nodes. :: - sage: seq = S.generating_series().counts(10)[1:] - sage: oeis(seq)[0] # optional -- internet + sage: seq = S.generating_series().counts(10)[1:] # optional - sage.modules + sage: oeis(seq)[0] # optional -- internet # optional - sage.modules A006125: a(n) = 2^(n*(n-1)/2). """ E = SetSpecies() diff --git a/src/sage/combinat/species/permutation_species.py b/src/sage/combinat/species/permutation_species.py index 64534c9e8bb..470a766a2c4 100644 --- a/src/sage/combinat/species/permutation_species.py +++ b/src/sage/combinat/species/permutation_species.py @@ -225,8 +225,8 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: g = P.cycle_index_series() - sage: g[0:5] + sage: g = P.cycle_index_series() # optional - sage.modules + sage: g[0:5] # optional - sage.modules [p[], p[1], p[1, 1] + p[2], @@ -244,7 +244,7 @@ def _cis_gen(self, base_ring, m, n): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: [P._cis_gen(QQ, 2, i) for i in range(10)] + sage: [P._cis_gen(QQ, 2, i) for i in range(10)] # optional - sage.modules [p[], 0, p[2], 0, p[2, 2], 0, p[2, 2, 2], 0, p[2, 2, 2, 2], 0] """ from sage.combinat.sf.sf import SymmetricFunctions diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index 0989d2a8f8c..a3bcb3f4bb4 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -58,12 +58,12 @@ def transport(self, perm): """ EXAMPLES:: - sage: p = PermutationGroupElement((2,3)) - sage: S = species.SetSpecies() - sage: F = S * S - sage: a = F.structures(['a','b','c'])[4]; a + sage: p = PermutationGroupElement((2,3)) # optional - sage.groups + sage: S = species.SetSpecies() # optional - sage.groups + sage: F = S * S # optional - sage.groups + sage: a = F.structures(['a','b','c'])[4]; a # optional - sage.groups {'a', 'b'}*{'c'} - sage: a.transport(p) + sage: a.transport(p) # optional - sage.groups {'a', 'c'}*{'b'} """ left, right = self._list @@ -151,17 +151,17 @@ def automorphism_group(self): """ EXAMPLES:: - sage: p = PermutationGroupElement((2,3)) - sage: S = species.SetSpecies() - sage: F = S * S - sage: a = F.structures([1,2,3,4])[1]; a + sage: p = PermutationGroupElement((2,3)) # optional - sage.groups + sage: S = species.SetSpecies() # optional - sage.groups + sage: F = S * S # optional - sage.groups + sage: a = F.structures([1,2,3,4])[1]; a # optional - sage.groups {1}*{2, 3, 4} - sage: a.automorphism_group() + sage: a.automorphism_group() # optional - sage.groups Permutation Group with generators [(2,3), (2,3,4)] :: - sage: [a.transport(g) for g in a.automorphism_group()] + sage: [a.transport(g) for g in a.automorphism_group()] # optional - sage.groups [{1}*{2, 3, 4}, {1}*{2, 3, 4}, {1}*{2, 3, 4}, @@ -171,9 +171,9 @@ def automorphism_group(self): :: - sage: a = F.structures([1,2,3,4])[8]; a + sage: a = F.structures([1,2,3,4])[8]; a # optional - sage.groups {2, 3}*{1, 4} - sage: [a.transport(g) for g in a.automorphism_group()] + sage: [a.transport(g) for g in a.automorphism_group()] # optional - sage.groups [{2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}] """ from sage.groups.perm_gps.constructor import PermutationGroupElement @@ -355,7 +355,7 @@ def _cis(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P * P - sage: F.cycle_index_series()[0:5] + sage: F.cycle_index_series()[0:5] # optional - sage.modules [p[], 2*p[1], 3*p[1, 1] + 2*p[2], @@ -409,7 +409,7 @@ def _equation(self, var_mapping): sage: X = species.SingletonSpecies() sage: S = X * X - sage: S.algebraic_equation_system() + sage: S.algebraic_equation_system() # optional - sage.graphs [node0 + (-z^2)] """ from sage.misc.misc_c import prod diff --git a/src/sage/combinat/species/set_species.py b/src/sage/combinat/species/set_species.py index daa7d7e5835..31020f8eb5e 100644 --- a/src/sage/combinat/species/set_species.py +++ b/src/sage/combinat/species/set_species.py @@ -57,8 +57,8 @@ def transport(self, perm): sage: F = species.SetSpecies() sage: a = F.structures(["a", "b", "c"]).random_element(); a {'a', 'b', 'c'} - sage: p = PermutationGroupElement((1,2)) - sage: a.transport(p) + sage: p = PermutationGroupElement((1,2)) # optional - sage.groups + sage: a.transport(p) # optional - sage.groups {'a', 'b', 'c'} """ return self @@ -74,7 +74,7 @@ def automorphism_group(self): sage: F = species.SetSpecies() sage: a = F.structures(["a", "b", "c"]).random_element(); a {'a', 'b', 'c'} - sage: a.automorphism_group() + sage: a.automorphism_group() # optional - sage.groups Symmetric group of order 3! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -170,8 +170,8 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: S = species.SetSpecies() - sage: g = S.cycle_index_series() - sage: g[0:5] + sage: g = S.cycle_index_series() # optional - sage.modules + sage: g[0:5] # optional - sage.modules [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], diff --git a/src/sage/combinat/species/species.py b/src/sage/combinat/species/species.py index 4cd3403ae61..9c3365f81b7 100644 --- a/src/sage/combinat/species/species.py +++ b/src/sage/combinat/species/species.py @@ -24,12 +24,12 @@ sage: L = species.LinearOrderSpecies(min=1) sage: T = species.CombinatorialSpecies(min=1) sage: T.define(leaf + internal_node*L(T)) - sage: T.isotype_generating_series()[0:6] + sage: T.isotype_generating_series()[0:6] # optional - sage.modules [0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q] Consider the following:: - sage: T.isotype_generating_series().coefficient(4) + sage: T.isotype_generating_series().coefficient(4) # optional - sage.modules q^3 + 3*q^2 + q This means that, among the trees on `4` nodes, one has a @@ -335,7 +335,7 @@ def functorial_composition(self, g): sage: WP = species.SubsetSpecies() sage: P2 = E2*E sage: G = WP.functorial_composition(P2) - sage: G.isotype_generating_series()[0:5] + sage: G.isotype_generating_series()[0:5] # optional - sage.modules [1, 1, 2, 4, 11] """ from .functorial_composition_species import FunctorialCompositionSpecies @@ -448,7 +448,7 @@ def __pow__(self, n): sage: X^1 is X True sage: A = X^32 - sage: A.digraph() + sage: A.digraph() # optional - sage.graphs Multi-digraph on 6 vertices TESTS:: @@ -643,8 +643,8 @@ def cycle_index_series(self, base_ring=None): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: g = P.cycle_index_series() - sage: g[0:4] + sage: g = P.cycle_index_series() # optional - sage.modules + sage: g[0:4] # optional - sage.modules [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3]] """ return self._get_series(CycleIndexSeriesRing, "cis", base_ring) @@ -710,19 +710,19 @@ def digraph(self): sage: X = species.SingletonSpecies() sage: B = species.CombinatorialSpecies() sage: B.define(X+B*B) - sage: g = B.digraph(); g + sage: g = B.digraph(); g # optional - sage.graphs Multi-digraph on 4 vertices - sage: sorted(g, key=str) + sage: sorted(g, key=str) # optional - sage.graphs [Combinatorial species, Product of (Combinatorial species) and (Combinatorial species), Singleton species, Sum of (Singleton species) and (Product of (Combinatorial species) and (Combinatorial species))] - sage: d = {sp: i for i, sp in enumerate(g)} - sage: g.relabel(d) - sage: g.canonical_label().edges(sort=True) + sage: d = {sp: i for i, sp in enumerate(g)} # optional - sage.graphs + sage: g.relabel(d) # optional - sage.graphs + sage: g.canonical_label().edges(sort=True) # optional - sage.graphs [(0, 3, None), (2, 0, None), (2, 0, None), (3, 1, None), (3, 2, None)] """ from sage.graphs.digraph import DiGraph @@ -739,13 +739,13 @@ def _add_to_digraph(self, d): EXAMPLES:: - sage: d = DiGraph(multiedges=True) - sage: X = species.SingletonSpecies() - sage: X._add_to_digraph(d); d + sage: d = DiGraph(multiedges=True) # optional - sage.graphs + sage: X = species.SingletonSpecies() # optional - sage.graphs + sage: X._add_to_digraph(d); d # optional - sage.graphs Multi-digraph on 1 vertex - sage: (X+X)._add_to_digraph(d); d + sage: (X+X)._add_to_digraph(d); d # optional - sage.graphs Multi-digraph on 2 vertices - sage: d.edges(sort=True) + sage: d.edges(sort=True) # optional - sage.graphs [(Sum of (Singleton species) and (Singleton species), Singleton species, None), (Sum of (Singleton species) and (Singleton species), Singleton species, None)] """ @@ -770,21 +770,25 @@ def algebraic_equation_system(self): EXAMPLES:: sage: B = species.BinaryTreeSpecies() - sage: B.algebraic_equation_system() + sage: B.algebraic_equation_system() # optional - sage.graphs [-node3^2 + node1, -node1 + node3 + (-z)] :: - sage: sorted(B.digraph().vertex_iterator(), key=str) + sage: sorted(B.digraph().vertex_iterator(), key=str) # optional - sage.graphs [Combinatorial species with min=1, - Product of (Combinatorial species with min=1) and (Combinatorial species with min=1), + Product of (Combinatorial species with min=1) + and (Combinatorial species with min=1), Singleton species, - Sum of (Singleton species) and (Product of (Combinatorial species with min=1) and (Combinatorial species with min=1))] + Sum of (Singleton species) + and (Product of (Combinatorial species with min=1) + and (Combinatorial species with min=1))] :: - sage: B.algebraic_equation_system()[0].parent() - Multivariate Polynomial Ring in node0, node1, node2, node3 over Fraction Field of Univariate Polynomial Ring in z over Rational Field + sage: B.algebraic_equation_system()[0].parent() # optional - sage.graphs + Multivariate Polynomial Ring in node0, node1, node2, node3 over + Fraction Field of Univariate Polynomial Ring in z over Rational Field """ d = self.digraph() diff --git a/src/sage/combinat/species/subset_species.py b/src/sage/combinat/species/subset_species.py index 81156e5183d..2d3b9f8dcb6 100644 --- a/src/sage/combinat/species/subset_species.py +++ b/src/sage/combinat/species/subset_species.py @@ -74,11 +74,11 @@ def transport(self, perm): sage: F = species.SubsetSpecies() sage: a = F.structures(["a", "b", "c"])[5]; a {'a', 'c'} - sage: p = PermutationGroupElement((1,2)) - sage: a.transport(p) + sage: p = PermutationGroupElement((1,2)) # optional - sage.groups + sage: a.transport(p) # optional - sage.groups {'b', 'c'} - sage: p = PermutationGroupElement((1,3)) - sage: a.transport(p) + sage: p = PermutationGroupElement((1,3)) # optional - sage.groups + sage: a.transport(p) # optional - sage.groups {'a', 'c'} """ l = sorted([perm(i) for i in self._list]) @@ -94,12 +94,12 @@ def automorphism_group(self): sage: F = species.SubsetSpecies() sage: a = F.structures([1,2,3,4])[6]; a {1, 3} - sage: a.automorphism_group() + sage: a.automorphism_group() # optional - sage.groups Permutation Group with generators [(2,4), (1,3)] :: - sage: [a.transport(g) for g in a.automorphism_group()] + sage: [a.transport(g) for g in a.automorphism_group()] # optional - sage.groups [{1, 3}, {1, 3}, {1, 3}, {1, 3}] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -224,7 +224,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: S = species.SubsetSpecies() - sage: S.cycle_index_series()[0:5] + sage: S.cycle_index_series()[0:5] # optional - sage.modules [p[], 2*p[1], 2*p[1, 1] + p[2], diff --git a/src/sage/combinat/species/sum_species.py b/src/sage/combinat/species/sum_species.py index fe45a352943..ae877a64314 100644 --- a/src/sage/combinat/species/sum_species.py +++ b/src/sage/combinat/species/sum_species.py @@ -171,7 +171,7 @@ def _cis(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F.cycle_index_series()[:5] + sage: F.cycle_index_series()[:5] # optional - sage.modules [2*p[], 2*p[1], 2*p[1, 1] + 2*p[2], @@ -214,7 +214,7 @@ def _equation(self, var_mapping): sage: X = species.SingletonSpecies() sage: S = X + X - sage: S.algebraic_equation_system() + sage: S.algebraic_equation_system() # optional - sage.graphs [node1 + (-2*z)] """ return sum(var_mapping[operand] for operand in self._state_info) From 6cb95c1d98c65fb692540ad7edba1955630b6871 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Jun 2023 17:49:30 -0700 Subject: [PATCH 142/538] More # optional --- .../species/characteristic_species.py | 27 +++++----- .../combinat/species/composition_species.py | 52 +++++++++---------- src/sage/combinat/species/cycle_species.py | 14 ++--- src/sage/combinat/species/empty_species.py | 6 +-- .../species/functorial_composition_species.py | 8 +-- .../combinat/species/linear_order_species.py | 6 +-- .../combinat/species/partition_species.py | 2 +- src/sage/combinat/species/product_species.py | 4 +- src/sage/combinat/species/species.py | 4 +- src/sage/combinat/species/structure.py | 6 +-- src/sage/combinat/species/sum_species.py | 6 +-- 11 files changed, 67 insertions(+), 68 deletions(-) diff --git a/src/sage/combinat/species/characteristic_species.py b/src/sage/combinat/species/characteristic_species.py index e529dc97bd1..ca88dd7e91b 100644 --- a/src/sage/combinat/species/characteristic_species.py +++ b/src/sage/combinat/species/characteristic_species.py @@ -60,16 +60,15 @@ def canonical_label(self): def transport(self, perm): """ - Returns the transport of this structure along the permutation - perm. + Return the transport of this structure along the permutation ``perm``. EXAMPLES:: sage: F = species.CharacteristicSpecies(3) sage: a = F.structures(["a", "b", "c"]).random_element(); a {'a', 'b', 'c'} - sage: p = PermutationGroupElement((1,2)) - sage: a.transport(p) + sage: p = PermutationGroupElement((1,2)) # optional - sage.groups + sage: a.transport(p) # optional - sage.groups {'a', 'b', 'c'} """ return self @@ -85,7 +84,7 @@ def automorphism_group(self): sage: F = species.CharacteristicSpecies(3) sage: a = F.structures(["a", "b", "c"]).random_element(); a {'a', 'b', 'c'} - sage: a.automorphism_group() + sage: a.automorphism_group() # optional - sage.groups Symmetric group of order 3! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -111,7 +110,7 @@ def __init__(self, n, min=None, max=None, weight=None): [0, 1, 0, 0] sage: X.isotype_generating_series()[0:4] [0, 1, 0, 0] - sage: X.cycle_index_series()[0:4] + sage: X.cycle_index_series()[0:4] # optional - sage.modules [0, p[1], 0, 0] sage: F = species.CharacteristicSpecies(3) @@ -204,7 +203,7 @@ def _cis_term(self, base_ring): EXAMPLES:: sage: F = species.CharacteristicSpecies(2) - sage: g = F.cycle_index_series() + sage: g = F.cycle_index_series() # optional - sage.modules sage: g[0:5] [0, 0, 1/2*p[1, 1] + 1/2*p[2], 0, 0] """ @@ -220,11 +219,11 @@ def _equation(self, var_mapping): EXAMPLES:: sage: C = species.CharacteristicSpecies(2) - sage: Qz = QQ['z'] - sage: R. = Qz[] - sage: var_mapping = {'z':Qz.gen(), 'node0':R.gen()} - sage: C._equation(var_mapping) - z^2 + sage: Qz = QQ['z'] + sage: R. = Qz[] + sage: var_mapping = {'z':Qz.gen(), 'node0':R.gen()} + sage: C._equation(var_mapping) + z^2 """ return var_mapping['z']**(self._n) @@ -252,7 +251,7 @@ def __init__(self, min=None, max=None, weight=None): [1, 0, 0, 0] sage: X.isotype_generating_series()[0:4] [1, 0, 0, 0] - sage: X.cycle_index_series()[0:4] + sage: X.cycle_index_series()[0:4] # optional - sage.modules [p[], 0, 0, 0] TESTS:: @@ -296,7 +295,7 @@ def __init__(self, min=None, max=None, weight=None): [0, 1, 0, 0] sage: X.isotype_generating_series()[0:4] [0, 1, 0, 0] - sage: X.cycle_index_series()[0:4] + sage: X.cycle_index_series()[0:4] # optional - sage.modules [0, p[1], 0, 0] TESTS:: diff --git a/src/sage/combinat/species/composition_species.py b/src/sage/combinat/species/composition_species.py index c96f3161ba5..1937ead0811 100644 --- a/src/sage/combinat/species/composition_species.py +++ b/src/sage/combinat/species/composition_species.py @@ -28,8 +28,8 @@ def __init__(self, parent, labels, pi, f, gs): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: a = L.structures(['a','b','c']).random_element() - sage: a == loads(dumps(a)) + sage: a = L.structures(['a','b','c']).random_element() # optional - sage.libs.flint + sage: a == loads(dumps(a)) # optional - sage.libs.flint True """ self._partition = pi @@ -41,7 +41,7 @@ def __repr__(self): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.structures(['a','b','c'])[0] + sage: L.structures(['a','b','c'])[0] # optional - sage.libs.flint F-structure: {{'a', 'b', 'c'}}; G-structures: (('a', 'b', 'c'),) """ f, gs = self._list @@ -51,13 +51,13 @@ def transport(self, perm): """ EXAMPLES:: - sage: p = PermutationGroupElement((2,3)) + sage: p = PermutationGroupElement((2,3)) # optional - sage.groups sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: S = L.structures(['a','b','c']).list() - sage: a = S[2]; a + sage: S = L.structures(['a','b','c']).list() # optional - sage.libs.flint + sage: a = S[2]; a # optional - sage.libs.flint F-structure: {{'a', 'c'}, {'b'}}; G-structures: (('a', 'c'), ('b')) - sage: a.transport(p) + sage: a.transport(p) # optional - sage.groups sage.libs.flint F-structure: {{'a', 'b'}, {'c'}}; G-structures: (('a', 'c'), ('b')) """ f, gs = self._list @@ -83,10 +83,10 @@ def change_labels(self, labels): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: S = L.structures(['a','b','c']).list() - sage: a = S[2]; a + sage: S = L.structures(['a','b','c']).list() # optional - sage.libs.flint + sage: a = S[2]; a # optional - sage.libs.flint F-structure: {{'a', 'c'}, {'b'}}; G-structures: (('a', 'c'), ('b')) - sage: a.change_labels([1,2,3]) + sage: a.change_labels([1,2,3]) # optional - sage.libs.flint F-structure: {{1, 3}, {2}}; G-structures: [(1, 3), (2)] """ f, gs = self._list @@ -116,7 +116,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) sage: c = L.generating_series()[:3] - sage: L._check() #False due to isomorphism types not being implemented + sage: L._check() #False due to isomorphism types not being implemented # optional - sage.libs.flint False sage: L == loads(dumps(L)) True @@ -135,7 +135,7 @@ def _structures(self, structure_class, labels): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.structures(['a','b','c']).list() + sage: L.structures(['a','b','c']).list() # optional - sage.libs.flint [F-structure: {{'a', 'b', 'c'}}; G-structures: (('a', 'b', 'c'),), F-structure: {{'a', 'b', 'c'}}; G-structures: (('a', 'c', 'b'),), F-structure: {{'a', 'c'}, {'b'}}; G-structures: (('a', 'c'), ('b')), @@ -145,21 +145,21 @@ def _structures(self, structure_class, labels): TESTS:: - sage: a = _[2] - sage: f, gs = a._list - sage: f + sage: a = _[2] # optional - sage.libs.flint + sage: f, gs = a._list # optional - sage.libs.flint + sage: f # optional - sage.libs.flint {{'a', 'c'}, {'b'}} - sage: f.parent() + sage: f.parent() # optional - sage.libs.flint Set species - sage: f._list + sage: f._list # optional - sage.libs.flint [1, 2] - sage: f._labels + sage: f._labels # optional - sage.libs.flint [{'a', 'c'}, {'b'}] - sage: [g.parent() for g in gs] + sage: [g.parent() for g in gs] # optional - sage.libs.flint [Cyclic permutation species, Cyclic permutation species] - sage: [g._labels for g in gs] + sage: [g._labels for g in gs] # optional - sage.libs.flint [['a', 'c'], ['b']] - sage: [g._list for g in gs] + sage: [g._list for g in gs] # optional - sage.libs.flint [[1, 2], [1]] """ from itertools import product @@ -180,7 +180,7 @@ def _isotypes(self, structure_class, labels): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.isotypes(['a','b','c']).list() + sage: L.isotypes(['a','b','c']).list() # optional - sage.modules Traceback (most recent call last): ... NotImplementedError @@ -204,7 +204,7 @@ def _itgs(self, series_ring, base_ring): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.isotype_generating_series()[:10] + sage: L.isotype_generating_series()[:10] # optional - sage.modules [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ cis = self.cycle_index_series(base_ring) @@ -216,7 +216,7 @@ def _cis(self, series_ring, base_ring): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.cycle_index_series()[:5] + sage: L.cycle_index_series()[:5] # optional - sage.modules [p[], p[1], p[1, 1] + p[2], @@ -233,7 +233,7 @@ def _cis(self, series_ring, base_ring): sage: E = species.SetSpecies() sage: C = species.CycleSpecies(weight=t) sage: S = E(C) - sage: S.isotype_generating_series()[:5] #indirect + sage: S.isotype_generating_series()[:5] #indirect # optional - sage.modules [1, t, t^2 + t, t^3 + t^2 + t, t^4 + t^3 + 2*t^2 + t] We do the same thing with set partitions weighted by the number of @@ -245,7 +245,7 @@ def _cis(self, series_ring, base_ring): sage: E = species.SetSpecies() sage: E_t = species.SetSpecies(min=1,weight=t) sage: Par = E(E_t) - sage: Par.isotype_generating_series()[:5] + sage: Par.isotype_generating_series()[:5] # optional - sage.modules [1, t, t^2 + t, t^3 + t^2 + t, t^4 + t^3 + 2*t^2 + t] """ f_cis = self._F.cycle_index_series(base_ring) diff --git a/src/sage/combinat/species/cycle_species.py b/src/sage/combinat/species/cycle_species.py index ed442e75ba9..e1faab86c91 100644 --- a/src/sage/combinat/species/cycle_species.py +++ b/src/sage/combinat/species/cycle_species.py @@ -51,7 +51,7 @@ def permutation_group_element(self): sage: F = species.CycleSpecies() sage: a = F.structures(["a", "b", "c"])[0]; a ('a', 'b', 'c') - sage: a.permutation_group_element() + sage: a.permutation_group_element() # optional - sage.groups (1,2,3) """ from sage.groups.perm_gps.constructor import PermutationGroupElement @@ -67,8 +67,8 @@ def transport(self, perm): sage: F = species.CycleSpecies() sage: a = F.structures(["a", "b", "c"])[0]; a ('a', 'b', 'c') - sage: p = PermutationGroupElement((1,2)) - sage: a.transport(p) + sage: p = PermutationGroupElement((1,2)) # optional - sage.groups + sage: a.transport(p) # optional - sage.groups ('a', 'c', 'b') """ p = self.permutation_group_element() @@ -88,12 +88,12 @@ def automorphism_group(self): sage: P = species.CycleSpecies() sage: a = P.structures([1, 2, 3, 4])[0]; a (1, 2, 3, 4) - sage: a.automorphism_group() + sage: a.automorphism_group() # optional - sage.groups Permutation Group with generators [(1,2,3,4)] :: - sage: [a.transport(perm) for perm in a.automorphism_group()] + sage: [a.transport(perm) for perm in a.automorphism_group()] # optional - sage.groups [(1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4)] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -255,8 +255,8 @@ def _cis_callable(self, base_ring, n): EXAMPLES:: sage: P = species.CycleSpecies() - sage: cis = P.cycle_index_series() - sage: cis[0:7] + sage: cis = P.cycle_index_series() # optional - sage.modules + sage: cis[0:7] # optional - sage.modules [0, p[1], 1/2*p[1, 1] + 1/2*p[2], diff --git a/src/sage/combinat/species/empty_species.py b/src/sage/combinat/species/empty_species.py index e66019360ac..d3ddcad0cf3 100644 --- a/src/sage/combinat/species/empty_species.py +++ b/src/sage/combinat/species/empty_species.py @@ -38,7 +38,7 @@ class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): [0, 0, 0, 0] sage: X.isotype_generating_series()[0:4] [0, 0, 0, 0] - sage: X.cycle_index_series()[0:4] + sage: X.cycle_index_series()[0:4] # optional - sage.modules [0, 0, 0, 0] The empty species is the zero of the semi-ring of species. @@ -55,7 +55,7 @@ class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): sage: (X.isotype_generating_series()[0:4] == ....: S.isotype_generating_series()[0:4]) True - sage: (X.cycle_index_series()[0:4] == + sage: (X.cycle_index_series()[0:4] == # optional - sage.modules ....: S.cycle_index_series()[0:4]) True @@ -69,7 +69,7 @@ class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): [0, 0, 0, 0] sage: Y.isotype_generating_series()[0:4] [0, 0, 0, 0] - sage: Y.cycle_index_series()[0:4] + sage: Y.cycle_index_series()[0:4] # optional - sage.modules [0, 0, 0, 0] TESTS:: diff --git a/src/sage/combinat/species/functorial_composition_species.py b/src/sage/combinat/species/functorial_composition_species.py index 118e924d426..99da72c1d9c 100644 --- a/src/sage/combinat/species/functorial_composition_species.py +++ b/src/sage/combinat/species/functorial_composition_species.py @@ -35,7 +35,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: WP = species.SubsetSpecies() sage: P2 = E2*E sage: G = WP.functorial_composition(P2) - sage: G.isotype_generating_series()[0:5] + sage: G.isotype_generating_series()[0:5] # optional - sage.modules [1, 1, 2, 4, 11] sage: G = species.SimpleGraphSpecies() @@ -81,7 +81,7 @@ def _isotypes(self, structure_class, s): EXAMPLES:: sage: G = species.SimpleGraphSpecies() - sage: G.isotypes([1,2,3]).list() + sage: G.isotypes([1,2,3]).list() # optional - sage.modules Traceback (most recent call last): ... NotImplementedError @@ -103,7 +103,7 @@ def _itgs(self, series_ring, base_ring): EXAMPLES:: sage: G = species.SimpleGraphSpecies() - sage: G.isotype_generating_series()[0:5] + sage: G.isotype_generating_series()[0:5] # optional - sage.modules [1, 1, 2, 4, 11] """ return self.cycle_index_series(base_ring).isotype_generating_series() @@ -113,7 +113,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: G = species.SimpleGraphSpecies() - sage: G.cycle_index_series()[0:5] + sage: G.cycle_index_series()[0:5] # optional - sage.modules [p[], p[1], p[1, 1] + p[2], diff --git a/src/sage/combinat/species/linear_order_species.py b/src/sage/combinat/species/linear_order_species.py index 6203442ec8f..6b64178bdbc 100644 --- a/src/sage/combinat/species/linear_order_species.py +++ b/src/sage/combinat/species/linear_order_species.py @@ -43,7 +43,7 @@ def transport(self, perm): sage: F = species.LinearOrderSpecies() sage: a = F.structures(["a", "b", "c"])[0]; a ['a', 'b', 'c'] - sage: p = PermutationGroupElement((1,2)) + sage: p = PermutationGroupElement((1,2)) # optional - sage.groups sage: a.transport(p) ['b', 'a', 'c'] """ @@ -60,7 +60,7 @@ def automorphism_group(self): sage: F = species.LinearOrderSpecies() sage: a = F.structures(["a", "b", "c"])[0]; a ['a', 'b', 'c'] - sage: a.automorphism_group() + sage: a.automorphism_group() # optional - sage.groups Symmetric group of order 1! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -155,7 +155,7 @@ def _cis_callable(self, base_ring, n): EXAMPLES:: sage: L = species.LinearOrderSpecies() - sage: g = L.cycle_index_series() + sage: g = L.cycle_index_series() # optional - sage.modules sage: g[0:5] [p[], p[1], p[1, 1], p[1, 1, 1], p[1, 1, 1, 1]] """ diff --git a/src/sage/combinat/species/partition_species.py b/src/sage/combinat/species/partition_species.py index f9044db7c73..f3038ad6ba2 100644 --- a/src/sage/combinat/species/partition_species.py +++ b/src/sage/combinat/species/partition_species.py @@ -272,7 +272,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: g = P.cycle_index_series() + sage: g = P.cycle_index_series() # optional - sage.modules sage: g[0:5] [p[], p[1], diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index a3bcb3f4bb4..b1ce34596fd 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -215,7 +215,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): Product of (Permutation species) and (Permutation species) sage: F == loads(dumps(F)) True - sage: F._check() + sage: F._check() # optional - sage.libs.flint True TESTS:: @@ -340,7 +340,7 @@ def _itgs(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P * P - sage: F.isotype_generating_series()[0:5] + sage: F.isotype_generating_series()[0:5] # optional - sage.libs.flint [1, 2, 5, 10, 20] """ res = (self.left_factor().isotype_generating_series(base_ring) * diff --git a/src/sage/combinat/species/species.py b/src/sage/combinat/species/species.py index 9c3365f81b7..871a62009af 100644 --- a/src/sage/combinat/species/species.py +++ b/src/sage/combinat/species/species.py @@ -401,7 +401,7 @@ def _check(self, n=5): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: P._check() + sage: P._check() # optional - sage.libs.flint True """ st = self.structures(range(n)) @@ -622,7 +622,7 @@ def isotype_generating_series(self, base_ring=None): sage: P = species.PermutationSpecies() sage: g = P.isotype_generating_series() - sage: g[0:4] + sage: g[0:4] # optional - sage.libs.flint [1, 1, 2, 3] sage: g.counts(4) [1, 1, 2, 3] diff --git a/src/sage/combinat/species/structure.py b/src/sage/combinat/species/structure.py index a4de6349c6d..d0ca053d632 100644 --- a/src/sage/combinat/species/structure.py +++ b/src/sage/combinat/species/structure.py @@ -277,9 +277,9 @@ def transport(self, perm): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: s = (P+P).structures([1,2,3])[1]; s + sage: s = (P+P).structures([1,2,3])[1]; s # optional - sage.libs.flint {{1, 3}, {2}} - sage: s.transport(PermutationGroupElement((2,3))) + sage: s.transport(PermutationGroupElement((2,3))) # optional - sage.groups sage.libs.flint {{1, 2}, {3}} """ return self.__class__(self._parent, self._s.transport(perm), **self._options) @@ -289,7 +289,7 @@ def canonical_label(self): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: s = (P+P).structures([1,2,3])[1]; s + sage: s = (P+P).structures([1,2,3])[1]; s # optional - sage.libs.flint {{1, 3}, {2}} sage: s.canonical_label() {{1, 2}, {3}} diff --git a/src/sage/combinat/species/sum_species.py b/src/sage/combinat/species/sum_species.py index ae877a64314..ac2e05943b3 100644 --- a/src/sage/combinat/species/sum_species.py +++ b/src/sage/combinat/species/sum_species.py @@ -38,7 +38,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F._check() + sage: F._check() # optional - sage.libs.flint True sage: F == loads(dumps(F)) True @@ -126,7 +126,7 @@ def _isotypes(self, structure_class, labels): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F.isotypes([1,2]).list() + sage: F.isotypes([1,2]).list() # optional - sage.libs.flint [[2, 1], [1, 2], [2, 1], [1, 2]] """ for res in self._F.isotypes(labels): @@ -157,7 +157,7 @@ def _itgs(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F.isotype_generating_series()[:5] + sage: F.isotype_generating_series()[:5] # optional - sage.libs.flint [2, 2, 4, 6, 10] """ return (self.left_summand().isotype_generating_series(base_ring) + From 7f205583588bc67af46c37e3ced399083af786c2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Jun 2023 23:46:00 -0700 Subject: [PATCH 143/538] sage.combinat: More # optional --- src/sage/combinat/species/characteristic_species.py | 2 +- src/sage/combinat/species/functorial_composition_species.py | 2 +- src/sage/combinat/species/linear_order_species.py | 4 ++-- src/sage/combinat/species/species.py | 6 +++--- src/sage/combinat/species/structure.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sage/combinat/species/characteristic_species.py b/src/sage/combinat/species/characteristic_species.py index ca88dd7e91b..c3e55239335 100644 --- a/src/sage/combinat/species/characteristic_species.py +++ b/src/sage/combinat/species/characteristic_species.py @@ -204,7 +204,7 @@ def _cis_term(self, base_ring): sage: F = species.CharacteristicSpecies(2) sage: g = F.cycle_index_series() # optional - sage.modules - sage: g[0:5] + sage: g[0:5] # optional - sage.modules [0, 0, 1/2*p[1, 1] + 1/2*p[2], 0, 0] """ cis = SetSpecies(weight=self._weight).cycle_index_series(base_ring) diff --git a/src/sage/combinat/species/functorial_composition_species.py b/src/sage/combinat/species/functorial_composition_species.py index 99da72c1d9c..68a07967671 100644 --- a/src/sage/combinat/species/functorial_composition_species.py +++ b/src/sage/combinat/species/functorial_composition_species.py @@ -44,7 +44,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: G == loads(dumps(G)) True - sage: G._check() #False due to isomorphism types not being implemented + sage: G._check() # False due to isomorphism types not being implemented # optional - sage.modules False """ self._F = F diff --git a/src/sage/combinat/species/linear_order_species.py b/src/sage/combinat/species/linear_order_species.py index 6b64178bdbc..a889c8ab6c2 100644 --- a/src/sage/combinat/species/linear_order_species.py +++ b/src/sage/combinat/species/linear_order_species.py @@ -44,7 +44,7 @@ def transport(self, perm): sage: a = F.structures(["a", "b", "c"])[0]; a ['a', 'b', 'c'] sage: p = PermutationGroupElement((1,2)) # optional - sage.groups - sage: a.transport(p) + sage: a.transport(p) # optional - sage.groups ['b', 'a', 'c'] """ return LinearOrderSpeciesStructure(self.parent(), self._labels, [perm(i) for i in self._list]) @@ -156,7 +156,7 @@ def _cis_callable(self, base_ring, n): sage: L = species.LinearOrderSpecies() sage: g = L.cycle_index_series() # optional - sage.modules - sage: g[0:5] + sage: g[0:5] # optional - sage.modules [p[], p[1], p[1, 1], p[1, 1, 1], p[1, 1, 1, 1]] """ from sage.combinat.sf.sf import SymmetricFunctions diff --git a/src/sage/combinat/species/species.py b/src/sage/combinat/species/species.py index 871a62009af..0efdb963981 100644 --- a/src/sage/combinat/species/species.py +++ b/src/sage/combinat/species/species.py @@ -624,11 +624,11 @@ def isotype_generating_series(self, base_ring=None): sage: g = P.isotype_generating_series() sage: g[0:4] # optional - sage.libs.flint [1, 1, 2, 3] - sage: g.counts(4) + sage: g.counts(4) # optional - sage.libs.flint [1, 1, 2, 3] - sage: P.isotypes([1,2,3]).list() + sage: P.isotypes([1,2,3]).list() # optional - sage.libs.flint [[2, 3, 1], [2, 1, 3], [1, 2, 3]] - sage: len(_) + sage: len(_) # optional - sage.libs.flint 3 """ return self._get_series(OrdinaryGeneratingSeriesRing, "itgs", base_ring) diff --git a/src/sage/combinat/species/structure.py b/src/sage/combinat/species/structure.py index d0ca053d632..6dc1fc2ea15 100644 --- a/src/sage/combinat/species/structure.py +++ b/src/sage/combinat/species/structure.py @@ -291,7 +291,7 @@ def canonical_label(self): sage: P = species.PartitionSpecies() sage: s = (P+P).structures([1,2,3])[1]; s # optional - sage.libs.flint {{1, 3}, {2}} - sage: s.canonical_label() + sage: s.canonical_label() # optional - sage.libs.flint {{1, 2}, {3}} """ return self.__class__(self._parent, self._s.canonical_label(), **self._options) From 7cdec9bc1bfcbd13c8594a5a1615575d1a0b8fd2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 12 Jul 2023 17:59:24 -0700 Subject: [PATCH 144/538] ./sage -fixdoctests --distribution sagemath-categories --only-tags src/sage/combinat --- .../species/characteristic_species.py | 16 +-- .../combinat/species/composition_species.py | 52 ++++---- src/sage/combinat/species/cycle_species.py | 14 +-- src/sage/combinat/species/empty_species.py | 6 +- .../species/functorial_composition_species.py | 10 +- .../combinat/species/generating_series.py | 116 +++++++++--------- src/sage/combinat/species/library.py | 22 ++-- .../combinat/species/linear_order_species.py | 10 +- .../combinat/species/partition_species.py | 2 +- .../combinat/species/permutation_species.py | 6 +- src/sage/combinat/species/product_species.py | 34 ++--- .../combinat/species/recursive_species.py | 12 +- src/sage/combinat/species/set_species.py | 10 +- src/sage/combinat/species/species.py | 48 ++++---- src/sage/combinat/species/structure.py | 12 +- src/sage/combinat/species/subset_species.py | 14 +-- src/sage/combinat/species/sum_species.py | 10 +- 17 files changed, 197 insertions(+), 197 deletions(-) diff --git a/src/sage/combinat/species/characteristic_species.py b/src/sage/combinat/species/characteristic_species.py index c3e55239335..37ce75abe28 100644 --- a/src/sage/combinat/species/characteristic_species.py +++ b/src/sage/combinat/species/characteristic_species.py @@ -67,8 +67,8 @@ def transport(self, perm): sage: F = species.CharacteristicSpecies(3) sage: a = F.structures(["a", "b", "c"]).random_element(); a {'a', 'b', 'c'} - sage: p = PermutationGroupElement((1,2)) # optional - sage.groups - sage: a.transport(p) # optional - sage.groups + sage: p = PermutationGroupElement((1,2)) # needs sage.groups + sage: a.transport(p) # needs sage.groups {'a', 'b', 'c'} """ return self @@ -84,7 +84,7 @@ def automorphism_group(self): sage: F = species.CharacteristicSpecies(3) sage: a = F.structures(["a", "b", "c"]).random_element(); a {'a', 'b', 'c'} - sage: a.automorphism_group() # optional - sage.groups + sage: a.automorphism_group() # needs sage.groups Symmetric group of order 3! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -110,7 +110,7 @@ def __init__(self, n, min=None, max=None, weight=None): [0, 1, 0, 0] sage: X.isotype_generating_series()[0:4] [0, 1, 0, 0] - sage: X.cycle_index_series()[0:4] # optional - sage.modules + sage: X.cycle_index_series()[0:4] # needs sage.modules [0, p[1], 0, 0] sage: F = species.CharacteristicSpecies(3) @@ -203,8 +203,8 @@ def _cis_term(self, base_ring): EXAMPLES:: sage: F = species.CharacteristicSpecies(2) - sage: g = F.cycle_index_series() # optional - sage.modules - sage: g[0:5] # optional - sage.modules + sage: g = F.cycle_index_series() # needs sage.modules + sage: g[0:5] # needs sage.modules [0, 0, 1/2*p[1, 1] + 1/2*p[2], 0, 0] """ cis = SetSpecies(weight=self._weight).cycle_index_series(base_ring) @@ -251,7 +251,7 @@ def __init__(self, min=None, max=None, weight=None): [1, 0, 0, 0] sage: X.isotype_generating_series()[0:4] [1, 0, 0, 0] - sage: X.cycle_index_series()[0:4] # optional - sage.modules + sage: X.cycle_index_series()[0:4] # needs sage.modules [p[], 0, 0, 0] TESTS:: @@ -295,7 +295,7 @@ def __init__(self, min=None, max=None, weight=None): [0, 1, 0, 0] sage: X.isotype_generating_series()[0:4] [0, 1, 0, 0] - sage: X.cycle_index_series()[0:4] # optional - sage.modules + sage: X.cycle_index_series()[0:4] # needs sage.modules [0, p[1], 0, 0] TESTS:: diff --git a/src/sage/combinat/species/composition_species.py b/src/sage/combinat/species/composition_species.py index 1937ead0811..a60b0cbed89 100644 --- a/src/sage/combinat/species/composition_species.py +++ b/src/sage/combinat/species/composition_species.py @@ -28,8 +28,8 @@ def __init__(self, parent, labels, pi, f, gs): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: a = L.structures(['a','b','c']).random_element() # optional - sage.libs.flint - sage: a == loads(dumps(a)) # optional - sage.libs.flint + sage: a = L.structures(['a','b','c']).random_element() # needs sage.libs.flint + sage: a == loads(dumps(a)) # needs sage.libs.flint True """ self._partition = pi @@ -41,7 +41,7 @@ def __repr__(self): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.structures(['a','b','c'])[0] # optional - sage.libs.flint + sage: L.structures(['a','b','c'])[0] # needs sage.libs.flint F-structure: {{'a', 'b', 'c'}}; G-structures: (('a', 'b', 'c'),) """ f, gs = self._list @@ -51,13 +51,13 @@ def transport(self, perm): """ EXAMPLES:: - sage: p = PermutationGroupElement((2,3)) # optional - sage.groups + sage: p = PermutationGroupElement((2,3)) # needs sage.groups sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: S = L.structures(['a','b','c']).list() # optional - sage.libs.flint - sage: a = S[2]; a # optional - sage.libs.flint + sage: S = L.structures(['a','b','c']).list() # needs sage.libs.flint + sage: a = S[2]; a # needs sage.libs.flint F-structure: {{'a', 'c'}, {'b'}}; G-structures: (('a', 'c'), ('b')) - sage: a.transport(p) # optional - sage.groups sage.libs.flint + sage: a.transport(p) # needs sage.groups sage.libs.flint F-structure: {{'a', 'b'}, {'c'}}; G-structures: (('a', 'c'), ('b')) """ f, gs = self._list @@ -83,10 +83,10 @@ def change_labels(self, labels): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: S = L.structures(['a','b','c']).list() # optional - sage.libs.flint - sage: a = S[2]; a # optional - sage.libs.flint + sage: S = L.structures(['a','b','c']).list() # needs sage.libs.flint + sage: a = S[2]; a # needs sage.libs.flint F-structure: {{'a', 'c'}, {'b'}}; G-structures: (('a', 'c'), ('b')) - sage: a.change_labels([1,2,3]) # optional - sage.libs.flint + sage: a.change_labels([1,2,3]) # needs sage.libs.flint F-structure: {{1, 3}, {2}}; G-structures: [(1, 3), (2)] """ f, gs = self._list @@ -116,7 +116,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) sage: c = L.generating_series()[:3] - sage: L._check() #False due to isomorphism types not being implemented # optional - sage.libs.flint + sage: L._check() #False due to isomorphism types not being implemented # needs sage.libs.flint False sage: L == loads(dumps(L)) True @@ -135,7 +135,7 @@ def _structures(self, structure_class, labels): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.structures(['a','b','c']).list() # optional - sage.libs.flint + sage: L.structures(['a','b','c']).list() # needs sage.libs.flint [F-structure: {{'a', 'b', 'c'}}; G-structures: (('a', 'b', 'c'),), F-structure: {{'a', 'b', 'c'}}; G-structures: (('a', 'c', 'b'),), F-structure: {{'a', 'c'}, {'b'}}; G-structures: (('a', 'c'), ('b')), @@ -145,21 +145,21 @@ def _structures(self, structure_class, labels): TESTS:: - sage: a = _[2] # optional - sage.libs.flint - sage: f, gs = a._list # optional - sage.libs.flint - sage: f # optional - sage.libs.flint + sage: a = _[2] # needs sage.libs.flint + sage: f, gs = a._list # needs sage.libs.flint + sage: f # needs sage.libs.flint {{'a', 'c'}, {'b'}} - sage: f.parent() # optional - sage.libs.flint + sage: f.parent() # needs sage.libs.flint Set species - sage: f._list # optional - sage.libs.flint + sage: f._list # needs sage.libs.flint [1, 2] - sage: f._labels # optional - sage.libs.flint + sage: f._labels # needs sage.libs.flint [{'a', 'c'}, {'b'}] - sage: [g.parent() for g in gs] # optional - sage.libs.flint + sage: [g.parent() for g in gs] # needs sage.libs.flint [Cyclic permutation species, Cyclic permutation species] - sage: [g._labels for g in gs] # optional - sage.libs.flint + sage: [g._labels for g in gs] # needs sage.libs.flint [['a', 'c'], ['b']] - sage: [g._list for g in gs] # optional - sage.libs.flint + sage: [g._list for g in gs] # needs sage.libs.flint [[1, 2], [1]] """ from itertools import product @@ -180,7 +180,7 @@ def _isotypes(self, structure_class, labels): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.isotypes(['a','b','c']).list() # optional - sage.modules + sage: L.isotypes(['a','b','c']).list() # needs sage.modules Traceback (most recent call last): ... NotImplementedError @@ -204,7 +204,7 @@ def _itgs(self, series_ring, base_ring): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.isotype_generating_series()[:10] # optional - sage.modules + sage: L.isotype_generating_series()[:10] # needs sage.modules [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ cis = self.cycle_index_series(base_ring) @@ -216,7 +216,7 @@ def _cis(self, series_ring, base_ring): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.cycle_index_series()[:5] # optional - sage.modules + sage: L.cycle_index_series()[:5] # needs sage.modules [p[], p[1], p[1, 1] + p[2], @@ -233,7 +233,7 @@ def _cis(self, series_ring, base_ring): sage: E = species.SetSpecies() sage: C = species.CycleSpecies(weight=t) sage: S = E(C) - sage: S.isotype_generating_series()[:5] #indirect # optional - sage.modules + sage: S.isotype_generating_series()[:5] #indirect # needs sage.modules [1, t, t^2 + t, t^3 + t^2 + t, t^4 + t^3 + 2*t^2 + t] We do the same thing with set partitions weighted by the number of @@ -245,7 +245,7 @@ def _cis(self, series_ring, base_ring): sage: E = species.SetSpecies() sage: E_t = species.SetSpecies(min=1,weight=t) sage: Par = E(E_t) - sage: Par.isotype_generating_series()[:5] # optional - sage.modules + sage: Par.isotype_generating_series()[:5] # needs sage.modules [1, t, t^2 + t, t^3 + t^2 + t, t^4 + t^3 + 2*t^2 + t] """ f_cis = self._F.cycle_index_series(base_ring) diff --git a/src/sage/combinat/species/cycle_species.py b/src/sage/combinat/species/cycle_species.py index e1faab86c91..c808f6a0db1 100644 --- a/src/sage/combinat/species/cycle_species.py +++ b/src/sage/combinat/species/cycle_species.py @@ -51,7 +51,7 @@ def permutation_group_element(self): sage: F = species.CycleSpecies() sage: a = F.structures(["a", "b", "c"])[0]; a ('a', 'b', 'c') - sage: a.permutation_group_element() # optional - sage.groups + sage: a.permutation_group_element() # needs sage.groups (1,2,3) """ from sage.groups.perm_gps.constructor import PermutationGroupElement @@ -67,8 +67,8 @@ def transport(self, perm): sage: F = species.CycleSpecies() sage: a = F.structures(["a", "b", "c"])[0]; a ('a', 'b', 'c') - sage: p = PermutationGroupElement((1,2)) # optional - sage.groups - sage: a.transport(p) # optional - sage.groups + sage: p = PermutationGroupElement((1,2)) # needs sage.groups + sage: a.transport(p) # needs sage.groups ('a', 'c', 'b') """ p = self.permutation_group_element() @@ -88,12 +88,12 @@ def automorphism_group(self): sage: P = species.CycleSpecies() sage: a = P.structures([1, 2, 3, 4])[0]; a (1, 2, 3, 4) - sage: a.automorphism_group() # optional - sage.groups + sage: a.automorphism_group() # needs sage.groups Permutation Group with generators [(1,2,3,4)] :: - sage: [a.transport(perm) for perm in a.automorphism_group()] # optional - sage.groups + sage: [a.transport(perm) for perm in a.automorphism_group()] # needs sage.groups [(1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4), (1, 2, 3, 4)] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -255,8 +255,8 @@ def _cis_callable(self, base_ring, n): EXAMPLES:: sage: P = species.CycleSpecies() - sage: cis = P.cycle_index_series() # optional - sage.modules - sage: cis[0:7] # optional - sage.modules + sage: cis = P.cycle_index_series() # needs sage.modules + sage: cis[0:7] # needs sage.modules [0, p[1], 1/2*p[1, 1] + 1/2*p[2], diff --git a/src/sage/combinat/species/empty_species.py b/src/sage/combinat/species/empty_species.py index d3ddcad0cf3..5c4762cb34d 100644 --- a/src/sage/combinat/species/empty_species.py +++ b/src/sage/combinat/species/empty_species.py @@ -38,7 +38,7 @@ class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): [0, 0, 0, 0] sage: X.isotype_generating_series()[0:4] [0, 0, 0, 0] - sage: X.cycle_index_series()[0:4] # optional - sage.modules + sage: X.cycle_index_series()[0:4] # needs sage.modules [0, 0, 0, 0] The empty species is the zero of the semi-ring of species. @@ -55,7 +55,7 @@ class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): sage: (X.isotype_generating_series()[0:4] == ....: S.isotype_generating_series()[0:4]) True - sage: (X.cycle_index_series()[0:4] == # optional - sage.modules + sage: (X.cycle_index_series()[0:4] == # needs sage.modules ....: S.cycle_index_series()[0:4]) True @@ -69,7 +69,7 @@ class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): [0, 0, 0, 0] sage: Y.isotype_generating_series()[0:4] [0, 0, 0, 0] - sage: Y.cycle_index_series()[0:4] # optional - sage.modules + sage: Y.cycle_index_series()[0:4] # needs sage.modules [0, 0, 0, 0] TESTS:: diff --git a/src/sage/combinat/species/functorial_composition_species.py b/src/sage/combinat/species/functorial_composition_species.py index 68a07967671..b327492a54a 100644 --- a/src/sage/combinat/species/functorial_composition_species.py +++ b/src/sage/combinat/species/functorial_composition_species.py @@ -35,7 +35,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: WP = species.SubsetSpecies() sage: P2 = E2*E sage: G = WP.functorial_composition(P2) - sage: G.isotype_generating_series()[0:5] # optional - sage.modules + sage: G.isotype_generating_series()[0:5] # needs sage.modules [1, 1, 2, 4, 11] sage: G = species.SimpleGraphSpecies() @@ -44,7 +44,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: G == loads(dumps(G)) True - sage: G._check() # False due to isomorphism types not being implemented # optional - sage.modules + sage: G._check() # False due to isomorphism types not being implemented # needs sage.modules False """ self._F = F @@ -81,7 +81,7 @@ def _isotypes(self, structure_class, s): EXAMPLES:: sage: G = species.SimpleGraphSpecies() - sage: G.isotypes([1,2,3]).list() # optional - sage.modules + sage: G.isotypes([1,2,3]).list() # needs sage.modules Traceback (most recent call last): ... NotImplementedError @@ -103,7 +103,7 @@ def _itgs(self, series_ring, base_ring): EXAMPLES:: sage: G = species.SimpleGraphSpecies() - sage: G.isotype_generating_series()[0:5] # optional - sage.modules + sage: G.isotype_generating_series()[0:5] # needs sage.modules [1, 1, 2, 4, 11] """ return self.cycle_index_series(base_ring).isotype_generating_series() @@ -113,7 +113,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: G = species.SimpleGraphSpecies() - sage: G.cycle_index_series()[0:5] # optional - sage.modules + sage: G.cycle_index_series()[0:5] # needs sage.modules [p[], p[1], p[1, 1] + p[2], diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index 24830b17bcd..9c0515bbead 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -16,18 +16,18 @@ TESTS:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() # optional - sage.modules - sage: CIS = CycleIndexSeriesRing(QQ) # optional - sage.modules - sage: geo1 = CIS(lambda i: p([1])^i) # optional - sage.modules - sage: geo2 = CIS(lambda i: p([2])^(i // 2) if is_even(i) else 0) # optional - sage.modules - sage: s = geo1 * geo2 # optional - sage.modules - sage: s[0] # optional - sage.modules + sage: p = SymmetricFunctions(QQ).power() # needs sage.modules + sage: CIS = CycleIndexSeriesRing(QQ) # needs sage.modules + sage: geo1 = CIS(lambda i: p([1])^i) # needs sage.modules + sage: geo2 = CIS(lambda i: p([2])^(i // 2) if is_even(i) else 0) # needs sage.modules + sage: s = geo1 * geo2 # needs sage.modules + sage: s[0] # needs sage.modules p[] - sage: s[1] # optional - sage.modules + sage: s[1] # needs sage.modules p[1] - sage: s[2] # optional - sage.modules + sage: s[2] # needs sage.modules p[1, 1] + p[2] - sage: s[3] # optional - sage.modules + sage: s[3] # needs sage.modules p[1, 1, 1] + p[2, 1] REFERENCES: @@ -293,14 +293,14 @@ def count(self, t): EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() # optional - sage.modules - sage: CIS = CycleIndexSeriesRing(QQ) # optional - sage.modules - sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])]) # optional - sage.modules - sage: f.count([1]) # optional - sage.modules + sage: p = SymmetricFunctions(QQ).power() # needs sage.modules + sage: CIS = CycleIndexSeriesRing(QQ) # needs sage.modules + sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])]) # needs sage.modules + sage: f.count([1]) # needs sage.modules 1 - sage: f.count([1,1]) # optional - sage.modules + sage: f.count([1,1]) # needs sage.modules 4 - sage: f.count([2,1]) # optional - sage.modules + sage: f.count([2,1]) # needs sage.modules 6 """ t = Partition(t) @@ -313,14 +313,14 @@ def coefficient_cycle_type(self, t): EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() # optional - sage.modules - sage: CIS = CycleIndexSeriesRing(QQ) # optional - sage.modules - sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])]) # optional - sage.modules - sage: f.coefficient_cycle_type([1]) # optional - sage.modules + sage: p = SymmetricFunctions(QQ).power() # needs sage.modules + sage: CIS = CycleIndexSeriesRing(QQ) # needs sage.modules + sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])]) # needs sage.modules + sage: f.coefficient_cycle_type([1]) # needs sage.modules 1 - sage: f.coefficient_cycle_type([1,1]) # optional - sage.modules + sage: f.coefficient_cycle_type([1,1]) # needs sage.modules 2 - sage: f.coefficient_cycle_type([2,1]) # optional - sage.modules + sage: f.coefficient_cycle_type([2,1]) # needs sage.modules 3 """ t = Partition(t) @@ -334,9 +334,9 @@ def isotype_generating_series(self): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: cis = P.cycle_index_series() # optional - sage.modules - sage: f = cis.isotype_generating_series() # optional - sage.modules - sage: f[:10] # optional - sage.modules + sage: cis = P.cycle_index_series() # needs sage.modules + sage: f = cis.isotype_generating_series() # needs sage.modules + sage: f[:10] # needs sage.modules [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ R = self.base_ring() @@ -352,8 +352,8 @@ def _ogs_gen(self, n, ao): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: cis = P.cycle_index_series() # optional - sage.modules - sage: [cis._ogs_gen(i, 0) for i in range(10)] # optional - sage.modules + sage: cis = P.cycle_index_series() # needs sage.modules + sage: [cis._ogs_gen(i, 0) for i in range(10)] # needs sage.modules [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ if n < ao: @@ -367,9 +367,9 @@ def generating_series(self): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: cis = P.cycle_index_series() # optional - sage.modules - sage: f = cis.generating_series() # optional - sage.modules - sage: f[:5] # optional - sage.modules + sage: cis = P.cycle_index_series() # needs sage.modules + sage: f = cis.generating_series() # needs sage.modules + sage: f[:5] # needs sage.modules [1, 1, 1, 5/6, 5/8] """ R = self.base_ring() @@ -385,8 +385,8 @@ def _egs_gen(self, n, ao): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: cis = P.cycle_index_series() # optional - sage.modules - sage: [cis._egs_gen(i, 0) for i in range(10)] # optional - sage.modules + sage: cis = P.cycle_index_series() # needs sage.modules + sage: [cis._egs_gen(i, 0) for i in range(10)] # needs sage.modules [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] """ if n < ao: @@ -409,16 +409,16 @@ def derivative(self, n=1): The species `E` of sets satisfies the relationship `E' = E`:: - sage: E = species.SetSpecies().cycle_index_series() # optional - sage.modules - sage: E[:8] == E.derivative()[:8] # optional - sage.modules + sage: E = species.SetSpecies().cycle_index_series() # needs sage.modules + sage: E[:8] == E.derivative()[:8] # needs sage.modules True The species `C` of cyclic orderings and the species `L` of linear orderings satisfy the relationship `C' = L`:: - sage: C = species.CycleSpecies().cycle_index_series() # optional - sage.modules - sage: L = species.LinearOrderSpecies().cycle_index_series() # optional - sage.modules - sage: L[:8] == C.derivative()[:8] # optional - sage.modules + sage: C = species.CycleSpecies().cycle_index_series() # needs sage.modules + sage: L = species.LinearOrderSpecies().cycle_index_series() # needs sage.modules + sage: L[:8] == C.derivative()[:8] # needs sage.modules True """ return self.derivative_with_respect_to_p1(n=n) @@ -439,9 +439,9 @@ def pointing(self): The species `E^{\bullet}` of "pointed sets" satisfies `E^{\bullet} = X \cdot E`:: - sage: E = species.SetSpecies().cycle_index_series() # optional - sage.modules - sage: X = species.SingletonSpecies().cycle_index_series() # optional - sage.modules - sage: E.pointing()[:8] == (X*E)[:8] # optional - sage.modules + sage: E = species.SetSpecies().cycle_index_series() # needs sage.modules + sage: X = species.SingletonSpecies().cycle_index_series() # needs sage.modules + sage: E.pointing()[:8] == (X*E)[:8] # needs sage.modules True """ X = self.parent()([1], valuation=1) @@ -463,9 +463,9 @@ def exponential(self): Let `BT` be the species of binary trees, `BF` the species of binary forests, and `E` the species of sets. Then we have `BF = E \circ BT`:: - sage: BT = species.BinaryTreeSpecies().cycle_index_series() # optional - sage.modules - sage: BF = species.BinaryForestSpecies().cycle_index_series() # optional - sage.modules - sage: BT.exponential().isotype_generating_series()[:8] == BF.isotype_generating_series()[:8] # optional - sage.modules + sage: BT = species.BinaryTreeSpecies().cycle_index_series() # needs sage.modules + sage: BF = species.BinaryForestSpecies().cycle_index_series() # needs sage.modules + sage: BT.exponential().isotype_generating_series()[:8] == BF.isotype_generating_series()[:8] # needs sage.modules True """ base_ring = self.parent().base_ring().base_ring() @@ -490,10 +490,10 @@ def logarithm(self): Let `G` be the species of nonempty graphs and `CG` be the species of nonempty connected graphs. Then `G = E^{+} \circ CG`, so `CG = \Omega \circ G`:: - sage: G = species.SimpleGraphSpecies().cycle_index_series() - 1 # optional - sage.modules + sage: G = species.SimpleGraphSpecies().cycle_index_series() - 1 # needs sage.modules sage: from sage.combinat.species.generating_series import LogarithmCycleIndexSeries - sage: CG = LogarithmCycleIndexSeries()(G) # optional - sage.modules - sage: CG.isotype_generating_series()[0:8] # optional - sage.modules + sage: CG = LogarithmCycleIndexSeries()(G) # needs sage.modules + sage: CG.isotype_generating_series()[0:8] # needs sage.modules [0, 1, 1, 2, 6, 21, 112, 853] """ base_ring = self.parent().base_ring().base_ring() @@ -536,17 +536,17 @@ class CycleIndexSeriesRing(LazySymmetricFunctions): EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: R = CycleIndexSeriesRing(QQ); R # optional - sage.modules + sage: R = CycleIndexSeriesRing(QQ); R # needs sage.modules Cycle Index Series Ring over Rational Field - sage: p = SymmetricFunctions(QQ).p() # optional - sage.modules - sage: R(lambda n: p[n]) # optional - sage.modules + sage: p = SymmetricFunctions(QQ).p() # needs sage.modules + sage: R(lambda n: p[n]) # needs sage.modules p[] + p[1] + p[2] + p[3] + p[4] + p[5] + p[6] + O^7 TESTS: We test to make sure that caching works:: - sage: R is CycleIndexSeriesRing(QQ) # optional - sage.modules + sage: R is CycleIndexSeriesRing(QQ) # needs sage.modules True """ Element = CycleIndexSeries @@ -559,8 +559,8 @@ def __init__(self, base_ring, sparse=True): sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: CycleIndexSeriesRing.options.halting_precision(12) - sage: R = CycleIndexSeriesRing(QQ) # optional - sage.modules - sage: TestSuite(R).run() # optional - sage.modules + sage: R = CycleIndexSeriesRing(QQ) # needs sage.modules + sage: TestSuite(R).run() # needs sage.modules sage: CycleIndexSeriesRing.options._reset() # reset options """ @@ -574,7 +574,7 @@ def _repr_(self): EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: CycleIndexSeriesRing(QQ) # optional - sage.modules + sage: CycleIndexSeriesRing(QQ) # needs sage.modules Cycle Index Series Ring over Rational Field """ return "Cycle Index Series Ring over %s" % self.base_ring() @@ -589,7 +589,7 @@ def _exp_term(n, R=QQ): EXAMPLES:: sage: from sage.combinat.species.generating_series import _exp_term - sage: [_exp_term(i) for i in range(4)] # optional - sage.modules + sage: [_exp_term(i) for i in range(4)] # needs sage.modules [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3]] """ p = SymmetricFunctions(R).power() @@ -611,7 +611,7 @@ def ExponentialCycleIndexSeries(R=QQ): EXAMPLES:: sage: from sage.combinat.species.generating_series import ExponentialCycleIndexSeries - sage: ExponentialCycleIndexSeries()[:5] # optional - sage.modules + sage: ExponentialCycleIndexSeries()[:5] # needs sage.modules [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3], 1/24*p[1, 1, 1, 1] + 1/4*p[2, 1, 1] + 1/8*p[2, 2] + 1/3*p[3, 1] + 1/4*p[4]] @@ -630,7 +630,7 @@ def _cl_term(n, R=QQ): EXAMPLES:: sage: from sage.combinat.species.generating_series import _cl_term - sage: [_cl_term(i) for i in range(4)] # optional - sage.modules + sage: [_cl_term(i) for i in range(4)] # needs sage.modules [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] """ n = Integer(n) # check that n is an integer @@ -662,15 +662,15 @@ def LogarithmCycleIndexSeries(R=QQ): its cycle index has negative coefficients:: sage: from sage.combinat.species.generating_series import LogarithmCycleIndexSeries - sage: LogarithmCycleIndexSeries()[0:4] # optional - sage.modules + sage: LogarithmCycleIndexSeries()[0:4] # needs sage.modules [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] Its defining property is that `\Omega \circ E^{+} = E^{+} \circ \Omega = X` (that is, that composition with `E^{+}` in both directions yields the multiplicative identity `X`):: - sage: Eplus = sage.combinat.species.set_species.SetSpecies(min=1).cycle_index_series() # optional - sage.modules - sage: LogarithmCycleIndexSeries()(Eplus)[0:4] # optional - sage.modules + sage: Eplus = sage.combinat.species.set_species.SetSpecies(min=1).cycle_index_series() # needs sage.modules + sage: LogarithmCycleIndexSeries()(Eplus)[0:4] # needs sage.modules [0, p[1], 0, 0] """ CIS = CycleIndexSeriesRing(R) diff --git a/src/sage/combinat/species/library.py b/src/sage/combinat/species/library.py index 3e3025d87f6..c50a9fe75fa 100644 --- a/src/sage/combinat/species/library.py +++ b/src/sage/combinat/species/library.py @@ -43,25 +43,25 @@ def SimpleGraphSpecies(): sage: S = species.SimpleGraphSpecies() sage: S.generating_series().counts(10) [1, 1, 2, 8, 64, 1024, 32768, 2097152, 268435456, 68719476736] - sage: S.cycle_index_series()[:5] # optional - sage.modules + sage: S.cycle_index_series()[:5] # needs sage.modules [p[], p[1], p[1, 1] + p[2], 4/3*p[1, 1, 1] + 2*p[2, 1] + 2/3*p[3], 8/3*p[1, 1, 1, 1] + 4*p[2, 1, 1] + 2*p[2, 2] + 4/3*p[3, 1] + p[4]] - sage: S.isotype_generating_series()[:6] # optional - sage.modules + sage: S.isotype_generating_series()[:6] # needs sage.modules [1, 1, 2, 4, 11, 34] TESTS:: - sage: seq = S.isotype_generating_series().counts(6)[1:] # optional - sage.modules - sage: oeis(seq)[0] # optional -- internet # optional - sage.modules + sage: seq = S.isotype_generating_series().counts(6)[1:] # needs sage.modules + sage: oeis(seq)[0] # optional - internet # needs sage.modules A000088: Number of graphs on n unlabeled nodes. :: - sage: seq = S.generating_series().counts(10)[1:] # optional - sage.modules - sage: oeis(seq)[0] # optional -- internet # optional - sage.modules + sage: seq = S.generating_series().counts(10)[1:] # needs sage.modules + sage: oeis(seq)[0] # optional - internet # needs sage.modules A006125: a(n) = 2^(n*(n-1)/2). """ E = SetSpecies() @@ -94,7 +94,7 @@ def BinaryTreeSpecies(): sage: B = species.BinaryTreeSpecies() sage: a = B.structures([1,2,3,4,5])[187]; a 2*((5*3)*(4*1)) - sage: a.automorphism_group() # optional - sage.groups + sage: a.automorphism_group() # needs sage.groups Permutation Group with generators [()] TESTS:: @@ -121,9 +121,9 @@ def BinaryForestSpecies(): sage: F = species.BinaryForestSpecies() sage: F.generating_series().counts(10) [1, 1, 3, 19, 193, 2721, 49171, 1084483, 28245729, 848456353] - sage: F.isotype_generating_series().counts(10) # optional - sage.modules + sage: F.isotype_generating_series().counts(10) # needs sage.modules [1, 1, 2, 4, 10, 26, 77, 235, 758, 2504] - sage: F.cycle_index_series()[:7] # optional - sage.modules + sage: F.cycle_index_series()[:7] # needs sage.modules [p[], p[1], 3/2*p[1, 1] + 1/2*p[2], @@ -134,8 +134,8 @@ def BinaryForestSpecies(): TESTS:: - sage: seq = F.isotype_generating_series().counts(10)[1:] # optional - sage.modules - sage: oeis(seq)[0] # optional -- internet # optional - sage.modules + sage: seq = F.isotype_generating_series().counts(10)[1:] # needs sage.modules + sage: oeis(seq)[0] # optional - internet # needs sage.modules A052854: Number of forests of ordered trees on n total nodes. """ B = BinaryTreeSpecies() diff --git a/src/sage/combinat/species/linear_order_species.py b/src/sage/combinat/species/linear_order_species.py index a889c8ab6c2..0761dea576d 100644 --- a/src/sage/combinat/species/linear_order_species.py +++ b/src/sage/combinat/species/linear_order_species.py @@ -43,8 +43,8 @@ def transport(self, perm): sage: F = species.LinearOrderSpecies() sage: a = F.structures(["a", "b", "c"])[0]; a ['a', 'b', 'c'] - sage: p = PermutationGroupElement((1,2)) # optional - sage.groups - sage: a.transport(p) # optional - sage.groups + sage: p = PermutationGroupElement((1,2)) # needs sage.groups + sage: a.transport(p) # needs sage.groups ['b', 'a', 'c'] """ return LinearOrderSpeciesStructure(self.parent(), self._labels, [perm(i) for i in self._list]) @@ -60,7 +60,7 @@ def automorphism_group(self): sage: F = species.LinearOrderSpecies() sage: a = F.structures(["a", "b", "c"])[0]; a ['a', 'b', 'c'] - sage: a.automorphism_group() # optional - sage.groups + sage: a.automorphism_group() # needs sage.groups Symmetric group of order 1! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -155,8 +155,8 @@ def _cis_callable(self, base_ring, n): EXAMPLES:: sage: L = species.LinearOrderSpecies() - sage: g = L.cycle_index_series() # optional - sage.modules - sage: g[0:5] # optional - sage.modules + sage: g = L.cycle_index_series() # needs sage.modules + sage: g[0:5] # needs sage.modules [p[], p[1], p[1, 1], p[1, 1, 1], p[1, 1, 1, 1]] """ from sage.combinat.sf.sf import SymmetricFunctions diff --git a/src/sage/combinat/species/partition_species.py b/src/sage/combinat/species/partition_species.py index f3038ad6ba2..bd24f470402 100644 --- a/src/sage/combinat/species/partition_species.py +++ b/src/sage/combinat/species/partition_species.py @@ -272,7 +272,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: g = P.cycle_index_series() # optional - sage.modules + sage: g = P.cycle_index_series() # needs sage.modules sage: g[0:5] [p[], p[1], diff --git a/src/sage/combinat/species/permutation_species.py b/src/sage/combinat/species/permutation_species.py index 470a766a2c4..59f41bbad0a 100644 --- a/src/sage/combinat/species/permutation_species.py +++ b/src/sage/combinat/species/permutation_species.py @@ -225,8 +225,8 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: g = P.cycle_index_series() # optional - sage.modules - sage: g[0:5] # optional - sage.modules + sage: g = P.cycle_index_series() # needs sage.modules + sage: g[0:5] # needs sage.modules [p[], p[1], p[1, 1] + p[2], @@ -244,7 +244,7 @@ def _cis_gen(self, base_ring, m, n): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: [P._cis_gen(QQ, 2, i) for i in range(10)] # optional - sage.modules + sage: [P._cis_gen(QQ, 2, i) for i in range(10)] # needs sage.modules [p[], 0, p[2], 0, p[2, 2], 0, p[2, 2, 2], 0, p[2, 2, 2, 2], 0] """ from sage.combinat.sf.sf import SymmetricFunctions diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index b1ce34596fd..41cd958532f 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -58,12 +58,12 @@ def transport(self, perm): """ EXAMPLES:: - sage: p = PermutationGroupElement((2,3)) # optional - sage.groups - sage: S = species.SetSpecies() # optional - sage.groups - sage: F = S * S # optional - sage.groups - sage: a = F.structures(['a','b','c'])[4]; a # optional - sage.groups + sage: p = PermutationGroupElement((2,3)) # needs sage.groups + sage: S = species.SetSpecies() # needs sage.groups + sage: F = S * S # needs sage.groups + sage: a = F.structures(['a','b','c'])[4]; a # needs sage.groups {'a', 'b'}*{'c'} - sage: a.transport(p) # optional - sage.groups + sage: a.transport(p) # needs sage.groups {'a', 'c'}*{'b'} """ left, right = self._list @@ -151,17 +151,17 @@ def automorphism_group(self): """ EXAMPLES:: - sage: p = PermutationGroupElement((2,3)) # optional - sage.groups - sage: S = species.SetSpecies() # optional - sage.groups - sage: F = S * S # optional - sage.groups - sage: a = F.structures([1,2,3,4])[1]; a # optional - sage.groups + sage: p = PermutationGroupElement((2,3)) # needs sage.groups + sage: S = species.SetSpecies() # needs sage.groups + sage: F = S * S # needs sage.groups + sage: a = F.structures([1,2,3,4])[1]; a # needs sage.groups {1}*{2, 3, 4} - sage: a.automorphism_group() # optional - sage.groups + sage: a.automorphism_group() # needs sage.groups Permutation Group with generators [(2,3), (2,3,4)] :: - sage: [a.transport(g) for g in a.automorphism_group()] # optional - sage.groups + sage: [a.transport(g) for g in a.automorphism_group()] # needs sage.groups [{1}*{2, 3, 4}, {1}*{2, 3, 4}, {1}*{2, 3, 4}, @@ -171,9 +171,9 @@ def automorphism_group(self): :: - sage: a = F.structures([1,2,3,4])[8]; a # optional - sage.groups + sage: a = F.structures([1,2,3,4])[8]; a # needs sage.groups {2, 3}*{1, 4} - sage: [a.transport(g) for g in a.automorphism_group()] # optional - sage.groups + sage: [a.transport(g) for g in a.automorphism_group()] # needs sage.groups [{2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}, {2, 3}*{1, 4}] """ from sage.groups.perm_gps.constructor import PermutationGroupElement @@ -215,7 +215,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): Product of (Permutation species) and (Permutation species) sage: F == loads(dumps(F)) True - sage: F._check() # optional - sage.libs.flint + sage: F._check() # needs sage.libs.flint True TESTS:: @@ -340,7 +340,7 @@ def _itgs(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P * P - sage: F.isotype_generating_series()[0:5] # optional - sage.libs.flint + sage: F.isotype_generating_series()[0:5] # needs sage.libs.flint [1, 2, 5, 10, 20] """ res = (self.left_factor().isotype_generating_series(base_ring) * @@ -355,7 +355,7 @@ def _cis(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P * P - sage: F.cycle_index_series()[0:5] # optional - sage.modules + sage: F.cycle_index_series()[0:5] # needs sage.modules [p[], 2*p[1], 3*p[1, 1] + 2*p[2], @@ -409,7 +409,7 @@ def _equation(self, var_mapping): sage: X = species.SingletonSpecies() sage: S = X * X - sage: S.algebraic_equation_system() # optional - sage.graphs + sage: S.algebraic_equation_system() # needs sage.graphs [node0 + (-z^2)] """ from sage.misc.misc_c import prod diff --git a/src/sage/combinat/species/recursive_species.py b/src/sage/combinat/species/recursive_species.py index a87bb27866b..8eaabf0d2a8 100644 --- a/src/sage/combinat/species/recursive_species.py +++ b/src/sage/combinat/species/recursive_species.py @@ -263,7 +263,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: F = CombinatorialSpecies() - sage: F.cycle_index_series() # optional - sage.modules + sage: F.cycle_index_series() # needs sage.modules Uninitialized Lazy Series """ if base_ring not in self._cycle_index_series: @@ -429,17 +429,17 @@ def _add_to_digraph(self, d): EXAMPLES:: - sage: d = DiGraph(multiedges=True) # optional - sage.graphs + sage: d = DiGraph(multiedges=True) # needs sage.graphs sage: X = species.SingletonSpecies() sage: B = species.CombinatorialSpecies() sage: B.define(X+B*B) - sage: B._add_to_digraph(d); d # optional - sage.graphs + sage: B._add_to_digraph(d); d # needs sage.graphs Multi-digraph on 4 vertices TESTS:: sage: C = species.CombinatorialSpecies() - sage: C._add_to_digraph(d) # optional - sage.graphs + sage: C._add_to_digraph(d) # needs sage.graphs Traceback (most recent call last): ... NotImplementedError @@ -461,7 +461,7 @@ def _equation(self, var_mapping): EXAMPLES:: sage: C = species.CombinatorialSpecies() - sage: C.algebraic_equation_system() # optional - sage.graphs + sage: C.algebraic_equation_system() # needs sage.graphs Traceback (most recent call last): ... NotImplementedError @@ -469,7 +469,7 @@ def _equation(self, var_mapping): :: sage: B = species.BinaryTreeSpecies() - sage: B.algebraic_equation_system() # optional - sage.graphs + sage: B.algebraic_equation_system() # needs sage.graphs [-node3^2 + node1, -node1 + node3 + (-z)] """ try: diff --git a/src/sage/combinat/species/set_species.py b/src/sage/combinat/species/set_species.py index 31020f8eb5e..94aa893cf46 100644 --- a/src/sage/combinat/species/set_species.py +++ b/src/sage/combinat/species/set_species.py @@ -57,8 +57,8 @@ def transport(self, perm): sage: F = species.SetSpecies() sage: a = F.structures(["a", "b", "c"]).random_element(); a {'a', 'b', 'c'} - sage: p = PermutationGroupElement((1,2)) # optional - sage.groups - sage: a.transport(p) # optional - sage.groups + sage: p = PermutationGroupElement((1,2)) # needs sage.groups + sage: a.transport(p) # needs sage.groups {'a', 'b', 'c'} """ return self @@ -74,7 +74,7 @@ def automorphism_group(self): sage: F = species.SetSpecies() sage: a = F.structures(["a", "b", "c"]).random_element(); a {'a', 'b', 'c'} - sage: a.automorphism_group() # optional - sage.groups + sage: a.automorphism_group() # needs sage.groups Symmetric group of order 3! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -170,8 +170,8 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: S = species.SetSpecies() - sage: g = S.cycle_index_series() # optional - sage.modules - sage: g[0:5] # optional - sage.modules + sage: g = S.cycle_index_series() # needs sage.modules + sage: g[0:5] # needs sage.modules [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], diff --git a/src/sage/combinat/species/species.py b/src/sage/combinat/species/species.py index 0efdb963981..2b505567433 100644 --- a/src/sage/combinat/species/species.py +++ b/src/sage/combinat/species/species.py @@ -24,12 +24,12 @@ sage: L = species.LinearOrderSpecies(min=1) sage: T = species.CombinatorialSpecies(min=1) sage: T.define(leaf + internal_node*L(T)) - sage: T.isotype_generating_series()[0:6] # optional - sage.modules + sage: T.isotype_generating_series()[0:6] # needs sage.modules [0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q] Consider the following:: - sage: T.isotype_generating_series().coefficient(4) # optional - sage.modules + sage: T.isotype_generating_series().coefficient(4) # needs sage.modules q^3 + 3*q^2 + q This means that, among the trees on `4` nodes, one has a @@ -335,7 +335,7 @@ def functorial_composition(self, g): sage: WP = species.SubsetSpecies() sage: P2 = E2*E sage: G = WP.functorial_composition(P2) - sage: G.isotype_generating_series()[0:5] # optional - sage.modules + sage: G.isotype_generating_series()[0:5] # needs sage.modules [1, 1, 2, 4, 11] """ from .functorial_composition_species import FunctorialCompositionSpecies @@ -401,7 +401,7 @@ def _check(self, n=5): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: P._check() # optional - sage.libs.flint + sage: P._check() # needs sage.libs.flint True """ st = self.structures(range(n)) @@ -448,7 +448,7 @@ def __pow__(self, n): sage: X^1 is X True sage: A = X^32 - sage: A.digraph() # optional - sage.graphs + sage: A.digraph() # needs sage.graphs Multi-digraph on 6 vertices TESTS:: @@ -622,13 +622,13 @@ def isotype_generating_series(self, base_ring=None): sage: P = species.PermutationSpecies() sage: g = P.isotype_generating_series() - sage: g[0:4] # optional - sage.libs.flint + sage: g[0:4] # needs sage.libs.flint [1, 1, 2, 3] - sage: g.counts(4) # optional - sage.libs.flint + sage: g.counts(4) # needs sage.libs.flint [1, 1, 2, 3] - sage: P.isotypes([1,2,3]).list() # optional - sage.libs.flint + sage: P.isotypes([1,2,3]).list() # needs sage.libs.flint [[2, 3, 1], [2, 1, 3], [1, 2, 3]] - sage: len(_) # optional - sage.libs.flint + sage: len(_) # needs sage.libs.flint 3 """ return self._get_series(OrdinaryGeneratingSeriesRing, "itgs", base_ring) @@ -643,8 +643,8 @@ def cycle_index_series(self, base_ring=None): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: g = P.cycle_index_series() # optional - sage.modules - sage: g[0:4] # optional - sage.modules + sage: g = P.cycle_index_series() # needs sage.modules + sage: g[0:4] # needs sage.modules [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3]] """ return self._get_series(CycleIndexSeriesRing, "cis", base_ring) @@ -710,19 +710,19 @@ def digraph(self): sage: X = species.SingletonSpecies() sage: B = species.CombinatorialSpecies() sage: B.define(X+B*B) - sage: g = B.digraph(); g # optional - sage.graphs + sage: g = B.digraph(); g # needs sage.graphs Multi-digraph on 4 vertices - sage: sorted(g, key=str) # optional - sage.graphs + sage: sorted(g, key=str) # needs sage.graphs [Combinatorial species, Product of (Combinatorial species) and (Combinatorial species), Singleton species, Sum of (Singleton species) and (Product of (Combinatorial species) and (Combinatorial species))] - sage: d = {sp: i for i, sp in enumerate(g)} # optional - sage.graphs - sage: g.relabel(d) # optional - sage.graphs - sage: g.canonical_label().edges(sort=True) # optional - sage.graphs + sage: d = {sp: i for i, sp in enumerate(g)} # needs sage.graphs + sage: g.relabel(d) # needs sage.graphs + sage: g.canonical_label().edges(sort=True) # needs sage.graphs [(0, 3, None), (2, 0, None), (2, 0, None), (3, 1, None), (3, 2, None)] """ from sage.graphs.digraph import DiGraph @@ -739,13 +739,13 @@ def _add_to_digraph(self, d): EXAMPLES:: - sage: d = DiGraph(multiedges=True) # optional - sage.graphs - sage: X = species.SingletonSpecies() # optional - sage.graphs - sage: X._add_to_digraph(d); d # optional - sage.graphs + sage: d = DiGraph(multiedges=True) # needs sage.graphs + sage: X = species.SingletonSpecies() # needs sage.graphs + sage: X._add_to_digraph(d); d # needs sage.graphs Multi-digraph on 1 vertex - sage: (X+X)._add_to_digraph(d); d # optional - sage.graphs + sage: (X+X)._add_to_digraph(d); d # needs sage.graphs Multi-digraph on 2 vertices - sage: d.edges(sort=True) # optional - sage.graphs + sage: d.edges(sort=True) # needs sage.graphs [(Sum of (Singleton species) and (Singleton species), Singleton species, None), (Sum of (Singleton species) and (Singleton species), Singleton species, None)] """ @@ -770,12 +770,12 @@ def algebraic_equation_system(self): EXAMPLES:: sage: B = species.BinaryTreeSpecies() - sage: B.algebraic_equation_system() # optional - sage.graphs + sage: B.algebraic_equation_system() # needs sage.graphs [-node3^2 + node1, -node1 + node3 + (-z)] :: - sage: sorted(B.digraph().vertex_iterator(), key=str) # optional - sage.graphs + sage: sorted(B.digraph().vertex_iterator(), key=str) # needs sage.graphs [Combinatorial species with min=1, Product of (Combinatorial species with min=1) and (Combinatorial species with min=1), @@ -786,7 +786,7 @@ def algebraic_equation_system(self): :: - sage: B.algebraic_equation_system()[0].parent() # optional - sage.graphs + sage: B.algebraic_equation_system()[0].parent() # needs sage.graphs Multivariate Polynomial Ring in node0, node1, node2, node3 over Fraction Field of Univariate Polynomial Ring in z over Rational Field """ diff --git a/src/sage/combinat/species/structure.py b/src/sage/combinat/species/structure.py index 6dc1fc2ea15..b3003ed0f13 100644 --- a/src/sage/combinat/species/structure.py +++ b/src/sage/combinat/species/structure.py @@ -16,8 +16,8 @@ sage: bar = species.EmptySetSpecies() sage: BB = CombinatorialSpecies() sage: BB.define(ball + ball*BB + ball*bar*BB) - sage: o = var('o') # optional - sage.symbolic - sage: BB.isotypes([o]*3).list() # optional - sage.symbolic + sage: o = var('o') # needs sage.symbolic + sage: BB.isotypes([o]*3).list() # needs sage.symbolic [o*(o*o), o*((o*{})*o), (o*{})*(o*o), (o*{})*((o*{})*o)] If we ignore the parentheses, we can read off that the integer @@ -277,9 +277,9 @@ def transport(self, perm): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: s = (P+P).structures([1,2,3])[1]; s # optional - sage.libs.flint + sage: s = (P+P).structures([1,2,3])[1]; s # needs sage.libs.flint {{1, 3}, {2}} - sage: s.transport(PermutationGroupElement((2,3))) # optional - sage.groups sage.libs.flint + sage: s.transport(PermutationGroupElement((2,3))) # needs sage.groups sage.libs.flint {{1, 2}, {3}} """ return self.__class__(self._parent, self._s.transport(perm), **self._options) @@ -289,9 +289,9 @@ def canonical_label(self): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: s = (P+P).structures([1,2,3])[1]; s # optional - sage.libs.flint + sage: s = (P+P).structures([1,2,3])[1]; s # needs sage.libs.flint {{1, 3}, {2}} - sage: s.canonical_label() # optional - sage.libs.flint + sage: s.canonical_label() # needs sage.libs.flint {{1, 2}, {3}} """ return self.__class__(self._parent, self._s.canonical_label(), **self._options) diff --git a/src/sage/combinat/species/subset_species.py b/src/sage/combinat/species/subset_species.py index 2d3b9f8dcb6..2e7a6697e29 100644 --- a/src/sage/combinat/species/subset_species.py +++ b/src/sage/combinat/species/subset_species.py @@ -74,11 +74,11 @@ def transport(self, perm): sage: F = species.SubsetSpecies() sage: a = F.structures(["a", "b", "c"])[5]; a {'a', 'c'} - sage: p = PermutationGroupElement((1,2)) # optional - sage.groups - sage: a.transport(p) # optional - sage.groups + sage: p = PermutationGroupElement((1,2)) # needs sage.groups + sage: a.transport(p) # needs sage.groups {'b', 'c'} - sage: p = PermutationGroupElement((1,3)) # optional - sage.groups - sage: a.transport(p) # optional - sage.groups + sage: p = PermutationGroupElement((1,3)) # needs sage.groups + sage: a.transport(p) # needs sage.groups {'a', 'c'} """ l = sorted([perm(i) for i in self._list]) @@ -94,12 +94,12 @@ def automorphism_group(self): sage: F = species.SubsetSpecies() sage: a = F.structures([1,2,3,4])[6]; a {1, 3} - sage: a.automorphism_group() # optional - sage.groups + sage: a.automorphism_group() # needs sage.groups Permutation Group with generators [(2,4), (1,3)] :: - sage: [a.transport(g) for g in a.automorphism_group()] # optional - sage.groups + sage: [a.transport(g) for g in a.automorphism_group()] # needs sage.groups [{1, 3}, {1, 3}, {1, 3}, {1, 3}] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup @@ -224,7 +224,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: S = species.SubsetSpecies() - sage: S.cycle_index_series()[0:5] # optional - sage.modules + sage: S.cycle_index_series()[0:5] # needs sage.modules [p[], 2*p[1], 2*p[1, 1] + p[2], diff --git a/src/sage/combinat/species/sum_species.py b/src/sage/combinat/species/sum_species.py index ac2e05943b3..b3ff129dc55 100644 --- a/src/sage/combinat/species/sum_species.py +++ b/src/sage/combinat/species/sum_species.py @@ -38,7 +38,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F._check() # optional - sage.libs.flint + sage: F._check() # needs sage.libs.flint True sage: F == loads(dumps(F)) True @@ -126,7 +126,7 @@ def _isotypes(self, structure_class, labels): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F.isotypes([1,2]).list() # optional - sage.libs.flint + sage: F.isotypes([1,2]).list() # needs sage.libs.flint [[2, 1], [1, 2], [2, 1], [1, 2]] """ for res in self._F.isotypes(labels): @@ -157,7 +157,7 @@ def _itgs(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F.isotype_generating_series()[:5] # optional - sage.libs.flint + sage: F.isotype_generating_series()[:5] # needs sage.libs.flint [2, 2, 4, 6, 10] """ return (self.left_summand().isotype_generating_series(base_ring) + @@ -171,7 +171,7 @@ def _cis(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F.cycle_index_series()[:5] # optional - sage.modules + sage: F.cycle_index_series()[:5] # needs sage.modules [2*p[], 2*p[1], 2*p[1, 1] + 2*p[2], @@ -214,7 +214,7 @@ def _equation(self, var_mapping): sage: X = species.SingletonSpecies() sage: S = X + X - sage: S.algebraic_equation_system() # optional - sage.graphs + sage: S.algebraic_equation_system() # needs sage.graphs [node1 + (-2*z)] """ return sum(var_mapping[operand] for operand in self._state_info) From bddb7fc8c5e89cbaa79a25225699436bc0820468 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 13 Jul 2023 23:26:30 -0700 Subject: [PATCH 145/538] sage.combinat.species: Update # needs --- .../combinat/species/composition_species.py | 19 ++++---- .../combinat/species/generating_series.py | 45 ++++++++++--------- .../combinat/species/partition_species.py | 2 +- src/sage/combinat/species/product_species.py | 22 ++++----- src/sage/combinat/species/species.py | 11 ++--- 5 files changed, 53 insertions(+), 46 deletions(-) diff --git a/src/sage/combinat/species/composition_species.py b/src/sage/combinat/species/composition_species.py index a60b0cbed89..b60e5348985 100644 --- a/src/sage/combinat/species/composition_species.py +++ b/src/sage/combinat/species/composition_species.py @@ -145,21 +145,22 @@ def _structures(self, structure_class, labels): TESTS:: - sage: a = _[2] # needs sage.libs.flint - sage: f, gs = a._list # needs sage.libs.flint - sage: f # needs sage.libs.flint + sage: # needs sage.libs.flint + sage: a = _[2] + sage: f, gs = a._list + sage: f {{'a', 'c'}, {'b'}} - sage: f.parent() # needs sage.libs.flint + sage: f.parent() Set species - sage: f._list # needs sage.libs.flint + sage: f._list [1, 2] - sage: f._labels # needs sage.libs.flint + sage: f._labels [{'a', 'c'}, {'b'}] - sage: [g.parent() for g in gs] # needs sage.libs.flint + sage: [g.parent() for g in gs] [Cyclic permutation species, Cyclic permutation species] - sage: [g._labels for g in gs] # needs sage.libs.flint + sage: [g._labels for g in gs] [['a', 'c'], ['b']] - sage: [g._list for g in gs] # needs sage.libs.flint + sage: [g._list for g in gs] [[1, 2], [1]] """ from itertools import product diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index 9c0515bbead..c585634d314 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -15,19 +15,20 @@ TESTS:: + sage: # needs sage.modules sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() # needs sage.modules - sage: CIS = CycleIndexSeriesRing(QQ) # needs sage.modules - sage: geo1 = CIS(lambda i: p([1])^i) # needs sage.modules - sage: geo2 = CIS(lambda i: p([2])^(i // 2) if is_even(i) else 0) # needs sage.modules - sage: s = geo1 * geo2 # needs sage.modules - sage: s[0] # needs sage.modules + sage: p = SymmetricFunctions(QQ).power() + sage: CIS = CycleIndexSeriesRing(QQ) + sage: geo1 = CIS(lambda i: p([1])^i) + sage: geo2 = CIS(lambda i: p([2])^(i // 2) if is_even(i) else 0) + sage: s = geo1 * geo2 + sage: s[0] p[] - sage: s[1] # needs sage.modules + sage: s[1] p[1] - sage: s[2] # needs sage.modules + sage: s[2] p[1, 1] + p[2] - sage: s[3] # needs sage.modules + sage: s[3] p[1, 1, 1] + p[2, 1] REFERENCES: @@ -292,15 +293,16 @@ def count(self, t): EXAMPLES:: + sage: # needs sage.modules sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() # needs sage.modules - sage: CIS = CycleIndexSeriesRing(QQ) # needs sage.modules - sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])]) # needs sage.modules - sage: f.count([1]) # needs sage.modules + sage: p = SymmetricFunctions(QQ).power() + sage: CIS = CycleIndexSeriesRing(QQ) + sage: f = CIS([0, p([1]), 2*p([1,1]), 3*p([2,1])]) + sage: f.count([1]) 1 - sage: f.count([1,1]) # needs sage.modules + sage: f.count([1,1]) 4 - sage: f.count([2,1]) # needs sage.modules + sage: f.count([2,1]) 6 """ t = Partition(t) @@ -312,15 +314,16 @@ def coefficient_cycle_type(self, t): EXAMPLES:: + sage: # needs sage.modules sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() # needs sage.modules - sage: CIS = CycleIndexSeriesRing(QQ) # needs sage.modules - sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])]) # needs sage.modules - sage: f.coefficient_cycle_type([1]) # needs sage.modules + sage: p = SymmetricFunctions(QQ).power() + sage: CIS = CycleIndexSeriesRing(QQ) + sage: f = CIS([0, p([1]), 2*p([1,1]),3*p([2,1])]) + sage: f.coefficient_cycle_type([1]) 1 - sage: f.coefficient_cycle_type([1,1]) # needs sage.modules + sage: f.coefficient_cycle_type([1,1]) 2 - sage: f.coefficient_cycle_type([2,1]) # needs sage.modules + sage: f.coefficient_cycle_type([2,1]) 3 """ t = Partition(t) diff --git a/src/sage/combinat/species/partition_species.py b/src/sage/combinat/species/partition_species.py index bd24f470402..21a57197ccd 100644 --- a/src/sage/combinat/species/partition_species.py +++ b/src/sage/combinat/species/partition_species.py @@ -273,7 +273,7 @@ def _cis(self, series_ring, base_ring): sage: P = species.PartitionSpecies() sage: g = P.cycle_index_series() # needs sage.modules - sage: g[0:5] + sage: g[0:5] # needs sage.modules [p[], p[1], p[1, 1] + p[2], diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index 41cd958532f..90209e64776 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -58,12 +58,13 @@ def transport(self, perm): """ EXAMPLES:: - sage: p = PermutationGroupElement((2,3)) # needs sage.groups - sage: S = species.SetSpecies() # needs sage.groups - sage: F = S * S # needs sage.groups - sage: a = F.structures(['a','b','c'])[4]; a # needs sage.groups + sage: # needs sage.groups + sage: p = PermutationGroupElement((2,3)) + sage: S = species.SetSpecies() + sage: F = S * S + sage: a = F.structures(['a','b','c'])[4]; a {'a', 'b'}*{'c'} - sage: a.transport(p) # needs sage.groups + sage: a.transport(p) {'a', 'c'}*{'b'} """ left, right = self._list @@ -151,12 +152,13 @@ def automorphism_group(self): """ EXAMPLES:: - sage: p = PermutationGroupElement((2,3)) # needs sage.groups - sage: S = species.SetSpecies() # needs sage.groups - sage: F = S * S # needs sage.groups - sage: a = F.structures([1,2,3,4])[1]; a # needs sage.groups + sage: # needs sage.groups + sage: p = PermutationGroupElement((2,3)) + sage: S = species.SetSpecies() + sage: F = S * S + sage: a = F.structures([1,2,3,4])[1]; a {1}*{2, 3, 4} - sage: a.automorphism_group() # needs sage.groups + sage: a.automorphism_group() Permutation Group with generators [(2,3), (2,3,4)] :: diff --git a/src/sage/combinat/species/species.py b/src/sage/combinat/species/species.py index 2b505567433..d3f1e9d3867 100644 --- a/src/sage/combinat/species/species.py +++ b/src/sage/combinat/species/species.py @@ -739,13 +739,14 @@ def _add_to_digraph(self, d): EXAMPLES:: - sage: d = DiGraph(multiedges=True) # needs sage.graphs - sage: X = species.SingletonSpecies() # needs sage.graphs - sage: X._add_to_digraph(d); d # needs sage.graphs + sage: # needs sage.graphs + sage: d = DiGraph(multiedges=True) + sage: X = species.SingletonSpecies() + sage: X._add_to_digraph(d); d Multi-digraph on 1 vertex - sage: (X+X)._add_to_digraph(d); d # needs sage.graphs + sage: (X+X)._add_to_digraph(d); d Multi-digraph on 2 vertices - sage: d.edges(sort=True) # needs sage.graphs + sage: d.edges(sort=True) [(Sum of (Singleton species) and (Singleton species), Singleton species, None), (Sum of (Singleton species) and (Singleton species), Singleton species, None)] """ From 02a8c740cc0ca9d0b6b255b52f4fa7dd10ff8d09 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 25 May 2023 17:51:07 -0700 Subject: [PATCH 146/538] sage.combinat: Modularization fixes for imports --- src/sage/combinat/words/suffix_trees.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/words/suffix_trees.py b/src/sage/combinat/words/suffix_trees.py index 5e4fa13ddea..59b3acb57d3 100644 --- a/src/sage/combinat/words/suffix_trees.py +++ b/src/sage/combinat/words/suffix_trees.py @@ -13,12 +13,15 @@ from itertools import chain from sage.structure.sage_object import SageObject -from sage.graphs.digraph import DiGraph from sage.sets.set import Set from sage.combinat.words.words import Words from sage.combinat.words.word import Word +from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer +lazy_import('sage.graphs.digraph', 'DiGraph') + + ################################################################################ # Suffix Tries ################################################################################ From d281815ebf8c330cd8d7b885dc5e2d8f16b8b16e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 3 Jun 2023 16:59:56 -0700 Subject: [PATCH 147/538] sage.combinat: Modularization fixes --- src/sage/combinat/words/finite_word.py | 5 +++-- src/sage/combinat/words/morphic.py | 10 +++++----- src/sage/combinat/words/morphism.py | 8 +++++--- src/sage/combinat/words/word.py | 4 +++- src/sage/combinat/words/word_generators.py | 4 +++- src/sage/combinat/words/words.py | 4 ++-- 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index bf355d9d10a..b5bb427373c 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -221,6 +221,7 @@ from sage.combinat.words.abstract_word import Word_class from sage.combinat.words.words import Words from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.combinat.words.word_options import word_options from sage.rings.infinity import Infinity from sage.rings.integer import Integer @@ -228,6 +229,8 @@ from sage.rings.rational_field import QQ from sage.sets.set import Set +lazy_import('sage.groups.perm_gps.permgroup_element', 'PermutationGroupElement') + class FiniteWord_class(Word_class): def __str__(self): @@ -6752,7 +6755,6 @@ def apply_permutation_to_positions(self, permutation): word: 3421 """ from sage.combinat.permutation import Permutation - from sage.groups.perm_gps.permgroup_element import PermutationGroupElement if not isinstance(permutation, Permutation): if isinstance(permutation, PermutationGroupElement): permutation = Permutation(permutation.domain()) @@ -6781,7 +6783,6 @@ def apply_permutation_to_letters(self, permutation): word: badc """ from sage.combinat.permutation import Permutation - from sage.groups.perm_gps.permgroup_element import PermutationGroupElement if not isinstance(permutation, Permutation): if isinstance(permutation, PermutationGroupElement): permutation = Permutation(permutation.domain()) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 389c37a9b65..d5c447403d0 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -14,8 +14,7 @@ Creation of the fixed point of a morphism:: sage: m = WordMorphism('a->abc,b->baba,c->ca') - sage: w = m.fixed_point('a') - sage: w + sage: w = m.fixed_point('a'); w word: abcbabacababaabcbabaabccaabcbabaabcbabaa... sage: w.length() +Infinity @@ -30,8 +29,10 @@ """ from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable +from sage.misc.lazy_import import lazy_import from sage.rings.infinity import Infinity -from sage.modules.free_module_element import vector + +lazy_import('sage.modules.free_module_element', 'import vector') class WordDatatype_morphic(WordDatatype_callable): @@ -78,8 +79,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): When the morphic word is finite:: sage: m = WordMorphism("a->ab,b->") - sage: w = m.fixed_point("a") - sage: w + sage: w = m.fixed_point("a"); w word: ab sage: w[0] # optional - sage.modules 'a' diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 7e04e8646d0..e618ccbdaeb 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -93,17 +93,19 @@ from sage.misc.callable_dict import CallableDict from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import from sage.misc.lazy_list import lazy_list from sage.sets.set import Set from sage.rings.rational_field import QQ from sage.rings.infinity import Infinity from sage.rings.integer_ring import IntegerRing from sage.rings.integer import Integer -from sage.modules.free_module_element import vector -from sage.matrix.constructor import Matrix from sage.combinat.words.word import FiniteWord_class from sage.combinat.words.words import FiniteWords, FiniteOrInfiniteWords +lazy_import('sage.modules.free_module_element', 'vector') +lazy_import('sage.matrix.constructor', 'Matrix') + def get_cycles(f, domain): r""" @@ -2084,7 +2086,7 @@ def language(self, n, u=None): A growing but non-primitive example. The DOL-languages generated by 0 and 2 are different:: - sage: s = WordMorphism({0: [0,1], 1:[0], 2:[2,0,2]}) + sage: s = WordMorphism({0: [0,1], 1: [0], 2: [2,0,2]}) sage: u = s.fixed_point(0) sage: A0 = u[:200].factor_set(5) diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index 4555c2df762..320bc3d9f0c 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -23,6 +23,7 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.misc.lazy_import import lazy_import from sage.combinat.words.word_char import WordDatatype_char from sage.combinat.words.abstract_word import Word_class from sage.combinat.words.finite_word import FiniteWord_class @@ -36,7 +37,8 @@ WordDatatype_callable_with_caching, WordDatatype_callable) from .morphic import WordDatatype_morphic -from sage.monoids.free_monoid_element import FreeMonoidElement + +lazy_import('sage.monoids.free_monoid_element', 'FreeMonoidElement') # TODO. Word needs to be replaced by Word. Consider renaming # Word_class to Word and imbedding Word as its __call__ method. diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index d7093ae997c..e21ab9a22b4 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -59,7 +59,6 @@ from random import randint from sage.misc.cachefunc import cached_method from sage.rings.integer_ring import ZZ -from sage.rings.real_mpfr import RR from sage.rings.infinity import Infinity from sage.combinat.words.abstract_word import Word_class from sage.combinat.words.word import FiniteWord_list @@ -68,6 +67,9 @@ from sage.combinat.words.morphism import WordMorphism from sage.arith.misc import gcd from sage.misc.decorators import rename_keyword +from sage.misc.lazy_import import lazy_import + +lazy_import('sage.rings.real_mpfr', 'RR') def _build_tab(sym, tab, W): diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index 63d6f1f0d05..8c23a452bc7 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -1973,7 +1973,7 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr sage: p.length() # optional - sage.modules 100 - Creation of a word path from a FiniteWord_callable:: + Creation of a word path from a :class:`FiniteWord_callable`:: sage: g = Word(lambda n: n%2, length=100) sage: P = WordPaths([0,1,2,3]) # optional - sage.modules @@ -1984,7 +1984,7 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr Creation of a word from a pickled function:: - sage: f = lambda n : n % 10 + sage: f = lambda n: n % 10 sage: from sage.misc.fpickle import pickle_function sage: s = pickle_function(f) sage: Word(s, datatype='pickled_function') From 4696b3d27464ab5dab1d0321757a605b161a6914 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 8 Jun 2023 18:33:43 -0700 Subject: [PATCH 148/538] sage.combinat: More # optional --- src/sage/combinat/words/finite_word.py | 6 +++--- src/sage/combinat/words/lyndon_word.py | 16 ++++++++-------- src/sage/combinat/words/morphic.py | 8 ++++---- src/sage/combinat/words/morphism.py | 26 +++++++++++++------------- src/sage/combinat/words/word_char.pyx | 4 ++-- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index b5bb427373c..bdb182ac6b9 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -1676,7 +1676,7 @@ def reduced_rauzy_graph(self, n): For ultimately periodic words:: sage: sigma = WordMorphism('a->abcd,b->cd,c->cd,d->cd') - sage: w = sigma.fixed_point('a')[:100]; w + sage: w = sigma.fixed_point('a')[:100]; w # optional - sage.modules word: abcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd... sage: g = w.reduced_rauzy_graph(5) # optional - sage.graphs sage: g.vertices(sort=True) # optional - sage.graphs @@ -6749,7 +6749,7 @@ def apply_permutation_to_positions(self, permutation): word: badc sage: w.apply_permutation_to_positions(Permutation([2,1,4,3])) word: badc - sage: w.apply_permutation_to_positions(PermutationGroupElement([2,1,4,3])) + sage: w.apply_permutation_to_positions(PermutationGroupElement([2,1,4,3])) # optional - sage.groups word: badc sage: Word([1,2,3,4]).apply_permutation_to_positions([3,4,2,1]) word: 3421 @@ -6779,7 +6779,7 @@ def apply_permutation_to_letters(self, permutation): word: dcba sage: w.apply_permutation_to_letters(Permutation(p)) word: badc - sage: w.apply_permutation_to_letters(PermutationGroupElement(p)) + sage: w.apply_permutation_to_letters(PermutationGroupElement(p)) # optional - sage.groups word: badc """ from sage.combinat.permutation import Permutation diff --git a/src/sage/combinat/words/lyndon_word.py b/src/sage/combinat/words/lyndon_word.py index 6adb96421e5..575d68c58bc 100644 --- a/src/sage/combinat/words/lyndon_word.py +++ b/src/sage/combinat/words/lyndon_word.py @@ -64,9 +64,9 @@ def LyndonWords(e=None, k=None): word: 1112 sage: LW.last() word: 2333 - sage: LW.random_element() # random + sage: LW.random_element() # random # optional - sage.libs.pari word: 1232 - sage: LW.cardinality() + sage: LW.cardinality() # optional - sage.libs.pari 18 If e is a (weak) composition, then it returns the class of Lyndon @@ -277,9 +277,9 @@ def cardinality(self): sage: LyndonWords([]).cardinality() 0 - sage: LyndonWords([2,2]).cardinality() + sage: LyndonWords([2,2]).cardinality() # optional - sage.libs.pari 1 - sage: LyndonWords([2,3,2]).cardinality() + sage: LyndonWords([2,3,2]).cardinality() # optional - sage.libs.pari 30 Check to make sure that the count matches up with the number of @@ -287,7 +287,7 @@ def cardinality(self): sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list() sage: lws = [LyndonWords(comp) for comp in comps] - sage: all(lw.cardinality() == len(lw.list()) for lw in lws) + sage: all(lw.cardinality() == len(lw.list()) for lw in lws) # optional - sage.libs.pari True """ evaluation = self._e @@ -417,7 +417,7 @@ def __call__(self, *args, **kwds): Make sure that the correct length is checked (:trac:`30186`):: sage: L = LyndonWords(2, 4) - sage: _ = L(L.random_element()) + sage: _ = L(L.random_element()) # optional - sage.libs.pari """ w = self._words(*args, **kwds) if kwds.get('check', True) and not w.is_lyndon(): @@ -443,7 +443,7 @@ def cardinality(self): """ TESTS:: - sage: [ LyndonWords(3,i).cardinality() for i in range(1, 11) ] + sage: [ LyndonWords(3,i).cardinality() for i in range(1, 11) ] # optional - sage.libs.pari [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880] """ if self._k == 0: @@ -470,7 +470,7 @@ def __iter__(self): sage: sum(1 for lw in LyndonWords(1, 1000)) 0 - sage: list(LyndonWords(1, 1)) + sage: list(LyndonWords(1, 1)) # optional - sage.libs.pari [word: 1] """ W = self._words._element_classes['list'] diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index d5c447403d0..96390756bfb 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -255,11 +255,11 @@ def _func(self, key): sage: m = WordMorphism("a->ab,b->a") sage: w = m.fixed_point("a") - sage: w[0] + sage: w[0] # optional - sage.modules 'a' - sage: w[5] + sage: w[5] # optional - sage.modules 'a' - sage: w[10000] + sage: w[10000] # optional - sage.modules 'a' TESTS: @@ -271,7 +271,7 @@ def _func(self, key): sage: W = m.domain() sage: from sage.combinat.words.morphic import WordDatatype_morphic sage: w = WordDatatype_morphic(W, m, 'a') - sage: w._func(5) + sage: w._func(5) # optional - sage.modules 'a' """ diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index e618ccbdaeb..e46f7f9d075 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -1590,25 +1590,25 @@ def is_primitive(self): EXAMPLES:: sage: tm = WordMorphism('a->ab,b->ba') - sage: tm.is_primitive() + sage: tm.is_primitive() # optional - sage.modules True sage: fibo = WordMorphism('a->ab,b->a') - sage: fibo.is_primitive() + sage: fibo.is_primitive() # optional - sage.modules True sage: m = WordMorphism('a->bb,b->aa') - sage: m.is_primitive() + sage: m.is_primitive() # optional - sage.modules False sage: f = WordMorphism({0:[1],1:[0]}) - sage: f.is_primitive() + sage: f.is_primitive() # optional - sage.modules False :: sage: s = WordMorphism('a->b,b->c,c->ab') - sage: s.is_primitive() + sage: s.is_primitive() # optional - sage.modules True sage: s = WordMorphism('a->b,b->c,c->d,d->e,e->f,f->g,g->h,h->ab') - sage: s.is_primitive() + sage: s.is_primitive() # optional - sage.modules True TESTS:: @@ -1618,8 +1618,8 @@ def is_primitive(self): Traceback (most recent call last): ... TypeError: self (=a->bb, b->aac) is not an endomorphism - sage: m = WordMorphism('a->,b->',codomain=Words('ab')) - sage: m.is_primitive() + sage: m = WordMorphism('a->,b->', codomain=Words('ab')) + sage: m.is_primitive() # optional - sage.modules False sage: m = WordMorphism('a->,b->') sage: m.is_primitive() @@ -1683,9 +1683,9 @@ def is_prolongable(self, letter): :: - sage: n0, n1 = matrix(2,[1,1,1,0]), matrix(2,[2,1,1,0]) - sage: n = {'a':n0, 'b':n1} - sage: WordMorphism(n).is_prolongable(letter='a') #todo: not implemented + sage: n0, n1 = matrix(2,[1,1,1,0]), matrix(2,[2,1,1,0]) # optional - sage.modules + sage: n = {'a':n0, 'b':n1} # optional - sage.modules + sage: WordMorphism(n).is_prolongable(letter='a') # todo: not implemented # optional - sage.modules Traceback (most recent call last): ... TypeError: codomain of self must be an instance of Words @@ -2089,7 +2089,7 @@ def language(self, n, u=None): sage: s = WordMorphism({0: [0,1], 1: [0], 2: [2,0,2]}) sage: u = s.fixed_point(0) - sage: A0 = u[:200].factor_set(5) + sage: A0 = u[:200].factor_set(5) # optional - sage.modules sage: B0 = s.language(5, [0]) # optional - sage.modules sage: set(A0) == B0 # optional - sage.modules True @@ -2888,7 +2888,7 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, sage: t = WordMorphism("a->aC,b->d,C->de,d->a,e->ab") # substitution found by Julien Bernat sage: V = [vector((0,0,1,0,-1)), vector((0,0,1,-1,0))] # optional - sage.modules - sage: S = set(map(tuple, [i*V[0] + j*V[1] + sage: S = set(map(tuple, [i*V[0] + j*V[1] # optional - sage.modules ....: for i in [-1,0,1] for j in [-1,0,1]])) sage: t.rauzy_fractal_plot(n=10000, # not tested (> 1 second) ....: translate=S, exchange=true) diff --git a/src/sage/combinat/words/word_char.pyx b/src/sage/combinat/words/word_char.pyx index f2b7b47edb2..31f642ffc65 100644 --- a/src/sage/combinat/words/word_char.pyx +++ b/src/sage/combinat/words/word_char.pyx @@ -716,9 +716,9 @@ cdef class WordDatatype_char(WordDatatype): sage: W = Words([0,1]) sage: w = words.FibonacciWord() sage: w = W(list(w[:5000])) - sage: L = [[len(w[n:].longest_common_prefix(w[n+fibonacci(i):])) + sage: L = [[len(w[n:].longest_common_prefix(w[n+fibonacci(i):])) # optional - sage.libs.pari ....: for i in range(5,15)] for n in range(1,1000)] - sage: for n,l in enumerate(L): + sage: for n,l in enumerate(L): # optional - sage.libs.pari ....: if l.count(0) > 4: ....: print("{} {}".format(n+1,l)) 375 [0, 13, 0, 34, 0, 89, 0, 233, 0, 233] From 0e31af803a4f84a93703617689a348b47238c9c8 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 9 Jun 2023 00:55:41 -0700 Subject: [PATCH 149/538] More # optional --- src/sage/combinat/words/morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index e46f7f9d075..6e11f5db4c9 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -2095,7 +2095,7 @@ def language(self, n, u=None): True sage: v = s.fixed_point(2) - sage: A2 = v[:200].factor_set(5) + sage: A2 = v[:200].factor_set(5) # optional - sage.modules sage: B2 = s.language(5, [2]) # optional - sage.modules sage: set(A2) == B2 # optional - sage.modules True From 9aa2aa470446581cca4a1a1da25c7af6f965a858 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Jun 2023 17:49:30 -0700 Subject: [PATCH 150/538] More # optional --- src/sage/combinat/words/morphism.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 6e11f5db4c9..5fc7d5e62b7 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -709,7 +709,7 @@ def __call__(self, w, order=1): sage: tm('a', 6.7) Traceback (most recent call last): ... - TypeError: order (6.70000000000000) must be a non-negative integer or plus Infinity + TypeError: order (6.7...) must be a non-negative integer or plus Infinity Only the first letter is considered for infinitely iterated image of a word under a morphism:: @@ -976,7 +976,7 @@ def __pow__(self, exp): sage: m^1.5 Traceback (most recent call last): ... - ValueError: exponent (1.50000000000000) must be an integer + ValueError: exponent (1.5...) must be an integer sage: m^-2 Traceback (most recent call last): ... @@ -2100,7 +2100,7 @@ def language(self, n, u=None): sage: set(A2) == B2 # optional - sage.modules True - sage: len(A0), len(A2) + sage: len(A0), len(A2) # optional - sage.modules (6, 20) The Chacon transformation (non-primitive):: From 91e44aa1caae5a8113f5811e5ca04a320c4d6bed Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Jun 2023 23:46:00 -0700 Subject: [PATCH 151/538] sage.combinat: More # optional --- src/sage/combinat/words/finite_word.py | 2 +- src/sage/combinat/words/morphic.py | 2 +- src/sage/combinat/words/paths.py | 3 ++- src/sage/combinat/words/word_generators.py | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index bdb182ac6b9..9fe6dc815c0 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -5977,7 +5977,7 @@ def is_sturmian_factor(self): sage: words.LowerMechanicalWord(random(),alphabet='01')[:100].is_sturmian_factor() True - sage: words.CharacteristicSturmianWord(random())[:100].is_sturmian_factor() + sage: words.CharacteristicSturmianWord(random())[:100].is_sturmian_factor() # optional - sage.rings.real_mpfr True :: diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 96390756bfb..73d4973af85 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -32,7 +32,7 @@ from sage.misc.lazy_import import lazy_import from sage.rings.infinity import Infinity -lazy_import('sage.modules.free_module_element', 'import vector') +lazy_import('sage.modules.free_module_element', 'vector') class WordDatatype_morphic(WordDatatype_callable): diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index cc4aecd250b..ae78cb206b9 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -188,7 +188,6 @@ lazy_import("sage.plot.all", ["arrow", "line", "polygon", "point", "Graphics"]) from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ -from sage.rings.number_field.number_field import QuadraticField from sage.rings.real_mpfr import RR from .word_datatypes import (WordDatatype_str, WordDatatype_list, @@ -202,6 +201,8 @@ WordDatatype_callable) from sage.matrix.constructor import vector_on_axis_rotation_matrix +lazy_import('sage.rings.number_field.number_field', 'QuadraticField') + ####################################################################### # # diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index e21ab9a22b4..54d8a96f637 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -778,9 +778,9 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): sage: words.CharacteristicSturmianWord(1/golden_ratio^2) # optional - sage.symbolic word: 0100101001001010010100100101001001010010... - sage: words.CharacteristicSturmianWord(4/5) + sage: words.CharacteristicSturmianWord(4/5) # optional - sage.rings.real_mpfr word: 11110 - sage: words.CharacteristicSturmianWord(5/14) + sage: words.CharacteristicSturmianWord(5/14) # optional - sage.rings.real_mpfr word: 01001001001001 sage: words.CharacteristicSturmianWord(pi - 3) # optional - sage.symbolic word: 0000001000000100000010000001000000100000... From 2e33391db782ec01029cbe384f5690b69443fea9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 12 Jul 2023 17:59:24 -0700 Subject: [PATCH 152/538] ./sage -fixdoctests --distribution sagemath-categories --only-tags src/sage/combinat --- src/sage/combinat/words/abstract_word.py | 10 +- src/sage/combinat/words/alphabet.py | 6 +- src/sage/combinat/words/finite_word.py | 96 ++++++++-------- src/sage/combinat/words/lyndon_word.py | 16 +-- src/sage/combinat/words/morphic.py | 36 +++--- src/sage/combinat/words/morphism.py | 126 ++++++++++----------- src/sage/combinat/words/paths.py | 84 +++++++------- src/sage/combinat/words/suffix_trees.py | 26 ++--- src/sage/combinat/words/word.py | 2 +- src/sage/combinat/words/word_char.pyx | 4 +- src/sage/combinat/words/word_generators.py | 88 +++++++------- src/sage/combinat/words/words.py | 44 +++---- 12 files changed, 269 insertions(+), 269 deletions(-) diff --git a/src/sage/combinat/words/abstract_word.py b/src/sage/combinat/words/abstract_word.py index 610dba1437a..eaf5cbd4975 100644 --- a/src/sage/combinat/words/abstract_word.py +++ b/src/sage/combinat/words/abstract_word.py @@ -1476,24 +1476,24 @@ def sum_digits(self, base=2, mod=None): Sum of digits modulo 2 of the prime numbers written in base 2:: - sage: Word(primes(1000)).sum_digits() # optional - sage.libs.pari + sage: Word(primes(1000)).sum_digits() # needs sage.libs.pari word: 1001110100111010111011001011101110011011... Sum of digits modulo 3 of the prime numbers written in base 3:: - sage: Word(primes(1000)).sum_digits(base=3) # optional - sage.libs.pari + sage: Word(primes(1000)).sum_digits(base=3) # needs sage.libs.pari word: 2100002020002221222121022221022122111022... - sage: Word(primes(1000)).sum_digits(base=3, mod=3) # optional - sage.libs.pari + sage: Word(primes(1000)).sum_digits(base=3, mod=3) # needs sage.libs.pari word: 2100002020002221222121022221022122111022... Sum of digits modulo 2 of the prime numbers written in base 3:: - sage: Word(primes(1000)).sum_digits(base=3, mod=2) # optional - sage.libs.pari + sage: Word(primes(1000)).sum_digits(base=3, mod=2) # needs sage.libs.pari word: 0111111111111111111111111111111111111111... Sum of digits modulo 7 of the prime numbers written in base 10:: - sage: Word(primes(1000)).sum_digits(base=10, mod=7) # optional - sage.libs.pari + sage: Word(primes(1000)).sum_digits(base=10, mod=7) # needs sage.libs.pari word: 2350241354435041006132432241353546006304... Negative entries:: diff --git a/src/sage/combinat/words/alphabet.py b/src/sage/combinat/words/alphabet.py index 3289ad5aa1a..1de8838df00 100644 --- a/src/sage/combinat/words/alphabet.py +++ b/src/sage/combinat/words/alphabet.py @@ -192,15 +192,15 @@ def build_alphabet(data=None, names=None, name=None): Traceback (most recent call last): ... ValueError: invalid value for names - sage: Alphabet(8, x) # optional - sage.symbolic + sage: Alphabet(8, x) # needs sage.symbolic Traceback (most recent call last): ... ValueError: invalid value for names - sage: Alphabet(name=x, names="punctuation") # optional - sage.symbolic + sage: Alphabet(name=x, names="punctuation") # needs sage.symbolic Traceback (most recent call last): ... ValueError: name cannot be specified with any other argument - sage: Alphabet(x) # optional - sage.symbolic + sage: Alphabet(x) # needs sage.symbolic Traceback (most recent call last): ... ValueError: unable to construct an alphabet from the given parameters diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 9fe6dc815c0..d43624c8ebe 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -136,7 +136,7 @@ sage: st = w.suffix_tree() sage: st Implicit Suffix Tree of the word: abaabbba - sage: st.show(word_labels=True) # optional - sage.plot + sage: st.show(word_labels=True) # needs sage.plot :: @@ -190,9 +190,9 @@ Rauzy graphs:: sage: f = words.FibonacciWord()[:30] - sage: f.rauzy_graph(4) # optional - sage.graphs + sage: f.rauzy_graph(4) # needs sage.graphs Looped digraph on 5 vertices - sage: f.reduced_rauzy_graph(4) # optional - sage.graphs + sage: f.reduced_rauzy_graph(4) # needs sage.graphs Looped multi-digraph on 2 vertices Left-special and bispecial factors:: @@ -1464,16 +1464,16 @@ def topological_entropy(self, n): sage: W = Words([0, 1]) sage: w = W([0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1]) - sage: t = w.topological_entropy(3); t # optional - sage.symbolic + sage: t = w.topological_entropy(3); t # needs sage.symbolic 1/3*log(7)/log(2) - sage: n(t) # optional - sage.symbolic + sage: n(t) # needs sage.symbolic 0.935784974019201 :: sage: w = words.ThueMorseWord()[:100] sage: topo = w.topological_entropy - sage: for i in range(0, 41, 5): # optional - sage.symbolic + sage: for i in range(0, 41, 5): # needs sage.symbolic ....: print("{} {}".format(i, n(topo(i), digits=5))) 0 1.0000 5 0.71699 @@ -1497,7 +1497,7 @@ def topological_entropy(self, n): sage: W = Words(range(20)) sage: w = W(range(20)) - sage: w.topological_entropy(3) # optional - sage.symbolic + sage: w.topological_entropy(3) # needs sage.symbolic 1/3*log(18)/log(20) """ d = self.parent().alphabet().cardinality() @@ -1525,12 +1525,12 @@ def rauzy_graph(self, n): sage: w = Word(range(10)); w word: 0123456789 - sage: g = w.rauzy_graph(3); g # optional - sage.graphs + sage: g = w.rauzy_graph(3); g # needs sage.graphs Looped digraph on 8 vertices sage: WordOptions(identifier='') - sage: g.vertices(sort=True) # optional - sage.graphs + sage: g.vertices(sort=True) # needs sage.graphs [012, 123, 234, 345, 456, 567, 678, 789] - sage: g.edges(sort=True) # optional - sage.graphs + sage: g.edges(sort=True) # needs sage.graphs [(012, 123, 3), (123, 234, 4), (234, 345, 5), @@ -1543,20 +1543,20 @@ def rauzy_graph(self, n): :: sage: f = words.FibonacciWord()[:100] - sage: f.rauzy_graph(8) # optional - sage.graphs + sage: f.rauzy_graph(8) # needs sage.graphs Looped digraph on 9 vertices :: sage: w = Word('1111111') - sage: g = w.rauzy_graph(3) # optional - sage.graphs - sage: g.edges(sort=True) # optional - sage.graphs + sage: g = w.rauzy_graph(3) # needs sage.graphs + sage: g.edges(sort=True) # needs sage.graphs [(word: 111, word: 111, word: 1)] :: sage: w = Word('111') - sage: for i in range(5): w.rauzy_graph(i) # optional - sage.graphs + sage: for i in range(5): w.rauzy_graph(i) # needs sage.graphs Looped multi-digraph on 1 vertex Looped digraph on 1 vertex Looped digraph on 1 vertex @@ -1567,9 +1567,9 @@ def rauzy_graph(self, n): sage: W = Words('abcde') sage: w = W('abc') - sage: w.rauzy_graph(0) # optional - sage.graphs + sage: w.rauzy_graph(0) # needs sage.graphs Looped multi-digraph on 1 vertex - sage: _.edges(sort=True) # optional - sage.graphs + sage: _.edges(sort=True) # needs sage.graphs [(word: , word: , word: a), (word: , word: , word: b), (word: , word: , word: c)] @@ -1636,21 +1636,21 @@ def reduced_rauzy_graph(self, n): sage: w = Word(range(10)); w word: 0123456789 - sage: g = w.reduced_rauzy_graph(3); g # optional - sage.graphs + sage: g = w.reduced_rauzy_graph(3); g # needs sage.graphs Looped multi-digraph on 2 vertices - sage: g.vertices(sort=True) # optional - sage.graphs + sage: g.vertices(sort=True) # needs sage.graphs [word: 012, word: 789] - sage: g.edges(sort=True) # optional - sage.graphs + sage: g.edges(sort=True) # needs sage.graphs [(word: 012, word: 789, word: 3456789)] For the Fibonacci word:: sage: f = words.FibonacciWord()[:100] - sage: g = f.reduced_rauzy_graph(8);g # optional - sage.graphs + sage: g = f.reduced_rauzy_graph(8);g # needs sage.graphs Looped multi-digraph on 2 vertices - sage: g.vertices(sort=True) # optional - sage.graphs + sage: g.vertices(sort=True) # needs sage.graphs [word: 01001010, word: 01010010] - sage: g.edges(sort=True) # optional - sage.graphs + sage: g.edges(sort=True) # needs sage.graphs [(word: 01001010, word: 01010010, word: 010), (word: 01010010, word: 01001010, word: 01010), (word: 01010010, word: 01001010, word: 10)] @@ -1659,14 +1659,14 @@ def reduced_rauzy_graph(self, n): sage: from itertools import cycle sage: w = Word(cycle('abcd'))[:100] - sage: g = w.reduced_rauzy_graph(3) # optional - sage.graphs - sage: g.edges(sort=True) # optional - sage.graphs + sage: g = w.reduced_rauzy_graph(3) # needs sage.graphs + sage: g.edges(sort=True) # needs sage.graphs [(word: abc, word: abc, word: dabc)] :: sage: w = Word('111') - sage: for i in range(5): w.reduced_rauzy_graph(i) # optional - sage.graphs + sage: for i in range(5): w.reduced_rauzy_graph(i) # needs sage.graphs Looped digraph on 1 vertex Looped digraph on 1 vertex Looped digraph on 1 vertex @@ -1676,12 +1676,12 @@ def reduced_rauzy_graph(self, n): For ultimately periodic words:: sage: sigma = WordMorphism('a->abcd,b->cd,c->cd,d->cd') - sage: w = sigma.fixed_point('a')[:100]; w # optional - sage.modules + sage: w = sigma.fixed_point('a')[:100]; w # needs sage.modules word: abcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd... - sage: g = w.reduced_rauzy_graph(5) # optional - sage.graphs - sage: g.vertices(sort=True) # optional - sage.graphs + sage: g = w.reduced_rauzy_graph(5) # needs sage.graphs + sage: g.vertices(sort=True) # needs sage.graphs [word: abcdc, word: cdcdc] - sage: g.edges(sort=True) # optional - sage.graphs + sage: g.edges(sort=True) # needs sage.graphs [(word: abcdc, word: cdcdc, word: dc), (word: cdcdc, word: cdcdc, word: dc)] AUTHOR: @@ -3099,9 +3099,9 @@ def defect(self, f=None): sage: sa = WordMorphism('a->ab,b->b') sage: sb = WordMorphism('a->a,b->ba') sage: w = (sa*sb*sb*sa*sa*sa*sb).fixed_point('a') - sage: w[:30].defect() # optional - sage.modules + sage: w[:30].defect() # needs sage.modules 0 - sage: w[110:140].defect() # optional - sage.modules + sage: w[110:140].defect() # needs sage.modules 0 It is even conjectured that the defect of an aperiodic word which is @@ -3109,11 +3109,11 @@ def defect(self, f=None): (see [BBGL2008]_):: sage: w = words.ThueMorseWord() - sage: w[:50].defect() # optional - sage.modules + sage: w[:50].defect() # needs sage.modules 12 - sage: w[:100].defect() # optional - sage.modules + sage: w[:100].defect() # needs sage.modules 16 - sage: w[:300].defect() # optional - sage.modules + sage: w[:300].defect() # needs sage.modules 52 For generalized defect with an involution different from the identity, @@ -5977,7 +5977,7 @@ def is_sturmian_factor(self): sage: words.LowerMechanicalWord(random(),alphabet='01')[:100].is_sturmian_factor() True - sage: words.CharacteristicSturmianWord(random())[:100].is_sturmian_factor() # optional - sage.rings.real_mpfr + sage: words.CharacteristicSturmianWord(random())[:100].is_sturmian_factor() # needs sage.rings.real_mpfr True :: @@ -6749,7 +6749,7 @@ def apply_permutation_to_positions(self, permutation): word: badc sage: w.apply_permutation_to_positions(Permutation([2,1,4,3])) word: badc - sage: w.apply_permutation_to_positions(PermutationGroupElement([2,1,4,3])) # optional - sage.groups + sage: w.apply_permutation_to_positions(PermutationGroupElement([2,1,4,3])) # needs sage.groups word: badc sage: Word([1,2,3,4]).apply_permutation_to_positions([3,4,2,1]) word: 3421 @@ -6779,7 +6779,7 @@ def apply_permutation_to_letters(self, permutation): word: dcba sage: w.apply_permutation_to_letters(Permutation(p)) word: badc - sage: w.apply_permutation_to_letters(PermutationGroupElement(p)) # optional - sage.groups + sage: w.apply_permutation_to_letters(PermutationGroupElement(p)) # needs sage.groups word: badc """ from sage.combinat.permutation import Permutation @@ -6824,18 +6824,18 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn EXAMPLES:: - sage: Word(range(20)).colored_vector() # optional - sage.plot + sage: Word(range(20)).colored_vector() # needs sage.plot Graphics object consisting of 21 graphics primitives - sage: Word(range(100)).colored_vector(0,0,10,1) # optional - sage.plot + sage: Word(range(100)).colored_vector(0,0,10,1) # needs sage.plot Graphics object consisting of 101 graphics primitives - sage: Words(range(100))(range(10)).colored_vector() # optional - sage.plot + sage: Words(range(100))(range(10)).colored_vector() # needs sage.plot Graphics object consisting of 11 graphics primitives sage: w = Word('abbabaab') - sage: w.colored_vector() # optional - sage.plot + sage: w.colored_vector() # needs sage.plot Graphics object consisting of 9 graphics primitives - sage: w.colored_vector(cmap='autumn') # optional - sage.plot + sage: w.colored_vector(cmap='autumn') # needs sage.plot Graphics object consisting of 9 graphics primitives - sage: Word(range(20)).colored_vector(label='Rainbow') # optional - sage.plot + sage: Word(range(20)).colored_vector(label='Rainbow') # needs sage.plot Graphics object consisting of 23 graphics primitives When two words are defined under the same parent, same letters are @@ -6844,25 +6844,25 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn sage: W = Words(range(20)) sage: w = W(range(20)) sage: y = W(range(10,20)) - sage: y.colored_vector(y=1, x=10) + w.colored_vector() # optional - sage.plot + sage: y.colored_vector(y=1, x=10) + w.colored_vector() # needs sage.plot Graphics object consisting of 32 graphics primitives TESTS: The empty word:: - sage: Word().colored_vector() # optional - sage.plot + sage: Word().colored_vector() # needs sage.plot Graphics object consisting of 1 graphics primitive - sage: Word().colored_vector(label='empty') # optional - sage.plot + sage: Word().colored_vector(label='empty') # needs sage.plot Graphics object consisting of 3 graphics primitives Unknown cmap:: - sage: Word(range(100)).colored_vector(cmap='jolies') # optional - sage.plot + sage: Word(range(100)).colored_vector(cmap='jolies') # needs sage.plot Traceback (most recent call last): ... RuntimeError: Color map jolies not known - sage: Word(range(100)).colored_vector(cmap='__doc__') # optional - sage.plot + sage: Word(range(100)).colored_vector(cmap='__doc__') # needs sage.plot Traceback (most recent call last): ... RuntimeError: Color map __doc__ not known diff --git a/src/sage/combinat/words/lyndon_word.py b/src/sage/combinat/words/lyndon_word.py index 575d68c58bc..4c978680380 100644 --- a/src/sage/combinat/words/lyndon_word.py +++ b/src/sage/combinat/words/lyndon_word.py @@ -64,9 +64,9 @@ def LyndonWords(e=None, k=None): word: 1112 sage: LW.last() word: 2333 - sage: LW.random_element() # random # optional - sage.libs.pari + sage: LW.random_element() # random # needs sage.libs.pari word: 1232 - sage: LW.cardinality() # optional - sage.libs.pari + sage: LW.cardinality() # needs sage.libs.pari 18 If e is a (weak) composition, then it returns the class of Lyndon @@ -277,9 +277,9 @@ def cardinality(self): sage: LyndonWords([]).cardinality() 0 - sage: LyndonWords([2,2]).cardinality() # optional - sage.libs.pari + sage: LyndonWords([2,2]).cardinality() # needs sage.libs.pari 1 - sage: LyndonWords([2,3,2]).cardinality() # optional - sage.libs.pari + sage: LyndonWords([2,3,2]).cardinality() # needs sage.libs.pari 30 Check to make sure that the count matches up with the number of @@ -287,7 +287,7 @@ def cardinality(self): sage: comps = [[],[2,2],[3,2,7],[4,2]] + Compositions(4).list() sage: lws = [LyndonWords(comp) for comp in comps] - sage: all(lw.cardinality() == len(lw.list()) for lw in lws) # optional - sage.libs.pari + sage: all(lw.cardinality() == len(lw.list()) for lw in lws) # needs sage.libs.pari True """ evaluation = self._e @@ -417,7 +417,7 @@ def __call__(self, *args, **kwds): Make sure that the correct length is checked (:trac:`30186`):: sage: L = LyndonWords(2, 4) - sage: _ = L(L.random_element()) # optional - sage.libs.pari + sage: _ = L(L.random_element()) # needs sage.libs.pari """ w = self._words(*args, **kwds) if kwds.get('check', True) and not w.is_lyndon(): @@ -443,7 +443,7 @@ def cardinality(self): """ TESTS:: - sage: [ LyndonWords(3,i).cardinality() for i in range(1, 11) ] # optional - sage.libs.pari + sage: [ LyndonWords(3,i).cardinality() for i in range(1, 11) ] # needs sage.libs.pari [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880] """ if self._k == 0: @@ -470,7 +470,7 @@ def __iter__(self): sage: sum(1 for lw in LyndonWords(1, 1000)) 0 - sage: list(LyndonWords(1, 1)) # optional - sage.libs.pari + sage: list(LyndonWords(1, 1)) # needs sage.libs.pari [word: 1] """ W = self._words._element_classes['list'] diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index 73d4973af85..0db7a8db6fe 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -23,7 +23,7 @@ abstract numeration system associated to the morphism and the starting letter, see chapter 3 of the book [BR2010b]_:: - sage: w[10000000] # optional - sage.modules + sage: w[10000000] # needs sage.modules 'b' """ @@ -58,7 +58,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: w = m.fixed_point('a') sage: w word: abaababaabaababaababaabaababaabaababaaba... - sage: w[555:1000] # optional - sage.modules + sage: w[555:1000] # needs sage.modules word: abaababaabaababaababaabaababaabaababaaba... sage: w.length() +Infinity @@ -69,11 +69,11 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: m.fixed_point('a') word: abcbabacababaabcbabaabccaabcbabaabcbabaa... sage: w = m.fixed_point('a') - sage: w[7] # optional - sage.modules + sage: w[7] # needs sage.modules 'c' - sage: w[2:7] # optional - sage.modules + sage: w[2:7] # needs sage.modules word: cbaba - sage: w[500:503] # optional - sage.modules + sage: w[500:503] # needs sage.modules word: caa When the morphic word is finite:: @@ -81,7 +81,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: m = WordMorphism("a->ab,b->") sage: w = m.fixed_point("a"); w word: ab - sage: w[0] # optional - sage.modules + sage: w[0] # needs sage.modules 'a' sage: w.length() 2 @@ -93,7 +93,7 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: from sage.combinat.words.morphic import WordDatatype_morphic sage: coding = {'a':'x', 'b':'y'} sage: w = WordDatatype_morphic(W, m, 'a', coding=coding) - sage: [w[i] for i in range(10)] # optional - sage.modules + sage: [w[i] for i in range(10)] # needs sage.modules ['x', 'y', 'x', 'x', 'y', 'x', 'y', 'x', 'x', 'y'] TESTS:: @@ -104,9 +104,9 @@ def __init__(self, parent, morphism, letter, coding=None, length=Infinity): sage: for _ in range(10000): _ = next(it) sage: L = [next(it) for _ in range(10)]; L ['d', 'd', 'd', 'c', 'd', 'd', 'd', 'c', 'b', 'a'] - sage: w[10000:10010] # optional - sage.modules + sage: w[10000:10010] # needs sage.modules word: dddcdddcba - sage: list(w[10000:10010]) == L # optional - sage.modules + sage: list(w[10000:10010]) == L # needs sage.modules True """ @@ -177,18 +177,18 @@ def representation(self, n): sage: m = WordMorphism('a->ab,b->a') sage: w = m.fixed_point('a') - sage: w.representation(5) # optional - sage.modules + sage: w.representation(5) # needs sage.modules [1, 0, 0, 0] When the morphic word is finite:: sage: m = WordMorphism("a->ab,b->,c->cdab,d->dcab") sage: w = m.fixed_point("a") - sage: w.representation(0) # optional - sage.modules + sage: w.representation(0) # needs sage.modules [] - sage: w.representation(1) # optional - sage.modules + sage: w.representation(1) # needs sage.modules [1] - sage: w.representation(2) # optional - sage.modules + sage: w.representation(2) # needs sage.modules Traceback (most recent call last): ... IndexError: index (=2) out of range, the fixed point is finite and has length 2 @@ -204,7 +204,7 @@ def representation(self, n): sage: w = WordDatatype_morphic(W, m, 'a') sage: type(w) - sage: w.representation(5) # optional - sage.modules + sage: w.representation(5) # needs sage.modules [1, 0, 0, 0] """ letters_to_int = {a:i for (i,a) in enumerate(self._alphabet)} @@ -255,11 +255,11 @@ def _func(self, key): sage: m = WordMorphism("a->ab,b->a") sage: w = m.fixed_point("a") - sage: w[0] # optional - sage.modules + sage: w[0] # needs sage.modules 'a' - sage: w[5] # optional - sage.modules + sage: w[5] # needs sage.modules 'a' - sage: w[10000] # optional - sage.modules + sage: w[10000] # needs sage.modules 'a' TESTS: @@ -271,7 +271,7 @@ def _func(self, key): sage: W = m.domain() sage: from sage.combinat.words.morphic import WordDatatype_morphic sage: w = WordDatatype_morphic(W, m, 'a') - sage: w._func(5) # optional - sage.modules + sage: w._func(5) # needs sage.modules 'a' """ diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 5fc7d5e62b7..1576c5aca6c 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -66,7 +66,7 @@ Incidence matrix:: - sage: matrix(m) # optional - sage.modules + sage: matrix(m) # needs sage.modules [2 3 1] [1 3 0] [1 1 1] @@ -614,7 +614,7 @@ def __str__(self) -> str: :: sage: s = WordMorphism({1:[1,2],2:[1]}) - sage: s.dual_map() # optional - sage.modules + sage: s.dual_map() # needs sage.modules E_1^*(1->12, 2->1) TESTS:: @@ -1101,21 +1101,21 @@ def _matrix_(self, R=None): sage: fibo = WordMorphism('a->ab,b->a') sage: tm = WordMorphism('a->ab,b->ba') - sage: Mfibo = matrix(fibo); Mfibo # indirect doctest # optional - sage.modules + sage: Mfibo = matrix(fibo); Mfibo # indirect doctest # needs sage.modules [1 1] [1 0] - sage: Mtm = matrix(tm); Mtm # optional - sage.modules + sage: Mtm = matrix(tm); Mtm # needs sage.modules [1 1] [1 1] - sage: Mtm * Mfibo == matrix(tm*fibo) # indirect doctest # optional - sage.modules + sage: Mtm * Mfibo == matrix(tm*fibo) # indirect doctest # needs sage.modules True - sage: Mfibo * Mtm == matrix(fibo*tm) # indirect doctest # optional - sage.modules + sage: Mfibo * Mtm == matrix(fibo*tm) # indirect doctest # needs sage.modules True - sage: Mfibo.parent() # optional - sage.modules + sage: Mfibo.parent() # needs sage.modules Full MatrixSpace of 2 by 2 dense matrices over Integer Ring - sage: p = Mfibo.charpoly(); p # optional - sage.modules + sage: p = Mfibo.charpoly(); p # needs sage.modules x^2 - x - 1 - sage: p.roots(ring=RR, multiplicities=False) # optional - sage.modules + sage: p.roots(ring=RR, multiplicities=False) # needs sage.modules [-0.618033988749895, 1.61803398874989] """ if R is None: @@ -1136,12 +1136,12 @@ def incidence_matrix(self): EXAMPLES:: sage: m = WordMorphism('a->abc,b->a,c->c') - sage: m.incidence_matrix() # optional - sage.modules + sage: m.incidence_matrix() # needs sage.modules [1 1 0] [1 0 0] [1 0 1] sage: m = WordMorphism('a->abc,b->a,c->c,d->abbccccabca,e->abc') - sage: m.incidence_matrix() # optional - sage.modules + sage: m.incidence_matrix() # needs sage.modules [1 1 0 3 1] [1 0 0 3 1] [1 0 1 5 1] @@ -1204,10 +1204,10 @@ def is_endomorphism(self): We check that :trac:`8674` is fixed:: - sage: P = WordPaths('abcd') # optional - sage.modules - sage: m = WordMorphism('a->adab,b->ab,c->cbcd,d->cd', # optional - sage.modules + sage: P = WordPaths('abcd') # needs sage.modules + sage: m = WordMorphism('a->adab,b->ab,c->cbcd,d->cd', # needs sage.modules ....: domain=P, codomain=P) - sage: m.is_endomorphism() # optional - sage.modules + sage: m.is_endomorphism() # needs sage.modules True """ return self.codomain() == self.domain() @@ -1496,11 +1496,11 @@ def pisot_eigenvector_right(self): EXAMPLES:: sage: m = WordMorphism('a->aaaabbc,b->aaabbc,c->aabc') - sage: matrix(m) # optional - sage.modules + sage: matrix(m) # needs sage.modules [4 3 2] [2 2 1] [1 1 1] - sage: m.pisot_eigenvector_right() # optional - sage.modules sage.rings.number_field + sage: m.pisot_eigenvector_right() # needs sage.modules sage.rings.number_field (1, 0.5436890126920763?, 0.2955977425220848?) """ eig = self.incidence_matrix().eigenvectors_right() @@ -1526,11 +1526,11 @@ def pisot_eigenvector_left(self): EXAMPLES:: sage: m = WordMorphism('a->aaaabbc,b->aaabbc,c->aabc') - sage: matrix(m) # optional - sage.modules + sage: matrix(m) # needs sage.modules [4 3 2] [2 2 1] [1 1 1] - sage: m.pisot_eigenvector_left() # optional - sage.modules sage.rings.number_field + sage: m.pisot_eigenvector_left() # needs sage.modules sage.rings.number_field (1, 0.8392867552141611?, 0.5436890126920763?) """ eig = self.incidence_matrix().eigenvectors_left() @@ -1590,25 +1590,25 @@ def is_primitive(self): EXAMPLES:: sage: tm = WordMorphism('a->ab,b->ba') - sage: tm.is_primitive() # optional - sage.modules + sage: tm.is_primitive() # needs sage.modules True sage: fibo = WordMorphism('a->ab,b->a') - sage: fibo.is_primitive() # optional - sage.modules + sage: fibo.is_primitive() # needs sage.modules True sage: m = WordMorphism('a->bb,b->aa') - sage: m.is_primitive() # optional - sage.modules + sage: m.is_primitive() # needs sage.modules False sage: f = WordMorphism({0:[1],1:[0]}) - sage: f.is_primitive() # optional - sage.modules + sage: f.is_primitive() # needs sage.modules False :: sage: s = WordMorphism('a->b,b->c,c->ab') - sage: s.is_primitive() # optional - sage.modules + sage: s.is_primitive() # needs sage.modules True sage: s = WordMorphism('a->b,b->c,c->d,d->e,e->f,f->g,g->h,h->ab') - sage: s.is_primitive() # optional - sage.modules + sage: s.is_primitive() # needs sage.modules True TESTS:: @@ -1619,7 +1619,7 @@ def is_primitive(self): ... TypeError: self (=a->bb, b->aac) is not an endomorphism sage: m = WordMorphism('a->,b->', codomain=Words('ab')) - sage: m.is_primitive() # optional - sage.modules + sage: m.is_primitive() # needs sage.modules False sage: m = WordMorphism('a->,b->') sage: m.is_primitive() @@ -1683,9 +1683,9 @@ def is_prolongable(self, letter): :: - sage: n0, n1 = matrix(2,[1,1,1,0]), matrix(2,[2,1,1,0]) # optional - sage.modules - sage: n = {'a':n0, 'b':n1} # optional - sage.modules - sage: WordMorphism(n).is_prolongable(letter='a') # todo: not implemented # optional - sage.modules + sage: n0, n1 = matrix(2,[1,1,1,0]), matrix(2,[2,1,1,0]) # needs sage.modules + sage: n = {'a':n0, 'b':n1} # needs sage.modules + sage: WordMorphism(n).is_prolongable(letter='a') # not implemented, needs sage.modules Traceback (most recent call last): ... TypeError: codomain of self must be an instance of Words @@ -2076,11 +2076,11 @@ def language(self, n, u=None): The fibonacci morphism:: sage: s = WordMorphism({0: [0,1], 1: [0]}) - sage: sorted(s.language(3)) # optional - sage.modules + sage: sorted(s.language(3)) # needs sage.modules [word: 001, word: 010, word: 100, word: 101] - sage: len(s.language(1000)) # optional - sage.modules + sage: len(s.language(1000)) # needs sage.modules 1001 - sage: all(len(s.language(n)) == n+1 for n in range(100)) # optional - sage.modules + sage: all(len(s.language(n)) == n+1 for n in range(100)) # needs sage.modules True A growing but non-primitive example. The DOL-languages generated @@ -2089,24 +2089,24 @@ def language(self, n, u=None): sage: s = WordMorphism({0: [0,1], 1: [0], 2: [2,0,2]}) sage: u = s.fixed_point(0) - sage: A0 = u[:200].factor_set(5) # optional - sage.modules - sage: B0 = s.language(5, [0]) # optional - sage.modules - sage: set(A0) == B0 # optional - sage.modules + sage: A0 = u[:200].factor_set(5) # needs sage.modules + sage: B0 = s.language(5, [0]) # needs sage.modules + sage: set(A0) == B0 # needs sage.modules True sage: v = s.fixed_point(2) - sage: A2 = v[:200].factor_set(5) # optional - sage.modules - sage: B2 = s.language(5, [2]) # optional - sage.modules - sage: set(A2) == B2 # optional - sage.modules + sage: A2 = v[:200].factor_set(5) # needs sage.modules + sage: B2 = s.language(5, [2]) # needs sage.modules + sage: set(A2) == B2 # needs sage.modules True - sage: len(A0), len(A2) # optional - sage.modules + sage: len(A0), len(A2) # needs sage.modules (6, 20) The Chacon transformation (non-primitive):: sage: s = WordMorphism({0: [0,0,1,0], 1:[1]}) - sage: sorted(s.language(10)) # optional - sage.modules + sage: sorted(s.language(10)) # needs sage.modules [word: 0001000101, word: 0001010010, ... @@ -2461,7 +2461,7 @@ def dual_map(self, k=1): EXAMPLES:: sage: sigma = WordMorphism({1: [2], 2: [3], 3: [1,2]}) - sage: sigma.dual_map() # optional - sage.modules + sage: sigma.dual_map() # needs sage.modules E_1^*(1->2, 2->3, 3->12) :: @@ -2515,7 +2515,7 @@ def rauzy_fractal_projection(self, eig=None, prec=53): is:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: s.rauzy_fractal_projection() # optional - sage.modules + sage: s.rauzy_fractal_projection() # needs sage.modules {'1': (1.00000000000000, 0.000000000000000), '2': (-1.41964337760708, -0.606290729207199), '3': (-0.771844506346038, 1.11514250803994)} @@ -2523,9 +2523,9 @@ def rauzy_fractal_projection(self, eig=None, prec=53): TESTS:: sage: t = WordMorphism('1->12,2->3,3->45,4->5,5->6,6->7,7->8,8->1') - sage: E = t.incidence_matrix().eigenvalues() # optional - sage.modules - sage: x = [x for x in E if -0.8 < x < -0.7][0] # optional - sage.modules - sage: t.rauzy_fractal_projection(prec=10) # optional - sage.modules + sage: E = t.incidence_matrix().eigenvalues() # needs sage.modules + sage: x = [x for x in E if -0.8 < x < -0.7][0] # needs sage.modules + sage: t.rauzy_fractal_projection(prec=10) # needs sage.modules {'1': (1.0, 0.00), '2': (-1.7, -0.56), '3': (0.79, 1.3), @@ -2534,7 +2534,7 @@ def rauzy_fractal_projection(self, eig=None, prec=53): '6': (0.79, 1.3), '7': (0.21, -1.3), '8': (-0.88, 0.74)} - sage: t.rauzy_fractal_projection(eig=x, prec=10) # optional - sage.modules + sage: t.rauzy_fractal_projection(eig=x, prec=10) # needs sage.modules {'1': (1.0, 0.00), '2': (-0.12, -0.74), '3': (-0.66, -0.56), @@ -2619,20 +2619,20 @@ def rauzy_fractal_points(self, n=None, exchange=False, eig=None, translate=None, and ``'3'`` are respectively:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: D = s.rauzy_fractal_points(n=100) # optional - sage.modules - sage: len(D['1']) # optional - sage.modules + sage: D = s.rauzy_fractal_points(n=100) # needs sage.modules + sage: len(D['1']) # needs sage.modules 54 - sage: len(D['2']) # optional - sage.modules + sage: len(D['2']) # needs sage.modules 30 - sage: len(D['3']) # optional - sage.modules + sage: len(D['3']) # needs sage.modules 16 TESTS:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: D = s.rauzy_fractal_points(n=100, exchange=True, # optional - sage.modules + sage: D = s.rauzy_fractal_points(n=100, exchange=True, # needs sage.modules ....: translate=[(3,1,-2), (5,-33,8)], prec=40) - sage: len(D['1']) # optional - sage.modules + sage: len(D['1']) # needs sage.modules 108 AUTHOR: @@ -2794,7 +2794,7 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, #. The Rauzy fractal of the Tribonacci substitution:: sage: s = WordMorphism('1->12,2->13,3->1') - sage: s.rauzy_fractal_plot() # long time # optional - sage.plot + sage: s.rauzy_fractal_plot() # long time # needs sage.plot Graphics object consisting of 3 graphics primitives #. The "Hokkaido" fractal. We tweak the plot using the plotting options @@ -2843,8 +2843,8 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, #. Different fractals can be obtained by choosing another (non-Pisot) eigenvalue:: sage: s = WordMorphism('1->12,2->3,3->45,4->5,5->6,6->7,7->8,8->1') - sage: E = s.incidence_matrix().eigenvalues() # optional - sage.modules - sage: x = [x for x in E if -0.8 < x < -0.7][0] # optional - sage.modules + sage: E = s.incidence_matrix().eigenvalues() # needs sage.modules + sage: x = [x for x in E if -0.8 < x < -0.7][0] # needs sage.modules sage: s.rauzy_fractal_plot() # not tested (> 1 second) sage: s.rauzy_fractal_plot(eig=x) # not tested (> 1 second) @@ -2887,8 +2887,8 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, :: sage: t = WordMorphism("a->aC,b->d,C->de,d->a,e->ab") # substitution found by Julien Bernat - sage: V = [vector((0,0,1,0,-1)), vector((0,0,1,-1,0))] # optional - sage.modules - sage: S = set(map(tuple, [i*V[0] + j*V[1] # optional - sage.modules + sage: V = [vector((0,0,1,0,-1)), vector((0,0,1,-1,0))] # needs sage.modules + sage: S = set(map(tuple, [i*V[0] + j*V[1] # needs sage.modules ....: for i in [-1,0,1] for j in [-1,0,1]])) sage: t.rauzy_fractal_plot(n=10000, # not tested (> 1 second) ....: translate=S, exchange=true) @@ -2911,7 +2911,7 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, TESTS:: sage: s = WordMorphism('a->ab,b->c,c->d,d->e,e->a') - sage: s.rauzy_fractal_plot(n=1000, colormap='Set1', # optional - sage.modules sage.plot + sage: s.rauzy_fractal_plot(n=1000, colormap='Set1', # needs sage.modules sage.plot ....: opacity={'a':0.5,'b':1,'c':0.7,'d':0,'e':0.2}, ....: plot_origin=(100,"black"), plot_basis=True, ....: point_size=2.5) @@ -3331,24 +3331,24 @@ def abelian_rotation_subspace(self): EXAMPLES:: - sage: WordMorphism('0->1,1->0').abelian_rotation_subspace() # optional - sage.modules + sage: WordMorphism('0->1,1->0').abelian_rotation_subspace() # needs sage.modules Vector space of degree 2 and dimension 2 over Rational Field Basis matrix: [1 0] [0 1] - sage: WordMorphism('0->01,1->10').abelian_rotation_subspace() # optional - sage.modules + sage: WordMorphism('0->01,1->10').abelian_rotation_subspace() # needs sage.modules Vector space of degree 2 and dimension 0 over Rational Field Basis matrix: [] - sage: WordMorphism('0->01,1->1').abelian_rotation_subspace() # optional - sage.modules + sage: WordMorphism('0->01,1->1').abelian_rotation_subspace() # needs sage.modules Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [0 1] - sage: WordMorphism('1->122,2->211').abelian_rotation_subspace() # optional - sage.modules + sage: WordMorphism('1->122,2->211').abelian_rotation_subspace() # needs sage.modules Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [ 1 -1] - sage: WordMorphism('0->1,1->102,2->3,3->4,4->2').abelian_rotation_subspace() # optional - sage.modules + sage: WordMorphism('0->1,1->102,2->3,3->4,4->2').abelian_rotation_subspace() # needs sage.modules Vector space of degree 5 and dimension 3 over Rational Field Basis matrix: [0 0 1 0 0] @@ -3357,7 +3357,7 @@ def abelian_rotation_subspace(self): The domain needs to be equal to the codomain:: - sage: WordMorphism('0->1,1->',codomain=Words('01')).abelian_rotation_subspace() # optional - sage.modules + sage: WordMorphism('0->1,1->',codomain=Words('01')).abelian_rotation_subspace() # needs sage.modules Vector space of degree 2 and dimension 0 over Rational Field Basis matrix: [] diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index ae78cb206b9..dcf37d8f456 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -45,7 +45,7 @@ [(0, 0), (1, 2), (-2, 6), (-1, 8), (-1, 5), (-1, 2), (-4, 6), (-3, 8)] sage: p.is_closed() False - sage: p.plot() # optional - sage.plot + sage: p.plot() # needs sage.plot Graphics object consisting of 3 graphics primitives To obtain a list of all the available word path specific functions, @@ -104,14 +104,14 @@ Finite Dyck paths sage: d = D('()()()(())'); d Path: ()()()(()) - sage: d.plot() # optional - sage.plot + sage: d.plot() # needs sage.plot Graphics object consisting of 3 graphics primitives :: sage: P = WordPaths('abcdef', steps='triangle_grid') sage: p = P('babaddefadabcadefaadfafabacdefa') - sage: p.plot() # optional - sage.plot + sage: p.plot() # needs sage.plot Graphics object consisting of 3 graphics primitives Vector steps may be in more than 2 dimensions:: @@ -120,7 +120,7 @@ sage: P = WordPaths(alphabet='abc', steps=d); P Word Paths over 3 steps sage: p = P('abcabcabcabcaabacabcababcacbabacacabcaccbcac') - sage: p.plot() # optional - sage.plot + sage: p.plot() # needs sage.plot Graphics3d Object :: @@ -137,7 +137,7 @@ sage: CubePaths = WordPaths('abcABC', steps='cube_grid'); CubePaths Word Paths on the cube grid - sage: CubePaths('abcabaabcabAAAAA').plot() # optional - sage.plot + sage: CubePaths('abcabaabcabAAAAA').plot() # needs sage.plot Graphics3d Object The input data may be a str, a list, a tuple, @@ -1366,15 +1366,15 @@ def plot_projection(self, v=None, letters=None, color=None, ring=None, To remove the axis, do like this:: - sage: r = w.plot_projection(v) # optional - sage.plot - sage: r.axes(False) # optional - sage.plot - sage: r # long time (2s) # optional - sage.plot + sage: r = w.plot_projection(v) # needs sage.plot + sage: r.axes(False) # needs sage.plot + sage: r # long time (2s) # needs sage.plot Graphics object consisting of 200 graphics primitives You can assign different colors to each letter:: sage: color = {'1': 'purple', '2': (.2,.3,.4), '3': 'magenta'} - sage: w.plot_projection(v, color=color) # long time (2s) # optional - sage.plot + sage: w.plot_projection(v, color=color) # long time (2s) # needs sage.plot Graphics object consisting of 200 graphics primitives The 3d-Rauzy fractal:: @@ -1384,14 +1384,14 @@ def plot_projection(self, v=None, letters=None, color=None, ring=None, sage: v = s.pisot_eigenvector_right() sage: P = WordPaths('1234',[(1,0,0,0), (0,1,0,0), (0,0,1,0), (0,0,0,1)]) sage: w = P(D[:200]) - sage: w.plot_projection(v) # optional - sage.plot + sage: w.plot_projection(v) # needs sage.plot Graphics3d Object The dimension of vector space of the parent must be 3 or 4:: sage: P = WordPaths('ab', [(1, 0), (0, 1)]) sage: p = P('aabbabbab') - sage: p.plot_projection() # optional - sage.plot + sage: p.plot_projection() # needs sage.plot Traceback (most recent call last): ... TypeError: The dimension of the vector space (=2) must be 3 or 4 @@ -1445,7 +1445,7 @@ def projected_path(self, v=None, ring=None): sage: p = w.projected_path(v) sage: p Path: 1213121121312121312112131213121121312121... - sage: p[:20].plot() # optional - sage.plot + sage: p[:20].plot() # needs sage.plot Graphics object consisting of 3 graphics primitives The ``ring`` argument allows to change the precision of the @@ -1531,42 +1531,42 @@ def plot(self, pathoptions=dict(rgbcolor='red',thickness=3), A non closed path on the square grid:: sage: P = WordPaths('abAB') - sage: P('abababAABAB').plot() # optional - sage.plot + sage: P('abababAABAB').plot() # needs sage.plot Graphics object consisting of 3 graphics primitives A closed path on the square grid:: - sage: P('abababAABABB').plot() # optional - sage.plot + sage: P('abababAABABB').plot() # needs sage.plot Graphics object consisting of 4 graphics primitives A Dyck path:: sage: P = WordPaths('()', steps='dyck') - sage: P('()()()((()))').plot() # optional - sage.plot + sage: P('()()()((()))').plot() # needs sage.plot Graphics object consisting of 3 graphics primitives A path in the triangle grid:: sage: P = WordPaths('abcdef', steps='triangle_grid') - sage: P('abcdedededefab').plot() # optional - sage.plot + sage: P('abcdedededefab').plot() # needs sage.plot Graphics object consisting of 3 graphics primitives A polygon of length 220 that tiles the plane in two ways:: sage: P = WordPaths('abAB') - sage: P('aBababAbabaBaBABaBabaBaBABAbABABaBabaBaBABaBababAbabaBaBABaBabaBaBABAbABABaBABAbAbabAbABABaBABAbABABaBabaBaBABAbABABaBABAbAbabAbABAbAbabaBababAbABAbAbabAbABABaBABAbAbabAbABAbAbabaBababAbabaBaBABaBababAbabaBababAbABAbAbab').plot() # optional - sage.plot + sage: P('aBababAbabaBaBABaBabaBaBABAbABABaBabaBaBABaBababAbabaBaBABaBabaBaBABAbABABaBABAbAbabAbABABaBABAbABABaBabaBaBABAbABABaBABAbAbabAbABAbAbabaBababAbABAbAbabAbABABaBABAbAbabAbABAbAbabaBababAbabaBaBABaBababAbabaBababAbABAbAbab').plot() # needs sage.plot Graphics object consisting of 4 graphics primitives With gridlines:: - sage: P('ababababab').plot(gridlines=True) # optional - sage.plot + sage: P('ababababab').plot(gridlines=True) # needs sage.plot TESTS:: sage: P = WordPaths('abAB') - sage: P().plot() # optional - sage.plot + sage: P().plot() # needs sage.plot Graphics object consisting of 3 graphics primitives - sage: sum(map(plot,map(P,['a','A','b','B']))) # optional - sage.plot + sage: sum(map(plot,map(P,['a','A','b','B']))) # needs sage.plot Graphics object consisting of 12 graphics primitives """ G = Graphics() @@ -1615,44 +1615,44 @@ def animate(self): sage: P = WordPaths('abAB') sage: p = P('aaababbb') - sage: a = p.animate(); print(a) # optional - sage.plot + sage: a = p.animate(); print(a) # needs sage.plot Animation with 9 frames - sage: show(a) # long time # optional -- ImageMagick sage.plot - sage: show(a, delay=35, iterations=3) # long time # optional -- ImageMagick sage.plot + sage: show(a) # long time, optional - imagemagick, needs sage.plot + sage: show(a, delay=35, iterations=3) # long time, optional - imagemagick, needs sage.plot :: sage: P = WordPaths('abcdef',steps='triangle') sage: p = P('abcdef') - sage: a = p.animate(); print(a) # optional - sage.plot + sage: a = p.animate(); print(a) # needs sage.plot Animation with 8 frames - sage: show(a) # long time # optional -- ImageMagick sage.plot + sage: show(a) # long time, optional - imagemagick, needs sage.plot If the path is closed, the plain polygon is added at the end of the animation:: sage: P = WordPaths('abAB') sage: p = P('ababAbABABaB') - sage: a = p.animate(); print(a) # optional - sage.plot + sage: a = p.animate(); print(a) # needs sage.plot Animation with 14 frames - sage: show(a) # long time # optional -- ImageMagick sage.plot + sage: show(a) # long time, optional - imagemagick, needs sage.plot Another example illustrating a Fibonacci tile:: sage: w = words.fibonacci_tile(2) - sage: a = w.animate(); print(a) # optional - sage.plot + sage: a = w.animate(); print(a) # needs sage.plot Animation with 54 frames - sage: show(a) # long time # optional -- ImageMagick sage.plot + sage: show(a) # long time, optional - imagemagick, needs sage.plot The first 4 Fibonacci tiles in an animation:: - sage: a = words.fibonacci_tile(0).animate() # optional - sage.plot - sage: b = words.fibonacci_tile(1).animate() # optional - sage.plot - sage: c = words.fibonacci_tile(2).animate() # optional - sage.plot - sage: d = words.fibonacci_tile(3).animate() # optional - sage.plot - sage: print(a*b*c*d) # optional - sage.plot + sage: a = words.fibonacci_tile(0).animate() # needs sage.plot + sage: b = words.fibonacci_tile(1).animate() # needs sage.plot + sage: c = words.fibonacci_tile(2).animate() # needs sage.plot + sage: d = words.fibonacci_tile(3).animate() # needs sage.plot + sage: print(a*b*c*d) # needs sage.plot Animation with 296 frames - sage: show(a*b*c*d) # long time # optional -- ImageMagick sage.plot + sage: show(a*b*c*d) # long time, optional - imagemagick, needs sage.plot .. note:: @@ -1714,17 +1714,17 @@ def plot_directive_vector(self, options=dict(rgbcolor='blue')): Word Paths on the square grid sage: p = P('aaaccaccacacacaccccccbbdd'); p Path: aaaccaccacacacaccccccbbdd - sage: R = p.plot() + p.plot_directive_vector() # optional - sage.plot - sage: R.axes(False) # optional - sage.plot - sage: R.set_aspect_ratio(1) # optional - sage.plot - sage: R.plot() # optional - sage.plot + sage: R = p.plot() + p.plot_directive_vector() # needs sage.plot + sage: R.axes(False) # needs sage.plot + sage: R.set_aspect_ratio(1) # needs sage.plot + sage: R.plot() # needs sage.plot Graphics object consisting of 4 graphics primitives TESTS: A closed path:: - sage: P('acbd').plot_directive_vector() # optional - sage.plot + sage: P('acbd').plot_directive_vector() # needs sage.plot Graphics object consisting of 1 graphics primitive """ start = self.start_point() @@ -2021,12 +2021,12 @@ def plot(self, pathoptions=dict(rgbcolor='red',arrow_head=True,thickness=3), Word Paths over 2 steps sage: p = P('ababab'); p Path: ababab - sage: p.plot() # optional - sage.plot + sage: p.plot() # needs sage.plot Graphics3d Object sage: P = WordPaths('abcABC', steps='cube_grid') sage: p = P('abcabcAABBC') - sage: p.plot() # optional - sage.plot + sage: p.plot() # needs sage.plot Graphics3d Object """ diff --git a/src/sage/combinat/words/suffix_trees.py b/src/sage/combinat/words/suffix_trees.py index 59b3acb57d3..8375bde1a8a 100644 --- a/src/sage/combinat/words/suffix_trees.py +++ b/src/sage/combinat/words/suffix_trees.py @@ -440,9 +440,9 @@ def to_digraph(self): sage: from sage.combinat.words.suffix_trees import SuffixTrie sage: w = Words("cao")("cac") sage: t = SuffixTrie(w) - sage: d = t.to_digraph(); d # optional - sage.graphs + sage: d = t.to_digraph(); d # needs sage.graphs Digraph on 6 vertices - sage: d.adjacency_matrix() # optional - sage.graphs sage.modules + sage: d.adjacency_matrix() # needs sage.graphs sage.modules [0 1 0 1 0 0] [0 0 1 0 0 0] [0 0 0 0 1 0] @@ -464,13 +464,13 @@ def plot(self, layout='tree', tree_root=0, tree_orientation='up', EXAMPLES:: sage: from sage.combinat.words.suffix_trees import SuffixTrie - sage: SuffixTrie(Word("cacao")).plot() # optional - sage.plot + sage: SuffixTrie(Word("cacao")).plot() # needs sage.plot Graphics object consisting of 38 graphics primitives TESTS:: sage: from sage.combinat.words.suffix_trees import SuffixTrie - sage: type(SuffixTrie(Word("cacao")).plot()) # optional - sage.plot + sage: type(SuffixTrie(Word("cacao")).plot()) # needs sage.plot """ tree = self.to_digraph() @@ -494,7 +494,7 @@ def show(self, *args, **kwds): sage: from sage.combinat.words.suffix_trees import SuffixTrie sage: w = Words("cao")("cac") sage: t = SuffixTrie(w) - sage: t.show() # optional - sage.plot + sage: t.show() # needs sage.plot """ self.plot(*args, **kwds).show() return @@ -832,7 +832,7 @@ def to_digraph(self, word_labels=False): sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree sage: W = Words([0,1,2]) sage: t = ImplicitSuffixTree(W([0,1,0,1,2])) - sage: t.to_digraph() # optional - sage.graphs + sage: t.to_digraph() # needs sage.graphs Digraph on 8 vertices """ if not self._letters: @@ -868,17 +868,17 @@ def plot(self, word_labels=False, layout='tree', tree_root=0, EXAMPLES:: sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree - sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=True) # optional - sage.graphs sage.plot + sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=True) # needs sage.graphs sage.plot Graphics object consisting of 23 graphics primitives - sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=False) # optional - sage.graphs sage.plot + sage: ImplicitSuffixTree(Word('cacao')).plot(word_labels=False) # needs sage.graphs sage.plot Graphics object consisting of 23 graphics primitives TESTS:: sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree - sage: type(ImplicitSuffixTree(Word('cacao')).plot(word_labels=True)) # optional - sage.graphs sage.plot + sage: type(ImplicitSuffixTree(Word('cacao')).plot(word_labels=True)) # needs sage.graphs sage.plot - sage: type(ImplicitSuffixTree(Word('cacao')).plot(word_labels=False)) # optional - sage.graphs sage.plot + sage: type(ImplicitSuffixTree(Word('cacao')).plot(word_labels=False)) # needs sage.graphs sage.plot """ tree = self.to_digraph(word_labels=word_labels) @@ -907,8 +907,8 @@ def show(self, word_labels=None, *args, **kwds): sage: from sage.combinat.words.suffix_trees import ImplicitSuffixTree sage: w = Words("cao")("cacao") sage: t = ImplicitSuffixTree(w) - sage: t.show(word_labels=True) # optional - sage.plot - sage: t.show(word_labels=False) # optional - sage.plot + sage: t.show(word_labels=True) # needs sage.plot + sage: t.show(word_labels=False) # needs sage.plot """ self.plot(word_labels=word_labels, *args, **kwds).show() return @@ -1509,7 +1509,7 @@ def uncompactify(self): sage: abbab = Words("ab")("abbab") sage: s = SuffixTrie(abbab) sage: t = ImplicitSuffixTree(abbab) - sage: t.uncompactify().is_isomorphic(s.to_digraph()) # optional - sage.graphs + sage: t.uncompactify().is_isomorphic(s.to_digraph()) # needs sage.graphs True """ tree = self.to_digraph(word_labels=True) diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index 320bc3d9f0c..132195589e9 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -265,7 +265,7 @@ class FiniteWord_char(WordDatatype_char, FiniteWord_class): sage: len(w.factor_set()) 127 - sage: w.rauzy_graph(5) # optional - sage.graphs + sage: w.rauzy_graph(5) # needs sage.graphs Looped digraph on 9 vertices sage: u = W([1,2,3]) diff --git a/src/sage/combinat/words/word_char.pyx b/src/sage/combinat/words/word_char.pyx index 31f642ffc65..1b68cd293ce 100644 --- a/src/sage/combinat/words/word_char.pyx +++ b/src/sage/combinat/words/word_char.pyx @@ -716,9 +716,9 @@ cdef class WordDatatype_char(WordDatatype): sage: W = Words([0,1]) sage: w = words.FibonacciWord() sage: w = W(list(w[:5000])) - sage: L = [[len(w[n:].longest_common_prefix(w[n+fibonacci(i):])) # optional - sage.libs.pari + sage: L = [[len(w[n:].longest_common_prefix(w[n+fibonacci(i):])) # needs sage.libs.pari ....: for i in range(5,15)] for n in range(1,1000)] - sage: for n,l in enumerate(L): # optional - sage.libs.pari + sage: for n,l in enumerate(L): # needs sage.libs.pari ....: if l.count(0) > 4: ....: print("{} {}".format(n+1,l)) 375 [0, 13, 0, 34, 0, 89, 0, 233, 0, 233] diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 54d8a96f637..681ce39e26e 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -243,10 +243,10 @@ def markoff_number(self): sage: w0 = words.LowerChristoffelWord(4,7) sage: w1, w2 = w0.standard_factorization() - sage: (m0,m1,m2) = (w.markoff_number() for w in (w0,w1,w2)) # optional - sage.modules - sage: (m0,m1,m2) # optional - sage.modules + sage: (m0,m1,m2) = (w.markoff_number() for w in (w0,w1,w2)) # needs sage.modules + sage: (m0,m1,m2) # needs sage.modules (294685, 13, 7561) - sage: m0**2 + m1**2 + m2**2 == 3*m0*m1*m2 # optional - sage.modules + sage: m0**2 + m1**2 + m2**2 == 3*m0*m1*m2 # needs sage.modules True """ from sage.matrix.constructor import matrix @@ -542,9 +542,9 @@ def FibonacciWord(self, alphabet=(0, 1), construction_method="recursive"): :: - sage: words.FibonacciWord([0,1], 'function') # optional - sage.symbolic + sage: words.FibonacciWord([0,1], 'function') # needs sage.symbolic word: 0100101001001010010100100101001001010010... - sage: words.FibonacciWord('ab', 'function') # optional - sage.symbolic + sage: words.FibonacciWord('ab', 'function') # needs sage.symbolic word: abaababaabaababaababaabaababaabaababaaba... TESTS:: @@ -642,7 +642,7 @@ def FixedPointOfMorphism(self, morphism, first_letter): sage: tm = words.FixedPointOfMorphism(mu,0); tm word: 0110100110010110100101100110100110010110... sage: TM = words.ThueMorseWord() - sage: tm[:1000] == TM[:1000] # optional - sage.modules + sage: tm[:1000] == TM[:1000] # needs sage.modules True :: @@ -652,7 +652,7 @@ def FixedPointOfMorphism(self, morphism, first_letter): word: 0100101001001010010100100101001001010010... sage: F = words.FibonacciWord(); F word: 0100101001001010010100100101001001010010... - sage: f[:1000] == F[:1000] # optional - sage.modules + sage: f[:1000] == F[:1000] # needs sage.modules True :: @@ -776,13 +776,13 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): From real slope:: - sage: words.CharacteristicSturmianWord(1/golden_ratio^2) # optional - sage.symbolic + sage: words.CharacteristicSturmianWord(1/golden_ratio^2) # needs sage.symbolic word: 0100101001001010010100100101001001010010... - sage: words.CharacteristicSturmianWord(4/5) # optional - sage.rings.real_mpfr + sage: words.CharacteristicSturmianWord(4/5) # needs sage.rings.real_mpfr word: 11110 - sage: words.CharacteristicSturmianWord(5/14) # optional - sage.rings.real_mpfr + sage: words.CharacteristicSturmianWord(5/14) # needs sage.rings.real_mpfr word: 01001001001001 - sage: words.CharacteristicSturmianWord(pi - 3) # optional - sage.symbolic + sage: words.CharacteristicSturmianWord(pi - 3) # needs sage.symbolic word: 0000001000000100000010000001000000100000... From an iterator of the continued fraction expansion of a real:: @@ -791,21 +791,21 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): ....: yield 0 ....: yield 2 ....: while True: yield 1 - sage: F = words.CharacteristicSturmianWord(cf()); F + sage: F = words.CharacteristicSturmianWord(cf()); F # needs sage.rings.real_mpfr word: 0100101001001010010100100101001001010010... sage: Fib = words.FibonacciWord(); Fib word: 0100101001001010010100100101001001010010... - sage: F[:10000] == Fib[:10000] + sage: F[:10000] == Fib[:10000] # needs sage.rings.real_mpfr True The alphabet may be specified:: - sage: words.CharacteristicSturmianWord(cf(), 'rs') + sage: words.CharacteristicSturmianWord(cf(), 'rs') # needs sage.rings.real_mpfr word: rsrrsrsrrsrrsrsrrsrsrrsrrsrsrrsrrsrsrrsr... The characteristic sturmian word of slope `(\sqrt{3}-1)/2`:: - sage: words.CharacteristicSturmianWord((sqrt(3)-1)/2) # optional - sage.symbolic + sage: words.CharacteristicSturmianWord((sqrt(3)-1)/2) # needs sage.symbolic word: 0100100101001001001010010010010100100101... The same word defined from the continued fraction expansion of @@ -848,17 +848,17 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): :: - sage: words.CharacteristicSturmianWord(1/golden_ratio^2) # optional - sage.symbolic + sage: words.CharacteristicSturmianWord(1/golden_ratio^2) # needs sage.symbolic word: 0100101001001010010100100101001001010010... - sage: _.length() # optional - sage.symbolic + sage: _.length() # needs sage.symbolic +Infinity :: - sage: a = words.LowerMechanicalWord(1/pi)[1:] # optional - sage.symbolic - sage: b = words.UpperMechanicalWord(1/pi)[1:] # optional - sage.symbolic - sage: c = words.CharacteristicSturmianWord(1/pi) # optional - sage.symbolic - sage: n = 500; a[:n] == b[:n] == c[:n] # optional - sage.symbolic + sage: a = words.LowerMechanicalWord(1/pi)[1:] # needs sage.symbolic + sage: b = words.UpperMechanicalWord(1/pi)[1:] # needs sage.symbolic + sage: c = words.CharacteristicSturmianWord(1/pi) # needs sage.symbolic + sage: n = 500; a[:n] == b[:n] == c[:n] # needs sage.symbolic True :: @@ -929,19 +929,19 @@ def _CharacteristicSturmianWord_LetterIterator(self, cf, alphabet=(0,1)): EXAMPLES:: - sage: continued_fraction(1/golden_ratio^2)[:8] # optional - sage.symbolic + sage: continued_fraction(1/golden_ratio^2)[:8] # needs sage.symbolic [0; 2, 1, 1, 1, 1, 2] - sage: cf = iter(_) # optional - sage.symbolic - sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) # optional - sage.symbolic + sage: cf = iter(_) # needs sage.symbolic + sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) # needs sage.symbolic word: 0100101001001010010100100101001010 :: - sage: alpha = (sqrt(3)-1)/2 # optional - sage.symbolic - sage: continued_fraction(alpha)[:10] # optional - sage.symbolic + sage: alpha = (sqrt(3)-1)/2 # needs sage.symbolic + sage: continued_fraction(alpha)[:10] # needs sage.symbolic [0; 2, 1, 2, 1, 2, 1, 2, 1, 2] - sage: cf = iter(_) # optional - sage.symbolic - sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) # optional - sage.symbolic + sage: cf = iter(_) # needs sage.symbolic + sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) # needs sage.symbolic word: 0100100101001001001010010010010100100101... """ try: @@ -1135,23 +1135,23 @@ def LowerMechanicalWord(self, alpha, rho=0, alphabet=None): EXAMPLES:: - sage: words.LowerMechanicalWord(1/golden_ratio^2) # optional - sage.symbolic + sage: words.LowerMechanicalWord(1/golden_ratio^2) # needs sage.symbolic word: 0010010100100101001010010010100100101001... - sage: words.LowerMechanicalWord(1/5) # optional - sage.symbolic + sage: words.LowerMechanicalWord(1/5) # needs sage.symbolic word: 0000100001000010000100001000010000100001... - sage: words.LowerMechanicalWord(1/pi) # optional - sage.symbolic + sage: words.LowerMechanicalWord(1/pi) # needs sage.symbolic word: 0001001001001001001001000100100100100100... TESTS:: - sage: m = words.LowerMechanicalWord(1/golden_ratio^2)[1:] # optional - sage.symbolic - sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) # optional - sage.symbolic - sage: m[:500] == s[:500] # optional - sage.symbolic + sage: m = words.LowerMechanicalWord(1/golden_ratio^2)[1:] # needs sage.symbolic + sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) # needs sage.symbolic + sage: m[:500] == s[:500] # needs sage.symbolic True Check that this returns a word in an alphabet (:trac:`10054`):: - sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() # optional - sage.symbolic + sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() # needs sage.symbolic Infinite words over {0, 1} """ if not 0 <= alpha <= 1: @@ -1195,23 +1195,23 @@ def UpperMechanicalWord(self, alpha, rho=0, alphabet=None): EXAMPLES:: - sage: words.UpperMechanicalWord(1/golden_ratio^2) # optional - sage.symbolic + sage: words.UpperMechanicalWord(1/golden_ratio^2) # needs sage.symbolic word: 1010010100100101001010010010100100101001... - sage: words.UpperMechanicalWord(1/5) # optional - sage.symbolic + sage: words.UpperMechanicalWord(1/5) # needs sage.symbolic word: 1000010000100001000010000100001000010000... - sage: words.UpperMechanicalWord(1/pi) # optional - sage.symbolic + sage: words.UpperMechanicalWord(1/pi) # needs sage.symbolic word: 1001001001001001001001000100100100100100... TESTS:: - sage: m = words.UpperMechanicalWord(1/golden_ratio^2)[1:] # optional - sage.symbolic - sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) # optional - sage.symbolic - sage: m[:500] == s[:500] # optional - sage.symbolic + sage: m = words.UpperMechanicalWord(1/golden_ratio^2)[1:] # needs sage.symbolic + sage: s = words.CharacteristicSturmianWord(1/golden_ratio^2) # needs sage.symbolic + sage: m[:500] == s[:500] # needs sage.symbolic True Check that this returns a word in an alphabet (:trac:`10054`):: - sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() # optional - sage.symbolic + sage: words.UpperMechanicalWord(1/golden_ratio^2).parent() # needs sage.symbolic Infinite words over {0, 1} """ if not 0 <= alpha <= 1: @@ -1522,7 +1522,7 @@ def fibonacci_tile(self, n): EXAMPLES:: - sage: for i in range(3): words.fibonacci_tile(i) # optional - sage.modules + sage: for i in range(3): words.fibonacci_tile(i) # needs sage.modules Path: 3210 Path: 323030101212 Path: 3230301030323212323032321210121232121010... @@ -1540,7 +1540,7 @@ def dual_fibonacci_tile(self, n): EXAMPLES:: - sage: for i in range(4): words.dual_fibonacci_tile(i) # optional - sage.modules + sage: for i in range(4): words.dual_fibonacci_tile(i) # needs sage.modules Path: 3210 Path: 32123032301030121012 Path: 3212303230103230321232101232123032123210... diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index 8c23a452bc7..0149df17598 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -705,9 +705,9 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr Construction of a word path from a finite word:: sage: W = FiniteWords('abcd') - sage: P = WordPaths('abcd') # optional - sage.modules + sage: P = WordPaths('abcd') # needs sage.modules sage: w = W('aaab') - sage: P(w) # optional - sage.modules + sage: P(w) # needs sage.modules Path: aaab Construction of a word path from a Christoffel word:: @@ -715,8 +715,8 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr sage: w = words.ChristoffelWord(5,8) sage: w word: 0010010100101 - sage: P = WordPaths([0,1,2,3]) # optional - sage.modules - sage: P(w) # optional - sage.modules + sage: P = WordPaths([0,1,2,3]) # needs sage.modules + sage: P(w) # needs sage.modules Path: 0010010100101 Construction of a word represented by a list from a word @@ -744,19 +744,19 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr sage: w = words.FibonacciWord() sage: f = w[:100] - sage: P = WordPaths([0,1,2,3]) # optional - sage.modules - sage: p = P(f); p # optional - sage.modules + sage: P = WordPaths([0,1,2,3]) # needs sage.modules + sage: p = P(f); p # needs sage.modules Path: 0100101001001010010100100101001001010010... - sage: p.length() # optional - sage.modules + sage: p.length() # needs sage.modules 100 Creation of a word path from a FiniteWord_callable:: sage: g = W(lambda n:n%2, length = 100) - sage: P = WordPaths([0,1,2,3]) # optional - sage.modules - sage: p = P(g); p # optional - sage.modules + sage: P = WordPaths([0,1,2,3]) # needs sage.modules + sage: p = P(g); p # needs sage.modules Path: 0101010101010101010101010101010101010101... - sage: p.length() # optional - sage.modules + sage: p.length() # needs sage.modules 100 Creation of a word from a pickled function:: @@ -1017,7 +1017,7 @@ def random_element(self, length=None, *args, **kwds): TESTS:: - sage: _ = FiniteWords(GF(5)).random_element() # optional - sage.rings.finite_rings + sage: _ = FiniteWords(GF(5)).random_element() # needs sage.rings.finite_rings """ if length is None: length = ZZ.random_element(0, 10) @@ -1928,9 +1928,9 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr Construction of a word path from a finite word:: sage: W = Words('abcd') - sage: P = WordPaths('abcd') # optional - sage.modules + sage: P = WordPaths('abcd') # needs sage.modules sage: w = W('aaab') - sage: P(w) # optional - sage.modules + sage: P(w) # needs sage.modules Path: aaab Construction of a word path from a Christoffel word:: @@ -1938,8 +1938,8 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr sage: w = words.ChristoffelWord(5,8) sage: w word: 0010010100101 - sage: P = WordPaths([0,1,2,3]) # optional - sage.modules - sage: P(w) # optional - sage.modules + sage: P = WordPaths([0,1,2,3]) # needs sage.modules + sage: P(w) # needs sage.modules Path: 0010010100101 Construction of a word represented by a list from a word @@ -1967,19 +1967,19 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr sage: w = words.FibonacciWord() sage: f = w[:100] - sage: P = WordPaths([0,1,2,3]) # optional - sage.modules - sage: p = P(f); p # optional - sage.modules + sage: P = WordPaths([0,1,2,3]) # needs sage.modules + sage: p = P(f); p # needs sage.modules Path: 0100101001001010010100100101001001010010... - sage: p.length() # optional - sage.modules + sage: p.length() # needs sage.modules 100 Creation of a word path from a :class:`FiniteWord_callable`:: sage: g = Word(lambda n: n%2, length=100) - sage: P = WordPaths([0,1,2,3]) # optional - sage.modules - sage: p = P(g); p # optional - sage.modules + sage: P = WordPaths([0,1,2,3]) # needs sage.modules + sage: p = P(g); p # needs sage.modules Path: 0101010101010101010101010101010101010101... - sage: p.length() # optional - sage.modules + sage: p.length() # needs sage.modules 100 Creation of a word from a pickled function:: @@ -2216,7 +2216,7 @@ def random_element(self, *args, **kwds): TESTS:: - sage: _ = Words(GF(5),4).random_element() # optional - sage.rings.finite_rings + sage: _ = Words(GF(5),4).random_element() # needs sage.rings.finite_rings Check that :trac:`18283` is fixed:: From 6613b17ad045b129a515a0fbd92cdf082698d3db Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 13 Jul 2023 23:26:21 -0700 Subject: [PATCH 153/538] sage.combinat.words: Update # needs --- src/sage/combinat/words/morphism.py | 11 ++++++----- src/sage/combinat/words/paths.py | 13 +++++++------ src/sage/combinat/words/word_generators.py | 18 ++++++++++-------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 1576c5aca6c..de7f00902ef 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -3331,24 +3331,25 @@ def abelian_rotation_subspace(self): EXAMPLES:: - sage: WordMorphism('0->1,1->0').abelian_rotation_subspace() # needs sage.modules + sage: # needs sage.modules + sage: WordMorphism('0->1,1->0').abelian_rotation_subspace() Vector space of degree 2 and dimension 2 over Rational Field Basis matrix: [1 0] [0 1] - sage: WordMorphism('0->01,1->10').abelian_rotation_subspace() # needs sage.modules + sage: WordMorphism('0->01,1->10').abelian_rotation_subspace() Vector space of degree 2 and dimension 0 over Rational Field Basis matrix: [] - sage: WordMorphism('0->01,1->1').abelian_rotation_subspace() # needs sage.modules + sage: WordMorphism('0->01,1->1').abelian_rotation_subspace() Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [0 1] - sage: WordMorphism('1->122,2->211').abelian_rotation_subspace() # needs sage.modules + sage: WordMorphism('1->122,2->211').abelian_rotation_subspace() Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [ 1 -1] - sage: WordMorphism('0->1,1->102,2->3,3->4,4->2').abelian_rotation_subspace() # needs sage.modules + sage: WordMorphism('0->1,1->102,2->3,3->4,4->2').abelian_rotation_subspace() Vector space of degree 5 and dimension 3 over Rational Field Basis matrix: [0 0 1 0 0] diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index dcf37d8f456..5c84a784533 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -1646,13 +1646,14 @@ def animate(self): The first 4 Fibonacci tiles in an animation:: - sage: a = words.fibonacci_tile(0).animate() # needs sage.plot - sage: b = words.fibonacci_tile(1).animate() # needs sage.plot - sage: c = words.fibonacci_tile(2).animate() # needs sage.plot - sage: d = words.fibonacci_tile(3).animate() # needs sage.plot - sage: print(a*b*c*d) # needs sage.plot + sage: # needs sage.plot + sage: a = words.fibonacci_tile(0).animate() + sage: b = words.fibonacci_tile(1).animate() + sage: c = words.fibonacci_tile(2).animate() + sage: d = words.fibonacci_tile(3).animate() + sage: print(a*b*c*d) Animation with 296 frames - sage: show(a*b*c*d) # long time, optional - imagemagick, needs sage.plot + sage: show(a*b*c*d) # long time, optional - imagemagick .. note:: diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 681ce39e26e..58886bd9108 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -855,10 +855,11 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): :: - sage: a = words.LowerMechanicalWord(1/pi)[1:] # needs sage.symbolic - sage: b = words.UpperMechanicalWord(1/pi)[1:] # needs sage.symbolic - sage: c = words.CharacteristicSturmianWord(1/pi) # needs sage.symbolic - sage: n = 500; a[:n] == b[:n] == c[:n] # needs sage.symbolic + sage: # needs sage.symbolic + sage: a = words.LowerMechanicalWord(1/pi)[1:] + sage: b = words.UpperMechanicalWord(1/pi)[1:] + sage: c = words.CharacteristicSturmianWord(1/pi) + sage: n = 500; a[:n] == b[:n] == c[:n] True :: @@ -937,11 +938,12 @@ def _CharacteristicSturmianWord_LetterIterator(self, cf, alphabet=(0,1)): :: - sage: alpha = (sqrt(3)-1)/2 # needs sage.symbolic - sage: continued_fraction(alpha)[:10] # needs sage.symbolic + sage: # needs sage.symbolic + sage: alpha = (sqrt(3)-1)/2 + sage: continued_fraction(alpha)[:10] [0; 2, 1, 2, 1, 2, 1, 2, 1, 2] - sage: cf = iter(_) # needs sage.symbolic - sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) # needs sage.symbolic + sage: cf = iter(_) + sage: Word(words._CharacteristicSturmianWord_LetterIterator(cf)) word: 0100100101001001001010010010010100100101... """ try: From 8153dbd027a4a21bcc0de7a60793b1252fff60d1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 4 Nov 2023 10:24:42 -0700 Subject: [PATCH 154/538] sage.combinat.words: More block tags --- src/sage/combinat/words/finite_word.py | 13 +++++++------ src/sage/combinat/words/morphism.py | 27 +++++++++++++------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index d43624c8ebe..35fd6e69c55 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -6824,18 +6824,19 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn EXAMPLES:: - sage: Word(range(20)).colored_vector() # needs sage.plot + sage: # needs sage.plot + sage: Word(range(20)).colored_vector() Graphics object consisting of 21 graphics primitives - sage: Word(range(100)).colored_vector(0,0,10,1) # needs sage.plot + sage: Word(range(100)).colored_vector(0,0,10,1) Graphics object consisting of 101 graphics primitives - sage: Words(range(100))(range(10)).colored_vector() # needs sage.plot + sage: Words(range(100))(range(10)).colored_vector() Graphics object consisting of 11 graphics primitives sage: w = Word('abbabaab') - sage: w.colored_vector() # needs sage.plot + sage: w.colored_vector() Graphics object consisting of 9 graphics primitives - sage: w.colored_vector(cmap='autumn') # needs sage.plot + sage: w.colored_vector(cmap='autumn') Graphics object consisting of 9 graphics primitives - sage: Word(range(20)).colored_vector(label='Rainbow') # needs sage.plot + sage: Word(range(20)).colored_vector(label='Rainbow') Graphics object consisting of 23 graphics primitives When two words are defined under the same parent, same letters are diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index de7f00902ef..279c238718e 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -346,7 +346,7 @@ def __init__(self, data, domain=None, codomain=None): The image of a letter can be a set, but the order is not preserved:: - sage: WordMorphism({2:[4,5,6],3:set([4,1,8])}) #random results + sage: WordMorphism({2:[4,5,6],3:set([4,1,8])}) # random results WordMorphism: 2->456, 3->814 If the image of a letter is not iterable, it is considered as a @@ -1099,23 +1099,24 @@ def _matrix_(self, R=None): EXAMPLES:: + sage: # needs sage.modules sage: fibo = WordMorphism('a->ab,b->a') sage: tm = WordMorphism('a->ab,b->ba') - sage: Mfibo = matrix(fibo); Mfibo # indirect doctest # needs sage.modules + sage: Mfibo = matrix(fibo); Mfibo # indirect doctest [1 1] [1 0] - sage: Mtm = matrix(tm); Mtm # needs sage.modules + sage: Mtm = matrix(tm); Mtm [1 1] [1 1] - sage: Mtm * Mfibo == matrix(tm*fibo) # indirect doctest # needs sage.modules + sage: Mtm * Mfibo == matrix(tm*fibo) # indirect doctest True - sage: Mfibo * Mtm == matrix(fibo*tm) # indirect doctest # needs sage.modules + sage: Mfibo * Mtm == matrix(fibo*tm) # indirect doctest True - sage: Mfibo.parent() # needs sage.modules + sage: Mfibo.parent() Full MatrixSpace of 2 by 2 dense matrices over Integer Ring - sage: p = Mfibo.charpoly(); p # needs sage.modules + sage: p = Mfibo.charpoly(); p x^2 - x - 1 - sage: p.roots(ring=RR, multiplicities=False) # needs sage.modules + sage: p.roots(ring=RR, multiplicities=False) [-0.618033988749895, 1.61803398874989] """ if R is None: @@ -1406,19 +1407,19 @@ def partition_of_domain_alphabet(self): EXAMPLES:: sage: m = WordMorphism('a->b,b->a') - sage: m.partition_of_domain_alphabet() #random ordering + sage: m.partition_of_domain_alphabet() # random ordering ({'a'}, {'b'}, {}) sage: m = WordMorphism('a->b,b->a,c->c') - sage: m.partition_of_domain_alphabet() #random ordering + sage: m.partition_of_domain_alphabet() # random ordering ({'a'}, {'b'}, {'c'}) sage: m = WordMorphism('a->a,b->b,c->c') - sage: m.partition_of_domain_alphabet() #random ordering + sage: m.partition_of_domain_alphabet() # random ordering ({}, {}, {'a', 'c', 'b'}) sage: m = WordMorphism('A->T,T->A,C->G,G->C') - sage: m.partition_of_domain_alphabet() #random ordering + sage: m.partition_of_domain_alphabet() # random ordering ({'A', 'C'}, {'T', 'G'}, {}) sage: I = WordMorphism({0:oo,oo:0,1:-1,-1:1,2:-2,-2:2,3:-3,-3:3}) - sage: I.partition_of_domain_alphabet() #random ordering + sage: I.partition_of_domain_alphabet() # random ordering ({0, -1, -3, -2}, {1, 2, 3, +Infinity}, {}) TESTS:: From 81dfb7bce2a04bac66050dc69c361fa7939088ba Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 4 Nov 2023 10:29:24 -0700 Subject: [PATCH 155/538] src/sage/combinat/species/partition_species.py: Fix indentation --- src/sage/combinat/species/partition_species.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/species/partition_species.py b/src/sage/combinat/species/partition_species.py index 21a57197ccd..dea38378a7a 100644 --- a/src/sage/combinat/species/partition_species.py +++ b/src/sage/combinat/species/partition_species.py @@ -141,7 +141,7 @@ def __classcall__(cls, *args, **kwds): sage: P = species.PartitionSpecies(); P Partition species - """ + """ return super().__classcall__(cls, *args, **kwds) def __init__(self, min=None, max=None, weight=None): From d2e559e95fc6eefb3f05b8cb8d84a38d56726cef Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 4 Nov 2023 11:42:18 -0700 Subject: [PATCH 156/538] src/sage/algebras/cluster_algebra.py: Restore lost # random --- src/sage/algebras/cluster_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index fa29367d014..4550e57e6ab 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -301,7 +301,7 @@ sage: # long time sage: A.reset_exploring_iterator(mutating_F=False) sage: v = (-1, 1, -2, 2, -1, 1, -1, 1, 1) - sage: seq = A.find_g_vector(v); seq + sage: seq = A.find_g_vector(v); seq # random [1, 0, 2, 6, 5, 4, 3, 8, 1] sage: S = A.initial_seed().mutate(seq, inplace=False) sage: v in S.g_vectors() From df17d12eb2fe08f69c175e670d786115b20b4440 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 4 Nov 2023 11:42:30 -0700 Subject: [PATCH 157/538] src/sage/algebras/orlik_solomon.py: Fix doctest fix --- src/sage/algebras/orlik_solomon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/orlik_solomon.py b/src/sage/algebras/orlik_solomon.py index 7cb469f09cc..76ed00aa855 100644 --- a/src/sage/algebras/orlik_solomon.py +++ b/src/sage/algebras/orlik_solomon.py @@ -368,7 +368,7 @@ def subset_image(self, S): sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[2,3],[1,3],[1,3]], multiedges=True) sage: MG = Matroid(G) - sage: sorted([sorted(c) for c in M.circuits()]) + sage: sorted([sorted(c) for c in MG.circuits()]) [[0, 1], [0, 2, 4], [0, 2, 5], [0, 3, 4], [0, 3, 5], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [2, 3], [4, 5]] From 0eaed3c4a04f90e9747ae17fa3e0f55373af5373 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 4 Nov 2023 15:16:31 -0700 Subject: [PATCH 158/538] .github/workflows/macos.yml: Use xcode_13.2.1 with macOS 11 so that homebrew does not complain --- .github/workflows/macos.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 5b448cec1bb..91c38807e76 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -21,16 +21,16 @@ on: osversion_xcodeversion_toxenv_tuples: description: 'Stringified JSON object' default: >- - [["latest", "", "homebrew-macos-usrlocal-minimal"], - ["latest", "", "homebrew-macos-usrlocal-standard"], - ["11", "xcode_11.7", "homebrew-macos-usrlocal-standard"], - ["12", "", "homebrew-macos-usrlocal-standard"], - ["13", "xcode_15.0", "homebrew-macos-usrlocal-standard"], - ["latest", "", "homebrew-macos-usrlocal-maximal"], - ["latest", "", "homebrew-macos-usrlocal-python3_xcode-standard"], - ["latest", "", "conda-forge-macos-minimal"], - ["latest", "", "conda-forge-macos-standard"], - ["latest", "", "conda-forge-macos-maximal"]] + [["latest", "", "homebrew-macos-usrlocal-minimal"], + ["latest", "", "homebrew-macos-usrlocal-standard"], + ["11", "xcode_13.2.1", "homebrew-macos-usrlocal-standard"], + ["12", "", "homebrew-macos-usrlocal-standard"], + ["13", "xcode_15.0", "homebrew-macos-usrlocal-standard"], + ["latest", "", "homebrew-macos-usrlocal-maximal"], + ["latest", "", "homebrew-macos-usrlocal-python3_xcode-standard"], + ["latest", "", "conda-forge-macos-minimal"], + ["latest", "", "conda-forge-macos-standard"], + ["latest", "", "conda-forge-macos-maximal"]] type: string extra_sage_packages: description: 'Extra Sage packages to install as system packages' From 166eb132f6179d73357989403fb29417eb8cb36e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 4 Nov 2023 15:18:47 -0700 Subject: [PATCH 159/538] .github/workflows/ci-macos.yml (dist): Fix use of 'git describe' --- .github/workflows/ci-macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index 9482eb9632b..2d101f7878a 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -85,7 +85,7 @@ jobs: run: | git config --global user.email "nobody@example.com" git config --global user.name "Sage GitHub CI" - SAGE_ROOT=. SAGE_SRC=./src src/bin/sage-update-version $(git describe) || echo "(ignoring error)" + SAGE_ROOT=. SAGE_SRC=./src src/bin/sage-update-version $(git describe --tags) || echo "(ignoring error)" - name: make dist run: | ./configure --enable-download-from-upstream-url && make dist From 543cd2dca5f88a23aacd5c50132b32639a87c083 Mon Sep 17 00:00:00 2001 From: "John H. Palmieri" Date: Sat, 4 Nov 2023 15:52:23 -0700 Subject: [PATCH 160/538] Check whether command-line tools includes the executable ld-classic, and if so, set LDFLAGS to use it. --- src/bin/sage-env | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/bin/sage-env b/src/bin/sage-env index 72aa454bf4a..b4fca91b314 100644 --- a/src/bin/sage-env +++ b/src/bin/sage-env @@ -277,15 +277,6 @@ export UNAME=`uname | sed 's/CYGWIN.*/CYGWIN/' ` # Mac OS X-specific setup if [ "$UNAME" = "Darwin" ]; then export MACOSX_VERSION=`uname -r | awk -F. '{print $1}'` - # Try to identify command-line tools version. - # See https://apple.stackexchange.com/q/180957/351985. - XCLT_VERSION=`pkgutil --pkg-info=com.apple.pkg.CLTools_Executables | awk '/version: / { print $NF }' | cut -d. -f-1` - # If this didn't produce an integer, set to 0. - case $XCLT_VERSION in - ''|*[!0-9]*) export XCLT_VERSION=0 ;; # bad - *) : ;; # good - esac - export XCLT_VERSION # Work around problems on recent OS X crashing with an error message # "... may have been in progress in another thread when fork() was called" # when objective-C functions are called after fork(). See Issue #25921. @@ -383,7 +374,10 @@ if [ -n "$PYTHONHOME" ]; then fi if [ -n "$SAGE_LOCAL" ]; then - if [ "$UNAME" = "Darwin" ] && [ "$XCLT_VERSION" -ge 15 ]; then + # On OS X, test whether "ld-classic" is present in the installed + # version of the command-line tools. If so, we add "-ld_classic" + # to LD_FLAGS. See #36599. + if [ "$UNAME" = "Darwin" ] && [ -x "$(xcode-select -p)/usr/bin/ld-classic" ] ; then LDFLAGS="-L$SAGE_LOCAL/lib -Wl,-ld_classic,-rpath,$SAGE_LOCAL/lib $LDFLAGS" else LDFLAGS="-L$SAGE_LOCAL/lib -Wl,-rpath,$SAGE_LOCAL/lib $LDFLAGS" From eff3be578a8efae01d8cdfcb8d79f7dd2341f2e3 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 5 Nov 2023 09:05:59 +0900 Subject: [PATCH 161/538] Check sagemath/sage also on publish-live-doc job --- .github/workflows/doc-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-publish.yml b/.github/workflows/doc-publish.yml index 1a42a22dbb8..961809e343e 100644 --- a/.github/workflows/doc-publish.yml +++ b/.github/workflows/doc-publish.yml @@ -94,7 +94,7 @@ jobs: publish-live-doc: runs-on: ubuntu-latest - if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'develop' + if: github.event.workflow_run.conclusion == 'success' && github.repository == 'sagemath/sage' && github.event.workflow_run.head_branch == 'develop' steps: - name: Download live doc uses: actions/github-script@v6.4.1 From 9ce90a05ffcd798eb96c06cf9be6555e0d1baa03 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 5 Nov 2023 09:16:38 +0900 Subject: [PATCH 162/538] Soothe linter --- src/sage/misc/sageinspect.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 8c734ecd36d..0fa8551a271 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1806,8 +1806,10 @@ def formatannotation(annotation, base_module=None): return annotation.__module__ + '.' + annotation.__qualname__ return repr(annotation) + _formatannotation = formatannotation + def sage_formatargspec(args, varargs=None, varkw=None, defaults=None, kwonlyargs=(), kwonlydefaults=None, annotations={}, formatarg=str, From fb22d1cdbf4e3870c7cf3995d5d0780735481ed1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Nov 2023 08:40:50 -0800 Subject: [PATCH 163/538] src/sage/misc/sageinspect.py: Fix pycodestyle complaint --- src/sage/misc/sageinspect.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 8c734ecd36d..0fa8551a271 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1806,8 +1806,10 @@ def formatannotation(annotation, base_module=None): return annotation.__module__ + '.' + annotation.__qualname__ return repr(annotation) + _formatannotation = formatannotation + def sage_formatargspec(args, varargs=None, varkw=None, defaults=None, kwonlyargs=(), kwonlydefaults=None, annotations={}, formatarg=str, From a739e04ea2516ccd6c6e7336baa1daf5ccb3e2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 5 Nov 2023 18:33:10 +0100 Subject: [PATCH 164/538] clean E702 etc in integer.pyx --- src/sage/rings/integer.pyx | 308 ++++++++++++++++++++----------------- 1 file changed, 167 insertions(+), 141 deletions(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 3ecd0bd986d..744e8d37cf8 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -207,7 +207,8 @@ new_gen_from_integer = None cdef extern from *: int unlikely(int) nogil # Defined by Cython -cdef object numpy_long_interface = {'typestr': '=i4' if sizeof(long) == 4 else '=i8' } +cdef object numpy_long_interface = {'typestr': '=i4' if sizeof(long) == 4 + else '=i8'} cdef object numpy_int64_interface = {'typestr': '=i8'} cdef object numpy_object_interface = {'typestr': '|O'} @@ -288,7 +289,6 @@ cdef _digits_internal(mpz_t v,l,int offset,int power_index,power_list,digits) no cdef mpz_t mpz_res cdef mpz_t mpz_quot cdef Integer temp - cdef int v_int if power_index < 5: # It turns out that simple repeated division is very fast for # relatively few digits. I don't think this is a real algorithmic @@ -318,6 +318,7 @@ cdef mpz_t PARI_PSEUDOPRIME_LIMIT mpz_init(PARI_PSEUDOPRIME_LIMIT) mpz_ui_pow_ui(PARI_PSEUDOPRIME_LIMIT, 2, 64) + def is_Integer(x): """ Return ``True`` if ``x`` is of the Sage :class:`Integer` type. @@ -336,12 +337,14 @@ def is_Integer(x): """ return isinstance(x, Integer) + cdef inline Integer as_Integer(x) noexcept: if isinstance(x, Integer): return x else: return Integer(x) + cdef class IntegerWrapper(Integer): r""" Rationale for the :class:`IntegerWrapper` class: @@ -612,8 +615,6 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): # mpz_init_set_sage(self.value, x) cdef Integer tmp - cdef char* xs - cdef int paritype cdef Py_ssize_t j cdef object otmp @@ -675,8 +676,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): elif (isinstance(x, list) or isinstance(x, tuple)) and base > 1: b = the_integer_ring(base) - if b == 2: # we use a faster method - for j from 0 <= j < len(x): + if b == 2: # we use a faster method + for j in range(len(x)): otmp = x[j] if isinstance(otmp, int): if ( otmp) == 1: @@ -968,7 +969,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: m.list() [5] """ - return [ self ] + return [self] def __dealloc__(self): mpz_clear(self.value) @@ -1037,7 +1038,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: (-45)._mathml_() '-45' """ - return '%s'%self + return '%s' % self def __mpz__(self): """ @@ -1098,7 +1099,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): '1000000000' """ if base < 2 or base > 36: - raise ValueError("base (=%s) must be between 2 and 36" % base) + raise ValueError(f"base (={base}) must be between 2 and 36") cdef size_t n cdef char *s n = mpz_sizeinbase(self.value, base) + 2 @@ -1157,16 +1158,15 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): '112th' sage: ZZ(111).ordinal_str() '111th' - """ - if self<0: + if self < 0: raise ValueError("Negative integers are not ordinals.") n = self.abs() - if ((n%100)!=11 and n%10==1): + if (n % 100) != 11 and n % 10 == 1: th = 'st' - elif ((n%100)!=12 and n%10==2): + elif (n % 100) != 12 and n % 10 == 2: th = 'nd' - elif ((n%100)!=13 and n%10==3): + elif (n % 100) != 13 and n % 10 == 3: th = 'rd' else: th = 'th' @@ -1513,7 +1513,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): o = -one z = zero l = [z]*(s if s >= padto else padto) - for i from 0<= i < s: + for i in range(s): # mpz_tstbit seems to return 0 for the high-order bit of # negative numbers?! if mpz_tstbit(self_abs.value,i): @@ -1521,7 +1521,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): else: s = mpz_sizeinbase(self.value, 2) do_sig_on = (s > 256) - if do_sig_on: sig_on() + if do_sig_on: + sig_on() # We use a divide and conquer approach (suggested by the prior # author, malb?, of the digits method) here: for base b, compute @@ -1577,7 +1578,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): # assigning zero. _digits_internal(self.value,l,0,i-1,power_list,digits) - if do_sig_on: sig_off() + if do_sig_on: + sig_off() # padding should be taken care of with-in the function # all we need to do is return @@ -1908,7 +1910,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if mpz_fits_slong_p(self.value): return s * mpz_get_si(self.value) else: - return s * int(self) # will raise the appropriate exception + return s * int(self) # will raise the appropriate exception cdef _mul_long(self, long n) noexcept: """ @@ -2024,9 +2026,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): # left * den(right) / num(right) y = Rational.__new__(Rational) mpq_div_zz(y.value, (left).value, - mpq_numref((right).value)) + mpq_numref((right).value)) mpz_mul(mpq_numref(y.value), mpq_numref(y.value), - mpq_denref((right).value)) + mpq_denref((right).value)) return y return coercion_model.bin_op(left, right, operator.truediv) @@ -2460,7 +2462,6 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef size_t l_min cdef size_t l_max cdef size_t l - cdef Integer result cdef mpz_t accum cdef mpz_t temp_exp @@ -2578,7 +2579,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if (1 << (pow_2-1)) == upper-lower: pow_2 -= 1 pow_2_things = [rif_m]*pow_2 - for i from 1<=ii>=0: middle = lower + int(2)**i @@ -2683,13 +2684,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef Integer result cdef size_t n_log2 cdef size_t m_log2 - cdef size_t guess # this will contain the final answer + cdef size_t guess # this will contain the final answer cdef bint guess_filled = 0 # this variable is only used in one branch below - cdef mpz_t z if isinstance(m, Integer): - _m=m + _m = m else: - _m=Integer(m) + _m = Integer(m) self_sgn = mpz_sgn(self.value) if self_sgn == 0: @@ -2717,7 +2717,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): # we've already excluded the case when m is an exact power of 2 - if n_log2/m_log2 > 8000: + if n_log2 / m_log2 > 8000: # If we have a very large number of digits, it can be a nice # shortcut to test the guess using interval arithmetic. # (suggested by David Harvey and Carl Witty) @@ -2729,7 +2729,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): guess_filled = 1 elif self < approx_compare: guess_filled = 1 - guess = guess - 1 + guess = guess - 1 if not guess_filled: # At this point, either # 1) self is close enough to a perfect power of m that we @@ -2864,15 +2864,14 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if elog == -sage.rings.infinity.infinity or m**elog == self: return elog - if (isinstance(m, Rational) - and m.numer() == 1): + if isinstance(m, Rational) and m.numer() == 1: elog = -self.exact_log(m.denom()) if m**elog == self: return elog from sage.functions.log import function_log return function_log(self,dont_call_method_on_arg=True)/\ - function_log(m,dont_call_method_on_arg=True) + function_log(m,dont_call_method_on_arg=True) def exp(self, prec=None): r""" @@ -3113,7 +3112,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef list all, prev, sorted cdef Py_ssize_t tip, top - cdef Py_ssize_t i, j, e, ee + cdef Py_ssize_t i, e, ee cdef Integer apn, p, pn, z, all_tip f = self.factor() @@ -3124,7 +3123,6 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef unsigned long p_c, pn_c, apn_c cdef Py_ssize_t all_len, sorted_len, prev_len cdef unsigned long* ptr - cdef unsigned long* empty_c cdef unsigned long* swap_tmp cdef unsigned long* all_c cdef unsigned long* sorted_c @@ -3222,7 +3220,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sorted = [] tip = 0 top = len(all) - mpz_mul(pn.value, pn.value, p.value) # pn *= p + mpz_mul(pn.value, pn.value, p.value) # pn *= p for a in prev: # apn = a*pn apn = PY_NEW(Integer) @@ -3510,7 +3508,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ZeroDivisionError: cannot raise to a power modulo 0 """ cdef Integer x, _exp, _mod - _exp = Integer(exp); _mod = Integer(mod) + _exp = Integer(exp) + _mod = Integer(mod) if mpz_cmp_si(_mod.value,0) == 0: raise ZeroDivisionError("cannot raise to a power modulo 0") @@ -3763,51 +3762,75 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): # We need to find i. m = start % 30 if 0 <= m <= 1: - i = 0; m = start + (1-m) + i = 0 + m = start + (1-m) elif 1 < m <= 7: - i = 1; m = start + (7-m) + i = 1 + m = start + (7-m) elif 7 < m <= 11: - i = 2; m = start + (11-m) + i = 2 + m = start + (11-m) elif 11 < m <= 13: - i = 3; m = start + (13-m) + i = 3 + m = start + (13-m) elif 13 < m <= 17: - i = 4; m = start + (17-m) + i = 4 + m = start + (17-m) elif 17 < m <= 19: - i = 5; m = start + (19-m) + i = 5 + m = start + (19-m) elif 19 < m <= 23: - i = 6; m = start + (23-m) + i = 6 + m = start + (23-m) elif 23 < m <= 29: - i = 7; m = start + (29-m) - dif[0]=6;dif[1]=4;dif[2]=2;dif[3]=4;dif[4]=2;dif[5]=4;dif[6]=6;dif[7]=2 + i = 7 + m = start + (29-m) + dif[0] = 6 + dif[1] = 4 + dif[2] = 2 + dif[3] = 4 + dif[4] = 2 + dif[5] = 4 + dif[6] = 6 + dif[7] = 2 cdef Integer x = PY_NEW(Integer) if mpz_fits_ulong_p(self.value): n = mpz_get_ui(self.value) # ignores the sign automatically - if n == 1: return one - if start <= 2 and n%2==0: - mpz_set_ui(x.value,2); return x - if start <= 3 and n%3==0: - mpz_set_ui(x.value,3); return x - if start <= 5 and n%5==0: - mpz_set_ui(x.value,5); return x + if n == 1: + return one + if start <= 2 and n % 2 == 0: + mpz_set_ui(x.value,2) + return x + if start <= 3 and n % 3 == 0: + mpz_set_ui(x.value,3) + return x + if start <= 5 and n % 5 == 0: + mpz_set_ui(x.value,5) + return x limit = sqrt_double( n) - if bound < limit: limit = bound + if bound < limit: + limit = bound # Algorithm: only trial divide by numbers that # are congruent to 1,7,11,13,17,19,23,29 mod 30=2*3*5. while m <= limit: - if n%m == 0: - mpz_set_ui(x.value, m); return x - m += dif[i%8] + if n % m == 0: + mpz_set_ui(x.value, m) + return x + m += dif[i % 8] i += 1 mpz_abs(x.value, self.value) return x else: # self is big -- it doesn't fit in unsigned long. if start <= 2 and mpz_even_p(self.value): - mpz_set_ui(x.value,2); return x + mpz_set_ui(x.value,2) + return x if start <= 3 and mpz_divisible_ui_p(self.value,3): - mpz_set_ui(x.value,3); return x + mpz_set_ui(x.value,3) + return x if start <= 5 and mpz_divisible_ui_p(self.value,5): - mpz_set_ui(x.value,5); return x + mpz_set_ui(x.value,5) + return x # x.value = floor(sqrt(self.value)) sig_on() @@ -3829,7 +3852,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return x def factor(self, algorithm='pari', proof=None, limit=None, int_=False, - verbose=0): + verbose=0): """ Return the prime factorization of this integer as a formal Factorization object. @@ -3949,23 +3972,22 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): raise ValueError("Algorithm is not known") cdef Integer n, p, unit - cdef int i if mpz_sgn(self.value) == 0: raise ArithmeticError("factorization of 0 is not defined") if mpz_sgn(self.value) > 0: - n = self + n = self unit = one else: - n = PY_NEW(Integer) + n = PY_NEW(Integer) unit = PY_NEW(Integer) mpz_neg(n.value, self.value) mpz_set_si(unit.value, -1) if mpz_cmpabs_ui(n.value, 1) == 0: return IntegerFactorization([], unit=unit, unsafe=True, - sort=False, simplify=False) + sort=False, simplify=False) if limit is not None: from sage.rings.factorint import factor_trial_division @@ -3986,7 +4008,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): F = [(smallInteger(a), smallInteger(b)) for a, b in F] F.sort() return IntegerFactorization(F, unit=unit, unsafe=True, - sort=False, simplify=False) + sort=False, simplify=False) if mpz_sizeinbase(n.value, 2) < 40: from sage.rings.factorint import factor_trial_division @@ -3997,20 +4019,20 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): F = factor_using_pari(n, int_=int_, debug_level=verbose, proof=proof) F.sort() return IntegerFactorization(F, unit=unit, unsafe=True, - sort=False, simplify=False) + sort=False, simplify=False) elif algorithm == 'flint': from sage.rings.factorint_flint import factor_using_flint F = factor_using_flint(n) F.sort() return IntegerFactorization(F, unit=unit, unsafe=True, - sort=False, simplify=False) + sort=False, simplify=False) elif algorithm in ['kash', 'magma']: if algorithm == 'kash': from sage.interfaces.kash import kash as I else: from sage.interfaces.magma import magma as I - str_res = I.eval('Factorization(%s)'%n) + str_res = I.eval('Factorization(%s)' % n) # The result looks like "[ , , ... ] str_res = str_res.replace(']', '').replace('[', '').replace('>', '').replace('<', '').split(',') res = [int(s.strip()) for s in str_res] @@ -4025,7 +4047,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): F = qsieve(n) F.sort() return IntegerFactorization(F, unit=unit, unsafe=True, - sort=False, simplify=False) + sort=False, simplify=False) else: from sage.interfaces.ecm import ecm res = [(p, 1) for p in ecm.factor(n, proof=proof)] @@ -4051,10 +4073,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: 0.support() Traceback (most recent call last): ... - ArithmeticError: Support of 0 not defined. + ArithmeticError: Support of 0 not defined """ if self.is_zero(): - raise ArithmeticError("Support of 0 not defined.") + raise ArithmeticError("Support of 0 not defined") return sage.arith.all.prime_factors(self) def coprime_integers(self, m): @@ -4345,7 +4367,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if mpz_cmpabs_ui(self.value, 1) <= 0: return self - odd = PY_NEW(Integer) + odd = PY_NEW(Integer) bits = mpz_scan1(self.value, 0) mpz_tdiv_q_2exp(odd.value, self.value, bits) return odd @@ -4918,100 +4940,100 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): cdef unsigned long b, c cdef mpz_t u, sabs, nabs a = mpz_cmp_ui(n.value, 2) - if a <= 0: # n <= 2 - if a == 0: # n == 2 - if mpz_popcount(self.value) == 1: #number of bits set in self == 1 + if a <= 0: # n <= 2 + if a == 0: # n == 2 + if mpz_popcount(self.value) == 1: # number of bits set in self == 1 return 1 else: return 0 a = mpz_cmp_si(n.value, -2) - if a >= 0: # -2 <= n < 2: + if a >= 0: # -2 <= n < 2: a = mpz_get_si(n.value) - if a == 1: # n == 1 - if mpz_cmp_ui(self.value, 1) == 0: # Only 1 is a power of 1 + if a == 1: # n == 1 + if mpz_cmp_ui(self.value, 1) == 0: # Only 1 is a power of 1 return 1 else: return 0 - elif a == 0: # n == 0 - if mpz_cmp_ui(self.value, 0) == 0 or mpz_cmp_ui(self.value, 1) == 0: # 0^0 = 1, 0^x = 0 + elif a == 0: # n == 0 + if mpz_cmp_ui(self.value, 0) == 0 or mpz_cmp_ui(self.value, 1) == 0: # 0^0 = 1, 0^x = 0 return 1 else: return 0 - elif a == -1: # n == -1 - if mpz_cmp_ui(self.value, 1) == 0 or mpz_cmp_si(self.value, -1) == 0: # 1 and -1 are powers of -1 + elif a == -1: # n == -1 + if mpz_cmp_ui(self.value, 1) == 0 or mpz_cmp_si(self.value, -1) == 0: # 1 and -1 are powers of -1 return 1 else: return 0 - elif a == -2: # n == -2 + elif a == -2: # n == -2 mpz_init(sabs) mpz_abs(sabs, self.value) - if mpz_popcount(sabs) == 1: # number of bits set in |self| == 1 - b = mpz_scan1(sabs, 0) % 2 # b == 1 if |self| is an odd power of 2, 0 if |self| is an even power + if mpz_popcount(sabs) == 1: # number of bits set in |self| == 1 + b = mpz_scan1(sabs, 0) % 2 # b == 1 if |self| is an odd power of 2, 0 if |self| is an even power mpz_clear(sabs) if (b == 1 and mpz_cmp_ui(self.value, 0) < 0) or (b == 0 and mpz_cmp_ui(self.value, 0) > 0): # An odd power of -2 is negative, an even power must be positive. return 1 - else: # number of bits set in |self| is not 1, so self cannot be a power of -2 + else: # number of bits set in |self| is not 1, so self cannot be a power of -2 return 0 - else: # |self| is not a power of 2, so self cannot be a power of -2 + else: # |self| is not a power of 2, so self cannot be a power of -2 return 0 - else: # n < -2 + else: # n < -2 mpz_init(nabs) mpz_neg(nabs, n.value) - if mpz_popcount(nabs) == 1: # |n| = 2^k for k >= 2. We special case this for speed + if mpz_popcount(nabs) == 1: # |n| = 2^k for k >= 2. We special case this for speed mpz_init(sabs) mpz_abs(sabs, self.value) - if mpz_popcount(sabs) == 1: # |self| = 2^L for some L >= 0. - b = mpz_scan1(sabs, 0) # the bit that self is set at - c = mpz_scan1(nabs, 0) # the bit that n is set at + if mpz_popcount(sabs) == 1: # |self| = 2^L for some L >= 0. + b = mpz_scan1(sabs, 0) # the bit that self is set at + c = mpz_scan1(nabs, 0) # the bit that n is set at # Having obtained b and c, we're done with nabs and sabs (on this branch anyway) mpz_clear(nabs) mpz_clear(sabs) - if b % c == 0: # Now we know that |self| is a power of |n| - b = (b // c) % 2 # Whether b // c is even or odd determines whether (-2^c)^(b // c) is positive or negative + if b % c == 0: # Now we know that |self| is a power of |n| + b = (b // c) % 2 # Whether b // c is even or odd determines whether (-2^c)^(b // c) is positive or negative a = mpz_cmp_ui(self.value, 0) if b == 0 and a > 0 or b == 1 and a < 0: # These two cases are that b // c is even and self positive, or b // c is odd and self negative return 1 - else: # The sign of self is wrong + else: # The sign of self is wrong return 0 - else: # Since |self| is not a power of |n|, self cannot be a power of n + else: # Since |self| is not a power of |n|, self cannot be a power of n return 0 - else: # self is not a power of 2, and thus cannot be a power of n, which is a power of 2. + else: # self is not a power of 2, and thus cannot be a power of n, which is a power of 2. mpz_clear(nabs) mpz_clear(sabs) return 0 - else: # |n| is not a power of 2, so we use mpz_remove + else: # |n| is not a power of 2, so we use mpz_remove mpz_init(u) sig_on() b = mpz_remove(u, self.value, nabs) sig_off() # Having obtained b and u, we're done with nabs mpz_clear(nabs) - if mpz_cmp_ui(u, 1) == 0: # self is a power of |n| + if mpz_cmp_ui(u, 1) == 0: # self is a power of |n| mpz_clear(u) - if b % 2 == 0: # an even power of |n|, and since self > 0, this means that self is a power of n + if b % 2 == 0: # an even power of |n|, and since self > 0, this means that self is a power of n return 1 else: return 0 - elif mpz_cmp_si(u, -1) == 0: # -self is a power of |n| + elif mpz_cmp_si(u, -1) == 0: # -self is a power of |n| mpz_clear(u) - if b % 2 == 1: # an odd power of |n|, and thus self is a power of n + if b % 2 == 1: # an odd power of |n|, and thus self is a power of n return 1 else: return 0 - else: # |self| is not a power of |n|, so self cannot be a power of n + else: # |self| is not a power of |n|, so self cannot be a power of n mpz_clear(u) return 0 - elif mpz_popcount(n.value) == 1: # n > 2 and in fact n = 2^k for k >= 2 - if mpz_popcount(self.value) == 1: # since n is a power of 2, so must self be. - if mpz_scan1(self.value, 0) % mpz_scan1(n.value, 0) == 0: # log_2(self) is divisible by log_2(n) + elif mpz_popcount(n.value) == 1: # n > 2 and in fact n = 2^k for k >= 2 + if mpz_popcount(self.value) == 1: # since n is a power of 2, so must self be. + if mpz_scan1(self.value, 0) % mpz_scan1(n.value, 0) == 0: # log_2(self) is divisible by log_2(n) return 1 else: return 0 - else: # self is not a power of 2, and thus not a power of n + else: # self is not a power of 2, and thus not a power of n return 0 - else: # n > 2, but not a power of 2, so we use mpz_remove + else: # n > 2, but not a power of 2, so we use mpz_remove mpz_init(u) sig_on() mpz_remove(u, self.value, n.value) @@ -5252,8 +5274,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return (self, zero) if get_data else False _small_primes_table[:] = [ - 0,1,1,1,0,1,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0, # 1, 3,..., 49 - 0,1,0,0,1,1,0,0,1,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,0, # 51, 53,..., 99 + 0,1,1,1,0,1,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0, # 001, 03,..., 49 + 0,1,0,0,1,1,0,0,1,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,0, # 051, 53,..., 99 1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,1, # 101,103,...,149 1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,1,0,0,0,0,1,1,0,1,1, # 151,153,...,199 0,0,0,0,0,1,0,0,0,0,0,1,0,1,1,0,1,0,0,1,1,0,0,0,0, # 201,203,...,249 @@ -5725,7 +5747,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): global objtogen if objtogen is None: from cypari2.gen import objtogen - flag = self < 0 and proof + flag = self < 0 and proof return objtogen(self).qfbclassno(flag).sage() def squarefree_part(self, long bound=-1): @@ -5829,7 +5851,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: 144168.next_probable_prime() 144169 """ - return Integer( self.__pari__().nextprime(True) ) + return Integer(self.__pari__().nextprime(True)) def next_prime(self, proof=None): r""" @@ -6138,7 +6160,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: len([D for D in srange(-100,100) if D.is_discriminant()]) 100 """ - return self%4 in [0,1] + return self % 4 in [0, 1] def is_fundamental_discriminant(self): """ @@ -6166,17 +6188,16 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: len([D for D in srange(-100,100) # needs sage.libs.pari ....: if D.is_fundamental_discriminant()]) 61 - """ - if self in [0,1]: + if self in [0, 1]: return False - Dmod4 = self%4 - if Dmod4 in [2,3]: + Dmod4 = self % 4 + if Dmod4 in [2, 3]: return False if Dmod4 == 1: return self.is_squarefree() - d = self//4 - return d%4 in [2,3] and d.is_squarefree() + d = self // 4 + return d % 4 in [2, 3] and d.is_squarefree() cpdef __pari__(self) noexcept: """ @@ -6274,9 +6295,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): True """ if self.ndigits(2) > 10000: - return 'StringToInteger("%s",16)'%self.str(16) - else: - return str(self) + return 'StringToInteger("%s",16)' % self.str(16) + return str(self) def _sage_input_(self, sib, coerced): r""" @@ -6339,13 +6359,13 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: Integer(-102).sqrtrem() Traceback (most recent call last): ... - ValueError: square root of negative integer not defined. + ValueError: square root of negative integer not defined """ if mpz_sgn(self.value) < 0: - raise ValueError("square root of negative integer not defined.") + raise ValueError("square root of negative integer not defined") cdef Integer s = PY_NEW(Integer) - cdef Integer r = PY_NEW(Integer) + cdef Integer r = PY_NEW(Integer) mpz_sqrtrem(s.value, r.value, self.value) return s, r @@ -6365,10 +6385,10 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: Integer(-102).isqrt() Traceback (most recent call last): ... - ValueError: square root of negative integer not defined. + ValueError: square root of negative integer not defined """ if mpz_sgn(self.value) < 0: - raise ValueError("square root of negative integer not defined.") + raise ValueError("square root of negative integer not defined") cdef Integer x = PY_NEW(Integer) @@ -6696,7 +6716,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): try: y = Integer(y) except TypeError: - raise TypeError("unsupported operands for %s: %s, %s"%(("<<" if sign == 1 else ">>"), self, y)) + raise TypeError("unsupported operands for %s: %s, %s" % (("<<" if sign == 1 else ">>"), self, y)) except ValueError: return coercion_model.bin_op(self, y, operator.lshift if sign == 1 else operator.rshift) @@ -6945,8 +6965,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): def crt(self, y, m, n): """ Return the unique integer between `0` and `mn` that is congruent to - the integer modulo `m` and to `y` modulo `n`. We assume that `m` and - `n` are coprime. + the integer modulo `m` and to `y` modulo `n`. + + We assume that `m` and `n` are coprime. EXAMPLES:: @@ -6958,10 +6979,12 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: m%11 5 """ - cdef object g, s, t + cdef object g, s cdef Integer _y, _m, _n - _y = Integer(y); _m = Integer(m); _n = Integer(n) - g, s, t = _m.xgcd(_n) + _y = Integer(y) + _m = Integer(m) + _n = Integer(n) + g, s, _ = _m.xgcd(_n) if not g.is_one(): raise ArithmeticError("CRT requires that gcd of moduli is 1.") # Now s*m + t*n = 1, so the answer is x + (y-x)*s*m, where x=self. @@ -7023,7 +7046,6 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return sage.rings.infinity.Infinity return smallInteger(mpz_popcount(self.value)) - def conjugate(self): """ Return the complex conjugate of this integer, which is the @@ -7323,7 +7345,7 @@ def GCD_list(v): cdef int i, n = len(v) cdef Integer z = PY_NEW(Integer) - for i from 0 <= i < n: + for i in range(n): if not isinstance(v[i], Integer): if not isinstance(v, list): v = list(v) @@ -7336,7 +7358,7 @@ def GCD_list(v): sig_on() mpz_gcd(z.value, (v[0]).value, (v[1]).value) - for i from 2 <= i < n: + for i in range(2, n): if mpz_cmp_ui(z.value, 1) == 0: break mpz_gcd(z.value, z.value, (v[i]).value) @@ -7480,7 +7502,7 @@ cdef class long_to_Z(Morphism): def _repr_type(self): return "Native" -############### INTEGER CREATION CODE ##################### +# ############## INTEGER CREATION CODE ##################### # This variable holds the size of any Integer object in bytes. cdef int sizeof_Integer @@ -7492,6 +7514,7 @@ global_dummy_Integer = Integer() # Reallocate to one limb to fix :trac:`31340` and :trac:`33081` _mpz_realloc(global_dummy_Integer.value, 1) + def _check_global_dummy_Integer(): """ Return ``True`` if the global dummy :class:`Integer` is ok. @@ -7560,13 +7583,13 @@ cdef PyObject* fast_tp_new(type t, args, kwds) except NULL: # they do not possess references to other Python # objects (as indicated by the Py_TPFLAGS_HAVE_GC flag). # See below for a more detailed description. - new = PyObject_Malloc( sizeof_Integer ) + new = PyObject_Malloc(sizeof_Integer) if unlikely(new == NULL): raise MemoryError # Now set every member as set in z, the global dummy Integer # created before this tp_new started to operate. - memcpy(new, (global_dummy_Integer), sizeof_Integer ) + memcpy(new, (global_dummy_Integer), sizeof_Integer) # We allocate memory for the _mp_d element of the value of this # new Integer. We allocate one limb. Normally, one would use @@ -7670,15 +7693,16 @@ cdef integer(x) noexcept: return x return Integer(x) + def free_integer_pool(): cdef int i cdef PyObject *o global integer_pool_count, integer_pool_size - for i from 0 <= i < integer_pool_count: + for i in range(integer_pool_count): o = integer_pool[i] - mpz_clear( (o).value ) + mpz_clear((o).value) # Free the object. This assumes that Py_TPFLAGS_HAVE_GC is not # set. If it was set another free function would need to be # called. @@ -7688,6 +7712,7 @@ def free_integer_pool(): integer_pool_count = 0 sig_free(integer_pool) + # Replace default allocation and deletion with faster custom ones hook_fast_tp_functions() @@ -7695,7 +7720,8 @@ hook_fast_tp_functions() initialized = False cdef set_zero_one_elements() noexcept: global the_integer_ring, initialized - if initialized: return + if initialized: + return the_integer_ring._zero_element = Integer(0) the_integer_ring._one_element = Integer(1) initialized = True From f7269e42d7ecac7afef5390a196ba29273b20b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 5 Nov 2023 18:54:38 +0100 Subject: [PATCH 165/538] some fixes for E221 --- src/sage/misc/superseded.py | 6 +-- src/sage/modules/free_module.py | 14 +++--- src/sage/modules/with_basis/morphism.py | 4 +- src/sage/plot/plot3d/platonic.py | 29 ++++++++----- src/sage/plot/plot3d/tri_plot.py | 58 ++++++++++++------------- 5 files changed, 58 insertions(+), 53 deletions(-) diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 6e93d8e5a51..87352e4f361 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -363,10 +363,10 @@ def __init__(self, issue_number, func, module, instance=None, unbound=None): try: self.__dict__.update(func.__dict__) except AttributeError: - pass # Cython classes don't have __dict__ + pass # Cython classes don't have __dict__ self.func = func - self.issue_number = issue_number - self.instance = instance # for use with methods + self.issue_number = issue_number + self.instance = instance # for use with methods self.unbound = unbound self.__module__ = module if isinstance(func, type(deprecation)): diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 5a65b4260f0..99538112cbc 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -2443,7 +2443,7 @@ def aux(length, norm, max_): iters = [iter(R) for _ in range(len(G))] for x in iters: next(x) # put at 0 - zero = R(0) + zero = R.zero() v = [zero for _ in range(len(G))] n = 0 z = self(0) @@ -3873,11 +3873,11 @@ def intersection(self, other): V2 = self A1 = V1.basis_matrix() A2 = V2.basis_matrix() - S = A1.stack(A2) - K = S.integer_kernel(self.base_ring()).basis_matrix() - n = int(V1.dimension()) + S = A1.stack(A2) + K = S.integer_kernel(self.base_ring()).basis_matrix() + n = int(V1.dimension()) K = K.matrix_from_columns(range(n)) - B = K*A1 + B = K * A1 return self.span(B) def __and__(self, other): @@ -5201,10 +5201,10 @@ def __quotient_matrices(self, sub): # Our algorithm is to note that D is determined if we just # replace both A and S by the submatrix got from their pivot # columns. - P = A.pivots() + P = A.pivots() AA = A.matrix_from_columns(P) SS = S.matrix_from_columns(P) - D = SS * AA**(-1) + D = SS * AA**(-1) # Compute the image of each basis vector for ``self`` under the # map "write an element of ``self`` in terms of the basis A" then diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index b94629a8dfe..30b4041f0cb 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -1055,7 +1055,7 @@ def coreduced(self, y): on_basis = self.on_basis() assert y in G - result = G.zero() + result = G.zero() remainder = y while not remainder.is_zero(): @@ -1447,7 +1447,7 @@ def __init__(self, domain, diagonal, codomain=None, category=None): if codomain is None: raise ValueError("The codomain should be specified") if not (domain.basis().keys() == codomain.basis().keys() and - domain.base_ring() == codomain.base_ring()): + domain.base_ring() == codomain.base_ring()): raise ValueError("The domain and codomain should have the same base ring " "and the same basis indexing") from collections.abc import Callable diff --git a/src/sage/plot/plot3d/platonic.py b/src/sage/plot/plot3d/platonic.py index be590739c3e..94d15ab16ad 100644 --- a/src/sage/plot/plot3d/platonic.py +++ b/src/sage/plot/plot3d/platonic.py @@ -152,6 +152,7 @@ def prep(G, center, size, kwds): G = G.translate(center) return G + @rename_keyword(alpha='opacity') def tetrahedron(center=(0, 0, 0), size=1, **kwds): """ @@ -255,15 +256,16 @@ def tetrahedron(center=(0, 0, 0), size=1, **kwds): one = RR.one() sqrt2 = RR(2).sqrt() sqrt6 = RR(6).sqrt() - point_list = [(0,0,1), - (2*sqrt2/3, 0, -one/3), - ( -sqrt2/3, sqrt6/3, -one/3), - ( -sqrt2/3, -sqrt6/3, -one/3)] + point_list = [(0, 0, 1), + (2*sqrt2/3, 0, -one/3), + (-sqrt2/3, sqrt6/3, -one/3), + (-sqrt2/3, -sqrt6/3, -one/3)] face_list = [[0,1,2],[1,3,2],[0,2,3],[0,3,1]] if 'aspect_ratio' not in kwds: kwds['aspect_ratio'] = [1, 1, 1] return index_face_set(face_list, point_list, enclosed=True, center=center, size=size, **kwds) + @rename_keyword(alpha='opacity') def cube(center=(0, 0, 0), size=1, color=None, frame_thickness=0, frame_color=None, **kwds): @@ -405,6 +407,7 @@ def cube(center=(0, 0, 0), size=1, color=None, frame_thickness=0, B += frame3d((-0.5,-0.5,-0.5),(0.5,0.5,0.5), thickness=frame_thickness, color=frame_color) return prep(B, center, size, kwds) + @rename_keyword(alpha='opacity') def octahedron(center=(0, 0, 0), size=1, **kwds): r""" @@ -440,7 +443,8 @@ def octahedron(center=(0, 0, 0), size=1, **kwds): kwds['enclosed'] = True if 'aspect_ratio' not in kwds: kwds['aspect_ratio'] = [1, 1, 1] - return prep(Box(1,1,1).dual(**kwds), center, size, kwds) + return prep(Box(1, 1, 1).dual(**kwds), center, size, kwds) + @rename_keyword(alpha='opacity') def dodecahedron(center=(0, 0, 0), size=1, **kwds): @@ -514,21 +518,21 @@ def dodecahedron(center=(0, 0, 0), size=1, **kwds): - Robert Bradshaw, William Stein """ RR = RDF - one = RR(1) + one = RR.one() sqrt3 = RR(3).sqrt() sqrt5 = RR(5).sqrt() R3 = RR**3 - rot = matrix(RR, [[ -one/2,-sqrt3/2, 0], - [ sqrt3/2, -one/2, 0], - [ 0, 0, 1]]) - rot2 = rot*rot + rot = matrix(RR, [[-one / 2, -sqrt3 / 2, 0], + [sqrt3 / 2, -one / 2, 0], + [0, 0, 1]]) + rot2 = rot * rot # The top - Q = R3([0,0,1]) + Q = R3([0, 0, 1]) # The first ring P1 = R3([2*one/3, 0, sqrt5/3]) # The second ring - R1 = R3([sqrt5/3, 1/sqrt3, one/3]) + R1 = R3([sqrt5/3, 1/sqrt3, one/3]) R2 = R3([sqrt5/3, -1/sqrt3, one/3]) top = [Q, P1, rot*P1, rot2*P1, R1, rot*R2, rot*R1, rot2*R2, rot2*R1, R2] @@ -555,6 +559,7 @@ def dodecahedron(center=(0, 0, 0), size=1, **kwds): # vertex_spheres += [faces.stickers(['red','yellow','blue','purple','black','orange'], .1, .1)] # [faces] # return Graphics3dGroup(vertex_spheres) + @rename_keyword(alpha='opacity') def icosahedron(center=(0, 0, 0), size=1, **kwds): r""" diff --git a/src/sage/plot/plot3d/tri_plot.py b/src/sage/plot/plot3d/tri_plot.py index da719020117..256b0d348c3 100644 --- a/src/sage/plot/plot3d/tri_plot.py +++ b/src/sage/plot/plot3d/tri_plot.py @@ -412,38 +412,38 @@ def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, self.interface(0, sw.top, sw.top_c, nw.bottom, nw.bottom_c) self.interface(0, se.top, se.top_c, ne.bottom, ne.bottom_c) - #get the boundary information about the subsquares - left = sw.left + nw.left[1:] - left_c = sw.left_c + nw.left_c - right = se.right + ne.right[1:] - right_c = se.right_c + ne.right_c - top = nw.top + ne.top[1:] - top_c = nw.top_c + ne.top_c - bottom = sw.bottom + se.bottom[1:] + # get the boundary information about the subsquares + left = sw.left + nw.left[1:] + left_c = sw.left_c + nw.left_c + right = se.right + ne.right[1:] + right_c = se.right_c + ne.right_c + top = nw.top + ne.top[1:] + top_c = nw.top_c + ne.top_c + bottom = sw.bottom + se.bottom[1:] bottom_c = sw.bottom_c + se.bottom_c else: # just build the square we're in if self._g is None: - sw = [(min_x,min_y,sw_z[0])] - nw = [(min_x,max_y,nw_z[0])] - se = [(max_x,min_y,se_z[0])] - ne = [(max_x,max_y,ne_z[0])] - c = [[(mid_x,mid_y,mid_z[0])]] + sw = [(min_x, min_y, sw_z[0])] + nw = [(min_x, max_y, nw_z[0])] + se = [(max_x, min_y, se_z[0])] + ne = [(max_x, max_y, ne_z[0])] + c = [[(mid_x, mid_y, mid_z[0])]] else: - sw = [(min_x,min_y,sw_z[0]),sw_z[1]] - nw = [(min_x,max_y,nw_z[0]),nw_z[1]] - se = [(max_x,min_y,se_z[0]),se_z[1]] - ne = [(max_x,max_y,ne_z[0]),ne_z[1]] - c = [[(mid_x,mid_y,mid_z[0]),mid_z[1]]] - - left = [sw,nw] - left_c = c - top = [nw,ne] - top_c = c - right = [se,ne] - right_c = c - bottom = [sw,se] + sw = [(min_x, min_y, sw_z[0]), sw_z[1]] + nw = [(min_x, max_y, nw_z[0]), nw_z[1]] + se = [(max_x, min_y, se_z[0]), se_z[1]] + ne = [(max_x, max_y, ne_z[0]), ne_z[1]] + c = [[(mid_x, mid_y, mid_z[0]), mid_z[1]]] + + left = [sw, nw] + left_c = c + top = [nw, ne] + top_c = c + right = [se, ne] + right_c = c + bottom = [sw, se] bottom_c = c return PlotBlock(left, left_c, top, top_c, right, right_c, bottom, bottom_c) @@ -465,9 +465,9 @@ def interface(self, n, p, p_c, q, q_c): sage: t._objects[-1].get_vertices() ((-1/4, 0, 1/16), (-1/4, 1/4, 1/8), (-3/8, 1/8, 3/16)) """ - m = [p[0]] # a sorted union of p and q - mpc = [p_c[0]] # centers from p_c corresponding to m - mqc = [q_c[0]] # centers from q_c corresponding to m + m = [p[0]] # a sorted union of p and q + mpc = [p_c[0]] # centers from p_c corresponding to m + mqc = [q_c[0]] # centers from q_c corresponding to m i = 1 j = 1 From a945f880985732b9c34030b47f451df761700904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 5 Nov 2023 18:55:44 +0100 Subject: [PATCH 166/538] E221 in cubic_braid --- src/sage/groups/cubic_braid.py | 66 +++++++++++++++++----------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index e8cb4a4e19f..debecbc0ba1 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -141,7 +141,7 @@ def eliminate_item(tietze_list): if second is None: return None middle = tietze_list[1:i] - end = tietze_list[i+1:l] + end = tietze_list[i+1:l] if first == second: return [-first] + middle + end else: @@ -490,7 +490,7 @@ def find_root(domain): if root[0] == 0: continue root_bur = root[0] - if root[1] == 1: + if root[1] == 1: break return root_bur @@ -747,7 +747,7 @@ def __init__(self, names, cbg_type=None): sage: U5 = AssionGroupU(5) # indirect doctest sage: TestSuite(U5).run() # long time """ - n = Integer(len(names)) + n = Integer(len(names)) if n < 1: raise ValueError("the number of strands must be an integer larger than one") @@ -759,12 +759,12 @@ def __init__(self, names, cbg_type=None): free_group = FreeGroup(names) self._cbg_type = cbg_type self._nstrands = n + 1 - self._ident = self._cbg_type.value + self._nstrands.str() + 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)] + 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 @@ -796,12 +796,12 @@ def __init__(self, names, cbg_type=None): # the following global pointers to classical group realizations will be set in the private method # _create_classical_realization # ------------------------------------------------------------------------------------------------ - self._classical_group = None # This is the classical Group returned by as_classical_group - self._classical_base_group = None # this only differs for special cases for Assion groups from the former - self._classical_invariant_form = None # invariant form of the classical base group - self._classical_embedding = None # if self._classical_group different from self._classical_base_group - self._centralizing_matrix = None # for Assion groups: element in classical base group commuting with self - self._centralizing_element = None # image under nat. map of the former one in the proj. classical group + self._classical_group = None # This is the classical Group returned by as_classical_group + self._classical_base_group = None # this only differs for special cases for Assion groups from the former + self._classical_invariant_form = None # invariant form of the classical base group + self._classical_embedding = None # if self._classical_group different from self._classical_base_group + self._centralizing_matrix = None # for Assion groups: element in classical base group commuting with self + self._centralizing_element = None # image under nat. map of the former one in the proj. classical group return def _repr_(self): @@ -1095,7 +1095,7 @@ def set_classical_realization(self, base_group, proj_group, centralizing_matrix, # ------------------------------------------------------------------------------ # Setting the List of Braid Images # ------------------------------------------------------------------------------ - im_gens = [base_group(m) for m in transvec_matrices] + im_gens = [base_group(m) for m in transvec_matrices] # ------------------------------------------------------------------------------ # By the work of Assion no check on the group homomorphism is needed, at all. @@ -1109,7 +1109,7 @@ def set_classical_realization(self, base_group, proj_group, centralizing_matrix, # ------------------------------------------------------------------------------ # Do the projective group realization if needed # ------------------------------------------------------------------------------ - embedding = self._classical_embedding + embedding = self._classical_embedding classical_group = None if proj_group is None: classical_group = base_group @@ -1128,19 +1128,19 @@ def set_classical_realization(self, base_group, proj_group, centralizing_matrix, nat_hom = base_group.hom(proj_group.gens(), check=check) centralizing_element = nat_hom(centralizing_matrix) classical_group_gens = [nat_hom(m) for m in transvec_matrices] - classical_group = proj_group.subgroup(classical_group_gens, canonicalize=False) + classical_group = proj_group.subgroup(classical_group_gens, canonicalize=False) hom_to_classic = self.hom(classical_group.gens(), check=check) classical_group.register_conversion(hom_to_classic) # ------------------------------------------------------------------------------ # register constructed items # ------------------------------------------------------------------------------ - self._classical_group = classical_group - self._classical_base_group = base_group - self._classical_invariant_form = base_group.invariant_form() - self._centralizing_matrix = centralizing_matrix - self._centralizing_element = centralizing_element - self._classical_embedding = embedding + self._classical_group = classical_group + self._classical_base_group = base_group + self._classical_invariant_form = base_group.invariant_form() + self._centralizing_matrix = centralizing_matrix + self._centralizing_element = centralizing_element + self._classical_embedding = embedding return # ------------------------------------------------------------------------------- @@ -1211,7 +1211,7 @@ def transvec2mat(v, bas=bas, bform=bform, fact=1): # ------------------------------------------------------------------------------ centralizing_vector = xbas[mhalf-1] centralizing_matrix = base_group(transvec2mat(centralizing_vector, fact=1)) - transvec_matrices = [transvec2mat(v) for v in transvections] + transvec_matrices = [transvec2mat(v) for v in transvections] set_classical_realization(self, base_group, proj_group, centralizing_matrix, transvec_matrices) return @@ -1273,9 +1273,9 @@ def create_unitary_realization(self, m): for j in range(mthird): pos = 3*(j+1)-1 transvections.append(xbas[pos-1]) # t_{3i} = x_{3i-1} - if pos + 1 < m: + if pos + 1 < m: transvections.append(xbas[pos-1]+xbas[pos]+xbas[pos+1]) # t_{3i+1} = x_{3i-1} + x_{3i} + x_{3i+1} - if pos + 3 < m: + if pos + 3 < m: transvections.append(xbas[pos+1]+xbas[pos+2]+xbas[pos+3]) # t_{3i+2} = x_{3i+1} + x_{3i+2} + x_{3i+3} # ----------------------------------------------------------- @@ -1294,7 +1294,7 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): # ------------------------------------------------------------------------------ centralizing_vector = xbas[m-2]+xbas[m-1] centralizing_matrix = base_group(transvec2mat(centralizing_vector, fact=1)) - transvec_matrices = [transvec2mat(v) for v in transvections] + transvec_matrices = [transvec2mat(v) for v in transvections] set_classical_realization(self, base_group, proj_group, centralizing_matrix, transvec_matrices) return @@ -1314,13 +1314,13 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): # Setting the Classical group # ------------------------------------------------------------------------------- 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) + 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) create_sympl_realization(self, dim_sympl_group) elif self._cbg_type == CubicBraidGroup.type.AssionU: dim_unitary_group = n-1 # U(n-1) = GU(n-1, 2) - if n % 3 == 0: + if n % 3 == 0: dim_unitary_group = n # U(n-1) = subgroup PGU(n, 3) create_unitary_realization(self, dim_unitary_group) else: @@ -1344,11 +1344,11 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): UCF = UniversalCyclotomicField() z12 = UCF.gen(12) classical_group = self.as_matrix_group(root_bur=~z12, domain=UCF, reduced='unitary') - self._classical_group = classical_group - self._classical_base_group = classical_group - self._classical_embedding = classical_group + self._classical_group = classical_group + self._classical_base_group = classical_group + self._classical_embedding = classical_group if self._classical_invariant_form is None: - self._classical_invariant_form = classical_group.ambient().invariant_form() + self._classical_invariant_form = classical_group.ambient().invariant_form() return def _element_constructor_(self, x, **kwds): From a4e65b6eac2219a575416b498be4810e2506dcc7 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Jun 2023 23:47:37 -0700 Subject: [PATCH 167/538] More # optional --- src/sage/misc/explain_pickle.py | 214 +++++++++++++++++--------------- 1 file changed, 112 insertions(+), 102 deletions(-) diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index 30c3988850b..2fb34a2234e 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -5,9 +5,9 @@ - Carl Witty (2009-03) -The explain_pickle function takes a pickle and produces Sage code that +The :func:`explain_pickle` function takes a pickle and produces Sage code that will evaluate to the contents of the pickle. Ideally, the combination -of explain_pickle to produce Sage code and sage_eval to evaluate the code +of :func:`explain_pickle` to produce Sage code and :func:`sage_eval` to evaluate the code would be a 100% compatible implementation of cPickle's unpickler; this is almost the case now. @@ -27,9 +27,9 @@ True By default (as above) the code produced contains calls to several -utility functions (unpickle_global, etc.); this is done so that the +utility functions (:func:`unpickle_global`, etc.); this is done so that the code is truly equivalent to the pickle. If the pickle can be loaded -into a future version of Sage, then the code that explain_pickle +into a future version of Sage, then the code that :func:`explain_pickle` produces today should work in that future Sage as well. It is also possible to produce simpler code, that is tied to the current @@ -44,11 +44,11 @@ from sage.rings.rational import make_rational Polynomial_rational_flint(unpickle_PolynomialRing(RationalField(), ('x',), None, False), [make_rational('0'), make_rational('1')], False, True) -The explain_pickle function has several use cases. +The :func:`explain_pickle` function has several use cases. - Write pickling support for your classes - You can use explain_pickle to see what will happen when a pickle + You can use :func:`explain_pickle` to see what will happen when a pickle is unpickled. Consider: is this sequence of commands something that can be easily supported in all future Sage versions, or does it expose internal design decisions that are subject to change? @@ -56,55 +56,55 @@ - Debug old pickles If you have a pickle from an old version of Sage that no longer - unpickles, you can use explain_pickle to see what it is trying to + unpickles, you can use :func:`explain_pickle` to see what it is trying to do, to figure out how to fix it. - - Use explain_pickle in doctests to help maintenance + - Use :func:`explain_pickle` in doctests to help maintenance If you have a ``loads(dumps(S))`` doctest, you could also add an ``explain_pickle(dumps(S))`` doctest. Then if something changes in a way that would invalidate old pickles, the output of - ``explain_pickle`` will also change. At that point, you can add + :func:`explain_pickle` will also change. At that point, you can add the previous output of :obj:`explain_pickle` as a new set of doctests (and then update the :obj:`explain_pickle` doctest to use the new output), to ensure that old pickles will continue to work. -As mentioned above, there are several output modes for :obj:`explain_pickle`, +As mentioned above, there are several output modes for :func:`explain_pickle`, that control fidelity versus simplicity of the output. For example, the GLOBAL instruction takes a module name and a class name and produces the corresponding class. So GLOBAL of ``sage.rings.integer``, ``Integer`` is approximately equivalent to ``sage.rings.integer.Integer``. However, this class lookup process can be customized (using -sage.misc.persist.register_unpickle_override). For instance, +:func:`sage.misc.persist.register_unpickle_override`). For instance, if some future version of Sage renamed ``sage/rings/integer.pyx`` to ``sage/rings/knuth_was_here.pyx``, old pickles would no longer work unless register_unpickle_override was used; in that case, GLOBAL of -'sage.rings.integer', 'integer' would mean +``sage.rings.integer``, ``integer`` would mean ``sage.rings.knuth_was_here.integer``. -By default, ``explain_pickle`` will map this GLOBAL instruction to +By default, :func:`explain_pickle` will map this GLOBAL instruction to ``unpickle_global('sage.rings.integer', 'integer')``. Then when this code -is evaluated, unpickle_global will look up the current mapping in the -register_unpickle_override table, so the generated code will continue -to work even in hypothetical future versions of Sage where integer.pyx +is evaluated, :func:`unpickle_global` will look up the current mapping in the +:func:`register_unpickle_override` table, so the generated code will continue +to work even in hypothetical future versions of Sage where ``integer.pyx`` has been renamed. If you pass the flag ``in_current_sage=True``, then -:obj:`explain_pickle` will generate code that may only work in the +:func:`explain_pickle` will generate code that may only work in the current version of Sage, not in future versions. In this case, it would generate:: from sage.rings.integer import integer -and if you ran explain_pickle in hypothetical future sage, it would generate: +and if you ran :func:`explain_pickle` in hypothetical future sage, it would generate: from sage.rings.knuth_was_here import integer but the current code wouldn't work in the future sage. If you pass the flag ``default_assumptions=True``, then -:obj:`explain_pickle` will generate code that would work in the +:func:`explain_pickle` will generate code that would work in the absence of any special unpickling information. That is, in either current Sage or hypothetical future Sage, it would generate:: @@ -114,32 +114,32 @@ human-readable), but may not actually work; so it is only intended for human reading. -There are several functions used in the output of :obj:`explain_pickle`. +There are several functions used in the output of :func:`explain_pickle`. Here I give a brief description of what they usually do, as well as how to modify their operation (for instance, if you're trying to get old pickles to work). - ``unpickle_global(module, classname)``: - unpickle_global('sage.foo.bar', 'baz') is usually equivalent to - sage.foo.bar.baz, but this can be customized with - register_unpickle_override. + ``unpickle_global('sage.foo.bar', 'baz')`` is usually equivalent to + ``sage.foo.bar.baz``, but this can be customized with + :func:`register_unpickle_override`. - ``unpickle_newobj(klass, args)``: Usually equivalent to ``klass.__new__(klass, *args)``. If ``klass`` is a Python class, then you can define :meth:`__new__` to control the result (this result actually need not be an - instance of klass). (This doesn't work for Cython classes.) + instance of ``klass``). (This doesn't work for Cython classes.) - ``unpickle_build(obj, state)``: If ``obj`` has a :meth:`__setstate__` method, then this is equivalent to - ``obj.__setstate__(state)``. Otherwise uses state to set the attributes + ``obj.__setstate__(state)``. Otherwise uses ``state`` to set the attributes of ``obj``. Customize by defining :meth:`__setstate__`. - ``unpickle_instantiate(klass, args)``: Usually equivalent to ``klass(*args)``. Cannot be customized. - - unpickle_appends(lst, vals): - Appends the values in vals to lst. If not ``isinstance(lst, list)``, + - ``unpickle_appends(lst, vals)``: + Appends the values in ``vals`` to ``lst``. If not ``isinstance(lst, list)``, can be customized by defining a :meth:`append` method. """ @@ -165,7 +165,6 @@ from pickletools import genops -import sage.all from sage.misc.sage_input import SageInputBuilder, SageInputExpression from sage.misc.sage_eval import sage_eval from sage.misc.persist import (unpickle_override, unpickle_global, dumps, @@ -181,30 +180,30 @@ def explain_pickle(pickle=None, file=None, compress=True, **kwargs): r""" Explain a pickle. That is, produce source code such that evaluating the code is equivalent to loading the pickle. Feeding the result - of ``explain_pickle`` to ``sage_eval`` should be totally equivalent to loading + of :func:`explain_pickle` to :func:`sage_eval` should be totally equivalent to loading the ``pickle`` with ``cPickle``. INPUT: - - ``pickle`` -- the pickle to explain, as a string (default: None) - - ``file`` -- a filename of a pickle (default: None) - - ``compress`` -- if False, don't attempt to decompress the pickle - (default: True) - - ``in_current_sage`` -- if True, produce potentially simpler code that is - tied to the current version of Sage. (default: False) - - ``default_assumptions`` -- if True, produce potentially simpler code that - assumes that generic unpickling code will be - used. This code may not actually work. - (default: False) - - ``eval`` -- if True, then evaluate the resulting code and return the - evaluated result. (default: False) - - ``preparse`` -- if True, then produce code to be evaluated with - Sage's preparser; if False, then produce standard - Python code; if None, then produce code that will work - either with or without the preparser. (default: True) - - ``pedantic`` -- if True, then carefully ensures that the result has - at least as much sharing as the result of cPickle - (it may have more, for immutable objects). (default: False) + - ``pickle`` -- the pickle to explain, as a string (default: ``None``) + - ``file`` -- a filename of a pickle (default: ``None``) + - ``compress`` -- if ``False``, don't attempt to decompress the pickle + (default: ``True``) + - ``in_current_sage`` -- if ``True``, produce potentially simpler code that is + tied to the current version of Sage. (default: ``False``) + - ``default_assumptions`` -- if ``True``, produce potentially simpler code that + assumes that generic unpickling code will be + used. This code may not actually work. + (default: ``False``) + - ``eval`` -- if ``True``, then evaluate the resulting code and return the + evaluated result. (default: ``False``) + - ``preparse`` -- if ``True``, then produce code to be evaluated with + Sage's preparser; if ``False``, then produce standard + Python code; if ``None``, then produce code that will work + either with or without the preparser. (default: ``True``) + - ``pedantic`` -- if ``True``, then carefully ensures that the result has + at least as much sharing as the result of cPickle + (it may have more, for immutable objects). (default: ``False``) Exactly one of ``pickle`` (a string containing a pickle) or ``file`` (the filename of a pickle) must be provided. @@ -263,16 +262,16 @@ def explain_pickle_string(pickle, in_current_sage=False, default_assumptions=False, eval=False, preparse=True, pedantic=False): r""" - This is a helper function for explain_pickle. It takes a decompressed + This is a helper function for :func:`explain_pickle`. It takes a decompressed pickle string as input; other than that, its options are all the same - as explain_pickle. + as :func:`explain_pickle`. EXAMPLES:: sage: sage.misc.explain_pickle.explain_pickle_string(dumps("Hello, world", compress=False)) 'Hello, world' - (See the documentation for ``explain_pickle`` for many more examples.) + (See the documentation for :func:`explain_pickle` for many more examples.) """ sib = SageInputBuilder(preparse=preparse) @@ -321,17 +320,19 @@ def name_is_valid(name): class PickleObject(): r""" - Pickles have a stack-based virtual machine. The explain_pickle - pickle interpreter mostly uses SageInputExpressions, from sage_input, + Pickles have a stack-based virtual machine. The :func:`explain_pickle` + pickle interpreter mostly uses :class:`sage.misc.sage_input.SageInputExpression` objects as the stack values. However, sometimes we want some more information about the value on the stack, so that we can generate better (prettier, less confusing) code. In such cases, we push - a PickleObject instead of a SageInputExpression. A PickleObject + a :class:`PickleObject` instead of a :class:`~sage.misc.sage_input.SageInputExpression`. + A :class:`PickleObject` contains a value (which may be a standard Python value, or a - PickleDict or PickleInstance), an expression (a SageInputExpression), + :class:`PickleDict` or :class:`PickleInstance`), an expression + (a :class:`~sage.misc.sage_input.SageInputExpression`), and an "immutable" flag (which checks whether this object - has been converted to a SageInputExpression; if it has, then we - must not mutate the object, since the SageInputExpression would not + has been converted to a :class:`SageInputExpression`; if it has, then we + must not mutate the object, since the :class:`SageInputExpression` would not reflect the changes). """ @@ -375,9 +376,9 @@ def _sage_input_(self, sib, coerced): class PickleDict(): r""" - An object which can be used as the value of a PickleObject. The items + An object which can be used as the value of a :class:`PickleObject`. The items is a list of key-value pairs, where the keys and values are - SageInputExpressions. We use this to help construct dictionary literals, + :class:`SageInputExpression` objects. We use this to help construct dictionary literals, instead of always starting with an empty dictionary and assigning to it. """ @@ -395,8 +396,8 @@ def __init__(self, items): class PickleInstance(): r""" - An object which can be used as the value of a PickleObject. Unlike - other possible values of a PickleObject, a PickleInstance doesn't represent + An object which can be used as the value of a :class:`PickleObject`. Unlike + other possible values of a :class:`PickleObject`, a :class:`PickleInstance` doesn't represent an exact value; instead, it gives the class (type) of the object. """ def __init__(self, klass): @@ -414,7 +415,7 @@ def __init__(self, klass): class PickleExplainer(): r""" An interpreter for the pickle virtual machine, that executes - symbolically and constructs SageInputExpressions instead of + symbolically and constructs :class:`SageInputExpression` objects instead of directly constructing values. """ def __init__(self, sib, in_current_sage=False, default_assumptions=False, @@ -448,7 +449,7 @@ def run_pickle(self, p): r""" Given an (uncompressed) pickle as a string, run the pickle in this virtual machine. Once a STOP has been executed, return - the result (a SageInputExpression representing code which, when + the result (a :class:`SageInputExpression` representing code which, when evaluated, will give the value of the pickle). EXAMPLES:: @@ -477,8 +478,8 @@ def run_pickle(self, p): def check_value(self, v): r""" - Check that the given value is either a SageInputExpression or a - PickleObject. Used for internal sanity checking. + Check that the given value is either a :class:`SageInputExpression` or a + :class:`PickleObject`. Used for internal sanity checking. EXAMPLES:: @@ -514,7 +515,7 @@ def push(self, v): def push_and_share(self, v): r""" Push a value onto the virtual machine's stack; also mark it as shared - for sage_input if we are in pedantic mode. + for :func:`sage_input` if we are in pedantic mode. EXAMPLES:: @@ -595,14 +596,15 @@ def pop_to_mark(self): def share(self, v): r""" - Mark a sage_input value as shared, if we are in pedantic mode. + Mark a :func:`sage_input` value as shared, if we are in pedantic mode. EXAMPLES:: sage: from sage.misc.explain_pickle import * sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() - sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True) + sage: pe = PickleExplainer(sib, in_current_sage=True, + ....: default_assumptions=False, pedantic=True) sage: v = sib(7) sage: v._sie_share False @@ -617,15 +619,16 @@ def share(self, v): def is_mutable_pickle_object(self, v): r""" - Test whether a PickleObject is mutable (has never been converted - to a SageInputExpression). + Test whether a :class:`PickleObject` is mutable (has never been converted + to a :class:`SageInputExpression`). EXAMPLES:: sage: from sage.misc.explain_pickle import * sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() - sage: pe = PickleExplainer(sib, in_current_sage=True, default_assumptions=False, pedantic=True) + sage: pe = PickleExplainer(sib, in_current_sage=True, + ....: default_assumptions=False, pedantic=True) sage: v = PickleObject(1, sib(1)) sage: pe.is_mutable_pickle_object(v) True @@ -1394,7 +1397,12 @@ def GLOBAL(self, name): # OK, we know what module and function name will actually # be used, as well as the actual function. # Is this already available at the command line? - cmdline_f = getattr(sage.all, func, None) + try: + import sage.all + except ImportError: + cmdline_f = None + else: + cmdline_f = getattr(sage.all, func, None) if cmdline_f is f: self.push(PickleObject(f, self.sib.name(func))) return @@ -2368,7 +2376,7 @@ def UNICODE(self, s): def unpickle_newobj(klass, args): r""" Create a new object; this corresponds to the C code - klass->tp_new(klass, args, NULL). Used by ``explain_pickle``. + ``klass->tp_new(klass, args, NULL)``. Used by :func:`explain_pickle`. EXAMPLES:: @@ -2413,7 +2421,7 @@ def pers_load(id): def unpickle_build(obj, state): r""" - Set the state of an object. Used by ``explain_pickle``. + Set the state of an object. Used by :func:`explain_pickle`. EXAMPLES:: @@ -2447,8 +2455,8 @@ def unpickle_build(obj, state): def unpickle_instantiate(fn, args): r""" - Instantiate a new object of class fn with arguments args. Almost always - equivalent to ``fn(*args)``. Used by ``explain_pickle``. + Instantiate a new object of class ``fn`` with arguments ``args``. Almost always + equivalent to ``fn(*args)``. Used by :func:`explain_pickle`. EXAMPLES:: @@ -2469,7 +2477,7 @@ def unpickle_persistent(s): r""" Takes an integer index and returns the persistent object with that index; works by calling whatever callable is stored in - unpickle_persistent_loader. Used by ``explain_pickle``. + ``unpickle_persistent_loader``. Used by :func:`explain_pickle`. EXAMPLES:: @@ -2484,7 +2492,7 @@ def unpickle_persistent(s): def unpickle_extension(code): r""" Takes an integer index and returns the extension object with that - index. Used by ``explain_pickle``. + index. Used by :func:`explain_pickle`. EXAMPLES:: @@ -2512,7 +2520,7 @@ def unpickle_appends(lst, vals): r""" Given a list (or list-like object) and a sequence of values, appends the values to the end of the list. This is careful to do so using the - exact same technique that cPickle would use. Used by ``explain_pickle``. + exact same technique that cPickle would use. Used by :func:`explain_pickle`. EXAMPLES:: @@ -2532,7 +2540,9 @@ def unpickle_appends(lst, vals): def test_pickle(p, verbose_eval=False, pedantic=False, args=()): r""" - Tests explain_pickle on a given pickle p. p can be: + Test :func:`explain_pickle` on a given pickle ``p``. + + ``p`` can be: - a string containing an uncompressed pickle (which will always end with a '.') @@ -2542,14 +2552,14 @@ def test_pickle(p, verbose_eval=False, pedantic=False, args=()): the stack (using persistent IDs), run the pickle fragment, and then STOP (if the string 'mark' occurs in args, then a mark will be pushed) - - an arbitrary object; test_pickle will pickle the object + - an arbitrary object; :func:`test_pickle` will pickle the object - Once it has a pickle, test_pickle will print the pickle's - disassembly, run explain_pickle with in_current_sage=True and - False, print the results, evaluate the results, unpickle the + Once it has a pickle, :func:`test_pickle` will print the pickle's + disassembly, run :func:`explain_pickle` with ``in_current_sage=True`` and + ``False``, print the results, evaluate the results, unpickle the object with cPickle, and compare all three results. - If verbose_eval is True, then test_pickle will print messages + If ``verbose_eval`` is ``True``, then :func:`test_pickle` will print messages before evaluating the pickles; this is to allow for tests where the unpickling prints messages (to verify that the same operations occur in all cases). @@ -2636,7 +2646,7 @@ def pers_load(s): class EmptyOldstyleClass: r""" A featureless old-style class (does not inherit from object); used for - testing explain_pickle. + testing :func:`explain_pickle`. """ def __repr__(self): r""" @@ -2674,7 +2684,7 @@ def __hash__(self): class EmptyNewstyleClass(): r""" A featureless new-style class (inherits from object); used for - testing explain_pickle. + testing :func:`explain_pickle`. """ def __repr__(self): r""" @@ -2696,8 +2706,8 @@ def __repr__(self): class TestReduceGetinitargs: r""" - An old-style class with a __getinitargs__ method. Used for testing - explain_pickle. + An old-style class with a :func:`__getinitargs__` method. Used for testing + :func:`explain_pickle`. """ def __init__(self): r""" @@ -2748,8 +2758,8 @@ def __repr__(self): class TestReduceNoGetinitargs: r""" - An old-style class with no __getinitargs__ method. Used for testing - explain_pickle. + An old-style class with no :meth:`__getinitargs__` method. Used for testing + :func:`explain_pickle`. """ def __init__(self): r""" @@ -2786,8 +2796,8 @@ def __repr__(self): class TestAppendList(list): r""" - A subclass of list, with deliberately-broken append and extend methods. - Used for testing explain_pickle. + A subclass of :class:`list`, with deliberately-broken append and extend methods. + Used for testing :func:`explain_pickle`. """ def append(self): r""" @@ -2835,7 +2845,7 @@ def extend(self): class TestAppendNonlist(): r""" A list-like class, carefully designed to test exact unpickling - behavior. Used for testing explain_pickle. + behavior. Used for testing :func:`explain_pickle`. """ def __init__(self): r""" @@ -2918,8 +2928,8 @@ def __repr__(self): class TestBuild(): r""" - A simple class with a __getstate__ but no __setstate__. Used for testing - explain_pickle. + A simple class with a :meth:`__getstate__` but no :meth:`__setstate__`. Used for testing + :func:`explain_pickle`. """ def __getstate__(self): r""" @@ -2955,8 +2965,8 @@ def __repr__(self): class TestBuildSetstate(TestBuild): r""" - A simple class with a __getstate__ and a __setstate__. Used for testing - explain_pickle. + A simple class with a :meth:`__getstate__` and a :meth:`__setstate__`. Used for testing + :func:`explain_pickle`. """ def __setstate__(self, state): r""" @@ -2978,8 +2988,8 @@ def __setstate__(self, state): class TestGlobalOldName(): r""" A featureless new-style class. When you try to unpickle an instance - of this class, it is redirected to create a TestGlobalNewName instead. - Used for testing explain_pickle. + of this class, it is redirected to create a :class:`TestGlobalNewName` instead. + Used for testing :func:`explain_pickle`. EXAMPLES:: @@ -2993,8 +3003,8 @@ class TestGlobalOldName(): class TestGlobalNewName(): r""" A featureless new-style class. When you try to unpickle an instance - of TestGlobalOldName, it is redirected to create an instance of this - class instead. Used for testing explain_pickle. + of :class:`TestGlobalOldName`, it is redirected to create an instance of this + class instead. Used for testing :func:`explain_pickle`. EXAMPLES:: From ed209d1512e17332480d5e2108049d95a9057882 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 17 May 2023 13:20:30 -0700 Subject: [PATCH 168/538] Massive modularization fixes --- ...ticle_heuberger_krenn_kropf_fsm-in-sage.py | 46 +++++++++---------- src/sage/tests/benchmark.py | 1 + src/sage/tests/book_stein_ent.py | 16 +++---- src/sage/tests/gosper-sum.py | 1 + src/sage/tests/symbolic-series.py | 1 + src/sage/tests/sympy.py | 1 + 6 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py index 6125930bd45..2df7199c47b 100644 --- a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +++ b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py @@ -505,21 +505,21 @@ Sage example in fsm-in-sage.tex, line 1091:: - sage: var('y') + sage: var('y') # optional - sage.symbolic y - sage: def am_entry(trans): + sage: def am_entry(trans): # optional - sage.symbolic ....: return y^add(trans.word_out) / 2 - sage: A = W.adjacency_matrix(entry=am_entry) + sage: A = W.adjacency_matrix(entry=am_entry) # optional - sage.symbolic Sage example in fsm-in-sage.tex, line 1097:: - sage: latex.matrix_column_alignment('c') + sage: latex.matrix_column_alignment('c') # optional - sage.symbolic Sage example in fsm-in-sage.tex, line 1099:: - sage: latex(A) + sage: latex(A) # optional - sage.symbolic \left(\begin{array}{ccccccccc} \frac{1}{2} & \frac{1}{2} \, y^{2} & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & \frac{1}{2} & \frac{1}{2} & 0 & 0 & 0 & 0 & 0 \\ @@ -535,95 +535,95 @@ Sage example in fsm-in-sage.tex, line 1109:: - sage: (pi_not_normalized,) = (A.subs(y=1) - A.parent().identity_matrix())\ + sage: (pi_not_normalized,) = (A.subs(y=1) - A.parent().identity_matrix())\ # optional - sage.symbolic ....: .left_kernel().basis() - sage: pi = pi_not_normalized / pi_not_normalized.norm(p=1) + sage: pi = pi_not_normalized / pi_not_normalized.norm(p=1) # optional - sage.symbolic Sage example in fsm-in-sage.tex, line 1110:: - sage: str(pi) + sage: str(pi) # optional - sage.symbolic '(1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9)' Sage example in fsm-in-sage.tex, line 1117:: - sage: expected_output = derivative(A, y).subs(y=1) * vector(len(W.states())*[1]) + sage: expected_output = derivative(A, y).subs(y=1) * vector(len(W.states())*[1]) # optional - sage.symbolic Sage example in fsm-in-sage.tex, line 1118:: - sage: latex(expected_output) + sage: latex(expected_output) # optional - sage.symbolic \left(1,\,0,\,0,\,0,\,\frac{1}{2},\,1,\,1,\,\frac{1}{2},\,1\right) Sage example in fsm-in-sage.tex, line 1126:: - sage: pi * expected_output + sage: pi * expected_output # optional - sage.symbolic 5/9 Sage example in fsm-in-sage.tex, line 1127:: - sage: latex(pi * expected_output) + sage: latex(pi * expected_output) # optional - sage.symbolic \frac{5}{9} Sage example in fsm-in-sage.tex, line 1129:: - sage: latex(pi * expected_output) + sage: latex(pi * expected_output) # optional - sage.symbolic \frac{5}{9} Sage example in fsm-in-sage.tex, line 1145:: - sage: var('k') + sage: var('k') # optional - sage.symbolic k - sage: moments = W.asymptotic_moments(k) + sage: moments = W.asymptotic_moments(k) # optional - sage.symbolic Sage example in fsm-in-sage.tex, line 1155:: - sage: latex(moments['expectation']) + sage: latex(moments['expectation']) # optional - sage.symbolic \frac{5}{9} \, k + \mathcal{O}\left(1\right) Sage example in fsm-in-sage.tex, line 1162:: - sage: latex(moments['variance']) + sage: latex(moments['variance']) # optional - sage.symbolic \frac{44}{243} \, k + \mathcal{O}\left(1\right) Sage example in fsm-in-sage.tex, line 1192:: - sage: expectation_binary = Id.asymptotic_moments(k)['expectation'] + sage: expectation_binary = Id.asymptotic_moments(k)['expectation'] # optional - sage.symbolic Sage example in fsm-in-sage.tex, line 1195:: - sage: latex(expectation_binary) + sage: latex(expectation_binary) # optional - sage.symbolic \frac{1}{2} \, k + \mathcal{O}\left(1\right) Sage example in fsm-in-sage.tex, line 1202:: - sage: expectation_NAF = Weight(NAF).asymptotic_moments(k)['expectation'] + sage: expectation_NAF = Weight(NAF).asymptotic_moments(k)['expectation'] # optional - sage.symbolic Sage example in fsm-in-sage.tex, line 1205:: - sage: latex(expectation_NAF) + sage: latex(expectation_NAF) # optional - sage.symbolic \frac{1}{3} \, k + \mathcal{O}\left(1\right) Sage example in fsm-in-sage.tex, line 1211:: - sage: Abs = transducers.abs([-1, 0, 1]) + sage: Abs = transducers.abs([-1, 0, 1]) # optional - sage.symbolic Sage example in fsm-in-sage.tex, line 1216:: - sage: latex(moments['expectation']) + sage: latex(moments['expectation']) # optional - sage.symbolic \frac{5}{9} \, k + \mathcal{O}\left(1\right) """ diff --git a/src/sage/tests/benchmark.py b/src/sage/tests/benchmark.py index 626388bd3ab..9f8d665e646 100644 --- a/src/sage/tests/benchmark.py +++ b/src/sage/tests/benchmark.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.symbolic """ Benchmarks diff --git a/src/sage/tests/book_stein_ent.py b/src/sage/tests/book_stein_ent.py index af4f77eb566..b03b5ad3a02 100644 --- a/src/sage/tests/book_stein_ent.py +++ b/src/sage/tests/book_stein_ent.py @@ -41,18 +41,18 @@ '12457502601536945540' sage: s[-20:] # the last 20 digits (long time) '11752880154053967871' -sage: prime_pi(6) +sage: prime_pi(6) # optional - sage.symbolic 3 -sage: prime_pi(100) +sage: prime_pi(100) # optional - sage.symbolic 25 -sage: prime_pi(3000000) +sage: prime_pi(3000000) # optional - sage.symbolic 216816 -sage: plot(prime_pi, 1,1000, rgbcolor=(0,0,1)) +sage: plot(prime_pi, 1,1000, rgbcolor=(0,0,1)) # optional - sage.plot sage.symbolic Graphics object consisting of 1 graphics primitive -sage: P = plot(Li, 2,10000, rgbcolor='purple') -sage: Q = plot(prime_pi, 2,10000, rgbcolor='black') -sage: R = plot(sqrt(x)*log(x),2,10000,rgbcolor='red') -sage: show(P+Q+R,xmin=0, figsize=[8,3]) +sage: P = plot(Li, 2,10000, rgbcolor='purple') # optional - sage.plot sage.symbolic +sage: Q = plot(prime_pi, 2,10000, rgbcolor='black') # optional - sage.plot sage.symbolic +sage: R = plot(sqrt(x)*log(x),2,10000,rgbcolor='red') # optional - sage.plot sage.symbolic +sage: show(P+Q+R,xmin=0, figsize=[8,3]) # optional - sage.plot sage.symbolic sage: R = Integers(3) sage: list(R) [0, 1, 2] diff --git a/src/sage/tests/gosper-sum.py b/src/sage/tests/gosper-sum.py index 76c2438d1c9..16d195dc71b 100644 --- a/src/sage/tests/gosper-sum.py +++ b/src/sage/tests/gosper-sum.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.symbolic """ Some tests about Gosper sums. diff --git a/src/sage/tests/symbolic-series.py b/src/sage/tests/symbolic-series.py index fb42289074d..4aff094d364 100644 --- a/src/sage/tests/symbolic-series.py +++ b/src/sage/tests/symbolic-series.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.symbolic """ Tests for the fast univariate series expansion in Pynac ------------------------------------------------------- diff --git a/src/sage/tests/sympy.py b/src/sage/tests/sympy.py index a42dcab7b2a..2f98f95e00c 100644 --- a/src/sage/tests/sympy.py +++ b/src/sage/tests/sympy.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sympy r""" TESTS: From ec4ac24baeededd93b395bc5420760adb967abca Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 May 2023 15:38:10 -0700 Subject: [PATCH 169/538] More # optional --- .../book_schilling_zabrocki_kschur_primer.py | 4 ++-- src/sage/tests/book_stein_ent.py | 24 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py index b0d56792851..55e6781d0f1 100644 --- a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py +++ b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py @@ -576,8 +576,8 @@ Sage example in ./kschurnotes/notes-mike-anne.tex, line 4055:: - sage: t = var('t') - sage: for mu in Partitions(5): + sage: t = var('t') # optional - sage.symbolic + sage: for mu in Partitions(5): # optional - sage.symbolic ....: print("{} {}".format(mu, sum(t^T.spin() for T in StrongTableaux(3,[4,1,1],mu)))) [5] 0 [4, 1] t diff --git a/src/sage/tests/book_stein_ent.py b/src/sage/tests/book_stein_ent.py index b03b5ad3a02..ed6b046de93 100644 --- a/src/sage/tests/book_stein_ent.py +++ b/src/sage/tests/book_stein_ent.py @@ -157,15 +157,15 @@ 1.09861228866811 sage: log(19683.0) / log(3.0) 9.00000000000000 -sage: plot(log, 0.1,10, rgbcolor=(0,0,1)) +sage: plot(log, 0.1, 10, rgbcolor=(0,0,1)) # optional - sage.plot Graphics object consisting of 1 graphics primitive sage: p = 53 sage: R = Integers(p) sage: a = R.multiplicative_generator() sage: v = sorted([(a^n, n) for n in range(p-1)]) -sage: G = plot(point(v,pointsize=50,rgbcolor=(0,0,1))) -sage: H = plot(line(v,rgbcolor=(0.5,0.5,0.5))) -sage: G + H +sage: G = plot(point(v,pointsize=50,rgbcolor=(0,0,1))) # optional - sage.plot +sage: H = plot(line(v,rgbcolor=(0.5,0.5,0.5))) # optional - sage.plot +sage: G + H # optional - sage.plot Graphics object consisting of 2 graphics primitives sage: q = 93450983094850938450983409623 sage: q.is_prime() @@ -421,11 +421,11 @@ [1, 2, 7, 30, 157] sage: c = continued_fraction([1,1,1,1,1,1,1,1]) sage: v = [(i, c.p(i)/c.q(i)) for i in range(len(c))] -sage: P = point(v, rgbcolor=(0,0,1), pointsize=40) -sage: L = line(v, rgbcolor=(0.5,0.5,0.5)) -sage: L2 = line([(0,c.value()),(len(c)-1,c.value())], \ -....: thickness=0.5, rgbcolor=(0.7,0,0)) -sage: (L+L2+P).show(xmin=0,ymin=1) +sage: P = point(v, rgbcolor=(0,0,1), pointsize=40) # optional - sage.plot +sage: L = line(v, rgbcolor=(0.5,0.5,0.5)) # optional - sage.plot +sage: L2 = line([(0,c.value()), (len(c)-1,c.value())], # optional - sage.plot +....: thickness=0.5, rgbcolor=(0.7,0,0)) +sage: (L + L2 + P).show(xmin=0, ymin=1) # optional - sage.plot sage: def cf(bits): ....: x = (1 + sqrt(RealField(bits)(5))) / 2 ....: return continued_fraction(x) @@ -497,13 +497,13 @@ sage: E Elliptic Curve defined by y^2 = x^3 - 5*x + 4 over Rational Field -sage: P = E.plot(thickness=4,rgbcolor=(0.1,0.7,0.1)) -sage: P.show(figsize=[4,6]) +sage: P = E.plot(thickness=4,rgbcolor=(0.1,0.7,0.1)) # optional - sage.plot +sage: P.show(figsize=[4,6]) # optional - sage.plot sage: E = EllipticCurve(GF(37), [1,0]) sage: E Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 37 -sage: E.plot(pointsize=45) +sage: E.plot(pointsize=45) # optional - sage.plot Graphics object consisting of 1 graphics primitive sage: E = EllipticCurve([-5,4]) sage: P = E([1,0]); Q = E([0,2]) From e808a2c152e5b6b4ae5ba8b01cf6c5ed7d159537 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 20 May 2023 22:49:07 -0700 Subject: [PATCH 170/538] Fixups --- src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py index 2df7199c47b..1731530b9fc 100644 --- a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +++ b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py @@ -535,8 +535,8 @@ Sage example in fsm-in-sage.tex, line 1109:: - sage: (pi_not_normalized,) = (A.subs(y=1) - A.parent().identity_matrix())\ # optional - sage.symbolic - ....: .left_kernel().basis() + sage: A1mI = (A.subs(y=1) - A.parent().identity_matrix()) # optional - sage.symbolic + sage: (pi_not_normalized,) = A1mI.left_kernel().basis() # optional - sage.symbolic sage: pi = pi_not_normalized / pi_not_normalized.norm(p=1) # optional - sage.symbolic From 446a1c971dd1b2f691c248714fc8dcd421b11539 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Thu, 13 Jul 2023 22:17:52 -0700 Subject: [PATCH 171/538] sage.tests: Add # needs --- ...ticle_heuberger_krenn_kropf_fsm-in-sage.py | 1 + src/sage/tests/arxiv_0812_2725.py | 1 + .../book_schilling_zabrocki_kschur_primer.py | 1 + src/sage/tests/book_stein_ent.py | 45 +++--- src/sage/tests/book_stein_modform.py | 1 + src/sage/tests/cmdline.py | 143 ++++++++++-------- src/sage/tests/combinatorial_hopf_algebras.py | 1 + src/sage/tests/finite_poset.py | 1 + src/sage/tests/gap_packages.py | 1 + src/sage/tests/lazy_imports.py | 1 + src/sage/tests/modular_group_cohomology.py | 35 ++--- src/sage/tests/numpy.py | 1 + src/sage/tests/parigp.py | 1 + 13 files changed, 133 insertions(+), 100 deletions(-) diff --git a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py index 1731530b9fc..3828fa50d1c 100644 --- a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +++ b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs r""" This file contains doctests of the article :: diff --git a/src/sage/tests/arxiv_0812_2725.py b/src/sage/tests/arxiv_0812_2725.py index 3f304803c31..62217b3e8d8 100644 --- a/src/sage/tests/arxiv_0812_2725.py +++ b/src/sage/tests/arxiv_0812_2725.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" Sage code for computing k-distant crossing numbers. diff --git a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py index 55e6781d0f1..12bdc5861cf 100644 --- a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py +++ b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat r""" This file contains doctests for the Chapter "k-Schur function primer" for the book "k-Schur functions and affine Schubert calculus" diff --git a/src/sage/tests/book_stein_ent.py b/src/sage/tests/book_stein_ent.py index ed6b046de93..6d8a7306878 100644 --- a/src/sage/tests/book_stein_ent.py +++ b/src/sage/tests/book_stein_ent.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari """ This file contains all the example code from the published book 'Elementary Number Theory: Primes, Congruences, and Secrets' by @@ -41,18 +42,21 @@ '12457502601536945540' sage: s[-20:] # the last 20 digits (long time) '11752880154053967871' -sage: prime_pi(6) # optional - sage.symbolic + +sage: # needs sage.symbolic +sage: prime_pi(6) 3 -sage: prime_pi(100) # optional - sage.symbolic +sage: prime_pi(100) 25 -sage: prime_pi(3000000) # optional - sage.symbolic +sage: prime_pi(3000000) 216816 -sage: plot(prime_pi, 1,1000, rgbcolor=(0,0,1)) # optional - sage.plot sage.symbolic +sage: plot(prime_pi, 1,1000, rgbcolor=(0,0,1)) # needs sage.plot Graphics object consisting of 1 graphics primitive -sage: P = plot(Li, 2,10000, rgbcolor='purple') # optional - sage.plot sage.symbolic -sage: Q = plot(prime_pi, 2,10000, rgbcolor='black') # optional - sage.plot sage.symbolic -sage: R = plot(sqrt(x)*log(x),2,10000,rgbcolor='red') # optional - sage.plot sage.symbolic -sage: show(P+Q+R,xmin=0, figsize=[8,3]) # optional - sage.plot sage.symbolic +sage: P = plot(Li, 2,10000, rgbcolor='purple') # needs sage.plot +sage: Q = plot(prime_pi, 2,10000, rgbcolor='black') # needs sage.plot +sage: R = plot(sqrt(x)*log(x),2,10000,rgbcolor='red') # needs sage.plot +sage: show(P+Q+R,xmin=0, figsize=[8,3]) # needs sage.plot + sage: R = Integers(3) sage: list(R) [0, 1, 2] @@ -157,15 +161,15 @@ 1.09861228866811 sage: log(19683.0) / log(3.0) 9.00000000000000 -sage: plot(log, 0.1, 10, rgbcolor=(0,0,1)) # optional - sage.plot +sage: plot(log, 0.1, 10, rgbcolor=(0,0,1)) # needs sage.plot Graphics object consisting of 1 graphics primitive sage: p = 53 sage: R = Integers(p) sage: a = R.multiplicative_generator() sage: v = sorted([(a^n, n) for n in range(p-1)]) -sage: G = plot(point(v,pointsize=50,rgbcolor=(0,0,1))) # optional - sage.plot -sage: H = plot(line(v,rgbcolor=(0.5,0.5,0.5))) # optional - sage.plot -sage: G + H # optional - sage.plot +sage: G = plot(point(v,pointsize=50,rgbcolor=(0,0,1))) # needs sage.plot +sage: H = plot(line(v,rgbcolor=(0.5,0.5,0.5))) # needs sage.plot +sage: G + H # needs sage.plot Graphics object consisting of 2 graphics primitives sage: q = 93450983094850938450983409623 sage: q.is_prime() @@ -421,11 +425,14 @@ [1, 2, 7, 30, 157] sage: c = continued_fraction([1,1,1,1,1,1,1,1]) sage: v = [(i, c.p(i)/c.q(i)) for i in range(len(c))] -sage: P = point(v, rgbcolor=(0,0,1), pointsize=40) # optional - sage.plot -sage: L = line(v, rgbcolor=(0.5,0.5,0.5)) # optional - sage.plot -sage: L2 = line([(0,c.value()), (len(c)-1,c.value())], # optional - sage.plot + +sage: # needs sage.plot +sage: P = point(v, rgbcolor=(0,0,1), pointsize=40) +sage: L = line(v, rgbcolor=(0.5,0.5,0.5)) +sage: L2 = line([(0,c.value()), (len(c)-1,c.value())], ....: thickness=0.5, rgbcolor=(0.7,0,0)) -sage: (L + L2 + P).show(xmin=0, ymin=1) # optional - sage.plot +sage: (L + L2 + P).show(xmin=0, ymin=1) + sage: def cf(bits): ....: x = (1 + sqrt(RealField(bits)(5))) / 2 ....: return continued_fraction(x) @@ -497,13 +504,13 @@ sage: E Elliptic Curve defined by y^2 = x^3 - 5*x + 4 over Rational Field -sage: P = E.plot(thickness=4,rgbcolor=(0.1,0.7,0.1)) # optional - sage.plot -sage: P.show(figsize=[4,6]) # optional - sage.plot +sage: P = E.plot(thickness=4,rgbcolor=(0.1,0.7,0.1)) # needs sage.plot +sage: P.show(figsize=[4,6]) # needs sage.plot sage: E = EllipticCurve(GF(37), [1,0]) sage: E Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 37 -sage: E.plot(pointsize=45) # optional - sage.plot +sage: E.plot(pointsize=45) # needs sage.plot Graphics object consisting of 1 graphics primitive sage: E = EllipticCurve([-5,4]) sage: P = E([1,0]); Q = E([0,2]) diff --git a/src/sage/tests/book_stein_modform.py b/src/sage/tests/book_stein_modform.py index a43391ba028..56ee188cd50 100644 --- a/src/sage/tests/book_stein_modform.py +++ b/src/sage/tests/book_stein_modform.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.modular """ This file contains a bunch of tests extracted from the published book 'Modular Forms: a Computational Approach' by William Stein, AMS 2007. diff --git a/src/sage/tests/cmdline.py b/src/sage/tests/cmdline.py index 5a06a349f63..5a577d1ff83 100644 --- a/src/sage/tests/cmdline.py +++ b/src/sage/tests/cmdline.py @@ -110,62 +110,68 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False Run Sage itself with various options:: - sage: (out, err, ret) = test_executable([ # long time + sage: # long time + sage: (out, err, ret) = test_executable([ ....: "sage"], pydebug_ignore_warnings=True) - sage: out.find(version()) >= 0 # long time + sage: out.find(version()) >= 0 True - sage: err # long time + sage: err '' - sage: ret # long time + sage: ret 0 - sage: (out, err, ret) = test_executable([ # long time + sage: # long time + sage: (out, err, ret) = test_executable([ ....: "sage"], "3^33\n", pydebug_ignore_warnings=True) - sage: out.find(version()) >= 0 # long time + sage: out.find(version()) >= 0 True - sage: out.find("5559060566555523") >= 0 # long time + sage: out.find("5559060566555523") >= 0 True - sage: err # long time + sage: err '' - sage: ret # long time + sage: ret 0 - sage: (out, err, ret) = test_executable([ # long time + sage: # long time + sage: (out, err, ret) = test_executable([ ....: "sage", "-q"], "3^33\n", pydebug_ignore_warnings=True) - sage: out.find(version()) >= 0 # long time + sage: out.find(version()) >= 0 False - sage: out.find("5559060566555523") >= 0 # long time + sage: out.find("5559060566555523") >= 0 True - sage: err # long time + sage: err '' - sage: ret # long time + sage: ret 0 - sage: (out, err, ret) = test_executable([ # long time + sage: # long time + sage: (out, err, ret) = test_executable([ ....: "sage", "-c", "print(3^33)"]) - sage: print(out) # long time + sage: print(out) 5559060566555523 - sage: err # long time + sage: err '' - sage: ret # long time + sage: ret 0 - sage: (out, err, ret) = test_executable([ # long time + sage: # long time + sage: (out, err, ret) = test_executable([ ....: "sage", "--min", "-c", "print(3^33)"]) - sage: print(out) # long time + sage: print(out) 5559060566555523 - sage: err # long time + sage: err '' - sage: ret # long time + sage: ret 0 - sage: (out, err, ret) = test_executable([ # long time + sage: # long time + sage: (out, err, ret) = test_executable([ ....: "sage", "--startuptime"]) - sage: out.find("Slowest module import") >= 0 # long time + sage: out.find("Slowest module import") >= 0 True - sage: err # long time + sage: err '' - sage: ret # long time + sage: ret 0 Test help:: @@ -208,25 +214,27 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: ret 0 - sage: (out, err, ret) = test_executable(["sage", "--root"]) # optional - sage_spkg - sage: len(out) >= 2 # at least one character + newline; optional - sage_spkg + sage: # optional - sage_spkg + sage: (out, err, ret) = test_executable(["sage", "--root"]) + sage: len(out) >= 2 True - sage: err # optional - sage_spkg + sage: err '' - sage: ret # optional - sage_spkg + sage: ret 0 Test ``sage --info [packages]``:: - sage: out, err, ret = test_executable(["sage", "--info", "sqlite"]) # optional - sage_spkg - sage: print(out) # optional - sage_spkg + sage: # optional - sage_spkg + sage: out, err, ret = test_executable(["sage", "--info", "sqlite"]) + sage: print(out) sqlite... SQLite is a software library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine. ... - sage: err # optional - sage_spkg + sage: err '' - sage: ret # optional - sage_spkg + sage: ret 0 Test ``sage-run`` on a Python file, both with an absolute and with a relative path:: @@ -292,17 +300,18 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False Now test my_script.sage and the preparsed version my_script.sage.py:: - sage: (out, err, ret) = test_executable([ # long time + sage: # long time + sage: (out, err, ret) = test_executable([ ....: "sage", "-t", "--optional=sage", script]) - sage: ret # long time + sage: ret 0 - sage: out.find("All tests passed!") >= 0 # long time + sage: out.find("All tests passed!") >= 0 True - sage: (out, err, ret) = test_executable([ # long time + sage: (out, err, ret) = test_executable([ ....: "sage", "-t", "--optional=sage", script_py]) - sage: ret # long time + sage: ret 0 - sage: out.find("All tests passed!") >= 0 # long time + sage: out.find("All tests passed!") >= 0 True Test that the coding line and doctest are preserved:: @@ -438,13 +447,14 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: ret 42 - sage: (out, err, ret) = test_executable([ # long time + sage: # long time + sage: (out, err, ret) = test_executable([ ....: "sage", "--ipython"], "\n3**33\n", pydebug_ignore_warnings=True) - sage: out.find("5559060566555523") >= 0 # long time + sage: out.find("5559060566555523") >= 0 True - sage: err # long time + sage: err '' - sage: ret # long time + sage: ret 0 sage: (out, err, ret) = test_executable(["sage", "--python"], "print(3^33)\n") @@ -494,13 +504,14 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: ret 0 - sage: (out, err, ret) = test_executable([ # long time + sage: # long time + sage: (out, err, ret) = test_executable([ ....: "sage", "--gap", "-q"], "Size(SymmetricGroup(5));\n") - sage: out # long time + sage: out '120\n' - sage: err.replace('gap: halving pool size.', '').strip() # long time + sage: err.replace('gap: halving pool size.', '').strip() '' - sage: ret # long time + sage: ret 0 sage: (out, err, ret) = test_executable([ # long time # optional - gdb @@ -551,12 +562,13 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False sage: ret 0 - sage: (out, err, ret) = test_executable(["sage", "--R", "--version"]) # optional - r - sage: out.find("R version ") >= 0 # optional - r + sage: # optional - r + sage: (out, err, ret) = test_executable(["sage", "--R", "--version"]) + sage: out.find("R version ") >= 0 True - sage: err # optional - r + sage: err '' - sage: ret # optional - r + sage: ret 0 sage: (out, err, ret) = test_executable(["sage", "--sqlite3", "--version"]) @@ -569,28 +581,31 @@ def test_executable(args, input="", timeout=100.0, pydebug_ignore_warnings=False Check some things requiring an internet connection:: - sage: (out, err, ret) = test_executable(["sage", "--standard"]) # optional - internet - sage: out.find("cython") >= 0 # optional - internet + sage: # optional - internet + sage: (out, err, ret) = test_executable(["sage", "--standard"]) + sage: out.find("cython") >= 0 True - sage: err # optional - internet + sage: err '' - sage: ret # optional - internet + sage: ret 0 - sage: (out, err, ret) = test_executable(["sage", "--optional"]) # optional - internet - sage: out.find("database_cremona_ellcurve") >= 0 # optional - internet + sage: # optional - internet + sage: (out, err, ret) = test_executable(["sage", "--optional"]) + sage: out.find("database_cremona_ellcurve") >= 0 True - sage: err # optional - internet + sage: err '' - sage: ret # optional - internet + sage: ret 0 - sage: (out, err, ret) = test_executable(["sage", "--experimental"]) # optional - internet - sage: out.find("valgrind") >= 0 # optional - internet + sage: # optional - internet + sage: (out, err, ret) = test_executable(["sage", "--experimental"]) + sage: out.find("valgrind") >= 0 True - sage: err # optional - internet + sage: err '' - sage: ret # optional - internet + sage: ret 0 Check an illegal command line option. This outputs an error to stdout, diff --git a/src/sage/tests/combinatorial_hopf_algebras.py b/src/sage/tests/combinatorial_hopf_algebras.py index 6ac40f7aad5..33c0472f404 100644 --- a/src/sage/tests/combinatorial_hopf_algebras.py +++ b/src/sage/tests/combinatorial_hopf_algebras.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.combinat sage.modules r""" Tests For Combinatorial Hopf Algebras diff --git a/src/sage/tests/finite_poset.py b/src/sage/tests/finite_poset.py index 11092c3d966..e6733ef7f5f 100644 --- a/src/sage/tests/finite_poset.py +++ b/src/sage/tests/finite_poset.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.graphs sage.modules """ This file contains test functions that can be used to search bugs by testing random finite posets and lattices. diff --git a/src/sage/tests/gap_packages.py b/src/sage/tests/gap_packages.py index c302b169b8a..b13bba24a83 100644 --- a/src/sage/tests/gap_packages.py +++ b/src/sage/tests/gap_packages.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.gap """ Test the optional GAP packages diff --git a/src/sage/tests/lazy_imports.py b/src/sage/tests/lazy_imports.py index e9bd2aea2c0..8ea93a15ab5 100644 --- a/src/sage/tests/lazy_imports.py +++ b/src/sage/tests/lazy_imports.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.all r""" TESTS: diff --git a/src/sage/tests/modular_group_cohomology.py b/src/sage/tests/modular_group_cohomology.py index be00146dc6f..35bc8b5387f 100644 --- a/src/sage/tests/modular_group_cohomology.py +++ b/src/sage/tests/modular_group_cohomology.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - p_group_cohomology r""" Tests for the optional ``p_group_cohomology`` package. @@ -7,26 +8,26 @@ TESTS:: - sage: from pGroupCohomology import CohomologyRing # optional - p_group_cohomology + sage: from pGroupCohomology import CohomologyRing Computation of a modular cohomology ring of a prime power group in characteristic 2, and comparison with stored result in a database:: - sage: CohomologyRing.set_workspace(tmp_dir()) # optional - p_group_cohomology - sage: H = CohomologyRing(64,14,from_scratch=True) # optional - p_group_cohomology - sage: H.make() # optional - p_group_cohomology - sage: CohomologyRing.set_workspace(tmp_dir()) # optional - p_group_cohomology - sage: H0 = CohomologyRing(64,14) # optional - p_group_cohomology - sage: H.is_isomorphic(H0) # optional - p_group_cohomology + sage: CohomologyRing.set_workspace(tmp_dir()) + sage: H = CohomologyRing(64,14,from_scratch=True) + sage: H.make() + sage: CohomologyRing.set_workspace(tmp_dir()) + sage: H0 = CohomologyRing(64,14) + sage: H.is_isomorphic(H0) ('1*a_2_1', '1*c_2_2', '1*c_4_4', '1*a_1_0', '1*a_1_1', '1*a_3_3') Computation of a modular cohomology ring of a prime power group in odd characteristic, and some algebraic constructions in the cohomology ring:: - sage: H = CohomologyRing(27,4) # optional - p_group_cohomology - sage: H.make() # optional - p_group_cohomology - sage: print(H) # optional - p_group_cohomology + sage: H = CohomologyRing(27,4) + sage: H.make() + sage: print(H) Cohomology ring of Extraspecial 3-group of order 27 and exponent 9 with coefficients in GF(3) @@ -45,14 +46,14 @@ b_2_1*a_3_1, a_1_0*a_5_1, a_3_1*a_5_1] - sage: H.5.massey_power() # optional - p_group_cohomology + sage: H.5.massey_power() : 8-Cocycle in H^*(M27; GF(3)) - sage: H.5.massey_power().as_polynomial() # optional - p_group_cohomology + sage: H.5.massey_power().as_polynomial() '-c_6_2*a_1_0*a_1_1' - sage: H.essential_ideal() # optional - p_group_cohomology + sage: H.essential_ideal() a_1_0*a_1_1, a_1_1*a_3_1 - sage: ascii_art(H.bar_code('LowerCentralSeries')[2]) # known bug (possibly, the output might be correct) # optional - p_group_cohomology + sage: ascii_art(H.bar_code('LowerCentralSeries')[2]) # known bug * *-* *-* @@ -61,11 +62,11 @@ Computation of a modular cohomology ring of a non prime power group in characteristic 2:: - sage: H = CohomologyRing(libgap.AlternatingGroup(6), # optional - p_group_cohomology + sage: H = CohomologyRing(libgap.AlternatingGroup(6), ....: GroupName="A(6)", prime=2, ....: from_scratch=True) - sage: H.make() # optional - p_group_cohomology - sage: print(H) # optional - p_group_cohomology + sage: H.make() + sage: print(H) Cohomology ring of A(6) with coefficients in GF(2) Computation complete diff --git a/src/sage/tests/numpy.py b/src/sage/tests/numpy.py index 8c1c42f385c..5cd78b148d2 100644 --- a/src/sage/tests/numpy.py +++ b/src/sage/tests/numpy.py @@ -1,3 +1,4 @@ +# sage.doctest: needs numpy r""" TESTS: diff --git a/src/sage/tests/parigp.py b/src/sage/tests/parigp.py index 4692b613de4..85eab45423f 100644 --- a/src/sage/tests/parigp.py +++ b/src/sage/tests/parigp.py @@ -1,3 +1,4 @@ +# sage.doctest: needs sage.libs.pari sage.modules r""" This file is meant to catch errors in the PARI/GP package which are not caught by any other tests. From 66dc5d282e2db6c2770b485bd4caf1c4f6ea1437 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 6 Aug 2023 18:32:57 -0700 Subject: [PATCH 172/538] Update # needs --- src/sage/doctest/fixtures.py | 4 ++-- src/sage/symbolic/function.pyx | 7 ++++--- .../tests/article_heuberger_krenn_kropf_fsm-in-sage.py | 4 ++-- src/sage/tests/book_schilling_zabrocki_kschur_primer.py | 9 +++++---- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/sage/doctest/fixtures.py b/src/sage/doctest/fixtures.py index a3b5e9edda7..9fbfdf86db9 100644 --- a/src/sage/doctest/fixtures.py +++ b/src/sage/doctest/fixtures.py @@ -80,9 +80,9 @@ def reproducible_repr(val): frozenset(['a', 'b', 'c', 'd']) sage: print(reproducible_repr([1, frozenset("cab"), set("bar"), 0])) [1, frozenset(['a', 'b', 'c']), set(['a', 'b', 'r']), 0] - sage: print(reproducible_repr({3.0:"three","2":"two",1:"one"})) + sage: print(reproducible_repr({3.0: "three", "2": "two", 1: "one"})) # optional - sage.rings.real_mpfr {'2': 'two', 1: 'one', 3.00000000000000: 'three'} - sage: print(reproducible_repr("foo\nbar")) # demonstrate default case + sage: print(reproducible_repr("foo\nbar")) # demonstrate default case 'foo\nbar' """ diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 589c500d00d..792d81ebcc9 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -642,10 +642,11 @@ cdef class Function(SageObject): sage: hurwitz_zeta(1/2, b) hurwitz_zeta(1/2, [1.500000000 +/- 1.01e-10]) - sage: iv = RIF(1, 1.0001) - sage: airy_ai(iv) + sage: iv = RIF(1, 1.0001) # needs sage.rings.real_interval_field + + sage: airy_ai(iv) # needs sage.rings.real_interval_field airy_ai(1.0001?) - sage: airy_ai(CIF(iv)) + sage: airy_ai(CIF(iv)) # needs sage.rings.complex_interval_field airy_ai(1.0001?) """ if isinstance(x, (float, complex)): diff --git a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py index 3828fa50d1c..6f92f85ec17 100644 --- a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +++ b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py @@ -508,14 +508,14 @@ sage: var('y') # optional - sage.symbolic y - sage: def am_entry(trans): # optional - sage.symbolic + sage: def am_entry(trans): ....: return y^add(trans.word_out) / 2 sage: A = W.adjacency_matrix(entry=am_entry) # optional - sage.symbolic Sage example in fsm-in-sage.tex, line 1097:: - sage: latex.matrix_column_alignment('c') # optional - sage.symbolic + sage: latex.matrix_column_alignment('c') Sage example in fsm-in-sage.tex, line 1099:: diff --git a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py index 12bdc5861cf..2d092c45e59 100644 --- a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py +++ b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py @@ -84,16 +84,17 @@ Sage example in ./kschurnotes/notes-mike-anne.tex, line 406:: - sage: w = W.an_element(); w # long time + sage: # long time + sage: w = W.an_element(); w [ 2 0 0 1 -2] [ 2 0 0 0 -1] [ 1 1 0 0 -1] [ 1 0 1 0 -1] [ 1 0 0 1 -1] - sage: w.reduced_word() # long time + sage: w.reduced_word() [0, 1, 2, 3, 4] - sage: w = W.from_reduced_word([2,1,0]) # long time - sage: w.is_affine_grassmannian() # long time + sage: w = W.from_reduced_word([2,1,0]) + sage: w.is_affine_grassmannian() True Sage example in ./kschurnotes/notes-mike-anne.tex, line 464:: From 8b3ae0b6189650a6d841c0cd29f27cdff4ed966f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 6 Aug 2023 20:45:15 -0700 Subject: [PATCH 173/538] src/sage/tests: Update file-level doctest tag --- src/sage/tests/benchmark.py | 2 +- src/sage/tests/gosper-sum.py | 2 +- src/sage/tests/symbolic-series.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/tests/benchmark.py b/src/sage/tests/benchmark.py index 9f8d665e646..9445a3f7633 100644 --- a/src/sage/tests/benchmark.py +++ b/src/sage/tests/benchmark.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: needs sage.symbolic """ Benchmarks diff --git a/src/sage/tests/gosper-sum.py b/src/sage/tests/gosper-sum.py index 16d195dc71b..84679ac0ff3 100644 --- a/src/sage/tests/gosper-sum.py +++ b/src/sage/tests/gosper-sum.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: needs sage.symbolic """ Some tests about Gosper sums. diff --git a/src/sage/tests/symbolic-series.py b/src/sage/tests/symbolic-series.py index 4aff094d364..5e53d1e07af 100644 --- a/src/sage/tests/symbolic-series.py +++ b/src/sage/tests/symbolic-series.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.symbolic +# sage.doctest: needs sage.symbolic """ Tests for the fast univariate series expansion in Pynac ------------------------------------------------------- From f173e10bbfafa6dff97d5da42eac55f7211f22b9 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 7 Aug 2023 22:44:23 -0700 Subject: [PATCH 174/538] src/sage/tests: sage -fixdoctests --only-tags --- ...ticle_heuberger_krenn_kropf_fsm-in-sage.py | 46 +++++++++---------- .../book_schilling_zabrocki_kschur_primer.py | 4 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py index 6f92f85ec17..d0a51a55eff 100644 --- a/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +++ b/src/sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py @@ -1,4 +1,4 @@ -# sage.doctest: needs sage.graphs +# sage.doctest: needs sage.graphs sage.modules r""" This file contains doctests of the article :: @@ -506,11 +506,11 @@ Sage example in fsm-in-sage.tex, line 1091:: - sage: var('y') # optional - sage.symbolic + sage: var('y') # needs sage.symbolic y sage: def am_entry(trans): ....: return y^add(trans.word_out) / 2 - sage: A = W.adjacency_matrix(entry=am_entry) # optional - sage.symbolic + sage: A = W.adjacency_matrix(entry=am_entry) # needs sage.symbolic Sage example in fsm-in-sage.tex, line 1097:: @@ -520,7 +520,7 @@ Sage example in fsm-in-sage.tex, line 1099:: - sage: latex(A) # optional - sage.symbolic + sage: latex(A) # needs sage.symbolic \left(\begin{array}{ccccccccc} \frac{1}{2} & \frac{1}{2} \, y^{2} & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & \frac{1}{2} & \frac{1}{2} & 0 & 0 & 0 & 0 & 0 \\ @@ -536,95 +536,95 @@ Sage example in fsm-in-sage.tex, line 1109:: - sage: A1mI = (A.subs(y=1) - A.parent().identity_matrix()) # optional - sage.symbolic - sage: (pi_not_normalized,) = A1mI.left_kernel().basis() # optional - sage.symbolic - sage: pi = pi_not_normalized / pi_not_normalized.norm(p=1) # optional - sage.symbolic + sage: A1mI = (A.subs(y=1) - A.parent().identity_matrix()) # needs sage.symbolic + sage: (pi_not_normalized,) = A1mI.left_kernel().basis() # needs sage.symbolic + sage: pi = pi_not_normalized / pi_not_normalized.norm(p=1) # needs sage.symbolic Sage example in fsm-in-sage.tex, line 1110:: - sage: str(pi) # optional - sage.symbolic + sage: str(pi) # needs sage.symbolic '(1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9, 1/9)' Sage example in fsm-in-sage.tex, line 1117:: - sage: expected_output = derivative(A, y).subs(y=1) * vector(len(W.states())*[1]) # optional - sage.symbolic + sage: expected_output = derivative(A, y).subs(y=1) * vector(len(W.states())*[1]) # needs sage.symbolic Sage example in fsm-in-sage.tex, line 1118:: - sage: latex(expected_output) # optional - sage.symbolic + sage: latex(expected_output) # needs sage.symbolic \left(1,\,0,\,0,\,0,\,\frac{1}{2},\,1,\,1,\,\frac{1}{2},\,1\right) Sage example in fsm-in-sage.tex, line 1126:: - sage: pi * expected_output # optional - sage.symbolic + sage: pi * expected_output # needs sage.symbolic 5/9 Sage example in fsm-in-sage.tex, line 1127:: - sage: latex(pi * expected_output) # optional - sage.symbolic + sage: latex(pi * expected_output) # needs sage.symbolic \frac{5}{9} Sage example in fsm-in-sage.tex, line 1129:: - sage: latex(pi * expected_output) # optional - sage.symbolic + sage: latex(pi * expected_output) # needs sage.symbolic \frac{5}{9} Sage example in fsm-in-sage.tex, line 1145:: - sage: var('k') # optional - sage.symbolic + sage: var('k') # needs sage.symbolic k - sage: moments = W.asymptotic_moments(k) # optional - sage.symbolic + sage: moments = W.asymptotic_moments(k) # needs sage.symbolic Sage example in fsm-in-sage.tex, line 1155:: - sage: latex(moments['expectation']) # optional - sage.symbolic + sage: latex(moments['expectation']) # needs sage.symbolic \frac{5}{9} \, k + \mathcal{O}\left(1\right) Sage example in fsm-in-sage.tex, line 1162:: - sage: latex(moments['variance']) # optional - sage.symbolic + sage: latex(moments['variance']) # needs sage.symbolic \frac{44}{243} \, k + \mathcal{O}\left(1\right) Sage example in fsm-in-sage.tex, line 1192:: - sage: expectation_binary = Id.asymptotic_moments(k)['expectation'] # optional - sage.symbolic + sage: expectation_binary = Id.asymptotic_moments(k)['expectation'] # needs sage.symbolic Sage example in fsm-in-sage.tex, line 1195:: - sage: latex(expectation_binary) # optional - sage.symbolic + sage: latex(expectation_binary) # needs sage.symbolic \frac{1}{2} \, k + \mathcal{O}\left(1\right) Sage example in fsm-in-sage.tex, line 1202:: - sage: expectation_NAF = Weight(NAF).asymptotic_moments(k)['expectation'] # optional - sage.symbolic + sage: expectation_NAF = Weight(NAF).asymptotic_moments(k)['expectation'] # needs sage.symbolic Sage example in fsm-in-sage.tex, line 1205:: - sage: latex(expectation_NAF) # optional - sage.symbolic + sage: latex(expectation_NAF) # needs sage.symbolic \frac{1}{3} \, k + \mathcal{O}\left(1\right) Sage example in fsm-in-sage.tex, line 1211:: - sage: Abs = transducers.abs([-1, 0, 1]) # optional - sage.symbolic + sage: Abs = transducers.abs([-1, 0, 1]) # needs sage.symbolic Sage example in fsm-in-sage.tex, line 1216:: - sage: latex(moments['expectation']) # optional - sage.symbolic + sage: latex(moments['expectation']) # needs sage.symbolic \frac{5}{9} \, k + \mathcal{O}\left(1\right) """ diff --git a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py index 2d092c45e59..7b49e6769b1 100644 --- a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py +++ b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py @@ -578,8 +578,8 @@ Sage example in ./kschurnotes/notes-mike-anne.tex, line 4055:: - sage: t = var('t') # optional - sage.symbolic - sage: for mu in Partitions(5): # optional - sage.symbolic + sage: t = var('t') # needs sage.symbolic + sage: for mu in Partitions(5): # needs sage.symbolic ....: print("{} {}".format(mu, sum(t^T.spin() for T in StrongTableaux(3,[4,1,1],mu)))) [5] 0 [4, 1] t From 72fc063d3849ba8276b2089aa249a2e5c41cb501 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 12 Aug 2023 19:23:47 -0700 Subject: [PATCH 175/538] Update # needs --- src/sage/tests/finite_poset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tests/finite_poset.py b/src/sage/tests/finite_poset.py index e6733ef7f5f..de92b818bab 100644 --- a/src/sage/tests/finite_poset.py +++ b/src/sage/tests/finite_poset.py @@ -105,7 +105,7 @@ def test_attrcall(name, L): sage: N5 = posets.PentagonPoset() sage: N5.is_modular() == test_attrcall('is_modular', N5) True - sage: N5.is_constructible_by_doublings('convex') == test_attrcall('is_doubling_convex', N5) + sage: N5.is_constructible_by_doublings('convex') == test_attrcall('is_doubling_convex', N5) # needs sage.combinat True """ if name == 'is_doubling_any': From 362e34f98480dcc0a211b31b373dd69759150e55 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 13 Aug 2023 12:31:51 -0700 Subject: [PATCH 176/538] sage --fixdoctests --no-test --- src/sage/tests/finite_poset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tests/finite_poset.py b/src/sage/tests/finite_poset.py index de92b818bab..d04221dcc13 100644 --- a/src/sage/tests/finite_poset.py +++ b/src/sage/tests/finite_poset.py @@ -105,7 +105,7 @@ def test_attrcall(name, L): sage: N5 = posets.PentagonPoset() sage: N5.is_modular() == test_attrcall('is_modular', N5) True - sage: N5.is_constructible_by_doublings('convex') == test_attrcall('is_doubling_convex', N5) # needs sage.combinat + sage: N5.is_constructible_by_doublings('convex') == test_attrcall('is_doubling_convex', N5) # needs sage.combinat True """ if name == 'is_doubling_any': From f1951b399e581b901a6a128a15c77143dacfe859 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 27 Aug 2023 13:40:45 -0700 Subject: [PATCH 177/538] Update # needs --- src/sage/ext/fast_callable.pyx | 2 +- src/sage/libs/coxeter3/__init__.py | 1 + src/sage/libs/coxeter3/all__sagemath_coxeter3.py | 1 + src/sage/tests/book_schilling_zabrocki_kschur_primer.py | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index bad30e0e605..0a1439b7530 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -1645,7 +1645,7 @@ class IntegerPowerFunction(): pi^2 sage: square(I) # needs sage.symbolic -1 - sage: square(RIF(-1, 1)).str(style='brackets') + sage: square(RIF(-1, 1)).str(style='brackets') # needs sage.rings.real_interval_field '[0.0000000000000000 .. 1.0000000000000000]' sage: IntegerPowerFunction(-1) (^(-1)) diff --git a/src/sage/libs/coxeter3/__init__.py b/src/sage/libs/coxeter3/__init__.py index e69de29bb2d..61138b7bc1a 100644 --- a/src/sage/libs/coxeter3/__init__.py +++ b/src/sage/libs/coxeter3/__init__.py @@ -0,0 +1 @@ +# sage_setup: distribution = sagemath-coxeter3 diff --git a/src/sage/libs/coxeter3/all__sagemath_coxeter3.py b/src/sage/libs/coxeter3/all__sagemath_coxeter3.py index e69de29bb2d..61138b7bc1a 100644 --- a/src/sage/libs/coxeter3/all__sagemath_coxeter3.py +++ b/src/sage/libs/coxeter3/all__sagemath_coxeter3.py @@ -0,0 +1 @@ +# sage_setup: distribution = sagemath-coxeter3 diff --git a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py index 7b49e6769b1..4f91b77e036 100644 --- a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py +++ b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py @@ -1,4 +1,4 @@ -# sage.doctest: needs sage.combinat +# sage.doctest: needs sage.combinat sage.graphs sage.groups r""" This file contains doctests for the Chapter "k-Schur function primer" for the book "k-Schur functions and affine Schubert calculus" From ba7b9f2ed4d2e7b68a82ad610a542a876f005504 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 3 Sep 2023 23:46:22 -0700 Subject: [PATCH 178/538] Add # needs --- src/sage/tests/book_stein_ent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/tests/book_stein_ent.py b/src/sage/tests/book_stein_ent.py index 6d8a7306878..b4d593ff427 100644 --- a/src/sage/tests/book_stein_ent.py +++ b/src/sage/tests/book_stein_ent.py @@ -33,7 +33,7 @@ sage: n.is_prime() # this is instant False sage: p = 2^32582657 - 1 -sage: p.ndigits() +sage: p.ndigits() # needs sage.rings.real_interval_field 9808358 sage: s = p.str(10) # this takes a long time sage: len(s) # s is a very long string (long time) From c506b0690a8107e5ecb7ff4bff4d49f5b585d5c1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 4 Sep 2023 21:55:17 -0700 Subject: [PATCH 179/538] sage.structure: Update # needs --- src/sage/structure/coerce.pyx | 2 ++ src/sage/structure/factorization.py | 7 ++++--- src/sage/structure/parent_old.pyx | 2 +- src/sage/tests/book_stein_modform.py | 2 ++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 8eed934aea3..1e7c4dd1a49 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -517,6 +517,8 @@ cdef class CoercionModel: Check that :trac:`8426` is fixed (see also :trac:`18076`):: sage: import numpy # needs numpy + + sage: # needs sage.rings.real_mpfr sage: x = polygen(RR) sage: numpy.float32('1.5') * x # needs numpy 1.50000000000000*x diff --git a/src/sage/structure/factorization.py b/src/sage/structure/factorization.py index 00571876e39..00ad9658e59 100644 --- a/src/sage/structure/factorization.py +++ b/src/sage/structure/factorization.py @@ -1232,9 +1232,10 @@ def __call__(self, *args, **kwds): sage: F(t=0) 0 - sage: R. = LaurentPolynomialRing(QQ, 1) # needs sage.modules - sage: F = ((x+2)/x**3).factor() # needs sage.modules - sage: F(x=4) # needs sage.modules + sage: # needs sage.libs.pari sage.modules + sage: R. = LaurentPolynomialRing(QQ, 1) + sage: F = ((x+2)/x**3).factor() + sage: F(x=4) 1/64 * 6 """ unit = self.__unit.subs(*args, **kwds) diff --git a/src/sage/structure/parent_old.pyx b/src/sage/structure/parent_old.pyx index c093febf375..c2afaa89000 100644 --- a/src/sage/structure/parent_old.pyx +++ b/src/sage/structure/parent_old.pyx @@ -52,7 +52,7 @@ cdef class Parent(parent.Parent): [(0, 0), (1, 0), (0, 1), (1, 1)] sage: MatrixSpace(GF(3), 1, 1).list() [[0], [1], [2]] - sage: DirichletGroup(3).list() # needs sage.modular + sage: DirichletGroup(3).list() # needs sage.libs.pari sage.modular [Dirichlet character modulo 3 of conductor 1 mapping 2 |--> 1, Dirichlet character modulo 3 of conductor 3 mapping 2 |--> -1] diff --git a/src/sage/tests/book_stein_modform.py b/src/sage/tests/book_stein_modform.py index 56ee188cd50..06e9717ded1 100644 --- a/src/sage/tests/book_stein_modform.py +++ b/src/sage/tests/book_stein_modform.py @@ -5,6 +5,7 @@ TESTS:: + sage: # needs sage.libs.gap sage: G = SL(2,ZZ); G Special Linear Group of degree 2 over Integer Ring sage: S, T = G.gens() @@ -14,6 +15,7 @@ sage: T [1 1] [0 1] + sage: delta_qexp(6) q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) sage: bernoulli(12) From 2a84d764aa25727305cc43eaae5208ba381cfc6a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 8 Sep 2023 22:59:40 -0700 Subject: [PATCH 180/538] sage.tests: Update # needs --- src/sage/tests/book_stein_modform.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/tests/book_stein_modform.py b/src/sage/tests/book_stein_modform.py index 06e9717ded1..667bb057c70 100644 --- a/src/sage/tests/book_stein_modform.py +++ b/src/sage/tests/book_stein_modform.py @@ -1,4 +1,5 @@ -# sage.doctest: needs sage.modular +# sage_setup: distribution = sagemath-repl +# sage.doctest: needs sage.libs.flint sage.modular """ This file contains a bunch of tests extracted from the published book 'Modular Forms: a Computational Approach' by William Stein, AMS 2007. From 3df8c81ab25b71785cc31ae53442d750d2cd58c4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 9 Sep 2023 13:27:47 -0700 Subject: [PATCH 181/538] sage.tests: Update # needs --- src/sage/tests/parigp.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/sage/tests/parigp.py b/src/sage/tests/parigp.py index 85eab45423f..1049149a147 100644 --- a/src/sage/tests/parigp.py +++ b/src/sage/tests/parigp.py @@ -40,32 +40,35 @@ Check that the optional PARI databases work:: - sage: gp.ellinit('"299998a1"') # optional -- pari_elldata + sage: # optional - pari_elldata + sage: gp.ellinit('"299998a1"') [1, 0, 1, 110, -3660, ...] - sage: E = EllipticCurve("1728ba1") - sage: gp(E).ellidentify() # optional -- pari_elldata + sage: E = EllipticCurve("1728ba1") # needs sage.schemes + sage: gp(E).ellidentify() # needs sage.schemes [["1728ba1", [0, 0, 0, -6, 6], [[1, 1]]], [1, 0, 0, 0]] - sage: pari("ellmodulareqn(211)") # optional -- pari_seadata - [x^212 + (-y^7 + 5207*y^6 - 10241606*y^5 + 9430560101*y^4 - 4074860204015*y^3 + 718868274900397*y^2 - 34897101275826114*y + 104096378056356968)*x^211... + sage: pari("ellmodulareqn(211)") # optional - pari_seadata + [x^212 + (-y^7 + 5207*y^6 - 10241606*y^5 + 9430560101*y^4 - 4074860204015*y^3 + + 718868274900397*y^2 - 34897101275826114*y + 104096378056356968)*x^211... The following requires the modular polynomials up to degree 223, while only those up to degree 199 come standard in Sage:: sage: p = next_prime(2^328) - sage: E = EllipticCurve(GF(p), [6,1]) - sage: E.cardinality() # long time (108s on sage.math, 2013), optional -- pari_seadata + sage: E = EllipticCurve(GF(p), [6,1]) # needs sage.schemes + sage: E.cardinality() # long time (108s on sage.math, 2013), optional - pari_seadata, needs sage.schemes 546812681195752981093125556779405341338292357723293496548601032930284335897180749997402596957976244 Create a number field with Galois group `A4`. Group `A4` corresponds to transitive group `(12,3)` in GAP:: + sage: # optional - pari_galpol sage: R. = PolynomialRing(ZZ) - sage: pol = pari("galoisgetpol(12,3)[1]") # optional -- pari_galpol - sage: K. = NumberField(R(pol)) # optional -- pari_galpol - sage: factor(K.discriminant()) # optional -- pari_galpol + sage: pol = pari("galoisgetpol(12,3)[1]") + sage: K. = NumberField(R(pol)) + sage: factor(K.discriminant()) 163^8 - sage: [F.degree() for F,a,b in K.subfields()] # optional -- pari_galpol + sage: [F.degree() for F,a,b in K.subfields()] [1, 3, 4, 4, 4, 4, 6, 6, 6, 12] sage: sorted([12/H.cardinality() for H in AlternatingGroup(4).subgroups()]) [1, 3, 4, 4, 4, 4, 6, 6, 6, 12] From dd20a8c21da480debe4633b043d51f765940bdba Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 9 Jun 2023 00:55:41 -0700 Subject: [PATCH 182/538] More # optional --- src/sage/sat/solvers/sat_lp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/sat/solvers/sat_lp.py b/src/sage/sat/solvers/sat_lp.py index d96ed62b125..dc1ff30d4b7 100644 --- a/src/sage/sat/solvers/sat_lp.py +++ b/src/sage/sat/solvers/sat_lp.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.numerical.mip r""" Solve SAT problems Integer Linear Programming From c9717a3cc1a726384a87368cd23f447b179f0988 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Jun 2023 17:49:17 -0700 Subject: [PATCH 183/538] Modularization fixes for imports --- src/sage/sat/converters/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sage/sat/converters/__init__.py b/src/sage/sat/converters/__init__.py index 70e0cdfdfaa..bb7b60bbb9c 100644 --- a/src/sage/sat/converters/__init__.py +++ b/src/sage/sat/converters/__init__.py @@ -1,2 +1,5 @@ +from sage.misc.lazy_import import lazy_import + from .anf2cnf import ANF2CNFConverter -from sage.rings.polynomial.pbori.cnf import CNFEncoder as PolyBoRiCNFEncoder + +lazy_import('sage.rings.polynomial.pbori.cnf', 'CNFEncoder', as_='PolyBoRiCNFEncoder') From cc1307b9a7ae98c60fee9faf59a773ca2d0828b2 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sat, 10 Jun 2023 17:49:30 -0700 Subject: [PATCH 184/538] More # optional --- src/sage/sat/boolean_polynomials.py | 77 +++++++++++++++-------------- src/sage/sat/converters/polybori.py | 1 + src/sage/sat/solvers/satsolver.pyx | 12 ++--- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index 80b1a13d89c..2c5075d6251 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -71,8 +71,8 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): We construct a very small-scale AES system of equations:: - sage: sr = mq.SR(1,1,1,4,gf2=True,polybori=True) - sage: while True: # workaround (see :trac:`31891`) + sage: sr = mq.SR(1,1,1,4,gf2=True,polybori=True) # optional - sage.modules + sage: while True: # workaround (see :trac:`31891`) # optional - sage.modules ....: try: ....: F, s = sr.polynomial_system() ....: break @@ -81,66 +81,69 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): and pass it to a SAT solver:: - sage: from sage.sat.boolean_polynomials import solve as solve_sat # optional - pycryptosat - sage: s = solve_sat(F) # optional - pycryptosat - sage: F.subs(s[0]) # optional - pycryptosat + sage: from sage.sat.boolean_polynomials import solve as solve_sat + sage: s = solve_sat(F) # optional - pycryptosat sage.modules + sage: F.subs(s[0]) # optional - pycryptosat sage.modules Polynomial Sequence with 36 Polynomials in 0 Variables This time we pass a few options through to the converter and the solver:: - sage: s = solve_sat(F, c_max_vars_sparse=4, c_cutting_number=8) # optional - pycryptosat - sage: F.subs(s[0]) # optional - pycryptosat + sage: s = solve_sat(F, c_max_vars_sparse=4, c_cutting_number=8) # optional - pycryptosat sage.modules + sage: F.subs(s[0]) # optional - pycryptosat sage.modules Polynomial Sequence with 36 Polynomials in 0 Variables - We construct a very simple system with three solutions and ask for a specific number of solutions:: + We construct a very simple system with three solutions + and ask for a specific number of solutions:: - sage: B. = BooleanPolynomialRing() # optional - pycryptosat - sage: f = a*b # optional - pycryptosat - sage: l = solve_sat([f],n=1) # optional - pycryptosat - sage: len(l) == 1, f.subs(l[0]) # optional - pycryptosat + sage: B. = BooleanPolynomialRing() # optional - pycryptosat sage.modules + sage: f = a*b # optional - pycryptosat sage.modules + sage: l = solve_sat([f],n=1) # optional - pycryptosat sage.modules + sage: len(l) == 1, f.subs(l[0]) # optional - pycryptosat sage.modules (True, 0) - sage: l = solve_sat([a*b],n=2) # optional - pycryptosat - sage: len(l) == 2, f.subs(l[0]), f.subs(l[1]) # optional - pycryptosat + sage: l = solve_sat([a*b],n=2) # optional - pycryptosat sage.modules + sage: len(l) == 2, f.subs(l[0]), f.subs(l[1]) # optional - pycryptosat sage.modules (True, 0, 0) - sage: sorted((d[a], d[b]) for d in solve_sat([a*b],n=3)) # optional - pycryptosat + sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=3)) # optional - pycryptosat sage.modules [(0, 0), (0, 1), (1, 0)] - sage: sorted((d[a], d[b]) for d in solve_sat([a*b],n=4)) # optional - pycryptosat + sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=4)) # optional - pycryptosat sage.modules [(0, 0), (0, 1), (1, 0)] - sage: sorted((d[a], d[b]) for d in solve_sat([a*b],n=infinity)) # optional - pycryptosat + sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=infinity)) # optional - pycryptosat sage.modules [(0, 0), (0, 1), (1, 0)] In the next example we see how the ``target_variables`` parameter works:: - sage: from sage.sat.boolean_polynomials import solve as solve_sat # optional - pycryptosat - sage: R. = BooleanPolynomialRing() # optional - pycryptosat - sage: F = [a+b,a+c+d] # optional - pycryptosat + sage: from sage.sat.boolean_polynomials import solve as solve_sat + sage: R. = BooleanPolynomialRing() # optional - pycryptosat sage.modules + sage: F = [a + b, a + c + d] # optional - pycryptosat sage.modules First the normal use case:: - sage: sorted((D[a], D[b], D[c], D[d]) for D in solve_sat(F,n=infinity)) # optional - pycryptosat + sage: sorted((D[a], D[b], D[c], D[d]) # optional - pycryptosat sage.modules + ....: for D in solve_sat(F, n=infinity)) [(0, 0, 0, 0), (0, 0, 1, 1), (1, 1, 0, 1), (1, 1, 1, 0)] Now we are only interested in the solutions of the variables a and b:: - sage: solve_sat(F,n=infinity,target_variables=[a,b]) # optional - pycryptosat + sage: solve_sat(F,n=infinity,target_variables=[a,b]) # optional - pycryptosat sage.modules [{b: 0, a: 0}, {b: 1, a: 1}] Here, we generate and solve the cubic equations of the AES SBox (see :trac:`26676`):: - sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence # optional - pycryptosat, long time - sage: from sage.sat.boolean_polynomials import solve as solve_sat # optional - pycryptosat, long time - sage: sr = sage.crypto.mq.SR(1, 4, 4, 8, allow_zero_inversions = True) # optional - pycryptosat, long time - sage: sb = sr.sbox() # optional - pycryptosat, long time - sage: eqs = sb.polynomials(degree = 3) # optional - pycryptosat, long time - sage: eqs = PolynomialSequence(eqs) # optional - pycryptosat, long time - sage: variables = map(str, eqs.variables()) # optional - pycryptosat, long time - sage: variables = ",".join(variables) # optional - pycryptosat, long time - sage: R = BooleanPolynomialRing(16, variables) # optional - pycryptosat, long time - sage: eqs = [R(eq) for eq in eqs] # optional - pycryptosat, long time - sage: sls_aes = solve_sat(eqs, n = infinity) # optional - pycryptosat, long time - sage: len(sls_aes) # optional - pycryptosat, long time + sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence + sage: from sage.sat.boolean_polynomials import solve as solve_sat + sage: sr = sage.crypto.mq.SR(1, 4, 4, 8, # long time, optional - pycryptosat sage.modules + ....: allow_zero_inversions=True) + sage: sb = sr.sbox() # long time, optional - pycryptosat sage.modules + sage: eqs = sb.polynomials(degree = 3) # long time, optional - pycryptosat sage.modules + sage: eqs = PolynomialSequence(eqs) # long time, optional - pycryptosat sage.modules + sage: variables = map(str, eqs.variables()) # long time, optional - pycryptosat sage.modules + sage: variables = ",".join(variables) # long time, optional - pycryptosat sage.modules + sage: R = BooleanPolynomialRing(16, variables) # long time, optional - pycryptosat sage.modules + sage: eqs = [R(eq) for eq in eqs] # long time, optional - pycryptosat sage.modules + sage: sls_aes = solve_sat(eqs, n = infinity) # long time, optional - pycryptosat sage.modules + sage: len(sls_aes) # long time, optional - pycryptosat sage.modules 256 TESTS: @@ -148,7 +151,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): Test that :trac:`26676` is fixed:: sage: varl = ['k{0}'.format(p) for p in range(29)] - sage: B = BooleanPolynomialRing(names = varl) + sage: B = BooleanPolynomialRing(names=varl) sage: B.inject_variables(verbose=False) sage: keqs = [ ....: k0 + k6 + 1, @@ -162,7 +165,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): ....: k9 + k28, ....: k11 + k20] sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: solve_sat(keqs, n=1, solver=SAT('cryptominisat')) # optional - pycryptosat + sage: solve_sat(keqs, n=1, solver=SAT('cryptominisat')) # optional - pycryptosat [{k28: 0, k26: 1, k24: 0, @@ -187,7 +190,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): k2: 0, k1: 0, k0: 0}] - sage: solve_sat(keqs, n=1, solver=SAT('picosat')) # optional - pycosat + sage: solve_sat(keqs, n=1, solver=SAT('picosat')) # optional - pycosat [{k28: 0, k26: 1, k24: 0, diff --git a/src/sage/sat/converters/polybori.py b/src/sage/sat/converters/polybori.py index ca39def12c1..cbf46d4faa2 100644 --- a/src/sage/sat/converters/polybori.py +++ b/src/sage/sat/converters/polybori.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.rings.polynomial.pbori """ An ANF to CNF Converter using a Dense/Sparse Strategy diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index 1c4ac400cb6..0ed7041c608 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -139,9 +139,9 @@ cdef class SatSolver: sage: from io import StringIO sage: file_object = StringIO("c A sample .cnf file with xor clauses.\np cnf 3 3\n1 2 0\n3 0\nx1 2 3 0") - sage: from sage.sat.solvers.sat_lp import SatLP - sage: solver = SatLP() - sage: solver.read(file_object) + sage: from sage.sat.solvers.sat_lp import SatLP # optional - sage.numerical.mip + sage: solver = SatLP() # optional - sage.numerical.mip + sage: solver.read(file_object) # optional - sage.numerical.mip Traceback (most recent call last): ... NotImplementedError: the solver "an ILP-based SAT Solver" does not support xor clauses @@ -339,7 +339,7 @@ def SAT(solver=None, *args, **kwds): EXAMPLES:: - sage: SAT(solver="LP") + sage: SAT(solver="LP") # optional - sage.numerical.mip an ILP-based SAT Solver TESTS:: @@ -351,12 +351,12 @@ def SAT(solver=None, *args, **kwds): Forcing CryptoMiniSat:: - sage: SAT(solver="cryptominisat") # optional - pycryptosat + sage: SAT(solver="cryptominisat") # optional - pycryptosat CryptoMiniSat solver: 0 variables, 0 clauses. Forcing PicoSat:: - sage: SAT(solver="picosat") # optional - pycosat + sage: SAT(solver="picosat") # optional - pycosat PicoSAT solver: 0 variables, 0 clauses. Forcing Glucose:: From a37b456669e71fbaf06e357fae373c87c576bdc1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Jun 2023 14:37:23 -0700 Subject: [PATCH 185/538] More # optional --- src/sage/sat/boolean_polynomials.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index 2c5075d6251..6d84171b95d 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -1,3 +1,4 @@ +# sage.doctest: optional - sage.rings.polynomial.pbori """ SAT Functions for Boolean Polynomials @@ -71,8 +72,8 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): We construct a very small-scale AES system of equations:: - sage: sr = mq.SR(1,1,1,4,gf2=True,polybori=True) # optional - sage.modules - sage: while True: # workaround (see :trac:`31891`) # optional - sage.modules + sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) # optional - sage.modules sage.rings.finite_rings + sage: while True: # workaround (see :trac:`31891`) # optional - sage.modules sage.rings.finite_rings ....: try: ....: F, s = sr.polynomial_system() ....: break @@ -82,14 +83,14 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): and pass it to a SAT solver:: sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: s = solve_sat(F) # optional - pycryptosat sage.modules - sage: F.subs(s[0]) # optional - pycryptosat sage.modules + sage: s = solve_sat(F) # optional - pycryptosat sage.modules sage.rings.finite_rings + sage: F.subs(s[0]) # optional - pycryptosat sage.modules sage.rings.finite_rings Polynomial Sequence with 36 Polynomials in 0 Variables This time we pass a few options through to the converter and the solver:: - sage: s = solve_sat(F, c_max_vars_sparse=4, c_cutting_number=8) # optional - pycryptosat sage.modules - sage: F.subs(s[0]) # optional - pycryptosat sage.modules + sage: s = solve_sat(F, c_max_vars_sparse=4, c_cutting_number=8) # optional - pycryptosat sage.modules sage.rings.finite_rings + sage: F.subs(s[0]) # optional - pycryptosat sage.modules sage.rings.finite_rings Polynomial Sequence with 36 Polynomials in 0 Variables We construct a very simple system with three solutions @@ -126,7 +127,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): Now we are only interested in the solutions of the variables a and b:: - sage: solve_sat(F,n=infinity,target_variables=[a,b]) # optional - pycryptosat sage.modules + sage: solve_sat(F, n=infinity, target_variables=[a,b]) # optional - pycryptosat sage.modules [{b: 0, a: 0}, {b: 1, a: 1}] Here, we generate and solve the cubic equations of the AES SBox (see :trac:`26676`):: @@ -136,7 +137,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): sage: sr = sage.crypto.mq.SR(1, 4, 4, 8, # long time, optional - pycryptosat sage.modules ....: allow_zero_inversions=True) sage: sb = sr.sbox() # long time, optional - pycryptosat sage.modules - sage: eqs = sb.polynomials(degree = 3) # long time, optional - pycryptosat sage.modules + sage: eqs = sb.polynomials(degree=3) # long time, optional - pycryptosat sage.modules sage: eqs = PolynomialSequence(eqs) # long time, optional - pycryptosat sage.modules sage: variables = map(str, eqs.variables()) # long time, optional - pycryptosat sage.modules sage: variables = ",".join(variables) # long time, optional - pycryptosat sage.modules @@ -343,11 +344,11 @@ def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=Fa We construct a simple system and solve it:: - sage: set_random_seed(2300) # optional - pycryptosat - sage: sr = mq.SR(1,2,2,4,gf2=True,polybori=True) # optional - pycryptosat - sage: F,s = sr.polynomial_system() # optional - pycryptosat - sage: H = learn_sat(F) # optional - pycryptosat - sage: H[-1] # optional - pycryptosat + sage: set_random_seed(2300) + sage: sr = mq.SR(1, 2, 2, 4, gf2=True, polybori=True) # optional - pycryptosat sage.modules sage.rings.finite_rings + sage: F,s = sr.polynomial_system() # optional - pycryptosat sage.modules sage.rings.finite_rings + sage: H = learn_sat(F) # optional - pycryptosat sage.modules sage.rings.finite_rings + sage: H[-1] # optional - pycryptosat sage.modules sage.rings.finite_rings k033 + 1 """ try: From a12c38c19c82b032d752279e8b5e1076bd58fd41 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 11 Jun 2023 23:47:37 -0700 Subject: [PATCH 186/538] More # optional --- src/sage/sat/solvers/dimacs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/sat/solvers/dimacs.py b/src/sage/sat/solvers/dimacs.py index cfe3c7cd4ed..51cffd27402 100644 --- a/src/sage/sat/solvers/dimacs.py +++ b/src/sage/sat/solvers/dimacs.py @@ -490,14 +490,14 @@ def __call__(self, assumptions=None): TESTS:: sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: sr = mq.SR(1,1,1,4,gf2=True,polybori=True) - sage: while True: # workaround (see :trac:`31891`) + sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) # optional - sage.rings.finite_rings sage.rings.polynomial.pbori + sage: while True: # workaround (see :trac:`31891`) # optional - sage.rings.finite_rings sage.rings.polynomial.pbori ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: solve_sat(F, solver=sage.sat.solvers.RSat) # optional - RSat + sage: solve_sat(F, solver=sage.sat.solvers.RSat) # optional - RSat # optional - sage.rings.finite_rings sage.rings.polynomial.pbori """ if assumptions is not None: From e43e09ad70c8d960f6686fc8095e72578a1d631a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 6 Aug 2023 20:45:14 -0700 Subject: [PATCH 187/538] src/sage/sat: Update file-level doctest tag --- src/sage/sat/boolean_polynomials.py | 2 +- src/sage/sat/converters/polybori.py | 2 +- src/sage/sat/solvers/sat_lp.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index 6d84171b95d..c47cae945d6 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.polynomial.pbori +# sage.doctest: needs sage.rings.polynomial.pbori """ SAT Functions for Boolean Polynomials diff --git a/src/sage/sat/converters/polybori.py b/src/sage/sat/converters/polybori.py index cbf46d4faa2..49da6f1819c 100644 --- a/src/sage/sat/converters/polybori.py +++ b/src/sage/sat/converters/polybori.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.rings.polynomial.pbori +# sage.doctest: needs sage.rings.polynomial.pbori """ An ANF to CNF Converter using a Dense/Sparse Strategy diff --git a/src/sage/sat/solvers/sat_lp.py b/src/sage/sat/solvers/sat_lp.py index dc1ff30d4b7..9b65b1d241d 100644 --- a/src/sage/sat/solvers/sat_lp.py +++ b/src/sage/sat/solvers/sat_lp.py @@ -1,4 +1,4 @@ -# sage.doctest: optional - sage.numerical.mip +# sage.doctest: needs sage.numerical.mip r""" Solve SAT problems Integer Linear Programming From 417429f000f0c237b4216c86635b2933f5927b59 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 7 Aug 2023 22:44:22 -0700 Subject: [PATCH 188/538] src/sage/sat: sage -fixdoctests --only-tags --- src/sage/sat/boolean_polynomials.py | 68 ++++++++++++++------------- src/sage/sat/solvers/cryptominisat.py | 33 +++++++------ src/sage/sat/solvers/dimacs.py | 6 +-- src/sage/sat/solvers/picosat.py | 24 +++++----- src/sage/sat/solvers/satsolver.pyx | 8 ++-- 5 files changed, 73 insertions(+), 66 deletions(-) diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index c47cae945d6..dc5fdb69ff0 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -72,8 +72,8 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): We construct a very small-scale AES system of equations:: - sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) # optional - sage.modules sage.rings.finite_rings - sage: while True: # workaround (see :trac:`31891`) # optional - sage.modules sage.rings.finite_rings + sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) # needs sage.modules sage.rings.finite_rings + sage: while True: # workaround (see :trac:`31891`) # needs sage.modules sage.rings.finite_rings ....: try: ....: F, s = sr.polynomial_system() ....: break @@ -83,68 +83,70 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): and pass it to a SAT solver:: sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: s = solve_sat(F) # optional - pycryptosat sage.modules sage.rings.finite_rings - sage: F.subs(s[0]) # optional - pycryptosat sage.modules sage.rings.finite_rings + sage: s = solve_sat(F) # optional - pycryptosat # needs sage.modules sage.rings.finite_rings + sage: F.subs(s[0]) # optional - pycryptosat # needs sage.modules sage.rings.finite_rings Polynomial Sequence with 36 Polynomials in 0 Variables This time we pass a few options through to the converter and the solver:: - sage: s = solve_sat(F, c_max_vars_sparse=4, c_cutting_number=8) # optional - pycryptosat sage.modules sage.rings.finite_rings - sage: F.subs(s[0]) # optional - pycryptosat sage.modules sage.rings.finite_rings + sage: s = solve_sat(F, c_max_vars_sparse=4, c_cutting_number=8) # optional - pycryptosat, needs sage.modules sage.rings.finite_rings + sage: F.subs(s[0]) # optional - pycryptosat # needs sage.modules sage.rings.finite_rings Polynomial Sequence with 36 Polynomials in 0 Variables We construct a very simple system with three solutions and ask for a specific number of solutions:: - sage: B. = BooleanPolynomialRing() # optional - pycryptosat sage.modules - sage: f = a*b # optional - pycryptosat sage.modules - sage: l = solve_sat([f],n=1) # optional - pycryptosat sage.modules - sage: len(l) == 1, f.subs(l[0]) # optional - pycryptosat sage.modules + sage: # optional - pycryptosat, needs sage.modules + sage: B. = BooleanPolynomialRing() + sage: f = a*b + sage: l = solve_sat([f],n=1) + sage: len(l) == 1, f.subs(l[0]) (True, 0) - sage: l = solve_sat([a*b],n=2) # optional - pycryptosat sage.modules - sage: len(l) == 2, f.subs(l[0]), f.subs(l[1]) # optional - pycryptosat sage.modules + sage: l = solve_sat([a*b],n=2) # optional - pycryptosat # needs sage.modules + sage: len(l) == 2, f.subs(l[0]), f.subs(l[1]) # optional - pycryptosat # needs sage.modules (True, 0, 0) - sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=3)) # optional - pycryptosat sage.modules + sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=3)) # optional - pycryptosat, needs sage.modules [(0, 0), (0, 1), (1, 0)] - sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=4)) # optional - pycryptosat sage.modules + sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=4)) # optional - pycryptosat, needs sage.modules [(0, 0), (0, 1), (1, 0)] - sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=infinity)) # optional - pycryptosat sage.modules + sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=infinity)) # optional - pycryptosat, needs sage.modules [(0, 0), (0, 1), (1, 0)] In the next example we see how the ``target_variables`` parameter works:: sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: R. = BooleanPolynomialRing() # optional - pycryptosat sage.modules - sage: F = [a + b, a + c + d] # optional - pycryptosat sage.modules + sage: R. = BooleanPolynomialRing() # optional - pycryptosat # needs sage.modules + sage: F = [a + b, a + c + d] # optional - pycryptosat # needs sage.modules First the normal use case:: - sage: sorted((D[a], D[b], D[c], D[d]) # optional - pycryptosat sage.modules + sage: sorted((D[a], D[b], D[c], D[d]) # optional - pycryptosat # needs sage.modules ....: for D in solve_sat(F, n=infinity)) [(0, 0, 0, 0), (0, 0, 1, 1), (1, 1, 0, 1), (1, 1, 1, 0)] Now we are only interested in the solutions of the variables a and b:: - sage: solve_sat(F, n=infinity, target_variables=[a,b]) # optional - pycryptosat sage.modules + sage: solve_sat(F, n=infinity, target_variables=[a,b]) # optional - pycryptosat, needs sage.modules [{b: 0, a: 0}, {b: 1, a: 1}] Here, we generate and solve the cubic equations of the AES SBox (see :trac:`26676`):: + sage: # long time, optional - pycryptosat, needs sage.modules sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: sr = sage.crypto.mq.SR(1, 4, 4, 8, # long time, optional - pycryptosat sage.modules + sage: sr = sage.crypto.mq.SR(1, 4, 4, 8, ....: allow_zero_inversions=True) - sage: sb = sr.sbox() # long time, optional - pycryptosat sage.modules - sage: eqs = sb.polynomials(degree=3) # long time, optional - pycryptosat sage.modules - sage: eqs = PolynomialSequence(eqs) # long time, optional - pycryptosat sage.modules - sage: variables = map(str, eqs.variables()) # long time, optional - pycryptosat sage.modules - sage: variables = ",".join(variables) # long time, optional - pycryptosat sage.modules - sage: R = BooleanPolynomialRing(16, variables) # long time, optional - pycryptosat sage.modules - sage: eqs = [R(eq) for eq in eqs] # long time, optional - pycryptosat sage.modules - sage: sls_aes = solve_sat(eqs, n = infinity) # long time, optional - pycryptosat sage.modules - sage: len(sls_aes) # long time, optional - pycryptosat sage.modules + sage: sb = sr.sbox() + sage: eqs = sb.polynomials(degree=3) + sage: eqs = PolynomialSequence(eqs) + sage: variables = map(str, eqs.variables()) + sage: variables = ",".join(variables) + sage: R = BooleanPolynomialRing(16, variables) + sage: eqs = [R(eq) for eq in eqs] + sage: sls_aes = solve_sat(eqs, n = infinity) + sage: len(sls_aes) 256 TESTS: @@ -345,10 +347,10 @@ def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=Fa We construct a simple system and solve it:: sage: set_random_seed(2300) - sage: sr = mq.SR(1, 2, 2, 4, gf2=True, polybori=True) # optional - pycryptosat sage.modules sage.rings.finite_rings - sage: F,s = sr.polynomial_system() # optional - pycryptosat sage.modules sage.rings.finite_rings - sage: H = learn_sat(F) # optional - pycryptosat sage.modules sage.rings.finite_rings - sage: H[-1] # optional - pycryptosat sage.modules sage.rings.finite_rings + sage: sr = mq.SR(1, 2, 2, 4, gf2=True, polybori=True) # optional - pycryptosat, needs sage.modules sage.rings.finite_rings + sage: F,s = sr.polynomial_system() # optional - pycryptosat # needs sage.modules sage.rings.finite_rings + sage: H = learn_sat(F) # optional - pycryptosat # needs sage.modules sage.rings.finite_rings + sage: H[-1] # optional - pycryptosat # needs sage.modules sage.rings.finite_rings k033 + 1 """ try: diff --git a/src/sage/sat/solvers/cryptominisat.py b/src/sage/sat/solvers/cryptominisat.py index d2a8ae9e5a6..82f1ffd9086 100644 --- a/src/sage/sat/solvers/cryptominisat.py +++ b/src/sage/sat/solvers/cryptominisat.py @@ -182,12 +182,13 @@ def __call__(self, assumptions=None): EXAMPLES:: + sage: # optional - pycryptosat sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat - sage: solver = CryptoMiniSat() # optional - pycryptosat - sage: solver.add_clause((1,2)) # optional - pycryptosat - sage: solver.add_clause((-1,2)) # optional - pycryptosat - sage: solver.add_clause((-1,-2)) # optional - pycryptosat - sage: solver() # optional - pycryptosat + sage: solver = CryptoMiniSat() + sage: solver.add_clause((1,2)) + sage: solver.add_clause((-1,2)) + sage: solver.add_clause((-1,-2)) + sage: solver() (None, False, True) sage: solver.add_clause((1,-2)) # optional - pycryptosat @@ -231,23 +232,25 @@ def clauses(self, filename=None): EXAMPLES:: + sage: # optional - pycryptosat sage: from sage.sat.solvers import CryptoMiniSat - sage: solver = CryptoMiniSat() # optional - pycryptosat - sage: solver.add_clause((1,2,3,4,5,6,7,8,-9)) # optional - pycryptosat - sage: solver.add_xor_clause((1,2,3,4,5,6,7,8,9), rhs=True) # optional - pycryptosat - sage: solver.clauses() # optional - pycryptosat + sage: solver = CryptoMiniSat() + sage: solver.add_clause((1,2,3,4,5,6,7,8,-9)) + sage: solver.add_xor_clause((1,2,3,4,5,6,7,8,9), rhs=True) + sage: solver.clauses() [((1, 2, 3, 4, 5, 6, 7, 8, -9), False, None), ((1, 2, 3, 4, 5, 6, 7, 8, 9), True, True)] DIMACS format output:: + sage: # optional - pycryptosat sage: from sage.sat.solvers import CryptoMiniSat - sage: solver = CryptoMiniSat() # optional - pycryptosat - sage: solver.add_clause((1, 2, 4)) # optional - pycryptosat - sage: solver.add_clause((1, 2, -4)) # optional - pycryptosat - sage: fn = tmp_filename() # optional - pycryptosat - sage: solver.clauses(fn) # optional - pycryptosat - sage: print(open(fn).read()) # optional - pycryptosat + sage: solver = CryptoMiniSat() + sage: solver.add_clause((1, 2, 4)) + sage: solver.add_clause((1, 2, -4)) + sage: fn = tmp_filename() + sage: solver.clauses(fn) + sage: print(open(fn).read()) p cnf 4 2 1 2 4 0 1 2 -4 0 diff --git a/src/sage/sat/solvers/dimacs.py b/src/sage/sat/solvers/dimacs.py index 51cffd27402..51e81a925a1 100644 --- a/src/sage/sat/solvers/dimacs.py +++ b/src/sage/sat/solvers/dimacs.py @@ -490,14 +490,14 @@ def __call__(self, assumptions=None): TESTS:: sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) # optional - sage.rings.finite_rings sage.rings.polynomial.pbori - sage: while True: # workaround (see :trac:`31891`) # optional - sage.rings.finite_rings sage.rings.polynomial.pbori + sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) # needs sage.rings.finite_rings sage.rings.polynomial.pbori + sage: while True: # workaround (see :trac:`31891`) # needs sage.rings.finite_rings sage.rings.polynomial.pbori ....: try: ....: F, s = sr.polynomial_system() ....: break ....: except ZeroDivisionError: ....: pass - sage: solve_sat(F, solver=sage.sat.solvers.RSat) # optional - RSat # optional - sage.rings.finite_rings sage.rings.polynomial.pbori + sage: solve_sat(F, solver=sage.sat.solvers.RSat) # optional - rsat, needs sage.rings.finite_rings sage.rings.polynomial.pbori """ if assumptions is not None: diff --git a/src/sage/sat/solvers/picosat.py b/src/sage/sat/solvers/picosat.py index a1a80e71794..a88f69da883 100644 --- a/src/sage/sat/solvers/picosat.py +++ b/src/sage/sat/solvers/picosat.py @@ -147,12 +147,13 @@ def __call__(self, assumptions=None): EXAMPLES:: + sage: # optional - pycosat sage: from sage.sat.solvers.picosat import PicoSAT - sage: solver = PicoSAT() # optional - pycosat - sage: solver.add_clause((1,2)) # optional - pycosat - sage: solver.add_clause((-1,2)) # optional - pycosat - sage: solver.add_clause((-1,-2)) # optional - pycosat - sage: solver() # optional - pycosat + sage: solver = PicoSAT() + sage: solver.add_clause((1,2)) + sage: solver.add_clause((-1,2)) + sage: solver.add_clause((-1,-2)) + sage: solver() (None, False, True) sage: solver.add_clause((1,-2)) # optional - pycosat @@ -207,13 +208,14 @@ def clauses(self, filename=None): DIMACS format output:: + sage: # optional - pycosat sage: from sage.sat.solvers.picosat import PicoSAT - sage: solver = PicoSAT() # optional - pycosat - sage: solver.add_clause((1, 2, 4)) # optional - pycosat - sage: solver.add_clause((1, 2, -4)) # optional - pycosat - sage: fn = tmp_filename() # optional - pycosat - sage: solver.clauses(fn) # optional - pycosat - sage: print(open(fn).read()) # optional - pycosat + sage: solver = PicoSAT() + sage: solver.add_clause((1, 2, 4)) + sage: solver.add_clause((1, 2, -4)) + sage: fn = tmp_filename() + sage: solver.clauses(fn) + sage: print(open(fn).read()) p cnf 4 2 1 2 4 0 1 2 -4 0 diff --git a/src/sage/sat/solvers/satsolver.pyx b/src/sage/sat/solvers/satsolver.pyx index 0ed7041c608..83735c86989 100644 --- a/src/sage/sat/solvers/satsolver.pyx +++ b/src/sage/sat/solvers/satsolver.pyx @@ -139,9 +139,9 @@ cdef class SatSolver: sage: from io import StringIO sage: file_object = StringIO("c A sample .cnf file with xor clauses.\np cnf 3 3\n1 2 0\n3 0\nx1 2 3 0") - sage: from sage.sat.solvers.sat_lp import SatLP # optional - sage.numerical.mip - sage: solver = SatLP() # optional - sage.numerical.mip - sage: solver.read(file_object) # optional - sage.numerical.mip + sage: from sage.sat.solvers.sat_lp import SatLP # needs sage.numerical.mip + sage: solver = SatLP() # needs sage.numerical.mip + sage: solver.read(file_object) # needs sage.numerical.mip Traceback (most recent call last): ... NotImplementedError: the solver "an ILP-based SAT Solver" does not support xor clauses @@ -339,7 +339,7 @@ def SAT(solver=None, *args, **kwds): EXAMPLES:: - sage: SAT(solver="LP") # optional - sage.numerical.mip + sage: SAT(solver="LP") # needs sage.numerical.mip an ILP-based SAT Solver TESTS:: From 7dabb0a656dcbf6d670be0bd0faebbc36240b9ad Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Nov 2023 15:16:19 -0800 Subject: [PATCH 189/538] build/pkgs/prompt_toolkit/distros/conda.txt: Use version range as in install-requires.txt --- build/pkgs/prompt_toolkit/distros/conda.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/prompt_toolkit/distros/conda.txt b/build/pkgs/prompt_toolkit/distros/conda.txt index 29392dfc5b3..bfb1ed6a874 100644 --- a/build/pkgs/prompt_toolkit/distros/conda.txt +++ b/build/pkgs/prompt_toolkit/distros/conda.txt @@ -1 +1 @@ -prompt_toolkit +prompt_toolkit>=3.0.5,<3.0.25 From 8e26e8ecd912dff2ec47775d8cd24c4b5f82c0cb Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Nov 2023 15:33:54 -0800 Subject: [PATCH 190/538] .github/workflows/ci-linux.yml: Fine-tune max-parallel for constructive clogging --- .github/workflows/ci-linux.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 7fd2064a108..b991fe11880 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -85,8 +85,9 @@ jobs: tox_packages_factors: >- ["standard"] docker_push_repository: ghcr.io/${{ github.repository }}/ - # Reduce from 30 to 25 because it runs in parallel with 'standard-sitepackages' below - max_parallel: 25 + # Reduce from 30 to 20 because it runs in parallel with 'standard-sitepackages' + # and 'minimal-pre' below + max_parallel: 20 standard-sitepackages: if: ${{ success() || failure() }} @@ -135,7 +136,7 @@ jobs: "opensuse-tumbleweed", "debian-bullseye-i386"] docker_push_repository: ghcr.io/${{ github.repository }}/ - max_parallel: 10 + max_parallel: 8 minimal-pre: if: ${{ success() || failure() }} @@ -148,9 +149,9 @@ jobs: tox_packages_factors: >- ["minimal"] docker_push_repository: ghcr.io/${{ github.repository }}/ - # Reduced from 30 because it may run in parallel with 'standard-sitepackages' above. + # Reduced from 30 because it may run in parallel with 'standard' and 'standard-sitepackages' above. # Calibrated for clogging the job pipeline until the "default" job has finished. - max_parallel: 20 + max_parallel: 24 minimal: if: ${{ success() || failure() }} @@ -169,6 +170,7 @@ jobs: tox_packages_factors: >- ["minimal"] docker_push_repository: ghcr.io/${{ github.repository }}/ + max_parallel: 24 maximal-pre: if: ${{ success() || failure() }} From c15418d962c6f984a4ddaebb146639125385f366 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 6 Nov 2023 10:39:51 +0900 Subject: [PATCH 191/538] Continue on error of building live doc --- .github/workflows/doc-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index e079fa04beb..bd789779245 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -201,6 +201,7 @@ jobs: - name: Build live doc id: buildlivedoc if: (success() || failure()) && steps.copy.outcome == 'success' && github.repository == 'sagemath/sage' && github.ref == 'refs/heads/develop' + continue-on-error: true run: | set -ex export SAGE_USE_CDNS=yes From f56cd83fe88763bf60e1d37ee40b4510bbb61ec3 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Nov 2023 19:19:34 -0800 Subject: [PATCH 192/538] build/pkgs/pyzmq: Update to 25.1.1 --- build/pkgs/pyzmq/checksums.ini | 6 +++--- build/pkgs/pyzmq/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/pyzmq/checksums.ini b/build/pkgs/pyzmq/checksums.ini index d9abd25d464..091981fb051 100644 --- a/build/pkgs/pyzmq/checksums.ini +++ b/build/pkgs/pyzmq/checksums.ini @@ -1,5 +1,5 @@ tarball=pyzmq-VERSION.tar.gz -sha1=1a2e7220d7d1b6167c14ae2cc001dfc5d9a28dde -md5=f10b7c3dee2c03557e2c5d00b73dfc7f -cksum=1163982926 +sha1=f750e59a3d5fcca64d0a1a6723c1bc72173e976f +md5=993a646d3f1c6201a8c93bcb2d2f867e +cksum=2057198190 upstream_url=https://pypi.io/packages/source/p/pyzmq/pyzmq-VERSION.tar.gz diff --git a/build/pkgs/pyzmq/package-version.txt b/build/pkgs/pyzmq/package-version.txt index 1b3e74f84e7..139ab877a87 100644 --- a/build/pkgs/pyzmq/package-version.txt +++ b/build/pkgs/pyzmq/package-version.txt @@ -1 +1 @@ -24.0.1 +25.1.1 From c1faab9433204079f132a7d158e141bc88672974 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 6 Nov 2023 13:11:42 +0900 Subject: [PATCH 193/538] Remove code distorting worktree --- .github/workflows/doc-build.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index bd789779245..10c9525d8a8 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -162,7 +162,7 @@ jobs: EOF echo '' >> ./docs/CHANGES.html echo '' >> ./docs/CHANGES.html - (cd /sage/local/share/doc/sage/html && git diff HEAD^ -- *.html; rm -rf .git) > ./docs/diff.txt + (cd /sage/local/share/doc/sage/html && git diff HEAD^ -- *.html) > ./docs/diff.txt /sage/sage -python - << EOF import re, html with open('./docs/diff.txt', 'r') as f: @@ -182,7 +182,6 @@ jobs: echo '' >> ./docs/CHANGES.html echo '' >>./docs/CHANGES.html rm ./docs/diff.txt ./docs/diff.html - (cd /sage/local/share/doc/sage/html && git reset --hard HEAD) # For some reason the deploy step below cannot find /sage/... # So copy everything from there to local folder # We also need to replace the symlinks because netlify is not following them From e18ac9f76c565b07336dc5903700098b1f5cedb4 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Nov 2023 20:21:38 -0800 Subject: [PATCH 194/538] build/pkgs/zeromq: Update to 4.3.5 --- build/pkgs/zeromq/checksums.ini | 6 +++--- build/pkgs/zeromq/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/zeromq/checksums.ini b/build/pkgs/zeromq/checksums.ini index dc802612ddd..bc7f6b0c8b1 100644 --- a/build/pkgs/zeromq/checksums.ini +++ b/build/pkgs/zeromq/checksums.ini @@ -1,5 +1,5 @@ tarball=zeromq-VERSION.tar.gz -sha1=47277a64749049123d1401600e8cfbab10a3ae28 -md5=c897d4005a3f0b8276b00b7921412379 -cksum=1500782345 +sha1=bdbf686c8a40ba638e21cf74e34dbb425e108500 +md5=ae933b1e98411fd7cb8309f9502d2737 +cksum=1351453048 upstream_url=https://github.com/zeromq/libzmq/releases/download/vVERSION/zeromq-VERSION.tar.gz diff --git a/build/pkgs/zeromq/package-version.txt b/build/pkgs/zeromq/package-version.txt index eda862a98c1..e198586e42b 100644 --- a/build/pkgs/zeromq/package-version.txt +++ b/build/pkgs/zeromq/package-version.txt @@ -1 +1 @@ -4.3.4 +4.3.5 From ebd4db3d6ad33e08b4e20744047633b239e49432 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Nov 2023 20:21:59 -0800 Subject: [PATCH 195/538] build/pkgs/zeromq/patches/438d5d88392baffa6c2c5e0737d9de19d6686f0d.patch: Remove --- ...5d88392baffa6c2c5e0737d9de19d6686f0d.patch | 58 ------------------- 1 file changed, 58 deletions(-) delete mode 100644 build/pkgs/zeromq/patches/438d5d88392baffa6c2c5e0737d9de19d6686f0d.patch diff --git a/build/pkgs/zeromq/patches/438d5d88392baffa6c2c5e0737d9de19d6686f0d.patch b/build/pkgs/zeromq/patches/438d5d88392baffa6c2c5e0737d9de19d6686f0d.patch deleted file mode 100644 index 75bfbd8744b..00000000000 --- a/build/pkgs/zeromq/patches/438d5d88392baffa6c2c5e0737d9de19d6686f0d.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 438d5d88392baffa6c2c5e0737d9de19d6686f0d Mon Sep 17 00:00:00 2001 -From: Sergei Trofimovich -Date: Tue, 20 Dec 2022 21:45:16 +0000 -Subject: [PATCH] src/secure_allocator.hpp: define missing 'rebind' type - -`gcc-13` added an assert to standard headers to make sure custom -allocators have intended implementation of rebind type instead -of inherited rebind. gcc change: - https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=64c986b49558a7 - -Without the fix build fails on this week's `gcc-13` as: - - [ 92%] Building CXX object tests/CMakeFiles/test_security_curve.dir/test_security_curve.cpp.o - In file included from /<>/gcc-13.0.0/include/c++/13.0.0/ext/alloc_traits.h:34, - from /<>/gcc-13.0.0/include/c++/13.0.0/bits/stl_uninitialized.h:64, - from /<>/gcc-13.0.0/include/c++/13.0.0/memory:69, - from tests/../src/secure_allocator.hpp:42, - from tests/../src/curve_client_tools.hpp:49, - from tests/test_security_curve.cpp:53: - /<>/gcc-13.0.0/include/c++/13.0.0/bits/alloc_traits.h: In instantiation of 'struct std::__allocator_traits_base::__rebind, unsigned char, void>': - /<>/gcc-13.0.0/include/c++/13.0.0/bits/alloc_traits.h:94:11: required by substitution of 'template using std::__alloc_rebind = typename std::__allocator_traits_base::__rebind<_Alloc, _Up>::type [with _Alloc = zmq::secure_allocator_t; _Up = unsigned char]' - /<>/gcc-13.0.0/include/c++/13.0.0/bits/alloc_traits.h:228:8: required by substitution of 'template template using std::allocator_traits< >::rebind_alloc = std::__alloc_rebind<_Alloc, _Tp> [with _Tp = unsigned char; _Alloc = zmq::secure_allocator_t]' - /<>/gcc-13.0.0/include/c++/13.0.0/ext/alloc_traits.h:126:65: required from 'struct __gnu_cxx::__alloc_traits, unsigned char>::rebind' - /<>/gcc-13.0.0/include/c++/13.0.0/bits/stl_vector.h:88:21: required from 'struct std::_Vector_base >' - /<>/gcc-13.0.0/include/c++/13.0.0/bits/stl_vector.h:423:11: required from 'class std::vector >' - tests/../src/curve_client_tools.hpp:64:76: required from here - /<>/gcc-13.0.0/include/c++/13.0.0/bits/alloc_traits.h:70:31: error: static assertion failed: allocator_traits::rebind_alloc must be A - 70 | _Tp>::value, - | ^~~~~ - -The change adds trivial `rebind` definition with expected return type -and satisfies conversion requirements. ---- - src/secure_allocator.hpp | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/src/secure_allocator.hpp b/src/secure_allocator.hpp -index e0871dcc99..5e97368911 100644 ---- a/src/secure_allocator.hpp -+++ b/src/secure_allocator.hpp -@@ -99,6 +99,17 @@ bool operator!= (const secure_allocator_t &, const secure_allocator_t &) - #else - template struct secure_allocator_t : std::allocator - { -+ secure_allocator_t () ZMQ_DEFAULT; -+ -+ template -+ secure_allocator_t (const secure_allocator_t &) ZMQ_NOEXCEPT -+ { -+ } -+ -+ template struct rebind -+ { -+ typedef secure_allocator_t other; -+ }; - }; - #endif - } From c4d3fd7d6b8b9e8857ce3c372f4b403fceb7c8cf Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 6 Nov 2023 13:34:38 +0900 Subject: [PATCH 196/538] Adding continue-on-error may disrupt doc-publish --- .github/workflows/doc-build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 10c9525d8a8..7f9e07aafe2 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -200,7 +200,6 @@ jobs: - name: Build live doc id: buildlivedoc if: (success() || failure()) && steps.copy.outcome == 'success' && github.repository == 'sagemath/sage' && github.ref == 'refs/heads/develop' - continue-on-error: true run: | set -ex export SAGE_USE_CDNS=yes From 2a5293c9761a1e4eb55abeebe7f040cb99852b10 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Sun, 5 Nov 2023 21:38:48 -0800 Subject: [PATCH 197/538] build/pkgs/pyzmq: Patch out broken rpath and version detection --- ...001-setup.py-Remove-setting-of-rpath.patch | 25 +++++++++++++++++++ ...y-Patch-out-broken-version-detection.patch | 24 ++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 build/pkgs/pyzmq/patches/0001-setup.py-Remove-setting-of-rpath.patch create mode 100644 build/pkgs/pyzmq/patches/0002-setup.py-Patch-out-broken-version-detection.patch diff --git a/build/pkgs/pyzmq/patches/0001-setup.py-Remove-setting-of-rpath.patch b/build/pkgs/pyzmq/patches/0001-setup.py-Remove-setting-of-rpath.patch new file mode 100644 index 00000000000..9f0483d8442 --- /dev/null +++ b/build/pkgs/pyzmq/patches/0001-setup.py-Remove-setting-of-rpath.patch @@ -0,0 +1,25 @@ +From 29427869ce0a9f13e29c7f89873a1880c8be55a1 Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Sun, 5 Nov 2023 21:12:48 -0800 +Subject: [PATCH 1/2] setup.py: Remove setting of rpath + +--- + setup.py | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/setup.py b/setup.py +index d5c77a23..8a2a4943 100755 +--- a/setup.py ++++ b/setup.py +@@ -300,8 +300,6 @@ def settings_from_prefix(prefix=None): + settings['include_dirs'] += [pjoin(env, 'include')] + settings['library_dirs'] += [pjoin(env, 'lib')] + +- for path in settings['library_dirs']: +- _add_rpath(settings, os.path.abspath(path)) + info(settings) + + return settings +-- +2.42.0 + diff --git a/build/pkgs/pyzmq/patches/0002-setup.py-Patch-out-broken-version-detection.patch b/build/pkgs/pyzmq/patches/0002-setup.py-Patch-out-broken-version-detection.patch new file mode 100644 index 00000000000..95e62898233 --- /dev/null +++ b/build/pkgs/pyzmq/patches/0002-setup.py-Patch-out-broken-version-detection.patch @@ -0,0 +1,24 @@ +From b5bdcad66a28394f6e5be4ad7fd00835deec73f7 Mon Sep 17 00:00:00 2001 +From: Matthias Koeppe +Date: Sun, 5 Nov 2023 21:35:29 -0800 +Subject: [PATCH 2/2] setup.py: Patch out broken version detection + +--- + setup.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/setup.py b/setup.py +index 8a2a4943..19d31654 100755 +--- a/setup.py ++++ b/setup.py +@@ -463,6 +463,7 @@ class Configure(build_ext): + + def check_zmq_version(self): + """check the zmq version""" ++ return + cfg = self.config + # build test program + zmq_prefix = cfg['zmq_prefix'] +-- +2.42.0 + From 33664560681dc013be7190d5adfc498880ac8974 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 6 Nov 2023 15:13:02 +0900 Subject: [PATCH 198/538] Remove .git for sure --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 7f9e07aafe2..3660ff3a947 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -162,7 +162,7 @@ jobs: EOF echo '' >> ./docs/CHANGES.html echo '' >> ./docs/CHANGES.html - (cd /sage/local/share/doc/sage/html && git diff HEAD^ -- *.html) > ./docs/diff.txt + (cd /sage/local/share/doc/sage/html && git diff HEAD^ -- *.html; rm -rf .git) > ./docs/diff.txt /sage/sage -python - << EOF import re, html with open('./docs/diff.txt', 'r') as f: From 69d7cdaa2fc1e71915a30e914a072509005db9ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 10:02:16 +0100 Subject: [PATCH 199/538] ruff auto-fix for C4 in modular --- src/sage/modular/abvar/abvar.py | 8 ++++---- src/sage/modular/abvar/homspace.py | 2 +- src/sage/modular/arithgroup/arithgroup_perm.py | 4 ++-- src/sage/modular/arithgroup/congroup_gammaH.py | 10 +++++----- src/sage/modular/btquotients/btquotient.py | 2 +- src/sage/modular/dirichlet.py | 2 +- src/sage/modular/etaproducts.py | 2 +- src/sage/modular/hypergeometric_motive.py | 2 +- src/sage/modular/local_comp/smoothchar.py | 8 ++++---- .../modular/modform_hecketriangle/abstract_space.py | 4 ++-- .../modular/modform_hecketriangle/analytic_type.py | 4 ++-- src/sage/modular/modform_hecketriangle/constructor.py | 4 ++-- src/sage/modular/modform_hecketriangle/element.py | 2 +- .../modform_hecketriangle/hecke_triangle_groups.py | 2 +- src/sage/modular/modform_hecketriangle/space.py | 4 ++-- src/sage/modular/modform_hecketriangle/subspace.py | 2 +- src/sage/modular/modsym/ambient.py | 2 +- src/sage/modular/modsym/boundary.py | 2 +- src/sage/modular/modsym/ghlist.py | 2 +- src/sage/modular/modsym/relation_matrix.py | 4 ++-- src/sage/modular/multiple_zeta.py | 6 +++--- src/sage/modular/multiple_zeta_F_algebra.py | 2 +- 22 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 4f23ab768fd..f47e1fc7448 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -2060,8 +2060,8 @@ def newform_level(self, none_if_not_known=False): if none_if_not_known: return None level = LCM([f.level() for f in self.newform_decomposition('a')]) - groups = sorted(set([f.group() for f in - self.newform_decomposition('a')])) + groups = sorted({f.group() for f in + self.newform_decomposition('a')}) if len(groups) == 1: groups = groups[0] self.__newform_level = level, groups @@ -3870,7 +3870,7 @@ def _factors_with_same_label(self, other): if not isinstance(other, ModularAbelianVariety_abstract): raise TypeError("other must be an abelian variety") D = self.decomposition() - C = set([A.newform_label() for A in other.decomposition()]) + C = {A.newform_label() for A in other.decomposition()} Z = [] for X in D: lbl = X.newform_label() @@ -4899,7 +4899,7 @@ def tamagawa_number_bounds(self, p): else: raise NotImplementedError("Atkin-Lehner at p must act as a scalar") else: - mul_primes = sorted(set([p] + [q for q in prime_range(2, 2 * self.dimension() + 2)])) + mul_primes = sorted(set([p] + list(prime_range(2, 2 * self.dimension() + 2)))) div = Integer(div) mul = Integer(mul) mul_primes = tuple(mul_primes) diff --git a/src/sage/modular/abvar/homspace.py b/src/sage/modular/abvar/homspace.py index 964df397a93..ab1544d2698 100644 --- a/src/sage/modular/abvar/homspace.py +++ b/src/sage/modular/abvar/homspace.py @@ -570,7 +570,7 @@ def calculate_generators(self): return if (self.domain() == self.codomain()) and (self.domain().dimension() == 1): - self._gens = tuple([ identity_matrix(ZZ,2) ]) + self._gens = ( identity_matrix(ZZ,2), ) return phi = self.domain()._isogeny_to_product_of_powers() diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index eb0e645559a..8204995e1d1 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -1798,7 +1798,7 @@ def cusp_widths(self,exp=False): """ inv = self.S2()**2 L = self.L() - cusps = set(c[0] for c in L.cycle_tuples(singletons=True)) + cusps = {c[0] for c in L.cycle_tuples(singletons=True)} if exp: widths = {} else: @@ -2603,7 +2603,7 @@ def odd_subgroups(self): s3 = PermutationConstructor([x + tuple(y + n for y in x) for x in s3cycs]) H = ArithmeticSubgroup_Permutation(S2=s2,S3=s3) - bucket = set([H]) + bucket = {H} res = [H] # We use a set *and* a list since checking whether an element is in a # set is very fast, but on the other hand we want the order the results diff --git a/src/sage/modular/arithgroup/congroup_gammaH.py b/src/sage/modular/arithgroup/congroup_gammaH.py index c9e53fdf3a8..60df7b2add9 100644 --- a/src/sage/modular/arithgroup/congroup_gammaH.py +++ b/src/sage/modular/arithgroup/congroup_gammaH.py @@ -146,7 +146,7 @@ def _normalize_H(H, level): for h in H: if gcd(h, level) > 1: raise ArithmeticError('The generators %s must be units modulo %s' % (H, level)) - H = set(u for u in H if u > 1) + H = {u for u in H if u > 1} final_H = set() for h in H: inv_h = h.inverse_mod(level) @@ -1140,7 +1140,7 @@ def ncusps(self): c = ZZ(0) for d in (d for d in N.divisors() if d**2 <= N): Nd = lcm(d, N // d) - Hd = set([x % Nd for x in H]) + Hd = {x % Nd for x in H} lenHd = len(Hd) if Nd - 1 not in Hd: lenHd *= 2 @@ -1182,7 +1182,7 @@ def nregcusps(self): c = ZZ(0) for d in (d for d in divisors(N) if d**2 <= N): Nd = lcm(d, N // d) - Hd = set([x % Nd for x in H]) + Hd = {x % Nd for x in H} if Nd - 1 not in Hd: summand = euler_phi(d) * euler_phi(N // d) // (2 * len(Hd)) if d**2 == N: @@ -1395,7 +1395,7 @@ def _list_subgroup(N, gens): sage: sage.modular.arithgroup.congroup_gammaH._list_subgroup(11, [3]) [1, 3, 4, 5, 9] """ - H = set([1]) + H = {1} N = int(N) for g in gens: if gcd(g, N) != 1: @@ -1405,7 +1405,7 @@ def _list_subgroup(N, gens): while not (gk in H): gk = (gk * g) % N sbgrp.append(gk) - H = set([(x * h) % N for x in sbgrp for h in H]) + H = {(x * h) % N for x in sbgrp for h in H} return sorted(H) diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 3c7bceb0aa3..acb47da55e7 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -3710,7 +3710,7 @@ def _compute_quotient(self, check=True): 'from expected.') self._nontorsion_generators = nontorsion_generators - self._boundary = dict([(vv.rep, vv) for vv in vertex_list]) + self._boundary = {vv.rep: vv for vv in vertex_list} self._edge_list = edge_list self._vertex_list = vertex_list self._num_edges = num_edges diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index e752cc36b59..568e7c678f0 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -1282,7 +1282,7 @@ def galois_orbit(self, sort=True): P = self.parent() z = self.element() o = int(z.additive_order()) - Auts = set([m % o for m in P._automorphisms()]) + Auts = {m % o for m in P._automorphisms()} v = [P.element_class(P, m * z, check=False) for m in Auts] if sort: v.sort() diff --git a/src/sage/modular/etaproducts.py b/src/sage/modular/etaproducts.py index b17a99068a8..700b369b5df 100644 --- a/src/sage/modular/etaproducts.py +++ b/src/sage/modular/etaproducts.py @@ -558,7 +558,7 @@ def basis(self, reduce=True): nf = (i < S.ncols() and S[i, i]) or 0 # ? good_vects.append((vect * 24 / gcd(nf, 24)).list()) for v in good_vects: - v.append(-sum([r for r in v])) + v.append(-sum(list(v))) dicts = [] for v in good_vects: dicts.append({}) diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 0db87ac9f66..b26e5c39be5 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -661,7 +661,7 @@ def wild_primes(self): [2, 3, 5] """ gamma = self.gamma_array() - return sorted(set([p for n in gamma.keys() for (p, _) in n.factor()])) + return sorted({p for n in gamma.keys() for (p, _) in n.factor()}) def zigzag(self, x, flip_beta=False): r""" diff --git a/src/sage/modular/local_comp/smoothchar.py b/src/sage/modular/local_comp/smoothchar.py index 62d80dc560a..1e4c25fe096 100644 --- a/src/sage/modular/local_comp/smoothchar.py +++ b/src/sage/modular/local_comp/smoothchar.py @@ -1103,7 +1103,7 @@ def quadratic_chars(self): q = 1 ram = [self.from_dirichlet(chi) for chi in DirichletGroup(self.prime() ** q, QQ) if not chi.is_trivial()] nr = self.character(0, [-1]) - return sorted([nr] + [f for f in ram] + [f*nr for f in ram]) + return sorted([nr] + list(ram) + [f*nr for f in ram]) class SmoothCharacterGroupQuadratic(SmoothCharacterGroupGeneric): r""" @@ -1793,12 +1793,12 @@ def exponents(self, c): c = ZZ(c) p = self.prime() if c == 0: - return tuple([0]) + return (0,) elif c == 1: - return tuple([p - 1, 0]) + return (p - 1, 0) elif p > 3 or self._unif_sqr == 3 or c <= 3: d = (c + 1) // 2 - return tuple([p**(d - 1) * (p - 1), p**(c // 2), 0]) + return (p**(d - 1) * (p - 1), p**(c // 2), 0) else: # awkward case, see above return self.ideal(c).idealstar(2).gens_orders() + (0,) diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index e0c4506122d..d1c52cc3b8f 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -761,7 +761,7 @@ def aut_factor(self, gamma, t): elif (gamma.is_reflection()): return self._ep * (t/QQbar(I))**self._weight else: - L = [v for v in gamma.word_S_T()[0]] + L = list(gamma.word_S_T()[0]) aut_f = ZZ(1) while (len(L) > 0): M = L.pop(-1) @@ -1857,7 +1857,7 @@ def _quasi_form_matrix(self, min_exp=0, order_1=ZZ(0), incr_prec_by=0): return A B = A - A = A.delete_rows([r for r in range(column_size + (row_size-column_size)//2 - 1, row_size)]) + A = A.delete_rows(list(range(column_size + (row_size-column_size)//2 - 1, row_size))) # Next we simply delete row by row. Note that A is still modified here... while (B.rank() == column_size): diff --git a/src/sage/modular/modform_hecketriangle/analytic_type.py b/src/sage/modular/modform_hecketriangle/analytic_type.py index bdbc34a778a..e5fc53abb25 100644 --- a/src/sage/modular/modform_hecketriangle/analytic_type.py +++ b/src/sage/modular/modform_hecketriangle/analytic_type.py @@ -445,7 +445,7 @@ def __init__(self): linear_extension=True, facade=False) L = self._base_poset.order_ideals_lattice() - H = L._hasse_diagram.relabel({i: x for i, x in enumerate(L._elements)}, + H = L._hasse_diagram.relabel(dict(enumerate(L._elements)), inplace=False) FiniteLatticePoset.__init__(self, hasse_diagram=H, elements=L._elements, category=L.category(), @@ -485,7 +485,7 @@ def __call__(self, *args, **kwargs): True """ if len(args) > 1: - return super().__call__([arg for arg in args], **kwargs) + return super().__call__(list(args), **kwargs) else: return super().__call__(*args, **kwargs) diff --git a/src/sage/modular/modform_hecketriangle/constructor.py b/src/sage/modular/modform_hecketriangle/constructor.py index 3a9e21fa852..040aa01add7 100644 --- a/src/sage/modular/modform_hecketriangle/constructor.py +++ b/src/sage/modular/modform_hecketriangle/constructor.py @@ -129,8 +129,8 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): num = R(f.numerator()) denom = R(f.denominator()) - ep_num = set([ZZ.one() - 2*((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(num).monomials()]) - ep_denom = set([ZZ.one() - 2*((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(denom).monomials()]) + ep_num = {ZZ.one() - 2*((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(num).monomials()} + ep_denom = {ZZ.one() - 2*((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(denom).monomials()} if (n == infinity): hom_num = R( num.subs(x=x**4, y=y**2, z=z**2) ) diff --git a/src/sage/modular/modform_hecketriangle/element.py b/src/sage/modular/modform_hecketriangle/element.py index b8cac1e9f52..4f58baafff5 100644 --- a/src/sage/modular/modform_hecketriangle/element.py +++ b/src/sage/modular/modform_hecketriangle/element.py @@ -337,7 +337,7 @@ def lseries(self, num_prec=None, max_imaginary_part=0, max_asymp_coeffs=40): # num_coeffs = L.num_coeffs() num_coeffs = L.num_coeffs(1.2) - coeff_vector = [coeff for coeff in self.q_expansion_vector(min_exp=0, max_exp=num_coeffs + 1, fix_d=True)] + coeff_vector = list(self.q_expansion_vector(min_exp=0, max_exp=num_coeffs + 1, fix_d=True)) pari_precode = "coeff = {};".format(coeff_vector) L.init_coeffs(v="coeff[k+1]", pari_precode=pari_precode, diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index 6c73cc50d40..b37898fc024 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -803,7 +803,7 @@ def root_extension_embedding(self, D, K=None): else: K = AlgebraicField() - L = [emb for emb in F.embeddings(K)] + L = list(F.embeddings(K)) # Three possibilities up to numerical artefacts: # (1) emb = e, purely imaginary diff --git a/src/sage/modular/modform_hecketriangle/space.py b/src/sage/modular/modform_hecketriangle/space.py index 9df1e2d60ba..e897808ef23 100644 --- a/src/sage/modular/modform_hecketriangle/space.py +++ b/src/sage/modular/modform_hecketriangle/space.py @@ -327,7 +327,7 @@ def coordinate_vector(self, v): ambient_space = self.graded_ring().reduce_type("holo", degree=(gens[0].weight(), gens[0].ep())) subspace = ambient_space.subspace(gens) vector_part_in_subspace = subspace(parts[r]) - coord_part = [v for v in vector_part_in_subspace.coordinate_vector()] + coord_part = list(vector_part_in_subspace.coordinate_vector()) coord_vector += coord_part return self._module(vector(self.coeff_ring(), coord_vector)) @@ -499,7 +499,7 @@ def coordinate_vector(self, v): ambient_space = self.graded_ring().reduce_type("cusp", degree=(gens[0].weight(), gens[0].ep())) subspace = ambient_space.subspace(gens) vector_part_in_subspace = subspace(parts[r]) - coord_part = [v for v in vector_part_in_subspace.coordinate_vector()] + coord_part = list(vector_part_in_subspace.coordinate_vector()) coord_vector += coord_part return self._module(vector(self.coeff_ring(), coord_vector)) diff --git a/src/sage/modular/modform_hecketriangle/subspace.py b/src/sage/modular/modform_hecketriangle/subspace.py index 4475f71530a..504c5fc1936 100644 --- a/src/sage/modular/modform_hecketriangle/subspace.py +++ b/src/sage/modular/modform_hecketriangle/subspace.py @@ -208,7 +208,7 @@ def __init__(self, ambient_space, basis, check): Module.__init__(self, base=ambient_space.base_ring()) self._ambient_space = ambient_space - self._basis = [v for v in basis] + self._basis = list(basis) # self(v) instead would somehow mess up the coercion model self._gens = [self._element_constructor_(v) for v in basis] self._module = ambient_space._module.submodule([ambient_space.coordinate_vector(v) for v in basis]) diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index a0e40c27785..89ba2741eac 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -2260,7 +2260,7 @@ def integral_structure(self, algorithm='default'): # The attribute _mod2term is set by self.compute_presentation(). # It is a list of pairs (n, c), such that the ith element of the list # is equivalent to c times the n-th basis Manin symbol. - G = set([i for i, _ in self._mod2term]) + G = {i for i, _ in self._mod2term} # Now G is a set of integer i such that these integers gives # indices of Manin symbols that together generate the integral diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index e90a5d165f6..903c57e9b96 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -567,7 +567,7 @@ def __call__(self, x): return sum([c * self._coerce_in_manin_symbol(v) for c, v in S]) elif is_FreeModuleElement(x): - y = {i: xi for i, xi in enumerate(x)} + y = dict(enumerate(x)) return BoundarySpaceElement(self, y) raise TypeError("Coercion of %s (of type %s) into %s not (yet) defined." % (x, type(x), self)) diff --git a/src/sage/modular/modsym/ghlist.py b/src/sage/modular/modsym/ghlist.py index 5df29f52af9..2e74217f851 100644 --- a/src/sage/modular/modsym/ghlist.py +++ b/src/sage/modular/modsym/ghlist.py @@ -48,7 +48,7 @@ def __init__(self, group): N = group.level() v = group._coset_reduction_data()[0] N = group.level() - coset_reps = set([a for a, b, _ in v if b == 1]) + coset_reps = {a for a, b, _ in v if b == 1} w = [group._reduce_coset(x*u, x*v) for x in coset_reps for u,v in p1list.P1List(N).list()] w = sorted(set(w)) self.__list = w diff --git a/src/sage/modular/modsym/relation_matrix.py b/src/sage/modular/modsym/relation_matrix.py index 5885812d36c..0533ea36f09 100644 --- a/src/sage/modular/modsym/relation_matrix.py +++ b/src/sage/modular/modsym/relation_matrix.py @@ -320,7 +320,7 @@ def gens_to_basis_matrix(syms, relation_matrix, mod, field, sparse): basis_set = set(A.nonpivots()) pivots = A.pivots() - basis_mod2 = set([j for j, c in mod if c != 0]) + basis_mod2 = {j for j, c in mod if c != 0} basis_set = basis_set.intersection(basis_mod2) basis = sorted(basis_set) @@ -333,7 +333,7 @@ def gens_to_basis_matrix(syms, relation_matrix, mod, field, 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))]) + cols_index = {basis[i]: i for i in range(len(basis))} for i in basis_mod2: t, l = search(basis, i) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 494d183e805..cefcb3b3c65 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -277,7 +277,7 @@ def composition_to_iterated(w, reverse=False) -> tuple[int, ...]: sage: composition_to_iterated((1,2), True) (1, 0, 1) """ - word = tuple() + word = () loop_over = reversed(w) if reverse else w for letter in loop_over: word += (1,) + (0,) * (letter - 1) @@ -1175,7 +1175,7 @@ def simplify_full(self, basis=None): """ if basis is None: basis = self.parent().basis_brown - support = set(sum(d) for d in self.support()) + support = {sum(d) for d in self.support()} result = self.parent().zero() for d in sorted(support): h = self.homogeneous_component(d) @@ -1994,7 +1994,7 @@ def __bool__(self) -> bool: P = self.parent() deg = P.degree_on_basis phi = P.phi - for d in sorted(set(deg(w) for w in self.support())): + for d in sorted({deg(w) for w in self.support()}): z = self.homogeneous_component(d) if not phi(z).is_zero(): return True diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index 251310de6b8..89ac3436cb2 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -121,7 +121,7 @@ def basis_f_odd_iterator(n, start=3) -> Iterator[tuple]: (3, 11)] """ if n == 0: - yield tuple() + yield () return if n % 2 and n >= start: yield (n,) From 71331829d84dc26b2c914d2ad5e1edc70e194d46 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Nov 2023 08:03:05 -0800 Subject: [PATCH 200/538] src/sage/tests/book_stein_ent.py: Use block tag --- src/sage/tests/book_stein_ent.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/sage/tests/book_stein_ent.py b/src/sage/tests/book_stein_ent.py index b4d593ff427..2c43a840cdc 100644 --- a/src/sage/tests/book_stein_ent.py +++ b/src/sage/tests/book_stein_ent.py @@ -50,12 +50,14 @@ 25 sage: prime_pi(3000000) 216816 -sage: plot(prime_pi, 1,1000, rgbcolor=(0,0,1)) # needs sage.plot + +sage: # needs sage.plot sage.symbolic +sage: plot(prime_pi, 1,1000, rgbcolor=(0,0,1)) Graphics object consisting of 1 graphics primitive -sage: P = plot(Li, 2,10000, rgbcolor='purple') # needs sage.plot -sage: Q = plot(prime_pi, 2,10000, rgbcolor='black') # needs sage.plot -sage: R = plot(sqrt(x)*log(x),2,10000,rgbcolor='red') # needs sage.plot -sage: show(P+Q+R,xmin=0, figsize=[8,3]) # needs sage.plot +sage: P = plot(Li, 2,10000, rgbcolor='purple') +sage: Q = plot(prime_pi, 2,10000, rgbcolor='black') +sage: R = plot(sqrt(x)*log(x), 2,10000, rgbcolor='red') +sage: show(P + Q + R, xmin=0, figsize=[8,3]) sage: R = Integers(3) sage: list(R) From d1c66423cf61be17b69dea107df2bf071c3923fd Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Nov 2023 08:09:38 -0800 Subject: [PATCH 201/538] src/sage/sat/boolean_polynomials.py: Use file-level # optional/needs --- src/sage/sat/boolean_polynomials.py | 53 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index dc5fdb69ff0..32753175384 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -1,4 +1,4 @@ -# sage.doctest: needs sage.rings.polynomial.pbori +# sage.doctest: optional - pycryptosat, needs sage.modules sage.rings.polynomial.pbori """ SAT Functions for Boolean Polynomials @@ -72,8 +72,8 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): We construct a very small-scale AES system of equations:: - sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) # needs sage.modules sage.rings.finite_rings - sage: while True: # workaround (see :trac:`31891`) # needs sage.modules sage.rings.finite_rings + sage: sr = mq.SR(1, 1, 1, 4, gf2=True, polybori=True) + sage: while True: # workaround (see :trac:`31891`) ....: try: ....: F, s = sr.polynomial_system() ....: break @@ -83,57 +83,56 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): and pass it to a SAT solver:: sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: s = solve_sat(F) # optional - pycryptosat # needs sage.modules sage.rings.finite_rings - sage: F.subs(s[0]) # optional - pycryptosat # needs sage.modules sage.rings.finite_rings + sage: s = solve_sat(F) + sage: F.subs(s[0]) Polynomial Sequence with 36 Polynomials in 0 Variables This time we pass a few options through to the converter and the solver:: - sage: s = solve_sat(F, c_max_vars_sparse=4, c_cutting_number=8) # optional - pycryptosat, needs sage.modules sage.rings.finite_rings - sage: F.subs(s[0]) # optional - pycryptosat # needs sage.modules sage.rings.finite_rings + sage: s = solve_sat(F, c_max_vars_sparse=4, c_cutting_number=8) + sage: F.subs(s[0]) Polynomial Sequence with 36 Polynomials in 0 Variables We construct a very simple system with three solutions and ask for a specific number of solutions:: - sage: # optional - pycryptosat, needs sage.modules sage: B. = BooleanPolynomialRing() sage: f = a*b sage: l = solve_sat([f],n=1) sage: len(l) == 1, f.subs(l[0]) (True, 0) - sage: l = solve_sat([a*b],n=2) # optional - pycryptosat # needs sage.modules - sage: len(l) == 2, f.subs(l[0]), f.subs(l[1]) # optional - pycryptosat # needs sage.modules + sage: l = solve_sat([a*b],n=2) + sage: len(l) == 2, f.subs(l[0]), f.subs(l[1]) (True, 0, 0) - sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=3)) # optional - pycryptosat, needs sage.modules + sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=3)) [(0, 0), (0, 1), (1, 0)] - sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=4)) # optional - pycryptosat, needs sage.modules + sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=4)) [(0, 0), (0, 1), (1, 0)] - sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=infinity)) # optional - pycryptosat, needs sage.modules + sage: sorted((d[a], d[b]) for d in solve_sat([a*b], n=infinity)) [(0, 0), (0, 1), (1, 0)] In the next example we see how the ``target_variables`` parameter works:: sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: R. = BooleanPolynomialRing() # optional - pycryptosat # needs sage.modules - sage: F = [a + b, a + c + d] # optional - pycryptosat # needs sage.modules + sage: R. = BooleanPolynomialRing() + sage: F = [a + b, a + c + d] First the normal use case:: - sage: sorted((D[a], D[b], D[c], D[d]) # optional - pycryptosat # needs sage.modules + sage: sorted((D[a], D[b], D[c], D[d]) ....: for D in solve_sat(F, n=infinity)) [(0, 0, 0, 0), (0, 0, 1, 1), (1, 1, 0, 1), (1, 1, 1, 0)] Now we are only interested in the solutions of the variables a and b:: - sage: solve_sat(F, n=infinity, target_variables=[a,b]) # optional - pycryptosat, needs sage.modules + sage: solve_sat(F, n=infinity, target_variables=[a,b]) [{b: 0, a: 0}, {b: 1, a: 1}] Here, we generate and solve the cubic equations of the AES SBox (see :trac:`26676`):: - sage: # long time, optional - pycryptosat, needs sage.modules + sage: # long time sage: from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence sage: from sage.sat.boolean_polynomials import solve as solve_sat sage: sr = sage.crypto.mq.SR(1, 4, 4, 8, @@ -145,7 +144,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): sage: variables = ",".join(variables) sage: R = BooleanPolynomialRing(16, variables) sage: eqs = [R(eq) for eq in eqs] - sage: sls_aes = solve_sat(eqs, n = infinity) + sage: sls_aes = solve_sat(eqs, n=infinity) sage: len(sls_aes) 256 @@ -168,7 +167,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): ....: k9 + k28, ....: k11 + k20] sage: from sage.sat.boolean_polynomials import solve as solve_sat - sage: solve_sat(keqs, n=1, solver=SAT('cryptominisat')) # optional - pycryptosat + sage: solve_sat(keqs, n=1, solver=SAT('cryptominisat')) [{k28: 0, k26: 1, k24: 0, @@ -342,16 +341,16 @@ def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=Fa EXAMPLES:: - sage: from sage.sat.boolean_polynomials import learn as learn_sat # optional - pycryptosat + sage: from sage.sat.boolean_polynomials import learn as learn_sat We construct a simple system and solve it:: - sage: set_random_seed(2300) - sage: sr = mq.SR(1, 2, 2, 4, gf2=True, polybori=True) # optional - pycryptosat, needs sage.modules sage.rings.finite_rings - sage: F,s = sr.polynomial_system() # optional - pycryptosat # needs sage.modules sage.rings.finite_rings - sage: H = learn_sat(F) # optional - pycryptosat # needs sage.modules sage.rings.finite_rings - sage: H[-1] # optional - pycryptosat # needs sage.modules sage.rings.finite_rings - k033 + 1 + sage: set_random_seed(2300) + sage: sr = mq.SR(1, 2, 2, 4, gf2=True, polybori=True) + sage: F,s = sr.polynomial_system() + sage: H = learn_sat(F) + sage: H[-1] + k033 + 1 """ try: len(F) From 3860c75944c5f536e682a74a20520c18cadc18b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 17:54:41 +0100 Subject: [PATCH 202/538] Update src/sage/rings/integer.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Köppe --- src/sage/rings/integer.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 744e8d37cf8..667d0bcbb13 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -3823,7 +3823,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): else: # self is big -- it doesn't fit in unsigned long. if start <= 2 and mpz_even_p(self.value): - mpz_set_ui(x.value,2) + mpz_set_ui(x.value, 2) return x if start <= 3 and mpz_divisible_ui_p(self.value,3): mpz_set_ui(x.value,3) From 6c514c9898973466c09af48eedb28d66d4e11f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 17:54:57 +0100 Subject: [PATCH 203/538] Update src/sage/rings/integer.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Köppe --- src/sage/rings/integer.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 667d0bcbb13..36fa4eb56ff 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -3825,7 +3825,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): if start <= 2 and mpz_even_p(self.value): mpz_set_ui(x.value, 2) return x - if start <= 3 and mpz_divisible_ui_p(self.value,3): + if start <= 3 and mpz_divisible_ui_p(self.value, 3): mpz_set_ui(x.value,3) return x if start <= 5 and mpz_divisible_ui_p(self.value,5): From 8955ceb13acccf55fef6958802f69c16e1f7c17e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 17:55:41 +0100 Subject: [PATCH 204/538] Update src/sage/rings/integer.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Köppe --- src/sage/rings/integer.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 36fa4eb56ff..52a2498eafa 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -2871,7 +2871,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): from sage.functions.log import function_log return function_log(self,dont_call_method_on_arg=True)/\ - function_log(m,dont_call_method_on_arg=True) + function_log(m, dont_call_method_on_arg=True) def exp(self, prec=None): r""" From 3453deaec6049dfb508673760d68a6ed21d3cbc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 17:55:59 +0100 Subject: [PATCH 205/538] Update src/sage/rings/integer.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Köppe --- src/sage/rings/integer.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 52a2498eafa..b86e6c26fa9 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -2870,7 +2870,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return elog from sage.functions.log import function_log - return function_log(self,dont_call_method_on_arg=True)/\ + return function_log(self, dont_call_method_on_arg=True)/\ function_log(m, dont_call_method_on_arg=True) def exp(self, prec=None): From e48fa7fc9ff23bac8e5e19aedd8f507c970cbf37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 17:56:21 +0100 Subject: [PATCH 206/538] Update src/sage/rings/integer.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Köppe --- src/sage/rings/integer.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index b86e6c26fa9..ba5818ed327 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -3829,7 +3829,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): mpz_set_ui(x.value,3) return x if start <= 5 and mpz_divisible_ui_p(self.value,5): - mpz_set_ui(x.value,5) + mpz_set_ui(x.value, 5) return x # x.value = floor(sqrt(self.value)) From 4d5efc6e96a955a5bbb51002cc960008bac0fd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 17:56:33 +0100 Subject: [PATCH 207/538] Update src/sage/rings/integer.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Köppe --- src/sage/rings/integer.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index ba5818ed327..6774df8b4c2 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -3826,9 +3826,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): mpz_set_ui(x.value, 2) return x if start <= 3 and mpz_divisible_ui_p(self.value, 3): - mpz_set_ui(x.value,3) + mpz_set_ui(x.value, 3) return x - if start <= 5 and mpz_divisible_ui_p(self.value,5): + if start <= 5 and mpz_divisible_ui_p(self.value, 5): mpz_set_ui(x.value, 5) return x From d3e4c701e32fd4061df0b51e247043de7001bad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 17:56:48 +0100 Subject: [PATCH 208/538] Update src/sage/rings/integer.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Köppe --- src/sage/rings/integer.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 6774df8b4c2..e6e19f1c6b6 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -4073,7 +4073,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): sage: 0.support() Traceback (most recent call last): ... - ArithmeticError: Support of 0 not defined + ArithmeticError: support of 0 not defined """ if self.is_zero(): raise ArithmeticError("Support of 0 not defined") From 0d3d2fc53d3c1b732a0e59f909be5044d5861e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 17:56:56 +0100 Subject: [PATCH 209/538] Update src/sage/rings/integer.pyx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Köppe --- src/sage/rings/integer.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index e6e19f1c6b6..4a3ce95f609 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -4076,7 +4076,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): ArithmeticError: support of 0 not defined """ if self.is_zero(): - raise ArithmeticError("Support of 0 not defined") + raise ArithmeticError("support of 0 not defined") return sage.arith.all.prime_factors(self) def coprime_integers(self, m): From b86d8920bf5dbb8e69ddb2216e92218805c538e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 17:59:31 +0100 Subject: [PATCH 210/538] suggested details --- src/sage/rings/integer.pyx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 4a3ce95f609..b1856bb9243 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -207,8 +207,7 @@ new_gen_from_integer = None cdef extern from *: int unlikely(int) nogil # Defined by Cython -cdef object numpy_long_interface = {'typestr': '=i4' if sizeof(long) == 4 - else '=i8'} +cdef object numpy_long_interface = {'typestr': '=i4' if sizeof(long) == 4 else '=i8'} cdef object numpy_int64_interface = {'typestr': '=i8'} cdef object numpy_object_interface = {'typestr': '|O'} @@ -5274,8 +5273,8 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return (self, zero) if get_data else False _small_primes_table[:] = [ - 0,1,1,1,0,1,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0, # 001, 03,..., 49 - 0,1,0,0,1,1,0,0,1,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,0, # 051, 53,..., 99 + 0,1,1,1,0,1,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0, # 1,3,...,49 + 0,1,0,0,1,1,0,0,1,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,0, # 51,53,...,99 1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,1, # 101,103,...,149 1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,1,0,0,0,0,1,1,0,1,1, # 151,153,...,199 0,0,0,0,0,1,0,0,0,0,0,1,0,1,1,0,1,0,0,1,1,0,0,0,0, # 201,203,...,249 From 9c8f3b6ffa182c3629b864805889f4ea5234cc43 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Nov 2023 11:04:52 -0800 Subject: [PATCH 211/538] .github/workflows/docker.yml: Set DOCKER_TAG from pre-merge commit sha even when docker_push_repository is not set --- .github/workflows/docker.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c12ec820f83..1a210cad29c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -191,6 +191,9 @@ jobs: echo "DOCKER_PUSH_REPOSITORY=$(echo ${{ inputs.docker_push_repository }} | tr "[:upper:]" "[:lower:]")" >> $GITHUB_ENV echo "DOCKER_CONFIG_FILE=$HOME/.docker/config.json" >> $GITHUB_ENV fi + + - name: Determine Docker tags to use + run: | # This line needs to be run before the step "Merge CI fixes from sagemath/sage". DOCKER_TAG="$(git describe --dirty --always)" echo "DOCKER_TAG=$DOCKER_TAG" >> $GITHUB_ENV From 46a14410e260666ba5359cc01d63df93855730c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 6 Nov 2023 20:44:48 +0100 Subject: [PATCH 212/538] suggested fix --- src/sage/modular/abvar/homspace.py | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/sage/modular/abvar/homspace.py b/src/sage/modular/abvar/homspace.py index ab1544d2698..d0e192d2808 100644 --- a/src/sage/modular/abvar/homspace.py +++ b/src/sage/modular/abvar/homspace.py @@ -168,15 +168,15 @@ - Craig Citro, Robert Bradshaw (2008-03): Rewrote with modabvar overhaul """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from copy import copy @@ -188,7 +188,6 @@ from . import morphism -import sage.rings.integer_ring from sage.rings.infinity import Infinity from sage.rings.ring import Ring @@ -276,7 +275,7 @@ def _matrix_space(self): sage: Hom(J0(11), J0(22))._matrix_space Full MatrixSpace of 2 by 4 dense matrices over Integer Ring """ - return MatrixSpace(ZZ,2*self.domain().dimension(), 2*self.codomain().dimension()) + return MatrixSpace(ZZ, 2*self.domain().dimension(), 2*self.codomain().dimension()) def _element_constructor_from_element_class(self, *args, **keywords): """ @@ -479,7 +478,7 @@ def free_module(self): """ self.calculate_generators() V = ZZ**(4*self.domain().dimension() * self.codomain().dimension()) - return V.submodule([ V(m.matrix().list()) for m in self.gens() ]) + return V.submodule([V(m.matrix().list()) for m in self.gens()]) def gen(self, i=0): """ @@ -570,7 +569,7 @@ def calculate_generators(self): return if (self.domain() == self.codomain()) and (self.domain().dimension() == 1): - self._gens = ( identity_matrix(ZZ,2), ) + self._gens = (identity_matrix(ZZ, 2),) return phi = self.domain()._isogeny_to_product_of_powers() @@ -583,9 +582,9 @@ def calculate_generators(self): Mt = psi.complementary_isogeny().matrix() R = ZZ**(4*self.domain().dimension()*self.codomain().dimension()) - gens = R.submodule([ (M*self._get_matrix(g)*Mt).list() - for g in im_gens ]).saturation().basis() - self._gens = tuple([ self._get_matrix(g) for g in gens ]) + gens = R.submodule([(M*self._get_matrix(g)*Mt).list() + for g in im_gens]).saturation().basis() + self._gens = tuple([self._get_matrix(g) for g in gens]) def _calculate_product_gens(self): """ @@ -746,7 +745,8 @@ def _calculate_simple_gens(self): Mf = f.matrix() Mg = g.matrix() - return [ Mf * self._get_matrix(e) * Mg for e in ls ] + return [Mf * self._get_matrix(e) * Mg for e in ls] + # NOTE/WARNING/TODO: Below in the __init__, etc. we do *not* check # that the input gens are give something that spans a sub*ring*, as apposed @@ -820,7 +820,7 @@ def __init__(self, A, gens=None, category=None): if gens is None: self._gens = None else: - self._gens = tuple([ self._get_matrix(g) for g in gens ]) + self._gens = tuple([self._get_matrix(g) for g in gens]) self._is_full_ring = gens is None def _repr_(self): @@ -903,7 +903,7 @@ def index_in_saturation(self): A = self.abelian_variety() d = A.dimension() M = ZZ**(4*d**2) - gens = [ x.matrix().list() for x in self.gens() ] + gens = [x.matrix().list() for x in self.gens()] R = M.submodule(gens) return R.index_in_saturation() @@ -934,8 +934,8 @@ def discriminant(self): 2 """ g = self.gens() - M = Matrix(ZZ,len(g), [ (g[i]*g[j]).trace() - for i in range(len(g)) for j in range(len(g)) ]) + M = Matrix(ZZ, len(g), [(g[i]*g[j]).trace() + for i in range(len(g)) for j in range(len(g))]) return M.determinant() def image_of_hecke_algebra(self, check_every=1): @@ -1002,18 +1002,18 @@ def image_of_hecke_algebra(self, check_every=1): EndVecZ = ZZ**(4*d**2) if d == 1: - self.__hecke_algebra_image = EndomorphismSubring(A, [[1,0,0,1]]) + self.__hecke_algebra_image = EndomorphismSubring(A, [[1, 0, 0, 1]]) return self.__hecke_algebra_image V = EndVecZ.submodule([A.hecke_operator(1).matrix().list()]) - for n in range(2,M.sturm_bound()+1): + for n in range(2, M.sturm_bound()+1): if (check_every > 0 and n % check_every == 0 and V.dimension() == d and V.index_in_saturation() == 1): break - V += EndVecZ.submodule([ A.hecke_operator(n).matrix().list() ]) + V += EndVecZ.submodule([A.hecke_operator(n).matrix().list()]) self.__hecke_algebra_image = EndomorphismSubring(A, V.basis()) return self.__hecke_algebra_image From 08cdb2275ccb767561b710d44c0e12a24875da6e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Nov 2023 13:30:13 -0800 Subject: [PATCH 213/538] build/pkgs/openblas: Stop openblas from using explicit 'make -j' --- build/pkgs/openblas/spkg-install.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/pkgs/openblas/spkg-install.in b/build/pkgs/openblas/spkg-install.in index 00413ca517d..eacd993e9d6 100644 --- a/build/pkgs/openblas/spkg-install.in +++ b/build/pkgs/openblas/spkg-install.in @@ -34,6 +34,9 @@ fi echo "Building OpenBLAS: $MAKE $OPENBLAS_CONFIGURE" +# Do not emit "-j" options +export MAKE_NB_JOBS=0 + # Ensure USE_TLS=1 ; see https://github.com/sagemath/sage/issues/27256 OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE USE_TLS=1" From 91a4e0617b224eae0818bd6518bba56caca33d1d Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Nov 2023 17:08:23 -0800 Subject: [PATCH 214/538] build/pkgs/openblas/spkg-install.in: Put MAKE_NB_JOBS in OPENBLAS_CONFIGURE --- build/pkgs/openblas/spkg-install.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/openblas/spkg-install.in b/build/pkgs/openblas/spkg-install.in index eacd993e9d6..5050e165787 100644 --- a/build/pkgs/openblas/spkg-install.in +++ b/build/pkgs/openblas/spkg-install.in @@ -35,7 +35,7 @@ fi echo "Building OpenBLAS: $MAKE $OPENBLAS_CONFIGURE" # Do not emit "-j" options -export MAKE_NB_JOBS=0 +OPENBLAS_CONFIGURE+=" MAKE_NB_JOBS=0" # Ensure USE_TLS=1 ; see https://github.com/sagemath/sage/issues/27256 OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE USE_TLS=1" From 33ea789e843c8e83ddf9014eae7ff4572e5cd73f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 14:58:41 -0700 Subject: [PATCH 215/538] pkgs/sage-conf_pypi/setup.py: Replace DistutilsSetupError --- pkgs/sage-conf_pypi/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/sage-conf_pypi/setup.py b/pkgs/sage-conf_pypi/setup.py index ac2b5fb3192..ff5ec5f5572 100644 --- a/pkgs/sage-conf_pypi/setup.py +++ b/pkgs/sage-conf_pypi/setup.py @@ -76,7 +76,7 @@ def run(self): cmd = f'cd {SAGE_ROOT} && {SETENV} && {SETMAKE} && $MAKE V=0 {TARGETS}' print(f"Running {cmd}", flush=True) if os.system(cmd) != 0: - raise DistutilsSetupError(f"make {TARGETS} failed") + raise SetupError(f"make {TARGETS} failed") setuptools_build_py.run(self) From 7a05c3673283ca20ed097a0c4f9602d057b01aaa Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 15:00:46 -0700 Subject: [PATCH 216/538] pkgs/sage-conf_pypi: Add missing .upstream.d to sage_root --- pkgs/sage-conf_pypi/sage_root/.upstream.d | 1 + 1 file changed, 1 insertion(+) create mode 120000 pkgs/sage-conf_pypi/sage_root/.upstream.d diff --git a/pkgs/sage-conf_pypi/sage_root/.upstream.d b/pkgs/sage-conf_pypi/sage_root/.upstream.d new file mode 120000 index 00000000000..243d6b8c910 --- /dev/null +++ b/pkgs/sage-conf_pypi/sage_root/.upstream.d @@ -0,0 +1 @@ +../../../.upstream.d \ No newline at end of file From 28df32fb95d5d28e7f755ba9062eb9be61426d93 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 15:45:58 -0700 Subject: [PATCH 217/538] pkgs/sage-conf_pypi/tox.ini: Pass HOMEBREW env var --- pkgs/sage-conf_pypi/tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/sage-conf_pypi/tox.ini b/pkgs/sage-conf_pypi/tox.ini index b530bd10554..00a53d0ea59 100644 --- a/pkgs/sage-conf_pypi/tox.ini +++ b/pkgs/sage-conf_pypi/tox.ini @@ -4,6 +4,8 @@ envlist = python [testenv] passenv = MAKE + # So that .homebrew-build-env will work + HOMEBREW setenv = HOME={envdir} From 5ce616bb8e178f48f537a1fa7514fdbb1a74dd1e Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 17:05:26 -0700 Subject: [PATCH 218/538] pkgs/sage-conf_pypi/setup.py: Fix invocation of .homebrew-build-env --- pkgs/sage-conf_pypi/setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/sage-conf_pypi/setup.py b/pkgs/sage-conf_pypi/setup.py index ff5ec5f5572..e482ed83bc3 100644 --- a/pkgs/sage-conf_pypi/setup.py +++ b/pkgs/sage-conf_pypi/setup.py @@ -36,14 +36,14 @@ def run(self): if os.environ.get('CONDA_PREFIX', ''): SETENV = ':' else: - SETENV = '(. ./.homebrew-build-env 2> /dev/null || :)' + SETENV = '. ./.homebrew-build-env 2> /dev/null' SAGE_LOCAL = os.path.join(SAGE_ROOT, 'local') if os.path.exists(os.path.join(SAGE_ROOT, 'config.status')): print(f'Reusing configured SAGE_ROOT={SAGE_ROOT}') else: - cmd = f"cd {SAGE_ROOT} && {SETENV} && ./configure --prefix={SAGE_LOCAL} --with-python={sys.executable} --enable-build-as-root --enable-download-from-upstream-url --with-system-python3=force --with-sage-venv --disable-notebook --disable-sagelib --disable-sage_conf --disable-doc" + cmd = f"cd {SAGE_ROOT} && ({SETENV}; ./configure --prefix={SAGE_LOCAL} --with-python={sys.executable} --enable-build-as-root --enable-download-from-upstream-url --with-system-python3=force --with-sage-venv --disable-notebook --disable-sagelib --disable-sage_conf --disable-doc)" print(f"Running {cmd}") sys.stdout.flush() if os.system(cmd) != 0: @@ -73,7 +73,7 @@ def run(self): # (that use native libraries shared with other packages). SETMAKE = 'if [ -z "$MAKE" ]; then export MAKE="make -j$(PATH=build/bin:$PATH build/bin/sage-build-num-threads | cut -d" " -f 2)"; fi' TARGETS = 'build' - cmd = f'cd {SAGE_ROOT} && {SETENV} && {SETMAKE} && $MAKE V=0 {TARGETS}' + cmd = f'cd {SAGE_ROOT} && ({SETENV}; {SETMAKE} && $MAKE V=0 {TARGETS})' print(f"Running {cmd}", flush=True) if os.system(cmd) != 0: raise SetupError(f"make {TARGETS} failed") From 2632428fa08accd2605631865e4331268997ab17 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 19:18:39 -0700 Subject: [PATCH 219/538] pkgs/sage-conf_pypi/setup.py: Accept environment variable SAGE_CONF_TARGETS --- pkgs/sage-conf_pypi/setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/sage-conf_pypi/setup.py b/pkgs/sage-conf_pypi/setup.py index e482ed83bc3..5a8240b6e9d 100644 --- a/pkgs/sage-conf_pypi/setup.py +++ b/pkgs/sage-conf_pypi/setup.py @@ -73,10 +73,10 @@ def run(self): # (that use native libraries shared with other packages). SETMAKE = 'if [ -z "$MAKE" ]; then export MAKE="make -j$(PATH=build/bin:$PATH build/bin/sage-build-num-threads | cut -d" " -f 2)"; fi' TARGETS = 'build' - cmd = f'cd {SAGE_ROOT} && ({SETENV}; {SETMAKE} && $MAKE V=0 {TARGETS})' + cmd = f'cd {SAGE_ROOT} && ({SETENV}; {SETMAKE} && $MAKE V=0 ${{SAGE_CONF_TARGETS-{TARGETS}}})' print(f"Running {cmd}", flush=True) if os.system(cmd) != 0: - raise SetupError(f"make {TARGETS} failed") + raise SetupError(f"make ${{SAGE_CONF_TARGETS-{TARGETS}}} failed") setuptools_build_py.run(self) From cf8f82675d85c688267980878e6a0cb714a595be Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 19:19:08 -0700 Subject: [PATCH 220/538] pkgs/sage-conf_pypi/tox.ini: Add environment 'python-user' --- pkgs/sage-conf_pypi/tox.ini | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/pkgs/sage-conf_pypi/tox.ini b/pkgs/sage-conf_pypi/tox.ini index 00a53d0ea59..ea7eee9eb48 100644 --- a/pkgs/sage-conf_pypi/tox.ini +++ b/pkgs/sage-conf_pypi/tox.ini @@ -1,14 +1,39 @@ [tox] -envlist = python +envlist = python, python-user -[testenv] +[testenv:.pkg] passenv = MAKE # So that .homebrew-build-env will work HOMEBREW setenv = - HOME={envdir} + HOME={work_dir}/home + # Passed to 'make' instead of 'build'. We test here: + # - frobby (standalone program with dependency on gmp; tests that .homebrew-build-env is invoked correctly) + # - lrcalc_python (builds a platform wheel, possibly with use of system library) + SAGE_CONF_TARGETS=frobby lrcalc_python +[testenv:python] +package = wheel +setenv = + HOME={work_dir}/home +allowlist_externals = + bash + env +commands = + bash -c 'eval $SETENV; sage-config' + bash -c 'eval $SETENV; ls $(sage-config SAGE_SPKG_WHEELS)' + +[testenv:python-user] +package = wheel +setenv = + HOME={work_dir}/home + PYTHONUSERBASE={work_dir}/userbase + SETENV=export PATH={env:PYTHONUSERBASE}/bin:{env:PATH} +system_site_packages = True +install_command = env PATH={env:PYTHONUSERBASE}/bin:{env_bin_dir} python -I -m pip install --user {opts} {packages} +allowlist_externals = + {[testenv:python]allowlist_externals} commands = - sage-config + {[testenv:python]commands} From 3c31ee62c62637cff3b28d1a306aa6b6166cc81f Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 24 Oct 2023 20:22:05 -0700 Subject: [PATCH 221/538] pkgs/sage-conf_pypi/tox.ini: Test more --- pkgs/sage-conf_pypi/tox.ini | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/pkgs/sage-conf_pypi/tox.ini b/pkgs/sage-conf_pypi/tox.ini index ea7eee9eb48..5a53c75ea35 100644 --- a/pkgs/sage-conf_pypi/tox.ini +++ b/pkgs/sage-conf_pypi/tox.ini @@ -12,23 +12,32 @@ setenv = # Passed to 'make' instead of 'build'. We test here: # - frobby (standalone program with dependency on gmp; tests that .homebrew-build-env is invoked correctly) # - lrcalc_python (builds a platform wheel, possibly with use of system library) - SAGE_CONF_TARGETS=frobby lrcalc_python + # - coxeter3 (which allows us to build sagemath-coxeter3) + SAGE_CONF_TARGETS=frobby lrcalc_python coxeter3 [testenv:python] package = wheel +deps = + # For the 'sage' script + sagemath-environment setenv = HOME={work_dir}/home allowlist_externals = bash env commands = - bash -c 'eval $SETENV; sage-config' - bash -c 'eval $SETENV; ls $(sage-config SAGE_SPKG_WHEELS)' + bash -c 'set -ex; eval $SETENV; \ + sage-config; \ + ls $(sage-config SAGE_SPKG_WHEELS); \ + sage -sh -c "frobby genideal"; \ + {envpython} -m pip install $(sage-config SAGE_SPKG_WHEELS)/*.whl' [testenv:python-user] package = wheel +deps = + {[testenv:python]deps} setenv = - HOME={work_dir}/home + {[testenv:python]setenv} PYTHONUSERBASE={work_dir}/userbase SETENV=export PATH={env:PYTHONUSERBASE}/bin:{env:PATH} system_site_packages = True From 19d1ea7f9878a387f981fbf346aa6e5b95dce8ba Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Nov 2023 17:36:06 -0800 Subject: [PATCH 222/538] pkgs/sage-conf/setup.cfg: Add python_requires --- pkgs/sage-conf/setup.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkgs/sage-conf/setup.cfg b/pkgs/sage-conf/setup.cfg index dac401c303d..d74e36432c2 100644 --- a/pkgs/sage-conf/setup.cfg +++ b/pkgs/sage-conf/setup.cfg @@ -9,6 +9,8 @@ author_email = sage-support@googlegroups.com url = https://www.sagemath.org [options] +python_requires = >=3.9, <3.12 + packages = _sage_conf From d2f56d204da9278169296d36a53fc4fd7009bf4a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Mon, 6 Nov 2023 18:01:25 -0800 Subject: [PATCH 223/538] build/pkgs/openblas/spkg-install.in: Work around hang with GNU make 3.81 (ubuntu-trusty) --- build/pkgs/openblas/spkg-install.in | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build/pkgs/openblas/spkg-install.in b/build/pkgs/openblas/spkg-install.in index 5050e165787..006067800af 100644 --- a/build/pkgs/openblas/spkg-install.in +++ b/build/pkgs/openblas/spkg-install.in @@ -34,8 +34,13 @@ fi echo "Building OpenBLAS: $MAKE $OPENBLAS_CONFIGURE" -# Do not emit "-j" options -OPENBLAS_CONFIGURE+=" MAKE_NB_JOBS=0" +if $MAKE --version | grep -q -F '3.81'; then + # Work around https://savannah.gnu.org/bugs/?15919 + OPENBLAS_CONFIGURE+=" MAKE_NB_JOBS=1" +else + # Do not emit "-j" options; use jobserver + OPENBLAS_CONFIGURE+=" MAKE_NB_JOBS=0" +fi # Ensure USE_TLS=1 ; see https://github.com/sagemath/sage/issues/27256 OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE USE_TLS=1" From f33ad68d24485d137b4e04f65f881055a67918ce Mon Sep 17 00:00:00 2001 From: Lorenz Panny <84067835+yyyyx4@users.noreply.github.com> Date: Tue, 7 Nov 2023 09:35:03 +0100 Subject: [PATCH 224/538] reviewer comment Co-authored-by: Travis Scrimshaw --- src/sage/schemes/elliptic_curves/mod_poly.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/schemes/elliptic_curves/mod_poly.py b/src/sage/schemes/elliptic_curves/mod_poly.py index 88af6185a7b..cb8cd703f69 100644 --- a/src/sage/schemes/elliptic_curves/mod_poly.py +++ b/src/sage/schemes/elliptic_curves/mod_poly.py @@ -163,4 +163,5 @@ def _set_cache_bound(bnd): """ global _cache_bound _cache_bound = bnd + classical_modular_polynomial.set_cache_bound = _set_cache_bound From d3767f0b4b99da2f74c6ef1703234f598929870c Mon Sep 17 00:00:00 2001 From: Enrique Artal Date: Tue, 7 Nov 2023 10:40:41 +0100 Subject: [PATCH 225/538] corrections from review --- src/sage/rings/polynomial/laurent_polynomial_ideal.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 924ce7ed7d3..d569dc06101 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -195,9 +195,7 @@ def __contains__(self, f): sage: x + 3*y in I True - We test that these changes allow to use this method in the inivariate case. - - TESTS:: + This also works in the univariate case:: sage: P. = LaurentPolynomialRing(QQ) sage: I = P.ideal([x^2 + 3*x]) @@ -215,7 +213,7 @@ def __contains__(self, f): def gens_reduced(self): """ - A reduced system of generators. + Return a reduced system of generators. EXAMPLES:: From 6d1a957d2b540da8717eb7d9b86f3f4005b22c6a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 7 Nov 2023 10:04:07 -0800 Subject: [PATCH 226/538] build/pkgs/openblas/spkg-install.in: Build targets libs, netlib, shared in separate make invocations --- build/pkgs/openblas/spkg-install.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/pkgs/openblas/spkg-install.in b/build/pkgs/openblas/spkg-install.in index 006067800af..2f8aea512bc 100644 --- a/build/pkgs/openblas/spkg-install.in +++ b/build/pkgs/openblas/spkg-install.in @@ -45,7 +45,7 @@ fi # Ensure USE_TLS=1 ; see https://github.com/sagemath/sage/issues/27256 OPENBLAS_CONFIGURE="$OPENBLAS_CONFIGURE USE_TLS=1" -if ! (sdh_make libs netlib shared $OPENBLAS_CONFIGURE); then +if ! (sdh_make libs $OPENBLAS_CONFIGURE && sdh_make netlib $OPENBLAS_CONFIGURE && sdh_make shared $OPENBLAS_CONFIGURE); then if [[ $OPENBLAS_CONFIGURE == *"TARGET"* ]]; then sdh_die "Error building OpenBLAS" else @@ -55,7 +55,7 @@ if ! (sdh_make libs netlib shared $OPENBLAS_CONFIGURE); then echo "Error building OpenBLAS" echo "Retrying building OpenBLAS: $MAKE $OPENBLAS_CONFIGURE" sdh_make clean - sdh_make libs netlib shared $OPENBLAS_CONFIGURE + sdh_make libs $OPENBLAS_CONFIGURE && sdh_make netlib $OPENBLAS_CONFIGURE && sdh_make shared $OPENBLAS_CONFIGURE fi fi From 0df3400b3d3cb672cc8848e4100f1c2927f19f2a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Tue, 7 Nov 2023 14:52:39 -0800 Subject: [PATCH 227/538] pkgs/sage-conf_pypi/tox.ini: Declare python versions to test, declare basepython of .pkg --- pkgs/sage-conf_pypi/tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/sage-conf_pypi/tox.ini b/pkgs/sage-conf_pypi/tox.ini index 5a53c75ea35..fadf9a9cc6c 100644 --- a/pkgs/sage-conf_pypi/tox.ini +++ b/pkgs/sage-conf_pypi/tox.ini @@ -1,7 +1,8 @@ [tox] -envlist = python, python-user +envlist = py39, py310, py311, py39-user, py310-user, py311-user [testenv:.pkg] +basepython = py311 passenv = MAKE # So that .homebrew-build-env will work From 11a8d350e0103224dcf71722bb1535c65162c7e1 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 8 Nov 2023 15:15:29 -0800 Subject: [PATCH 228/538] pkgs/sage-conf/.gitignore: Remove setup.cfg from here --- pkgs/sage-conf/.gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgs/sage-conf/.gitignore b/pkgs/sage-conf/.gitignore index 2f96201a1c9..2fff1627b9f 100644 --- a/pkgs/sage-conf/.gitignore +++ b/pkgs/sage-conf/.gitignore @@ -1,5 +1,4 @@ /_sage_conf/_conf.py -/setup.cfg /build /dist /*.egg-info From 6274cdc3e887508dd08cac14d14b7e3e530ab907 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Wed, 8 Nov 2023 15:57:17 -0800 Subject: [PATCH 229/538] Revert "pkgs/sage-conf/setup.cfg: Add python_requires" This reverts commit 19d1ea7f9878a387f981fbf346aa6e5b95dce8ba. --- pkgs/sage-conf/setup.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/pkgs/sage-conf/setup.cfg b/pkgs/sage-conf/setup.cfg index d74e36432c2..dac401c303d 100644 --- a/pkgs/sage-conf/setup.cfg +++ b/pkgs/sage-conf/setup.cfg @@ -9,8 +9,6 @@ author_email = sage-support@googlegroups.com url = https://www.sagemath.org [options] -python_requires = >=3.9, <3.12 - packages = _sage_conf From 5f96b24e3cfc7c77ad436c00bb92ecdbaedd1006 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 9 Nov 2023 08:27:06 +0100 Subject: [PATCH 230/538] typos --- src/sage/graphs/generic_graph.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 9e1923cc9fa..af107b74f31 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8070,17 +8070,17 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", Traceback (most recent call last): ... ValueError: parameters s, t, and use_edge_labels can not be used in - combinaiton with algorithms 'backtrack' and 'heuristic' + combination with algorithms 'backtrack' and 'heuristic' sage: G.longest_path(algorithm='heuristic', t=2) Traceback (most recent call last): ... ValueError: parameters s, t, and use_edge_labels can not be used in - combinaiton with algorithms 'backtrack' and 'heuristic' + combination with algorithms 'backtrack' and 'heuristic' sage: G.longest_path(algorithm='heuristic', use_edge_labels=True) Traceback (most recent call last): ... ValueError: parameters s, t, and use_edge_labels can not be used in - combinaiton with algorithms 'backtrack' and 'heuristic' + combination with algorithms 'backtrack' and 'heuristic' """ self._scream_if_not_simple() @@ -8095,7 +8095,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", if algorithm == 'heuristic': if s is not None or t is not None or use_edge_labels: raise ValueError("parameters s, t, and use_edge_labels can not " - "be used in combinaiton with algorithms " + "be used in combination with algorithms " "'backtrack' and 'heuristic'") # Quick improvement From 2fbaf8afc0216f318898d7066f6e318e8b7f3e96 Mon Sep 17 00:00:00 2001 From: dcoudert Date: Thu, 9 Nov 2023 08:55:01 +0100 Subject: [PATCH 231/538] deprecate algorithm backtrack --- src/sage/graphs/generic_graph.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index af107b74f31..b6d2fc13917 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -7907,8 +7907,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", * ``"MILP"`` returns an exact answer. - * ``"backtrack"`` will be renamed ``"heuristic"`` in the future. A - warning is raised when used. + * ``"backtrack"`` is renamed ``"heuristic"`` (:issue:`36574`). * ``"heuristic"`` is a randomized heuristic for finding a long path in an unweighted (di)graph. This heuristic does not take into account @@ -8064,39 +8063,38 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", sage: G = graphs.PathGraph(3) sage: P = G.longest_path(algorithm='backtrack') - doctest:...: FutureWarning: algorithm 'backtrack' will be renamed 'heuristic' in the future. + doctest:...: DeprecationWarning: algorithm 'backtrack' is deprecated. + Use algorithm 'heuristic' instead. See https://github.com/sagemath/sage/issues/36574 for details. sage: G.longest_path(algorithm='heuristic', s=0) Traceback (most recent call last): ... ValueError: parameters s, t, and use_edge_labels can not be used in - combination with algorithms 'backtrack' and 'heuristic' + combination with algorithm 'heuristic' sage: G.longest_path(algorithm='heuristic', t=2) Traceback (most recent call last): ... ValueError: parameters s, t, and use_edge_labels can not be used in - combination with algorithms 'backtrack' and 'heuristic' + combination with algorithm 'heuristic' sage: G.longest_path(algorithm='heuristic', use_edge_labels=True) Traceback (most recent call last): ... ValueError: parameters s, t, and use_edge_labels can not be used in - combination with algorithms 'backtrack' and 'heuristic' + combination with algorithm 'heuristic' """ self._scream_if_not_simple() if algorithm not in ("backtrack", "heuristic", "MILP"): raise ValueError("algorithm must be either 'backtrack', 'heuristic' or 'MILP'") if algorithm == "backtrack": - from sage.misc.superseded import warning - warning(36574, - "algorithm 'backtrack' will be renamed 'heuristic' in the future.", - FutureWarning) + from sage.misc.superseded import deprecation + deprecation(36574, "algorithm 'backtrack' is deprecated. " + "Use algorithm 'heuristic' instead.") algorithm = 'heuristic' if algorithm == 'heuristic': if s is not None or t is not None or use_edge_labels: raise ValueError("parameters s, t, and use_edge_labels can not " - "be used in combination with algorithms " - "'backtrack' and 'heuristic'") + "be used in combination with algorithm 'heuristic'") # Quick improvement if not self.is_connected(): From fe0b6255475ce182833898d0175354f6c58a33e9 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Mon, 30 Oct 2023 23:21:36 +0900 Subject: [PATCH 232/538] Add pull_from_function_field --- src/sage/schemes/curves/affine_curve.py | 168 ++++++++++++++++---- src/sage/schemes/curves/projective_curve.py | 68 +++++++- 2 files changed, 201 insertions(+), 35 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index ce8c0ff0655..194353c79c4 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -2118,9 +2118,11 @@ def function(self, f): INPUT: - - ``f`` -- an element of the coordinate ring of either the curve or its + - ``f`` -- an element of the fraction field of the coordinate ring of the curve or its ambient space. + OUTPUT: An element of the function field of this curve. + EXAMPLES:: sage: # needs sage.rings.finite_rings @@ -2161,38 +2163,76 @@ def coordinate_functions(self): """ return self._coordinate_functions + def pull_from_function_field(self, f): + """ + Return the fraction corresponding to ``f``. + + INPUT: + + - ``f`` -- an element of the function field + + OUTPUT: + + A fraction of polynomials in the coordinate ring of this curve. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: A. = AffineSpace(GF(8), 2) + sage: C = Curve(x^5 + y^5 + x*y + 1) + sage: F = C.function_field() + sage: C.pull_from_function_field(F.gen()) + y + sage: C.pull_from_function_field(F.one()) + 1 + sage: C.pull_from_function_field(F.zero()) + 0 + sage: f1 = F.gen() + sage: f2 = F.base_ring().gen() + sage: C.function(C.pull_from_function_field(f1)) == f1 + True + sage: C.function(C.pull_from_function_field(f2)) == f2 + True + """ + return self._pull_from_function_field(f) + @lazy_attribute def _nonsingular_model(self): """ Return the data of a nonsingular model of the curve. The data consists of an abstract function field `M` and a map from the - coordinate ring `R` of the ambient space of the curve into the function - field. The coordinate ring of the curve is thus the quotient of `R` by - the kernel of the map. + fraction field of the coordinate ring `R` of the ambient space of the curve to the function + field. The coordinate ring of the curve is the quotient of `R` by + the kernel of the map restricted to `R`. + TESTS:: - sage: A. = AffineSpace(GF(11), 3) sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A) sage: C._nonsingular_model (Function field in z defined by z^3 + 10*x, Ring morphism: - From: Multivariate Polynomial Ring in x, y, z - over Finite Field of size 11 + From: Fraction Field of Multivariate Polynomial Ring in x, y, z over Finite Field of size 11 To: Function field in z defined by z^3 + 10*x Defn: x |--> x y |--> z^2 - z |--> z) + z |--> z, + Ring morphism: + From: Function field in z defined by z^3 + 10*x + To: Fraction Field of Multivariate Polynomial Ring in x, y, z over Finite Field of size 11) """ + from sage.structure.sequence import Sequence + from sage.rings.fraction_field import FractionField from sage.rings.function_field.constructor import FunctionField + from sage.rings.function_field.maps import FunctionFieldRingMorphism k = self.base_ring() - I0 = self.defining_ideal() + I = self.defining_ideal() # invlex is the lex order with x < y < z for R = k[x,y,z] for instance - R = I0.parent().ring().change_ring(order='invlex') - I0 = I0.change_ring(R) + R = I.parent().ring().change_ring(order='invlex') + I0 = I.change_ring(R) n = R.ngens() names = R.variable_names() @@ -2228,6 +2268,7 @@ def _nonsingular_model(self): # syzygy for z. Now x is the generator of a rational function field F0; # y is the generator of the extension F1 of F0 by f3; z is the # generator of the extension F2 of F1 by f2. + basis = list(gbasis) syzygy = {} for i in range(n): @@ -2241,11 +2282,11 @@ def _nonsingular_model(self): basis.append(f) break - indep = [i for i in range(n) if i not in syzygy] - if len(indep) != 1: + # sanity check + indeps = [i for i in range(n) if i not in syzygy] + if len(indeps) != 1: raise TypeError("not a curve") - else: - indep = indep[0] + indep = indeps[0] F = FunctionField(k, names[indep]) coords = {indep: F.gen()} @@ -2258,20 +2299,60 @@ def _nonsingular_model(self): F = F.extension(f, names[i]) coords[i] = F.gen() - if F.base_field() is not F: # proper extension + proper_extension = F.base_field() is not F # and n is 1 + + if proper_extension: N, from_N, to_N = F.simple_model() M, from_M, to_M = N.separable_model() coordinate_functions = tuple([to_M(to_N(F(coords[i]))) for i in range(n)]) - else: # rational function field - M = F + else: + M = F # is rational function field coordinate_functions = tuple([coords[i] for i in range(n)]) - lift_to_function_field = hom(R, M, coordinate_functions) + # map to M + + FR = FractionField(I.ring()) + map_to_function_field = hom(FR, M, coordinate_functions) + + # map from M + + def convert(f, i): + if i == indep: + i = i - 1 + if i < 0: + return f._x # fraction representing rational function field element + fx = f._x # polynomial representing function field element + if not fx: + fxlist = [fx.base_ring().zero()] + else: + fxlist = fx.list() + coeffs = Sequence(convert(c, i - 1) for c in fxlist) + B = coeffs.universe() + S = B[names[i]] + return S(coeffs) + + z = M.gen() + + if proper_extension: + Z = FR(convert(from_N(from_M(z)), n - 1)) + + def evaluate(f): + coeffs = f._x.list() + v = 0 + while coeffs: + v = v * Z + coeffs.pop()._x + return FR(v) + else: + def evaluate(f): + return FR(f._x) + + map_from_function_field = FunctionFieldRingMorphism(Hom(M, FR), evaluate) # sanity check - assert all(lift_to_function_field(f).is_zero() for f in I0.gens()) + assert all(map_to_function_field(f).is_zero() for f in I.gens()) + assert map_to_function_field(map_from_function_field(z)) == z - return M, lift_to_function_field + return M, map_to_function_field, map_from_function_field @lazy_attribute def _function_field(self): @@ -2290,7 +2371,7 @@ def _function_field(self): @lazy_attribute def _lift_to_function_field(self): """ - Return the map to function field of the curve. + Return the map to the function field of the curve. TESTS:: @@ -2298,8 +2379,7 @@ def _lift_to_function_field(self): sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A) sage: C._lift_to_function_field Ring morphism: - From: Multivariate Polynomial Ring in x, y, z - over Finite Field of size 11 + From: Fraction Field of Multivariate Polynomial Ring in x, y, z over Finite Field of size 11 To: Function field in z defined by z^3 + 10*x Defn: x |--> x y |--> z^2 @@ -2321,16 +2401,34 @@ def _coordinate_functions(self): """ return self._nonsingular_model[1].im_gens() + @lazy_attribute + def _pull_from_function_field(self): + """ + Return the map from the function field of the curve. + + TESTS:: + + sage: A. = AffineSpace(GF(11), 3) + sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A) + sage: C._pull_from_function_field + Ring morphism: + From: Function field in z defined by z^3 + 10*x + To: Fraction Field of Multivariate Polynomial Ring in x, y, z over Finite Field of size 11 + """ + return self._nonsingular_model[2] + @lazy_attribute def _singularities(self): """ - Return a list of the pairs of singular closed points and the places above it. + Return a list of the pairs of a singular closed point and the places + above it. TESTS:: - sage: A. = AffineSpace(GF(7^2), 2) # needs sage.rings.finite_rings - sage: C = Curve(x^2 - x^4 - y^4) # needs sage.rings.finite_rings - sage: C._singularities # long time # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: A. = AffineSpace(GF(7^2), 2) + sage: C = Curve(x^2 - x^4 - y^4) + sage: C._singularities # long time [(Point (x, y), [Place (x, 1/x*y^3 + 1/x*y^2 + 1), Place (x, 1/x*y^3 + 1/x*y^2 + 6)])] """ @@ -2370,9 +2468,10 @@ def singular_closed_points(self): EXAMPLES:: - sage: A. = AffineSpace(GF(7^2), 2) # needs sage.rings.finite_rings - sage: C = Curve(x^2 - x^4 - y^4) # needs sage.rings.finite_rings - sage: C.singular_closed_points() # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: A. = AffineSpace(GF(7^2), 2) + sage: C = Curve(x^2 - x^4 - y^4) + sage: C.singular_closed_points() [Point (x, y)] :: @@ -2726,11 +2825,12 @@ class IntegralAffinePlaneCurve_finite_field(AffinePlaneCurve_finite_field, Integ EXAMPLES:: - sage: A. = AffineSpace(GF(8), 2) # needs sage.rings.finite_rings - sage: C = Curve(x^5 + y^5 + x*y + 1); C # needs sage.rings.finite_rings + sage: # needs sage.rings.finite_rings + sage: A. = AffineSpace(GF(8), 2) + sage: C = Curve(x^5 + y^5 + x*y + 1); C Affine Plane Curve over Finite Field in z3 of size 2^3 defined by x^5 + y^5 + x*y + 1 - sage: C.function_field() # needs sage.rings.finite_rings + sage: C.function_field() Function field in y defined by y^5 + x*y + x^5 + 1 """ _point = IntegralAffinePlaneCurvePoint_finite_field diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 5a4f9f5f4ce..1cd62149bc9 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -2325,7 +2325,13 @@ def __call__(self, *args): def function(self, f): """ - Return the function field element coerced from ``x``. + Return the function field element coerced from ``f``. + + INPUT: + + - ``f`` -- an element in the fraction field of the coordinate ring + + OUTPUT: An element of the function field EXAMPLES:: @@ -2373,6 +2379,39 @@ def coordinate_functions(self, i=None): inv = ~coords[i] return tuple([coords[j]*inv for j in range(len(coords)) if j != i]) + def pull_from_function_field(self, f): + """ + Return the fraction corresponding to ``f``. + + INPUT: + + - ``f`` -- an element of the function field + + OUTPUT: + + A fraction of homogeneous polynomials in the coordinate ring of this curve. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: P. = ProjectiveSpace(GF(4), 2) + sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5) + sage: F = C.function_field() + sage: C.pull_from_function_field(F.gen()) + z/x + sage: C.pull_from_function_field(F.one()) + 1 + sage: C.pull_from_function_field(F.zero()) + 0 + sage: f1 = F.gen() + sage: f2 = F.base_ring().gen() + sage: C.function(C.pull_from_function_field(f1)) == f1 + True + sage: C.function(C.pull_from_function_field(f2)) == f2 + True + """ + return self._pull_from_function_field(f) + @lazy_attribute def _function_field(self): """ @@ -2425,6 +2464,33 @@ def _coordinate_functions(self): coords.insert(self._open_affine_index, self._function_field.one()) return tuple(coords) + @lazy_attribute + def _pull_from_function_field(self): + """ + Return the map to the function field of the curve. + + TESTS:: + + sage: P. = ProjectiveSpace(GF(5), 2) + sage: C = Curve(y^2*z^7 - x^9 - x*z^8) + sage: F = C.function_field() + sage: f = F.random_element() + sage: C.function(C._pull_from_function_field(f)) == f + True + """ + F = self._function_field + S = self.ambient_space().coordinate_ring() + phi = self._open_affine._nonsingular_model[2] + i = self._open_affine_index + + def pull(f): + pf = phi(f) + num = S(pf.numerator()).homogenize(i) + den = S(pf.denominator()).homogenize(i) + return num / den * S.gen(i) ** (den.total_degree() - num.total_degree()) + + return pull + @lazy_attribute def _singularities(self): """ From 465bb927ec0e4bfbf46d9a029f6a21eabcd8e88c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Tue, 31 Oct 2023 10:37:16 +0900 Subject: [PATCH 233/538] Style fixes --- src/sage/schemes/curves/affine_curve.py | 22 ++++++++++++--------- src/sage/schemes/curves/projective_curve.py | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 194353c79c4..97d4bc08dd3 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -2118,8 +2118,8 @@ def function(self, f): INPUT: - - ``f`` -- an element of the fraction field of the coordinate ring of the curve or its - ambient space. + - ``f`` -- an element of the fraction field of the coordinate ring of + the curve or its ambient space. OUTPUT: An element of the function field of this curve. @@ -2202,9 +2202,9 @@ def _nonsingular_model(self): Return the data of a nonsingular model of the curve. The data consists of an abstract function field `M` and a map from the - fraction field of the coordinate ring `R` of the ambient space of the curve to the function - field. The coordinate ring of the curve is the quotient of `R` by - the kernel of the map restricted to `R`. + fraction field of the coordinate ring `R` of the ambient space of the + curve to the function field. The coordinate ring of the curve is the + quotient of `R` by the kernel of the map restricted to `R`. TESTS:: @@ -2213,14 +2213,16 @@ def _nonsingular_model(self): sage: C._nonsingular_model (Function field in z defined by z^3 + 10*x, Ring morphism: - From: Fraction Field of Multivariate Polynomial Ring in x, y, z over Finite Field of size 11 + From: Fraction Field of Multivariate Polynomial Ring in x, y, z + over Finite Field of size 11 To: Function field in z defined by z^3 + 10*x Defn: x |--> x y |--> z^2 z |--> z, Ring morphism: From: Function field in z defined by z^3 + 10*x - To: Fraction Field of Multivariate Polynomial Ring in x, y, z over Finite Field of size 11) + To: Fraction Field of Multivariate Polynomial Ring in x, y, z + over Finite Field of size 11) """ from sage.structure.sequence import Sequence from sage.rings.fraction_field import FractionField @@ -2379,7 +2381,8 @@ def _lift_to_function_field(self): sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A) sage: C._lift_to_function_field Ring morphism: - From: Fraction Field of Multivariate Polynomial Ring in x, y, z over Finite Field of size 11 + From: Fraction Field of Multivariate Polynomial Ring in x, y, z + over Finite Field of size 11 To: Function field in z defined by z^3 + 10*x Defn: x |--> x y |--> z^2 @@ -2413,7 +2416,8 @@ def _pull_from_function_field(self): sage: C._pull_from_function_field Ring morphism: From: Function field in z defined by z^3 + 10*x - To: Fraction Field of Multivariate Polynomial Ring in x, y, z over Finite Field of size 11 + To: Fraction Field of Multivariate Polynomial Ring in x, y, z + over Finite Field of size 11 """ return self._nonsingular_model[2] diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 1cd62149bc9..fcb87d9e31c 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -2331,7 +2331,7 @@ def function(self, f): - ``f`` -- an element in the fraction field of the coordinate ring - OUTPUT: An element of the function field + OUTPUT: An element of the function field. EXAMPLES:: From 64c755e5d7cb14acbb55c4aea1e8cbc9a4c15c2c Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Thu, 9 Nov 2023 21:44:47 +0900 Subject: [PATCH 234/538] Fix an example --- src/sage/schemes/curves/affine_curve.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index 97d4bc08dd3..d329b21fddf 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -2209,6 +2209,7 @@ def _nonsingular_model(self): TESTS:: + sage: A. = AffineSpace(GF(11), 3) sage: C = Curve([x*z - y^2, y - z^2, x - y*z], A) sage: C._nonsingular_model (Function field in z defined by z^3 + 10*x, From 28655bd2072d07f99535ca8f94c840b2064b20f7 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 9 Nov 2023 14:49:49 +0100 Subject: [PATCH 235/538] fix point_of_order() for l==p --- src/sage/schemes/elliptic_curves/ell_field.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 064aeeed78b..d29ae37c1ae 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -2122,7 +2122,8 @@ def ffext(poly): if not m: raise NotImplementedError('only prime-power orders are currently supported') - xpoly = E.division_polynomial(n) // E.division_polynomial(n//l) + xpoly = E.division_polynomial(n).radical() + xpoly //= E.division_polynomial(n//l).radical() if xpoly.degree() < 1: # supersingular and l == p raise ValueError('curve does not have any points of the specified order') From 36af1591299737a8acfb6a3151a59bf92ee87d13 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 9 Nov 2023 15:49:17 +0100 Subject: [PATCH 236/538] add .inseparable_degree() method --- .../elliptic_curves/ell_curve_isogeny.py | 25 +-- src/sage/schemes/elliptic_curves/hom.py | 168 +++++++++++++++--- .../schemes/elliptic_curves/hom_composite.py | 58 ++---- .../schemes/elliptic_curves/hom_frobenius.py | 55 +----- .../schemes/elliptic_curves/hom_scalar.py | 79 +++----- src/sage/schemes/elliptic_curves/hom_sum.py | 88 +++++---- .../schemes/elliptic_curves/hom_velusqrt.py | 18 +- .../elliptic_curves/weierstrass_morphism.py | 29 ++- 8 files changed, 273 insertions(+), 247 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 75d10d147d6..1ab3981b4cf 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -2879,28 +2879,19 @@ def kernel_polynomial(self): self.__init_kernel_polynomial() return self.__kernel_polynomial - def is_separable(self): + def inseparable_degree(self): r""" - Determine whether or not this isogeny is separable. + Return the inseparable degree of this isogeny. - Since :class:`EllipticCurveIsogeny` only implements - separable isogenies, this method always returns ``True``. + Since this class only implements separable isogenies, + this method always returns one. - EXAMPLES:: - - sage: E = EllipticCurve(GF(17), [0,0,0,3,0]) - sage: phi = EllipticCurveIsogeny(E, E((0,0))) - sage: phi.is_separable() - True - - :: + TESTS:: - sage: E = EllipticCurve('11a1') - sage: phi = EllipticCurveIsogeny(E, E.torsion_points()) - sage: phi.is_separable() - True + sage: EllipticCurveIsogeny.inseparable_degree(None) + 1 """ - return True + return Integer(1) def _set_pre_isomorphism(self, preWI): """ diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index fe95bb7e2b3..9133fe13691 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -674,41 +674,115 @@ def is_normalized(self): ALGORITHM: We check if :meth:`scaling_factor` returns `1`. """ - return self.scaling_factor() == 1 + return self.scaling_factor().is_one() - def is_separable(self): + def inseparable_degree(self): r""" - Determine whether or not this morphism is separable. + Return the inseparable degree of this isogeny. Implemented by child classes. For examples, see: - - :meth:`EllipticCurveIsogeny.is_separable` - - :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.is_separable` - - :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.is_separable` - - :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.is_separable` - - :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.is_separable` - - :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.is_separable` + - :meth:`EllipticCurveIsogeny.inseparable_degree` + - :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.inseparable_degree` + - :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.inseparable_degree` + - :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.inseparable_degree` + - :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.inseparable_degree` + - :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.inseparable_degree` TESTS:: sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom - sage: EllipticCurveHom.is_separable(None) + sage: EllipticCurveHom.inseparable_degree(None) Traceback (most recent call last): ... NotImplementedError: ... """ raise NotImplementedError('children must implement') - def is_surjective(self): + def is_separable(self): r""" - Determine whether or not this morphism is surjective. + Determine whether or not this morphism is a separable isogeny. - .. NOTE:: + EXAMPLES:: + + sage: E = EllipticCurve(GF(17), [0,0,0,3,0]) + sage: phi = EllipticCurveIsogeny(E, E((0,0))) + sage: phi.is_separable() + True + + :: + + sage: E = EllipticCurve('11a1') + sage: phi = EllipticCurveIsogeny(E, E.torsion_points()) + sage: phi.is_separable() + True + + :: + + sage: E = EllipticCurve(GF(31337), [0,1]) # needs sage.rings.finite_rings + sage: {f.is_separable() for f in E.automorphisms()} # needs sage.rings.finite_rings + {True} + + :: + + sage: # needs sage.rings.finite_rings + sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + sage: E = EllipticCurve(GF(7^2), [3,2]) + sage: P = E.lift_x(1) + sage: phi = EllipticCurveHom_composite(E, P); phi + Composite morphism of degree 7 = 7: + From: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 + over Finite Field in z2 of size 7^2 + To: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 + over Finite Field in z2 of size 7^2 + sage: phi.is_separable() + True + + :: + + sage: E = EllipticCurve(GF(11), [4,4]) + sage: E.scalar_multiplication(11).is_separable() + False + sage: E.scalar_multiplication(-11).is_separable() + False + sage: E.scalar_multiplication(777).is_separable() + True + sage: E.scalar_multiplication(-1).is_separable() + True + sage: E.scalar_multiplication(77).is_separable() + False + sage: E.scalar_multiplication(121).is_separable() + False - This method currently always returns ``True``, since a - non-constant map of algebraic curves must be surjective, - and Sage does not yet implement the constant zero map. - This will probably change in the future. + :: + + sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius + sage: E = EllipticCurve(GF(11), [1,1]) + sage: pi = EllipticCurveHom_frobenius(E) + sage: pi.degree() + 11 + sage: pi.is_separable() + False + sage: pi = EllipticCurveHom_frobenius(E, 0) + sage: pi.degree() + 1 + sage: pi.is_separable() + True + + :: + + sage: E = EllipticCurve(GF(17), [0,0,0,3,0]) + sage: phi = E.isogeny(E((1,2)), algorithm='velusqrt') + sage: phi.is_separable() + True + """ + if self.is_zero(): + raise ValueError('constant zero map is not an isogeny') + return self.inseparable_degree().is_one() + + def is_surjective(self): + r""" + Determine whether or not this morphism is surjective. EXAMPLES:: @@ -741,6 +815,9 @@ def is_injective(self): r""" Determine whether or not this morphism has trivial kernel. + The kernel is trivial if and only if this morphism is a + purely inseparable isogeny. + EXAMPLES:: sage: E = EllipticCurve('11a1') @@ -763,22 +840,59 @@ def is_injective(self): sage: phi = EllipticCurveIsogeny(E, E(0)) sage: phi.is_injective() True + + :: + + sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + sage: E = EllipticCurve([1,0]) + sage: phi = EllipticCurveHom_composite(E, E(0,0)) + sage: phi.is_injective() + False + sage: E = EllipticCurve_from_j(GF(3).algebraic_closure()(0)) + sage: nu = EllipticCurveHom_composite.from_factors(E.automorphisms()) + sage: nu + Composite morphism of degree 1 = 1^12: + From: Elliptic Curve defined by y^2 = x^3 + x + over Algebraic closure of Finite Field of size 3 + To: Elliptic Curve defined by y^2 = x^3 + x + over Algebraic closure of Finite Field of size 3 + sage: nu.is_injective() + True + + :: + + sage: E = EllipticCurve(GF(23), [1,0]) + sage: E.scalar_multiplication(4).is_injective() + False + sage: E.scalar_multiplication(5).is_injective() + False + sage: E.scalar_multiplication(1).is_injective() + True + sage: E.scalar_multiplication(-1).is_injective() + True + sage: E.scalar_multiplication(23).is_injective() + True + sage: E.scalar_multiplication(-23).is_injective() + True + sage: E.scalar_multiplication(0).is_injective() + False + + :: + + sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius + sage: E = EllipticCurve(GF(11), [1,1]) + sage: pi = EllipticCurveHom_frobenius(E, 5) + sage: pi.is_injective() + True """ - if not self.is_separable(): - # TODO: should implement .separable_degree() or similar - raise NotImplementedError - return self.degree() == 1 + if self.is_zero(): + return False + return self.inseparable_degree() == self.degree() def is_zero(self): r""" Check whether this elliptic-curve morphism is the zero map. - .. NOTE:: - - This function currently always returns ``True`` as Sage - does not yet implement the constant zero morphism. This - will probably change in the future. - EXAMPLES:: sage: E = EllipticCurve(j=GF(7)(0)) diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index e457c9854ee..ed87349bdcd 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -814,30 +814,6 @@ def dual(self): phis = (phi.dual() for phi in self._phis[::-1]) return EllipticCurveHom_composite.from_factors(phis) - def is_separable(self): - """ - Determine whether this composite isogeny is separable. - - A composition of isogenies is separable if and only if - all factors are. - - EXAMPLES:: - - sage: # needs sage.rings.finite_rings - sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - sage: E = EllipticCurve(GF(7^2), [3,2]) - sage: P = E.lift_x(1) - sage: phi = EllipticCurveHom_composite(E, P); phi - Composite morphism of degree 7 = 7: - From: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 - over Finite Field in z2 of size 7^2 - To: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 - over Finite Field in z2 of size 7^2 - sage: phi.is_separable() - True - """ - return all(phi.is_separable() for phi in self._phis) - def formal(self, prec=20): """ Return the formal isogeny corresponding to this composite @@ -899,29 +875,21 @@ def scaling_factor(self): """ return prod(phi.scaling_factor() for phi in self._phis) - def is_injective(self): - """ - Determine whether this composite morphism has trivial kernel. + def inseparable_degree(self): + r""" + Return the inseparable degree of this morphism. - In other words, return ``True`` if and only if ``self`` is a - purely inseparable isogeny. + Like the degree, the inseparable degree is multiplicative + under composition, so this method returns the product of + the inseparable degrees of the factors. EXAMPLES:: - sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - sage: E = EllipticCurve([1,0]) - sage: phi = EllipticCurveHom_composite(E, E(0,0)) - sage: phi.is_injective() - False - sage: E = EllipticCurve_from_j(GF(3).algebraic_closure()(0)) - sage: nu = EllipticCurveHom_composite.from_factors(E.automorphisms()) - sage: nu - Composite morphism of degree 1 = 1^12: - From: Elliptic Curve defined by y^2 = x^3 + x - over Algebraic closure of Finite Field of size 3 - To: Elliptic Curve defined by y^2 = x^3 + x - over Algebraic closure of Finite Field of size 3 - sage: nu.is_injective() - True + sage: E = EllipticCurve(j=GF(11^5).random_element()) + sage: phi = E.frobenius_isogeny(2) * E.scalar_multiplication(77) + sage: type(phi) + + sage: phi.inseparable_degree() + 1331 """ - return all(phi.is_injective() for phi in self._phis) + return prod(phi.inseparable_degree() for phi in self._phis) diff --git a/src/sage/schemes/elliptic_curves/hom_frobenius.py b/src/sage/schemes/elliptic_curves/hom_frobenius.py index fb4496aedbb..edd6180f0db 100644 --- a/src/sage/schemes/elliptic_curves/hom_frobenius.py +++ b/src/sage/schemes/elliptic_curves/hom_frobenius.py @@ -309,20 +309,6 @@ def _repr_(self): # EllipticCurveHom methods - def degree(self): - """ - Return the degree of this Frobenius isogeny. - - EXAMPLES:: - - sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius - sage: E = EllipticCurve(GF(11), [1,1]) - sage: pi = EllipticCurveHom_frobenius(E, 4) - sage: pi.degree() - 14641 - """ - return self._degree - def rational_maps(self): """ Return the explicit rational maps defining this Frobenius @@ -515,44 +501,21 @@ def dual(self): iso = find_post_isomorphism(Phi * self, scalar_mul) return iso * Phi - def is_separable(self): - """ - Determine whether or not this Frobenius isogeny is separable. - - Since Frobenius isogenies are purely inseparable, this method - returns ``True`` if and only if the degree is `1`. - - EXAMPLES:: - - sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius - sage: E = EllipticCurve(GF(11), [1,1]) - sage: pi = EllipticCurveHom_frobenius(E) - sage: pi.degree() - 11 - sage: pi.is_separable() - False - sage: pi = EllipticCurveHom_frobenius(E, 0) - sage: pi.degree() - 1 - sage: pi.is_separable() - True + def inseparable_degree(self): """ - return self._degree == 1 - - def is_injective(self): - """ - Determine whether or not this Frobenius isogeny has trivial - kernel. + Return the degree of this Frobenius isogeny. - Since Frobenius isogenies are purely inseparable, this method - always returns ``True``. + Since this class implements only purely inseparable isogenies, + the inseparable degree equals the degree. EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius sage: E = EllipticCurve(GF(11), [1,1]) - sage: pi = EllipticCurveHom_frobenius(E, 5) - sage: pi.is_injective() + sage: pi = EllipticCurveHom_frobenius(E, 4) + sage: pi.inseparable_degree() + 14641 + sage: pi.inseparable_degree() == pi.degree() True """ - return True + return self._degree diff --git a/src/sage/schemes/elliptic_curves/hom_scalar.py b/src/sage/schemes/elliptic_curves/hom_scalar.py index 66e675250f9..03f042fd830 100644 --- a/src/sage/schemes/elliptic_curves/hom_scalar.py +++ b/src/sage/schemes/elliptic_curves/hom_scalar.py @@ -452,69 +452,38 @@ def dual(self): """ return self - def is_separable(self): - """ - Determine whether this scalar-multiplication map is a - separable isogeny. (This is the case if and only if the - scalar `m` is coprime to the characteristic.) + def inseparable_degree(self): + r""" + Return the inseparable degree of this scalar-multiplication map. EXAMPLES:: - sage: E = EllipticCurve(GF(11), [4,4]) - sage: E.scalar_multiplication(11).is_separable() - False - sage: E.scalar_multiplication(-11).is_separable() - False - sage: E.scalar_multiplication(777).is_separable() - True - sage: E.scalar_multiplication(-1).is_separable() - True - sage: E.scalar_multiplication(77).is_separable() + sage: E = EllipticCurve(GF(7), [0,1]) + sage: E.is_supersingular() False - sage: E.scalar_multiplication(121).is_separable() - False - - TESTS:: - - sage: E.scalar_multiplication(0).is_separable() - Traceback (most recent call last): - ... - ValueError: [0] is not an isogeny - """ - if self._m.is_zero(): - raise ValueError('[0] is not an isogeny') - return bool(self.scaling_factor()) + sage: E.scalar_multiplication(4).inseparable_degree() + 1 + sage: E.scalar_multiplication(-7).inseparable_degree() + 7 - def is_injective(self): - """ - Determine whether this scalar multiplication defines an - injective map (over the algebraic closure). - - Equivalently, return ``True`` if and only if this scalar - multiplication is a purely inseparable isogeny. - - EXAMPLES:: + :: - sage: E = EllipticCurve(GF(23), [1,0]) - sage: E.scalar_multiplication(4).is_injective() - False - sage: E.scalar_multiplication(5).is_injective() - False - sage: E.scalar_multiplication(1).is_injective() - True - sage: E.scalar_multiplication(-1).is_injective() - True - sage: E.scalar_multiplication(23).is_injective() + sage: E = EllipticCurve(GF(7), [1,0]) + sage: E.is_supersingular() True - sage: E.scalar_multiplication(-23).is_injective() - True - sage: E.scalar_multiplication(0).is_injective() - False + sage: E.scalar_multiplication(4).inseparable_degree() + 1 + sage: E.scalar_multiplication(-7).inseparable_degree() + 49 """ - if self._m.is_zero(): - return False - p = self._domain.base_ring().characteristic() - return self._m.abs().is_power_of(p) and self._domain.is_supersingular() + p = self.base_ring().characteristic() + if not p: + return ZZ.one() + v = self._m.valuation(p) + if not v: + return ZZ.one() + rk = 1 + self._domain.is_supersingular() + return p**(rk*v) def __neg__(self): """ diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py index cfe6a7e85a6..703a8b71185 100644 --- a/src/sage/schemes/elliptic_curves/hom_sum.py +++ b/src/sage/schemes/elliptic_curves/hom_sum.py @@ -257,25 +257,17 @@ def to_isogeny_chain(self): raise ValueError('zero morphism cannot be written as a composition of isogenies') p = self.base_ring().characteristic() - insep = 0 + insep = self.inseparable_degree().valuation(p) if p else 0 + scalar = 1 #TODO Can we detect scalar factors earlier to save some extensions below? ker = [] for l,m in deg.factor(): if l == p: # possibly inseparable - try: - P = point_of_order(self.domain(), l**m) - except ValueError: - # supersingular; every p-isogeny is purely inseparable - insep = m - continue - Q = self._eval(P) - u = order_from_multiple(Q, l**m).valuation(l) - if u < m: - pt = l**u * P - pt.set_order(l**(m-u)) - ker.append(pt) - insep = u + if insep < m: + # kernel of the separable p-power part is unique + P = point_of_order(self.domain(), p**(m-insep)) + ker.append(P) continue # F = self.domain().division_field(l**m) #FIXME this can be used once #35936 is done; workaround below @@ -616,29 +608,59 @@ def dual(self): psi.dual.set_cache(self) return psi - def is_separable(self): + @cached_method + def inseparable_degree(self): r""" - Test whether this sum morphism is a separable isogeny. + Compute the inseparable degree of this sum morphism. EXAMPLES:: - sage: E = EllipticCurve(GF(5^2), [0,1]) - sage: m2 = E.scalar_multiplication(2) + sage: E = EllipticCurve(GF(7), [0,1]) sage: m3 = E.scalar_multiplication(3) - sage: m2.is_separable() - True - sage: E.frobenius() - -5 - sage: (m2 + m3).is_separable() - False - sage: (m2 - m2).is_separable() - Traceback (most recent call last): - ... - ValueError: zero morphism is not an isogeny + sage: m3.inseparable_degree() + 1 + sage: m4 = E.scalar_multiplication(4) + sage: m7 = m3 + m4; m7 + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 + To: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 + Via: (Scalar-multiplication endomorphism [3] of Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7, Scalar-multiplication endomorphism [4] of Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7) + sage: m7.degree() + 49 + sage: m7.inseparable_degree() + 7 + + A supersingular example:: + + sage: E = EllipticCurve(GF(7), [1,0]) + sage: m3 = E.scalar_multiplication(3) + sage: m3.inseparable_degree() + 1 + sage: m4 = E.scalar_multiplication(4) + sage: m7 = m3 + m4; m7 + Sum morphism: + From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 + To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7 + Via: (Scalar-multiplication endomorphism [3] of Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7, Scalar-multiplication endomorphism [4] of Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 7) + sage: m7.inseparable_degree() + 49 """ - deg = self.degree() - if deg.is_zero(): + if self.is_zero(): raise ValueError('zero morphism is not an isogeny') - if not self.domain().base_field().characteristic().divides(deg): - return True - return self.to_isogeny_chain().is_separable() + + p = self.base_ring().characteristic() + if not p: + return ZZ.one() + + m = self.degree().valuation(p) + if not m: + return ZZ.one() + + try: + P = point_of_order(self.domain(), p**m) + except ValueError: + # supersingular; every p-isogeny is purely inseparable + return p**m + + Q = self._eval(P) + return order_from_multiple(Q, p**m) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 4bc84d944f8..fbe4887dbae 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -1173,21 +1173,21 @@ def scaling_factor(self): """ return self._pre_iso.scaling_factor() * self._post_iso.scaling_factor() - def is_separable(self): + def inseparable_degree(self): r""" - Determine whether or not this isogeny is separable. + Return the inseparable degree of this square-root Vélu + isogeny. Since :class:`EllipticCurveHom_velusqrt` only implements - separable isogenies, this method always returns ``True``. + separable isogenies, this method always returns one. - EXAMPLES:: + TESTS:: - sage: E = EllipticCurve(GF(17), [0,0,0,3,0]) - sage: phi = E.isogeny(E((1,2)), algorithm='velusqrt') - sage: phi.is_separable() - True + sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + sage: EllipticCurveHom_velusqrt.inseparable_degree(None) + 1 """ - return True + return Integer(1) def _random_example_for_testing(): diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index 57ff015a2b2..d6027e2d195 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -849,21 +849,6 @@ def kernel_polynomial(self): """ return self._poly_ring(1) - def is_separable(self): - r""" - Determine whether or not this isogeny is separable. - - Since :class:`WeierstrassIsomorphism` only implements - isomorphisms, this method always returns ``True``. - - EXAMPLES:: - - sage: E = EllipticCurve(GF(31337), [0,1]) # needs sage.rings.finite_rings - sage: {f.is_separable() for f in E.automorphisms()} # needs sage.rings.finite_rings - {True} - """ - return True - def dual(self): """ Return the dual isogeny of this isomorphism. @@ -956,6 +941,20 @@ def scaling_factor(self): """ return self.u + def inseparable_degree(self): + r""" + Return the inseparable degree of this Weierstrass isomorphism. + + For isomorphisms, this method always returns one. + + TESTS:: + + sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism + sage: WeierstrassIsomorphism.inseparable_degree(None) + 1 + """ + return Integer(1) + def identity_morphism(E): r""" From 7b4199f51b85bed8d1975d4a6897d0da6ac623ad Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Thu, 9 Nov 2023 16:36:23 +0100 Subject: [PATCH 237/538] streamline use of Cauchy-Schwarz bound for degree computation --- src/sage/schemes/elliptic_curves/hom_sum.py | 62 ++++++++++++--------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py index 703a8b71185..15db537f6c8 100644 --- a/src/sage/schemes/elliptic_curves/hom_sum.py +++ b/src/sage/schemes/elliptic_curves/hom_sum.py @@ -45,8 +45,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.sequence import Sequence -from sage.arith.misc import integer_floor, gcd -from sage.functions.other import sqrt +from sage.arith.misc import gcd from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring import polygen @@ -325,24 +324,24 @@ def to_isogeny_chain(self): # EllipticCurveHom methods - def _degree_bound(self): + def _degree_bounds(self): r""" - Return an upper bound on the degree of this sum morphism. - - ALGORITHM: Induction using the bound - `|\deg(f+g) - \deg(f) - \deg(g)| \leq 2\sqrt{\deg(f)\cdot\deg(g)}`; - see for instance Lemma V.1.2 of [Sil2009]_. + Return a lower and upper bound on the degree of this sum morphism. EXAMPLES:: - sage: E = EllipticCurve(GF(101), [5,5]) - sage: phi = E.isogenies_prime_degree(7)[0] - sage: (phi + phi)._degree_bound() - 28 - sage: (phi + phi).degree() - 28 - sage: (phi - phi)._degree_bound() - 28 + sage: E = EllipticCurve(GF(307), [5,5]) + sage: phi = E.isogenies_prime_degree(3)[0]; phi + Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 307 to Elliptic Curve defined by y^2 = x^3 + 227*x + 163 over Finite Field of size 307 + sage: psi = next(iso*psi for psi in E.isogenies_prime_degree(43) + ....: for iso in psi.codomain().isomorphisms(phi.codomain())); psi + Isogeny of degree 43 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 307 to Elliptic Curve defined by y^2 = x^3 + 227*x + 163 over Finite Field of size 307 + sage: (phi + psi)._degree_bounds() + (24, 68) + sage: (phi + psi).degree() + 61 + sage: (phi - phi)._degree_bounds() + (0, 12) sage: (phi - phi).degree() 0 @@ -351,15 +350,25 @@ def _degree_bound(self): sage: E = EllipticCurve(GF(443), [1,1]) sage: pi = E.frobenius_endomorphism() sage: m1 = E.scalar_multiplication(1) - sage: (pi - m1)._degree_bound() - 486 + sage: (pi - m1)._degree_bounds() + (402, 486) + sage: (pi - m1)._degree_bounds() == Hasse_bounds(443) + True sage: (pi - m1).degree() 433 + + ALGORITHM: Repeated application of the Cauchy-Schwarz inequality, + here in the form + `|\deg(f+g) - \deg(f) - \deg(g)| \leq 2\sqrt{\deg(f)\cdot\deg(g)}`. + See for instance Lemma V.1.2 of [Sil2009]_. """ - B = ZZ(0) + lo, hi = ZZ.zero(), ZZ.zero() for phi in self._phis: - B += phi.degree() + 2*sqrt(B * phi.degree()) - return integer_floor(B) + m = (hi * phi.degree()).isqrt() + hi += phi.degree() + 2*m + lo += phi.degree() - 2*m + lo = max(lo, 0) + return lo, hi def _compute_degree(self): r""" @@ -406,10 +415,11 @@ def _compute_degree(self): # compute the kernel polynomial using the addition formulas? from sage.rings.finite_rings.integer_mod import Mod - M = self._degree_bound() + 1 - deg = Mod(0,1) + lo, hi = self._degree_bounds() + M = hi - lo + 1 + rem = Mod(0,1) for l in Primes(): - if deg.modulus() >= M: + if rem.modulus() >= M: break try: P = point_of_order(self._domain, l) @@ -418,9 +428,9 @@ def _compute_degree(self): Q = self.dual()._eval(self._eval(P)) d = discrete_log(Q, P, ord=l, operation='+') - deg = deg.crt(Mod(d, l)) + rem = rem.crt(Mod(d-lo, l)) - self._degree = ZZ(deg) + self._degree = lo + rem.lift() self.dual()._degree = self._degree @staticmethod From a2e1aae2baf923a8329748f7fb9d219c59f59cfe Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 10 Nov 2023 09:51:51 +0100 Subject: [PATCH 238/538] some tiny docstring corrections --- src/sage/schemes/elliptic_curves/hom_frobenius.py | 2 +- src/sage/schemes/elliptic_curves/hom_sum.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom_frobenius.py b/src/sage/schemes/elliptic_curves/hom_frobenius.py index edd6180f0db..0c1254e15b0 100644 --- a/src/sage/schemes/elliptic_curves/hom_frobenius.py +++ b/src/sage/schemes/elliptic_curves/hom_frobenius.py @@ -503,7 +503,7 @@ def dual(self): def inseparable_degree(self): """ - Return the degree of this Frobenius isogeny. + Return the inseparable degree of this Frobenius isogeny. Since this class implements only purely inseparable isogenies, the inseparable degree equals the degree. diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py index 15db537f6c8..6660035634d 100644 --- a/src/sage/schemes/elliptic_curves/hom_sum.py +++ b/src/sage/schemes/elliptic_curves/hom_sum.py @@ -202,8 +202,8 @@ def summands(self): def to_isogeny_chain(self): r""" Convert this formal sum of elliptic-curve morphisms into a - :class:`EllipticCurveHom_composite` object representing the - same morphism. + :class:`~sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite` + object representing the same morphism. EXAMPLES:: @@ -466,7 +466,7 @@ def degree(self): r""" Return the degree of this sum morphism. - EXAMPLES: + EXAMPLES:: sage: E = EllipticCurve(GF(101), [5,5]) sage: phi = E.isogenies_prime_degree(7)[0] From fbe441ef29fc8cab483337837dc24215a35f048d Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 10 Nov 2023 09:59:31 +0100 Subject: [PATCH 239/538] add .separable_degree() to complement .inseparable_degree() --- src/sage/schemes/elliptic_curves/hom.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 9133fe13691..fb7855993ea 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -699,6 +699,28 @@ def inseparable_degree(self): """ raise NotImplementedError('children must implement') + def separable_degree(self): + r""" + Return the separable degree of this isogeny. + + The separable degree is the result of dividing the :meth:`degree` + by the :meth:`inseparable_degree`. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(11), [5,5]) + sage: E.is_supersingular() + False + sage: E.scalar_multiplication(-77).separable_degree() + 539 + sage: E = EllipticCurve(GF(11), [5,0]) + sage: E.is_supersingular() + True + sage: E.scalar_multiplication(-77).separable_degree() + 49 + """ + return self.degree() // self.inseparable_degree() + def is_separable(self): r""" Determine whether or not this morphism is a separable isogeny. @@ -887,7 +909,7 @@ def is_injective(self): """ if self.is_zero(): return False - return self.inseparable_degree() == self.degree() + return self.separable_degree().is_one() def is_zero(self): r""" From 560bf2a2017b7049eb51aa3216d563d8da1cf66a Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 10 Nov 2023 15:22:58 +0100 Subject: [PATCH 240/538] n-division polynomial has repeated roots when p|n --- src/sage/schemes/elliptic_curves/ell_field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 0d27c622b7a..ed052e42f0b 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1049,7 +1049,7 @@ def division_field(self, n, names='t', map=False, **kwds): verbose("Adjoining X-coordinates of %s-torsion points" % n) F = self.base_ring() - f = self.division_polynomial(n) + f = self.division_polynomial(n).radical() if n == 2 or f.is_constant(): # For n = 2, the division field is the splitting field of From dfd4aa53824b9651c2139ed4387b85734d57b137 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Fri, 10 Nov 2023 15:29:19 +0100 Subject: [PATCH 241/538] "fix" doctest for 32-bit machines --- src/sage/schemes/elliptic_curves/ell_field.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index ed052e42f0b..eeb37db72ed 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -977,7 +977,7 @@ def division_field(self, n, names='t', map=False, **kwds): sage: K. = NumberField(x^2 + 1) sage: E = EllipticCurve([0,0,0,0,i]) sage: L,emb = E.division_field(6, names='b', map=True); L - Number Field in b with defining polynomial x^24 + 12*x^23 + 66*x^22 - 504*x^21 + 92415*x^20 + 1372020*x^19 + 9791248*x^18 + 9161712*x^17 + 2248687014*x^16 + 39282444252*x^15 + 319379172870*x^14 + 1647604458936*x^13 + 6124888492503*x^12 + 17596271352348*x^11 + 40654930682496*x^10 + 76552797892176*x^9 + 116296878586974*x^8 + 139157022368196*x^7 + 127681305928690*x^6 + 87539428627680*x^5 + 43598049444279*x^4 + 15182945758692*x^3 + 3479289119772*x^2 + 468890060424*x + 28234163953 + Number Field in b with defining polynomial x^24 + 12*x^23 + ... sage: E.change_ring(emb).torsion_subgroup().invariants() (6, 6) From e349b0024996e4ac4878d70a0a34ae6b742e88c5 Mon Sep 17 00:00:00 2001 From: Release Manager Date: Fri, 10 Nov 2023 16:41:57 +0100 Subject: [PATCH 242/538] Updated SageMath version to 10.2.rc1 --- CITATION.cff | 4 ++-- 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_bliss/install-requires.txt | 2 +- build/pkgs/sagemath_categories/install-requires.txt | 2 +- build/pkgs/sagemath_coxeter3/install-requires.txt | 2 +- build/pkgs/sagemath_environment/install-requires.txt | 2 +- build/pkgs/sagemath_mcqd/install-requires.txt | 2 +- build/pkgs/sagemath_meataxe/install-requires.txt | 2 +- build/pkgs/sagemath_objects/install-requires.txt | 2 +- build/pkgs/sagemath_repl/install-requires.txt | 2 +- build/pkgs/sagemath_sirocco/install-requires.txt | 2 +- build/pkgs/sagemath_tdlib/install-requires.txt | 2 +- pkgs/sage-conf/VERSION.txt | 2 +- pkgs/sage-conf_conda/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-bliss/VERSION.txt | 2 +- pkgs/sagemath-categories/VERSION.txt | 2 +- pkgs/sagemath-coxeter3/VERSION.txt | 2 +- pkgs/sagemath-environment/VERSION.txt | 2 +- pkgs/sagemath-mcqd/VERSION.txt | 2 +- pkgs/sagemath-meataxe/VERSION.txt | 2 +- pkgs/sagemath-objects/VERSION.txt | 2 +- pkgs/sagemath-repl/VERSION.txt | 2 +- pkgs/sagemath-sirocco/VERSION.txt | 2 +- pkgs/sagemath-tdlib/VERSION.txt | 2 +- src/VERSION.txt | 2 +- src/bin/sage-version.sh | 6 +++--- src/sage/version.py | 6 +++--- 38 files changed, 45 insertions(+), 45 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index bcd3dad6665..b1b171fb1a1 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,8 +4,8 @@ title: SageMath abstract: SageMath is a free open-source mathematics software system. authors: - name: "The SageMath Developers" -version: 10.2.rc0 +version: 10.2.rc1 doi: 10.5281/zenodo.593563 -date-released: 2023-11-05 +date-released: 2023-11-10 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/VERSION.txt b/VERSION.txt index a43284eebe1..8ceae8bb576 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.2.rc0, Release Date: 2023-11-05 +SageMath version 10.2.rc1, Release Date: 2023-11-10 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index f7a9e8a1ba6..cabeaab3b1e 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=e965180c957a340bb04576df39802f3a36d340e7 -md5=932bfcea357845fa9610dc698e2390d3 -cksum=2852244160 +sha1=1be054f67f0d283b5eb57e6a6b06383a5418dd1a +md5=d14e84540b8f76777d225fa90fc8fba9 +cksum=3781778115 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 00dc1d6c929..1ef35d3a00f 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -fb5b09d7f749e15c38ecb4ffe2de7b398e37f73f +81bf4e52c662db7167c3955c93308c4a6bdb850c diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 4b66d1b0602..326aa7578ec 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 ~= 10.2rc0 +sage-conf ~= 10.2rc1 diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index cebed4e3b62..de534e08518 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 ~= 10.2rc0 +sage-docbuild ~= 10.2rc1 diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 1631564eec7..3c0a80511a3 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 ~= 10.2rc0 +sage-setup ~= 10.2rc1 diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index 628374d5f1a..4a13b95c8f6 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 ~= 10.2rc0 +sage-sws2rst ~= 10.2rc1 diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index 6004e85c25d..9dd84a6d4d7 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 -sagemath-standard ~= 10.2rc0 +sagemath-standard ~= 10.2rc1 diff --git a/build/pkgs/sagemath_bliss/install-requires.txt b/build/pkgs/sagemath_bliss/install-requires.txt index 5ea4526cc33..c66665c1f4d 100644 --- a/build/pkgs/sagemath_bliss/install-requires.txt +++ b/build/pkgs/sagemath_bliss/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-bliss ~= 10.2rc0 +sagemath-bliss ~= 10.2rc1 diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index 1d37a18c187..a1695d082b4 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 ~= 10.2rc0 +sagemath-categories ~= 10.2rc1 diff --git a/build/pkgs/sagemath_coxeter3/install-requires.txt b/build/pkgs/sagemath_coxeter3/install-requires.txt index 8d6115b1868..b9db4ef19c8 100644 --- a/build/pkgs/sagemath_coxeter3/install-requires.txt +++ b/build/pkgs/sagemath_coxeter3/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-coxeter3 ~= 10.2rc0 +sagemath-coxeter3 ~= 10.2rc1 diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index c870e97dca1..f704a57eb7e 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 ~= 10.2rc0 +sagemath-environment ~= 10.2rc1 diff --git a/build/pkgs/sagemath_mcqd/install-requires.txt b/build/pkgs/sagemath_mcqd/install-requires.txt index cff0dac0026..947642f6baf 100644 --- a/build/pkgs/sagemath_mcqd/install-requires.txt +++ b/build/pkgs/sagemath_mcqd/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-mcqd ~= 10.2rc0 +sagemath-mcqd ~= 10.2rc1 diff --git a/build/pkgs/sagemath_meataxe/install-requires.txt b/build/pkgs/sagemath_meataxe/install-requires.txt index 464942fef75..b05223e6735 100644 --- a/build/pkgs/sagemath_meataxe/install-requires.txt +++ b/build/pkgs/sagemath_meataxe/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-meataxe ~= 10.2rc0 +sagemath-meataxe ~= 10.2rc1 diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index 663b7d78f8b..8245904bf01 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 ~= 10.2rc0 +sagemath-objects ~= 10.2rc1 diff --git a/build/pkgs/sagemath_repl/install-requires.txt b/build/pkgs/sagemath_repl/install-requires.txt index 917144d154c..83c797f99a3 100644 --- a/build/pkgs/sagemath_repl/install-requires.txt +++ b/build/pkgs/sagemath_repl/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-repl ~= 10.2rc0 +sagemath-repl ~= 10.2rc1 diff --git a/build/pkgs/sagemath_sirocco/install-requires.txt b/build/pkgs/sagemath_sirocco/install-requires.txt index 896662f1b95..f828bbac488 100644 --- a/build/pkgs/sagemath_sirocco/install-requires.txt +++ b/build/pkgs/sagemath_sirocco/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-sirocco ~= 10.2rc0 +sagemath-sirocco ~= 10.2rc1 diff --git a/build/pkgs/sagemath_tdlib/install-requires.txt b/build/pkgs/sagemath_tdlib/install-requires.txt index c26900d9abf..cd0d3390b93 100644 --- a/build/pkgs/sagemath_tdlib/install-requires.txt +++ b/build/pkgs/sagemath_tdlib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-tdlib ~= 10.2rc0 +sagemath-tdlib ~= 10.2rc1 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sage-conf_conda/VERSION.txt b/pkgs/sage-conf_conda/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sage-conf_conda/VERSION.txt +++ b/pkgs/sage-conf_conda/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/src/VERSION.txt b/src/VERSION.txt index 7694f7787b5..a9591a7f98d 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.2.rc0 +10.2.rc1 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index d6b42fe389d..6ba84d36e70 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='10.2.rc0' -SAGE_RELEASE_DATE='2023-11-05' -SAGE_VERSION_BANNER='SageMath version 10.2.rc0, Release Date: 2023-11-05' +SAGE_VERSION='10.2.rc1' +SAGE_RELEASE_DATE='2023-11-10' +SAGE_VERSION_BANNER='SageMath version 10.2.rc1, Release Date: 2023-11-10' diff --git a/src/sage/version.py b/src/sage/version.py index 9d384e5af6e..087d777c94b 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 = '10.2.rc0' -date = '2023-11-05' -banner = 'SageMath version 10.2.rc0, Release Date: 2023-11-05' +version = '10.2.rc1' +date = '2023-11-10' +banner = 'SageMath version 10.2.rc1, Release Date: 2023-11-10' From 429555a926b20d83ca89cd3531d38945d3e6403d Mon Sep 17 00:00:00 2001 From: Release Manager Date: Fri, 10 Nov 2023 16:54:59 +0100 Subject: [PATCH 243/538] Updated SageMath version to 10.2.rc1 --- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index cabeaab3b1e..f3165c40860 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=1be054f67f0d283b5eb57e6a6b06383a5418dd1a -md5=d14e84540b8f76777d225fa90fc8fba9 -cksum=3781778115 +sha1=75fe450806e89ce82978f9167b664d3e403d9af9 +md5=26211fca17d4d912cc11f22f353684b1 +cksum=1423896271 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 1ef35d3a00f..20a74069b66 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -81bf4e52c662db7167c3955c93308c4a6bdb850c +e349b0024996e4ac4878d70a0a34ae6b742e88c5 From 0c801304bf2435a606250c2ddd0a7b73557c7c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Thu, 26 Oct 2023 10:51:08 -0300 Subject: [PATCH 244/538] Fix bug in QF.find_primitive_p_divisible_vector__next When the vector [0,...,0,1] is a zero mod p, it was missed from the iteration. Fix by check and return it if this is the case. A doctest triggering the bug is included. --- src/sage/quadratic_forms/quadratic_form__neighbors.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/sage/quadratic_forms/quadratic_form__neighbors.py b/src/sage/quadratic_forms/quadratic_form__neighbors.py index fb781e20122..9b9b62a0689 100644 --- a/src/sage/quadratic_forms/quadratic_form__neighbors.py +++ b/src/sage/quadratic_forms/quadratic_form__neighbors.py @@ -74,6 +74,10 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v (1, 0) sage: v = Q.find_primitive_p_divisible_vector__next(5, v); v + sage: v = Q.find_primitive_p_divisible_vector__next(2) ; v + (0, 1) + sage: v = Q.find_primitive_p_divisible_vector__next(2, v) ; v + (1, 0) sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1])) sage: v = Q.find_primitive_p_divisible_vector__next(2) sage: Q(v) @@ -83,6 +87,9 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): n = self.dim() if v is None: w = vector(ZZ, [0] * (n - 1) + [1]) + a = self(w) + if a in ZZ and (a % p == 0): + return w else: w = deepcopy(v) From e773be6a959511fff1e1ebb78b5e34e82f6bdee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Thu, 26 Oct 2023 10:57:26 -0300 Subject: [PATCH 245/538] Add return_matrix option for QF.find_p_neighbor_from_vec Similar to QF.is_globally_equivalent_to, etc. --- .../quadratic_form__neighbors.py | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/sage/quadratic_forms/quadratic_form__neighbors.py b/src/sage/quadratic_forms/quadratic_form__neighbors.py index 9b9b62a0689..ec853cd52ef 100644 --- a/src/sage/quadratic_forms/quadratic_form__neighbors.py +++ b/src/sage/quadratic_forms/quadratic_form__neighbors.py @@ -139,7 +139,7 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): return w -def find_p_neighbor_from_vec(self, p, y): +def find_p_neighbor_from_vec(self, p, y, return_matrix=False): r""" Return the `p`-neighbor of ``self`` defined by ``y``. @@ -154,25 +154,32 @@ def find_p_neighbor_from_vec(self, p, y): - ``p`` -- a prime number - ``y`` -- a vector with `q(y) \in p \ZZ` - ``odd`` -- (default: ``False``) if `p=2`, return also odd neighbors + - ``return_matrix`` -- (boolean, default ``False``) return + the transformation matrix instead of the quadratic form EXAMPLES:: + sage: # needs sage.libs.pari sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: v = vector([0,2,1,1]) - sage: X = Q.find_p_neighbor_from_vec(3, v); X # needs sage.libs.pari + sage: X = Q.find_p_neighbor_from_vec(3, v); X Quadratic form in 4 variables over Integer Ring with coefficients: [ 1 0 0 0 ] [ * 1 4 4 ] [ * * 5 12 ] [ * * * 9 ] + sage: B = Q.find_p_neighbor_from_vec(3, v, return_matrix=True) + sage: Q(B) == X + True Since the base ring and the domain are not yet separate, for rational, half integral forms we just pretend the base ring is `\ZZ`:: + sage: # needs sage.libs.pari sage: Q = QuadraticForm(QQ, matrix.diagonal([1,1,1,1])) sage: v = vector([1,1,1,1]) - sage: Q.find_p_neighbor_from_vec(2, v) # needs sage.libs.pari + sage: Q.find_p_neighbor_from_vec(2, v) Quadratic form in 4 variables over Rational Field with coefficients: [ 1/2 1 1 1 ] [ * 1 1 2 ] @@ -234,9 +241,12 @@ def find_p_neighbor_from_vec(self, p, y): # by definition this is the p-neighbor of L at y # assert B.det().abs() == 1 - QF = self.parent() - Gnew = (B*G*B.T).change_ring(R) - return QF(Gnew) + if return_matrix: + return B.T + else: + QF = self.parent() + Gnew = (B*G*B.T).change_ring(R) + return QF(Gnew) def neighbor_iteration(seeds, p, mass=None, max_classes=ZZ(10)**3, From 522edd143dd44697818fe156a2be1f24f545ca88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Wed, 8 Nov 2023 18:36:33 -0300 Subject: [PATCH 246/538] Fix bug in QF.ternary.extend() This breaks TernaryQF.find_p_neighbor_from_vec(). --- src/sage/quadratic_forms/ternary.pyx | 19 +++++++++++++++++++ src/sage/quadratic_forms/ternary_qf.py | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/src/sage/quadratic_forms/ternary.pyx b/src/sage/quadratic_forms/ternary.pyx index 28dd9514c30..6e7c4389083 100644 --- a/src/sage/quadratic_forms/ternary.pyx +++ b/src/sage/quadratic_forms/ternary.pyx @@ -955,7 +955,26 @@ def extend(v): [ 30 0 -7] sage: M.det() 2 + + TESTS:: + + sage: M = matrix(3, extend( (0, 0, 1) )) + sage: M.det() + 1 + sage: M.column(0) + (0, 0, 1) + sage: M = matrix(3, extend( (0, 0, -2) )) + sage: M.det() + 2 + sage: M.column(0) + (0, 0, -2) """ + if v[0] == v[1] == 0: + if v[2] < 0: + return v[0], 0, 1, v[1], 1, 0, v[2], 0, 0 + else: + return v[0], 1, 0, v[1], 0, 1, v[2], 0, 0 + b1 = xgcd(v[0], v[1]) b2 = xgcd(b1[1], b1[2]) b3 = xgcd(b1[0], v[2]) diff --git a/src/sage/quadratic_forms/ternary_qf.py b/src/sage/quadratic_forms/ternary_qf.py index fa4499566a9..2f3a57fa713 100644 --- a/src/sage/quadratic_forms/ternary_qf.py +++ b/src/sage/quadratic_forms/ternary_qf.py @@ -918,6 +918,13 @@ def find_p_neighbor_from_vec(self, p, v, mat=False): [ 0 -3/11 13/11] sage: Q(M) == Q11 True + + Test that it works with (0, 0, 1):: + + sage: Q.find_p_neighbor_from_vec(3, (0,0,1)) + Ternary quadratic form with integer coefficients: + [1 3 3] + [-2 0 -1] """ if mat: q, M = _find_p_neighbor_from_vec(self._a, self._b, self._c, self._r, self._s, self._t, p, v, mat) From 5a755e950d035edb48242409131dd31130071001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Fri, 10 Nov 2023 19:56:05 -0300 Subject: [PATCH 247/538] Fix ssl timeout in testing internet feature --- src/sage/features/internet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/internet.py b/src/sage/features/internet.py index f1eb000fe92..576b0136926 100644 --- a/src/sage/features/internet.py +++ b/src/sage/features/internet.py @@ -56,7 +56,7 @@ def _is_present(self): try: urlopen(req, timeout=1, context=default_context()) return FeatureTestResult(self, True) - except urllib.error.URLError: + except (urllib.error.URLError, TimeoutError): return FeatureTestResult(self, False) From 70036fb879831adce7a82906a6a1b6f3a7d48547 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 6 Nov 2023 18:51:58 +0000 Subject: [PATCH 248/538] shift the upper bound for implemented matrices to 1200 also, list unknown orders of (skew) Hadamard matrices in the corresponding docstring --- src/sage/combinat/matrices/hadamard_matrix.py | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 908a3bec603..d6477decec6 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -31,21 +31,23 @@ of `4`. The module below implements constructions of Hadamard and skew Hadamard matrices -for all known orders `\le 1000`, plus some more greater than `1000`. It also +for all known orders `\le 1200`, plus some more greater than `1200`. It also allows you to pull a Hadamard matrix from the database at [SloaHada]_. The following code will test that a construction for all known orders `\le 4k` -is implemented. The assertion above can be verified by setting ``k=250`` +is implemented. The assertion above can be verified by setting ``k=300`` (note that it will take a long time to run):: sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix, ....: skew_hadamard_matrix, is_hadamard_matrix, ....: is_skew_hadamard_matrix) sage: k = 20 - sage: unknown_hadamard = [668, 716, 892] + sage: unknown_hadamard = [668, 716, 892, 1132] sage: unknown_skew_hadamard = [356, 404, 428, 476, 596, 612, 668, 708, 712, 716, ....: 764, 772, 804, 808, 820, 836, 856, 892, 900, 916, - ....: 932, 940, 952, 980, 996] + ....: 932, 940, 952, 980, 996, 1004, 1012, 1028, 1036, + ....: 1044, 1060, 1076, 1100, 1108, 1132, 1140, 1148, + ....: 1156, 1180, 1192, 1196] sage: for n in range(1, k+1): ....: if 4*n not in unknown_hadamard: ....: H = hadamard_matrix(4*n, check=False) @@ -58,7 +60,7 @@ - David Joyner (2009-05-17): initial version - Matteo Cati (2023-03-18): implemented more constructions for Hadamard and skew - Hadamard matrices, to cover all known orders up to 1000. + Hadamard matrices, to cover all known orders up to 1200. REFERENCES: @@ -1641,8 +1643,8 @@ def hadamard_matrix(n, existence=False, check=True): r""" Tries to construct a Hadamard matrix using the available methods. - Currently all orders `\le 1000` for which a construction is - known are implemented. For `n > 1000`, only some orders are available. + Currently all orders `\le 1200` for which a construction is + known are implemented. For `n > 1200`, only some orders are available. INPUT: @@ -3055,8 +3057,8 @@ def skew_hadamard_matrix(n, existence=False, skew_normalize=True, check=True): Tries to construct a skew Hadamard matrix. A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix - and `-S=S^\top`. Currently all orders `\le 1000` for which a construction is - known are implemented. For `n > 1000`, only some orders are available. + and `-S=S^\top`. Currently all orders `\le 1200` for which a construction is + known are implemented. For `n > 1200`, only some orders are available. INPUT: From 780c3024f3b38eb03b2646ea291fda6ee800eb86 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 6 Nov 2023 19:07:36 +0000 Subject: [PATCH 249/538] add a reference to arxiv preprint Cati & Pasechnik --- src/doc/en/reference/references/index.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index d9f406d055d..697c50a6bcf 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -1373,6 +1373,10 @@ REFERENCES: for closed Riemannian manifolds*, Ann. of Math. (2) 45 (1944), 747–752. +.. [CP2023] \M. Cati and D.V. Pasechnik. + *Implementing Hadamard Matrices in SageMath*. + Preprint, :arxiv:`2306.16812`, (2023). + .. [CQ2019] \A. Cassella and C. Quadrelli. *Right-angled Artin groups and enhanced Koszul properties*. Preprint, :arxiv:`1907.03824`, (2019). From 93e987308a233e004c05512e34752a28e537e968 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Mon, 6 Nov 2023 19:09:49 +0000 Subject: [PATCH 250/538] refer to [CP2023] --- src/sage/combinat/matrices/hadamard_matrix.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index d6477decec6..0693941851e 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -69,6 +69,8 @@ - [HadaWiki]_ - [Hora]_ + +- [CP2023]_ """ # ***************************************************************************** From fad25bbfe57cb0289a49f9d4eda25dccc4976c09 Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 10 Nov 2023 16:55:54 -0800 Subject: [PATCH 251/538] tox.ini (conda-python{3.9,3.10,3.11,3.12}): Reorder so that the _python3.... package is actually installed --- tox.ini | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tox.ini b/tox.ini index c039103f422..438c1ca8763 100644 --- a/tox.ini +++ b/tox.ini @@ -559,22 +559,21 @@ setenv = CONFIG_CONFIGURE_ARGS_1=--with-system-python3=yes python3_spkg: CONFIG_CONFIGURE_ARGS_1=--without-system-python3 python3.9,python3.10,python3.11,python3.12: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python{env:PYTHON_MAJOR}.{env:PYTHON_MINOR} - python3.9,python3.10,python3.11,python3.12: EXTRA_SAGE_PACKAGES_5=_python{env:PYTHON_MAJOR}.{env:PYTHON_MINOR} _bootstrap liblzma bzip2 libffi libpng zlib # As of 2023-9, Xcode 15.0.0, this is Python 3.9.6. macos-python3_xcode: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/usr/bin/python3 - macos-python3_xcode: EXTRA_SAGE_PACKAGES_5=_bootstrap liblzma bzip2 libffi libpng zlib macos-{python3_xcode,nohomebrew}-{python3.9}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # Homebrew keg installs homebrew-{python3.9,python3.10,python3.11,python3.12}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python={env:HOMEBREW}/opt/python@{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # Installers from https://www.python.org/downloads/macos/ (must manually download and install) macos-python3_pythonorg: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Frameworks/Python.framework/Versions/{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 - macos-python3_pythonorg: EXTRA_SAGE_PACKAGES_5=_bootstrap liblzma bzip2 libffi libpng zlib # https://github.com/pypa/manylinux manylinux-standard: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/opt/python/cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}-cp{env:PYTHON_MAJOR}{env:PYTHON_MINOR}/bin/python3 - manylinux-{python3.9,python3.10,python3.11,python3.12}: EXTRA_SAGE_PACKAGES_5=_bootstrap liblzma bzip2 libffi libpng conda: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python3 conda: EXTRA_SAGE_PACKAGES_5=_bootstrap liblzma bzip2 libffi libpng zlib - + python3.9,python3.10,python3.11,python3.12: EXTRA_SAGE_PACKAGES_5=_python{env:PYTHON_MAJOR}.{env:PYTHON_MINOR} _bootstrap liblzma bzip2 libffi libpng zlib + manylinux-{python3.9,python3.10,python3.11,python3.12}: EXTRA_SAGE_PACKAGES_5=_bootstrap liblzma bzip2 libffi libpng + macos-python3_pythonorg: EXTRA_SAGE_PACKAGES_5=_bootstrap liblzma bzip2 libffi libpng zlib + macos-python3_xcode: EXTRA_SAGE_PACKAGES_5=_bootstrap liblzma bzip2 libffi libpng zlib {centos-stream,almalinux}-8-python3.9: EXTRA_SYSTEM_PACKAGES=python39 python39-devel # # - toolchain From df0ca5b4a2f7f75b5e5c7c18de4890c829b5638a Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 10 Nov 2023 16:57:49 -0800 Subject: [PATCH 252/538] build/pkgs/_python{3.9,3.10,3.11,3.12}/distros/conda.txt: Use = instead of ==, for fuzzy match --- build/pkgs/_python3.10/distros/conda.txt | 2 +- build/pkgs/_python3.11/distros/conda.txt | 2 +- build/pkgs/_python3.12/distros/conda.txt | 2 +- build/pkgs/_python3.9/distros/conda.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/_python3.10/distros/conda.txt b/build/pkgs/_python3.10/distros/conda.txt index 0e2312f6abf..3fe0755f28f 100644 --- a/build/pkgs/_python3.10/distros/conda.txt +++ b/build/pkgs/_python3.10/distros/conda.txt @@ -1 +1 @@ -python==3.10 +python=3.10 diff --git a/build/pkgs/_python3.11/distros/conda.txt b/build/pkgs/_python3.11/distros/conda.txt index 875818d94e8..b025c36b396 100644 --- a/build/pkgs/_python3.11/distros/conda.txt +++ b/build/pkgs/_python3.11/distros/conda.txt @@ -1 +1 @@ -python==3.11 +python=3.11 diff --git a/build/pkgs/_python3.12/distros/conda.txt b/build/pkgs/_python3.12/distros/conda.txt index 08c4473f336..6c4c1ce29a1 100644 --- a/build/pkgs/_python3.12/distros/conda.txt +++ b/build/pkgs/_python3.12/distros/conda.txt @@ -1 +1 @@ -python==3.12 +python=3.12 diff --git a/build/pkgs/_python3.9/distros/conda.txt b/build/pkgs/_python3.9/distros/conda.txt index ca224649651..23caf0e0ee2 100644 --- a/build/pkgs/_python3.9/distros/conda.txt +++ b/build/pkgs/_python3.9/distros/conda.txt @@ -1 +1 @@ -python==3.9 +python=3.9 From ddc6a464e4b7a3128c538ecc0740de979855657c Mon Sep 17 00:00:00 2001 From: Matthias Koeppe Date: Fri, 10 Nov 2023 19:38:43 -0800 Subject: [PATCH 253/538] src/sage/combinat/root_system/coxeter_group.py: Fix typo in lazy_import --- src/sage/combinat/root_system/coxeter_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/combinat/root_system/coxeter_group.py b/src/sage/combinat/root_system/coxeter_group.py index 83c1c0c7e9e..8fadad6035c 100644 --- a/src/sage/combinat/root_system/coxeter_group.py +++ b/src/sage/combinat/root_system/coxeter_group.py @@ -12,7 +12,7 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.misc.lazy_import import lazy_import -lazy_import('from sage.combinat.root_system.reflection_group_real', 'ReflectionGroup') +lazy_import('sage.combinat.root_system.reflection_group_real', 'ReflectionGroup') lazy_import('sage.combinat.root_system.weyl_group', 'WeylGroup') From 4a70c1e535bc621bdbe95d8f531375e5700d7c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Tornar=C3=ADa?= Date: Fri, 10 Nov 2023 19:56:31 -0300 Subject: [PATCH 254/538] Exclude external software from --hide=all and --hide=optional --- src/sage/doctest/control.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 8583d7a447d..633afd5c2e6 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -457,11 +457,15 @@ def __init__(self, options, args): options.hide.discard('all') from sage.features.all import all_features feature_names = {f.name for f in all_features() if not f.is_standard()} + from sage.doctest.external import external_software + feature_names.difference_update(external_software) options.hide = options.hide.union(feature_names) if 'optional' in options.hide: options.hide.discard('optional') from sage.features.all import all_features feature_names = {f.name for f in all_features() if f.is_optional()} + from sage.doctest.external import external_software + feature_names.difference_update(external_software) options.hide = options.hide.union(feature_names) options.disabled_optional = set() From 84fb6dac85ffbab02d69c1594a9ae4a2bccf6c84 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 12 Nov 2023 13:22:23 +0900 Subject: [PATCH 255/538] Fix pdf doc build --- .github/workflows/doc-build.yml | 2 +- src/doc/Makefile | 14 +++---- src/doc/en/reference/references/index.rst | 7 ++++ .../combinat/species/generating_series.py | 11 +----- src/sage/rings/lazy_series.py | 2 +- src/sage_docbuild/builders.py | 38 +++++++++++++++---- src/sage_docbuild/conf.py | 2 +- 7 files changed, 49 insertions(+), 27 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 3660ff3a947..7d87c9ed4c5 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -206,7 +206,7 @@ jobs: export SAGE_LIVE_DOC=yes export SAGE_JUPYTER_SERVER=binder:sagemath/sage-binder-env/dev make doc-clean doc-uninstall - ./config.status && make sagemath_doc_html-no-deps + ./config.status && make doc-html && make doc-pdf working-directory: ./worktree-image env: MAKE: make -j2 --output-sync=recurse diff --git a/src/doc/Makefile b/src/doc/Makefile index 2f76dfb9cb4..912eb5cb0e9 100644 --- a/src/doc/Makefile +++ b/src/doc/Makefile @@ -46,14 +46,17 @@ doc-inventory-reference: doc-src $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" doc-inventory--reference_top endif -# reference manual, html -doc-html-reference: doc-inventory-reference +# sub docs of reference manual, html +doc-html-reference-sub: doc-inventory-reference $(eval DOCS = $(shell sage --docbuild --all-documents reference)) @if [ -z "$(DOCS)" ]; then echo "Error: 'sage --docbuild --all-documents' failed"; exit 1; fi $(eval BIBLIO = $(firstword $(DOCS))) $(eval OTHER_DOCS = $(wordlist 2, 100, $(DOCS))) $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" doc-html--$(subst /,-,$(BIBLIO)) $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" $(foreach doc, $(OTHER_DOCS), doc-html--$(subst /,-,$(doc))) + +# reference manual, html; reference_top is built after sub docs +doc-html-reference: doc-html-reference-sub $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" doc-html--reference_top # other documentation, html @@ -79,16 +82,13 @@ doc-pdf-reference: doc-inventory-reference $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" doc-pdf--reference_top # other documentation, pdf -doc-pdf-other: doc-html-reference +doc-pdf-other: doc-pdf-reference $(eval DOCS = $(shell sage --docbuild --all-documents all)) @if [ -z "$(DOCS)" ]; then echo "Error: 'sage --docbuild --all-documents' failed"; exit 1; fi $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" $(foreach doc, $(wordlist 2, 100, $(DOCS)), doc-pdf--$(subst /,-,$(doc))) -# website with pdf links -doc-pdf-website: - sage --docbuild website html $(SAGE_DOCBUILD_OPTS) +doc-pdf: doc-pdf-reference doc-pdf-other -doc-pdf: doc-pdf-reference doc-pdf-other doc-pdf-website .PHONY: all clean \ doc-src \ diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index d9f406d055d..50b4ad0fead 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -960,6 +960,13 @@ REFERENCES: .. [BL2003] \S. Brlek, A. Ladouceur, A note on differentiable palindromes, Theoret. Comput. Sci. 302 (2003) 167--178. +.. [BLL1998] \F. Bergeron, G. Labelle, and P. Leroux. + "Combinatorial species and tree-like structures". + Encyclopedia of Mathematics and its Applications, vol. 67, Cambridge Univ. Press. 1998. + +.. [BLL2008] François Bergeron, Gilbert Labelle, and Pierre Leroux. + "Introduction to the Theory of Species of Structures", March 14, 2008. + .. [BraLea2008] \C. Bracken and Gregor Leander: *New families of functions with differential uniformity of 4*, Proceedings of the Conference BFCA, Copenhagen, 2008. diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index e7f7c8ee978..dca117a9971 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -30,13 +30,6 @@ sage: s[3] # optional - sage.modules p[1, 1, 1] + p[2, 1] -REFERENCES: - -.. [BLL] \F. Bergeron, G. Labelle, and P. Leroux. - "Combinatorial species and tree-like structures". - Encyclopedia of Mathematics and its Applications, vol. 67, Cambridge Univ. Press. 1998. -.. [BLL-Intro] François Bergeron, Gilbert Labelle, and Pierre Leroux. - "Introduction to the Theory of Species of Structures", March 14, 2008. """ # **************************************************************************** @@ -217,7 +210,7 @@ def functorial_composition(self, y): REFERENCES: - - Section 2.2 of [BLL]_. + - Section 2.2 of [BLL1998]_. EXAMPLES:: @@ -651,7 +644,7 @@ def LogarithmCycleIndexSeries(R=QQ): Return the cycle index series of the virtual species `\Omega`, the compositional inverse of the species `E^{+}` of nonempty sets. - The notion of virtual species is treated thoroughly in [BLL]_. + The notion of virtual species is treated thoroughly in [BLL1998]_. The specific algorithm used here to compute the cycle index of `\Omega` is found in [Labelle2008]_. diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 8086e15f9ef..5fdfb64cea4 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -6219,7 +6219,7 @@ def functorial_composition(self, *args): whose labels are the set of all `G`-structures on `A`. The Frobenius character (or cycle index series) of `F \Box G` - can be computed as follows, see section 2.2 of [BLL]_): + can be computed as follows, see section 2.2 of [BLL1998]_): .. MATH:: diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index 323c9247252..c79b61c1506 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -637,17 +637,21 @@ def pdf(self): """ super().pdf() - # we need to build master index file which lists all - # of the PDF file. So we create an html file, based on - # the file index.html from the "reference_top" target. - - # First build the top reference page. This only takes a few seconds. - getattr(get_builder('reference_top'), 'html')() + # We want to build master index file which lists all of the PDF file. + # We modify the file index.html from the "reference_top" target, if it + # exists. Otherwise, we are done. from sage.env import SAGE_DOC reference_dir = os.path.join(SAGE_DOC, 'html', 'en', 'reference') output_dir = self._output_dir('pdf') + # Check if the top reference index.html exists. + try: + with open(os.path.join(reference_dir, 'index.html')) as f: + html = f.read() + except FileNotFoundError: + return + # Install in output_dir a symlink to the directory containing static files. # Prefer relative path for symlinks. relpath = os.path.relpath(reference_dir, output_dir) @@ -657,8 +661,6 @@ def pdf(self): pass # Now modify top reference index.html page and write it to output_dir. - with open(os.path.join(reference_dir, 'index.html')) as f: - html = f.read() html_output_dir = os.path.dirname(reference_dir) # Fix links in navigation bar @@ -1051,13 +1053,33 @@ def get_modules(self, filename): Given a filename for a reST file, return an iterator for all of the autogenerated reST files that it includes. """ + from sage.features.all import all_features + # Create the regular expression used to detect an autogenerated file auto_re = re.compile(r'^\s*(..\/)*(sage(_docbuild)?\/[\w\/]*)\s*$') # Read the lines with open(filename) as f: lines = f.readlines() + + skip = False for line in lines: + if skip: + if not line.strip() or line.count(' ', 0) >= indent: + continue + skip = False + elif line.lstrip().lower().startswith('.. only::'): + try: + tag_name = line[line.index('feature_') + 8:].strip() + for feature in all_features(): + if tag_name == feature.name.replace('.', '_'): + break + else: + skip = True + indent = line.index('.. ') + 3 + continue + except ValueError: + pass match = auto_re.match(line) if match: yield match.group(2).replace(os.path.sep, '.') diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index 93333c2509d..8602016d042 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -296,7 +296,7 @@ def set_intersphinx_mappings(app, config): intersphinx.normalize_intersphinx_mapping(app, config) -# By default document are not master. +# By default document is master. multidocs_is_master = True # https://sphinx-copybutton.readthedocs.io/en/latest/use.html From 907276a710c25df6aea8a09dc6c8f8621f7eda5e Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 12 Nov 2023 13:47:22 +0900 Subject: [PATCH 256/538] Revert live doc - no pdfs --- .github/workflows/doc-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 7d87c9ed4c5..3660ff3a947 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -206,7 +206,7 @@ jobs: export SAGE_LIVE_DOC=yes export SAGE_JUPYTER_SERVER=binder:sagemath/sage-binder-env/dev make doc-clean doc-uninstall - ./config.status && make doc-html && make doc-pdf + ./config.status && make sagemath_doc_html-no-deps working-directory: ./worktree-image env: MAKE: make -j2 --output-sync=recurse From 8912679e891e4ea8e8383a2110df66738b7c80c9 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Sun, 12 Nov 2023 19:57:29 +0900 Subject: [PATCH 257/538] Revive pdf docs index page --- src/doc/en/website/root_index.html | 2 +- src/doc/en/website/templates/index.html | 54 ++++++++++---------- src/doc/en/website/templates/index_furo.html | 54 ++++++++++---------- src/sage_docbuild/builders.py | 33 ++++++++++-- 4 files changed, 83 insertions(+), 60 deletions(-) diff --git a/src/doc/en/website/root_index.html b/src/doc/en/website/root_index.html index 21a6086ed72..c3d25ff495b 100644 --- a/src/doc/en/website/root_index.html +++ b/src/doc/en/website/root_index.html @@ -118,7 +118,7 @@

Sage Documentation

Constructions
FAQ
-
Reference Manual
+
Reference Manual
Installation Guide
Developer Guide
diff --git a/src/doc/en/website/templates/index.html b/src/doc/en/website/templates/index.html index c63d109b4dc..cad4cbc287a 100644 --- a/src/doc/en/website/templates/index.html +++ b/src/doc/en/website/templates/index.html @@ -44,12 +44,12 @@

markup. start = rst.rfind('*\n') + 1 end = rst.find('\nUser Interfaces') @@ -725,7 +748,7 @@ def pdf(self): rst_toc = re.sub(r'\n([A-Z][a-zA-Z, ]*)\n[-]*\n', r'\n\n\n

\1

\n\n
PREP Tutorials